README.TXT000664 045065 024037 00000000572 14501440107 012521 0ustar00fdckermit000000 000000 C-KERMIT 10.0 DEVELOPMENT C-Kermit 10.0 pre-Beta.11 16 September 2023... From David Goodwin: several hundred compiler warnings when building for Windows with OpenWatcom 1.9 fixed; for details see: https://www.kermitproject.org/ckupdates.html which contains an account of all the previous development versions, Alphas, and Betas since C-Kermit 9.0 was released in 2011. COPYING.TXT000664 045065 024037 00000002735 11601155363 012704 0ustar00fdckermit000000 000000 THE C-KERMIT 9.0 LICENSE Fri Jun 24 14:43:35 2011 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + Neither the name of Columbia University nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. makefile000664 045065 024037 00001447157 14767414117 012722 0ustar00fdckermit000000 000000 # makefile / Makefile / ckuker.mak / CKUKER.MAK # # Sun Mar 24 13:21:46 2024 BUILDID=20250322 CKVER= "10.0 Beta.12" # # -- Makefile to build C-Kermit for UNIX and UNIX-like platforms -- # # Copyright (C) 1985, 2024, # Trustees of Columbia University in the City of New York. # All rights reserved. See the C-Kermit COPYING.TXT file or the # copyright text in the ckcmai.c module for disclaimer and permissions. # In case you can't find the COPYING.TXT file, as of 2011 it contains the # Simplified 3-Clause BSD License, which is an Open Source license. # # Note: As of 3 February 2024, the ckcwart.c and ckcpro.w files have been # reinstated. They are not used when building C-Kermit, but any changes to # to the Kermit protocol itself must be made ckcpro.w, and then you must: # # make wart # make ckcpro.c # # before building C-Kermit (e.g. with "make linux"). # # Author: Frank da Cruz (principal author) # Email: fdc@kermitproject.org # Web: https://kermitproject.org # # Example for Linux: # 1. cd to your C-Kermit source-code directory # 2. make clean (to delete object files from previous builds) # 3. rm wermit (remove any previous binary) # 4. make linux (to build a version for your Linux machine) # 5. make check (to check the result - depends on step 3) # 6. test it and report any any problems by email to the address above # 7. mv it to where it should reside, e.g. mv wermit /usr/local/bin/kermit # 8. chmod 755 or 775 if necessary and give appropriate owner and gruop # .. Many variations possible; see https://www.kermitproject.org/ckccfg.html # # Shortcut - Steps 4 and 5 can be combined: "make linux check" # # Note: Author is no longer at Columbia University or at the 115th Street # address as of 1 July 2011. Even so, C-Kermit remains Copyright Columbia # University because that is where it was first written in 1985 and further # developed through mid-2011. # # Contributions from many others. Special thanks to Jeff Altman for the # secure-build targets, Peter Eichhorn, assyst GmbH, for the consolidated # HP-UX targets and the "uninstall" target, to Robert Lipe for the updated # and consolidated SCO UNIX / ODT / OSR5 targets, to Ric Anderson for the # IRIX 6.x targets, to Seth Theriault for major improvements to the # Mac OS X targets, and to Alexey Dokuchaev for FreeBSD 9.0. # # C-Kermit is written and produced by hand without any external automated # procedures such as autoconf / automake / configure, although some of the # targets below (especially the linux target) inspect the environment and make # some decisions in the most portable way possible. The automated tools are # not used because (a) C-Kermit predates them, and (b) they are not portable # to all the platforms where C-Kermit must be (or once was) built, (c) the # automated tools are always changing, and (d) to keep C-Kermit as independent # as possible from external tools over which we have no control. # # Most entries use the "xermit" target, which uses the select()-based CONNECT # module, ckucns.c. The "wermit" target uses the original fork()-based # CONNECT module, ckucon.c, which has some drawbacks but was portable to every # Unix variant whether it had TCP/IP or not (select() is part of the TCP/IP # library, which was not standard on older Unixes). If your target still uses # the "wermit" target, please try substituting the "xermit" one and if it # works, let us know (mailto:fdc@columbia.edu). When changing a target over # from wermit to xermit, also remove -DNOLOEARN. # # CAREFUL: Don't put the lowercase word "if", "define", or "end" as the first # word after the "#" comment introducer in the makefile, even if it is # separated by whitespace. Some versions of "make" understand these as # directives, which older make versions do not understand. Uppercase letters # remove the danger, e.g. "# If you have..." # # WARNING: This is a huge makefile. Although it is less likely since the # turn of the century, some "make" programs might run out of memory. If this # happens to you, edit away the parts that do not apply to your platform and # try again. # # WARNING 2: In many cases this file invokes itself recursively, sometimes # several levels deep (as in the Linux targets); i.e. some targets are used # as 'subroutines' of other targets, with parameters passed by setting # environment variables. For that reason, don't use 'make -e'. # # Certain UNIX variations have their own separate makefiles: # . For Android, use android.mk. # . For 2.10 or 2.11 BSD on the DEC PDP-11, use ckubs2.mak. # . For Plan 9, use ckpker.mk. # # Separate build procedures are provided non-UNIX platforms: VMS, VOS, # AOS/VS, etc. See the ckaaaa.txt file or the Kermit website for details. # # # DIRECTIONS FOR UNIX # # Rename this file to "makefile" or "Makefile" if necessary. Pick out the # entry most appropriate for your UNIX version from the list below and then # give the appropriate "make" command, for example "make aix", "make macosx", # "make linux". If you experience any difficulties with the build procedure, # then please also read any comments that accompany the make entry itself # (search for the make entry name on the left margin). # # Other targets: # 'make install' is an installation script (read accompanying comments!). # 'make uninstall' undoes 'make install' (read accompanying comments!). # 'make clean' removes intermediate and object files. # 'make show' tells the default include and lib paths for secure builds. # # IMPORTANT: # For more detailed installation instructions, read the files ckuins.txt # and ckccfg.txt, also available at the Kermit website in HTML form: # http://www.columbia.edu/kermit/ckuins.html # http://www.columbia.edu/kermit/ckccfg.html # # For descriptions of known problems and limitations, # read the files ckcbwr.txt and ckubwr.txt (the "beware files") or: # http://www.columbia.edu/kermit/ckcbwr.html # http://www.columbia.edu/kermit/ckubwr.html # # Most targets build C-Kermit with its symbol table included. To reduce the # size of the executable program, add "LNKFLAGS=-s" to the end of your 'make' # command or to the makefile entry, or 'strip' the executable after # building. To further reduce the size after building, use 'mcs -d' if your # Unix version has such a command. For further details on size reduction, read # ckccfg.txt to find out how to remove features that you don't need. # # TCP/IP networking support: If your C-Kermit version does not include TCP/IP # networking, but your UNIX system does, try adding -DTCPSOCKET to the CFLAGS # of your makefile entry. If that doesn't work, look at some of the other # targets that include this flag for ideas about what libraries might need to # be included (typically -lsocket and/or -lBSD and/or -lnsl and/or -linet). # NOTE: In some cases (old versions of SCO or HP-UX), you might need not only # a C compiler, but also a "TCP/IP developers kit" for the required object # libraries and header files. # # Please report modifications, failures (preferably with fixes) or successes # to the author, fdc@columbia.edu. # # TARGETS FOR DIFFERENT UNIX PLATFORMS AND VERSIONS: # # + Marks those that have been built successfully for C-Kermit 9.0 or later. # - Those that once built OK but no longer do (e.g. too big). # ? Those that worked in a previous version but have not been tested recently. # -------------------------- # Some commonly used targets: # # + "make -f android.mk" (separate makefile) for Android. # + "make linux" should work for any version of Linux on any hardware. # Note: new "make linux" (2016) not yet widely tested. # Use "make linux-2015" (the old "make linux") # if "make linux" causes problems. # + "make linux+ssl" ditto, with OpenSSL security added. # + "make linux+krb5" ditto, with Kerberos 5 security added. # + "make linux+krb5+ssl" Linux with OpenSSL and Kerberos 5. # Note: the Linux targets work for Raspberry Pi with Debian 7.0 (Raspbian) # + "make netbsd", NetBSD, any version. # + "make netbsd+ssl", NetBSD with OpenSSL 0.9.7 or later. # + "make netbsd+krb5", NetBSD with Kerberos 5. # + "make netbsd+krb5+ssl", NetBSD with Kerberos 5 and OpenSSL 0.9.7 or later. # ? "make freebsd1" for FreeBSD 1.x # ? "make freebsd2" for FreeBSD 2.x # + "make freebsd3" for FreeBSD 3.x # ? "make freebsd4" for FreeBSD 4.0 # + "make freebsd", FreeBSD 4.1 or later. # + "make freebsd+ssl", FreeBSD 5.0 or later with OpenSSL 0.9.7 or later. # + "make openbsd", OpenBSD 2.3 or later. # + "make openbsd+ssl", OpenBSD 2.3 or later with OpenSSL 0.9.7 or later. # + "make mirbsd", MirBSD. # + "make mirbsd+ssl", MirBSD with OpenSSL 0.9.7 or later. # More recent macOS re-branded releases for Intel (x86_64) Sierra (10.12), # High Sierra (10.13), Mojave (10.14), Catalina (10.15), and Intel x86_64/ARM # Big Sur (11), Monterey (12) # + "make macos" (without 'x') should be used for 10.12 and later. # + "make macosx" should work for any Mac OS X version up until 10.8 or 10.12. # + "make macosx+krb5+openssl" Mac OS X 10.3.9 or later + Kerberos V + OpenSSL. # + "make aix" should work for any version of AIX 4.2 or later. # + "make aixg" should work for any version of AIX 4.2 or later, using gcc. # + "make aix+ssl" ditto, with OpenSSL (specifying SSLLIB and SSLINC) # + "make aix+ibmssl" ditto, with IBM OpenSSL # + "make solaris9", "make solaris10" for Solaris 9 or 10 with Sun cc. # + "make solaris9g", "make solaris10g" for Solaris 9 or 10 with gcc. # + "make solaris11" for Solaris 11 with Sun CC # + "make solaris11g" for Solaris 11 with gcc # + "make sco_osr600" for SCO OpenServer 6.0.0. # # For other current OSs such as Solaris, HP-UX, and SCO there are separate # targets for different combinations of OS version and compiler; see the # complete list. For older OS's see the complete list. If an old target # doesn't work in this release of C-Kermit you can get a previous release from # the Kermit FTP site: ftp://kermit.columbia.edu/kermit/ # # SECURE TARGETS (versions that support authentication and encryption) # are described after the following list. Search for ******* below. # # -------------------------- # Complete list (alphabetical): # ? for 386BSD (Jolix) 0.0, 0.1, "make 386bsd" (see comments in entry), # or (preferably, if it works) "make bsd44" or "make bsd44c". # ? for Acorn RISCiX, "make riscix" or "make riscix-gcc" # ? for Alliant FX/8 with Concentrix 4.1 or later, "make bsdlck" # ? for Altos 486, 586, 986 with Xenix 3.0, "make altos" # ? for Altos ACS68000, 8Mhz 68000, UNIX System 3 Rel 2, 512K, "make altos3" # ? for Amdahl UTS 2.4 on IBM 370 series & compatible mainframes, "make uts24" # ? for Amdahl UTSV IBM 370 series & compatible mainframes, "make utsv" # ? for Amdahl UTSV IBM 370 series mainframes with TCP/IP, "make utsvtcp" # ? for Amdahl mainframes with UNIX System V R 5.2.6b 580, "make sys3" # ? for Apollo Aegis 9.x, DOMAIN/IX 9.x, "make aegis" # (Last tested in C-Kermit 5A(189)) # ? for Apollo DOMAIN/IX, if the above fails, try "make apollobsd" # ? for Apollo with SR10.0 or later, BSD environment, "make sr10-bsd" # ? for Apollo with SR10.0 or later, System V environment, "make sr10-s5r3" # ? for Apple Macintosh II with A/UX pre-3.0, "make aux", "auxgcc" or "auxufs" # ? for Apple Macintosh with A/UX 3.0 and gcc, "make aux3gcc" or aux3gccc # ? for Apple PowerMac with MkLinux, "make mklinux" (read Linux entry first) # ? for Apple PowerMac with LinuxPPC, "make linuxppc" # ? for Apple Macintosh with Minix 1.5.10, "make minix68k" or "make minixc68" # ? for Apple Macintosh with Mac OS X 1.0 (Rhapsody), "make macosx10" # (no curses), "make macosx10c" (curses), or "make macosx10nc" (ncurses). # Or "make macosx10ncx" (ncurses but "make macosx10nc" doesn't work). # ? for Apple Macintosh with Mac OS X 10.2, "make macosx102nc" (ncurses). # ? for Apple Macintosh with Mac OS X 10.3, "make macosx103" # ? for Apple Macintosh with Mac OS X 10.3.9 or later, "make macosx" # ? for Arix System 90 with AT&T SVR3, "make sys5r3na" # - for AT&T 6300 with IN/ix, "make sys5" # - for AT&T 6300 PLUS, "make att6300" or (with no debugging) "make att6300nd" # ? for AT&T 6386 WGS UNIX PC, "make sys5r3" # ? for AT&T 3B2, 3B20 systems, "make att3b2". # for AT&T 3B1, 7300 UNIX PC (see notes with the entries): # In C-Kermit 7.0, only the gcc entries work: # ? "make sys3upcg", "make sys3upcgc", "make att351gm" # The others fail with "too many defines" (usually in ckuusr.h): # - "make sys3upc", "make sys3upcold", "make sys3upcc", "make sys3upcx", # "make sys3upcm", "make att351m" # ? for AT&T System III/System V R2 or earlier, "make sys3" or "make sys3nid" # ? for AT&T System III/System V with Honey DanBer UUCP, "make sys3hdb" # ? for AT&T System V on DEC VAX, "make sys3" or "make sys5r3" # ? for AT&T System V R3, use "make sys5r3" or "make sys5r3c" # ? for AT&T System V/386 R3.2 built on Interactive 4.1.1, "make sys5r32is". # ? for AT&T System V/386 R320.0 Versyss Systems, use "make sys5r3" # or "make sys5r3c". # ? for AT&T System V R4, "make sys5r4", "make sys5r4sx", or "make sys5r4nx", # or if the ANSI C function prototyping makes trouble, add -DNOANSI, # as in "sys5r4sxna" entry # ? for AT&T (USL) System V R4.2 use the sys5r4* entries. # ? for Atari Falcon with MiNT, "make posix" # ? for Atari ST with Minix ST 1.5.10.3, "make minix68k" or "make minixc68" # ? for BBN C/70 with IOS 2.0, "make c70" # ? for BeBox with Be OS 1.x DR7, "make beboxdr7" # Compiles OK but doesn't link with default linker which is limited to 64K. # Links OK with "Code Warrior Gold". Many hacks in the source code need # to be removed when DR8 and later come out. # (Last tested in C-Kermit 6.0) # - for BeBox with Be OS 1.x DR8, "make bebox" # (Needed functions missing from operating system and/or not working.) # - for Bell Labs UNIX Version 6 (6th Edition), there is no makefile entry. # ? for Bell Labs UNIX Version 7 (7th Edition), "make v7" (but see notes below) # (last built successfully in C-Kermit 5A188) # ? for Bell Labs Research UNIX Version 10, "make bellv10" # (last built successfully in C-Kermit 6.0) # ? for Bell Labs / Lucent Plan 9, use separate makefile ckpker.mk: # can be built for Intel, MIPS, 680x0, and PowerPC (last built C-Kermit 7.0) # ? for BSDI BSD/386 1.x, "make bsdi" # ? for BSDI BSD/OS 2.x, "make bsdi2" # ? for BSDI BSD/OS 3.0 or 3.1, "make bsdi3" # ? for BSDI BSD/OS 4.x, "make bsdi4" # ? for BSDI BSD/OS 4.x, to build a binary that also works on FreeBSD, # "make bsdix". # ? for Berkeley Unix 2.4, "make v7" (but read v7 material below) # ? for Berkeley Unix 2.9 (DEC PDP-11 or Pro-3xx), "make bsd29" # - for Berkeley Unix 2.10, use ckubs2.mak (a separate makefile) # - for Berkeley Unix 2.11, use ckubs2.mak (a separate makefile) # This makefile is too big. Read the instructions in ckubs2.mak. # "make -f ckubs2.mak bsd210" or "make -f ckubs2.mak bsd211". # (last built successfully in C-Kermit 6.0 - later versions too big) # ? for Berkeley Unix 2.11 "make -f ckubs2.mak bsd210noicp" (no command parser) # ? for Berkeley Unix 4.1, "make bsd41" # ? for Berkeley Unix 4.2 on VAX, "make bsd42" or "make bsd42c" # ? for Berkeley Unix 4.2 or 4.3 with HoneyDanBer UUCP, "make bsdhdb" # ? for Berkeley Unix 4.3 on VAX, "make bsd43", "make bsd43nc". # ? for Berkeley Unix 4.3 on VAX, no networking "make bsd43nonet. # ? for Berkeley Unix 4.3 without acucntrl program, "make bsd42" or "bsd42c" # NOTE: all the C-Kermit 7.0 full builds for old BSDs fail with # "too many defines" in CPP, even on big architectures like VAX. This # can be worked around with a clever ruse. See comments at target. # ? for Berkeley Unix 4.3, command-line only, "make bsdm". # ? for Berkeley Unix 4.3-Tahoe, same as 4.3 BSD # ? for Berkeley Unix 4.3-Reno, "make bsd43" or "make bsd44" or "make bsd44c" # ? for Berkeley Unix 4.3-Carson City, "make bsd44" or "make bsd44c" # ? for Berkeley Unix 4.4-Networking/2 or -Alpha, "make bsd44" or "make bsd44c" # ? for Berkeley Unix 4.4, "make bsd44" or "make bsd44c" # ? for Berkeley Unix 4.4-Lite, "make bsd44" or "make bsd44c" # ? for Bull DPX/2 with BOS/X, "make bulldpx2" # ? for Cadmus, "make sys3" # for Caldera, see SCO, Linux. # ? for Callan Unistar, "make sys3" # ? for CDC VX/VE 5.2.1 System V emulation, "make vxve" # ? for Charles River Data Systems Universe 680x0 with UNOS 9.2, maybe # also other UNOS versions, "make crds" # ? for CIE Systems 680/20 with Regulus, "make cie" # ? for Commodore Amiga 3000UX Sys V R4, "make sys5r4sx" # ? for Commodore Amiga 3000UX Sys V R4 and TCP/IP, "make svr4amiganet" # ? for Commodore Amiga with Minix 1.5.10, "make minix68k" of "make minixc68" # ? for Concurrent/Masscomp with RTU 4.0 or later, BSD environment, "make # rtubsd", "make rtubsd2", "make rtubsd3" (depending on where ndir.h # is stored, see entries below). # ? for Concurrent/Masscomp with RTU 4.0 or later, System V R2, "make rtus5" # ? for Concurrent (Perkin-Elmer) 3200 series, "make sys5". # ? for Concurrent (Perkin-Elmer) 3200 series with , "make ccop1" # ? for Concurrent PowerMAX OS SVR4, "make powermax" # ? for Consensys UNIX SV/386 R4V3, "make sys5r4sxtcpc" or "make sys5r4sx" # ? for Convergent with CTIX Sys V R2, "make sys5" # ? for Convergent with CTIX 6.4.1, "make ctix" # ? for Convex C1, "make convex" # ? for Convex C210 with Convex/OS 8, "make convex8" # ? for Convex C2 with Convex/OS 9.1, "make convex9" # ? for Convex C2 with Convex/OS 10.1 and gcc 2.x, "make convex10gcc" # ? for Cray Research X/MP or YMP or C90 with UNICOS 6.x (System V R3), # "make cray" # ? for Cray Research X/MP or YMP or C90 with UNICOS 7.x (System V R4), # "make cray" # ? for Cray Research X/MP or YMP or C90 with UNICOS 8.0 Alpha, "make cray8" # ? for Cray Research X/MP or Y-MP or C90 with UNICOS 9.0, "make cray9" # ? for Cray Computer Cray-2 or Cray3 with CSOS, "make craycsos" # ? for Cyber 910 (Silicon-Graphics Iris) with Irix 3.3, "irix33" # ? for Data General AViiON with DG/UX 5.4 before R3.00, "make dgux540" # or "make dgux540c" # ? for DG/UX 5.4 on AViiON Intel models, "make dgux540i" or dgux540ic. # ? for DG/UX 5.4R4.11 on AViiON, all models, "make dgux54411" # ? for DG/UX 5.4R4.20 on AViiON, all models, "make dgux54420" # ? for Data General AViiON with DG/UX 4.3x using Sys V-isms, "make dgux430" # ? for Data General AViiON with DG/UX 4.3x using BSD-isms, "make dgux430bsd" # ? for Data General AViiON, earlier UNIX versions, "make sys5r3" # ? for Data General MV systems with DG/UX, ??? # ? for Data General MV systems with MV/UX, use AOS/VS C-Kermit (CKDKER.MAK) # ? for Data General MV systems with AOS/VS, use CKDKER.MAK (last = C-K 7.0) # ? for DEC PDP-11 with Berkeley UNIX 2.x, see Berkeley UNIX 2.x. # ? for DEC PDP-11 with Mini-UNIX (Bell 6th Edition for PDP-11 with no MMU), # probably no way to fit C-Kermit without I&D space. # ? for DEC PDP-11 with Ultrix-11 3.x, ??? (probably needs overlays) # ? for DEC VAX with Ultrix 1.x "make bsd" # ? for DEC VAX with Ultrix 2.x "make ultrix2x" # ? for DEC VAX or DECstation with Ultrix 3.0, 3.1, "make ultrix3x" # ? for DECstation or VAX with Ultrix 4.0 or 4.1, "make ultrix40" # ? for DECstation or VAX with Ultrix 4.2, "make ultrix42" or "make ultrix42c" # ? for DECstation or VAX with Ultrix 4.x, POSIX world, "make posix" # ? for DECstation or VAX with Ultrix 4.3, "make ultrix43". # ? for DECstation or VAX with Ultrix 4.4, "make ultrix44". # ? for DECstation 5000/50, /150 or /260 (R4x00 MIPS CPU), Ultrix 4.3A or later # "make ultrix43-mips3" or "make ultrix43c-mips3" # ? for DECstation (MIPS) with Berkeley Sprite, "make bsd44"? # ? for DECstation (MIPS) with OSF/1 V1.0 to 1.3, "make dec-osf" # ? for DEC Alpha with OSF/1 1.0 to 1.3, "make dec-osf" # ? for DEC PC 486 with OSF/1, "make dec-osf" # ? for DEC Alpha with OSF/1 2.x, "make dec-osf20" # ? for DEC Alpha with OSF/1 3.0, "make dec-osf30" # ? for DEC Alpha with Digital UNIX 3.2, "make du32" # ? for DEC Alpha with Digital UNIX 4.0-4.0D, "make du40" or "make du40gcc" # ? for DEC Alpha with Digital UNIX 4.0E or higher, see Tru64. # + for DEC Alpha with any version of DU or OSF/1, "make dec-osf1" # - for DEC Pro-350 with Pro/Venix V1.x, "make provx1" (version 5A is too big) # ? for DEC Pro-380 with Pro/Venix V2.0 (Sys V), "make sys3" or "make sys3nid" # ? for DEC Pro-380 with 2.9, 2.10, or 2.11 BSD, "make bsd29" or "make bsd210" # for DEC PDP-11 with 2.xBSD (use separate makefile ckubs2.mak) # ? for Dell UNIX Issue 2.x (= USL Sys V/386 R4.x + fixes), "make dellsys5r4" # or "make dellsys5r4c" (last tested in C-Kermit 5A). # ? for DIAB DS90 with DNIX (any version) create an empty if # this file does not already exist (or add -DNOFILEH to the make entry). # ? for DIAB DS90 with DNIX 5.2 (Sys V.2) or earlier, "make dnix", # "make dnixnd", or (to add curses and TCP/IP) "make dnixnetc", # ? for DIAB DS90 with DNIX 5.3 (Sys V.3), "make dnix5r3" # ? for DIAB DS90 with DNIX 5.3 (Sys V.3) and TCP/IP, "make dnix5r3net" # ? for DIAB DS90 with DNIX 5.3 2.2 (Sys V.3), ANSI C, "make dnix5r3ansi" # or, to include TCP/IP, "make dnix5r3ansinet", # but you have to fix a bug in /usr/include/stdlib.h first: # change "extern void free(char *str);" to "extern void free(void *str);" # ? for Dolphin Server Technology Triton 88/17 with SV/88 R3.2, "make sv88r32" # ? for Encore Multimax 310, 510 with Umax 4.2, "make umax42" # ? for Encore Multimax 310, 510 with Umax 4.3, "make umax43" # ? for Encore Multimax 310, 510 with Umax V 2.2, use Berkeley cc, "make bsd" # ? for Encore 88K with Umax V 5.2, "make encore88k" # ? for ESIX System V R4.0.3 or 4.04 with TCP/IP support, "make esixr4" # NOTE: You can also build on Unixware 2.x with "make esixr4", and run # on ESIX, but there you must first: # ln /usr/lib/libsocket.so /usr/lib/libsocket.so.1 # ln /usr/lib/libnsl.so /usr/lib/libnsl.so.1 # (This worked for C-Kermit 6.0 but does not work for 7.0) # (But you can probably still build a non-networking version this way) # ? for Everex STEP 386/25 Rev G with ESIX Sys V R3.2D, "make sys5r3" # ? for Fortune 32:16, For:Pro 1.8, "make ft18" # ? for Fortune 32:16, For:Pro 2.1, "make ft21" # ? for FPS 500 with FPX 4.1, "made bsd" # ? for FreeBSD 1.0, "make freebsd1" # ? for FreeBSD 2.x, "make freebsd2" (ncurses) or "make freebsd2c" (curses) # ? for FreeBSD 3.x, "make freebsd3" (ncurses) or "make freebsd3c" (curses) # ? for FreeBSD 4.0, "make freebsd40" # ? for FreeBSD 4.1 or later, "make freebsd" # + NOTE: Just use "make freebsd" for any reasonably recent FreeBSD version. # ? for Harris HCX-2900, "make sys5r3" # ? for Harris Night Hawk 88K or 68K with CX/UX pre-6.1, "make sys5r3" # ? for Harris Night Hawk 88K or 68K with CX/UX 6.1 or later, "make cx_ux" # ? for Heurikon, "make sys3" # ? for HP-3000, MPE/ix, "make posix"? # ? for HP-9000 Series 300 with 4.4BSD, "make bsd44" # NOTE: Most of the HP-UX targets were tested successfully in 2010. # Verification needed for C-Kermit 9.0 Beta.01... # ? for HP-9000 Series 500, HP-UX 5.21 and no networking "make hpux0500" # ? for HP-9000 Series 500, HP-UX 5.21 with WIN/TCP 1.2 "make hpux0500wintcp" # ? for HP-9000 Series, HP-UX 6.5, without long filenames, # "make hpux0650", "make hpux0650c" or "make hpux0650tcpc" # ? for HP-9000 Series, HP-UX 7.0 or later no long filenames, "make hpux0700sf" # or (to include tcp/ip, curses, etc) "make hpux0700sftcpc" # ? for HP-9000 Series with HP-UX 7.0, TCP/IP,long filenames,"make hpux0700lfn" # ? for HP-9000 300/400 Series (680x0) with HP-UX 8.0, TCP/IP, "make hpux0800" # or "make hpux0800c" # ? for HP-9000 700/800 Series (PA-RISC), HP-UX 8.0, TCP/IP, "make hpux0800pa" # or "make hpux0800pac" # ? for HP-9000 Series with HP-UX 8.0, no TCP/IP, long filenames, # "make hpux0800notcp" # ? for HP-9000 Series, HP-UX 9.0 - 9.10, TCP/IP, curses, restricted compiler # (no optimization, no ANSI), all models, "make hpux0900". Read the # hpux0900 entry below for more info. # ? for HP-9000 700 and 800 Series, HP-UX 9.x, TCP/IP, curses, # HP optimizing ANSI C compiler, "make hpux0900o700". # ? for HP-9000 with Motorola CPUs, HP-UX 9.x, TCP/IP, curses, # HP optimizing ANSI C compiler, "make hpux0900mot". # ? for HP-9000 on other CPUs, HP-UX 9.x, TCP/IP, curses, # HP optimizing ANSI C compiler, "make hpux0900o". # ? for HP-9000 series, HP-UX 9.x, TCP/IP, curses, gcc, all models, # "make hpux0900gcc" # ? for HP-9000 700/800 Series, HP-UX 10.00,10.01,10.10,10.20,10.30, TCP/IP, # curses, restricted compiler (no optimization, no ANSI) "make hpux1000". # ? for HP-9000 700/800 Series, HP-UX 10.00,10.01,10.10,10.20,10.30, TCP/IP, # curses, HP ANSI/optimizing compiler "make hpux1000o" or "make hpux1000o+" # ? for HP-9000 HP-UX 10.00 or later with gcc, "make hpux1000gcc" # ? for Trusted HP-UX 10.xx "make hpux1000t", "make hpux1000to", # or make hpux1000to+" # ? for HP-9000 700/800 Series, HP-UX 11.00,TCP/IP,curses, restricted compiler # (no optimization, no ANSI) "make hpux1100". # ? for HP-9000 700/800 Series, HP-UX 11.00,TCP/IP,curses, restricted compiler # HP ANSI/optimizing compiler "make hpux1100o" or "make hpux1100o+" # ? for Trusted HP-UX 11.xx "make hpux1100t", "make hpux1100to", # make hpux1100to+" # ? for HP-9000 PA-RISC models with NeXTSTEP 3.3, "make nextquadfat". # ? for HP-9000 PA-RISC models with OPENSTEP/Mach 4.1, "make nextquadfat". # ? for IBM 370 Series with IX/370, "make ix370" # ? for IBM 370 Series with AIX/370 1.2, "make aix370" # ? for IBM 370 Series with AIX/370 3.0, "make aix370" # ? for IBM 370 Series with AIX/ESA 2.1, "make aixesa" # - for IBM PC/AT 286 & compatibles with Mark Williams Coherent OS, # command-line-only version, "make coherent" (version 5A & later too big) # ? for IBM PC 386 & compatibles with Mark Williams Coherent OS, # minimum interactive version, "make coherentmi" # ? for IBM PC 386 & compatibles with Mark Williams Coherent OS, # full interactive version, prior to v4.2, "make coherentmax" # ? for IBM PC 386 & compatibles with Mark Williams Coherent OS 4.2, # "make coherent42" # ? for IBM PC 386 & compatibles with LynxOS 2.0 or 2.1, "make lynx21" # ? for IBM PC 386 & compatibles with LynxOS 2.2, "make lynx" # - for IBM PC/AT & compatibles with original MINIX, "make minix" (too big) # ? for IBM PC family, 386-based, with MINIX/386 1.5, "make minix386" # or if you have GNU CC, "make minix386gcc" # ? for IBM PC family, 386-based, with MINIX 2.0, "make minix20" # ? for IBM PC family, 386-based, with MINIX 3.0, "make minix3" # + for IBM PC family, 386-based, with MINIX 3.0, "make minix315" # ? for IBM PS/2 with PS/2 AIX 1.0, 1.1, or 1.2, "make ps2aix" or ps2aixnetc. # ? for IBM PS/2 with PS/2 AIX 1.3, "make ps2aix3" # ? for IBM RISC System/6000 with AIX 3.0, "make aix30" # ? for IBM RISC System/6000 with AIX 3.1.x, "make aix31" # ? for IBM RISC System/6000 with AIX 3.2.0 thru 3.2.5, "make aix32" # ? for IBM RS/6000 or Power Series with AIX 4.1.x, "make aix41" # ? for IBM RS/6000 or Power Series with AIX 4.1.x with gcc, "make aix41g" # ? for IBM RS/6000 or Power Series with AIX 4.1 with X.25, "make aix41x25" # ? for IBM RS/6000 or Power Series with AIX 4.2 or later: "make aix" # (the following "make aixnn" targets are no longer necessary except for gcc) # ? for IBM RS/6000 or Power Series with AIX 4.2, "make aix42" # ? for IBM RS/6000 or Power Series with AIX 4.3, "make aix43" (or aix43gcc) # ? for IBM RS/6000 or Power Series with AIX 4.4, "make aix44" (or aix44gcc) # ? for IBM RS/6000 or Power Series with AIX 4.5, "make aix45" (or aix45gcc) # ? for IBM RS/6000 or Power Series with AIX 5.0, "make aix50" (or aix50gcc) # ? for IBM RS/6000 or Power Series with AIX 5.1, "make aix51" (or aix51gcc) # ? for IBM RS/6000 or Power Series with AIX 5.2, "make aix52" (or aix52gcc) # ? for IBM RS/6000 or Power Series with AIX 5.3, "make aix53" (or aix53gcc) # ? for IBM RS/6000 or Power Series with AIX 6.1, "make aix61" (or aix53gcc) # ? for IBM RT PC with AIX 2.1, "make sys3" # ? for IBM RT PC with AIX 2.2.1, "make rtaix" or "make rtaixc" # ? for IBM RT PC with ACIS 4.2, "make bsd" # ? for IBM RT PC with ACIS 4.3, "make rtacis" or "make bsd KFLAGS=-DNOANSI" # ? for IBM RT PC with 4.3BSD/Reno, "make bsd44" or "make bsd44c" # ? for ICL DRS400 or 400E, "make iclsys5r3" # ? for ICL DRS3000 (80486) with DRS/NX, "make iclsys5r4_486" # ? for ICL DRS6000 (SPARC) with DRS/NX, "make iclsys5r4" # ? for ICL DRS6000 (SPARC) with DRS/NX 4.2MP 7MPlus, "make iclsys5r4m+" # ? Ditto but with IKSD support included, "make iclsys5r4m+iksd" # ? for Integrated Solutions Inc V8S VME 68020, "make isi" # ? for Intel 302 with Bell Tech Sys V/386 R3.2, "make sys5r3" # ? for Intel Xenix/286, "make sco286" # ? for Interactive System III (PC/IX), "make pcix" or "make is3" # ? for Interactive System III (PC/IX) with gcc, "make is3gcc" # ? for Interactive 386/ix 1.0.6 with TCP/IP networking, "make is5r3net2" # ? for Interactive 386/ix 2.0.x, "make is5r3" or (POSIX) "make is5r3p" # ? for Interactive 386/ix 2.0.x with TCP/IP networking, "make is5r3net" # or "make is5r3net2" # ? for Interactive 386/ix 2.2.1, job control, curses, no net, gcc, # "make is5r3gcc" # ? for Interactive UNIX Sys V R3.2 V2.2 - 4.0 without TCP/IP, "make is5r3jc" # ? for Interactive UNIX Sys V R3.2 V2.2 - 4.0 with TCP/IP, "make is5r3netjc" # ? for Intergraph Clipper, "make clix" or "make clixnet" # ? for Jolix (see 386BSD) # + for Linux 1.2 and later, "make linux". Uses ncurses. This version # handles serial speeds up to 460800 bps, Linux FSSTD 1.2, TCP/IP, and # should work on both libc and glibc systems. For static linking, use # "make linux LNKFLAGS=-static". Please read the comments that accompany # the linux entry. As of 8.0.212 Dev.10, this also includes Large File # Support (LFS). # + for Linux builds that fail with "sys/select.h: No such file or directory", # "make linuxns" # + for Linux 1.2 and later but with curses.h and libcurses (rather than # ncurses.h and libncurses), use "make linuxc". # + for Linux 1.2 and later with no curses support at all, "make linuxnc". # + for Linux with no TCP/IP, "make linuxnotcp" # (The following Linux targets are historic and might not work...) # ? for Red Hat Linux 7.1 through RH9, fully configured (krb5, SSL, etc): # "make redhat71", "make redhat72", "make redhat73", "make redhat80" # "make redhat9" # NOTE: You must use this target for Red Hat 7.1 since it # also includes a workaround for its broken curses library. # WARNING: These targets create binaries that include code for # strong encryption and are therefore not exportable. DO NOT PUT # THESE BINARIES ON US OR CANADIAN WEB OR FTP SITES. # ? for Linux on PowerMac (Mklinux DR3), "make mklinux". # ? for Linux 1.2 and later, to build with egcs, "make linuxegcs". # ? for Linux with lcc compiler, no TCP/IP, "make linuxnotcp-lcc" # ? for Linux 1.0 or earlier, "make linux10". # (End old linux targets) # ? for Mach 2.6 on (anything, e.g. DECstation), "make bsd42" or "make bsd43". # ? for MachTen (Tenon) 2.1.1.D on (e.g.) Apple Powerbook, "make machten". # ? for Masscomp RTU AT&T System III, "make rtu" # for other Masscomp, see Concurrent. # ? for Microport SV/AT (System V R2), "make mpsysv" (last edit tested: 144) # ? for Microport SVR4 2.2, 3.1, or 4.1 "make sys5r4sx" # ? for Microsoft,IBM Xenix (/286, PC/AT, etc), "make xenix" or "make sco286" # ? for MIPS System with RISC/os (UMIPS) 4.52 = AT&T SVR3, "make mips" # or "make mipstcpc" # ? for MkLinux on Power Macintosh, "make mklinux" # ? for Modcomp 9730, Real/IX, "make sys5r3" (or modify to use gcc = GLS cc) # ? for Modcomp Realstar 1000 with REAL/IX D.1, "make sv88r32" # ? for Motorola Four Phase, "make sys3" or "make sys3nid" # ? for Motorola Delta System V/68 R3, "make sv68r3" # ? for Motorola Delta System V/68 R3V5, "make sv68r3v5" # ? for Motorola Delta System V/68 R3V5.1, "make sv68r3v51" # ? for Motorola Delta System V/68 R3V6 with NSE TCP/IP, "make sv68r3v6" # ? for Motorola Delta System V/88 R32, "make sv88r32" # ? for Motorola Delta System V/88 R40, "make sv88r40" # ? for Mt Xinu Mach386 on 386/486-based PCs, "make bsd43" # ? for NCR Tower 1632, OS 1.02, "make tower1" # ? for NCR Tower 1632 or Minitower with System V R2, "make sys3" # or "make sys3nv" # ? for NCR Tower 32, OS Release 1.xx.xx, "make tower32-1" # ? for NCR Tower 32, OS Release 2.xx.xx, "make tower32-2" # ? for NCR Tower 32, OS Releases based on Sys V R3, "make tower32" # ? for NCR Tower 32, OS Releases based on Sys V R3 with gcc "make tower32g" # ? for NCR System 3000, AT&T UNIX System V R4 2.0, "make sys5r4sxna" # ? for NCR System 3000, AT&T UNIX System V R4 2.0 with Wollongong TCP/IP, # "make sys5r4net2" or "make sys5r4net2c". # Some header files might be misplaced; try this: # ln /usr/include/netinet/in.h /usr/include/sys/in.h # ln /usr/include/arpa/inet.h /usr/include/sys/inet.h # ln /usr/include/sys/termiox.h /usr/include/termiox.h # ? for NCR System 3000, NCR UNIX 02.02.01, same as above. # ? for NCR MP-RAS System V R4 V2.03 or 3.02, "make mpras" or "make mprastcpc" # + for NetBSD any version on any architecture, "make netbsd" # + for NetBSD with OpenSSL, "make netbsd+ssl" # ? for NetBSD with ncurses specified instead of curses, "make netbsdn" # ? for NetBSD with all curses support omitted, "make netbsdnc" # ? for NeXT with NeXTSTEP 1.0 through 3.2, "make next" (on a NeXT) # ? for NeXT with NeXTSTEP 3.3, "make next33" # ? for NeXT with OPENSTEP/Mach 4.1, "make nextquadfat". # ? for NeXT with OPENSTEP/Mach 4.2, "make openstep42". # ? for NeXTSTEP/486, "make next" (on a PC) # ? for NeXTSTEP portable binary (runs on Intel or Motorola), "make nextfat" # ? for NeXTSTEP portable binary (Intel, Motorola, HP PA-RISC, or SPARC), # "make nextquadfat" # ? for Nixdorf Targon/31, "make t31tos40x" # ? for Norsk Data Uniline 88/17 with SV/88 R3.2, "make sv88r32" # for Novell UnixWare - see UnixWare # ? for OSF/1 (vanilla, from OS/F), "make posix" # ? for OkiStation 7300 Series, "make sys5r4sxtcp" # ? for Olivetti LSX-3020 with X/OS R.2.3, "make xos23" or "make xos23c" # + for OpenBSD, "make openbsd" (also see secure targets listed below). # ? for OPENSTEP/Mach 4.1, "make nextquadfat" (NeXT, Intel, PA-RISC, SPARC) # ? for OPENSTEP/Mach 4.2, "make openstep42" (tested on NeXT) # ? for Perkin-Elmer (Concurrent) 3200 series, "make sys5". # ? for Perkin-Elmer (Concurrent) 3200 series with , "make ccop1" # ? for Perkin-Elmer/Concurrent 3200 with Xelos R02, "make ccop1" # ? for PFU Compact A Series SX/A TISP V10/E50 (Japan), "make sxae50" # ? for Plexus, "make sys3" # ? for Pyramid 9XXX (e.g. 9845) or MIServer T series, OSx 4.4b thru 5.1, # "ucb make pyramid" or for HDB UUCP, "ucb make pyramid-hdb" or: # ? for Pyramid MIServer S or ES Series, DataCenter/OSx, "make pyrdcosx" # ? for Pyramid MIS-S MIPS R3000, DataCenter OSx System V R4, "make pyrdcosx" # ? for POSIX on anything, "make posix" (but adjustments might be necessary). # NOTE: this target is not very useful - many features are missing. # ? for Prime 8000 MIPS, SVR3, "make mips" or "make mipstcpc" # - for QNX 2.x (sorry we don't have a version of C-Kermit for QNX 2.x) # ? for QNX 4.0 or 4.1, 16-bit, on 286 PC, Watcom C 8.5, "make qnx16_41" # ? for QNX 4.21 - 4.22A (286+), and 4.23 (386+), or higher, 16-bit, # Watcom C 9.5x or higher, "make qnx16" # + for QNX 4.21-4.25, 32-bit, 386 or above, Watcom C 10.6, "make qnx32" # NOTE: ("make qnx" == "make qnx32") # ? for QNX Neutrino 2+, "make qnx_nto2+" (crosscompiled on QNX4 with Watcom C) # ? for QNX 6 = Neutrino 2.xx, "make qnx6" # + for QNX 8.0 x86_64, "make qnx8i" # + for QNX 8.0 ARM64 , "make qnx8a" # ? for Ridge 32 (ROS3.2), "make ridge32" # ? for Samsung MagicStation, "make sys5r4" # ? for SCO Xenix 2.2.1 with development system 2.2 on 8086/8 "make sco86" # ? for SCO Xenix/286 2.2.1 with development system 2.2 on 80286, "make sco286" # NOTE: reportedly this makefile is too long for SCO Xenix/286 make, but it # works with "makeL", or if some of the other make entries are edited out. # ? for SCO Xenix/386 2.2.2, "make sco386" # ? for SCO Xenix/386 2.3.x, "make sco3r2" # ? for SCO Xenix/386 SCO 2.3.3 or 2.3.4 with gcc 1.37 or later, # "make sco386gcc" or (to add curses) "make sco386gccc". # ? for SCO Xenix/386 or UNIX/386 with Excelan TCP/IP, "make sco3r2net" # or (to add curses support) "make sco3r2netc" or "sco386netc" # + for SCO XENIX 2.3.4, "make sco234" or "make sco234c" to add curses. # ? for SCO XENIX 2.3.4 with SCO TCP/IP & curses, "make sco234netc". # ? for SCO Xenix 2.3.x with Racal-InterLan TCP/IP, "make sco3r2netri" # for other UNIX varieties with Racal Interlan TCP/IP, read sco3r2netri entry # ? for SCO Xenix 2.3.x with SCO (Lachman) TCP/IP, "make sco3r2lai" # or (to add curses) "make sco3r2laic" # for SCO UNIX... ALSO READ COMMENTS in the SCO UNIX entries for more info! # ? for SCO UNIX/386 3.2.0 or 3.2.1, "make sco3r2" or "make sco3r2x" # ? for SCO UNIX/386 3.2.2, "make sco3r22" or "make sco3r22gcc" # or "make sco3r22c" # ? for SCO UNIX/386 3.2.2 with SCO TCP/IP, "make sco3r22net" # or "make sco3r22netc" (curses) # ? for SCO ODT 1.1, "make sco3r22net" or "make sco3r22netc" (curses) # ? for SCO UNIX/386 3.2 V4.x, no network support, "make sco32v4" # ? or "make sco32v4ns" (this one uses no select() or sockets library) # ? for SCO UNIX/386 3.2 V4.x with TCP/IP, "make sco32v4net" # (also sco32v4gcc, sco32v4netgcc) # ? for SCO UNIX/386 3.2 V5.0 - see SCO OpenServer. # ? for SCO UNIX 3.2v4.x with TCP/IP, for Extended Acer File # System (EAFS), curses, ANSI C compilation, "make sco32v4net" # ? or (to use select()-based CONNECT module) "make sco32v4netx". # ? for SCO UNIX 3.2v4.2, "make sco-odt30" (includes TCP/IP). # ? for SCO MPX 3.0 - The SCO UNIX binary runs on the corresponding MPX system. # # NOTE: Also see below for other entries that are variations on these. # Also be sure to read the comments accompanying each SCO entry. # Also see Unixware section. # # ? for SCO ODT 2.0, "make sco32v4net" # ? for SCO ODT 3.0, "make sco-odt30" # ? for SCO OpenServer 5.0 (OSR5), "make sco32v500" # ? for SCO OpenServer 5.0 (OSR5) with networking, "make sco32v500net" # ? for SCO OpenServer 5.0 (OSR5), gcc, "make sco32v500gcc" # ? for SCO OpenServer 5.0 (OSR5), gcc, with networking, "make sco32v500netgcc" # ? for SCO OpenServer 5.0 (OSR5), as above, ELF, "make sco32v500netgccelf" # ? for SCO OpenServer 5.0.2, use "make sco32v502xxx" entries as above. # ? for SCO OpenServer 5.0.4, use "make sco32v504xxx" entries as above. # ? for SCO OpenServer 5.0.5, use "make sco32v505xxx" entries as above. # Use the sco32v505udkxxx entries if you have the UDK rather than /bin/cc. # ? for SCO OpenServer 5.0.6, use "make sco32v506xxx" entries as above. # ? for SCO OpenServer 5.0.6a,use "make sco32v506axxx" entries as above. # ? for SCO OpenServer 5.0.7, use "make sco32v507", "make sco32v507net" # ? for SCO (Univel) UnixWare 1.x, "make unixware" or "make unixwarenetc". # If there are problems with this in C-K 7+ see notes at unixware entry. # + for SCO OpenServer 6.0.0, "make sco_osr600" # ? for SCO UnixWare 2.0.x, "make uw20" # ? for SCO UnixWare 2.1.0, "make uw21" # ? for SCO UnixWare 2.1.3, "make uw213" # + for SCO UnixWare 7, "make uw7" (includes large file support) # ? for SCO UnixWare 7 with IKSD support, "make uw7iksd" or "make uw7iksdudk" # ? for SCO UnixWare 7 with OpenSSL, "make uw7ssl" # ? for SCO (Caldera) Open UNIX 8, "make ou8" # ? for Sharp Zaurus SL5500 PDA, "make zsl5500". # ? for Sequent with DYNIX/ptx 1.2.1, "make dynixptx12" # ? for Sequent with DYNIX/ptx 1.3 or 1.4 with TCP/IP, "make dynixptx13" # ? for Sequent with DYNIX/ptx 2.0 or 2.1 with TCP/IP, "make dynixptx20" # or "dynixptx20c" # ? for Sequent with DYNIX/ptx 2.1.6 on i486, "dynixptx216c" # ? for Sequent with DYNIX/ptx V4.1.3 with TCP/IP, "make dynixptx41c" # ? for Sequent with DYNIX/ptx V4.4.2 with TCP/IP, "make dynixptx44" # ? for Sequent Balance 8000 or B8 with DYNIX 3.0.xx, "make dynix3" # or "make dynix3noacu" # ? for Sequent Symmetry S81 with DYNIX 3.0.xx, "make dynix3" # ? for Sequent DYNIX 3.1.xx, "make dynix31" or "make dynix31c" # ? for Siemens/Nixdorf SINIX-L Intel V5.41, "make sinix541i" # + for Siemens/Nixdorf SINIX-N MIPS V5.42, "make sinix542" # ? for Siemens/Nixdorf SINIX-P MIPS V5.42 with gcc, "make sinix542g" # ? for Siemens/Nixdorf SINIX-Z Intel V5.42, "make sinix542i" # ? for Siemens/Nixdorf Reliant UNIX V5.43, "make sni543" # ? for Siemens/Nixdorf Reliant UNIX V5.44, "make sni544" # ? for Silicon Graphics Iris System V IRIX 3.2 or earlier, "make iris" # ? for Silicon Graphics Sys V R3 with IRIX 3.3 or later, "make sys5r3" # ? for Silicon Graphics Iris Indigo with IRIX 4.0 or 5.0, "make irix40" or # (to include Yellow Pages and Curses) "make irix40ypc" # ? for Silicon Graphics Iris Indigo or Elan with IRIX 4.0.x with microcode # optimization and -O4, "make irix40u" or "irix40uc" (and read notes # accompanying these entries). # ? for Silicon Graphics IRIX 5.1, "make irix51" or "irix51x" (no optimize) # ? for Silicon Graphics IRIX 5.2, "make irix52" # ? for Silicon Graphics IRIX 5.3, "make irix53" or "irix53x" (no optimize) # ? for Silicon Graphics IRIX 6.0, "make irix60". # ? for Silicon Graphics IRIX 6.2, "make irix62". # ? for Silicon Graphics IRIX 6.3, "make irix63". # ? for Silicon Graphics IRIX 6.4, "make irix64" or "make irix64gcc". # + for Silicon Graphics (SGI) IRIX 6.5, "make irix65" # + or "make irix65mips2" to force MIPS2, or "make irix65gcc" for GCC. # + for Silicon Graphics (SGI) IRIX 6.5, "make irix65" or "make irix65mips2" # ? for SGI IRIX 6.5 with SSL/TLS, SRP, and ZLIB "make irix65+ssl+srp+zlib" # ? for Solaris 2.0-2.3 on SPARC or Intel, SunPro CC, "make solaris2x", # ? or to add SunLink X.25 8.0x support, "make solaris2x25". # ? for Solaris 2.4 built with gcc, "make solaris24g". # ? for Solaris 2.0-2.3 on SPARC or Intel, GNU CC, "make solaris2xg". # ? for Solaris 2.4 with X.25, "make solaris24x25". # ? for Solaris 2.5 on SPARC or Intel, SunPro CC, "make solaris25". # ? or to add SunLink X.25 8.0x support, "make solaris25x25". # ? for Solaris 2.5 on SPARC or Intel, GNU CC, "make solaris25g". # ? for Solaris 2.6 on SPARC or Intel, "make solaris26". # ? for Solaris 7 on SPARC or Intel, SunPro CC, "make solaris7". # ? for Solaris 7 on SPARC or Intel, GNU CC, "make solaris7g". # ? for Solaris 8 on SPARC or Intel, SunPro CC, "make solaris8". # ? for Solaris 8 on SPARC or Intel, GNU CC, "make solaris8g". # + for Solaris 9 on SPARC (or Intel?), 32-bit, SunPro CC, "make solaris9". # + for Solaris 9 on SPARC (or Intel?), 32-bit, GNU CC, "make solaris9g". # ? for Solaris 9 on SPARC (or Intel?), 64-bit, GNU CC, "make solaris9g64". # + for Solaris 10 on SPARC (or Intel?), 32-bit, SunPro CC, "make solaris10". # + for Solaris 10 on SPARC 64-bit, SunPro CC, "make solaris10_64". # + for Solaris 10 on SPARC (or Intel?), 32-bit, GNU CC, "make solaris10g". # ? for Solaris 10 on SPARC (or Intel?), 64-bit, GNU CC, "make solaris10g64". # ? for Solbourne 4/500 with OS/MP 4 "make sunos4" # ? for Solbourne 4/500 with OS/MP 4.1 "make sunos41" or "make sunos41c" # ? for SONY NEWS with NEWS-OS 4.0.1C, "make sonynews" # ? for SONY NEWS with NEWS-OS 4.1.2C, "make sonynews" # ? for Sperry/UNISYS 5000/20, UTS V 5.2 3R1, "make sys5" # ? for Sperry/UNISYS 5000/30/35/50/55, UTS V 5.2 2.01, "make unisys5r2" # ? for Sperry/UNISYS 5000/80 with System V R3, "make sys5r3" # ? for Sperry/UNISYS 5000/95 with System V R3, "make sys5r3" # For UNISYS SVR3 it might be necessary to "make sys5r3 KFLAGS=-UDYNAMIC" # ? for Stardent 1520, "make sys5r3" # ? for Stratus FTX 2.x, try "make ftx" or else "make sys5r4" or "sys5r4sx" # ? for Stratus FTX 3.x, PA-RISC 1.0 or 2.0, "make ftx" or "make ftxtcp" # ? for Sun with Sun UNIX 3.5 and gcc, "make sunos3gcc" # ? for Sun with pre-4.0 SunOS versions, "make bsd" (or appropriate variant) # ? for Sun with SunOS 4.0, BSD environment, "make sunos4" # ? for Sun with SunOS 4.0, BSD, with SunLink X.25, make sunos4x25 # ? for Sun with SunOS 4.1 or 4.1.1, BSD environment, "make sunos41" # or "make sunos41c" (curses) or "make sunos41gcc" (compile with gcc) # ? for Sun with SunOS 4.1.x, BSD, with SunLink X.25 7.00 or earlier, # "make sunos41x25" or "make sunos41x25c" (curses) # ? for Sun with SunOS 4.1, 4.1.1, AT&T Sys V R3 environment, "make sunos41s5" # ? for Sun with SunOS 4.1.2, "make sunos41" or any of its variations. # NOTE: All SunOS 4.x systems -- Shared libraries are used by default. # If this causes problems, add -Bstatic to CFLAGS. # NOTE2: When building C-Kermit under SunOS for the BSD universe, # but /usr/5bin/cc is ahead of /usr/ucb/cc in your PATH, add # "CC=/usr/ucb/cc CC2=/usr/ucb/cc" to the make entry. # NOTE3: If an executable built on one type of Sun hardware does not work # on another type, rebuild the program from source on the target machine. # for Sun with Solaris 1.x use SunOS 4.1 entries. # for Sun with Solaris 2.0 and higher use Solaris entries. # + for Sun SPARC with Linux, "make linux" # ? for Sun SPARC with OPENSTEP/Mach 4.1, "make nextquadfat" # ? for Sun SPARC with OPENSTEP/Mach 4.2, "make openstep42" # - for Tandy 16/6000 with Xenix 3.0, "make trs16" (C-Kermit 7.0 is too big) # ? for Tektronix 6130/4132/43xx (e.g.4301) with UTek OS, "make utek" # or (for models without hardware flow control), "make uteknohwfc" # ? for Tektronix XD88 series with UTekV OS, "make utekvr3" # ? for Tri Star Flash Cache with Esix SVR3.2, "make sys5r3" # NOTE: The Tru64 builds have been failing since 2010, but "make dec-osf" is OK # ? for Tru64 UNIX 4.0E, "make tru64-40e" # ? for Tru64 UNIX 4.0F, "make tru64-40f" # ? for Tru64 UNIX 4.0G, "make tru64-40g" # ? for Tru64 UNIX 5.0A, "make tru64-50a" # ? for Tru64 UNIX 5.1A, "make tru64-51a" # ? for Tru64 UNIX 5.1B, "make tru64-51b" # ? for Unistar, "make sys5" # ? for Unisys S/4040 68040 CTIX SVR3.2 6.4.1, "make ctix" or "make sys5r3" # ? for Unisys U5000 UNIX SVR3 6.x, "make sys5r3" or "make sys5r3c" # ? for Unisys U6000 UNIX SVR4 1.x, "make sys5r4nx" or "make sys5r4nxnetc" # for Unisys ... (also see Sperry) # for Univel - see UnixWare # for Unixware - see SCO # ? for Valid Scaldstar, "make valid" # ? for Whitechapel MG01 Genix 1.3, "make white" # ? for Zilog ZEUS 3.21, "make zilog" # # The result should be a runnable program called "wermit" in the current # directory. After satisfactory testing, you can rename wermit to "kermit" # and put it in some directory that's in everybody's PATH, such as # /usr/local or /opt/local. # # To remove intermediate and object files, "make clean". # If your C compiler produces files with an extension other than "o", # then "make clean EXT=u", "make clean EXT=s", or whatever. # # To run lint on the source files, "make lintsun", "make lintbsd", # "make lints5", as appropriate. # # ****************************** # SECURE TARGETS # # Beginning with C-Kermit 7.0, secure targets are included, as are the # source modules (ckuat*.[ch], ck_*.[ch]) needed to build them. Secure # target names are like the regular names, but with security features # indicated by plus (+) signs. The features are: # # krb4 MIT Kerberos IV # krb5 MIT Kerberos V # openssl OpenSSL (SSL/TLS) # zlib ZLIB compression for SSL/TLS # srp Stanford Secure Remote Password # pam PAM (pluggable authentication module) # shadow Shadow Password File # # You can build these targets if you have the Kermit source files and the # required libraries (Kerberos, OpenSSL, SRP, etc) and header files. See: # http://www.columbia.edu/kermit/security.html # for specific details regarding supported versions. # # NOTE: OpenSSL 0.9.6 and earlier are not compatible with 0.9.7 and later. # C-Kermit code was originally designed for 0.9.6. To build with 0.9.7 you # must add -DOPENSSL_097 to avoid missing symbols in the DES library and to # use the entry points that were renamed to avoid conflict with Kerberos 4. # If you have OpenSSL 0.9.8, add -DOPENSSL_098, which is a synonym for # -DOPENSSL_097. If you have 1.0.0 or later, add -DOPENSSL_100, which is # another synonym. # In OpenSSL builds add -ldl if you get unresolved references for # dlopen, dlclose, dlsym, and/or dlerror. # # In order to build a secure version of Kermit, you need to know the location # of the header (include) files and libraries for the desired form of # security. Unless you specify a location, this makefile looks in /usr/local # and if the required files are not found, the build fails. # # If the secure headers and libraries are not on your computer, you have # to download and install them, for example from http://www.openssl.org . # # The following symbols are used to specify library and header file locations. # prefix statement changed in 10.0 Beta.06 to allow prefix to be specified # from the make command line e.g. $ env PREFIX=/usr/pkg make install. # October 2022. # prefix = $${PREFIX:-/usr/local} srproot = $(prefix) sslroot = $(prefix) manroot = $(prefix) # The default Kerberos settings seem to be based on AIX, Irix, and Solaris # but are not appropriate for (e.g.) Linux. K4LIB=-L/usr/kerberos/lib K4INC=-I/usr/kerberos/include K5LIB=-L/usr/kerberos/lib K5INC=-I/usr/kerberos/include SRPLIB=-L$(srproot)/lib SRPINC=-I$(srproot)/include SSLLIB=-L$(sslroot)/ssl/lib SSLINC=-I$(sslroot)/ssl/include # To override these assignments; for example, if your OpenSSL files are # not in /usr/local/ssl, invoke the desired target like this: # # make solaris9+openssl "SSLINC=-I/opt/openssl-0.9.8k/include" \ # "SSLLIB=-L/opt/openssl-0.9.8k/lib" # # (don't set the variables and then do "make -e" because that breaks # chaining of makefile targets.) # # Here are some up-to-date secure targets as of Sep 2009: # # aix+openssl: IBM AIX 4.2 or later with OpenSSL # freebsd44+srp+openssl FreeBSD 4.4 with SRP and OpenSSL # freebsd50+openssl FreeBSD 5.0 with OpenSSL # hpux1100o+openssl: HP-UX 11.xx with OpenSSL # hpux1000gcc+openssl: HP-UX 10.xx with OpenSSL (build with gcc) # hpux1100gcc+openssl: HP-UX 11.xx with OpenSSL (build with gcc) # irix6x+krb5: IRIX 6.x with Kerberos V # irix65+krb5: etc etc... # solaris9+openssl Solaris 9,10, or 11 with Openssl (Sun cc) # solaris9g+openssl Solaris 9,10, or 11 with Openssl (gcc) # linux+ssl OpenSSL only # linux+krb5+ssl Linux with Kerberos 5 and OpenSSL # linux+krb5: Kerberos 5 only # # The following secure Linux targets have not been updated or tested recently. # linux+krb5+krb4: # linux+srp: # linux+srp+pam: # linux+srp+gmp: # linux+srp+gmp+no-des: # linux+srp+gmp-export: # linux+srp+gmp+pam: # linux+shadow+pam: # linux+openssl: # linux+openssl+shadow: # linux+openssl+zlib+shadow+pam: # linux+srp+openssl: # linux+krb5+krb4+srp: # linux+krb5+krb4+srp+openssl: # linux+krb5+krb4+openssl: # linux+krb5+krb4+openssl+shadow: # linux+krb5+krb4+openssl+zlib+shadow: # linux+krb5+krb4+srp-export: # linux+krb5+krb4+srp+pam: # linux+krb5+krb4+srp+openssl+pam-debug: # linux+krb5+krb4+srp+openssl+pam: # linux+krb5+krb4+srp+openssl+zlib+pam: # linux+krb5+krb4+openssl+shadow+pam: # linux+krb5+openssl+zlib+shadow+pam: # # The following have not been tested recently either and might # need adjustment. # # macosx+krb5+ssl: Mac OS X 10.3.9 or later + OpenSSL and Kerberos 5 # macosx103+secure: This one is probably redundant # netbsd+openssl: NetBSD with OpenSSL # openbsd30+ssl: OpenBSD 3.0 with OpenSSL # redhat71,redhat72,redhat73,redhat80,redhat9 (Krb5,OpenSSL,Showdow,PAM,Zlib) # sco32v500net+ssl: # sco32v505net+ssl: # solaris2x+krb4: # solaris2xg+krb4: # solaris2xg+openssl+pam+shadow: # solaris2xg+openssl+zlib+pam+shadow: # solaris2xg+krb5+krb4+openssl+shadow: # solaris25+krb4: # solaris25g+krb4: # solaris26g+openssl: # solaris8g+openssl+zlib+pam+shadow: # solaris8g+krb4: # solaris9g+openssl+zlib+pam+shadow: # solaris9g+openssl+shadow+pam+zlib # sunos41gcc+krb4: SunOS 4.1 built with gcc with Kerberos IV # sunos41gcc+openssl: SunOS 4.1 built with gcc with OpenSSL # sunos41gcc+krb4+openssl: ...with Kerberos IV and OpenSSL # sunos41gcc+krb4+openssl+zlib: ditto, plus ZLIB compression # sunos41gcc+krb4+srp+openssl+zlib: ditto, plus SRP # sunos41gcc+srp+openssl+zlib: # tru64-51b-openssl: Tru64 (Digital) Unix 5.1B with OpenSSL # uw7ssl Unixware 7 with SSL # ########################################################################### # # Compile and Link variables: # # EXT is the extension (file type) for object files, normally o. # See MINIX entry for what to do if another filetype must be used. # EXT=o #LNKFLAGS= SHAREDLIB= CC= cc CC2= cc MAKE= make SHELL=/bin/sh ########################################################################### # (Ancient) UNIX V7-specific variables. # These are set up for Perkin-Elmer 3230 V7 Unix: # PROC=proc DIRECT= NPROC=nproc NPTYPE=int BOOTFILE=/edition7 # # ( For old Tandy TRS-80 Model 16A or 6000 V7-based Xenix, use PROC=_proc, # DIRECT=-DDIRECT, NPROC=_Nproc, NPTYPE=short, BOOTFILE=/xenix ) # ########################################################################### # SAMPLE INSTALLATION SCRIPT # # Modify to suit your own computer's file organization and permissions. If # you don't have write access to the destination directories, "make install" # fails. In most cases, a real installation also requires you to chown / # chgrp the Kermit binary for the UUCP lockfile and/or tty devices, and # perhaps also to chmod +s the corresponding permission fields. # # Default binary, man, and doc directories are supplied below. You can # override them in your 'make' command. Examples: # # make install # Accept defaults. # make "INFODIR=/usr/share/lib/kermit" install # Override INFODIR default. # # You can also build and install in one step, e.g.: # # make linux install # # If you use the 'install' target to install C-Kermit, it creates an # UNINSTALL script that can be used to uninstall it. # WERMIT = makewhat BINARY = wermit DESTDIR = BINDIR = $(prefix)/bin MANDIR = $(manroot)/man/man1 MANEXT = 1 SRCDIR = INFODIR = CERTDIR = TEXTFILES = COPYING.TXT ckcbwr.txt ckubwr.txt ckuins.txt ckccfg.txt \ ckcplm.txt ckermit.ini ckermod.ini ckermit70.txt ckermit80.txt # How many targets? count: @grep -c '^[^#[:space:]].*:' makefile # List all targets list: @grep '^[^#[:space:]].*:' makefile | sed 's/:.*$/:/' # @grep '^[^#[:space:]].*:' makefile ALL = $(WERMIT) all: $(ALL) .c.o: $(CC) $(CFLAGS) -DKTARGET=\"$(KTARGET)\" -c $< #Clean up intermediate and object files clean: @echo 'Removing object files...' -rm -f ckcmai.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckcpro.$(EXT) ckcfns.$(EXT) \ ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) ckucon.$(EXT) ckutio.$(EXT) \ ckufio.$(EXT) ckudia.$(EXT) ckuscr.$(EXT) ckwart.$(EXT) ckuusx.$(EXT) \ ckuusy.$(EXT) ckcnet.$(EXT) ckuus6.$(EXT) ckuus7.$(EXT) ckusig.$(EXT) \ ckucns.$(EXT) ckcmdb.$(EXT) ckuath.$(EXT) ckctel.$(EXT) ckclib.$(EXT) \ ckcuni.$(EXT) ck_crp.$(EXT) ck_ssl.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) \ ckcpro.c wart show: @echo prefix=$(prefix) @echo srproot=$(srproot) @echo sslroot=$(sslroot) @echo manroot=$(manroot) @echo K4LIB=$(K4LIB) @echo K4INC=$(K4INC) @echo K5LIB=$(K5LIB) @echo K5INC=$(K5INC) @echo SRPLIB=$(SRPLIB) @echo SRPINC=$(SRPINC) @echo SSLLIB=$(SSLLIB) @echo SSLINC=$(SSLINC) @exit # Install C-Kermit after building -- IMPORTANT: Read the instructions above # (SAMPLE INSTALLATION SCRIPT). For SSL/TLS versions, ca_certs.pem file # should be installed in the appropriate place for your OpenSSL library, e.g.: # # cp ca_certs.pem /usr/local/ssl/ # cp ca_certs.pem /usr/share/ssl/ # # To make sure 'man' notices the new source file and doesn't keep # showing the old formatted version, remove the old formatted version, # something like this: # rm -f $(MANDIR)/../cat$(MANEXT)/kermit.$(MANEXT) # or this (which requires CATDIR to be defined): # rm -f $(CATDIR)/kermit.$(MANEXT) # # As of C-Kermit 8.0.205 this target also builds an UNINSTALL script, and # so it might be too long for some old Bourne shells, in which case you can # use a different shell: # # make SHELL=ksh install # make SHELL=/bin/posix/sh install # # POSTSCRIPT November 2022... This target can not possibly cover all the # possible scenarios. For example, installation on a multiuser timesharing # system by a sysadmin with root privilege versus installation on a desktop # by a home user who doesn't even know what "root" is. Not to mention # differences among BSD, Linux, macOS, and the hundreds of historical Unix # versions that this makefile still aims to support. If there is to be an # install script at this point, it makes more sense for it to be a Kermit # script. I hope to find the the time to write one in time for the C-Kermit # 10.0 release. - fdc, Thu Nov 24 08:13:18 2022 # install: @echo Installing C-Kermit version $(CKVER)...;\ rm -f UNINSTALL;\ exec 3>./UNINSTALL;\ echo "# C-Kermit UNINSTALL script" >&3;\ echo "# `date`\n" >&3;\ echo "CKVER=$(CKVER)" >&3;\ echo "PrN Uninstalling C-Kermit version $(CKVER)..." >&3;\ echo DESTDIR=$(DESTDIR);\ if test -n "$(DESTDIR)"; then\ if test -d $(DESTDIR); then\ echo "$(DESTDIR) exists...\n";\ else\ echo "Creating $(DESTDIR)...";\ DESTDIR=`echo $(DESTDIR) | sed 's!/*$$!!'`;\ mkdir $$DESTDIR || exit 1;\ fi;\ chmod 755 $(DESTDIR) || exit 1;\ fi;\ echo BINARY=$(BINARY);\ if test -f $(BINARY); then\ ls -l $(BINARY);\ else\ echo "?$(BINARY) not found";\ exit 1;\ fi;\ if test -z "$(DESTDIR)$(BINDIR)"; then\ echo "Binary directory not specified";\ exit 1;\ fi;\ if test -d $(DESTDIR)$(BINDIR); then\ echo "$(DESTDIR)$(BINDIR) exists...";\ else\ echo "Creating $(DESTDIR)$(BINDIR)/...";\ mkdir $(DESTDIR)$(BINDIR) || exit 1;\ chmod 755 $(DESTDIR)$(BINDIR);\ fi;\ rm -f $(DESTDIR)$(BINDIR)/kermit;\ cp $(BINARY) $(DESTDIR)$(BINDIR)/kermit || exit 1;\ chmod 755 $(DESTDIR)$(BINDIR)/kermit || exit 1;\ rm -f $(DESTDIR)$(BINDIR)/kermit-sshsub;\ ln -s $(DESTDIR)$(BINDIR)/kermit\ $(DESTDIR)$(BINDIR)/kermit-sshsub || exit 1;\ echo 'set flag=f\nPrC Removing binaries' >&3;\ echo "RmF $(DESTDIR)$(BINDIR)/kermit-sshsub" >&3;\ echo "RmF $(DESTDIR)$(BINDIR)/kermit" >&3;\ if test -f ckermit.ini; then\ echo "#!$(BINDIR)/kermit" >\ $(DESTDIR)$(BINDIR)/_tmp.ini;\ cat ckermit.ini >> $(DESTDIR)$(BINDIR)/_tmp.ini;\ mv $(DESTDIR)$(BINDIR)/_tmp.ini\ $(DESTDIR)$(BINDIR)/ckermit.ini;\ chmod 755 $(DESTDIR)$(BINDIR)/ckermit.ini;\ echo "RmF $(DESTDIR)$(BINDIR)/ckermit.ini" >&3;\ fi;\ echo;\ echo 'EfM' >&3;\ echo "Kermit binary installed:";\ ls -l $(DESTDIR)$(BINDIR)/kermit\ $(DESTDIR)$(BINDIR)/kermit-sshsub\ $(DESTDIR)$(BINDIR)/ckermit.ini;\ echo;\ echo " WARNING: If C-Kermit is to be used for dialing out,";\ echo " you must change its owner and group and permissions";\ echo " to match the 'cu' program. See the ckuins.txt file";\ echo " for details.";\ echo;\ echo MANDIR=$(MANDIR);\ if test -n "$(DESTDIR)$(MANDIR)"; then\ if test -d $(DESTDIR)$(MANDIR); then\ echo "$(DESTDIR)$(MANDIR) exists...";\ else\ echo "Creating $(MANDIR)...";\ mkdir $(MANDIR) || exit 1;\ chmod 755 $(MANDIR) || exit 1;\ fi;\ rm -f $(DESTDIR)$(MANDIR)/kermit.$(MANEXT);\ cp ckuker.nr $(DESTDIR)$(MANDIR)/kermit.$(MANEXT) || exit 1;\ chmod 644 $(DESTDIR)$(MANDIR)/kermit.$(MANEXT) || exit 1;\ echo 'set flag=f\nPrC Removing man pages' >&3;\ echo "RmF $(DESTDIR)$(MANDIR)/kermit.$(MANEXT)" >&3;\ echo 'EfM' >&3;\ echo;\ else\ echo "Not installing man page!\n";\ fi;\ echo CERTDIR=$(CERTDIR);\ if test -n "$(CERTDIR)"; then\ if test -f ca_certs.pem; then\ if test -d $(CERTDIR); then\ echo "$(CERTDIR) exists...";\ else\ echo "Creating $(CERTDIR)...";\ mkdir $(CERTDIR) || exit 1;\ chmod 755 $(CERTDIR) || exit 1;\ fi;\ echo "Installing certificates file...";\ cp ca_certs.pem $(CERTDIR) || exit 1;\ echo 'set flag=f' >&3;\ echo 'PrC Removing certificates file' >&3;\ echo "RmF $(CERTDIR)/ca_certs.pem" >&3;\ echo 'EfM' >&3;\ echo;\ fi;\ else\ echo "Not installing certificates file!\n";\ fi;\ echo SRCDIR=$(DESTDIR)$(SRCDIR);\ if test -n "$(SRCDIR)"; then\ echo "Installing source files...";\ if test -d $(DESTDIR)$(SRCDIR); then\ echo "$(DESTDIR)$(SRCDIR) exists...";\ else\ echo "Creating $(DESTDIR)$(SRCDIR)/...";\ mkdir $(DESTDIR)$(SRCDIR) || exit 1;\ chmod 755 $(DESTDIR)$(SRCDIR);\ fi;\ echo "Copying source files to $(DESTDIR)$(SRCDIR)...";\ echo 'set flag=f\nPrC Removing source files' >&3;\ for TextFile in COPYING.TXT ck[cuw_]*.[cwh] makefile; do\ cp $$TextFile $(DESTDIR)$(SRCDIR)/ && echo ".\c";\ echo "RmF $(DESTDIR)$(SRCDIR)/$$TextFile" >&3;\ done; echo;\ echo 'EfM' >&3;\ ( cd $(DESTDIR)$(SRCDIR)/ &&\ ls -l COPYING.TXT ck[cuw_]*.[cwh] makefile );echo;\ else\ echo "Not installing source code!\n";\ fi;\ echo INFODIR=$(DESTDIR)$(INFODIR);\ if test -n "$(INFODIR)"; then\ echo "Installing info files...";\ if test -d $(DESTDIR)$(INFODIR); then\ echo "$(DESTDIR)$(INFODIR) exists...";\ else\ echo "Creating $(DESTDIR)$(INFODIR)/...";\ mkdir $(DESTDIR)$(INFODIR) || exit 1;\ chmod 755 $(DESTDIR)$(INFODIR);\ fi;\ echo "Copying text files to $(DESTDIR)$(INFODIR)...";\ echo 'set flag=f\nPrC Removing text files' >&3;\ FileCopyList='';\ for TextFile in $(TEXTFILES); do\ test -f $$TextFile || continue;\ cp $$TextFile $(DESTDIR)$(INFODIR) && echo ".\c" &&\ FileCopyList="$$FileCopyList $$TextFile";\ echo "RmF $(DESTDIR)$(INFODIR)/$$TextFile" >&3;\ done; echo;\ echo 'EfM' >&3;\ ( cd $(DESTDIR)$(INFODIR)/ && chmod 644 $$FileCopyList );\ ( cd $(DESTDIR)$(INFODIR)/ && pwd && ls -l $$FileCopyList );\ else\ echo "Not installing text files!\n";\ fi;\ echo "set flag=d\nPrN Removing empty dirs..." >&3;\ echo "RmD $(DESTDIR)$(BINDIR)" >&3;\ echo "RmD $(DESTDIR)$(SRCDIR)" >&3;\ echo "RmD $(DESTDIR)$(INFODIR)" >&3;\ echo "RmD $(CERTDIR)" >&3;\ echo "RmD $(MANDIR)" >&3;\ echo "RmD $(DESTDIR)" >&3;\ echo "EfM" >&3;\ echo "PrN C-Kermit version $(CKVER) is uninstalled!" >&3;\ echo C-Kermit version $(CKVER) installed! # UN-Install C-Kermit after building # Please to not remove the extra blanks before and after '{}' within the # functions. You would get syntax errors for some older Bourne shells! Best is # you don't change or remove anything. # uninstall: @if test ! -f UNINSTALL; then\ echo "?C-Kermit UNINSTALL data file not found!";\ exit 1;\ fi; \ X=`grep '^CKVER='$(CKVER)'$$' ./UNINSTALL || :`;\ if test -z "$$X"; then\ echo "?UNINSTALL file is not for C-Kermit version $(CKVER)";\ exit 2;\ fi;\ PrN () { echo "$$*"; };\ PrC () { echo "$$* \c"; };\ RmF () { test -f "$$1" && rm -f "$$1" && echo ".\c" && flag=F ; };\ RmD () { \ dir=$$1;\ while test -d "$$dir"; do\ rmdir "$$dir" 2>&- || return && echo "$$dir" && flag=D;\ dir=`echo "$$dir" | sed 's!/[^/]*/*$$!!'`;\ done; \ };\ EfM () { \ case "$$flag" in\ f) echo "- Nothing to remove!";;\ d) echo "Nothing to remove!";;\ F) echo " done";;\ D) echo "done";;\ esac; \ };\ while read Act Args; do\ case $$Act in\ EfM) EfM;;\ RmD) RmD $$Args;;\ RmF) RmF $$Args;;\ PrN) PrN $$Args;;\ PrC) PrC $$Args;;\ set) eval $$Args;;\ esac;\ done < ./UNINSTALL makewhat: @echo 'make what? You must tell which platform to make C-Kermit for.' @echo Examples: make linux, make aix, make solaris10, make hpux1100. @echo Please read the comments at the beginning of the makefile. ########################################################################### # # Dependencies Section: wermit: ckcmai.$(EXT) ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \ ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) ckcpro.$(EXT) \ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \ ckucon.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \ ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) \ $(CC2) $(LNKFLAGS) -o wermit \ ckcmai.$(EXT) ckclib.$(EXT) ckutio.$(EXT) ckufio.$(EXT) \ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \ ckcpro.$(EXT) ckucmd.$(EXT) ckuus2.$(EXT) ckuus3.$(EXT) \ ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) ckuus7.$(EXT) \ ckuusx.$(EXT) ckuusy.$(EXT) ckuusr.$(EXT) ckucon.$(EXT) \ ckudia.$(EXT) ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) \ ckusig.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) \ $(LIBS) # Preferred configuration with select()-based CONNECT xermit: ckcmai.$(EXT) ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \ ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) ckcpro.$(EXT) \ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \ ckucns.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \ ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) ckuath.$(EXT) \ ck_crp.$(EXT) ck_ssl.$(EXT) $(CC2) $(LNKFLAGS) -o wermit \ ckcmai.$(EXT) ckclib.$(EXT) ckutio.$(EXT) ckufio.$(EXT) \ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \ ckcpro.$(EXT) ckucmd.$(EXT) ckuus2.$(EXT) ckuus3.$(EXT) \ ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) ckuus7.$(EXT) \ ckuusx.$(EXT) ckuusy.$(EXT) ckuusr.$(EXT) ckucns.$(EXT) \ ckudia.$(EXT) ckuscr.$(EXT) ckcnet.$(EXT) ckusig.$(EXT) \ ckctel.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) \ ckuath.$(EXT) ck_crp.$(EXT) ck_ssl.$(EXT) $(LIBS) # Malloc Debugging version mermit: ckcmdb.$(EXT) ckcmai.$(EXT) ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) \ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \ ckcpro.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) \ ckuxla.$(EXT) ckucon.$(EXT) ckutio.$(EXT) ckufio.$(EXT) \ ckudia.$(EXT) ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) \ ckusig.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) $(CC2) $(LNKFLAGS) -o mermit ckcmdb.$(EXT) ckclib.$(EXT) ckcmai.$(EXT)\ ckutio.$(EXT) ckufio.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) \ ckcfn3.$(EXT) ckuxla.$(EXT) ckcpro.$(EXT) ckucmd.$(EXT) \ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \ ckuusr.$(EXT) ckucon.$(EXT) ckudia.$(EXT) ckuscr.$(EXT) \ ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) ckcuni.$(EXT) \ ckupty.$(EXT) ckcftp.$(EXT) $(LIBS) # Kerberized Version - Subject to USA export restrictions. # NOTE: We don't use this any more -- As of 15 Feb 2003, the "xermit" # target is used for both secure and regular version. krbmit: ckcmai.$(EXT) ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \ ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) ckcpro.$(EXT) \ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \ ckucns.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \ ckuath.$(EXT) ck_crp.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) \ ckcftp.$(EXT) ck_ssl.$(EXT) $(CC2) $(LNKFLAGS) -o krbmit ckcmai.$(EXT) ckclib.$(EXT) \ ckutio.$(EXT) ckufio.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) \ ckcfn3.$(EXT) ckuxla.$(EXT) ckcpro.$(EXT) ckucmd.$(EXT) \ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \ ckuusr.$(EXT) ckucns.$(EXT) ckudia.$(EXT) ckuscr.$(EXT) \ ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) ckuath.$(EXT) \ ck_crp.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) \ ck_ssl.$(EXT) $(LIBS) krbmit-debug: ckcmai.$(EXT) ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) \ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \ ckcpro.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) \ ckuxla.$(EXT) ckucns.$(EXT) ckutio.$(EXT) ckufio.$(EXT) \ ckudia.$(EXT) ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) \ ckusig.$(EXT) ckuath.$(EXT) ck_crp.$(EXT) ckcuni.$(EXT) \ ckupty.$(EXT) ck_ssl.$(EXT) ckcmdb.$(EXT) ckcftp.$(EXT) $(CC2) $(LNKFLAGS) -o krbmit ckcmdb.$(EXT) ckcmai.$(EXT) \ ckclib.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckcfns.$(EXT) \ ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) ckcpro.$(EXT) \ ckucmd.$(EXT) ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) \ ckuus5.$(EXT) ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) \ ckuusy.$(EXT) ckuusr.$(EXT) ckucns.$(EXT) ckudia.$(EXT) \ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \ ckuath.$(EXT) ck_crp.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) \ ckcftp.$(EXT) ck_ssl.$(EXT) $(LIBS) # SRP(TM) Version - Subject to USA export restrictions. srpmit: ckcmai.$(EXT) ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \ ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) ckcpro.$(EXT) \ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \ ckucns.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \ ckuath.$(EXT) ck_crp.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) \ ckcftp.$(EXT) ck_ssl.$(EXT) $(CC2) $(LNKFLAGS) -o srpmit ckcmai.$(EXT) ckclib.$(EXT) \ ckutio.$(EXT) ckufio.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) \ ckcfn3.$(EXT) ckuxla.$(EXT) ckcpro.$(EXT) ckucmd.$(EXT) \ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \ ckuusr.$(EXT) ckucns.$(EXT) ckudia.$(EXT) ckuscr.$(EXT) \ ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) ckuath.$(EXT) \ ck_crp.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ck_ssl.$(EXT) \ ckcftp.$(EXT) $(LIBS) # Kerberized Version - Not subject to USA export restrictions. krbmit-export: ckcmai.$(EXT) \ ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \ ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) ckcpro.$(EXT) \ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \ ckucns.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \ ckuath.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) $(CC2) $(LNKFLAGS) -o krbmit-export ckcmai.$(EXT) ckclib.$(EXT) \ ckutio.$(EXT) ckufio.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) \ ckcfn3.$(EXT) ckuxla.$(EXT) ckcpro.$(EXT) ckucmd.$(EXT) \ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \ ckuusr.$(EXT) ckucns.$(EXT) ckudia.$(EXT) ckuscr.$(EXT) \ ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) ckuath.$(EXT) \ ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) $(LIBS) # SRP(TM) Version - Not subject to USA export restrictions. srpmit-export: ckcmai.$(EXT) \ ckclib.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \ ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) ckcpro.$(EXT) \ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \ ckucns.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \ ckuscr.$(EXT) ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) \ ckuath.$(EXT) ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) $(CC2) $(LNKFLAGS) -o srpmit-export ckcmai.$(EXT) ckclib.$(EXT) \ ckutio.$(EXT) ckufio.$(EXT) ckcfns.$(EXT) ckcfn2.$(EXT) \ ckcfn3.$(EXT) ckuxla.$(EXT) ckcpro.$(EXT) ckucmd.$(EXT) \ ckuus2.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \ ckuus6.$(EXT) ckuus7.$(EXT) ckuusx.$(EXT) ckuusy.$(EXT) \ ckuusr.$(EXT) ckucns.$(EXT) ckudia.$(EXT) ckuscr.$(EXT) \ ckcnet.$(EXT) ckctel.$(EXT) ckusig.$(EXT) ckuath.$(EXT) \ ckcuni.$(EXT) ckupty.$(EXT) ckcftp.$(EXT) $(LIBS) ########################################################################### # man page... # ckuker.nr: @echo This target is obsolete. @echo The ckuker.nr file no longer needs any preprocessing. ########################################################################### # Dependencies for each module... # ckcmai.$(EXT): ckcmai.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcnet.h ckcsig.h \ ckuusr.h ckctel.h ckclib.h ckcfnp.h ckclib.$(EXT): ckclib.c ckclib.h ckcdeb.h ckcasc.h ckcsym.h ckcfnp.h wart: ckwart.$(EXT) $(CC) $(LNKFLAGS) -o wart ckwart.$(EXT) $(LIBS) ckcpro.c: ckcpro.w wart ckcdeb.h ckcsym.h ckcasc.h ckcker.h ckcnet.h ckctel.h \ ckclib.h ./wart ckcpro.w ckcpro.c ckcfns.$(EXT): ckcfns.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcxla.h ckcuni.h \ ckuxla.h ckclib.h ckcnet.h ckcfnp.h ckcfn2.$(EXT): ckcfn2.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcxla.h \ ckuxla.h ckctel.h ckclib.h ckcnet.h ckcuni.h ckcfnp.h ckcfn3.$(EXT): ckcfn3.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcxla.h \ ckuxla.h ckclib.h ckcuni.h ckcfnp.h ckuxla.$(EXT): ckuxla.c ckcker.h ckcsym.h ckcdeb.h ckcxla.h ckuxla.h ckclib.h \ ckcuni.h ckcfnp.h ckcuni.$(EXT): ckcuni.c ckcdeb.h ckcker.h ckucmd.h ckcuni.h ckcxla.h ckuxla.h \ ckcfnp.h ckuusr.$(EXT): ckuusr.c ckucmd.h ckcker.h ckuusr.h ckcsym.h ckcdeb.h ckcxla.h \ ckuxla.h ckcasc.h ckcnet.h ckctel.h ckclib.h ckcuni.h ckcfnp.h ckuus2.$(EXT): ckuus2.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcxla.h ckuxla.h \ ckcasc.h ckcnet.h ckcsym.h ckctel.h ckclib.h ckcuni.h ckcfnp.h ckuus3.$(EXT): ckuus3.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcxla.h ckuxla.h \ ckcasc.h ckcnet.h ckcsym.h ckctel.h ckclib.h ckcuni.h ckcfnp.h ckuus4.$(EXT): ckuus4.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcxla.h ckuxla.h \ ckcasc.h ckcnet.h ckuver.h ckcsym.h ckctel.h ckclib.h \ ckcuni.h ckcfnp.h ckuus5.$(EXT): ckuus5.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcasc.h ckcnet.h \ ckcsym.h ckctel.h ckclib.h ckcxla.h ckuxla.h ckcuni.h ckcfnp.h ckuus6.$(EXT): ckuus6.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcasc.h ckcnet.h \ ckcsym.h ckctel.h ckclib.h ckcfnp.h ckuus7.$(EXT): ckuus7.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcxla.h ckuxla.h \ ckcasc.h ckcnet.h ckcsym.h ckctel.h ckclib.h ckcuni.h ckcfnp.h ckuusx.$(EXT): ckuusx.c ckcker.h ckuusr.h ckcdeb.h ckcasc.h ckcsym.h \ ckcsig.h ckcnet.h ckctel.h ckclib.h ckcxla.h ckuxla.h \ ckcuni.h ckcfnp.h ckuusy.$(EXT): ckuusy.c ckcker.h ckcdeb.h ckcasc.h ckcnet.h ckcsym.h ckctel.h \ ckclib.h ckcfnp.h ckucmd.$(EXT): ckucmd.c ckcasc.h ckucmd.h ckcdeb.h ckcsym.h ckctel.h ckclib.h \ ckcfnp.h ckufio.$(EXT): ckufio.c ckcdeb.h ckuver.h ckcsym.h ckclib.h \ ckcxla.h ckuxla.h ckcuni.h ckcfnp.h ckutio.$(EXT): ckutio.c ckcdeb.h ckcnet.h ckuver.h ckcsym.h ckctel.h ckclib.h \ ckcfnp.h ckucon.$(EXT): ckucon.c ckcker.h ckcdeb.h ckcasc.h ckcnet.h ckcsym.h ckctel.h \ ckclib.h ckcfnp.h ckucns.$(EXT): ckucns.c ckcker.h ckcdeb.h ckcasc.h ckcnet.h ckcsym.h ckctel.h \ ckclib.h ckcxla.h ckuxla.h ckcuni.h ckcfnp.h ckcnet.$(EXT): ckcnet.c ckcdeb.h ckcker.h ckcnet.h ckcsym.h ckcsig.h ckctel.h \ ckclib.h ckcfnp.h ckuusr.h ckctel.$(EXT): ckcsym.h ckcdeb.h ckcker.h ckcnet.h ckctel.h ckclib.h ckcfnp.h ckcmdb.$(EXT): ckcmdb.c ckcdeb.h ckcsym.h ckclib.h ckcfnp.h ckudia.$(EXT): ckudia.c ckcker.h ckcdeb.h ckucmd.h ckcasc.h ckcsym.h ckcsig.h \ ckcnet.h ckctel.h ckclib.h ckcfnp.h ckuscr.$(EXT): ckuscr.c ckcker.h ckcdeb.h ckcasc.h ckcsym.h ckcsig.h \ ckcnet.h ckctel.h ckclib.h ckcfnp.h ckusig.$(EXT): ckusig.c ckcasc.h ckcdeb.h ckcker.h ckcnet.h ckuusr.h \ ckcsig.h ckctel.h ckclib.h ckcfnp.h ckcftp.$(EXT): ckcftp.c ckcdeb.h ckcasc.h ckcker.h ckucmd.h ckuusr.h \ ckcnet.h ckctel.h ckcxla.h ckuxla.h ckcuni.h ckcfnp.h ckupty.$(EXT): ckupty.c ckupty.h ckcdeb.h ckcfnp.h ckuath.$(EXT): ckuath.c ckcdeb.h ckucmd.h ckuath.h ckuat2.h ckctel.h \ ckclib.h ckcnet.h ckcfnp.h ck_crp.$(EXT): ck_crp.c ckcdeb.h ckcnet.h ckuath.h ckclib.h ckcfnp.h ck_ssl.$(EXT): ck_ssl.c ckcdeb.h ckucmd.h ckuath.h ckuat2.h ckctel.h \ ckclib.h ck_ssl.h ckcfnp.h ########################################################################### # # Entries to make C-Kermit for specific systems. # # Put the ones that need short makefiles first. #Apollo Aegis 9.x. Includes TCP/IP support. #You can also add processor-dependent optimization switches like -M570. aegis: @echo Making C-Kermit $(CKVER) for Apollo Aegis 9.x... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD4 -DTCPSOCKET -DNOCSETS -DCK_CURSES -O $(KFLAGS)" \ "LIBS = -lcurses -ltermcap" #Apple Mac II, A/UX pre-3.0 #Warning, if "send *" doesn't work, try the auxufs makefile entry below. aux: @echo Making C-Kermit $(CKVER) for Macintosh A/UX... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DAUX -DTCPSOCKET $(KFLAGS) -i -O" "LNKFLAGS = -i" #Apple Mac II, A/UX pre-3.0, compiled with gcc auxgcc: @echo Making C-Kermit $(CKVER) for Macintosh A/UX... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DAUX -DTCPSOCKET -traditional $(KFLAGS) -i -O" \ "LNKFLAGS = " "CC = gcc" "CC2 = gcc" #Apple Mac II, A/UX, pre-3.0, but with ufs file volumes, uses . auxufs: @echo Making C-Kermit $(CKVER) for Macintosh A/UX... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DAUX -DTCPSOCKET -DDIRENT $(KFLAGS) -i -O" "LNKFLAGS = -i" #Apple Mac II, A/UX 3.0, compiled with gcc aux3gcc: @echo Making C-Kermit $(CKVER) for Macintosh A/UX 3.0... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DAUX -DHDBUUCP -DLFDEVNO -DTCPSOCKET -DDIRENT $(KFLAGS)" \ "LNKFLAGS = -s" "LIBS = $(LIBS)" \ "CC=gcc -pipe -traditional" "CC2=gcc -pipe -traditional" #Apple Mac II, A/UX 3.0, compiled with gcc, uses curses aux3cgcc: @echo Making C-Kermit $(CKVER) for Macintosh A/UX 3.0... $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) aux3gcc \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(KFLAGS) -DCK_CURSES" "LIBS = -lcurses $(LIBS)" # Tenon MachTen, tested on Apple Powerbook with MachTen 2.1.1.D. # NOTE: This doesn't do anything about UUCP. It only works if /usr/spool/uucp # has permission of 777, and dialout device is world read/writeable. machten: @echo Making C-Kermit $(CKVER) for MachTen... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD43 -DTCPSOCKET -DSIG_V -DNDGPWNAM -DCK_CURSES -O \ $(KFLAGS)" "LIBS=-lcurses -ltermcap" #Bell Labs Research UNIX V10 #Can't add TCP/IP because there is no sockets library. It would have to #be done using streams, but there is no code in C-Kermit for that. #Remove -DNOJC if desired (if your system has csh, ksh, or bash). bellv10: @echo Making C-Kermit $(CKVER) for Bell Labs Research UNIX V10... $(MAKE) wermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBELLV10 -DBSD4 -DNDIR -DNOJC -DNOSYSIOCTLH -DNOSETREU \ -DNOCSETS -MINIDIAL $(KFLAGS)" # WARNING: The early BSD entries do not build in version 7.0 with the stock # BSD compiler: "Too many defines". Unless you can rebuild cpp to have more # space for defines, these builds must be accomplished by: # copying the /usr/include tree to someplace else, preprocessing there with cc # -E -I./include or whatever (plus all the same -D's, adding any necessary # -U/-D to override the architecture)), renaming the the resulting files back # to their original names, bringing them back to the original BSD system, and # running the make target there. This technique was used for 4.2 and 4.3 BSD # on a VAX in C-Kermit 7.0 (later, cpp on that machine was rebuilt to allow # more symbols, so the C-Kermit 8.0 build proceeds normally). #Berkeley Unix 4.1 bsd41: @echo Making C-Kermit $(CKVER) for 4.1BSD... $(MAKE) wermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD41" "LIBS = -ljobs" #Berkeley 4.2, 4.3, also Ultrix-32 1.x, 2.x, 3.x, many others # Add -O, -s, etc, if they work. # If you have a version of BSD but signal() is void rather than int, # "make bsd KFLAGS=-DSIG_V". bsd42: @echo Making C-Kermit $(CKVER) for 4.2BSD... $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD4 -DTCPSOCKET -DNOREALPATH -DNOTIMEH -DNOIKSD \ -DCK_CURSES -DSYSTIMEBH -DNOPUTENV -DNOANSI -DBIGBUFOK -DBSD42HACK \ $(KFLAGS)" "LIBS=-lcurses -ltermcap $(LIBS)" bsd: $(MAKE) CC=$(CC) CC2=$(CC2) bsd42 KTARGET=$${KTARGET-$(@)} #Berkeley Unix 4.2 or 4.3 with HoneyDanBer UUCP bsdhdb: @echo Making C-Kermit $(CKVER) for 4.2BSD with HDB UUCP... $(MAKE) CC=$(CC) CC2=$(CC2) bsd KTARGET=$${KTARGET-$(@)} \ "KFLAGS= -DHDBUUCP $(KFLAGS)" #Berkeley Unix 4.3 with acucntrl program, curses, TCP/IP included. bsd43: @echo Making C-Kermit $(CKVER) for 4.3BSD... $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD4 -DBSD43 -DTCPSOCKET -DNOREALPATH -DNOTIMEH -DNOIKSD \ -DCK_CURSES -DACUCNTRL -DSYSTIMEBH -DNOPUTENV -DNOANSI -DBIGBUFOK \ -DBSD42HACK $(KFLAGS)" "LIBS=-lcurses -ltermcap $(LIBS)" #4.3BSD, curses excluded bsd43nc: @echo Making C-Kermit $(CKVER) for 4.3BSD... $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD4 -DBSD43 -DTCPSOCKET -DNOREALPATH -DNOTIMEH \ -DACUCNTRL -DSYSTIMEBH -DNOIKSD -DNOPUTENV -DNOANSI -DBIGBUFOK \ -DBSD42HACK $(KFLAGS)" "LIBS=$(LIBS)" #4.3BSD, TCP/IP excluded. bsd43nonet: @echo Making C-Kermit $(CKVER) for 4.3BSD + curses... $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD4 -DBSD43 -DTCPSOCKET -DNOREALPATH -DNOTIMEH -DNOIKSD \ -DCK_CURSES -DACUCNTRL -DSYSTIMEBH -DNOPUTENV -DNOANSI -DBIGBUFOK \ -DBSD42HACK -DNONET $(KFLAGS)" "LIBS=-lcurses -ltermcap $(LIBS)" #Berkeley Unix 4.2 or 4.3 with lock directory /usr/spool/uucp/LCK/LCK..ttyxx, #but without acucntrl program bsdlck: @echo Making C-Kermit $(CKVER) for 4.2BSD, /usr/spool/uucp/LCK/... $(MAKE) CC=$(CC) CC2=$(CC2) bsd KTARGET=$${KTARGET-$(@)} \ "KFLAGS= -DLCKDIR $(KFLAGS)" #Berkeley UNIX 4.4-Lite, 4.4-Encumbered, Net/2, etc (Post-Reno), #with TCP/IP networking. This was the basis for FreeBSD, NetBSD, OpenBSD, #BSDI, BSD/OS, and Mac OS X (each of which has its own set of targets that #are newer than this one). # #NOTE: This is not a pure POSIX configuration. Using -DPOSIX instead of # -DBSD44 prevents any kind of directory-reading (for wildcard expansion), #and disallows use of ENOTCONN symbol for detecting broken network #connections, and disallows RTS/CTS flow control, and would also require #definition of the appropriate UUCP lockfile convention. #Do not add -DCK_POSIX_SIG without reading first! For example, #sigsetjmp(), etc, tend to be defined but not implemented. # #NOTE: originally crypt was in libc - later it was unbundled. #Remove the LIBS clause to build on an early 4.4BSD platform. # bsd44: @echo Making C-Kermit $(CKVER) for 4.4BSD... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DTCPSOCKET $(KFLAGS) -O" "LIBS=-lcrypt" #Berkeley UNIX 4.4, as above, but with curses for fullscreen display #Please read notes for bsd44 entry just above. # NOTE: This one dumped core on the real 4.4BSD development system at # UC Berkeley (an HP-9000/300), so the no-curses version was used # for that one, which was unplugged years ago. bsd44c: @echo Making C-Kermit $(CKVER) for 4.4BSD with curses... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_CURSES -DTCPSOCKET $(KFLAGS) -O" \ "LIBS= -lcurses -ltermcap -lcrypt $(LIBS)" #For FreeBSD 1.x. freebsd1: @echo 'Making C-Kermit $(CKVER) for FreeBSD...' $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_CURSES -DTCPSOCKET -DNOCOTFMC -funsigned-char \ -DFNFLOAT -DNOHTERMCAP -DNOREALPATH -DNOSYSCONF $(KFLAGS) -O -pipe" \ "LIBS= -lcurses -ltermcap -lm $(LIBS)" #FreeBSD 2.x with ncurses freebsd2: @echo 'Making C-Kermit $(CKVER) for FreeBSD 2.x with ncurses...' $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_NCURSES -DTCPSOCKET -DNOCOTFMC -DUSE_STRERROR \ -DTPUTSARGTYPE=int -DTPUTSARG1CONST -DFREEBSD2 -funsigned-char \ -DFNFLOAT $(KFLAGS) -O -pipe" \ "LIBS= -lncurses -ltermlib -lcrypt -lm $(LIBS)" #For FreeBSD 2.x -- Uses curses rather than ncurses freebsd2c: @echo 'Making C-Kermit $(CKVER) for FreeBSD 2.x with curses...' $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_CURSES -DTCPSOCKET -DNOCOTFMC -DUSE_STRERROR \ -DTPUTSARGTYPE=int -DTPUTSARG1CONST -DFREEBSD2 -DFNFLOAT \ -funsigned-char $(KFLAGS) -O -pipe" \ "LIBS= -lcurses -ltermlib -lcrypt -lm $(LIBS)" #FreeBSD 3.x with ncurses and uu_lock() #(Note: uu_lock() goes back to 2.2.2, but not necessarily 2.0) #OK 2011/08/20 FreeBSD 3.3 freebsd3: @echo 'Making C-Kermit $(CKVER) for FreeBSD 3.x with ncurses...' $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_NCURSES -DTCPSOCKET -DNOCOTFMC -funsigned-char \ -DTPUTSARGTYPE=int -DUSE_STRERROR -DFREEBSD3 -DUSE_UU_LOCK -DFNFLOAT \ $(KFLAGS) -O -pipe" \ "LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)" #As above but with curses rather than ncurses. freebsd3c: @echo 'Making C-Kermit $(CKVER) for FreeBSD 3.x with curses...' $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_CURSES -DTCPSOCKET -DNOCOTFMC -DUSE_UU_LOCK \ -DTPUTSARGTYPE=int -DUSE_STRERROR -DFREEBSD3 $(KFLAGS) -DFNFLOAT \ -funsigned-char -pipe -O" \ "LIBS= -lcurses -lcrypt -lutil -lm $(LIBS)" #FreeBSD 4.0 with ncurses and uu_lock(). Note - there is no curses in 4.0. #ncurses 5.0 is broken requiring us to work around with setbuf(). freebsd40: @echo 'Making C-Kermit $(CKVER) for FreeBSD 4.x with ncurses...' $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_NCURSES -DTCPSOCKET -DNOCOTFMC -DFNFLOAT \ -funsigned-char -DTPUTSARGTYPE=int -DUSE_STRERROR -DFREEBSD4 \ -DNONOSETBUF -DUSE_UU_LOCK $(KFLAGS) -O -pipe" \ "LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)" #FreeBSD 4.1 and above #Like FreeBSD 4.0 but without the NONOSETBUF hack and with CK_NEWTERM. #New stanza 27 June 2023 to squelch "sys/timeb.h deprecated" warning. #Most recently tested on FreeBSD 13.1 # freebsd freebsd41 freebsd72 freebsd5 freebsd6 freebsd7 freebsd8 freebsd9: @echo 'Making C-Kermit $(CKVER) for FreeBSD 4.1 or later...' @if test `uname -r | cut -d . -f 1` -ge 8; then \ HAVE_FBSD8='-DFREEBSD8'; \ else HAVE_FBSD8=''; fi; \ if test `uname -r | cut -d . -f 1` -ge 9; then \ HAVE_FBSD9='-DFREEBSD9'; \ else HAVE_FBSD9=''; fi; \ if test -f /usr/include/utmpx.h ; \ then HAVE_UTMPX='-DHAVEUTMPX' ; \ else HAVE_UTMPX='' ; fi; \ if test -f /usr/include/sys/wait.h ; \ then HAVE_WAITH='-DHAVEWAITH' ; \ else HAVE_WAITH='' ; fi; \ NOSYSTIMEBH="-DNOSYSTIMEBH" ; \ if test -f /usr/include/sys/timeb.h ; \ then x=`grep deprecated /usr/include/sys/timeb.h | wc -l` ; \ if [ $x > 0 ] ; \ then NOSYSTIMEBH='' ; fi ; fi ; \ if `grep -q "[[:space:]]utimes" /usr/include/sys/time.h` ; \ then HAVE_UTIMES='-DHAVE_UTIMES' ; \ else HAVE_UTIMES=''; fi; \ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \ -DFREEBSD4 $$HAVE_FBSD8 $$HAVE_FBSD9 -DUSE_UU_LOCK -DFNFLOAT \ $$HAVE_UTMPX $$HAVE_WAITH $$NOSYSTIMEBH $$HAVE_UTIMES \ -DHERALD=\"\\\" `uname -rs`\\\"\" \ -funsigned-char -DTPUTSARGTYPE=int -DUSE_STRERROR $(KFLAGS) \ -O2 -pipe"\ "LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)" #FreeBSD 5.0 or later with OpenSSL. #OK 2011/06/15 FreeBSD 4.7 and 8.2 #OK 2011/08/20 FreeBSD 9.0-CURRENT freebsd+ssl freebsd+openssl freebsd50+openssl: @echo 'Making C-Kermit $(CKVER) for FreeBSD with Kerberos 5...' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac; \ HAVE_DES=''; \ DES_LIB=''; \ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \ DES_LIB='-ldes'; \ HAVE_DES='-DCK_DES -DLIBDES'; \ echo "HAVE DES"; \ else echo "NO DES"; \ fi; \ $(MAKE) freebsd KTARGET=$${KTARGET:-$(@)} "CC = $(CC)" "CC2 = $(CC2)" \ KFLAGS="-DCK_AUTHENTICATION -DCK_SSL $(SSLINC) -DZLIB $$OPENSSLOPTION \ $$HAVE_DES $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS= -lncurses -lcrypt -lssl -lcrypto -lutil -lm \ $(SSLLIB) $$DES_LIB $(LIBS)"; \ if [ ! -f ./wermit ] || [ ./ckcmai.o -nt ./wermit ] ; then \ echo ""; \ echo "If build failed try:"; \ echo ""; \ echo " make clean ; make $${KTARGET:-$(@)} KFLAGS=-UCK_DES"; \ echo ""; \ fi #NetBSD 1.4.1 or later with vanity banner automated with uname #and automatic inclusion of large file support if it is available. #This target tested successfully on NetBSD 1.4.1, 1.5.2, and 2.0.3 (Jan 2006). #Fails on NetBSD 2.0 on Sun/3 mc68030 with gcc 3.3.3 unless optimization is #disabled on ckcfn2.c ("KFLAGS=-O0") (Letter O Digit Zero). #(This could be automated by testing `uname -m` for "sun3".) #OK: 2011/06/15 on NetBSD 1.5.2 and 5.1. #NetBSD 4.1: have to include . #OK: 2011/08/21 on 5.1. #OK: (many more up through NetBSD 9.2) #OK: NetBSD 8.x #OK: 2020/08/24 NetBSD 9.0 #OK: 2022/10/02 NetBSD 9.3 # `uname -r | grep "[6789].[0-9]" > /dev/null && echo '-DTIMEH'` # Note: netbsd15 and 15 are for 1.5 and 1.6 (not 15 and 16). netbsd netbsd2 netbsd15 netbsd16 old-netbsd: @echo Making C-Kermit $(CKVER) for NetBSD `uname -r` with curses... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS=`grep fseeko /usr/include/stdio.h > /dev/null && \ echo '-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'` \ -DTIMEH -DBSD44 -DCK_CURSES -DTCPSOCKET -DUSE_STRERROR \ -funsigned-char -DHERALD=\"\\\" `uname -s -r`\\\"\" \ -DCK_DTRCD -DCK_DTRCTS -DTPUTSARGTYPE=int -DFNFLOAT $(KFLAGS) -O" \ "LIBS= -lcurses -lcrypt -lm -lutil $(LIBS)" ; $(shell ./ckubuildlog) buildlog: @(shell ./ckubuildlog -v) netbsd-clang netbsdclang: # Dummy comment \ @echo 'Making C-Kermit $(CKVER) for Linux with Clang compiler' $(MAKE) CC=clang CC2=clang KTARGET=$${KTARGET:-$(@)} \ "LNKFLAGS = $(LNKFLAGS)" \ netbsd # NetBSD with pedantic warnings (cc is gcc). netbsd-pedantic: @echo Making C-Kermit $(CKVER) for NetBSD `uname -r` gcc pedantic... $(MAKE) linux KTARGET=$${KTARGET:-$(@)} \ KFLAGS="-Wpedantic $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" \ netbsd # NetBSD with no TCP/IP or any other kind of networking # but with the external SSH client netbsd-nonet: @echo Making C-Kermit $(CKVER) for NetBSD `uname -r` with no TCP/IP... $(MAKE) KTARGET=$${KTARGET:-$(@)} \ KFLAGS="-DNONET -DSSHCMD -DANYSSH $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" \ netbsd # NetBSD with no TCP/IP but with the external SSH client netbsd-notcp: @echo Making C-Kermit $(CKVER) for NetBSD `uname -r` with no TCP/IP... $(MAKE) KTARGET=$${KTARGET:-$(@)} \ KFLAGS="-DNOTCPIP -DSSHCMD -DANYSSH $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" \ netbsd # NetBSD with "legacy" and deprecated features removed: # FTP, Telnet, Rlogin, Wtmp logging, and arrow keys, # which depend on a deprecated API that has no undeprecated replacement. netbsd-nodeprecated: \ # Dummy comment \ @echo 'Making C-Kermit $(CKVER) for Linux without deprecated features' $(MAKE) KTARGET=$${KTARGET:-$(@)} \ KFLAGS="-DNODEPRECATED $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" \ netbsd #NetBSD 1.4.1 or later with OpenSSL #OK: 2011/06/15 on NetBSD 5.1 (but not 1.5.2 with OpenSSL 0.9.5a) #OK: 2011/08/21 on 5.1. #OK (but with warnings) 2022/11/03. #Use "make netbsd+ssl-des" (minus DES) to get rid of DES warnings. netbsd+ssl netbsd+openssl: @echo 'Making C-Kermit $(CKVER) for NetBSD+OpenSSL SSLLIB=$(SSLLIB)' @echo 'If you get DES-related warnings try make netbsd+ssl-des' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac; \ HAVE_DES=''; \ DES_LIB=''; \ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \ DES_LIB='-ldes'; \ HAVE_DES='-DCK_DES -DLIBDES'; \ echo "HAVE DES"; \ else echo "NO DES"; \ fi; \ $(MAKE) netbsd KTARGET=$${KTARGET:-$(@)} "CC = $(CC)" "CC2 = $(CC2)" \ "KFLAGS= -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_CAST $$HAVE_DES \ -DCK_SSL -DCK_PAM -DZLIB -DNO_DCL_INET_ATON $$OPENSSLOPTION \ -I/usr/include/des $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS= -L/usr/pkg/lib -R/usr/pkg/lib -lssl $$DES_LIB -lcurses \ -lcrypto -lcrypt -lz -lm -lpam -lutil $(LIBS)" # ONLY ON PANIX5, which, as of 16 November 2022, has OpenSSL3 in a nonstandard # place because the production version, 1.1.1g is installed in the normal # place, so have to "export LD_LIBRARY_PATH=/usr/local/openssl3/lib"; adding # these to the this target doesn't work: # "LD_LIBRARY_PATH=/usr/local/openssl3/lib \ # "LD_RUN_PATH=/usr/local/openssl3/lib \ # But all this is only because we're doing an end-run around the production # SSL libs. If SSL3 is installed as the production version, the regular # netbsd+ssl target should work. # netbsd+ssl3: @echo 'Making C-Kermit $(CKVER) for NetBSD+OpenSSL SSLLIB=$(SSLLIB)' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac; \ HAVE_DES=''; \ $(MAKE) netbsd KTARGET=$${KTARGET:-$(@)} "CC = $(CC)" "CC2 = $(CC2)" \ "KFLAGS=-DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_CAST $$HAVE_DES \ -DCK_SSL -DCK_PAM -DZLIB -DNO_DCL_INET_ATON $$OPENSSLOPTION \ -I/usr/local/openssl3/include $(KFLAGS)" \ "LNKFLAGS = -L/usr/local/openssl3/lib $(LNKFLAGS)" \ "LIBS= -lssl -lcurses -R/usr/pkg/lib -lcrypto -lcrypt -lz -lm -lpam \ -lutil -W $(LIBS)" netbsd+ssl-des: @echo 'Making C-Kermit $(CKVER) for NetBSD+OpenSSL SSLLIB=$(SSLLIB)' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac; \ HAVE_DES=''; \ DES_LIB=''; \ $(MAKE) netbsd KTARGET=$${KTARGET:-$(@)} "CC = $(CC)" "CC2 = $(CC2)" \ "KFLAGS= -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_CAST $$HAVE_DES \ -DCK_SSL -DCK_PAM -DZLIB -DNO_DCL_INET_ATON $$OPENSSLOPTION \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS= -L/usr/pkg/lib -R/usr/pkg/lib -lssl $$DES_LIB -lcurses \ -lcrypto -lcrypt -lz -lm -lpam -lutil $(LIBS)" #NetBSD with MIT Kerberos 5: # OK 2011/06/15 (once K5INC and K5LIB were set right). # NOT OK for Heimdal - Heimdal Kerberos support in C-Kermit needs work. # OK: 2011/08/21 on 5.1. netbsd+krb5: @echo 'Making C-Kermit $(CKVER) for NetBSD with Kerberos 5...' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac; \ HAVE_DES=''; \ DES_LIB=''; \ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \ DES_LIB='-ldes'; \ HAVE_DES='-DCK_DES -DLIBDES'; \ echo "HAVE DES"; \ else echo "NO DES"; \ fi; \ $(MAKE) netbsd KTARGET=$${KTARGET:-$(@)} "CC = $(CC)" "CC2 = $(CC2)" \ "KFLAGS= -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_KERBEROS -DKRB5 \ -DCK_CAST $$HAVE_DES -DNOFTP_GSSAPI $(K5INC) $(K5INC)/krb5 \ $(KFLAGS)" \ "LIBS= $(K5LIB) -L/usr/pkg/lib -R/usr/pkg/lib -lcurses $$DES_LIB \ -lcrypto -lgssapi -lkrb5 -lm -lutil $(LIBS)" # This target added 24 Nov 2022, based on linux+krb5-new. # This is for Heimdal Kerberos, not MIT. # It doesn't work. - fdc Thu Nov 24 19:15:47 2022 netbsd+krb5-new: @echo 'Making C-Kermit $(CKVER) for NetBSD with Kerberos 5...' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac; \ K5LIB=''; \ if ld -lkrb5 > /dev/null 2> /dev/null; then \ K5LIB='-lkrb5'; else \ echo "Failed - Can't find Kerberos 5 library" ; exit 2; \ fi; \ KRB5_H=''; \ KRB5_KRB5_H=''; \ if test -f /usr/include/krb5/krb.h; then \ KRB5_H=-DKRB5_H; \ fi; \ CRYPT_H=''; \ if test -f /usr/include/crypt.h; then \ CRYPT_H='-DCRYPT_H'; \ fi; \ LIBCRYPT=''; \ if ld -lcrypt > /dev/null 2> /dev/null; then \ LIBCRYPT='-lcrypt'; \ fi; \ LIBCRYPTO=''; \ if ld -lcrypto > /dev/null 2> /dev/null; then \ LIBCRYPTO='-lcrypto'; \ fi; \ LIBK5CRYPTO=''; \ if ld -lk5crypto > /dev/null 2> /dev/null; then \ LIBK5CRYPTO='-lk5crypto'; \ fi; \ HAVE_DES=''; \ if ld -ldes > /dev/null 2> /dev/null; then \ LIBDES='-ldes'; \ HAVE_DES='-DCK_DES -DLIBDES'; \ fi; \ XX_COM_ERR=H''; \ K5_COM_ERR_H=''; \ ET_COM_ERR_H=''; \ COM_ERR_LIB=''; \ if ld -lcom_err > /dev/null 2> /dev/null; then \ if test -f /usr/include/krb5/com_err.h; then \ COM_ERR_LIB='-lcom_err'; \ COM_ERR_H='-DK5_COM_ERR_H'; \ else if test -f /usr/include/et/com_err.h; then \ COM_ERR_LIB='-lcom_err'; \ COM_ERR_H='-DET_COM_ERR_H'; \ else if test -f /usr/include/com_err.h; then \ COM_ERR_LIB='-lcom_err'; \ COM_ERR_H='-DXX_COM_ERR_H'; \ fi; \ fi; \ fi; \ fi; \ GSSAPILIB=''; \ HAVE_GSSAPI=''; \ if name=`locate libgssapi | grep ^/usr/lib | head -1`; then \ echo name=$$name; \ path=$${name%/*}; \ echo PATH=$$path; \ GSSAPILIB=$$(basename $$name); \ echo GSSAPILIB=$$GSSAPILIB ; \ HAVE_GSSAPI='-DHAVE_GSSAPI'; \ fi ; \ if [ -z "$$LD_LIBRARY_PATH" ] ; then \ export LD_LIBRARY_PATH=$$path ; else \ export LD_LIBRARY_PATH=$$LD_LIBRARY_PATH:$$path; \ HAVE_GSSAPI='-DHAVE_GSSAPI'; \ fi; \ if ls $${path}/libgssapi_krb5.* >/dev/null 2>/dev/null; then \ echo HAVE libgssapi_krb5 ; \ GSSAPILIB=-lgssapi_krb5 ; else \ if ls $${path}/libgssapi.* >/dev/null 2>/dev/null; then \ GSSAPILIB=-lgssapi ; \ fi; \ fi; \ echo GSSAPILIB=$GSSAPILIB; \ echo LD_LIBRARY_PATH=$$LD_LIBRARY_PATH; \ if ld -lggssapi_krb5 > /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi_krb5'; \ HAVE_GSSAPI='-DHAVE_GSSAPI'; \ echo GSSAPILIB-1=$$GSSAPILIB; \ else if ld -lggssapi > /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi'; \ HAVE_GSSAPI='-DHAVE_GSSAPI'; \ echo GSSAPILIB-2=$$GSSAPILIB; \ fi; \ fi; \ echo GSSAPILIB=$$GSSAPILIB; \ $(MAKE) netbsd KTARGET=$${KTARGET:-$(@)} "CC = $(CC)" "CC2 = $(CC2)" \ "KFLAGS= -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_KERBEROS -DKRB5 \ -DCK_CAST $$HAVE_DES $$CRYPT_H $$COM_ERR_H $$KRB5_H \ -I/usr/include -I/usr/include/et /$(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" \ "LIBS= $$LIBCRYPT $$LIBCRYPTO $$LIBK5CRYPTO $$LIBDES $$COM_ERR_LIB \ $$K5LIB $$GSSAPILIB $(K5LIB) -L/usr/pkg/lib -R/usr/pkg/lib \ -lcurses $$DES_LIB -lm -lutil $(LIBS)" # NetBSD - With Kerberos 5 and SSL and Zlib. # OK: 2011/08/21 on 5.1 with MIT Kerberos. netbsd+krb5+ssl netbsd+krb5+openssl+zlib: @echo 'Making C-Kermit $(CKVER) for NetBSD+OpenSSL+Kerberos5...' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac; \ HAVE_DES=''; \ DES_LIB=''; \ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \ DES_LIB='-ldes'; \ HAVE_DES='-DCK_DES -DLIBDES'; \ echo "HAVE DES"; \ else echo "NO DES"; \ fi; \ $(MAKE) netbsd KTARGET=$${KTARGET:-$(@)} "CC = $(CC)" "CC2 = $(CC2)" \ "KFLAGS= -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_CAST $$HAVE_DES \ -DCK_KERBEROS -DKRB5 -DNOFTP_GSSAPI $(K5INC) $(K5INC)/krb5 \ -DCK_SSL -DCK_PAM -DZLIB -DNO_DCL_INET_ATON $$OPENSSLOPTION \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS= $(K5LIB) -L/usr/pkg/lib -R/usr/pkg/lib -lssl $$DES_LIB \ -lcrypto -lcrypt -lgssapi -lkrb5 -lz -lm -lpam -lutil -lcurses $(LIBS)" #Special Security Enhanced NetBSD target with SRP, SSL, and zlib support. #To build this, you need to BUILD the pkgsrc srp_client package. After #you build it, you must go into work/srp-x.y.z/libkrypto and "bmake install" #then go to work/srp-x.y.z/libsrp and "bmake install". As of 2005Q3, the #pkgsrc install only installed the statically linked client applications. You #need to manually install the libraries to build your own applications. #NOT TESTED RECENTLY - probably needs work. netbsd+ssl+srp+zlib: @echo Making C-Kermit $(CKVER) for NetBSD with curses... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_CURSES -DTCPSOCKET -DUSE_STRERROR -DNETBSD15 \ -DCK_DTRCD -DCK_DTRCTS -DTPUTSARGTYPE=int \ -I/usr/include/openssl -I/usr/pkg/include \ -DCK_AUTHENTICATION -DCK_SRP -DPRE_SRP_1_4_5 -DCK_ENCRYPTION \ -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DZLIB -DFNFLOAT $(KFLAGS) -O" \ "LIBS= -L/usr/pkg/lib -R/usr/pkg/lib -lcurses -lsrp -lgmp -ldes \ -lssl -lkrypto -lcrypto -lcrypt -lz -lm -lutil $(LIBS)" #NetBSD with curses left out (e.g. for use as IKSD). netbsdnc: @echo Making C-Kermit $(CKVER) for NetBSD with no curses... $(MAKE) CC=$(CC) CC2=$(CC2) netbsd KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DNOCURSES" #NetBSD with ncurses requested explicitly rather than curses-which-is-ncurses netbsdn: @echo Making C-Kermit $(CKVER) for NetBSD with curses... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS=`grep fseeko /usr/include/stdio.h > /dev/null && \ echo '-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'` \ -DBSD44 -DCK_CURSES -DTCPSOCKET -DUSE_STRERROR \ -DHERALD=\"\\\" NetBSD `uname -r`\\\"\" \ -DCK_DTRCD -DCK_DTRCTS -DTPUTSARGTYPE=int -DFNFLOAT $(KFLAGS) -O" \ "LIBS= -L/usr/pkg/lib -lncurses -lcrypt -lm -lutil $(LIBS)" #OpenBSD before 2.3. #Uses ncurses as its curses so use -ltermlib, not -ltermcap #But it doesn't use uu_lock() which was introduced in OpenBSD 2.3. #For that use the next entry. #Add -DMAINTYPE=int if you get complaints about main: return type is not int. openbsdold: @echo Making C-Kermit $(CKVER) for OpenBSD... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_CURSES -DCK_NEWTERM -DTCPSOCKET -DOPENBSD \ -DFNFLOAT -DNDSYSERRLIST $(KFLAGS) -O" "LIBS= -lcurses -ltermlib -lm" #OpenBSD 2.3 or later #Add -DMAINTYPE=int if you get complaints about main: return type is not int. #For C-Kermit 8.0 (Christian Weisgerber): # -ltermlib removed (presumably because -lcurses==ncurses already includes it) # -DUSE_UU_LOCK and -lutil added for uu_lock() # -DNDSYSERRLIST changed to -DUSE_STRERROR #If this gives you trouble use the previous entry. #29 April 2023 for C-Kermit 10.0: New clauses to account the presence # or absence of term.h (curses) sys/timeb.h (dates and times). openbsd: @echo Making C-Kermit $(CKVER) for OpenBSD 2.3 or later... NOTIMEBH='' ; if test -f /usr/include/sys/timeb.h ; \ then if `grep deprecated /usr/include/sys/timeb.h` ; \ then NOSYSTIMEBH='-DNOSYSTIMEBH' ; fi ; \ else NOSYSTIMEBH='-DNOSYSTIMEBH' ; fi; \ if test -f /usr/include/sys/term.h ; \ then HAVETERMH='-DHAVETERMH' ; \ else HAVETERMH='' ; fi; \ if test -f /usr/include/sys/wait.h ; \ then HAVE_WAITH='-DHAVEWAITH' ; \ else HAVE_WAITH='' ; fi; \ if `grep -q "[[:space:]]utimes" /usr/include/sys/time.h` ; \ then HAVE_UTIMES='-DHAVE_UTIMES' ; \ else HAVE_UTIMES=''; fi; \ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_CURSES -DCK_NEWTERM -DTCPSOCKET -DOPENBSD \ $$NOSYSTIMEBH -DHERALD=\"\\\" OpenBSD `uname -r`\\\"\" \ -DUSE_UU_LOCK -DFNFLOAT -DUSE_STRERROR $$HAVETERMH $$HAVE_WAITH \ $$HAVE_UTIMES \ $(KFLAGS) -O" \ "LIBS= -lcurses -lutil -lm" #Better to chain to the openbsd target but... mirbsd: @echo Making C-Kermit $(CKVER) for OpenBSD 2.3 or later... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_CURSES -DCK_NEWTERM -DTCPSOCKET -DOPENBSD \ -DHERALD=\"\\\" MirBSD `uname -r`\\\"\" \ -DUSE_UU_LOCK -DFNFLOAT -DUSE_STRERROR $(KFLAGS) -O" \ "LIBS= -lcurses -lutil -lm" #New OpenBSD + OpenSSL target from Piotr Kolasinski, 18 September 2023... openbsd+ssl: @echo Making C-Kermit $(CKVER) for OpenBSD 3.0 or later... NOTIMEBH='' ; if test -f /usr/include/sys/timeb.h ; \ then if `grep deprecated /usr/include/sys/timeb.h` ; \ then NOSYSTIMEBH='-DNOSYSTIMEBH' ; fi ; \ else NOSYSTIMEBH='-DNOSYSTIMEBH' ; fi; \ if test -f /usr/include/sys/wait.h ; \ then HAVE_WAITH='-DHAVEWAITH' ; \ else HAVE_WAITH='' ; fi; \ if `grep -q "[[:space:]]utimes" /usr/include/sys/time.h` ; \ then HAVE_UTIMES='-DHAVE_UTIMES' ; \ else HAVE_UTIMES=''; fi; \ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_CURSES -DCK_NEWTERM -DTCPSOCKET -DOPENBSD \ $$NOSYSTIMEBH -DHERALD=\"\\\" OpenBSD `uname -r`\\\"\" \ -DUSE_UU_LOCK -DFNFLOAT -DUSE_STRERROR -DCK_AUTHENTICATION \ -DCK_SSL $$HAVE_WAITH $$HAVE_UTIMES $(KFLAGS) -O" \ "LIBS= -lcurses -lutil -lm -lssl -lcrypto" mirbsd+ssl: @echo Making C-Kermit $(CKVER) for OpenBSD 3.0 or later... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DCK_CURSES -DCK_NEWTERM -DTCPSOCKET -DOPENBSD \ -DHERALD=\"\\\" MirBSD `uname -r`\\\"\" \ -DUSE_UU_LOCK -DFNFLOAT -DUSE_STRERROR -DCK_AUTHENTICATION \ -DCK_SSL -DNO_DCL_INET_ATON $(KFLAGS) -O" \ "LIBS= -lcurses -lutil -lm -lssl -lcrypto" # make 386bsd 0.0new, posix # for 386bsd 0.1.24, change /usr/include/termios.h to #define NCCS if # _POSIX_SOURCE is #defined. (source: lewine, posix prgmrs guide, o`reilly) #NOTE: Lock directory is /var/spool/lock. Formerly, it was /var/spool/uucp, #but reportedly that was due to a typo in 'man tip'. 386bsd: @echo 'Making C-Kermit $(CKVER) for jolix 386BSD 0.0new and 0.1.24...' $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DPOSIX -DSETREUID -DPIDSTRING -DUSLEEP \ -D_386BSD -DCK_CURSES -DTCPSOCKET \ -DLOCK_DIR=\\\"/var/spool/lock\\\" \ $(KFLAGS) -O" "LNKFLAGS = -s" "LIBS = -lcurses -ltermcap" # Mac OS X 10 early versions. # For 10.3.9 and later, use the macosx target below. #Mac OS X 1.0 (Rhapsody, Darwin) -- TCP/IP but no curses. oldmacosx10: @echo Making C-Kermit $(CKVER) for `uname -s`... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DMACOSX10 -DTCPSOCKET -DUSE_STRERROR -O $(KFLAGS)" #Mac OS X 1.0 (Rhapsody, Darwin) -- TCP/IP and curses. #Note: curses must be obtained separately. See next entry for ncurses. #Add "LIBS = -lcurses -ltermcap" if necessary (but reportedly it is not). oldmacosx10c: @echo Making C-Kermit $(CKVER) for `uname -s` + curses... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DMACOSX10 -DCK_CURSES -DTPUTSFNTYPE=void -DTPUTSISVOID \ -DTCPSOCKET -DUSE_STRERROR -O $(KFLAGS)" #Mac OS X 1.0 (Rhapsody, Darwin) -- TCP/IP and ncurses. #Note: ncurses must be obtained separately. #In the event of trouble with this one try the next one. oldmacosx10nc: @echo Making C-Kermit $(CKVER) for `uname -s` + ncurses... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DMACOSX10 -DCK_NCURSES -DTCPSOCKET -DUSE_STRERROR -O \ $(KFLAGS)" "LIBS= -lncurses $(LIBS)" #Mac OS X 10.2 (Jaguar) ncurses. oldmacosx102nc: @echo Making C-Kermit $(CKVER) for `uname -s` + ncurses... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DMACOSX10 -DCK_NCURSES -DTCPSOCKET -DUSE_STRERROR -O \ $(KFLAGS) " "LIBS= -lncurses $(LIBS)" #The problem here is that if curses.h also exists, it conflicts with #ncurses.h and and we have fatal errors. If this happens to you, then #try this target. oldmacosx10ncx: @echo Making C-Kermit $(CKVER) for `uname -s` + ncurses... @rm -f ./curses.h; touch ./curses.h $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DMACOSX10 -DCK_NCURSES -DTCPSOCKET -DUSE_STRERROR \ -I. -O $(KFLAGS) " \ "LIBS= -lncurses $(LIBS)" @rm -f ./curses.h #Mac OS X 10.3 (Panther) - Assumes ncurses is installed. oldmacosx103: @echo Making C-Kermit $(CKVER) for `uname -s` + ncurses... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DMACOSX10 -DMACOSX103 -DCK_NCURSES -DTCPSOCKET -DCKHTTP \ -DUSE_STRERROR -DUSE_NAMESER_COMPAT -O \ $(KFLAGS) " "LIBS= -lncurses -lresolv $(LIBS)" #Mac OS X 10.3 (Panther) with Kerberos 5 and SSL, assumes ncurses is installed. oldmacosx103+secure: @echo Making Secure C-Kermit $(CKVER) for `uname -s` + ncurses... $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DMACOSX10 -DMACOSX103 -DCK_NCURSES -DTCPSOCKET \ -DUSE_STRERROR -DUSE_NAMESER_COMPAT -O -DCK_PAM \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DZLIB \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL \ $(KFLAGS) " "LIBS= -lssl -lcrypto -lkrb5 -lcom_err \ -lk5crypto -lgssapi_krb5 -lpam -lncurses -lresolv $(LIBS)" # THIS IS THE MAIN MAC OS X TARGET (the next one is for Kerberos/SSL builds). # Use this target for 10.3.9 (or maybe earlier) through 10.6 (maybe later) # on both Power and Intel architectures. This one uses utmp.h on 10.4 and # earlier and utmpx.h on 10.5 onwards. # Note: Mac OS X 10.5 and earlier are 32-bit; 10.6 and later 64-bit. # Note 2: As of C-Kermit 9.0 -DNOUUCP is included by default because # Mac OS X doesn't support UUCP. To undo this, use KFLAGS=-UNOUUCP. #OK: 2011/06/14 (for 10.4.11, 10.5.8, 10.6.7) macosx macosx10 macosx10.3.9 macosx10.4 macosx10.5 macosx10.6: @MACOSNAME=`/usr/bin/sw_vers -productName`; \ MACOSV=`/usr/bin/sw_vers -productVersion`; \ echo Making C-Kermit $(CKVER) for $$MACOSNAME $$MACOSV... ; \ MACCPU=$$HOSTTYPE; \ if test `uname -r | cut -d . -f 1` -gt 8; \ then if test -f /usr/include/utmpx.h ; \ then HAVE_UTMPX='-DHAVEUTMPX -D_UTMPX_COMPAT' ; \ else HAVE_UTMPX='' ; fi ; fi; \ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DMACOSX10 -DMACOSX103 -DCK_NCURSES -DTCPSOCKET -DCKHTTP \ -DUSE_STRERROR -DUSE_NAMESER_COMPAT -DNOCHECKOVERFLOW -DFNFLOAT \ -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 $$HAVE_UTMPX \ -funsigned-char -DNODCLINITGROUPS -DMACOSHISPEED \ -DNOUUCP -O -DHERALD=\"\\\" $${MACOSNAME} $${MACOSV}\\\"\" \ -DCKCPU=\"\\\"$${MACCPU}\\\"\" \ $(KFLAGS)" "LIBS= -lncurses -lresolv $(LIBS)" # Mac OS X 10.3.9 or later with Kerberos 5 and OpenSSL... # NOTE: Apple has removed all support for DES in OpenSSL and Kerberos # in Mac OS X 10.6 and later. The DES flags are included or left out # automatically based on the Mac OS X version number. # See note about UUCP in previous target. #OK: 2009/11/16 (for 10.3.9, 10.4.11, 10.5.8, 10.6.1) #OK: 2011/06/14 (for 10.4.11, 10.5.8, 10.6.7) macosx+krb5+ssl macosx10.5+krb5+ssl macosx10.6+krb5+ssl \ macosx+krb5+openssl macosx10.5+krb5+openssl macosx10.6+krb5+openssl: @MACOSNAME=`/usr/bin/sw_vers -productName`; \ MACOSV=`/usr/bin/sw_vers -productVersion`; \ echo Making C-Kermit $(CKVER) for $$MACOSNAME $$MACOSV... ; \ MACCPU=$$HOSTTYPE; \ if test `uname -r | cut -d . -f 1` -gt 8; \ then if test -f /usr/include/utmpx.h ; \ then HAVE_UTMPX='-DHAVEUTMPX -D_UTMPX_COMPAT' ; \ else HAVE_UTMPX='' ; fi ; fi; \ if test `uname -r | cut -d . -f 1` -eq 7; \ then IS_MACOSX103='-DMACOSX103' ; \ else IS_MACOSX103='' ; fi; \ case $$MACOSV in \ 10.[012345].*) HAVE_DES='-DCK_DES -DLIBDES' ;; \ *.*) HAVE_DES='' ;; \ esac ; \ if test -x /usr/bin/krb5-config ; \ then HAVE_KRB5CONFIG=`/usr/bin/krb5-config --libs krb5 gssapi` ; \ else HAVE_KRB5CONFIG='-lgssapi_krb5 -lkrb5 -lk5crypto \ -lcom_err -lresolv' ; fi; \ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DMACOSX10 $$IS_MACOSX103 -DCK_NCURSES -DTCPSOCKET \ -DUSE_STRERROR -DUSE_NAMESER_COMPAT -DNOCHECKOVERFLOW -DFNFLOAT \ -DCKHTTP -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 $$HAVE_UTMPX \ -DNODCLINITGROUPS -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DZLIB \ -DCK_ENCRYPTION -DCK_CAST -DCK_SSL -DOPENSSL_098 $$HAVE_DES \ -DNOUUCP -DHERALD=\"\\\" $${MACOSNAME} $${MACOSV}\\\"\" \ -DCKCPU=\"\\\"$${MACCPU}\\\"\" \ -funsigned-char -O $(KFLAGS)" \ "LIBS= $$HAVE_KRB5CONFIG -lssl -lcrypto -lpam -lncurses $(LIBS)" # Additional target "macos" by Tony Nicholson 4-Nov-2021. # # More recent macOS re-branded releases for Intel (x86_64) Sierra (10,12), # High Sierra (10,13), Mojave (10.14), Catalina (10.15), and Intel x86_64/ARM # Big Sur (11), Monterey (12) # # Apple's Clang C compiler reports many warnings that can safely be ignored - # so keep reporting the ones that may have not been detected by other # compilers by selectively disabling dangling-else, string-compare and # parentheses related warnings. -DNOWTMP added because it always provokes # a "deprecated" warning. Wtmp logging is only for IKSD, so if you're # not going to be using macOS C-Kermit as an IKSD server, no worries. # If you are, and want the server to make Wtmp log entries, do # 'make macos "KFLAGS=-UNOWTMP". # macos: @MACOSNAME=`/usr/bin/sw_vers -productName`; \ MACOSV=`/usr/bin/sw_vers -productVersion`; \ echo Making C-Kermit $(CKVER) for $$MACOSNAME $$MACOSV... ; \ MACCPU=$$HOSTTYPE; \ HAVE_UTMPX=''; \ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS=-Wno-dangling-else -Wno-string-compare -Wno-parentheses \ -Wno-pointer-sign -Wno-unused-value -Wdeprecated-declarations \ -DMACOSX10 -DMACOSX103 -DCK_NCURSES -DTCPSOCKET -DCKHTTP \ -DUSE_STRERROR -DUSE_NAMESER_COMPAT -DNOCHECKOVERFLOW -DFNFLOAT \ -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 $$HAVE_UTMPX \ -funsigned-char -DNODCLINITGROUPS \ -DNOUUCP -O -DHERALD=\"\\\" $${MACOSNAME} $${MACOSV}\\\"\" \ -DCKCPU=\"\\\"$${MACCPU}\\\"\" \ $(KFLAGS)" "LIBS= -lncurses -lresolv $(LIBS)" # Experimental. 2022-11-30 SMS. macos+ssl macos+openssl: if test -n "$(KZLIBDIR)" ; then \ ZLIBDIR="$(KZLIBDIR)" ; \ else \ ZLIBDIR='/usr/local/lib' ; \ fi ; \ case "$(KTARGET)" in \ *-zlib*) ZLIBFLAG='' ; ZLIBOPT='' ;; \ *) ZLIBFLAG='-DZLIB' ; ZLIBOPT="-L $$ZLIBDIR -lz" ;; \ esac ; \ case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac ; \ SSLINC=$${KSSLINC:-$(SSLINC)}; \ SSLLIB=$${KSSLLIB:-$(SSLLIB)}; \ $(MAKE) CC=$(CC) CC2=$(CC2) macos KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DCK_AUTHENTICATION -DCK_SSL $(KCFLAGS) \ $$OPENSSLOPTION $$ZLIBFLAG $$SSLINC" \ "LIBS= $$SSLLIB -lssl -lcrypto $$ZLIBOPT $(KLIBS)" macos+ssl-zlib macos+openssl-zlib: $(MAKE) macos+ssl KTARGET=$${KTARGET:-$(@)} # Trial using the Homebrew install of krb5 and openssl # (newer versions of macOS have dropped the Kerberos5 include # files and moved to LibreSSL). # NB: not yet working **DON'T USE THIS TARGET** # macos+krb5+ssl macos+krb5+openssl: @MACOSNAME=`/usr/bin/sw_vers -productName`; \ MACOSV=`/usr/bin/sw_vers -productVersion`; \ echo Making C-Kermit $(CKVER) for $$MACOSNAME $$MACOSV... ; \ MACCPU=$$HOSTTYPE; \ HAVE_UTMPX=''; \ IS_MACOSX103=''; \ HAVE_DES=''; \ if test -x ${HOMEBREW_PREFIX}/opt/krb5/bin/krb5-config ; \ then HAVE_KRB5CONFIG=`${HOMEBREW_PREFIX}/opt/krb5/bin/krb5-config \ --libs krb5 gssapi` ; \ else HAVE_KRB5CONFIG='-lgssapi_krb5 -lkrb5 -lk5crypto \ -lcom_err -lresolv' ; fi; \ $(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS=-Wno-dangling-else -DMACOSX10 $$IS_MACOSX103 -DCK_NCURSES \ -DTCPSOCKET -DUSE_STRERROR -DUSE_NAMESER_COMPAT -DNOCHECKOVERFLOW \ -DFNFLOAT -DCKHTTP -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 \ $$HAVE_UTMPX -DNODCLINITGROUPS -DCK_AUTHENTICATION -DCK_KERBEROS \ -DKRB5 -DZLIB -DCK_ENCRYPTION -DCK_CAST -DCK_SSL -DOPENSSL_098 \ $$HAVE_DES -DNOUUCP -DHERALD=\"\\\" $${MACOSNAME} $${MACOSV}\\\"\" \ -DCKCPU=\"\\\"$${MACCPU}\\\"\" \ $${K5INC} $${SSLINC} \ -funsigned-char -O $(KFLAGS)" \ "LIBS= $$HAVE_KRB5CONFIG $${SSLLIB} \ -lssl -lcrypto -lpam -lncurses $(LIBS)" # End of Mac OS X Section #Acorn RISCiX, based on ... #Berkeley Unix 4.2 or 4.3 with lock directory /usr/spool/uucp/LCK/LCK..ttyxx, #but without acucntrl program riscix: @echo Making C-Kermit $(CKVER) for RISCiX, /usr/spool/uucp/LCK..ttyxx $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD42 -DBSD4 -DRISCIX -DNOCSETS \ -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DDIRENT -DCK_CURSES \ -DMAXSP=9024 -DMAXRD=9024 -DSBSIZ=9050 -DRBSIZ=9050 \ -DDFTTY=\\\"/dev/serial\\\" -DNOCSETS -DNOCYRIL \ -DNOANSI -w -O2 -fomit-frame-pointer" \ "LIBS= -lcurses -ltermcap " \ "CC= /usr/ucb/cc" \ "CC2= /usr/ucb/cc" #Acorn RISCiX, as above, but using gcc riscix-gcc: @echo Making C-Kermit $(CKVER) for RISCiX, /usr/spool/uucp/LCK..ttyxx $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD42 -DBSD4 -DRISCIX -DNOCSETS \ -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DDIRENT -DCK_CURSES \ -DMAXSP=9024 -DMAXRD=9024 -DSBSIZ=9050 -DRBSIZ=9050 \ -DDFTTY=\\\"/dev/serial\\\" -DNOCSETS -DNOCYRIL \ -DNOANSI -w -O2 -fomit-frame-pointer" \ "LIBS= -lcurses -ltermcap " \ "CC= gcc -mbsd" \ "CC2= gcc -mbsd" #Convergent CTIX 6.4.1 ctix: @echo 'Making C-Kermit $(CKVER) for Convergent CTIX 6.4.1' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DSVR3 -DDIRENT -DTCPSOCKET -DHDBUUCP -DCK_CURSES \ -DNONAWS -DNOLEARN -DNOLONGLONG $(KFLAGS) -XO" \ "LNKFLAGS=-s" "LIBS=-lsocket -lcurses -lc_s" mcs -d wermit # The following makefile entry should work for any Harris Night Hawk system # (either 88k or 68k based) running release 6.1 or later of the CX/UX # operating system. This is a POSIX and ANSI-C compliant system which also # supports BSD networking. (Earlier CX/UX releases will probably work with # sys5r3, but this has not been verified). # cx_ux: @echo Making C-Kermit $(CKVER) for Harris Night Hawk CX/UX 6.1 or later $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS=-DPOSIX -DTCPSOCKET -DHDBUUCP -DPID_T=pid_t -DWAIT_T=int \ -Dd_ino=d_fileno -DUID_T=uid_t -DGID_T=gid_t -DNOLONGLONG \ $(KFLAGS) -Xa -O3 -g" "LNKFLAGS=-O3" #Intergraph Clipper, CLIX, job control, HDB UUCP. clix: @echo 'Making C-Kermit $(CKVER) for Intergraph CLIX...' $(MAKE) wermit "CC=acc" "CC2=acc" KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -w -DSVR3 -DCLIX -DDIRENT -DHDBUUCP -DNOSYSLOG -DUSE_MEMCPY \ -DNOGETUSERSHELL -DNOREALPATH -DNOLEARN $(KFLAGS) -O" \ "LNKFLAGS=" "LIBS= -lbsd" #As above + TCP/IP... clixnet: @echo 'Making networked C-Kermit $(CKVER) for Intergraph CLIX...' $(MAKE) wermit "CC=acc" "CC2=acc" KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -w -DSVR3 -DCLIX -DDIRENT -DHDBUUCP -DNOSYSLOG -DUSE_MEMCPY \ -DTCPSOCKET -DNOGETUSERSHELL -DNOLEARN -DNOREALPATH $(KFLAGS) -O" \ "LNKFLAGS=" "LIBS= -lbsd" #Mark Williams Coherent 286 or 386 on IBM PC family. #There is a 64K limit on program size, so this is a command-line only version. coherent: $(MAKE) "CFLAGS = -O -DCOHERENT -DNOANSI -DNOICP -DNOSETKEY -DNOLEARN \ -DNOCSETS -DNOHELP -DNODIAL -DNOSCRIPT -DNODEBUG -DNOTLOG -DNOXMIT \ -DNOMSEND -DNOFRILLS -DNOSYSIOCTLH -DSELECT_H $(KFLAGS) -VSUVAR" \ -DNOFLOAT KTARGET=$${KTARGET:-$(@)} wermit #Mark Williams Coherent 386 on IBM PC family. #This will make a "minimum interactive" version - no scripts, #no character sets, no help, no dial, no debug/transaction logging, no #transmit, msend, mail, type, etc. coherentmi: $(MAKE) "CFLAGS = -O -DCOHERENT -DNOANSI -DNOSETKEY -DNOLEARN \ -DNOSHOW -DNOCSETS -DNOHELP -DNODIAL -DNOSCRIPT -DNODEBUG -DNOTLOG \ -DNOXMIT -DNOMSEND -DNOFRILLS -DNOSYSIOCTLH -DNOSERVER -DNOUUCP \ -DNOSPL -DNOPUSH -DNOMDMHUP -DNOJC -DNOFDZERO -DNOESCSEQ -DNOFLOAT \ -DNOCMDL $(KFLAGS) -VSUVAR -DSELECT_H" KTARGET=$${KTARGET:-$(@)} \ wermit #Mark Williams Coherent 386 on IBM PC/AT family. coherentmax: $(MAKE) "CFLAGS = -O -DCOHERENT -DNOANSI -DSELECT_H -DNOLEARN \ -DNOFLOAT -DNOSYSIOCTLH $(KFLAGS) -VSUVAR" "LNKFLAGS = -O -s" \ KTARGET=$${KTARGET:-$(@)} wermit #Mark Williams Coherent 386 4.2. Includes curses but not TCP/IP. #Requires updates to the 4.2.10 compiler; the regular compiler fails to #to handle "complex expressions". NOFLOAT is so it can work on old PCs #without floating-point hardware. coherent42: $(MAKE) "CFLAGS = -T500000 -DNOFLOAT -DCOHERENT -DNOANSI -DSELECT \ -DNOSYSLOG -DDIRENT -DCK_CURSES -DCK_NEWTERM -DCK_WREFRESH -VSUVAR \ -DDCLGETCWD -DNOSYSIOCTLH -DNOINITGROUPS -DNOSYMLINK -DSELECT_H \ -DDCLGETCWD -O $(KFLAGS)" \ "LNKFLAGS = -O -s" KTARGET=$${KTARGET:-$(@)} \ "LIBS = -lsocket -lcurses" wermit #DEC Ultrix 2.x # Add -O, -DDYNAMIC, -s, etc, if they work. ultrix2x: @echo Making C-Kermit $(CKVER) for Ultrix 2.x ... $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD4 -DTCPSOCKET -DDU2 -DNOGETUSERSHELL $(KFLAGS)" du2: $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET-$(@)} ultrix2x #DEC Ultrix 3.0 and 3.1 ultrix30: @echo Making C-Kermit $(CKVER) for Ultrix 3.0... $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD4 -DTCPSOCKET -DDIRENT -DSIG_V -DNOGETUSERSHELL \ -DULTRIX3 -DCK_CURSES $(KFLAGS) -O" "LIBS= -lcurses -ltermcap" du3: $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET-$(@)} ultrix30 ultrix3x: $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET-$(@)} ultrix30 #DEC Ultrix 4.0 or 4.1 on DECstation, VAXstation, VAX, etc. ultrix40: @echo Making C-Kermit $(CKVER) for Ultrix 4.0 or 4.1... $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD4 -DTCPSOCKET -DSIG_V -DDU4 -DNOGETUSERSHELL \ $(KFLAGS) -Olimit 1450" "LNKFLAGS = -s" #DEC Ultrix 4.2-4.5 on DECstation, DECsystem, VAXstation, VAX, etc. #Like ultrix40, except now C compiler supports -O2 optimization. ultrix42: @echo Making C-Kermit $(CKVER) for Ultrix 4.2 or later... $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD4 -DTCPSOCKET -DSIG_V -DNOGETUSERSHELL $(KFLAGS) \ -O2 -Olimit 1750" "LNKFLAGS = -s" du42: $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET-$(@)} ultrix42 #DEC Ultrix 4.2-4.5 on DECstation, DECsystem, VAXstation, VAX, etc. #Like du42, but with curses support added and a couple features. ultrix42c: @echo Making C-Kermit $(CKVER) for Ultrix 4.2 or later... $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD4 -DTCPSOCKET -DSIG_V -DNOGETUSERSHELL \ -DCK_CURSES -DNOIKSD $(KFLAGS)-G6 -O2 -Olimit 3000 " \ "LNKFLAGS = -s" "LIBS= -lcurses -ltermcap" ultrix43: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \ "KFLAGS=-DULTRIX43 $(KFLAGS)" KTARGET=$${KTARGET-$(@)} ultrix42c ultrix43notcp: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \ "KFLAGS=-DULTRIX43 -DNONET $(KFLAGS)" \ KTARGET=$${KTARGET-$(@)} ultrix42c # NOTE: need -DNODEBUG on MIPS to avoid relocation errors at link time. # Actually now (8.0) that we have discovered the -G option maybe debugging # can be put back. ultrix44: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \ "KFLAGS=-DULTRIX44 -G7 -DNODEBUG -DNETPTY -DNO_DEVTTY $(KFLAGS)" \ KTARGET=$${KTARGET-$(@)} ultrix42c ultrix45: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \ "KFLAGS=-DULTRIX45 $(KFLAGS)-DNETPTY -DNO_DEVTTY $(KFLAGS)" \ KTARGET=$${KTARGET-$(@)} ultrix42c du42c: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \ KTARGET=$${KTARGET-$(@)} ultrix42c #DEC Ultrix 4.3A or later on DECsystem and DECstation 5000/50, /150 or /260 #with MIPS R4x00 processor. The "-mips3" switch generates R4000-specific #code, which is faster and more compact, but *won't* run on earlier #DECsystems and DECstations. ultrix43-mips3: @echo Making C-Kermit $(CKVER) for Ultrix 4.3A or later, R4000 cpu... $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD4 -DTCPSOCKET -DSIG_V -DNOGETUSERSHELL \ $(KFLAGS) -O2 -Olimit 1750 -mips3" "LNKFLAGS = -s -mips3" du43-mips3: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) ultrix43-mips3 #DEC Ultrix 4.3A or later on MIPS R4x000 based systems. #Like ultrix43-mips3 but with curses support added ultrix43c-mips3: @echo Making C-Kermit $(CKVER) for Ultrix 4.3A or later, R4000 cpu... $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD4 -DTCPSOCKET -DSIG_V -DNOGETUSERSHELL -DCK_CURSES \ $(KFLAGS) -O2 -Olimit 3000 -mips3" "LNKFLAGS = -s -mips3" \ "LIBS= -lcurses -ltermcap" du43c-mips3: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \ KTARGET=$${KTARGET-$(@)} ultrix43c-mips3 #DEC Ultrix 4.4 on DECstation 5000/50 or /150 with R4000 MIPS processor, #or 5000/260 with R4400. The "-mips3" switch generates R4000-specific code, #which is faster and more compact but *won't* run on earlier DECstations. ultrix44-mips3: @echo Making C-Kermit $(CKVER) for Ultrix 4.4, R4000 cpu ... $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD4 -DTCPSOCKET -DSIG_V -DNOGETUSERSHELL \ $(KFLAGS) -O2 -Olimit 1450 -mips3" "LNKFLAGS = -s -mips3" du44-mips3: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \ KTARGET=$${KTARGET-$(@)} ultrix44c-mips3 #DEC Ultrix 4.2 on DECstation, VAXstation, VAX, etc, System V R4 environment ultrix42s5r4: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4 on Ultrix...' $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS = -O2 -Olimit 1500 -DSVR4 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \ -DTCPSOCKET $(KFLAGS)" "LNKFLAGS = -s" #OSF/1 osf osf1: $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD4 -DOSF -D_BSD -DTCPSOCKET -DCK_ANSIC -DSIG_V \ -DCK_CURSES -DCK_RTSCTS -DFNFLOAT $(KFLAGS)" \ "LNKFLAGS = -s" "LIBS = $(LIBS) -lbsd -lcurses -ltermcap -lm" #DEC OSF/1 V1.0-1.3 on DECstation, VAX, Alpha, or PC. dec-osf dec-osf1: $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD4 -DOSF -DOSF13 -D_BSD -DTCPSOCKET -DCK_ANSIC -DSIG_V \ -DNOREALPATH -DNOIKSD -DCK_CURSES -DCK_RTSCTS -DFNFLOAT -DNODEBUG \ -DNOUNICODE $(KFLAGS)" \ "LNKFLAGS = -non_shared" "LIBS = -lbsd -lcurses -ltermcap -lm" # This one causes "relocation out-of-range" errors in the linker. old-dec-osf: @echo Making C-Kermit $(CKVER) for DEC OSF/1 V1.x... @echo If you are building for DEC OSF/1 2.0, please use dec-osf20. @echo Remove or adjust -O2 and/or -Olimit if they cause trouble. $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= -O2 -Olimit 2400 $(KFLAGS)" #DEC OSF/1 2.0 on Alpha and probably nowhere else. #The only difference from OSF/1 is that optimization is omitted. #The optimized version gets strange runtime errors, like the PAUSE command #not working. Add "-unsigned" to make all chars unsigned. dec-osf20: @echo Making C-Kermit $(CKVER) for DEC OSF/1 V2.0... @echo Optimization omitted because it causes runtime errors. @echo See comments in makefile. $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= -DOSF20 $(KFLAGS)" dec-osf30: @echo Making C-Kermit $(CKVER) for DEC OSF/1 V3.0... $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= -DOSF30 -O2 -Olimit 2400 $(KFLAGS)" #Digital UNIX 3.2 # Must compile ckuus[6x].c separately without optimization otherwise # the optimizer dumps core - keep CFLAGS here in sync with those from osf. du32: @echo Making C-Kermit $(CKVER) for Digital UNIX 3.2... $(MAKE) CC=$(CC) CC2=$(CC2) ckuus6.$(EXT) \ "CFLAGS= -DBSD4 -DOSF -D_BSD -DTCPSOCKET -DCK_ANSIC -DSIG_V \ -DCK_CURSES -DCK_RTSCTS -DFNFLOAT -DOSF32 -DHDBUUCP $(KFLAGS)" $(MAKE) CC=$(CC) CC2=$(CC2) ckuusx.$(EXT) \ "CFLAGS= -DBSD4 -DOSF -D_BSD -DTCPSOCKET -DCK_ANSIC -DSIG_V \ -DCK_CURSES -DCK_RTSCTS -DFNFLOAT -DOSF32 -DHDBUUCP $(KFLAGS)" $(MAKE) CC=$(CC) CC2=$(CC2) osf \ "KFLAGS= -DOSF32 -DHDBUUCP -O2 -Olimit 3200 $(KFLAGS)" dec-osf32: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) du32 \ KTARGET=$${KTARGET:-$(@)} #Digital UNIX 4.0 through 4.0D (use tru64 targets for 4.0E and above)... du40: @echo Making C-Kermit $(CKVER) for Digital UNIX 4.0... $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= -DOSF40 -DHDBUUCP -DFNFLOAT \ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)" "LIBS=-lm" du40gcc: @echo Making C-Kermit $(CKVER) for Digital UNIX 4.0 with gcc ... $(MAKE) osf CC=gcc CC2=gcc KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= -DOSF40 -DHDBUUCP $(KFLAGS)" #Tru64 Unix 4.0E tru64-40e: @echo Making C-Kermit $(CKVER) for Tru64 UNIX 4.0E... $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= -DOSF40 -DOSF40E -DTRU64 -DHDBUUCP -DFNFLOAT -DNOCOTFMC \ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)" "LIBS=-lm" tru64-40f: @echo Making C-Kermit $(CKVER) for Tru64 UNIX 4.0F... $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= -DOSF40 -DOSF40F -DTRU64 -DHDBUUCP -DFNFLOAT -DNOCOTFMC \ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)" "LIBS=-lm" tru64-40g: @echo Making C-Kermit $(CKVER) for Tru64 UNIX 4.0G... $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= -DOSF40 -DOSF40G -DTRU64 -DHDBUUCP -DFNFLOAT -DNOCOTFMC \ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)" "LIBS=-lm" tru64-50a: @echo Making C-Kermit $(CKVER) for Tru64 UNIX 5.0A... $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= -DTRU64 -DOSF50 -DHDBUUCP \ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)" tru64-51a: @echo Making C-Kermit $(CKVER) for Tru64 UNIX 5.1A... $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= -DTRU64 -DOSF50 -DOSF51A -DHDBUUCP \ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)" tru64-51b: @echo Making C-Kermit $(CKVER) for Tru64 UNIX 5.1B... $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= -DTRU64 -DOSF50 -DOSF51A -DOSF51B -DHDBUUCP \ -unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)" # Added 5.1b version with OpenSSL - CDW 6-13-2005... tru64-51b+openssl: @echo Making C-Kermit $(CKVER) for Tru64 UNIX 5.1b @echo including OpenSSL... $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= -DTRU64 -DOSF50 -DOSF51A -DOSF51B -DHDBUUCP \ -unsigned -std1 -O3 -Olimit 2400 \ -DCK_AUTHENTICATION -DCK_SSL $(SSLINC) $(KFLAGS)" \ "LIBS= $(SSLLIB) -rpath $(sslroot)/ssl/lib -lssl -lcrypto" du50: $(MAKE) CC=$(CC) CC2=$(CC2) tru64-50a KTARGET=$${KTARGET:-$(@)} du40-ridiculous-checking: @echo Making C-Kermit $(CKVER) for Digital UNIX 4.0. @echo Checking everything - assumes DECC... $(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= -DOSF40 -DHDBUUCP -w0 -warnprotos -check -portable \ -unsigned -std1 -O3 -Olimit 1760 $(KFLAGS)" #Sequent DYNIX/ptx 1.2.1 dynixptx12: @echo Making C-Kermit $(CKVER) for Sequent DYNIX/ptx 1.2.1... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -DPTX -DNOGETUSERSHELL -DNOLEARN \ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t $(KFLAGS) -i -O" \ "LNKFLAGS = -i" #Sequent DYNIX/ptx 1.3 or 1.4 dynixptx13: @echo Making C-Kermit $(CKVER) for Sequent DYNIX/ptx 1.3 TCP/IP... $(MAKE) xermit "CFLAGS= -O KTARGET=$${KTARGET:-$(@)} \ -DSVR3 -DDIRENT -DHDBUUCP -DPTX -DCK_POLL -DNOGETUSERSHELL \ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t -DTCPSOCKET $(KFLAGS) -i" \ "LNKFLAGS = -i" "LIBS = -lsocket -linet -lnsl" #Sequent DYNIX/ptx 2.0, ANSI C compilation #Should work on any hardware platform when DYNIX/ptx runs, including #386, 486, Pentium. dynixptx20: @echo 'Making C-Kermit $(CKVER) for POSIX, Sequent DYNIX/ptx 2.0...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DPOSIX -DHDBUUCP -DTCPSOCKET \ -DWAIT_T=int -DPTX -DNOGETUSERSHELL $(KFLAGS) -O" \ "LIBS = -lsocket -linet -lnsl" #Sequent DYNIX/ptx 2.0, ANSI C compilation, with curses dynixptx20c: @echo 'Making C-Kermit $(CKVER) for POSIX, Sequent DYNIX/ptx 2.0...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DPOSIX -DHDBUUCP -DTCPSOCKET -DWAIT_T=int -DPTX -DCK_CURSES \ -DCK_NEWTERM -DNOGETUSERSHELL $(KFLAGS) -O" \ "LIBS = -lsocket -linet -lnsl -lcurses -ltermcap" #Sequent DYNIX/ptx 2.1.6, 80486, ANSI C compilation, with curses: # -Xa -- use ANSI compiler. # -Wc,-pw -- suppress portability warnings. # -Wc,-i386 -- 80386 cpu. # -Wc,-i486 -- 80486 cpu. # -Wc,-P5 -- Pentium (default). # -Wc,-O3 -- highest optimization. # -Wa,-N17061 -- increase symbol table from default of 15013 for ckcuni.c. # Early versions of DYNIX/ptx 2.1.x may need -DCK_POLL instead of -DSELECT. # Add "$&" after the colon in the "xermit" target for parallel makes. dynixptx216c: @echo 'Making C-Kermit $(CKVER) for POSIX, Sequent DYNIX/ptx 2.1.6' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DPOSIX -DHDBUUCP -DDYNAMIC -DTCPSOCKET \ -DSELECT -DCK_REDIR -DCK_NAWS -DCK_WREFRESH -DSW_ACC_ID \ -DTCP_NODELAY=1 -DTRMBUFL=2048 -DBIGBUFOK -DHADDRLIST \ -DPTX -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL -DNOREALPATH \ $(KFLAGS) -Xa -Wc,-pw -Wc,-i486 -Wc,-O3 -Wa,-N17061" \ "LIBS = -lXbsd -lseq -lsocket -linet -lnsl -lmalloc -lm -lcurses" \ "LNKFLAGS = -s" #Sequent DYNIX/ptx 2.1.6, gcc 2.7.2.2, with curses: dynixptx216cgcc: @echo 'Making C-Kermit $(CKVER) for POSIX, Sequent DYNIX/ptx 2.1.6 gcc' $(MAKE) xermit "CC = gcc" "CC2 = gcc" KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DPOSIX -DHDBUUCP -DDYNAMIC -DTCPSOCKET \ -DSELECT -DCK_REDIR -DCK_NAWS -DCK_WREFRESH -DSW_ACC_ID \ -DTCP_NODELAY=1 -DTRMBUFL=2048 -DBIGBUFOK -DHADDRLIST \ -DPTX -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL -DNOREALPATH \ $(KFLAGS) -O3 -pipe -funsigned-char" \ "LIBS = -lXbsd -lseq -lsocket -linet -lnsl -lmalloc -lm -lcurses" \ "LNKFLAGS = -s" #Sequent DYNIX/ptx 4.0, ANSI C compilation, with curses dynixptx41c: @echo 'Making C-Kermit $(CKVER) for POSIX, Sequent DYNIX/ptx 4.0...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DPOSIX -DHDBUUCP -DTCPSOCKET \ -DWAIT_T=int -DPTX -DPTX4 -DCK_CURSES -DCK_NEWTERM \ -DNOGETUSERSHELL $(KFLAGS) -O" \ "LIBS = -lsocket -lnsl -lcurses -ltermcap" #Sequent DYNIX/ptx 4.4, ANSI C compilation, with curses dynixptx44: @echo 'Making C-Kermit $(CKVER) for POSIX, Sequent DYNIX/ptx 4.4...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DPTX -DPTX4 -DPOSIX -DHDBUUCP -DTCPSOCKET -DWAIT_T=int \ -DCK_CURSES -DCK_NEWTERM -DBIGBUFOK -DSELECT -DNOGETUSERSHELL \ $(KFLAGS) -O" "LIBS = -lsocket -lnsl -lcurses -ltermcap" #Sequent DYNIX 3.0.x dynix3: @echo Making C-Kermit $(CKVER) for Sequent DYNIX 3.0.x... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD43 -DACUCNTRL -DTCPSOCKET -O \ -DPWUID_T=int -DGID_T=int $(KFLAGS)" #Sequent DYNIX 3.0.x, no ACUCNTRL dynix3noacu: @echo Making C-Kermit $(CKVER) for Sequent DYNIX 3.0.x... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD43 -DLCKDIR -DTCPSOCKET -O \ -DUID_T=int -DGID_T=int $(KFLAGS)" #Sequent DYNIX 3.1.x dynix31: @echo Making C-Kermit $(CKVER) for Sequent DYNIX 3.1.x... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -O -DDCLPOPEN -DLCKDIR -DBSD4 -DTCPSOCKET $(KFLAGS)" #Sequent DYNIX 3.1.2, as above but with curses, to be compiled by gcc 2.3.3. dynix31c: @echo 'Making C-Kermit $(CKVER) for Sequent DYNIX 3.1.2, curses...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -O2 -DDCLPOPEN -DACUCNTRL \ -DBSD43 -DTCPSOCKET -DCK_CURSES -DUID_T=int \ $(KFLAGS)" "LIBS= -lcurses -ltermcap" #Convex C1 with Berkeley Unix convex: @echo Making C-Kermit $(CKVER) for Convex C1 / BSD... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD4 -DNOLEARN $(KFLAGS) -Dmsleep=mnap" #Convex C210 with Convex/OS 8 convex8: @echo Making C-Kermit $(CKVER) for Convex C210 with OS 8 $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD4 -DTCPSOCKET -DNODEBUG -DDIRENT -DNOFILEH \ $(KFLAGS) -DSIG_V -Dmsleep=mnap" #Convex C2 with Convex OS 9.1 (should also work with 8.1 or later) #with ANSI C compiler, uses BSD 4.3 uucp lockfile convention. convex9: @echo Making C-Kermit $(CKVER) for Convex C210 with OS 9.1 $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DPOSIX -DCONVEX9 -DNOIEXTEN -DDIRENT -DNOFILEH -DTCPSOCKET \ -D__STDC__ -DLCKDIR -Dmsleep=mnap -O -ext -tm c1 $(KFLAGS)" \ "LNKFLAGS = -ext" #Convex C2 with Convex OS 10.1 or later #with gcc 2.x C compiler convex10gcc: @echo Making C-Kermit $(CKVER) for Convex C2 with OS 10.1 using gcc $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DPOSIX -DCONVEX9 -DNOIEXTEN -DDIRENT -DNOFILEH -DTCPSOCKET \ -D__STDC__ -Dmsleep=mnap -O2 $(KFLAGS)" CC=gcc CC2=gcc #Cray X-MP or Y-MP UNICOS 6.x or 7.x. #NOTE: NPROC tells how many parallel makes to run. If your Cray has multiple #processors, you can set NPROC up to the number of CPUs, e.g. NPROC=16. cray: @echo 'Making C-Kermit $(CKVER) for Cray X/Y-MP UNICOS 6.x or 7.0... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} NPROC=1 \ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -DTCPSOCKET $(KFLAGS) -O1" #Cray X-MP or Y-MP UNICOS 8.0 Alpha. cray8: @echo 'Making C-Kermit $(CKVER) for Cray X/Y-MP UNICOS 8.0 Alpha... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} NPROC=1 \ "CFLAGS= -DSVR4 -DDIRENT -DHDBUUCP -DTCPSOCKET $(KFLAGS) -O1" #Cray X-MP or Y-MP UNICOS 9.0. #This one was executed successfully for C-Kermit 8.0.209. #Earlier versions of Unicos will probably need the same flags. cray9: @echo 'Making C-Kermit $(CKVER) for Cray X/Y-MP UNICOS 9.0... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} NPROC=1 \ "CFLAGS= -DSVR4 -DDIRENT -DHDBUUCP -DNOLFDEVNO \ -DTCPSOCKET $(KFLAGS) -O1" #Cray-2 or Cray 3-CSOS #NOTE: NPROC tells how many parallel makes to run. If your Cray has multiple #processors, you can set NPROC up to the number of CPUs, e.g. NPROC=16. craycsos: @echo 'Making C-Kermit $(CKVER) for Cray-2/3 CSOS $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} NPROC=1 \ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -DTCPSOCKET \ $(KFLAGS) -DCK_ANSIC -DCK_CURSES" "LIBS=-lnet" #NeXTSTEP 1.0 through 3.2. #Includes fullscreen file transfer display (curses) and TCP/IP support. #Uses shared library to make executable program about 80K smaller. #Remove "LIBS = -lsys_s" if this causes trouble. next: @echo Making C-Kermit $(CKVER) for NeXTSTEP... @echo 'If you get errors in ckutio.c about w_S, w_T, etc,' @echo 'add KFGLAGS=-DNOREDIRECT to your make command.' $(MAKE) xermit CC=$(CC) CC2=$(CC2) KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DNEXT -DTCPSOCKET -DLCKDIR -DNOPUTENV -DFNFLOAT \ -pipe -DCK_CURSES $(KFLAGS) -O -w" "LIBS = -lsys_s -lcurses -ltermcap" nextc: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) next \ KTARGET=$${KTARGET:-$(@)} nextg: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) next \ KFLAGS=-Wall KTARGET=$${KTARGET:-$(@)} nextgc: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) next \ KFLAGS=-Wall KTARGET=$${KTARGET:-$(@)} #NeXTSTEP 3.3. #Includes fullscreen file transfer display and TCP/IP. # You might have to add 1 line to 1 NeXT header file # to declare n_long as u_long by adding #include next33: @echo Making C-Kermit $(CKVER) for NeXTSTEP 3.3... $(MAKE) xermit CC=$(CC) CC2=$(CC2) KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DNEXT33 -DTCPSOCKET -DLCKDIR -DNOPUTENV -DFNFLOAT \ -pipe -DCK_CURSES $(KFLAGS) -O -w" "LIBS = -lsys_s -lcurses -ltermcap" #OPENSTEP 4.2 for Sparc, m680x0, HP PA-RISC, and Intel. #Includes fullscreen file transfer display and TCP/IP. openstep42: @echo Making C-Kermit $(CKVER) for OPENSTEP 4.2... $(MAKE) ckcpro.$(EXT) \ "CFLAGS= -DOPENSTEP42 -DNEXT33 -DTCPSOCKET -DLCKDIR -DNOPUTENV \ -DFNFLOAT -pipe -DCK_CURSES $(KFLAGS) -w" $(MAKE) xermit CC=$(CC) CC2=$(CC2) KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DOPENSTEP42 -DNEXT33 -DTCPSOCKET -DLCKDIR -DNOPUTENV \ -DFNFLOAT -pipe -DCK_CURSES $(KFLAGS) -O -w" \ "LIBS = -lsys_s -lcurses -ltermcap" #NeXT with malloc debugger nextmd: @echo Making C-Kermit $(CKVER) for NeXT with malloc debugging... $(MAKE) mermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DNEXT -DTCPSOCKET -DLCKDIR -DNOPUTENV -DFNFLOAT \ -DCK_CURSES $(KFLAGS) -O -w -Dmalloc=dmalloc -Dfree=dfree -DMDEBUG" \ "LIBS = -lsys_s -lcurses -ltermcap" #Build for NeXTSTEP with "fat" binaries (MABs) that run on both Motorola #and Intel platforms. nextfat: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \ next KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-Wall -arch m68k -arch i386" "LNKFLAGS = -arch m68k -arch i386" #NeXTSTEP on Intel Platforms. next486: @echo Making C-Kermit $(CKVER) for NeXTSTEP on Intel Platforms... @echo 'If you get errors in ckutio.c about w_S, w_T, etc,' @echo 'add KFGLAGS=D-DNOREDIRECT to your make command.' $(MAKE) xermit CC=$(CC) CC2=$(CC2) KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DNEXT -DTCPSOCKET -DLCKDIR -DNOPUTENV -DFNFLOAT \ -DNODEBUG -O3 -fno-omit-frame-pointer -fschedule-insns2 -pipe \ -DCK_CURSES $(KFLAGS) -w" "LIBS = -lsys_s -lcurses -ltermcap" #Single binary that runs on NeXT 68030 and 68040, Intel, HP, and Sparc, #as well as on OpenStep/Mach. nextquadfat: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) next \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-Wall -arch m68k -arch i386 -arch hppa -arch sparc" \ "LNKFLAGS = -arch m68k -arch i386 -arch hppa -arch sparc" #BeBox beboxdr7: @echo 'Making C-Kermit $(CKVER) for the BeBox...' @echo 'Link step will fail with default Metroworks linker 64K limit.' @echo 'Code Warrior Gold required to link big programs.' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CC=/boot/develop/tools/mwcc" "CC2=/boot/develop/tools/mwld" \ "CFLAGS= -DBEBOX -DBE_DR_7 -DPOSIX -DNOUUCP -DNOLEARN $(KFLAGS) -O" #BeBox BeOS DR7 only bebox: @echo 'Making C-Kermit $(CKVER) for BeBox...' @echo 'Link step will fail with default Metroworks linker 64K limit.' @echo 'Code Warrior Pro 3.0 for BeBox required to link big programs.' $(MAKE) wermit "CC=mwcc" "CC2=mwld" KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBEBOX -DPOSIX -DNOLEARN -DNOUUCP $(KFLAGS) -O" #BeOS 4.5 #We have to use the wermit target because 'fd_set' is unknown. beos45: $(MAKE) wermit "CC=$(CC)" "CC2=$(CC2)" KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBEOS -DBEOS45 -DPOSIX -DNOIKSD -DNOREALPATH -DSYSTIMEH \ -DNOCOTFMC -DNOUUCP -DNOLEARN $(KFLAGS) -O" \ "LIBS = $(LIBS)" #BeOS 4.5 beos45net: $(MAKE) CC=$(CC) CC2=$(CC2) beos45 \ "KFLAGS=-DTCPSOCKET -DNO_DNS_SRV $(KFLAGS)" "LIBS=-lnet -lnetapi" #Plan 9 from Bell Labs plan9: @echo 'C-Kermit for Plan 9 from Bell Labs - calling ckpker.mk...' make -f ckpker.mk #POSIX posix: @echo 'Making C-Kermit $(CKVER) for pure POSIX...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DPOSIX -DNOUUCP -DNOLEARN $(KFLAGS) -O" # PowerMAX OS (SVR4) from Concurrent (tested on PowerMAX 5.1) powermax: @echo 'Making C-Kermit $(CKVER) for Concurrent PowerMAX OS...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DPOWERMAX \ -DNETPTY -DHAVE_STREAMS -DHAVE_GRANTPT -DHAVE_PTSNAME -DPUSH_PTEM \ -DPUSH_LDTERM -DPUSH_TTCOMPAT \ -DSTERMIOX -DTCPSOCKET -DCK_CURSES $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lresolv -lcurses -lgen -lc -lucbc" #Berkeley Software Design Inc. BSDI # Substitute "LIBS= -lnewcurses -ltermcap" if desired. bsdi: @echo 'Making C-Kermit $(CKVER) for BSDI ...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD44 -DSETREUID -DSW_ACC_ID -DBIGBUFOK -DFIXCRTSCTS \ -DTCPSOCKET -DCK_CURSES -DFNFLOAT $(KFLAGS) -O" \ "LIBS= -lcurses -ltermcap -lm" #Berkeley Software Design Inc. BSDI - has higher serial speeds than 1.x. bsdi2: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) bsdi \ KTARGET=$${KTARGET:-$(@)} "KFLAGS=-DBSDI2 $(KFLAGS)" bsdi3: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) bsdi \ KTARGET=$${KTARGET:-$(@)} "KFLAGS=-DBSDI2 -DBSDI3 $(KFLAGS)" bsdi4: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) bsdi \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DBSDI2 -DBSDI3 -DBSDI4 -DTPUTSFNTYPE=void -DTPUTSISVOID \ -DCKHTTP -m486 $(KFLAGS)" # (old name for the above) bsdiposix: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) bsdi #Build a BSDI 4.x binary that also runs under FreeBSD (Terry Kennedy). #But watch out for details like serial-port locking. bsdix: $(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) bsdi \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DBSDI2 -DBSDI3 -DBSDI4 -DTPUTSFNTYPE=void -DTPUTSISVOID \ -m486 $(KFLAGS)" "LNKFLAGS=-static -Wl,-m,i386bsdi -Wl,-e,_start" #Pyramid 9XXX (e.g. 9845) or MIServer T series, OSx 4.4b thru 5.1 pyramid: @echo Making C-Kermit $(CKVER) for Pyramid Dual Port OSx ucb $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD43 -DTCPSOCKET -DPYRAMID -O $(KFLAGS)" "LNKFLAGS = -s" #Pyramid Dual Port OSx using HoneyDanBer UUCP, curses and TCP pyramid-hdb: @echo Making C-Kermit $(CKVER) for Pyramid Dual Port OSx ucb $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DBSD43 -DTCPSOCKET -DHBDUUCP -DCK_CURSES -O $(KFLAGS)" \ "LNKFLAGS = -s" "LIBS = -lcurses -ltermcap" #Pyramid DC/OSx (UNIX System V R4). #Has , regular Berkeley sockets library, i.e. in.h and inet.h #are not misplaced in sys (rather than netinet and arpa, respectively). #Uses ANSI C. #NOTE: Remove -O and Olimit:2500 from CFLAGS if TELNET connections do not work. pyrdcosx: @echo 'Making C-Kermit $(CKVER) for Pyramid DC/OSx...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -Xa -O -DSVR4 -DDIRENT -DHDBUUCP -DSELECT -DNOGETUSERSHELL \ -DCK_CURSES -DSTERMIOX -DTCPSOCKET -DPYRAMID -K Olimit:3100 \ -DNO_DNS_SRV $(KFLAGS)" "LIBS= -lcurses -lsocket -lnsl" "LNKFLAGS = -s" #IBM's AIX 3.0 on IBM 370 mainframe, tested on AIX F44 thru F50. aix370: @echo Making C-Kermit $(CKVER) for IBM System/370 AIX 3.0... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIX370 -DTCPSOCKET -DLCKDIR -DDIRENT $(KFLAGS)" \ "LIBS = -lbsd" #IBM's AIX/ESA 2.1 (OSF/1) on IBM mainframe aixesa: @echo Making C-Kermit $(CKVER) for IBM AIX/ESA... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIXESA -DTCPSOCKET $(KFLAGS) -O" #IBM PS/2 with AIX 1.0 thru 1.3. # Reports indicate that -O switch must be omitted. # It is also possible that "make bsd" will work (reports welcome). # One report said "make LIBS=-lbsd bsd" did the trick. # NOTLOG is to get around a 'tlog' symbol defined in one of the headers. ps2aix: @echo 'Making C-Kermit $(CKVER) for IBM AIX 1.x PS/2...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATTSV -DNOREALPATH -DPS2AIX10 -DSIG_V \ -DNOUNICODE -DNOTLOG -DNOLEARN $(KFLAGS) -i" \ "LNKFLAGS = -i" ps2aixnetc: @echo 'Making C-Kermit $(CKVER) for IBM AIX 1.x PS/2...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATTSV -DNOREALPATH -DPS2AIX10 -DTCPSOCKET -DCK_CURSES \ -DSIG_V -DNOUNICODE -DNOTLOG -DNOLEARN $(KFLAGS) -i" \ "LIBS = -lcurses" "LNKFLAGS = -i" ps2aix3: $(MAKE) ps2aix KTARGET=$${KTARGET:-$(@)} #IBM RT PC with AIX 2.2.1, valid as of C-Kermit 8.0. #NOTLOG because of a conflict in . #This one has unique and strange lockfiles. # -O removed on purpose (8.0). # In case of "compiler error: symbol table full", increase the -Nn number. # In case of "compiler error: Constant pool too big", boost the -Np number. # Add -DNOPUTENV if putenv() causes trouble. # Put -DNOIKSD back if IKSD-related problems occur. rtaix: @echo 'Making C-Kermit $(CKVER) for IBM RT PC, AIX 2.2.1...' $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS = -DATTSV -DRTAIX -DHDBUUCP -DDIRENT -DNOTLOG -DTCPSOCKET \ -DNOGETUSERSHELL -DCLSOPN -DNOREALPATH -DNOUNICODE -DBSD_INCLUDES \ -DUSE_LSTAT -DFNFLOAT -Nn2500 -Np1000 -Wq,-SJ2 -a -w $(KFLAGS)" \ "LIBS = -lm $(LIBS)" "LNKFLAGS = -s" #### IBM RT PC - these targets were last verified in C-Kermit 8.0.211. #IBM RT PC with AIX 2.2.1 + curses rtaixc: $(MAKE) rtaix CC=$(CC) CC2=$(CC2) "KFLAGS=-DCK_CURSES" "LIBS=-lcurses" #IBM RT PC with AIX (ACIS) 2.2.1 (BSD 4.3) # Add -O, -DDYNAMIC, -s, etc, if they work. rtacis: @echo Making C-Kermit $(CKVER) for RT PC with ACIS 2.2.1 = BSD 4.3... $(MAKE) xermit KTARGET=$${KTARGET-$(@)} \ "CFLAGS= -DBSD4 -DTCPSOCKET -DNOREALPATH -DNOIKSD -DNOPUTENV \ $(KFLAGS) -U__STDC__" "LNKFLAGS = -s" #### IBM AIX. The first two targets should work for any version of AIX #### from 4.2 onwards. The ones after that are for older versions or #### specific configurations, and/or with gcc. # This one should work for any AIX 4.2 or later: "make aix". # Other tags are for compatibility with old makefile targets. #OK: 2011/06/11 aix aix42 aix43 aix44 aix45 aix50 aix51 aix52 aix53 aix54 aix61: @echo Making C-Kermit $(CKVER) for IBM AIX... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIXRS -DAIX41 -DAIX42 -DSVR4 -DSTERMIOX -DTCPSOCKET \ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DFNFLOAT \ -DSELECT -DSELECT_H -DNOGETUSERSHELL -qmaxmem=16000 -O \ -DCKCPU=\\\"`uname -p`\\\" \ -DHERALD=\"\\\" IBM AIX `uname -v`.`uname -r`\\\"\" \ -D_LARGE_FILES $(KFLAGS)" "LNKFLAGS = -s" "LIBS=-lcurses -lm" # Same but using gcc instead of cc # This works but we get "gcc: unrecognized option '-qmaxmem-..'" each module. aixg: @echo "Using gcc..." $(MAKE) aix KTARGET=$${KTARGET:-$(@)} \ CC=gcc CC2=gcc "KFLAGS=-pipe -funsigned-char" # AIX 4.2 or later with OpenSSL 0.9.7 or later: "make aix+ssl" # For earlier OpenSSL remove -DOPENSSL_097 or add "KFLAGS=-UOPENSSL_097". # Synonym target names added to cover old redundant targets that were removed. # If SSL is not installed in the /usr/local tree (see SSLINC and SSLLIB # definitions near the top), you can specify the locations in your make # command as in this example: # # SSLINC=-I/opt/ssl/include SSLLIB=-L/opt/ssl/lib make -e aix+ssl # # To build with gcc use "make aix CC=gcc CC2=gcc", or "make aixg" # #OK: 2011/06/15 aix+ssl aix51+openssl aix52+openssl aix53+openssl: @echo "Making C-Kermit $(CKVER) for IBM AIX with OpenSSL..." @echo "SSLINC=$(SSLINC) SSLLIB=$(SSLLIB)" $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ CC=$(CC) CC2=$(CC2) \ "CFLAGS=-DAIXRS -DAIX41 -DAIX42 -DSVR4 -DSTERMIOX -DTCPSOCKET \ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DFNFLOAT \ -D_LARGE_FILES -DSELECT -DSELECT_H -DNOGETUSERSHELL \ -DCKCPU=\\\"`uname -p`\\\" \ -DHERALD=\"\\\" IBM AIX `uname -v`.`uname -r`\\\"\" \ -DCK_AUTHENTICATION -DCK_SSL -DOPENSSL_097 $(SSLINC) $(KFLAGS)" \ "LNKFLAGS=-s" "LIBS=$(SSLLIB) -lssl -lcrypto -lcurses -lm -lcrypt" # AIX 5.3 or 6.1 or later with IBM OpenSSL, which is always in the directories # shown below so you don't have to set SSLINC and SSLLIB. If for some reason # the SSL include files and libraries are not in the places assumed, then use # "make aix+ssl" (just above) and set SSLINC and SSLLIB to indicate where the # SSL files are. To build with gcc use "make aix+ibmssl CC=gcc CC2=gcc". aix+ibmssl: @echo "Making C-Kermit $(CKVER) for IBM AIX 6.1 with OpenSSL..." @echo "If this fails use 'make aix+ss' and specify SSLINC and SSLLIB" $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ CC=$(CC) CC2=$(CC2) \ "CFLAGS=-DAIXRS -DAIX41 -DAIX42 -DSVR4 -DSTERMIOX -DTCPSOCKET \ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DFNFLOAT \ -D_LARGE_FILES -DSELECT -DSELECT_H -DNOGETUSERSHELL \ -DCKCPU=\\\"`uname -p`\\\" \ -DHERALD=\"\\\" IBM AIX `uname -v`.`uname -r`\\\"\" \ -DCK_AUTHENTICATION -DCK_SSL -DOPENSSL_098 \ -I/usr/include/openssl $(KFLAGS)" \ "LNKFLAGS=-s" \ "LIBS=-L/usr/lib/openssl -lssl -lcrypto -lcurses -lm -lcrypt" # Old AIX versions... #IBM AIX 3.0, 3.1, or 3.2 for RISC System/6000. rs6000: @echo Making C-Kermit $(CKVER) for IBM AIX 3.0 or 3.1, RS/6000... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIXRS -DTCPSOCKET -DSVR3 -DDIRENT -DCK_ANSIC \ -DCK_POLL -DCLSOPN -DSELECT_H -DNOTTYLOCK -O $(KFLAGS)" \ "LNKFLAGS = -s" #IBM AIX 3.0, 3.1, or 3.2 for RISC System/6000, with curses. rs6000c: @echo Making C-Kermit $(CKVER) for IBM AIX 3.0 or 3.1, RS/6000... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIXRS -DTCPSOCKET -DSVR3 -DDIRENT -DCK_ANSIC \ -DCK_POLL -DCLSOPN -DCK_CURSES -DSELECT_H -DNOTTYLOCK -DNOREALPATH \ -O $(KFLAGS)" "LIBS= -lcurses -ltermcap" "LNKFLAGS = -s" aix30: $(MAKE) rs6000 CC=$(CC) CC2=$(CC2) KTARGET=$${KTARGET:-$(@)} aix31: $(MAKE) rs6000 CC=$(CC) CC2=$(CC2) KTARGET=$${KTARGET:-$(@)} #IBM AIX 3.2 for RISC System/6000. #In case of "subprogram too complex" warnings, add "-qmaxmem=16000" to CFLAGS. rs6aix32: @echo Making C-Kermit $(CKVER) for IBM AIX 3.2, RS/6000... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIXRS -DTCPSOCKET -DSVR4 -DDIRENT -DCK_ANSIC -DNOREALPATH \ -DSELECT_H -DCLSOPN -DNOTTYLOCK -O $(KFLAGS)" "LNKFLAGS = -s" #IBM AIX 3.2 for RISC System/6000. rs6aix32c: @echo Making C-Kermit $(CKVER) for IBM AIX 3.2, RS/6000, TCP+curses... @echo In case of Subprogram Too Complex warnings, @echo add -qmaxmem=16000 to CFLAGS. $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIXRS -DTCPSOCKET -DSVR4 -DDIRENT -DCK_ANSIC -DNOREALPATH \ -DCLSOPN -DCK_CURSES -DSELECT_H -DNOTTYLOCK -O $(KFLAGS)" \ "LNKFLAGS = -s" "LIBS=-lcurses" aix32: $(MAKE) rs6aix32c KTARGET=$${KTARGET:-$(@)} #IBM AIX 4.1, 4.1.x on RISC System/6000 or Power Series. #Generates common binary for all platforms if using xlc (IBM C compiler). #When using gcc, add -mcpu=common to generate common binary. #Note that this one needs CK_NEWTERM. # Add -bbigtoc in case ld fails with TOC overflow. aix41: @echo Making C-Kermit $(CKVER) for IBM AIX 4.1.1 RS/6000 or PowerPC... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIXRS -DAIX41 -DSVR4 -DSTERMIOX -DTCPSOCKET -DDIRENT \ -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DSELECT -DSELECT_H \ -DNOGETUSERSHELL -qmaxmem=16000 -O $(KFLAGS)" \ "LNKFLAGS = -s" "LIBS=-lcurses" #Ditto but with gcc. #Remove "CC=gcc CC2=gcc" if you have gcc installed as cc. aix41g: @echo Making C-Kermit $(CKVER) for IBM AIX 4.1.1 RS/6000 or PowerPC... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC=gcc" "CC2=gcc" \ "CFLAGS= -DAIXRS -DAIX41 -DSVR4 -DSTERMIOX -DTCPSOCKET -DDIRENT \ -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DSELECT -DSELECT_H \ -DNOGETUSERSHELL -O $(KFLAGS)" \ "LNKFLAGS = -s -Xlinker -bbigtoc" "LIBS=-lcurses" # Add -bbigtoc in case ld fails with TOC overflow. aix41+krb5+krb4: @echo Making C-Kermit $(CKVER) for IBM AIX 4.1.1 RS/6000 or PowerPC... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIXRS -DAIX41 -DSVR4 -DSTERMIOX -DTCPSOCKET -DDIRENT \ -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DSELECT -DSELECT_H \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_DES $(K5INC) $(K5INC)/krb5 \ -DNOGETUSERSHELL -qmaxmem=16000 -O $(KFLAGS)" \ "LNKFLAGS = -s" \ "LIBS = $(K5LIB) -lcurses -lkrb4 -ldes425 -lkrb5 \ -lcom_err -lk5crypto -lgssapi_krb5" #Old name for "aix41". rs6aix41c: $(MAKE) aix41 KTARGET=$${KTARGET:-$(@)} #IBM AIX 4.1, 4.1.x, or 4.2 on RISC System/6000 or Power Series, # with X.25 support #Generates common binary for all platforms if using xlc (IBM C compiler). #When using gcc, add -mcpu=common to generate common binary. # Add -bbigtoc in case ld fails with TOC overflow. aix41x25: @echo Making C-Kermit $(CKVER) for IBM AIX 4.1.1 RS/6000 or PowerPC... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIXRS -DAIX41 -DSVR4 -DSTERMIOX -DTCPSOCKET -DDIRENT \ -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DSELECT -DSELECT_H \ -DIBMX25 -DDEBUG -DNOGETUSERSHELL -qmaxmem=16000 -g $(KFLAGS)" \ "LNKFLAGS = -g -bI:/lib/pse.exp" "LIBS=-lcurses -lodm -lcfg" -@echo "]0;kermit done\c" #As above but without -g in LNKFLAGS. # Add -bbigtoc in case ld fails with TOC overflow. aix41x25o: @echo Making C-Kermit $(CKVER) for IBM AIX 4.1.1 RS/6000 or PowerPC... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIXRS -DAIX41 -DSVR4 -DSTERMIOX -DTCPSOCKET -DDIRENT \ -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DSELECT -DSELECT_H \ -DIBMX25 -DNODEBUG -DNOGETUSERSHELL -qmaxmem=16000 $(KFLAGS)" \ "LNKFLAGS = -bI:/lib/pse.exp" "LIBS=-lcurses -lodm -lcfg" -@echo "]0;kermit done\c" #AIX 4.2 -- Use this target if the regular "make aix" doesn't work. # Must have CK_NEWTERM or echoing is lost after curses. # Add -bbigtoc in case ld fails with TOC overflow. As of C-Kermit 8.0.212, # all AIX builds 4.2 and later include large file support. oldaix42: @echo Making C-Kermit $(CKVER) for IBM AIX 4.2 or higher... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIXRS -DAIX41 -DAIX42 -DSVR4 -DSTERMIOX -DTCPSOCKET \ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DCK_NEWTERM -DFNFLOAT \ -DSELECT -DSELECT_H -DNOGETUSERSHELL -qmaxmem=16000 -O \ -DCKCPU=\\\"`uname -p`\\\" \ -DHERALD=\\\"\ IBM\ AIX\ `uname -v`.`uname -r`\\\" \ -D_LARGE_FILES $(KFLAGS)" "LNKFLAGS = -s" "LIBS=-lcurses -lm" #AIX 4.3 - Use this target if the regular "make aix" doesn't work. # Must NOT have CK_NEWTERM or else C-Kermit hangs after curses. # -bbigtoc needed on some systems but not others to avoid TOC overflow. # "man ld" says -bbigtoc makes program run slower. oldaix43: @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 or higher... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIXRS -DAIX41 -DAIX43 -DSVR4 -DSTERMIOX -DTCPSOCKET \ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \ -DFNFLOAT -DNOGETUSERSHELL -qmaxmem=16000 -bbigtoc -O $(KFLAGS)" \ "LNKFLAGS = -s" "LIBS=-lcurses -lm" #AIX 4.3 with IBM X.25. aix43x25: @echo "Making C-Kermit $(CKVER) for IBM AIX 4.3 with X.25..." $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DAIXRS -DAIX41 -DAIX43 -DSVR4 -DSTERMIOX -DTCPSOCKET \ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \ -DFNFLOAT -DNOGETUSERSHELL -DIBMX25 \ -qmaxmem=16000 -bbigtoc -O $(KFLAGS)" \ "LNKFLAGS = -bI:/lib/pse.exp" "LIBS=-lcurses -lodm -lcfg -lm" #AIX 4.3 -- Must NOT have CK_NEWTERM or else C-Kermit hangs after curses. # -mminimal-toc needed on some systems but not others to avoid TOC overflow. # "man ld" says -bbigtoc makes program run slower. aix43g: @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 gcc... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL $(KFLAGS)" \ "LIBS=-lcurses -lm" aix43gcc: $(MAKE) aix43g # None of the following aix43gcc attempts work on a gcc-only AIX 4.3.3 box. # It just plain can't find the math routines (fmod, pow, exp, sqrt, log10,...) # Which is odd because nm /usr/lib/libC.a finds them... #in case aix43gcc can't find its math library... aix43gccx: @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 gcc... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL $(KFLAGS)" \ "LIBS= -L/usr/local/lib/gcc-lib/powerpc-ibm-aix4.3.1.0/2.95.2 \ -lcurses -bloadmap -bnoquiet" #in case aix43gccx can't find its math library... aix43gccy: @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 gcc... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL $(KFLAGS)" \ "LIBS= -lcurses -bloadmap -bnoquiet" #in case aix43gccx can't find its math library... aix43gccz: @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 gcc... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL $(KFLAGS)" \ "LIBS= -L. -lcurses -bloadmap -bnoquiet" #AIX 4.3 with MIT Kerberos 5 and Kerberos 4 compatibility mode # Must NOT have CK_NEWTERM or else C-Kermit hangs after curses. # -mminimal-toc needed on some systems but not others to avoid TOC overflow. # "man ld" says -bbigtoc makes program run slower. aix43gcc+krb5+krb4: @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 or higher w/Kerberos... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_DES -funsigned-char $(K5INC) $(K5INC)/krb5 \ $(KFLAGS)" \ "LIBS=$(K5LIB) -lcurses -lm -lkrb4 -ldes425 -lkrb5 \ -lcom_err -lk5crypto -lcrypt -lgssapi_krb5" #AIX 4.3 with MIT Kerberos 5, Kerberos 4 compatibility mode and OpenSSL # Must NOT have CK_NEWTERM or else C-Kermit hangs after curses. # -mminimal-toc needed on some systems but not others to avoid TOC overflow. # "man ld" says -bbigtoc makes program run slower. aix43gcc+krb5+krb4+openssl: @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 or higher w/Kerberos... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_DES -DCK_CAST -DLIBDES -DCK_SSL \ -funsigned-char $(K5INC) $(K5INC)/krb5 $(SSLINC) $(KFLAGS)" \ "LIBS=$(K5LIB) $(SSLLIB) -lssl -lcrypto \ -lcurses -lm -lkrb4 -ldes425 -lkrb5 -lcom_err -lk5crypto -lcrypt \ -lgssapi_krb5" aix43gcc+openssl: @echo Making C-Kermit $(CKVER) for IBM AIX 4.3 or higher w/OpenSSL... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS= -mminimal-toc -g -O -DAIXRS -DAIX41 -DAIX43 -DSVR4 \ -DDIRENT -DCK_ANSIC -DCLSOPN -DCK_CURSES -DSELECT -DSELECT_H \ -DSTERMIOX -DTCPSOCKET -DFNFLOAT -DNOGETUSERSHELL \ -DCK_AUTHENTICATION -DCK_SSL -funsigned-char $(SSLINC) $(KFLAGS)" \ "LIBS=$(SSLLIB) -lssl -lcrypto -lcurses -lm -lcrypt" aix44gcc: $(MAKE) aix43g "KFLAGS=-DAIX44 $(KFLAGS)" \ KTARGET=$${KTARGET:-$(@)} aix45gcc: $(MAKE) aix43g "KFLAGS=-DAIX45 $(KFLAGS)" \ KTARGET=$${KTARGET:-$(@)} aix50gcc: $(MAKE) aix43g "KFLAGS=-DAIX50 $(KFLAGS)" \ KTARGET=$${KTARGET:-$(@)} aix51gcc: $(MAKE) aix43g "KFLAGS=-DAIX51 $(KFLAGS)" \ KTARGET=$${KTARGET:-$(@)} aix52gcc: $(MAKE) aix43g "KFLAGS=-DAIX52 $(KFLAGS)" \ KTARGET=$${KTARGET:-$(@)} aix53gcc: $(MAKE) aix43g "KFLAGS=-DAIX53 $(KFLAGS)" \ KTARGET=$${KTARGET:-$(@)} #Bull DPX/2 with BOS/X, like AIX/RS6000 bulldpx2: @echo Making C-Kermit $(CKVER) for Bull DPX/2 with BOS/X... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DSVR3 -DDIRENT -DCK_ANSIC -DCKTYP_H= \ -DCK_POLL -DNOGETUSERSHELL -DCLSOPN -DNOLEARN -O $(KFLAGS)" \ "LNKFLAGS = -s" #Sun UNIX 3.5 with gcc 2.3.3. sunos3gcc: @echo Making C-Kermit $(CKVER) for Sun UNIX 3.5 and gcc... $(MAKE) xermit CC=gcc CC2=gcc KTARGET=$${KTARGET:-$(@)} \ CFLAGS="-g -O -DBSD4 -DTCPSOCKET $(KFLAGS)" #SunOS version 4.0, BSD environment, has saved original euid feature. # Add "CC=/usr/ucb/cc CC2=/usr/ucb/cc" if necessary. # Note: Including Unicode crashes the assembler in ckcuni.c. sunos4: @echo Making C-Kermit $(CKVER) for SunOS 4.0, BSD environment... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -O -DSUNOS4 -DFNFLOAT -DNOUNICODE $(KFLAGS)" \ "LIBS=-lm" #As above, but with SunLink X.25 support sunos4x25: @echo SunLink X.25 support $(MAKE) "MAKE=$(MAKE)" sunos4 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(KFLAGS) -DFNFLOAT -DSUNX25" \ "LIBS=-lm" #SUN OS version 4.1 - 4.1.3, BSD environment, has saved original euid feature. #Uses Honey DanBer UUCP. Requires presence of /usr/spool/locks directory. # /var/spool/ should be a symbolic link to /usr/spool/. # ... or 'make xermit "CC= /usr/ucb/cc " \' # Uses bundled Sun C compiler, pre-ANSI, no version number. # Note: "xermit" means use the select() version of the CONNECT module. # Note2: ckutio.c includes both and and these # two header files each define the same symbols: ECHO, NL0, NL1, TAB0, etc, # because the #define's aren't enclosed in #indef ECHO..#endif, etc. # The warnings are unavoidable but harmless. Last built: 27 October 2022. sunos41: @echo Making C-Kermit $(CKVER) for SunOS 4.1 / BSD... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNOUNICODE $(KFLAGS)" \ "LIBS= $(LIBS) -lresolv -lm" #As above, but compiled with gcc. Gives 24-32K size reduction #with gcc 2.1 or 2.2.2. CAUTION: make sure "fixincludes" has been run on #the include files, so gcc's are in sync with the regular Sun ones. #This includes the curses library for fullscreen file transfer display. #NDGPWNAM needed for GCC 2.5.6, not needed for 2.4.0, but it's uncertain #whether it will do any harm for 2.4.0 compilation -- if so, remove it. sunos41gcc: @echo Making C-Kermit $(CKVER) for SunOS 4.1 with gcc and curses... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \ -funsigned-char $(KFLAGS)" "LIBS= -lcurses -ltermcap -lresolv -lm" # As above, but without -funsigned-char so I can see the warnings that # everybody else will get when they use ANSI compilers that don't have this # option (gsc = gcc signed char). sunos41gsc: @echo Making C-Kermit $(CKVER) for SunOS 4.1 with gcc and curses... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \ $(KFLAGS)" "LIBS= -lcurses -ltermcap -lresolv -lm" #As above but with ckucon.c rather than ckucns.c (for testing only) sunos41gccfork: @echo Making C-Kermit $(CKVER) for SunOS 4.1 with gcc and curses... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \ -DNOLEARN -funsigned-char $(KFLAGS)" \ "LIBS= -lcurses -ltermcap -lresolv -lm" #as above but configured for Kerberos IV sunos41gcc+krb4: @echo Making C-Kermit $(CKVER) for SunOS 4.1, gcc, curses, krb4... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \ -DTCPSOCKET -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB4 \ -DCK_ENCRYPTION -DCK_DES -DCK_CAST -DBIGBUFOK -funsigned-char \ $(K4INC) $(KFLAGS)" \ "LIBS= $(K4LIB) -lcurses -ltermcap -lresolv -lm -lkrb -ldes" #as above but configured for SSL/TLS sunos41gcc+openssl: @echo Making C-Kermit $(CKVER) for SunOS 4.1, gcc, curses, ssl... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \ -DCK_AUTHENTICATION -funsigned-char \ -DCK_SSL -DTCPSOCKET -DBIGBUFOK $(SSLINC) $(KFLAGS)" \ "LIBS= $(SSLLIB) -lcurses -ltermcap -lresolv -lm -lssl -lcrypto" #as above but configured for Kerberos IV and SSL/TLS sunos41gcc+krb4+openssl: @echo Making C-Kermit $(CKVER) for SunOS 4.1, gcc, curses, krb4... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB4 -DCK_ENCRYPTION -DCK_DES \ -DCK_CAST -DCK_SSL -DLIBDES -DTCPSOCKET -DBIGBUFOK -funsigned-char \ $(K4INC) $(SSLINC) $(KFLAGS)" \ "LIBS= $(K4LIB) $(SSLLIB) \ -lcurses -ltermcap -lresolv -lm -lkrb -lssl -lcrypto" #as above but configured for Kerberos IV and ZLIB enabled SSL/TLS sunos41gcc+krb4+openssl+zlib: @echo Making C-Kermit $(CKVER) for SunOS 4.1, gcc, curses, krb4... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB4 -DCK_ENCRYPTION -DCK_DES \ -DCK_CAST -DCK_SSL -DLIBDES -DTCPSOCKET -DBIGBUFOK -funsigned-char \ -DZLIB $(K4INC) $(SSLINC) \ $(KFLAGS)" \ "LIBS= $(K4LIB) $(SSLLIB) \ -lcurses -ltermcap -lresolv -lm -lkrb -lssl -lcrypto -lz" #as above but configured for Kerberos IV and SRP and ZLIB enabled SSL/TLS sunos41gcc+krb4+srp+openssl+zlib: @echo "C-Kermit $(CKVER) SunOS 4.1: gcc,curses,krb4,srp,ssl,zlib..." $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB4 -DCK_ENCRYPTION -DCK_DES \ -DCK_CAST -DCK_SSL -DLIBDES -DTCPSOCKET -DBIGBUFOK -funsigned-char \ -DZLIB -DCK_SRP $(K4INC) $(SRPINC) $(SSLINC) $(KFLAGS)" \ "LIBS= $(K4LIB) $(SRPLIB) $(SSLLIB) \ -lcurses -ltermcap -lresolv -lm -lkrb -lkrypto \ -lsrp -lssl -lcrypto -lz" #as above but configured for Kerberos IV and SRP and ZLIB enabled SSL/TLS sunos41gcc+srp+openssl+zlib: @echo "C-Kermit $(CKVER) SunOS 4.1: gcc,curses,srp,ssl,zlib..." $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNDGPWNAM -DCK_CURSES -DFNFLOAT \ -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_DES \ -DCK_CAST -DCK_SSL -DLIBDES -DTCPSOCKET -DBIGBUFOK -funsigned-char \ -DZLIB -DCK_SRP $(SRPINC) $(SSLINC) \ $(KFLAGS)" \ "LIBS= $(SRPLIB) $(SSLLIB) \ -lcurses -ltermcap -lresolv -lm -lkrypto -lsrp -lssl -lcrypto -lz " #SUNOS 4.1 as sunos41 above, but also with curses support sunos41c: @echo Curses support $(MAKE) "MAKE=$(MAKE)" sunos41 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(KFLAGS) -DCK_CURSES -DFNFLOAT " \ "LIBS= -lcurses -ltermcap" #As SunOS 4.1.x, gcc, configured as Internet Kermit Server. # . NOLOCAL removes capability to make connections # . TNCODE allows server-side Telnet negotiation. # . used to include -lpwent, why? # . used to include -L/usr/local/lib -lm, why? sunos41giks: @echo Making C-Kermit $(CKVER) for SunOS 4.1 with gcc for IKS... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc" "CC2= gcc" \ "CFLAGS= -O -DSUNOS41 -DNDGPWNAM -DFNFLOAT \ -DNOLOCAL -DTCPSOCKET -DTNCODE -DNOPUSH $(KFLAGS)" \ "LIBS= -lm -lresolv" #SUNOS 4.1 with SunLink X.25 support sunos41x25: @echo SunLink X.25 support $(MAKE) "MAKE=$(MAKE)" wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNOUNICODE -DFNFLOAT -DSUNX25 \ -DNOLEARN $(KFLAGS)" "LIBS= $(LIBS) -lresolv -lm" #SUNOS 4.1 with SunLink X.25 support and curses sunos41x25c: @echo SunLink X.25 support + curses $(MAKE) "MAKE=$(MAKE)" wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DNOUNICODE -DFNFLOAT -DSUNX25 \ -DCK_CURSES -DNOLEARN $(KFLAGS)" \ "LIBS= $(LIBS) -lcurses -ltermcap -lresolv -lm" #SUN with Solaris 2.0 = SunOS 5.0. #Mostly the same as System V R4. Don't use this with later Solaris versions. solaris20: @echo 'Making C-Kermit $(CKVER) for Sun with Solaris 2.0 and curses...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DSOLARIS -DDIRENT -DHDBUUCP -DSTERMIOX \ -DTCPSOCKET -DCK_CURSES -DFNFLOAT -DCK_POLL $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lcurses -ltermlib -lm" "LNKFLAGS = -s" #SUN with Solaris 2.0. #As above, but built with the gcc compiler from the Cygnus CD-ROM. solaris20g: @echo 'Making C-Kermit $(CKVER) for Sun Solaris 2.0, gcc, and curses..' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DSOLARIS -DDIRENT -DHDBUUCP -DSTERMIOX \ -DTCPSOCKET -DCK_CURSES -DCK_POLL -DFNFLOAT $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lcurses -ltermlib -lm" "LNKFLAGS = -s" \ CC=/opt/cygnus-sol2-1.1/bin/gcc CC2=/opt/cygnus-sol2-1.1/bin/gcc #SunOS 5.1 = Solaris 2.1. #NOTE: A C compiler is no longer bundled with SunOS 5.1, so to compile C #programs, you might have to change your PATH to include the directory #/usr/ccs/bin AFTER the directory containing the compiler. SunPRO C is #installed by default in /opt/SUNWspro/bin. So a sample PATH might be: # # /usr/local/bin:/usr/bin:/opt/SUNWspro/bin:/usr/ccs/bin:\ # /usr/ucb:/usr/sbin:/sbin:. # # or: # # /usr/openwin/bin:/export/home/SUNWspro/bin:/usr/ccs/bin:/usr/sbin:/usr/bin. # #NOTE 2: Compilation with the Apogee C compiler (apcc) might not work, #because it refuses to allow "-Usun". Reportedly, newer releases of apcc #(such as 1.2.17) work OK, use: "make -e sunos51 CC=apcc CC2=apcc". solaris21: @echo 'Making C-Kermit $(CKVER) for SunOS 5.x....' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -Usun -DSVR4 -DSOLARIS -DDIRENT -DHDBUUCP -DFNFLOAT \ -DSELECT -DNODEBUG -DSTERMIOX $(KFLAGS)" "LIBS = -lm" "LNKFLAGS = -s" #Solaris 2.0 - 2.4, SunPro compiler, includes curses and TCP/IP. #When using SUNWspro CC 2.0.1 under Solaris 2.3, be sure all cc patches #are applied, otherwise corrupt or truncated object files can result. #To build, set your PATH as follows: # /usr/local/bin:/usr/bin:/opt/SUNWspro/bin:/usr/ccs/bin:\ # /usr/ucb:/usr/sbin:/sbin:. # or (depending on where the compiler has been installed): # /usr/openwin/bin:/export/home/SUNWspro/bin:/usr/ccs/bin:/usr/sbin:/usr/bin. #For additional optimization try using "-fast -xO4 -xdepend". solaris2x: @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with SunPro cc...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -Usun -i -DSVR4 -DDIRENT -DSOLARIS -DHDBUUCP -DFNFLOAT \ -DSELECT -DCK_CURSES -DCK_NEWTERM -DSTERMIOX -DTCPSOCKET $(KFLAGS)" \ "LNKFLAGS = -s" "LIBS= -ltermlib -lsocket -lnsl -lm -lresolv" #as above but configured for Kerberos IV solaris2x+krb4: @echo 'Making C-Kermit $(CKVER) for Solaris 2.x, SunPro cc, krb4...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -Usun -i -DSVR4 -DDIRENT -DSOLARIS -DHDBUUCP -DFNFLOAT \ -DSELECT -DCK_CURSES -DCK_NEWTERM -DSTERMIOX -DTCPSOCKET \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB4 \ -DCK_ENCRYPTION -DCK_DES -DCK_CAST $(K4INC) $(KFLAGS)" \ "LNKFLAGS = -s" \ "LIBS= $(K4LIB) -ltermlib -lsocket -lnsl -lm -lresolv -lkrb -ldes" #C-Kermit for Solaris 2.0-2.4 compiled with gcc, includes curses and TCP/IP. #Change -O2 to -O if -O2 gives trouble. #Remove -Usun if it causes trouble. #Your PATH should start with something like: # /usr/local/gnu/bin:/usr/ccs/bin: #Produces a huge executable -- strip with /usr/ccs/bin/strip (not Gnu strip). #Also don't add "LNKFLAGS = -s" -- strip manually instead. #Also note: this can NOT be linked statically - Sun makes it impossible. #And for Solaris 2.4, you might have to replace: # /usr/local/lib/gcc-lib/i486-sun-solaris2/2.4.5/include/sys/stat.h #with /usr/include/sys/stat.h. solaris2xg: @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with GNU cc...' @echo 'Please read the comments that accompany the solaris2xg target.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET $(KFLAGS)" \ "LIBS= -ltermlib -lsocket -lnsl -lm -lresolv $(LIBS)" #ditto but no curses. solaris2xgnc: @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with GNU cc...' @echo 'Please read the comments that accompany the solaris2xg target.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \ -DDIRENT -DHDBUUCP -DTCPSOCKET $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lm -lresolv $(LIBS)" #and with Kerberos IV solaris2xg+krb4: @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with GNU cc, krb4...' @echo 'Please read the comments that accompany the solaris2xg target.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB4 -DCK_ENCRYPTION \ -DCK_DES -DCK_CAST -DBIGBUFOK $(K4INC) $(KFLAGS)" \ "LIBS= $(K4LIB) -ltermlib -lsocket -lnsl -lm -lresolv -lkrb -ldes \ $(LIBS)" #and with OpenSSL,ZLIB,PAM,SHADOW solaris2xg+openssl+zlib+pam+shadow: @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with gcc, OpenSSL...' @echo 'Please read the comments that accompany the solaris2xg target.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \ -DCK_AUTHENTICATION -DCK_SSL -DCK_PAM -DCK_SHADOW -DZLIB \ -DBIGBUFOK $(SSLINC) $(KFLAGS)" \ "LIBS= $(SSLLIB) -ltermlib \ -lsocket -lnsl -lm -lresolv -lssl -lcrypto -lpam -lz" #Ditto but with GCC 3.1 in which you have to specify 32-bit with -m32. #In Solaris 9 (and maybe 8) you'll also need specifiy the Library path. #Reportedly this can be done here, but only with: # crle -l /usr/lib:/usr/local/ssl/lib #prior to building. Note: 64-bit not tested with SSL. #For no-crypto 64-bit builds see the solaris9g64 target. solaris2xg32+openssl+zlib+pam+shadow: @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with gcc, OpenSSL...' @echo 'Please read the comments that accompany the solaris2xg target.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC="gcc -m32" CC2="gcc -m32" \ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \ -DCK_AUTHENTICATION -DCK_SSL -DCK_PAM -DCK_SHADOW -DZLIB \ -DBIGBUFOK $(SSLINC) $(KFLAGS)" \ "LIBS= $(SSLLIB) -ltermlib \ -lsocket -lnsl -lm -lresolv -lssl -lcrypto -lpam -lz" #and with Krb5,Krb4,OpenSSL,SHADOW solaris2xg+krb5+krb4+openssl+shadow: @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with gcc,k5,k4,ssl...' @echo 'Please read the comments that accompany the solaris2xg target.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS = -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_SSL -DCK_DES -DCK_CAST -DBIGBUFOK \ $(K5INC) $(K5INC)/krb5 $(SSLINC) $(KFLAGS)" \ "LIBS= $(K5LIB) $(SSLLIB) -ltermlib -lsocket -lnsl -lm -lresolv \ -lkrb4 -lssl -lcrypto -lgssapi_krb5 -lkrb5 -lcom_err -lk5crypto \ -ldes $(LIBS)" #and with OpenSSL solaris2xg+openssl+pam+shadow: @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with gcc, OpenSSL...' @echo 'Please read the comments that accompany the solaris2xg target.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \ -DCK_AUTHENTICATION -DCK_SSL -DCK_PAM -DCK_SHADOW \ -DBIGBUFOK $(SSLINC) $(KFLAGS)" \ "LIBS= $(SSLLIB) -ltermlib \ -lsocket -lnsl -lm -lresolv -lssl -lcrypto -lpam" solaris2xg+openssl+zlib+srp+pam+shadow: @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with gcc, OpenSSL...' @echo 'Please read the comments that accompany the solaris2xg target.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DFNFLOAT \ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET -DBIGBUFOK \ -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_DES -DLIBDES -DCK_CAST \ -DCK_SSL -DCK_PAM -DCK_SHADOW -DZLIB -DCK_SRP $(SSLINC) $(KFLAGS)" \ "LIBS= $(SSLLIB) -ltermlib -lsocket -lnsl -lm -lresolv -lsrp -lssl \ -ldes -lkrypto -lcrypto -lpam -lz" solaris22g: $(MAKE) "MAKE=$(MAKE)" "KFLAGS=-DPOSIX_CRTSCTS $(KFLAGS)" solaris2xg \ KTARGET=$${KTARGET:-$(@)} solaris23g: $(MAKE) "MAKE=$(MAKE)" "KFLAGS=-DPOSIX_CRTSCTS $(KFLAGS)" solaris2xg \ KTARGET=$${KTARGET:-$(@)} #Solaris 2.4 built with gcc solaris24g: $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET:-$(@)} \ solaris2xg "KFLAGS=-DSOLARIS24 -DPOSIX_CRTSCTS $(KFLAGS)" #Solaris 2.0-2.3, SunPro compiler, with SunLink X.25 support. #This will only run if user has /opt/SUNWconn/lib/libsockx25.so.1 #exists and can be dynamically linked. #NOTE: Do not change target to xermit -- it doesn't support X.25. solaris2x25: @echo 'Making C-Kermit $(CKVER) for Solaris 2.x+X.25 with SunPro cc...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -i -Usun -DSVR4 -DSOLARIS -DDIRENT \ -DSUNX25 -DTCPSOCKET -DHDBUUCP -DFNFLOAT -DNOLEARN \ -DSELECT -DCK_CURSES -DCK_NEWTERM -DSTERMIOX $(KFLAGS)" \ "LNKFLAGS = -s" \ "LIBS= -ltermlib -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib \ -lsockx25 -lsocket -lnsl -lm -lresolv" #Solaris 2.0-2.4, gcc, SunLink X.25 added. #NOTE: Can't use xermit target with X.25. solaris2xgx25: @echo 'Making C-Kermit $(CKVER) for Solaris 2.x + X.25 with GNU cc...' @echo 'Please read the comments that accompany the solaris2xg entry.' $(MAKE) wermit CC=gcc CC2=gcc KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSTERMIOX -DSELECT -DSUNX25 \ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET -DFNFLOAT \ -DNOLEARN $(KFLAGS)" \ "LIBS= -ltermlib -lm -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib \ -lsockx25 -lsocket -lnsl" #Solaris 2.4, SunPro compiler, with SunLink X.25 support. #This will only run if user has /opt/SUNWconn/lib/libsockx25.so.1 #exists and can be dynamically linked. solaris24x25: @echo 'Making C-Kermit $(CKVER) for Solaris 2.4+X.25 with SunPro cc...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -i -Usun -DSVR4 -DSOLARIS -DSOLARIS24 -DDIRENT -DNOLEARN \ -DSUNX25 -DTCPSOCKET -DHDBUUCP -DFNFLOAT -DPOSIX_CRTSCTS \ -DSELECT -DCK_CURSES -DCK_NEWTERM -DSTERMIOX $(KFLAGS)" \ "LNKFLAGS = -s" \ "LIBS= -ltermlib -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib \ -lsockx25 -lsocket -lnsl -lm -lresolv" #Solaris 2.5, SunPro compiler, with SunLink X.25 support. solaris25x25: @echo 'Making C-Kermit $(CKVER) for Solaris 2.5+X.25 with SunPro cc...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -i -Usun -DSVR4 -DSOLARIS25 -DDIRENT -DSUNX25 \ -DTCPSOCKET -DHDBUUCP -DSELECT -DCK_CURSES \ -DCK_NEWTERM -DSTERMIOX -DFNFLOAT -DPOSIX_CRTSCTS -DNOLEARN \ -I/opt/SUNWconn/include $(KFLAGS)" \ "LIBS= -ltermlib -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib \ -lsockx25 -lsocket -lnsl -lm -lresolv" solaris23: $(MAKE) "MAKE=$(MAKE)" solaris2x KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(KFLAGS)" solaris24: $(MAKE) "MAKE=$(MAKE)" solaris2x KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS24 -DPOSIX_CRTSCTS $(KFLAGS)" # template for Solaris 2.5 and above. solaris25x: @echo 'Making C-Kermit $(CKVER) for Solaris 2.x with SunPro cc...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DFNFLOAT -O -Usun -i $(KFLAGS)" \ "LNKFLAGS = -s" \ "LIBS= -ltermlib -lsocket -lnsl -lm -lresolv $(LIBS)" #Solaris 2.5, SunPro compiler, curses, TCP/IP solaris25: $(MAKE) "MAKE=$(MAKE)" solaris25x KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS25 $(KFLAGS)" #Solaris 2.5, SunPro compiler, curses, TCP/IP, Kerberos IV solaris25+krb4: $(MAKE) "MAKE=$(MAKE)" solaris25x+krb4 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS25 $(KFLAGS)" #Solaris 2.5 built with gcc solaris25g: $(MAKE) "MAKE=$(MAKE)" solaris2xg KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-funsigned-char -DSOLARIS25 $(KFLAGS)" #Solaris 2.5 built with gcc and Kerberos IV solaris25g+krb4: $(MAKE) "MAKE=$(MAKE)" solaris2xg+krb4 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-funsigned-char -DSOLARIS25 $(KFLAGS)" #Solaris 2.5 built with gcc and Kerberos V/IV, SSL, ... solaris25g+krb5+krb4+openssl+shadow: $(MAKE) "MAKE=$(MAKE)" solaris2xg+krb5+krb4+openssl+shadow \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-funsigned-char -DSOLARIS25 $(KFLAGS)" #Solaris 2.5, gcc, SunLink X.25 added. solaris25gx25: $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET:-$(@)} solaris2xgx25 \ "KFLAGS=-DSOLARIS25 $(KFLAGS)" #Solaris 2.6, gcc, SunLink X.25 added. solaris26gx25: $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET:-$(@)} solaris2xgx25 \ "KFLAGS=-DSOLARIS26 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \ "LIBS= -lpam" #Solaris 2.6, SunPro compiler, curses, TCP/IP solaris26: $(MAKE) "MAKE=$(MAKE)" solaris25x KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS26 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \ "LIBS= -lpam" #Solaris 2.6 with gcc solaris26g: $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET:-$(@)} solaris2xg \ "KFLAGS= -DSOLARIS26 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \ "LIBS = -lpam" #Solaris 2.6 with gcc and SSL solaris26g+openssl: $(MAKE) "MAKE=$(MAKE)" solaris2xg+openssl+pam+shadow \ KTARGET=$${KTARGET:-$(@)} "KFLAGS= -DSOLARIS26 $(KFLAGS)" #Solaris 2.6 with gcc, no curses (e.g. because libtermlib is missing). solaris26gnc: $(MAKE) "MAKE=$(MAKE)" KTARGET=$${KTARGET:-$(@)} solaris2xgnc \ "KFLAGS= -DSOLARIS26 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \ "LIBS= -lpam" #Solaris 2.6, SunPro compiler, with SunLink X.25 support. solaris26x25: @echo 'Making C-Kermit $(CKVER) for Solaris 2.6+X.25 with SunPro cc...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -i -Usun -DSVR4 -DSOLARIS26 -DDIRENT -DSUNX25 \ -DTCPSOCKET -DHDBUUCP -DSELECT -DCK_CURSES -DCK_PAM -DCK_SHADOW \ -DCK_NEWTERM -DSTERMIOX -DFNFLOAT -DPOSIX_CRTSCTS -DNOLEARN \ -I/opt/SUNWconn/include $(KFLAGS)" \ "LIBS= -ltermlib -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib \ -lsockx25 -lsocket -lnsl -lm -lresolv -lpam" #Solaris 7 (2.7) with Sun CC solaris7: $(MAKE) "MAKE=$(MAKE)" solaris25x KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS7 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \ "LIBS= -lpam" #Solaris 7 with gcc (32-bit) solaris7g: $(MAKE) "MAKE=$(MAKE)" solaris2xg KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS7 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \ "LIBS= -lpam" #Solaris 7 with gcc + Kerberos IV (32-bit) solaris7g+krb4: $(MAKE) "MAKE=$(MAKE)" solaris2xg+krb4 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS7 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \ "LIBS= -lpam" solaris7g+openssl+zlib+pam+shadow: $(MAKE) "MAKE=$(MAKE)" solaris2xg+openssl+zlib+pam+shadow \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS7 -DCK_PAM -DCK_SHADOW $(KFLAGS)" #Solaris 7 with gcc + OpenSSL (32-bit) solaris7g+openssl+zlib+srp+pam+shadow: $(MAKE) "MAKE=$(MAKE)" solaris2xg+openssl+zlib+srp+pam+shadow \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS7 -DCK_PAM -DCK_SHADOW $(KFLAGS)" #Solaris 8 solaris8: $(MAKE) "MAKE=$(MAKE)" solaris25x KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS8 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \ "LIBS= -lpam" #Solaris 8 with gcc (32-bit) solaris8g: $(MAKE) "MAKE=$(MAKE)" solaris2xg KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS8 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \ "LIBS= -lpam" # In OpenSSL builds add -ldl if you get unresolved references for # dlclose, dlsym, dlopen, dlerror. #Solaris 8 with gcc + OpenSSL (32-bit) solaris8g+openssl+zlib+pam+shadow: $(MAKE) "MAKE=$(MAKE)" solaris2xg+openssl+zlib+pam+shadow \ KTARGET=$${KTARGET:-$(@)} "KFLAGS=-DSOLARIS8 $(KFLAGS)" #Solaris 8 with gcc + Kerberos IV (32-bit) solaris8g+krb4: $(MAKE) "MAKE=$(MAKE)" solaris2xg+krb4 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS8 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \ "LIBS= -lpam" solaris9nolfs: $(MAKE) "MAKE=$(MAKE)" solaris25x KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS9 -DCK_PAM -DCK_SHADOW -DUSE_STRERROR $(KFLAGS)" \ "LIBS= -lpam" #Solaris 9 with malloc debugging solaris9md: $(MAKE) mermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DFNFLOAT -O -Usun -i -D_FILE_OFFSET_BITS=64 \ -DSOLARIS9 -Dmalloc=dmalloc -Dfree=dfree -DMDEBUG \ -DCK_PAM -DCK_SHADOW -DUSE_STRERROR $(KFLAGS)" \ "LIBS= -lpam -ltermlib -lsocket -lnsl -lm -lresolv" #Solaris 9 with gcc + OpenSSL + Shadow (32-bit) #Add -DOPENSSL_097 for OpenSSL 0.9.7 or later. solaris9g+openssl+shadow+pam+zlib: $(MAKE) "MAKE=$(MAKE)" solaris2xg+openssl+zlib+pam+shadow \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS9 -DHDBUUCP -DDIRENT -D_FILE_OFFSET_BITS=64 \ -DNO_DCL_INET_ATON -DZLIB -DCK_PAM -DCK_SHADOW -DLIBDES $(KFLAGS)" \ "LIBS= -lpam -ldes425 -lz $(LIBS)" #Solaris 9 with gcc + OpenSSL + Kerberos 5 + Krb4 + Shadow (32-bit) #Add -DOPENSSL_097 for OpenSSL 0.9.7 or later. solaris9g+krb5+krb4+openssl+shadow+pam+zlib: $(MAKE) "MAKE=$(MAKE)" solaris2xg+krb5+krb4+openssl+shadow \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS9 -DHDBUUCP -DDIRENT -D_FILE_OFFSET_BITS=64 \ -DNO_DCL_INET_ATON -DZLIB -DCK_PAM -DCK_SHADOW -DLIBDES $(KFLAGS)" \ "LIBS= -lpam -ldes -lz $(LIBS)" #Solaris 9 with gcc + Kerberos 4 and 5: solaris9g+krb5+krb4: $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS = -O -Usun -DSVR4 -DSOLARIS9 -DSTERMIOX -DSELECT -DFNFLOAT \ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -D_FILE_OFFSET_BITS=64 \ -DCK_ENCRYPTION -DCK_DES -DCK_CAST -DBIGBUFOK \ $(K5INC) $(K5INC)/krb5 $(KFLAGS)" \ "LIBS= $(K5LIB) -ltermlib -lsocket -lnsl -lm -lresolv \ -lkrb4 -lcrypto -lgssapi_krb5 -lkrb5 -lcom_err -lk5crypto \ -ldes $(LIBS)" #Solaris 9, 10, or 11 with gcc... #Uses streams PTYs rather than BSD ptys as in C-Kermit 8.0 and earlier. #This target is chained to be the secure solaris9g+xxx targets below. solaris9g solaris10g solaris11g: @echo 'Making C-Kermit $(CKVER) for Solaris 9 or later with gcc' @case `uname -r` in \ 5.9) SOLARISVERSION="-DSOLARIS9" ;; \ 5.10) SOLARISVERSION="-DSOLARIS10" ;; \ 5.11) SOLARISVERSION="-DSOLARIS11" ;; \ *) SOLARISVERSION="-DSOLARIS" ;; \ esac ; \ $(MAKE) "MAKE=$(MAKE)" CC="gcc -m32" CC2="gcc -m32" xermit \ KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -g -O -Usun -DSVR4 $$SOLARISVERSION -DUSE_STRERROR \ -DSTERMIOX -DSELECT -DFNFLOAT -DCK_PAM -DCK_SHADOW -funsigned-char \ -DHAVE_STREAMS -DHAVE_GRANTPT -DHAVE_PTSNAME -DPUSH_PTEM \ -DPUSH_LDTERM -DPUSH_TTCOMPAT \ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \ -D_FILE_OFFSET_BITS=64 $(KFLAGS)" \ "LIBS= -ltermlib -lsocket -lnsl -lm -lresolv -lpam $(LIBS)" #Solaris 9, 10, or 11 with gcc + Kerberos 5 + OpenSSL. #OK C-Kermit 9.0.301. solaris9g+krb5+ssl solaris10g+krb5+ssl solaris11g+krb5+ssl: @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac ; \ HAVE_DES=''; \ DES_LIB=''; \ if ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \ DES_LIB='-ldes425'; \ HAVE_DES='-DCK_DES -DLIBDES'; \ echo "HAVE DES"; \ else echo "NO DES"; \ fi; \ GSSAPILIB=''; \ K5DIR=`echo $(K5LIB) | sed 's|-L||'`; \ echo K5DIR=$$K5DIR; \ if ls $$K5DIR/libgssapi_krb5* > /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi_krb5'; \ else GSSAPILIB='-lgssapi'; \ fi; \ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS = -O -Usun -DSVR4 -DSOLARIS9 -DSTERMIOX -DSELECT -DFNFLOAT \ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET -DBIGBUFOK \ -DCK_AUTHENTICATION -DCK_SSL -DZLIB -DCK_KERBEROS -DKRB5 \ -DCK_ENCRYPTION -DCK_CAST $$OPENSSLOPTION \ $$HAVE_DES $(SSLINC) $(K5INC) $(K5INC)/krb5 $(KFLAGS)" \ "LIBS= $(SSLLIB) $(K5LIB) -lz -lssl -ltermlib -lsocket -lnsl -lm \ -lresolv -lcrypto \ $$GSSAPILIB -lkrb5 -lcom_err -lk5crypto $$DES_LIB $(LIBS)" #Solaris 9, 10, or 11 with gcc, 64 bit build. #Peeking inside FILE struct not allowed in 64-bit world. #DON'T USE THIS ONE ON PC ARCHITECTURE - It compiles and links but won't run. #OK: 2009/09/25 (but not tested on Solaris 11) solaris9g64 solaris10g64 solaris11g64: @echo 'Making C-Kermit $(CKVER) for Solaris 9++ with gcc 64-bit' @case `uname -r` in \ 5.9) SOLARISVERSION="-DSOLARIS9" ;; \ 5.10) SOLARISVERSION="-DSOLARIS10" ;; \ 5.11) SOLARISVERSION="-DSOLARIS11" ;; \ *) SOLARISVERSION="-DSOLARIS" ;; \ esac ; \ $(MAKE) "MAKE=$(MAKE)" CC="gcc -m64" CC2="gcc -m64" xermit \ KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -g -O -Usun -funsigned-char \ -DSVR4 $$SOLARISVERSION \ -DSTERMIOX -DSELECT -DFNFLOAT -DUSE_STRERROR -DCK_PAM -DCK_SHADOW \ -DHAVE_STREAMS -DHAVE_GRANTPT -DHAVE_PTSNAME -DPUSH_PTEM \ -DPUSH_LDTERM -DPUSH_TTCOMPAT \ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET $(KFLAGS)" \ "LIBS= -ltermlib -lsocket -lnsl -lm -lresolv -lpam $(LIBS)" #Solaris 9, 10, or 11 with SunPro CC #Uses streams PTYs rather than BSD ptys as in C-Kermit 8.0 and earlier. #This target is chained to by the secure targets below. #OK C-Kermit 9.0 solaris9 solaris10 solaris11: @echo 'Making C-Kermit $(CKVER) for Solaris 9 or later with Sun CC' @case `uname -r` in \ 5.9) SOLARISVERSION="-DSOLARIS9" ;; \ 5.10) SOLARISVERSION="-DSOLARIS10" ;; \ 5.11) SOLARISVERSION="-DSOLARIS11" ;; \ *) SOLARISVERSION="-DSOLARIS" ;; \ esac ; \ $(MAKE) "MAKE=$(MAKE)" xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -Usun -DSVR4 $$SOLARISVERSION -DUSE_STRERROR \ -DSTERMIOX -DSELECT -DFNFLOAT -DCK_PAM -DCK_SHADOW \ -DHAVE_STREAMS -DHAVE_GRANTPT -DHAVE_PTSNAME -DPUSH_PTEM \ -DPUSH_LDTERM -DPUSH_TTCOMPAT \ -DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET \ -D_FILE_OFFSET_BITS=64 $(KFLAGS)" \ "LIBS= $(LIBS) -ltermlib -lsocket -lnsl -lm -lresolv -lpam" # Solaris 9, 10, or 11 with OpenSSL built with Sun CC. # Here's an example of how to invoke this target in case your OpenSSL # headers and libraries are not in /usr/local: # # make solaris9+openssl "SSLINC=" "SSLLIB=" \ # "KFLAGS= -I/opt/openssl-0.9.8k/include -L/opt/openssl-0.9.8k/lib" # # Don't use 'make -e' because that inhibits passing of KFLAGS to # the base (solaris9) target. # #OK C-Kermit 9.0 solaris9+ssl solaris10+ssl solaris11+ssl \ solaris9+openssl solaris10+openssl solaris11+openssl: @echo 'Making C-Kermit $(CKVER) for Solaris 9/10/11 with OpenSSL: cc' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac ; \ HAVE_DES=''; \ DES_LIB=''; \ if ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \ DES_LIB='-ldes425'; \ HAVE_DES='-DCK_DES -DLIBDES'; \ echo "HAVE DES"; \ else echo "NO DES"; \ fi; \ $(MAKE) "MAKE=$(MAKE)" solaris9 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DCK_AUTHENTICATION -DCK_SSL -DZLIB $$HAVE_DES \ -DNO_DCL_INET_ATON $$OPENSSLOPTION $(SSLINC) $(KFLAGS)" \ "LIBS= $(SSLLIB) -lz -lssl $$DES_LIB -lcrypto $(LIBS)" # Solaris 9 or later with OpenSSL, built with gcc. # Remove -DNO_DCL_INET_ATON if inet_aton comes up missing. This target nicely # chains to the solaris{9,10,11}g target but for some reason it doesn't work if # you add the -DFORWARD_X option, thus the solaris9g+openssl+forward_x target. # #OK: 2011/06/14 solaris9g+ssl solaris10g+ssl solaris11g+ssl \ solaris9g+openssl solaris10g+openssl solaris11g+openssl: @echo 'Making C-Kermit $(CKVER) for Solaris 9/10/11 with OpenSSL: gcc' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac ; \ HAVE_DES=''; \ DES_LIB=''; \ if ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \ DES_LIB='-ldes425'; \ HAVE_DES='-DCK_DES -DLIBDES'; \ echo "HAVE DES"; \ else echo "NO DES"; \ fi; \ $(MAKE) "MAKE=$(MAKE)" solaris9g KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DCK_AUTHENTICATION -DCK_SSL -DZLIB $$HAVE_DES \ -DNO_DCL_INET_ATON $$OPENSSLOPTION $(SSLINC) $(KFLAGS)" \ "LIBS= $(SSLLIB) -lz -lssl $$DES_LIB -lcrypto $(LIBS)" # Solaris 9 or later with gcc + OpenSSL + Shadow (32-bit). # Remove -DNO_DCL_INET_ATON if inet_aton comes up missing. # Includes long file support - not sure if this was available before Solaris 9. # Detects Solaris version automatically. # solaris9g+openssl+forward_x: @echo 'Making C-Kermit $(CKVER) for Solaris 9 or later with OpenSSL...' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac ; case `uname -r` in \ 5.9) SOLARISVERSION="-DSOLARIS9" ;; \ 5.10) SOLARISVERSION="-DSOLARIS10" ;; \ 5.11) SOLARISVERSION="-DSOLARIS11" ;; \ *) SOLARISVERSION="-DSOLARIS" ;; \ esac ; \ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "CFLAGS = -g -O -Usun -DSVR4 $$SOLARISVERSION \ -DHAVE_STREAMS -DHAVE_GRANTPT -DHAVE_PTSNAME -DPUSH_PTEM \ -DPUSH_LDTERM -DPUSH_TTCOMPAT \ -DSTERMIOX -DSELECT -DFNFLOAT -DBIGBUFOK -D_FILE_OFFSET_BITS=64 \ -DCK_AUTHENTICATION -DCK_SSL -DCK_PAM -DCK_SHADOW -DZLIB -DLIBDES \ -DFORWARD_X $$OPENSSLOPTION $(SSLINC) $(KFLAGS)" \ "LIBS= $(SSLLIB) -lpam -ldes425 -lz -ltermlib \ -lsocket -lnsl -lm -lresolv -lssl -lcrypto -lpam -lz $(LIBS)" # These two should be folded in with the ones just above. #Solaris 9 with gcc 3.1 + OpenSSL (32-bit) solaris9g+openssl+zlib+pam+shadow: $(MAKE) "MAKE=$(MAKE)" solaris2xg32+openssl+zlib+pam+shadow \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS9 -DUSE_STRERROR $(KFLAGS)" #Solaris 10 with gcc 3.1 + OpenSSL (32-bit) solaris10g+openssl+zlib+pam+shadow: $(MAKE) "MAKE=$(MAKE)" solaris2xg32+openssl+zlib+pam+shadow \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSOLARIS10 -DUSE_STRERROR $(KFLAGS)" #The following (old, old) sunosxxx entries are for debugging and testing only. sunos41x: $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -O -DSUNOS41 -DDIRENT -DNOTLOG -DNOMSEND \ -DNOUUCP -DNOSIGWINCH -DNOREDIRECT -DNOPUSH -DNOCCTRAP \ -DNOICP -DNOLOCAL $(KFLAGS)" #SunOS 4.1.x, debugging with Pure Software, Inc., Purify 2 (commercial runtime #error-detection software for catching wild array references, etc). #Before running the resulting wermit, you'll also need to define and export #the following environment variables (as in this example): #PURIFYHOME=/usr/local/purify ; export PURIFYHOME #PURIFYCACHEDIR=/tmp ; export PURIFYCACHEDIR sunos41cp: @echo Making C-Kermit $(CKVER) for SunOS 4.1 / BSD / Curses / Purify... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CC2= purify -cache_dir=/usr/tmp cc" \ "CFLAGS= -g -DSUNOS41 -DHDBUUCP -DDIRENT -DTCPSOCKET \ -DSAVEDUID -DCK_CURSES $(KFLAGS)" \ "LIBS= -lcurses -ltermcap" #SunOS 4.1 with malloc debugger sunos41md: @echo Making C-Kermit $(CKVER) for SunOS 4.1 malloc debug... $(MAKE) mermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -O -DSUNOS41 -DHDBUUCP -DDIRENT -DTCPSOCKET \ -DSAVEDUID $(KFLAGS) -Dmalloc=dmalloc -Dfree=dfree -DMDEBUG" sunos41gmd: @echo Making C-Kermit $(CKVER) for SunOS 4.1 with gcc and curses... $(MAKE) mermit KTARGET=$${KTARGET:-$(@)} "CC= gcc " "CC2= gcc" \ "CFLAGS= -g -DSUNOS41 -DHDBUUCP -DDIRENT -DTCPSOCKET \ -DNDGPWNAM -DSAVEDUID -DCK_CURSES -DRLOGCODE \ $(KFLAGS) -Dmalloc=dmalloc -Dfree=dfree -DMDEBUG" \ "LIBS= -lcurses -ltermcap" #SunOS version 4.1, gcc, profiling with gprof, no debugging. #To get profile, "make sunos41p" (on Sun), then "./wermit". After running #wermit, "gprof ./wermit | lpr" (or whatever) to get execution profile. sunos41p: @echo Making C-Kermit $(CKVER) for SunOS 4.x with profiling... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC= gcc " "CC2= gcc" \ "CFLAGS= -DSUNOS41 -DNODEBUG -DSAVEDUID -DDIRENT -DTCPSOCKET \ -DNDGPWNAM $(KFLAGS) -pg" "LNKFLAGS = -pg" #SunOS version 4.1 or later, BSD environment, minimum features. sunos41min: @echo Minimum interactive $(MAKE) "MAKE=$(MAKE)" sunos41 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DNOSPL -DNOXMIT -DNOMSEND -DNOFRILLS -DNORETRY \ -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG -DNOSCRIPT -DNOCSETS \ -DNOSHOW -DNOSETKEY -DNOUUCP -DNORECALL -DNOREDIRECT \ -DNOPUSH -DNOMDMHUP -DNOJC -DNOFDZERO -DNOESCSEQ \ -DNONET -DCK_SMALL -DNOCKSPEED -DNOCKTIMERS -DNOLOGIN \ -DNOCKXYZ -DNOKERBEROS -DNOMKDIR -DNOPATTERNS -DNOPERMS -DNOPIPESEND \ -DNORECURSIVE -DNORENAME -DNORESEND -DNOSETKEY \ -DNOTRIGGER -DNOTUNING $(KFLAGS)" "LNKFLAGS = -s" #SunOS version 4.1, BSD environment, min size, command-line only... sunos41m: @echo Minimum size $(MAKE) "MAKE=$(MAKE)" sunos41min KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DNOICP $(KFLAGS)" #SunOS version 4.1, BSD environment, min size, cmd-line only, remote only... # sunos41mr: @echo Minimum size $(MAKE) "MAKE=$(MAKE)" sunos41min KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DNOICP -DNOLOCAL $(KFLAGS)" #SunOS version 4.1, BSD environment, min size, interactive... sunos41mi: @echo Minimum size $(MAKE) "MAKE=$(MAKE)" sunos41min KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DNOCMDL $(KFLAGS)" #SunOS version 4.1, BSD environment, min size, interactive, remote only... sunos41mir: @echo Minimum size $(MAKE) "MAKE=$(MAKE)" sunos41min KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DNOCMDL -DNOLOCAL $(KFLAGS)" #SunOS 4.1, System V R3 environment (-i option omitted). sunos41s5: @echo Making C-Kermit $(CKVER) for SunOS 4.1 System V R3... @echo For testing purposes only - NOT for production use. @echo For a useable version, make sunos41 instead. $(MAKE) wermit "CC= /usr/5bin/cc " "CC2=/usr/5bin/cc " \ KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSUN4S5 -DDIRENT -DHDBUUCP -DNOLEARN -DCK_POLL $(KFLAGS) -O" #As above, but with curses support sunos41s5c: @echo Making C-Kermit $(CKVER) for SunOS 4.1 System V R3... @echo Curses included. @echo For testing purposes only - NOT for production use. @echo For a useable version, make sunos41 instead. $(MAKE) wermit "CC= /usr/5bin/cc " "CC2=/usr/5bin/cc " \ KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSUN4S5 -DDIRENT -DHDBUUCP -DNOLEARN \ -DCK_POLL -DCK_CURSES -DCK_NEWTERM $(KFLAGS) -O" "LIBS= -lcurses" #As above, but with curses support AND net support sunos41s5tcpc: @echo Making C-Kermit $(CKVER) for SunOS 4.1 System V R3... @echo TCP/IP and curses included. No debug log. @echo For testing purposes only - NOT for production use. @echo For a useable version, make sunos41 instead. $(MAKE) xermit "CC= /usr/5bin/cc " "CC2=/usr/5bin/cc " \ KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSUN4S5 -DDIRENT -DHDBUUCP -DCK_POLL \ -DNODEBUG -DCK_CURSES -DCK_NEWTERM -DTCPSOCKET $(KFLAGS) -O" \ "LIBS= -lcurses -lresolv" # (End of SunOS test entries...) #Apollo with Domain SR10.0 or later, BSD environment #Reportedly, it might also help to add '-A,systype=bsd4.3' to CFLAGS. #Reportedly, there is also a problem with getc & putc macros that can #be handled by using '#ifdef apollo' somewhere to redefine them??? #On the other hand, other reports indicate that it works fine as-is. #NOTE: This entry was previously like this: # $(MAKE) wermit "CFLAGS= -DNOFILEH -DBSD4 $(KFLAGS) -Uaegis \ # -DTCPSOCKET -U__STDC__" #Reports (Dec 91) indicate SR10 has an ANSI-compliant C compiler, #in addition to an older one that claimed to be ANSI-compliant but wasn't. #The following make entry (plus checks that are made in ckcdeb.h) detect #which compiler is used and define the CK_ANSIC or NOANSI flags accordingly. sr10-bsd: @echo Making C-Kermit $(CKVER) for Apollo SR10.0 / BSD ... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -O -DAPOLLOSR10 -DBSD43 -DTCPSOCKET -DCK_CURSES -DNOLEARN \ -Uaegis $(KFLAGS)" "LIBS= -lcurses -ltermcap" #Apollo with Domain SR10.0 or later, System V R3 environment. #Don't use the optimizer (-O), it causes problems at runtime. sr10-s5r3: @echo Making C-Kermit $(CKVER) for Apollo SR10.0 / Sys V R3 ... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DNOFILEH -DSVR3 -DAPOLLOSR10 -DNOLEARN $(KFLAGS) \ -Uaegis -U__STDC__" #Apollo Domain/IX (untested, try this if sr10-bsd doesn't work) # -DTCPSOCKET can probably be added here. apollobsd: @echo Making C-Kermit $(CKVER) for Apollo Domain/IX... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CC= /bin/cc " "CC2= /bin/cc " \ "CFLAGS= -DNOFILEH -DBSD4 -DAPOLLOBSD -DNOLEARN $(KFLAGS) -Uaegis" #Version 7 Unix (see comments near top of makefile) #-DNOSYSLOG -DNOHELP added in October 2022, the latter because it was #taking hours to compile ckuus2.c. Anyway the build failed later with with #an assembler error: "Unexpected end of file writing the interpass tmp file" v7: @echo Making C-Kermit $(CKVER) for UNIX Version 7. @echo Read the makefile if you have trouble with this... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS=-DV7 -DPROCNAME=\\\"$(PROC)\\\" \ -DBOOTNAME=\\\"$(BOOTFILE)\\\" -DNPROCNAME=\\\"$(NPROC)\\\" \ -DNPTYPE=$(NPTYPE) $(DIRECT) -DO_RDWR=2 -DO_NDELAY=0 -DO_SCCS_ID \ -DNOLEARN -DNOSYSLOG -DNOHELP $(KFLAGS)" #Version 7 Unix minumum size - commandline only, no interactive commands. # See the V7 section of ckcdeb.h for all the NOxxx definitions because # they can't all be put on the command line: "too many -D options, # ignoring -DNOxxx". Some of these -DNO items are to skip over correct # C code that the compiler erroneously flags as errors. # 2 November 2022 v7min: @echo Making C-Kermit $(CKVER) for UNIX Version 7 smallest possible. $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS=-DV7 -DPROCNAME=\\\"$(PROC)\\\" \ -DBOOTNAME=\\\"$(BOOTFILE)\\\" -DNPROCNAME=\\\"$(NPROC)\\\" \ -DNPTYPE=$(NPTYPE) $(DIRECT) -DO_RDWR=2 -DO_NDELAY=0 -DO_SCCS_ID \ -DV7MIN $(KFLAGS)" #AT&T UNIX System V R3, signal() is void rather than int. #Uses dirent.h and Honey DanBer UUCP. #Add the -i link option if necessary. #If you get errors like "ws_row undefined" in ckutio.c, add -DNONAWS. sys5r3: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R3...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -DNOLEARN $(KFLAGS) -O" \ "LNKFLAGS=" #As above, plus curses. sys5r3c: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R3 + curses...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -DCK_CURSES -DNONAWS -DNOLEARN \ $(KFLAGS) -O" "LNKFLAGS=" "LIBS = -ltermlib" #System V R3.2 for PCs built on Interactive UNIX SV/386 R4.x #but with all calls to dup2() disabled because generic SVR3 does not have dup2. # (The -linet library might not need to be in this one.) sys5r32is: @echo 'Making C-Kermit $(CKVER) for System V/386 R32 $(MAKE) wermit CC="$(CC)" CC2="$(CC2)" \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -O -DNOCSETS -DNOREALPATH \ -DUID_T=ushort -DGID_T=ushort -DI386IX -DSVR3JC -DCK_CURSES -DNONAWS \ -DPOSIX_JC -DCK_REDIR -DCK_POLL -DDCLGETCWD -DNOFDZERO -DNOREDIRECT \ -DNOZEXEC -DNOLEARN $(KFLAGS)" "LIBS=-lcurses -lc_s -linet" #System V R3.2 for PCs built on Interactive UNIX SV/386 R4.x #but with all calls to dup2() disabled because generic SVR3 does not have dup2. #With TCP/IP added. sys5r32isnet: @echo 'Making C-Kermit $(CKVER) for System V/386 R32 + TCP/IP $(MAKE) wermit CC="$(CC)" CC2="$(CC2)" \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -O -DNOCSETS -DNOREALPATH \ -DUID_T=ushort -DGID_T=ushort -DI386IX -DSVR3JC -DCK_CURSES -DNONAWS \ -DPOSIX_JC -DCK_REDIR -DCK_POLL -DDCLGETCWD -DNOFDZERO -DNOREDIRECT \ -DNOLEARN -DNOZEXEC -DTCPSOCKET $(KFLAGS)" "LIBS=-lcurses -lc_s -linet" iclsys5r3: make sys5r3 KTARGET=$${KTARGET:-$(@)} KFLAGS=-DICLSVR3 #AT&T UNIX System V R3. As above, but no ANSI prototyping. sys5r3na: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R3...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -DNOANSI -DNOLEARN $(KFLAGS) -O" \ "LNKFLAGS=" #AT&T UNIX System V R3, for 3B computers with Wollongong TCP/IP. sys5r3net3b: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX SVR3/3B/Wollongong...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DWOLLONGONG -DNOLEARN $(KFLAGS) \ -O" "LIBS= -lnet -lnsl_s" "LNKFLAGS =" #AT&T UNIX System V R3, signal() is void rather than int. #Uses dirent.h and Honey DanBer uucp, has . #Has for RTS/CTS flow control. sys5r3tx: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R3...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DTERMIOX -DNOLEARN \ $(KFLAGS) -i -O" "LNKFLAGS =" #AT&T UNIX System V R3, signal() is void rather than int. #Uses dirent.h and Honey DanBer uucp, has . #Has for RTS/CTS flow control. sys5r3sx: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R3...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DSTERMIOX -DNOLEARN \ $(KFLAGS) -i -O" "LNKFLAGS =" #AT&T UNIX System V R4. #Has . sys5r4: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DTERMIOX -DNOLEARN $(KFLAGS)" \ "LNKFLAGS = -s" #AT&T UNIX System V R4 with Wollongong TCP/IP. #Has . sys5r4net: @echo 'Making C-Kermit $(CKVER) for System V R4 + Wollongong TCP/IP...' @echo ' If sockets-library routines are missing at link time, then' @echo ' try the sys5r4net2 entry.' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DNOLEARN \ -DTERMIOX -DWOLLONGONG $(KFLAGS)" "LNKFLAGS = -s" #As above, but needs libs included. sys5r4net2: @echo ' PLEASE READ ckuins.txt IF YOU GET MISSING HEADER FILES.' @echo ' (Search for WOLLONGONG...)' $(MAKE) sys5r4net KTARGET=$${KTARGET:-$(@)} "LIBS= -lsocket -lnsl" #As above plus curses. sys5r4net2c: echo 'Making C-Kermit $(CKVER) for System V R4 + Wollongong TCP/IP...' @echo ' PLEASE READ ckuins.txt IF YOU GET MISSING HEADER FILES.' @echo ' (Search for WOLLONGONG...)' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DNOLEARN \ -DTERMIOX -DWOLLONGONG -DCK_CURSES $(KFLAGS)" "LNKFLAGS = -s" \ "LIBS= -lsocket -lnsl -lcurses" #DELL UNIX System V R4. #Has , regular Berkeley sockets library, i.e. in.h and inet.h #are not misplaced in sys (rather than netinet and arpa, respectively). #Uses ANSI C constructs, advisory file locking on devices, etc. #Warning: -DSTERMIOX enables hardware flow control (RTS/CTS), but reportedly #this does not work with the normal drivers. However, it might still work #on non-Dell systems, or even Dell systems with different drivers installed. dellsys5r4: @echo 'Making C-Kermit $(CKVER) for DELL UNIX System V R4...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDELL_SVR4 -DDIRENT -DHDBUUCP \ -DTCPSOCKET -DSTERMIOX -DCK_POLL $(KFLAGS)" \ "LIBS= -lsocket -lnsl" "LNKFLAGS = -s" #As above, curses support added... dellsys5r4c: @echo 'Making C-Kermit $(CKVER) for DELL UNIX System V R4...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDELL_SVR4 -DDIRENT -DHDBUUCP \ -DTCPSOCKET -DSTERMIOX -DCK_CURSES -DCK_POLL \ $(KFLAGS)" "LIBS= -lsocket -lnsl -lcurses -ltermcap" "LNKFLAGS = -s" #Minimum interactive: As above, but with every conceivable option removed. dellsys5r4mi: @echo 'Making C-Kermit $(CKVER) for DELL UNIX System V R4...' @echo 'Minimum-size interactive' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDELL_SVR4 -DDIRENT \ -UTCPSOCKET -DNOCMDL -DNOSPL -DNOXMIT -DCK_POLL \ -DNOMSEND -DNOFRILLS -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG \ -DNOSCRIPT -DNOCSETS -DNOSHOW -DNOSETKEY -DNOSERVER -DNOUUCP \ -DNOPUSH -DNOMDMHUP -DNOJC -DNOFDZERO -DNOESCSEQ \ $(KFLAGS)" "LNKFLAGS = -s" #Command-line only version. dellsys5r4m: @echo 'Making C-Kermit $(CKVER) for DELL UNIX System V R4...' @echo 'Command-line only' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDELL_SVR4 -DDIRENT \ -UTCPSOCKET -DNOICP -DNOFRILLS -DNODIAL -DNODEBUG -DNOTLOG -DNOCSETS \ -DNOSETKEY -DNOESCSEQ -DNOJC -DNOFDZERO -DCK_POLL \ $(KFLAGS)" "LNKFLAGS = -s" #AT&T UNIX System V R4. #Has . sys5r4sx: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DSTERMIOX -DNOLEARN \ $(KFLAGS)" "LNKFLAGS = -s" "LIBS=$(LIBS)" #AT&T UNIX System V R4. #Has , regular Berkeley sockets library, i.e. in.h and inet.h #are not misplaced in sys (rather than netinet and arpa, respectively). #Uses ANSI C constructs, , etc etc. sys5r4sxtcp: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP \ -DSTERMIOX -DTCPSOCKET $(KFLAGS)" \ "LIBS= -lsocket -lnsl $(LIBS)" "LNKFLAGS= -s" #AT&T UNIX System V R4. #As above + curses. sys5r4sxtcpc: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP \ -DSTERMIOX -DCK_CURSES -DTCPSOCKET $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lcurses -ltermcap $(LIBS)" "LNKFLAGS = -s" #AT&T UNIX System V R4. CONSENSYS SVR4.2-1. #Has , regular Berkeley sockets library, i.e. in.h and inet.h #are not misplaced in sys (rather than netinet and arpa, respectively). #Uses ANSI C constructs, , etc. # Fullscreen -DCK_CURSES added (with curses & termcap libs) # Submission by Robert Weiner/Programming Plus, rweiner@watsun.cc.columbia.edu sys5r4sxtcpf: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP \ -DSTERMIOX -DTCPSOCKET -DCK_CURSES $(KFLAGS)" \ "LIBS= -lsocket -lnsl -L/usr/ccs/lib -lcurses -ltermcap" \ "LIBS=$(LIBS)" "LNKFLAGS = -s" #Smallest possible version for System V R4 s5r4m: @echo Minimum size $(MAKE) "MAKE=$(MAKE)" sys5r4sx KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(KFLAGS) -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG \ -DNOSCRIPT -DNOCSETS -DNOICP -DNOMSEND -UTCPSOCKET" "LNKFLAGS = -s" #Smallest possible interactive version of above s5r4mi: @echo Minimum interactive $(MAKE) "MAKE=$(MAKE)" sys5r4sx \ "KFLAGS=-DNOSPL -DNOXMIT -DNOMSEND -DNOFRILLS -DNOSHOW \ -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG -DNOSCRIPT -DNOCSETS -DNOSETKEY \ -UTCPSOCKET $(KFLAGS)" "LNKFLAGS = -s" #AT&T UNIX System V R4, has #ANSI C function prototyping disabled. sys5r4sxna: @echo No ANSI C prototyping... $(MAKE) "MAKE=$(MAKE)" sys5r4sx KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(KFLAGS) -DNOANSI" #Stratus FTX. ftx: @echo 'Making C-Kermit $(CKVER) for Stratus FTX 3.x...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DFTX -DDIRENT -DHDBUUCP -DSTERMIOX \ -DNOGETUSERSHELL -DNOLEARN +DA1.1 $(KFLAGS)" \ "LNKFLAGS = -s" "LIBS=$(LIBS)" #Stratus FTX + TCP/IP. ftxtcp: @echo 'Making C-Kermit $(CKVER) for Stratus FTX 3.x...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DFTX -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \ -DSTERMIOX -DTCPSOCKET -DNO_DNS_SRV +DA1.1 $(KFLAGS)" \ "LIBS= -lsocket -lnsl $(LIBS)" "LNKFLAGS= -s" #NCR MP-RAS 2.03 or 3.02 mpras: @echo 'Making C-Kermit $(CKVER) for NCR MP-RAS...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DNCRMPRAS -DDIRENT -DHDBUUCP -DSTERMIOX \ -DNOGETUSERSHELL -DUSE_FILE__CNT -DNOLEARN -DNO_DNS_SRV $(KFLAGS)" \ "LNKFLAGS = -s" "LIBS=$(LIBS)" #NCR MP-RAS 2.03 or 3.02 with TCP/IP and curses mprastcpc: @echo 'Making C-Kermit $(CKVER) for NCR MP-RAS + TCP/IP + curses...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CFLAGS=-DTCPSOCKET \ -DCK_CURSES -DSVR4 -DNCRMPRAS -DDIRENT -DHDBUUCP -DSTERMIOX -DNOLEARN \ -DNOGETUSERSHELL -DNO_DNS_SRV DUSE_FILE__CNT -O $(KFLAGS)" \ "LNKFLAGS = -s" "LIBS= -lsocket -lnsl -lcurses -ltermcap $(LIBS)" #SINIX-L V5.41 - includes curses, tcp/ip - Use this one for i386. #This version of SINIX doesn't like fdopen() or popen(). sinix541: @echo 'Making C-Kermit $(CKVER) for Siemens/Nixdorf SINIX V5.41/i386' $(MAKE) ckcpro.$(EXT) "CFLAGS = -DSINIX -DSVR4 -DDIRENT -DHDBUUCP \ -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC -DNO_DNS_SRV \ -DSNI541 -DNOGETUSERSHELL -DNONETCMD -DNOPOPEN -kansi -W0 $(KFLAGS)" $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSINIX -DSVR4 -DDIRENT -DHDBUUCP -DNO_DNS_SRV -DNOPOPEN \ -DFNFLOAT -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC \ -DSNI541 -DNOGETUSERSHELL -DNONETCMD -kansi -W0 -O $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lcurses -ltermcap -lm" "LNKFLAGS = -s" sinix541i: $(MAKE) "MAKE=$(MAKE)" "KFLAGS=$(KFLAGS)" sinix541 #SINIX V5.42 - includes curses, tcp/ip, everything - Use this one for MIPS. # As of C-Kermit 7.1, optimization removed -- takes (literally) forever. sinix542: $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSINIX -DSVR4 -DDIRENT -DHDBUUCP -DNO_DNS_SRV \ -DFNFLOAT -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC \ -DSNI542 -DNOGETUSERSHELL -kansi -W0 $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lcurses -ltermcap -lm" "LNKFLAGS = -s" #SINIX V5.42 gcc - includes curses, tcp/ip, everything. #This one was used to build the Pyramid-architecture RM600 version #on SINIX-P 5.42 A10 with gcc but should work for SINIX 5.42 on any other #architecture with gcc. sinix542g: $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC=gcc" "CC2=gcc" \ "CFLAGS = -DSINIX -DSVR4 -DDIRENT -DHDBUUCP -DNO_DNS_SRV \ -DFNFLOAT -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC \ -DSNI542 -DNOGETUSERSHELL $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lcurses -ltermcap -lm" \ "LNKFLAGS = -s" #SINIX V5.42 - includes curses, tcp/ip, everything - Use this one for Intel. # (Note: SNI discontinued Intel support after 5.42.) sinix542i: @echo 'Making C-Kermit $(CKVER) for Siemens/Nixdorf SINIX-Z V5.42...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSINIX -DSVR4 -DDIRENT -DHDBUUCP -DFNFLOAT -DSTERMIOX \ -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC -DNO_DNS_SRV -kansi \ -DSNI542 $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lcurses -ltermcap -lm" \ "LNKFLAGS = -s" #Siemens Nixdorf Reliant UNIX V5.43 - includes curses, tcp/ip, everything: # . gettimeofday() suddenly has only one arg instead of two (GTODONEARG). # . The syntax of the Olimit specifier changed. # . The name was changed from SINIX to Reliant UNIX in version 5.43C. sni543: @echo 'Making C-Kermit $(CKVER) for Siemens/Nixdorf Reliant UNIX V5.43' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSINIX -DSNI543 -DSVR4 -DDIRENT -DHDBUUCP \ -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC -DGTODONEARG \ -DNO_DNS_SRV -kansi -W0 -O -F Olimit,3100 $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lcurses -ltermcap" "LNKFLAGS = -s" #Siemens Nixdorf Reliant UNIX V5.44 - Like 5.43 but with different banner. sni544: @echo 'Making C-Kermit $(CKVER) for Siemens/Nixdorf Reliant UNIX V5.44' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSINIX -DSNI544 -DSVR4 -DDIRENT -DHDBUUCP \ -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DSELECT -DCK_ANSIC -DGTODONEARG \ -DNO_DNS_SRV -kansi -W0 -O -K Olimit,3100 $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lcurses -ltermcap" "LNKFLAGS = -s" #Commodore Amiga with AT&T UNIX System V R4 and TCP/IP support. #Has . svr4amiganet: @echo 'Making C-Kermit $(CKVER) for Amiga SVR4 + TCP/IP...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC=gcc" "CC2=gcc" \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DSTERMIOX \ -DTCPSOCKET -DCK_CURSES $(KFLAGS)" "LNKFLAGS = -s" \ "LIBS = -lsocket -lnsl -ltermlib" #SCO (Novell (Univel)) UnixWare 1.x or 2.0, no TCP/IP. #This assumes the Novell SDK 1.0, which has . #UnixWare users with the "Prime Time Freeware" CD-ROM SDK will probably have #to use the sys5r4 entry (no termiox.h file, so no hardware flow control). #Change -DSELECT to -DCK_POLL if -DSELECT causes problems. # NOTE: Unixware 1.x builds have not been tried in C-Kermit 7.0. unixware: $(MAKE) "MAKE=$(MAKE)" sys5r4sx KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DOLD_UNIXWARE -DCK_NEWTERM -DSELECT -DNOGETUSERSHELL \ -DNOSYSLOG $(KFLAGS)" "LIBS=-lcrypt" #UnixWare 1.x or 2.0 with TCP/IP and curses. #fork()-based CONNECT - no high serial speeds. unixwarenetc: $(MAKE) "MAKE=$(MAKE)" sys5r4sxtcpc KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DOLD_UNIXWARE -DCK_NEWTERM -DSELECT -DNOGETUSERSHELL \ -DNOSYSLOG $(KFLAGS)" "LIBS=-lcrypt -lresolv" uw10: $(MAKE) unixwarenetc KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS)" #This is for Unixware 2.0.x only - use unixware21 for UW 2.1.x. #Has special library search and enables special kludge around library #foulup regarding vfork() (which Kermit doesn't use). Forces POSIX-style #hangup. unixware20: @echo 'Making C-Kermit $(CKVER) for UnixWare 2.0.x...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DOLD_UNIXWARE -DUNIXWARE2 -DSELECT -DSVR4 -DDIRENT \ -DHDBUUCP -DBIGBUFOK -DNOGETUSERSHELL -DSTERMIOX -DCK_CURSES \ -DTCPSOCKET -DUW200 -DFNFLOAT -DCK_NEWTERM -DNOSYSLOG $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lcurses -ltermcap -lcrypt -lgen -lm -lresolv" \ "LNKFLAGS = -s" uw20: $(MAKE) unixware20 KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS)" #Adds big buffers ("large memory model") - otherwise the same as UnixWare 1.x. unixware21: @echo 'Making C-Kermit $(CKVER) for UnixWare 2.1.x...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DUNIXWARE -DSELECT -DSVR4 -DDIRENT -DHDBUUCP -DBIGBUFOK \ -DNOSYSLOG -DSTERMIOX -DCK_CURSES -DTCPSOCKET \ -DCK_NEWTERM -DFNFLOAT -DUNIXWARE2 $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lcurses -ltermcap -lcrypt -lm -lresolv \ $(LIBS)" "LNKFLAGS = -s" #Unixware 2.1.0 uw21: $(MAKE) unixware21 KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS)" #Unixware 2.1.3 uw213: $(MAKE) unixware21 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DUSE_FILE__CNT $(KFLAGS)" #Unixware 2.1 with IKSD support uw21iksd: $(MAKE) unixware21 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DCK_SHADOW $(KFLAGS)" "LIBS= -lgen" #UnixWare 7 with tc[gs]etspeed() high serial speeds & select()-based CONNECT #and as of C-Kermit 8.0.212, large file support (LFS). #NOTE: This is the one we use. unixware7t: @echo 'Making C-Kermit $(CKVER) for UnixWare 7 with POSIX i/o...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DUNIXWARE -DSELECT -DSVR4 -DDIRENT -DHDBUUCP -DBIGBUFOK \ -DFNFLOAT -DNOGETUSERSHELL -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DPOSIX \ -DUW7 -DUSETCSETSPEED -DCK_NEWTERM -DNOLSTAT -DDCLTIMEVAL \ -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DNEEDMDMDEFS $(KFLAGS)" \ "LIBS=-lsocket -lnsl -lcurses -ltermcap -lcrypt -lm -lresolv $(LIBS)" \ "LNKFLAGS = -s" #UnixWare 7 - select()-based CONNECT - no POSIX i/o - no high serial speeds. #In other words, just like the UnixWare 1 and 2 builds. unixware7x: @echo 'Making C-Kermit $(CKVER) for UnixWare 7...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DUNIXWARE -DSELECT -DSVR4 -DDIRENT -DHDBUUCP -DBIGBUFOK \ -DUW7 -DNOGETUSERSHELL -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DNOLSTAT \ -DFNFLOAT -DCK_NEWTERM $(KFLAGS)" \ "LIBS=-lsocket -lnsl -lcurses -ltermcap -lcrypt -lm -lresolv $(LIBS)" \ "LNKFLAGS = -s" #UnixWare 7 with POSIX cfset[oi]speed() to allow high serial speeds. #(but the high speeds don't work) unixware7p: @echo 'Making C-Kermit $(CKVER) for UnixWare 7 with POSIX i/o...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DUNIXWARE -DSELECT -DSVR4 -DDIRENT -DHDBUUCP -DBIGBUFOK \ -DUW7 -DNOGETUSERSHELL -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DPOSIX \ -DFNFLOAT -DCK_NEWTERM -DNOLSTAT $(KFLAGS)" \ "LIBS=-lsocket -lnsl -lcurses -ltermcap -lcrypt -lm -lresolv $(LIBS)" \ "LNKFLAGS = -s" # UnixWare 7 built with gcc - This does not work at all... # Reportedly gcc 2.8.1 is broken on Unixware 7. Try egcs? unixware7g: @echo 'Making C-Kermit $(CKVER) for UnixWare 7 with gcc...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CC = gcc" "CC2 = gcc" "LNKFLAGS = -s -shlib" "CFLAGS = -O -DUNIXWARE -DSELECT -DSVR4 -DDIRENT -DHDBUUCP -DBIGBUFOK \ -DUW7 -DNOGETUSERSHELL -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DNOLSTAT \ -DFNFLOAT -DCK_NEWTERM $(KFLAGS)" \ "LIBS=-lsocket -lnsl -lcurses -ltermcap -lcrypt -lm -lresolv $(LIBS)" \ "LNKFLAGS = -s" unixware7: $(MAKE) "MAKE=$(MAKE)" "KFLAGS=$(KFLAGS)" unixware7t \ KTARGET=$${KTARGET:-$(@)} uw7: $(MAKE) "MAKE=$(MAKE)" "KFLAGS=$(KFLAGS)" unixware7t \ KTARGET=$${KTARGET:-$(@)} #SCO OpenUNIX 8.0 ou8: @echo 'Making C-Kermit $(CKVER) for Open UNIX 8...' $(MAKE) "MAKE=$(MAKE)" "KFLAGS=-DOU8 $(KFLAGS)" unixware7t \ KTARGET=$${KTARGET:-$(@)} #UnixWare 7 with OpenSSL uw7ssl uw7+ssl: @echo 'Making C-Kermit $(CKVER) for UnixWare 7 and OpenSSL...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DCK_AUTHENTICATION -DCK_SSL -DCK_SHADOW \ -DUNIXWARE -DSELECT -DSVR4 -DDIRENT -DHDBUUCP -DBIGBUFOK \ -DFNFLOAT -DNOGETUSERSHELL -DSTERMIOX -DCK_CURSES -DTCPSOCKET -DPOSIX \ -DUW7 -DUSETCSETSPEED -DCK_NEWTERM -DNOLSTAT -DDCLTIMEVAL \ $(SSLINC) $(KFLAGS)" \ "LIBS=-lsocket -lnsl -lcurses -ltermcap -lcrypt -lm -lresolv \ -lgen -lcudk70 $(SSLLIB) -lssl -lcrypto $(LIBS)" \ "LNKFLAGS = -s" #As above but includes Shadow password support needed for IKSD. uw7iksd: $(MAKE) "MAKE=$(MAKE)" "KFLAGS=-DCK_SHADOW $(KFLAGS)" \ KTARGET=$${KTARGET:-$(@)} "LIBS= -lgen" unixware7t #As above but links with static API for realpath() so a binary built #with this target on UW7.1 will also work on 7.0. Requires SCO UDK #rather than the stock compiler. uw7iksdudk: $(MAKE) "MAKE=$(MAKE)" "KFLAGS=-DCK_SHADOW $(KFLAGS)" \ KTARGET=$${KTARGET:-$(@)} "LIBS= -lgen -lcudk70" unixware7t #ESIX SVR4.0.3 or 4.04 with TCP/IP support. #Has , ANSI C function prototyping disabled. #Add -m486 to CFLAGS if desired. esixr4: @echo 'Making C-Kermit $(CKVER) for ESIX SVR4 + TCP/IP...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DNOANSI \ -DSTERMIOX -DTCPSOCKET $(KFLAGS)" "LNKFLAGS = -s" \ "LIBS = -lsocket -lnsl" #AT&T UNIX System V R4. #Has , Wollongong WIN/TCP TCP/IP. sys5r4sxnet: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP \ -DSTERMIOX -DWOLLONGONG $(KFLAGS)" "LNKFLAGS = -s" #AT&T UNIX System V R4, no or . sys5r4nx: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DNOLEARN $(KFLAGS)" \ "LNKFLAGS = -s" #AT&T UNIX System V R4, no or , curses, TCP/IP. sys5r4nxnetc: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP \ -DCK_CURSES -DTCPSOCKET $(KFLAGS)" \ "LIBS = -lcurses -lsocket -lnsl -ltcpip" \ "LNKFLAGS = -s" #AT&T UNIX System V R4, no or , Wollongong TCP/IP. sys5r4nxtwg: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System V R4...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DDIRENT -DHDBUUCP -DWOLLONGONG $(KFLAGS)" "LNKFLAGS = -s" #ICL UNIX System V R4.(DRS N/X) version :- #UNIX System V Release 4.0 ICL DRS 6000 (SPARC) #DRS/NX 6000 SVR4 Version 5 Level 1 Increment 4 #Has , regular Berkeley sockets library, i.e. in.h and inet.h #are not misplaced in sys (rather than netinet and arpa, respectively). #Uses ANSI C constructs, advisory file locking on devices, etc. #Remove -lnsl if it causes trouble. iclsys5r4: @echo 'Making C-Kermit $(CKVER) for ICL UNIX System V R4 (DRS N/X)' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DICL_SVR4 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \ -DSTERMIOX -DTCPSOCKET $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lresolv " "LNKFLAGS = -s" #As above but for DRS/NX 4.2MP 7MPlus. iclsys5r4m+: @echo 'Making C-Kermit $(CKVER) for ICL UNIX System V R4 DRS/NX 4.2MP+' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DICL_SVR4 -DDIRENT -DHDBUUCP -DNOIKSD \ -DSTERMIOX -DTCPSOCKET $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lm -lc -g -lgen " "LNKFLAGS = -s" #As above but for DRS/NX 4.2MP 7MPlus with IKSD support. iclsys5r4m+iksd: @echo 'Making C-Kermit $(CKVER) for ICL UNIX System V R4 DRS/NX 4.2MP+' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DICL_SVR4 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \ -DSTERMIOX -DTCPSOCKET $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lm -lc -g -lgen -lresolv " "LNKFLAGS = -s" iclsys5r4_486: $(MAKE) "MAKE=$(MAKE)" iclsys5r4 KTARGET=$${KTARGET:-$(@)} #Data General DG/UX 4.30 (System V R3) for DG AViiON, with TCP/IP support. dgux430: @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 4.30...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DDGUX430 -DSVR3 -DDIRENT -DTCPSOCKET \ -DNOINADDRX -DNOGETUSERSHELL $(KFLAGS)" #Data General DG/UX 4.30 for DG AViiON, with TCP/IP support with BSDisms. dgux430bsd: @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 4.30...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DDGUX430 -D_BSD_SOURCE -DBSD4 \ -DNOINADDRX -DTCPSOCKET -DNOGETUSERSHELL $(KFLAGS)" #Data General DG/UX 5.4 (System V R4) for DG AViiON, with TCP/IP support. #Add -lsocket -lnsl if inet_addr comes up missing... #Hmmm - I really think CK_POLL can be removed from this one in which case #there is no difference between dgux540 and dgux540i. dgux540: @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 5.40...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DDGUX540 -DDIRENT -DHDBUUCP -DNOINADDRX \ -DSTERMIOX -DTCPSOCKET -DCK_POLL -DNOGETUSERSHELL $(KFLAGS)" #Data General DG/UX 5.40 (System V R4) for Intel AViiON, with TCP/IP support. dgux540i: @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 5.40...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DDGUX540 -DDIRENT -DHDBUUCP -DNOINADDRX \ -DSTERMIOX -DTCPSOCKET -DNOGETUSERSHELL $(KFLAGS)" \ "LIBS = -lsocket -lnsl" dgux54: make dgux540 KTARGET=$${KTARGET:-$(@)} #Data General DG/UX 5.4 (= System V R4) for DG AViiON, with TCP/IP support. # And curses. dgux540c: @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 5.4...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DDGUX540 -DDIRENT -DHDBUUCP -DNOINADDRX \ -DSTERMIOX -DTCPSOCKET -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL \ $(KFLAGS)" "LIBS= -lcurses8 -ltermcap" "LNKFLAGS = -s" #As above but for Intel - only difference is name library names. dgux540ic: @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 5.40...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DDGUX540 -DDIRENT -DHDBUUCP -DNOINADDRX \ -DSTERMIOX -DTCPSOCKET -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL \ $(KFLAGS)" "LIBS = -lsocket -lnsl -lcurses -ltermcap" dgux54c: make dgux540c KTARGET=$${KTARGET:-$(@)} #DG/UX 5.4R3.10 dgux54310: @echo 'Making C-Kermit $(CKVER) for DG AViiON DG/UX 5.4R3...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DDGUX540 -DDGUX54310 -DDIRENT -DHDBUUCP -DSELECT \ -DSTERMIOX -DTCPSOCKET -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL \ -DNOINADDRX $(KFLAGS)" "LIBS= -lcurses8 -ltermcap" "LNKFLAGS = -s" #DG/UX 5.4R4.10 - Includes everything. dgux54410: @echo 'Making C-Kermit $(CKVER) for DG/UX 5.4R4.10...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DDGUX540 -DDGUX54410 -DDIRENT -DHDBUUCP -DSELECT \ -DSTERMIOX -DTCPSOCKET -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL \ -DNOINADDRX $(KFLAGS)" "LIBS = -lsocket -lnsl -lcurses -ltermcap" #DG/UX 5.4R4.11 - Includes everything. dgux54411: @echo 'Making C-Kermit $(CKVER) for DG/UX 5.4R4.11...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DDGUX540 -DDGUX54411 -DDIRENT -DHDBUUCP -DSELECT \ -DSTERMIOX -DTCPSOCKET -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL \ -DNOINADDRX $(KFLAGS)" "LIBS = -lsocket -lnsl -lcurses -ltermcap" #DG/UX 5.4R4.20 - Includes everything. dgux54420: @echo 'Making C-Kermit $(CKVER) for DG/UX 5.4R4.20...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DDGUX540 -DDGUX54420 -DDIRENT -DHDBUUCP -DSELECT \ -DSTERMIOX -DTCPSOCKET -DCK_CURSES -DCK_NEWTERM -DNOGETUSERSHELL \ -DNOINADDRX $(KFLAGS)" \ "LIBS = -lsocket -lresolv -lnsl -lcurses -ltermcap" #Silicon Graphics System V R3 with BSD file system (IRIS) iris: @echo Making C-Kermit $(CKVER) for Silicon Graphics IRIX pre-3.3... $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR3 -DLONGFN -DNOLEARN $(KFLAGS) -I/usr/include/bsd" \ "LIBS = -lbsd" #Silicon Graphics IRIS System V R3 irix33: @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 3.3...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DNOLEARN $(KFLAGS) -O" \ "LNKFLAGS = -s" #Silicon Graphics Iris Indigo with IRIX 4.0.0 or 5.0... #Strict ANSI C compilation, TCP/IP support included irix40: @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 4.0...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DIRIX40 -DSVR3 -DDIRENT -DHDBUUCP -DPWID_T=uid_t \ -DCK_ANSIC -DTCPSOCKET $(KFLAGS) -O -Olimit 1600 -I/usr/include/bsd" \ "LNKFLAGS = -s" #As above, but with fullscreen display (curses) and Sun Yellow Pages support. #NOTE: IRIX versions prior to 5 run COFF binaries. irix40ypc: @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 4.0.' @echo 'Includes fullscreen file display and Sun Yellow Pages...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DIRIX40 -DSVR3 -DDIRENT -DHDBUUCP -DCK_CURSES \ -DPWID_T=uid_t -DCK_ANSIC -DTCPSOCKET $(KFLAGS) \ -O -Olimit 1600 -I/usr/include/bsd" \ "LIBS = -lcurses -lsun" "LNKFLAGS = -s" # Silicon Graphics Iris Series 4D/*, IRIX 4.0.x, -O4 ucode optimized. # Huge temporary file space needed for ucode optimizer. If you get an error # like "ugen: internal error writing to /tmp/ctmca08777: Error 0", define the # the TMPDIR environment variable to point to a file system that has more # space available, e.g. "setenv TMPDIR /usr/tmp". irix40u: @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 4.0...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DIRIX40 -DSVR3 -DDIRENT -DHDBUUCP -DPWID_T=uid_t \ -DCK_ANSIC -DTCPSOCKET $(KFLAGS) -O4 -Olimit 1600" \ "LNKFLAGS=-O4 -Olimit 1600 -s" "EXT=u" # As above, with Curses Support added irix40uc: @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 4.0...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DIRIX40 -DSVR3 -DDIRENT -DHDBUUCP -DPWID_T=uid_t \ -DCK_ANSIC -DCK_CURSES -DTCPSOCKET $(KFLAGS) -O4 -Olimit 1600" \ "LNKFLAGS=-O4 -Olimit 1600 -s" "EXT=u" "LIBS= -lcurses -ltermcap" #Silicon Graphics IRIX 5.x. #Yellow Pages and Curses support included. #IRIX version 5.x can run COFF or ELF binaries. irix51: @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 5.x' @echo 'Includes fullscreen file display and Yellow Pages...' @echo 'Add -mips to CFLAGS specify a particular hardware target.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DIRIX51 -DSVR4 -DDIRENT -DHDBUUCP -DCK_CURSES -DCK_NEWTERM \ -DPWID_T=uid_t -DCK_ANSIC -DTCPSOCKET -DSELECT -DNOGETUSERSHELL \ -DSYSTIMEH -DDCLPOPEN -DDCLFDOPEN $(KFLAGS) -ansi -O -Olimit 3000" \ "LIBS = -lcurses" "LNKFLAGS = -s" #Use this one if irix51 blows up due to lack of swap space or whatever. irix51x: @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 5.x' @echo 'Includes fullscreen file display and Yellow Pages...' @echo 'Add -mips to CFLAGS specify a particular hardware target.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DIRIX51 -DSVR4 -DDIRENT -DHDBUUCP -DCK_CURSES -DCK_NEWTERM \ -DPWID_T=uid_t -DCK_ANSIC -DTCPSOCKET -DSELECT -DNOGETUSERSHELL \ -DSYSTIMEH -DDCLPOPEN -DDCLFDOPEN $(KFLAGS)" \ "LIBS = -lcurses" "LNKFLAGS = -s" irix51ypc: $(MAKE) "MAKE=$(MAKE)" irix51 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS= $(KFLAGS)" #IRIX 5.2 adds RTS/CTS irix52: $(MAKE) "MAKE=$(MAKE)" irix51 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DIRIX52 -DCK_RTSCTS $(KFLAGS)" irix53: $(MAKE) "MAKE=$(MAKE)" irix51 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DIRIX52 -DIRIX53 -DCK_RTSCTS $(KFLAGS)" irix53x: $(MAKE) "MAKE=$(MAKE)" irix51x KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DIRIX52 -DIRIX53 -DCK_RTSCTS $(KFLAGS)" #Silicon Graphics IRIX 6.[024] common stuff. #Yellow Pages and Curses support included. #IRIX version 6.0 and later runs only ELF binaries. #Depends on code changes in ckcdeb.h that make -DIRIX6x define all #lower IRIX6x values and IRIX51. irix6x: @echo 'Includes fullscreen file display and Yellow Pages...' @echo 'Add -mips to specify a particular hardware target.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSVR4 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \ -DCK_CURSES -DCK_NEWTERM -DPWID_T=uid_t -DCK_ANSIC -DTCPSOCKET \ -DSELECT -DCK_RTSCTS -O $(KFLAGS)" \ "LIBS = -lcurses" "LNKFLAGS = -s $(LNKFLAGS)" #Silicon Graphics IRIX 6.0. irix60: @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 6.0' @$(MAKE) "MAKE=$(MAKE)" \ "KFLAGS=-DIRIX60 -Olimit 2138 $(KFLAGS)" \ irix6x KTARGET=$${KTARGET:-$(@)} #Silicon Graphics IRIX 6.2. #Serial speeds > 38400 are available in IRIX 6.2 on O-class machines only. #Note: Olimit must be a number > 0. irix62: @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 6.2' @$(MAKE) "MAKE=$(MAKE)" \ LNKFLAGS="-Wl,-woff,84" \ "KFLAGS=-DIRIX62 -Olimit 4700 $(KFLAGS)" \ irix6x KTARGET=$${KTARGET:-$(@)} #Silicon Graphics IRIX 6.3. irix63: @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 6.3' @$(MAKE) "MAKE=$(MAKE)" irix62 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DIRIX63" #Silicon Graphics IRIX 6.4. # -woff,84 to linker stops complaints about no symbols loaded from # curses, and -woff 1110 stops complaints about unreachable "break;" # statements in ckcpro.c among others. # tested on SGI Octane, running IRIX 6.4 up to 115200 bps. # -Olimit 0 means infinite. irix64: @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 6.4' @$(MAKE) "MAKE=$(MAKE)" \ LNKFLAGS="-Wl,-woff,84" \ "KFLAGS=-DIRIX64 -DCK_RTSCTS -Olimit 3000 -woff 1110 $(KFLAGS)" \ irix6x KTARGET=$${KTARGET:-$(@)} irix64gcc: @echo 'Making C-Kermit $(CKVER) for Silicon Graphics IRIX 6.4 gcc' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS= -DSVR4 -DIRIX64 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \ -DSELECT -DPWID_T=uid_t -DTCPSOCKET -DNOCOTFMC \ -DCK_ANSIC -DCK_RTSCTS -DCK_NEWTERM -DCK_CURSES \ $(KFLAGS) -O" "LIBS= -lcurses -ltermcap -lcrypt" #Note the new Optimization option syntax for MIPSpro CC 7.2.1.2m. #See note on irix65gcc target about Large File Support (LFS). irix65: @echo 'Making C-Kermit $(CKVER) for SGI IRIX 6.5' @$(MAKE) "MAKE=$(MAKE)" LNKFLAGS="-Wl,-woff,84" \ "KFLAGS=-DIRIX65 -D_LARGEFILE_SOURCE -DCK_RTSCTS -OPT:Olimit=0 \ -woff 1110,1552,1174 $(KFLAGS)" \ irix6x KTARGET=$${KTARGET:-$(@)} #Build for those that have GCC instead of MIPSpro. # # Large File Support note: use the define _LARGEFILE_SOURCE to enable support # for files larger than 2GB. This may work on releases of Irix prior to # 6.5.xx. To verify, check the man page for fstat and verify that off_t is a # 64 bit value for an -n32 build. Also check the manpage for fseek and ftell # to verify that the fseek64 and ftell64 functions are provided. If so, then # LFS support should work and you can try adding -D_LARGEFILE_SOURCE to CFLAGS # for your selected Irix target. # irix65gcc: @echo 'Making C-Kermit $(CKVER) for SGI IRIX 6.5 with gcc' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CC = gcc" "CC2 = gcc" \ "CFLAGS= -DSVR4 -DIRIX65 -D_LARGEFILE_SOURCE -DDIRENT -DHDBUUCP \ -DNOGETUSERSHELL -DSELECT -DPWID_T=uid_t -DTCPSOCKET -DNOCOTFMC \ -DCK_ANSIC -DCK_RTSCTS -DCK_NEWTERM -DCK_CURSES \ $(KFLAGS) -O" "LIBS= -lcurses" # The 64-bit IRIX target works but presumably is no longer needed given the # large file support in the more portable and compact 32-bit version. irix65_64: @echo 'Making C-Kermit $(CKVER) 64-bit for SGI IRIX 6.5' @$(MAKE) "MAKE=$(MAKE)" LNKFLAGS="-Wl,-woff,84" \ "KFLAGS=-DIRIX65 -64 -DCK_RTSCTS -OPT:Olimit=0 -woff 1110,1552,1174 \ -DCK_64BIT $(KFLAGS)" \ irix6x KTARGET=$${KTARGET:-$(@)} #Dumb down to MIPS-2 if building on R5000 or higher... irix65mips2: @echo 'Making C-Kermit $(CKVER) for SGI IRIX 6.5 MIPS-2' @$(MAKE) "MAKE=$(MAKE)" LNKFLAGS="-o32 -mips2 -Wl,-woff,84" \ "KFLAGS=-DIRIX65 -DCK_RTSCTS -OPT:Olimit=0 -o32 -mips2 \ -woff 1110,1552,1174 $(KFLAGS)" \ irix6x KTARGET=$${KTARGET:-$(@)} #Special target that adds srp, ssl, and zlib support. This requires #that you have pkgsrc installed instead of Irix Freeware. See #NetBSD.org for pkgsrc for Irix. You will need to BUILD the srp_client #package yourself. Install it manually using the directions found #in the netbsds+ssl+srp+zlib target comments. irix65+ssl+srp+zlib: @echo 'Making C-Kermit $(CKVER) for IRIX 6.5 with gcc and SSL SRP ZLIB' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CC = gcc" "CC2 = gcc" \ "CFLAGS= -DIRIX65 -DSVR4 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL -DSELECT \ -DTCPSOCKET -DNOCOTFMC -DCK_NEWTERM -DPWID_T=uid_t -DCK_ANSIC \ -I/usr/pkg/include -DCK_AUTHENTICATION -DCK_SRP -DPRE_SRP_1_4_5 \ -DCK_RTSCTS -DCK_NCURSES -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DCK_SSL \ -DLIBDES -DZLIB -DFNFLOAT -I/usr/pkg/include/openssl $(KFLAGS) -O" \ "LIBS= -L/usr/pkg/lib -rpath /usr/pkg/lib -lncurses -lsrp -lgmp -ldes \ -lssl -lkrypto -lcrypto -lcrypt -lz -lm" irix6x+krb5: @echo 'Includes fullscreen file display and Yellow Pages...' @echo 'Add -mips to specify a particular hardware target.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSVR4 -DDIRENT -DHDBUUCP -DNOGETUSERSHELL \ -DCK_CURSES -DCK_NEWTERM -DPWID_T=uid_t -DCK_ANSIC -DTCPSOCKET\ -DSELECT -DCK_RTSCTS -O \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DCK_ENCRYPTION -DCK_DES \ $(K5INC) $(K5INC)/krb5 $(KFLAGS)" \ "LIBS = -lcurses $(K5LIB) -ldes425 -lkrb5 \ -lcom_err -lcrypto -lcrypt -lgssapi_krb5" \ "LNKFLAGS = -s $(LNKFLAGS)" irix65+krb5: @echo 'Making C-Kermit $(CKVER) for SGI IRIX 6.5' @$(MAKE) "MAKE=$(MAKE)" \ LNKFLAGS="-Wl,-woff,84" \ "KFLAGS=-DIRIX65 -DCK_RTSCTS -OPT:Olimit=0 -woff 1110,1552,1174 \ $(KFLAGS)" \ irix6x+krb5 KTARGET=$${KTARGET:-$(@)} #In case they type "make sys5"... sys5: $(MAKE) "MAKE=$(MAKE)" sys3 KTARGET=$${KTARGET:-$(@)} #Generic ATT System III or System V (with I&D space) sys3: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System III' @echo 'or System V R2 or earlier...' @echo 'add -DNOMKDIR if mkdir is an undefined symbol.' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATTSV -DNOUNICODE -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL \ -DNOINITGROUPS -DNOFTRUNCATE -DNOREALPATH -DNOLEARN $(KFLAGS) -i -O" \ "LNKFLAGS = -i" #Generic ATT System III or System V (no I&D space) sys3nid: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System III' @echo 'or System V R2 or earlier, no I&D space...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATTSV -DNOREALPATH -DNOUNICODE -DNOSYSLOG -DNOSYMLINK \ -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE -DNOLEARN $(KFLAGS) -O" \ "LNKFLAGS =" #Generic ATT System III or System V R2 or earlier, "no void": #special entry to remove "Illegal pointer combination" warnings. sys3nv: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System III' @echo 'or System V R2 or earlier...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DATTSV -DNOREALPATH -DNOUNICODE -DNOSYSLOG -DNOGETUSERSHELL \ -DNOSYMLINK -DNOFTRUNCATE -DNOINITGROUPS -DNOLEARN \ -Dvoid=int $(KFLAGS) -i -O" \ "LNKFLAGS = -i" # AT&T 7300 UNIX PC. As of C-Kermit 6.1, many of these entries don't work # any more due to "Out of memory" or "Too many defines" errors during # compilation, at least not on systems without lots of memory. The sys3upcgc # entry works (using gcc) with optimization removed, and might also work # with optimization enabled on machines with larger memories. #AT&T 7300/UNIX PC (3B1) systems, sys3 but special handling for internal modem. #Link with the shared library -- the conflict with openi in shared library #is solved with -Dopeni=xopeni. Note that the xermit target can't be used #for the Unix PC; there is no select(). sys3upc: @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC, shared lib...' @echo 'If shared lib causes trouble, use make sys3upcold.' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DATT7300 -DNOMKDIR -DUSE_MEMCPY -DNOREALPATH -DNOLEARN \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DNOREDIRECT -DNOGFTIMER -DNOUNICODE $(KFLAGS) -Dopeni=xopeni" \ "CC2 = ld /lib/crt0s.o /lib/shlib.ifile" "LNKFLAGS = -s" #AT&T 7300/Unix PC systems, minimum kermit for those with smaller amounts #of memory. sys3upcm: @echo Minimum interactive $(MAKE) "MAKE=$(MAKE)" sys3upc KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DNOSPL -DNOFRILLS -DNOHELP -DNODEBUG -DNOTLOG -DNOCSETS \ -DNOSYSLOG -DNOSETKEY -DNOREALPATH" #AT&T 7300/UNIX PC (3B1) systems, with curses support. #Curses and the shared library don't get along, so we don't use the #shared library. We need to include CK_NEWTERM to avoid a conflict #with curses and buffering on stdout. Merged with submission by #Robert Weiner/Programming Plus, rweiner@watsun.cc.columbia.edu. #We don't need -Dopeni=xopeni since we're not using the shared library, #but we keep it to be consistent with the other entries. sys3upcc: @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC, curses...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DATT7300 -DNOREALPATH \ -DCK_CURSES -DCK_NEWTERM -DNOMKDIR -DNOREDIRECT -DNOGFTIMER -DNOLEARN \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DUSE_MEMCPY -DNOUNICODE $(KFLAGS) -Dopeni=xopeni" \ "LIBS = -lcurses" "LNKFLAGS = -s" #Like sys3upcc but for AT&T UNIX 3.51m (released as a patch on Fix Disk 2), #adds hardware flow control. att351m: $(MAKE) "MAKE=$(MAKE)" sys3upcc KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DCK_RTSCTS -DUNIX351M" #As above but with gcc. att351gm: $(MAKE) "MAKE=$(MAKE)" sys3upcgc KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DCK_RTSCTS -DUNIX351M" #AT&T 7300 UNIX PC (3B1), as above, but no newterm(). sys3upcx: @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC, curses...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DATT7300 -DNOREALPATH -DNOUNICODE -DNOLEARN \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DCK_CURSES -DNOMKDIR -DNOREDIRECT -DNOGFTIMER -DUSE_MEMCPY $(KFLAGS) \ -Dopeni=xopeni" "LIBS = -lcurses -ltermcap" "LNKFLAGS = -s" #AT&T 7300/UNIX PC (3B1) systems, with curses and shared library support. sys3upcshcc: @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC, shared lib...' @echo 'With curses. Requires shcc.' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DATT7300 -DNOMKDIR -DNOREALPATH -DNOLEARN \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DCK_NEWTERM -DCK_CURSES -DNOREDIRECT -DNOGFTIMER \ -DUSE_MEMCPY -DNOUNICODE $(KFLAGS) -Dopeni=xopeni" \ "LNKFLAGS = -i -s" "CC = shcc" "CC2 = shcc" "LIBS = -lcurses" #AT&T 7300/UNIX PC (3B1) systems, as above, no curses, but use gcc. sys3upcg: @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATT7300 -DNOREDIRECT -DUSE_MEMCPY -DNOUNICODE -DNOLEARN \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DNOGFTIMER -DNOMKDIR -DNOREALPATH $(KFLAGS) -Dopeni=xopeni" \ "CC = gcc" "CC2 = gcc" "LNKFLAGS = -s -shlib" #AT&T 7300/UNIX PC (3B1) systems, curses and gcc. #Optimization omitted -- add it back in if your machine has lots of memory. sys3upcgc: @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC, curses...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATT7300 -DNOREDIRECT -DUSE_MEMCPY -DNOGFTIMER -DNOUNICODE \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DCK_CURSES -DCK_NEWTERM -DNOMKDIR -DNOREALPATH -DNOLEARN $(KFLAGS)" \ "CC = gcc" "CC2 = gcc" "LIBS = -lcurses" "LNKFLAGS = -s" #AT&T 7300/UNIX PC (3B1) systems, special handling for internal modem. #No FULLSCREEN file transfer display (curses). sys3upcold: @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATT7300 -DNOMKDIR -DUSE_MEMCPY -DNOUNICODE -DNOLEARN \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DNOGFTIMER -DNOREDIRECT -DNOREALPATH $(KFLAGS) -O" "LNKFLAGS = -i" #As above, but with gcc. mininum features - fits on a 400K UNIX PC floppy #after compression with room to spare; add -DNOSHOW or other -DNOxxxx items #to reduce size even further. sys3upcgm: @echo Minimum interactive $(MAKE) "MAKE=$(MAKE)" sys3upcg KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DNOSPL -DNOFRILLS -DNOHELP -DNODEBUG -DNOTLOG -DNOCSETS \ -DNOSETKEY $(KFLAGS)" #This target is designed to create a version with the most features possible #that, after compression, still fits on a 400K UNIX PC floppy. sys3upcgfd: @echo 'Making C-Kermit $(CKVER) for AT&T 7300 UNIX PC floppy...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATT7300 -DNOREDIRECT -DUSE_MEMCPY -DNOSPL -DNOLEARN \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DNOGFTIMER -DNOREALPATH -Dopeni=xopeni \ -DNOHELP -DNODEBUG -DNOTLOG -DNOCSETS -DNOSETKEY -DNOMKDIR $(KFLAGS)" \ "CC = gcc" "CC2 = gcc" "LNKFLAGS = -s" #AT&T 6300 PLUS (warning, -O might make it run out of space). #NOTE: Remove -DHDBUUCP if not using Honey DanBer UUCP. att6300: @echo 'Making C-Kermit $(CKVER) for AT&T 6300 PLUS...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATT6300 -DHDBUUCP -DNOFILEH -DNOREALPATH -DNOLEARN \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DNOUNICODE $(KFLAGS) -O -Ml -i" "LNKFLAGS = -i -Ml" #As above, but with curses support. Debugging disabled to prevent thrashing. att6300c: @echo 'Making C-Kermit $(CKVER) for AT&T 6300 PLUS...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATT6300 -DHDBUUCP -DNOFILEH -DNOCSETS -DNOREALPATH \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DCK_CURSES -DNODEBUG -DNOUNICODE -DNOLEARN $(KFLAGS) -O -Ml -i" \ "LNKFLAGS = -i -Ml" "LIBS = -lcurses" #AT&T 6300 PLUS with no curses, no debugging (about 34K smaller) # -Optimization saves about 20K too. att6300nd: @echo 'Making C-Kermit $(CKVER) for AT&T 6300 PLUS, no debugging...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATT6300 -DHDBUUCP -DNODEBUG -DNOFILEH -DNOREALPATH \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DNOUNICODE -DNOLEARN $(KFLAGS) -O -i -Ml" "LNKFLAGS = -i -Ml" #AT&T 3B2 and maybe 3B20-series computers running AT&T UNIX System V R3. #This one was actually used to build C-Kermit 7.0 successfully on a 3B2/300. att3b2: @echo 'Making C-Kermit $(CKVER) for AT&T 3B2' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATTSV -DNOREDIRECT -DUSE_MEMCPY \ -DNOTIMEVAL -DNOTIMEZONE -DMINIDIAL -DNOCHANNELIO -DNOBIGBUF \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DNOGFTIMER -DNOREALPATH -Dopeni=xopeni -DNOFRILLS -DNOLEARN \ -DNOHELP -DNODEBUG -DNOTLOG -DNOCSETS -DNOSETKEY -DNOMKDIR $(KFLAGS)" \ "CC = gcc" "CC2 = gcc" "LNKFLAGS = -s" # The next two are likely not to work as-is. #AT&T 3B2, 3B20-series computers running AT&T UNIX System V. #This is just generic System V with Honey DanBer UUCP, so refer to sys3hdb. #Remove -DNONAWS if you can get away with it. att3bx: $(MAKE) "MAKE=$(MAKE)" sys3hdb KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(KFLAGS) -DNONAWS -DNOTIMEVAL" # 3Bx with charsets (except Unicode) but no curses. att3bx1: @echo 'Making C-Kermit $(CKVER) for AT&T 3B2 or 3B20' @echo 'with Honey DanBer UUCP no curses...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATTSV -DHDBUUCP $(KFLAGS) -DNOREDIRECT \ -DNOTIMEVAL -DNOTIMEZONE -DMINIDIAL -DNOCHANNELIO -DNOBIGBUF \ -DNOHELP -DNODEBUG -DNOGFTIMER -DNOLEARN \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DNOREALPATH -DNOUNICODE -i" \ "CC = gcc" "CC2 = gcc" "LNKFLAGS = -i -s" #AT&T 3B2, 3B20-series computers running AT&T UNIX System V, #with fullscreen file transfer display. att3bxc: @echo 'Making C-Kermit $(CKVER) for AT&T 3B2 or 3B20' @echo 'with Honey DanBer UUCP and curses...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATTSV -DHDBUUCP -DNONAWS -DNOTIMEVAL $(KFLAGS) \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DNOREALPATH -DCK_CURSES -DCK_NEWTERM -DNOUNICODE -DNOLEARN -i -O" \ "LNKFLAGS = -i" "LIBS=-lcurses" #3bx with curses but no charsets att3bxc3: @echo 'Making C-Kermit $(CKVER) for AT&T 3B2 or 3B20' @echo 'with Honey DanBer UUCP with curses... no CSETS' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATTSV -DHDBUUCP $(KFLAGS) -DNOREDIRECT \ -DNOTIMEVAL -DNOTIMEZONE -DMINIDIAL -DNOCHANNELIO -DNOBIGBUF \ -DNOHELP -DNODEBUG -DNOGFTIMER -DNOLEARN \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DNOREALPATH -DNOCSETS -DCK_CURSES -DCK_NEWTERM -i" \ "CC = gcc" "CC2 = gcc" "LNKFLAGS = -i -s" "LIBS = -lcurses" #Any System V R2 or earlier with Honey DanBer UUCP (same as above) sys3hdb: @echo 'Making C-Kermit $(CKVER) for AT&T UNIX System III' @echo 'or System V R2 or earlier with Honey DanBer UUCP...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATTSV -DHDBUUCP -DNOREALPATH -DNOUNICODE -DNOLEARN \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ $(KFLAGS) -i -O" "LNKFLAGS = -i" #Sperry/UNISYS 5000 UTS V 5.2 (System V R2), Honey DanBer UUCP unisys5r2: @echo 'Making C-Kermit $(CKVER) for Sperry/UNISYS 5000 UTS V 5.2...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATTSV -DUNISYS52 -DHDBUUCP -DNOREALPATH -DNOUNICODE \ -DNOSYSLOG -DNOSYMLINK -DNOGETUSERSHELL -DNOINITGROUPS -DNOFTRUNCATE \ -DNOLEARN $(KFLAGS) -i -O" "LNKFLAGS = -i" #In case they say "make sys5hdb" instead of "make sys3hdb"... sys5hdb: $(MAKE) "MAKE=$(MAKE)" sys3hdb #Create the common header line for all hpux[5-11]* entries and above. This #extra entry is here because our header message length may differ for each #C-Kermit version. Don't use 'fold -s' for HP-UX 5.x - 7.x! This option is #available only for HP-UX 8.0 and above! hpux-header: @HPUX=`uname -r | sed -e 's/^[^1-9]*//' -e 's/\.00$$/.0/'` ; \ [ "$(MESSAGE0)" ] && MESSAGE1="$(MESSAGE0)" ; \ Message0='Making C-Kermit $(CKVER) for HP9000 HP-UX' ; \ Message1=$${MESSAGE1:='without any extra compiler optimization'} ; \ MessageH="$$Message0 $$HPUX" ; \ case $$HPUX in \ [567].*) echo "$$MessageH\n$$Message1" ;; \ *.*) echo "$$MessageH $${Message1}$(MESSAGE1A)" | fold -s ;; \ esac | sed -e 's/^ //' -e 's/ *$$//' # Peter E's updated HP-UX 5.xx entries Oct 2001. #HP-9000 500 HP-UX 5.xx, no TCP/IP. # Last known successful build: C-Kermit 8.0.206 2002/20/27. hpux0500: @MESSAGE0="no TCP/IP and no compiler optimization";\ MESSAGE0=$${MESSAGE1:-$$MESSAGE0} \ $(MAKE) hpux-header $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DHPUX -DHPUX5 -DHPUXPRE65 -DNOREDIRECT -DDCLGETCWD \ -DNOGETUSERSHELL -DNOGFTIMER -DNOSYSLOG -DNOTOMACROS -DNOLSTAT \ -DNOSYMLINK -DNOINITGROUPS -DNOUNICODE -DNOLEARN -DNOLONGLONG \ -DVOID=int -DCKVOID=int $(KFLAGS)" "LIBS = $(LIBS)" "LNKFLAGS = " #HP-9000 500 HP-UX 5.21 with Wollongong WIN/TCP 1.2 TCP/IP. #Requires /usr/wins/usr/include and /usr/lib/libnet.a from Wollongong. #Optimization skipped - takes forever. Really. # WARNING: this doesn't work if a file called "hpux0500" is on the disk. # Last known successful build: C-Kermit 8.0.206 2002/20/27. hpux0500wintcp: @MESSAGE1="with WIN/TCP but without any extra compiler optimization" \ $(MAKE) hpux0500 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = -DTCPSOCKET -DHPUX5WINTCP -DINADDRX -DNO_DNS_SRV \ -DNOMHHOST -DVOID=int -DCKVOID=int -DNOHADDRLIST -DNOLONGLONG \ -I/usr/wins/usr/include $(KFLAGS)" "LIBS = /usr/lib/libnet.a" #HP-UX 6.5, short filenames, no network and no curses support. #ckcpro, ckuusr, ckuus3 and others are broken out because they make the #optimizer run away. Note that the XERMIT target does not work with HP-UX 6.5! # #If you get compiler warnings like: #'Switch table overflow. Try the -Wc,-Nw option.' (for ckcuni.c, or #other files) increase the '...' value in '-Wc,-Nw...'! The default maximum #switch table stack (-Nw) is 250 table entries. ckcuni.c from Oct 16 2009 #needs 257 table entries (C-Kermit Version "9.0.299"). #OK: 2010/03/26 hpux0650: @$(MAKE) hpux-header @MESSAGE2=$${MESSAGE2:-'and NO network'}; \ echo "supporting: NO long filenames $$MESSAGE2." $(MAKE) KTARGET=$${KTARGET:-$(@)} \ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckuus6.$(EXT) \ ckuusr.$(EXT) ckuxla.$(EXT) ckcftp.$(EXT) ckcpro.$(EXT) \ "CFLAGS = -DHPUX -DHPUX6 -DSIG_V -DNOSYSLOG -DNOSELECT -DFNFLOAT \ -DDCLGETCWD -DNOGETUSERSHELL -DNO_DNS_SRV -DNOLEARN -DNOLONGLONG \ $(KFLAGS)" $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DHPUX -DHPUX6 -DSIG_V -DNOSYSLOG -DNOSELECT -DFNFLOAT \ -DDCLGETCWD -DNOGETUSERSHELL -DNO_DNS_SRV -DNOLEARN -DNOLONGLONG \ $(KFLAGS) -Wc,-Nw260 $(OFLAGS)" "LNKFLAGS = -s" "LIBS = -lm $(LIBS)" #Exactly as above, plus curses: #OK: 2009/10/06 hpux0650c: @MESSAGE2="and NO network but with curses" \ $(MAKE) hpux0650 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = -DCK_CURSES $(KFLAGS)" \ "LIBS = -lcurses" #Exactly as above, plus curses + network: #OK: 2009/10/02 hpux0650tcpc: @MESSAGE2="but with curses and with TCP/IP" \ $(MAKE) hpux0650 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DCK_CURSES -DTCPSOCKET -DNOHADDRLIST \ -DINTSELECT -DNOCKGETFQHOST $(KFLAGS)" \ "LIBS=-lcurses" #Exactly as hpux0650 but with compiler optimization: #OK: 2009/10/06 hpux0650o: @MESSAGE1="with compiler optimization" \ $(MAKE) hpux0650 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS)" "OFLAGS = -O" #Exactly as hpux0650c but with compiler optimization: #OK: 2009/10/06 hpux0650oc: @MESSAGE1="with compiler optimization" \ $(MAKE) hpux0650c KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS)" "OFLAGS = -O" #Exactly as hpux0650tcpc but with compiler optimization: #OK: 2009/10/06 hpux0650otcpc: @MESSAGE1="with compiler optimization" \ $(MAKE) hpux0650tcpc KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS)" "OFLAGS = -O" #Take this as startup entry for all 'non-optimized' files under HP-UX 7.x! #Make sure we don't call it with the '-O' option because this will blow up #the compiler! #OK: 2009/09/30 hpux0700noopt: @case "$(CFLAGS)" in \ *-O*) echo "Don't use CFLAGS= -O here!" ;; \ *) $(MAKE) KTARGET=$${KTARGET:-$(@)} \ ckuusr.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \ ckuus6.$(EXT) ckuus7.$(EXT) ckuxla.$(EXT) \ ckcuni.$(EXT) ckcftp.$(EXT) ckcpro.$(EXT) \ ;; \ esac #HP-UX 7.0, no long filenames, no network support, no curses. #If you get compiler warnings like: #'Switch table overflow. Try the -Wc,-Nw option.' (for ckcuni.c, or #other files) increase the '...' value in '-Wc,-Nw...'! The default maximum #switch table stack (-Nw) is 250 table entries. ckcuni.c from Oct 16 2009 #needs 257 table entries (C-Kermit Version "9.0.299"). #OK: 2010/10/26 hpux0700sf: @$(MAKE) hpux-header @echo 'supporting: NO long filenames, NO network, NO curses.' $(MAKE) hpux0700noopt KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DHPUX -DHPUX7 -DSIG_V -DNOGETUSERSHELL -DFNFLOAT \ -DNO_DNS_SRV $(KFLAGS) -Wc,-Nw260" $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DHPUX -DHPUX7 -DSIG_V -DNOGETUSERSHELL -DFNFLOAT \ -DNO_DNS_SRV $(KFLAGS) -Wc,-Nw260 $(OFLAGS)" \ "LNKFLAGS = -s" "LIBS = -lm $(LIBS)" #Exactly as hpux0700sf but with compiler optimization: #OK: 2009/09/30 hpux0700osf: @MESSAGE1="with compiler optimization" \ $(MAKE) hpux0700sf KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS)" "OFLAGS = -O" #HP-UX 7.0, short filenames, but with tcp/ip and curses. #To use this, you must have bought the ARPA Services Product from HP, and you #must have /usr/lib/libBSD.a. # #If you get compiler warnings like: #'Symbol table overflow. Try the -Wc,-Ns option.' (as for ckuus4.c or #other files) increase the '...' value in '-Wc,-Ns...'! The default maximum #symbol table size (-Ns) is 2000 table entries. ckuus4.c from Mar 12 2010 #needs 2031 table entries (C-Kermit Version "9.0.299"). #OK: 2010/03/24 hpux0700sftcpc: @$(MAKE) hpux-header @echo 'supporting: NO long filenames, \c' @echo 'but with networking, curses, HDB uucp...' $(MAKE) hpux0700noopt KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DHPUXDEBUG -DHPUX -DHPUX7 -DTCPSOCKET -DSIG_V \ -DCK_REDIR -DCK_RTSCTS -DCK_CURSES -DNOGETUSERSHELL -DFNFLOAT \ -DNO_DNS_SRV -DHDBUUCP -DLOCK_DIR=\\\"/usr/spool/uucp\\\" \ -DNOLONGLONG $(KFLAGS) -Wc,-Nw260,-Ns2040" $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DHPUXDEBUG -DHPUX -DHPUX7 -DTCPSOCKET -DSIG_V \ -DCK_REDIR -DCK_RTSCTS -DCK_CURSES -DNOGETUSERSHELL -DFNFLOAT \ -DNO_DNS_SRV -DHDBUUCP -DLOCK_DIR=\\\"/usr/spool/uucp\\\" \ -DNOLONGLONG $(KFLAGS) -Wc,-Nw260,-Ns2040 $(OFLAGS)" \ "LNKFLAGS = -s" "LIBS = -lm -lBSD -lcurses" #Exactly as above but with compiler optimization: #OK: 2009/09/30 hpux0700osftcpc: @MESSAGE1="with compiler optimization" \ $(MAKE) hpux0700sftcpc KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS)" "OFLAGS = -O" #HP 9000 series 300/800 HP-UX 7.0, long filenames, network support, HDB uucp, #but NO curses. See comments in hpux0700sftcpc about TCP/IP support. # #If you get compiler warnings like: #'Symbol table overflow. Try the -Wc,-Ns option.' (as for ckuus4.c or #other files) increase the '...' value in '-Wc,-Ns...'! The default maximum #symbol table size (-Ns) is 2000 table entries. ckuus4.c from Mar 12 2010 #needs 2031 table entries (C-Kermit Version "9.0.299"). #OK: 2010/03/24 hpux0700lfn: @$(MAKE) hpux-header @echo 'supporting: long filenames, networking, HDB uucp$(MESSAGE2)...' $(MAKE) hpux0700noopt KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DHPUXDEBUG -DHPUX -DHPUX7 -DTCPSOCKET -DSIG_V -DFNFLOAT \ -DNOGETUSERSHELL -DNOSETBUF -DCK_REDIR -DCK_RTSCTS -DLONGFN \ -DNO_DNS_SRV -DDIRENT -DHDBUUCP -DLOCK_DIR=\\\"/usr/spool/uucp\\\" \ -DNOLONGLONG $(KFLAGS) -Wc,-Nw260,-Ns2040" $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DHPUXDEBUG -DHPUX -DHPUX7 -DTCPSOCKET -DSIG_V -DFNFLOAT \ -DNOGETUSERSHELL -DNOSETBUF -DCK_REDIR -DCK_RTSCTS -DLONGFN \ -DNO_DNS_SRV -DDIRENT -DHDBUUCP -DLOCK_DIR=\\\"/usr/spool/uucp\\\" \ -DNOLONGLONG $(KFLAGS) -Wc,-Nw260,-Ns2040 $(OFLAGS)" \ "LNKFLAGS = -s" "LIBS = -lm -lBSD $(LIBS)" #Exactly as above + curses. #OK: 2009/09/30 hpux0700lfnc: @MESSAGE2=', curses' \ $(MAKE) hpux0700lfn KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = -DCK_CURSES $(KFLAGS)" \ "LIBS = -lcurses" #Exactly as above hpux0700lfn but with compiler optimization: #OK: 2009/09/30 hpux0700olfn: @MESSAGE1="with compiler optimization" \ $(MAKE) hpux0700lfn KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS)" "OFLAGS = -O" #Exactly as above hpux0700lfnc but with compiler optimization: #OK: 2009/09/30 hpux0700olfnc: @MESSAGE1="with compiler optimization" \ $(MAKE) hpux0700lfnc KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS)" "OFLAGS = -O" #HP 9000 Series 300 or 400, HP-UX 8.0, long filenames and TCP/IP support. #This one should also work on 700/800, but without PA-specific optimization. #In case -DCK_RTSCTS and -DCK_REDIR make trouble, remove them. #NOTE: ckcpro.c, ckuusr.c and ckuus3.c blow up the optimizer, so don't optimize #them. #For HP-UX 8.0 on Motorola CPUs, you might have to reinstall your kernel with #maxdsiz >= 0x03000000. But if physical memory is small, that still will not #help much. #OK: 2009/10/01 hpux0800: @$(MAKE) hpux-header @MESSAGE3=$${MESSAGE3:='TCP/IP'}; \ echo "supporting: long filenames, $$MESSAGE3, HDB UUCP$(MESSAGE2)..." $(MAKE) -B "CC=$(CC)" "CC2=$(CC2)" KTARGET=$${KTARGET:-$(@)} \ ckcpro.$(EXT) ckuusr.$(EXT) ckuus3.$(EXT) \ "CFLAGS = -DCK_REDIR -DHPUXDEBUG -DHPUX -DHPUX8 -DRENAME -DSIG_V \ -DNOSETBUF -DDIRENT -DCK_RTSCTS -DSTERMIOX -DLONGFN -DTCPSOCKET \ -DHDBUUCP -DNO_DNS_SRV -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DFNFLOAT \ -DNOLONGLONG $(KFLAGS)" $(MAKE) -B "CC=$(CC)" "CC2=$(CC2)" xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DCK_REDIR -DHPUXDEBUG -DHPUX -DHPUX8 -DRENAME -DSIG_V \ -DNOSETBUF -DDIRENT -DCK_RTSCTS -DSTERMIOX -DLONGFN -DTCPSOCKET \ -DHDBUUCP -DNO_DNS_SRV -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DFNFLOAT \ -DNOLONGLONG -DNODCLENDUSERSHELL $(KFLAGS) $(OFLAGS)" \ "LNKFLAGS = -s" "LIBS = -lm -lBSD $(LIBS)" #Exactly as above hpux0800 + curses. #OK: 2009/10/01 hpux0800c: @MESSAGE2=', curses' \ $(MAKE) hpux0800 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS) -DCK_CURSES" "LIBS = -lcurses" #HP 9000 HP-UX 8.0, no TCP/IP because /usr/lib/libBSD.a can't be found, #or TCP/IP header files missing. #OK: 2009/10/01 hpux0800notcp: @MESSAGE3='NO network, NO curses' \ $(MAKE) "MAKE=$(MAKE)" hpux0800 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS) -UTCPSOCKET" #Now the same as above hpux0800 but with compiler optimization #OK: 2009/10/01 hpux0800o: @MESSAGE1="with compiler optimization" \ $(MAKE) hpux0800 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS)" "OFLAGS = -O" #Exactly as above hpux0800 + curses and with compiler optimization. #OK: 2009/10/01 hpux0800oc: @MESSAGE1="with compiler optimization" \ $(MAKE) hpux0800c KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS)" "OFLAGS = -O" "LIBS = -lcurses" #Exactly as above hpux0800notcp but with compiler optimization #OK: 2009/10/01 hpux0800onotcp: @MESSAGE1="with compiler optimization" \ $(MAKE) "MAKE=$(MAKE)" hpux0800notcp KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS)" "OFLAGS = -O" #HP 9000 Series 700 or 800, HP-UX 8.0, long filenames and TCP/IP support. # Like the previous entries, but with PA-RISC-specific optimization. #OK: 2009/10/01 hpux0800pa: @MESSAGE1="with PA-RISC-specific optimization" \ $(MAKE) hpux0800 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS) +Obb1100" #As above, but with curses. #OK: 2009/10/01 hpux0800pac: @MESSAGE1="with PA-RISC-specific optimization" \ $(MAKE) hpux0800c KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS) +Obb1100" #As above, but compiled with GCC 2.3.3. #OK: 2009/10/01 hpux0800pagcc: @MESSAGE1='using the gcc compiler' \ $(MAKE) hpux0800 KTARGET=$${KTARGET:-$(@)} \ "CC=gcc" "CC2=gcc" "KFLAGS = -funsigned-char $(KFLAGS)" #HP-UX 9.0, 9.01, 9.03, 9.04, 9.05, 9.07, 9.10 ..., + TCP/IP + curses, fully #configured. Use this entry with the restricted compiler: no optimization, no #ANSI support. If you get unresolved sockets library references at link time, #then try adding -lBSD to LIBS, or else remove -DTCPSOCKET to build a version #without TCP/IP support. # #Please note that we have to add the compiler option +DA1.0/+DA1.1 to avoid #core-dumps for large arguments in IF MATCH. The man page says these options #are default but C-Kermit dumps core without them! Therefore keep them #untouched. If you want to overwrite or disable the +DA1.0/+DA1.1 option use #'make hpux0900 OFLAGS=...'. An other possibility would be to create a new #kernel with maxssiz >= 0x01185000 (default maxssiz=0x00800000). #OK: 2009/09/24 hpux0900: @MESSAGE1A='. Read hpux0900 entry comments if you have trouble.' \ $(MAKE) hpux-header @case `uname -m` in \ */[34]*) KFLAGS='-DNOLONGLONG $(KFLAGS)' ;; \ */7*) AFLAGS='+DA1.1' ;; \ */8*) AFLAGS='+DA1.0' ;; \ esac ; \ OFLAGS=$${OFLAGS:-$$AFLAGS} ; \ $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DHPUXDEBUG -DHPUX9 -DSTERMIOX -DDIRENT -DUTIMEH \ -DNOSETBUF -DCK_CURSES -DTCPSOCKET -DRENAME -DCK_REDIR -DLONGFN \ -DHDBUUCP -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DFNFLOAT \ -DNODCLENDUSERSHELL $$KFLAGS $$OFLAGS" \ "LNKFLAGS = -s" "LIBS = -lm -lcurses" "CC=$(CC)" "CC2=$(CC2)" #Like hpux0900, but for the "value-added" compiler on all HP 9000 models. #Adds optimization and ANSI compilation: # +O2 makes smaller executable (= -O = Level-1 and global optimization) # +O3 adds interprocedural global optimization, makes bigger executable. # Please note: To support long-long we would need compiler switch '-Ae' but # this one works only on Risc systems. But the equivalant compiler flags # '-Aa -D_HPUX_SOURCE +e' works for Motorola and Risc. # If optimization fails on some modules, you can add: # +Obb, +Olimit , or +Onolimit, depending on your cc version, # where is a number, e.g. +Obb1200. In other words, if you get optimizer # warnings, add (for example) +Obb1200; if you still get optimizer warnings, # increase the number. Repeat until warnings go away. If your compiler # permits it, use +Onolimit. If optimizer blows up on ckcpro.c, see next entry. # Reportedly, on some configurations, such as HP9000/425e or /340, perhaps # depending on the amount of main memory, this entry might fail no matter what # you do ("Out of Memory", "cc: Fatal error in /lib/c.c1", etc). In that case # use "make hpux0900" (no "o"). #OK: 2009/09/24 hpux0900o: @MESSAGE1=$${MESSAGE1:-"with compiler optimization"} \ $(MAKE) hpux0900 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS) -Aa -DCK_ANSIC -D_HPUX_SOURCE +O2 +e" # For HP-UX 9.0 on Motorola CPUs, optimization of ckcpro.c tends to blow up # the compiler. You might have to reinstall your kernel with maxdsiz >= # 0x03000000. But if physical memory is small, that still will not help much. # In that case, use this entry to skip optimization of ckcpro.c. But for # C-Kermit 8.0.208 you need a kernel with maxdsiz >= 0x02000000 to compile an # optimized ckcftp.c. # Please note: To support long-long we would need compiler switch '-Ae' but # this one works only on Risc systems. But the equivalant compiler flags # '-Aa -D_HPUX_SOURCE +e' works for Motorola and Risc. hpux0900m68ko: @MESSAGE1='without compiler optimization for ckcpro.$(EXT) ...' \ $(MAKE) hpux-header $(MAKE) ckuusr.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) \ ckcftp.$(EXT) ckcpro.$(EXT) \ "CFLAGS = -DHPUXDEBUG -DHPUX9 -DSTERMIOX -DDIRENT \ -DNOSETBUF -DCK_CURSES -DTCPSOCKET -DRENAME -DCK_REDIR -DLONGFN \ -DHDBUUCP -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DFNFLOAT $(KFLAGS)" @echo @MESSAGE1="with compiler optimization for the rest" \ $(MAKE) hpux0900 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS) -Aa -DCK_ANSIC -D_HPUX_SOURCE +O2 +e" # Old name for hpux0900m68ko. hpux0900mot: $(MAKE) hpux0900m68ko KTARGET=$${KTARGET:-$(@)} "KFLAGS = $(KFLAGS)" #Like hpux0900o but with additional model-700/800-specific optimizations. # +ESlit = consolidate strings in read-only memory. # +ESfsc = inline millicode calls when comparing pointers. hpux0900o700: @echo 'If you get optimizer warnings \c' @echo 'try "make hpux0900o700 KFLAGS=+Obb1200"' @MESSAGE1="with PA-RISC-specific optimizations" \ $(MAKE) hpux0900o KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS) +ESlit +ESsfc" #HP-UX 9.0, 9.01, 9.03, 9.04, 9.05, 9.07, 9.10 ..., + TCP/IP + curses, fully #configured, built with gcc, all models except 800 series. #You might need to add the include path for gcc headers, for example: # 'KFLAGS=-I/usr/gnu/lib/gcc-lib/hppa1.1-hp-hpux/2.4.5/include/' hpux0900gcc: @MESSAGE1='using the gcc compiler' \ $(MAKE) hpux0900 KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "KFLAGS = -DCK_ANSIC $(KFLAGS)" \ "OFLAGS = -funsigned-char -O2 $(OFLAGS)" #HP-9000 HP-UX 10.0 + TCP/IP + curses, fully configured. #Use with restricted (bundled) compiler: no optimization, no ANSI support. #libcurses needed for fullscreen file xfer display in HP-UX 10.00 and 10.01. #libHcurses (NOT libcurses!) for fullscreen display, to work around fatal bugs #in HP-UX 10.10 and 10.20 curses. Maybe we could use lcurses for 10.30, since #the 10.10 curses problem is supposedly fixed in 10.30. # +DA1.0 = Generate PA-RISC 1.0 code that runs on both 700 and 800 models. # +DA1.1 = Generate PA-RISC 1.1 code that runs on both 700 and 800 models. # Note that HP-UX 10.20 and upwards do not support PA-RISC 1.0 systems. # And that as of Dec 2001, 11.00 and 11.11 are PA-only and 11.20 is IA64-only. # Later 11.2x releases are expected to be for both. Architecture can be # determined with the model command, at least in 10.20 and later... #For future releases, we need to include +DA1.1 for PA builds, so that a #binary built on PA 2.0 will still work on PA 1.1 machines, whereas +DA1.1 #must NOT be included for IA64 builds. #4 Jan 2006 - Added Large File Support (LFS). Large files (>2GB) are #possible in HP-UX 10.20 and later. The only change is to add: # -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 #to KFLAGS. These should be harmless in 10.00 and 10.10, if any of examples #of those still exist, but I have no way to test this hypothesis. #OK: 2009/11/16 #As of version 9.0305 Alpha.06 we have to add KFLAG "-DNO_PTY_XOPEN_SOURCE" #to "make hpux1000" and "make hpux1000t" because "#define _XOPEN_SOURCE 500" #that was added to ckupty.c in 2014 triggers big problems with the HP C #compiler in default (i.e. pre-ANSI K&R) mode. hpux1000: @$(MAKE) hpux-header @LIBS='-lHcurses' ; \ AFLAGS='+DA1.1' ; \ case `uname -r` in \ [AB].10.0*) KFLAGS='-DHPUX1000 $(KFLAGS)' ; \ AFLAGS='+DA1.0' ; LIBS='-lcurses' ;; \ [AB].10.1*) KFLAGS='-DHPUX1010 -D__HP_CURSES $(KFLAGS)' ; \ ;; \ [AB].10.2*) KFLAGS='-DHPUX1020 -D__HP_CURSES $(KFLAGS)' ; \ ;; \ [AB].10.3*) KFLAGS='-DHPUX1030 -D__HP_CURSES $(KFLAGS)' ; \ ;; \ [AB].10.?*) KFLAGS='-DHPUX10XX -D__HP_CURSES $(KFLAGS)' ; \ ;; \ [AB].11.0*) KFLAGS='-DHPUX1100 -D__HP_CURSES $(KFLAGS)' ; \ ;; \ [AB].11.1*) KFLAGS='-DHPUX1100 -D__HP_CURSES $(KFLAGS)' ; \ ;; \ [AB].11.?*) KFLAGS='-DHPUX1100 -D__HP_CURSES $(KFLAGS)' ; \ AFLAGS='' ; LIBS='-lcurses' ;; \ esac ; \ #echo KTARGET="$${KTARGET:-$(@)}" ; \ case "$${KTARGET:-$(@)}" in \ hpux1000 | hpux1000t | \ hpux1100 | hpux1100t) \ KFLAGS="$$KFLAGS -DNO_PTY_XOPEN_SOURCE" ;; \ esac ; \ OFLAGS=$${OFLAGS:-$$AFLAGS} ; \ $(MAKE) "SHELL=/usr/bin/sh" xermit KTARGET=$${KTARGET:-$(@)} \ "CC=$(CC)" "CC2=$(CC2)" \ "CFLAGS = -DHPUX10 -DDIRENT -DSTERMIOX -DCK_DSYSINI -DHDBUUCP \ -DCK_CURSES -DCK_WREFRESH -DTCPSOCKET -DCK_REDIR -DRENAME -DFNFLOAT \ -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 \ $$KFLAGS $$OFLAGS" \ "LNKFLAGS=-s $(LNKFLAGS)" "LIBS = -lm $$LIBS $(KLIBS)" # This is a kludge, copying hpux0900gcc and adapting hpux1000 # (add CC and CC2, drop the A1.[0||1]) # Builds w/ no compiler warnings but minimally tested. # #OK: 2009/09/21 hpux1000gcc: @MESSAGE1="using the gcc compiler $(MESSAGE1)" \ $(MAKE) hpux1000 KTARGET=$${KTARGET:-$(@)} CC=gcc CC2=gcc \ "KFLAGS = $(KFLAGS)" "OFLAGS = -DCK_ANSIC -funsigned-char -O2" # Trusted HP-UX 10 # echo KFLAGS=$(KFLAGS) YTARGET YTARGET=$(YTARGET) $(XTARGET) ; hpux1000t: @case "$(KTARGET)" in \ *+openssl | *+ssl) \ KENTRY=hpux1000o+openssl ;; \ *gcc) \ KENTRY=hpux1000gcc ;; \ *o+) KENTRY=hpux1000o+ ;; \ *o) KENTRY=hpux1000o ;; \ *) KENTRY=hpux1000 ;; \ esac ; \ MESSAGE1="and support for 'Trusted HP-UX'" \ $(MAKE) $$KENTRY KTARGET=$${KTARGET:-$(@)} \ "KFLAGS = $(KFLAGS) -DHPUX10_TRUSTED" "KLIBS=-lsec" hpux1000to: $(MAKE) hpux1000t KTARGET=$${KTARGET:-$(@)} hpux1000to+: $(MAKE) hpux1000t KTARGET=$${KTARGET:-$(@)} hpux1000tgcc: $(MAKE) hpux1000t KTARGET=$${KTARGET:-$(@)} hpux1000to+ssl hpux1000to+openssl: $(MAKE) hpux1000t KTARGET=$${KTARGET:-$(@)} hpux1000tgcc+ssl hpux1000tgcc+openssl: $(MAKE) hpux1000t KTARGET=$${KTARGET:-$(@)} #HP-9000 HP-UX 10.00 and higher with ANSI prototyping and optimization. #PA-RISC only, no Motorola or other hardware is supported in HP-UX 10.00++. #The unbundled optional compiler is required. #Your path should start with /opt/ansic/bin. # -Wl,-Fw = Remove stack unwind table (info used by debuggers). # +O2 makes a smaller executable (= -O = Level-1 and global optimization). # +O3 adds interprocedural global optimization, makes a bigger executable. # +Onolimit allows all modules to be optimized, no matter how complex. But: # (a) +Onolimit does not seem to always be there in HP-UX 10.00, and: # (b) some modules might take hours on low-memory and/or slow systems. # The following are PA-RISC-specific optimizations: # +ESlit = Consolidate strings in read-only memory. # +ESfsc = Inline millicode calls when comparing pointers. # You might need to configure your kernel for a maxdsiz of 0x0B000000 (176MB) # or greater to prevent the optimizer from running out of space. # December 2001: +ESlit +ESsfc removed because not supported on IA64. # Somebody who cares can use 'model' to see whether it's PA-RISC or IA64 # and include the architecture-specific optimization flags. Also note: # +DA1.1 is PA-only. If this is included in in HP-UX 11.00 or later, # then +DS2.0 should be included too (but don't use +DS2.0 without +DA1.1, # or else the binary won't run on older PA hardware). #OK: 2009/09/21 hpux1000o: @case `uname -m` in \ ia64) ;; \ *) MFLAGS='+ESlit +ESsfc' ;; \ esac ; \ MESSAGE1="with PA-RISC-specific optimizations $(MESSAGE1)" \ $(MAKE) "SHELL=/usr/bin/sh" "PATH=/opt/ansic/bin:$$PATH" hpux1000 \ KTARGET=$${KTARGET:-$(@)} "KFLAGS = $(KFLAGS) \ -Ae -D_HPUX_SOURCE -DCK_ANSIC -DUTIMEH \ +O2 -Wl,-Fw $$MFLAGS" #Like hpux1000o but with "+Onolimit". #On 700 series set kernel parameter maxdsiz >= 0x0D000000 (=208MB). #Takes a long time. hpux1000o+: @MESSAGE1="and +Onolimit $(MESSAGE1)" KTARGET=$${KTARGET:-$(@)} \ $(MAKE) hpux1000o \ "KFLAGS = $(KFLAGS) +Onolimit" #HP-UX 10.xx + 11.xx with optimizing ANSI compiler and OpenSSL. #Define SSLLIB and SSLINC appropriately for your OpenSSL installation. #To overwrite the default SSLLIB and SSLINC settings you can also use the #command-line variable KSSLLIB and KSSLINC like: #make hpux1000o+openssl KSSLLIB=-L/opt/openssl/lib KSSLINC=-I/... #To specify the path for the zlib library: KZLIBDIR=dir #This entry works for C-Kermit 8.0.206 on HP-UX 10.20 + 11.11 #with OpenSSL 0.9.6 + 0.9.7 #NOTE: an ANSI C compiler is required for the SSL interface. If you don't #have the HP Optimizing ANSI compiler, see the hpux1000gcc+openssl target #below. hpux1000o+ssl hpux1000o+openssl: @case "$(KTARGET)" in \ *gcc+*) \ KENTRY=hpux1000gcc ;; \ *) KENTRY=hpux1000o ;; \ esac ; \ if test -n "$(KZLIBDIR)" ; then \ ZLIBDIR="$(KZLIBDIR)" ; \ else \ ZLIBDIR='/usr/local/lib' ; \ fi ; \ case "$(KTARGET)" in \ *-zlib*) ZLIBFLAG='' ; ZLIBOPT='' ;; \ *) ZLIBFLAG='-DZLIB' ; ZLIBOPT="-L $$ZLIBDIR -lz" ;; \ esac ; \ case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac ; \ SSLINC=$${KSSLINC:-$(SSLINC)}; \ SSLLIB=$${KSSLLIB:-$(SSLLIB)}; \ MESSAGE1="and with OpenSSL $(MESSAGE1)" \ $(MAKE) $$KENTRY KTARGET=$${KTARGET:-$(@)} \ KFLAGS="-DCK_AUTHENTICATION -DCK_SSL $$OPENSSLOPTION $$ZLIBFLAG \ $$SSLINC $(KFLAGS)" \ KLIBS="$(KLIBS) \ $$SSLLIB -lssl -lcrypto \ $$ZLIBOPT \ " # Ditto but without Zlib: hpux1000o+ssl-zlib hpux1000o+openssl-zlib: @MESSAGE1="but without Zlib $(MESSAGE1)" \ $(MAKE) hpux1000o+ssl KTARGET=$${KTARGET:-$(@)} #HP-UX 10.00 or higher with OpenSSL 0.9.7. Compiled with gcc. #From Chris Chaney, NEC America Inc. His instructions: # (1) Install gcc version 3.2.3 & binutils version 2.13.2 # (used binary depot from http://hpux.cs.utah.edu/) # (2) Install gcc make version 3.80 from http://hpux.cs.utah.edu/ # # or: gcc 2.9.2000-12-1 from "Linux to hp-ux 11.0/11i porting kit version 1.0 # (2CD)" free from: http://www.software.hp.com # # (3) Install openSSL version 0.9.7b from http://www.software.hp.com # (4) Install flex version 2.5.4 from http://hpux.cs.utah.edu/ # (5) Install gmp version 3.1.1 from http://hpux.cs.utah.edu/ # #Note from Peter Eichhorn, assyst Munich. It works also without gcc make! hpux1000gcc+ssl hpux1000gcc+openssl: $(MAKE) hpux1000o+openssl KTARGET=$${KTARGET:-$(@)} # Ditto but without Zlib: hpux1000gcc+ssl-zlib hpux1000gcc+openssl-zlib: $(MAKE) hpux1000o+openssl-zlib KTARGET=$${KTARGET:-$(@)} # Same for HP-UX 11 hpux1100o+ssl hpux1100o+openssl: $(MAKE) hpux1000o+openssl KTARGET=$${KTARGET:-$(@)} #OK: 2009/09/26 hpux1100gcc+ssl hpux1100gcc+openssl: $(MAKE) hpux1000gcc+openssl KTARGET=$${KTARGET:-$(@)} hpux1100o+ssl-zlib hpux1100o+openssl-zlib: $(MAKE) hpux1000o+openssl-zlib KTARGET=$${KTARGET:-$(@)} hpux1100gcc+ssl-zlib hpux1100gcc+openssl-zlib: $(MAKE) hpux1000gcc+openssl-zlib KTARGET=$${KTARGET:-$(@)} # HP-UX 11 # Note: these are 32-bit builds even on IA64. # Adding +DD64 to CFLAGS produces 64-bit object files, # but the linker fails to find the needed 64-bit libs. #OK: 2009/09/26 hpux1100: $(MAKE) hpux1000 KTARGET=$${KTARGET:-$(@)} #OK: 2009/09/26 hpux1100o: $(MAKE) hpux1000o KTARGET=$${KTARGET:-$(@)} hpux1100o+: $(MAKE) hpux1000o+ KTARGET=$${KTARGET:-$(@)} #OK: 2009/09/26 hpux1100gcc: $(MAKE) hpux1000gcc KTARGET=$${KTARGET:-$(@)} # Trusted HP-UX 11 hpux1100t: $(MAKE) hpux1000t KTARGET=$${KTARGET:-$(@)} hpux1100to: $(MAKE) hpux1000to KTARGET=$${KTARGET:-$(@)} hpux1100to+: $(MAKE) hpux1000to+ KTARGET=$${KTARGET:-$(@)} hpux1100tgcc: $(MAKE) hpux1000tgcc KTARGET=$${KTARGET:-$(@)} hpux1100to+ssl hpux1100to+openssl: $(MAKE) hpux1000to+openssl KTARGET=$${KTARGET:-$(@)} hpux1100tgcc+ssl hpux1100tgcc+openssl: $(MAKE) hpux1000tgcc+openssl KTARGET=$${KTARGET:-$(@)} #Regulus on CIE Systems 680/20 cie: @echo 'Making C-Kermit $(CKVER) for CIE Systems 680/20 Regulus...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DATTSV -DNOFILEH -DCIE -DNOLEARN $(KFLAGS) -O" "LNKFLAGS =" # Android. android: @echo Please use \"make -f android.mk\" to build C-Kermit for Android. # Linux 1.2 or later with gcc, dynamic libraries, ncurses, TCP/IP. # # If your Linux system has curses rather than ncurses, use the linuxc # entry, or if that doesn't work, linuxnc. # # The Kermit "large memory model" is used by default to configure big packet # and script buffers, etc. For small-memory or limited-resource systems, # "make linux KFLAGS=-DNOBIGBUF". # # -DLINUXFSSTND (Linux File System Standard 1.2) gives UUCP lockfile /var/lock # with string pid. Remove this to get /usr/spool/uucp with int pid, used in # very early Linux versions. FSSTND 1.2 also says that the PID string in the # UUCP lock file has leading spaces. This is a change from FSSTND 1.0, which # used leading zeros. Add -DFSSTND10 to support FSSTND 1.0 instead of 1.2. # I hope subsequent editions of the file-system standard did not change these # again. # # Add -DOLINUXHISPEED (Old Linux High Speed support) to turn on an ugly kludge # in Linux 1.0 and earlier to support speeds of 57600 and 115200. Extremely # old Linux systems (pre-0.99pl15) will not support this. If OLINUXHISPEED is # not defined, then only the standard POSIX termios methods of setting the port # speed will be used, and in this case speeds can be as high as 460800 in most # modern Linux versions. # # -DCK_POSIX_SIG (POSIX signal handling) is good for Linux releases back to at # least 0.99.14; if it causes trouble for you, remove it from the CFLAGS. # # -pipe removes the need for temp files - remove it if it causes trouble. # # -funsigned-char makes all characters unsigned, as they should have been # in the first place. # # Add -DCK_DSYSINI if you want a shared system-wide init file. # # See http://www.columbia.edu/kermit/ckubwr.html about -DNOCOTFMC. # Better still, should read the entire Linux section of that document. # # The "linuxa" entry can be referenced directly on LIBC systems, but not # GLIBC, where -lcrypt is required. The "make linux" entry should normally # be used for all builds on all Linux distributions unless you have special # requirements, in which case keep reading. CK_NEWTERM added after 7.0b04 # due to new complaints about ncurses changing buffering of tty. # # By the way, the trick for testing if a lib exists ("if ld -lncurses ...") # might seem crazy but it works everywhere, whereas the more appropriate test # ("if locate libncurses") is not necessarily available on all Linuxes. linuxa: @echo 'Making C-Kermit $(CKVER) for Linux 1.2 or later...' @echo 'IMPORTANT: Read the comments in the linux section of the' @echo 'makefile if you have trouble.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC=$(CC)" "CC2=$(CC)" \ "CFLAGS = -O -DLINUX -pipe -funsigned-char -DFNFLOAT -DCK_POSIX_SIG \ -DCK_NEWTERM -DTCPSOCKET -DLINUXFSSTND -DNOCOTFMC -DPOSIX \ -DUSE_STRERROR $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(LIBS) -lm" # As above but with profiling linuxp: $(MAKE) linuxa KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS) -pg" \ "LIBS=-pg -lcrypt -lresolv" #Linux. Completely new target: 18 January 2016. No more looking in 100 #different places for libraries, let ld do it, since it knows what libraries #it's going to use. If this target fails to work somewhere, use the #'linux-2015' target just below this one. # #This entry should work for any Linux distribution on any platform, #32-bit or 64-bit, except for extremely ancient ones. Automatically detects: # . curses, ncurses, or no curses # . Old versus new pty handling (new == glibc 2.1++) # . Presence or absence of libcrypt and # . Presence or absence of libresolv # . Presence of various serial port locking schemes # . Transitional Long File API for 32-bit platforms (SUS V2 UNIX 98 LFS). # #Long file support for 32-bit builds added in 8.0.212 - if features.h contains #__USE_LARGEFILE64 then we set the flags that must be set before reading any #header files; on 32-bit platforms such as i386, this produces a 32-bit build #capable of accessing, sending, receiving, and managing long (> 2GB) files. #On 64-bit platforms, it does no harm. # # The clause regarding errno includes "extern int errno" in the source files # by supplying a symbol DCL_ERRNO if errno is not declared or defined in any # header files in the /usr/include tree. # # This target uses the computer's default C compiler, whatever it is # (usually gcc, but beware: it might also be clang, which is extremely # hostile to "old" code. # linux gnu-linux: @echo "Making C-Kermit for `uname -spm` $(CC) \ `$(CC) -dumpversion`..."; \ # Dummy comment \ DCL_ERRNO='-DDCL_ERRNO'; \ if egrep -r \ "(int *errno|\#define *errno|\# *define *errno)" /usr/include/* \ > /dev/null 2> /dev/null; \ then DCL_ERRNO=''; \ fi ; \ if test `grep grantpt /usr/include/*.h | wc -l` -gt 0; \ then if test -c /dev/ptmx; \ then HAVE_PTMX='-DHAVE_PTMX'; \ else HAVE_PTMX=''; \ fi; \ fi ; \ HAVE_OPENPTY=''; \ if test `grep openpty /usr/include/*.h | wc -l` -gt 0; then \ HAVE_OPENPTY='-DHAVE_OPENPTY'; \ fi; \ if test -n '$$HAVE_OPENPTY'; \ then if ld -lutil > /dev/null 2> /dev/null; then \ LIB_UTIL='-lutil'; \ else \ LIB_UTIL=''; \ fi; \ fi; \ HAVE_LIBCURSES=''; \ HAVE_CURSES=''; \ if ld -lncurses > /dev/null 2> /dev/null; then \ HAVE_LIBCURSES='-lncurses'; \ if test -f /usr/include/ncurses.h; then \ HAVE_CURSES='-DCK_NCURSES -I/usr/include/ncurses'; \ else \ HAVE_LIBCURSES=''; \ fi; \ fi; \ if test -z '$$HAVE_LIBCURSES'; then \ if ld -lcurses > /dev/null 2> /dev/null; then \ HAVE_LIBCURSES='-lcurses'; \ if test -f /usr/include/curses.h; then \ HAVE_CURSES='-DCK_CURSES -I/usr/include/curses'; \ else \ HAVE_LIBCURSES=''; \ fi; \ fi; \ fi; \ HAVE_RESOLV=''; \ if ld -lresolv > /dev/null 2> /dev/null; then \ HAVE_RESOLV='-lresolv'; \ fi; \ HAVE_CRYPT=''; \ HAVE_CRYPT_H=''; \ if ld -lcrypt > /dev/null 2> /dev/null; then \ if test -f /usr/include/crypt.h; then \ HAVE_CRYPT_H='-DHAVE_CRYPT_H'; \ HAVE_CRYPT='-lcrypt'; \ fi; \ fi; \ if test -f /usr/include/baudboy.h ; \ then HAVE_BAUDBOY='-DHAVE_BAUDBOY' ; \ else HAVE_BAUDBOY=''; \ fi; \ if test -n '$$HAVE_BAUDBOY' || test -f /usr/include/ttylock.h; \ then HAVE_LOCKDEV='-DHAVE_LOCKDEV' ; \ else HAVE_LOCKDEV='' ; \ fi ; \ if test -n '$$HAVE_LOCKDEV'; then \ if ld -llockdev > /dev/null 2> /dev/null; then \ HAVE_LIBLOCKDEV='-llockdev'; \ else \ HAVE_LOCKDEV=''; \ fi; \ fi; \ if grep __USE_LARGEFILE64 /usr/include/features.h > /dev/null; \ then HAVE_LARGEFILES='-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'; \ else HAVE_LARGEFILES=''; \ fi; \ $(MAKE) KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$$HAVE_CURSES $$HAVE_PTMX $$HAVE_LOCKDEV $$HAVE_CRYPT_H \ $$HAVE_BAUDBOY $$HAVE_OPENPTY $$HAVE_LARGEFILES $(KFLAGS)" \ "LIBS=$(LIBS) $$LIB_UTIL \ $$HAVE_LIBCURSES $$HAVE_RESOLV $$HAVE_CRYPT $$HAVE_LOCKDEV" \ linuxa # Force compilation with gcc linuxgcc: $(MAKE) "CC=gcc" "CC2=gcc" linux # Force compilation with clang linux-clang linuxclang: $(MAKE) CC=clang CC2=clang linux # Linux clang compilation with implicit function declaration warnings. # Clang 12 or later required to see the warnings. In clang 16 (at least # the first release of it) the implicit function declaration is fatal error. linux-clang-wimplicit: $(MAKE) CC=clang CC2=clang -Wimplicit-function-declaration linux # Linux clang compilation in C89 mode... # For me this bombed out instantly in clang 3.4.2 with "ckcsig.h:52:9: # typedef sigjmp_buf ckjmpbuf; error: unknown type name 'sigjmp_buf'" # It happened on both RHEL 6.1 (old) and Ubuntu 20.04.1 (recent). # Needs testing in clang 12 or later, and especially in Clang 16. linux-clang-c89: $(MAKE) "CC=clang -std=c89" "CC2=clang" linux # Linux clang compilation in gnu89 mode. For me this compiled successfully # in clang 3.4.2 but with lots of "if && ||" warnings. # Ditto in clang 10.0.0 but no "if && ||" warnings. # Needs testing in clang 12 or later. linux-clang-gnu89: $(MAKE) "CC=clang -std=gnu89" "CC2=clang" linux # Minimum size for Linux - many features deselected. # No interactive commands, no scripting, no character sets, etc. # About 1/7 the size of the normal version. # 3 November 2022 linuxmin: @echo 'Making C-Kermit $(CKVER) for Linux many features deselected..' $(MAKE) linux "KFLAGS=-DV7MIN" #PREVIOUS LINUX TARGET #Use this target if you have trouble with "make linux". #This is the previous target for Linux, retired at the end of 2015. #As you can see the tests for curses/ncurses and other libraries and #header files were getting ridiculous and were only going to get worse #as Linux versions proliferated. # #The HAVE_PTMX test was previously "if test -c /dev/ptmx" but this was #not sufficient for Debian 2.1, because although it had /dev/ptmx, it did not #have grantpt(), unlockpt(), or ptsname(), so has been changed to look for a #grantpt() prototype in the header files. Modified in 8.0.206 to allow for #libraries that contain .so's but no .a's, e.g. Mandrake 9.0. #HAVE_BAUDBOY added in 8.0.210 for Red Hat -- it's like AIX ttylock(). #Modified 17 Aug 2005 to use openpty() if available because the other stuff #dumps core in 64-bit ia64 and x86_64 builds. # #Added HAVE_LOCKDEV on openSuSE >= 11.3, which uses ttylock directly instead #of baudboy 2010/08/23 linux-2015: @if test \ `grep grantpt /usr/include/*.h /usr/include/sys/*.h | wc -l` -gt 0; \ then if test -c /dev/ptmx; then HAVE_PTMX='-DHAVE_PTMX'; \ else HAVE_PTMX=''; fi; fi ; \ if test `grep openpty /usr/include/pty.h | wc -l` -gt 0; \ then HAVE_OPENPTY='-DHAVE_OPENPTY'; \ else HAVE_OPENPTY=''; fi ; \ HAVE_LIBCURSES=''; \ if test -f /lib64/libncurses.so.5 || \ test -f /lib64/libncurses.so || \ test -f /lib64/libncurses.a; then \ HAVE_LIBCURSES='-lncurses'; \ else if test -f /usr/lib64/libncurses.so || \ test -f /usr/lib/libncurses.a || \ test -f /usr/lib64/libncurses.so.5 || \ test -f /usr/lib/libncurses.so; then \ HAVE_LIBCURSES='-lncurses'; \ else if test -f /usr/lib/$(MULTIARCH)/libncurses.so || \ test -f /usr/lib/$(MULTIARCH)/libncurses.a || \ test -f /usr/lib/$(MULTIARCH)/libncurses.so; then \ HAVE_LIBCURSES='-lncurses'; \ else if test -f /usr/lib64/libcurses.so || \ test -f /usr/lib/libcurses.a || \ test -f /usr/lib/libcurses.so; then \ HAVE_LIBCURSES='-lcurses'; fi; fi; fi; fi; \ HAVE_CURSES=''; \ if test -n '$$HAVE_LIBCURSES'; then \ if test -f /usr/include/ncurses.h; then \ HAVE_CURSES='-DCK_NCURSES -I/usr/include/ncurses'; \ else if test -f /usr/include/curses.h; then \ HAVE_CURSES='-DCK_CURSES'; \ else HAVE_LIBCURSES=''; \ fi; fi; fi; \ if test -f /usr/include/baudboy.h || test -f /usr/include/ttylock.h; \ then HAVE_LOCKDEV='-DHAVE_LOCKDEV' ; \ else HAVE_LOCKDEV='' ; fi ; \ if test -f /usr/include/baudboy.h ; \ then HAVE_BAUDBOY='-DHAVE_BAUDBOY' ; \ else HAVE_BAUDBOY='' ; fi ; \ $(MAKE) KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$$HAVE_CURSES $$HAVE_PTMX $$HAVE_LOCKDEV \ $$HAVE_BAUDBOY $$HAVE_OPENPTY \ `grep __USE_LARGEFILE64 /usr/include/features.h > /dev/null && \ echo '-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'` \ `if test -f /usr/include/crypt.h; then echo -DHAVE_CRYPT_H; fi` \ $(KFLAGS)" \ "LIBS=$(LIBS) $$HAVE_LIBCURSES \ `if test -n '$$HAVE_OPENPTY'; then echo -lutil; fi` \ `if test -f /usr/lib64/libresolv.a || test -f /usr/lib64/libresolv.so \ || test -f /usr/lib/libresolv.a || test -f /usr/lib/libresolv.so \ || test -f /usr/lib/i386-linux-gnu/libresolv.a \ || test -f /usr/lib/i386-linux-gnu/libresolv.so \ || ls /lib/$(MULTIARCH)/libresolv.* > /dev/null 2> /dev/null \ || ls /lib/x86_64-linux-gnu/libresolv.* > /dev/null 2> /dev/null; \ then echo -lresolv; fi` \ `if test -f /usr/lib64/libcrypt.a || test -f /usr/lib64/libcrypt.so \ || test -f /usr/lib/libcrypt.a || test -f /usr/lib/libcrypt.so \ || ls /lib/$(MULTIARCH)/libcrypt.* > /dev/null 2> /dev/null \ || ls /lib/x86_64-linux-gnu/libcrypt.* > /dev/null 2> /dev/null; \ then echo -lcrypt; fi` \ `if test -f /usr/lib64/liblockdev.a \ || test -f /usr/lib64/liblockdev.so \ || test -f /usr/lib/liblockdev.a \ || test -f /usr/lib/liblockdev.so \ || ls /usr/lib/$(MULTIARCH)/liblockdev.* > /dev/null 2> /dev/null; \ then echo -llockdev; fi`" \ linuxa # Linux with "legacy" and "deprecated" features removed: # FTP, Telnet, Rlogin, Wtmp logging. And arrow keys, which depend on # a deprecated API that as yet has no undeprecated replacement. linux-nodeprecated: \ # Dummy comment \ @echo 'Making C-Kermit $(CKVER) for Linux without deprecated features' $(MAKE) linux KTARGET=$${KTARGET:-$(@)} \ KFLAGS="-DNODEPRECATED $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" # Linux with pedantic warnings (force gcc) linux-pedantic: @echo Making C-Kermit $(CKVER) for Linux `uname -r` gcc pedantic... $(MAKE) "CC=gcc" "CC2=gcc" linux KTARGET=$${KTARGET:-$(@)} \ KFLAGS="-pedantic $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" # Linux with no TCP/IP support but with the external ssh client linux-notcp: @echo Making C-Kermit $(CKVER) for Linux `uname -r` NO TCP/IP... $(MAKE) linux KTARGET=$${KTARGET:-$(@)} \ KFLAGS="-DNOTCPIP -DSSHCMD -DANYSSH $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" # Linux with no TCP/IP support but with the external ssh client linux-nonet: @echo Making C-Kermit $(CKVER) for Linux `uname -r` NO NETWORKING... $(MAKE) linux KTARGET=$${KTARGET:-$(@)} \ KFLAGS="-DNONET -DNONETDIR -DSSHCMD -DANYSSH $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" # Linux + Shadow passwords + PAM # OK 2011/06/18 linux+shadow+pam: @echo 'Making C-Kermit $(CKVER) for Linux+Shadow+PAM...' $(MAKE) linux KTARGET=$${KTARGET:-$(@)} \ KFLAGS="-DCK_SHADOW -DCK_PAM $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = -lpam" # Linux systems that have no . # (not tested in recent years, perhaps no longer needed) linuxns: $(MAKE) linux KTARGET=$${KTARGET:-$(@)} KFLAGS=-DNO_SYS_SELECT_H # Linux build with no curses (restored 24 November 2022) linuxnc: $(MAKE) linux KTARGET=$${KTARGET:-$(@)} \ KFLAGS="-DNOCURSES -UCK_CURSES" # Linux-script-only: # A minimum-size version for Linux that does only scripting and # serial communication -- no networks, no file transfer, no security. # OK 2011/06/18 // 2022/10/14: compiles but various commands don't work. linuxso: $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -DLINUX -pipe -funsigned-char -DPOSIX -DCK_POSIX_SIG \ -DLINUXFSSTND -DNOCOTFMC -DNOXFER -DNODEBUG -DNOCSETS -DNOHELP \ -DNONET -DMINIDIAL -DNOSCRIPT -DNOIKSD -DNOPUSH $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" "LIBS = " # Secure targets for Linux. These work on RHAS4, RHEL4, and RHEL5, # unlike some of the older targets that follow. They hook into the main Linux # target so we pick up all the other new stuff - large files, baudboy.h, the # appropriate pty interface, etc. # Linux with Kerberos 5. # Use "make linux+krb5 KFLAGS=-DNO_KRB5_INIT_ETS" if necessary. #OK 2011/06/16 on Fedora 14 with: # make linux+krb5 "LIBS=$LIBS /lib/libk5crypto.so.3 /lib/libcom_err.so.2" # On RHEL5.x: make linux+krb5 -UCK_DES # On RHEL6.6: make linux+krb5 "K5LIB=-L /lib64" # This one tends to have trouble finding all its pieces. # As of C-Kermit 10.0 Beta.08 this target was renamed from linux+krb5 # to linux+krb5-old and the next target, originally called linux+krb5-new # is now linux+krb5, and should work in most cases. linux+krb5-old: @echo 'Making C-Kermit $(CKVER) for Linux with Kerberos 5...' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac; \ HAVE_DES=''; \ DES_LIB=''; \ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \ DES_LIB='-ldes425'; \ HAVE_DES='-DCK_DES -DLIBDES'; \ echo "HAVE DES"; \ else echo "NO DES"; \ fi; \ K5CRYPTO=''; \ if ls /lib/libk5crypto* > /dev/null 2> /dev/null; then \ K5CRYPTO='-lk5crypto'; \ else if ls /usr/lib/libk5crypto* > /dev/null 2> /dev/null; then \ K5CRYPTO='-lk5crypto'; \ else if ls /usr/lib64/libk5crypto* > /dev/null 2> /dev/null; then \ K5CRYPTO='-lk5crypto'; \ else if ls usr/lib/x86_64-linux-gnu/libk5crypto* \ > /dev/null 2> /dev/null; then \ K5CRYPTO='-lk5crypto'; \ fi; fi; fi; fi; \ COM_ERR=''; \ if ls /lib/libcom_err* > /dev/null 2> /dev/null; then \ COM_ERR='-lcom_err'; \ else if ls /lib64/libcom_err* > /dev/null 2> /dev/null; then \ COM_ERR='-lcom_err'; \ else if ls /x86_64-linux-gnu/libcom_err* >/dev/null 2>/dev/null; then \ COM_ERR='-lcom_err'; \ fi; fi; fi; \ GSSAPILIB='-lgssapi'; \ if ls /lib/libgssapi_krb5* > /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi_krb5'; \ else if ls /usr/lib/libgssapi_krb5* > /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi_krb5'; \ else if ls /usr/lib/x86_64-linux-gnu/libgssapi_krb5* > \ /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi_krb5'; \ else K5DIR=`echo $(K5LIB) | sed 's|-L||'`; \ if ls $$K5DIR/libgssapi_krb5* > /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi_krb5'; \ fi; fi; fi; fi; \ $(MAKE) linux KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "KFLAGS= -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 $$OPENSSLOPTION \ -DCK_ENCRYPTION $$HAVE_DES $(K5INC) $(K5INC)/krb5 \ -I/usr/include/et $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(K5LIB) $$DES_LIB -lcrypto $$COM_ERR \ $$GSSAPILIB -lkrb5 $$K5CRYPTO $(LIBS)" # The previous linux+krb was a big mess, with hardwired pathnames for all the # possible places the Kerberos libs might be. This version just relies on the # linker to find them. It also handles the frequent situation where the # gssapi library is install but the linker doesn't know about it. Thanks to # Peter Eichhorn for a great deal of help with the syntax in the gssapi # section! - fdc 24 November 2022 (renamed to linux+krb5 15 December 2022) linux+krb5 linux+krb5-new: @echo 'NEW Making C-Kermit $(CKVER) for Linux with Kerberos 5...' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac; \ K5LIB=''; \ if ld -lkrb5 > /dev/null 2> /dev/null; then \ K5LIB='-lkrb5'; else \ echo "Failed - Can't find Kerberos 5 library" ; exit 2; \ fi; \ KRB5_H=''; \ if test -f /usr/include/krb5/krb.h; then \ KRB5_H=-DKRB5_H; \ fi; \ CRYPT_H=''; \ if test -f /usr/include/crypt.h; then \ CRYPT_H='-DCRYPT_H'; \ fi; \ LIBCRYPT=''; \ if ld -lcrypt > /dev/null 2> /dev/null; then \ LIBCRYPT='-lcrypt'; \ fi; \ LIBCRYPTO=''; \ if ld -lcrypto > /dev/null 2> /dev/null; then \ LIBCRYPTO='-lcrypto'; \ fi; \ LIBK5CRYPTO=''; \ if ld -lk5crypto > /dev/null 2> /dev/null; then \ LIBK5CRYPTO='-lk5crypto'; \ fi; \ HAVE_DES=''; \ if ld -ldes > /dev/null 2> /dev/null; then \ LIBDES='-ldes'; \ HAVE_DES='-DCK_DES -DLIBDES'; \ fi; \ XX_COM_ERR=H''; \ K5_COM_ERR_H=''; \ ET_COM_ERR_H=''; \ COM_ERR_LIB=''; \ if ld -lcom_err > /dev/null 2> /dev/null; then \ if test -f /usr/include/krb5/com_err.h; then \ COM_ERR_LIB='-lcom_err'; \ COM_ERR_H='-DK5_COM_ERR_H'; \ else if test -f /usr/include/et/com_err.h; then \ COM_ERR_LIB='-lcom_err'; \ COM_ERR_H='-DET_COM_ERR_H'; \ else if test -f /usr/include/com_err.h; then \ COM_ERR_LIB='-lcom_err'; \ COM_ERR_H='-DXX_COM_ERR_H'; \ fi; \ fi; \ fi; \ fi; \ GSSAPILIB=''; \ HAVE_GSSAPI=''; \ if name=`locate libgssapi | grep ^/usr/lib | head -1`; then \ echo name=$$name; \ path=$${name%/*}; \ echo PATH=$$path; \ GSSAPILIB=$$(basename $$name); \ echo GSSAPILIB=$$GSSAPILIB ; \ HAVE_GSSAPI='-DHAVE_GSSAPI'; \ fi ; \ if [ -z "$$LD_LIBRARY_PATH" ] ; then \ export LD_LIBRARY_PATH=$$path ; else \ export LD_LIBRARY_PATH=$$LD_LIBRARY_PATH:$$path; \ HAVE_GSSAPI='-DHAVE_GSSAPI'; \ fi; \ if ls $${path}/libgssapi_krb5.* >/dev/null 2>/dev/null; then \ echo HAVE libgssapi_krb5 ; \ GSSAPILIB=-lgssapi_krb5 ; else \ if ls $${path}/libgssapi.* >/dev/null 2>/dev/null; then \ GSSAPILIB=-lgssapi ; \ fi; \ fi; \ echo GSSAPILIB=$GSSAPILIB; \ echo LD_LIBRARY_PATH=$$LD_LIBRARY_PATH; \ if ld -lggssapi_krb5 > /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi_krb5'; \ HAVE_GSSAPI='-DHAVE_GSSAPI'; \ echo GSSAPILIB-1=$$GSSAPILIB; \ else if ld -lggssapi_krb5 > /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi'; \ HAVE_GSSAPI='-DHAVE_GSSAPI'; \ echo GSSAPILIB-2=$$GSSAPILIB; \ fi; \ fi; \ echo GSSAPILIB=$$GSSAPILIB; \ $(MAKE) linux KTARGET=$${KTARGET:-$(@)} "CC = $(CC)" "CC2 = $(CC2)" \ "KFLAGS= -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_KERBEROS -DKRB5 \ $$HAVE_GSSAPI $$HAVE_DES $$OPENSSLOPTION $$CRYPT_H $$COM_ERR_H \ $$KRB5_H $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $$LIBCRYPT $$LIBCRYPTO $$LIBK5CRYPTO $$LIBDES $$COM_ERR_LIB \ $$K5LIB $$GSSAPILIB $(LIBS)" # Linux with Kerberos 5 and Kerberos 4. # Use "make linux+krb5 KFLAGS=-DNO_KRB5_INIT_ETS" if necessary. # Add "KFLAGS=-UCK_DES" if failure messages look DES-related. # UNTESTED (because I can't find a box with Krb4 and Krb5 installed) linux+krb5+krb4: @echo 'Making C-Kermit for Linux with Kerberos 4 and Kerberos 5' $(MAKE) linux+krb5 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DKRB4 -DKRB524 $(KFLAGS)" "LIBS=$(LIBS) -lkrb4" # Linux with OpenSSL # In Linux, SSL libs are often in /lib or /usr/lib and so found by default. # This targets takes into account the DES library might or might not # exist. If it does exist, however, the target will require some editing # if its basename is not libdes425. - fdc Tue Sep 21 14:28:00 2010 # IMPORTANT: Some Linux platforms have DES libraries but they are missing # functions used by Kermit. In that case you will get fatal errors at # link time involving routines such as des_ecb3_encrypt, des_random_seed, # and des_set_odd_parity. In that case, "make linux KFLAGS=-UCK_DES" # There's a new warning at the end that should come out if this happens, # and that should not come out if it didn't. # # Newer versions of OpenSSL cause profuse "-Wdeprecated-declarations" # warnings, meaning C-Kermit's SSL code needs to be updated to allow (by # copious use if #ifdefs) for both old and new versions. Also it has been # noted that libpam0g-dev must be installed for OpenSSL 3 builds, which # is needed for /usr/include/security/pam_appl.h, which ckufio.c #includes. # - fdc 14 May 2023 # linux+ssl linux+openssl linux+openssl+zlib+shadow+pam linux+openssl+shadow: @echo 'Making C-Kermit $(CKVER) for Linux+OpenSSL SSLLIB=$(SSLLIB)' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac; \ HAVE_DES=''; \ DES_LIB=''; \ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \ DES_LIB='-ldes425'; \ HAVE_DES='-DCK_DES -DLIBDES'; \ echo "HAVE DES"; \ else echo "NO DES"; \ fi; \ $(MAKE) linux KTARGET=$${KTARGET:-$(@)} "CC = $(CC)" "CC2 = $(CC2)" \ "KFLAGS= -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_CAST $$HAVE_DES \ -DCK_SSL -DCK_PAM -DZLIB -DCK_SHADOW $$OPENSSLOPTION $(SSLINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SSLLIB) -lssl $$DES_LIB -lcrypto -lpam -ldl -lz $(LIBS)" # Linux with Kerberos 5 and OpenSSL # OK 2011/05/16 # Add -UCK_DES if functions like des_ecb3_encrypt, es_random_seed, # come up missing at link time. # NOTE: MULTIARCH is defined externally, e.g. in DEB_HOST_MULTIARCH # On RHEL6.6: make linux+krb5+ssl "K5LIB=-L /lib64" linux+krb5+ssl linux+krb5+openssl: @echo 'Making C-Kermit $(CKVER) for Linux with Krb5 and OpenSSL...' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac; \ HAVE_DES=''; \ DES_LIB=''; \ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \ DES_LIB='-ldes425'; \ HAVE_DES='-DCK_DES -DLIBDES'; \ echo "HAVE DES"; \ else echo "NO DES"; \ fi; \ K5CRYPTO=''; \ if ls /lib/libk5crypto* > /dev/null 2> /dev/null; then \ K5CRYPTO='-lk5crypto'; \ else if ls /usr/lib/libk5crypto* > /dev/null 2> /dev/null; then \ K5CRYPTO='-lk5crypto'; \ else if ls /usr/lib64/libk5crypto* > /dev/null 2> /dev/null; then \ K5CRYPTO='-lk5crypto'; \ else if ls /usr/lib/$(MULTIARCH)/libk5crypto* \ > /dev/null 2> /dev/null; then K5CRYPTO='-lk5crypto'; \ fi; fi; fi; fi; \ COM_ERR=''; \ if ls /lib/libcom_err* > /dev/null 2> /dev/null; then \ COM_ERR='-lcom_err'; \ else if ls /lib/$(MULTIARCH)/libcom_err* \ > /dev/null 2> /dev/null; then COM_ERR='-lcom_err'; \ else if ls /lib64/libcom_err* > /dev/null 2> /dev/null; then \ COM_ERR='-lcom_err'; \ fi; fi; fi; \ GSSAPILIB='-lgssapi'; \ if ls /lib/libgssapi_krb5* > /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi_krb5'; \ else if ls /usr/lib/$(MULTIARCH)/libgssapi_krb5* \ > /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi_krb5'; \ else K5DIR=`echo $(K5LIB) | sed 's|-L||'`; \ if ls $$K5DIR/libgssapi_krb5* > /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi_krb5'; \ fi; fi; fi; \ $(MAKE) linux KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "KFLAGS= -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 \ -DCK_SSL -DCK_PAM -DZLIB -DCK_SHADOW $$OPENSSLOPTION $(SSLINC) \ -DCK_ENCRYPTION $$HAVE_DES $(K5INC) $(K5INC)/krb5 \ -I/usr/include/et $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(K5LIB) $(SSLLIB) -lssl $$DES_LIB -lpam -lz \ -lcrypto $$GSSAPILIB -lkrb5 $$K5CRYPTO $$COM_ERR $(LIBS)" linux+krb5+ssl-new: @echo 'Making C-Kermit $(CKVER) for Linux with Krb5 and OpenSSL...' @case `openssl version` in \ *0.9.7*) OPENSSLOPTION="-DOPENSSL_097" ;; \ *0.9.8*) OPENSSLOPTION="-DOPENSSL_098" ;; \ *1.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_100" ;; \ *3.[0-9].[0-9]*) OPENSSLOPTION="-DOPENSSL_300" ;; \ *) OPENSSLOPTION="" ;; \ esac; \ HAVE_DES=''; \ DES_LIB=''; \ if ls /usr/lib/libdes* > /dev/null 2> /dev/null || \ ls $(SSLLIB)/libdes* > /dev/null 2> /dev/null; then \ DES_LIB='-ldes425'; \ HAVE_DES='-DCK_DES -DLIBDES'; \ echo "HAVE DES"; \ else echo "NO DES"; \ fi; \ LIBK5CRYPTO=''; \ if ld -lk5crypto > /dev/null 2> /dev/null; then \ LIBK5CRYPTO='-lk5crypto'; \ fi; \ XX_COM_ERR=H''; \ K5_COM_ERR_H=''; \ ET_COM_ERR_H=''; \ COM_ERR_LIB=''; \ if ld -lcom_err > /dev/null 2> /dev/null; then \ if test -f /usr/include/krb5/com_err.h; then \ COM_ERR_LIB='-lcom_err'; \ COM_ERR_H='-DK5_COM_ERR_H'; \ else if test -f /usr/include/et/com_err.h; then \ COM_ERR_LIB='-lcom_err'; \ COM_ERR_H='-DET_COM_ERR_H'; \ else if test -f /usr/include/com_err.h; then \ COM_ERR_LIB='-lcom_err'; \ COM_ERR_H='-DXX_COM_ERR_H'; \ fi; \ fi; \ fi; \ fi; \ GSSAPILIB=''; \ HAVE_GSSAPI=''; \ if name=`locate libgssapi | grep ^/usr/lib | head -1`; then \ echo name=$$name; \ path=$${name%/*}; \ echo PATH=$$path; \ GSSAPILIB=$$(basename $$name); \ echo GSSAPILIB=$$GSSAPILIB ; \ HAVE_GSSAPI='-DHAVE_GSSAPI'; \ fi ; \ if [ -z "$$LD_LIBRARY_PATH" ] ; then \ export LD_LIBRARY_PATH=$$path ; else \ export LD_LIBRARY_PATH=$$LD_LIBRARY_PATH:$$path; \ HAVE_GSSAPI='-DHAVE_GSSAPI'; \ fi; \ if ls $${path}/libgssapi_krb5.* >/dev/null 2>/dev/null; then \ echo HAVE libgssapi_krb5 ; \ GSSAPILIB=-lgssapi_krb5 ; else \ if ls $${path}/libgssapi.* >/dev/null 2>/dev/null; then \ GSSAPILIB=-lgssapi ; \ fi; \ fi; \ echo GSSAPILIB=$GSSAPILIB; \ echo LD_LIBRARY_PATH=$$LD_LIBRARY_PATH; \ if ld -lggssapi_krb5 > /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi_krb5'; \ HAVE_GSSAPI='-DHAVE_GSSAPI'; \ echo GSSAPILIB-1=$$GSSAPILIB; \ else if ld -lggssapi_krb5 > /dev/null 2> /dev/null; then \ GSSAPILIB='-lgssapi'; \ HAVE_GSSAPI='-DHAVE_GSSAPI'; \ echo GSSAPILIB-2=$$GSSAPILIB; \ fi; \ fi; \ $(MAKE) linux KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "KFLAGS= -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 \ -DCK_SSL -DCK_PAM -DZLIB -DCK_SHADOW $$OPENSSLOPTION $(SSLINC) \ -DCK_ENCRYPTION $$HAVE_DES $(K5INC) $(K5INC)/krb5 \ -I/usr/include -I/usr/include/et /$(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(K5LIB) $(SSLLIB) -lssl $$DES_LIB -lpam -lz \ -lcrypto $$GSSAPILIB -lkrb5 $$K5CRYPTO $$COM_ERR $(LIBS)" # ::BEGIN_OLD_LINUX_TARGETS:: # The remaining Linux entries are for special or customized builds. They have # not been generalized ("subroutinized") like the ones above. Ideally, we # should allow for every combination of libc vs glibc, gcc vs egcs, curses vs # ncurses, Kerberos IV vs Kerberos V vs SRP (in any combination), and so on. # The best way to do this is to set KFLAGS and LIBS values and then chain to # the main "linux" target, as in the examples just above. To skip past all of # these old targets (and there are many) search for ::END_OLD_LINUX_TARGETS:: # (after this line). #Sharp Zaurus SL-5500 - Linux based zsl5500: @echo 'Making C-Kermit $(CKVER) for Sharp Zaurus SL-5500...' $(MAKE) linuxnc $(MAKE) linux KTARGET=$${KTARGET:-$(@)} \ KFLAGS="-DNOCURSES -UCK_CURSES" KTARGET=$${KTARGET:-$(@)} "KFLAGS=-DZSL5500" \ "CC = gcc" "CC2 = gcc" #Mklinux DR3 has horrible bug in - see ckufio.c. mklinux: $(MAKE) KTARGET=$${KTARGET:-$(@)} "KFLAGS=-DUTMPBUG" \ "LIBS=-lcrypt -lresolv" linuxa #LinuxPPC 1999 linuxppc: @echo 'Making C-Kermit $(CKVER) for LinuxPPC 1999...' @if test -f /usr/lib/libcrypt.a; then \ if test -f /usr/lib/libresolv.a; then \ $(MAKE) KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(NCURSES_CPP) -DHAVE_CRYPT_H \ -DLOCK_DIR=\\\\\\"\"/var/lock/modem\\\\\\"\" $(KFLAGS)" \ "LIBS=-lncurses -lresolv -lcrypt" linuxa ; \ else \ $(MAKE) KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(NCURSES_CPP) -DHAVE_CRYPT_H \ -DLOCK_DIR=\\\\\\"\"/var/lock/modem\\\\\\"\" $(KFLAGS)" \ "LIBS=-lncurses -lcrypt" linuxa ; \ fi \ else \ if test -f /usr/lib/libresolv.a; then \ $(MAKE) KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(NCURSES_CPP) \ -DLOCK_DIR=\\\\\\"\"/var/lock/modem\\\\\\"\" $(KFLAGS)" \ "LIBS=-lncurses -lresolv" linuxa ; \ else \ $(MAKE) KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(NCURSES_CPP) \ -DLOCK_DIR=\\\\\\"\"/var/lock/modem\\\\\\"\" $(KFLAGS)" \ "LIBS=-lncurses" linuxa ; \ fi \ fi # Like "make linux" but built with egcs rather than gcc. # If you get "Internal compiler error xxx, output pipe has been closed", # try removing -pipe. linuxegcs: @echo 'Making C-Kermit $(CKVER) for Linux 1.2 or later with egcs...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = egcs" "CC2 = egcs" \ "CFLAGS = -O -DLINUX -pipe -funsigned-char \ -DPOSIX -DCK_POSIX_SIG -DCK_NCURSES -DNOCOTFMC \ -DTCPSOCKET -DLINUXFSSTND $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" "LIBS = -lncurses -lcrypt -lresolv" #Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.1 (no K4 compatibility). linux+krb5-older: @echo 'Making C-Kermit $(CKVER) for Linux on Intel with Kerberos...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 \ -DCK_ENCRYPTION -DCK_DES -DCK_CURSES -DCK_POSIX_SIG \ -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H $(K5INC) $(K5INC)/krb5 \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(K5LIB) -lncurses -ltermcap -ldes425 -lkrb5 \ -lcom_err -lk5crypto -lgssapi_krb5 -lcrypt -lresolv" # Linux on Intel PC with SRP 1.7.4 using GNU MP, Krypto, and Eric Young's # DES library. Remove the -DCK_DES, -DLIBDES and -ldes if you do not have # Eric Young's# libdes.a installed. # linux+srp+gmp: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...' $(MAKE) srpmit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(SRPINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SRPLIB) \ -lncurses -ltermcap -lsrp -lgmp -ldes -lkrypto -lcrypt -lresolv" linux+srp+gmp+no-des: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP ...' $(MAKE) srpmit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP \ -DCK_ENCRYPTION -DCK_CAST \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(SRPINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SRPLIB) \ -lncurses -ltermcap -lsrp -lgmp -lkrypto -lcrypt -lresolv" linux+srp+gmp-export: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...' $(MAKE) srpmit-export KTARGET=$${KTARGET:-$(@)} \ "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP -DFNFLOAT \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(SRPINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SRPLIB) \ -lncurses -ltermcap -lsrp -lgmp -lkrypto -lcrypt -lm -lresolv" linux+srp+gmp+pam: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...' $(MAKE) srpmit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ -DCK_PAM -DFNFLOAT $(SRPINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SRPLIB) -lncurses -ltermcap -lsrp -lgmp -ldes -lkrypto \ -lcrypt -lpam -ldl -lm -lresolv" #Linux on Intel PC with SRP 1.7.4 built with OpenSSL for Big Number Math #and Cryptographic functionality. # linux+srp: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...' $(MAKE) srpmit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(SRPINC) $(SSLINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SRPLIB) $(SSLLIB) \ -lncurses -ltermcap -lsrp -lkrypto -lcrypto -lcrypt -lresolv" linux+srp+pam: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...' $(MAKE) srpmit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ -DCK_PAM -DFNFLOAT $(SRPINC) $(SSLINC) $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SRPLIB) $(SSLLIB) -lncurses -ltermcap -lsrp -lkrypto \ -lcrypto -lcrypt -lpam -ldl -lm -lresolv" #Linux on Intel PC with SRP and SSL/TLS. # # libsrp.a should be build with OpenSSL # Requires the Kerberos 1.2.2 or higher to be compiled with KRB4 compatibility. #Remove -ltermcap if it causes trouble e.g. in Debian 2.2. #If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS. linux+srp+openssl: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(SRPINC) $(SSLINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SRPLIB) $(SSLLIB) \ -lncurses -ltermcap -lsrp -lssl -lkrypto -lcrypto \ -lcrypt -lresolv" #Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2 and SRP. # # libsrp.a should be build with GNU MP (libgmp.a) # instead of AT&T CryptoLib (libcrypt.a) due to naming conflicts with # standard distribution Linux libraries. # Requires the Kerberos 1.2.2 or higher to be compiled with KRB4 compatibility. linux+krb5+krb4+srp: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB54+SRP...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(K5INC) $(K5INC)/krb5 $(SRPINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(K5LIB) $(SRPLIB) \ -lncurses -ltermcap -lsrp -lgmp -lgssapi_krb5 -lkrypto \ -ldes -lkrb4 -ldes425 -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv" #Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, SRP and SSL/TLS. # # libsrp.a should be build with OpenSSL # Requires the Kerberos 1.2.2 or higher to be compiled with KRB4 compatibility. # Requires OpenSSL 0.9.6a or higher #If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS. linux+krb5+krb4+srp+openssl: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(K5INC) $(K5INC)/krb5 $(SRPINC) $(SSLINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(K5LIB) $(SRPLIB) $(SSLLIB) \ -lncurses -ltermcap -lsrp \ -lkrb4 -lssl -lkrypto -lcrypto \ -lkrb5 -lcom_err -lk5crypto -lgssapi_krb5 -lcrypt -lresolv" #Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, SSL/TLS. # # libsrp.a should be build with OpenSSL # Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility. #If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS. linux+krb5+krb4+openssl: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SSL...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(K5INC) $(K5INC)/krb5 $(SSLINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(K5LIB) $(SSLLIB) \ -lncurses -ltermcap \ -lkrb4 -lssl -lcrypto -lkrb5 -lcom_err \ -lk5crypto -lgssapi_krb5 -lcrypt -lresolv" #Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.1, SSL/TLS. # # libsrp.a should be build with OpenSSL # Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility. # If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS. linux+krb5+krb4+openssl+shadow: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SSL...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_SHADOW \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(K5INC) $(K5INC)/krb5 $(SSLINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(K5LIB) $(SSLLIB) \ -lncurses -ltermcap \ -lkrb4 -lssl -lcrypto -lkrb5 -lcom_err \ -lk5crypto -lgssapi_krb5 -lcrypt -lresolv" #Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2, SSL/TLS. # # libsrp.a should be build with OpenSSL # Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility. # If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS. linux+krb5+krb4+openssl+zlib+shadow: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SSL...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 -DZLIB \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_SHADOW \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(K5INC) $(K5INC)/krb5 $(SSLINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(K5LIB) $(SSLLIB) \ -lncurses -ltermcap \ -lkrb4 -lssl -lcrypto -lkrb5 -lcom_err \ -lk5crypto -lgssapi_krb5 -lcrypt -lresolv -lz" linux+krb5+krb4+srp-export: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...' $(MAKE) xermit-export KTARGET=$${KTARGET:-$(@)} \ "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(K5INC) $(K5INC)/krb5 $(SRPINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SRPLIB) $(K5LIB) \ -lncurses -ltermcap -lsrp -lgmp -lkrb4 -ldes425 -lkrb5 -lgssapi_krb5 \ -lcom_err -lk5crypto -lkrypto -lcrypt -lresolv" linux+krb5+krb4+srp+pam: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with SRP...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ -DCK_PAM $(K5INC) $(K5INC)/krb5 $(SRPINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SRPLIB) $(K5LIB) \ -lncurses -ltermcap -lsrp -lgmp -ldes -lkrb4 -ldes425 -lkrb5 \ -lcom_err -lk5crypto -lgssapi_krb5 -lkrypto -lcrypt -lpam -ldl \ -lresolv" #Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, SRP and SSL/TLS. # and PAM. # # libsrp.a should be build with OpenSSL # Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility. # If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS. linux+krb5+krb4+srp+openssl+pam-debug: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...' $(MAKE) xermit-debug KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ -w -Dmalloc=dmalloc -Dfree=dfree -DMDEBUG $(K5INC) $(K5INC)/krb5 \ $(SRPINC) $(SSLINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SRPLIB) $(K5LIB) $(SSLLIB) \ -lncurses -ltermcap -lsrp -lkrb4 -lssl -lkrypto -lcrypto \ -lkrb5 -lcom_err -lk5crypto -lgssapi_krb5 -lcrypt -lresolv -lpam -ldl" #Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.1, SRP and SSL/TLS. # and PAM. # # libsrp.a should be build with OpenSSL # Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility. # If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS. linux+krb5+krb4+srp+openssl+pam: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(K5INC) $(K5INC)/krb5 $(SRPINC) $(SSLINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SRPLIB) $(K5LIB) $(SSLLIB) \ -lm -lncurses -ltermcap -lsrp \ -lkrb4 -lssl -lkrypto -lcrypto -lgssapi_krb5 \ -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv -lpam -ldl" #Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, SRP, OpenSSL # with ZLIB and PAM # # libsrp.a should be build with OpenSSL # Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility. # If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS. linux+krb5+krb4+srp+openssl+zlib+pam: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM -DZLIB \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(K5INC) $(K5INC)/krb5 $(SRPINC) $(SSLINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SRPLIB) $(K5LIB) $(SSLLIB) \ -lm -lncurses -ltermcap -lsrp \ -lkrb4 -lssl -lkrypto -lcrypto -lgssapi_krb5 \ -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv -lpam -ldl -lz" #Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, SRP, OpenSSL # with ZLIB, Shadow Passwords, and PAM # # libsrp.a should be build with OpenSSL # Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility. # If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS. linux+krb5+krb4+srp+openssl+zlib+shadow+pam: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_SRP -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM -DZLIB \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ -DCK_SHADOW $(K5INC) $(K5INC)/krb5 $(SRPINC) $(SSLINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(SRPLIB) $(K5LIB) $(SSLLIB) \ -lm -lncurses -ltermcap -lsrp -lkrypto \ -lkrb4 -lssl -lcrypto -lgssapi_krb5 \ -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv -lpam -ldl -lz" #Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, OpenSSL # with Shadow Passwords, PAM # # Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility. linux+krb5+krb4+openssl+shadow+pam: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SSL,...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ -DCK_SHADOW $(K5INC) $(K5INC)/krb5 $(SSLINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(K5LIB) $(SSLLIB) \ -lm -lncurses -ltermcap \ -lkrb4 -lssl -lcrypto -lgssapi_krb5 \ -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv -lpam -ldl" #Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, OpenSSL # with ZLIB, Shadow Passwords, PAM # # libsrp.a should be build with OpenSSL # Requires the Kerberos 1.2.2 be compiled with KRB4 compatibility. # If you have OpenSSL 0.9.7 or later, add -DOPENSSL_097 to KFLAGS. linux+krb5+krb4+openssl+zlib+shadow+pam: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB,SRP,SSL...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DKRB4 -DKRB524 \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM -DZLIB \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ -DCK_SHADOW $(K5INC) $(K5INC)/krb5 $(SSLINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(K5LIB) $(SSLLIB) \ -lm -lncurses -ltermcap \ -lkrb4 -lssl -lcrypto -lgssapi_krb5 \ -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv -lpam -ldl -lz" #Red Hat 9 - full install includes Kerberos 5 (4 compat), PAM, SSL. #Also works around bug in curses in which terminal goes dead after #returning from file-transfer display. Assumes OpenSSL 0.9.7 or later. redhat9: @echo "Building SECURE Kermit for Red Hat 9.0..." $(MAKE) linux+krb5+krb4+openssl+zlib+shadow+pam \ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH90 -DOPENSSL_097 $(KFLAGS)" #Ditto plus SRP (which is not normally included with RH Linux). redhat9+srp: @echo "Building SECURE Kermit for Red Hat 9.0..." $(MAKE) linux+krb5+krb4+srp+openssl+zlib+shadow+pam \ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH90 -DOPENSSL_097 $(KFLAGS)" #For Red Hat AS 2.1 with OpenSSL redhat21+ssl: @echo "Building SECURE Kermit for Red Hat 2.1..." $(MAKE) linux+openssl+zlib+shadow+pam \ KTARGET=$${KTARGET:-$(@)} "KFLAGS = $(KFLAGS)" #Red Hat Linux 8.0 - full install includes Kerberos 5 (4 compat), PAM, SSL. #Also works around bug in curses in which terminal goes dead after #returning from file-transfer display. redhat80: @echo "Building SECURE Kermit for Red Hat 8.0..." $(MAKE) linux+krb5+krb4+openssl+zlib+shadow+pam \ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH80 $(KFLAGS)" redhat80+srp: @echo "Building SECURE Kermit for Red Hat 8.0..." $(MAKE) linux+krb5+krb4+srp+openssl+zlib+shadow+pam \ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH80 $(KFLAGS)" #Red Hat Linux 7.3 - full install includes Kerberos 5 (4 compat), PAM, SSL. #Also works around bug in curses in which terminal goes dead after #returning from file-transfer display. redhat73: @echo "Building SECURE Kermit for Red Hat 7.3..." $(MAKE) linux+krb5+krb4+openssl+zlib+shadow+pam \ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH73 $(KFLAGS)" redhat73+srp: @echo "Building SECURE Kermit for Red Hat 7.3..." $(MAKE) linux+krb5+krb4+srp+openssl+zlib+shadow+pam \ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH73 $(KFLAGS)" #Red Hat Linux 7.2 - full install includes Kerberos 5 (4 compat), PAM, SSL. #Also works around bug in curses in which terminal goes dead after #returning from file-transfer display. redhat72: @echo "Building SECURE Kermit for Red Hat 7.2..." $(MAKE) linux+krb5+krb4+openssl+zlib+shadow+pam \ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH72 $(KFLAGS)" redhat72+srp: @echo "Building SECURE Kermit for Red Hat 7.2..." $(MAKE) linux+krb5+krb4+srp+openssl+zlib+shadow+pam \ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH72 $(KFLAGS)" #Red Hat Linux 7.1 - full install includes Kerberos 5 (4 compat), PAM, SSL. #Also works around bug in curses in which terminal goes dead after #returning from file-transfer display. redhat71: @echo "Building SECURE Kermit for Red Hat 7.1..." $(MAKE) linux+krb5+krb4+openssl+zlib+shadow+pam \ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH71 $(KFLAGS)" redhat71+srp: @echo "Building SECURE Kermit for Red Hat 7.1..." $(MAKE) linux+krb5+krb4+srp+openssl+zlib+shadow+pam \ KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DRH71 $(KFLAGS)" #Linux on Intel PC with Cygnus or MIT Kerberos 5 1.2.2, OpenSSL # with ZLIB and PAM and Shadow passwords linux+krb5+openssl+zlib+shadow+pam: @echo 'Making C-Kermit $(CKVER) for Linux on i386 with KRB5,SSL...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -g -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \ -DCK_AUTHENTICATION -DCK_KERBEROS -DKRB5 -DCK_SHADOW -DHAVE_PTMX \ -DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL -DCK_PAM -DZLIB \ -DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \ $(K5INC) $(K5INC)/krb5 $(SSLINC) \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \ "LIBS = $(K5LIB) $(SSLLIB) \ -lm -lncurses -ltermcap -lssl -lcrypto -lgssapi_krb5 \ -lkrb5 -lcom_err -lk5crypto -lcrypt -lresolv -lpam -ldl -lz" # "make linuxnotcp" with lcc (see http://www.cs.princeton.edu/software/lcc) # lcc does not understand various gcc extensions: # "__inline__" -- can be eliminated by adding "-D__inline__=" # "__asm__ and "long long" -- in header files, should be surrounded by # "#ifndef(__STRICT_ANSI__)"/"#endif" # however, TCP requires some __asm__ functions, so cannot be compiled linuxnotcp-lcc: @echo 'Making C-Kermit $(CKVER) for Linux with lcc ...' @echo 'Read comments in makefile for additional information.' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC = lcc" "CC2 = lcc" \ "CFLAGS = -DLINUX -DPOSIX -DCK_CURSES -DCK_POSIX_SIG \ -UTCPSOCKET -DLINUXFSSTND -DNOLEARN $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" "LIBS = -lcurses -ltermcap" # Linux 0.99.14 thru 1.0 with gcc, dynamic libraries, curses, TCP/IP. # For Linux 1.2 or later, use "make linux" (above). # # -DLINUXFSSTND (Linux File System Standard) gives UUCP lockfile /var/lock with # string pid. Remove this and get /usr/spool/uucp with int pid, which was used # in early Linux versions. # # If you get compiler errors regarding , add -DNOHISPEED. # # -DCK_POSIX_SIG (POSIX signal handling) is good for Linux releases back to at # least 0.99.14; if it causes trouble for you, just remove it. # # -DCK_CURSES: Here we link with the regular curses library. But you should # be using ncurses. Internally, the ckuusx.c module includes , but # this really should be . Thus if you have the new curses # material, you should either install it with the standard names, or else # create symbolic links from the standard names to the new ones. If you get # compile-time errors complaining about data definitions in termcap.h, it # means you have new kernel material mixed with older libc header files. To # fix, add "#include " to the file. Or if all this is # too confusing, create a new makefile entry based on this one, but with # -DCK_CURSES removed from CFLAGS and the entire LIBS= clause removed. # # But wait, there's more. On most Linux systems, -ltermcap must be included # in LIBS. But on others, the linker complains that libtermcap can't be # found. In that case, try removing -ltermcap from LIBS=. # # But wait, there's more. The format of the PID string in the UUCP lockfile # changed between Linux FSSTND 1.0 and 1.2. In the earlier standard, it had # leading zeros; in the second, it has leading spaces. By default this entry # uses the newer standard. To force the older one, add -DFSSTND10. # # "The nice thing about the Linux standard is there are so many to choose from" # # NOTE: Remove -DBIGBUFOK for small-memory or limited-resource systems. linux10: @echo 'Making C-Kermit $(CKVER) for Linux 1.0 or earlier...' @echo 'IMPORTANT: Read the comments in the linux section of the' @echo 'makefile if you get compilation or link errors.' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -DPOSIX -DCK_CURSES -DCK_POSIX_SIG -DLINUX \ -DTCPSOCKET -DLINUXFSSTND -DOLINUXHISPEED -DNOLEARN $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS)" "LIBS = -lcurses -ltermcap" #This version was used for Linux prior to C-Kermit 6.0.192. #Now the "Linux File System Standard" is considered standard, ditto TCP/IP. linuxold: @echo 'Making C-Kermit $(CKVER) for Linux...' @echo 'For FSSTND-recommended UUCP lockfiles, use:' @echo ' make linux "KFLAGS=-DLINUXFSSTND".' @echo 'Read comments in makefile for additional options.' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS = -O -DLINUX -DPOSIX -DCK_CURSES -DCK_POSIX_SIG -DNOLEARN \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" "LIBS = -lcurses -ltermcap" # ::END_OLD_LINUX_TARGETS:: # LynxOS 2.2 with GCC compiler, TCP/IP and fullscreen display. # Probably also works with Lynx 2.1, and maybe even Lynx 2.0. # -X means use termios serial drivers rather than BSD4.3-style sgtty drivers. # If you have trouble with this, try "make bsd KFLAGS=-DNOFDZERO". lynx: @echo 'Making C-Kermit $(CKVER) for LynxOS 2.2 with TCP/IP' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS= -O -DPOSIX -DDIRENT -DSETREUID -DCK_CURSES -DTCPSOCKET \ -DCK_ANSIC -DLYNXOS -DNOLEARN" "LNKFLAGS = -X" "LIBS = -lcurses -lbsd" lynx22: $(MAKE) lynx KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS)" # LynxOS 2.1 with GCC compiler 1.40 and TCP/IP. lynx21: @echo 'Making C-Kermit $(CKVER) for LynxOS 2.1 with TCP/IP' $(MAKE) kermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS= -O -DSETREUID -DTCPSOCKET -DCK_ANSIC -DBSD4 -DLYNXOS" \ "LIBS = -lbsd" #SCO Xenix 2.2.1 for IBM PC, XT, PS2/30, or other 8088 or 8086 machine #Should this not work, try some of the tricks from sco286. #NOTE: -DRENAME is omitted for early SCO Xenix releases because it didn't #exist, or its semantics were different from the later POSIX-compliant #version of rename(). sco86: @echo 'Making C-Kermit $(CKVER) for SCO Xenix/86...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DXENIX -DNOFILEH -DNOIKSD -DNOUNICODE -DNOLEARN \ $(KFLAGS) -Dunix -F 3000 -i -M0me" \ "LNKFLAGS = -F 3000 -i -s -M0me" "LIBS = -lx" #SCO Xenix/286 2.2.1, e.g. for IBM PC/AT, PS/2 Model 50, etc. #Reportedly, this "make" can fail simply because of the size of this #makefile. If that happens, use "makeL", or edit out some of the #other entries. No debugging or character-set translation. sco286: @echo 'Making C-Kermit $(CKVER) for SCO Xenix/286...' @echo 'If make fails, try using makeL.' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -xenix -s -O -LARGE -DXENIX -DNOFILEH -Dunix -DRDCHK -DNAP \ -DNOIKSD -DNODEBUG -DNOTLOG -DNOCSETS -DNOLEARN \ $(KFLAGS) -F 3000 -i -M2let16" \ "LIBS = -lx" "LNKFLAGS = -xenix -s -O -LARGE -F 3000 -i -M2let16" #SCO Xenix/286 2.2.1, e.g. for IBM PC/AT, PS/2 Model 50, etc. #As above, but with HDBUUCP (This one might need fixing -- see sco286). sco286hdb: @echo 'Making C-Kermit $(CKVER) for SCO Xenix/286 with HDB UUCP...' @echo 'If make fails, try using makeL.' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -s -O -LARGE -DXENIX -DNOFILEH -Dunix -DRDCHK -DNAP \ -DHDBUUCP -DNOIKSD -DNOUNICODE -DNOLEARN \ $(KFLAGS) -F 3000 -i -M2let32" \ "LIBS = -lx" "LNKFLAGS = -s -O -LARGE -F 3000 -i -M2let32" #SCO Xenix/386 2.2.2 and 2.2.3 sco386: @echo 'Making C-Kermit $(CKVER) for SCO Xenix/386 2.2.2...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DXENIX -DNOFILEH -DNOIKSD -DNOREDIRECT -DNOLEARN \ -Dunix -DRDCHK -DNAP -DNOUNICODE $(KFLAGS) -Otcl -M3e" \ "LNKFLAGS = -s" "LIBS = -lx" #SCO XENIX/386 2.2.3 with Excelan TCP/IP + curses. # NOTE: This one might need some work in C-Kermit 6.0. # You might need to include /usr/include/sys/types.h # containing "typedef char *caddr_t;". Then at least it compiles. sco386netc: @echo 'Making C-Kermit $(CKVER) for SCO Xenix/386 2.2.3 + Excelan TCP' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -I/usr/include/exos -DXENIX -DCK_CURSES -DNOUNICODE \ -Dunix -DRDCHK -DNAP -DTCPSOCKET -DEXCELAN -DNOJC -DNOMKDIR -DNOFILEH \ -DNOLEARN -DNOREDIRECT -DNOIKSD -DNO_DNS_SRV $(KFLAGS) -Otcl -M3e" \ "LNKFLAGS = -s" "LIBS = -lc -lx -lsocket -lcurses -ltermcap" #SCO XENIX/386 2.3.3 with gcc 1.37 or later... sco386gcc: @echo 'Making C-Kermit $(CKVER) for SCO Xenix/386 2.3.3, gcc...' @echo 'Add -D_NO_PROTOTYPE if you have trouble with Xenix header files' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS= -O -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP \ -DNOJC -DNODEBUG -DNOUNICODE -DNOLEARN $(KFLAGS) \ -traditional -fpcc-struct-return -fstrength-reduce \ -DM_BITFIELDS -DM_COFF -DM_I386 -DM_I86 -DM_I86SM \ -DM_INTERNAT -DM_SDATA -DM_STEXT -DM_SYS3 -DM_SYS5 \ -DM_SYSIII -DM_SYSV -DM_WORDSWAP -DM_XENIX -DNOIKSD -DNOREDIRECT \ -DPWID_T=int " "LNKFLAGS = -s" "LIBS = -lx" #As above, but with curses... sco386gccc: @echo 'Making C-Kermit $(CKVER) for SCO Xenix/386 2.3.3, gcc...' @echo 'Add -D_NO_PROTOTYPE if you have trouble with Xenix header files' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \ "CFLAGS= -O -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP \ -DNOJC -DNODEBUG -DCK_CURSES -DNOUNICODE -DNOLEARN $(KFLAGS) \ -traditional -fpcc-struct-return -fstrength-reduce \ -DM_BITFIELDS -DM_COFF -DM_I386 -DM_I86 -DM_I86SM -DNOREDIRECT \ -DM_INTERNAT -DM_SDATA -DM_STEXT -DM_SYS3 -DM_SYS5 \ -DM_SYSIII -DM_SYSV -DM_WORDSWAP -DM_XENIX -DNOIKSD \ -DPWID_T=int " "LNKFLAGS = -s" "LIBS = -lx -lcurses -ltermlib" #SCO UNIX (and ODT) entries... # #NOTE: All SCO UNIX entry LIBS should have "-lc_s -lc -lx" IN THAT ORDER (if #shared C library is desired), or else "-lc -lx" IN THAT ORDER. Use shared C #libraries to save memory, but then don't expect to run the resulting binary #on a different machine. When using -lc_s, you must also use -lc, because the #shared C library does not contain all of libc.a. And in all cases, -lc must #ALWAYS precede -lx. # #ANOTHER NOTE: -DRENAME is included in all SCO UNIX entries. Remove it if it #causes trouble. No harm is done by removing it (see ckuins.txt). # #AND ANOTHER: In theory, it should be possible to run SCO UNIX binaries on #SCO Xenix 2.3 and later. In practice, this might not work because of the #libraries, etc. Also, don't add the -link -z switch (which is supposed to #root out references to null pointers) because it makes UNIX binaries core #dump when they are run under Xenix. #NOTE: -Otcl removed and replaced by -O, since -Otcl produced incorrect code. #SCO UNIX/386 3.2.0, 3.2.1, and SCO Xenix 2.3.x sco3r2: @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2.0 or 3.2.1 ...' @echo 'Warning: If make blows up, edit the makefile to join' @echo 'the following three continued lines into one line.' @echo 'Also, remove -DRENAME if _rename unresolved at link time.' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP -DNOLEARN \ -DRENAME -DNOIKSD -DNOJC $(KFLAGS) -O" \ "LNKFLAGS = -s" "LIBS = -lc -lx" #SCO UNIX/386 3.2.0 and SCO Xenix 2.3.x with Excelan TCP/IP support. #In case of compilation or runtime problems, try adding #"-DUID_T=int -DGID_T=int" to the CFLAGS. If that doesn't work, try #"-DUID_T=uid_t -DGID_T=gid_t". sco3r2net: @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 / Excelan...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -I/usr/include/exos -DXENIX -DSVR3 -DNOFILEH -DNOLEARN \ -DHDBUUCP -DRDCHK -DNAP -DRENAME -DTCPSOCKET -DEXCELAN -DNOJC \ -DNOIKSD -DNOREDIRECT $(KFLAGS) -O" \ "LNKFLAGS = -s" "LIBS = -lc -lx -lsocket" #SCO UNIX/386 3.2.0 and SCO Xenix 2.3.x with Excelan TCP/IP support. #As above, with curses added. sco3r2netc: @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 / Excelan / curses...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -I/usr/include/exos -DXENIX -DSVR3 -DNOFILEH -DNOLEARN \ -DHDBUUCP -DRDCHK -DNAP -DTCPSOCKET -DEXCELAN -DNOJC $(KFLAGS) \ -DRENAME -DCK_CURSES -DNOREDIRECT -DNOIKSD -O" "LNKFLAGS = -s" \ "LIBS = -lc -lx -lsocket -lcurses -ltermcap" #SCO UNIX 3.2.x or SCO Xenix 2.3.x with Racal InterLan TCP/IP support # Extra compile flags for other version of Racal InterLan TCP/IP: # Xenix286/NP621-286, use -Ml -DPARAMH -DINTERLAN -Di286 -DSYSV # Xenix386/NP621-386, use -DPARAMH -DINTERLAN -Di386 -DSYSV # ISC386ix/NP622I, use -DSYSV -Di386 # SCO Unix3.2/NP622S, use -DSYSV -Di386 -DSCO_UNIX # AT&T SVR3.2/NP622A, use -DSYSV -Di386 -DATT sco3r2netri: @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 / Racal InterLan...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -I/usr/include/interlan -DXENIX -DNOFILEH -DHDBUUCP \ -DSVR3 -DRDCHK -DNAP -DTCPSOCKET -DPARAMH -DINTERLAN -Di386 -DSYSV \ -DRENAME -DNOREDIRECT -DNOIKSD -DNOJC -DNOLEARN $(KFLAGS) -Otcl -M3e" \ "LNKFLAGS = -s" "LIBS = -lc -lx -ltcp" # SCO XENIX/386 2.3.3 SysV with SCO TCP/IP # System V STREAMS TCP developed by Lachman Associates Inc and # Convergent Technologies. # -DRENAME removed since some reports indicate it is not supported # (whereas others say it is.) sco3r2lai: @echo 'Making C-Kermit $(CKVER) for SCO XENIX/386 2.3.3 + TCP/IP...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DLAI_TCP -Di386 -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK \ -DNAP -DTCPSOCKET -DPWID_T=int -DNOREDIRECT -DNOIKSD -DNOLEARN \ $(KFLAGS) -Otcl -i -M3e" \ "LNKFLAGS = -i -s" "LIBS = -lc -lx -lsocket" sco3r2laic: @echo 'Making C-Kermit $(CKVER) for SCO XENIX/386 2.3.3 + TCP/IP...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DLAI_TCP -Di386 -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK \ -DNAP -DTCPSOCKET -DCK_ANSIC -DCK_CURSES -DM_TERMINFO -DNOLEARN \ -DPWID_T=int -DNOREDIRECT -DNOIKSD $(KFLAGS) -Otcl -i -M3e" \ "LNKFLAGS = -i -s" "LIBS = -ltinfo -lc -lx -lsocket" #SCO UNIX/386 3.2v2 (POSIX job control), shared libraries. sco3r22: @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v2 ...' make wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNOLEARN \ -DNAP -DRENAME -DPID_T=pid_t -DPWID_T=int -DDIRENT -DNOIKSD \ -DNOREDIRECT $(KFLAGS) -O" \ "LNKFLAGS = -s" "LIBS = -lc_s -lc -lx" #SCO UNIX/386 3.2v2, POSIX job control, fullscreen file transfer display, #dynamic memory allocation, shared C library sco3r22c: @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v2 ...' @echo 'Warning: If make blows up, edit the makefile to join' @echo 'the following four continued lines into one line.' make wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP -DNOLEARN \ -DCK_CURSES -DDIRENT -DRENAME -DNOREDIRECT -DNOIKSD \ -DPID_T=pid_t -DPWID_T=int $(KFLAGS) -O" \ "LNKFLAGS = -s" "LIBS = -lcurses -lc_s -lc -lx" #SCO UNIX/386 3.2v2 with gcc 1.40 or later (POSIX job control) sco3r22gcc: @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v2, gcc' @echo 'Warning: If make blows up, edit the makefile to join' @echo 'the following seven continued lines into one line.' make wermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" \ "CFLAGS= -O -DPOSIX -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP \ -DNOLEARN -DRENAME -traditional -fpcc-struct-return -fstrength-reduce \ -DM_BITFIELDS -DM_COFF -DM_I386 -DM_I86 -DM_I86SM \ -DM_INTERNAT -DM_SDATA -DM_STEXT -DM_SYS3 -DM_SYS5 \ -DM_SYSIII -DM_SYSV -DM_UNIX -DM_WORDSWAP -DM_XENIX -Dunix \ -DPID_T=pid_t -DPWID_T=int -DNOREDIRECT -DNOIKSD $(KFLAGS) " \ "LNKFLAGS = -s" "LIBS = -lc_s -lc -lx" #SCO UNIX/386 3.2v2 (ODT 1.1) (POSIX job control) with SCO TCP/IP, shared libs #Requires SCO TCP/IP or ODT development system for telnet.h, etc. sco3r22net: @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2.2 + TCP/IP...' @echo 'Warning: If make blows up, edit the makefile to join' @echo 'the following three continued lines into one line.' make xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP -DTCPSOCKET \ -DRENAME -DPID_T=pid_t -DPWID_T=int -DDIRENT -DNOREDIRECT -DNOIKSD \ $(KFLAGS) -O" "LNKFLAGS = -s" "LIBS = -lsocket -lc_s -lc -lx" #As above, but with curses for fullscreen file transfer display. #Requires SCO TCP/IP or ODT development system for telnet.h, etc. sco3r22netc: @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v2 + TCP/IP...' @echo 'Warning: If make blows up, edit the makefile to join' @echo 'the following three continued lines into one line.' make xermit KTARGET=$${KTARGET:-$(@)} "CFLAGS= \ -DXENIX -DSVR3 -DNOFILEH -DHDBUUCP -DRDCHK -DNAP -DTCPSOCKET -DRENAME \ -DCK_CURSES -DDIRENT -DNOIKSD -DNOREDIRECT \ -DPID_T=pid_t -DPWID_T=int -O $(KFLAGS)" \ "LNKFLAGS = -s" "LIBS = -lcurses -lsocket -lc_s -lc -lx" #SCO XENIX 2.3.4, no curses, no TCP/IP, no IKSD. #This one built and tested in C-Kermit 7.0. #lcfp is C library floating-point support. #Use -M3 to generate 32-bit i386 code instead of 16-bit segmented i286 code. #Use -Me to enable MS nonstandard keywords in system headers. #Use -W2 or W3 to increase the warning level. #OK: 2011/06/15 sco234: @echo 'Making C-Kermit $(CKVER) for SCO XENIX 2.3.4...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DSCO32 -DXENIX -DNOFILEH -DHDBUUCP -DRDCHK -DNOLEARN \ -DNAP -DNOJC -DNOCOTFMC -DNOIKSD -DNOREDIRECT -DNOTNCODE -DNOGFTIMER \ -DNOTIMEVAL -DNOTIMEZONE -DNOSYMLINK -DSCO234 -DDCLGETCWD $(KFLAGS) \ -Otcl" "LNKFLAGS = -s" "LIBS = -lcfp -lc -lx" #SCO XENIX 2.3.4, no TCP/IP, no IKSD, but with curses. # Built and tested in C-Kermit 7.0. # Note: XENIX 2.3.4 does not have newterm() so no point in adding -DCK_NEWTERM. sco234c: @echo 'Making C-Kermit $(CKVER) for SCO XENIX 2.3.4 + curses...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DSCO32 -DXENIX -DNOFILEH -DHDBUUCP -DRDCHK -DNOLEARN \ -DNAP -DNOJC -DNOCOTFMC -DNOIKSD -DNOREDIRECT -DNOTNCODE -DNOGFTIMER \ -DNOTIMEVAL -DNOTIMEZONE -DNOSYMLINK -DCK_CURSES -DSCO234 \ -DDCLGETCWD $(KFLAGS) -Otcl" \ "LNKFLAGS = -s" "LIBS = -lcfp -lc -ltinfo -lx" #SCO XENIX 2.3.4 with SCO TCP/IP and curses, no IKSD. # Built and tested in C-Kermit 7.0. TCP/IP works and curses works. # Previous versions of this target included -lmalloc, but this caused "error: # " _calloc : symbol defined more than once" at link time so I removed it. # Results are likely to vary depending on exactly which version of the SDK # and TCP/IP SDK you have. sco234netc: @echo 'Making C-Kermit $(CKVER) for SCO XENIX 2.3.4 + TCP + curses...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DSCO32 -DXENIX -DNOFILEH -DHDBUUCP -DRDCHK -DNOLEARN \ -DNAP -DNOJC -DNOCOTFMC -DNOIKSD -DNOREDIRECT -DNOTNCODE -DNOGFTIMER \ -DNOTIMEVAL -DNOTIMEZONE -DNOSYMLINK -DCK_CURSES -DSCO234 \ -DDCLGETCWD -DTCPSOCKET -DNO_DNS_SRV $(KFLAGS) -Otcl" \ "LNKFLAGS = -s" "LIBS = -ltinfo -lsocket -lcfp -lc -lx" # SCO 3.2v4.x targets... # NOTE: Add -DDCLPOPEN and/or -DDCLFDOPEN to anySCO 3.2v4.x non-gcc entries # that complain about fdopen() or popen() at compile time. They compile OK # without these flags as of July 1999. However, the gcc entries seem to # need them, at least for gcc 2.7.2.2. # NOTE 2: To enable IKSD support, add: # -DCK_LOGIN -DNOGETUSERSHELL -DNOINITGROUPS # to CFLAGS (not tested). #SCO UNIX/386 3.2v4 (POSIX job control), curses, ANSI C compilation, # (EAFS) file system. Remove -lmalloc if it causes trouble. It was #put there to avoid core dumps caused by regular libc.a malloc. Add -J to make #all chars unsigned. This version uses select() for CONNECT and also has #high-precision timers and so might not work on non-TCP systems, in which case #sco32v4ns should be used instead. # If you get _ftime redefinition_ complaint, try adding -DODT30 to CFLAGS. sco32v4: @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v4...' make xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DCK_SCO32V4 -DNOFILEH -DHDBUUCP -DCK_CURSES -DM_TERMINFO \ -DNOANSI -DSELECT -DNOIKSD -DDCLGETCWD -NOLSTAT \ -DNOLINKBITS -DDCLGETCWD $(KFLAGS) -O" \ "LNKFLAGS = -s" "LIBS = -lcurses -lmalloc -lsocket -lc_s -lc -lx" # As above, but with no dependence on sockets library or select(). sco32v4ns: @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v4...' @echo 'No select() and no sockets library.' make wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DCK_SCO32V4 -DNOFILEH -DHDBUUCP -DCK_CURSES -DM_TERMINFO \ -DNOANSI -DNOIKSD -DNOGFTIMER -DCK_POLL -DNAP -DDCLGETCWD -DNOLSTAT \ -DNOLINKBITS -DDCLGETCWD -DNOLEARN -O $(KFLAGS)" \ "LNKFLAGS = -s" "LIBS = -lcurses -lmalloc -lc_s -lc -lx" #SCO UNIX/386 3.2v4 (POSIX job control), TCP/IP, curses, ANSI C compilation, # (EAFS) file system. With DIRENT, -lc must come before -lx. #Reportedly it's OK to add -DCK_REDIR and -DCK_WREFRESH, and to remove -lc_s. #Requires SCO TCP/IP development system or ODT for telnet.h, etc. #See sco32v4 above for additional comments. #NOTE: No more room for -Dxxx -- 25 seems to be the limit. Move some to #ckcdeb.h or somewhere... sco32v4net: @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v4...' @echo 'If you get _ftime redefinition_ complaint,' @echo 'use make sco-odt30.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DNOFILEH -DHDBUUCP -DTCPSOCKET -DCK_ANSIC -DCK_CURSES \ -DNAP -DCK_WREFRESH -DNOLINKBITS -D_IBCS2 -DSELECT -DNOLSTAT \ -DDCLGETCWD -DCK_SCO32V4 -DNOIKSD -O \ $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS) -s" \ "LIBS = $(LIBS) -lcurses -lsocket -lmalloc -lsocket -lc_s -lc -lx" #SCO UNIX/386 3.2v4 with gcc 1.40 or later, POSIX job control. #Also see comments in sco32r4 entry. sco32v4gcc: make xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" \ "CFLAGS= -O -DNOFILEH -DHDBUUCP -DNOANSI -DCK_CURSES -DM_TERMINFO \ -traditional -fpcc-struct-return -fstrength-reduce -funsigned-char \ -D_KR -D_NO_PROTOTYPE -D_SVID -DNOIKSD -DCK_SCO32V4 -DNOLINKBITS \ -DM_BITFIELDS -DM_COFF -DM_I386 -DM_I86 -DM_I86SM -DSELECT -DNOLSTAT \ -DM_INTERNAT -DM_SDATA -DM_STEXT -DM_SYS3 -DM_SYS5 -DDCLGETCWD \ -DM_SYSIII -DM_SYSV -DM_UNIX -DM_WORDSWAP -DM_XENIX -Dunix \ -DDCLPOPEN -DDCLFDOPEN $(KFLAGS) " \ "LNKFLAGS = -s" "LIBS = -lcurses -lsocket -lc_s -lc -lx" #SCO UNIX/386 3.2v4 (POSIX job control), TCP/IP, curses, ANSI C compilation, #Requires SCO TCP/IP or ODT development system for telnet.h, etc. # (EAFS) file system. With DIRENT, -lc must come before -lx. #gcc 1.40 or later. Also see comments in sco32r4 entry. sco32v4netgcc: make xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2=gcc" \ "CFLAGS= -O2 -DNOFILEH -DHDBUUCP -DSELECT -DNOLSTAT \ -DNOANSI -DTCPSOCKET -DCK_CURSES -DM_TERMINFO \ -D_KR -D_NO_PROTOTYPE -D_SVID -DNOIKSD -DCK_SCO32V4 -DNOLINKBITS \ -DM_BITFIELDS -DM_COFF -DM_I386 -DM_I86 -DM_I86SM -DDCLGETCWD \ -DM_INTERNAT -DM_SDATA -DM_STEXT -DM_SYS3 -DM_SYS5 \ -DM_SYSIII -DM_SYSV -DM_UNIX -DM_WORDSWAP -DM_XENIX -Dunix \ -DDCLPOPEN -DDCLFDOPEN $(KFLAGS)" \ "LNKFLAGS = -s" "LIBS = -lcurses -lsocket -lc_s -lc -lx" #As above but with bgcc BOUNDS CHECKING (for developers only). -lcheck has #bounds-checking replacements for malloc, memcpy, bcopy, etc, so must come #before -lsocket and -lc. sco32v4netbgcc: make xermit KTARGET=$${KTARGET:-$(@)} \ "CC = bgcc -pipe -m386" "CC2=bgcc -pipe -m386" \ "CFLAGS= -O1 -g -DNOFILEH -DHDBUUCP -DSELECT \ -DNOANSI -DTCPSOCKET -DCK_CURSES -DM_TERMINFO \ -D_KR -D_NO_PROTOTYPE -D_SVID -DNOIKSD -DCK_SCO32V4 -DNOLSTAT \ -DM_BITFIELDS -DM_COFF -DM_I386 -DM_I86 -DM_I86SM -DNOLINKBITS \ -DM_INTERNAT -DM_SDATA -DM_STEXT -DM_SYS3 -DM_SYS5 -DDCLGETCWD \ -DM_SYSIII -DM_SYSV -DM_UNIX -DM_WORDSWAP -DM_XENIX -Dunix \ -DDCLPOPEN -DDCLFDOPEN $(KFLAGS) " \ "LNKFLAGS = -g" "LIBS = -lcurses -lcheck -lsocket -lx" sco32v4netnd: @echo sco32v4net with no debug $(MAKE) "MAKE=$(MAKE)" sco32v4net KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(KFLAGS) -DNODEBUG -DNOTLOG" "LIBS=$(LIBS)" sco3r2netnd: @echo sco32v4netnd built for SCO XENIX 2.3 under SCO UNIX... @echo requires copying /lib/386/Slibc.a to /lib/386/Slibc_s.a and @echo getting /lib/386/Slibsocket.a from a XENIX devkit. @echo WARNING: poll/CK_POLL supported only on XENIX 2.3.4 echo For earlier XENIX systems, replace CK_POLL with RDCHK. $(MAKE) "MAKE=$(MAKE)" sco32v4netnd KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(KFLAGS) -x2.3 -DNORENAME -DNOSYMLINK" \ "LNKFLAGS = $(LNKFLAGS) -x2.3" \ "LIBS=-ldir -lcfp $(LIBS)" #SCO UNIX/386 3.2v4 (POSIX job control), TCP/IP, curses, ANSI C compilation, # (EAFS) file system. With DIRENT, -lc must come before -lx. #Reportedly it's OK to add -DCK_REDIR and -DCK_WREFRESH, and to remove -lc_s. #Requires SCO TCP/IP development system or ODT for telnet.h, etc. #See sco32v4 above for additional comments. # Note: "xermit" means use the select() version of the CONNECT module. sco32v4netx: @echo 'Making C-Kermit $(CKVER) for SCO UNIX/386 3.2v4...' @echo 'If you get _ftime redefinition_ complaint,' @echo 'use make sco-odt30.' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DNOFILEH -DHDBUUCP -DTCPSOCKET -DCK_ANSIC -DCK_CURSES -DNAP \ -DCK_WREFRESH -DNOLINKBITS -D_IBCS2 -DSELECT -DDCLGETCWD \ -DCK_SCO32V4 -DNOIKSD -DNOLSTAT -O $(KFLAGS)" \ "LNKFLAGS = $(LNKFLAGS) -s" \ "LIBS = $(LIBS) -lcurses -lsocket -lmalloc -lsocket -lc_s -lc -lx" sco32v4netndx: @echo sco32v4netx with no debug $(MAKE) "MAKE=$(MAKE)" sco32v4netx KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(KFLAGS) -DNODEBUG -DNOTLOG" "LIBS=$(LIBS)" sco3r2netndx: @echo sco32v4netndx built for SCO XENIX 2.3 under SCO UNIX... @echo requires copying /lib/386/Slibc.a to /lib/386/Slibc_s.a and @echo getting /lib/386/Slibsocket.a from a XENIX devkit. @echo WARNING: poll/CK_POLL supported only on XENIX 2.3.4 echo For earlier XENIX systems, replace CK_POLL with RDCHK. $(MAKE) "MAKE=$(MAKE)" sco32v4netndx KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(KFLAGS) -x2.3 -DNORENAME -DNOSYMLINK" \ "LNKFLAGS = $(LNKFLAGS) -x2.3" \ "LIBS=-ldir -lcfp $(LIBS)" sco-odt30: @echo SCO ODT 3.0 $(MAKE) "MAKE=$(MAKE)" sco32v4net KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=$(KFLAGS) -DODT30" #SCO OpenServer 5.0 (SCO UNIX 3.2v5.0) with SCO development tools, no TCP/IP. #SCO OSR5 is much more like standard System V than previous SCO releases. #The SCO development tools include TCP/IP, so this target is only for creating #artificially limited versions of kermit required by site policy rather than #the operating system. NOSYSLOG is included because syslog() requires the #sockets library. sco32v500: @echo Making C-Kermit $(CKVER) for SCO OpenServer Release 5... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -O -DDIRENT -DHDBUUCP -DSVR4 -DCK_SCOV5 -DCK_RTSCTS \ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DSELECT -DSELECT_H \ -DNOGETUSERSHELL -DNOLSTAT -DNOLINKBITS -DNOSYSLOG \ -DNORLOGIN -DNO_PTY_XOPEN_SOURCE \ $(KFLAGS)" \ "LIBS=-lcurses $(LIBS)" "LNKFLAGS=$(LNKFLAGS)" sco32v5: $(MAKE) "MAKE=$(MAKE)" "KFLAGS=$(KFLAGS)" sco32v500 #SCO OpenServer 5.0 with networking, SCO development tools. #Networking libraries are now provided with the OS. sco32v500net: @echo Making C-Kermit $(CKVER) for SCO OpenServer Release 5... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -O -DDIRENT -DHDBUUCP -DSVR4 -DCK_SCOV5 -DCK_RTSCTS \ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DSELECT -DSELECT_H \ -DNOGETUSERSHELL -DNOLSTAT -DNOLINKBITS -DTCPSOCKET \ -DNORLOGIN -DNO_PTY_XOPEN_SOURCE \ -DNO_DNS_SRV $(KFLAGS)" \ "LIBS=-lcurses -lsocket $(LIBS)" "LNKFLAGS=$(LNKFLAGS)" sco32v5net: $(MAKE) "MAKE=$(MAKE)" "KFLAGS=$(KFLAGS)" sco32v500net #SCO OpenServer 5.0 with networking and OpenSSL, SCO development tools. #Networking libraries are now provided with the OS. sco32v500net+ssl: @echo Making C-Kermit $(CKVER) for SCO OSR5 with OpenSSL... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -O -DDIRENT -DHDBUUCP -DSVR4 -DCK_SCOV5 -DCK_RTSCTS \ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DSELECT -DSELECT_H \ -DNOGETUSERSHELL -DNOLSTAT -DNOLINKBITS -DTCPSOCKET \ -DNO_DNS_SRV -DCK_AUTHENTICATION -DCK_SSL -DCK_TRIGGER \ -DNORLOGIN -DNO_PTY_XOPEN_SOURCE \ $(SSLINC) $(SSLLIB) $(KFLAGS)" \ "LIBS=$(SSLLIB) -lcurses -lsocket -lssl -lcrypto $(LIBS)" \ "LNKFLAGS=$(LNKFLAGS)" #SCO OpenServer 5.0 with gcc, no networking. #Note: NOSYSLOG required for non-net entries because it requires sco32v500gcc: @echo Using gcc... $(MAKE) "MAKE=$(MAKE)" sco32v500 CC=gcc CC2=gcc \ KTARGET=$${KTARGET:-$(@)} "KFLAGS= $(KFLAGS)" #SCO OpenServer 5.0 with networking, gcc. sco32v500netgcc: @echo TCP/IP networking added - using gcc... $(MAKE) "MAKE=$(MAKE)" sco32v500net CC=gcc CC2=gcc \ KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS)" #SCO OpenServer 5.0 with networking, gcc, elf. sco32v500netgccelf: @echo TCP/IP networking added - using gcc, dynamic elf library $(MAKE) "MAKE=$(MAKE)" sco32v500net "CC=gcc" "CC2=gcc" \ KTARGET=$${KTARGET:-$(@)} "KFLAGS=-O3 -belf" "LNKFLAGS=-belf" sco32v502: $(MAKE) "MAKE=$(MAKE)" sco32v500 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR502 $(KFLAGS)" #SCO OpenServer 5.0.2 with networking, SCO development tools. sco32v502net: @echo TCP/IP networking added... $(MAKE) "MAKE=$(MAKE)" sco32v500net KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-b elf -DSCO_OSR502 $(KFLAGS)" #SCO OpenServer 5.0.4 (SCO UNIX 3.2v5.0.4) with SCO development tools. #Like 5.0, but adds high serial speeds. First POSIX-based SCO version. #Note: the -O flag is deliberately omitted for /bin/cc (= /usr/ccs/bin/cc). sco32v504: @echo Making C-Kermit $(CKVER) for SCO OpenServer Release 5.0.4... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DDIRENT -DHDBUUCP -DSVR4 -DCK_SCOV5 -DCK_RTSCTS \ -DSCO_OSR504 -b elf -DPOSIX \ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DSELECT -DSELECT_H \ -DNOGETUSERSHELL -DNOLSTAT -DNOLINKBITS -DNOSYSLOG $(KFLAGS)" \ "LIBS=-lcurses $(LIBS)" "LNKFLAGS=$(LNKFLAGS)" #SCO OpenServer 5.0.4 with gcc, no networking. sco32v504gcc: @echo Using gcc... $(MAKE) "MAKE=$(MAKE)" sco32v504 "CC=gcc" "CC2=gcc" \ KTARGET=$${KTARGET:-$(@)} "KFLAGS= $(KFLAGS)" #SCO OpenServer 5.0.4 with networking. #SCO development tools (/bin/cc = /usr/ccs/bin/cc). #Optimization deliberately suppressed. sco32v504net: @echo Making C-Kermit $(CKVER) for SCO OpenServer Release 5.0.4... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DDIRENT -DHDBUUCP -DSVR4 -DCK_SCOV5 -DCK_RTSCTS \ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DSELECT -DSELECT_H \ -DNOGETUSERSHELL -DNOLSTAT -DNOLINKBITS -DTCPSOCKET \ -DNORLOGIN -DNO_PTY_XOPEN_SOURCE \ -b elf -DSCO_OSR504 -DPOSIX -DNO_DNS_SRV $(KFLAGS)" \ "LIBS=-lcurses -lsocket $(LIBS)" "LNKFLAGS=$(LNKFLAGS)" #SCO OpenServer 5.0.4 with networking, gcc. sco32v504netgcc: @echo TCP/IP networking added - using gcc... $(MAKE) "MAKE=$(MAKE)" sco32v500net "CC=gcc" "CC2=gcc" \ KTARGET=$${KTARGET:-$(@)} "KFLAGS=-DSCO_OSR504 -DPOSIX $(KFLAGS)" #SCO OpenServer 5.0.4 with networking, gcc, elf. sco32v504netgccelf: @echo TCP/IP networking added - using gcc, dynamic elf library $(MAKE) "MAKE=$(MAKE)" sco32v500net "CC=gcc" "CC2=gcc" KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR504 -DPOSIX -O3 -belf $(KFLAGS)" \ LNKFLAGS="-belf" #SCO OpenServer 5.0.5 (SCO UNIX 3.2v5.0.5) with SCO /bin/cc. #Like 5.0, but adds high serial speeds. First POSIX-based SCO version. #You might have to add "LIBS=-ltinfo" (some do, some don't). sco32v505: $(MAKE) "MAKE=$(MAKE)" sco32v500 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DNOSHADOW -b elf -DPOSIX $(KFLAGS)" #SCO OpenServer 5.0.5 (SCO UNIX 3.2v5.0.5) with SCO UDK. #This one can't see the high serial speeds and anything to do with modem #signals doesn't work because UKD cc has its own alternative universe of #header files. sco32v505udk: $(MAKE) "MAKE=$(MAKE)" sco32v500 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DDCLTIMEVAL -DNOSHADOW -b elf -DPOSIX $(KFLAGS)" #SCO OpenServer 5.0.5 with networking, SCO /bin/cc. #See comments with sco32v505 targets. sco32v505net: @echo TCP/IP networking added... $(MAKE) "MAKE=$(MAKE)" sco32v500net KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DNOSHADOW -b elf -DPOSIX $(KFLAGS)" #SCO OpenServer 5.0.5 with networking and OpenSSL, SCO /bin/cc. #See comments with sco32v505 targets. sco32v505net+ssl: @echo TCP/IP networking and OpenSSL added... $(MAKE) "MAKE=$(MAKE)" sco32v500net+ssl KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DNOSHADOW -b elf -DPOSIX $(KFLAGS) " \ "LIBS=$(SSLLIB) -lcurses -lsocket -lssl -lcrypto $(LIBS)" \ "LNKFLAGS=$(LNKFLAGS)" #SCO OpenServer 5.0.5 with networking, SCO UDK. #See comments with above sco32v505 targets. sco32v505udknet: @echo TCP/IP networking added... $(MAKE) "MAKE=$(MAKE)" sco32v500net KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DNORLOGIN -DDCLTIMEVAL -DNOSHADOW \ -b elf -DPOSIX $(KFLAGS)" #SCO OpenServer 5.0.5 with gcc, no networking. sco32v505gcc: @echo Using gcc... $(MAKE) "MAKE=$(MAKE)" sco32v500 "CC=gcc" "CC2=gcc" \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DPOSIX -funsigned-char $(KFLAGS)" #SCO OpenServer 5.0.5 with gcc, no networking, no shadow passwords. sco32v505xgcc: @echo Using gcc... $(MAKE) "MAKE=$(MAKE)" sco32v500 "CC=gcc" "CC2=gcc" \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DNOSHADOW -DPOSIX -funsigned-char $(KFLAGS)" #SCO OpenServer 5.0.5 with networking, gcc. sco32v505netgcc: @echo TCP/IP networking added - using gcc... $(MAKE) "MAKE=$(MAKE)" sco32v500net "CC=gcc" "CC2=gcc" \ KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DNOSHADOW -DPOSIX -funsigned-char $(KFLAGS)" #egcs is just like gcc but generates ELF by default. #Or you can include -melf (not -belf) to force it. sco32v505netegcs: $(MAKE) "MAKE=$(MAKE)" "KFLAGS=$(KFLAGS)" sco32v505netgcc \ KTARGET=$${KTARGET:-$(@)} #SCO OpenServer 5.0.5 with networking, gcc, elf. sco32v505netgccelf: @echo TCP/IP networking added - using gcc, dynamic elf library $(MAKE) "MAKE=$(MAKE)" sco32v500net "CC=gcc" "CC2=gcc" \ "KFLAGS=-DSCO_OSR505 -DPOSIX -funsigned-char -O3 -belf $(KFLAGS)" \ KTARGET=$${KTARGET:-$(@)} LNKFLAGS="-belf" #SCO OpenServer 5.0.6 with SCO /bin/cc. # Add -DDCLTIMEVAL when building with UDK. #Like 5.0.5. IMPORTANT: Use sco32v506a target for 5.0.6a. sco32v506: $(MAKE) "MAKE=$(MAKE)" sco32v500 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DSCO_OSR506 -b elf -DPOSIX $(KFLAGS)" #SCO OpenServer 5.0.6 with networking, SCO /bin/cc. # Add -DDCLTIMEVAL when building with UDK. # IMPORTANT: Use sco32v506a target for 5.0.6a. sco32v506net: @echo TCP/IP networking added... $(MAKE) "MAKE=$(MAKE)" sco32v500net KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DSCO_OSR506 -b elf -DPOSIX $(KFLAGS)" #SCO OpenServer 5.0.6a, no networking, SCO development tools. #This one has patched sio drivers that, for the first time, #actually handle modem signals correctly. # Add -DDCLTIMEVAL when building with UDK. sco32v506a: $(MAKE) "MAKE=$(MAKE)" sco32v500 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DSCO_OSR506 -DSCO_OSR506A -DNEEDMDMDEFS \ -b elf -DPOSIX $(KFLAGS)" #SCO OpenServer 5.0.6a with networking, SCO development tools. # Add -DDCLTIMEVAL when building with UDK. sco32v506anet: @echo TCP/IP networking added... $(MAKE) "MAKE=$(MAKE)" sco32v500net KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DSCO_OSR506 -DSCO_OSR506A -DNEEDMDMDEFS \ -b elf -DPOSIX $(KFLAGS)" #SCO OpenServer 5.0.7, no networking, SCO development tools. #Adds flags to make PTY and SSH commands work. These have been tested #only in 5.0.7 but probably they can also be added to earlier OSR5 targets. sco32v507: $(MAKE) "MAKE=$(MAKE)" sco32v500 KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DSCO_OSR506 -DSCO_OSR507 -DNEEDMDMDEFS \ -DHAVE_PTSNAME -DHAVE_PTMX -DHAVE_GRANTPT \ -b elf -DPOSIX $(KFLAGS)" #SCO OpenServer 5.0.7 as above but with networking. sco32v507net: @echo TCP/IP networking added... $(MAKE) "MAKE=$(MAKE)" sco32v500net KTARGET=$${KTARGET:-$(@)} \ "KFLAGS=-DSCO_OSR505 -DSCO_OSR506 -DSCO_OSR507 -DNEEDMDMDEFS \ -DHAVE_PTSNAME -DHAVE_PTMX -DHAVE_GRANTPT \ -b elf -DPOSIX $(KFLAGS)" #SCO OpenServer 6 (new target 30 Jan 2006) sco_osr600 sco600: @echo Making C-Kermit $(CKVER) for SCO OpenServer 6.0.0... $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -O -DDIRENT -DHDBUUCP -DSVR4 -DCK_SCOV5 -DCK_RTSCTS \ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DSELECT -DSELECT_H \ -DNOGETUSERSHELL -DNOLSTAT -DNOLINKBITS -DTCPSOCKET \ -DNO_DNS_SRV -DSCO_OSR505 -DSCO_OSR506 -DSCO_OSR507 -DNEEDMDMDEFS \ -DHAVE_PTSNAME -DHAVE_PTMX -DHAVE_GRANTPT -DDCLTIMEVAL \ -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 \ -DSOCKOPT_T=socklen_t -DGSOCKNAME_T=size_t -DGPEERNAME_T=size_t \ -DHERALD=\"\\\" SCO OpenServer `uname -v`\\\"\" \ -b elf -DPOSIX $(KFLAGS)" \ "LIBS=-lcurses -lsocket $(LIBS)" "LNKFLAGS=$(LNKFLAGS)" #Tandy 16/6000 with Xenix 3.0 (16 bits) #C-Kermit 7.0 (and later) do not build here; "too many defines". #Add more -DNOxxx options to remove features if program won't load. #Successful operation is a function of program size, physical memory, #available swap space, etc. The following stripped-down configuration #seems to work on most Tandy 6000s. NOTE: "-+" means allow long variable #names, needed for C-Kermit 6.0 because some identifiers are not unique #within the first six characters. trs16: @echo 'Making C-Kermit $(CKVER) for Tandy 16/6000, Xenix 3.0...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -+ -DATTSV -DTRS16 -DNOMKDIR -DDCLPOPEN -DCK_CURSES \ -DNODEBUG -DNOTLOG -DNOHELP -DNOSCRIPT -DNOCSETS -DNOIKSD \ -DNOREDIRECT -DNOSYSLOG -DNOPUTENV -DNOREALPATH -DNOLEARN \ $(KFLAGS) -O" "LIBS= -lcurses -ltermcap" "LNKFLAGS = -+ -n -s" # QNX 4.21 and above, 32-bit version, Watcom C32 10.6, fully configured, # except no job control because QNX 4.x does not support it. New NCURSES # library used instead of CURSES. # # -Oatx optimizes to favor speed over size: loop optimization, inline fn's. # -Os favors size over speed. Saves 30-40K out of about 1.75M. # -3r = generate 386 code with register-based arg passing. # -3s = generate 386 code with stack-based arg passing. # -ms = separate code & data 4GB segments (32-bit builds only). # -mf = flat memory model code+data in one 4GB segment (ditto). # -zc = place literal strings in code segment. # -N4M = Big stack (increase the digit upon SIGSEGVs at runtime). # chars are unsigned by default (-j makes them signed by default). # -NOUUCP is included because QNX doesn't use it. # Add these to the end if you like but they dump core on my QNX 4.25 system: # # @wermit -h >use.qnx # @usemsg wermit use.qnx # @rm use.qnx # # If you get warnings about HEADER or C_IN add -DNO_DNS_SRV. # OK 2011/06/14 qnx32: @echo 'Making C-Kermit $(CKVER) for QNX 4.2x, 32-bit...' $(MAKE) xermit \ "LNKFLAGS = -N4M -3r" \ "CFLAGS = -ms -3r -DQNX -DTCPSOCKET -DCK_CURSES -DNOGETUSERSHELL \ -DCK_WREFRESH -DCK_REDIR -DSELECT -DSELECT_H -DCK_RTSCTS -DNOJC \ -DNOINITGROUPS -DNOUUCP -DCK_ANSIC -DPID_T=pid_t -Oatx -zc $(KFLAGS)" \ "LIBS= -lsocket -lncurses -ltermcap" # As above but no networking since some QNX systems do not have TCP/IP # installed, or the TCP/IP developers kit, which includes all the needed # header files. This entry has not been tested on a QNX system that, in # fact, does not have TCP/IP installed; some adjustments might be necessary, # in particular regarding the use of select(): is -lsocket needed, can we # get the needed definitions from non-TCP/IP header files (FD_SET, etc)? qnx32nonet: @echo 'Making C-Kermit $(CKVER) for QNX 4.2x, 32-bit, no net...' $(MAKE) xermit \ "LNKFLAGS = -N4M -3r" \ "CFLAGS = -3r -ms -DQNX -DNONET -DNOIKSD -DCK_CURSES \ -DCK_WREFRESH -DCK_REDIR -DSELECT -DSELECT_H -DCK_RTSCTS -DNOJC \ -DNOUUCP -DCK_ANSIC -DPID_T=pid_t -Oatx -zc $(KFLAGS)" \ "LIBS= -lsocket -lncurses -ltermcap" @wermit -h >use.qnx @usemsg wermit use.qnx @rm use.qnx # Synonym for qnx32. qnx: $(MAKE) qnx32 "KFLAGS=$(KFLAGS)" # QNX 4.21 and above, 16-bit version, Watcom C 8.5 - and higher on i286 PCs # and above. # # IMPORTANT: Do not use Watcom C 10.6!!! # If you have it installed, add "-v9.52 to CFLAGS" # # NOTE: QNX 4.23 onward does not work on 286's anyway. # Stacksize 26000, objects larger than 100 bytes in their own segments, # string constants to the codesegment, etc. Fully configured except job ctrl. # This entry works for building a 16-bit executable on a 32-bit system, but # has not been tested on a 16-bit system. Uses large memory model, links # explicitly with large-model sockets library. Correct-model curses library # is chosen automatically. See comment in qnx32 entry about -DNOUUCP. # # WARNING: # # Watcom C prior to 10.6 never had released curses library. To link against it, # you must obtain ported free curses source from ftp://ftp.qnx.com/usr/free, # then compile and build library (cursesl.lib) and place it in /usr/lib. You # must also copy curses.h to /usr/include. Be aware that if you have Watcom # 10.6 installed, you should already have curses.h, which is the new ncurses # library. You must back it up and use free curses.h instead, since ncurses is # only for 32-bit applications and some definitions in these files are # different (e.g., clearok()). For safety, curses is not defined in build. # # In 7.0 -DNOHELP added to keep ckuus2.c from blowing up; NOCSETS and NOSPL # added because ckuus4 was blowing up, and NOFLOAT just because it seemed # dangerous (remove -DNOFLOAT if you want to try it), The result works OK # except for some mysterious beeps upon termination of the top-level keyword. # # Things to try next time we get in trouble: # . Change -zt100 to something smaller like -zt25 # . Change -Oatx to -Omilerat (enable stack checking) # . Maybe get rid of -v9.52 -- it's only there because we were warned. # qnx16: @echo 'Making C-Kermit $(CKVER) for QNX 4.21, 16-bit...' $(MAKE) xermit \ "LNKFLAGS = -2 -ml -N 26000" \ "CFLAGS = -2 -Oatx -zc -zt100 -ml -DQNX -DQNX16 -DNOUUCP -DNOHELP \ -DCK_REDIR -DSELECT -DSELECT_H -DNOJC -DNOGETUSERSHELL -DNO_DNS_SRV \ -v9.52 -DTCPSOCKET -DCK_RTSCTS -DCK_ANSIC -DNOINITGROUPS -DNOKVERBS \ -DNORANDOM -DNOCSETS -DNOSPL -DNOFLOAT -DPID_T=pid_t $(KFLAGS)" # QNX 4.1, 16-bit version, with Watcom C 8.5 on i286 PCs and above. # stacksize 26000, objects larger than 100 bytes in their own segments, # string constants to the codesegment, etc. Add -DNOUUCP if desired. qnx16_41: @echo 'Making C-Kermit $(CKVER) for QNX 4.1, 16-bit...' $(MAKE) xermit \ "LNKFLAGS = -mh -N 26000" "CFLAGS = -Wc,-fpc -Wc,-j -DNOGETUSERSHELL \ -Wc,-Ols -Wc,-zdf -Wc,-zc -Wc,-zt100 -mh -DPOSIX -DQNX -DDIRENT \ -DNOCYRIL -DNODEBUG -DNOMSEND -DMINIDIAL -DNOXMIT -DNOSCRIPT -DNOSPL \ -DNOSETKEY -DNOINITGROUPS -DQNX16 -DPID_T=pid_t $(KFLAGS)" # QNX Neutrino 2 (pwaechtler@qnx.de) crosscompiled on QNX 4.25. # Gets lots of compiler warnings. qnx_nto2+: @echo 'Making C-Kermit $(CKVER) for QNX Neutrino 2+ ' $(MAKE) xermit \ "CC = qcc -Vgcc_ntox86" \ "CC2 = qcc -Vgcc_ntox86" \ "LNKFLAGS = " \ "CFLAGS = -DNEUTRINO -DTCPSOCKET -DCK_CURSES -DNOGETUSERSHELL \ -DNOUUCP -DCK_WREFRESH -DCK_REDIR -DSELECT -DSELECT_H -DCK_RTSCTS \ -DNOJC -DNOINITGROUPS -DCK_ANSIC -DPID_T=pid_t -DUNIX -DDIRENT \ -DMYREAD -DBSD44ORPOSIX -DSVORPOSIX -DNDGPWNAM $(KFLAGS)" \ "LIBS= -lsocket -lncurses " # QNX 6 (= Neutrino 2.xx) native build (kirussel@cisco.com). qnx6: @echo 'Making C-Kermit $(CKVER) for QNX6' $(MAKE) xermit KTARGET=QNX6 \ "CFLAGS = -DPOSIX -DCK_POSIX_SIG -DNETPTY \ -DUSE_TIOCSDTR -DBIGBUFOK -DCKMAXOPEN=100 -DRLOGCODE -DNOREALPATH \ -DMAXNAMLEN=48 -DQNX6 -DUSE_TERMIO -DINIT_SPTY \ -DCK_CURSES -DCK_WREFRESH -DCK_NEWTERM -DDYNAMIC \ -DTCPSOCKET -DNOGETUSERSHELL -DCK_REDIR -DSELECT -DSELECT_H \ -DCK_RTSCTS -DNOJC -DSVORPOSIX -DBSD44ORPOSIX -DNOUUCP -DCK_ANSIC \ $(KFLAGS) -O" \ "LIBS= -lsocket -lncurses -llogin" # QNX 8.0 for Intel (x86_64) crosscompiled build qnx8i: @echo 'Making wart for host' $(MAKE) wart @echo 'Making C-Kermit $(CKVER) for QNX8' $(MAKE) xermit KTARGET=QNX6 \ "CC = qcc -Vgcc_ntox86_64" \ "CC2 = qcc -Vgcc_ntox86_64" \ "CFLAGS = -DPOSIX -DCK_POSIX_SIG -DNETPTY -DHAVE_OPENPTY \ -DUSE_TIOCSDTR -DBIGBUFOK -DCKMAXOPEN=100 -DRLOGCODE \ -DMAXNAMLEN=48 -DQNX6 -DUSE_TERMIO -DINIT_SPTY -DFNFLOAT \ -DCK_NCURSES -DCK_WREFRESH -DCK_NEWTERM -DDYNAMIC -DUSE_STRERROR \ -DTCPSOCKET -DNOGETUSERSHELL -DCK_REDIR -DSELECT -DSELECT_H \ -DCK_RTSCTS -DSVORPOSIX -DBSD44ORPOSIX -DCK_ANSIC \ $(KFLAGS) -O" \ "LIBS= -lsocket -lncurses -llogin -lm" # QNX 8.0 for ARM (aarch64le) crosscompiled build qnx8a: @echo 'Making wart for host' $(MAKE) wart @echo 'Making C-Kermit $(CKVER) for QNX8' $(MAKE) xermit KTARGET=QNX6 \ "CC = qcc -Vgcc_ntoaarch64le" \ "CC2 = qcc -Vgcc_ntoaarch64le" \ "CFLAGS = -DPOSIX -DCK_POSIX_SIG -DNETPTY -DHAVE_OPENPTY \ -DUSE_TIOCSDTR -DBIGBUFOK -DCKMAXOPEN=100 -DRLOGCODE \ -DMAXNAMLEN=48 -DQNX6 -DUSE_TERMIO -DINIT_SPTY -DFNFLOAT \ -DCK_NCURSES -DCK_WREFRESH -DCK_NEWTERM -DDYNAMIC -DUSE_STRERROR \ -DTCPSOCKET -DNOGETUSERSHELL -DCK_REDIR -DSELECT -DSELECT_H \ -DCK_RTSCTS -DSVORPOSIX -DBSD44ORPOSIX -DCK_ANSIC \ $(KFLAGS) -O" \ "LIBS= -lsocket -lncurses -llogin -lm" #MINIX/2.0 32 Bit version for intel 386+ running the POSIX-compliant MINIX # version 2.0 (The definition of fatal avoids a conflict with a symbol by # the same name in the curses library.) It is impossible to compile with # network support since Minix does not support Berkeley sockets. # Note: use chmem liberally on the compiler passes, make, and the final # kermit executable. (3 megabytes of memory for each is sufficient.) # From Terry McConnell, Syracuse U, and Will Rose. Will says: # The stacks for make and some compiler passes needed to be increased # with chmem as follows: # make 1MB # /usr/lib/em_cemcom.ansi 3MB # /usr/lib/em_opt 1MB # /usr/lib/i386/cg 1MB # /usr/lib/i386/as 1MB # The compiler temporary directory was set to /usr/tmp via the TMPDIR # environment variable; more than 1MB of temporary space was needed. # Kermit itself needs at least 1MB of stack. minix20: @echo 'Making C-Kermit $(CKVER) for MINIX 2.0/386...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} EXT=o \ "CFLAGS= -wo -DV7 -DMINIX2 -DMINIX -DSIG_V -D_POSIX_SOURCE \ -DCKCPU=\\\"i-386\\\" -DNOIKSD -Dfatal=myfatal -DCK_CURSES -DNOLEARN \ -DNOSYSLOG -DUSE_MEMCPY -DNOREALPATH $(KFLAGS)" "LIBS= -lcurses" #MINIX/386 (PC Minix modified by Bruce Evans in Australia for 386 addressing) # For MINIX 1.5+ (but < 2.0) minix386: @echo 'Making C-Kermit $(CKVER) for MINIX/386...' @echo 'TOTALLY UNTESTED!' $(MAKE) wermit EXT=s KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DV7 -DMINIX -D_POSIX_SOURCE -DNOLEARN $(KFLAGS)" #MINIX/386 Minix modified by Bruce Evans in Australia to use 386 addressing minix386gcc: @echo 'Making C-Kermit $(CKVER) for MINIX/386 with gcc...' @echo 'TOTALLY UNTESTED!' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} "CC=gcc -g -O" "CC2=gcc -g" \ "CFLAGS= -DV7 -DMINIX -D_POSIX_SOURCE -DNOLEARN $(KFLAGS)" #MINIX - 68k version with ACK compiler. # The version configured below has many features removed, including # the TRANSMIT, MSEND, HELP, and SCRIPT commands, international # character set support, and the entire script programming language. # But it does have an interactive command parser. # Make sure make(1) has (at least) 100000 chmemory! # If you are using the Amsterdam C compiler, you might have to add "-D__ACK__". minix68k: @echo 'Making C-Kermit $(CKVER) for MINIX 68k with ACK...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DV7 -DMINIX -D_MINIX -D_POSIX_SOURCE -DNOLEARN \ -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG \ -DNOSCRIPT -DNOCSETS -DNOSPL $(KFLAGS) \ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t -DSIG_V" #MINIX - 68k version with c68 compiler. # Compiling ckudia.c (no -DNODIAL!) might fail. # Give c68 250000 bytes of stack+heap; make sure make(1) has at least # 100000 chmemory. On a 1MB Atari ST this means that the recursive # call of make fails due to memory shortage. Try "make -n minixc68 >makeit", # followed by ". makeit". Otherwise, as above. minixc68: @echo 'Making C-Kermit $(CKVER) for MINIX 68k with c68...' $(MAKE) wermit "CC= cc -c68" KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DV7 -DMINIX -D_MINIX -D_POSIX_SOURCE -DNOLEARN \ -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG \ -DNOSCRIPT -DNOCSETS -DNOSPL $(KFLAGS) \ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t -DSIG_V" #MINIX - 68k version with c68 compiler. #A variation on the above that was recently (Sep 95) reported to work. minixc68a: @echo 'Making C-Kermit $(CKVER) for MINIX 68k with c68...' $(MAKE) wermit "CC= cc -c68" KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DV7 -DMINIX -D_MINIX -D_POSIX_SOURCE \ -DCK_ANSIC -DNODEBUG -DNOTLOG -DMINIDIAL -DEXTEN -DMYCURSES \ -DNOSCRIPT -DNOCSETS -DNOSPL -DNOJC -DDIRENT -DNOLEARN \ -DNOSETKEY -DNOESCSEQ $(KFLAGS) \ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t -DSIG_V" #MIPS Computer Systems with UMIPS RISC/OS 4.52 = AT&T UNIX System V R3.0. #Remove -DNOJC if job control can be safely used. mips: @echo 'Making C-Kermit $(CKVER) for MIPS RISC/OS...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DMIPS -DDIRENT -DCK_POLL -DNOJC -DNOLEARN -DPID_T=int \ -DGID_T=gid_t -DUID_T=uid_t -i -O1500 $(KFLAGS)" #As above, but with TCP/IP and fullscreen support. mipstcpc: @echo 'Making C-Kermit $(CKVER) for MIPS RISC/OS...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DMIPS -DDIRENT -DCK_POLL -DNOJC \ -DTCPSOCKET -DCK_CURSES -I/usr/include/bsd \ -DPID_T=int -DGID_T=gid_t -DUID_T=uid_t -i -O1500 $(KFLAGS)" \ "LIBS = -lcurses -lbsd" #Motorola Delta System V/68 R3, signal() is void rather than int. #Uses dirent.h and Honey DanBer uucp. Supports TCP/IP. #After building, use "mcs -d" to reduce size of the executable program. sv68r3: @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/68 R3...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSVR3 -DSV68 -DDIRENT -DHDBUUCP -DNO_DNS_SRV -DTCPSOCKET \ -DNOUNICODE -DNOLEARN -DUSE_MEMCPY $(KFLAGS) -O" "LNKFLAGS =" #Motorola Delta System V/68 R3V5, signal() is void rather than int. #Uses dirent.h and Honey DanBer UUCP. Supports TCP/IP. #After building, use "mcs -d" to reduce size of the executable program. sv68r3v5: @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/68 R3V5' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSVR3 -DSV68 -DDIRENT -DHDBUUCP -DNO_DNS_SRV -DUSE_MEMCPY \ -DTCPSOCKET -DINADDRX -DNOUNICODE -DFNFLOAT -DNOLEARN $(KFLAGS) -O" \ "LNKFLAGS =" "LIBS = -linet -lm" #Motorola MVME147 System V/68 R3 V5.1. Requires gcc 2.1 to compile. #After building, use "mcs -d" to reduce size of the executable program. sv68r3v51: @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/68 R3V5.1' $(MAKE) wermit "CC=gcc-delta" "CC2=gcc-delta" \ KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DNODEBUG -DNO_DNS_SRV -DNOLEARN \ -DNOUNICODE -DFNFLOAT -DSV68 -DUSE_MEMCPY $(KFLAGS) \ -O2 -v -ftraditional" \ "LNKFLAGS = -s -v" "LIBS = -lm881 -lm" #Motorola MVME147 System V/68 R3V6. derived from Motorola Delta System R3V5. #Checked on larger Motorola System V/68 R3V6 (with NSE Network Services Ext.) #After building, use "strip" to reduce size of the executable program. # "LIBS = -lnsl" removed in C-Kermit 6.1 - put back if needed. # "LIBS = lm" added in 7.1/8.0 for floating-point math. # ckuusr.c clobbers the optimizer. sv68r3v6: @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/68 R3V6' $(MAKE) ckuusr.$(EXT) KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSV68R3V6 -DDIRENT -DHDBUUCP -DNOLOGIN -DNOINITGROUPS \ -DNOSYMLINK -DNOREDIRECT -DNOGFTIMER -DTCPSOCKET -DDCLGETCWD -DSV68 \ -DNO_DNS_SRV -DNOUNICODE -DFNFLOAT -DSELECT -DUSE_MEMCPY $(KFLAGS)" $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSV68R3V6 -DDIRENT -DHDBUUCP -DNOLOGIN -DNOINITGROUPS \ -DNOSYMLINK -DNOREDIRECT -DNOGFTIMER -DTCPSOCKET -DDCLGETCWD -DSV68 \ -DNO_DNS_SRV -DNOUNICODE -DFNFLOAT -DSELECT -DUSE_MEMCPY $(KFLAGS)" \ "LNKFLAGS =" "LIBS = -lm" #Motorola Delta System V/88 R32, signal() is void rather than int. #Uses dirent.h and Honey DanBer uucp. Needs for setting #file dates. Supports TCP/IP. #After building, use "mcs -d" to reduce size of the executable program. sv88r32: @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/88 R32...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -DSV88R32 -DDIRENT -DHDBUUCP -DTCPSOCKET \ -DSYSUTIMEH -DCK_CURSES -DNOGETUSERSHELL -DGTODONEARG $(KFLAGS) -O" \ "LIBS= -lcurses -lresolv" "LNKFLAGS = -s" #Motorola Delta System V/88 R40. Has , regular Berkeley #sockets library, i.e. in.h and inet.h are not misplaced in sys (rather than #netinet and arpa, respectively). Uses ANSI C constructs, advisory file #locking on devices, etc. curses support added. Reportedly, the #/usr/include/sys/vnode.h file has a bug which must be fixed before this #makefile entry can work correctly. The "if DEBUG" directive at about line #320 must be changed to "ifdef DEBUG" (Reportedly, this was fixed in #in System V/88 R4.3). #After building, use "mcs -d" to reduce size of the executable program. sv88r40: @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/88 R40...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DMOTSV88R4 -DDIRENT -DHDBUUCP -DSTERMIOX \ -DTCPSOCKET -DCK_CURSES -DNOGETUSERSHELL -DGTODONEARG -DFNFLOAT \ $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lcurses -lresolv -lm" "LNKFLAGS = -s" #As above but without the floating-point math library. sv88r40nm: @echo 'Making C-Kermit $(CKVER) for Motorola UNIX System V/88 R40...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS = -O -DSVR4 -DMOTSV88R4 -DDIRENT -DHDBUUCP -DSTERMIOX \ -DTCPSOCKET -DCK_CURSES -DNOGETUSERSHELL -DGTODONEARG $(KFLAGS)" \ "LIBS= -lsocket -lnsl -lcurses -lresolv" "LNKFLAGS = -s" #As above but with floating-point math library support \ffp...() functions #and S-Expressions. #Olivetti X/OS R2.3, 3.x. #NOTES: # . If you build the executable on 2.x X/OS, it will also run on 3.x. # . If you build it on 3.x X/OS, it will NOT run on 2.x. # . Kermit can run with no privileges unless the uucp lines are protected, # in which case kermit must be owned by uucp with suid bit set: # chown uucp kermit ; chmod 4111 kermit. xos23: @echo 'Making C-Kermit $(CKVER) for Olivetti X/OS...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ 'CFLAGS=-OLM -DOXOS -DTCPSOCKET -DHDBUUCP $(KFLAGS)' \ "LIBS=" "LNKFLAGS=" #As above, but with curses. xos23c: @echo 'Making C-Kermit $(CKVER) for Olivetti X/OS with curses...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ 'CFLAGS=-OLM -DOXOS -DTCPSOCKET -DHDBUUCP -DCK_CURSES $(KFLAGS)' \ "LIBS=-lcurses" "LNKFLAGS=" ckuuid: @echo 'building C-Kermit $(CKVER) set-UID/set-GID test programs' $(CC) -DANYBSD -DSAVEDUID -o ckuuid1 ckuuid.c $(CC) -DANYBSD -o ckuuid2 ckuuid.c $(CC) -DANYBSD -DNOSETREU -o ckuuid3 ckuuid.c $(CC) -DANYBSD -DSETEUID -DNOSETREU -o ckuuid4 ckuuid.c $(CC) -o ckuuid5 ckuuid.c @echo 'Read the top of ckuuid.c for directions...for testing' @echo 'you must make these programs setuid and setgid' ############################################################################ # A N T I Q U I T I E S # # The following are antique targets from C-Kermit 5A or earlier. They have # not been updated or tested in years. Most of them will need recent features # disabled, usually with some combination of -DNOUNICODE, -DNOIKSD, -DNOANSI, # -DNOCKGHNLHOST, -DNO_DNS_SRV, -DNOREDIRECT, -DNOREALPATH, -DNOCURSES, etc. # They are also missing the KTARGET=$${KTARGET:-$(@)} business. # For details see ckuins.txt and ckccfg.txt. # ############################################################################ #Berkeley Unix 2.8, 2.9 for PDP-11s with I&D space, maybe also Ultrix-11??? #C-Kermit(5A) is simply too large (even turning off almost every feature #available) to run without both I&D space plus overlays. The old comment #suggested running 'pcc' but that won't help. Changing 'cc' to 'ckustr.sed' #will cause a string extraction to be done, saving D space by moving strings #to a file. bsd29: @echo Making C-Kermit $(CKVER) for 2.8 or 2.9BSD. @echo Read the makefile if you have trouble with this... $(MAKE) ovwermit \ "CFLAGS= -DBSD29 -DNODEBUG -DNOTLOG -DNOCSETS -DNOHELP \ -DNOSCRIPT -DNOSPL -DNOXMIT -DNODIAL $(KFLAGS)" \ "LNKFLAGS= -i -lndir" "CC= cc " "CC2= cc" bsd210: @echo Please use ckubs2.mak to build C-Kermit $(CKVER) for 2.10BSD. bsd211: @echo Please use ckubs2.mak to build C-Kermit $(CKVER) for 2.11BSD. #Charles River Data Systems Universe with UNOS Version 9.2 crds: @echo 'Making C-Kermit $(CKVER) for Charles River Data Systems...' make xermit \ "CFLAGS = -DATTSV -DNOANSI -DDIRENT -DLONGFN -DTCPSOCKET \ -DLOCK_DIR=\\\"/usr/spool/uucp\\\" -DNOSETREU \ -Dsuspend=ksuspend $(KFLAGS) -O" "LNKFLAGS =" #Microport SV/AT for IBM PC/AT 286 and clones, System V R2. #The -O flag may fail on some modules (like ckuus2.c), in which case you #should compile them by hand, omitting the -O. If you get "hash table #overflow", try adding -DNODEBUG. #Also, reportedly this compiles better with gcc than with cc. mpsysv: @echo 'Making C-Kermit $(CKVER) for Microport SV/AT 286...' $(MAKE) wermit \ "CFLAGS= -DATTSV -DNOLEARN $(KFLAGS) -O -Ml" "LNKFLAGS = -Ml" #Microsoft "Xenix/286" e.g. for IBM PC/AT xenix: @echo 'Making C-Kermit $(CKVER) for Xenix/286' $(MAKE) wermit \ "CFLAGS= -DXENIX -DNOFILEH -DNOLEARN $(KFLAGS) -Dunix -F 3000 -i" \ "LNKFLAGS = -F 3000 -i" #PC/IX, Interactive Corp System III for IBM PC/XT pcix: @echo 'Making C-Kermit $(CKVER) for PC/IX...' $(MAKE) wermit \ "CFLAGS= -DPCIX -DISIII -DNOLEARN $(KFLAGS) \ -Dsdata=sdatax -O -i" "LNKFLAGS = -i" #Integrated Solutions Inc V8S VME 68020 isi: @echo Making C-Kermit $(CKVER) for 4.2BSD on ISI... $(MAKE) wermit "CC = cc" \ "CFLAGS= -DBSD4 -DTCPSOCKET -DINADDRX -DDCLPOPEN -DDEBUG -DNOSETREU \ -DCK_CURSES -DNOLEARN $(KFLAGS)" "LIBS = -lcurses -ltermcap" #Interactive Corp version of AT&T System III #is3: (very old, probably not sufficient for 5A or later) # @echo 'Making C-Kermit $(CKVER) for Interactive System III...' # make wermit "CFLAGS = -DISIII -Ddata=datax -O -i" "LNKFLAGS = -i" #The following should work, use it if you don't have gcc. #Use is3gcc if you have gcc. is3: @echo 'Making C-Kermit $(CKVER) for Interactive System III...' $(MAKE) wermit \ "CFLAGS= -DISIII $(KFLAGS) -Ddata=datax -DNAP -DHDBUUCP -DLOCK_DIR=\"/usr/spool/uucp\" -DSIGTYP=void -O -i" "LNKFLAGS = -i" #Interactive UNIX System V R3, no network support. Uses and Honey #DanBer UUCP. If this entry does not compile correctly, try any or all of the #following. These suggestions also apply more or less to the other is5r3xxx #entries that follow this one. # . Remove the UID_T and GID_T definitions, or change them as required. # . Change -DDIRENT to -DSDIRENT. # . Add -DSIGTYP=void. # . Remove -g from LNKFLAGS. # . Add -DNOANSI to remove compiler complaints about ANSI C constructions # . Add other -DNOxxx's to save space (e.g. -DNOCSETS) # See the next few makefile entries for related examples. # Also see sys5r32is for making a portable i386 SVR3 binary. is5r3: @echo 'Making C-Kermit $(CKVER) for Interactive 386/ix or later...' @echo 'If this does not work please read the makefile entry.' $(MAKE) wermit \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -g -DNOCSETS -DNOREALPATH \ -DUID_T=ushort -DGID_T=ushort -DI386IX $(KFLAGS)" \ "LNKFLAGS = -g" #Interactive Corp System System V R3 with gcc is3gcc: @echo 'Making C-Kermit $(CKVER) for Interactive System V R3 / gcc...' $(MAKE) wermit CC=gcc CC2=gcc \ 'CFLAGS = -D_SYSV3 -DISIII -Ddata=datax -DNAP -DHDBUUCP -DNOREALPATH \ -DLOCK_DIR=\"/usr/spool/uucp\" -DSIGTYP=void -O' "LNKFLAGS =" #Interactive UNIX System V R3, POSIX variant. Untested. #Uses dirent.h and Honey DanBer uucp. Read comments in is5r3 entry. is5r3p: @echo 'Making C-Kermit $(CKVER) for Interactive 386/ix or later...' $(MAKE) wermit \ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP -g -DNOCSETS -DNOREALPATH \ -DI386IX -DPOSIX $(KFLAGS)" "LNKFLAGS=" "LIBS=-lcposix" #Interactive UNIX SVR3 2.2.1, job control, curses, no net, gcc. is5r3gcc: $(MAKE) wermit CC=gcc CC2=gcc \ "CFLAGS=-g -posix -DSVR3 -DDIRENT -DNOREALPATH \ -DHDBUUCP -O -DNOCSETS -DI386IX -DSVR3JC -DCK_CURSES \ $(KFLAGS)" LNKFLAGS="-posix" LIBS="-lcurses -lc_s" #Interactive UNIX System V R3 with TCP/IP network support. #Needs -linet for net functions. signal() is void rather than int. #Uses dirent.h and Honey DanBer uucp. Read comments in is5r3 entry. #Also see is5r3net2 if you have trouble with this entry. is5r3net: @echo 'Making C-Kermit $(CKVER) for Interactive 386/ix...' @echo 'If this does not work please read the makefile entry.' $(MAKE) wermit CC="$(CC)" CC2="$(CC2)" \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DTCPSOCKET -DNOREALPATH \ -DI386IX $(KFLAGS) -O" "LIBS = -linet" is5r3netgcc: $(MAKE) is5r3net CC=gcc CC2=gcc #Interactive UNIX System V R3, no job control, signal() void rather than int. #Uses dirent.h and Honey DanBer uucp. Needs -linet for net functions. #Read comments in is5r3 entry. Use this entry if is5r3net fails. #Saves some space by stripping (-s) and using shared library (-lc_s). is5r3net2: @echo 'Making C-Kermit $(CKVER) for Interactive 386/ix...' $(MAKE) wermit \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DTCPSOCKET -DNOJC -DNOREALPATH \ -DSIGTYP=void -DNOANSI -DI386IX $(KFLAGS) -O" \ "LNKFLAGS= -s" "LIBS = -linet -lc_s" #Interactive UNIX System V R3 (version 2.2 or later) with job control & curses. #Uses dirent.h and Honey DanBer UUCP. is5r3jc: @echo 'Making C-Kermit $(CKVER) for Interactive Unix 2.2 or later...' $(MAKE) wermit CC="$(CC)" CC2="$(CC2)" \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -O -DNOCSETS -DNOREALPATH \ -DUID_T=ushort -DGID_T=ushort -DI386IX -DSVR3JC -DCK_CURSES \ -DPOSIX_JC -DCK_REDIR -DCK_POLL -DDCLGETCWD \ $(KFLAGS)" "LIBS=-lcurses -lc_s -linet" is5r3jcgcc: $(MAKE) is5r3jc CC="gcc -DCK_ANSILIBS -DDCGPWNAM -O4" CC2=gcc \ KFLAGS="$(KFLAGS)" LNKFLAGS="$(LNKFLAGS)" #Sunsoft/Interactive UNIX System V R3 (version 2.2 or later) #with job control, curses, and TCP/IP networking. #Uses dirent.h and Honey DanBer UUCP. is5r3netjc: @echo 'Making C-Kermit $(CKVER) for Interactive Unix 2.2 or later...' $(MAKE) wermit CC="$(CC)" CC2="$(CC2)" \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -O -DNOCSETS -DNOREALPATH \ -DUID_T=ushort -DGID_T=ushort -DI386IX -DSVR3JC -DCK_CURSES \ -DPOSIX_JC -DCK_REDIR -DTCPSOCKET -DSELECT \ $(KFLAGS)" "LIBS=-linet -lcurses -lc_s" is5r3netjcgcc: $(MAKE) is5r3netjc CC="gcc -DCK_ANSILIBS -DDCGPWNAM -O4" CC2=gcc \ KFLAGS="$(KFLAGS)" LNKFLAGS="$(LNKFLAGS)" #Masscomp System III rtu: @echo 'Making C-Kermit $(CKVER) for Masscomp RTU System III...' $(MAKE) wermit \ "CFLAGS= -UFIONREAD -DATTSV $(KFLAGS) -O" "LNKFLAGS =" "LIBS= -ljobs" #Masscomp/Concurrent RTU 4.0 or later, Berkeley environment. #Includes = /usr/include/ndir.h #Note "LIBS = -lndir" might not be necessary because of "ucb make". rtubsd: @echo 'Making C-Kermit $(CKVER) for Masscomp RTU 4.1A...' ucb make wermit \ "CFLAGS= -DBSD4 -DRTU -DNDIR -DHDBUUCP -DTCPSOCKET $(KFLAGS)" \ "LIBS = -lndir" #Masscomp/Concurrent RTU 4.0 or later, same as above, #Includes "usr/lib/ndir.h" #Note "LIBS = -lndir" might not be necessary because of "ucb make". rtubsd2: @echo 'Making C-Kermit $(CKVER) for Masscomp RTU 4.1A...' ucb make wermit \ "CFLAGS= -DBSD4 -DRTU -DXNDIR -DHDBUUCP $(KFLAGS)" \ "LIBS = -lndir" #Masscomp/Concurrent RTU 4.0 or later, same as above, #Includes #Note "LIBS = -lndir" might not be necessary because of "ucb make". rtubsd3: @echo 'Making C-Kermit $(CKVER) for Masscomp RTU 4.x BSD...' ucb make wermit "CFLAGS= -DBSD4 -DRTU -DHDBUUCP $(KFLAGS)" \ "LIBS = -lndir" #Masscomp/Concurrent RTU 4.0 or later, System V R2, using . #In case of problems, add back the -DRTU switch. #In case -DTCPSOCKET gives trouble, remove it. rtus5: @echo 'Making C-Kermit $(CKVER) for Masscomp RTU 4.x...' $(MAKE) wermit \ "CFLAGS= -DATTSV -DHDBUUCP -DDIRENT -DTCPSOCKET $(KFLAGS)" #Masscomp/Concurrent RTU 4.x, System V R3, using . #Use this one if rtus5 gives warnings about pointer type mismatches. #In case of problems, add back the -DRTU switch. rtus5r3: @echo 'Making C-Kermit $(CKVER) for Masscomp RTU Sys V R3...' $(MAKE) wermit "CFLAGS= -DSVR3 -DHDBUUCP -DDIRENT $(KFLAGS)" #DEC Pro-3xx with Pro/Venix V1.0 or V1.1 # Requires code-mapping on non-I&D-space 11/23 processor, plus some # fiddling to get interrupt targets into resident code section. # This almost certainly doesn't work any more. provx1: @echo 'Making C-Kermit $(CKVER) for DEC Pro-3xx, Pro/Venix 1.x...' $(MAKE) wermit "CFLAGS = -DPROVX1 -DNOFILEH -md780" \ "LNKFLAGS= -u _sleep -lc -md780" #Nixdorf Targon/31. #AT&T UNIX System V R3, signal() is void rather than int. #Uses dirent.h without Honey DanBer uucp. t31tos40x: @echo 'Making C-Kermit $(CKVER) for Targon/31 with TOS 4.0.xx...' $(MAKE) wermit \ "CFLAGS= -DSVR3 -DDIRENT $(KFLAGS) -O" \ "LNKFLAGS=" #NCR Tower 1632, OS 1.02 tower1: @echo 'Making C-Kermit $(CKVER) for NCR Tower 1632, OS 1.02...' $(MAKE) wermit "CFLAGS= -DTOWER1 $(KFLAGS)" #NCR Tower 32, OS Release 1.xx.xx tower32-1: @echo 'Making C-Kermit $(CKVER) for NCR Tower 32 Rel 1 System V R2...' @echo 'Add KFLAGS=-DISDIRBUG if you get errors about S_ISREG/S_ISDIR.' $(MAKE) wermit \ "CFLAGS = -DATTSV $(KFLAGS) -O" "LNKFLAGS = -n" #NCR Tower 32, OS Release 2.xx.xx tower32-2: @echo 'Making C-Kermit $(CKVER) for NCR Tower 32 Rel 2 System V R2...' $(MAKE) wermit \ "CFLAGS = -DATTSV -DHDBUUCP $(KFLAGS) -O2" \ "LNKFLAGS = -n" #NCR Tower 32, OS Releases based on System V R3 #Don't add -DNAP (doesn't work right) or -DRDCHK (not available in libc). tower32: @echo 'Making C-Kermit $(CKVER) for NCR Tower 32 System V R3...' $(MAKE) wermit \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DNOSYSIOCTLH $(KFLAGS) \ -DUID_T=ushort -DGID_T=ushort -O1" #NCR Tower 32, OS Releases based on System V R3 tower32g: @echo 'Making C-Kermit $(CKVER) for NCR Tower 32 System V R3, gcc...' $(MAKE) wermit "CC = gcc" \ "CFLAGS = -DSVR3 -DDIRENT -DHDBUUCP -DNOSYSIOCTLH $(KFLAGS) \ DUID_T=ushort -DGID_T=ushort -O -fstrength-reduce -fomit-frame-pointer" #Fortune 32:16, For:Pro 1.8 (mostly like 4.1bsd) ft18: @echo 'Making C-Kermit $(CKVER) for Fortune 32:16 For:Pro 1.8...' $(MAKE) wermit \ "CFLAGS= -DNODEBUG -DBSD4 -DFT18 -DNOFILEH $(KFLAGS) \ -DPID_T=short" #Fortune 32:16, For:Pro 2.1 (mostly like 4.1bsd). #The modules that break the optimizer are compiled separately. ft21: @echo 'Making C-Kermit $(CKVER) for Fortune 32:16 For:Pro 2.1...' $(MAKE) ckuusx.$(EXT) "CFLAGS= -DNODEBUG -DBSD4 -DFT21 -DNOFILEH \ -SYM 800 -DCK_CURSES $(KFLAGS) -DPID_T=short" \ "LNKFLAGS= -n -s" "LIBS= -lcurses -ltermcap -lv -lnet" $(MAKE) ckuxla.$(EXT) "CFLAGS= -DNODEBUG -DBSD4 -DFT21 -DNOFILEH \ -SYM 800 -DCK_CURSES $(KFLAGS) -DPID_T=short" \ "LNKFLAGS= -n -s" "LIBS= -lcurses -ltermcap -lv -lnet" $(MAKE) ckudia.$(EXT) "CFLAGS= -DNODEBUG -DBSD4 -DFT21 -DNOFILEH \ -SYM 800 -DCK_CURSES $(KFLAGS) -DPID_T=short" \ "LNKFLAGS= -n -s" "LIBS= -lcurses -ltermcap -lv -lnet" $(MAKE) wermit \ "CFLAGS= -O -DNODEBUG -DBSD4 -DFT21 -DNOFILEH -SYM 800 \ -DCK_CURSES $(KFLAGS) -DPID_T=short" \ "LNKFLAGS= -n -s" "LIBS= -lcurses -ltermcap -lv -lnet" #Valid Scaldstar #Berkeleyish, but need to change some variable names. valid: @echo 'Making C-Kermit $(CKVER) for Valid Scaldstar...' $(MAKE) wermit \ "CFLAGS= -DBSD4 -DNODEBUG -DNOTLOG -Dcc=ccx -DFREAD=1 $(KFLAGS)" #IBM IX/370 on IBM 370 Series mainframes #Mostly like sys3, but should buffer packets. ix370: @echo 'Making C-Kermit $(CKVER) for IBM IX/370...' $(MAKE) wermit "CFLAGS = -DIX370 -DATTSV $(KFLAGS) -i -O" \ "LNKFLAGS = -i" #Amdahl UTS 2.4 on IBM 370 series compatible mainframes. #Mostly like V7, but can't do initrawq() buffer peeking. uts24: @echo 'Making C-Kermit $(CKVER) for Amdahl UTS 2.4...' $(MAKE) wermit "CFLAGS=-DV7 -DPROCNAME=\\\"$(PROC)\\\" \ -DUTS24 -DBOOTNAME=\\\"$(BOOTFILE)\\\" -DNPROCNAME=\\\"$(NPROC)\\\" \ -DNPTYPE=$(NPTYPE) $(DIRECT) $(KFLAGS)" #Amdahl UTSV UNIX System V = System V R2 or earlier. utsv: @echo 'Making C-Kermit $(CKVER) for Amdahl UTSV...' $(MAKE) wermit \ "CFLAGS = -DUTSV $(KFLAGS) -i -O" "LNKFLAGS = -i" #Amdahl UTSV UNIX System V = System V R2 or earlier, with TCP sockets library. utsvtcp: @echo 'Making C-Kermit $(CKVER) for Amdahl UTSV w/tcp...' $(MAKE) wermit "CFLAGS = \ -DTCPSOCKET -DUTSV $(KFLAGS) -i -O" "LNKFLAGS = -i" \ "LIBS = -lsocket" #BBN C/70 with IOS 2.0 #Mostly Berkeley-like, but with some ATTisms c70: @echo 'Making C-Kermit $(CKVER) for BBN C/70 IOS 2.0...' $(MAKE) wermit "CFLAGS= -DBSD4 -DC70 $(KFLAGS)" #Zilog ZEUS 3.21 zilog: @echo 'Making C-Kermit $(CKVER) for Zilog Zeus 3.21...' $(MAKE) wermit \ "CFLAGS = -DATTSV -DZILOG -DNODEBUG $(KFLAGS) -i -O" \ "LNKFLAGS = -i -lpw" #Whitechapel MG-1 Genix 1.3 white: @echo 'Making C-Kermit $(CKVER) for Whitechapel MG-1 Genix 1.3...' $(MAKE) wermit "CFLAGS= -DBSD4 -Dzkself()=0 $(KFLAGS)" #Pixel 1000 pixel: @echo 'Making C-Kermit $(CKVER) for Pixel 1000...' $(MAKE) wermit "CFLAGS= -DBSD4 -Dzkself()=0 $(KFLAGS)" ptx: $(MAKE) "MAKE=$(MAKE)" dynixptx12 #CDC VX/VE 5.2.1 vxve: @echo 'Making C-Kermit $(CKVER) for CDC VX/VE 5.2.1...' $(MAKE) wermit \ "CFLAGS = -DATTSV -DVXVE -DNODEBUG -DNOTLOG $(KFLAGS) -i -O" \ "LNKFLAGS = -i" #DIAB DS90 or LUXOR ABC-9000 with pre-5.2 DNIX. Sys V with nap() and rdchk(). # nd = no opendir(), readdir(), closedir(), etc. # Some of the modules fail to compile with -O. dnixnd: @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with very old DNIX 5.2.' $(MAKE) wermit \ "CFLAGS = -DATTSV -DNAP -DRDCHK -DDCLPOPEN \ -U__STDC__ $(KFLAGS)" #DIAB DS90 with DNIX 5.2. Sys V with nap() and rdchk(). # This one has opendir(), readdir(), closedir(), etc. # Some of the modules fail to compile with -O. dnix: @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with old DNIX 5.2...' $(MAKE) wermit \ "CFLAGS = -DATTSV -DNAP -DRDCHK -DDIRENT \ -U__STDC__ $(KFLAGS)" #DIAB DS90 with DNIX 5.2. Sys V with nap() and rdchk(). # As above, but with curses and TCP/IP. # You might get complaints about redefinition of O_RDONLY, etc, because # of bugs in the DNIX header files, which can be fixed by adding #ifndef... # around the offending definitions in the header files. dnixnetc: @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with old DNIX 5.2...' $(MAKE) wermit \ "CFLAGS = -DATTSV -DNAP -DRDCHK -DDIRENT \ -DTCPSOCKET -DCK_CURSES -I/usr/include/bsd -U__STDC__ $(KFLAGS)" \ "LIBS = -ln -lcurses" #DIAB DS90 with DNIX 5.3 or later, with HDB UUCP, nap() and rdchk(). dnix5r3: @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with DNIX 5.3...' @echo 'with Honey DanBer UUCP' $(MAKE) wermit \ "CFLAGS = -DSVR3 -DHDBUUCP -DNAP -DRDCHK -DDIRENT \ -DCK_CURSES -DRENAME $(KFLAGS) -O" "LIBS= -lcurses" #DIAB DS90 with DNIX 5.3 or later, with HDB UUCP, nap() and rdchk() + TCP/IP dnix5r3net: @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with DNIX 5.3...' @echo 'with Honey DanBer UUCP and TCP/IP' $(MAKE) wermit \ "CFLAGS = -DSVR3 -DHDBUUCP -DNAP -DRDCHK -DDIRENT \ -DTCPSOCKET -DCK_CURSES -DRENAME $(KFLAGS) -O \ -I/usr/include/bsd" "LIBS = -ln -lcurses" #DIAB DS90 with DNIX 5.3 2.2 or later, with HDB UUCP, nap() and rdchk(), #ANSI C compilation and libraries. #Note that for DNIX 5.3 2.2 you have to correct a bug in /usr/include/stdlib.h: #change "extern void free(char *str);" #to "extern void free(void *str);" #NOTE: This bug is reportedly fixed in DNIX 5.3 2.2.1. #Should you get fatal errors caused by harmless pointer-type mismatches, #like between signed and unsigned char, just remove -X7. dnix5r3ansi: @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with DNIX 5.3...' @echo 'with ANSI C Honey DanBer UUCP' $(MAKE) wermit \ "CFLAGS = -DSVR3 -DDIAB -DHDBUUCP -DNAP -DRDCHK -DDIRENT \ -DCK_ANSILIBS -DCK_CURSES -DRENAME -O -X7 -X9 $(KFLAGS)" \ "LIBS= -lcurses" #DIAB DS90 with DNIX 5.3 2.2 or later, with HDB UUCP, nap() and rdchk(), # + TCP/IP, ANSI C compilation and libraries. #Should you get fatal errors caused by harmless pointer-type mismatches, #like between signed and unsigned char, just remove -X7. dnix5r3ansinet: @echo 'Making C-Kermit $(CKVER) for DIAB DS90 with DNIX 5.3...' @echo 'with ANSI C Honey DanBer UUCP' $(MAKE) wermit \ "CFLAGS = -DSVR3 -DDIAB -DHDBUUCP -DNAP -DRDCHK -DDIRENT \ -DTCPSOCKET -DCK_ANSILIBS -DCK_CURSES -DRENAME -O -X7 -X9 $(KFLAGS) \ -I/usr/include/bsd" "LIBS= -ln -lcurses" #Ridge 32 with ROS 3.2 ridge32: @echo 'Making C-Kermit $(CKVER) Ridge 32 ROS 3.2' $(MAKE) wermit \ "CFLAGS = -DATTSV -DNOFILEH -DNODEBUG -DNOTLOG $(KFLAGS) -i -O" \ "LNKFLAGS = -i" #Altos 486, 586, or 986 with Xenix 3.0 altos: @echo 'Making C-Kermit $(CKVER) for Altos x86 with Xenix 3.0...' $(MAKE) wermit \ "CFLAGS= -DATTSV -DA986 -DNODEBUG -DNOTLOG $(KFLAGS) -i -O" \ "LNKFLAGS= -i" #Altos 986 with Xenix 3.0, as above, but command-line only, minimal size. #For systems with small memories. It might also be necessary to chop certain #modules up into smaller pieces, e.g. ckuus3-6, because of symbol table #overflow. If this makefile is too big or complex for the Altos, compile #and link by hand or write shell scripts. altosc: @echo 'Making C-Kermit $(CKVER) for Altos x86 Xenix 3.0, remote...' $(MAKE) wermit \ "CFLAGS= -DATTSV -DA986 -DNODEBUG -DNOTLOG -DNOSCRIPT -DNODIAL \ -DNOCSETS -DNOANSI -DNOMSEND -DNOSPL -DNOICP $(KFLAGS) -Mm -O" \ "LNKFLAGS= -Mm -s" #Altos 986 with Xenix 3.0, as above, but interactive only, minimal size. altosi: @echo 'Making C-Kermit $(CKVER) for Altos x86 Xenix 3.0, local...' $(MAKE) wermit \ "CFLAGS= -DATTSV -DA986 -DNODEBUG -DNOTLOG -DNOSCRIPT -DNODIAL \ -DNOCSETS -DNOANSI -DNOMSEND -DNOSPL -DNOCMDL -DNOFRILLS -DNOHELP \ -DNOSETKEY $(KFLAGS) -Mm -O" "LNKFLAGS= -Mm -s" # Altos ACS68000 68000 System, UNIX System 3 Release 2, 512k memory. # also needs getcwd() external function; see ckuins.txt file. # also, sys/types.h needed modifying: # #ifdef __SYS_TYPES_H__, #define ..., #endif # also, ckuus2.c MUST be compiled NOOPT else symbol table is destroyed! # Submission by Robert Weiner/Programming Plus, rweiner@progplus.com. # altos3: @echo 'Making C-Kermit $(CKVER) for Altos ACS68k UNIX System III' $(MAKE) ckuus2.$(EXT) "CFLAGS = -DATTSV -DNOCSETS -DNOSETKEY -DNOJC \ -DNODIAL -DDCLPOPEN -DNOSCRIPT -DNOHELP $(KFLAGS) -i" $(MAKE) wermit \ "CFLAGS = -DATTSV -DNOCSETS -DNOSETKEY -DNOJC \ -DNODIAL -DDCLPOPEN -DNOSCRIPT -DNOHELP $(KFLAGS) -i -O" \ "LNKFLAGS = -i" "LIBS = getcwd.$(EXT)" #MINIX - Original PC version with 64K+64K limit. # Reportedly, the linker (asld) can run out of space while linking. The only # way around this is to make a copy of libc.a from which all modules that are # not used by Kermit are removed. # # The version configured below has no interactive command parser. # If you can build this version successfully, maybe there will be room for # a minimal interactive command parser too; try replacing -DNOICP with # -DNOSPL, plus every other -DNOxxx flag there is, except for -DNOICP # (see ckccfg.txt). minix: @echo 'Making C-Kermit $(CKVER) for MINIX, no command parser...' @echo 'TOTALLY UNTESTED!' $(MAKE) wermit EXT=s \ "CFLAGS= -DV7 -DMINIX -i -D_MINIX -D_POSIX_SOURCE \ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t -DSIG_V \ -DNOXMIT -DNOMSEND -DNOFRILLS -DNODIAL -DNOHELP -DNODEBUG -DNOTLOG \ -DNOSCRIPT -DNOCSETS -DNOICP -DNOSETKEY $(KFLAGS)" \ "LNKFLAGS= -i -T" # MINIX - PC version with 64K+64K limit, newer ACK 2.0 beta C compiler, # which outputs .o object files, rather than .s. But MINIX 'make' still # expects *.s object files, so must be patched to use .o. # Tested on Minix 1.5.10. minix15: @echo 'Making C-Kermit $(CKVER) for MINIX (new ACK 2.0 compiler),' @echo 'no command parser... TOTALLY UNTESTED!' $(MAKE) wermit \ "CFLAGS= -DV7 -DMINIX -i -D_MINIX -D_POSIX_SOURCE \ -DPID_T=pid_t -DUID_T=uid_t -DGID_T=gid_t -DSIG_V -DNODIAL \ -DNOHELP -DNODEBUG -DNOTLOG -DNOSCRIPT -DNOCSETS -DNOICP $(KFLAGS)" \ "LNKFLAGS= -i -T" #MINIX3 - MINIX 3.0 #Uses the old fork()-based CONNECT command module ckucon.c #Support for select() was added to MINIX somewhere between 3.0 and 3.3; #it's definitely in 3.3 (see next target). #OK 28 November 2022 on MINIX 3.2.1 and 3.3.0. minix3: @echo 'Making C-Kermit $(CKVER) for MINIX3...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DPOSIX -DNOUUCP -DNOLEARN -DMINIX2 -DMINIX3 \ -DNO_PARAM_H -DNOSYSLOG -DNOGETUSERSHELL -DNOINITGROUPS \ -DNOFTRUNCATE -DDNOREALPATH -DTCPSOCKET -DNOTIMEZONE -DNORLOGIN \ -DNOFTP -DNO_DNS_SRV -DNOIKSD $(KFLAGS) -O" #MINIX3 - MINIX 3.0 # This uses the currently (i.e. last 20-30 years) standard CONNECT # command code, which is based on select(), rather than the 1980s C-Kermit # original fork()-based method. This target can be used on at least MINIX # 3.3.0, maybe also earlier MINIX 3 editions, but not MINIX 2 or earlier. # OK 28 November 2022 on MINIX 3.3.0 minix3+select: @echo 'Making C-Kermit $(CKVER) for MINIX3...' $(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DPOSIX -DNOUUCP -DNOLEARN -DMINIX2 -DMINIX3 \ -DNO_PARAM_H -DNOSYSLOG -DNOGETUSERSHELL -DNOINITGROUPS \ -DNOFTRUNCATE -DDNOREALPATH -DTCPSOCKET -DNOTIMEZONE -DNORLOGIN \ -DNOFTP -DNO_DNS_SRV -DNOIKSD $(KFLAGS) -O" #MINIX315 - MINIX 3 1.5 - January 2010 #Last tested successfully on MINIX 3.3.0 28 November 2022 minix315: @echo 'Making C-Kermit $(CKVER) for Minix 3 1.5...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DMINIX315 -DPOSIX -DNOUUCP -DNOJC -DNOLEARN $(KFLAGS) \ -DHAVE_OPENPTY -DNO_PARAM_H -DNOSYSLOG -DNOGETUSERSHELL \ -DSYSTIMEH -DNOINITGROUPS -DNOFTRUNCATE -DNOREALPATH \ -DNORLOGIN -DTCPSOCKET -DNOTIMEZONE -DNO_DNS_SRV -DNOFTP -O" #MINIX340 - MINIX 3.4.0 - January 2022 #Last tested successfully on MINIX 3.3.0 28 November 2022 minix340: @echo 'Making C-Kermit $(CKVER) for Minix 3.4.0...' $(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \ "CFLAGS= -DMINIX340 -DPOSIX -DCK_CURSES \ -DCK_TRCD -DCK_TRCTS -DZLIB -DBSD44 -DNOJC \ -DNDSYSERRLIST -DNOJC -DHAVE_OPENPTY $(KFLAGS) \ -DLOCK_DIR=\\\"/var/spool/uucp\\\" \ -DSYSTIMEH -DTCPSOCKET -O" \ "LIBS= -lcrypt -lcurses -lutil" #PFU Compact A Series UNIX System V R3, SX/A TISP V10/L50 (Japan) #Maybe the -i link option should be removed? sxae50: @echo 'Making C-Kermit $(CKVER) for PFU SX/A V10/L50...' $(MAKE) xermit \ "CFLAGS= -DSVR3 -DDIRENT -DsxaE50 -DTCPSOCKET $(KFLAGS) -i -O" \ "LNKFLAGS= " #Tektronix 6130, 4319, 4301, etc, with UTek OS, /usr/spool/uucp/LCK./... #The models that support hardware flow control. utek: @echo 'Making C-Kermit $(CKVER) for 4.2BSD/UTek, hardware flow control' $(MAKE) wermit \ "CFLAGS= -O -DLCKDIR -DBSD4 -DTCPSOCKET \ -DUTEK -DDCLPOPEN -DLOCK_DIR=\\\"/usr/spool/uucp/LCK.\\\" \ -DTRMBUFL=2048 -DCK_DTRCTS $(KFLAGS)" #Tektronix 4315, 4316, 4317 with UTek OS, /usr/spool/uucp/LCK./... #The models that do not fully support hardware flow control. uteknohwfc: @echo 'Making C-Kermit $(CKVER) for 4.2BSD/UTek, no h/w flow control' $(MAKE) wermit \ "CFLAGS= -O -DLCKDIR -DBSD4 -DTCPSOCKET \ -DUTEK -DDCLPOPEN -DLOCK_DIR=\\\"/usr/spool/uucp/LCK.\\\" \ -DTRMBUFL=2048 $(KFLAGS)" #Tektronix XD88 with UTekV OS utekvr3: @echo 'Making C-Kermit $(CKVER) for Tektronix XD88 UTekV R3...' $(MAKE) wermit \ "CFLAGS= -DSVR3 -DDIRENT -DHDBUUCP \ -DTCPSOCKET -DSYSUTIMEH -DCK_CURSES $(KFLAGS) -O" \ "LIBS= -lcurses" "LNKFLAGS= -s" #Perkin-Elmer 3200 Xelos R02 or earlier ccop1: @echo 'Making C-Kermit $(CKVER) for Xelos & Public Domain Dirent calls' @echo 'or System V R2 or earlier...' $(MAKE) wermit \ "CFLAGS = -DATTSV -Dvoid=int -DDIRENT -DCK_CURSES \ $(KFLAGS) -O" "LNKFLAGS =" "LIBS= -lcurses -ltermlib" #Encore, UMAX 4.3 (BSD) but without acucntrl program. encore: $(MAKE) "MAKE=$(MAKE)" umax43 "KFLAGS=$(KFLAGS)" #Encore, as above, but with curses file transfer display included. encorec: $(MAKE) "MAKE=$(MAKE)" umax43 "KFLAGS=-DCK_CURSES $(KFLAGS)" \ "LIBS= -lcurses -ltermcap" #Encore, UMAX 4.3 (BSD) but without acucntrl program. umax43: @echo Making C-Kermit $(CKVER) for Encore UMAX 4.3... $(MAKE) "MAKE=$(MAKE)" PARALLEL=4 xermit \ "CFLAGS= -DBSD43 -DENCORE -DTCPSOCKET $(KFLAGS) -O" #Encore, UMAX 4.2 (BSD) umax42: @echo Making C-Kermit $(CKVER) for Encore UMAX 4.2... $(MAKE) "MAKE=$(MAKE)" PARALLEL=4 xermit \ "CFLAGS= -DBSD4 -DENCORE -DTCPSOCKET $(KFLAGS) -O" #Encore 88K UMAX 5.3 with TCP/IP support encore88k: @echo 'Making C-Kermit $(CKVER) for Encore 88K UMAX V, TCP/IP...' $(MAKE) xermit \ "CFLAGS = -q ext=pcc -DSVR3 -DTCPSOCKET -DDIRENT \ -DNOGETID_PROTOS -DHDBUUCP $(KFLAGS) -O" "LNKFLAGS =" #Encore 88K UMAX 5.3 with TCP/IP support encore88kgcc: @echo 'Making C-Kermit $(CKVER) for Encore 88K UMAX V, TCP/IP, gcc...' $(MAKE) xermit CC=gcc CC2=gcc \ "CFLAGS = -DSVR3 -DTCPSOCKET -DDIRENT \ -DNOGETID_PROTOS -DHDBUUCP $(KFLAGS) -O" "LNKFLAGS =" #SONY NEWS, NEWS-OS 4.01C sonynews: @echo Making C-Kermit $(CKVER) for SONY NEWS-OS 4.01C... $(MAKE) xermit "CFLAGS= -DBSD43 -DACUCNTRL -DTCPSOCKET -O" #Run Lint on this mess for selected versions. #These are pretty much obsolete since ANSI C / gcc. lintsun: @echo 'Running Lint on C-Kermit $(CKVER) sources for SunOS version...' lint -x -DSUNOS4 -DDIRENT -DTCPSOCKET -DSAVEDUID \ ck[cu]*.c > ckuker.lint.sun lintbsd: @echo 'Running Lint on C-Kermit $(CKVER) sources for BSD 4.2 version..' lint -x -DBSD4 -DTCPSOCKET ck[cu]*.c > ckuker.lint.bsd42 lints5: @echo 'Running Lint on C-Kermit $(CKVER) sources for Sys V version...' lint -x -DATTSV ck[cu]*.c > ckuker.lint.s5 #Who remembers TECO? love: @echo 'Not war?' #Check the most recent build (assuming any previous wermit had been deleted) check: @if test -s wermit -a -x wermit ; then \ echo SUCCESS:; ls -log wermit ; else \ echo FAILED; \ fi ckubs2.mak000664 045065 024037 00000025675 07023327500 013063 0ustar00fdckermit000000 000000 # CKUBS2.MAK Sun May 23 11:52:55 1999 # CKVER= "7.0.195 Beta.07" # # Abbreviated version for 2.10 / 2.11 BSD, which chokes on full-size makefile # because "Make: out of memory". # # C-Kermit 6.0 was the last version that could be built with an interactive # command parser under the 2.11 BSD memory model -- it fit into the overlay # structure with only a few bytes to spare. # # C-Kermit 7.0 and later can be built only in command-line form. # # Instructions: # 1. Make sure there are no other files called "makefile" or "Makefile" # in the same directory. # 2. Change the name of this file to "makefile". # 3. Read below about the strings file. # 4. "make bsd211" (for interactive version) or # "make bsd211noicp" (for command-line-only version). # 5. If you are not on a system with /usr/lib/ctimed (2.10BSD for example), # type "make bsd210" (which will compile cku2tm.c into 'ctimed') # and then install 'ctimed' in the right place (default is /usr/lib). # 6. 2.11BSD includes ctimed and the necessary stub routines. The 'ctimed' # path is in . The "libstubs.a" (obtained via a "-lstubs" at # link time) contains the stub routines. # # Authors: Frank da Cruz, Columbia University, fdc@columbia.edu, # and Steven M Schultz, sms@wlv.iipo.gtegsc.com. # # Modified 4 July 1992 to reshuffle overlays (because the first one got too # big) and to improve the method of defining the string file. fdc. # And again 23 Aug 1992. fdc. # And again 06 Sep 1992 to work around ckudia.c blowing up optimizers. sms. # And again 09 Sep 1992 to incorporate cku2tm.c and new ckustr.c. sms. # & again 19 Sep 92 to add -DMINIDIAL to reduce size of DIAL module. fdc. # & again 7 Nov 92 because two of the segments got too big. fdc. # & again 15-18 Apr 94, ditto, fdc. # + again 11-13 Jun 96, for version 6.0.192, fdc. # 18 Jul 96 to incorporate new 'ctimed' and stubs, sms. # 22 Aug 96 to reshuffle overlays, fdc. # 23 May 99 for C-Kermit 7.0: add new modules and command-line-only build, fdc. ########################################################################### # # 2.10BSD and 2.11BSD (the latter to a larger extent) are the same as 4.3BSD # but without a large address space. # # A string extraction method is used to put approx. 16KB of strings into a # file. The module ckustr.c needs to find this file when C-Kermit runs. # The pathname where this file will reside is defined below (change it if # necessary). After make is finished, the file cku195.sr must be moved to # where ckustr.c has been told to look for it, or you can define an # environment variable KSTR to override the built-in pathname, for example: # # setenv KSTR `pwd`/cku195.sr # # If the resulting wermit program sprews garbage all over your screen, it's # because it is reading the wrong strings file. # # If the resulting wermit program doesn't run at all because UNIX says it # is too big, it's most likely because the data segment, the root segment, # or one of the overlays is too big. The sum of the data (mostly strings.o) # and bss (mostly static buffers) sizes must be less than about 52K (56K is # the maximum, but about 4K is needed for stdio buffers that are added in at # runtime). If the comibed data+bss size exceeds 52K, start chopping away # at static buffers. When it is borderline (> 52K but < 56K), performance # will be terrible -- screen output will be very slow and jerky because # stdio functions are doing a system call per character because they could # not allocate any buffers. # # The maximum number of overlays is 15, but the fewer overlays, the better # the peformance. The smaller the root segment, the bigger the overlays can # be: # # Root Overlay # 56KB 8KB # 48KB 16KB # 40KB 24KB <-- This arrangement used in 6.0.192 # 32KB 32KB # 24KB 40KB # 16KB 48KB # 8KB 56KB # # The hardest-hit modules should go into the root segment, so top priority # goes to ckutio and ckufio, the low-level i/o modules. It would also be # good to put ckcpro and ckucmd in the root segment but they are too big. # # Here is the layout for 6.0.192: # # % size wermit # text data bss dec hex # 34368 25574 26414 86356 15154 total text: 126912 # overlays: 23936,24512,23872,20224 # # This shows root segment text is less than 40K, # data+bss is less than 52K, and each overlay is less than 24K. # ########################################################################### # # Compile and Link variables: # # EXT is the extension (file type) for object files, normally o. # EFLAGS is the CFLAGS _without_ the optimize flag (that is added separately). # The optimizer can not handle a couple modules (ckcpro.c and ckudia.c). # Sometimes this happens silently -- it just dies. # In that case there might be a message like: # Fatal error in /lib/c2 (which is the optimizer) # mv: x.o: Cannot access: No such file or directory # NOTE: You can't add any more -D's to these because there is already # the maximum number of them. See ckcker.h and ckucmd.h for additional # PDP-11 feature disabling. EXT=o OPT=-O EFLAGS=-DBSD43 -DLCKDIR -DNODEBUG -DNOTLOG -DNODIAL \ -DNOCSETS -DNOHELP -DNOSCRIPT -DNOSPL -DNOXMIT -DNOSETBUF \ -DNOMSEND -DNOFRILLS -DNOPARSEN -DNOAPC $(KFLAGS) \ -DSTR_FILE=\\\"/usr/local/lib/cku195.sr\\\" LNKFLAGS= -i CC=./ckustr.sed CC2=cc # ########################################################################### # # Dependencies section and overlay structure for the command-line only version. wermit: ckcmai.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckcpro.$(EXT) \ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \ ckucon.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \ ckuscr.$(EXT) ckcnet.$(EXT) ckuus6.$(EXT) ckuus7.$(EXT) \ ckuusx.$(EXT) ckuusy.$(EXT) ckusig.$(EXT) ckustr.o strings.o \ ckctel.$(EXT) ckclib.$(EXT) $(CC2) $(LNKFLAGS) -o wermit \ ckutio.$(EXT) ckusig.$(EXT) \ -Z ckcfns.$(EXT) ckuus3.$(EXT) ckuusy.$(EXT) \ ckclib.$(EXT) ckcmai.$(EXT) \ -Z ckcpro.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \ ckuus6.$(EXT) ckuus2.$(EXT) ckctel.$(EXT) \ -Z ckucmd.$(EXT) ckuxla.$(EXT) ckuscr.$(EXT) \ ckuusr.$(EXT) ckuus7.$(EXT) ckudia.$(EXT) \ ckcfn2.$(EXT) ckcfn3.$(EXT) \ -Z ckcnet.$(EXT) ckuusx.$(EXT) ckufio.$(EXT) ckucon.$(EXT) \ -Y ckustr.o strings.o $(LIBS) # This is for the interactive version, which is too big as of C-Kermit 7.0. wermiti: ckcmai.$(EXT) ckucmd.$(EXT) ckuusr.$(EXT) ckuus2.$(EXT) \ ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) ckcpro.$(EXT) \ ckcfns.$(EXT) ckcfn2.$(EXT) ckcfn3.$(EXT) ckuxla.$(EXT) \ ckucon.$(EXT) ckutio.$(EXT) ckufio.$(EXT) ckudia.$(EXT) \ ckuscr.$(EXT) ckcnet.$(EXT) ckuus6.$(EXT) ckuus7.$(EXT) \ ckuusx.$(EXT) ckuusy.$(EXT) ckusig.$(EXT) ckustr.o strings.o $(CC2) $(LNKFLAGS) -o wermit \ ckufio.$(EXT) ckutio.$(EXT) ckcmai.$(EXT) ckusig.$(EXT) \ -Z ckcfns.$(EXT) ckuus3.$(EXT) ckuusy.$(EXT) \ -Z ckcpro.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \ ckuus6.$(EXT) ckuus2.$(EXT) \ -Z ckucmd.$(EXT) ckuxla.$(EXT) ckuscr.$(EXT) \ ckuusr.$(EXT) ckuus7.$(EXT) ckudia.$(EXT) \ -Z ckcfn2.$(EXT) ckcfn3.$(EXT) ckucon.$(EXT) \ ckcnet.$(EXT) ckuusx.$(EXT) \ -Y ckustr.o strings.o $(LIBS) strings.o: strings xstr cc -c xs.c mv -f xs.o strings.o rm -f xs.c ########################################################################### # Dependencies for each module... # ckcmai.$(EXT): ckcmai.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcnet.h ckcsig.h \ ckctel.h ckclib.h ckclib.$(EXT): ckclib.c ckclib.h ckcdeb.h ckcasc.h ckcsym.h ckcpro.$(EXT): ckcpro.c ckcker.h ckcdeb.h ckcasc.h ckctel.h ckclib.h $(CC) CFLAGS=${EFLAGS} -c ckcpro.c ckcpro.c: ckcpro.w wart ckcdeb.h ckcasc.h ckcker.h ./wart ckcpro.w ckcpro.c ckcfns.$(EXT): ckcfns.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcxla.h \ ckuxla.h ckctel.h ckclib.h ckcfn2.$(EXT): ckcfn2.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcxla.h ckuxla.h \ ckctel.h ckclib.h ckcfn3.$(EXT): ckcfn3.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcxla.h \ ckuxla.h ckctel.h ckclib.h ckuxla.$(EXT): ckuxla.c ckcker.h ckcdeb.h ckcxla.h ckuxla.h ckctel.h ckclib.h ckuusr.$(EXT): ckuusr.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcxla.h ckuxla.h \ ckcasc.h ckcnet.h ckctel.h ckclib.h ckuus2.$(EXT): ckuus2.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcxla.h ckuxla.h \ ckcasc.h ckctel.h ckclib.h ckuus3.$(EXT): ckuus3.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcxla.h ckuxla.h \ ckcasc.h ckcnet.h ckctel.h ckclib.h ckuus4.$(EXT): ckuus4.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcxla.h ckuxla.h \ ckcasc.h ckcnet.h ckctel.h ckclib.h ckuus5.$(EXT): ckuus5.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcasc.h \ ckctel.h ckclib.h ckuus6.$(EXT): ckuus6.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcasc.h \ ckctel.h ckclib.h ckuus7.$(EXT): ckuus7.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcxla.h ckuxla.h \ ckcasc.h ckcnet.h ckctel.h ckclib.h ckuusx.$(EXT): ckuusx.c ckcker.h ckuusr.h ckcdeb.h ckcasc.h ckcsig.h \ ckctel.h ckclib.h ckuusy.$(EXT): ckuusy.c ckcker.h ckcdeb.h ckcasc.h ckctel.h ckclib.h ckucmd.$(EXT): ckucmd.c ckcasc.h ckucmd.h ckcdeb.h ckctel.h ckclib.h ckufio.$(EXT): ckufio.c ckcdeb.h ckuver.h ckctel.h ckclib.h ckutio.$(EXT): ckutio.c ckcdeb.h ckcnet.h ckuver.h ckctel.h ckclib.h ckucon.$(EXT): ckucon.c ckcker.h ckcdeb.h ckcasc.h ckcnet.h ckcsig.h \ ckctel.h ckclib.h ckcnet.$(EXT): ckcnet.c ckcdeb.h ckcker.h ckcnet.h ckcsig.h ckctel.h ckclib.h ckctel.$(EXT): ckcsym.h ckcdeb.h ckcker.h ckcnet.h ckctel.h ckclib.h wart: ckwart.$(EXT) $(CC) $(LNKFLAGS) -o wart ckwart.$(EXT) ckcmdb.$(EXT): ckcmdb.c ckcdeb.h ckwart.$(EXT): ckwart.c ckudia.$(EXT): ckudia.c ckcker.h ckcdeb.h ckucmd.h ckcasc.h ckcsig.h \ ckctel.h ckclib.h $(CC) CFLAGS=${EFLAGS} -c ckudia.c ckuscr.$(EXT): ckuscr.c ckcker.h ckcdeb.h ckcasc.h ckcsig.h ckctel.h ckclib.h ckusig.$(EXT): ckusig.c ckcsig.h ckcasc.h ckcdeb.h ckcker.h ckcnet.h ckuusr.h \ ckctel.h ckclib.h #2.11BSD # bsd211: @echo "Making C-Kermit $(CKVER) for 2.10/2.11BSD with overlays..." @echo -n "Be sure to install cku195.sr with the same pathname" @echo " specified in ckustr.c!" chmod +x ckustr.sed make wermiti CFLAGS="${OPT} ${EFLAGS}" LIBS=-lstubs bsd211noicp: @echo "Making C-Kermit $(CKVER) for 2.10/2.11BSD NOICP..." @echo -n "Be sure to install cku195.sr with the same pathname" @echo " specified in ckustr.c!" chmod +x ckustr.sed make wermit CFLAGS="${OPT} ${EFLAGS} -DNOICP" LIBS=-lstubs #2.10BSD # bsd210: @echo -n "Be sure to install ctimed with the same pathname" @echo " specified in ckustr.c for STR_CTIMED!" @echo "Making C-Kermit $(CKVER) for 2.10/2.11BSD with overlays..." @echo -n "Be sure to install cku195.sr with the same pathname" @echo " specified in ckustr.c!" chmod +x ckustr.sed make wermiti CFLAGS="${OPT} ${EFLAGS} \ -DSTR_CTIMED=\\\"/usr/lib/ctimed\\\"" ctimed: $(CC2) $OPT $(EFLAGS) $(LNKFLAGS) -o ctimed cku2tm.c #Clean up intermediate and object files clean: @echo 'Removing intermediate files...' -rm -f *.$(EXT) ckcpro.c wart strings cku195.sr ctimed wermit xs.c -rm -f xxmk.c mk.c x.c ck_crp.c000664 045065 024037 00000511074 14767401600 012605 0ustar00fdckermit000000 000000 char *ckcrpv = "Encryption Engine, 10.0.121, 23 Mar 2023"; /* C K _ C R P . C - Cryptography for C-Kermit" Copyright (C) 1998, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Author: Jeffrey E Altman (jaltman@secure-endpoints.com) Secure Endpoints Inc., New York City */ #define CK_CRP_C #ifdef CK_DES #ifdef CK_SSL #ifndef LIBDES #define LIBDES #endif /* LIBDES */ #endif /* CK_SSL */ #endif /* CK_DES */ #ifdef CRYPT_DLL #define CK_AUTHENTICATION #define CK_ENCRYPTION #define CK_DES #define CK_CAST #ifndef LIBDES #define LIBDES #endif /* LIBDES */ #define TELCMDS /* to define name array */ #define TELOPTS /* to define name array */ #define ENCRYPT_NAMES #endif /* CRYPT_DLL */ #include "ckcsym.h" #include "ckcdeb.h" #include "ckcnet.h" #ifdef DEBUG #undef DEBUG #endif /* DEBUG */ #ifdef CK_AUTHENTICATION #ifdef CK_ENCRYPTION #define ENCRYPTION #ifdef CK_DES #define DES_ENCRYPTION #endif /* CK_DES */ #ifdef CK_CAST #define CAST_ENCRYPTION #endif /* CK_CAST */ #ifdef COMMENT #define CAST_EXPORT_ENCRYPTION #endif /* COMMENT */ #endif /* CK_ENCRYPTION */ #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION #include "ckucmd.h" /* For struct keytab definition */ #include "ckuath.h" #include "ckuat2.h" #ifdef MIT_CURRENT #include #endif /* MIT_CURRENT */ #include #include #ifdef OS2 #include #ifdef OS2ONLY #include #undef COMMENT #endif /* OS2ONLY */ #include "ckosyn.h" #else /* OS2 */ static char * tmpstring = NULL; #endif /* OS2 */ #ifndef CAST_OR_EXPORT #ifdef CAST_ENCRYPTION #define CAST_OR_EXPORT #endif /* CAST_ENCRYPTION */ #ifdef CAST_EXPORT_ENCRYPTION #define CAST_OR_EXPORT #endif /* CAST_EXPORT_ENCRYPTION */ #endif /* CAST_OR_EXPORT */ #ifdef MACOSX #undef LIBDES #endif /* MACOSX */ #ifdef CRYPT_DLL int cmd_quoting = 0; #ifdef OS2 /* Copied from ckctel.c */ char * #ifdef CK_ANSIC tel_unk(int opt) /* "UNKNOWN-%u" string. */ #else tel_unk(opt) int opt; #endif /* CK_ANSIC */ { /* 2024-03-27 SMS. Added (decimal) value to "UNKNOWN" messages. */ static char val_str[ 20]; sprintf(val_str, "UNKNOWN-%u", opt); return(val_str); } #endif /* OS2 */ #ifndef TELOPT_MACRO int telopt_index(opt) int opt; { if ( opt >= 0 && opt <= TELOPT_SEND_URL ) return(opt); else if ( opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT ) return(opt-89); else return(NTELOPTS); } int telopt_ok(opt) int opt; { return((opt >= TELOPT_BINARY && opt <= TELOPT_SEND_URL) || (opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT)); } CHAR * telopt(opt) int opt; { if ( telopt_ok(opt) ) return(telopts[telopt_index(opt)]); else return("UNKNOWN"); } #endif /* TELOPT_MACRO */ static int (*p_ttol)(char *,int)=NULL; static int (*p_dodebug)(int,char *,char *,CK_OFF_T)=NULL; static int (*p_dohexdump)(char *,char *,int)=NULL; static void (*p_tn_debug)(char *)=NULL; static int (*p_scrnprint)(const char *)=NULL; static void * p_k5_context=NULL; static unsigned long (*p_reqtelmutex)(unsigned long)=NULL; static unsigned long (*p_reltelmutex)(void)=NULL; unsigned long RequestTelnetMutex(unsigned long x) { if ( p_reqtelmutex ) return p_reqtelmutex(x); return 0; } unsigned long ReleaseTelnetMutex(void) { if ( p_reltelmutex ) return p_reltelmutex(); return 0; } int ttol(char * s, int n) { if ( p_ttol ) return(p_ttol(s,n)); else return(-1); } int dodebug(int flag, char * s1, char * s2, CK_OFF_T n) { if ( p_dodebug ) return(p_dodebug(flag,s1,s2,n)); else return(-1); } int dohexdump( char * s1, char * s2, int n ) { if ( p_dohexdump ) p_dohexdump(s1,s2,n); return(0); } void tn_debug( char * s ) { if ( p_tn_debug ) p_tn_debug(s); } static char myprtfstr[4096]; int Vscrnprintf(const char * format, ...) { int i, len, rc=0; char *cp; va_list ap; va_start(ap, format); #ifdef NT rc = _vsnprintf(myprtfstr, sizeof(myprtfstr)-1, format, ap); #else /* NT */ rc = vsprintf(myprtfstr, format, ap); #endif /* NT */ va_end(ap); if ( p_scrnprint ) return(p_scrnprint(myprtfstr)); else return(-1); } int #ifdef CK_ANSIC tn_hex(CHAR * buf, int buflen, CHAR * data, int datalen) #else /* CK_ANSIC */ tn_hex(buf, buflen, data, datalen) CHAR * buf; int buflen; CHAR * data; int datalen; #endif /* CK_ANSIC */ { int i = 0, j = 0, k = 0; CHAR tmp[8]; #ifdef COMMENT int was_hex = 1; for (k=0; k < datalen; k++) { if (data[k] < 32 || data[k] >= 127) { sprintf(tmp,"%s%02X ",was_hex?"":"\" ",data[k]); was_hex = 1; } else { sprintf(tmp,"%s%c",was_hex?"\"":"",data[k]); was_hex = 0; } ckstrncat(buf,tmp,buflen); } if (!was_hex) ckstrncat(buf,"\" ",buflen); #else /* COMMENT */ if (datalen <= 0 || data == NULL) return(0); for (i = 0; i < datalen; i++) { ckstrncat(buf,"\r\n ",buflen); for (j = 0 ; (j < 16); j++) { if ((i + j) < datalen) sprintf(tmp, "%s%02x ", (j == 8 ? "| " : ""), (CHAR) data[i + j] ); else sprintf(tmp, "%s ", (j == 8 ? "| " : "") ); ckstrncat(buf,tmp,buflen); } ckstrncat(buf," ",buflen); for (k = 0; (k < 16) && ((i + k) < datalen); k++) { sprintf(tmp, "%s%c", (k == 8 ? " " : ""), isprint(data[i + k]) ? data[i + k] : '.' ); ckstrncat(buf,tmp,buflen); } i += j - 1; } /* end for */ ckstrncat(buf,"\r\n ",buflen); #endif /* COMMENT */ return(strlen(buf)); } #ifdef COMMENT #define ttol dll_ttol #define dodebug dll_dodebug #define dohexdump dll_dohexdump #define tn_debug dll_tn_debug #define Vscrnprintf dll_vscrnprintf #endif /* COMMENT */ char tn_msg[TN_MSG_LEN], hexbuf[TN_MSG_LEN]; /* from ckcnet.c */ int deblog=1, debses=1, tn_deb=1; #else /* CRYPT_DLL */ extern char tn_msg[], hexbuf[]; /* from ckcnet.c */ extern int deblog, debses, tn_deb; #ifdef MIT_CURRENT extern krb5_context k5_context; #endif /* MIT_CURRENT */ #endif /* CRYPT_DLL */ #ifdef LIBDES #ifdef MACOSX #define des_new_random_key ck_des_new_random_key #define des_set_random_generator_seed ck_des_set_random_generator_seed #define des_key_sched ck_des_key_sched #define des_ecb_encrypt ck_des_ecb_encrypt #define des_string_to_key ck_des_string_to_key #define des_fixup_key_parity ck_des_fixup_key_parity #endif /* MACOSX */ #ifndef UNIX #define des_new_random_key des_random_key #define des_set_random_generator_seed des_random_seed #endif /* UNIX */ #define des_fixup_key_parity des_set_odd_parity #ifdef OPENSSL_097 #define OPENSSL_ENABLE_OLD_DES_SUPPORT #include #endif /* OPENSSL_097 */ #else /* LIBDES */ #ifdef UNIX #define des_set_random_generator_seed(x) des_init_random_number_generator(x) #endif /* UNIX */ #ifdef OS2 #define des_new_random_key ck_des_new_random_key #define des_set_random_generator_seed ck_des_set_random_generator_seed #define des_key_sched ck_des_key_sched #define des_ecb_encrypt ck_des_ecb_encrypt #define des_string_to_key ck_des_string_to_key #define des_fixup_key_parity ck_des_fixup_key_parity #endif /* OS2 */ #endif /* LIBDES */ #ifdef CK_DES /* This code comes from Eric Young's libdes package and is not part */ /* of the standard MIT DES library that is part of Kerberos. However, */ /* it is extremely useful. So we add it here. */ /* Weak and semi week keys as take from * %A D.W. Davies * %A W.L. Price * %T Security for Computer Networks * %I John Wiley & Sons * %D 1984 * Many thanks to smb@ulysses.att.com (Steven Bellovin) for the reference * (and actual cblock values). */ #define NUM_WEAK_KEY 16 static Block weak_keys[NUM_WEAK_KEY]={ /* weak keys */ {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}, {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE}, {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F}, {0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0}, /* semi-weak keys */ {0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE}, {0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01}, {0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1}, {0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E}, {0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1}, {0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01}, {0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE}, {0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E}, {0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E}, {0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01}, {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE}, {0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1}}; int ck_des_is_weak_key(key) Block key; { int i; for (i=0; i unsigned long unix_time_gmt_unixsec (usecptr) unsigned long *usecptr; { struct timeval now; (void) gettimeofday (&now, (struct timezone *)0); if (usecptr) *usecptr = now.tv_usec; return now.tv_sec; } void des_set_random_generator_seed(Block B) { des_random_seed(B); return; } #ifdef COMMENT /* added to openssl in 0.9.5 */ void des_fixup_key_parity(Block B) { des_set_odd_parity(B); return; } #endif /* COMMENT */ int des_new_random_key(Block B) { int rc=0; /* WARNING: This might need to have the "rc = " removed because this is VOID in later, and maybe even all, versions. */ rc = des_random_key(B); return(rc); } #endif /* MACOSX */ #endif /* LIBDES */ #endif /* UNIX */ #endif /* CK_DES */ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* based on @(#)encrypt.c 8.1 (Berkeley) 6/4/93 */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #include /* * These function pointers point to the current routines * for encrypting and decrypting data. */ /* NOTE: These next two might need to have the "static " removed */ static VOID (*encrypt_output) P((unsigned char *, int)); static int (*decrypt_input) P((int)); #ifdef DEBUG static int encrypt_debug_mode = 1; static int encrypt_verbose = 1; #else static int encrypt_verbose = 1; static int encrypt_debug_mode = 0; #endif /* DEBUG */ static char dbgbuf [16384]; static int decrypt_mode = 0; static int encrypt_mode = 0; static int autoencrypt = 1; static int autodecrypt = 1; static int havesessionkey = 0; static kstream EncryptKSGlobalHack = NULL; static int EncryptType = ENCTYPE_ANY; #define typemask(x) ((x) > 0 ? 1 << ((x)-1) : 0) static long i_support_encrypt = typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64); static long i_support_decrypt = typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64); static long i_wont_support_encrypt = 0; static long i_wont_support_decrypt = 0; #define I_SUPPORT_ENCRYPT (i_support_encrypt & ~i_wont_support_encrypt) #define I_SUPPORT_DECRYPT (i_support_decrypt & ~i_wont_support_decrypt) static long remote_supports_encrypt = 0; static long remote_supports_decrypt = 0; /* Make sure that this list is in order of algorithm strength */ /* as it determines the search order for selecting specific */ /* encryption choices. All CFB modes must come before OFB modes. */ static Encryptions encryptions[] = { #ifdef DES_ENCRYPTION { "DES3_CFB64", ENCTYPE_DES3_CFB64, des3_cfb64_encrypt, des3_cfb64_decrypt, des3_cfb64_init, des3_cfb64_start, des3_cfb64_is, des3_cfb64_reply, des3_cfb64_session, des3_cfb64_keyid, NULL }, #endif /* DES_ENCRYPTION */ #ifdef CAST_ENCRYPTION #ifndef CAST_EXPORT_ENCRYPTION { "CAST128_CFB64", ENCTYPE_CAST128_CFB64, cast_cfb64_encrypt, cast_cfb64_decrypt, cast_cfb64_init, cast_cfb64_start, cast_cfb64_is, cast_cfb64_reply, cast_cfb64_session, cast_cfb64_keyid, NULL }, #endif #endif #ifdef DES_ENCRYPTION { "DES_CFB64", ENCTYPE_DES_CFB64, cfb64_encrypt, cfb64_decrypt, cfb64_init, cfb64_start, cfb64_is, cfb64_reply, cfb64_session, cfb64_keyid, NULL }, #endif /* DES_ENCRYPTION */ #if defined (CAST_EXPORT_ENCRYPTION) || defined(CAST_ENCRYPTION) { "CAST5_40_CFB64", ENCTYPE_CAST5_40_CFB64, castexp_cfb64_encrypt, castexp_cfb64_decrypt, castexp_cfb64_init, castexp_cfb64_start, castexp_cfb64_is, castexp_cfb64_reply, castexp_cfb64_session, castexp_cfb64_keyid, NULL }, #endif /* CAST_ENCRYPTION */ #ifdef DES_ENCRYPTION { "DES3_OFB64", ENCTYPE_DES3_OFB64, des3_ofb64_encrypt, des3_ofb64_decrypt, des3_ofb64_init, des3_ofb64_start, des3_ofb64_is, des3_ofb64_reply, des3_ofb64_session, des3_ofb64_keyid, NULL }, #endif /* DES_ENCRYPTION */ #ifdef CAST_ENCRYPTION #ifndef CAST_EXPORT_ENCRYPTION { "CAST128_OFB64", ENCTYPE_CAST128_OFB64, cast_ofb64_encrypt, cast_ofb64_decrypt, cast_ofb64_init, cast_ofb64_start, cast_ofb64_is, cast_ofb64_reply, cast_ofb64_session, cast_ofb64_keyid, NULL }, #endif #endif #ifdef DES_ENCRYPTION { "DES_OFB64", ENCTYPE_DES_OFB64, ofb64_encrypt, ofb64_decrypt, ofb64_init, ofb64_start, ofb64_is, ofb64_reply, ofb64_session, ofb64_keyid, NULL }, #endif /* DES_ENCRYPTION */ #if defined (CAST_EXPORT_ENCRYPTION) || defined(CAST_ENCRYPTION) { "CAST5_40_OFB64", ENCTYPE_CAST5_40_OFB64, castexp_ofb64_encrypt, castexp_ofb64_decrypt, castexp_ofb64_init, castexp_ofb64_start, castexp_ofb64_is, castexp_ofb64_reply, castexp_ofb64_session, castexp_ofb64_keyid, NULL }, #endif /* CAST_ENCRYPTION */ { 0,0,0,0,0,0,0,0,0,0,0 } }; int get_crypt_table( struct keytab ** pTable, int * pN ) { int i=0,n=0; if ( *pTable ) { for ( i=0 ; i < *pN ; i++ ) free( (*pTable)[i].kwd ) ; free ( *pTable ) ; } *pTable = NULL; *pN = 0; /* How many encryption types do we have? */ while ( encryptions[n].name ) n++; if ( n ) { *pTable = malloc( sizeof(struct keytab) * (n+2) ) ; if ( !(*pTable) ) return(0); #ifdef OS2 (*pTable)[0].kwd =strdup("automatic"); #else /* OS2 */ makestr(&tmpstring,"automatic"); (*pTable)[0].kwd = tmpstring; tmpstring = NULL; #endif /* OS2 */ (*pTable)[0].kwval = ENCTYPE_ANY; (*pTable)[0].flgs = 0; #ifdef OS2 (*pTable)[1].kwd =strdup("none"); #else /* OS2 */ makestr(&tmpstring,"none"); (*pTable)[1].kwd = tmpstring; tmpstring = NULL; #endif /* OS2 */ (*pTable)[1].kwval = 999; (*pTable)[1].flgs = 0; (*pN) = 2; for ( i=0 ; i < n ; i++ ) { char * newstr = NULL, * p; int newval = encryptions[i].type; int j = 0, len = 0; #ifdef OS2 newstr = strdup(encryptions[i].name); strlwr(newstr); #else /* OS2 */ makestr(&tmpstring,encryptions[i].name); newstr = tmpstring; tmpstring = NULL; for (p = newstr; *p; p++) if (isupper(*p)) *p = tolower(*p); #endif /* OS2 */ for (j = 0; j < (*pN); j++) { int tempval = 0; char * tempstr = NULL; if ( strcmp( (*pTable)[j].kwd, newstr ) > 0 ) { tempval = (*pTable)[j].kwval; tempstr = (*pTable)[j].kwd; (*pTable)[j].kwd = newstr ; (*pTable)[j].kwval = newval; newval = tempval; newstr = tempstr; (*pTable)[j].flgs = 0; } } (*pTable)[*pN].kwd = newstr ; (*pTable)[*pN].kwval = newval; (*pTable)[*pN].flgs = 0 ; (*pN)++ ; } } else { *pTable = malloc( sizeof(struct keytab) * 2 ) ; if ( !(*pTable) ) return(0); #ifdef OS2 (*pTable)[0].kwd =strdup("automatic"); #else /* OS2 */ makestr(&tmpstring,"automatic"); (*pTable)[0].kwd = tmpstring; tmpstring = NULL; #endif /* OS2 */ (*pTable)[0].kwval = ENCTYPE_ANY; (*pTable)[0].flgs = 0; #ifdef OS2 (*pTable)[1].kwd =strdup("none"); #else /* OS2 */ makestr(&tmpstring,"none"); (*pTable)[1].kwd = tmpstring; tmpstring = NULL; #endif /* OS2 */ (*pTable)[1].kwval = 999; (*pTable)[1].flgs = 0; (*pN) = 2; } return(*pN); } static unsigned char str_send[64] = { IAC, SB, TELOPT_ENCRYPTION, ENCRYPT_SUPPORT }; static unsigned char str_suplen = 0; static unsigned char str_start[72] = { IAC, SB, TELOPT_ENCRYPTION }; static unsigned char str_end[] = { IAC, SB, TELOPT_ENCRYPTION, 0, IAC, SE }; _PROTOTYP(int encrypt_request_end, (VOID)); _PROTOTYP(int encrypt_request_start, (VOID)); _PROTOTYP(int encrypt_enc_keyid, (unsigned char *, int)); _PROTOTYP(int encrypt_dec_keyid, (unsigned char *, int)); _PROTOTYP(int encrypt_support, (unsigned char *, int)); _PROTOTYP(int encrypt_start, (unsigned char *, int)); _PROTOTYP(int encrypt_end, (VOID)); _PROTOTYP(int encrypt_ks_stream,(struct kstream_data_block *, /* output */ struct kstream_data_block *)); /* input */ _PROTOTYP(int decrypt_ks_stream,(struct kstream_data_block *, /* output */ struct kstream_data_block *)); /* input */ int #ifdef CK_ANSIC encrypt_ks_stream(struct kstream_data_block *i, struct kstream_data_block *o) #else encrypt_ks_stream(i,o) struct kstream_data_block *i; struct kstream_data_block *o; #endif { /* * this is really quite bogus, since it does an in-place encryption... */ if (encrypt_output) { encrypt_output(i->ptr, i->length); return 1; } return 0; } int #ifdef CK_ANSIC decrypt_ks_stream(struct kstream_data_block *i, struct kstream_data_block *o) #else decrypt_ks_stream(i,o) struct kstream_data_block *i; struct kstream_data_block *o; #endif { unsigned int len; /* * this is really quite bogus, since it does an in-place decryption... */ if (decrypt_input) { for (len = 0 ; len < i->length ; len++) ((unsigned char *)i->ptr)[len] = decrypt_input(((unsigned char *)i->ptr)[len]); return 1; } return 0; } int #ifdef CK_ANSIC decrypt_ks_hack(unsigned char *buf, int cnt) #else decrypt_ks_hack(buf,cnt) unsigned char *buf; int cnt; #endif { int len; /* * this is really quite bogus, since it does an in-place decryption... */ for (len = 0 ; len < cnt ; len++) buf[len] = decrypt_input(buf[len]); #ifdef DEBUG ckhexdump("decrypt ks hack", buf, cnt); #endif return 1; } /* * parsedat[0] == the suboption we might be negotiating, */ int #ifdef CK_ANSIC encrypt_parse(unsigned char *parsedat, int end_sub) #else encrypt_parse(parsedat,end_sub) unsigned char *parsedat; int end_sub; #endif { int rc = 0; switch(parsedat[1]) { case ENCRYPT_START: rc = encrypt_start(parsedat + 2, end_sub - 2); break; case ENCRYPT_END: rc = encrypt_end(); break; case ENCRYPT_SUPPORT: rc = encrypt_support(parsedat + 2, end_sub - 2); break; case ENCRYPT_REQSTART: rc = encrypt_request_start(); break; case ENCRYPT_REQEND: /* * We can always send an REQEND so that we cannot * get stuck encrypting. We should only get this * if we have been able to get in the correct mode * anyhow. */ rc = encrypt_request_end(); break; case ENCRYPT_IS: rc = encrypt_is(parsedat + 2, end_sub - 2); break; case ENCRYPT_REPLY: rc = encrypt_reply(parsedat + 2, end_sub - 2); break; case ENCRYPT_ENC_KEYID: rc = encrypt_enc_keyid(parsedat + 2, end_sub - 2); break; case ENCRYPT_DEC_KEYID: rc = encrypt_dec_keyid(parsedat + 2, end_sub - 2); break; default: rc = -1; break; } return(rc); } /* XXX */ Encryptions * #ifdef CK_ANSIC findencryption(int type) #else findencryption(type) int type; #endif { Encryptions *ep = encryptions; if (!(I_SUPPORT_ENCRYPT & remote_supports_decrypt & typemask(type))) return(0); while (ep->type && ep->type != type) ++ep; return(ep->type ? ep : 0); } Encryptions * #ifdef CK_ANSIC finddecryption(int type) #else finddecryption(type) int type; #endif { Encryptions *ep = encryptions; if (!(I_SUPPORT_DECRYPT & remote_supports_encrypt & typemask(type))) return(0); while (ep->type && ep->type != type) ++ep; return(ep->type ? ep : 0); } #define MAXKEYLEN 64 static struct key_info { unsigned char keyid[MAXKEYLEN]; int keylen; int dir; int *modep; Encryptions *(*getcrypt)(); } ki[2] = { { { 0 }, 0, DIR_ENCRYPT, &encrypt_mode, findencryption }, { { 0 }, 0, DIR_DECRYPT, &decrypt_mode, finddecryption }, }; VOID #ifdef CK_ANSIC encrypt_init(kstream iks, int type) #else encrypt_init(iks, type) kstream iks; int type; #endif { Encryptions *ep = encryptions; i_support_encrypt = i_support_decrypt = 0; remote_supports_encrypt = remote_supports_decrypt = 0; i_wont_support_encrypt = i_wont_support_decrypt = 0; encrypt_mode = 0; decrypt_mode = 0; encrypt_output = NULL; decrypt_input = NULL; ki[0].keylen = 0; memset(ki[0].keyid,0,MAXKEYLEN); ki[1].keylen = 0; memset(ki[1].keyid,0,MAXKEYLEN); havesessionkey = 0; autoencrypt = 1; autodecrypt = 1; EncryptKSGlobalHack = iks; EncryptType = type; str_send[0] = IAC; str_send[1] = SB; str_send[2] = TELOPT_ENCRYPTION; str_send[3] = ENCRYPT_SUPPORT; str_suplen = 4; while (ep->type) { if ( EncryptType == ENCTYPE_ANY || EncryptType == ep->type ) { #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>I will support %s\n", ENCTYPE_NAME(ep->type)); /* safe */ debug(F110,"encrypt_init",dbgbuf,0); } #endif i_support_encrypt |= typemask(ep->type); i_support_decrypt |= typemask(ep->type); if ((i_wont_support_decrypt & typemask(ep->type)) == 0) if ((str_send[str_suplen++] = ep->type) == IAC) str_send[str_suplen++] = IAC; } if (ep->init) (*ep->init)(0); ++ep; } str_send[str_suplen++] = IAC; str_send[str_suplen++] = SE; } VOID #ifdef CK_ANSIC encrypt_send_support(VOID) #else encrypt_send_support() #endif { Encryptions *ep = encryptions; #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) return; #endif /* CK_SSL */ str_send[0] = IAC; str_send[1] = SB; str_send[2] = TELOPT_ENCRYPTION; str_send[3] = ENCRYPT_SUPPORT; str_suplen = 4; while (ep->type) { if ( EncryptType == ENCTYPE_ANY || EncryptType == ep->type ) { #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>I will support %s\n", ENCTYPE_NAME(ep->type)); /* safe */ debug(F110,"encrypt_send_support",dbgbuf,0); } #endif if ((i_wont_support_decrypt & typemask(ep->type)) == 0) if ((str_send[str_suplen++] = ep->type) == IAC) str_send[str_suplen++] = IAC; } ++ep; } str_send[str_suplen++] = IAC; str_send[str_suplen++] = SE; /* * If the user has requested that decryption start * immediatly, then send a "REQUEST START" before * we negotiate the type. */ if (autodecrypt) encrypt_send_request_start(); if (deblog || tn_deb || debses) { int i; sprintf(tn_msg,"TELNET SENT SB %s SUPPORT ", TELOPT(TELOPT_ENCRYPTION)); /* safe */ for ( i=4;i 0) { debug(F101,"XXX cnt","",cnt); type = *typelist++; debug(F101,"XXX type","",type); debug(F101,"XXX ENCTYPE_ANY","",ENCTYPE_ANY); if ( EncryptType == ENCTYPE_ANY || EncryptType == type ) { #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>Remote supports %s (%d)\n", ENCTYPE_NAME(type), type); /* safe */ debug(F110,"encrypt_support",dbgbuf,0); } #endif if ((type < ENCTYPE_CNT) && (I_SUPPORT_ENCRYPT & typemask(type))) { remote_supports_decrypt |= typemask(type); if (use_type == 0) use_type = type; } } } debug(F101,"XXX use_type","",use_type); if (use_type) { ep = findencryption(use_type); if (!ep) { debug(F111,"encrypt_support","findencryption == NULL",use_type); return(-1); } debug(F100,"XXX ep not NULL","",0); type = ep->start ? (*ep->start)(DIR_ENCRYPT, 0) : 0; debug(F101,"XXX new type","",type); #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>(*ep->start)() %s returned %d (%s)\n", ENCTYPE_NAME(use_type), type, ENCRYPT_NAME(type)); /* safe */ debug(F110,"encrypt_support",dbgbuf,0); } #endif if (type < 0) { debug(F111,"encrypt_support","type < 0",type); return(-1); } encrypt_mode = use_type; if (type == 0) encrypt_start_output(use_type); debug(F111,"encrypt_support","success",type); return(0); } debug(F111,"encrypt_support","failed",use_type); return(-1); } int #ifdef CK_ANSIC encrypt_is(unsigned char *data, int cnt) #else encrypt_is(data, cnt) unsigned char *data; int cnt; #endif /* CK_ANSIC */ { Encryptions *ep; register int type, ret; if (--cnt < 0) return(-1); type = *data++; if (type < ENCTYPE_CNT) remote_supports_encrypt |= typemask(type); if (!(ep = finddecryption(type))) { #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>encrypt_is: " "Can't find type %s (%d) for initial negotiation\n", ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); /* safe */ debug(F110,"encrypt_is",dbgbuf,0); } #endif return(-1); } if (!ep->is) { #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>encrypt_is: " "No initial negotiation needed for type %s (%d)\n", ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); /* safe */ debug(F110,"encrypt_is",dbgbuf,0); } #endif ret = 0; } else { ret = (*ep->is)(data, cnt); #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, "encrypt_is: " "(*ep->is)(%x, %d) returned %s(%d)\n", data, cnt, (ret < 0) ? "FAIL " : (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); /* safe */ debug(F110,"encrypt_is",dbgbuf,0); } #endif } if (ret < 0) { autodecrypt = 0; return(-1); } else { decrypt_mode = type; if (ret == 0 && autodecrypt) { encrypt_send_request_start(); } } return(0); } int #ifdef CK_ANSIC encrypt_reply(unsigned char *data, int cnt) #else encrypt_reply(data, cnt) unsigned char *data; int cnt; #endif { Encryptions *ep; register int ret, type; if (--cnt < 0) return(-1); type = *data++; if (!(ep = findencryption(type))) { #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>Can't find type %s (%d) for initial negotiation\n", ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); /* safe */ debug(F110,"encrypt_reply",dbgbuf,0); } #endif return(-1); } if (!ep->reply) { #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>No initial negotiation needed for type %s (%d)\n", ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); /* safe */ debug(F110,"encrypt_reply",dbgbuf,0); } #endif ret = 0; } else { ret = (*ep->reply)(data, cnt); #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, "(*ep->reply)(%x, %d) returned %s(%d)\n", data, cnt, (ret < 0) ? "FAIL " : (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); /* safe */ debug(F110,"encrypt_reply",dbgbuf,0); } #endif } #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>encrypt_reply returned %d\n", ret); /* safe */ debug(F110,"encrypt_reply",dbgbuf,0); } #endif if (ret < 0) { autoencrypt = 0; return(-1); } else { encrypt_mode = type; if (ret == 0 && autoencrypt) encrypt_start_output(type); } return(0); } /* * Called when a ENCRYPT START command is received. */ int #ifdef CK_ANSIC encrypt_start(unsigned char *data, int cnt) #else encrypt_start(data, cnt) unsigned char *data; int cnt; #endif { Encryptions *ep; if (!decrypt_mode) { /* * Something is wrong. We should not get a START * command without having already picked our * decryption scheme. Send a REQUEST-END to * attempt to clear the channel... */ encrypt_send_request_end(); printf("Authentication error!\n%s\n", "Warning, Cannot decrypt input stream!!!"); return(-1); } if (ep = finddecryption(decrypt_mode)) { if ( decrypt_input != ep->input ) { decrypt_input = ep->input; EncryptKSGlobalHack->decrypt = decrypt_ks_stream; EncryptKSGlobalHack->decrypt_type = ep->type; if (encrypt_verbose) { sprintf(dbgbuf, "Input is now decrypted with type %s", ENCTYPE_NAME(decrypt_mode)); /* safe */ debug(F110,"encrypt_start",dbgbuf,0); printf("%s\n",dbgbuf); } #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>Start to decrypt input with type %s", ENCTYPE_NAME(decrypt_mode)); /* safe */ debug(F110,"ck_crp",dbgbuf,0); } #endif } } else { char buf[1024]; sprintf(buf, "Warning, Cannot decrypt type %s (%d)!!!", ENCTYPE_NAME_OK(decrypt_mode) ? ENCTYPE_NAME(decrypt_mode) : "(unknown)", decrypt_mode); /* safe */ printf("Authentication error!\n%s\n",buf); encrypt_send_request_end(); return(-1); } return(0); } int #ifdef CK_ANSIC encrypt_dont_support(int type) #else encrypt_dont_support(type) int type; #endif { i_wont_support_encrypt |= typemask(type); i_wont_support_decrypt |= typemask(type); return(0); } int #ifdef CK_ANSIC encrypt_session_key(Session_Key *key, int server) #else encrypt_session_key(key, server) Session_Key *key; int server; #endif { Encryptions *ep = encryptions; if (havesessionkey) return(0); havesessionkey = 1; while (ep->type) { debug(F111,"encrypt_session_key",ep->name,ep->type); if (ep->session) { if ((*ep->session)(key, server) < 0) { i_wont_support_encrypt |= typemask(ep->type); i_wont_support_decrypt |= typemask(ep->type); } } ++ep; } debug(F111,"encrypt_session_key (done)",ep->name,ep->type); return(0); } /* * Called when ENCRYPT END is received. */ int #ifdef CK_ANSIC encrypt_end(VOID) #else encrypt_end() #endif { decrypt_input = NULL; EncryptKSGlobalHack->decrypt = NULL; EncryptKSGlobalHack->decrypt_type = ENCTYPE_ANY; #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>Input is back to clear text"); /* safe */ debug(F110,"encrypt_end",dbgbuf,0); } #endif if (encrypt_verbose) { sprintf(dbgbuf, "Input is now clear text"); /* safe */ debug(F110,"encrypt_end",dbgbuf,0); printf("%s\n",dbgbuf); } return(0); } /* * Called when ENCRYPT REQUEST-END is received. */ int #ifdef CK_ANSIC encrypt_request_end(VOID) #else encrypt_request_end() #endif { encrypt_send_end(); return(0); } /* * Called when ENCRYPT REQUEST-START is received. If we receive * this before a type is picked, then that indicates that the * other side wants us to start encrypting data as soon as we * can. */ int #ifdef CK_ANSIC encrypt_request_start(VOID) #else encrypt_request_start() #endif { if (encrypt_mode != 0) encrypt_start_output(encrypt_mode); return(0); } static unsigned char str_keyid[(MAXKEYLEN*2)+5] = { IAC, SB, TELOPT_ENCRYPTION }; _PROTOTYP(int encrypt_keyid,(struct key_info *,unsigned char *,int)); int #ifdef CK_ANSIC encrypt_enc_keyid(unsigned char *keyid, int len) #else encrypt_enc_keyid(keyid, len) unsigned char *keyid; int len; #endif { return(encrypt_keyid(&ki[1], keyid, len)); } int #ifdef CK_ANSIC encrypt_dec_keyid(unsigned char *keyid, int len) #else encrypt_dec_keyid(keyid, len) unsigned char *keyid; int len; #endif /* CK_ANSIC */ { return(encrypt_keyid(&ki[0], keyid, len)); } int #ifdef CK_ANSIC encrypt_keyid(struct key_info *kp, unsigned char *keyid, int len) #else encrypt_keyid(kp, keyid, len) struct key_info *kp; unsigned char *keyid; int len; #endif { Encryptions *ep; int dir = kp->dir; register int ret = 0; if (!(ep = (*kp->getcrypt)(*kp->modep))) { if (len == 0) return(-1); kp->keylen = 0; } else if (len == 0 || len > MAXKEYLEN) { /* * Empty option or Key too long, indicates a failure. */ if (kp->keylen == 0) return(-1); kp->keylen = 0; if (ep->keyid) (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen); } else if ((len != kp->keylen) || (memcmp(keyid, kp->keyid, len) != 0)) { /* * Length or contents are different */ kp->keylen = len; memcpy(kp->keyid, keyid, len); /* length < MAXKEYLEN */ if (ep->keyid) (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen); } else { if (ep->keyid) ret = (*ep->keyid)(dir, kp->keyid, &kp->keylen); if ((ret == 0) && (dir == DIR_ENCRYPT) && autoencrypt) encrypt_start_output(*kp->modep); return(0); } encrypt_send_keyid(dir, kp->keyid, kp->keylen, 0); return(0); } int #ifdef CK_ANSIC encrypt_send_keyid(int dir, unsigned char *keyid, int keylen, int saveit) #else encrypt_send_keyid(dir, keyid, keylen, saveit) int dir; unsigned char *keyid; int keylen; int saveit; #endif { unsigned char *strp; #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) return(0); #endif /* CK_SSL */ str_keyid[3] = (dir == DIR_ENCRYPT) ? ENCRYPT_ENC_KEYID : ENCRYPT_DEC_KEYID; if (saveit && keylen <= MAXKEYLEN) { struct key_info *kp = &ki[(dir == DIR_ENCRYPT) ? 0 : 1]; memcpy(kp->keyid, keyid, keylen); kp->keylen = keylen; } for (strp = &str_keyid[4]; keylen > 0; --keylen) { if ((*strp++ = *keyid++) == IAC) *strp++ = IAC; } *strp++ = IAC; *strp++ = SE; if (deblog || tn_deb || debses) { int i; sprintf(tn_msg,"TELNET SENT SB %s %s ", TELOPT(TELOPT_ENCRYPTION), (dir == DIR_ENCRYPT) ? "ENC-KEYID" : "DEC-KEYID"); /* safe */ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_keyid[4],strp-str_keyid-2-4); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol(str_keyid, strp - str_keyid); #ifdef OS2 ReleaseTelnetMutex(); #endif return(0); } VOID #ifdef CK_ANSIC encrypt_auto(int on) #else encrypt_auto(on) int on; #endif { if (on < 0) autoencrypt ^= 1; else autoencrypt = on ? 1 : 0; } VOID #ifdef CK_ANSIC decrypt_auto(int on) #else decrypt_auto(on) int on; #endif { if (on < 0) autodecrypt ^= 1; else autodecrypt = on ? 1 : 0; } VOID #ifdef CK_ANSIC encrypt_start_output(int type) #else encrypt_start_output(type) int type; #endif { Encryptions *ep; register unsigned char *p; register int i; #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) return; #endif /* CK_SSL */ if (!(ep = findencryption(type))) { #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>Can't encrypt with type %s (%d)\n", ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); /* safe */ debug(F110,"encrypt_start_output",dbgbuf,0); } #endif return; } if (ep->start) { i = (*ep->start)(DIR_ENCRYPT, 0); #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>Encrypt start: %s (%d) %s\n", (i < 0) ? "failed" : "initial negotiation in progress", i, ENCTYPE_NAME(type)); /* safe */ debug(F110,"encrypt_start_output",dbgbuf,0); } #endif if (i) return; } if ( encrypt_output != ep->output ) { p = str_start; *p++ = IAC; *p++ = SB; *p++ = TELOPT_ENCRYPTION; *p++ = ENCRYPT_START; for (i = 0; i < ki[0].keylen; ++i) { if (( *p++ = ki[0].keyid[i]) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; if (deblog || tn_deb || debses) { int i; sprintf(tn_msg,"TELNET SENT SB %s START ", TELOPT(TELOPT_ENCRYPTION)); /* safe */ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_start[4],p-str_start-2-4); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol(str_start, p - str_start); #ifdef OS2 ReleaseTelnetMutex(); #endif /* * If we are already encrypting in some mode, then * encrypt the ring (which includes our request) in * the old mode, mark it all as "clear text" and then * switch to the new mode. */ encrypt_output = ep->output; EncryptKSGlobalHack->encrypt = encrypt_ks_stream; EncryptKSGlobalHack->encrypt_type = type; encrypt_mode = type; #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>Started to encrypt output with type %s", ENCTYPE_NAME(type)); /* safe */ debug(F110,"encrypt_start_output",dbgbuf,0); } #endif if (encrypt_verbose) { sprintf(dbgbuf, "Output is now encrypted with type %s", ENCTYPE_NAME(type)); /* safe */ debug(F110,"encrypt_start_output",dbgbuf,0); printf("%s\n",dbgbuf); } } } VOID #ifdef CK_ANSIC encrypt_send_end(VOID) #else encrypt_send_end() #endif { #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) return; #endif /* CK_SSL */ if (!encrypt_output) return; str_end[0] = IAC; str_end[1] = SB; str_end[2] = TELOPT_ENCRYPTION; str_end[3] = ENCRYPT_END; str_end[4] = IAC; str_end[5] = SE; if (deblog || tn_deb || debses) { int i; sprintf(tn_msg,"TELNET SENT SB %s END IAC SE", TELOPT(TELOPT_ENCRYPTION)); /* safe */ debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol(str_end, sizeof(str_end)); #ifdef OS2 ReleaseTelnetMutex(); #endif encrypt_output = 0; EncryptKSGlobalHack->encrypt = NULL; EncryptKSGlobalHack->encrypt_type = ENCTYPE_ANY; #ifdef DEBUG if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>Output is back to clear text"); /* safe */ debug(F110,"encrypt_send_end",dbgbuf,0); } #endif if (encrypt_verbose) { sprintf(dbgbuf, "Output is now clear text"); /* safe */ debug(F110,"encrypt_send_end",dbgbuf,0); printf("%s\n",dbgbuf); } } VOID #ifdef CK_ANSIC encrypt_send_request_start(VOID) #else encrypt_send_request_start() #endif { register unsigned char *p; register int i; #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) return; #endif /* CK_SSL */ p = str_start; *p++ = IAC; *p++ = SB; *p++ = TELOPT_ENCRYPTION; *p++ = ENCRYPT_REQSTART; for (i = 0; i < ki[1].keylen; ++i) { if (( *p++ = ki[1].keyid[i]) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; if (deblog || tn_deb || debses) { int i; sprintf(tn_msg,"TELNET SENT SB %s REQUEST-START ", TELOPT(TELOPT_ENCRYPTION)); /* safe */ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_start[4],p-str_start-2-4); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol(str_start, p - str_start); #ifdef OS2 ReleaseTelnetMutex(); #endif if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>Request input to be encrypted\n"); /* safe */ debug(F110,"encrypt_send_request_start",dbgbuf,0); } } VOID #ifdef CK_ANSIC encrypt_send_request_end(VOID) #else encrypt_send_request_end() #endif { #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) return; #endif /* CK_SSL */ str_end[0] = IAC; str_end[1] = SB; str_end[2] = TELOPT_ENCRYPTION; str_end[3] = ENCRYPT_REQEND; str_end[4] = IAC; str_end[5] = SE; if (deblog || tn_deb || debses) { int i; sprintf(tn_msg,"TELNET SENT SB %s REQEND IAC SE", TELOPT(TELOPT_ENCRYPTION)); /* safe */ debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol(str_end, sizeof(str_end)); #ifdef OS2 ReleaseTelnetMutex(); #endif if (encrypt_debug_mode) { sprintf(dbgbuf, ">>>Request input to be clear text\n"); /* safe */ debug(F110,"encrypt_send_request_end",dbgbuf,0); } } int #ifdef CK_ANSIC encrypt_is_encrypting(VOID) #else encrypt_is_encrypting() #endif { if (encrypt_output) return 1; return 0; } int #ifdef CK_ANSIC encrypt_is_decrypting(VOID) #else encrypt_is_decrypting() #endif { if (decrypt_input) return 1; return 0; } #ifdef DEBUG void encrypt_debug(mode) int mode; { encrypt_debug_mode = mode; } #endif #ifdef CK_DES /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* based on @(#)enc_des.c 8.1 (Berkeley) 6/4/93 */ #define CFB 0 #define OFB 1 #define NO_SEND_IV 1 #define NO_RECV_IV 2 #define NO_KEYID 4 #define IN_PROGRESS (NO_SEND_IV|NO_RECV_IV|NO_KEYID) #define SUCCESS 0 #define xFAILED -1 Schedule test_sched; struct des_stinfo { Block str_output; Block str_feed; Block str_iv; Block str_ikey; #ifdef MIT_CURRENT unsigned char str_keybytes[8]; krb5_keyblock str_key; #else /* MIT_CURRENT */ Schedule str_sched; int str_index; #endif /* MIT_CURRENT */ int str_flagshift; }; struct des_fb { #ifndef MIT_CURRENT Block krbdes_key; Schedule krbdes_sched; #endif /* MIT_CURRENT */ Block temp_feed; unsigned char fb_feed[64]; int need_start; int state[2]; int keyid[2]; int once; #ifdef MIT_CURRENT int validkey; #endif /* MIT_CURRENT */ struct des_stinfo streams[2]; }; static struct des_fb des_fb[2]; struct des3_stinfo { Block str_output; Block str_feed; Block str_iv; Block str_ikey[3]; Schedule str_sched[3]; int str_index; int str_flagshift; }; struct des3_fb { #ifndef MIT_CURRENT Block krbdes_key[3]; Schedule krbdes_sched[3]; #endif /* MIT_CURRENT */ Block temp_feed; unsigned char fb_feed[64]; int need_start; int state[2]; int keyid[2]; int once; #ifdef MIT_CURRENT int validkey; #endif /* MIT_CURRENT */ struct des3_stinfo streams[2]; }; static struct des3_fb des3_fb[2]; struct keyidlist { char *keyid; int keyidlen; char *key; int keylen; int flags; } keyidlist [] = { { "\0", 1, 0, 0, 0 }, /* default key of zero */ { 0, 0, 0, 0, 0 } }; #define KEYFLAG_MASK 03 #define KEYFLAG_NOINIT 00 #define KEYFLAG_INIT 01 #define KEYFLAG_OK 02 #define KEYFLAG_BAD 03 #define KEYFLAG_SHIFT 2 #define SHIFT_VAL(a,b) (KEYFLAG_SHIFT*((a)+((b)*2))) #define FB64_IV 1 #define FB64_IV_OK 2 #define FB64_IV_BAD 3 #define FB64_CHALLENGE 4 #define FB64_RESPONSE 5 void fb64_stream_iv P((Block, struct des_stinfo *)); void fb64_init P((struct des_fb *)); static int fb64_start P((struct des_fb *, int, int)); int fb64_is P((unsigned char *, int, struct des_fb *)); int fb64_reply P((unsigned char *, int, struct des_fb *)); static int fb64_session P((Session_Key *, int, struct des_fb *)); void fb64_stream_key P((Block, struct des_stinfo *)); int fb64_keyid P((int, unsigned char *, int *, struct des_fb *)); #ifdef MIT_CURRENT static void #ifdef CK_ANSIC ecb_encrypt(struct des_stinfo *stp, Block in, Block out) #else /* CKANSIC */ ecb_encrypt(stp, in, out) struct des_stinfo *stp; Block in; Block out; #endif /* CK_ANSIC */ { krb5_error_code code; krb5_data din; krb5_enc_data dout; din.length = 8; din.data = in; dout.ciphertext.length = 8; dout.ciphertext.data = out; dout.enctype = ENCTYPE_UNKNOWN; #ifdef CRYPT_DLL code = krb5_c_encrypt(*p_k5_context, &stp->str_key, 0, 0, &din, &dout); #else /* CRYPT_DLL */ code = krb5_c_encrypt(k5_context, &stp->str_key, 0, 0, &din, &dout); #endif /* CRYPT_DLL */ /* XXX I'm not sure what to do if this fails */ if (code) com_err("libtelnet", code, "encrypting stream data"); } #endif /* MIT_CURRENT */ void cfb64_init(server) int server; { fb64_init(&des_fb[CFB]); des_fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64; des_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB); des_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB); } void ofb64_init(server) int server; { fb64_init(&des_fb[OFB]); des_fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64; des_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB); des_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB); } void fb64_init(fbp) register struct des_fb *fbp; { memset((void *)fbp, 0, sizeof(*fbp)); fbp->state[0] = fbp->state[1] = xFAILED; fbp->fb_feed[0] = IAC; fbp->fb_feed[1] = SB; fbp->fb_feed[2] = TELOPT_ENCRYPTION; fbp->fb_feed[3] = ENCRYPT_IS; } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. * 2: Not yet. Other things (like getting the key from * Kerberos) have to happen before we can continue. */ int cfb64_start(dir, server) int dir; int server; { return(fb64_start(&des_fb[CFB], dir, server)); } int ofb64_start(dir, server) int dir; int server; { return(fb64_start(&des_fb[OFB], dir, server)); } static int fb64_start(fbp, dir, server) struct des_fb *fbp; int dir; int server; { int x; unsigned char *p; register int state; switch (dir) { case DIR_DECRYPT: /* * This is simply a request to have the other side * start output (our input). He will negotiate an * IV so we need not look for it. */ state = fbp->state[dir-1]; if (state == xFAILED) state = IN_PROGRESS; break; case DIR_ENCRYPT: state = fbp->state[dir-1]; if (state == xFAILED) state = IN_PROGRESS; else if ((state & NO_SEND_IV) == 0) break; #ifdef MIT_CURRENT if (!fbp->validkey) { fbp->need_start = 1; break; } #else /* MIT_CURRENT */ if (!VALIDKEY(fbp->krbdes_key)) { fbp->need_start = 1; break; } #endif /* MIT_CURRENT */ state &= ~NO_SEND_IV; state |= NO_RECV_IV; /* * Create a random feed and send it over. */ #ifdef MIT_CURRENT { krb5_data d; krb5_error_code code; d.data = fbp->temp_feed; d.length = sizeof(fbp->temp_feed); #ifdef CRYPT_DLL if (code = krb5_c_random_make_octets(*p_k5_context,&d)) return(xFAILED); #else /* CRYPT_DLL */ if (code = krb5_c_random_make_octets(k5_context,&d)) return(xFAILED); #endif /* CRYPT_DLL */ } #else /* MIT_CURRENT */ des_new_random_key(fbp->temp_feed); des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed, fbp->krbdes_sched, 1); #endif /* MIT_CURRENT */ p = fbp->fb_feed + 3; *p++ = ENCRYPT_IS; p++; *p++ = FB64_IV; for (x = 0; x < sizeof(Block); ++x) { if (( *p++ = fbp->temp_feed[x]) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; if (deblog || tn_deb || debses) { int i; sprintf(tn_msg, "TELNET SENT SB %s IS %s FB64_IV ", TELOPT(fbp->fb_feed[2]), enctype_names[fbp->fb_feed[4]]); /* safe */ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&fbp->fb_feed[6], (p-fbp->fb_feed)-2-6); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol(fbp->fb_feed, p - fbp->fb_feed); #ifdef OS2 ReleaseTelnetMutex(); #endif break; default: return(xFAILED); } return(fbp->state[dir-1] = state); } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. */ int cfb64_is(data, cnt) unsigned char *data; int cnt; { return(fb64_is(data, cnt, &des_fb[CFB])); } int ofb64_is(data, cnt) unsigned char *data; int cnt; { return(fb64_is(data, cnt, &des_fb[OFB])); } int fb64_is(data, cnt, fbp) unsigned char *data; int cnt; struct des_fb *fbp; { unsigned char *p; register int state = fbp->state[DIR_DECRYPT-1]; if (cnt-- < 1) goto failure; #ifdef CK_SSL if (!TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) #endif /* CK_SSL */ switch (*data++) { case FB64_IV: if (cnt != sizeof(Block)) { #ifdef DEBUG if (encrypt_debug_mode) printf("CFB64: initial vector failed on size\r\n"); #endif state = xFAILED; goto failure; } #ifdef DEBUG if (encrypt_debug_mode) { printf("CFB64: initial vector received\r\n"); printf("Initializing Decrypt stream\r\n"); } #endif fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]); p = fbp->fb_feed + 3; *p++ = ENCRYPT_REPLY; p++; *p++ = FB64_IV_OK; *p++ = IAC; *p++ = SE; if (deblog || tn_deb || debses) { int i; sprintf(tn_msg, "TELNET SENT SB %s REPLY %s FB64_IV_OK ", TELOPT(fbp->fb_feed[2]), enctype_names[fbp->fb_feed[4]]); /* safe */ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&fbp->fb_feed[6], (p-fbp->fb_feed)-2-6); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol(fbp->fb_feed, p - fbp->fb_feed); #ifdef OS2 ReleaseTelnetMutex(); #endif state = IN_PROGRESS; break; default: #if 0 if (encrypt_debug_mode) { printf("Unknown option type: %d\r\n", *(data-1)); printf("\r\n"); } #endif /* FALL THROUGH */ failure: /* * We failed. Send an FB64_IV_BAD option * to the other side so it will know that * things failed. */ p = fbp->fb_feed + 3; *p++ = ENCRYPT_REPLY; p++; *p++ = FB64_IV_BAD; *p++ = IAC; *p++ = SE; if (deblog || tn_deb || debses) { int i; sprintf(tn_msg, "TELNET SENT SB %s REPLY %s FB64_IV_BAD ", TELOPT(fbp->fb_feed[2]), enctype_names[fbp->fb_feed[4]]); /* safe */ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&fbp->fb_feed[6], (p-fbp->fb_feed)-2-6); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol(fbp->fb_feed, p - fbp->fb_feed); #ifdef OS2 ReleaseTelnetMutex(); #endif break; } return(fbp->state[DIR_DECRYPT-1] = state); } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. */ int cfb64_reply(data, cnt) unsigned char *data; int cnt; { return(fb64_reply(data, cnt, &des_fb[CFB])); } int ofb64_reply(data, cnt) unsigned char *data; int cnt; { return(fb64_reply(data, cnt, &des_fb[OFB])); } int fb64_reply(data, cnt, fbp) unsigned char *data; int cnt; struct des_fb *fbp; { register int state = fbp->state[DIR_ENCRYPT-1]; if (cnt-- < 1) goto failure; switch (*data++) { case FB64_IV_OK: fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); if (state == xFAILED) state = IN_PROGRESS; state &= ~NO_RECV_IV; encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1); break; case FB64_IV_BAD: memset(fbp->temp_feed, 0, sizeof(Block)); fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); state = xFAILED; break; default: #if 0 if (encrypt_debug_mode) { printf("Unknown option type: %d\r\n", data[-1]); printf("\r\n"); } #endif /* FALL THROUGH */ failure: state = xFAILED; break; } return(fbp->state[DIR_ENCRYPT-1] = state); } int cfb64_session(key, server) Session_Key *key; int server; { return(fb64_session(key, server, &des_fb[CFB])); } int ofb64_session(key, server) Session_Key *key; int server; { return(fb64_session(key, server, &des_fb[OFB])); } static int fb64_session(key, server, fbp) Session_Key *key; int server; struct des_fb *fbp; { int rc=0; int use2keys; struct des_stinfo * s_stream; struct des_stinfo * c_stream; if(server) { s_stream = &fbp->streams[DIR_ENCRYPT-1]; c_stream = &fbp->streams[DIR_DECRYPT-1]; } else { s_stream = &fbp->streams[DIR_DECRYPT-1]; c_stream = &fbp->streams[DIR_ENCRYPT-1]; } if (!key || key->length < sizeof(Block)) { CHAR buf[80]; sprintf((char *)buf,"Can't set DES session key (%d < %d)", key ? key->length : 0, sizeof(Block)); /* safe */ #ifdef DEBUG if (encrypt_debug_mode) printf("%s\r\n",buf); #endif debug(F110,"fb64_session",buf,0); return(-1); } use2keys = (key->type == SK_DES || key->length < 2 * sizeof(Block)) ? 0 : 1; #ifdef MIT_CURRENT if(use2keys) { memcpy((void *) fbp->keybytes, (void *) (key->data + sizeof(Block)), sizeof(Block)); des_fixup_key_parity(fbp->); fb64_stream_key(fbp->krbdes_key, s_stream); } memcpy((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block)); if (key->type != SK_DES) des_fixup_key_parity(fbp->krbdes_key); if(!use2keys) fb64_stream_key(fbp->krbdes_key, s_stream); fb64_stream_key(fbp->krbdes_key, c_stream); fbp->validkey = 1; fb64_stream_key(key->data, &fbp->streams[DIR_ENCRYPT-1]); fb64_stream_key(key->data, &fbp->streams[DIR_DECRYPT-1]); #else /* MIT_CURRENT */ if(use2keys) { memcpy((void *) fbp->krbdes_key, (void *) (key->data + sizeof(Block)), sizeof(Block)); des_fixup_key_parity(fbp->krbdes_key); fb64_stream_key(fbp->krbdes_key, s_stream); } memcpy((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block)); if (key->type != SK_DES) des_fixup_key_parity(fbp->krbdes_key); if(!use2keys) fb64_stream_key(fbp->krbdes_key, s_stream); fb64_stream_key(fbp->krbdes_key, c_stream); if (fbp->once == 0) { des_set_random_generator_seed(fbp->krbdes_key); fbp->once = 1; } memset(fbp->krbdes_sched,0,sizeof(Schedule)); ckhexdump("fb64_session_key",fbp->krbdes_key,8); rc = des_key_sched(fbp->krbdes_key, fbp->krbdes_sched); if ( rc == -1 ) { printf("?Invalid DES key specified for encryption\n"); debug(F110,"fb64_session_key", "invalid DES Key specified for encryption",0); } else if ( rc == -2 ) { printf("?Weak DES key specified for encryption\n"); debug(F110,"fb64_session_key", "weak DES Key specified for encryption",0); } else if ( rc != 0 ) { printf("?Key Schedule not created by encryption\n"); debug(F110,"fb64_session_key", "Key Schedule not created by encryption",0); } ckhexdump("fb64_session_key schedule",fbp->krbdes_sched,8*16); #endif /* MIT_CURRENT */ /* * Now look to see if krbdes_start() was was waiting for * the key to show up. If so, go ahead an call it now * that we have the key. */ if (fbp->need_start) { fbp->need_start = 0; fb64_start(fbp, DIR_ENCRYPT, server); } return(0); } /* * We only accept a keyid of 0. If we get a keyid of * 0, then mark the state as SUCCESS. */ int cfb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(fb64_keyid(dir, kp, lenp, &des_fb[CFB])); } int ofb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(fb64_keyid(dir, kp, lenp, &des_fb[OFB])); } int fb64_keyid(dir, kp, lenp, fbp) int dir, *lenp; unsigned char *kp; struct des_fb *fbp; { register int state = fbp->state[dir-1]; if (*lenp != 1 || (*kp != '\0')) { *lenp = 0; return(state); } if (state == xFAILED) state = IN_PROGRESS; state &= ~NO_KEYID; return(fbp->state[dir-1] = state); } #if 0 void fb64_printsub(data, cnt, buf, buflen, type) unsigned char *data, *buf, *type; int cnt, buflen; { char lbuf[64]; register int i; char *cp; buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ buflen -= 1; switch(data[2]) { case FB64_IV: sprintf(lbuf, "%s_IV", type); cp = lbuf; goto common; case FB64_IV_OK: sprintf(lbuf, "%s_IV_OK", type); cp = lbuf; goto common; case FB64_IV_BAD: sprintf(lbuf, "%s_IV_BAD", type); cp = lbuf; goto common; case FB64_CHALLENGE: sprintf(lbuf, "%s_CHALLENGE", type); cp = lbuf; goto common; case FB64_RESPONSE: sprintf(lbuf, "%s_RESPONSE", type); cp = lbuf; goto common; default: sprintf(lbuf, " %d (unknown)", data[2]); cp = lbuf; common: for (; (buflen > 0) && (*buf = *cp++); buf++) buflen--; for (i = 3; i < cnt; i++) { sprintf(lbuf, " %d", data[i]); for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++) buflen--; } break; } } void cfb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { fb64_printsub(data, cnt, buf, buflen, "CFB64"); } void ofb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { fb64_printsub(data, cnt, buf, buflen, "OFB64"); } #endif void fb64_stream_iv(seed, stp) Block seed; register struct des_stinfo *stp; { int rc=0; memcpy(stp->str_iv, seed, sizeof(Block)); memcpy(stp->str_output, seed, sizeof(Block)); memset(stp->str_sched,0,sizeof(Schedule)); ckhexdump("fb64_stream_iv",stp->str_ikey,8); #ifndef MIT_CURRENT rc = des_key_sched(stp->str_ikey, stp->str_sched); if ( rc == -1 ) { printf("?Invalid DES key specified for encryption\r\n"); debug(F110,"fb64_stream_iv", "invalid DES Key specified for encryption",0); } else if ( rc == -2 ) { printf("?Weak DES key specified for encryption\r\n"); debug(F110,"fb64_stream_iv", "weak DES Key specified for encryption",0); } else if ( rc != 0 ) { printf("?Key Schedule not created by encryption\r\n"); debug(F110,"fb64_stream_iv", "Key Schedule not created by encryption",0); } ckhexdump("fb64_stream_iv schedule",stp->str_sched,8*16); #endif /* MIT_CURRENT */ stp->str_index = sizeof(Block); } void fb64_stream_key(key, stp) Block key; register struct des_stinfo *stp; { int rc = 0; #ifdef MIT_CURRENT memcpy(stp->str_keybytes, key, sizeof(Block)); stp->str_key.length = 8; stp->str_key.contents = stp->str_keybytes; /* the original version of this code uses des ecb mode, but it only ever does one block at a time. cbc with a zero iv is identical */ stp->str_key.enctype = ENCTYPE_DES_CBC_RAW; #else /* MIT_CURRENT */ memcpy(stp->str_ikey, key, sizeof(Block)); memset(stp->str_sched,0,sizeof(Schedule)); ckhexdump("fb64_stream_key",key,8); rc = des_key_sched(key, stp->str_sched); if ( rc == -1 ) { printf("?Invalid DES key specified for encryption\r\n"); debug(F110,"fb64_stream_key", "invalid DES Key specified for encryption",0); } else if ( rc == -2 ) { printf("?Weak DES key specified for encryption\r\n"); debug(F110,"fb64_stream_key", "weak DES Key specified for encryption",0); } else if ( rc != 0 ) { printf("?Key Schedule not created by encryption\r\n"); debug(F110,"fb64_stream_key", "Key Schedule not created by encryption",0); } ckhexdump("fb64_stream_key schedule",stp->str_sched,8*16); #endif /* MIT_CURRENT */ memcpy(stp->str_output, stp->str_iv, sizeof(Block)); stp->str_index = sizeof(Block); } /* * DES 64 bit Cipher Feedback * * key --->+-----+ * +->| DES |--+ * | +-----+ | * | v * INPUT --(--------->(+)+---> DATA * | | * +-------------+ * * * Given: * iV: Initial vector, 64 bits (8 bytes) long. * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. * * V0 = DES(iV, key) * On = Dn ^ Vn * V(n+1) = DES(On, key) */ void cfb64_encrypt(s, c) register unsigned char *s; int c; { register struct des_stinfo *stp = &des_fb[CFB].streams[DIR_ENCRYPT-1]; register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; #ifdef MIT_CURRENT ecb_encrypt(stp, stp->str_output, b); #else /* MIT_CURRENT */ des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1); #endif /* MIT_CURRENT */ memcpy(stp->str_feed,b,sizeof(Block)); index = 0; } /* On encryption, we store (feed ^ data) which is cypher */ *s = stp->str_output[index] = (stp->str_feed[index] ^ *s); s++; index++; } stp->str_index = index; } int cfb64_decrypt(data) int data; { register struct des_stinfo *stp = &des_fb[CFB].streams[DIR_DECRYPT-1]; int index; if (data == -1) { /* * Back up one byte. It is assumed that we will * never back up more than one byte. If we do, this * may or may not work. */ if (stp->str_index) --stp->str_index; return(0); } index = stp->str_index++; if (index == sizeof(Block)) { Block b; #ifdef MIT_CURRENT ecb_encrypt(stp, stp->str_output, b); #else /* MIT_CURRENT */ des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1); #endif /* MIT_CURRENT */ memcpy(stp->str_feed, b, sizeof(Block)); stp->str_index = 1; /* Next time will be 1 */ index = 0; /* But now use 0 */ } /* On decryption we store (data) which is cypher. */ stp->str_output[index] = data; return(data ^ stp->str_feed[index]); } /* * DES 64 bit Output Feedback * * key --->+-----+ * +->| DES |--+ * | +-----+ | * +-----------+ * v * INPUT -------->(+) ----> DATA * * Given: * iV: Initial vector, 64 bits (8 bytes) long. * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. * * V0 = DES(iV, key) * V(n+1) = DES(Vn, key) * On = Dn ^ Vn */ void ofb64_encrypt(s, c) register unsigned char *s; int c; { register struct des_stinfo *stp = &des_fb[OFB].streams[DIR_ENCRYPT-1]; register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; #ifdef MIT_CURRENT ecb_encrypt(stp, stp->str_feed, b); #else /* MIT_CURRENT */ des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1); #endif /* MIT_CURRENT */ memcpy(stp->str_feed,b,sizeof(Block)); index = 0; } *s++ ^= stp->str_feed[index]; index++; } stp->str_index = index; } int ofb64_decrypt(data) int data; { register struct des_stinfo *stp = &des_fb[OFB].streams[DIR_DECRYPT-1]; int index; if (data == -1) { /* * Back up one byte. It is assumed that we will * never back up more than one byte. If we do, this * may or may not work. */ if (stp->str_index) --stp->str_index; return(0); } index = stp->str_index++; if (index == sizeof(Block)) { Block b; #ifdef MIT_CURRENT ecb_encrypt(stp, stp->str_feed, b); #else /* MIT_CURRENT */ des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1); #endif /* MIT_CURRENT */ memcpy(stp->str_feed, b, sizeof(Block)); stp->str_index = 1; /* Next time will be 1 */ index = 0; /* But now use 0 */ } return(data ^ stp->str_feed[index]); } void des3_fb64_stream_iv P((Block, struct des3_stinfo *)); void des3_fb64_init P((struct des3_fb *)); static int des3_fb64_start P((struct des3_fb *, int, int)); int des3_fb64_is P((unsigned char *, int, struct des3_fb *)); int des3_fb64_reply P((unsigned char *, int, struct des3_fb *)); static int des3_fb64_session P((Session_Key *, int, struct des3_fb *)); void des3_fb64_stream_key P((Block *, struct des3_stinfo *)); int des3_fb64_keyid P((int, unsigned char *, int *, struct des3_fb *)); void des3_cfb64_init(server) int server; { des3_fb64_init(&des3_fb[CFB]); des3_fb[CFB].fb_feed[4] = ENCTYPE_DES3_CFB64; des3_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB); des3_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB); } void des3_ofb64_init(server) int server; { des3_fb64_init(&des3_fb[OFB]); des3_fb[OFB].fb_feed[4] = ENCTYPE_DES3_OFB64; des3_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB); des3_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB); } void des3_fb64_init(fbp) register struct des3_fb *fbp; { memset((void *)fbp, 0, sizeof(*fbp)); fbp->state[0] = fbp->state[1] = xFAILED; fbp->fb_feed[0] = IAC; fbp->fb_feed[1] = SB; fbp->fb_feed[2] = TELOPT_ENCRYPTION; fbp->fb_feed[3] = ENCRYPT_IS; } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. * 2: Not yet. Other things (like getting the key from * Kerberos) have to happen before we can continue. */ int des3_cfb64_start(dir, server) int dir; int server; { return(des3_fb64_start(&des3_fb[CFB], dir, server)); } int des3_ofb64_start(dir, server) int dir; int server; { return(des3_fb64_start(&des3_fb[OFB], dir, server)); } static int des3_fb64_start(fbp, dir, server) struct des3_fb *fbp; int dir; int server; { int x; unsigned char *p; register int state; switch (dir) { case DIR_DECRYPT: /* * This is simply a request to have the other side * start output (our input). He will negotiate an * IV so we need not look for it. */ state = fbp->state[dir-1]; if (state == xFAILED) state = IN_PROGRESS; break; case DIR_ENCRYPT: state = fbp->state[dir-1]; if (state == xFAILED) state = IN_PROGRESS; else if ((state & NO_SEND_IV) == 0) break; if (!VALIDKEY(fbp->krbdes_key[0]) || !VALIDKEY(fbp->krbdes_key[1]) || !VALIDKEY(fbp->krbdes_key[2]) ) { fbp->need_start = 1; break; } state &= ~NO_SEND_IV; state |= NO_RECV_IV; /* * Create a random feed and send it over. */ des_new_random_key(fbp->temp_feed); #ifdef LIBDES des_ecb3_encrypt(fbp->temp_feed, fbp->temp_feed, fbp->krbdes_sched[0], fbp->krbdes_sched[1], fbp->krbdes_sched[2], 1); #else /* LIBDES */ des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed, fbp->krbdes_sched[0], 1); des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed, fbp->krbdes_sched[1], 0); des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed, fbp->krbdes_sched[2], 1); #endif /* LIBDES */ p = fbp->fb_feed + 3; *p++ = ENCRYPT_IS; p++; *p++ = FB64_IV; for (x = 0; x < sizeof(Block); ++x) { if (( *p++ = fbp->temp_feed[x]) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; if (deblog || tn_deb || debses) { int i; sprintf(tn_msg, "TELNET SENT SB %s IS %s FB64_IV ", TELOPT(fbp->fb_feed[2]), enctype_names[fbp->fb_feed[4]]); /* safe */ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&fbp->fb_feed[6], (p-fbp->fb_feed)-2-6); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol(fbp->fb_feed, p - fbp->fb_feed); #ifdef OS2 ReleaseTelnetMutex(); #endif break; default: return(xFAILED); } return(fbp->state[dir-1] = state); } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. */ int des3_cfb64_is(data, cnt) unsigned char *data; int cnt; { return(des3_fb64_is(data, cnt, &des3_fb[CFB])); } int des3_ofb64_is(data, cnt) unsigned char *data; int cnt; { return(des3_fb64_is(data, cnt, &des3_fb[OFB])); } int des3_fb64_is(data, cnt, fbp) unsigned char *data; int cnt; struct des3_fb *fbp; { unsigned char *p; register int state = fbp->state[DIR_DECRYPT-1]; if (cnt-- < 1) goto failure; #ifdef CK_SSL if (!TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) #endif /* CK_SSL */ switch (*data++) { case FB64_IV: if (cnt != sizeof(Block)) { #ifdef DEBUG if (encrypt_debug_mode) printf("DES3_FB64: initial vector failed on size\r\n"); #endif state = xFAILED; goto failure; } #ifdef DEBUG if (encrypt_debug_mode) { printf("DES3_FB64: initial vector received\r\n"); printf("Initializing Decrypt stream\r\n"); } #endif des3_fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]); p = fbp->fb_feed + 3; *p++ = ENCRYPT_REPLY; p++; *p++ = FB64_IV_OK; *p++ = IAC; *p++ = SE; if (deblog || tn_deb || debses) { int i; sprintf(tn_msg, "TELNET SENT SB %s REPLY %s FB64_IV_OK ", TELOPT(fbp->fb_feed[2]), enctype_names[fbp->fb_feed[4]]); /* safe */ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&fbp->fb_feed[6], (p-fbp->fb_feed)-2-6); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol(fbp->fb_feed, p - fbp->fb_feed); #ifdef OS2 ReleaseTelnetMutex(); #endif state = IN_PROGRESS; break; default: #if 0 if (encrypt_debug_mode) { printf("Unknown option type: %d\r\n", *(data-1)); printf("\r\n"); } #endif /* FALL THROUGH */ failure: /* * We failed. Send an FB64_IV_BAD option * to the other side so it will know that * things failed. */ p = fbp->fb_feed + 3; *p++ = ENCRYPT_REPLY; p++; *p++ = FB64_IV_BAD; *p++ = IAC; *p++ = SE; if (deblog || tn_deb || debses) { int i; sprintf(tn_msg, "TELNET SENT SB %s REPLY %s FB64_IV_BAD ", TELOPT(fbp->fb_feed[2]), enctype_names[fbp->fb_feed[4]]); /* safe */ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&fbp->fb_feed[6], (p-fbp->fb_feed)-2-6); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol(fbp->fb_feed, p - fbp->fb_feed); #ifdef OS2 ReleaseTelnetMutex(); #endif break; } return(fbp->state[DIR_DECRYPT-1] = state); } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. */ int des3_cfb64_reply(data, cnt) unsigned char *data; int cnt; { return(des3_fb64_reply(data, cnt, &des3_fb[CFB])); } int des3_ofb64_reply(data, cnt) unsigned char *data; int cnt; { return(des3_fb64_reply(data, cnt, &des3_fb[OFB])); } int des3_fb64_reply(data, cnt, fbp) unsigned char *data; int cnt; struct des3_fb *fbp; { register int state = fbp->state[DIR_ENCRYPT-1]; if (cnt-- < 1) goto failure; switch (*data++) { case FB64_IV_OK: des3_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); if (state == xFAILED) state = IN_PROGRESS; state &= ~NO_RECV_IV; encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1); break; case FB64_IV_BAD: memset(fbp->temp_feed, 0, sizeof(Block)); des3_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); state = xFAILED; break; default: #if 0 if (encrypt_debug_mode) { printf("Unknown option type: %d\r\n", data[-1]); printf("\r\n"); } #endif /* FALL THROUGH */ failure: state = xFAILED; break; } return(fbp->state[DIR_ENCRYPT-1] = state); } int des3_cfb64_session(key, server) Session_Key *key; int server; { return(des3_fb64_session(key, server, &des3_fb[CFB])); } int des3_ofb64_session(key, server) Session_Key *key; int server; { return(des3_fb64_session(key, server, &des3_fb[OFB])); } static int des3_fb64_session(key, server, fbp) Session_Key *key; int server; struct des3_fb *fbp; { int rc=0,i=0; int keys2use=0; struct des3_stinfo * s_stream; struct des3_stinfo * c_stream; if(server) { s_stream = &fbp->streams[DIR_ENCRYPT-1]; c_stream = &fbp->streams[DIR_DECRYPT-1]; } else { s_stream = &fbp->streams[DIR_DECRYPT-1]; c_stream = &fbp->streams[DIR_ENCRYPT-1]; } keys2use = key->length / sizeof(Block); if (!key || (key->type == SK_DES) || (keys2use < 2)) { CHAR buf[80]; sprintf((char *)buf,"Can't set 3DES session key (%d < %d)", key ? key->length : 0, 2 * (int)sizeof(Block)); /* safe */ #ifdef DEBUG if (encrypt_debug_mode) printf("%s\r\n",buf); #endif debug(F110,"des3_fb64_session",buf,0); return(-1); } debug(F111,"des3_fb64_session","keys2use",keys2use); /* Compute the first set of keys / key order */ switch ( keys2use ) { case 2: memcpy((void *)fbp->krbdes_key[0], (void *)key->data, sizeof(Block)); memcpy((void *) fbp->krbdes_key[1],(void *)(key->data + sizeof(Block)), sizeof(Block)); memcpy((void *)fbp->krbdes_key[2], (void *)key->data, sizeof(Block)); break; case 3: default: memcpy((void *)fbp->krbdes_key[0], (void *)key->data, sizeof(Block)); memcpy((void *) fbp->krbdes_key[1],(void *)(key->data + sizeof(Block)), sizeof(Block)); memcpy((void *) fbp->krbdes_key[2], (void *) (key->data + 2*sizeof(Block)), sizeof(Block)); break; } ckhexdump("des3_session_key key->data",key->data,sizeof(Block)); ckhexdump("des3_session_key fbp->krbdes_key[0]", fbp->krbdes_key[0], sizeof(Block) ); if (fbp->once == 0) { des_set_random_generator_seed(fbp->krbdes_key[0]); fbp->once = 1; } for ( i=0;i<3;i++ ) des_fixup_key_parity(fbp->krbdes_key[i]); des3_fb64_stream_key(fbp->krbdes_key, s_stream); /* Compute the second set of keys / key order */ switch ( keys2use ) { case 2: memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)), sizeof(Block)); memcpy((void *)fbp->krbdes_key[1], (void *)key->data, sizeof(Block)); memcpy((void *) fbp->krbdes_key[2],(void *)(key->data + sizeof(Block)), sizeof(Block)); break; case 3: memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)), sizeof(Block)); memcpy((void *) fbp->krbdes_key[1], (void *) (key->data + 2*sizeof(Block)), sizeof(Block)); memcpy((void *)fbp->krbdes_key[2], (void *)key->data, sizeof(Block)); break; case 4: memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)), sizeof(Block)); memcpy((void *) fbp->krbdes_key[1], (void *) (key->data + 3*sizeof(Block)), sizeof(Block)); memcpy((void *)fbp->krbdes_key[2], (void *)key->data, sizeof(Block)); break; case 5: memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)), sizeof(Block)); memcpy((void *) fbp->krbdes_key[1], (void *) (key->data + 3*sizeof(Block)), sizeof(Block)); memcpy((void *)fbp->krbdes_key[2], (void *)(key->data + 4*sizeof(Block)), sizeof(Block)); break; case 6: memcpy((void *) fbp->krbdes_key[0], (void *) (key->data + 3*sizeof(Block)), sizeof(Block)); memcpy((void *)fbp->krbdes_key[1], (void *)(key->data + 4*sizeof(Block)), sizeof(Block)); memcpy((void *) fbp->krbdes_key[2], (void *) (key->data + 5 *sizeof(Block)), sizeof(Block)); break; } for ( i=0;i<3;i++ ) des_fixup_key_parity(fbp->krbdes_key[i]); des3_fb64_stream_key(fbp->krbdes_key, c_stream); /* now use the second set of keys to build the default Key Schedule */ /* which is used for generating the IV. */ for ( i=0;i<3;i++ ) { memset(fbp->krbdes_sched[i],0,sizeof(Schedule)); rc = des_key_sched(fbp->krbdes_key[i], fbp->krbdes_sched[i]); if ( rc == -1 ) { printf("?Invalid DES key specified for encryption [DES3,%s]\r\n", server?"server":"client"); debug(F110,"des3_fb64_stream_iv", "invalid DES Key specified for encryption",0); } else if ( rc == -2 ) { printf("?Weak DES key specified for encryption\r\n"); debug(F110,"des3_fb64_stream_iv", "weak DES Key specified for encryption",0); } else if ( rc != 0 ) { printf("?Key Schedule not created by encryption\r\n"); debug(F110,"des3_fb64_stream_iv", "Key Schedule not created by encryption",0); } ckhexdump("des3_fb64_session_key schedule",fbp->krbdes_sched[i],8*16); } /* * Now look to see if krbdes_start() was was waiting for * the key to show up. If so, go ahead an call it now * that we have the key. */ if (fbp->need_start) { fbp->need_start = 0; des3_fb64_start(fbp, DIR_ENCRYPT, server); } return(0); } /* * We only accept a keyid of 0. If we get a keyid of * 0, then mark the state as SUCCESS. */ int des3_cfb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(des3_fb64_keyid(dir, kp, lenp, &des3_fb[CFB])); } int des3_ofb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(des3_fb64_keyid(dir, kp, lenp, &des3_fb[OFB])); } int des3_fb64_keyid(dir, kp, lenp, fbp) int dir, *lenp; unsigned char *kp; struct des3_fb *fbp; { register int state = fbp->state[dir-1]; if (*lenp != 1 || (*kp != '\0')) { *lenp = 0; return(state); } if (state == xFAILED) state = IN_PROGRESS; state &= ~NO_KEYID; return(fbp->state[dir-1] = state); } #if 0 void des3_fb64_printsub(data, cnt, buf, buflen, type) unsigned char *data, *buf, *type; int cnt, buflen; { char lbuf[64]; register int i; char *cp; buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ buflen -= 1; switch(data[2]) { case FB64_IV: sprintf(lbuf, "%s_IV", type); cp = lbuf; goto common; case FB64_IV_OK: sprintf(lbuf, "%s_IV_OK", type); cp = lbuf; goto common; case FB64_IV_BAD: sprintf(lbuf, "%s_IV_BAD", type); cp = lbuf; goto common; case FB64_CHALLENGE: sprintf(lbuf, "%s_CHALLENGE", type); cp = lbuf; goto common; case FB64_RESPONSE: sprintf(lbuf, "%s_RESPONSE", type); cp = lbuf; goto common; default: sprintf(lbuf, " %d (unknown)", data[2]); cp = lbuf; common: for (; (buflen > 0) && (*buf = *cp++); buf++) buflen--; for (i = 3; i < cnt; i++) { sprintf(lbuf, " %d", data[i]); for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++) buflen--; } break; } } void des3_cfb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { des3_fb64_printsub(data, cnt, buf, buflen, "CFB64"); } void des3_ofb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { des3_fb64_printsub(data, cnt, buf, buflen, "OFB64"); } #endif void des3_fb64_stream_iv(seed, stp) Block seed; register struct des3_stinfo *stp; { int rc=0, i = 0;; memcpy(stp->str_iv, seed, sizeof(Block)); memcpy(stp->str_output, seed, sizeof(Block)); for ( i=0;i<3;i++ ) { memset(stp->str_sched[i],0,sizeof(Schedule)); ckhexdump("des3_fb64_stream_iv",stp->str_ikey[i],8); rc = des_key_sched(stp->str_ikey[i], stp->str_sched[i]); if ( rc == -1 ) { printf("?Invalid DES key specified for encryption [DES3 iv]\r\n"); debug(F110,"des3_fb64_stream_iv", "invalid DES Key specified for encryption",0); } else if ( rc == -2 ) { printf("?Weak DES key specified for encryption\r\n"); debug(F110,"des3_fb64_stream_iv", "weak DES Key specified for encryption",0); } else if ( rc != 0 ) { printf("?Key Schedule not created by encryption\r\n"); debug(F110,"des3_fb64_stream_iv", "Key Schedule not created by encryption",0); } ckhexdump("des3_fb64_stream_iv schedule",stp->str_sched[i],8*16); } stp->str_index = sizeof(Block); } void des3_fb64_stream_key(key, stp) Block * key; register struct des3_stinfo *stp; { int rc = 0, i = 0; for ( i=0;i<3;i++ ) { memcpy(stp->str_ikey[i], key[i], sizeof(Block)); memset(stp->str_sched[i],0,sizeof(Schedule)); ckhexdump("des3_fb64_stream_key",key[i],8); rc = des_key_sched(key[i], stp->str_sched[i]); if ( rc == -1 ) { printf("?Invalid DES key specified for encryption [DES3 key]\r\n"); debug(F110,"des3_fb64_stream_key", "invalid DES Key specified for encryption",0); } else if ( rc == -2 ) { printf("?Weak DES key specified for encryption\r\n"); debug(F110,"des3_fb64_stream_key", "weak DES Key specified for encryption",0); } else if ( rc != 0 ) { printf("?Key Schedule not created by encryption\r\n"); debug(F110,"des3_fb64_stream_key", "Key Schedule not created by encryption",0); } ckhexdump("des3_fb64_stream_key schedule",stp->str_sched[i],8*16); } memcpy(stp->str_output, stp->str_iv, sizeof(Block)); stp->str_index = sizeof(Block); } /* * DES3 64 bit Cipher Feedback * * key1 key2 key3 * | | | * v v v * +-------+ +-------+ +-------+ * +->| DES-e |->| DES-d |->| DES-e |-- + * | +-------+ +-------+ +-------+ | * | v * INPUT --(-------------------------------->(+)+---> DATA * | | * +------------------------------------+ * * * Given: * iV: Initial vector, 64 bits (8 bytes) long. * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. * * V0 = DES-e(DES-d(DES-e(iV, key1),key2),key3) * On = Dn ^ Vn * V(n+1) = DES-e(DES-d(DES-e(On, key1),key2),key3) */ void des3_cfb64_encrypt(s, c) register unsigned char *s; int c; { register struct des3_stinfo *stp = &des3_fb[CFB].streams[DIR_ENCRYPT-1]; register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; #ifdef LIBDES des_ecb3_encrypt(stp->str_output, b, stp->str_sched[0], stp->str_sched[1], stp->str_sched[2], 1); #else /* LIBDES */ des_ecb_encrypt(stp->str_output, b, stp->str_sched[0], 1); des_ecb_encrypt(stp->str_output, b, stp->str_sched[1], 0); des_ecb_encrypt(stp->str_output, b, stp->str_sched[2], 1); #endif /* LIBDES */ memcpy(stp->str_feed,b,sizeof(Block)); index = 0; } /* On encryption, we store (feed ^ data) which is cypher */ *s = stp->str_output[index] = (stp->str_feed[index] ^ *s); s++; index++; } stp->str_index = index; } int des3_cfb64_decrypt(data) int data; { register struct des3_stinfo *stp = &des3_fb[CFB].streams[DIR_DECRYPT-1]; int index; if (data == -1) { /* * Back up one byte. It is assumed that we will * never back up more than one byte. If we do, this * may or may not work. */ if (stp->str_index) --stp->str_index; return(0); } index = stp->str_index++; if (index == sizeof(Block)) { Block b; #ifdef LIBDES des_ecb3_encrypt(stp->str_output, b, stp->str_sched[0], stp->str_sched[1], stp->str_sched[2], 1); #else /* LIBDES */ des_ecb_encrypt(stp->str_output, b, stp->str_sched[0], 1); des_ecb_encrypt(stp->str_output, b, stp->str_sched[1], 0); des_ecb_encrypt(stp->str_output, b, stp->str_sched[2], 1); #endif /* LIBDES */ memcpy(stp->str_feed, b, sizeof(Block)); stp->str_index = 1; /* Next time will be 1 */ index = 0; /* But now use 0 */ } /* On decryption we store (data) which is cypher. */ stp->str_output[index] = data; return(data ^ stp->str_feed[index]); } /* * DES3 64 bit Output Feedback * * * key1 key2 key3 * | | | * v v v * +-------+ +-------+ +-------+ * +->| DES-e |->| DES-d |->| DES-e |-- + * | +-------+ +-------+ +-------+ | * +------------------------------------+ * v * INPUT ------------------------------------->(+) ----> DATA * * Given: * iV: Initial vector, 64 bits (8 bytes) long. * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. * * V0 = DES-e(DES-d(DES-e(iV, key1),key2),key3) * V(n+1) = DES-e(DES-d(DES-e(Vn, key1),key2),key3) * On = Dn ^ Vn */ void des3_ofb64_encrypt(s, c) register unsigned char *s; int c; { register struct des3_stinfo *stp = &des3_fb[OFB].streams[DIR_ENCRYPT-1]; register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; #ifdef LIBDES des_ecb3_encrypt(stp->str_feed, b, stp->str_sched[0], stp->str_sched[1], stp->str_sched[2], 1); #else /* LIBDES */ des_ecb_encrypt(stp->str_output, b, stp->str_sched[0], 1); des_ecb_encrypt(stp->str_output, b, stp->str_sched[1], 0); des_ecb_encrypt(stp->str_output, b, stp->str_sched[2], 1); #endif /* LIBDES */ memcpy(stp->str_feed,b,sizeof(Block)); index = 0; } *s++ ^= stp->str_feed[index]; index++; } stp->str_index = index; } int des3_ofb64_decrypt(data) int data; { register struct des3_stinfo *stp = &des3_fb[OFB].streams[DIR_DECRYPT-1]; int index; if (data == -1) { /* * Back up one byte. It is assumed that we will * never back up more than one byte. If we do, this * may or may not work. */ if (stp->str_index) --stp->str_index; return(0); } index = stp->str_index++; if (index == sizeof(Block)) { Block b; #ifdef LIBDES des_ecb3_encrypt(stp->str_feed, b, stp->str_sched[0], stp->str_sched[1], stp->str_sched[2], 1); #else /* LIBDES */ des_ecb_encrypt(stp->str_output, b, stp->str_sched[0], 1); des_ecb_encrypt(stp->str_output, b, stp->str_sched[1], 0); des_ecb_encrypt(stp->str_output, b, stp->str_sched[2], 1); #endif /* LIBDES */ memcpy(stp->str_feed, b, sizeof(Block)); stp->str_index = 1; /* Next time will be 1 */ index = 0; /* But now use 0 */ } return(data ^ stp->str_feed[index]); } #endif /* CK_DES */ #ifdef CK_CAST /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright (c) 1997 Stanford University * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that the above copyright notices and this permission notice appear in * all copies of the software and related documentation. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #ifdef __STDC__ #include #endif #include "ckcfnp.h" /* Prototypes */ /* * cast.h * Author: Tom Wu * * Type and function declarations for CAST. */ #ifndef _CAST_H_ #define _CAST_H_ #ifndef P #ifdef __STDC__ #define P(x) x #else #define P(x) () #endif /* __STDC__ */ #endif /* P */ #ifndef LITTLE_ENDIAN #ifndef BIG_ENDIAN #ifndef WORDS_BIGENDIAN #define LITTLE_ENDIAN 1 #endif /* WORDS_BIGENDIAN */ #endif /* BIG_ENDIAN */ #endif /* LITTLE_ENDIAN */ typedef unsigned int uint32; /* Must be 32 bits */ typedef uint32 * uint32p; typedef unsigned char uint8; typedef uint8 * uint8p; typedef struct { struct CastSubkeyPair { uint32 Km; uint32 Kr; } K[16]; int ksize; } CastKeySched; /* * cast*_key_sched(schedule, key) * * Initializes the CAST key schedule "schedule" according to the given key. * The different setup routines accept different length keys: * * ck_cast5_40_key_sched: 40-bit/5-byte (12 round) keys * ck_cast5_64_key_sched: 64-bit/8-byte (12 round) keys * ck_cast5_80_key_sched: 80-bit/10-byte (12 round) keys * ck_cast128_key_sched: 128-bit/16-byte (16 round) keys */ extern void ck_cast5_40_key_sched P((CastKeySched *, uint8 *)); extern void ck_cast5_64_key_sched P((CastKeySched *, uint8 *)); extern void ck_cast5_80_key_sched P((CastKeySched *, uint8 *)); extern void ck_cast128_key_sched P((CastKeySched *, uint8 *)); /* * ck_cast_ecb_encrypt(output, input, schedule, mode) * ck_cast_ecb_crypt(data, schedule, mode) * * Encrypts the 64-bit "input" according to the CAST key schedule * "schedule" and places the result in "output". If "mode" is 0, * ck_cast_ecb_encrypt will encrypt, otherwise it will decrypt. * "Output" and "input" can point to the same memory, in which case * en/decryption will be performed in place. * * ck_cast_ecb_crypt accepts input in the form of an array of two * 32-bit words and performs encryption/decryption in place. */ extern void ck_cast_ecb_encrypt P((uint8 *, uint8 *, CastKeySched *, int)); extern void ck_cast_ecb_crypt P((uint32 *, CastKeySched *, int)); #endif /* CAST_H */ #define CFB_40 0 #define OFB_40 1 #ifdef CAST_EXPORT_ENCRYPTION #define FB_CNT 2 #else #define CFB_128 2 #define OFB_128 3 #define FB_CNT 4 #endif #define NO_SEND_IV 1 #define NO_RECV_IV 2 #define NO_KEYID 4 #define IN_PROGRESS (NO_SEND_IV|NO_RECV_IV|NO_KEYID) #define SUCCESS 0 #define cFAILED -1 struct cast_fb { Block temp_feed; unsigned char fb_feed[64]; int key_isset; int need_start; int state[2]; struct cast_stinfo { Block str_output; Block str_feed; Block str_iv; CastKeySched str_sched; int str_index; } streams[2]; }; static struct cast_fb cast_fb[FB_CNT]; #define FB64_IV 1 #define FB64_IV_OK 2 #define FB64_IV_BAD 3 static void cast_fb64_stream_iv P((Block, struct cast_stinfo *)); static void cast_fb64_init P((struct cast_fb *)); static int cast_fb64_start P((struct cast_fb *, int, int)); static int cast_fb64_is P((unsigned char *, int, struct cast_fb *)); static int cast_fb64_reply P((unsigned char *, int, struct cast_fb *)); static int cast_fb64_session P((Session_Key *, int, struct cast_fb *, int)); static void cast_fb64_stream_key P((Block, struct cast_stinfo *, int)); static int cast_fb64_keyid P((int, unsigned char *, int *, struct cast_fb *)); static void _cast_cfb64_encrypt P((unsigned char *,int, struct cast_stinfo *)); static int _cast_cfb64_decrypt P((int, struct cast_stinfo *)); static void _cast_ofb64_encrypt P((unsigned char *,int, struct cast_stinfo *)); static int _cast_ofb64_decrypt P((int, struct cast_stinfo *)); #ifndef CAST_EXPORT_ENCRYPTION void cast_cfb64_init(server) int server; { cast_fb64_init(&cast_fb[CFB_128]); cast_fb[CFB_128].fb_feed[4] = ENCTYPE_CAST128_CFB64; } void cast_ofb64_init(server) int server; { cast_fb64_init(&cast_fb[OFB_128]); cast_fb[OFB_128].fb_feed[4] = ENCTYPE_CAST128_OFB64; } #endif void castexp_cfb64_init(server) int server; { cast_fb64_init(&cast_fb[CFB_40]); cast_fb[CFB_40].fb_feed[4] = ENCTYPE_CAST5_40_CFB64; } void castexp_ofb64_init(server) int server; { cast_fb64_init(&cast_fb[OFB_40]); cast_fb[OFB_40].fb_feed[4] = ENCTYPE_CAST5_40_OFB64; } static void cast_fb64_init(fbp) register struct cast_fb *fbp; { memset((void *)fbp, 0, sizeof(*fbp)); fbp->key_isset = 0; fbp->state[0] = fbp->state[1] = cFAILED; fbp->fb_feed[0] = IAC; fbp->fb_feed[1] = SB; fbp->fb_feed[2] = TELOPT_ENCRYPTION; fbp->fb_feed[3] = ENCRYPT_IS; } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. * 2: Not yet. Other things (like getting the key from * Kerberos) have to happen before we can continue. */ #ifndef CAST_EXPORT_ENCRYPTION int cast_cfb64_start(dir, server) int dir; int server; { return(cast_fb64_start(&cast_fb[CFB_128], dir, server)); } int cast_ofb64_start(dir, server) int dir; int server; { return(cast_fb64_start(&cast_fb[OFB_128], dir, server)); } #endif int castexp_cfb64_start(dir, server) int dir; int server; { return(cast_fb64_start(&cast_fb[CFB_40], dir, server)); } int castexp_ofb64_start(dir, server) int dir; int server; { return(cast_fb64_start(&cast_fb[OFB_40], dir, server)); } static int cast_fb64_start(fbp, dir, server) struct cast_fb *fbp; int dir; int server; { Block b; int x; unsigned char *p; register int state; switch (dir) { case DIR_DECRYPT: /* * This is simply a request to have the other side * start output (our input). He will negotiate an * IV so we need not look for it. */ state = fbp->state[dir-1]; if (state == cFAILED) state = IN_PROGRESS; break; case DIR_ENCRYPT: state = fbp->state[dir-1]; if (state == cFAILED) state = IN_PROGRESS; else if ((state & NO_SEND_IV) == 0) break; if (!fbp->key_isset) { fbp->need_start = 1; break; } state &= ~NO_SEND_IV; state |= NO_RECV_IV; #ifdef DEBUG if (encrypt_debug_mode) printf("Creating new feed\r\n"); #endif /* * Create a random feed and send it over. */ ck_cast_ecb_encrypt(fbp->temp_feed, fbp->temp_feed, &fbp->streams[dir-1].str_sched, 0); p = fbp->fb_feed + 3; *p++ = ENCRYPT_IS; p++; *p++ = FB64_IV; for (x = 0; x < sizeof(Block); ++x) { if ((*p++ = fbp->temp_feed[x]) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; ttol(fbp->fb_feed, p - fbp->fb_feed); break; default: return(cFAILED); } return(fbp->state[dir-1] = state); } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. */ #ifndef CAST_EXPORT_ENCRYPTION int cast_cfb64_is(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_is(data, cnt, &cast_fb[CFB_128])); } int cast_ofb64_is(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_is(data, cnt, &cast_fb[OFB_128])); } #endif int castexp_cfb64_is(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_is(data, cnt, &cast_fb[CFB_40])); } int castexp_ofb64_is(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_is(data, cnt, &cast_fb[OFB_40])); } static int cast_fb64_is(data, cnt, fbp) unsigned char *data; int cnt; struct cast_fb *fbp; { int x; unsigned char *p; Block b; register int state = fbp->state[DIR_DECRYPT-1]; if (cnt-- < 1) goto failure; #ifdef CK_SSL if (!TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) #endif /* CK_SSL */ switch (*data++) { case FB64_IV: if (cnt != sizeof(Block)) { #ifdef DEBUG if (encrypt_debug_mode) printf("FB64: initial vector failed on size\r\n"); #endif state = cFAILED; goto failure; } #ifdef DEBUG if (encrypt_debug_mode) printf("FB64: initial vector received\r\n"); if (encrypt_debug_mode) printf("Initializing Decrypt stream\r\n"); #endif cast_fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]); p = fbp->fb_feed + 3; *p++ = ENCRYPT_REPLY; p++; *p++ = FB64_IV_OK; *p++ = IAC; *p++ = SE; ttol(fbp->fb_feed, p - fbp->fb_feed); state = IN_PROGRESS; break; default: /* unknown option type */ /* FALL THROUGH */ failure: /* * We failed. Send an FB64_IV_BAD option * to the other side so it will know that * things failed. */ p = fbp->fb_feed + 3; *p++ = ENCRYPT_REPLY; p++; *p++ = FB64_IV_BAD; *p++ = IAC; *p++ = SE; ttol(fbp->fb_feed, p - fbp->fb_feed); break; } return(fbp->state[DIR_DECRYPT-1] = state); } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. */ #ifndef CAST_EXPORT_ENCRYPTION int cast_cfb64_reply(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_reply(data, cnt, &cast_fb[CFB_128])); } int cast_ofb64_reply(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_reply(data, cnt, &cast_fb[OFB_128])); } #endif int castexp_cfb64_reply(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_reply(data, cnt, &cast_fb[CFB_40])); } int castexp_ofb64_reply(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_reply(data, cnt, &cast_fb[OFB_40])); } static int cast_fb64_reply(data, cnt, fbp) unsigned char *data; int cnt; struct cast_fb *fbp; { int x; unsigned char *p; Block b; register int state = fbp->state[DIR_ENCRYPT-1]; if (cnt-- < 1) goto failure; switch (*data++) { case FB64_IV_OK: cast_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); if (state == cFAILED) state = IN_PROGRESS; state &= ~NO_RECV_IV; encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1); break; case FB64_IV_BAD: memset(fbp->temp_feed, 0, sizeof(Block)); cast_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); state = cFAILED; break; default: #if 0 if (encrypt_debug_mode) { printf("Unknown option type: %d\r\n", data[-1]); printd(data, cnt); printf("\r\n"); } #endif /* FALL THROUGH */ failure: state = cFAILED; break; } return(fbp->state[DIR_ENCRYPT-1] = state); } #ifndef CAST_EXPORT_ENCRYPTION int cast_cfb64_session(key, server) Session_Key *key; int server; { return(cast_fb64_session(key, server, &cast_fb[CFB_128], 1)); } int cast_ofb64_session(key, server) Session_Key *key; int server; { return(cast_fb64_session(key, server, &cast_fb[OFB_128], 1)); } #endif int castexp_cfb64_session(key, server) Session_Key *key; int server; { return(cast_fb64_session(key, server, &cast_fb[CFB_40], 0)); } int castexp_ofb64_session(key, server) Session_Key *key; int server; { return(cast_fb64_session(key, server, &cast_fb[OFB_40], 0)); } #define CAST128_KEYLEN 16 /* 128 bits */ #define CAST5_40_KEYLEN 5 /* 40 bits */ static int cast_fb64_session(key, server, fbp, fs) Session_Key *key; int server; struct cast_fb *fbp; int fs; { int klen; unsigned char * kptr; if(fs) klen = CAST128_KEYLEN; else klen = CAST5_40_KEYLEN; if (!key || key->length < klen) { CHAR buf[80]; sprintf((char *)buf,"Can't set CAST session key (%d < %d)", key ? key->length : 0, klen); /* safe */ #ifdef DEBUG if (encrypt_debug_mode) printf("%s\r\n",buf); #endif debug(F110,"cast_fb64_session",buf,0); return(cFAILED); } if(key->length < 2 * klen) kptr = key->data; else kptr = key->data + klen; if(server) { cast_fb64_stream_key(kptr, &fbp->streams[DIR_ENCRYPT-1], fs); cast_fb64_stream_key(key->data, &fbp->streams[DIR_DECRYPT-1], fs); } else { cast_fb64_stream_key(kptr, &fbp->streams[DIR_DECRYPT-1], fs); cast_fb64_stream_key(key->data, &fbp->streams[DIR_ENCRYPT-1], fs); } /* Stuff leftovers into the feed */ if(key->length >= 2 * klen + sizeof(Block)) memcpy(fbp->temp_feed, key->data + 2 * klen, sizeof(Block)); else { #ifdef COMMENT /* This is a better way of erasing the password */ /* but we do not want to link in libsrp */ t_random(fbp->temp_feed, sizeof(Block)); #else memset(fbp->temp_feed, 0, sizeof(Block)); #endif } fbp->key_isset = 1; /* * Now look to see if cast_fb64_start() was was waiting for * the key to show up. If so, go ahead an call it now * that we have the key. */ if (fbp->need_start) { fbp->need_start = 0; cast_fb64_start(fbp, DIR_ENCRYPT, server); } return(0); } /* * We only accept a keyid of 0. If we get a keyid of * 0, then mark the state as SUCCESS. */ #ifndef CAST_EXPORT_ENCRYPTION int cast_cfb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[CFB_128])); } int cast_ofb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[OFB_128])); } #endif int castexp_cfb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[CFB_40])); } int castexp_ofb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[OFB_40])); } static int cast_fb64_keyid(dir, kp, lenp, fbp) int dir, *lenp; unsigned char *kp; struct cast_fb *fbp; { register int state = fbp->state[dir-1]; if (*lenp != 1 || (*kp != '\0')) { *lenp = 0; return(state); } if (state == cFAILED) state = IN_PROGRESS; state &= ~NO_KEYID; return(fbp->state[dir-1] = state); } static void cast_fb64_printsub(data, cnt, buf, buflen, type) unsigned char *data, *buf, *type; int cnt, buflen; { char lbuf[64]; register int i; char *cp; buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ buflen -= 1; switch(data[2]) { case FB64_IV: sprintf(lbuf, "%s_IV", type); cp = lbuf; goto common; case FB64_IV_OK: sprintf(lbuf, "%s_IV_OK", type); cp = lbuf; goto common; case FB64_IV_BAD: sprintf(lbuf, "%s_IV_BAD", type); cp = lbuf; goto common; default: sprintf(lbuf, " %d (unknown)", data[2]); cp = lbuf; common: for (; (buflen > 0) && (*buf = *cp++); buf++) buflen--; for (i = 3; i < cnt; i++) { sprintf(lbuf, " %d", data[i]); for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++) buflen--; } break; } } void cast_cfb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { cast_fb64_printsub(data, cnt, buf, buflen, "CFB64"); } void cast_ofb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { cast_fb64_printsub(data, cnt, buf, buflen, "OFB64"); } static void cast_fb64_stream_iv(seed, stp) Block seed; register struct cast_stinfo *stp; { memcpy((void *)stp->str_iv, (void *)seed, sizeof(Block)); memcpy((void *)stp->str_output, (void *)seed, sizeof(Block)); stp->str_index = sizeof(Block); } static void cast_fb64_stream_key(key, stp, fs) unsigned char * key; register struct cast_stinfo *stp; int fs; { #ifndef CAST_EXPORT_ENCRYPTION if(fs) ck_cast128_key_sched(&stp->str_sched, key); else #endif ck_cast5_40_key_sched(&stp->str_sched, key); memcpy((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block)); stp->str_index = sizeof(Block); } /* * CAST 64 bit Cipher Feedback * * key --->+------+ * +->| CAST |--+ * | +------+ | * | v * INPUT --(---------->(+)+---> DATA * | | * +--------------+ * * * Given: * iV: Initial vector, 64 bits (8 bytes) long. * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. * * V0 = CAST(iV, key) * On = Dn ^ Vn * V(n+1) = CAST(On, key) */ #ifndef CAST_EXPORT_ENCRYPTION void cast_cfb64_encrypt(s, c) register unsigned char *s; int c; { _cast_cfb64_encrypt(s, c, &cast_fb[CFB_128].streams[DIR_ENCRYPT-1]); } #endif void castexp_cfb64_encrypt(s, c) register unsigned char *s; int c; { _cast_cfb64_encrypt(s, c, &cast_fb[CFB_40].streams[DIR_ENCRYPT-1]); } static void _cast_cfb64_encrypt(s, c, stp) register unsigned char *s; int c; register struct cast_stinfo *stp; { register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; ck_cast_ecb_encrypt(b, stp->str_output, &stp->str_sched, 0); memcpy((void *)stp->str_feed, (void *)b, sizeof(Block)); index = 0; } /* On encryption, we store (feed ^ data) which is cypher */ *s = stp->str_output[index] = (stp->str_feed[index] ^ *s); s++; index++; } stp->str_index = index; } #ifndef CAST_EXPORT_ENCRYPTION int cast_cfb64_decrypt(data) int data; { return _cast_cfb64_decrypt(data, &cast_fb[CFB_128].streams[DIR_DECRYPT-1]); } #endif int castexp_cfb64_decrypt(data) int data; { return _cast_cfb64_decrypt(data, &cast_fb[CFB_40].streams[DIR_DECRYPT-1]); } static int _cast_cfb64_decrypt(data, stp) int data; register struct cast_stinfo *stp; { int index; if (data == -1) { /* * Back up one byte. It is assumed that we will * never back up more than one byte. If we do, this * may or may not work. */ if (stp->str_index) --stp->str_index; return(0); } index = stp->str_index++; if (index == sizeof(Block)) { Block b; ck_cast_ecb_encrypt(b, stp->str_output, &stp->str_sched, 0); memcpy((void *)stp->str_feed, (void *)b, sizeof(Block)); stp->str_index = 1; /* Next time will be 1 */ index = 0; /* But now use 0 */ } /* On decryption we store (data) which is cypher. */ stp->str_output[index] = data; return(data ^ stp->str_feed[index]); } /* * CAST 64 bit Output Feedback * * key --->+------+ * +->| CAST |--+ * | +------+ | * +------------+ * v * INPUT --------->(+) ----> DATA * * Given: * iV: Initial vector, 64 bits (8 bytes) long. * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. * * V0 = CAST(iV, key) * V(n+1) = CAST(Vn, key) * On = Dn ^ Vn */ #ifndef CAST_EXPORT_ENCRYPTION void cast_ofb64_encrypt(s, c) register unsigned char *s; int c; { _cast_ofb64_encrypt(s, c, &cast_fb[OFB_128].streams[DIR_ENCRYPT-1]); } #endif void castexp_ofb64_encrypt(s, c) register unsigned char *s; int c; { _cast_ofb64_encrypt(s, c, &cast_fb[OFB_40].streams[DIR_ENCRYPT-1]); } static void _cast_ofb64_encrypt(s, c, stp) register unsigned char *s; int c; register struct cast_stinfo *stp; { register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; ck_cast_ecb_encrypt(b, stp->str_feed, &stp->str_sched, 0); memcpy((void *)stp->str_feed, (void *)b, sizeof(Block)); index = 0; } *s++ ^= stp->str_feed[index]; index++; } stp->str_index = index; } #ifndef CAST_EXPORT_ENCRYPTION int cast_ofb64_decrypt(data) int data; { return _cast_ofb64_decrypt(data, &cast_fb[OFB_128].streams[DIR_DECRYPT-1]); } #endif int castexp_ofb64_decrypt(data) int data; { return _cast_ofb64_decrypt(data, &cast_fb[OFB_40].streams[DIR_DECRYPT-1]); } static int _cast_ofb64_decrypt(data, stp) int data; register struct cast_stinfo *stp; { int index; if (data == -1) { /* * Back up one byte. It is assumed that we will * never back up more than one byte. If we do, this * may or may not work. */ if (stp->str_index) --stp->str_index; return(0); } index = stp->str_index++; if (index == sizeof(Block)) { Block b; ck_cast_ecb_encrypt(b, stp->str_feed, &stp->str_sched, 0); memcpy((void *)stp->str_feed, (void *)b, sizeof(Block)); stp->str_index = 1; /* Next time will be 1 */ index = 0; /* But now use 0 */ } return(data ^ stp->str_feed[index]); } /* * Copyright (c) 1997 Stanford University * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that the above copyright notices and this permission notice appear in * all copies of the software and related documentation. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * cast.c * Author: Tom Wu * * An implementation of the CAST-128 encryption algorithm, as * specified in RFC 2144. */ /* The first four S-boxes are for encryption/decryption */ static uint32 S1[] = { 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf }; static uint32 S2[] = { 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1 }; static uint32 S3[] = { 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783 }; static uint32 S4[] = { 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2 }; /* Encrypt/decrypt one 64-bit block of data */ void ck_cast_ecb_encrypt(out, in, sched, mode) uint8p out; uint8p in; CastKeySched * sched; int mode; /* zero means encrypt */ { uint32 t[2]; #ifdef LITTLE_ENDIAN t[0] = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3]; t[1] = (in[4] << 24) | (in[5] << 16) | (in[6] << 8) | in[7]; #else t[0] = *(uint32p) in; t[1] = *(uint32p) (in + 4); #endif ck_cast_ecb_crypt(t, sched, mode); #ifdef LITTLE_ENDIAN out[0] = (t[0] >> 24) & 0xff; out[1] = (t[0] >> 16) & 0xff; out[2] = (t[0] >> 8) & 0xff; out[3] = t[0] & 0xff; out[4] = (t[1] >> 24) & 0xff; out[5] = (t[1] >> 16) & 0xff; out[6] = (t[1] >> 8) & 0xff; out[7] = t[1] & 0xff; #else *(uint32p) out = t[0]; *(uint32p) (out + 4) = t[1]; #endif } void ck_cast_ecb_crypt(data, sched, mode) uint32p data; CastKeySched * sched; int mode; { register uint32 L, R, temp; register struct CastSubkeyPair * kp; register uint8p Ia, Ib, Ic, Id; uint32 I; #ifdef LITTLE_ENDIAN Id = (uint8p) &I; Ic = Id + 1; Ib = Ic + 1; Ia = Ib + 1; #else Ia = (uint8p) &I; Ib = Ia + 1; Ic = Ib + 1; Id = Ic + 1; #endif L = data[0]; R = data[1]; #define type0(left,right) \ temp = kp->Km + right;\ I = (temp << kp->Kr) | (temp >> (32 - kp->Kr));\ left ^= ((S1[*Ia] ^ S2[*Ib]) - S3[*Ic]) + S4[*Id]; #define type1(left,right) \ temp = kp->Km ^ right;\ I = (temp << kp->Kr) | (temp >> (32 - kp->Kr));\ left ^= ((S1[*Ia] - S2[*Ib]) + S3[*Ic]) ^ S4[*Id]; #define type2(left,right) \ temp = kp->Km - right;\ I = (temp << kp->Kr) | (temp >> (32 - kp->Kr));\ left ^= ((S1[*Ia] + S2[*Ib]) ^ S3[*Ic]) - S4[*Id]; if(mode) { #ifndef CAST_EXPORT_ENCRYPTION if(sched->ksize > 10) { kp = &sched->K[15]; type0(L, R); --kp; type2(R, L); --kp; type1(L, R); --kp; type0(R, L); --kp; } else #endif kp = &sched->K[11]; type2(L, R); --kp; type1(R, L); --kp; type0(L, R); --kp; type2(R, L); --kp; type1(L, R); --kp; type0(R, L); --kp; type2(L, R); --kp; type1(R, L); --kp; type0(L, R); --kp; type2(R, L); --kp; type1(L, R); --kp; type0(R, L); } else { kp = &sched->K[0]; type0(L, R); ++kp; type1(R, L); ++kp; type2(L, R); ++kp; type0(R, L); ++kp; type1(L, R); ++kp; type2(R, L); ++kp; type0(L, R); ++kp; type1(R, L); ++kp; type2(L, R); ++kp; type0(R, L); ++kp; type1(L, R); ++kp; type2(R, L); ++kp; #ifndef CAST_EXPORT_ENCRYPTION if(sched->ksize > 10) { type0(L, R); ++kp; type1(R, L); ++kp; type2(L, R); ++kp; type0(R, L); } #endif } data[0] = R; data[1] = L; } /* The last four S-boxes are for key schedule setup */ static uint32 S5[] = { 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4 }; static uint32 S6[] = { 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f }; static uint32 S7[] = { 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3 }; static uint32 S8[] = { 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e }; /* Initialize a key schedule from a 128-bit key */ static void cast_key_sched(sched, key) CastKeySched * sched; uint8p key; { uint8p x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xA, xB, xC, xD, xE, xF; uint8p z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, zA, zB, zC, zD, zE, zF; uint32 X03, X47, X8B, XCF, Z03, Z47, Z8B, ZCF; #ifdef LITTLE_ENDIAN x3 = (uint8p) &X03; x2 = x3 + 1; x1 = x2 + 1; x0 = x1 + 1; x7 = (uint8p) &X47; x6 = x7 + 1; x5 = x6 + 1; x4 = x5 + 1; xB = (uint8p) &X8B; xA = xB + 1; x9 = xA + 1; x8 = x9 + 1; xF = (uint8p) &XCF; xE = xF + 1; xD = xE + 1; xC = xD + 1; z3 = (uint8p) &Z03; z2 = z3 + 1; z1 = z2 + 1; z0 = z1 + 1; z7 = (uint8p) &Z47; z6 = z7 + 1; z5 = z6 + 1; z4 = z5 + 1; zB = (uint8p) &Z8B; zA = zB + 1; z9 = zA + 1; z8 = z9 + 1; zF = (uint8p) &ZCF; zE = zF + 1; zD = zE + 1; zC = zD + 1; #else x0 = (uint8p) &X03; x1 = x0 + 1; x2 = x1 + 1; x3 = x2 + 1; x4 = (uint8p) &X47; x5 = x4 + 1; x6 = x5 + 1; x7 = x6 + 1; x8 = (uint8p) &X8B; x9 = x8 + 1; xA = x9 + 1; xB = xA + 1; xC = (uint8p) &XCF; xD = xC + 1; xE = xD + 1; xF = xE + 1; z0 = (uint8p) &Z03; z1 = z0 + 1; z2 = z1 + 1; z3 = z2 + 1; z4 = (uint8p) &Z47; z5 = z4 + 1; z6 = z5 + 1; z7 = z6 + 1; z8 = (uint8p) &Z8B; z9 = z8 + 1; zA = z9 + 1; zB = zA + 1; zC = (uint8p) &ZCF; zD = zC + 1; zE = zD + 1; zF = zE + 1; #endif #ifdef LITTLE_ENDIAN *x0 = key[0]; *x1 = key[1]; *x2 = key[2]; *x3 = key[3]; *x4 = key[4]; *x5 = key[5]; *x6 = key[6]; *x7 = key[7]; *x8 = key[8]; *x9 = key[9]; *xA = key[10]; *xB = key[11]; *xC = key[12]; *xD = key[13]; *xE = key[14]; *xF = key[15]; #else X03 = *(uint32p) key; X47 = *(uint32p) (key + 4); X8B = *(uint32p) (key + 8); XCF = *(uint32p) (key + 12); #endif /* First half of key schedule */ Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8]; Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA]; Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9]; ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB]; sched->K[0].Km = S5[*z8] ^ S6[*z9] ^ S7[*z7] ^ S8[*z6] ^ S5[*z2]; sched->K[1].Km = S5[*zA] ^ S6[*zB] ^ S7[*z5] ^ S8[*z4] ^ S6[*z6]; sched->K[2].Km = S5[*zC] ^ S6[*zD] ^ S7[*z3] ^ S8[*z2] ^ S7[*z9]; sched->K[3].Km = S5[*zE] ^ S6[*zF] ^ S7[*z1] ^ S8[*z0] ^ S8[*zC]; X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0]; X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2]; X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1]; XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3]; sched->K[4].Km = S5[*x3] ^ S6[*x2] ^ S7[*xC] ^ S8[*xD] ^ S5[*x8]; sched->K[5].Km = S5[*x1] ^ S6[*x0] ^ S7[*xE] ^ S8[*xF] ^ S6[*xD]; sched->K[6].Km = S5[*x7] ^ S6[*x6] ^ S7[*x8] ^ S8[*x9] ^ S7[*x3]; sched->K[7].Km = S5[*x5] ^ S6[*x4] ^ S7[*xA] ^ S8[*xB] ^ S8[*x7]; Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8]; Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA]; Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9]; ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB]; sched->K[8].Km = S5[*z3] ^ S6[*z2] ^ S7[*zC] ^ S8[*zD] ^ S5[*z9]; sched->K[9].Km = S5[*z1] ^ S6[*z0] ^ S7[*zE] ^ S8[*zF] ^ S6[*zC]; sched->K[10].Km = S5[*z7] ^ S6[*z6] ^ S7[*z8] ^ S8[*z9] ^ S7[*z2]; sched->K[11].Km = S5[*z5] ^ S6[*z4] ^ S7[*zA] ^ S8[*zB] ^ S8[*z6]; X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0]; X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2]; X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1]; XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3]; sched->K[12].Km = S5[*x8] ^ S6[*x9] ^ S7[*x7] ^ S8[*x6] ^ S5[*x3]; sched->K[13].Km = S5[*xA] ^ S6[*xB] ^ S7[*x5] ^ S8[*x4] ^ S6[*x7]; sched->K[14].Km = S5[*xC] ^ S6[*xD] ^ S7[*x3] ^ S8[*x2] ^ S7[*x8]; sched->K[15].Km = S5[*xE] ^ S6[*xF] ^ S7[*x1] ^ S8[*x0] ^ S8[*xD]; /* Second half of key schedule - just like first half */ Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8]; Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA]; Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9]; ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB]; sched->K[0].Kr = (S5[*z8] ^ S6[*z9] ^ S7[*z7] ^ S8[*z6] ^ S5[*z2]) & 0x1f; sched->K[1].Kr = (S5[*zA] ^ S6[*zB] ^ S7[*z5] ^ S8[*z4] ^ S6[*z6]) & 0x1f; sched->K[2].Kr = (S5[*zC] ^ S6[*zD] ^ S7[*z3] ^ S8[*z2] ^ S7[*z9]) & 0x1f; sched->K[3].Kr = (S5[*zE] ^ S6[*zF] ^ S7[*z1] ^ S8[*z0] ^ S8[*zC]) & 0x1f; X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0]; X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2]; X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1]; XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3]; sched->K[4].Kr = (S5[*x3] ^ S6[*x2] ^ S7[*xC] ^ S8[*xD] ^ S5[*x8]) & 0x1f; sched->K[5].Kr = (S5[*x1] ^ S6[*x0] ^ S7[*xE] ^ S8[*xF] ^ S6[*xD]) & 0x1f; sched->K[6].Kr = (S5[*x7] ^ S6[*x6] ^ S7[*x8] ^ S8[*x9] ^ S7[*x3]) & 0x1f; sched->K[7].Kr = (S5[*x5] ^ S6[*x4] ^ S7[*xA] ^ S8[*xB] ^ S8[*x7]) & 0x1f; Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8]; Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA]; Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9]; ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB]; sched->K[8].Kr = (S5[*z3] ^ S6[*z2] ^ S7[*zC] ^ S8[*zD] ^ S5[*z9]) & 0x1f; sched->K[9].Kr = (S5[*z1] ^ S6[*z0] ^ S7[*zE] ^ S8[*zF] ^ S6[*zC]) & 0x1f; sched->K[10].Kr = (S5[*z7] ^ S6[*z6] ^ S7[*z8] ^ S8[*z9] ^ S7[*z2]) & 0x1f; sched->K[11].Kr = (S5[*z5] ^ S6[*z4] ^ S7[*zA] ^ S8[*zB] ^ S8[*z6]) & 0x1f; X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0]; X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2]; X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1]; XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3]; sched->K[12].Kr = (S5[*x8] ^ S6[*x9] ^ S7[*x7] ^ S8[*x6] ^ S5[*x3]) & 0x1f; sched->K[13].Kr = (S5[*xA] ^ S6[*xB] ^ S7[*x5] ^ S8[*x4] ^ S6[*x7]) & 0x1f; sched->K[14].Kr = (S5[*xC] ^ S6[*xD] ^ S7[*x3] ^ S8[*x2] ^ S7[*x8]) & 0x1f; sched->K[15].Kr = (S5[*xE] ^ S6[*xF] ^ S7[*x1] ^ S8[*x0] ^ S8[*xD]) & 0x1f; } /* Initialize with a full-strength 128-bit key */ #ifndef CAST_EXPORT_ENCRYPTION void ck_cast128_key_sched(sched, key) CastKeySched * sched; uint8 * key; { sched->ksize = 16; cast_key_sched(sched, key); } #endif /* Handle reduced-keysize variants */ static void cast5_key_sched(sched, key, sz) CastKeySched * sched; uint8 * key; int sz; { uint8 buf[16]; sched->ksize = sz; memset(buf, 0, sizeof(buf)); memcpy(buf, key, sz); cast_key_sched(sched, buf); } /* 40, 64, and 80-bit keys - all use 12 rounds */ void ck_cast5_40_key_sched(sched, key) CastKeySched * sched; uint8 * key; { cast5_key_sched(sched, key, 5); } #ifndef CAST_EXPORT_ENCRYPTION void ck_cast5_64_key_sched(sched, key) CastKeySched * sched; uint8 * key; { cast5_key_sched(sched, key, 8); } void ck_cast5_80_key_sched(sched, key) CastKeySched * sched; uint8 * key; { cast5_key_sched(sched, key, 10); } #endif /* CAST_EXPORT_ENCRYPTION */ #endif /* CK_CAST */ #ifdef CRYPT_DLL static char * ck_crypt_dll_version() { return(ckcrpv); } int crypt_dll_init( crypt_dll_init_data * init ) { #ifdef LIBDES extern int des_check_key; extern void libdes_dll_init(crypt_dll_init_data *); des_check_key = 1; #endif /* LIBDES */ if ( init->version >= 1 ) { p_ttol = init->p_ttol; p_dodebug = init->p_dodebug; p_dohexdump = init->p_dohexdump; p_tn_debug = init->p_tn_debug; p_scrnprint = init->p_scrnprint; if ( init->version == 1 ) return(1); } if ( init->version >= 2 ) { /* This is a k5_context but we don't want to include krb5.h */ p_k5_context = (void *) init->p_k5_context; if ( init->version == 2 ) return(1); } if ( init->version >= 3 ) { init->callbackp_install_dllfunc("encrypt_parse",encrypt_parse); init->callbackp_install_dllfunc("encrypt_init",encrypt_init); init->callbackp_install_dllfunc("encrypt_session_key",encrypt_session_key); init->callbackp_install_dllfunc("encrypt_send_request_start", encrypt_send_request_start ); init->callbackp_install_dllfunc("encrypt_request_start",encrypt_request_start); init->callbackp_install_dllfunc("encrypt_send_request_end", encrypt_send_request_end ); init->callbackp_install_dllfunc("encrypt_request_end",encrypt_request_end); init->callbackp_install_dllfunc("encrypt_send_end",encrypt_send_end); init->callbackp_install_dllfunc("encrypt_send_support",encrypt_send_support); init->callbackp_install_dllfunc("encrypt_is_encrypting",encrypt_is_encrypting); init->callbackp_install_dllfunc("encrypt_is_decrypting",encrypt_is_decrypting); init->callbackp_install_dllfunc("get_crypt_table",get_crypt_table); init->callbackp_install_dllfunc("des_is_weak_key",ck_des_is_weak_key); libdes_dll_init(init); if (init->version == 3) return(1); } if ( init->version >= 4 ) { init->callbackp_install_dllfunc("crypt_dll_version",ck_crypt_dll_version); if (init->version == 4) return(1); } if ( init->version >= 5 ) { p_reqtelmutex = init->p_reqtelmutex; p_reltelmutex = init->p_reltelmutex; if (init->version == 5) return(1); } if ( init->version >= 6 ) { init->callbackp_install_dllfunc("encrypt_dont_support",encrypt_dont_support); if ( init->version == 6 ) return(1); /* when adding new versions; migrate the next two lines */ init->version = 6; return(1); } return(0); } #undef malloc #undef realloc #undef free #undef strdup static void fatal(char *msg) { if (!msg) msg = ""; printf(msg); exit(1); /* Exit indicating failure */ } void * kmalloc(size_t size) { void *ptr; if (size == 0) { fatal("kmalloc: zero size"); } ptr = malloc(size); if (ptr == NULL) { fatal("kmalloc: out of memory"); } return ptr; } void * krealloc(void *ptr, size_t new_size) { void *new_ptr; if (new_size == 0) { fatal("krealloc: zero size"); } if (ptr == NULL) new_ptr = malloc(new_size); else new_ptr = realloc(ptr, new_size); if (new_ptr == NULL) { fatal("krealloc: out of memory"); } return new_ptr; } void kfree(void *ptr) { if (ptr == NULL) { printf("kfree: NULL pointer given as argument"); return; } free(ptr); } char * kstrdup(const char *str) { size_t len; char *cp; if (str == NULL) { fatal("kstrdup: NULL pointer given as argument"); } len = strlen(str) + 1; cp = kmalloc(len); if (cp) memcpy(cp, str, len); return cp; } #endif /* CRYPT_DLL */ #endif /* CK_ENCRYPTION */ ck_des.c000664 045065 024037 00000005723 14767401604 012577 0ustar00fdckermit000000 000000 /* C K _ D E S . C - libDES interface for Kermit 95" Copyright (C) 1998, 2023, Trustees of Columbia University in the City of New York. The C-Kermit software may not be, in whole or in part, licensed or sold for profit as a software product itself, nor may it be included in or distributed with commercial products or otherwise distributed by commercial concerns to their clients or customers without written permission of the Office of Kermit Development and Distribution, Columbia University. This copyright notice must not be removed, altered, or obscured. Author: Jeffrey E Altman (jaltman@secure-endpoints.com) Last update: 13 December 2022 David Goodwin. */ /* This file contains wrappers so that the following functions will be imported into the k95crypt.dll/k2crypt.dll files in such a form that they can be re-exported to k95.exe/k2.exe. This subset of the DES library is needed to provide DES based Kerberos authentication. */ #ifdef LIBDES /* The following is specific to my installation, but since I'm the only one */ /* that uses this file ... */ #include "ckcdeb.h" #include "ckuath.h" #define CK_DES_C #include "ckuat2.h" #ifdef LIBDES_USE_OPENSSL #else #include #endif #include "ckucmd.h" /* xx_strp */ #include "ckcfnp.h" /* Prototypes */ /* This is required by ckclib.c and normally defined in ckuus4.c */ #ifdef CRYPT_DLL int fp_digits = 0; /* Digits of floating point precision */ #else extern int fp_digits; #endif /* CRYPT_DLL */ int libdes_random_key(des_cblock B) { des_random_key(B); return(0); } void libdes_random_seed(des_cblock B) { des_random_seed(B); } void libdes_key_sched(des_cblock * B, des_key_schedule S) { des_key_sched(B,S); } void libdes_ecb_encrypt(des_cblock * B1, des_cblock * B2, des_key_schedule S, int n) { des_ecb_encrypt(B1,B2,S,n); } int libdes_string_to_key(char * s, des_cblock * B) { des_string_to_key(s,B); return(0); } void libdes_fixup_key_parity(des_cblock * B) { des_set_odd_parity(B); } void libdes_pcbc_encrypt(des_cblock *input, des_cblock *output, long length, des_key_schedule schedule, des_cblock *ivec, int enc) { des_pcbc_encrypt(input,output,length,schedule,ivec,enc); } #ifdef CRYPT_DLL void libdes_dll_init(crypt_dll_init_data * init) { init->callbackp_install_dllfunc("libdes_random_key",libdes_random_key); init->callbackp_install_dllfunc("libdes_random_seed",libdes_random_seed); init->callbackp_install_dllfunc("libdes_key_sched",libdes_key_sched); init->callbackp_install_dllfunc("libdes_ecb_encrypt",libdes_ecb_encrypt); init->callbackp_install_dllfunc("libdes_string_to_key",libdes_string_to_key); init->callbackp_install_dllfunc("libdes_fixup_key_parity",libdes_fixup_key_parity); init->callbackp_install_dllfunc("libdes_pcbc_encrypt",libdes_pcbc_encrypt); } #endif /* CRYPT_DLL */ #endif /* LIBDES */ ck_ssl.c000664 045065 024037 00000471564 14767401610 012634 0ustar00fdckermit000000 000000 char *cksslv = "SSL/TLS support, 10.0.239 18 Sep 2023"; /* C K _ S S L . C -- OpenSSL Interface for C-Kermit Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Authors: Jeffrey E Altman (jaltman@secure-endpoints.com) Secure Endpoints Inc., New York City David Goodwin, New Zealand Provides: . Telnet Auth SSL option compatible with Tim Hudson's hack. . Telnet START_TLS option . Configuration of certificate and key files . Certificate verification and revocation list checks . Client certificate to user id routine Note: This code is written to be compatible with OpenSSL 0.9.6[abcdefgh] and 0.9.7 beta 5 and later, and (since July 2012) 1.0.x. It will also compile with version 0.9.5 although that is discouraged due to security weaknesses in that release. $NetBSD: patch-ab,v 1.8 2020/04/08 15:22:07 rhialto Exp $ - Update for openssl 1.1.1e. - Kermit tries to keep SSL and TLS contexts (since in old openssl, the *v23* methods were not version-flexible enough). Now after simplification there is lots of duplicate code left over that could be simplified more. Adapted for LibreSSL by Bernard Spil, December 2015 (search "Spil") */ #ifndef NOSSL #include "ckcsym.h" #include "ckcdeb.h" #ifdef CK_SSL #include "ckcnet.h" #include "ckuath.h" #include #include #ifdef UNIX #include #ifndef FREEBSD4 #include #endif /* FREEBSD4 */ #endif /* UNIX */ #ifdef DEC_TCPIP #include #include #endif /* DEC_TCPIP */ #ifdef OS2 extern char exedir[]; #ifdef NT char * GetAppData(int); #endif #endif /* OS2 */ extern int quiet; /* fdc - Mon Nov 28 11:44:15 2005 */ static int ssl_installed = 1; #endif /* CK_SSL */ #ifdef SSHBUILTIN #include "ckossh.h" #endif /* SSHBUILTIN */ int ck_ssh_is_installed() { #ifdef SSHBUILTIN #ifdef SSH_DLL return ssh_avail(); #else /* SSH_DLL */ return(1); #endif /* SSH_DLL */ #else /* SSHBUILTIN */ return(0); #endif /* SSHBUILTIN */ } int #ifdef CK_ANSIC ck_ssleay_is_installed(void) #else ck_ssleay_is_installed() #endif { #ifdef CK_SSL #ifdef SSLDLL #ifdef NT extern HINSTANCE hSSL, hCRYPTO; #else /* NT */ extern HMODULE hSSL, hCRYPTO; #endif /* NT */ debug(F111,"ck_ssleay_is_installed","hSSL",hSSL); debug(F111,"ck_ssleay_is_installed","hCRYPTO",hCRYPTO); return(ssl_installed && (hSSL != NULL) && (hCRYPTO != NULL)); #else /* SSLDLL */ return(ssl_installed); #endif /* SSLDLL */ #else /* CK_SSL */ return(0); #endif /* CK_SSL */ } #ifdef CK_SSL #include "ckcker.h" #include "ckucmd.h" /* For struct keytab */ #include "ckctel.h" #include "ck_ssl.h" #ifdef UNIX #include /* Password file for home directory */ #endif /* UNIX */ #ifdef OS2 #include #endif /* OS2 */ #ifdef OS2ONLY #include "ckotcp.h" #endif /* OS2ONLY */ #include "ckuusr.h" /* struct mtab */ #include "ckcfnp.h" /* Prototypes */ #ifdef SSLDLL int ssl_finished_messages = 0; #else /* SSLDLL */ #ifdef OPENSSL_VERSION_NUMBER int ssl_finished_messages = (OPENSSL_VERSION_NUMBER >= 0x0090581fL); #else !ERROR This module requires OpenSSL 0.9.5a or higher #endif /* OPENSSL_VERSION_NUMBER */ #endif /* SSLDLL */ static int auth_ssl_valid = 0; static char *auth_ssl_name = 0; /* this holds the oneline name */ char ssl_err[SSL_ERR_BFSZ]=""; BIO *bio_err=NULL; X509_STORE *crl_store = NULL; #ifndef NOFTP #ifndef SYSFTP SSL *ssl_ftp_con = NULL; SSL_CTX *ssl_ftp_ctx = NULL; SSL *ssl_ftp_data_con = NULL; int ssl_ftp_active_flag = 0; int ssl_ftp_data_active_flag = 0; #endif /* SYSFTP */ #endif /* NOFTP */ #ifndef NOHTTP SSL *tls_http_con = NULL; SSL_CTX *tls_http_ctx = NULL; int tls_http_active_flag = 0; int ssl_http_initialized = 0; #endif /* NOHTTP */ SSL_CTX *ssl_ctx = NULL; SSL *ssl_con = NULL; int ssl_debug_flag = 0; int ssl_verbose_flag = 0; int ssl_only_flag = 0; int ssl_raw_flag = 0; int ssl_active_flag = 0; int ssl_verify_flag = SSL_VERIFY_PEER; int ssl_certsok_flag = 0; char *ssl_rsa_cert_file = NULL; char *ssl_rsa_cert_chain_file = NULL; char *ssl_rsa_key_file = NULL; char *ssl_dsa_cert_file = NULL; char *ssl_dsa_cert_chain_file = NULL; char *ssl_dh_key_file = NULL; char *ssl_crl_file = NULL; char *ssl_crl_dir = NULL; char *ssl_verify_file = NULL; char *ssl_verify_dir = NULL; char *ssl_dh_param_file = NULL; char *ssl_cipher_list = NULL; char *ssl_rnd_file = NULL; SSL_CTX *tls_ctx = NULL; SSL *tls_con = NULL; int tls_only_flag = 0; int tls_raw_flag = 0; int tls_active_flag = 0; int ssl_initialized = 0; int ssl_verify_depth = -1; /* used to track depth in verify routines */ /* compile this set to 1 to negotiate SSL/TLS but not actually start it */ int ssl_dummy_flag=0; extern int inserver; extern int debses; extern int accept_complete; extern char szHostName[], szUserNameRequested[], szUserNameAuthenticated[]; _PROTOTYP(int X509_to_user,(X509 *, char *, int)); static int verbosity = 0; /* Message control */ static VOID setverbosity() { verbosity = ssl_verbose_flag; if (quiet) verbosity = 0; } int #ifdef CK_ANSIC ssl_server_verify_callback(int ok, X509_STORE_CTX * ctx) #else /* CK_ANSIC */ ssl_server_verify_callback(ok, ctx) int ok; X509_STORE_CTX *ctx; #endif /* CK_ANSIC */ { static char *saved_subject=NULL; char *subject=NULL, *issuer=NULL; int depth,error; X509 *xs = NULL; if ( ssl_certsok_flag ) return(1); setverbosity(); error=X509_STORE_CTX_get_error(ctx); depth=X509_STORE_CTX_get_error_depth(ctx); xs=X509_STORE_CTX_get_current_cert(ctx); if (depth==0) { /* clear things */ if (saved_subject!=NULL) { free(saved_subject); saved_subject=NULL; } if (auth_ssl_name!=NULL) { free(auth_ssl_name); auth_ssl_name=NULL; } } if (ssl_debug_flag && !inserver) { printf("ssl:server_verify_callback:depth=%d ok=%d err=%d-%s\r\n", depth,ok,error,X509_verify_cert_error_string(error)); } /* first thing is to have a meaningful name for the current * certificate that is being verified ... and if we cannot * determine that then something is seriously wrong! */ makestr(&subject, (char *)X509_NAME_oneline(X509_get_subject_name(xs),NULL,0)); makestr(&issuer, (char *)X509_NAME_oneline(X509_get_issuer_name(xs),NULL,0)); if (!subject || !subject[0] || !issuer || !issuer[0]) { ok = 0; goto return_time; } if (verbosity && !inserver && depth != ssl_verify_depth) { printf("[%d] Certificate Subject:\r\n%s\r\n",depth,subject); printf("[%d] Certificate Issuer:\r\n%s\r\n",depth,issuer); ssl_verify_depth = depth; } /* make sure that the certificate that has been presented */ /* has not been revoked (if we have been given a CRL. */ ok = ssl_verify_crl(ok, ctx); /* if we have any form of error in secure mode we reject the connection */ if (error!=X509_V_OK) { if (inserver) { #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_LI && ckxlogging) { cksyslog(SYSLG_LI, 0, "X.509 Certificate verify failure", (char *) subject, (char *)X509_verify_cert_error_string(error) ); } #endif /* CKSYSLOG */ } else { if ( ssl_verify_flag & (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) printf("Error: "); else printf("Warning: "); switch (error) { case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: printf("Certificate is self signed.\r\n"); break; case X509_V_ERR_CERT_HAS_EXPIRED: printf("Certificate has expired.\r\n"); break; case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: printf( "Certificate issuer's certificate isn't available locally.\r\n"); break; case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: printf("Unable to verify leaf signature.\r\n"); break; case X509_V_ERR_CERT_REVOKED: printf("Certificate revoked.\r\n"); break; default: printf("Error %d while verifying certificate.\r\n", error); break; } } ok = !(ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT); } else { /* if we got all the way to the top of the tree then * we *can* use this certificate for a username to * match ... in all other cases we must not! */ auth_ssl_name = saved_subject; saved_subject = NULL; } return_time: /* save the name if at least the first level is okay */ if (depth == 0 && ok) makestr(&saved_subject,subject); /* clean up things */ if (subject!=NULL) free(subject); if (issuer!=NULL) free(issuer); return ok; } int #ifdef CK_ANSIC ssl_client_verify_callback(int ok, X509_STORE_CTX * ctx) #else ssl_client_verify_callback(ok, ctx) int ok; X509_STORE_CTX *ctx; #endif { char subject[256]="", issuer[256]=""; int depth, error, len; X509 *xs; setverbosity(); xs=X509_STORE_CTX_get_current_cert(ctx); error=X509_STORE_CTX_get_error(ctx); depth=X509_STORE_CTX_get_error_depth(ctx); if ( ssl_debug_flag ) printf("ssl:client_verify_callback:depth=%d ok=%d err=%d-%s\r\n", depth,ok,error,X509_verify_cert_error_string(error)); if ( ssl_certsok_flag ) { ok = 1; } /* first thing is to have a meaningful name for the current * certificate that is being verified ... and if we cannot * determine that then something is seriously wrong! */ #ifdef XN_FLAG_SEP_MULTILINE X509_NAME_print_ex(bio_err,X509_get_subject_name(xs),4, XN_FLAG_SEP_MULTILINE); len = BIO_read(bio_err,subject,256); subject[len < 256 ? len : 255] = '\0'; if (!subject[0]) { ERR_print_errors(bio_err); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; uq_ok("X.509 Subject Name unavailable", ssl_err, 1, NULL, 0); ok=0; goto return_time; } X509_NAME_print_ex(bio_err,X509_get_issuer_name(xs),4, XN_FLAG_SEP_MULTILINE); len = BIO_read(bio_err,issuer,256); issuer[len < 256 ? len : 255] = '\0'; if (!issuer[0]) { ERR_print_errors(bio_err); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; uq_ok("X.509 Issuer Name unavailable", ssl_err, 1, NULL, 0); ok=0; goto return_time; } #else /* XN_FLAG_SEP_MULTILINE */ X509_NAME_oneline(X509_get_subject_name(xs),subject,256); if (!subject[0]) { int len; ERR_print_errors(bio_err); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; uq_ok("X.509 Subject Name unavailable", ssl_err, 1, NULL, 0); ok=0; goto return_time; } X509_NAME_oneline(X509_get_issuer_name(xs),issuer,256); if (!issuer[0]) { int len; ERR_print_errors(bio_err); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; uq_ok("X.509 Issuer Name unavailable", ssl_err, 1, NULL, 0); ok=0; goto return_time; } #endif /* XN_FLAG_SEP_MULTILINE */ if (verbosity && depth != ssl_verify_depth) { printf("[%d] Certificate Subject:\r\n%s\r\n",depth,subject); printf("[%d] Certificate Issuer:\r\n%s\r\n",depth,issuer); ssl_verify_depth = depth; } ok = ssl_verify_crl(ok, ctx); if ( !ok ) { char prefix[1024]; /* if the server is using a self signed certificate then * we need to decide if that is good enough for us to * accept ... */ switch ( error ) { case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: { if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { /* make 100% sure that in secure more we drop the * connection if the server does not have a * real certificate! */ ckmakxmsg(prefix,1024, "Error: Server has a self-signed certificate\n", "[",ckitoa(depth),"] Certificate Subject=\n",subject, "\n[",ckitoa(depth),"] Certificate Issuer=\n",issuer, NULL,NULL,NULL); uq_ok(prefix, "Rejecting Connection", 1, NULL, 0); /* sometimes it is really handy to be able to debug things * and still get a connection! */ if (ssl_debug_flag) { printf("SSL: debug -> ignoring cert required!\r\n"); ok=1; } else { ok=0; } goto return_time; } else if (ssl_verify_flag != SSL_VERIFY_NONE) { ckmakxmsg(prefix,1024, "Warning: Server has a self-signed certificate\n", "[",ckitoa(depth),"] Certificate Subject=\n",subject, "\n[",ckitoa(depth),"] Certificate Issuer=\n",issuer, NULL,NULL,NULL); ok = uq_ok(prefix, "Continue? (Y/N) ", 3, NULL, 0); if ( ok < 0 ) ok = 0; goto return_time; } } case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { /* make 100% sure that in secure more we drop the * connection if the server does not have a * real certificate! */ ckmakxmsg(prefix,1024, "Error: ", (char *)X509_verify_cert_error_string(error), "\nCertificate Issuer=\n",issuer, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); uq_ok(prefix, "Rejecting Connection", 1, NULL, 0); /* sometimes it is really handy to be able to debug things * and still get a connection! */ if (ssl_debug_flag) { printf("SSL: debug -> ignoring cert required!\r\n"); ok=1; } else { ok=0; } goto return_time; } else if (ssl_verify_flag != SSL_VERIFY_NONE) { ckmakxmsg(prefix,1024, "Warning: ", (char *)X509_verify_cert_error_string(error), "\nCertificate Issuer=\n",issuer, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0); goto return_time; } break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { int len; /* make 100% sure that in secure more we drop the * connection if the server does not have a * real certificate! */ ASN1_TIME_print(bio_err,X509_get_notBefore(xs)); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; ckmakxmsg(prefix,1024, "Error: ", (char *)X509_verify_cert_error_string(error), "\nCertificate Subject=\n",subject, "\nnotBefore=",ssl_err, NULL,NULL,NULL,NULL,NULL,NULL); uq_ok(prefix, "Rejecting Connection", 1, NULL, 0); /* sometimes it is really handy to be able to debug things * and still get a connection! */ if (ssl_debug_flag) { printf("SSL: debug -> ignoring cert required!\r\n"); ok=1; } else { ok=0; } goto return_time; } else if (ssl_verify_flag != SSL_VERIFY_NONE) { int len; ASN1_TIME_print(bio_err,X509_get_notBefore(xs)); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; ckmakxmsg(prefix,1024, "Warning: ", (char *)X509_verify_cert_error_string(error), "\nCertificate Subject=\n",subject, "\n notBefore=",ssl_err, NULL,NULL,NULL,NULL,NULL,NULL); ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0); } break; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { int len; /* make 100% sure that in secure more we drop the * connection if the server does not have a * real certificate! */ ASN1_TIME_print(bio_err,X509_get_notAfter(xs)); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; ckmakxmsg(prefix,1024, "Error: ", (char *)X509_verify_cert_error_string(error), "\nCertificate Subject=\n",subject, "\n notAfter=",ssl_err, NULL,NULL,NULL,NULL,NULL,NULL); uq_ok(prefix, "Rejecting Connection", 1, NULL, 0); /* sometimes it is really handy to be able to debug things * and still get a connection! */ if (ssl_debug_flag) { printf("SSL: debug -> ignoring cert required!\r\n"); ok=1; } else { ok=0; } goto return_time; } else if (ssl_verify_flag != SSL_VERIFY_NONE) { int len; ASN1_TIME_print(bio_err,X509_get_notAfter(xs)); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; ckmakxmsg(prefix,1024, "Warning: ", (char *)X509_verify_cert_error_string(error), "\nCertificate Subject=\n",subject, "\n notAfter=",ssl_err, NULL,NULL,NULL,NULL,NULL,NULL); ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0); } break; case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: /* * When an SSL server sends its certificates to the client there * are two" conventions": one is to send the complete certificate * chain and the other is to send the whole chain apart from the * root. * * You don't usually need the root because the root is normally * stored and trusted locally. * * So if you get the whole chain it will complain about the self * signed certificate whereas if the root is missing it says it * can't find the issuer certificate. */ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { /* make 100% sure that in secure more we drop the * connection if the server does not have a * real certificate! */ ckmakxmsg(prefix,1024, "Error: ", (char *)X509_verify_cert_error_string(error), "\nCertificate Issuer=\n",issuer, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); uq_ok(prefix, "Rejecting Connection", 1, NULL, 0); /* sometimes it is really handy to be able to debug things * and still get a connection! */ if (ssl_debug_flag) { printf("SSL: debug -> ignoring cert required!\r\n"); ok=1; } else { ok=0; } goto return_time; } else if (ssl_verify_flag != SSL_VERIFY_NONE) { ckmakxmsg(prefix,1024, "Warning: ", (char *)X509_verify_cert_error_string(error), "\nCertificate Issuer=\n",issuer, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0); #ifdef NT if (ok) { /* if the user decides to accept the certificate * offer to store it for future connections in * the user's private store */ ok = uq_ok( "Do you wish to store the certificate to verify future connections?", "Continue (Y/N)", 3, NULL, 0); if (ok) ck_X509_save_cert_to_user_store(xs); } #endif /* NT */ } break; case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: case X509_V_ERR_UNABLE_TO_GET_CRL: case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: case X509_V_ERR_CERT_SIGNATURE_FAILURE: case X509_V_ERR_CRL_SIGNATURE_FAILURE: case X509_V_ERR_CRL_NOT_YET_VALID: case X509_V_ERR_CRL_HAS_EXPIRED: case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: case X509_V_ERR_OUT_OF_MEM: case X509_V_ERR_CERT_CHAIN_TOO_LONG: case X509_V_ERR_CERT_REVOKED: case X509_V_ERR_APPLICATION_VERIFICATION: default: if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { /* make 100% sure that in secure mode we drop the * connection if the server does not have a * real certificate! */ ckmakxmsg(prefix,1024, "Error: ", (char *)X509_verify_cert_error_string(error), "\nCertificate Subject=\n",subject, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); uq_ok(prefix, "Rejecting Connection", 1, NULL, 0); /* sometimes it is really handy to be able to debug things * and still get a connection! */ if (ssl_debug_flag) { printf("SSL: debug -> ignoring cert required!\r\n"); ok=1; } else { ok=0; } goto return_time; } else if (ssl_verify_flag != SSL_VERIFY_NONE) { ckmakxmsg(prefix,1024, "Warning: ", (char *)X509_verify_cert_error_string(error), "\nCertificate Subject=\n",subject, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); ok = uq_ok(prefix, "Continue (Y/N)", 3, NULL, 0); } break; } } return_time: if ( ssl_debug_flag ) printf("ssl:client_verify_callback => ok: %d\r\n",ok); return ok; } VOID #ifdef CK_ANSIC ssl_client_info_callback(const SSL *s, int where, int ret) #else ssl_client_info_callback(s,where,ret) const SSL *s; int where; int ret; #endif /* CK_ANSIC */ { if (inserver || !ssl_debug_flag) return; setverbosity(); switch ( where ) { case SSL_CB_CONNECT_LOOP: printf("SSL_connect:%s %s\r\n", SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s)); break; case SSL_CB_CONNECT_EXIT: if (ret == 0) { printf("SSL_connect:failed in %s %s\r\n", SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s)); } else if (ret < 0) { printf("SSL_connect:error in %s %s\r\n", SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s)); } break; case SSL_CB_ACCEPT_LOOP: printf("SSL_accept:%s %s\r\n", SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s)); break; case SSL_CB_ACCEPT_EXIT: if (ret == 0) { printf("SSL_accept:failed in %s %s\r\n", SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s)); } else if (ret < 0) { printf("SSL_accept:error in %s %s\r\n", SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s)); } break; case SSL_CB_READ_ALERT: printf("SSL_read_alert\r\n"); break; case SSL_CB_WRITE_ALERT: printf("SSL_write_alert\r\n"); break; case SSL_CB_HANDSHAKE_START: printf("SSL_handshake:%s %s\r\n", SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s)); break; case SSL_CB_HANDSHAKE_DONE: printf("SSL_handshake:%s %s\r\n", SSL_state_string((SSL *)s),SSL_state_string_long((SSL *)s)); break; } } #ifdef USE_CERT_CB /* Return 1, client cert is available */ /* Return 0, no client cert is available */ /* Return -1, callback must be called again. SSL_want_x509_lookup() == 1 */ int #ifdef CK_ANSIC ssl_client_cert_callback(SSL * s, X509 ** x509, EVP_PKEY ** pkey) #else /* CK_ANSIC */ ssl_client_cert_callback(s, x509, pkey) SSL * s; X509 ** x509; EVP_PKEY ** pkey; #endif /* CK_ANSIC */ { setverbosity(); if ( ssl_debug_flag ) { const char * cipher_list=SSL_get_cipher(s); printf("ssl_client_cert_callback called (%s)\r\n", cipher_list?cipher_list:"UNKNOWN"); } #ifdef COMMENT if ( s == tls_con ) { if (tls_load_certs(tls_cts,tls_con,0)) { *x509 = SSL_get_certificate(s); *pkey = SSL_get_privatekey(s); return(1); } } else if ( s == ssl_con ) { if (tls_load_certs(ssl_ctx,ssl_con,0)) { *x509 = SSL_get_certificate(s); *pkey = SSL_get_privatekey(s); return(1); } } return(0); #else /* COMMENT */ return(0); #endif /* COMMENT */ } #endif /* USE_CERT_CB */ #ifndef MS_CALLBACK #define MS_CALLBACK #endif /* MS_CALLBACK */ static BIGNUM *get_RSA_F4() { static BIGNUM *bn; if (!bn) { bn = BN_new(); BN_add_word(bn, RSA_F4); } return bn; } static RSA MS_CALLBACK * #ifdef CK_ANSIC tmp_rsa_cb(SSL * s, int export, int keylength) #else /* CK_ANSIC */ tmp_rsa_cb(s,export,keylength) SSL *s; int export; int keylength; #endif /* CK_ANSIC */ { static RSA *rsa_tmp=NULL; #ifndef NO_RSA if (rsa_tmp == NULL) { if (ssl_debug_flag) printf("Generating temporary (%d bit) RSA key...\r\n",keylength); rsa_tmp = RSA_new(); if (rsa_tmp) { int error = RSA_generate_key_ex(rsa_tmp, keylength, get_RSA_F4(),NULL); if (error) { if (ssl_debug_flag) printf(" error %d", error); RSA_free(rsa_tmp); rsa_tmp = NULL; } } if (ssl_debug_flag) printf("\r\n"); } #else /* NO_RSA */ if (ssl_debug_flag) printf("Unable to generate temporary RSA key...\r\n"); #endif return(rsa_tmp); } #ifndef NO_DH static unsigned char dh512_p[]={ 0xE9,0x4E,0x3A,0x64,0xFA,0x65,0x5F,0xA6,0x44,0xC7,0xFC,0xF1, 0x16,0x8B,0x11,0x11,0x7A,0xF0,0xB2,0x49,0x80,0x56,0xA3,0xF8, 0x0F,0x7D,0x01,0x68,0x5D,0xF6,0x8A,0xEA,0x8C,0xDD,0x01,0xDC, 0x43,0x18,0xE0,0xC4,0x89,0x80,0xE6,0x2D,0x44,0x77,0x45,0xFD, 0xBA,0xFC,0x43,0x35,0x12,0xC0,0xED,0x32,0xD3,0x16,0xEF,0x51, 0x09,0x44,0xA2,0xDB, }; static unsigned char dh512_g[]={ 0x05, }; static unsigned char dh768_p[]={ 0x8B,0x2A,0x8C,0x6C,0x0F,0x87,0xC7,0x34,0xEE,0x2E,0xFB,0x60, 0x94,0xB3,0xBF,0x95,0xBA,0x84,0x74,0x86,0xEA,0xE0,0xA4,0x33, 0xE0,0x8F,0x7C,0x79,0x5C,0x62,0xE2,0x91,0xC5,0x6D,0x68,0xB9, 0x6C,0x5E,0x4E,0x94,0x0C,0x8E,0x56,0x8E,0xEB,0x98,0x7C,0x6E, 0x0E,0xF2,0xD5,0xAA,0x22,0x27,0x3F,0x0F,0xAF,0x10,0xB5,0x0B, 0x16,0xCC,0x05,0x27,0xBB,0x58,0x6D,0x61,0x4B,0x2B,0xAB,0xDC, 0x6A,0x15,0xBC,0x36,0x75,0x4D,0xEC,0xAB,0xFA,0xB6,0xE1,0xB1, 0x13,0x70,0xD8,0x77,0xCD,0x5E,0x51,0x77,0x81,0x0D,0x77,0x43, }; static unsigned char dh768_g[]={ 0x05, }; static unsigned char dh1024_p[]={ 0xA4,0x75,0xCF,0x35,0x00,0xAF,0x3C,0x17,0xCE,0xB0,0xD0,0x52, 0x43,0xA0,0x0E,0xFA,0xA2,0xC9,0xBE,0x0B,0x76,0x7A,0xD9,0x2E, 0xF4,0x97,0xAC,0x02,0x24,0x69,0xF6,0x36,0x4F,0xAB,0xCC,0x43, 0xC1,0x74,0xFF,0xA3,0xD4,0x04,0x0F,0x11,0x2B,0x6D,0x8C,0x47, 0xC9,0xCF,0x40,0x93,0x9B,0x7D,0x1E,0x52,0x85,0xB2,0x17,0x55, 0x9C,0xF2,0x41,0x02,0x2A,0x9D,0x5F,0x24,0x22,0xC6,0x04,0xC4, 0xAB,0x92,0x6D,0xC7,0xC8,0xF3,0x41,0x58,0x6C,0x86,0xFD,0xB8, 0x0F,0x2D,0xDD,0xBF,0xA8,0x40,0x0C,0x58,0xC8,0xF2,0x3F,0x18, 0xEF,0xF1,0x93,0x3E,0xBA,0x16,0x41,0xBE,0x32,0x6C,0xC5,0x63, 0xFF,0x8A,0x02,0x3D,0xAC,0xD5,0x5A,0x49,0x64,0x34,0x14,0x2E, 0xFB,0x2E,0xE7,0x39,0x1A,0x0F,0x3C,0x33, }; static unsigned char dh1024_g[]={ 0x05, }; static unsigned char dh1536_p[]={ 0xA3,0x2B,0x75,0x0E,0x7B,0x31,0x82,0xCA,0xF2,0xFC,0xF3,0x3D, 0xCE,0x5F,0xCD,0x5B,0x95,0xF6,0x2F,0xA4,0x5D,0x08,0x26,0xD2, 0x5F,0xC0,0x3F,0xC5,0xD8,0xA2,0xFE,0x83,0x26,0xBC,0xEB,0x7D, 0xF0,0x4E,0xD2,0xA6,0xBB,0x3C,0x88,0x63,0xCE,0x98,0xDE,0x08, 0xE2,0xE1,0xAF,0xE2,0x38,0xA8,0xFA,0x68,0x76,0x8D,0xBF,0xDF, 0xBB,0x30,0x15,0xFE,0xBD,0x22,0xCC,0x03,0x4E,0x5E,0x33,0xA3, 0x6D,0xD6,0x68,0x12,0x97,0x17,0x4B,0xB5,0x84,0x5F,0x5F,0xA3, 0x5C,0x2F,0xA4,0x10,0xC1,0xAD,0xBF,0xAC,0x30,0xCA,0x47,0x64, 0x63,0xFE,0xEE,0xEE,0xA1,0x64,0x73,0x70,0xAA,0xF9,0xFE,0xC6, 0xAD,0x5E,0xF6,0xF3,0x9C,0xDF,0x34,0x53,0x34,0x72,0xA6,0xA4, 0xBB,0x81,0x5A,0x43,0x41,0xFD,0x41,0x05,0x5B,0x77,0x7B,0x84, 0x03,0xFA,0x8A,0xFA,0xF7,0x8E,0x0F,0xCB,0x51,0xA2,0xB8,0x45, 0xFF,0x59,0x42,0xEF,0xCF,0xF6,0x25,0x37,0xE2,0x6D,0xFF,0x69, 0x11,0xF5,0x77,0x59,0x79,0x1C,0x5F,0x05,0xFC,0x7A,0x65,0x81, 0x03,0x4A,0x78,0xC6,0xE9,0x48,0x73,0xF6,0x10,0xBC,0x99,0x1C, 0xEE,0x44,0x2F,0x8B,0x70,0xCA,0xA8,0xB6,0x02,0x83,0x3E,0x0B, }; static unsigned char dh1536_g[]={ 0x05, }; static unsigned char dh2048_p[]={ 0xFA,0x4E,0xE4,0x3B,0xFA,0xC1,0x87,0xDD,0xE7,0xC6,0x8B,0xE6, 0x13,0x85,0xBC,0x9B,0x2B,0x8B,0x5B,0x46,0xBB,0x8B,0x86,0x6D, 0xD7,0xB6,0xD5,0x49,0xC5,0x54,0xF2,0x3E,0xD2,0x39,0x64,0x9B, 0x0E,0x33,0x39,0x8F,0xFA,0xFA,0xD9,0x78,0xED,0x34,0x82,0x29, 0x37,0x58,0x4D,0x5D,0x40,0xCB,0x69,0xE3,0x8A,0x9F,0x17,0x0C, 0x01,0x23,0x6B,0x05,0x01,0xAF,0x33,0xDE,0xDF,0x1A,0xBB,0x7B, 0x6A,0x9F,0xD8,0xED,0x8D,0x5E,0x44,0x19,0x5B,0xE0,0xB6,0x23, 0xF9,0x7A,0x96,0x6E,0x94,0x33,0x31,0x49,0xBA,0x84,0xD5,0x12, 0xD7,0x6D,0xDC,0x35,0x54,0x64,0xA3,0xD8,0x04,0x26,0xC5,0xAF, 0x7F,0xE3,0xFE,0x6F,0xBE,0xD5,0x17,0x72,0x4B,0xA6,0xD0,0xA7, 0x5F,0x18,0xF5,0xF0,0x2D,0x11,0x9A,0xF6,0xD5,0x3B,0x6C,0x61, 0x3C,0x6F,0x8E,0x09,0x4F,0x2C,0xE1,0x26,0x06,0x51,0xB3,0x19, 0x85,0x85,0x13,0xF9,0xC2,0x6E,0x80,0x28,0x9E,0x8A,0xA0,0x01, 0x46,0xD1,0x85,0x44,0x8C,0xE6,0xEE,0x7E,0x1E,0x17,0x3D,0xBA, 0x54,0xFF,0xE8,0x0E,0xDD,0x51,0xF3,0x74,0x7F,0x0D,0x0B,0xAB, 0xCA,0x84,0x8D,0x24,0x5D,0x56,0xD4,0x47,0x02,0xFC,0x93,0x9F, 0xAE,0x9B,0x5C,0xDB,0x63,0xEB,0x65,0x01,0x38,0xC2,0x7B,0x30, 0x1E,0x17,0x1C,0x75,0xF5,0x16,0x3B,0x4F,0x5F,0x41,0x32,0xB5, 0xFF,0x9E,0x61,0xFD,0xD2,0x62,0x6E,0xFD,0x8A,0x28,0x93,0x59, 0x2D,0x70,0x14,0x4D,0xE1,0x86,0xD5,0x90,0xB4,0xDF,0x72,0x71, 0xE0,0xB4,0xD0,0xD6,0x82,0x3A,0x4A,0x04,0x58,0x32,0x0B,0xD3, 0x51,0x13,0x32,0x63, }; static unsigned char dh2048_g[]={ 0x02, }; static DH * get_dh512() { DH *dh=NULL; BIGNUM *p = NULL; BIGNUM *g = NULL; if ((dh=DH_new()) == NULL) return(NULL); #if OPENSSL_VERSION_NUMBER >= 0x10100005L p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL); g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL); if ((p == NULL) || (g == NULL)) { BN_free(g); BN_free(p); DH_free(dh); return(NULL); } DH_set0_pqg(dh, p, NULL, g); #else dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL); dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL); if ((dh->p == NULL) || (dh->g == NULL)) { BN_free(dh->g); BN_free(dh->p); DH_free(dh); return(NULL); } #endif return(dh); } static DH * get_dh768() { DH *dh=NULL; BIGNUM *p = NULL; BIGNUM *g = NULL; if ((dh=DH_new()) == NULL) return(NULL); #if OPENSSL_VERSION_NUMBER >= 0x10100005L p=BN_bin2bn(dh768_p,sizeof(dh768_p),NULL); g=BN_bin2bn(dh768_g,sizeof(dh768_g),NULL); if ((p == NULL) || (g == NULL)) { BN_free(g); BN_free(p); DH_free(dh); return(NULL); } DH_set0_pqg(dh, p, NULL, g); #else dh->p=BN_bin2bn(dh768_p,sizeof(dh768_p),NULL); dh->g=BN_bin2bn(dh768_g,sizeof(dh768_g),NULL); if ((dh->p == NULL) || (dh->g == NULL)) { BN_free(dh->g); BN_free(dh->p); DH_free(dh); return(NULL); } #endif return(dh); } static DH * get_dh1024() { DH *dh=NULL; BIGNUM *p = NULL; BIGNUM *g = NULL; if ((dh=DH_new()) == NULL) return(NULL); #if OPENSSL_VERSION_NUMBER >= 0x10100005L p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL); g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL); if ((p == NULL) || (g == NULL)) { BN_free(g); BN_free(p); DH_free(dh); return(NULL); } DH_set0_pqg(dh, p, NULL, g); #else dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL); dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL); if ((dh->p == NULL) || (dh->g == NULL)) { BN_free(dh->g); BN_free(dh->p); DH_free(dh); return(NULL); } #endif return(dh); } static DH * get_dh1536() { DH *dh=NULL; BIGNUM *p = NULL; BIGNUM *g = NULL; if ((dh=DH_new()) == NULL) return(NULL); #if OPENSSL_VERSION_NUMBER >= 0x10100005L p=BN_bin2bn(dh1536_p,sizeof(dh1536_p),NULL); g=BN_bin2bn(dh1536_g,sizeof(dh1536_g),NULL); if ((p == NULL) || (g == NULL)) { BN_free(g); BN_free(p); DH_free(dh); return(NULL); } DH_set0_pqg(dh, p, NULL, g); #else dh->p=BN_bin2bn(dh1536_p,sizeof(dh1536_p),NULL); dh->g=BN_bin2bn(dh1536_g,sizeof(dh1536_g),NULL); if ((dh->p == NULL) || (dh->g == NULL)) { BN_free(dh->g); BN_free(dh->p); DH_free(dh); return(NULL); } #endif return(dh); } static DH * get_dh2048() { DH *dh=NULL; BIGNUM *p = NULL; BIGNUM *g = NULL; if ((dh=DH_new()) == NULL) return(NULL); #if OPENSSL_VERSION_NUMBER >= 0x10100005L p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL); g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL); if ((p == NULL) || (g == NULL)) { BN_free(g); BN_free(p); DH_free(dh); return(NULL); } DH_set0_pqg(dh, p, NULL, g); #else dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL); dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL); if ((dh->p == NULL) || (dh->g == NULL)) { BN_free(dh->g); BN_free(dh->p); DH_free(dh); return(NULL); } #endif return(dh); } #endif /* NO_DH */ static DH MS_CALLBACK * #ifdef CK_ANSIC tmp_dh_cb(SSL * s, int export, int keylength) #else /* CK_ANSIC */ tmp_dh_cb(s,export,keylength) SSL *s; int export; int keylength; #endif /* CK_ANSIC */ { static DH *dh_tmp=NULL; BIO *bio=NULL; #ifndef NO_DH if (dh_tmp == NULL) { if (ssl_dh_param_file && (bio=BIO_new_file(ssl_dh_param_file,"r")) != NULL) dh_tmp=PEM_read_bio_DHparams(bio,NULL,NULL,NULL); if (bio != NULL) BIO_free(bio); if ( dh_tmp == NULL ) { if ( keylength < 768 ) dh_tmp = get_dh512(); else if ( keylength < 1024 ) dh_tmp = get_dh768(); else if ( keylength < 1536 ) dh_tmp = get_dh1024(); else if ( keylength < 2048 ) dh_tmp = get_dh1536(); else dh_tmp = get_dh2048(); } } #else /* NO_DH */ if (ssl_debug_flag) printf("DH not supported...\r\n"); #endif /* NO_DH */ return(dh_tmp); } static void ssl_display_comp(SSL * ssl) { #ifndef OPENSSL_NO_COMP const COMP_METHOD *method; #endif /* OPENSSL_NO_COMP */ if ( quiet ) /* fdc - Mon Nov 28 11:44:15 2005 */ return; if ( !ck_ssleay_is_installed() ) return; if (ssl == NULL) return; #ifndef OPENSSL_NO_COMP /* ifdefs Bernard Spil 12/2015 */ method = SSL_get_current_compression(ssl); if (method == NULL) #endif /* OPENSSL_NO_COMP */ printf("Compression: None\r\n"); #ifndef OPENSSL_NO_COMP /* ifdefs Bernard Spil 12/2015 */ else { printf("Compression: %s\r\n",SSL_COMP_get_name(method)); } #endif /* OPENSSL_NO_COMP */ } int #ifdef CK_ANSIC ssl_display_connect_details(SSL * ssl_con, int server, int verbose) #else /* CK_ANSIC */ ssl_display_connect_details(ssl_con,server,verbose) SSL *ssl_con; int server; int verbose; #endif /* CK_ANSIC */ { X509 *peer; const SSL_CIPHER * cipher; const char *cipher_list; char buf[512]=""; if ( quiet ) /* fdc - Mon Nov 28 11:44:15 2005 */ return(0); if ( !ck_ssleay_is_installed() ) return(0); if ( inserver && !tn_deb ) return(0); /* the cipher list *can* be NULL ... useless but it happens! */ cipher = SSL_get_current_cipher(ssl_con); cipher_list = SSL_CIPHER_get_name(cipher); SSL_CIPHER_description(cipher,buf,sizeof(buf)); if (cipher_list==NULL) cipher_list=""; printf("[TLS - %s",buf); ssl_display_comp(ssl_con); if ( server ) { cipher_list=SSL_get_shared_ciphers(ssl_con,buf,512); if (cipher_list==NULL) cipher_list=""; printf("[TLS - shared ciphers=%s]\r\n", cipher_list); } if ( server || tn_deb ) { peer=SSL_get_peer_certificate(ssl_con); if (peer != NULL) { X509_NAME_oneline(X509_get_subject_name(peer),buf,512); printf("[TLS - subject=%s]\r\n",buf); X509_NAME_oneline(X509_get_issuer_name(peer),buf,512); printf("[TLS - issuer=%s]\r\n",buf); /* X509_free(peer); */ } else if (!tls_is_krb5(0)) { if ( !sstelnet && !tcp_incoming ) { printf("[TLS - No certificate provided.]\r\n"); printf( "[TLS - The identity of the host could not be verified.]\r\n"); } } } return(0); } /* * Use SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *, void * userdata) * to set the value of the userdata. We are going to use it to store the * prompt. */ int #ifdef CK_ANSIC ssl_passwd_callback(char *buf, int len, int rwflag, VOID * userdata) #else /* CK_ANSIC */ ssl_passwd_callback(buf,len,rwflag,userdata) char * buf; int len; int rwflag; VOID *userdata; #endif /* CK_ANSIC */ { extern char pwbuf[]; extern int pwflg, pwcrypt; int ok; char *prompt=NULL; if ( pwbuf[0] && pwflg ) { int n; n = ckstrncpy(buf,pwbuf,len); #ifdef OS2 if ( pwcrypt ) ck_encrypt((char *)buf); #endif /* OS2 */ return(n); } if ( userdata == NULL ) prompt="Enter certificate passphrase: "; else prompt=(char*)userdata; ok = uq_txt(NULL,prompt,2,NULL,buf,len,NULL,DEFAULT_UQ_TIMEOUT); return(ok > 0 ? strlen(buf) : 0); } /* Attempts to load certificate data into the TLS context structures */ /* Returns 1 on success; 0 on failure */ int tls_load_certs(SSL_CTX * ctx, SSL * con, int server) { int rc = 1; if ( !ck_ssleay_is_installed() ) return(0); debug(F110,"tls_load_certs","SSL_CTX",0); debug(F110,"tls_load_certs","SSL",0); debug(F110,"tls_load_certs","server",0); if ( con ) { if (ssl_rsa_cert_file) { if ( ssl_debug_flag ) printf("Loading RSA certificate into SSL\r\n"); rc = SSL_use_certificate_file(con, ssl_rsa_cert_file, X509_FILETYPE_PEM); if (!rc) { if ( !quiet || ssl_debug_flag ) printf("Error loading certificate from %s\r\n", ssl_rsa_cert_file); } else { if (!ssl_rsa_key_file || !ssl_rsa_key_file[0]) makestr(&ssl_rsa_key_file,ssl_rsa_cert_file); rc = SSL_use_PrivateKey_file(con, ssl_rsa_key_file, X509_FILETYPE_PEM); if (!rc) rc = SSL_use_PrivateKey_file(con, ssl_rsa_cert_file, X509_FILETYPE_PEM); if (!rc) { if ( !quiet || ssl_debug_flag ) printf("Error loading key from %s\r\n", ssl_rsa_key_file); } else { rc = SSL_check_private_key(con); if (!rc) { if ( ssl_debug_flag ) printf( "Private key does not match the certificate public key\r\n"); } } } } if (ssl_dsa_cert_file) { if ( ssl_debug_flag ) printf("Loading DSA certificate into SSL\r\n"); rc = SSL_use_certificate_file(con, ssl_dsa_cert_file, X509_FILETYPE_PEM); if (!rc) { if ( ssl_debug_flag ) { printf("Error loading certificate from %s\r\n", ssl_dsa_cert_file); } } else { if (!ssl_dh_key_file || !ssl_dh_key_file[0]) makestr(&ssl_dh_key_file,ssl_dsa_cert_file); rc = SSL_use_PrivateKey_file(con, ssl_dh_key_file, X509_FILETYPE_PEM); if (!rc) rc = SSL_use_PrivateKey_file(con, ssl_dsa_cert_file, X509_FILETYPE_PEM); if (!rc) { if ( !quiet || ssl_debug_flag ) { printf("Error loading key from %s\r\n", ssl_dh_key_file); } } else { rc = SSL_check_private_key(con); if (!rc) { if ( ssl_debug_flag ) printf( "Private key does not match the certificate public key\n"); } } } } } else { if (ssl_rsa_cert_file) { if ( ssl_debug_flag ) printf("Loading RSA certificate into SSL\r\n"); rc = SSL_CTX_use_certificate_file(ctx, ssl_rsa_cert_file, X509_FILETYPE_PEM); if (!rc) { if ( !quiet || ssl_debug_flag ) printf("Error loading certificate from %s\r\n", ssl_rsa_cert_file); } else { if (!ssl_rsa_key_file || !ssl_rsa_key_file[0]) makestr(&ssl_rsa_key_file,ssl_rsa_cert_file); rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_rsa_key_file, X509_FILETYPE_PEM); if (!rc) rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_rsa_cert_file, X509_FILETYPE_PEM); if (!rc) { if ( ssl_debug_flag ) printf("Error loading key from %s\r\n",ssl_rsa_key_file); } else { rc = SSL_CTX_check_private_key(ctx); if (!rc) { if ( ssl_debug_flag ) printf( "Private key does not match the certificate public key\r\n"); } } } } if (ssl_dsa_cert_file) { if ( ssl_debug_flag ) printf("Loading DSA certificate into SSL\r\n"); rc = SSL_CTX_use_certificate_file(ctx, ssl_dsa_cert_file, X509_FILETYPE_PEM); if (!rc) { if ( ssl_debug_flag ) { printf("Error loading certificate from %s\r\n", ssl_dsa_cert_file); } } else { if (!ssl_dh_key_file || !ssl_dh_key_file[0]) makestr(&ssl_dh_key_file,ssl_dsa_cert_file); rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_dh_key_file, X509_FILETYPE_PEM); if (!rc) rc = SSL_CTX_use_PrivateKey_file(ctx, ssl_dsa_cert_file, X509_FILETYPE_PEM); if (!rc) { if ( ssl_debug_flag ) printf("Error loading key from %s\r\n",ssl_dh_key_file); } else { rc = SSL_CTX_check_private_key(ctx); if (!rc) { if ( ssl_debug_flag ) printf( "Private key does not match the certificate public key\n"); } } } } } if (ssl_rsa_cert_chain_file && server) { int skip1st = 0; if (ssl_debug_flag) printf("Loading RSA Certificate Chain into SSL\r\n"); if (!ckstrcmp(ssl_rsa_cert_chain_file,ssl_rsa_cert_file,-1, #ifdef OS2 0 #else 1 #endif /* OS2 */ )) skip1st = 1; rc = SSL_CTX_use_certificate_chain_file(ctx,ssl_rsa_cert_chain_file); if (!rc && ssl_debug_flag) printf("Error loading RSA Certificate Chain into SSL\r\n"); } if (ssl_dsa_cert_chain_file && server) { int skip1st = 0; if (ssl_debug_flag) printf("Loading DSA Certificate Chain into SSL\r\n"); if (!ckstrcmp(ssl_dsa_cert_chain_file,ssl_dsa_cert_file,-1, #ifdef OS2 0 #else 1 #endif /* OS2 */ )) skip1st = 1; rc = SSL_CTX_use_certificate_chain_file(ctx,ssl_dsa_cert_chain_file); if (!rc && ssl_debug_flag) printf("Error loading DSA Certificate Chain into SSL\r\n"); } return(rc); } VOID #ifdef CK_ANSIC ssl_once_init(void) #else ssl_once_init() #endif /* CK_ANSIC */ { #ifndef OPENSSL_NO_COMP COMP_METHOD * cm; #endif char * s; if ( !ck_ssleay_is_installed() ) return; /* Pre-OpenSSL 1.0.0 comment: OpenSSL does not provide for ABI compatibility between releases prior to version 1.0.0. If the version does not match, it is not safe to assume that any function you call takes the same parameters or does the same thing with them. Removing this test prior to the OpenSSL 1.0.0 release will result in an increase in unexplained or incorrect behaviors. The test should be revised once OpenSSL 1.0.0 is released and we see what its claims are as to ABI compatibility. */ /* Post-OpenSSL 1.0.0 comment: OpenSSL does not provide for ABI compatibility between releases prior to version 1.0.0. After 1.0, the following holds: Changes to last letter: security and bugfix only, no new features. E.g. 1.0.0->1.0.0a Changes to last number: new ABI compatible features. E.g. 1.0.0->1.0.1 Changes to middle number: major release, ABI compatibility not guaranteed. E.g. 1.0.0->1.1.0 (per Dr. Stephen Henson) */ debug(F111,"Kermit built for OpenSSL",OPENSSL_VERSION_TEXT,SSLEAY_VERSION_NUMBER); #ifndef OS2ONLY debug(F111,"OpenSSL Library",SSLeay_version(SSLEAY_VERSION), SSLeay()); debug(F110,"OpenSSL Library",SSLeay_version(SSLEAY_BUILT_ON),0); debug(F110,"OpenSSL Library",SSLeay_version(SSLEAY_CFLAGS),0); debug(F110,"OpenSSL Library",SSLeay_version(SSLEAY_PLATFORM),0); /* The following test is suggested by Richard Levitte */ /* if (((OPENSSL_VERSION_NUMBER ^ SSLeay()) & 0xffffff0f) */ /* Modified by Adam Friedlander for OpenSSL >= 1.0.0 */ if (OPENSSL_VERSION_NUMBER > SSLeay() || ((OPENSSL_VERSION_NUMBER ^ SSLeay()) & COMPAT_VERSION_MASK) #ifdef OS2 /* DG 2024-08-05: Not sure what the point of this was. Presumably the goal was * to prevent updated OpenSSL libraries from being used, though why you'd * want to do that I'm not sure. Might have been to do with how Kermit 95s * SSH code was built way back in the early 2000s I guess. Today Kermit 95s * use of OpenSSL is largely the same as how C-Kermit uses it on other * platforms so I don't see any reason to treat it differently here. || ckstrcmp(OPENSSL_VERSION_TEXT,(char *)SSLeay_version(SSLEAY_VERSION),-1,1) */ #endif /* OS2 */ ) { ssl_installed = 0; debug(F111,"OpenSSL Version does not match. Built with", SSLeay_version(SSLEAY_VERSION),SSLEAY_VERSION_NUMBER); printf("?OpenSSL libraries do not match required version:\r\n"); printf(" . C-Kermit built with %s\r\n",OPENSSL_VERSION_TEXT); printf(" . Version found %s\r\n",SSLeay_version(SSLEAY_VERSION)); #ifdef OPENSSL_100 printf(" OpenSSL versions 1.0.0 or newer must be the same\r\n"); printf(" major and minor version number, and Kermit may not\r\n"); printf(" be used with a version of OpenSSL older than the one\r\n"); printf(" supplied at compile time.\r\n"); #else printf(" OpenSSL versions prior to 1.0.0 must be the same.\r\n"); #endif /* OPENSSL_100 */ s = "R"; #ifdef SOLARIS printf(" Set CD_LIBRARY_PATH for %s.\r\n",OPENSSL_VERSION_TEXT); s = " Or r"; #endif /* SOLARIS */ #ifdef HPUX printf(" Set SHLIB_PATH for %s.\r\n",OPENSSL_VERSION_TEXT); s = " Or r"; #endif /* HPUX */ #ifdef AIX printf(" Set LIBPATH for %s.\r\n",OPENSSL_VERSION_TEXT); s = " Or r"; #endif /* AIX */ #ifdef LINUX printf(" Set LD_LIBRARY_PATH for %s.\r\n",OPENSSL_VERSION_TEXT); s = " Or r"; #endif /* LINUX */ printf(" %sebuild C-Kermit from source on this computer to make \ versions agree.\r\n",s); #ifdef KTARGET { char * s; s = KTARGET; if (!s) s = ""; if (!*s) s = "(unknown)"; printf(" C-Kermit makefile target: %s\r\n",s); } #endif /* KTARGET */ printf(" Or if that is what you did then try to find out why\r\n"); printf(" the program loader (image activator) is choosing a\r\n"); printf(" different OpenSSL library than the one specified in \ the build.\r\n\r\n"); printf(" All SSL/TLS features disabled.\r\n\r\n"); bleep(BP_FAIL); #ifdef SSLDLL ck_ssl_unloaddll(); ck_crypto_unloaddll(); #endif /* SSLDLL */ return; } #endif /* OS2ONLY */ /* init things so we will get meaningful error messages * rather than numbers */ SSL_load_error_strings(); #ifdef SSHBUILTIN OPENSSL_add_all_algorithms_noconf(); #else /* SSL_library_init() only loads those ciphers needs for SSL */ /* These happen to be a similar set to those required for SSH */ /* but they are not a complete set of ciphers provided by the */ /* crypto library. */ SSL_library_init(); #endif /* SSHBUILTIN */ #ifndef OPENSSL_NO_COMP #ifdef ZLIB cm = COMP_zlib(); #if OPENSSL_VERSION_NUMBER >= 0x10100005L if (cm != NULL && COMP_get_type(cm) != NID_undef) { #else if (cm != NULL && cm->type != NID_undef) { #endif SSL_COMP_add_compression_method(0xe0, cm); /* EAY's ZLIB ID */ } #endif /* ZLIB */ #ifdef NID_rle_compression cm = COMP_rle(); #if OPENSSL_VERSION_NUMBER >= 0x10100005L if (cm != NULL && COMP_get_type(cm) != NID_undef) #else if (cm != NULL && cm->type != NID_undef) #endif SSL_COMP_add_compression_method(0xe1, cm); /* EAY's RLE ID */ #endif /* NID_rle_compression */ #endif /* OPENSSL_NO_COMP */ /* Ensure the Random number generator has enough entropy */ if ( !RAND_status() ) { char buffer[256]=""; char randombytes[256]; int rc1 = -1, rc2 = 1; /* assume failure and success */ debug(F110,"ssl_once_init","!RAND_status()",0); if ( ssl_rnd_file == NULL ) { debug(F110,"ssl_rnd_file","ssl_rnd_file is NULL",0); RAND_file_name(buffer,256); if ( buffer[0] ) makestr(&ssl_rnd_file, buffer); else makestr(&ssl_rnd_file,".rnd"); } debug(F110,"ssl_rnd_file",ssl_rnd_file,0); #ifndef OPENSSL_NO_EGD /* ifdef Bernard Spil 12/2015 */ rc1 = RAND_egd(ssl_rnd_file); debug(F111,"ssl_once_init","RAND_egd()",rc1); if ( rc1 <= 0 ) { rc2 = RAND_load_file(ssl_rnd_file, -1); debug(F111,"ssl_once_init","RAND_load_file()",rc1); } #endif /* OPENSSL_NO_EGD */ if ( rc1 <= 0 && !rc2 ) { time_t t = time(NULL); int tlen = sizeof(time_t); int pid = getpid(); int plen = sizeof(int); int n; #ifndef RAND_MAX #define RAND_MAX 0x7FFF #endif debug(F110,"ssl_once_init","calling RAND_seed()",0); RAND_seed((unsigned char *)&t, tlen); RAND_seed((unsigned char *)&pid, plen); srand((unsigned int)t); sprintf(buffer, "%.0f", (((double)(rand()%RAND_MAX)/RAND_MAX)* (sizeof(randombytes)-128-1))); n = (atoi(buffer)+1)%(sizeof(randombytes)-128-1); RAND_seed(randombytes, 128); } if ( !RAND_status() ) { debug(F110,"ssl_once_init","Unable to initialize PRNG",0); printf(" Unable to load 'random state'\n"); printf(" SSL and TLS are unavailble.\n"); printf(" Use SET AUTH SSL RANDOM-FILE command to provide random data.\n"); printf(" Specified file will be overwritten with new random data after use.\n"); return; } if ( ssl_rnd_file ) { int rc = RAND_write_file(ssl_rnd_file); debug(F111,"ssl_once_init","RAND_write_file()",rc); } } #ifdef NT // Initialize additional OID types for use when saving certs to a file OBJ_create("2.99999.3","SET.ex3","SET x509v3 extension 3"); #endif /* NT */ /* make sure we have somewhere we can log errors to */ bio_err=BIO_new(BIO_s_mem()); debug(F100,"ssl_once_init() complete","",0); } int #ifdef CK_ANSIC ssl_tn_init(int mode) #else ssl_tn_init(mode) int mode; #endif /* CK_ANSIC */ { #ifdef KRB5 extern char * k5_keytab; extern char * krb5_d_srv; #endif /* KRB5 */ static int last_ssl_mode = -1; SSL * ssl_conx=NULL, * tls_conx=NULL; ssl_initialized = 0; if ( !ck_ssleay_is_installed() ) return(0); debug(F111,"ssl_tn_init","mode",mode); if (ssl_debug_flag) printf("SSL_DEBUG_FLAG on\r\n"); if (last_ssl_mode != mode) { if (ssl_ctx) { SSL_CTX_free(ssl_ctx); ssl_ctx = NULL; } if (tls_ctx) { SSL_CTX_free(tls_ctx); tls_ctx = NULL; } } if ( (last_ssl_mode != mode) || !ssl_ctx || !tls_ctx ) { if ( mode == SSL_CLIENT ) { ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_client_method()); /* This can fail because we do not have RSA available */ if ( !ssl_ctx ) { debug(F110,"ssl_tn_init","SSLv23_client_method failed",0); last_ssl_mode = -1; return(0); } /* TLS 1.0 is the new default as of 5 Feb 2015. Previously this was commented out because "too many web servers still do not support TLSv1". Now we try TLS 1.0 first, falling back to SSL 2.3 and SSL 3.0 in that order. Maybe there should be an option not to fall back. 2022-09-06: 7+ years later and TLS 1.0/1.1 are now deprecated and usually disabled for security reasons. Use TLS_client_method where available as this negotiates the newest version of TLS supported by both ends. Else use TLS 1.2 or 1.0. */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* OpenSSL >= 1.1.0: Negotiate the best TLS version possible */ tls_ctx=(SSL_CTX *)SSL_CTX_new(TLS_client_method()); #else /* OPENSSL_VERSION_NUMBER < 0x10100000L */ #if OPENSSL_VERSION_NUMBER >= 0x10001000L /* OpenSSL >= 1.0.1: Use TLS 1.2 - not yet deprecated as of 2022-09-06 */ tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_2_client_method()); #else /* OpenSSL 0.9.8 and 1.0.0 can't handle anything newer than TSL 1.0 */ tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_client_method()); #endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */ #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ if ( tls_ctx ) { debug(F110,"ssl_tn_init","TLS_client_method OK",0); } else { debug(F110,"ssl_tn_init","TLS_client_method failed",0); /* This can fail because we do not have RSA available */ tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_client_method()); if ( !tls_ctx ) { debug(F110,"ssl_tn_init","SSLv23_client_method OK",0); } else { debug(F110,"ssl_tn_init","SSLv23_client_method failed",0); #ifndef OPENSSL_NO_SSL3 /* ifdef Bernard Spil 12/2015 */ tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_client_method()); #endif /* OPENSSL_NO_SSL3 */ if ( !tls_ctx ) { debug(F110, "ssl_tn_init","TLS_client_method failed",0); debug(F110, "ssl_tn_init","All SSL client methods failed",0); last_ssl_mode = -1; return(0); } } } #ifdef USE_CERT_CB SSL_CTX_set_client_cert_cb(ssl_ctx,ssl_client_cert_callback); SSL_CTX_set_client_cert_cb(tls_ctx,ssl_client_cert_callback); #endif /* USE_CERT_CB */ } else if (mode == SSL_SERVER) { /* We are a server */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* Since OpenSSL 1.1.0, SSLv23_server_method() has been renamed to * TLS_server_method with the old name #defined to the new one. This * is still the case in OpenSSL 3.1 but perhaps someday the old name * will disappear so for OpenSSL 1.1.0 and newer we'll just use the * new name. */ ssl_ctx=(SSL_CTX *)SSL_CTX_new(TLS_server_method()); /* This can fail because we do not have RSA available */ if ( !ssl_ctx ) { debug(F110,"ssl_tn_init","TLS_server_method failed",0); last_ssl_mode = -1; return(0); } tls_ctx=(SSL_CTX *)SSL_CTX_new(TLS_server_method()); if ( !tls_ctx ) { debug(F110,"ssl_tn_init","TLS_server_method failed",0); last_ssl_mode = -1; return(0); } #else /* OPENSSL_VERSION_NUMBER < 0x10100000L */ ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_server_method()); /* This can fail because we do not have RSA available */ if ( !ssl_ctx ) { debug(F110,"ssl_tn_init","SSLv23_server_method failed",0); last_ssl_mode = -1; return(0); } tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_server_method()); /* This can fail because we do not have RSA available */ if ( !tls_ctx ) { debug(F110,"ssl_tn_init","SSLv23_server_method failed",0); tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_server_method()); } if ( !tls_ctx ) { debug(F110,"ssl_tn_init","TLSv1_server_method failed",0); last_ssl_mode = -1; return(0); } #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ } else /* Unknown mode */ return(0); if ( !inserver ) { SSL_CTX_set_default_passwd_cb(ssl_ctx, (pem_password_cb *)ssl_passwd_callback); SSL_CTX_set_default_passwd_cb(tls_ctx, (pem_password_cb *)ssl_passwd_callback); } /* for SSL switch on all the interoperability and bug * workarounds so that we will communicate with people * that cannot read poorly written specs :-) * for TLS be sure to prevent use of SSLv2 */ SSL_CTX_set_options(ssl_ctx,SSL_OP_ALL|SSL_OP_NO_SSLv2); SSL_CTX_set_options(tls_ctx, SSL_OP_NO_SSLv2|SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA); SSL_CTX_set_info_callback(ssl_ctx,ssl_client_info_callback); SSL_CTX_set_info_callback(tls_ctx,ssl_client_info_callback); /* Set the proper caching mode */ if ( mode == SSL_SERVER ) { SSL_CTX_set_session_cache_mode(ssl_ctx,SSL_SESS_CACHE_SERVER); SSL_CTX_set_session_cache_mode(tls_ctx,SSL_SESS_CACHE_SERVER); } else { SSL_CTX_set_session_cache_mode(ssl_ctx,SSL_SESS_CACHE_CLIENT); SSL_CTX_set_session_cache_mode(tls_ctx,SSL_SESS_CACHE_CLIENT); } SSL_CTX_set_session_id_context(ssl_ctx,(CHAR *)"1",1); SSL_CTX_set_session_id_context(tls_ctx,(CHAR *)"2",1); } /* The server uses defaults for the certificate files. */ /* The client does not. */ if (mode == SSL_SERVER) { char cert_filepath[1024]; const char * defdir = NULL; DH * dh = NULL; defdir = getenv("SSL_CERT_DIR"); if ( !defdir ) { #ifdef OS2 defdir = exedir; #else /* OS2 */ defdir = X509_get_default_cert_dir(); #endif /* OS2 */ debug(F110,"ssl_tn_init - setting default directory to",defdir,0); } if ( !defdir ) defdir = ""; if (!ssl_rsa_cert_file) { /* we need to know the fullpath to the location of the * certificate that we will be running with as we cannot * be sure of the cwd when we are launched */ sprintf(cert_filepath,"%s/%s",defdir,"telnetd-rsa.pem"); if (zchki(cert_filepath) > 0) makestr(&ssl_rsa_cert_file,cert_filepath); } if (ssl_rsa_cert_file && !ssl_rsa_key_file) { /* we need to know the fullpath to the location of the * certificate that we will be running with as we cannot * be sure of the cwd when we are launched */ sprintf(cert_filepath,"%s/%s",defdir,"telnetd-rsa-key.pem"); if (zchki(cert_filepath) > 0) makestr(&ssl_rsa_key_file,cert_filepath); } if (!ssl_dsa_cert_file) { /* we need to know the fullpath to the location of the * certificate that we will be running with as we cannot * be sure of the cwd when we are launched */ sprintf(cert_filepath,"%s/%s",defdir,"telnetd-dsa.pem"); if (zchki(cert_filepath) > 0) makestr(&ssl_dsa_cert_file,cert_filepath); } if (ssl_dsa_cert_file && !ssl_dh_key_file) { /* we need to know the fullpath to the location of the * certificate that we will be running with as we cannot * be sure of the cwd when we are launched */ sprintf(cert_filepath,"%s/%s",defdir,"telnetd-dsa-key.pem"); if (zchki(cert_filepath) > 0) makestr(&ssl_dh_key_file,cert_filepath); } if (!ssl_crl_dir) { /* we need to know the fullpath to the location of the * certificate that we will be running with as we cannot * be sure of the cwd when we are launched */ sprintf(cert_filepath,"%s/crl",defdir); if (zchki(cert_filepath) > 0) makestr(&ssl_crl_dir,cert_filepath); } if (ssl_only_flag && !tls_load_certs(ssl_ctx,ssl_con,1)) { debug(F110,"ssl_tn_init","Unable to load SSL certs",0); last_ssl_mode = -1; return(0); } if (tls_only_flag && !tls_load_certs(tls_ctx,tls_con,1)) { debug(F110,"ssl_tn_init","Unable to load TLS certs",0); last_ssl_mode = -1; return(0); } if ( (last_ssl_mode != mode) || !ssl_ctx || !tls_ctx ) { /* we may require a temp 512 bit RSA key because of the * wonderful way export things work ... if so we generate * one now! */ SSL_CTX_set_tmp_rsa_callback(ssl_ctx, tmp_rsa_cb); SSL_CTX_set_tmp_dh_callback( ssl_ctx, tmp_dh_cb); SSL_CTX_set_tmp_rsa_callback(tls_ctx, tmp_rsa_cb); SSL_CTX_set_tmp_dh_callback( tls_ctx, tmp_dh_cb); dh = tmp_dh_cb(NULL,0,512); SSL_CTX_set_tmp_dh(ssl_ctx,dh); SSL_CTX_set_tmp_dh(tls_ctx,dh); /* The following code is only called if we are using a * certificate with an RSA public key and where the * certificate has a key length less than 512 bits or is * marked for signing only. This is so we can support * the greatest legal privacy level with exportable clients. */ if (SSL_CTX_need_tmp_RSA(ssl_ctx) || SSL_CTX_need_tmp_RSA(tls_ctx)) { RSA *rsa; if ( ssl_debug_flag ) printf("Generating temp (512 bit) RSA key ...\r\n"); rsa = RSA_new(); if (rsa) { int error = RSA_generate_key_ex(rsa,512,get_RSA_F4(),NULL); if (error) { RSA_free(rsa); rsa = NULL; } } if ( ssl_debug_flag ) printf("Generation of temp (512 bit) RSA key done\r\n"); if (SSL_CTX_need_tmp_RSA(ssl_ctx)) { if (!SSL_CTX_set_tmp_rsa(ssl_ctx,rsa)) { if ( ssl_debug_flag ) printf( "Failed to assign generated temp RSA key to SSL!\r\n"); } } if (SSL_CTX_need_tmp_RSA(tls_ctx)) { if (!SSL_CTX_set_tmp_rsa(tls_ctx,rsa)) { if ( ssl_debug_flag ) printf( "Failed to assign generated temp RSA key to TLS!\r\n"); } } RSA_free(rsa); if ( ssl_debug_flag ) printf("Assigned temp (512 bit) RSA key\r\n"); } } } /* make sure we will find certificates in the standard * location ... otherwise we don't look anywhere for * these things which is going to make client certificate * exchange rather useless :-) * In OS2, default values for ssl_verify_file and ssl_verify_path. */ #ifdef OS2 #ifdef NT { /* The defaults in the SSL crypto library are not appropriate for OS/2 */ char path[CKMAXPATH]; ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL); if (isdir(path) && SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1) { debug(F110,"ssl_tn_init certificate verify dir",path,0); if (ssl_debug_flag) printf(" Certificate Verification Directory: %s\r\n",path); SSL_CTX_load_verify_locations(ssl_ctx,NULL,path); } ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/certs",NULL,NULL); if (isdir(path) && SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1) { debug(F110,"ssl_tn_init certificate verify dir",path,0); if (ssl_debug_flag) printf(" Certificate Verification Directory: %s\r\n",path); SSL_CTX_load_verify_locations(ssl_ctx,NULL,path); } ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/certs",NULL,NULL); if (isdir(path) && SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1) { debug(F110,"ssl_tn_init certificate verify dir",path,0); if (ssl_debug_flag) printf(" Certificate Verification Directory: %s\r\n",path); SSL_CTX_load_verify_locations(ssl_ctx,NULL,path); } ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL); if (zchki(path) > 0 && SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) { debug(F110,"ssl_tn_init certificate verify file",path,0); if (ssl_debug_flag) printf(" Certificate Verification File: %s\r\n",path); SSL_CTX_load_verify_locations(ssl_ctx,path,NULL); } ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_certs.pem",NULL,NULL); if (zchki(path) > 0 && SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) { debug(F110,"ssl_tn_init certificate verify file",path,0); if (ssl_debug_flag) printf(" Certificate Verification File: %s\r\n",path); SSL_CTX_load_verify_locations(ssl_ctx,path,NULL); } ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_certs.pem",NULL,NULL); if (zchki(path) > 0 && SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) { debug(F110,"ssl_tn_init certificate verify file",path,0); if (ssl_debug_flag) printf(" Certificate Verification File: %s\r\n",path); SSL_CTX_load_verify_locations(ssl_ctx,path,NULL); } } #else /* NT */ { /* The defaults in the SSL crypto library are not appropriate for OS/2 */ char path[CKMAXPATH]; ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL); if (isdir(path) && SSL_CTX_load_verify_locations(tls_ctx,NULL,path) == 1) { debug(F110,"ssl_tn_init certificate verify dir",path,0); if (ssl_debug_flag) printf(" Certificate Verification Directory: %s\r\n",path); SSL_CTX_load_verify_locations(ssl_ctx,NULL,path); } ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL); if (zchki(path) > 0 && SSL_CTX_load_verify_locations(tls_ctx,path,NULL) == 1) { debug(F110,"ssl_tn_init certificate verify file",path,0); if (ssl_debug_flag) printf(" Certificate Verification File: %s\r\n",path); SSL_CTX_load_verify_locations(ssl_ctx,path,NULL); } } #endif /* NT */ #else /* OS2 */ SSL_CTX_set_default_verify_paths(ssl_ctx); SSL_CTX_set_default_verify_paths(tls_ctx); #endif /* OS2 */ if (ssl_verify_file) { if (zchki(ssl_verify_file) > 0 && SSL_CTX_load_verify_locations(tls_ctx,ssl_verify_file,NULL) == 1) { debug(F110,"ssl_tn_init certificate verify file",ssl_verify_file,0); if (ssl_debug_flag) printf(" Certificate Verification File: %s\r\n",ssl_verify_file); SSL_CTX_load_verify_locations(ssl_ctx,ssl_verify_file,NULL); } } if (ssl_verify_dir && isdir(ssl_verify_dir)) { if (SSL_CTX_load_verify_locations(tls_ctx,NULL,ssl_verify_dir) == 1) { debug(F110,"ssl_tn_init certificate verify dir",ssl_verify_dir,0); if (ssl_debug_flag) printf(" Certificate Verification Directory: %s\r\n",ssl_verify_dir); SSL_CTX_load_verify_locations(ssl_ctx,NULL,ssl_verify_dir); } } if (mode == SSL_SERVER) { SSL_CTX_set_verify(ssl_ctx, ssl_verify_flag?ssl_verify_flag|SSL_VERIFY_CLIENT_ONCE:0, ssl_server_verify_callback); SSL_CTX_set_verify(tls_ctx, ssl_verify_flag?ssl_verify_flag|SSL_VERIFY_CLIENT_ONCE:0, ssl_server_verify_callback); } else { SSL_CTX_set_verify(ssl_ctx,ssl_verify_flag, ssl_client_verify_callback); SSL_CTX_set_verify(tls_ctx,ssl_verify_flag, ssl_client_verify_callback); } /* Free the existing CRL Store */ if (crl_store) { X509_STORE_free(crl_store); crl_store = NULL; } /* set up the new CRL Store */ crl_store = X509_STORE_new(); if (crl_store) { #ifdef OS2 char path[CKMAXPATH]; ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL); if (isdir(path) && X509_STORE_load_locations(crl_store,NULL,path) == 1) { debug(F110,"ssl_tn_init crl dir",path,0); if (ssl_debug_flag) printf(" CRL Directory: %s\r\n",path); } #ifdef NT ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/crls",NULL,NULL); if (isdir(path) && X509_STORE_load_locations(crl_store,NULL,path) == 1) { debug(F110,"ssl_tn_init crl dir",path,0); if (ssl_debug_flag) printf(" CRL Directory: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/crls",NULL,NULL); if (isdir(path) && X509_STORE_load_locations(crl_store,NULL,path) == 1) { debug(F110,"ssl_tn_init crl dir",path,0); if (ssl_debug_flag) printf(" CRL Directory: %s\r\n",path); } #endif /* NT */ ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL); if (zchki(path) > 0 && X509_STORE_load_locations(crl_store,path,NULL) == 1) { debug(F110,"ssl_tn_init crl file",path,0); if (ssl_debug_flag) printf(" CRL File: %s\r\n",path); } #ifdef NT ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_crls.pem",NULL,NULL); if (zchki(path) > 0 && X509_STORE_load_locations(crl_store,path,NULL) == 1) { debug(F110,"ssl_tn_init crl file",path,0); if (ssl_debug_flag) printf(" CRL File: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_crls.pem",NULL,NULL); if (zchki(path) > 0 && X509_STORE_load_locations(crl_store,path,NULL) == 1) { debug(F110,"ssl_tn_init crl file",path,0); if (ssl_debug_flag) printf(" CRL File: %s\r\n",path); } #endif /* NT */ #endif /* OS2 */ if (ssl_crl_file || ssl_crl_dir) { if (ssl_crl_file && zchki(ssl_crl_file) > 0 && X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 1) { debug(F110,"ssl_tn_init crl file",ssl_crl_file,0); if (ssl_debug_flag) printf(" CRL File: %s\r\n",ssl_crl_file); } if (ssl_crl_dir && isdir(ssl_crl_dir) && X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 1) { debug(F110,"ssl_tn_init crl dir",ssl_crl_dir,0); if (ssl_debug_flag) printf(" CRL Directory: %s\r\n",ssl_crl_dir); } } #ifndef OS2 else { X509_STORE_set_default_paths(crl_store); } #endif /* OS2 */ } #ifndef COMMENT ssl_conx = ssl_con; ssl_con=(SSL *)SSL_new(ssl_ctx); if ( !ssl_con ) { debug(F110,"ssl_tn_init","SSL_new(ssl_con) failed",0); last_ssl_mode = -1; ssl_con = ssl_conx; return(0); } if (ssl_conx) { if ( mode == SSL_CLIENT ) { SSL_set_session(ssl_con, SSL_get_session(ssl_conx)); } #ifdef SSL_KRB5 if (ssl_conx->kssl_ctx) { kssl_ctx_free(ssl_conx->kssl_ctx); ssl_conx->kssl_ctx = NULL; } #endif /* SSL_KRB5 */ SSL_free(ssl_conx); ssl_conx = NULL; } tls_conx = tls_con; tls_con=(SSL *)SSL_new(tls_ctx); if ( !tls_con ) { debug(F110,"ssl_tn_init","SSL_new(tls_con) failed",0); last_ssl_mode = -1; tls_con = tls_conx; return(0); } if (tls_conx) { if ( mode == SSL_CLIENT ) SSL_set_session(tls_con, SSL_get_session(tls_conx)); #ifdef SSL_KRB5 if (tls_conx->kssl_ctx) { kssl_ctx_free(tls_conx->kssl_ctx); tls_conx->kssl_ctx = NULL; } #endif /* SSL_KRB5 */ SSL_free(tls_conx); tls_conx = NULL; } #else /* COMMENT */ /* I don't know why this does not work to reuse the connection. */ if ( ssl_con ) { SSL_clear(ssl_con); SSL_set_session(ssl_con,NULL); SSL_set_accept_state(ssl_con) ; } else { ssl_con=(SSL *)SSL_new(ssl_ctx); if (!ssl_con) { debug(F110,"ssl_tn_init","SSL_new(ssl_ctx) failed",0); last_ssl_mode = -1; ssl_con = ssl_conx; return(0); } } if ( tls_con ) { SSL_clear(tls_con); SSL_set_session(tls_con,NULL); SSL_set_accept_state(tls_con) ; } else { tls_con=(SSL *)SSL_new(tls_ctx); if ( !tls_con ) { debug(F110,"ssl_tn_init","SSL_new(tls_ctx) failed",0); last_ssl_mode = -1; tls_con = tls_conx; return(0); } } #endif /* COMMENT */ #ifdef SSL_KRB5 #ifndef KRB5_SERVICE_NAME #define KRB5_SERVICE_NAME "host" #endif if (ssl_con->kssl_ctx == NULL) ssl_con->kssl_ctx = kssl_ctx_new(); if (tls_con->kssl_ctx == NULL) tls_con->kssl_ctx = kssl_ctx_new(); if (mode == SSL_SERVER) { if (ssl_con->kssl_ctx != NULL) kssl_ctx_setstring(ssl_con->kssl_ctx, KSSL_KEYTAB, k5_keytab); if (tls_con->kssl_ctx != NULL) kssl_ctx_setstring(tls_con->kssl_ctx, KSSL_KEYTAB, k5_keytab); } else { if (ssl_con->kssl_ctx != NULL) { if (!SSL_set_tlsext_host_name(ssl_con, hostname)) { debug(F100, "ssl_tn_init: SSL_set_tlsext_host_name failed", "", 0); } kssl_ctx_setstring(ssl_con->kssl_ctx, KSSL_SERVER, szHostName); } if (tls_con->kssl_ctx != NULL) { if (!SSL_set_tlsext_host_name(tls_con, hostname)) { debug(F100, "ssl_tn_init: SSL_set_tlsext_host_name failed", "", 0); } kssl_ctx_setstring(tls_con->kssl_ctx, KSSL_SERVER, szHostName); } } kssl_ctx_setstring(ssl_con->kssl_ctx, KSSL_SERVICE, krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME); kssl_ctx_setstring(tls_con->kssl_ctx, KSSL_SERVICE, krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME); #endif /* SSL_KRB5 */ if (ssl_cipher_list) { SSL_set_cipher_list(ssl_con,ssl_cipher_list); SSL_set_cipher_list(tls_con,ssl_cipher_list); } else { char * p; if ((p = getenv("SSL_CIPHER"))) { SSL_set_cipher_list(ssl_con,p); SSL_set_cipher_list(tls_con,p); } else { SSL_set_cipher_list(ssl_con,DEFAULT_CIPHER_LIST); SSL_set_cipher_list(tls_con,DEFAULT_CIPHER_LIST); } } ssl_verify_depth = -1; if ( ssl_debug_flag ) printf("SSL/TLS init done!\r\n"); ssl_initialized = 1; last_ssl_mode = mode; debug(F110,"ssl_tn_init","done",0); return(1); } #ifndef NOHTTP int #ifdef CK_ANSIC ssl_http_init(char * hostname) #else ssl_http_init(hostname) char * hostname; #endif /* CK_ANSIC */ { #ifdef KRB5 extern char * k5_keytab; extern char * krb5_d_srv; #endif /* KRB5 */ SSL * tls_conx=NULL; ssl_http_initialized = 0; if ( !ck_ssleay_is_installed() ) return(0); debug(F110,"ssl_http_init",hostname,0); if (ssl_debug_flag) printf("SSL_DEBUG_FLAG on\r\n"); if (!tls_http_ctx ) { /* TLS 1.0 is the new default as of 5 Feb 2015. Previously this was commented out because "too many web servers still do not support TLSv1". Now we try TLS 1.0 first, falling back to SSL 2.3 and SSL 3.0 in that order. Maybe there should be an option not to fall back. 2022-09-06: 7+ years later and TLS 1.0/1.1 are now deprecated and usually disabled for security reasons. Use TLS_client_method where available as this negotiates the newest version of TLS supported by both ends. Else use TLS 1.2 or 1.0. */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* OpenSSL >= 1.1.0: Negotiate the best TLS version possible */ tls_http_ctx=(SSL_CTX *)SSL_CTX_new(TLS_client_method()); #else /* OPENSSL_VERSION_NUMBER < 0x10100000L */ #if OPENSSL_VERSION_NUMBER >= 0x10001000L /* OpenSSL >= 1.0.1: Use TLS 1.2 - not yet deprecated as of 2022-09-06 */ tls_http_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_2_client_method()); #else /* OpenSSL 0.9.8 and 1.0.0 can't handle anything newer than TSL 1.0 */ tls_http_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_client_method()); #endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */ #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ if ( tls_http_ctx ) { debug(F110,"ssl_http_init","TLS_client_method OK",0); } } SSL_CTX_set_default_passwd_cb(tls_http_ctx, (pem_password_cb *)ssl_passwd_callback); /* for SSL switch on all the interoperability and bug * workarounds so that we will communicate with people * who cannot read poorly written specs :-) * for TLS be sure to prevent use of SSLv2 */ SSL_CTX_set_options(tls_http_ctx, SSL_OP_NO_SSLv2/*|SSL_OP_NO_SSLv3*/|SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA); SSL_CTX_set_info_callback(tls_http_ctx,ssl_client_info_callback); #ifndef COMMENT SSL_CTX_set_session_cache_mode(tls_http_ctx,SSL_SESS_CACHE_CLIENT); SSL_CTX_set_session_id_context(tls_http_ctx,(CHAR *)"3",1); #else /* COMMENT */ SSL_CTX_set_session_cache_mode(tls_http_ctx,SSL_SESS_CACHE_OFF); #endif /* COMMENT */ /* make sure we will find certificates in the standard * location ... otherwise we don't look anywhere for * these things which is going to make client certificate * exchange rather useless :-) */ #ifdef OS2 #ifdef NT { /* The defaults in the SSL crypto library are not appropriate for OS/2 */ char path[CKMAXPATH]; ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL); if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0) { debug(F110,"ssl_http_init unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-dir: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/certs",NULL,NULL); if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0) { debug(F110,"ssl_http_init unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-dir: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/certs",NULL,NULL); if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0) { debug(F110,"ssl_http_init unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-dir: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL); if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) { debug(F110,"ssl_http_init unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-file: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_certs.pem",NULL,NULL); if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) { debug(F110,"ssl_http_init unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-file: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_certs.pem",NULL,NULL); if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) { debug(F110,"ssl_http_init unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-file: %s\r\n",path); } } #else /* NT */ { /* The defaults in the SSL crypto library are not appropriate for OS/2 */ char path[CKMAXPATH]; ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL); if (SSL_CTX_load_verify_locations(tls_http_ctx,NULL,path) == 0) { debug(F110,"ssl_http_init unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-dir: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL); if (SSL_CTX_load_verify_locations(tls_http_ctx,path,NULL) == 0) { debug(F110,"ssl_http_init unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-file: %s\r\n",path); } } #endif /* NT */ #else /* OS2 */ SSL_CTX_set_default_verify_paths(tls_http_ctx); #endif /* OS2 */ if (ssl_verify_file && SSL_CTX_load_verify_locations(tls_http_ctx,ssl_verify_file,NULL) == 0) { debug(F110,"ssl_http_init unable to load ssl_verify_file",ssl_verify_file,0); if (ssl_debug_flag) printf("?Unable to load verify-file: %s\r\n",ssl_verify_file); } if (ssl_verify_dir && SSL_CTX_load_verify_locations(tls_http_ctx,NULL,ssl_verify_dir) == 0) { debug(F110,"ssl_http_init unable to load ssl_verify_dir",ssl_verify_dir,0); if (ssl_debug_flag) printf("?Unable to load verify-dir: %s\r\n",ssl_verify_dir); } SSL_CTX_set_verify(tls_http_ctx,ssl_verify_flag, ssl_client_verify_callback); /* Free the existing CRL Store */ if (crl_store) { X509_STORE_free(crl_store); crl_store = NULL; } /* set up the new CRL Store */ crl_store = X509_STORE_new(); if (crl_store) { #ifdef OS2 char path[CKMAXPATH]; ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL); if (X509_STORE_load_locations(crl_store,NULL,path) == 0) { debug(F110,"ssl_http_init unable to load dir",path,0); if (ssl_debug_flag) printf("?Unable to load crl-dir: %s\r\n",path); } #ifdef NT ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/crls",NULL,NULL); if (X509_STORE_load_locations(crl_store,NULL,path) == 0) { debug(F110,"ssl_http_init unable to load dir",path,0); if (ssl_debug_flag) printf("?Unable to load crl-dir: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/crls",NULL,NULL); if (X509_STORE_load_locations(crl_store,NULL,path) == 0) { debug(F110,"ssl_http_init unable to load dir",path,0); if (ssl_debug_flag) printf("?Unable to load crl-dir: %s\r\n",path); } #endif /* NT */ ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL); if (X509_STORE_load_locations(crl_store,path,NULL) == 0) { debug(F110,"ssl_http_init unable to load file",path,0); if (ssl_debug_flag) printf("?Unable to load crl-file: %s\r\n",path); } #ifdef NT ckmakmsg(path,CKMAXPATH,GetAppData(1),"kermit 95/ca_crls.pem",NULL,NULL); if (X509_STORE_load_locations(crl_store,path,NULL) == 0) { debug(F110,"ssl_http_init unable to load file",path,0); if (ssl_debug_flag) printf("?Unable to load crl-file: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/ca_crls.pem",NULL,NULL); if (X509_STORE_load_locations(crl_store,path,NULL) == 0) { debug(F110,"ssl_http_init unable to load file",path,0); if (ssl_debug_flag) printf("?Unable to load crl-file: %s\r\n",path); } #endif /* NT */ #endif /* OS2 */ if (ssl_crl_file || ssl_crl_dir) { if (ssl_crl_file && X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 0) { debug(F110,"ssl_http_init unable to load ssl_crl_file",ssl_crl_file,0); if (ssl_debug_flag) printf("?Unable to load crl-file: %s\r\n",ssl_crl_file); } if (ssl_crl_dir && X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 0) { debug(F110,"ssl_http_init unable to load ssl_crl_dir",ssl_crl_dir,0); if (ssl_debug_flag) printf("?Unable to load crl-dir: %s\r\n",ssl_crl_dir); } } else { X509_STORE_set_default_paths(crl_store); } } #ifndef COMMENT tls_conx = tls_http_con; tls_http_con=(SSL *)SSL_new(tls_http_ctx); if ( !tls_http_con ) { debug(F110,"ssl_http_init","SSL_new(tls_http_con) failed",0); tls_http_con = tls_conx; return(0); } if (tls_conx) { SSL_set_session(tls_http_con, SSL_get_session(tls_conx)); #ifdef SSL_KRB5 if (tls_conx->kssl_ctx) { kssl_ctx_free(tls_conx->kssl_ctx); tls_conx->kssl_ctx = NULL; } #endif /* SSL_KRB5 */ SSL_free(tls_conx); tls_conx = NULL; } #else /* COMMENT */ /* I don't know why this does not work to reuse the connection. */ if ( tls_http_con ) { SSL_clear(tls_http_con); SSL_set_session(tls_http_con,NULL); SSL_set_accept_state(tls_http_con) ; } else { tls_http_con=(SSL *)SSL_new(tls_http_ctx); if ( !tls_http_con ) { debug(F110,"ssl_http_init","SSL_new(tls_http_ctx) failed",0); tls_http_con = tls_conx; return(0); } } #endif /* COMMENT */ if (!SSL_set_tlsext_host_name(tls_http_con, hostname)) { debug(F100, "ssl_http_init: SSL_set_tlsext_host_name failed", "", 0); } #ifdef SSL_KRB5 #ifndef KRB5_SERVICE_NAME #define KRB5_SERVICE_NAME "host" #endif if (tls_http_con->kssl_ctx == NULL) tls_http_con->kssl_ctx = kssl_ctx_new(); if (tls_http_con->kssl_ctx != NULL) kssl_ctx_setstring(tls_http_con->kssl_ctx, KSSL_SERVER, hostname); kssl_ctx_setstring(tls_http_con->kssl_ctx, KSSL_SERVICE, krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME); #endif /* SSL_KRB5 */ if (ssl_cipher_list) SSL_set_cipher_list(tls_http_con,ssl_cipher_list); else { char * p; if ((p = getenv("SSL_CIPHER"))) { SSL_set_cipher_list(tls_http_con,p); } else { SSL_set_cipher_list(tls_http_con,DEFAULT_CIPHER_LIST); } } ssl_verify_depth = -1; if ( ssl_debug_flag ) printf("SSL/TLS init done!\r\n"); ssl_http_initialized = 1; return(1); } #endif /* NOHTTP */ char * #ifdef CK_ANSIC ssl_get_dNSName(SSL *ssl) #else ssl_get_dNSName(ssl) SSL * ssl; #endif /* CK_ANSIC */ { static char *dns = NULL; X509 *server_cert = NULL; int i; X509_EXTENSION *ext = NULL; STACK_OF(GENERAL_NAME) *ialt = NULL; GENERAL_NAME *gen = NULL; if ( dns ) { free(dns); dns = NULL; } if ((server_cert = SSL_get_peer_certificate(ssl))) { if ((i = X509_get_ext_by_NID(server_cert, NID_subject_alt_name, -1))<0) return NULL; if (!(ext = X509_get_ext(server_cert, i))) return NULL; X509V3_add_standard_extensions(); if (!(ialt = X509V3_EXT_d2i(ext))) return NULL; for (i = 0; i < sk_GENERAL_NAME_num(ialt); i++) { gen = sk_GENERAL_NAME_value(ialt, i); if (gen->type == GEN_DNS) { if (!gen->d.ia5 || !gen->d.ia5->length) break; if (strlen((char *)gen->d.ia5->data) != gen->d.ia5->length) { /* Ignoring IA5String containing null character */ continue; } dns = malloc(gen->d.ia5->length + 1); if (dns) { memcpy(dns, gen->d.ia5->data, gen->d.ia5->length); dns[gen->d.ia5->length] = 0; } break; } } #ifndef LIBRESSL_VERSION_NUMBER /* This function was removed in LibreSSL 3.9 * https://github.com/libressl/portable/issues/1050 * In both LibreSSL 3.9 and OpenSSL 3.4, X509V3_add_standard_extensions * does nothing so possibly there is nothing to clean up these days. * -- DG */ X509V3_EXT_cleanup(); #endif /* LIBRESSL_VERSION_NUMBER */ } cleanup: if (ialt) sk_GENERAL_NAME_free(ialt); if (server_cert) X509_free(server_cert); return dns; } char * #ifdef CK_ANSIC ssl_get_commonName(SSL *ssl) #else ssl_get_commonName(ssl) SSL * ssl; #endif /* CK_ANSIC */ { static char name[256]; int name_text_len; int err; X509 *server_cert; name_text_len = 0; if ((server_cert = SSL_get_peer_certificate(ssl))) { name_text_len = X509_NAME_get_text_by_NID(X509_get_subject_name(server_cert), NID_commonName, name, sizeof(name)); X509_free(server_cert); } if (name_text_len <= 0) { /* Common Name was empty or not retrieved */ err = 0; } else if (strlen(name) != name_text_len) { /* Ignoring Common Name containing null character */ err = 0; } else { err = 1; } if (err > 0) return name; else return NULL; } char * #ifdef CK_ANSIC ssl_get_issuer_name(SSL *ssl) #else ssl_get_issuer_name(ssl) SSL * ssl; #endif /* CK_ANSIC */ { static char name[256]; X509 *server_cert; name[0] = '\0'; if ((server_cert = SSL_get_peer_certificate(ssl))) { X509_NAME_oneline(X509_get_issuer_name(server_cert),name,sizeof(name)); X509_free(server_cert); return name; } else { #ifdef COMMENT fprintf(stderr, "Warning: No certificate from server!\r\n"); #endif /* COMMENT */ return NULL; } } char * #ifdef CK_ANSIC ssl_get_subject_name(SSL *ssl) #else ssl_get_subject_name(ssl) SSL * ssl; #endif /* CK_ANSIC */ { static char name[256]; X509 *server_cert; name[0] = '\0'; if ((server_cert = SSL_get_peer_certificate(ssl))) { X509_NAME_oneline(X509_get_subject_name(server_cert),name,sizeof(name)); X509_free(server_cert); return name; } else return NULL; } #ifdef COMMENT #ifdef CK_SSL && !(ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) && ssl_anonymous_cipher(tls_active_flag?tls_con:ssl_con)) #endif /* CK_SSL */ int ssl_anonymous_cipher(ssl) SSL * ssl; { X509 * cert; if (sstelnet) cert = SSL_get_certificate(ssl); else cert = SSL_get_peer_certificate(ssl); if ( cert ) { X509_free(cert); return 0; } return 1; } #endif /* COMMENT */ /* This one is (very much!) based on work by Ralf S. Engelschall . Comments by Ralf. */ int ssl_verify_crl(int ok, X509_STORE_CTX *ctx) { #if OPENSSL_VERSION_NUMBER >= 0x10100005L X509_OBJECT *obj; #else X509_OBJECT obj; #endif X509_NAME *subject = NULL; X509_NAME *issuer = NULL; X509 *xs = NULL; X509_CRL *crl = NULL; X509_REVOKED *revoked = NULL; X509_STORE_CTX * store_ctx = NULL; long serial; BIO *bio = NULL; int i, n, rc; char *cp; char *cp2; /* * Unless a revocation store for CRLs was created we * cannot do any CRL-based verification, of course. */ if (!crl_store) return ok; #if OPENSSL_VERSION_NUMBER >= 0x10100005L obj = X509_OBJECT_new(); if (!obj) return(ok); #else memset((char *)&obj, 0, sizeof(obj)); #endif store_ctx = X509_STORE_CTX_new(); if ( !store_ctx ) return(ok); /* * Determine certificate ingredients in advance */ xs = X509_STORE_CTX_get_current_cert(ctx); subject = X509_get_subject_name(xs); issuer = X509_get_issuer_name(xs); /* * OpenSSL provides the general mechanism to deal with CRLs but does not * use them automatically when verifying certificates, so we do it * explicitly here. We will check the CRL for the currently checked * certificate, if there is such a CRL in the store. * * We come through this procedure for each certificate in the certificate * chain, starting with the root-CA's certificate. At each step we've to * both verify the signature on the CRL (to make sure it's a valid CRL) * and it's revocation list (to make sure the current certificate isn't * revoked). But because to check the signature on the CRL we need the * public key of the issuing CA certificate (which was already processed * one round before), we've a little problem. But we can both solve it and * at the same time optimize the processing by using the following * verification scheme (idea and code snippets borrowed from the GLOBUS * project): * * 1. We'll check the signature of a CRL in each step when we find a CRL * through the _subject_ name of the current certificate. This CRL * itself will be needed the first time in the next round, of course. * But we do the signature processing one round before this where the * public key of the CA is available. * * 2. We'll check the revocation list of a CRL in each step when * we find a CRL through the _issuer_ name of the current certificate. * This CRLs signature was then already verified one round before. * * This verification scheme allows a CA to revoke its own certificate as * well, of course. */ /* * Try to retrieve a CRL corresponding to the _subject_ of * the current certificate in order to verify it's integrity. */ X509_STORE_CTX_init(store_ctx, crl_store, NULL, NULL); #if OPENSSL_VERSION_NUMBER >= 0x10100005L rc = X509_STORE_get_by_subject(store_ctx, X509_LU_CRL, subject, obj); X509_STORE_CTX_cleanup(store_ctx); crl = X509_OBJECT_get0_X509_CRL(obj); #else rc = X509_STORE_get_by_subject(store_ctx, X509_LU_CRL, subject, &obj); X509_STORE_CTX_cleanup(store_ctx); crl = obj.data.crl; #endif if (rc > 0 && crl != NULL) { /* * Verify the signature on this CRL */ if (X509_CRL_verify(crl, X509_get_pubkey(xs)) <= 0) { fprintf(stderr, "Invalid signature on CRL!\n"); X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); #if OPENSSL_VERSION_NUMBER >= 0x10100005L X509_OBJECT_free(obj); #else X509_OBJECT_free_contents(&obj); #endif X509_STORE_CTX_free(store_ctx); return 0; } /* * Check date of CRL to make sure it's not expired */ #if OPENSSL_VERSION_NUMBER >= 0x10100005L i = X509_cmp_current_time(X509_CRL_get0_nextUpdate(crl)); #else i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl)); #endif if (i == 0) { fprintf(stderr, "Found CRL has invalid nextUpdate field.\n"); X509_STORE_CTX_set_error(ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); #if OPENSSL_VERSION_NUMBER >= 0x10100005L X509_OBJECT_free(obj); #else X509_OBJECT_free_contents(&obj); #endif X509_STORE_CTX_free(store_ctx); return 0; } if (i < 0) { fprintf(stderr, "Found CRL is expired - revoking all certificates until you get updated CRL.\n" ); X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED); #if OPENSSL_VERSION_NUMBER >= 0x10100005L X509_OBJECT_free(obj); #else X509_OBJECT_free_contents(&obj); #endif X509_STORE_CTX_free(store_ctx); return 0; } #if OPENSSL_VERSION_NUMBER >= 0x10100005L X509_OBJECT_free(obj); #else X509_OBJECT_free_contents(&obj); #endif } /* * Try to retrieve a CRL corresponding to the _issuer_ of * the current certificate in order to check for revocation. */ #if OPENSSL_VERSION_NUMBER < 0x10100005L memset((char *)&obj, 0, sizeof(obj)); #endif X509_STORE_CTX_init(store_ctx, crl_store, NULL, NULL); #if OPENSSL_VERSION_NUMBER >= 0x10100005L rc = X509_STORE_get_by_subject(store_ctx, X509_LU_CRL, issuer, obj); X509_STORE_CTX_free(store_ctx); /* calls X509_STORE_CTX_cleanup() */ crl = X509_OBJECT_get0_X509_CRL(obj); #else rc = X509_STORE_get_by_subject(store_ctx, X509_LU_CRL, issuer, &obj); X509_STORE_CTX_free(store_ctx); /* calls X509_STORE_CTX_cleanup() */ crl = obj.data.crl; #endif if (rc > 0 && crl != NULL) { /* * Check if the current certificate is revoked by this CRL */ n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); for (i = 0; i < n; i++) { revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); #if OPENSSL_VERSION_NUMBER >= 0x10100005L if (ASN1_INTEGER_cmp(X509_REVOKED_get0_serialNumber(revoked), X509_get_serialNumber(xs)) == 0) { // } serial = ASN1_INTEGER_get(X509_REVOKED_get0_serialNumber(revoked)); #else if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(xs)) == 0) { serial = ASN1_INTEGER_get(revoked->serialNumber); #endif cp = X509_NAME_oneline(issuer, NULL, 0); free(cp); X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED); #if OPENSSL_VERSION_NUMBER >= 0x10100005L X509_OBJECT_free(obj); #else X509_OBJECT_free_contents(&obj); #endif return 0; } } #if OPENSSL_VERSION_NUMBER >= 0x10100005L X509_OBJECT_free(obj); #else X509_OBJECT_free_contents(&obj); #endif } return ok; } char * #ifdef CK_ANSIC tls_userid_from_client_cert(SSL *ssl) #else tls_userid_from_client_cert(ssl) SSL * ssl; #endif /* CK_ANSIC */ { /* DavidG 2022-09-05: On Windows and OS/2, X509_to_user is expected to be * provided by a user-supplied DLL as described here: * http://www.columbia.edu/kermit/security70.html#x3.1.4 * This DLL would normally be loaded in ckossl.c (search for X5092UID) but * at the moment that only happens when K95 is built with SSLDLL. SSLDLL is * only compatible with OpenSSL 0.9.x so in practice X509_to_user is never * available. It wouldn't be hard to make it work without SSLDLL if needed. */ #ifndef OS2 /* [jt] 2013/11/21 - K-95 doesn't have X509_to_user */ static char cn[256]; static char *r = cn; int err; X509 *client_cert; if ((client_cert = SSL_get_peer_certificate(ssl))) { /* call the custom function */ err = X509_to_user(client_cert, cn, sizeof(cn)); X509_free(client_cert); if (err) return r = NULL; else return r; } else return r = NULL; #else return NULL; #endif /* OS2 */ } unsigned char ** tls_get_SAN_objs(SSL * ssl, int type) /* returns NULL or an array of malloc'ed objects of type `type' from the server's * subjectAltName, remember to free() them all! */ { #define NUM_SAN_OBJS 64 static unsigned char *objs[NUM_SAN_OBJS]; unsigned char **rv = NULL; X509 *server_cert = NULL; int i, j; X509_EXTENSION *ext = NULL; STACK_OF(GENERAL_NAME) *ialt = NULL; GENERAL_NAME *gen = NULL; memset(objs, 0, sizeof(objs)); if ((server_cert = SSL_get_peer_certificate(ssl))) { if ((i = X509_get_ext_by_NID(server_cert, NID_subject_alt_name, -1)) < 0) goto eject; if (!(ext = X509_get_ext(server_cert, i))) goto eject; X509V3_add_standard_extensions(); if (!(ialt = X509V3_EXT_d2i(ext))) goto eject; rv = objs; for (i = 0, j = 0; i < sk_GENERAL_NAME_num(ialt) && j < NUM_SAN_OBJS - 2; i++) { gen = sk_GENERAL_NAME_value(ialt, i); /* The use of V_ASN1_CONTEXT_SPECIFIC is because OpenSSL 0.9.6 defined its * types | V_ASN1_CONTEXT_SPECIFIC. 0.9.7 does not. In case, we are built * with one and linked to the other we use this hack. */ if ((gen->type | V_ASN1_CONTEXT_SPECIFIC) == (type | V_ASN1_CONTEXT_SPECIFIC)) { if (!gen->d.ia5 || !gen->d.ia5->length) break; if (strlen((char *)gen->d.ia5->data) != gen->d.ia5->length) { /* Ignoring IA5String containing null character */ continue; } objs[j] = malloc(gen->d.ia5->length + 1); if (objs[j]) { memcpy(objs[j], gen->d.ia5->data, gen->d.ia5->length); objs[j][gen->d.ia5->length] = 0; j++; } } } #ifndef LIBRESSL_VERSION_NUMBER /* This function was removed in LibreSSL 3.9 * https://github.com/libressl/portable/issues/1050 * In both LibreSSL 3.9 and OpenSSL 3.4, X509V3_add_standard_extensions * does nothing so possibly there is nothing to clean up these days. * -- DG */ X509V3_EXT_cleanup(); #endif /* LIBRESSL_VERSION_NUMBER */ } eject: if (ialt) sk_GENERAL_NAME_free(ialt); if (server_cert) X509_free(server_cert); return rv; } static int dNSName_cmp(const char *host, const char *dNSName) { int c1 = 1, c2 = 1, num_comp, rv = -1; char *p, *p1, *p2, *host_copy=NULL, *dNSName_copy=NULL; /* first we count the number of domain name components in both parameters. * they should be equal many, or it's not a match */ p = (char *) host; while ((p = strstr(p, "."))) { c1++; p++; } p = (char *) dNSName; while ((p = strstr(p, "."))) { c2++; p++; } if (c1 != c2) return -1; num_comp = c1; makestr(&host_copy,host); makestr(&dNSName_copy,dNSName); if (host_copy == NULL || dNSName_copy == NULL) goto eject; /* make substrings by replacing '.' with '\0' */ p = dNSName_copy; while ((p = strstr(p, "."))) { *p = '\0'; p++; } p = host_copy; while ((p = strstr(p, "."))) { *p = '\0'; p++; } /* compare each component */ p1 = host_copy; p2 = dNSName_copy; for (; num_comp; num_comp--) { if (!ckmatch(p2, p1,0,1)) /* failed match */ goto eject; p1 += strlen(p1) + 1; p2 += strlen(p2) + 1; } /* match ok */ rv = 0; eject: if (dNSName_copy) free(dNSName_copy); if (host_copy) free(host_copy); return rv; } static int show_hostname_warning(char *s1, char *s2) { char prefix[1024]; int ok = 1; setverbosity(); ckmakxmsg(prefix,1024, "Warning: Hostname (\"", s1, "\") does not match server's certificate (\"", s2, "\")", NULL,NULL,NULL,NULL,NULL,NULL,NULL); if (ssl_verify_flag) ok = uq_ok(prefix, "Continue? (Y/N) ", 3, NULL, 0); else if (verbosity) printf(prefix); return(ok); } #ifndef OSF50 #ifndef HPUX10 #ifndef HPUX1100 #ifndef SCO_OSR505 #ifndef OpenBSD #ifndef FREEBSD4 #ifndef NETBSD15 #ifndef __DragonFly__ #ifndef LINUX #ifndef AIX41 #ifndef UW7 #ifndef IRIX65 #ifndef SOLARIS9 #ifndef SOLARIS8 #ifndef SOLARIS7 #ifndef MACOSX #ifdef DEC_TCPIP #define inet_aton INET_ATON #endif /* DEC_TCPIP */ #ifndef NO_DCL_INET_ATON static int inet_aton(char * ipaddress, struct in_addr * ia) { struct stringarray * q; union { unsigned long l; unsigned char b[4]; } dummy; q = cksplit(1,0,ipaddress,".","0123456789abcdefACDEF",8,0,0,0); if (q->a_size == 4) { dummy.b[0] = atoi(q->a_head[1]); dummy.b[1] = atoi(q->a_head[2]); dummy.b[2] = atoi(q->a_head[3]); dummy.b[3] = atoi(q->a_head[4]); ia->s_addr = dummy.l; return(ia->s_addr != 0); } return(0); } #endif /* NO_DCL_INET_ATON */ #endif /* MACOSX */ #endif /* SOLARIS7 */ #endif /* SOLARIS8 */ #endif /* SOLARIS9 */ #endif /* IRIX65 */ #endif /* UW7 */ #endif /* AIX41 */ #endif /* LINUX */ #endif /* __DragonFly__ */ #endif /* NETBSD15 */ #endif /* FREEBSD4 */ #endif /* OpenBSD */ #endif /* SCO_OSR505 */ #endif /* HPUX1100 */ #endif /* HPUX10 */ #endif /* OSF50 */ int ssl_check_server_name(SSL * ssl, char * hostname) /* returns 0 if hostname and server's cert matches, else -1 */ { char * commonName; unsigned char ** dNSName; unsigned char ** ipAddress; struct in_addr ia; int rv; setverbosity(); if (verbosity && !inserver) { if ((dNSName = tls_get_SAN_objs(ssl,GEN_DNS))) { int i = 0; for (i = 0; dNSName[i]; i++) { printf("Certificate[0] altSubjectName DNS=%s\r\n",dNSName[i]); free(dNSName[i]); } } if ((ipAddress = tls_get_SAN_objs(ssl,GEN_IPADD))) { int i = 0; char *server_ip; struct in_addr ia; for (i = 0; ipAddress[i]; i++) { if (ipAddress[i]) { ia.s_addr = *(unsigned long *)ipAddress[i]; server_ip = inet_ntoa(ia); printf("Certificate[0] altSubjectName IPAddr=%s\r\n",server_ip); } free(ipAddress[i]); } /* ipAddress points to a static - don't free */ } if ((dNSName = tls_get_SAN_objs(ssl,GEN_EMAIL))) { int i = 0; for (i = 0; dNSName[i]; i++) { printf("Certificate[0] altSubjectName Email=%s\r\n",dNSName[i]); free(dNSName[i]); } } if ((dNSName = tls_get_SAN_objs(ssl,GEN_URI))) { int i = 0; for (i = 0; dNSName[i]; i++) { printf("Certificate[0] altSubjectName URI=%s\r\n",dNSName[i]); free(dNSName[i]); } } if ((dNSName = tls_get_SAN_objs(ssl,GEN_OTHERNAME))) { int i = 0; for (i = 0; dNSName[i]; i++) { printf("Certificate[0] altSubjectName Other=%s\r\n",dNSName[i]); free(dNSName[i]); } } } /* first we check if `hostname' is in fact an ip address */ if (inet_aton(hostname, &ia)) { ipAddress = tls_get_SAN_objs(ssl,GEN_IPADD); if (ipAddress) { int i = 0; char *server_ip = "UNKNOWN"; for (i = 0; ipAddress[i]; i++) if (*(unsigned long *)ipAddress[i] == ia.s_addr) return 0; if (ipAddress[i - 1]) { ia.s_addr = *(unsigned long *)ipAddress[i - 1]; server_ip = inet_ntoa(ia); } rv = show_hostname_warning(hostname, server_ip) ? 0 : -1; for (i = 0; ipAddress[i]; i++) free(ipAddress[i]); } else { rv = show_hostname_warning(hostname, "NO IP IN CERT") ? 0 : -1; } return(rv); } /* look for dNSName(s) in subjectAltName in the server's certificate */ dNSName = tls_get_SAN_objs(ssl,GEN_DNS); if (dNSName) { int i = 0; for (i = 0; dNSName[i]; i++) { if (!dNSName_cmp(hostname,(char *)dNSName[i])) return 0; } rv = show_hostname_warning(hostname, (char *)((dNSName[i - 1] == NULL) ? (char *)"UNKNOWN" : (char *)dNSName[i - 1])) ? 0 : -1; for (i = 0; dNSName[i]; i++) free(dNSName[i]); return rv; } else if ((commonName = ssl_get_commonName(ssl))) { /* so the server didn't have any dNSName's, check the commonName */ if (!dNSName_cmp(hostname, commonName)) return 0; else return (show_hostname_warning(hostname, commonName) ? 0 : -1); } return -1; } /* Is 'user' authorized to access the system without a login */ int tls_is_user_valid(SSL * ssl, const char *user) { #ifndef OS2 /* [jt] 2013/11/21 - K-95 doesn't have X509_userok */ X509 *client_cert; int r = 0; if ( !ssl || !user || !user[0] ) return(0); if (!(client_cert = SSL_get_peer_certificate(ssl))) return 0; /* Use user supplied function */ r = X509_userok(client_cert,user); X509_free(client_cert); return r; #else return 0; #endif /* OS2 */ } int tls_is_anon(int x) { char buf[128]; const SSL_CIPHER * cipher; SSL * ssl = NULL; switch ( x ) { #ifndef NOFTP #ifndef SYSFTP case 1: /* ftp command */ if ( ssl_ftp_active_flag ) ssl = ssl_ftp_con; else return(0); break; case 2: /* ftp data */ if ( ssl_ftp_data_active_flag ) ssl = ssl_ftp_data_con; else return(0); break; #endif /* SYSFTP */ #endif /* NOFTP */ default: if (tls_active_flag) ssl = tls_con; else if (ssl_active_flag) ssl = ssl_con; else return(0); } cipher = SSL_get_current_cipher(ssl); if (SSL_CIPHER_description(cipher,buf,sizeof(buf))) { if (ckindex("Au=None",buf,0,0,0) != 0) return(1); /* anonymous */ return(0); /* known */ } else { /* could not get cipher description. Assume anonymous */ return(1); } } int tls_is_krb5(int x) { char buf[128]; const SSL_CIPHER * cipher; SSL * ssl = NULL; switch ( x ) { #ifndef NOFTP #ifndef SYSFTP case 1: /* ftp command */ if ( ssl_ftp_active_flag ) ssl = ssl_ftp_con; else return(0); break; case 2: /* ftp data */ if ( ssl_ftp_data_active_flag ) ssl = ssl_ftp_data_con; else return(0); break; #endif /* SYSFTP */ #endif /* NOFTP */ #ifndef NOHTTP case 3: if ( tls_http_active_flag ) ssl = tls_http_con; break; #endif /* NOHTTP */ default: if (tls_active_flag) ssl = tls_con; else if (ssl_active_flag) ssl = ssl_con; else return(0); } cipher = SSL_get_current_cipher(ssl); if (cipher && SSL_CIPHER_description(cipher,buf,sizeof(buf))) { if (ckindex("Au=KRB5",buf,0,0,0) != 0) return(1); /* krb5 */ } return(0); /* not */ } int ssl_get_client_finished(char *buf, int count) { #ifdef NO_GET_FINISHED return(0); #else if (sstelnet || tcp_incoming) { return(SSL_get_peer_finished(ssl_active_flag?ssl_con:tls_con, buf,count)); } else { return(SSL_get_finished(ssl_active_flag?ssl_con:tls_con, buf,count)); } #endif /* NO_GET_FINISHED */ } int ssl_get_server_finished(char *buf, int count) { #ifdef NO_GET_FINISHED return(0); #else if (sstelnet || tcp_incoming) { return(SSL_get_finished(ssl_active_flag?ssl_con:tls_con, buf,count)); } else { return(SSL_get_peer_finished(ssl_active_flag?ssl_con:tls_con, buf,count)); } #endif /* NO_GET_FINISHED */ } #ifdef CK_AUTHENTICATION int #ifdef CK_ANSIC ssl_reply(int how, unsigned char *data, int cnt) #else ssl_reply(how,data,cnt) int how; unsigned char *data; int cnt; #endif { char * str=NULL; setverbosity(); data += 4; /* Point to status byte */ cnt -= 4; if(cnt-- < 1) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } switch(*data++) { case SSL_ACCEPT: if (tn_deb || debses) tn_debug("[SSL - handshake starting]"); else if ( verbosity ) printf("[SSL - handshake starting]\r\n"); debug(F110,"ssl_reply","[SSL - handshake starting]",0); /* right ... now we drop into the SSL library */ if (!ssl_only_flag) { if (ssl_dummy_flag) { if (tn_deb || debses) tn_debug("[SSL - Dummy Connected]"); else if ( verbosity ) { printf("[SSL - Dummy Connected]\r\n"); } debug(F110,"ssl_reply","[SSL - Dummy Connected]",0); auth_finished(AUTH_UNKNOWN); accept_complete = 1; return AUTH_SUCCESS; } if (SSL_connect(ssl_con) <= 0) { int len; if (tn_deb || debses) { tn_debug("[SSL - FAILED]"); ERR_print_errors(bio_err); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; printf(ssl_err); } else if ( verbosity ) { printf("[SSL - FAILED]\r\n"); ERR_print_errors(bio_err); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; printf(ssl_err); } debug(F110,"ssl_reply","[SSL - FAILED]",0); auth_finished(AUTH_REJECT); ttclos(0); return AUTH_FAILURE; } else { if (tn_deb || debses) tn_debug("[SSL - OK]"); else if ( verbosity ) { printf("[SSL - OK]\r\n"); } debug(F110,"ssl_reply","[SSL - OK]",0); ssl_active_flag = 1; ssl_display_connect_details(ssl_con,0,verbosity); } } auth_finished(AUTH_UNKNOWN); accept_complete = 1; break; case SSL_REJECT: if (tn_deb || debses) { tn_debug( "[SSL - failed to switch on SSL - trying plaintext login]"); } else if ( verbosity ) { printf("[SSL - failed to switch on SSL]\r\n"); printf("Trying plaintext login:\r\n"); } debug(F110,"ssl_reply","[SSL - failed to switch on SSL]",0); auth_finished(AUTH_REJECT); return AUTH_FAILURE; default: return AUTH_FAILURE; } return AUTH_SUCCESS; } int #ifdef CK_ANSIC ssl_is(unsigned char *data, int cnt) #else ssl_is(data,cnt) unsigned char *data; int cnt; #endif { if ((cnt -= 4) < 1) return AUTH_FAILURE; setverbosity(); data += 4; switch(*data++) { case SSL_START: /* server starts the SSL stuff now ... */ if (!ssl_only_flag) { if ( !tls_load_certs(ssl_ctx,ssl_con,1) ) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } if (tn_deb || debses) tn_debug("[SSL - handshake starting]"); else if ( verbosity ) printf("[SSL - handshake starting]\r\n"); debug(F110,"ssl_is","[SSL - handshake starting]",0); SendSSLAuthSB(SSL_ACCEPT, (void *)0, 0); auth_ssl_valid = 1; if (ssl_dummy_flag) { if (tn_deb || debses) tn_debug("[SSL - Dummy Connected]"); else if ( verbosity ) { printf("[SSL - Dummy Connected]\r\n"); } debug(F110,"ssl_is","[SSL - Dummy Connected]",0); accept_complete = 1; auth_finished(AUTH_UNKNOWN); return AUTH_SUCCESS; } if (SSL_accept(ssl_con) <= 0) { char errbuf[1024]; sprintf(errbuf,"[SSL - SSL_accept error: %s", ERR_error_string(ERR_get_error(),NULL)); if (tn_deb || debses) tn_debug(errbuf); else if ( ssl_debug_flag ) printf("%s\r\n",errbuf); else if ( verbosity ) printf("[SSL - SSL_accept error]\r\n"); debug(F110,"ssl_is",errbuf,0); auth_finished(AUTH_REJECT); ttclos(0); return AUTH_FAILURE; } if (tn_deb || debses) tn_debug("[SSL - OK]"); else if ( verbosity ) { printf("[SSL - OK]\r\n"); } debug(F110,"ssl_is","[SSL - OK]",0); ssl_active_flag = 1; ssl_display_connect_details(ssl_con,1,verbosity); /* now check to see that we got exactly what we * wanted from the caller ... if a certificate is * required then we make 100% sure that we were * given one during the handshake (as it is an optional * part of SSL) */ #ifdef SSL_KRB5 if ( tls_is_krb5(0) ) { if (ssl_con->kssl_ctx->client_princ) debug(F110,"ssl_is KRB5",ssl_con->kssl_ctx->client_princ,0); } else #endif /* SSL_KRB5 */ if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { X509 * peer = SSL_get_peer_certificate(ssl_con); if (peer == NULL) { if (tn_deb || debses) tn_debug("[SSL - peer check failed]"); else if (ssl_debug_flag) printf("[SSL - peer check failed]\r\n"); debug(F110,"ssl_is","[SSL - peer check failed]",0); /* LOGGING REQUIRED HERE! */ auth_finished(AUTH_REJECT); return AUTH_FAILURE; } } auth_finished(AUTH_UNKNOWN); accept_complete = 1; } break; default: SendSSLAuthSB(SSL_REJECT, (void *) "Unknown option received", -1); if (tn_deb || debses) tn_debug("[SSL - Unknown option received]"); else printf("Unknown SSL option %d\r\n", data[-1]); debug(F111,"ssl_is","[SSL - Unknown option received]",data[-1]); auth_ssl_valid = 0; auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } return AUTH_SUCCESS; } #endif /* CK_AUTHENTICATION */ int ck_tn_tls_negotiate(VOID) { X509 * peer = NULL; char str[256], *uid=NULL; extern int sstelnet; if ( !ck_ssleay_is_installed() ) return(-1); setverbosity(); if (sstelnet) { /* server starts the TLS stuff now ... */ if (!tls_only_flag) { if ( !tls_load_certs(tls_ctx,tls_con,1) ) { auth_finished(AUTH_REJECT); return -1; } if (tn_deb || debses) tn_debug("[TLS - handshake starting]"); else if ( verbosity ) printf("[TLS - handshake starting]\r\n"); debug(F110,"ck_tn_tls_negotiate","[TLS - handshake starting]",0); if (ssl_dummy_flag) { if (tn_deb || debses) tn_debug("[TLS - Dummy Connected]"); else if ( verbosity ) { printf("[TLS - Dummy Connected]\r\n"); } debug(F110,"ck_tn_tls_negotiate","[TLS - Dummy Connected]",0); accept_complete = 1; auth_finished(AUTH_REJECT); return 0; } if (SSL_accept(tls_con) <= 0) { char errbuf[1024]; sprintf(errbuf,"[TLS - SSL_accept error: %s", ERR_error_string(ERR_get_error(),NULL)); if (tn_deb || debses) tn_debug(errbuf); else if ( ssl_debug_flag ) printf("%s\r\n",errbuf); else if ( verbosity ) printf("[TLS - SSL_accept error]\r\n"); debug(F110,"ck_tn_tls_negotiate",errbuf,0); auth_finished(AUTH_REJECT); return -1; } if (tn_deb || debses) tn_debug("[TLS - OK]"); else if ( verbosity ) { printf("[TLS - OK]\r\n"); } debug(F110,"ck_tn_tls_negotiate","[TLS - OK]",0); tls_active_flag = 1; ssl_display_connect_details(tls_con,1,verbosity); #ifdef SSL_KRB5 if ( tls_is_krb5(0) ) { if (tls_con->kssl_ctx->client_princ) { char *p; ckstrncpy(szUserNameAuthenticated, tls_con->kssl_ctx->client_princ, UIDBUFLEN); ckstrncpy(szUserNameRequested, tls_con->kssl_ctx->client_princ, UIDBUFLEN); for ( p = szUserNameRequested; *p ; p++ ) { if ( *p == '@' || *p == '/' ) { *p = '\0'; break; } } } else { szUserNameRequested[0] = '\0'; szUserNameAuthenticated[0] = '\0'; } #ifdef CK_LOGIN if (zvuser(szUserNameRequested)) auth_finished(AUTH_VALID); else #endif /* CK_LOGIN */ auth_finished(AUTH_USER); } else #endif /* SSL_KRB5 */ { /* now check to see that we got exactly what we * wanted from the caller ... if a certificate is * required then we make 100% sure that we were * given one during the handshake (as it is an optional * part of TLS) */ peer=SSL_get_peer_certificate(tls_con); if (peer == NULL) { debug(F100,"SSL_get_peer_certificate() == NULL","",0); auth_finished(AUTH_REJECT); if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { if (tn_deb || debses) tn_debug("[TLS - peer check failed]"); else if (ssl_debug_flag) { printf("[TLS - peer check failed]\r\n"); } debug(F110, "ck_tn_tls_negotiate", "[TLS - peer check failed]", 0 ); /* LOGGING REQUIRED HERE! */ return -1; } } else { debug(F100,"SSL_get_peer_certificate() != NULL","",0); X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName,str, 256 ); if ( verbosity ) printf("[TLS - commonName=%s]\r\n",str); X509_NAME_get_text_by_NID(X509_get_subject_name(peer), #ifndef NID_x500UniqueIdentifier NID_uniqueIdentifier, #else NID_x500UniqueIdentifier, #endif str, 256 ); if ( verbosity ) printf("[TLS - uniqueIdentifier=%s]\r\n",str); /* Try to determine user name */ uid = tls_userid_from_client_cert(tls_con); if ( uid ) { /* This code is very questionable. * How should it behave? * The client has presented a certificate that * contains a username. We have validated the * certificate but we do not automatically * log the user in unless there is a .tlslogin * file. */ ckstrncpy(szUserNameRequested,uid,UIDBUFLEN); #ifdef CK_LOGIN if (zvuser(uid)) auth_finished(AUTH_VALID); else #endif /* CK_LOGIN */ auth_finished(AUTH_USER); } else { szUserNameRequested[0] = '\0'; auth_finished(AUTH_REJECT); } } } } } else { char * str=NULL; if (tn_deb || debses) tn_debug("[TLS - handshake starting]"); else if ( verbosity ) printf("[TLS - handshake starting]\r\n"); debug(F110,"ck_tn_tls_negotiate","[TLS - handshake starting]",0); /* right ... now we drop into the SSL library */ if (!tls_only_flag) { char *subject=NULL, *issuer=NULL, *commonName=NULL, *dNSName=NULL; if (ssl_dummy_flag) { if (tn_deb || debses) tn_debug("[TLS - Dummy Connected]"); else if ( verbosity ) { printf("[TLS - Dummy Connected]\r\n"); } debug(F110,"ck_tn_tls_negotiate","[TLS - Dummy Connected]",0); auth_finished(AUTH_REJECT); accept_complete = 1; return 0; } #ifndef USE_CERT_CB if (!tls_load_certs(tls_ctx,tls_con,0)) return(-1); #endif /* USE_CERT_CB */ if (SSL_connect(tls_con) <= 0) { int len; if (tn_deb || debses) { tn_debug("[TLS - FAILED]"); ERR_print_errors(bio_err); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; printf(ssl_err); } else if ( verbosity ) { printf("[TLS - FAILED]\r\n"); ERR_print_errors(bio_err); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; printf(ssl_err); } debug(F110,"ck_tn_tls_negotiate","[TLS - FAILED]",0); auth_finished(AUTH_REJECT); return -1; } tls_active_flag = 1; if ( !ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER) && !tls_is_krb5(0)) { char prmpt[1024]; subject = ssl_get_subject_name(tls_con); if (!subject) { if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { if (tn_deb || debses) tn_debug("[TLS - FAILED]"); else if ( verbosity ) printf("[TLS - FAILED]\r\n"); debug(F110,"ck_tn_tls_negotiate","[TLS - FAILED]",0); auth_finished(AUTH_REJECT); return -1; } else { int ok; ok = uq_ok("Warning: Server didn't provide a certificate", "Continue? (Y/N)", 3, NULL, 0); if (!ok) { if (tn_deb || debses) tn_debug("[TLS - FAILED]"); else if ( verbosity ) printf("[TLS - FAILED]\r\n"); debug(F110, "ck_tn_tls_negotiate","[TLS - FAILED]",0); auth_finished(AUTH_REJECT); return -1; } } } else if (ssl_check_server_name(tls_con, szHostName)) { if (tn_deb || debses) tn_debug("[TLS - FAILED]"); else if ( verbosity ) printf("[TLS - FAILED]\r\n"); debug(F110, "ck_tn_tls_negotiate","[TLS - FAILED]",0); auth_finished(AUTH_REJECT); return -1; } } if ( ssl_debug_flag && ssl_finished_messages) { char msg[32]; int i, len=32; extern char tn_msg[], hexbuf[]; tn_msg[0] = '\0'; len = ssl_get_client_finished(msg,len); if ( len > 0 ) { for ( i=0;i 0 ) { for ( i=0;i 0) return 0; /* END EXAMPLE */ #else /* X509_UID_TO_USER */ #ifdef X509_SUBJECT_ALT_NAME_TO_USER /* BEGIN EXAMPLE */ int i; X509_EXTENSION *ext = NULL; STACK_OF(GENERAL_NAME) *ialt = NULL; GENERAL_NAME *gen = NULL; char email[256]; if (!(peer_cert && userid) || len <= 0) return -1; userid[0] = '\0'; email[0] = '\0'; debug(F110,"X509_to_user() subject", X509_NAME_oneline(X509_get_subject_name(peer_cert),NULL,0),0); if ((i = X509_get_ext_by_NID(peer_cert, NID_subject_alt_name, -1))<0) return -1; if (!(ext = X509_get_ext(peer_cert, i))) return -1; X509V3_add_standard_extensions(); if (!(ialt = X509V3_EXT_d2i(ext))) return -1; for (i = 0; i < sk_GENERAL_NAME_num(ialt); i++) { gen = sk_GENERAL_NAME_value(ialt, i); if (gen->type == GEN_DNS) { if (!gen->d.ia5 || !gen->d.ia5->length) break; if (strlen(gen->d.ia5->data) != gen->d.ia5->length) { /* Ignoring IA5String containing null character */ continue; } if ( gen->d.ia5->length + 1 > sizeof(email) ) { goto cleanup; } memcpy(email, gen->d.ia5->data, gen->d.ia5->length); email[gen->d.ia5->length] = 0; break; } } cleanup: #ifndef LIBRESSL_VERSION_NUMBER /* This function was removed in LibreSSL 3.9 * https://github.com/libressl/portable/issues/1050 * In both LibreSSL 3.9 and OpenSSL 3.4, X509V3_add_standard_extensions * does nothing so possibly there is nothing to clean up these days. * -- DG */ X509V3_EXT_cleanup(); #endif /* LIBRESSL_VERSION_NUMBER */ if (ialt) sk_GENERAL_NAME_free(ialt); debug(F110,"X509_to_user() email",email,0); if ( email[0] ) { char * domain = NULL; /* Find domain */ for ( i=0 ; email[i] ; i++ ) { if ( email[i] == '@' ) { email[i] = '\0'; domain = &email[i+1]; break; } } if ( domain ) { /* XXX - Put code to Verify domain here */ if ( /* domain is okay */ 1 ) ckstrncpy(userid,email,len); } } return(userid[0] ? 0 : -1); /* END EXAMPLE */ #endif /* X509_SUBJECT_ALT_NAME_TO_USER */ #endif /* X509_UID_TO_USER */ return -1; } /* The following function should be replaced by institution specific */ /* code that will determine whether or not the combination of the */ /* provided X509 certificate and username is valid for automatic */ /* login. Whereas X509_to_user() is used to provide authentication */ /* of the user, the X509_userok() function is used to provide */ /* authorization. The certificate passed into X509_userok() does */ /* need to map to a userid; nor would the userid it would map to */ /* need to match the userid provided to the function. There are */ /* numerous circumstances in which it is beneficial to have the ability */ /* for multiple users to gain access to a common account such as */ /* 'root' on Unix; or a class account on a web server. In Unix we */ /* implement this capability with the ~userid/.tlslogin file which */ /* a list of X509 certificates which may be used to access the */ /* account 'userid'. */ /* X509_to_user() returns 0 if access is denied; 1 is access is permitted */ int X509_userok(X509 * peer_cert, const char * userid) { #ifndef VMS /* check if clients cert is in "user"'s ~/.tlslogin file */ char buf[512]; int r = 0; FILE *fp; struct passwd *pwd; X509 *file_cert; if ( peer_cert == NULL ) return(0); if (!(pwd = getpwnam(userid))) return 0; if (strlen(pwd->pw_dir) > 500) return(0); sprintf(buf, "%s/.tlslogin", pwd->pw_dir); if (!(fp = fopen(buf, "r"))) return 0; while (!r && (file_cert = PEM_read_X509(fp, NULL, NULL, NULL))) { #if OPENSSL_VERSION_NUMBER >= 0x10100005L const ASN1_BIT_STRING *peer_cert_sig, *file_cert_sig; X509_get0_signature(&peer_cert_sig, NULL, peer_cert); X509_get0_signature(&file_cert_sig, NULL, file_cert); if (!ASN1_STRING_cmp(peer_cert_sig, file_cert_sig)) #else if (!ASN1_STRING_cmp(peer_cert->signature, file_cert->signature)) #endif r = 1; X509_free(file_cert); } fclose(fp); return(r); #else /* VMS */ /* Need to implement an appropriate function for VMS */ return(0); #endif /* VMS */ } #endif /* OS2 */ #endif /* CK_SSL */ #endif /* NOSSL */ ck_ssl.h000664 045065 024037 00000013033 14767401613 012623 0ustar00fdckermit000000 000000 /* C K _ S S L . H -- OpenSSL Interface Header for C-Kermit Copyright (C) 1985, 2020, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Authors: Jeffrey E Altman (jaltman@secure-endpoints.com) Secure Endpoints Inc., New York City David Goodwin, New Zealand SMS Last update: Tue Nov 15 15:09:05 2022 */ #ifdef CK_SSL #ifndef CK_ANSIC #define NOPROTO #endif /* CK_ANSIC */ #ifdef COMMENT /* Not for C-Kermit 7.1 */ #ifdef KRB5 #ifndef NOSSLK5 #ifndef SSL_KRB5 #define SSL_KRB5 #endif /* SSL_KRB5 */ #endif /* NOSSLK5 */ #endif /* KRB5 */ #endif /* COMMENT */ #ifdef OS2 #ifndef ZLIB #define ZLIB #endif /* ZLIB */ #endif /* OS2 */ #ifdef ZLIB #ifndef OPENSSL_NO_COMP #include #endif /* OPENSSL_NO_COMP */ #endif /* ZLIB */ /* We place the following to avoid loading openssl/mdc2.h since it * relies on the OpenSSL des.h. Since we do not need the MDC2 * definitions there is no reason to have it included by openssl/evp.h */ #define OPENSSL_NO_MDC2 #ifdef OPENSSL_300 /* sms 15 November 2022 */ #ifndef OPENSSL_100 #define OPENSSL_100 #endif /* OPENSSL_100 */ #endif /* def OPENSSL_300 */ #ifdef OPENSSL_100 #ifndef OPENSSL_098 /* sms 15 November 2022 */ #define OPENSSL_098 #endif /* OPENSSL_098 */ /* Different major/minor version or development version of OpenSSL * means ABI may break compatibility. * Modified by Adam Friedlander for OpenSSL >= 1.0.0 * (See for OpenSSL version encoding details.) */ #define COMPAT_VERSION_MASK 0xfff0000f /* MNNffppS, major+minor+status */ #else /* Different major/minor/fix/development (not patch) version of OpenSSL * means ABI may break compatibility. */ #define COMPAT_VERSION_MASK 0xfffff00f /* MNNFFppS, major+minor+fix+status */ #endif /* OPENSSL_100 */ #ifdef OPENSSL_098 #ifndef OPENSSL_097 /* sms 15 November 2022 */ #define OPENSSL_097 #endif /* OPENSSL_097 */ #endif /* OPENSSL_098 */ #ifdef CK_DES #include #endif /* CK_DES */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SSL_KRB5 #include #endif /* SSL_KRB5 */ extern BIO *bio_err; extern SSL *ssl_con; extern SSL_CTX *ssl_ctx; extern int ssl_debug_flag; extern int ssl_only_flag; extern int ssl_active_flag; extern int ssl_verify_flag; extern int ssl_verbose_flag; extern int ssl_certsok_flag; extern int ssl_dummy_flag; extern int ssl_verify_depth; extern char *ssl_rsa_cert_file; extern char *ssl_rsa_cert_chain_file; extern char *ssl_rsa_key_file; extern char *ssl_dsa_cert_file; extern char *ssl_dsa_cert_chain_file; extern char *ssl_dh_key_file; extern char *ssl_cipher_list; extern char *ssl_crl_file; extern char *ssl_crl_dir; extern char *ssl_verify_file; extern char *ssl_verify_dir; extern char *ssl_dh_param_file; extern char *ssl_rnd_file; extern SSL_CTX *tls_ctx; extern SSL *tls_con; extern int tls_only_flag; extern int tls_active_flag; extern int x509_cert_valid; extern X509_STORE *crl_store; extern int ssl_raw_flag; extern int tls_raw_flag; #ifndef NOHTTP extern SSL_CTX *tls_http_ctx; extern SSL *tls_http_con; extern int tls_http_active_flag; #endif /* NOHTTP */ extern int ssl_initialized; _PROTOTYP(VOID ssl_once_init,(void)); _PROTOTYP(int ssl_tn_init,(int)); _PROTOTYP(int ssl_http_init,(char *)); _PROTOTYP(int ck_ssl_http_client,(int,char *)); _PROTOTYP(int ssl_display_connect_details,(SSL *,int,int)); _PROTOTYP(int ssl_server_verify_callback,(int, X509_STORE_CTX *)); _PROTOTYP(int ssl_client_verify_callback,(int, X509_STORE_CTX *)); _PROTOTYP(int ssl_reply,(int, unsigned char *, int)); _PROTOTYP(int ssl_is,(unsigned char *, int)); _PROTOTYP(int ck_ssl_incoming,(int)); _PROTOTYP(int ck_ssl_outgoing,(int)); _PROTOTYP(int tls_is_user_valid,(SSL *, const char *)); _PROTOTYP(char * ssl_get_dnsName,(SSL *)); _PROTOTYP(char * ssl_get_commonName,(SSL *)); _PROTOTYP(char * ssl_get_issuer_name,(SSL *)); _PROTOTYP(char * ssl_get_subject_name,(SSL *)); _PROTOTYP(int ssl_get_client_finished,(char *, int)); _PROTOTYP(int ssl_get_server_finished,(char *, int)); _PROTOTYP(int ssl_passwd_callback,(char *, int, int, VOID *)); _PROTOTYP(VOID ssl_client_info_callback,(const SSL *,int, int)); _PROTOTYP(int ssl_anonymous_cipher,(SSL * ssl)); _PROTOTYP(int tls_load_certs,(SSL_CTX * ctx, SSL * con, int server)); _PROTOTYP(int ssl_verify_crl,(int, X509_STORE_CTX *)); _PROTOTYP(int tls_is_krb5,(int)); _PROTOTYP(int X509_userok,(X509 *,const char *)); _PROTOTYP(int ck_X509_save_cert_to_user_store,(X509 *)); /* SMS 2007/02/15 */ _PROTOTYP(int ssl_check_server_name,(SSL * ssl, char * hostname)); #ifdef COMMENT /* [jt] 2013/11/21 - Kermit 95 is no longer a special case */ #ifdef OS2 #include "ckosslc.h" #include "ckossl.h" #endif /* OS2 */ #endif /* COMMENT */ #define SSL_CLIENT 0 #define SSL_SERVER 1 #define SSL_HTTP 2 #define SSL_ERR_BFSZ 4096 #ifdef SSL_KRB5 #define DEFAULT_CIPHER_LIST "HIGH:MEDIUM:LOW:+KRB5:+ADH:+EXP" #else #define DEFAULT_CIPHER_LIST "HIGH:MEDIUM:LOW:+ADH:+EXP" #endif /* SSL_KRB5 */ #endif /* CK_SSL */ ckcasc.h000664 045065 024037 00000005363 14767401616 012606 0ustar00fdckermit000000 000000 /* File CKCASC.H Mnemonics for ASCII control characters (and Space) for use with C-Kermit. */ /* Author: Frank da Cruz (fdc@columbia.edu). Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 2022, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ #ifndef CKCASC_H #define CKCASC_H #define NUL '\0' /* Null Ctrl-@ */ #define SOH 1 /* Start of header Ctrl-A */ #define STX 2 /* Ctrl-B */ #define ETX 3 /* Ctrl-C */ #define EOT 4 /* Ctrl-D */ #define ENQ 5 /* ENQ Ctrl-E */ #define ACK 6 /* Ctrl-F */ #define BEL 7 /* Bell (Beep) Ctrl-G */ #define BS 8 /* Backspace Ctrl-H */ #define HT 9 /* Horizontal Tab Ctrl-I */ #define LF 10 /* Linefeed Ctrl-J */ #define VT 11 /* Vertical Tab Ctrl-K */ #define NL '\n' /* Newline */ #define FF 12 /* Formfeed Ctrl-L */ #define CK_CR 13 /* Carriage Return Ctrl-M (CR Windows conflict) */ #define SO 14 /* Shift Out Ctrl-N */ #define SI 15 /* Shift In Ctrl-O */ #define DLE 16 /* Datalink Escape Ctrl-P */ #define XON 17 /* XON Ctrl-Q */ #define DC1 17 #define DC2 18 /* Ctrl-R */ #define XOFF 19 /* XOFF Ctrl-S */ #define DC3 19 #define DC4 20 /* Ctrl-T */ #define NAK 21 /* Ctrl-U */ #define SYN 22 /* SYN, Ctrl-V */ #define ETB 23 /* Ctrl-W */ #define CAN 24 /* CAN, Ctrl-X */ #define XEM 25 /* Ctrl-Y (was EM but conflicts with OpenSSL) */ #define SUB 26 /* SUB Ctrl-Z */ #define ESC 27 /* Escape Ctrl-[ */ #define XFS 28 /* Field Separator, Ctrl-Backslash */ #define XGS 29 /* Group Separator, Ctrl-Rightbracket */ #define XRS 30 /* Record Separator, Ctrl-Circumflex */ #define US 31 /* Unit Separator, Ctrl-Underscore */ #define SP 32 /* Space */ #define DEL 127 /* Delete (Rubout) */ #define RUB 127 /* Delete (Rubout) */ #ifdef OS2 /* These are needed in OS/2, so let's not cause any unnecessary conflicts. */ #define _CSI 0233 /* 8-bit Control Sequence Introducer */ #define _SS2 0216 /* 8-bit Single Shift 2 */ #define _SS3 0217 /* 8-bit Single Shift 3 */ #define _DCS 0220 /* 8-bit Device Control String Introducer */ #define _ST8 0234 /* 8-bit String Terminator */ #define _OSC 0235 /* 8-bit Operating System Command */ #define _PM8 0236 /* 8-bit Privacy Message */ #define _APC 0237 /* 8-bit Application Program Command */ #endif /* OS2 */ #endif /* CKCASC_H */ ckcdeb.h000664 045065 024037 00000473527 14767411403 012600 0ustar00fdckermit000000 000000 /* C K C D E B . H */ /* For recent additions search below for "2021" and "2022" and "2023". Most recent updates: Sat Jul 1 10:27:16 2023 (David Goodwin, fdc) More recent: Sun Feb 4 20:17:33 2024 (removed prototypes for malloc()) NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be compatible with C preprocessors that support only #ifdef, #else, #endif, #define, and #undef. Please do not use #if, logical operators, or other later-model preprocessor features in any of the portable C-Kermit modules. You can, of course, use these constructions in platform-specific modules when you know they are supported. */ /* This file is included by all C-Kermit modules, including the modules that aren't specific to Kermit (like the command parser and the ck?tio and ck?fio modules). It should be included BEFORE any other C-Kermit header files. It specifies format codes for debug(), tlog(), and similar functions, and includes any necessary definitions to be used by all C-Kermit modules, and also includes some feature selection compile-time switches, and also system- or compiler-dependent definitions, plus #includes and prototypes required by all C-Kermit modules. */ /* Author: Frank da Cruz , Columbia University Academic Information Systems, NYC (1974-2011) The Kermit Project, Bronx NY (2011-present) Changes from David Goodwin for Windows and OS/2 (2022) Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ /* Etymology: The name of this file means "C-Kermit Common-C-Language Debugging Header", because originally it contained only the formats (F000-F111) for the debug() and tlog() functions. Since then it has grown to include all material required by all or most of the other C-Kermit modules, including the non-Kermit specific ones. In other words, this is the one header file that is guaranteed to be included by all C-Kermit source modules. */ #ifndef CKCDEB_H /* Don't include me more than once. */ #define CKCDEB_H /* Some ancient MIPS compilers for Windows NT define "MIPS" which causes * problems here and elsewhere. None of the windows headers depend on MIPS being * defined (they all check for _MIPS_), so it's safe to just undefine it. */ #ifdef MIPS #ifdef OS2 #undef MIPS /* MIPS should never be defined when targeting OS/2 */ #endif /* OS2 */ #ifdef CKT_NT31 #undef MIPS /* MIPS should never be defined when targeting NT 3.1 */ #endif /* CKT_NT31 */ #endif /* MIPS */ /* Moved here from ckcmai.c October 2022... REMOVE THIS AFTER BETA TEST! */ #ifndef BETATEST #define BETATEST #endif /* BETATEST */ /* Now that WTMP and Syslog are "deprecated" don't include them by default */ #ifndef DOWTMP /* Unless explicitly requested */ #ifndef NOWTMP /* No more WTMP logging */ #define NOWTMP #endif /* NOWTMP */ #endif /* DOWTMP */ #ifndef DOSYSLOG /* Unless explicitly requested */ #ifndef NOSYSLOG /* No more syslog */ #define NOSYSLOG #endif /* NOSYSLOG */ #endif /* DOSYSLOG */ /* 14 Sep 2022 - TYPE command's new /INTERPRET switch enabled by default except in Windows where it doesn't work because of character-set issues. */ #ifdef NT #ifndef NOTYPEINTERPRET #define NOTYPEINTERPRET #endif /* NOTYPEINTERPRET */ #endif /* NT */ #ifdef NOICP /* 2 Nov 2022 */ #ifndef NOIKSD #define NOIKSD #endif /* NOIKSD */ #endif /* NOICP */ #ifdef NOSPL /* 30 Oct 2022 */ #ifndef NOIKSD /* 30 Oct 2022 */ #define NOIKSD #endif /* NOIKSD */ #ifndef NOLEARN /* 30 Oct 2022 */ #define NOLEARN #endif /* NOLEARN */ #else /* 12 December 2022 */ #ifndef NOTYPEINTERPRET /* 23 August 2022 - TYPE /INTERPRET */ #ifndef TYPEINTERPRET #define TYPEINTERPRET #endif /* TYPEINTERPRET */ #endif /* NOTYPEINTERPRET */ #ifndef NOCOPYINTERPRET /* 20 Sep 2022 - COPY /INTERPRET */ #ifndef COPYINTERPRET #define COPYINTERPRET #endif /* COPYINTERPRET */ #endif /* NOCOPYINTERPRET */ #endif /* NOSPL */ /* Disinclude features that are "deprecated" in 2022; on amd64 this saves about 185K out of 2.48MB, so this is really more about political correctness that saving space. -fdc 12 May 2022 */ #ifdef NODEPRECATED #ifndef NOFTP /* No more FTP client */ #define NOFTP #endif /* NOFTP */ #ifndef NOTELNET /* No more Telnet client */ #define NOTELNET #endif /* NOTELNET */ #ifdef TNCODE #undef TNCODE #endif /* TNCODE */ #ifndef NORLOGIN /* No more RLOGIN client */ #define NORLOGIN #endif /* NORLOGIN */ #endif /* NODEPRECATED */ /* As of 26 September 2022, the Arrow-key feature is included only if explicitly requested because the API is disappearing not only in glibc but also other libcs like musl and whatever Android uses. */ #ifndef DOARROWKEYS #ifndef NOARROWKEYS /* Arrow keys use a deprecated API */ #define NOARROWKEYS /* (at least in glibc) */ #endif /* NOARROWKEYS */ #endif /* DOARROWKEYS */ #ifdef OS2 #ifndef CKODIALER #include "ckoker.h" #endif /* CKODIALER */ #else /* OS2 */ /* Unsigned numbers */ #ifndef USHORT #define USHORT unsigned short #endif /* USHORT */ #ifndef UINT #define UINT unsigned int #endif /* UINT */ #ifndef ULONG #define ULONG unsigned long #endif /* ULONG */ #endif /* OS2 */ #ifdef MACOSX10 /* Mac OS X 1.0 */ #ifndef MACOSX /* implies Mac OS X */ #define MACOSX #endif /* MACOSX */ #endif /* MACOSX10 */ #ifdef MACOSX /* Mac OS X */ #ifndef BSD44 /* implies 4.4 BSD */ #define BSD44 #endif /* BSD44 */ #endif /* MACOSX */ #ifdef SCO_OSR505 /* SCO 3.2v5.0.5 */ #ifndef SCO_OSR504 /* implies SCO 3.2v5.0.4 */ #define SCO_OSR504 #endif /* SCO_OSR504 */ #endif /* SCO_OSR505 */ #ifdef SCO_OSR504 /* SCO 3.2v5.0.4 */ #ifndef CK_SCOV5 /* implies SCO 3.2v5.0 */ #define CK_SCOV5 #endif /* CK_SCOV5 */ #include /* To sidestep header-file mess */ #endif /* SCO_OSR504 */ #ifdef CK_SCOV5 #ifndef ANYSCO #define ANYSCO #endif /* ANYSCO */ #endif /* CK_SCOV5 */ #ifdef UNIXWARE #ifndef ANYSCO #define ANYSCO #endif /* ANYSCO */ #endif /* UNIXWARE */ #ifndef MINIX /* MINIX versions */ #ifdef MINIX340 /* TIH 1 Feb 2022 */ #define MINIX #else #ifdef MINIX315 #define MINIX #else #ifdef MINIX3 #define MINIX #else #ifdef MINIX2 #define MINIX #endif /* MINIX2 */ #endif /* MINIX3 */ #endif /* MINIX315 */ #endif /* MINIX340 */ #endif /* MINIX */ #ifdef CK_SCO32V4 /* SCO 3.2v4 */ #ifndef ANYSCO #define ANYSCO #endif /* ANYSCO */ #ifndef XENIX #define XENIX #endif /* XENIX */ #ifndef SVR3 #define SVR3 #endif /* SVR3 */ #ifndef DIRENT #define DIRENT #endif /* DIRENT */ #ifndef RENAME #define RENAME #endif /* RENAME */ #ifndef SVR3JC #define SVR3JC #endif /* SVR3JC */ #ifndef CK_RTSCTS #define CK_RTSCTS #endif /* CK_RTSCTS */ #ifndef PID_T #define PID_T pid_t #endif /* PID_T */ #ifndef PWID_T #define PWID_T int #endif /* PWID_T */ #endif /* CK_SCO32V4 */ /* The UNIX Seventh Edition (1979) compiler doesn't allow a lot of -D's on the make command line and big modules can result in nonsensical fatal compilation errors so I have to remove a lot of features to make it compile at all without putting more -D's on the make-command line. KFLAGS=-DV7MIN can also be used on other platforms, e.g. Linux, to build the smallest possible C-Kermit program, about 400kb: command-line only, no script programming, no making network connections, no character-set support, dialing of only the most common modem types, no use of external processes, and no logging or debugging. On Ubuntu this results in an executable of about 402KB, compared to the normal one of 2.8MB. -fdc, 3 November 2022 */ #ifdef V7MIN /* UNIX V7 MINIMUM-SIZE BUILD */ #ifndef NOICP /* No interactive commands */ #define NOICP #endif /* NOICP */ #ifndef NONET /* No networking of any kind */ #define NONET #endif /* NONET */ #ifndef NOCSETS /* No character-set conversion */ #define NOCSETS #endif /* NOCSETS */ #ifndef MINIDIAL /* Minimum modem support */ #define MINIDIAL #endif /* MINIDIAL */ #ifndef NOPTY /* No spawning */ #define NOPTY #endif /* NOPTY */ #ifndef NODEBUG /* No debugging */ #define NODEBUG #endif /* NODEBUG */ #endif /* V7MIN */ #ifdef NOICP /* If no command parser */ #ifndef NOSPL /* Then no script language either */ #define NOSPL #endif /* NOSPL */ #ifndef NOCSETS /* Or characer sets */ #define NOCSETS #endif /* NOCSETS */ #ifndef NOFTP /* Or FTP client */ #define NOFTP #endif /* NOFTP */ #endif /* NOICP */ /* Built-in makefile entries */ #ifdef SOLARIS11 /* Solaris 11 implies 10 */ #ifndef SOLARIS10 #define SOLARIS10 #endif /* SOLARIS10 */ #endif /* SOLARIS11 */ #ifdef SOLARIS10 /* Solaris 10 implies 9 */ #ifndef SOLARIS9 #define SOLARIS9 #endif /* SOLARIS9 */ #endif /* SOLARIS10 */ #ifdef SOLARIS9 /* Solaris 9 implies 8 */ #ifndef SOLARIS8 #define SOLARIS8 #endif /* SOLARIS8 */ #endif /* SOLARIS9 */ #ifdef SOLARIS8 /* Solaris 8 implies 7 */ #ifndef SOLARIS7 #define SOLARIS7 #endif /* SOLARIS7 */ #endif /* SOLARIS8 */ #ifdef SOLARIS7 /* Solaris 7 implies 2.6 */ #ifndef SOLARIS26 #define SOLARIS26 #endif /* SOLARIS26 */ #endif /* SOLARIS7 */ #ifdef SOLARIS26 /* Solaris 2.6 implies 2.5 */ #ifndef SOLARIS25 #define SOLARIS25 #endif /* SOLARIS25 */ #endif /* SOLARIS26 */ #ifdef SOLARIS25 /* Solaris 2.5 implies Solaris */ #ifndef SOLARIS #define SOLARIS #endif /* SOLARIS */ #ifndef POSIX /* And POSIX */ #define POSIX #endif /* POSIX */ #ifndef CK_WREFRESH /* And this (curses) */ #define CK_WREFRESH #endif /* CK_WREFRESH */ #endif /* SOLARIS25 */ #ifdef SOLARIS24 /* Solaris 2.4 implies Solaris */ #ifndef SOLARIS #define SOLARIS #endif /* SOLARIS */ #endif /* SOLARIS24 */ #ifdef SOLARIS /* Solaris gets "POSIX" RTS/CTS API */ #ifdef POSIX #ifndef POSIX_CRTSCTS #define POSIX_CRTSCTS #endif /* POSIX_CRTSCTS */ #endif /* POSIX */ #ifndef SVR4 #define SVR4 #endif /* SVR4 */ #ifndef STERMIOX #define STERMIOX #endif /* STERMIOX */ #ifndef SELECT #define SELECT #endif /* SELECT */ #ifndef FNFLOAT #define FNFLOAT #endif /* FNFLOAT */ #ifndef DIRENT #define DIRENT #endif /* DIRENT */ #ifndef BIGBUFOK #define BIGBUFOK #endif /* BIGBUFOK */ #ifndef CK_NEWTERM #define CK_NEWTERM #endif /* CK_NEWTERM */ #endif /* SOLARIS */ #ifdef SUN4S5 /* Sun-4 System V environment */ #ifndef SVR3 /* implies System V R3 or later */ #define SVR3 #endif /* SVR3 */ #endif /* SUN4S5 */ #ifdef SUNOS41 /* SUNOS41 implies SUNOS4 */ #ifndef SUNOS4 #define SUNOS4 #endif /* SUNOS4 */ #endif /* SUNOS41 */ #ifdef SUN4S5 /* Sun-4 System V environment */ #ifndef SVR3 /* implies System V R3 or later */ #define SVR3 #endif /* SVR3 */ #endif /* SUN4S5 */ #ifdef SUNOS41 /* SUNOS41 implies SUNOS4 */ #ifndef SUNOS4 #define SUNOS4 #endif /* SUNOS4 */ #endif /* SUNOS41 */ #ifdef SUNOS4 /* Built-in SUNOS4 makefile entry */ #ifndef UNIX #define UNIX #endif /* UNIX */ #ifndef BSD4 #define BSD4 #endif /* BSD4 */ #ifndef BIGBUFOK #define BIGBUFOK #endif /* BIGBUFOK */ #ifndef NOSETBUF #define NOSETBUF #endif /* NOSETBUF */ #ifndef DIRENT #define DIRENT #endif /* DIRENT */ #ifndef NONET #ifndef TCPSOCKET #define TCPSOCKET #endif /* TCPSOCKET */ #endif /* NONET */ #ifndef SAVEDUID #define SAVEDUID #endif /* SAVEDUID */ #ifndef DYNAMIC #define DYNAMIC #endif /* DYNAMIC */ #endif /* SUNOS4 */ #ifdef SOLARIS /* Built in makefile entry */ #ifndef NOSETBUF /* for Solaris 2.x */ #define NOSETBUF #endif /* NOSETBUF */ #ifndef NOCURSES #ifndef CK_CURSES #define CK_CURSES #endif /* CK_CURSES */ #endif /* NOCURSES */ #ifndef CK_NEWTERM #define CK_NEWTERM #endif /* CK_NEWTERM */ #ifndef DIRENT #define DIRENT #endif /* DIRENT */ #ifndef NONET #ifndef TCPSOCKET #define TCPSOCKET #endif /* TCPSOCKET */ #endif /* NONET */ #ifndef UNIX #define UNIX #endif /* UNIX */ #ifndef SVR4 #define SVR4 #endif /* SVR4 */ #ifndef HADDRLIST #define HADDRLIST #endif /* HADDRLIST */ #ifndef STERMIOX #define STERMIOX #endif /* STERMIOX */ #ifndef SELECT #define SELECT #endif /* SELECT */ #ifndef DYNAMIC #define DYNAMIC #endif /* DYNAMIC */ #ifndef NOUUCP #ifndef HDBUUCP #define HDBUUCP #endif /* HDBUUCP */ #endif /* NOUUCP */ #endif /* SOLARIS */ /* Features that can be eliminated from a no-file-transfer version */ #ifdef NOXFER #ifndef NOFTP #define NOFTP #endif /* NOFTP */ #ifndef OS2 #ifndef NOCURSES /* Fullscreen file-transfer display */ #define NOCURSES #endif /* NOCURSES */ #endif /* OS2 */ #ifndef NOCKXYZ /* XYZMODEM support */ #define NOCKXYZ #endif /* NOCKXYZ */ #ifndef NOCKSPEED /* Ctrl-char unprefixing */ #define NOCKSPEED #endif /* NOCKSPEED */ #ifndef NOSERVER /* Server mode */ #define NOSERVER #endif /* NOSERVER */ #ifndef NOCKTIMERS /* Dynamic packet timers */ #define NOCKTIMERS #endif /* NOCKTIMERS */ #ifndef NOPATTERNS /* File-type patterns */ #define NOPATTERNS #endif /* NOPATTERNS */ #ifndef NOSTREAMING /* Streaming */ #define NOSTREAMING #endif /* NOSTREAMING */ #ifndef NOIKSD /* Internet Kermit Service */ #define NOIKSD #endif /* NOIKSD */ #ifndef NOPIPESEND /* Sending from pipes */ #define NOPIPESEND #endif /* NOPIPESEND */ #ifndef NOAUTODL /* Autodownload */ #define NOAUTODL #endif /* NOAUTODL */ #ifndef NOMSEND /* MSEND */ #define NOMSEND #endif /* NOMSEND */ #ifndef NOTLOG /* Transaction logging */ #define NOTLOG #endif /* NOTLOG */ #ifndef NOCKXXCHAR /* Packet character doubling */ #define NOCKXXCHAR #endif /* NOCKXXCHAR */ #endif /* NOXFER */ #ifdef NOICP /* No Interactive Command Parser */ #ifndef NODIAL /* Implies No DIAL command */ #define NODIAL #endif /* NODIAL */ #ifndef NOCKXYZ /* and no external protocols */ #define NOCKXYZ #endif /* NOCKXYZ */ #endif /* NOICP */ #ifndef NOIKSD #ifdef IKSDONLY #ifndef IKSD #define IKSD #endif /* IKSD */ #ifndef NOLOCAL #define NOLOCAL #endif /* NOLOCAL */ #ifndef NOPUSH #define NOPUSH #endif /* NOPUSH */ #ifndef TNCODE #define TNCODE #endif /* TNCODE */ #ifndef TCPSOCKET #define TCPSOCKET #endif /* TCPSOCKET */ #ifndef NETCONN #define NETCONN #endif /* NETCONN */ #ifdef SUNX25 #undef SUNX25 #endif /* SUNX25 */ #ifdef IBMX25 #undef IBMX25 #endif /* IBMX25 */ #ifdef STRATUSX25 #undef STRATUSX25 #endif /* STRATUSX25 */ #ifdef CK_NETBIOS #undef CK_NETBIOS #endif /* CK_NETBIOS */ #ifdef SUPERLAT #undef SUPERLAT #endif /* SUPERLAT */ #ifdef NPIPE #undef NPIPE #endif /* NPIPE */ #ifdef NETFILE #undef NETFILE #endif /* NETFILE */ #ifdef NETCMD #undef NETCMD #endif /* NETCMD */ #ifdef NETPTY #undef NETPTY #endif /* NETPTY */ #ifdef RLOGCODE #undef RLOGCODE #endif /* RLOGCODE */ #ifdef NETDLL #undef NETDLL #endif /* NETDLL */ #ifndef NOSSH #undef NOSSH #endif /* NOSSH */ #ifndef NOFORWARDX #define NOFORWARDX #endif /* NOFORWARDX */ #ifndef NOBROWSER #define NOBROWSER #endif /* NOBROWSER */ #ifndef NOHTTP #define NOHTTP #endif /* NOHTTP */ #ifndef NOFTP #define NOFTP #endif /* NOFTP */ #ifndef NO_COMPORT #define NO_COMPORT #endif /* NO_COMPORT */ #endif /* IKSDONLY */ #endif /* NOIKSD */ /* Features that can be eliminated from a remote-only version */ #ifdef NOLOCAL #ifndef NOFTP #define NOFTP #endif /* NOFTP */ #ifndef NOHTTP #define NOHTTP #endif /* NOHTTP */ #ifndef NOSSH #define NOSSH #endif /* NOSSH */ #ifndef NOTERM #define NOTERM #endif /* NOTERM */ #ifndef NOCURSES /* Fullscreen file-transfer display */ #define NOCURSES #endif /* NOCURSES */ #ifndef NODIAL #define NODIAL #endif /* NODIAL */ #ifndef NOSCRIPT #define NOSCRIPT #endif /* NOSCRIPT */ #ifndef NOSETKEY #define NOSETKEY #endif /* NOSETKEY */ #ifndef NOKVERBS #define NOKVERBS #endif /* NOKVERBS */ #ifndef NOXMIT #define NOXMIT #endif /* NOXMIT */ #ifdef CK_CURSES #undef CK_CURSES #endif /* CK_CURSES */ #ifndef IKSDONLY #ifndef NOAPC #define NOAPC #endif /* NOAPC */ #ifndef NONET #define NONET #endif /* NONET */ #endif /* IKSDONLY */ #endif /* NOLOCAL */ #ifdef NONET #ifndef NOTCPIP #define NOTCPIP #endif /* NOTCPIP */ #ifndef NONETDIR #define NONETDIR #endif /* NONETDIR */ #ifndef NOIKSD #define NOIKSD #endif /* NOIKSD */ #ifdef TNCODE #undef TNCODE #endif /* TNCODE */ #ifdef NETCONN #undef NETCONN #endif /* NETCONN */ #ifdef TCPSOCKET #undef TCPSOCKET #endif /* TCPSOCKET */ #ifndef NOTCPOPTS #define NOTCPOPTS #endif /* NOTCPOPTS */ #ifdef SUNX25 #undef SUNX25 #endif /* SUNX25 */ #ifdef IBMX25 #undef IBMX25 #endif /* IBMX25 */ #ifdef STRATUSX25 #undef STRATUSX25 #endif /* STRATUSX25 */ #ifdef CK_NETBIOS #undef CK_NETBIOS #endif /* CK_NETBIOS */ #ifdef SUPERLAT #undef SUPERLAT #endif /* SUPERLAT */ #ifdef NPIPE #undef NPIPE #endif /* NPIPE */ #ifdef NETFILE #undef NETFILE #endif /* NETFILE */ #ifdef NETCMD #undef NETCMD #endif /* NETCMD */ /* Commented out fdc May 2020 to allow external SSH command */ /* #ifdef NETPTY */ /* #undef NETPTY */ /* #endif NETPTY */ #ifdef RLOGCODE #undef RLOGCODE #endif /* RLOGCODE */ #ifdef NETDLL #undef NETDLL #endif /* NETDLL */ #ifndef NO_SSL /* added May 2020 fdc */ #define NO_SSL #endif /* NO_SSL */ /* Commented out fdc May 2020 */ /* so we can use external ssh client in NONET builds */ /* #ifndef NOSSH */ /* #define NOSSH */ /* #endif */ /* NOSSH */ #ifndef NOFTP #define NOFTP #endif /* NOFTP */ #ifndef NOHTTP #define NOHTTP #endif /* NOHTTP */ #ifndef NOBROWSER #define NOBROWSER #endif /* NOBROWSER */ #ifndef NOFORWARDX #define NOFORWARDX #endif /* NOFORWARDX */ #ifndef NOURL /* 1 July 2023 for -DV7MIN, -DNOTCP, -DNONET, etc */ #define NOURL #endif /* NOURL */ #endif /* NONET */ #ifdef IKSDONLY #ifdef SUNX25 #undef SUNX25 #endif /* SUNX25 */ #ifdef IBMX25 #undef IBMX25 #endif /* IBMX25 */ #ifdef STRATUSX25 #undef STRATUSX25 #endif /* STRATUSX25 */ #ifdef CK_NETBIOS #undef CK_NETBIOS #endif /* CK_NETBIOS */ #ifdef SUPERLAT #undef SUPERLAT #endif /* SUPERLAT */ #ifdef NPIPE #undef NPIPE #endif /* NPIPE */ #ifdef NETFILE #undef NETFILE #endif /* NETFILE */ #ifdef NETCMD #undef NETCMD #endif /* NETCMD */ #ifdef NETPTY #undef NETPTY #endif /* NETPTY */ #ifdef RLOGCODE #undef RLOGCODE #endif /* RLOGCODE */ #ifdef NETDLL #undef NETDLL #endif /* NETDLL */ #ifndef NOSSH #define NOSSH #endif /* NOSSH */ #ifndef NOHTTP #define NOHTTP #endif /* NOHTTP */ #ifndef NOBROWSER #define NOBROWSER #endif /* NOBROWSER */ #endif /* IKSDONLY */ /* Note that none of the above precludes TNCODE, which can be defined in the absence of TCPSOCKET, etc, to enable server-side Telnet negotation. */ #ifndef TNCODE /* This is for the benefit of */ #ifdef TCPSOCKET /* modules that might need TNCODE */ #define TNCODE /* not all of ckcnet.h... */ #endif /* TCPSOCKET */ #endif /* TNCODE */ #ifndef NETCONN #ifdef TCPSOCKET #define NETCONN #endif /* TCPSOCKET */ #endif /* NETCONN */ #ifndef DEFPAR /* Default parity */ #define DEFPAR 0 /* Must be here because it is used */ #endif /* DEFPAR */ /* by all classes of modules */ #ifdef NT #ifndef OS2ORWIN32 #define OS2ORWIN32 #endif /* OS2ORWIN32 */ #ifndef WIN32ORUNIX #define WIN32ORUNIX #endif /* WIN32ORUNIX */ #ifndef OS2 #define WIN32ONLY #endif /* OS2 */ #endif /* NT */ #ifdef OS2 /* For OS/2 debugging */ #ifndef OS2ORWIN32 #define OS2ORWIN32 #endif /* OS2ORWIN32 */ #ifdef NT #define NOCRYPT #include #define NTSIG #else /* NT */ #define OS2ONLY #include #endif /* NT */ #ifndef OS2ORUNIX #define OS2ORUNIX #endif /* OS2ORUNIX */ #ifndef OS2ORVMS #define OS2ORVMS #endif /* OS2ORVMS */ #endif /* OS2 */ /* Kermit 95 can now be 64-bit so OS2ORWIN32 is a misnomer */ #ifdef OS2ORWIN32 #ifndef OS2ORWINDOWS #define OS2ORWINDOWS #endif /* OS2ORWINDOWS */ #endif /* OS2ORWIN32 */ /* Moved here from ckcfnp.h 3 May 2023 */ /* NEW PROTOTYPE FOR MAIN() ADDED 02 MAY 2023 */ #ifndef MAINNAME #ifdef OS2ORWINDOWS #define MAINISVOID #ifdef KUI #define MAINNAME Main #else /* not KUI */ #define MAINNAME main #endif /* KUI */ #else /* not OS/2 or Windows */ #define MAINNAME main #endif /* OS2ORWINDOWS */ #endif /* MAINNAME */ #ifdef MAINISVOID /* This is a leftover from original Macintosh */ typedef VOID MAINTYPE; #else typedef int MAINTYPE; /* if any other types are needed add them here */ #endif /* MAINISVOID */ #include /* Begin by including this. */ #include /* and this. */ #ifdef VMS #include /* Ensure off_t. */ #include "ckvrms.h" /* Get NAMDEF NAMX_C_MAXRSS. */ #endif /* def VMS */ /* System-type compilation switches */ #ifdef FT21 /* Fortune For:Pro 2.1 implies 1.8 */ #ifndef FT18 #define FT18 #endif /* FT18 */ #endif /* FT21 */ #ifdef __bsdi__ #ifndef BSDI #define BSDI #endif /* BSDI */ #endif /* __bsdi__ */ #ifdef AIXPS2 /* AIXPS2 implies AIX370 */ #ifndef AIX370 #define AIX370 #endif /* AIX370 */ #endif /* AIXPS2 */ #ifdef AIX370 /* AIX PS/2 or 370 implies BSD4 */ #ifndef BSD4 #define BSD4 #endif /* BSD4 */ #endif /* AIX370 */ #ifdef AIXESA /* AIX/ESA implies BSD4.4 */ #ifndef BSD44 #define BSD44 #endif /* BSD44 */ #endif /* AIXESA */ #ifdef AIX53 /* AIX53 implies AIX52 */ #ifndef AIX52 #define AIX52 #endif /* AIX52 */ #endif /* AIX53 */ #ifdef AIX52 /* AIX52 implies AIX51 */ #ifndef AIX51 #define AIX51 #endif /* AIX51 */ #endif /* AIX52 */ #ifdef AIX51 /* AIX51 implies AIX50 */ #ifndef AIX50 #define AIX50 #endif /* AIX50 */ #endif /* AIX51 */ #ifdef AIX50 /* AIX50 implies AIX45 */ #ifndef AIX45 #define AIX45 #endif /* AIX45 */ #endif /* AIX50 */ #ifdef AIX45 /* AIX45 implies AIX44 */ #ifndef AIX44 #define AIX44 #endif /* AIX44 */ #endif /* AIX45 */ #ifdef AIX44 /* AIX44 implies AIX43 */ #ifndef AIX43 #define AIX43 #endif /* AIX43 */ #endif /* AIX44 */ #ifdef AIX43 /* AIX43 implies AIX42 */ #ifndef AIX42 #define AIX42 #endif /* AIX42 */ #endif /* AIX43 */ #ifdef AIX42 /* AIX42 implies AIX41 */ #ifndef AIX41 #define AIX41 #endif /* AIX41 */ #endif /* AIX42 */ #ifdef SV68R3V6 /* System V/68 R32V6 implies SVR3 */ #ifndef SVR3 #define SVR3 #endif /* SVR3 */ #endif /* SV68R3V6 */ #ifdef SV88R32 /* System V/88 R32 implies SVR3 */ #ifndef SVR3 #define SVR3 #endif /* SVR3 */ #endif /* SV88R32 */ #ifdef DGUX540 /* DG UX 5.40 implies Sys V R 4 */ #ifndef SVR4 #define SVR4 #endif /* SVR4 */ #endif /* DGUX540 */ #ifndef DGUX #ifdef DGUX540 /* DG/UX 5.40 implies DGUX */ #define DGUX #else #ifdef DGUX430 /* So does DG/UX 4.30 */ #define DGUX #endif /* DGUX430 */ #endif /* DGUX540 */ #endif /* DGUX */ #ifdef IRIX65 /* IRIX 6.5 implies IRIX 6.4 */ #ifndef IRIX64 #define IRIX64 #endif /* IRIX64 */ #endif /* IRIX65 */ #ifdef IRIX64 /* IRIX 6.4 implies IRIX 6.2 */ #ifndef BSD44ORPOSIX #define BSD44ORPOSIX /* for ckutio's benefit */ #endif /* BSD44ORPOSIX */ #ifndef IRIX62 #define IRIX62 #endif /* IRIX62 */ #endif /* IRIX64 */ #ifdef IRIX62 /* IRIX 6.2 implies IRIX 6.0 */ #ifndef IRIX60 #define IRIX60 #endif /* IRIX60 */ #endif /* IRIX62 */ #ifdef IRIX60 /* IRIX 6.0 implies IRIX 5.1 */ #ifndef IRIX51 #define IRIX51 #endif /* IRIX51 */ #ifndef IRIX52 /* And IRIX 5.2 (for hwfc) */ #define IRIX52 #endif /* IRIX52 */ #endif /* IRIX60 */ #ifndef IRIX /* IRIX 4.0 or greater implies IRIX */ #ifdef IRIX64 #define IRIX #else #ifdef IRIX62 #define IRIX #else #ifdef IRIX60 #define IRIX #else #ifdef IRIX51 #define IRIX #else #ifdef IRIX40 #define IRIX #endif /* IRIX40 */ #endif /* IRIX51 */ #endif /* IRIX60 */ #endif /* IRIX62 */ #endif /* IRIX64 */ #endif /* IRIX */ #ifdef MIPS /* MIPS System V environment */ #ifndef SVR3 /* implies System V R3 or later */ #define SVR3 #endif /* SVR3 */ #endif /* MIPS */ #ifdef HPUX9 /* HP-UX 9.x */ #ifndef SVR3 #define SVR3 #endif /* SVR3 */ #ifndef HPUX #define HPUX #endif /* HPUX */ #ifndef HPUX9PLUS #define HPUX9PLUS #endif /* HPUX9PLUS */ #endif /* HPUX9 */ #ifdef HPUX10 /* HP-UX 10.x */ #ifndef HPUX1010 /* If anything higher is defined */ #ifdef HPUX1020 /* define HPUX1010 too. */ #define HPUX1010 #endif /* HPUX1020 */ #ifdef HPUX1030 #define HPUX1010 #endif /* HPUX1030 */ #endif /* HPUX1010 */ #ifdef HPUX1100 /* HP-UX 11.00 implies 10.10 */ #ifndef HPUX1010 #define HPUX1010 #endif /* HPUX1010 */ #endif /* HPUX1100 */ #ifndef SVR4 #define SVR4 #endif /* SVR4 */ #ifndef HPUX #define HPUX #endif /* HPUX */ #ifndef HPUX9PLUS #define HPUX9PLUS #endif /* HPUX9PLUS */ #endif /* HPUX10 */ #ifdef QNX /* QNX Software Systems Inc */ #ifndef POSIX /* QNX 4.0 or later is POSIX */ #define POSIX #endif /* POSIX */ #ifndef __386__ /* Comes in 16-bit and 32-bit */ #define __16BIT__ #define CK_QNX16 #else #define __32BIT__ #define CK_QNX32 #endif /* __386__ */ #endif /* QNX */ /* 4.4BSD is a mixture of System V R4, POSIX, and 4.3BSD. */ #ifdef BSD44 /* 4.4 BSD */ #ifndef SVR4 /* BSD44 implies SVR4 */ #define SVR4 #endif /* SVR4 */ #ifndef NOSETBUF /* NOSETBUF is safe */ #define NOSETBUF #endif /* NOSETBUF */ #ifndef DIRENT /* Uses */ #define DIRENT #endif /* DIRENT */ #endif /* BSD44 */ #ifdef OPENBSD /* OpenBSD might or might not */ #ifndef __OpenBSD__ /* have this defined... */ #define __OpenBSD__ #endif /* __OpenBSD__ */ #endif /* OPENBSD */ #ifdef SVR3 /* SVR3 implies ATTSV */ #ifndef ATTSV #define ATTSV #endif /* ATTSV */ #endif /* SVR3 */ #ifdef SVR4 /* SVR4 implies ATTSV */ #ifndef ATTSV #define ATTSV #endif /* ATTSV */ #ifndef SVR3 /* ...as well as SVR3 */ #define SVR3 #endif /* SVR3 */ #endif /* SVR4 */ #ifdef OXOS #ifndef ATTSV #define ATTSV /* OXOS implies ATTSV */ #endif /* ! ATTSV */ #define SW_ACC_ID /* access() wants privs on */ #define kill priv_kill /* kill() wants privs on */ #ifndef NOSETBUF #define NOSETBUF /* NOSETBUF is safe */ #endif /* ! NOSETBUF */ #endif /* OXOS */ #ifdef UTSV /* UTSV implies ATTSV */ #ifndef ATTSV #define ATTSV #endif /* ATTSV */ #endif /* UTSV */ #ifdef XENIX /* XENIX implies ATTSV */ #ifndef ATTSV #define ATTSV #endif /* ATTSV */ #endif /* XENIX */ #ifdef AUX /* AUX implies ATTSV */ #ifndef ATTSV #define ATTSV #endif /* ATTSV */ #endif /* AUX */ #ifdef ATT7300 /* ATT7300 implies ATTSV */ #ifndef ATTSV #define ATTSV #endif /* ATTSV */ #endif /* ATT7300 */ #ifdef ATT6300 /* ATT6300 implies ATTSV */ #ifndef ATTSV #define ATTSV #endif /* ATTSV */ #endif /* ATT6300 */ #ifdef HPUX /* HPUX implies ATTSV */ #ifndef ATTSV #define ATTSV #endif /* ATTSV */ #endif /* HPUX */ #ifdef ISIII /* ISIII implies ATTSV */ #ifndef ATTSV #define ATTSV #endif /* ATTSV */ #endif /* ISIII */ #ifdef NEXT33 /* NEXT33 implies NEXT */ #ifndef NEXT #define NEXT #endif /* NEXT */ #endif /* NEXT33 */ #ifdef NEXT /* NEXT implies BSD4 */ #ifndef BSD4 #define BSD4 #endif /* BSD4 */ #endif /* NEXT */ #ifdef BSD41 /* BSD41 implies BSD4 */ #ifndef BSD4 #define BSD4 #endif /* BSD4 */ #endif /* BSD41 */ #ifdef BSD43 /* BSD43 implies BSD4 */ #ifndef BSD4 #define BSD4 #endif /* BSD4 */ #endif /* BSD43 */ #ifdef BSD4 /* BSD4 implies ANYBSD */ #ifndef ANYBSD #define ANYBSD #endif /* ANYBSD */ #endif /* BSD4 */ #ifdef BSD29 /* BSD29 implies ANYBSD */ #ifndef ANYBSD #define ANYBSD #endif /* ANYBSD */ #endif /* BSD29 */ #ifdef ATTSV /* ATTSV implies UNIX */ #ifndef UNIX #define UNIX #endif /* UNIX */ #endif /* ATTSV */ #ifdef ANYBSD /* ANYBSD implies UNIX */ #ifndef UNIX #define UNIX #endif /* UNIX */ #endif /* ANYBSD */ #ifdef POSIX /* POSIX implies UNIX */ #ifndef UNIX #define UNIX #endif /* UNIX */ #ifndef DIRENT /* and DIRENT, i.e. */ #ifndef SDIRENT #define DIRENT #endif /* SDIRENT */ #endif /* DIRENT */ #ifndef NOFILEH /* POSIX doesn't use */ #define NOFILEH #endif /* NOFILEH */ #endif /* POSIX */ #ifdef V7 #ifndef UNIX #define UNIX extern int errno; /* fdc 1 November 2022 */ #endif /* UNIX */ #endif /* V7 */ #ifdef COHERENT #ifndef UNIX #define UNIX #endif /* UNIX */ #ifdef COMMENT #ifndef NOCURSES #define NOCURSES #endif /* NOCURSES */ #endif /* COMMENT */ #endif /* COHERENT */ #ifdef MINIX #ifndef UNIX #define UNIX #endif /* UNIX */ #endif /* MINIX */ /* The symbol SVORPOSIX is defined for both AT&T and POSIX compilations to make it easier to select items that System V and POSIX have in common, but which BSD, V7, etc, do not have. */ #ifdef ATTSV #ifndef SVORPOSIX #define SVORPOSIX #endif /* SVORPOSIX */ #endif /* ATTSV */ #ifdef POSIX #ifndef SVORPOSIX #define SVORPOSIX #endif /* SVORPOSIX */ #endif /* POSIX */ /* The symbol SVR4ORPOSIX is defined for both AT&T System V R4 and POSIX compilations to make it easier to select items that System V R4 and POSIX have in common, but which BSD, V7, and System V R3 and earlier, etc, do not have. */ #ifdef POSIX #ifndef SVR4ORPOSIX #define SVR4ORPOSIX #endif /* SVR4ORPOSIX */ #endif /* POSIX */ #ifdef SVR4 #ifndef SVR4ORPOSIX #define SVR4ORPOSIX #endif /* SVR4ORPOSIX */ #endif /* SVR4 */ /* The symbol BSD44ORPOSIX is defined for both 4.4BSD and POSIX compilations to make it easier to select items that 4.4BSD and POSIX have in common, but which System V, BSD, V7, etc, do not have. */ #ifdef BSD44 #ifndef BSD44ORPOSIX #define BSD44ORPOSIX #endif /* BSD44ORPOSIX */ #endif /* BSD44 */ #ifdef POSIX #ifndef BSD44ORPOSIX #define BSD44ORPOSIX #endif /* BSD44ORPOSIX */ #endif /* POSIX */ #ifdef UNIX /* For items common to OS/2 and UNIX */ #ifndef OS2ORUNIX #define OS2ORUNIX #endif /* OS2ORUNIX */ #endif /* UNIX */ #ifdef UNIX /* For items common to Win32 and UNIX */ #ifndef WIN32ORUNIX #define WIN32ORUNIX #endif /* WIN32ORUNIX */ #endif /* UNIX */ #ifdef UNIX /* For items common to VMS and UNIX */ #define VMSORUNIX #else #ifdef VMS #define VMSORUNIX #ifndef OS2ORVMS #define OS2ORVMS #endif /* OS2ORVMS */ #endif /* VMS */ #endif /* UNIX */ #ifndef UNIXOROSK /* UNIX or OS-9 (or OS-9000) */ #ifdef UNIX #define UNIXOROSK #else #ifdef OSK #define UNIXOROSK #endif /* OSK */ #endif /* UNIX */ #endif /* UNIXOROSK */ #ifndef OSKORUNIX #ifdef UNIXOROSK #define OSKORUNIX #endif /* UNIXOROSK */ #endif /* OSKORUNIX */ #ifdef OS2 #ifndef CK_ANSIC #define CK_ANSIC /* OS/2 supports ANSIC and more extensions */ #endif /* CK_ANSIC */ #endif /* OS2 */ #ifdef OSF50 /* Newer OSF/1 versions imply older ones */ #ifndef OSF40 #define OSF40 #endif /* OSF40 */ #endif /* OSF50 */ #ifdef OSF40 #ifndef OSF32 #define OSF32 #endif /* OSF32 */ #endif /* OSF40 */ #ifdef OSF32 #ifndef OSF30 #define OSF30 #endif /* OSF30 */ #endif /* OSF32 */ #ifdef OSF30 #ifndef OSF20 #define OSF20 #endif /* OSF20 */ #endif /* OSF30 */ #ifdef OSF20 #ifndef OSF10 #define OSF10 #endif /* OSF10 */ #endif /* OSF20 */ #ifdef __DECC /* For DEC Alpha VMS or OSF/1 */ #ifndef CK_ANSIC #define CK_ANSIC /* Even with /stand=vaxc, need ansi */ #endif /* CKANSIC */ #ifndef SIG_V #define SIG_V /* and signal type is VOID */ #endif /* SIG_V */ #ifndef CK_ANSILIBS #define CK_ANSILIBS /* (Martin Zinser, Feb 1995) */ #endif /* CK_ANSILIBS */ #ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 1 #endif /* _POSIX_C_SOURCE */ #endif /* __DECC */ #ifdef VMS /* 2022-12-05 SMS. All hardware architectures after VAX are 64-bit. * Testing for (32-bit) VAX is safer in the long term than testing for * __ALPHA, __ia64, __x86_64, et al. */ #ifndef VMS64 /* Belt. */ #ifdef __ALPHA #define VMS64 #else /* def __ALPHA */ #ifdef __ia64 #define VMS64 #else /* def __ia64 */ #ifdef __x86_64 #define VMS64 #endif /* def __x86_64 */ #endif /* def __ia64 [else] */ #endif /* def __ALPHA [else] */ #endif /* ndef VMS64 */ #ifndef VMS64 /* Suspenders. */ #ifndef __VAX #ifndef vax #ifndef __vax #ifndef __vax__ #define VMS64 #endif /* ndef __vax__ */ #endif /* ndef __vax */ #endif /* ndef vax */ #endif /* ndef __VAX */ #endif /* ndef VMS64 */ #endif /* def VMS */ #ifdef apollo /* May be ANSI-C, check further */ #ifdef __STDCPP__ #define CK_ANSIC /* Yes, this is real ANSI-C */ #define SIG_V #else #define NOANSI /* Nope, not ANSI */ #undef __STDC__ /* Even though it say it is! */ #define SIG_I #endif /* __STDCPP__ */ #endif /* apollo */ #ifdef POSIX /* -DPOSIX on cc command line */ #ifndef _POSIX_SOURCE /* Implies _POSIX_SOURCE */ #define _POSIX_SOURCE #endif /* _POSIX_SOURCE */ #endif /* POSIX */ /* ANSI C? That is, do we have function prototypes, new-style function declarations, and parameter type checking and coercion? */ #ifdef MAC /* MPW C is ANSI */ #ifndef NOANSI #ifndef CK_ANSIC #define CK_ANSIC #endif /* CK_ANSIC */ #endif /* NOANSI */ #endif /* MAC */ #ifdef STRATUS /* Stratus VOS */ #ifndef CK_ANSIC #define CK_ANSIC #endif /* CK_ANSIC */ #ifndef NOSTAT #define NOSTAT #endif /* NOSTAT */ #endif /* STRATUS */ #ifndef NOANSI #ifdef __STDC__ /* __STDC__ means ANSI C */ #ifndef CK_ANSIC #define CK_ANSIC #endif /* CK_ANSIC */ #endif /* __STDC__ */ #endif /* NOANSI */ /* _PROTOTYP() is used for forward declarations of functions so we can have parameter and return value type checking if the compiler offers it. __STDC__ should be defined by the compiler only if function prototypes are allowed. Otherwise, we get old-style forward declarations. Our own private CK_ANSIC symbol tells whether we use ANSI C prototypes. To force use of ANSI prototypes, include -DCK_ANSIC on the cc command line. To disable the use of ANSI prototypes, include -DNOANSI. */ #ifdef CK_ANSIC #define _PROTOTYP( func, parms ) func parms #else /* Not ANSI C */ #define _PROTOTYP( func, parms ) func() #endif /* CK_ANSIC */ #ifndef OS2 #ifdef NOLOGIN /* NOLOGIN implies NOIKSD */ #ifndef NOIKSD #define NOIKSD #endif /* NOIKSD */ #endif /* NOLOGIN */ #endif /* OS2 */ #ifdef NOIKSD /* Internet Kermit Service Daemon */ #ifndef OS2 #ifndef NOPRINTFSUBST #define NOPRINTFSUBST #endif /* NOPRINTFSUBST */ #endif /* OS2 */ #ifndef NOLOGIN #define NOLOGIN #endif /* NOLOGIN */ #ifndef NOSYSLOG #define NOSYSLOG #endif /* NOSYSLOG */ #ifndef NOWTMP /* Redundant but does no harm */ #define NOWTMP #endif /* NOWTMP */ #else #ifndef IKSD #ifdef OS2ORUNIX /* Platforms where IKSD is supported */ #define IKSD #endif /* OS2ORUNIX */ #endif /* IKSD */ #endif /* NOIKSD */ #ifdef IKSD /* IKSD options... */ #ifndef IKSDCONF /* IKSD configuration file */ #ifdef UNIX #define IKSDCONF "/etc/iksd.conf" #else #ifdef OS2 #define IKSDCONF "iksd.ksc" #endif /* OS2 */ #endif /* UNIX */ #endif /* IKSDCONF */ #ifndef NOIKSDB #ifndef IKSDB /* IKSD database */ #ifdef UNIX #define IKSDB #define IK_LCKTRIES 16 /* How many times to try to get lock */ #define IK_LCKSLEEP 1 /* How long to sleep between tries */ #define IK_LOCKFILE "iksd.lck" /* Database lockfilename */ #define IK_DBASEDIR "/var/log/" /* Database directory */ #define IK_DBASEFIL "iksd.db" /* Database filename */ #else /* UNIX */ #ifdef OS2 #define IKSDB #ifndef NOFTRUNCATE /* ftruncate() not available */ #define NOFTRUNCATE #endif /* NOFTRUNCATE */ #define IK_LCKTRIES 16 /* How many times to try to get lock */ #define IK_LCKSLEEP 1 /* How long to sleep between tries */ #define IK_LOCKFILE "iksd.lck" /* DB lockfilename (in systemroot) */ #define IK_DBASEFIL "iksd.db" /* Database filename */ #endif /* OS2 */ #endif /* UNIX */ #endif /* IKSDB */ #endif /* NOIKSDB */ #endif /* IKSD */ /* Substitutes for printf() and friends used in IKS to compensate for lack of a terminal driver, mainly to supply CR after LF. */ #ifndef NOPRINTFSUBST #ifdef MAC /* * The MAC doesn't use standard stdio routines. */ #undef getchar #define getchar() mac_getchar() #undef putchar #define putchar(c) mac_putchar(c) #define printf mac_printf #define perror mac_perror #define puts mac_puts extern int mac_putchar (int c); extern int mac_puts (const char *string); extern int mac_printf(const char *, ...); extern int mac_getchar (void); #endif /* MAC */ #ifdef OS2 #ifndef CKODIALER #define printf Vscrnprintf #define fprintf Vscrnfprintf extern int Vscrnprintf(const char *, ...); extern int Vscrnprintw(const char *, ...); extern int Vscrnfprintf(FILE *, const char *, ...); #ifdef putchar #undef putchar #endif /* putchar */ #define putchar(x) Vscrnprintf("%c",x) #define perror(x) Vscrnperror(x) void Vscrnperror( const char *str ); #endif /* CKODIALER */ #endif /* OS2 */ #ifndef CKWART_C #ifdef UNIX #ifndef pdp11 #ifndef CKXPRINTF #define CKXPRINTF #endif /* CKXPRINTF */ #endif /* pdp11 */ #endif /* UNIX */ #endif /* CKWART_C */ #endif /* NOPRINTFSUBST */ #ifdef CKXPRINTF #define printf ckxprintf #define fprintf ckxfprintf #ifdef CK_ANSIC _PROTOTYP(int ckxprintf,(const char *, ...)); #ifdef NEXT _PROTOTYP(void ckxperror,(const char *)); #else #ifdef CK_SCOV5 _PROTOTYP(void ckxperror,(const char *)); #else _PROTOTYP(int ckxperror,(const char *)); #endif /* CK_SCOV5 */ #endif /* NEXT */ _PROTOTYP(int ckxfprintf,(FILE *, const char *, ...)); #endif /* CK_ANSIC */ #ifdef putchar #undef putchar #endif /* putchar */ #define putchar(x) ckxprintf("%c",x) #ifdef putc #undef putc #endif /* putc */ #define putc(a,b) ckxfprintf(b,"%c",a) #define perror(x) ckxperror(x) #endif /* CKXPRINTF */ /* Altos-specific items: 486, 586, 986 models... */ #ifdef A986 #define M_VOID #define void int #define CHAR char #define SIG_I #endif /* A986 */ /* Signal handling */ #ifdef QNX #ifndef CK_POSIX_SIG #define CK_POSIX_SIG #endif /* CK_POSIX_SIG */ #endif /* QNX */ /* void type, normally available only in ANSI compilers. The HP-UX exception (for its "bundled" non-ANSI C compiler) is known to be valid back to HP-UX 6.5. Adjustments might be needed for earlier HP-UX versions. */ #ifndef VOID /* Used throughout all C-Kermit */ #ifdef CK_ANSIC /* modules... */ #define VOID void #else #ifdef HPUX #define VOID void #else #define VOID int #endif /* HPUX */ #endif /* CK_ANSIC */ #endif /* VOID */ /* Exactly the same as VOID but for use in contexts where the VOID symbol conflicts some header-file definition. This is needed for the section of ckuusx.c that provides C-Kermit's curses interface, roughly the second half of ckuusx.c. */ #ifndef CKVOID #ifdef CK_ANSIC #define CKVOID void #else #ifdef HPUX #define CKVOID void #else #define CKVOID int #endif /* HPUX */ #endif /* CK_ANSIC */ #endif /* CKVOID */ /* Const type */ #ifndef CONST #ifdef OSK #ifdef _UCC #define CONST const #else #define CONST #endif /* _UCC */ #else /* !OSK */ #ifdef CK_SCO32V4 #define CONST #else #ifdef CK_ANSIC #define CONST const #else #define CONST #endif /* CK_ANSIC */ #endif /* CK_SCO32V4 */ #endif /* OSK */ #endif /* CONST */ /* Signal type */ #ifndef SIG_V /* signal() type, if not def'd yet */ #ifndef SIG_I #ifdef OS2 #define SIG_V #else #ifdef POSIX #define SIG_V #else #ifdef SVR3 /* System V R3 and later */ #define SIG_V #else #ifdef SUNOS4 /* SUNOS V 4.0 and later */ #ifndef sun386 #define SIG_V #else #define SIG_I #endif /* sun386 */ #else #ifdef NEXT /* NeXT */ #define SIG_V #else #ifdef AIX370 #include #define SIG_V #define SIGTYP __SIGVOID /* AIX370 */ #else #ifdef STRATUS /* Stratus VOS */ #define SIG_V #else #ifdef MAC #define SIGTYP long #define SIG_I #ifndef MPW33 #define SIG_IGN 0 #endif /* MPW33 */ #define SIGALRM 1 #ifndef MPW33 #define SIGINT 2 #endif /* MPW33 */ #else /* Everything else */ #define SIG_I #endif /* MAC */ #endif /* STRATUS */ #endif /* AIX370 */ #endif /* NEXT */ #endif /* SUNOS4 */ #endif /* SVR3 */ #endif /* POSIX */ #endif /* OS2 */ #endif /* SIG_I */ #endif /* SIG_V */ #ifdef SIG_I #define SIGRETURN return(0) #ifndef SIGTYP #define SIGTYP int #endif /* SIGTYP */ #endif /* SIG_I */ #ifdef SIG_V #define SIGRETURN return #ifndef SIGTYP #define SIGTYP void #endif /* SIGTYP */ #endif /* SIG_V */ #ifdef NT #ifndef SIGTYP #define SIGTYP void #endif /* SIGTYP */ #endif /* NT */ #ifndef SIGTYP #define SIGTYP int #endif /* SIGTYP */ #ifndef SIGRETURN #define SIGRETURN return(0) #endif /* SIGRETURN */ #ifdef CKNTSIG /* This does not work, so don't use it. */ #define signal ckntsignal SIGTYP (*ckntsignal(int type, SIGTYP (*)(int)))(int); #endif /* CKNTSIG */ /* We want all characters to be unsigned if the compiler supports it */ #ifdef KUI #ifdef CHAR #undef CHAR #endif /* CHAR */ #define CHAR unsigned char #else #ifdef PROVX1 typedef char CHAR; /* typedef long LONG; */ typedef int void; #else #ifdef MINIX typedef unsigned char CHAR; #else #ifdef V7 typedef char CHAR; #else #ifdef C70 typedef char CHAR; /* typedef long LONG; */ #else #ifdef BSD29 typedef char CHAR; /* typedef long LONG; */ #else #ifdef datageneral #define CHAR unsigned char /* 3.22 compiler */ #else #ifdef HPUX #define CHAR unsigned char #else #ifdef OS2 #ifdef NT #define CHAR unsigned char #else /* NT */ #ifdef CHAR #undef CHAR #endif /* CHAR */ typedef unsigned char CHAR; #endif /* NT */ #else /* OS2 */ #ifdef VMS typedef unsigned char CHAR; #else #ifdef CHAR #undef CHAR #endif /* CHAR */ typedef unsigned char CHAR; #endif /* VMS */ #endif /* OS2 */ #endif /* HPUX */ #endif /* datageneral */ #endif /* BSD29 */ #endif /* C70 */ #endif /* V7 */ #endif /* MINIX */ #endif /* PROVX1 */ #endif /* KUI */ union ck_short { /* Mainly for Unicode */ USHORT x_short; CHAR x_char[2]; }; #ifdef MAC /* Macintosh file routines */ #ifndef CKWART_C /* But not in "wart"... */ #ifdef feof #undef feof #endif /* feof */ #define feof mac_feof #define rewind mac_rewind #define fgets mac_fgets #define fopen mac_fopen #define fclose mac_fclose int mac_feof(); void mac_rewind(); char *mac_fgets(); FILE *mac_fopen(); int mac_fclose(); #endif /* CKCPRO_W */ #endif /* MAC */ /* Systems whose mainline modules have access to the communication-line file descriptor, ttyfd. */ #ifndef CK_TTYFD #ifdef UNIX #define CK_TTYFD #else #ifdef OS2 #define CK_TTYFD #else #ifdef VMS #define CK_TTYFD #endif /* VMS */ #endif /* OS2 */ #endif /* UNIX */ #endif /* CK_TTYFD */ /* Systems where we can get our own process ID */ #ifndef CK_PID #ifdef UNIX #define CK_PID #endif /* UNIX */ #ifdef OS2 #define CK_PID #endif /* OS2 */ #ifdef VMS #define CK_PID #endif /* VMS */ #endif /* CK_PID */ /* Systems that support the Microsoft Telephony API (TAPI) */ #ifndef NODIAL #ifndef CK_TAPI #ifdef NT #ifndef NOTAPI #define CK_TAPI #endif /* NOTAPI */ #endif /* NT */ #endif /* CK_TAPI */ #endif /* NODIAL */ #ifndef NONZXPAND #ifndef NZXPAND #ifdef OS2ORUNIX #define NZXPAND #else #ifdef VMS #define NZXPAND #else #ifdef datageneral #define NZXPAND #else #ifdef OSK #define NZXPAND #endif /* OSK */ #endif /* datageneral */ #endif /* VMS */ #endif /* OS2ORUNIX */ #endif /* NZXPAND */ #else #ifdef NZXPAND #undef NZXPAND #endif /* NZXPAND */ #endif /* NONZXPAND */ /* nzxpand() option flags */ #define ZX_FILONLY 1 /* Match only regular files */ #define ZX_DIRONLY 2 /* Match only directories */ #define ZX_RECURSE 4 /* Descend through directory tree */ #define ZX_MATCHDOT 8 /* Match "dot files" */ #define ZX_NOBACKUP 16 /* Don't match "backup files" */ #define ZX_NOLINKS 32 /* Don't follow symlinks */ #ifndef NZXPAND #define nzxpand(a,b) zxpand(a) #endif /* NZXPAND */ #ifndef NOZXREWIND #ifndef ZXREWIND /* Platforms that have zxrewind() */ #ifdef OS2ORUNIX #define ZXREWIND #else #ifdef VMS #define ZXREWIND #else #ifdef datageneral #define ZXREWIND #else #ifdef OSK #define ZXREWIND #else #ifdef STRATUS #define ZXREWIND #endif /* STRATUS */ #endif /* OSK */ #endif /* datageneral */ #endif /* VMS */ #endif /* OS2ORUNIX */ #endif /* ZXREWIND */ #else #ifdef ZXREWIND #undef ZXREWIND #endif /* ZXREWIND */ #endif /* NOZXREWIND */ /* Temporary-directory-for-RECEIVE feature ... */ /* This says whether we have the isdir() function defined. */ #ifdef UNIX /* UNIX has it */ #ifndef CK_TMPDIR #ifndef pdp11 #define CK_TMPDIR #define TMPDIRLEN 256 #endif /* pdp11 */ #endif /* CK_TMPDIR */ #endif /* UNIX */ #ifdef VMS /* VMS too */ #ifndef CK_TMPDIR #define CK_TMPDIR #define TMPDIRLEN 256 #endif /* CK_TMPDIR */ #endif /* VMS */ #ifdef OS2 /* OS two too */ #ifndef CK_TMPDIR #define CK_TMPDIR #define TMPDIRLEN 129 #endif /* CK_TMPDIR */ #endif /* OS2 */ #ifdef STRATUS /* Stratus VOS too. */ #ifndef CK_TMPDIR #define CK_TMPDIR #define TMPDIRLEN 256 #endif /* CK_TMPDIR */ #endif /* STRATUS */ #ifdef OSK /* OS-9 too */ #ifndef CK_TMPDIR #define CK_TMPDIR #define TMPDIRLEN 256 #endif /* CK_TMPDIR */ #endif /* OSK */ #ifdef datageneral /* AOS/VS too */ #ifndef CK_TMPDIR #define CK_TMPDIR #define TMPDIRLEN 256 #endif /* CK_TMPDIR */ #endif /* datageneral */ #ifdef CK_TMPDIR /* Needs command parser */ #ifdef NOICP #undef CK_TMPDIR #endif /* NOICP */ #endif /* CK_TMPDIR */ /* Whether to include or */ #ifndef NOTIMEH /* */ #ifndef TIMEH #define TIMEH #endif /* TIMEH */ #endif /* NOTIMEH */ #ifndef NOSYSTIMEH /* */ #ifndef SYSTIMEH #ifdef UNIX /* UNIX */ #ifdef SVORPOSIX /* System V or POSIX... */ #ifdef M_UNIX #define SYSTIMEH #else #ifdef SCO_32V4 #define SYSTIMEH #else #ifdef OXOS #define SYSTIMEH #else #ifdef BSD44 #define SYSTIMEH #else #ifdef __linux__ #define SYSTIMEH #else #ifdef AIXRS #ifndef AIX41 #define SYSTIMEH #endif /* AIX41 */ #else #ifdef IRIX60 #define SYSTIMEH #else #ifdef I386IX #define SYSTIMEH #else #ifdef SV68R3V6 #define SYSTIMEH #endif /* SV68R3V6 */ #endif /* I386IX */ #endif /* IRIX60 */ #endif /* AIXRS */ #endif /* __linux__ */ #endif /* BSD44 */ #endif /* OXOS */ #endif /* SCO_32V4 */ #endif /* M_UNIX */ #else /* Not SVORPOSIX */ #ifndef BELLV10 /* All but these... */ #ifndef PROVX1 #ifndef V7 #ifndef BSD41 #ifndef COHERENT #define SYSTIMEH #endif /* COHERENT */ #endif /* BSD41 */ #endif /* V7 */ #endif /* PROVX1 */ #endif /* BELLV10 */ #endif /* SVORPOSIX */ #endif /* UNIX */ #endif /* SYSTIMEH */ #endif /* NOSYSTIMEH */ #ifndef NOSYSTIMEBH /* */ #ifndef SYSTIMEBH #ifdef OSF #define SYSTIMEBH #else #ifdef COHERENT #define SYSTIMEBH #else #ifdef BSD41 #define SYSTIMEBH #else #ifdef BSD29 #define SYSTIMEBH #else #ifdef TOWER1 #define SYSTIMEBH #else #ifdef FT21 #define SYSTIMEBH #else #ifdef BELLV10 #define SYSTIMEBH #endif /* BELLV10 */ #endif /* FT21 */ #endif /* TOWER1 */ #endif /* BSD29 */ #endif /* BSD41 */ #endif /* COHERENT */ #endif /* OSF */ #endif /* SYSTIMEBH */ #endif /* NOSYSTIMEBH */ /* Debug and transaction logging is included automatically unless you define NODEBUG or NOTLOG. Do this if you want to save the space and overhead. (Note, in version 4F these definitions changed from "{}" to the null string to avoid problems with semicolons after braces, as in: "if (x) tlog(this); else tlog(that);" */ #ifndef NODEBUG #ifndef DEBUG #define DEBUG #endif /* DEBUG */ #else #ifdef DEBUG #undef DEBUG #endif /* DEBUG */ #endif /* NODEBUG */ #ifdef NOTLOG #ifdef TLOG #undef TLOG #endif /* TLOG */ #else /* NOTLOG */ #ifndef TLOG #define TLOG #endif /* TLOG */ #endif /* NOTLOG */ /* debug() macro style selection. */ #ifdef VMS #ifndef IFDEBUG #define IFDEBUG #endif /* IFDEBUG */ #endif /* VMS */ #ifdef MAC #ifndef IFDEBUG #define IFDEBUG #endif /* IFDEBUG */ #endif /* MAC */ #ifdef OS2 #ifndef IFDEBUG #define IFDEBUG #endif /* IFDEBUG */ #endif /* OS2 */ #ifdef OXOS /* tst is faster than jsr */ #ifndef IFDEBUG #define IFDEBUG #endif /* IFDEBUG */ #endif /* OXOS */ #ifndef CKCMAI extern int deblog; extern int debok; extern int debxlen; extern int matchdot; extern int tt_bell; #endif /* CKCMAI */ #ifdef OS2 _PROTOTYP( void bleep, (short) ); #else /* OS2 */ #define bleep(x) if(tt_bell)putchar('\07') #endif /* OS2 */ #ifndef BEOSORBEBOX #ifdef BEBOX /* This was used only for DR7 */ #define BEOSORBEBOX #else #ifdef BEOS /* This is used for BeOS 4.x */ #define BEOSORBEBOX #endif /* BEOS */ #endif /* BEBOX */ #endif /* BEOSORBEBOX */ #ifdef NOICP #ifdef TLOG #undef TLOG #endif /* TLOG */ #endif /* NOICP */ /* Formats for debug() and tlog() */ #define F000 0 #define F001 1 #define F010 2 #define F011 3 #define F100 4 #define F101 5 #define F110 6 #define F111 7 #ifdef __linux__ #ifndef LINUX #define LINUX #endif /* LINUX */ #ifdef __ANDROID__ #ifndef ANDROID #define ANDROID #endif /* ANDROID */ #endif /* __ANDROID__ */ #endif /* __linux__ */ /* Platforms where small size is needed */ #ifdef pdp11 #define CK_SMALL #endif /* pdp11 */ /* Can we use realpath()? */ #ifndef NOREALPATH #ifdef pdp11 #define NOREALPATH #endif /* pdp11 */ #endif /* NOREALPATH */ #ifndef NOREALPATH #ifdef UNIX #ifdef HPUX5 #define NOREALPATH #else #ifdef HPUX6 #define NOREALPATH #else #ifdef HPUX7 #define NOREALPATH #else #ifdef HPUX8 #define NOREALPATH #else #ifdef SV68R3V6 #define NOREALPATH #else #ifdef XENIX #define NOREALPATH #else #ifdef CK_SCO32V4 #define NOREALPATH #else #ifdef CK_SCOV5 #define NOREALPATH #else #ifdef OSF32 #define NOREALPATH #else #ifdef OSF30 #define NOREALPATH #else #ifdef ultrix #define NOREALPATH #else #ifdef COHERENT #define NOREALPATH #endif /* COHERENT */ #endif /* ultrix */ #endif /* OSF30 */ #endif /* OSF32 */ #endif /* CK_SCOV5 */ #endif /* CK_SCO32V4 */ #endif /* XENIX */ #endif /* SV68R3V6 */ #endif /* HPUX8 */ #endif /* HPUX7 */ #endif /* HPUX6 */ #endif /* HPUX5 */ #endif /* NOREALPATH */ #ifndef NOREALPATH #ifndef CKREALPATH #define CKREALPATH #endif /* NOREALPATH */ #endif /* CKREALPATH */ #endif /* UNIX */ #ifdef CKREALPATH #ifdef OS2ORUNIX #ifndef CKROOT #define CKROOT #endif /* CKROOT */ #endif /* OS2ORUNIX */ #endif /* CKREALPATH */ /* CKSYMLINK should be set only if we can use readlink() */ #ifdef UNIX #ifndef NOSYMLINK #ifndef CKSYMLINK #define CKSYMLINK #endif /* NOSYMLINK */ #endif /* CKSYMLINK */ #endif /* UNIX */ /* Platforms where we can use lstat() instead of stat() (for symlinks) */ /* This should be set only if both lstat() and readlink() are available */ #ifndef NOLSTAT #ifndef NOSYMLINK #ifndef USE_LSTAT #ifdef UNIX #ifdef CKSYMLINK #ifdef SVR4 /* SVR4 has lstat() */ #define USE_LSTAT #else #ifdef BSD42 /* 4.2BSD and 4.3BSD have it */ #define USE_LSTAT /* This should include old HPUXs */ #else #ifdef BSD44 /* 4.4BSD has it */ #define USE_LSTAT #else #ifdef LINUX /* LINUX has it */ #define USE_LSTAT #else #ifdef SUNOS4 /* SunOS has it */ #define USE_LSTAT #endif /* SUNOS4 */ #endif /* LINUX */ #endif /* BSD44 */ #endif /* BSD42 */ #endif /* SVR4 */ #endif /* CKSYMLINK */ #endif /* UNIX */ #endif /* USE_LSTAT */ #endif /* NOSYMLINK */ #endif /* NOLSTAT */ #ifdef NOLSTAT #ifdef USE_LSTAT #undef USE_LSTAT #endif /* USE_LSTAT */ #endif /* NOLSTAT */ #ifndef NOTTYLOCK /* UNIX systems that have ttylock() */ #ifndef USETTYLOCK #ifdef AIXRS /* AIX 3.1 and later */ #define USETTYLOCK #else #ifdef USE_UU_LOCK /* FreeBSD or other with uu_lock() */ #define USETTYLOCK #else /* Prior to 8.0.299 Alpha.08 this was HAVE_BAUDBOY which was added for Red Hat 7.2 in May 2003 but which is no longer supported in Debian and OpenSuse (at least). */ #ifdef HAVE_LOCKDEV #define USETTYLOCK #endif /* HAVE_LOCKDEV */ #endif /* USE_UU_LOCK */ #endif /* AIXRS */ #endif /* USETTYLOCK */ #endif /* NOTTYLOCK */ /* This could be more inclusive... But better not to use snprintf() at all, it's hard to find a way to test for its availability without using nonportable preprocessor constructions. Use ckclib.c: ckmakmsg() or ckmakxmsg() instead of both sprintf() and snprintf() to squelch compiler warnings and ensure no memory leaks. */ #ifndef HAVE_SNPRINTF /* Safe to use snprintf() */ #ifdef HAVE_OPENPTY #define HAVE_SNPRINTF #endif /* HAVE_OPENPTY */ #endif /* HAVE_SNPRINTF */ /* Kermit feature selection */ #ifndef NOSPL #ifndef NOCHANNELIO /* Channel-based file i/o package */ #ifndef CKCHANNELIO #ifdef UNIX #define CKCHANNELIO #else #ifdef OS2 #define CKCHANNELIO #else #ifdef VMS #define CKCHANNELIO #else #ifdef STRATUS #define CKCHANNELIO #endif /* STRATUS */ #endif /* VMS */ #endif /* OS2 */ #endif /* UNIX */ #endif /* CKCHANNELIO */ #endif /* NOCHANNELIO */ #endif /* NOSPL */ #ifndef NOCKEXEC /* EXEC command */ #ifndef NOPUSH #ifndef CKEXEC #ifdef UNIX /* UNIX can do it */ #define CKEXEC #endif /* UNIX */ #endif /* CKEXEC */ #endif /* NOPUSH */ #endif /* NOCKEXEC */ #ifndef NOFAST /* Fast Kermit protocol by default */ #ifndef CK_FAST #ifdef UNIX #define CK_FAST #else #ifdef VMS #define CK_FAST #else #ifdef OS2 #define CK_FAST #endif /* OS2 */ #endif /* VMS */ #endif /* UNIX */ #endif /* CK_FAST */ #endif /* NOFAST */ #ifdef UNIX /* Transparent print */ #ifndef NOXPRINT #ifndef XPRINT #define XPRINT #endif /* XPRINT */ #endif /* NOXPRINT */ #endif /* UNIX */ #ifndef NOHWPARITY /* Hardware parity */ #ifndef HWPARITY #ifdef SVORPOSIX /* System V or POSIX can have it */ #define HWPARITY #else #ifdef SUNOS41 /* SunOS 4.1 can have it */ #define HWPARITY #else #ifdef OS2 /* K95 can have it */ #define HWPARITY #endif /* OS2 */ #endif /* SUNOS41 */ #endif /* SVORPOSIX */ #endif /* HWPARITY */ #endif /* NOHWPARITY */ #ifndef NOSTOPBITS /* Stop-bit selection */ #ifndef STOPBITS #ifdef OS2ORUNIX /* In Unix really this should only be if CSTOPB is defined. */ /* But we don't know that yet. */ #define STOPBITS #else #ifdef TN_COMPORT #define STOPBITS #endif /* TN_COMPORT */ #endif /* OS2ORUNIX */ #endif /* STOPBITS */ #endif /* NOSTOPBITS */ #ifdef UNIX #ifndef NETCMD /* Can SET NETWORK TYPE COMMAND */ #define NETCMD #endif /* NETCMD */ #endif /* UNIX */ /* Pty support, nonportable, available on a case-by-case basis */ #ifndef NOPTY #ifdef NEXT /* NeXTSTEP (tested on 3.1)*/ #define NETPTY #else #ifdef CK_SCOV5 /* SCO OSR5 (tested on 5.0.5)*/ #define NETPTY #else #ifdef QNX /* QNX (tested on 4.25) */ #define NETPTY #else #ifdef SINIX /* Sinix (tested on 5.42) */ #define NETPTY #else #ifdef DGUX540 /* DG/UX 5.4++ (tested on 5.4R4.11) */ #define NETPTY #else #ifdef OSF32 /* Digital Unix 3.2 */ #define NETPTY #else #ifdef OSF40 /* Digital Unix 4.0 / Tru64 */ #define NETPTY #else #ifdef IRIX60 /* IRIX 6.0 (not earlier) */ #define NETPTY #else #ifdef HPUX10 /* HPUX 10.00 or later */ #define NETPTY #ifndef HAVE_PTYTRAP #define HAVE_PTYTRAP #endif /* HAVE_PTYTRAP */ #else #ifdef HPUX9 /* HPUX 9.00 (not earlier) */ #define NETPTY #ifndef HAVE_PTYTRAP #define HAVE_PTYTRAP #endif /* HAVE_PTYTRAP */ #else #ifdef BSD44 /* BSD44, {Net,Free,Open}BSD */ #define NETPTY #else #ifdef BSDI /* BSDI/OS (tested in 4) */ #define NETPTY #else #ifdef SOLARIS /* Solaris (tested in 2.5) */ #define NETPTY #else #ifdef UW7 /* Unixware 7 */ #define NETPTY #else #ifdef SUNOS41 /* SunOS (tested in 4.1.3) */ #define NETPTY #else #ifdef AIX41 /* AIX 4.1 and later */ #define NETPTY #else #ifdef LINUX /* Linux */ #define NETPTY #else #ifdef NT /* Windows NT */ /* NT only gets PTY support when built with CK_CONPTY as it requires * a sufficiently new Platform SDK and compiler. */ #ifdef CK_CONPTY #define NETPTY #endif /* CK_CONPTY */ #endif /* NT */ #endif /* LINUX */ #endif /* AIX41 */ #endif /* SUNOS41 */ #endif /* UW7 */ #endif /* SOLARIS */ #endif /* BSDI */ #endif /* BSD44 */ #endif /* HPUX9 */ #endif /* HPUX10 */ #endif /* IRIX60 */ #endif /* OSF40 */ #endif /* OSF32 */ #endif /* DGUX540 */ #endif /* SINIX */ #endif /* QNX */ #endif /* CK_SCOV5 */ #endif /* NEXT */ #else /* NOPTY */ #ifdef NETPTY #undef NETPTY #endif /* NETPTY */ #endif /* NOPTY */ #ifdef NETPTY /* NETCMD required for NETPTY */ #ifndef NETCMD #define NETCMD #endif /* NETCMD */ #ifndef NO_OPENPTY /* Can use openpty() */ #ifndef HAVE_OPENPTY #ifdef __linux__ #define HAVE_OPENPTY #else #ifdef __FreeBSD__ #define HAVE_OPENPTY #else #ifdef __OpenBSD__ #define HAVE_OPENPTY #else #ifdef __NetBSD__ #define HAVE_OPENPTY #include #else #ifdef MACOSX10 #define HAVE_OPENPTY #endif /* MACOSX10 */ #endif /* __NetBSD__ */ #endif /* __OpenBSD__ */ #endif /* __FreeBSD__ */ #endif /* __linux__ */ #endif /* HAVE_OPENPTY */ #endif /* NO_OPENPTY */ /* This needs to be expanded and checked. The makefile assumes the library (at least for all linuxes) is always libutil but I've only verified it for a few. If a build fails because */ #ifdef HAVE_OPENPTY #ifdef __linux__ #include #else #ifdef __NetBSD__ #include #else #ifdef __OpenBSD__ #include #else #ifdef __FreeBSD__ #include #else #ifdef MACOSX #include #else #ifdef QNX #include #endif /* QNX */ #endif /* MACOSX */ #endif /* __FreeBSD__ */ #endif /* __OpenBSD__ */ #endif /* __NetBSD__ */ #endif /* __linux__ */ #endif /* HAVE_OPENPTY */ #endif /* NETPTY */ #ifndef CK_UTSNAME /* Can we call uname()? */ #ifdef VMS #define CK_UTSNAME #else #ifdef OS2 #define CK_UTSNAME #else #ifdef POSIX /* It's in POSIX.1 */ #define CK_UTSNAME #else #ifdef SUNOS41 /* It's in SunOS 4.1 */ #define CK_UTSNAME #else #ifdef AIXRS /* It's in AIX */ #define CK_UTSNAME #else #ifdef SVR4 /* It's in SVR4 (but not SVR3) */ #define CK_UTSNAME #else #ifdef HPUX /* It's in HP-UX 5.00 and later */ #define CK_UTSNAME #else #ifdef OSF /* It's in OSF/1 / Digital UNIX */ #define CK_UTSNAME #else #ifdef CK_SCOV5 #define CK_UTSNAME #endif /* CK_SCOV5 */ #endif /* OSF */ #endif /* HPUX */ #endif /* SVR4 */ #endif /* AIXRS */ #endif /* SUNOS41 */ #endif /* POSIX */ #endif /* OS2 */ #endif /* VMS */ #endif /* CK_UTSNAME */ /* This section for anything that might use floating-point */ /* If the following causes trouble use -DFLOAT=float on the command line */ #ifdef NOSPL #ifdef FNFLOAT #undef FNFLOAT #endif /* FNFLOAT */ #ifdef CKFLOAT #undef CKFLOAT #endif /* CKFLOAT */ #endif /* NOSPL */ #ifndef NOFLOAT #ifdef __alpha /* Why only __alpha? Other 64-bit systems? */ #define FLT_NOT_DBL /* (See also ckclib.c:ckround()). */ #else /* def __alpha */ #ifdef VMS64 #define FLT_NOT_DBL /* Was testing only __alpha below. */ #endif /* def VMS64 */ #endif /* def __alpha [else] */ #ifndef CKFLOAT #ifdef FLT_NOT_DBL /* 2024-05-16 SMS. Use instead of __alpha. */ /* Don't use double on 64-bit platforms -- bad things happen */ /* "double" on 64-bit platforms typically means 128-bit? Do we care?*/ #define CKFLOAT float #define CKFLOAT_S "float" #else /* def FLT_NOT_DBL */ #define CKFLOAT double #define CKFLOAT_S "double" #endif /* def FLT_NOT_DBL [else] */ #endif /* CKFLOAT */ #ifndef NOGFTIMER /* Floating-point timers */ #ifndef GFTIMER #ifdef UNIX /* For UNIX */ #define GFTIMER #endif /* UNIX */ #ifdef VMS /* VMS */ #ifndef OLD_VMS /* 5.0 and later */ #define GFTIMER #endif /* OLD_VMS */ #endif /* VMS */ #ifdef OS2 /* And K95 */ #define GFTIMER #endif /* OS2 */ #ifdef STRATUS /* And Stratus VOS */ #define GFTIMER #endif /* STRATUS */ #endif /* GFTIMER */ #endif /* NOGFTIMER */ #ifndef NOSPL #ifndef FNFLOAT /* Floating-point math functions */ #ifdef VMS /* defined by default in VMS */ #define FNFLOAT #else #ifdef OS2 /* and K95 */ #define FNFLOAT #endif /* OS2 */ #endif /* VMS */ #endif /* FNFLOAT */ #endif /* NOSPL */ #else /* NOFLOAT is defined */ #ifdef CKFLOAT #undef CKFLOAT #endif /* CKFLOAT */ #ifdef GFTIMER #undef GFTIMER #endif /* GFTIMER */ #ifdef FNFLOAT #undef FNFLOAT #endif /* FNFLOAT */ #endif /* NOFLOAT */ #ifdef GFTIMER /* Fraction of second to use when */ #ifndef GFMINTIME /* elapsed time is <= 0 */ #define GFMINTIME 0.005 #endif /* GFMINTIME */ #endif /* GFTIMER */ #ifndef CKCMAI extern long ztmsec, ztusec; /* Fraction of sec of current time */ #endif /* CKCMAI */ #ifndef NOUNPREFIXZERO /* Allow unprefixing of NUL (0) */ #ifndef UNPREFIXZERO /* in file-transfer packets */ #define UNPREFIXZERO #endif /* UNPREFIXZERO */ #endif /* NOUNPREFIXZERO */ #ifdef CK_SMALL #define NOCAL /* Calibrate */ #endif /* CK_SMALL */ #ifndef NOPATTERNS /* Filetype matching patterns */ #ifndef PATTERNS #ifndef VMS #ifndef CK_SMALL #define PATTERNS #endif /* CK_SMALL */ #endif /* VMS */ #endif /* PATTERNS */ #endif /* NOPATTERNS */ #ifndef NOCAL #ifndef CALIBRATE #define CALIBRATE #endif /* CALIBRATE */ #else #ifdef CALIBRATE #undef CALIBRATE #endif /* CALIBRATE */ #endif /* NOCAL */ #ifndef NORECURSE /* Recursive directory traversal */ #ifndef RECURSIVE #ifdef VMS #define RECURSIVE #else #ifdef OS2ORUNIX #ifndef CK_SMALL #define RECURSIVE #endif /* CK_SMALL */ #else #ifdef STRATUS #define RECURSIVE #else #ifdef OSK #define RECURSIVE #endif /* OSK */ #endif /* STRATUS */ #endif /* OS2ORUNIX */ #endif /* VMS */ #endif /* RECURSIVE */ #endif /* NORECURSE */ #ifndef CK_SMALL /* Enable file-transfer tuning code */ #ifndef CKTUNING /* in which more code is added */ #ifndef NOTUNING /* to avoid function calls, etc */ #define CKTUNING #endif /* NOTUNING */ #endif /* CKTUNING */ #endif /* CK_SMALL */ #ifndef NOURL /* Parse URLs in SET HOST, etc */ #define CK_URL #define NO_FTP_AUTH /* No auth "ftp" / "anonymous" */ #endif /* NOURL */ #ifndef NOTRIGGER #ifndef CK_TRIGGER /* Trigger string to exit CONNECT */ #ifdef OS2ORUNIX /* OK for UNIX and K95 */ #define CK_TRIGGER #else #ifdef VMS /* and VMS */ #define CK_TRIGGER #else #ifdef datageneral /* and AOS/VS */ #define CK_TRIGGER #endif /* datageneral */ #endif /* OS2ORUNIX */ #endif /* VMS */ #endif /* CK_TRIGGER */ #endif /* NOTRIGGER */ #ifdef CK_TRIGGER #define TRIGGERS 8 /* How many triggers allowed */ #endif /* CK_TRIGGER */ #ifndef XLIMITS /* CONNECT limits */ #ifdef OS2 #define XLIMITS #endif /* OS2 */ #endif /* XLIMITS */ #ifdef NOFRILLS #ifndef NOBROWSER #define NOBROWSER #endif /* NOBROWSER */ #ifndef NOFTP #define NOFTP #endif /* NOFTP */ #endif /* NOFRILLS */ #ifndef NOHTTP /* HTTP features need... */ #ifdef NOICP /* an interactive command parser */ #define NOHTTP #endif /* NOICP */ #ifndef VMS #ifndef OS2ORUNIX /* K95 or UNIX (because of */ #define NOHTTP /* time functions, time_t, etc) */ #endif /* OS2ORUNIX */ #endif /* VMS */ #endif /* NOHTTP */ #ifndef NONET #ifdef TCPSOCKET /* The HTTP code is not very portable, so it must be asked for with -DCKHTTP */ #ifndef NOHTTP #ifndef CKHTTP #ifdef SUNOS4 /* We can use it in SunOS */ #define CKHTTP #endif /* SUNOS4 */ #ifdef SOLARIS /* And in Solaris */ #define CKHTTP #endif /* SOLARIS */ #ifdef LINUX /* And Linux */ #define CKHTTP #endif /* LINUX */ #ifdef HPUX10 /* And HP-UX 10 and above */ #define CKHTTP #endif /* HPUX10 */ #ifdef OS2 /* And in K-95 */ #define CKHTTP #endif /* OS2 */ #ifdef AIX41 /* In AIX 4.1 and higher */ #define CKHTTP #endif /* AIX41 */ #ifdef UNIXWARE /* In Unixware 2.1 and higher */ #define CKHTTP /* and probably also in 1.x and 2.0 */ #endif /* UNIXWARE */ #ifdef CK_SCOV5 #define CKHTTP #endif /* CK_SCOV5 */ #ifdef OSF /* And in OSF Digital UNIX/True 64 */ #define CKHTTP #endif /* OSF */ #ifdef ultrix /* And in Ultrix Mips */ #ifdef mips #define CKHTTP #endif /* mips */ #endif /* ultrix */ #ifdef __NetBSD__ /* NetBSD */ #define CKHTTP #endif /* __NetBSD__ */ #ifdef __FreeBSD__ #define CKHTTP #endif /* __FreeBSD__ */ #ifdef __OpenBSD__ #define CKHTTP #endif /* __OpenBSD__ */ /* Add more here... */ #endif /* CKHTTP */ #ifndef CKHTTP /* If CKHTTP not defined yet */ #define NOHTTP /* then define NOHTTP */ #endif /* CKHTTP */ #endif /* NOHTTP */ #ifdef NETCONN /* Special "network" types... */ #ifndef NOLOCAL #ifdef OS2 #ifndef NETFILE #define NETFILE #endif /* NETFILE */ #ifndef NOPUSH #ifndef NETCMD #define NETCMD #endif /* NETCMD */ #endif /* NOPUSH */ #ifdef NT #ifndef NETDLL #define NETDLL #endif /* NETDLL */ #endif /* NT */ #endif /* OS2 */ #endif /* NOLOCAL */ #endif /* NETCONN */ #ifndef NOFTP #ifndef SYSFTP #ifndef NEWFTP #ifdef OS2ORUNIX #define NEWFTP #endif /* OS2ORUNIX */ #endif /* NEWFTP */ #endif /* SYSFTP */ #endif /* NOFTP */ #ifndef NOFTP #ifdef NEWFTP #ifdef SYSFTP #undef SYSFTP #endif /* SYSFTP */ #else /* NEWFTP */ #ifndef SYSFTP #define SYSFTP #endif /* SYSFTP */ #endif /* NEWFTP */ #else /* NOFTP */ #ifdef NEWFTP #undef NEWFTP #endif /* NEWFTP */ #ifdef SYSFTP #undef SYSFTP #endif /* SYSFTP */ #endif /* NOFTP */ #ifndef NOBROWSER #ifdef UNIX #ifndef BROWSER #ifndef NOPUSH #define BROWSER #endif /* NOPUSH */ #endif /* BROWSER */ #endif /* UNIX */ #ifdef OS2 #ifndef BROWSER #ifndef NOPUSH #define BROWSER #endif /* NOPUSH */ #endif /* BROWSER */ #endif /* OS2 */ #else #ifdef BROWSER #undef BROWSER #endif /* BROWSER */ #endif /* NOBROWSER */ #else /* TCPSOCKET */ #ifndef NOHTTP /* HTTP requires TCPSOCKET */ #define NOHTTP #endif /* NOHTTP */ #endif /* TCPSOCKET */ #endif /* NONET */ #ifdef TCPSOCKET #ifndef NOCKGETFQHOST #ifdef __ia64__ #define NOCKGETFQHOST #else /* __ia64__ */ #ifdef SV68 #define NOCKGETFQHOST #else #ifdef HPUXPRE65 #define NOCKGETFQHOST #endif /* HPUXPRE65 */ #endif /* SV68 */ #endif /* __ia64 */ #endif /* NOCKGETFQHOST */ /* Regarding System V/68 (SV68) (from Gerry Belanger, Oct 2002): 1) The gethostbyname() appears to return the actual host IP address in the hostent struct, instead of the expected pointer to the address. Hence the bogus address in the bcopy/memcopy. This is despite the header agreeing with our expectations. 2) the expected argument swap between bcopy and memcopy did not happen. What grief this might cause, I know not. */ #endif /* TCPSOCKET */ #ifdef TCPSOCKET #ifdef OS2ONLY #ifndef NOSOCKS #define NOSOCKS #endif /* NOSOCKS */ #endif /* OS2ONLY */ #ifdef NOSOCKS #ifdef CK_SOCKS #undef CK_SOCKS #endif /* CK_SOCKS */ #ifdef CK_SOCKS5 #undef CK_SOCKS5 #endif /* CK_SOCKS5 */ #else /* NOSOCKS */ #ifdef NT #ifndef CK_SOCKS #define CK_SOCKS #endif /* CK_SOCKS */ #endif /* NT */ #ifdef CK_SOCKS5 /* CK_SOCKS5 implies CK_SOCKS */ #ifndef CK_SOCKS #define CK_SOCKS #endif /* CK_SOCKS */ #endif /* CK_SOCKS5 */ #endif /* NOSOCKS */ #endif /* TCPSOCKET */ #ifdef TNCODE #ifndef CK_AUTHENTICATION #ifdef OS2 #ifdef _M_PPC #define NO_KERBEROS #define NO_SRP #else /* _M_PPC */ #ifndef NO_SSL #define CK_SSL /*#define SSLDLL*/ /* OpenSSL included at link time now - [jt] 2013/11/21 */ #endif /* NO_SSL */ #endif /* _M_PPC */ #ifndef NO_KERBEROS #ifndef CK_KERBEROS /* If neither CK_KERBEROS nor NO_KERBEROS were defined on the command line * then just enable everything */ #define CK_KERBEROS #define KRB4 #define KRB5 #define KRB524 #define KRB524_CONV #ifdef NT #ifndef _M_PPC #ifndef _M_ALPHA #ifndef NO_SSL_KRB5 #define SSL_KRB5 #endif /* NO_SSL_KRB5 */ #endif /* _M_ALPHA */ #endif /* _M_PPC */ #endif /* NT */ #endif /* CK_KERBEROS */ #endif /* NO_KERBEROS */ #ifndef NO_SRP #define CK_SRP #endif /* NO_SRP */ #define CK_AUTHENTICATION #endif /* OS2 */ #endif /* CK_AUTHENTICATION */ #ifdef CK_AUTHENTICATION /* Encryption must have Auth */ #ifndef CK_ENCRYPTION #ifndef NO_ENCRYPTION #ifdef OS2 #define CK_ENCRYPTION #define CK_DES #define CK_CAST #endif /* OS2 */ #endif /* NO_ENCRYPTION */ #endif /* CK_ENCRYPTION */ #endif /* CK_AUTHENTICATION */ #ifdef NO_AUTHENTICATION /* Allow authentication to be */ #ifdef CK_AUTHENTICATION /* disabled in NT and OS/2 */ #undef CK_AUTHENTICATION #endif /* CK_AUTHENTICATION */ #ifdef CK_KERBEROS #undef CK_KERBEROS #endif /* CK_KERBEROS */ #ifdef CK_SRP #undef CK_SRP #endif /* CK_SRP */ #ifdef CK_ENCRYPTION #undef CK_ENCRYPTION #endif /* CK_ENCRYPTION */ #endif /* NO_AUTHENTICATION */ #ifdef NO_ENCRYPTION /* Allow encryption to be */ #ifdef CK_ENCRYPTION /* disabled in NT and OS/2 */ #undef CK_ENCRYPTION #endif /* CK_ENCRYPTION */ #endif /* NO_ENCRYPTION */ #ifdef CK_KERBEROS /* Disable funcs not yet supported with Heimdal */ #ifdef KRB5 #ifndef HEIMDAL #define KRB5_U2U #endif /* HEIMDAL */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ /* SSH section. NOSSH disables any form of SSH support. If NOSSH is not defined (or implied by NONET, NOLOCAL, etc) then SSHBUILTIN is defined for K95 and SSHCMD is defined for UNIX. Then, if either SSHBUILTIN or SSHCMD is defined, ANYSSH is also defined. */ #ifdef COMMENT #undef COMMENT /* The OS/2 headers define this for some insane reason */ #endif /* COMMENT */ #ifdef COMMENT /* Built-in SSH no longer depends on SSL support. Built-in SSH is now provided by a library (libssh, ssh.dll) which is itself linked against OpenSSL. */ #ifndef NOSSH #ifndef NO_SSL #ifdef OS2ONLY #define NOSSH #endif /* OS2ONLY */ #ifdef NT #ifndef CK_SSL #define NOSSH #endif /* CK_SSL */ #endif /* NT */ #else /* NO_SSL */ #define NOSSH #endif /* NO_SSL */ #endif /* NOSSH */ #endif /* COMMENT */ #ifdef NOSSH /* NOSSH */ #ifdef SSHBUILTIN /* undefines any SSH selctors */ #undef SSHBUILTIN #endif /* SSHBUILTIN */ #ifdef SFTP_BUILTIN #undef SFTP_BUILTIN #endif /* SFTP_BUILTIN */ #ifdef SSHCMD #undef SSHCMD #endif /* SSHCMD */ #ifdef ANYSSH #undef ANYSSH #endif /* ANYSSH */ #else /* Not NOSSH */ #ifndef NOLOCAL #ifdef OS2 #ifndef SSHBUILTIN #define SSHBUILTIN #endif /* SSHBUILTIN */ #else /* Not OS2 */ #ifdef UNIX #ifndef SSHCMD #ifdef NETPTY #ifndef NOPUSH #define SSHCMD #endif /* NOPUSH */ #endif /* NETPTY */ #endif /* SSHCMD */ #endif /* UNIX */ #endif /* OS2 */ #ifndef ANYSSH #ifdef SSHBUILTIN #define ANYSSH #ifdef SSHCMD #undef SSHCMD #endif /* SSHCMD */ #else /* SSHBUILTIN */ #ifdef SSHCMD #define ANYSSH #endif /* SSHCMD */ #endif /* SSHBUILTIN */ #endif /* ANYSSH */ #endif /* NOLOCAL */ #endif /* NOSSH */ /* This is in case #ifdef SSH is used anywhere in the K95 modules */ #ifdef OS2 #ifdef SSHBUILTIN #ifndef SSH #define SSH #endif /* SSH */ #endif /* SSHBUILTIN */ #endif /* OS2 */ #ifdef CK_AUTHENTICATION #define CK_SECURITY #else #ifdef CK_SSL #define CK_AUTHENTICATION #define CK_SECURITY #endif /* CK_SSL */ #endif /* CK_AUTHENTICATION */ /* Environment stuff */ #ifndef OS2ORUNIX #ifndef NOPUTENV #define NOPUTENV #endif /* NOPUTENV */ #endif /* OS2ORUNIX */ #ifndef CK_ENVIRONMENT #ifdef OS2 #define CK_ENVIRONMENT #else #ifdef UNIX #define CK_ENVIRONMENT #else #ifdef STRATUS #define CK_ENVIRONMENT #else #ifdef VMS #define CK_ENVIRONMENT #endif /* VMS */ #endif /* STRATUS */ #endif /* UNIX */ #endif /* OS2 */ #endif /* CK_ENVIRONMENT */ #ifndef NOSNDLOC /* RFC 779 SEND LOCATION */ #ifndef CK_SNDLOC #define CK_SNDLOC #endif /* CK_SNDLOC */ #endif /* NOSNDLOC */ #ifndef NOXDISPLOC /* RFC 1096 XDISPLOC */ #ifndef CK_XDISPLOC #define CK_XDISPLOC #endif /* CK_XDISPLOC */ #endif /* NOXDISPLOC */ #ifndef NOFORWARDX #ifndef NOPUTENV #ifndef NOSELECT #ifndef CK_FORWARD_X #ifdef CK_AUTHENTICATION #ifndef OS2ONLY #define CK_FORWARD_X #endif /* OS2ONLY */ #endif /* CK_AUTHENTICATION */ #endif /* CK_FORWARD_X */ #endif /* NOSELECT */ #endif /* NOPUTENV */ #endif /* NOFORWARDX */ #ifndef NO_COMPORT #ifdef TCPSOCKET #ifndef TN_COMPORT #define TN_COMPORT #endif /* TN_COMPORT */ #endif /* TCPSOCKET */ #endif /* NO_COMPORT */ #endif /* TNCODE */ #ifndef NOXFER #ifndef NOCTRLZ /* Allow SET FILE EOF CTRL-Z */ #ifndef CK_CTRLZ #ifdef OS2ORUNIX #define CK_CTRLZ #endif /* OS2ORUNIX */ #endif /* CK_CTRLZ */ #endif /* NOCTRLZ */ #endif /* NOXFER */ #ifndef NOPERMS /* File permissions in A packets */ #ifndef CK_PERMS #ifdef UNIX #define CK_PERMS #else #ifdef VMS #define CK_PERMS #endif /* VMS */ #endif /* UNIX */ #endif /* CK_PERMS */ #endif /* NOPERMS */ #ifdef CK_PERMS #define CK_PERMLEN 24 /* Max length of sys-dependent perms */ #endif /* CK_PERMS */ #ifdef UNIX /* NOSETBUF for everybody */ #ifndef NOSETBUF #ifndef USE_SETBUF /* This is the escape clause */ #define NOSETBUF #endif /* USE_SETBUF */ #endif /* NOSETBUF */ #endif /* UNIX */ #ifndef USE_STRERROR /* Whether to use strerror() */ #ifdef pdp11 #define USE_STRERROR #endif /* pdp11 */ #endif /* USE_STRERROR */ #ifdef VMS /* Features for all VMS builds */ #ifndef NOJC #define NOJC #endif /* NOJC */ #ifndef NOSETBUF #define NOSETBUF #endif /* NOSETBUF */ #ifndef DYNAMIC #define DYNAMIC #endif /* DYNAMIC */ #ifndef NOCURSES #ifndef CK_CURSES #define CK_CURSES #endif /* CK_CURSES */ #endif /* NOCURSES */ #endif /* VMS */ #ifndef NOCKTIMERS /* Dynamic timeouts */ #ifndef CK_TIMERS #define CK_TIMERS #endif /* CK_TIMERS */ #endif /* NOCKTIMERS */ #define CK_SPEED /* Control-prefix removal */ #ifdef NOCKSPEED #undef CK_SPEED #endif /* NOCKSPEED */ #ifndef NOCKXXCHAR #ifndef CKXXCHAR #ifdef UNIX #define CKXXCHAR #else #ifdef OS2 #define CKXXCHAR #endif /* OS2 */ #endif /* UNIX */ #endif /* CKXXCHAR */ #endif /* NOCKXXCHAR */ #ifdef MAC /* For Macintosh, no escape */ #define NOPUSH /* to operating system */ #endif /* MAC */ /* Systems where we can call zmkdir() to create directories. */ #ifndef CK_MKDIR #ifndef NOMKDIR #ifdef UNIX #ifndef pdp11 #define CK_MKDIR #endif /* pdp11 */ #endif /* UNIX */ #ifdef OS2 #define CK_MKDIR #endif /* OS2 */ #ifdef VMS #define CK_MKDIR #endif /* VMS */ #ifdef STRATUS #define CK_MKDIR #endif /* STRATUS */ #ifdef OSK #define CK_MKDIR #endif /* OSK */ #ifdef datageneral #define CK_MKDIR #endif /* datageneral */ #endif /* CK_MKDIR */ #endif /* NOMKDIR */ #ifdef NOMKDIR /* Allow for command-line override */ #ifdef CK_MKDIR #undef CK_MKDIR #endif /* CK_MKDIR */ #endif /* NOMKDIR */ /* Systems for which we can enable the REDIRECT command automatically */ /* As of 6.0.193, it should work for all UNIX... */ #ifndef NOREDIRECT #ifndef CK_REDIR #ifdef UNIX #define CK_REDIR #endif /* UNIX */ #ifdef OS2 /* As well as OS/2 and friends... */ #define CK_REDIR #endif /* OS2 */ #endif /* CK_REDIR */ #endif /* NOREDIRECT */ #ifdef NOPUSH /* But... REDIRECT command is not */ #ifdef CK_REDIR /* allowed if NOPUSH is defined. */ #undef CK_REDIR #endif /* CK_REDIR */ #ifdef NETCMD /* Nor is SET NET COMMAND */ #undef NETCMD #endif /* NETCMD */ #ifdef NETPTY #undef NETPTY #endif /* NETPTY */ #endif /* NOPUSH */ #ifndef PEXITSTAT /* \v(pexitstat) variable defined */ #ifdef OS2ORUNIX #define PEXITSTAT #else #ifdef VMS #define PEXITSTAT #endif /* VMS */ #endif /* OS2ORUNIX */ #endif /* PEXITSTAT */ /* The following allows automatic enabling of REDIRECT to be overridden... */ #ifdef NOREDIRECT #ifdef NETCMD #undef NETCMD #endif /* NETCMD */ #ifdef NETPTY #undef NETPTY #endif /* NETPTY */ #ifdef CK_REDIR #undef CK_REDIR #endif /* CK_REDIR */ #endif /* NOREDIRECT */ #ifdef NONETCMD #ifdef NETCMD #undef NETCMD #endif /* NETCMD */ #ifdef NETPTY #undef NETPTY #endif /* NETPTY */ #endif /* NONETCMD */ #ifdef CK_REDIR _PROTOTYP( int ttruncmd, (char *) ); #endif /* CK_REDIR */ /* Use built-in DIRECTORY command */ #ifndef NOMYDIR #ifndef DOMYDIR #ifdef UNIXOROSK #define DOMYDIR #else #ifdef OS2 #define DOMYDIR #else #ifdef VMS #define DOMYDIR #endif /* VMS */ #endif /* OS2 */ #endif /* UNIXOROSK */ #endif /* DOMYDIR */ #endif /* NOMYDIR */ /* Sending from and receiving to commands/pipes */ #ifndef PIPESEND #ifdef UNIX #define PIPESEND #endif /* UNIX */ #ifdef OS2 #define PIPESEND #endif /* OS2 */ #endif /* PIPESEND */ #ifdef PIPESEND #ifdef NOPIPESEND #undef PIPESEND #endif /* NOPIPESEND */ #ifdef NOPUSH #undef PIPESEND #endif /* NOPUSH */ #endif /* PIPESEND */ #ifdef NOPUSH #ifdef BROWSER #undef BROWSER #endif /* BROWSER */ #endif /* NOPUSH */ /* Versions where we support the RESEND command */ #ifndef NOXFER #ifndef NORESEND #ifndef CK_RESEND #ifdef UNIX #ifndef pdp11 #define CK_RESEND #endif /* pdp11 */ #endif /* UNIX */ #ifdef VMS #define CK_RESEND #endif /* VMS */ #ifdef OS2 #define CK_RESEND #endif /* OS2 */ #ifdef AMIGA #define CK_RESEND #endif /* AMIGA */ #ifdef datageneral #define CK_RESEND #endif /* datageneral */ #ifdef STRATUS #define CK_RESEND #endif /* STRATUS */ #ifdef OSK #define CK_RESEND #endif /* OSK */ #endif /* CK_RESEND */ #endif /* NORESEND */ #endif /* NOXFER */ /* Systems implementing "Doomsday Kermit" protocol ... */ #ifndef DOOMSDAY #ifdef UNIX #define DOOMSDAY #else #ifdef VMS #define DOOMSDAY #else #ifdef OS2 #define DOOMSDAY #else #ifdef STRATUS #define DOOMSDAY #endif /* STRATUS */ #endif /* OS2 */ #endif /* VMS */ #endif /* UNIX */ #endif /* DOOMSDAY */ /* Systems where we want the Thermometer to be used for fullscreen */ #ifdef OS2 #ifndef CK_PCT_BAR #define CK_PCT_BAR #endif /* CK_PCT_BAR */ #endif /* OS2 */ /* Systems where we have a REXX command */ #ifdef OS2 #ifdef __32BIT__ #ifndef NOREXX #define CK_REXX #endif /* NOREXX */ #endif /* __32BIT__ */ #endif /* OS2 */ /* Platforms that have a ZCHKPID function */ #ifdef OS2ORUNIX #define ZCHKPID #endif /* OS2ORUNIX */ #ifndef ZCHKPID /* If we can't check pids then we have treat all pids as active & valid. */ #define zchkpid(x) 1 #endif /* ZCHKPID */ /* Systems that have a ZRENAME function */ #define ZRENAME /* They all do */ /* Systems that have a ZCOPY function */ #ifndef ZCOPY #ifdef VMS #define ZCOPY #else #ifdef OS2 #define ZCOPY #else #ifdef UNIX #define ZCOPY #else #ifdef STRATUS #define ZCOPY #endif /* STRATUS */ #endif /* UNIX */ #endif /* OS2 */ #endif /* VMS */ #endif /* ZCOPY */ /* Systems that have ttgwsiz() (they all should but they don't) */ #ifndef NOTTGWSIZ #ifndef CK_TTGWSIZ #ifdef UNIX #define CK_TTGWSIZ #else #ifdef VMS #define CK_TTGWSIZ #else #ifdef OS2 #define CK_TTGWSIZ #else #ifdef OSK #define CK_TTGWSIZ #endif /* OSK */ #endif /* OS2 */ #endif /* VMS */ #endif /* UNIX */ #endif /* CK_TTGWSIZ */ #endif /* NOTTGWSIZ */ #ifdef NOTTGWSIZ #ifdef CK_TTGWSIZ #undef CK_TTGWSIZ #endif /* CK_TTGWSIZ */ #endif /* NOTTGWSIZ */ #ifdef OS2 /* OS/2 C-Kermit features not available in 16-bit version... */ #ifdef OS2ONLY #ifndef __32BIT__ #ifndef NOLOCAL #ifdef PCFONTS /* PC Font support */ #undef PCFONTS #endif /* PCFONTS */ #ifdef NPIPE /* Named Pipes communication */ #undef NPIPE #endif /* NPIPE */ #ifdef CK_NETBIOS /* NETBIOS communication */ #undef CK_NETBIOS #endif /* CK_NETBIOS */ #ifdef OS2MOUSE /* Mouse */ #undef OS2MOUSE #endif /* OS2MOUSE */ #ifdef OS2PM /* Presentation Manager */ #undef OS2PM #endif /* OS2PM */ #endif /* NOLOCAL */ #ifdef CK_REXX /* Rexx */ #undef CK_REXX #endif /* CK_REXX */ #endif /* __32BIT__ */ #endif /* OS2ONLY */ /* OS/2 C-Kermit features not available in Windows NT version... */ #ifdef NT #ifdef PCFONTS /* PC Font support */ #undef PCFONTS #endif /* PCFONTS */ #ifdef OS2PM /* Presentation Manager */ #undef OS2PM #endif /* OS2PM */ #endif /* NT */ #endif /* OS2 */ /* Systems that have select(). This is used for both msleep() and for read-buffer checking in in_chk(). */ #define CK_SLEEPINT 250 /* milliseconds - set this to something that divides evenly into 1000 */ #ifndef SELECT #ifndef NOSELECT #ifdef __linux__ #define SELECT #else #ifdef SUNOS4 #define SELECT #else #ifdef NEXT #define SELECT #else #ifdef RTAIX #define SELECT #else #ifdef HPUX /* Not really. I think it's only in HP-UX 7.0 and later, except it's also in earlier versions that have TCP/IP installed. Override this default in particular HP-UX makefile entries by adding -DNOSELECT, as in (e.g.) the HP-UX 6.5 ones. */ #define SELECT #else #ifdef AIXRS #define SELECT #else #ifdef BSD44 #define SELECT #else #ifdef BSD4 #define SELECT #else #ifdef OXOS #define SELECT #else #ifdef OS2 #define SELECT #else #ifdef BEBOX #define SELECT #endif /* BEBOX */ #endif /* OS2 */ #endif /* OXOS */ #endif /* BSD4 */ #endif /* BSD44 */ #endif /* AIXRS */ #endif /* HPUX */ #endif /* RTAIX */ #endif /* NEXT */ #endif /* __linux__ */ #endif /* SUNOS4 */ #endif /* NOSELECT */ #endif /* SELECT */ /* The following section moved here from ckcnet.h in 6.1 because select() is now used for non-networking purposes. */ /* On HP-9000/500 HP-UX 5.21 this stuff is not defined in any header file */ #ifdef hp9000s500 #ifndef NEEDSELECTDEFS #define NEEDSELECTDEFS #endif /* NEEDSELECTDEFS */ #endif /* hp9000s500 */ #ifdef NEEDSELECTDEFS typedef long fd_mask; #ifndef NBBY #define NBBY 8 #endif /* NBBY */ #ifndef FD_SETSIZE #define FD_SETSIZE 32 #endif /* FD_SETSIZE */ #ifndef NFDBITS #define NFDBITS (sizeof(fd_mask) * NBBY) #endif /* NFDBITS */ #ifndef howmany #define howmany(x,y) (((x)+((y)-1))/(y)) #endif /* howmany */ typedef struct fd_set { fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; } fd_set; #ifndef FD_SET #define FD_SET(n,p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) #endif /* FD_SET */ #ifndef FD_CLR #define FD_CLR(n,p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) #endif /* FD_CLR */ #ifndef FD_ISSET #define FD_ISSET(n,p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) #endif /* FD_ISSET */ #ifndef FD_COPY #define FD_COPY(f,t) (bcopy(f,t,sizeof(*(f))) #endif /* FD_COPY */ #ifndef FD_ZERO #define FD_ZERO(p) bzero((char *)(p),sizeof(*(p))) #endif /* FD_ZERO */ #endif /* NEEDSELECTDEFS */ /* CK_NEED_SIG is defined if the system cannot check the console to to see if characters are waiting. This is used during local-mode file transfer to interrupt the transfer, refresh the screen display, etc. If CK_NEED_SIG is defined, then file-transfer interruption characters have to be preceded a special character, e.g. the SIGQUIT character. CK_NEED_SIG should be defined if the conchk() function is not operational. */ #ifdef NOPOLL /* For overriding CK_POLL definition */ #ifdef CK_POLL #undef CK_POLL #endif /* CK_POLL */ #endif /* NOPOLL */ #ifndef CK_POLL /* If we don't have poll() */ #ifndef RDCHK /* And we don't have rdchk() */ #ifndef SELECT /* And we don't have select() */ #ifdef ATTSV #ifndef aegis #ifndef datageneral #ifndef OXOS #define CK_NEED_SIG #endif /* OXOS */ #endif /* datageneral */ #endif /* aegis */ #endif /* ATTSV */ #ifdef POSIX #ifndef CK_NEED_SIG #define CK_NEED_SIG #endif /* CK_NEED_SIG */ #endif /* POSIX */ #endif /* SELECT */ #endif /* RDCHK */ #endif /* CK_POLL */ #ifdef HPUX /* HP-UX has select() */ #ifdef CK_NEED_SIG #undef CK_NEED_SIG #endif /* CK_NEED_SIG */ #endif /* HPUX */ #ifdef AIXRS /* AIX has select() */ #ifdef CK_NEED_SIG #undef CK_NEED_SIG #endif /* CK_NEED_SIG */ #endif /* AIXRS */ #ifdef BSD44 /* 4.4BSD has FIONREAD */ #ifdef CK_NEED_SIG #undef CK_NEED_SIG #endif /* CK_NEED_SIG */ #endif /* BSD44 */ #ifdef QNX /* QNX has FIONREAD and select() */ #ifdef CK_NEED_SIG #undef CK_NEED_SIG #endif /* CK_NEED_SIG */ #endif /* QNX */ #ifdef COHERENT #ifndef NOTIMEZONE #define NOTIMEZONE #endif /* NOTIMEZONE */ #endif /* COHERENT */ #ifdef UNIX #ifndef HAVE_TZ /* Can we use struct timezone? */ #ifndef NOTIMEZONE #ifdef PTX #define NOTIMEZONE #else #ifndef SELECT #ifdef COHERENT #define NOTIMEZONE #else #ifdef BELLV10 #define NOTIMEZONE #endif /* BELLV10 */ #endif /* COHERENT */ #endif /* SELECT */ #endif /* PTX */ #endif /* NOTIMEZONE */ #endif /* HAVE_TZ */ #ifndef NOTIMEVAL /* Can we use struct timeval? */ #ifndef HAVE_TV #define HAVE_TV #endif /* HAVE_TV */ #endif /* NOTIMEVAL */ #ifndef NOTIMEZONE #ifndef HAVE_TZ #define HAVE_TZ #endif /* HAVE_TZ */ #endif /* NOTIMEZONE */ #endif /* UNIX */ #ifdef SCO32 #ifdef HAVE_TV #undef HAVE_TV #endif /* HAVE_TV */ #ifdef HAVE_TZ #undef HAVE_TZ #endif /* HAVE_TZ */ #ifndef NOTIMEVAL #define NOTIMEVAL #endif /* NOTIMEVAL */ #ifndef NOTIMEZONE #define NOTIMEZONE #endif /* NOTIMEZONE */ #endif /* SCO32 */ #ifdef ATT7300 #ifdef HAVE_TV #undef HAVE_TV #endif /* HAVE_TV */ #ifdef HAVE_TZ #undef HAVE_TZ #endif /* HAVE_TZ */ #ifndef NOTIMEVAL #define NOTIMEVAL #endif /* NOTIMEVAL */ #ifndef NOTIMEZONE #define NOTIMEZONE #endif /* NOTIMEZONE */ #endif /* ATT7300 */ /* Automatic parity detection. This actually implies a lot more now: length-driven packet reading, "Doomsday Kermit" IBM Mainframe file transfer through 3270 data streams, etc. */ #ifdef UNIX /* For Unix */ #ifndef NOPARSEN #define PARSENSE #endif /* NOPARSEN */ #endif /* UNIX */ #ifdef VMS /* ... and VMS */ #ifndef NOPARSEN #define PARSENSE #endif /* NOPARSEN */ #ifdef __GNUC__ #define VMSGCC #endif /* __GNUC__ */ #endif /* VMS */ #ifdef MAC /* and Macintosh */ #ifndef NOPARSEN #define PARSENSE #endif /* NOPARSEN */ #endif /* MAC */ #ifdef STRATUS /* and Stratus VOS */ #ifndef NOPARSEN #define PARSENSE #endif /* NOPARSEN */ #endif /* STRATUS */ #ifdef OS2 /* and OS/2, finally */ #ifndef NOPARSEN #define PARSENSE #endif /* NOPARSEN */ #endif /* OS2 */ #ifndef NODYNAMIC /* DYNAMIC is default for UNIX */ #ifndef DYNAMIC /* as of C-Kermit 7.0 */ #ifdef UNIX #define DYNAMIC #endif /* UNIX */ #endif /* DYNAMIC */ #endif /* NODYNAMIC */ #ifdef DYNAMIC /* If DYNAMIC is defined */ #define DCMDBUF /* then also define this. */ #endif /* DYNAMIC */ #ifndef CK_LBRK /* Can send Long BREAK */ #ifdef UNIX /* (everybody but OS-9) */ #define CK_LBRK #endif /* UNIX */ #ifdef VMS #define CK_LBRK #endif /* VMS */ #ifdef datageneral #define CK_LBRK #endif /* datageneral */ #ifdef GEMDOS #define CK_LBRK #endif /* GEMDOS */ #ifdef OS2 #define CK_LBRK #endif /* OS2 */ #ifdef AMIGA #define CK_LBRK #endif /* AMIGA */ #ifdef STRATUS #define CK_LBRK #endif /* STRATUS */ #endif /* CK_LBRK */ /* Carrier treatment */ /* These are defined here because they are shared by the system dependent */ /* and the system independent modules. */ #define CAR_OFF 0 /* Off: ignore carrier always. */ #define CAR_ON 1 /* On: heed carrier always, except during DIAL. */ #define CAR_AUT 2 /* Auto: heed carrier, but only if line is declared */ /* to be a modem line, and only during CONNECT. */ /* And more generically (for use with any ON/OFF/AUTO feature) */ #define CK_OFF 0 #define CK_ON 1 #define CK_AUTO 2 #ifndef NOLOCAL /* Serial interface speeds available. As of C-Kermit 6.1 there is a new method to get the supported speeds, which obviates the need for all the craziness below. At runtime, just call the new ttspdlist() routine to get a list of supported speeds. Then the user interface module can build a keyword table or menu from it. */ #ifndef TTSPDLIST #ifdef UNIX /* For now, only for UNIX */ #ifndef OLINUXHISPEED /* But not systems with hacks for */ #ifndef MINIX /* high speeds, like 110 = 115200 */ #define TTSPDLIST #endif /* MINIX */ #endif /* OLINUXHISPEED */ #else #ifdef VMS #define TTSPDLIST /* VMS gets it too */ #endif /* VMS */ #endif /* UNIX */ #endif /* TTSPDLIST */ #ifndef NODIAL /* Hangup by modem command */ #ifndef NOMDMHUP #ifndef MDMHUP #define MDMHUP #endif /* MDMHUP */ #endif /* NOMDMHUP */ #endif /* NODIAL */ #ifdef NOSPL #ifndef NOLOGDIAL /* Connection log needs mjd(), etc. */ #define NOLOGDIAL #endif /* NOLOGDIAL */ #endif /* NOSPL */ #ifdef pdp11 #define NOLOGDIAL #endif /* pdp11 */ #ifndef NOLOGDIAL /* Connection log */ #ifndef CXLOGFILE #define CXLOGFILE "CX.LOG" /* Default connection log file name */ #endif /* CXLOGFILE */ #ifndef CKLOGDIAL #ifndef CK_SMALL #define CKLOGDIAL #define CXLOGBUFL 1024 /* Connection log record buffer size */ #endif /* CK_SMALL */ #endif /* NOLOGDIAL */ #endif /* CKLOGDIAL */ #endif /* NOLOCAL */ #ifdef NOTTSPDLIST /* Except if NOTTSPDLIST is defined */ #ifdef TTSPDLIST #undef TTSPDLIST #endif /* TTSPDLIST */ #endif /* NOTTSPDLIST */ #ifdef TTSPDLIST _PROTOTYP( long * ttspdlist, (void) ); #else /* TTSPDLIST not defined */ /* We must use a long and convoluted series of #ifdefs that have to be kept in sync with the code in the ck?tio.c module. We assume that everybody supports: 0, 110, 300, 600, 1200, 2400, 4800, and 9600 bps. Symbols for other speeds are defined here. You can also add definitions on the CC command lines. These definitions affect the SET SPEED keyword table, and are not necessarily usable in the system-dependent speed-setting code in the ck?tio.c modules, which depends on system-specific symbols like (in UNIX) B19200. In other words, just defining it doesn't mean it'll work -- you also have to supply the supporting code in ttsspd() and ttgspd() in ck?tio.c. The symbols have the form BPS_xxxx, where xxxx is the speed in bits per second, or (for bps values larger than 9999) thousands of bps followed by K. The total symbol length should be 8 characters or less. Some values are enabled automatically below. You can disable a particular value by defining NOB_xxxx on the CC command line. */ #ifndef NOB_50 #define BPS_50 /* 50 bps */ #endif #ifndef NOB_75 #define BPS_75 /* 75 bps */ #endif #ifndef NOB7512 #ifdef ANYBSD #define BPS_7512 /* 75/1200 Split Speed */ #endif /* ANYBSD */ #endif /* NOB7512 */ #ifndef NOB134 #ifdef SOLARIS25 #define BPS_134 #else #undef BPS_134 /* 134.5 bps (IBM 2741) */ #endif /* BPS_134 */ #endif /* NOB134 */ #ifndef NOB_150 #define BPS_150 /* 150 bps */ #endif #ifndef NOB_200 #define BPS_200 /* 200 bps */ #endif #ifndef NOB_1800 #ifdef MAC #define BPS_1800 /* 1800 bps */ #else #ifdef SOLARIS25 #define BPS_1800 #endif #endif #endif #ifndef NOB_3600 #ifndef SOLARIS25 #define BPS_3600 /* 3600 bps */ #endif #endif #ifndef NOB_7200 #ifndef SOLARIS25 #define BPS_7200 /* 7200 bps */ #endif /* SOLARIS25 */ #endif #ifndef NOB_14K #ifdef BSD44 #define BPS_14K /* 14400 bps */ #else #ifdef OS2 #define BPS_14K #else #ifdef NEXT #define BPS_14K #else #ifdef MAC #define BPS_14K #else #ifdef AMIGA #define BPS_14K #endif /* AMIGA */ #endif /* MAC */ #endif /* NEXT */ #endif /* OS2 */ #endif /* BSD44 */ #endif /* NOB_14K */ #ifndef NOB_19K #define BPS_19K /* 19200 bps */ #endif #ifndef NOB_28K #ifdef BSD44 #define BPS_28K #else #ifdef OS2 #define BPS_28K #else #ifdef NEXT #define BPS_28K /* 28800 bps */ #else #ifdef MAC #define BPS_28K /* 28800 bps */ #endif /* MAC */ #endif /* NEXT */ #endif /* OS2 */ #endif /* BSD44 */ #endif /* NOB_28K */ #ifndef NOB_38K #define BPS_38K /* 38400 bps */ #endif #ifndef NOB_57K #ifdef Plan9 #define BPS_57K #else #ifdef SOLARIS25 #define BPS_57K #else #ifdef VMS #define BPS_57K /* 57600 bps */ #else #ifdef OS2 #define BPS_57K #else #ifdef __linux__ #define BPS_57K #else #ifdef HPUX #define BPS_57K #else #ifdef NEXT #define BPS_57K #else #ifdef __386BSD__ #define BPS_57K #else #ifdef __FreeBSD__ #define BPS_57K #else #ifdef __NetBSD__ #define BPS_57K #else #ifdef MAC #define BPS_57K #else #ifdef QNX #define BPS_57K #else #ifdef BEOSORBEBOX #define BPS_57K #else #ifdef IRIX62 #define BPS_57K #else #ifdef SCO_OSR504 #define BPS_57K #else #ifdef BSDI2 #define BPS_57K #endif /* BSDI2 */ #endif /* SCO_OSR504 */ #endif /* IRIX62 */ #endif /* BEOSORBEBOX */ #endif /* QNX */ #endif /* MAC */ #endif /* __NetBSD__ */ #endif /* __FreeBSD__ */ #endif /* __386BSD__ */ #endif /* NEXT */ #endif /* HPUX */ #endif /* __linux__ */ #endif /* OS2 */ #endif /* VMS */ #endif /* SOLARIS25 */ #endif /* Plan9 */ #endif /* NOB_57K */ #ifndef NOB_76K #ifdef BSDI2 #define BPS_76K #endif /* BSDI2 */ #ifdef Plan9 #define BPS_76K #endif /* Plan9 */ #ifdef SOLARIS25 #define BPS_76K #endif /* SOLARIS25 */ #ifdef VMS #define BPS_76K /* 76800 bps */ #endif /* VMS */ #ifdef OS2 #ifdef __32BIT__ #define BPS_76K #endif /* __32BIT__ */ #endif /* OS2 */ #ifdef QNX #define BPS_76K #endif /* QNX */ #ifdef IRIX62 #define BPS_76K #endif /* IRIX62 */ #ifdef SCO_OSR504 #define BPS_76K #endif /* SCO_OSR504 */ #endif /* NOB_76K */ #ifndef NOB_115K #ifdef BSDI2 #define BPS_115K #endif /* BSDI2 */ #ifdef Plan9 #define BPS_115K #endif /* Plan9 */ #ifdef SOLARIS25 #define BPS_115K #endif /* SOLARIS25 */ #ifdef VMS #define BPS_115K /* 115200 bps */ #else #ifdef QNX #define BPS_115K #define BPS_1500K #else #ifdef HPUX #define BPS_115K #else #ifdef __linux__ #define BPS_115K #define BPS_1500K #else #ifdef __386BSD__ #define BPS_115K #else #ifdef __FreeBSD__ #define BPS_115K #else #ifdef __NetBSD__ #define BPS_115K #else #ifdef OS2 #ifdef __32BIT__ #define BPS_115K #endif /* __32BIT__ */ #else #ifdef BEOSORBEBOX #define BPS_115K #else #ifdef IRIX62 #define BPS_115K #else #ifdef SCO_OSR504 #define BPS_115K #endif /* SCO_OSR504 */ #endif /* IRIX62 */ #endif /* BEOSORBEBOX */ #endif /* OS2 */ #endif /* __NetBSD__ */ #endif /* __FreeBSD__ */ #endif /* __386BSD__ */ #endif /* __linux__ */ #endif /* HPUX */ #endif /* QNX */ #endif /* VMS */ #endif /* NOB_115K */ #ifndef NOB_230K /* 230400 bps */ #ifdef BSDI2 #define BPS_230K #else #ifdef SCO_OSR504 #define BPS_230K #else #ifdef __linux__ #define BPS_230K #else #ifdef SOLARIS25 #define BPS_230K #else #ifdef OS2 #ifdef __32BIT__ #define BPS_230K #endif /* __32BIT__ */ #else #undef BPS_230K #endif /* OS2 */ #endif /* SOLARIS25 */ #endif /* __linux__ */ #endif /* SCO_OSR504 */ #endif /* BSDI2 */ #endif /* NOB_230K */ #ifndef NOB_460K /* 460800 bps */ #ifdef SCO_OSR504 #define BPS_460K #else #ifdef __linux__ #define BPS_460K #else #ifdef OS2 #ifdef __32BIT__ #define BPS_460K #endif /* __32BIT__ */ #else #undef BPS_460K #endif /* __linux__ */ #endif /* SCO_OSR504 */ #endif /* OS2 */ #endif /* NOB_460K */ #ifndef NOB_921K /* 921600 bps */ #ifdef SCO_OSR504 #define BPS_921K #endif /* SCO_OSR504 */ #endif /* NOB_921K */ /* 13 October 2021 From Elad Lahav: Added support for 1.5MHz (1500000bps) serial speed for Linux and QNX. */ #ifdef BPS_1500K /* Maximum speed defined */ #define MAX_SPD 1500000L #else #ifdef BPS_921K #define MAX_SPD 921600L #else #ifdef BPS_460K #define MAX_SPD 460800L #else #ifdef BPS_230K #define MAX_SPD 230400L #else #ifdef BPS_115K #define MAX_SPD 115200L #else #ifdef BPS_76K #define MAX_SPD 76800L #else #ifdef BPS_57K #define MAX_SPD 57600L #else #ifdef BPS_38K #define MAX_SPD 38400L #else #ifdef BPS_28K #define MAX_SPD 28800L #else #ifdef BPS_19K #define MAX_SPD 19200L #else #ifdef BPS_14K #define MAX_SPD 14400L #else #define MAX_SPD 9600L #endif #endif #endif #endif #endif #endif #endif #endif #endif #endif #endif #endif /* TTSPDLIST */ #ifndef CONGSPD /* Systems that can call congspd() */ #ifdef UNIX #define CONGSPD #endif /* UNIX */ #ifdef VMS #define CONGSPD #endif /* VMS */ #ifdef STRATUS #define CONGSPD #endif /* STRATUS */ #endif /* CONGSPD */ /* Types of flow control available */ #define CK_XONXOFF /* Everybody can do this, right? */ #ifdef AMIGA /* Commodore Amiga */ #define CK_RTSCTS /* has RTS/CTS */ #endif /* AMIGA */ #ifdef SUN4S5 /* SunOS in System V environment */ #define CK_RTSCTS #else /* SunOS 4.0/4.1 in BSD environment */ #ifdef SUNOS4 /* SunOS 4.0+later supports RTS/CTS */ #ifdef SUNOS41 /* Easy in 4.1 and later */ #define CK_RTSCTS #else /* Harder in 4.0 */ #ifndef __GNUC__ /* (see tthflow() in ckutio.c) */ #ifndef GNUC #define CK_RTSCTS /* Only if not using GNU gcc */ #endif /* __GNUC__ */ #endif /* GNUC */ #endif /* SUNOS41 */ #endif /* SUNOS4 */ #endif /* SUN4S5 */ #ifdef BSD44 /* And in 4.4 BSD, including BSDI */ #define CK_RTSCTS #endif /* BSD44 */ #ifdef TERMIOX /* Sys V R4 */ #ifndef CK_RTSCTS #define CK_RTSCTS #endif /* CK_RTSCTS */ #ifndef CK_DTRCD #define CK_DTRCD #endif /* CK_DTRCD */ #else #ifdef STERMIOX /* Sys V R4 */ #ifndef CK_RTSCTS #define CK_RTSCTS #endif /* CK_RTSCTS */ #ifndef CK_DTRCD #define CK_DTRCD #endif /* CK_DTRCD */ #endif /* STERMIOX */ #endif /* TERMIOX */ #ifdef OXOS /* Olivetti X/OS R2 struct termios */ #define CK_RTSCTS /* Ditto. */ #define CK_DTRCD #endif /* OXOS */ #ifdef AIXRS /* RS/6000 with AIX 3.x */ #define CK_RTSCTS /* Has its own peculiar method... */ #endif /* AIXRS */ #ifdef __linux__ /* Linux */ #define CK_RTSCTS #endif /* __linux__ */ /* Hardware flow control is not defined in POSIX.1. Nevertheless, a certain style API for hardware flow control, using tcsetattr() and the CRTSCTS bit(s), seems to be gaining currency on POSIX-based UNIX systems. The following code defines the symbol POSIX_CRTSCTS for such systems. */ #ifdef CK_RTSCTS #ifdef __bsdi__ /* BSDI, a.k.a. BSD/386 */ #define POSIX_CRTSCTS #endif /* __bsdi__ */ #ifdef __linux__ /* Linux */ #define POSIX_CRTSCTS #endif /* __linux__ */ #ifdef __NetBSD__ /* NetBSD */ #define POSIX_CRTSCTS #endif /* __NetBSD__ */ #ifdef __OpenBSD__ #define POSIX_CRTSCTS #endif /* __OpenBSD__ */ #ifdef BEOSORBEBOX /* BeBOX */ #define POSIX_CRTSCTS /* BEBOX defines CRTSFL as (CTSFLOW & RTSFLOW) */ #define CRTSCTS CRTSFL #endif /* BEOSORBEBOX */ #ifdef IRIX52 /* IRIX 5.2 and later */ #define POSIX_CRTSCTS #define CRTSCTS CNEW_RTSCTS /* See */ #endif /* IRIX52 */ #endif /* CK_RTSCTS */ /* Implementations that have implemented the ttsetflow() function. */ #ifndef CK_TTSETFLOW #ifdef UNIX #define CK_TTSETFLOW #endif /* UNIX */ #ifdef OS2 #define CK_TTSETFLOW #endif /* OS2 */ #endif /* CK_TTSETFLOW */ #ifdef CK_TTSETFLOW _PROTOTYP( int ttsetflow, (int) ); #endif /* CK_TTSETFLOW */ /* Systems where we can expand tilde at the beginning of file or directory names */ #ifdef POSIX #ifndef DTILDE #define DTILDE #endif /* DTILDE */ #endif /* POSIX */ #ifdef BSD4 #ifndef DTILDE #define DTILDE #endif /* DTILDE */ #endif /* BSD4 */ #ifdef ATTSV #ifndef DTILDE #define DTILDE #endif /* DTILDE */ #endif /* ATTSV */ #ifdef OSK #ifndef DTILDE #define DTILDE #endif /* DTILDE */ #endif /* OSK */ #ifdef HPUX /* I don't know why this is */ #ifndef DTILDE /* necessary, since -DHPUX */ #define DTILDE /* automatically defines ATTSV */ #endif /* DTILDE */ /* (see above) ... */ #endif /* HPUX */ /* This is mainly for the benefit of ckufio.c (UNIX and OS/2 file support). Systems that have an atomic rename() function, so we don't have to use link() and unlink(). */ #ifdef POSIX #ifndef RENAME #define RENAME #endif /* RENAME */ #endif /* POSIX */ #ifdef OS2 #ifndef RENAME #define RENAME #endif /* RENAME */ #endif /* OS2 */ #ifdef SUNOS41 #ifndef RENAME #define RENAME #endif /* RENAME */ #endif /* SUNOS41 */ #ifdef SVR4 #ifndef RENAME #define RENAME #endif /* RENAME */ #endif /* SVR4 */ #ifdef AIXRS #ifndef RENAME #define RENAME #endif /* RENAME */ #endif /* AIXRS */ #ifdef BSD44 #ifndef RENAME #define RENAME #endif /* RENAME */ #endif /* BSD44 */ #ifdef NORENAME /* Allow for compile-time override */ #ifdef RENAME #undef RENAME #endif /* RENAME */ #endif /* NORENAME */ #ifdef STRATUS /* Stratus VOS */ #ifndef RENAME #define RENAME #endif /* RENAME */ #endif /* STRATUS */ /* Line delimiter for text files */ /* If the system uses a single character for text file line delimitation, define NLCHAR to the value of that character. For text files, that character will be converted to CRLF upon output, and CRLF will be converted to that character on input during text-mode (default) packet operations. */ #ifdef MAC /* Macintosh */ #define NLCHAR 015 #else #ifdef OSK /* OS-9/68K */ #define NLCHAR 015 #else /* All Unix-like systems */ #define NLCHAR 012 #endif /* OSK */ #endif /* MAC */ /* At this point, if there's a system that uses ordinary CRLF line delimitation AND the C compiler actually returns both the CR and the LF when doing input from a file, then #undef NLCHAR. */ #ifdef OS2 /* OS/2 */ #undef NLCHAR #endif /* OS2 */ #ifdef GEMDOS /* Atari ST */ #undef NLCHAR #endif /* GEMDOS */ /* VMS file formats are so complicated we need to do all the conversion work in the CKVFIO module, so we tell the rest of C-Kermit not to fiddle with the bytes. */ #ifdef vms #undef NLCHAR #endif /* vms */ /* The device name of a job's controlling terminal */ /* Special for VMS, same for all Unixes (?), not used by Macintosh */ #ifdef BEOS #define CTTNAM dftty #else #ifdef vms #define CTTNAM "SYS$INPUT:" /* (4 Jan 2002) Was TT: */ #else #ifdef datageneral #define CTTNAM "@output" #else #ifdef OSK extern char myttystr[]; #define CTTNAM myttystr #else #ifdef OS2 #define CTTNAM "con" #else #ifdef UNIX #define CTTNAM "/dev/tty" #else #ifdef GEMDOS #define CTTNAM "aux:" #else #ifdef STRATUS extern char myttystr[]; #define CTTNAM myttystr #else /* Anyone else... */ #define CTTNAM "stdout" /* This is a kludge used by Mac */ #endif /* STRATUS */ #endif /* GEMDOS */ #endif /* UNIX */ #endif /* OS2 */ #endif /* OSK */ #endif /* datageneral */ #endif /* vms */ #endif /* BEOS */ #ifndef HAVECTTNAM #ifdef UNIX #define HAVECTTNAM #else #ifdef VMS #define HAVECTTNAM #endif /* VMS */ #endif /* UNIX */ #endif /* HAVECTTNAM */ #ifndef ZFCDAT /* zfcdat() function available? */ #ifdef UNIX #define ZFCDAT #else #ifdef STRATUS #define ZFCDAT #else #ifdef GEMDOS #define ZFCDAT #else #ifdef AMIGA #define ZFCDAT #else #ifdef OS2 #define ZFCDAT #else #ifdef datageneral #define ZFCDAT #else #ifdef VMS #define ZFCDAT #endif /* VMS */ #endif /* datageneral */ #endif /* OS2 */ #endif /* AMIGA */ #endif /* GEMDOS */ #endif /* STRATUS */ #endif /* UNIX */ #endif /* ZFCDAT */ #ifdef SUNS4S5 #define tolower _tolower #define toupper _toupper #endif /* SUNS4S5 */ /* Error number */ #ifdef _CRAY #ifdef _CRAYCOM /* Cray Computer Corp. */ extern int errno; #else /* _CRAYCOM */ #include /* Cray Research UNICOS defines */ /* errno as a function. */ #endif /* _CRAYCOM */ /* OK for UNICOS 6.1 and 7.0. */ #else /* _CRAY */ #ifdef STRATUS /* Stratus VOS */ #include #else /* not STRATUS */ #ifndef VMS #ifndef OS2 #ifdef __GLIBC__ /* "glibc uses threads, kermit uses glibc; errno access is in Thread Local Storage (TLS) from glibc-3.2.2. ...a thread specific errno is being run in thread local storage relative to the %gs segment register, so some means to revector gets/puts needs to be done." - Jeff Johnson, Red Hat, Feb 2003. */ #include #else /* It is assumed that if the foregoing code doesn't explicitly include errno.h, that it gets included anyway by some other header file that *is* included. If there is still some platform where the build fails because errno is not defined, add -DDCL_ERRNO to the Cflags for that makefile target. Also see the new first stanza of the "linux" makefile target for code that that checks for this at 'make' time and adds DCL_ERRNO only if necessary. WARNING: this might break if errno.h does not exist or is not in the the default directory for header files. - fdc, 7-8 October 2020 */ #ifdef DCL_ERRNO extern int errno; #else #include #endif /* DCL_ERRNO */ #endif /* __GLIBC__ */ #endif /* OS2 */ #endif /* VMS */ #endif /* STRATUS */ #endif /* _CRAY */ #ifdef VMSORUNIX /* Catch-all so we can have */ #ifndef ESRCH /* access to error mnemonics */ #include /* in all modules - 2007/08/25 */ #endif /* ESRCH */ /* 2024-06-07 SMS. Added VMSOR. */ #endif /* VMSORUNIX */ #ifdef pdp11 /* Try to make some space on PDP-11 */ #ifndef NODIAL #define NODIAL #endif /* NODIAL */ #ifndef NOCURSES #define NOCURSES #endif /* NOCURSES */ #ifndef NOBIGBUF #define NOBIGBUF #endif /* NOBIGBUF */ #endif /* pdp11 */ #ifndef NOBIGBUF #ifndef BIGBUFOK /* Platforms with lots of memory */ #ifdef QNX /* QNX */ #ifndef QNX16 /* But not 16-bit versions */ #define BIGBUFOK #endif /* QNX16 */ #endif /* QNX */ #ifdef BSD44 #define BIGBUFOK #endif /* BSD44 */ #ifdef STRATUS /* Stratus VOS */ #define BIGBUFOK #endif /* STRATUS */ #ifdef sparc /* SPARC processors */ #define BIGBUFOK #else #ifdef SUNOS /* fdc 23 September 2023 */ #define BIGBUFOK #endif /* SUNOS41 */ #endif /* sparc */ #ifdef mips /* MIPS processors */ #define BIGBUFOK #endif /* mips */ #ifdef HPUX9 /* HP-UX 9.x */ #define BIGBUFOK #endif /* HPUX9 */ #ifdef HPUX10 /* HP-UX 10.0 PA-RISC */ #define BIGBUFOK #endif /* HPUX10 */ #ifdef NEXT /* NeXTSTEP */ #ifdef mc68000 /* on NEXT platforms... */ #define BIGBUFOK #endif /* mc68000 */ #endif /* NEXT */ #ifdef LINUX /* Linux from 1998 on should be OK */ #ifndef BIGBUFOK #define BIGBUFOK #endif /* BIGBUFOK */ #endif /* LINUX */ #ifdef OS2 /* 32-bit OS/2 2.x and above */ #ifdef __32BIT__ #define BIGBUFOK #endif /* __32BIT__ */ #ifdef NT #define BIGBUFOK #endif /* NT */ #endif /* OS2 */ #ifdef Plan9 /* Plan 9 is OK */ #define BIGBUFOK #endif /* Plan9 */ #ifdef VMS /* Any VMS is OK */ #ifndef BIGBUFOK #define BIGBUFOK #endif /* BIGBUFOK */ #endif /* VMS */ #ifdef __alpha /* DEC 64-bit Alpha, e.g. OSF/1 */ #ifndef BIGBUFOK /* Might already be defined for VMS */ #define BIGBUFOK #endif /* BIGBUFOK */ #endif /* __alpha */ #ifdef sgi /* SGI with IRIX 4.0 or later */ #ifndef BIGBUFOK #define BIGBUFOK #endif /* BIGBUFOK */ #endif /* sgi */ #ifdef AIXRS /* AIX on RISC */ #define BIGBUFOK #endif /* AIXRS */ #ifdef CK_SCOV5 /* SCO OSR5 */ #ifndef BIGBUFOK #define BIGBUFOK #endif /* BIGBUFOK */ #endif /* CK_SCOV5 */ #ifdef SOLARIS /* Solaris x86 */ #ifndef BIGBUFOK #define BIGBUFOK #endif /* BIGBUFOK */ #endif /* SOLARIS */ #endif /* BIGBUFOK */ #endif /* NOBIGBUF */ #ifdef CK_SMALL #ifdef BIGBUFOK #undef BIGBUFOK #endif /* BIGBUFOK */ #endif /* CK_SMALL */ /* If "memory is no problem" then this improves performance */ #ifdef DEBUG #ifdef BIGBUFOK #ifndef IFDEBUG #define IFDEBUG #endif /* IFDEBUG */ #endif /* BIGBUFOK */ #endif /* DEBUG */ /* File System Defaults */ #ifndef UIDBUFLEN /* Length of User ID */ #ifdef OS2 #define UIDBUFLEN 256 #else /* OS2 */ #ifdef BIGBUFOK #define UIDBUFLEN 256 #else #define UIDBUFLEN 64 #endif /* BIGBUFOK */ #endif /* OS2 */ #endif /* UIDBUFLEN */ #ifdef UNIX #ifdef PROVX1 #define MAXWLD 50 #else #ifdef pdp11 #define MAXWLD 50 #else #ifdef BIGBUFOK #define MAXWLD 102400 #else #define MAXWLD 1024 #endif /* BIGBUFOK */ #endif /* pdp11 */ #endif /* PROVX1 */ #else #ifdef VMS #define MAXWLD 102400 /* Maximum wildcard filenames */ #else #ifdef datageneral #define MAXWLD 500 #else #ifdef STRATUS #define MAXWLD 5000 #endif /* STRATUS */ #endif /* datageneral */ #endif /* VMS */ #endif /* UNIX */ #ifdef VMS #define DBLKSIZ 512 #define DLRECL 512 #else #define DBLKSIZ 0 #define DLRECL 0 #endif /* VMS */ /* Communication device / network host name length */ #ifdef BIGBUFOK #define TTNAMLEN 512 #else #ifdef MAC #define TTNAMLEN 256 #else #ifndef CK_SMALL #define TTNAMLEN 128 #else #define TTNAMLEN 80 #endif /* CK_SMALL */ #endif /* MAC */ #endif /* BIGBUFOK */ /* Program return codes for DECUS C and UNIX (VMS uses UNIX codes) */ #ifdef decus #define GOOD_EXIT IO_NORMAL #define BAD_EXIT IO_ERROR #else #define GOOD_EXIT 0 #define BAD_EXIT 1 #endif /* decus */ /* Special hack for Fortune, which doesn't have ... */ #ifdef FT18 #define FREAD 0x01 #define FWRITE 0x10 #endif /* FT18 */ /* Special hack for OS-9/68k */ #ifdef OSK #ifndef _UCC #define SIGALRM 30 /* May always cancel I/O */ #endif /* _UCC */ #define SIGARB 1234 /* Arbitrary for I/O */ SIGTYP (*signal())(); #endif /* OSK */ #ifdef MINIX #ifdef putchar #undef putchar #endif /* putchar */ #define putchar(c) (putc(c,stdout)!=EOF)&&fflush(stdout) #endif /* MINIX */ #ifdef datageneral /* Data General AOS/VS */ #ifdef putchar #undef putchar #endif /* putchar */ #define putchar(c) conoc(c) #endif /* datageneral */ /* Escape/quote character used by the command parser */ #define CMDQ '\\' /* Symbols for RS-232 modem signals */ #define KM_FG 1 /* Frame ground */ #define KM_TXD 2 /* Transmit */ #define KM_RXD 3 /* Receive */ #define KM_RTS 4 /* Request to Send */ #define KM_CTS 5 /* Clear to Send */ #define KM_DSR 6 /* Data Set Ready */ #define KM_SG 7 /* Signal ground */ #define KM_DCD 8 /* Carrier Detect */ #define KM_DTR 20 /* Data Terminal Ready */ #define KM_RI 22 /* Ring Indication */ /* Bit mask values for modem signals */ #define BM_CTS 0001 /* Clear to send (From DCE) */ #define BM_DSR 0002 /* Dataset ready (From DCE) */ #define BM_DCD 0004 /* Carrier (From DCE) */ #define BM_RNG 0010 /* Ring Indicator (From DCE) */ #define BM_DTR 0020 /* Data Terminal Ready (From DTE) */ #define BM_RTS 0040 /* Request to Send (From DTE) */ /* Codes for full duplex flow control */ #define FLO_NONE 0 /* None */ #define FLO_XONX 1 /* Xon/Xoff (soft) */ #define FLO_RTSC 2 /* RTS/CTS (hard) */ #define FLO_DTRC 3 /* DTR/CD (hard) */ #define FLO_ETXA 4 /* ETX/ACK (soft) */ #define FLO_STRG 5 /* String-based (soft) */ #define FLO_DIAL 6 /* DIALing kludge */ #define FLO_DIAX 7 /* Cancel dialing kludge */ #define FLO_DTRT 8 /* DTR/CTS (hard) */ #define FLO_KEEP 9 /* Keep, i.e. don't touch or change */ #define FLO_AUTO 10 /* Figure out automatically */ /* Types of connections */ #define CXT_REMOTE 0 /* Remote mode - no connection */ #define CXT_DIRECT 1 /* Direct serial connection */ #define CXT_MODEM 2 /* Modem dialout */ #define CXT_TCPIP 3 /* TCP/IP - Telnet, Rlogin, etc */ #define CXT_X25 4 /* X.25 peer-to-peer */ #define CXT_DECNET 5 /* DECnet (CTERM, etc) */ #define CXT_LAT 6 /* LAT */ #define CXT_NETBIOS 7 /* NETBIOS */ #define CXT_NPIPE 8 /* Named Pipe */ #define CXT_PIPE 9 /* Pipe, Command, PTY, DLL, etc */ #define CXT_SSH 10 /* SSH */ #define CXT_MAX 10 /* Highest connection type */ /* Autodownload Detection Options */ #define ADL_PACK 0 /* Auto-Download detect packet */ #define ADL_STR 1 /* Auto-Download detect string */ /* And finally... */ #ifdef COMMENT /* Make sure this is NOT defined! */ #undef COMMENT #endif /* COMMENT */ /* zstr zattr filinfo were here (moved to top for DECC 5 Jun 2000) */ #ifndef ZFNQFP /* Versions that have zfnqfp() */ #ifdef UNIX #define ZFNQFP #else #ifdef VMS #define ZFNQFP #else #ifdef OS2 #define ZFNQFP #else #ifdef datageneral #define ZFNQFP #else #ifdef STRATUS #define ZFNQFP #endif /* STRATUS */ #endif /* datageneral */ #endif /* OS2 */ #endif /* VMS */ #endif /* UNIX */ struct zfnfp { int len; /* Length of full pathname */ char * fpath; /* Pointer to full pathname */ char * fname; /* Pointer to name part */ }; #endif /* ZFNQFP */ /* Systems that support FILE TYPE LABELED */ #ifdef VMS #define CK_LABELED #else #ifdef OS2 #ifdef __32BIT__ #ifndef NT #define CK_LABELED #endif /* NT */ #endif /* __32BIT__ */ #endif /* OS2 */ #endif /* VMS */ /* Systems that support builtin variable "exedir", use getexedir() function */ #ifdef OS2 #define HAVE_VN_EXEDIR #else /* def OS2 */ #ifdef UNIX #define GETEXEDIR #define HAVE_VN_EXEDIR #else /* def UNIX */ #ifdef VMS #define GETEXEDIR #define HAVE_VN_EXEDIR #endif /* def VMS */ #endif /* def UNIX [else] */ #endif /* def OS2 [else] */ /* LABELED FILE options bitmask */ #ifdef VMS /* For VMS */ #define LBL_NAM 1 /* Ignore incoming name if set */ #define LBL_PTH 2 /* Use complete path if set */ #define LBL_ACL 4 /* Preserve ACLs if set */ #define LBL_BCK 8 /* Preserve backup date if set */ #define LBL_OWN 16 /* Preserve ownership if set */ #else #ifdef OS2 /* Ditto for OS/2 */ #define LBL_NOR 0x0000 /* Normal file */ #define LBL_ARC 0x0020 /* Archive */ #define LBL_DIR 0x0010 /* Directory */ #define LBL_HID 0x0002 /* Hidden file */ #define LBL_RO 0x0001 /* Read only file */ #define LBL_SYS 0x0004 /* System file */ #define LBL_EXT 0x0040 /* Extended */ #endif /* OS2 */ #endif /* VMS */ /* Data types. First the header file for data types so we can pick up the types used for pids, uids, and gids. Override this section by putting -DCKTYP_H=xxx on the command line to specify the header file where your system defines these types. */ #ifndef STRATUS #ifdef __ALPHA #ifdef MULTINET #define CK_TGV_AXP #endif /* MULTINET */ #endif /* __ALPHA */ #ifdef CK_TGV_AXP /* Alpha, VMS, MultiNet */ /* Starting in DECC 5.0, no longer includes . But before that an elaborate workaround is required, which results in including sometimes but not others, evidently depending on whether protects itself against multiple inclusion, which in turn probably differentiates between DECC and TGV . Unfortunately I don't remember the details. (fdc, 25 Oct 96) */ #ifdef COMMENT /* Previously the test here was for DEC version prior to 4.0, but since the test involved an "#if" statement, it was not portable and broke some non-VMS builds. In any case, condition was never satisfied, so the result of commenting this section out is the same as the previous "#if" condition. */ #ifndef __TYPES_LOADED #define __TYPES_LOADED /* Work around bug in .h files */ #endif /* __TYPES_LOADED */ #endif /* COMMENT */ #include #ifdef IF_DOT_H #ifndef MULTINET #include /* Needed to put up u_int typedef */ #endif /* MULTINET */ #else /* IF_DOT_H */ #ifdef NEEDUINT typedef unsigned int u_int; #endif /* NEEDUINT */ #endif /* IF_DOT_H */ #else /* !CK_TGV_AXP */ #ifdef OSK /* OS-9 */ #include #else /* General case, not OS-9 */ #ifndef CKTYP_H #ifndef VMS #ifndef MAC #ifndef AMIGA #define CKTYP_H #endif /* AMIGA */ #endif /* MAC */ #endif /* VMS */ #endif /* CKTYP_H */ #ifdef GEMDOS #undef CKTYP_H #include #endif /* GEMDOS */ #ifdef OS2 #undef CKTYP_H #include #endif /* OS2 */ #ifdef CKTYP_H /* Include it. */ #ifdef COHERENT /* Except for COHERENT */ #include #include #else #ifdef datageneral /* AOS/VS */ #include #else /* All others */ #ifdef __bsdi__ /* BSDI */ #ifdef POSIX #undef _POSIX_SOURCE #endif /* POSIX */ #endif /* __bsdi__ */ #include CKTYP_H #ifdef __bsdi__ #ifdef POSIX #define _POSIX_SOURCE #endif /* POSIX */ #endif /* __bsdi__ */ #endif /* datageneral */ #endif /* COHERENT */ #endif /* CKTYP_H */ #endif /* OSK */ #endif /* CK_TGV_AXP */ #endif /* STRATUS */ /* End of types.h section */ /* File lengths and offsets. This section is expected to grow as we support long files on 32-bit platforms. We want this data type to be signed because so many functions return either a file size or a negative value to indicate an error. */ #ifndef CK_OFF_T #ifdef OS2 #ifdef NT #ifdef CKT_NT31 #ifdef CKT_NT35 /* Any compiler capable of targeting NT 3.50 should support __int64 * (Visual C++ 2.0, Open Watcom) */ #define CK_OFF_T __int64 #else /* CKT_NT35 */ /* Compilers capable of targeting only Windows NT 3.1 * (Visual C++ 1.0 32-bit edition) may not support __int64 */ #define CK_OFF_T long #endif /* CKT_NT35 */ #else /* CKT_NT31 */ #define CK_OFF_T __int64 #endif /* CKT_NT31 */ #else /* NT */ #define CK_OFF_T long #endif /* NT */ #endif /* OS2 */ #endif /* CK_OFF_T */ /* FreeBSD and OpenBSD set off_t to the appropriate size unconditionally */ #ifndef CK_OFF_T #ifdef __FreeBSD__ #define CK_OFF_T off_t #else #ifdef __OpenBSD__ #define CK_OFF_T off_t #endif /* __OpenBSD__ */ #endif /* __FreeBSD__ */ #endif /* CK_OFF_T */ /* 32-bit platforms that support long files thru "transitional interface" */ /* These include Linux, Solaris, NetBSD... */ #ifdef AIXRS #ifdef _LARGE_FILES #ifndef CK_OFF_T #define CK_OFF_T off_t #endif /* CK_OFF_T */ #endif /* _LARGE_FILES */ #endif /* AIXRS */ #ifdef _LARGEFILE_SOURCE #ifndef CK_OFF_T #define CK_OFF_T off_t #endif /* CK_OFF_T */ #ifdef IRIX #define CKFSEEK(a,b,c) fseek64(a,b,c) #define CKFTELL(a) ftell64(a) #else /* IRIX */ #define CKFSEEK(a,b,c) fseeko(a,b,c) #define CKFTELL(a) ftello(a) #endif /* IRIX */ #else /* Not _LARGEFILE_SOURCE */ #define CKFSEEK(a,b,c) fseek(a,b,c) #define CKFTELL(a) ftell(a) /* See below the next section for the catch-all case */ #endif /* _LARGEFILE_SOURCE */ /* 32-bit or 64-bit platforms */ /* CK_64BIT is a compile-time symbol indicating a true 64-bit build */ /* meaning that longs and pointers are 64 bits */ #ifndef NT #ifndef VMS /* VMS Alpha and IA64 are 32-bit! */ #ifndef CK_64BIT #ifdef _LP64 /* Solaris */ #define CK_64BIT #else #ifdef __LP64__ /* MacOS X 10.4 (or _LP64,__ppc64__) */ #define CK_64BIT #else #ifdef __arch64__ /* gcc alpha, sparc */ #define CK_64BIT #else #ifdef __alpha /* Alpha decc (or __ALPHA) */ #define CK_64BIT #else #ifdef __amd64 /* AMD x86_64 */ #define CK_64BIT #else #ifdef __x86_64 /* AMD/Intel x86_64 */ #define CK_64BIT #else #ifdef __ia64 /* Intel IA64 */ #ifndef HPUX #define CK_64BIT #endif /* HPUX */ #endif /* __ia64 */ #endif /* __x86_64 */ #endif /* __amd64 */ #endif /* __alpha */ #endif /* __arch64__ */ #endif /* __LP64__ */ #endif /* _LP64 */ #endif /* CK_64BIT */ #endif /* VMS */ #else /* NT */ #ifdef _WIN64 /* NT can be 32bit or 64bit */ #define CK_64BIT #endif /* _WIN64 */ #endif /* NT */ #ifndef CK_OFF_T #ifdef CK_64BIT #define CK_OFF_T off_t /* This has to be signed */ #else /* CK_64BIT */ #define CK_OFF_T long /* Signed */ #endif /* CK_64BIT */ #endif /* CK_OFF_T */ #ifndef TLOG #define tlog(a,b,c,d) #else #ifndef CKCMAI /* Debugging included. Declare debug log flag in main program only. */ extern int tralog, tlogfmt; #endif /* CKCMAI */ _PROTOTYP(VOID dotlog,(int, char *, char *, CK_OFF_T)); #define tlog(a,b,c,d) if (tralog && tlogfmt) dotlog(a,b,c,(CK_OFF_T)d) _PROTOTYP(VOID doxlog,(int, char *, CK_OFF_T, int, int, char *)); #endif /* TLOG */ #ifndef DEBUG /* Compile all the debug() statements away. Saves a lot of space and time. */ #define debug(a,b,c,d) #define ckhexdump(a,b,c) /* Now define the debug() macro. */ #else /* DEBUG */ _PROTOTYP(int dodebug,(int,char *,char *,CK_OFF_T)); _PROTOTYP(int dohexdump,(CHAR *,CHAR *,int)); #ifdef IFDEBUG /* Use this form to avoid function calls: */ #ifdef COMMENT #define debug(a,b,c,d) if (deblog) dodebug(a,b,(char *)(c),(CK_OFF_T)(d)) #define ckhexdump(a,b,c) if (deblog) dohexdump((CHAR *)(a),(CHAR *)(b),c) #else #ifdef CK_ANSIC #define debug(a,b,c,d) \ ((void)(deblog?dodebug(a,b,(char *)(c),(CK_OFF_T)(d)):0)) #define ckhexdump(a,b,c) \ ((void)(deblog?dohexdump((CHAR *)(a),(CHAR *)(b),c):0)) #else #define debug(a,b,c,d) (deblog?dodebug(a,b,(char *)(c),(CK_OFF_T)(d)):0) #define ckhexdump(a,b,c) (deblog?dohexdump((CHAR *)(a),(CHAR *)(b),c):0) #endif /* CK_ANSIC */ #endif /* COMMENT */ #else /* IFDEBUG */ /* Use this form to save space: */ #define debug(a,b,c,d) dodebug(a,b,(char *)(c),(CK_OFF_T)(d)) #define ckhexdump(a,b,c) dohexdump((CHAR *)(a),(CHAR *)(b),c) #endif /* IFDEBUG */ #endif /* DEBUG */ /* Structure definitions for Kermit file attributes */ /* All strings come as pointer and length combinations */ /* Empty string (or for numeric variables, -1) = unused attribute. */ struct zstr { /* string format */ int len; /* length */ char *val; /* value */ }; struct zattr { /* Kermit File Attribute structure */ CK_OFF_T lengthk; /* (!) file length in K */ struct zstr type; /* (") file type (text or binary) */ struct zstr date; /* (#) file creation date yyyymmdd[ hh:mm[:ss]] */ struct zstr creator; /* ($) file creator id */ struct zstr account; /* (%) file account */ struct zstr area; /* (&) area (e.g. directory) for file */ struct zstr password; /* (') password for area */ long blksize; /* (() file blocksize */ struct zstr xaccess; /* ()) file access: new, supersede, append, warn */ struct zstr encoding; /* (*) encoding (transfer syntax) */ struct zstr disp; /* (+) disposition (mail, message, print, etc) */ struct zstr lprotect; /* (,) protection (local syntax) */ struct zstr gprotect; /* (-) protection (generic syntax) */ struct zstr systemid; /* (.) ID for system of origin */ struct zstr recfm; /* (/) record format */ struct zstr sysparam; /* (0) system-dependent parameter string */ CK_OFF_T length; /* (1) exact length on system of origin */ struct zstr charset; /* (2) transfer syntax character set */ #ifdef OS2 struct zstr longname; /* OS/2 longname if applicable */ #endif /* OS2 */ struct zstr reply; /* This goes last, used for attribute reply */ }; /* Kermit file information structure */ struct filinfo { int bs; /* Blocksize */ int cs; /* Character set */ long rl; /* Record length */ int org; /* Organization */ int fmt; /* Record format */ int cc; /* Carriage control */ int typ; /* Type (text/binary) */ int dsp; /* Disposition */ char *os_specific; /* OS-specific attributes */ #ifdef OS2 unsigned long int lblopts; /* LABELED FILE options bitmask */ #else int lblopts; #endif /* OS2 */ }; /* Data type for pids. If your system uses a different type, put something like -DPID_T=pid_t on command line, or override here. */ #ifndef PID_T #define PID_T int #endif /* PID_T */ /* Data types for uids and gids. Same deal as for pids. Wouldn't be nice if there was a preprocessor test to find out if a typedef existed? */ #ifdef VMS /* Not used in VMS so who cares */ #define UID_T int #define GID_T int #endif /* VMS */ #ifdef POSIX /* Or would it be better (or worse?) to use _POSIX_SOURCE here? */ #ifndef UID_T #define UID_T uid_t #endif /* UID_T */ #ifndef GID_T #define GID_T gid_t #endif /* GID_T */ #else /* Not POSIX */ #ifdef SVR4 /* SVR4 and later have uid_t and gid_t. */ /* SVR3 and earlier use int, or unsigned short, or.... */ #ifndef UID_T #define UID_T uid_t #endif /* UID_T */ #ifndef GID_T #define GID_T gid_t #endif /* GID_T */ #else /* Not SVR4 */ #ifdef BSD43 #ifndef UID_T #define UID_T uid_t #endif /* UID_T */ #ifndef GID_T #define GID_T gid_t #endif /* GID_T */ #else /* Not BSD43 */ /* Default these to int for older UNIX versions */ #ifndef UID_T #define UID_T int #endif /* UID_T */ #ifndef GID_T #define GID_T int #endif /* GID_T */ #endif /* BSD43 */ #endif /* SVR4 */ #endif /* POSIX */ /* getpwuid() arg type, which is not necessarily the same as UID_T, e.g. in SCO UNIX SVR3, it's int. */ #ifndef PWID_T #define PWID_T UID_T #endif /* PWID_T */ #ifdef CK_REDIR #ifdef NEXT #define MACHWAIT #else #ifdef MACH #define MACHWAIT #endif /* MACH */ #endif /* NEXT */ #ifdef MACHWAIT /* WAIT_T argument for wait() */ #include #define CK_WAIT_H typedef union wait WAIT_T; #else #ifdef POSIX #ifdef OSF /* OSF wait.h defines BSD wait if _BSD is defined so hide _BSD from wait.h */ #ifdef _BSD #define CK_OSF_BSD #undef _BSD #endif /* _BSD */ #endif /* OSF */ #include #define CK_WAIT_H #ifndef WAIT_T typedef int WAIT_T; #endif /* WAIT_T */ #ifdef CK_OSF_BSD /* OSF/1: Restore _BSD definition */ #define _BSD #undef CK_OSF_BSD #endif /* CK_OSF_BSD */ #else /* !POSIX */ typedef int WAIT_T; #endif /* POSIX */ #endif /* MACHWAIT */ #else typedef int WAIT_T; #endif /* CK_REDIR */ /* Assorted other blah_t's handled here... */ #ifndef SIZE_T #define SIZE_T size_t #endif /* SIZE_T */ /* Forward declarations of system-dependent functions callable from all */ /* C-Kermit modules. */ /* File-related functions from system-dependent file i/o module */ #ifndef CKVFIO_C /* For some reason, this does not agree with DEC C */ _PROTOTYP( int zkself, (void) ); #endif /* CKVFIO_C */ _PROTOTYP( int zopeni, (int, char *) ); _PROTOTYP( int zopeno, (int, char *, struct zattr *, struct filinfo *) ); _PROTOTYP( int zclose, (int) ); #ifndef MAC _PROTOTYP( int zchin, (int, int *) ); #endif /* MAC */ _PROTOTYP( int zxin, (int, char *, int) ); _PROTOTYP( int zsinl, (int, char *, int) ); _PROTOTYP( int zinfill, (void) ); _PROTOTYP( int zsout, (int, char*) ); _PROTOTYP( int zsoutl, (int, char*) ); _PROTOTYP( int zsoutx, (int, char*, int) ); _PROTOTYP( int zchout, (int, char) ); _PROTOTYP( int zoutdump, (void) ); _PROTOTYP( int zsyscmd, (char *) ); _PROTOTYP( int zshcmd, (char *) ); #ifdef UNIX _PROTOTYP( int zsetfil, (int, int) ); #endif /* UNIX */ #ifdef OS2ORUNIX _PROTOTYP( int zchkpid, (unsigned long) ); #endif /* OS2ORUNIX */ #ifdef CKEXEC _PROTOTYP( VOID z_exec, (char *, char **, int) ); #endif /* CKEXEC */ _PROTOTYP( int chkfn, (int) ); _PROTOTYP( CK_OFF_T zchki, (char *) ); #ifdef VMSORUNIX _PROTOTYP( CK_OFF_T zgetfs, (char *) ); #else #ifdef OS2 _PROTOTYP( CK_OFF_T zgetfs, (char *) ); #else #define zgetfs(a) zchki(a) #endif /* OS2 */ #endif /* VMSORUNIX */ _PROTOTYP( int iswild, (char *) ); _PROTOTYP( int isdir, (char *) ); _PROTOTYP( int zchko, (char *) ); _PROTOTYP( int zdelet, (char *) ); _PROTOTYP( VOID zrtol, (char *,char *) ); _PROTOTYP( VOID zltor, (char *,char *) ); _PROTOTYP( VOID zstrip, (char *,char **) ); #ifdef VMS _PROTOTYP( char * zrelname, (char *, char *) ); #endif /* VMS */ _PROTOTYP( int zchdir, (char *) ); _PROTOTYP( char * zhome, (void) ); _PROTOTYP( char * zgtdir, (void) ); _PROTOTYP( int zxcmd, (int, char *) ); #ifndef MAC _PROTOTYP( int zclosf, (int) ); #endif /* MAC */ #ifdef NZXPAND #ifdef OS2 /* [jt] 2013/11/21 - CHAR/char conflict between K95 and others */ _PROTOTYP( int nzxpand, (CHAR *, int) ); #else _PROTOTYP( int nzxpand, (char *, int) ); #endif /* OS2 */ #else /* NZXPAND */ _PROTOTYP( int zxpand, (char *) ); #endif /* NZXPAND */ _PROTOTYP( int znext, (char *) ); #ifdef ZXREWIND _PROTOTYP( int zxrewind, (void) ); #endif /* ZXREWIND */ _PROTOTYP( int zchkspa, (char *, CK_OFF_T) ); _PROTOTYP( VOID znewn, (char *, char **) ); _PROTOTYP( int zrename, (char *, char *) ); _PROTOTYP( int zcopy, (char *, char *) ); _PROTOTYP( int zsattr, (struct zattr *) ); _PROTOTYP( int zfree, (char *) ); _PROTOTYP( char * zfcdat, (char *) ); _PROTOTYP( int zstime, (char *, struct zattr *, int) ); #ifdef CK_PERMS _PROTOTYP( char * zgperm, (char *) ); _PROTOTYP( char * ziperm, (char *) ); #else /* CK_PERMS */ #ifdef OS2 /* zgperm exists on OS/2 and NT regardless of CK_PERMS */ _PROTOTYP( char * zgperm, (char *) ); #endif /* OS2 */ #endif /* CK_PERMS */ _PROTOTYP( int zmail, (char *, char *) ); _PROTOTYP( int zprint, (char *, char *) ); _PROTOTYP( char * tilde_expand, (char *) ); _PROTOTYP( int zmkdir, (char *) ) ; _PROTOTYP( int zfseek, (CK_OFF_T) ) ; #ifdef ZFNQFP _PROTOTYP( struct zfnfp * zfnqfp, (char *, int, char * ) ) ; #else #define zfnqfp(a,b,c) ckstrncpy(c,a,b) #endif /* ZFNQFP */ _PROTOTYP( int zvuser, (char *) ) ; _PROTOTYP( int zvpass, (char *) ) ; _PROTOTYP( VOID zvlogout, (void) ) ; #ifdef OS2 _PROTOTYP( int os2setlongname, ( char * fn, char * ln ) ) ; _PROTOTYP( int os2getlongname, ( char * fn, char ** ln ) ) ; _PROTOTYP( int os2rexx, ( char *, char *, int ) ) ; _PROTOTYP( int os2rexxfile, ( char *, char *, char *, int) ) ; _PROTOTYP( int os2geteas, (char *) ) ; _PROTOTYP( int os2seteas, (char *) ) ; _PROTOTYP( char * get_os2_vers, (void) ) ; _PROTOTYP( int do_label_send, (char *) ) ; _PROTOTYP( int do_label_recv, (void) ) ; #ifdef OS2MOUSE _PROTOTYP( unsigned long os2_mouseon, (void) ); _PROTOTYP( unsigned long os2_mousehide, (void) ); _PROTOTYP( unsigned long os2_mouseshow, (void) ); _PROTOTYP( unsigned long os2_mouseoff, (void) ); _PROTOTYP( void os2_mouseevt, (void *) ); _PROTOTYP( int mousebuttoncount, (void)); #endif /* OS2MOUSE */ #endif /* OS2 */ /* Functions from system-dependent terminal i/o module */ _PROTOTYP( int ttopen, (char *, int *, int, int) ); /* tty functions */ #ifndef MAC _PROTOTYP( int ttclos, (int) ); #endif /* MAC */ _PROTOTYP( int tthang, (void) ); _PROTOTYP( int ttres, (void) ); _PROTOTYP( int ttpkt, (long, int, int) ); #ifndef MAC _PROTOTYP( int ttvt, (long, int) ); #endif /* MAC */ _PROTOTYP( int ttsspd, (int) ); _PROTOTYP( long ttgspd, (void) ); _PROTOTYP( int ttflui, (void) ); _PROTOTYP( int ttfluo, (void) ); _PROTOTYP( int ttpushback, (CHAR *, int) ); _PROTOTYP( int ttpeek, (void) ); _PROTOTYP( int ttgwsiz, (void) ); _PROTOTYP( int ttchk, (void) ); _PROTOTYP( int ttxin, (int, CHAR *) ); _PROTOTYP( int ttxout, (CHAR *, int) ); _PROTOTYP( int ttol, (CHAR *, int) ); _PROTOTYP( int ttoc, (char) ); _PROTOTYP( int ttinc, (int) ); _PROTOTYP( int ttscarr, (int) ); _PROTOTYP( int ttgmdm, (void) ); _PROTOTYP( int ttsndb, (void) ); _PROTOTYP( int ttsndlb, (void) ); #ifdef UNIX _PROTOTYP( char * ttglckdir, (void) ); #endif /* UNIX */ #ifdef PARSENSE #ifdef UNIX _PROTOTYP( int ttinl, (CHAR *, int, int, CHAR, CHAR, int) ); #else #ifdef VMS _PROTOTYP( int ttinl, (CHAR *, int, int, CHAR, CHAR, int) ); #else #ifdef STRATUS _PROTOTYP( int ttinl, (CHAR *, int, int, CHAR, CHAR, int) ); #else #ifdef OS2 _PROTOTYP( int ttinl, (CHAR *, int, int, CHAR, CHAR, int) ); #else #ifdef OSK _PROTOTYP( int ttinl, (CHAR *, int, int, CHAR, CHAR, int) ); #else _PROTOTYP( int ttinl, (CHAR *, int, int, CHAR, CHAR) ); #endif /* OSK */ #endif /* OS2 */ #endif /* STRATUS */ #endif /* VMS */ #endif /* UNIX */ #else /* ! PARSENSE */ _PROTOTYP( int ttinl, (CHAR *, int, int, CHAR) ); #endif /* PARSENSE */ /* XYZMODEM support */ /* CK_XYZ enables the various commands and data structures. XYZ_INTERNAL means these protocols are built-in; if not defined, then they are external. XYZ_DLL is used to indicate a separate loadable library containing the XYZmodem protocol code. */ #ifdef pdp11 /* No room for this in PDP-11 */ #define NOCKXYZ #endif /* pdp11 */ #ifndef NOCKXYZ /* Alternative protocols */ #ifndef CK_XYZ #ifdef UNIX #define CK_XYZ #else #ifdef OS2 #define CK_XYZ #ifndef NOXYZDLL #define XYZ_INTERNAL /* Internal and DLL */ #ifndef XYZ_DLL #define XYZ_DLL #endif /* XYZ_DLL */ #endif /* NOXYZDLL */ #endif /* OS2 */ #endif /* UNIX */ #endif /* CK_XYZ */ #endif /* NOCKXYZ */ #ifdef XYZ_INTERNAL /* This ensures that XYZ_INTERNAL */ #ifndef CK_XYZ /* is defined only if CK_XYZ is too */ #undef XYZ_INTERNAL #endif /* CK_XYZ */ #endif /* XYZ_INTERNAL */ #ifdef XYZ_DLL /* This ensures XYZ_DLL is defined */ #ifndef XYZ_INTERNAL /* only if XYZ_INTERNAL is too */ #undef XYZ_DLL #endif /* XYZ_INTERNAL */ #endif /* XYZ_DLL */ /* Console functions */ _PROTOTYP( int congm, (void) ); #ifdef COMMENT _PROTOTYP( VOID conint, (SIGTYP (*)(int, int), SIGTYP (*)(int, int)) ); #else _PROTOTYP( VOID conint, (SIGTYP (*)(int), SIGTYP (*)(int)) ); #endif /* COMMENT */ _PROTOTYP( VOID connoi, (void) ); _PROTOTYP( int concb, (char) ); #ifdef CONGSPD _PROTOTYP( long congspd, (void) ); #endif /* CONGSPD */ _PROTOTYP( int conbin, (char) ); _PROTOTYP( int conres, (void) ); _PROTOTYP( int conoc, (char) ); _PROTOTYP( int conxo, (int, char *) ); _PROTOTYP( int conol, (char *) ); _PROTOTYP( int conola, (char *[]) ); _PROTOTYP( int conoll, (char *) ); _PROTOTYP( int conchk, (void) ); _PROTOTYP( int coninc, (int) ); _PROTOTYP( char * conkbg, (void) ); _PROTOTYP( int psuspend, (int) ); _PROTOTYP( int priv_ini, (void) ); _PROTOTYP( int priv_on, (void) ); _PROTOTYP( int priv_off, (void) ); _PROTOTYP( int priv_can, (void) ); _PROTOTYP( int priv_chk, (void) ); _PROTOTYP( int priv_opn, (char *, int) ); _PROTOTYP( int sysinit, (void) ); /* Misc Kermit functions */ _PROTOTYP( int syscleanup, (void) ); _PROTOTYP( int msleep, (int) ); _PROTOTYP( VOID rtimer, (void) ); _PROTOTYP( int gtimer, (void) ); #ifdef GFTIMER _PROTOTYP( VOID rftimer, (void) ); _PROTOTYP( CKFLOAT gftimer, (void) ); #endif /* GFTIMER */ _PROTOTYP( VOID ttimoff, (void) ); _PROTOTYP( VOID ztime, (char **) ); _PROTOTYP( int parchk, (CHAR *, CHAR, int) ); _PROTOTYP( VOID doexit, (int, int) ); _PROTOTYP( int askmore, (void) ); _PROTOTYP( VOID fatal, (char *) ); _PROTOTYP( VOID fatal2, (char *, char *) ); #ifdef VMS _PROTOTYP( int ck_cancio, (void) ); #endif /* VMS */ /* Key mapping support */ #ifdef NOICP #ifndef NOSETKEY #define NOSETKEY #endif /* NOSETKEY */ #endif /* NOICP */ #ifdef MAC #ifndef NOSETKEY #define NOSETKEY #endif /* NOSETKEY */ #endif /* MAC */ _PROTOTYP( int congks, (int) ); #ifdef OS2 /* OS2 requires these definitions even if SET KEY is not being supported */ #define KMSIZE 8916 typedef ULONG KEY; typedef CHAR *MACRO; extern int wideresult; #else /* Not OS2 */ #ifndef NOSETKEY /* Catch-all for systems where we don't know how to read keyboard scan codes > 255. */ #define KMSIZE 256 /* Note: CHAR (i.e. unsigned char) is very important here. */ typedef CHAR KEY; typedef CHAR * MACRO; #define congks coninc #endif /* NOSETKEY */ #endif /* OS2 */ #ifndef OS2 #ifndef NOKVERBS /* No \Kverbs unless... */ #define NOKVERBS #endif /* NOKVERBS */ #endif /* OS2 */ #ifndef NOKVERBS #ifdef OS2 /* Note: this value chosen to be bigger than PC BIOS key modifier bits, but still fit in 16 bits without affecting sign. As of K95 1.1.5, this no longer fits in 16 bits, good thing we are 32 bit. */ #define F_MACRO 0x2000 /* Bit indicating a macro indice */ #define IS_MACRO(x) (x & F_MACRO) #define F_KVERB 0x4000 /* Bit indicating a keyboard verb */ #define IS_KVERB(x) (x & F_KVERB) /* Test this bit */ #endif /* OS2 */ #endif /* NOKVERBS */ #define F_ESC 0x8000 /* Bit indicating ESC char combination */ #define IS_ESC(x) (x & F_ESC) #define F_CSI 0x10000 /* Bit indicating CSI char combination */ #define IS_CSI(x) (x & F_CSI) #ifdef NOSPL /* This might be overkill.. */ #ifndef NOKVERBS /* Not all \Kverbs require */ #define NOKVERBS /* the script programming language. */ #endif /* NOKVERBS */ #ifndef NOTAKEARGS #define NOTAKEARGS #endif /* NOTAKEARGS */ #endif /* NOSPL */ /* Function prototypes for system and library functions. */ #ifdef _POSIX_SOURCE #ifndef VMS #ifndef MAC #define CK_ANSILIBS #endif /* MAC */ #endif /* VMS */ #endif /* _POSIX_SOURCE */ #ifdef NEXT #define CK_ANSILIBS #endif /* NEXT */ #ifdef SVR4 #define CK_ANSILIBS #endif /* SVR4 */ #ifdef STRATUS /* Stratus VOS uses ANSI libraries */ #define CK_ANSILIBS #endif /* STRATUS */ #ifdef OS2 #define CK_ANSILIBS #ifndef NOCURSES #define MYCURSES #endif /* NOCURSES */ #define CK_RTSCTS #ifdef __IBMC__ #define S_IFMT 0xF000 #define timezone _timezone #endif /* __IBMC__ */ #include #include #ifdef __EMX__ #ifndef __32BIT__ #define __32BIT__ #endif /* __32BIT__ */ #ifndef NOSYSTIMEBH #include #endif /* NOSYSTIMEBH */ #else /* __EMX__ */ #ifndef __WATCOMC__ /* Watcom direct.h definition incompatible with the * implementation in ckodir.h and ckotio.c */ #include #endif /* __WATCOMC__ */ #undef SIGALRM #ifndef SIGUSR1 #ifndef __WATCOMC__ #define SIGUSR1 7 #endif /* __WATCOMC__ */ #endif /* SIGUSR1 */ #define SIGALRM SIGUSR1 _PROTOTYP( unsigned alarm, (unsigned) ); _PROTOTYP( unsigned sleep, (unsigned) ); #endif /* __EMX__ */ _PROTOTYP( CK_OFF_T zdskspace, (int) ); _PROTOTYP( int zchdsk, (int) ); _PROTOTYP( int conincraw, (int) ); _PROTOTYP( int ttiscom, (int f) ); _PROTOTYP( int IsFileNameValid, (char *) ); _PROTOTYP( void ChangeNameForFAT, (char *) ); _PROTOTYP( char *GetLoadPath, (void) ); #endif /* OS2 */ /* Fullscreen file transfer display items... */ #ifndef NOCURSES #ifdef CK_NCURSES /* CK_NCURSES implies CK_CURSES */ #ifndef CK_CURSES #define CK_CURSES #endif /* CK_CURSES */ #endif /* CK_NCURSES */ #ifdef MYCURSES /* MYCURSES implies CK_CURSES */ #ifndef CK_CURSES #define CK_CURSES #endif /* CK_CURSES */ #endif /* MYCURSES */ #endif /* NOCURSES */ #ifdef NOCURSES #ifdef CK_CURSES #undef CK_CURSES #endif /* CK_CURSES */ #ifndef NODISPLAY #define NODISPLAY #endif /* NODISPLAY */ #endif /* NOCURSES */ #ifdef CK_CURSES /* The CK_WREFRESH symbol is defined if the curses library provides clearok() and wrefresh() functions, which are used in repainting the screen. */ #ifdef NOWREFRESH /* Override CK_WREFRESH */ #ifdef CK_WREFRESH /* If this is defined, */ #undef CK_WREFRESH /* undefine it. */ #endif /* CK_WREFRESH */ #else /* !NOWREFRESH */ /* No override... */ #ifndef CK_WREFRESH /* If CK_WREFRESH not defined */ /* Automatically define it for systems known to have it ... */ #ifdef VMS /* DEC (Open)VMS has it */ #define CK_WREFRESH #else #ifdef ultrix /* DEC ULTRIX has it */ #else #ifdef SVR3 /* System V has it */ #define CK_WREFRESH #else #ifdef BSD44 /* 4.4 BSD has it */ #define CK_WREFRESH #else #ifdef NEXT /* Define it for NeXTSTEP */ #define CK_WREFRESH #else #ifdef SUNOS4 /* SunOS 4.x... */ #define CK_WREFRESH #else #ifdef SOLARIS25 /* Solaris 2.5 and later */ #define CK_WREFRESH #else #ifdef AIXRS /* RS/6000 AIX ... */ #define CK_WREFRESH #else #ifdef RTAIX /* RT PC AIX ... */ #define CK_WREFRESH #else #ifdef OSF /* DEC OSF/1 ... */ #define CK_WREFRESH /* Add more here, or just define CK_WREFRESH on the CC command line... */ #endif /* OSF */ #endif /* RTAIX */ #endif /* AIXRS */ #endif /* SOLARIS25 */ #endif /* SUNOS4 */ #endif /* NEXT */ #endif /* BSD44 */ #endif /* SVR3 */ #endif /* ultrix */ #endif /* VMS */ #else /* CK_WREFRESH is defined */ /* This is within an ifdef CK_CURSES block. The following is not needed */ #ifndef CK_CURSES /* CK_WREFRESH implies CK_CURSES */ #define CK_CURSES #endif /* CK_CURSES */ #endif /* CK_WREFRESH */ #endif /* NOWREFRESH */ #ifndef TRMBUFL #ifdef BIGBUFOK #define TRMBUFL 16384 #else #ifdef DYNAMIC #define TRMBUFL 8192 #else #define TRMBUFL 1024 #endif /* BIGBUFOK */ #endif /* DYNAMIC */ #endif /* TRMBUFL */ #endif /* CK_CURSES */ /* Whether to use ckmatch() in all its glory for C-Shell-like patterns. If CKREGEX is NOT defined, all but * and ? matching are removed from ckmatch(). NOTE: Defining CKREGEX does not necessarily mean that ckmatch() regexes are used for filename matching. That depends on whether zxpand() in ck?fio.c calls ckmatch(). NOTE 2: REGEX is a misnomer -- these are not regular expressions in the computer-science sense (in which, e.g. "a*b" matches 0 or more 'a' characters followed by 'b') but patterns (in which "a*b" matches 'a' followed by 0 or more non-b characters, followed by b). */ #ifndef NOCKREGEX #ifndef CKREGEX #define CKREGEX #endif /* CKREGEX */ #endif /* NOCKREGEX */ /* Learned-script feature */ #ifndef NOLEARN #ifdef NOSPL #define NOLEARN #else #ifdef NOLOCAL #define NOLEARN #endif /* NOLOCAL */ #endif /* NOSPL */ #endif /* NOLEARN */ #ifdef NOLEARN #ifdef CKLEARN #undef CKLEARN #endif /* CKLEARN */ #else /* !NOLEARN */ #ifndef CKLEARN #ifdef OS2ORUNIX /* In UNIX this can work only with ckucns.c builds */ #define CKLEARN #else #ifdef VMS #define CKLEARN #endif /* VMS */ #endif /* OS2ORUNIX */ #endif /* CKLEARN */ #endif /* NOLEARN */ #ifdef CKLEARN #ifndef LEARNBUFSIZ #define LEARNBUFSIZ 128 #endif /* LEARNBUFSIZ */ #endif /* CKLEARN */ #ifndef IKSDONLY #ifndef CKTIDLE /* Pseudo-keepalive in CONNECT */ #ifdef OS2 /* In K95 */ #define CKTIDLE #else #ifdef UNIX /* In UNIX but only ckucns versions */ #ifndef NOLEARN #ifndef NOSELECT #define CKTIDLE #endif /* NOSELECT */ #endif /* NOLEARN */ #endif /* UNIX */ #endif /* OS2 */ #endif /* CKTIDLE */ #endif /* IKSDONLY */ #ifdef CK_ANSILIBS /* String library functions. For ANSI C, get prototypes from . Otherwise, skip the prototypes. */ #include /* Prototypes for other commonly used library functions, such as malloc, free, getenv, atol, atoi, and exit. Otherwise, no prototypes. */ #include #ifdef DIAB /* DIAB DS90 */ /* #include */ #include #define CK_WAIT_H #ifdef COMMENT extern void exit(int status); extern void _exit(int status); extern int uname(struct utsname *name); #endif /* COMMENT */ extern int chmod(char *path, int mode); extern int ioctl(int fildes, int request, ...); extern int rdchk(int ttyfd); extern int nap(int m); #ifdef COMMENT extern int getppid(void); #endif /* COMMENT */ extern int _filbuf(FILE *stream); extern int _flsbuf(char c,FILE *stream); #endif /* DIAB */ /* Prototypes for UNIX functions like access, alarm, chdir, sleep, fork, and pause. Otherwise, no prototypes. */ #ifdef VMS #include /* SMS: sleep() for old (V4.0-000) DEC C. */ #include #include /* SMS: getpid() for old (V4.0-000) DEC C. */ #endif /* VMS */ #ifdef NEXT #ifndef NEXT33 #include #endif /* NEXT33 */ #else /* NoT NeXT */ #ifndef AMIGA #ifndef OS2 #ifdef STRATUS #include #else /* !STRATUS */ #ifndef OSKXXC #include #endif /* OSKXXC */ #ifdef HAVE_CRYPT_H #include #endif /* HAVE_CRYPT_H */ #endif /* STRATUS */ #endif /* OS2 */ #endif /* AMIGA */ #endif /* NEXT */ #else /* Not ANSI libs... */ #ifdef MAC #include #include #endif /* MAC */ #ifdef HPUX #ifndef HPUXPRE65 #include #endif /* HPUXPRE65 */ #endif /* HPUX */ #ifdef SUNOS41 #include #include #else #ifndef MAC /* It is essential that these are declared correctly! Which is not always easy. Take malloc() for instance ... NOTE: there were a bunch of protypes here for malloc() here before but why??? The specs come from the header files. */ #ifdef PYRAMID #ifdef SVR4 #ifdef __STDC__ #define SIZE_T_MALLOC #endif /* __STDC__ */ #endif /* SVR4 */ #endif /* PYRAMID */ #endif /* !MAC */ #endif /* SUNOS41 */ #endif /* CK_ANSILIBS */ /* generally picks up NULL, MAXPATHLEN, and MAXNAMLEN and seems to present on all Unixes going back at least to SCO Xenix with the exception(s) noted. */ #ifndef NO_PARAM_H /* 2001-11-03 */ #ifndef UNIX /* Non-Unixes don't have it */ #define NO_PARAM_H #else #ifdef TRS16 /* Tandy Xenix doesn't have it */ #define NO_PARAM_H #endif /* TRS16 */ #endif /* UNIX */ #endif /* NO_PARAM_H */ #ifndef NO_PARAM_H #ifndef INCL_PARAM_H #define INCL_PARAM_H #endif /* INCL_PARAM_H */ #include #endif /* NO_PARAM_H */ #ifndef NULL /* In case NULL is still not defined */ #define NULL 0L /* or #define NULL 0 */ /* or #define NULL ((char *) 0) */ /* or #define NULL ((void *) 0) */ #endif /* NULL */ /* Macro to differentiate "" from NULL (to avoid comparisons with literals) */ #ifndef isemptystring #define isemptystring(s) ((s?(*s?0:1):0)) #endif /* isemptystring */ /* Maximum length for a fully qualified filename, not counting \0 at end. */ /* This is a rough cut, and errs on the side of being too big. We don't want to pull in hundreds of header files looking for many and varied symbols, for fear of introducing unnecessary conflicts. */ #ifndef CKMAXPATH #ifdef VMS /* VMS may have bad (small, ODS2) */ #define CKMAXPATH NAMX_C_MAXRSS /* PATH_MAX, so use NAMX_C_MAXRSS. */ #else /* def VMS */ #ifdef MAXPATHLEN /* (it probably isn't) */ #define CKMAXPATH MAXPATHLEN #else #ifdef PATH_MAX /* POSIX */ #define CKMAXPATH PATH_MAX #else /* def PATH_MAX */ #ifdef MAC #define CKMAXPATH 63 #else /* def MAC */ #ifdef pdp11 #define CKMAXPATH 255 #else /* def pdp11 */ #ifdef UNIX /* Even though some are way less... */ #define CKMAXPATH 1024 #else /* def UNIX */ #ifdef STRATUS #define CKMAXPATH 256 /* == $MXPL from PARU.H */ #else /* def STRATUS */ #ifdef datageneral #define CKMAXPATH 256 /* == $MXPL from PARU.H */ #else /* def datageneral */ #define CKMAXPATH 255 #endif /* def STRATUS [else] */ #endif /* def datageneral [else] */ #endif /* def UNIX [else] */ #endif /* def pdp11 [else] */ #endif /* def MAC [else] */ #endif /* def PATH_MAX [else] */ #endif /* def MAXPATHLEN [else] */ #endif /* def VMS [else] */ #endif /* ndef CKMAXPATH */ /* 2021-10-30 SMS (Steven M Schweda) * MAXPATHLEN might have come up undefined because all the consumers * should be using CKMAXPATH instead of MAXPATHLEN, or PATH_MAX, or * whatever. The idea was to put all the system dependencies into the * definition of CKMAXPATH. Previously, MAXPATHLEN was not used in * ckuus4.c or ckuus6.c, * * Apparently, I failed to make the required change(s) in UNIX * modules/sections ckufio.c, ckuus3.c, ckuus5.c. (But _I_ didn't spell * "#define" as "def".) * * On VMS, PATH_MAX is defined as 256 in , but that is an * obsolete value, which is why NAMX_C_MAXRSS is used instead. */ /* Maximum length for a simple filename, not counting \0 at end. */ /* Define maximum length for a file name if not already defined. NOTE: This applies to a path segment (directory or file name), not the entire path string, which can be CKMAXPATH bytes long. */ /* On VMS, this is ill-defined, and depends on the file system: * ODS2: 39.39 + version (;32767), so 84. * ODS5: 238 + version (;32767), so 233. */ #ifndef CKMAXNAM #ifdef VMS #ifdef NAML$C_BID #define CKMAXNAM 233 /* ODS5 possible. */ #else #define CKMAXNAM 84 /* ODS5 unknown. */ #endif /* def NAML$C_BID */ #else /* def VMS */ /* Non-VMS definitions moved here from ckufio.c. with MAXNAMLEN -> CKMAXNAM. */ #ifndef CKMAXNAM /* If MAXNAMLEN is defined, then use that. */ #ifdef MAXNAMLEN #define CKMAXNAM MAXNAMLEN #endif /* def MAXNAMLEN */ #endif /* ndef CKMAXNAM */ #ifdef QNX #ifdef _MAX_FNAME #define CKMAXNAM _MAX_FNAME #else #define CKMAXNAM 48 #endif /* _MAX_FNAME */ #else #ifndef CKMAXNAM #ifdef sun #define CKMAXNAM 255 #else #ifdef FILENAME_MAX #define CKMAXNAM FILENAME_MAX #else #ifdef NAME_MAX #define CKMAXNAM NAME_MAX #else #ifdef _POSIX_NAME_MAX #define CKMAXNAM _POSIX_NAME_MAX #else #ifdef _D_NAME_MAX #define CKMAXNAM _D_NAME_MAX #else #ifdef DIRSIZ #define CKMAXNAM DIRSIZ #else #define CKMAXNAM 14 #endif /* DIRSIZ */ #endif /* _D_NAME_MAX */ #endif /* _POSIX_NAME_MAX */ #endif /* _POSIX_NAME_MAX */ #endif /* NAME_MAX */ #endif /* FILENAME_MAX */ #endif /* sun */ #endif /* CKMAXNAM */ #endif /* QNX */ #endif /* def VMS [else] */ /* Maximum length for the name of a tty device */ #ifndef DEVNAMLEN #define DEVNAMLEN CKMAXPATH #endif /* DEVNAMLEN */ /* Directory (path segment) separator */ /* Not fully general - Tricky for VMS, Amiga, ... */ #ifndef DIRSEP #ifdef UNIX #define DIRSEP '/' #define STRDIRSEP "/" #define ISDIRSEP(c) ((c)=='/') #else #ifdef OS2 #define DIRSEP '/' #define STRDIRSEP "/" #define ISDIRSEP(c) ((c)=='/'||(c)=='\\') #else #ifdef datageneral #define DIRSEP ':' #define STRDIRSEP ":" #define ISDIRSEP(c) (((c)==':')||((c)=='^')||((c)=='=')) #else #ifdef STRATUS #define DIRSEP '>' #define ISDIRSEP(c) ((c)=='>') #else #ifdef VMS #define DIRSEP ']' /* (not really) */ #define STRDIRSEP "]" #define ISDIRSEP(c) ((c)==']'||(c)==':') #else #ifdef MAC #define DIRSEP ':' #define STRDIRSEP ":" #define ISDIRSEP(c) ((c)==':') #else #ifdef AMIGA #define DIRSEP '/' #define STRDIRSEP "/" #define ISDIRSEP(c) ((c)=='/'||(c)==':') #else #ifdef GEMDOS #define DIRSEP '\\' #define STRDIRSEP "\\" #define ISDIRSEP(c) ((c)=='\\'||(c)==':') #else #define DIRSEP '/' #define STRDIRSEP "/" #define ISDIRSEP(c) ((c)=='/') #endif /* GEMDOS */ #endif /* AMIGA */ #endif /* MAC */ #endif /* VMS */ #endif /* STRATUS */ #endif /* datageneral */ #endif /* OS2 */ #endif /* UNIX */ #endif /* DIRSEP */ /* FILE package parameters */ #ifdef pdp11 #define NOCHANNELIO #else #ifndef CKMAXOPEN #ifdef QNX #define CKMAXOPEN 390 #else #ifdef VMS #define CKMAXOPEN 64 #else #ifdef OPEN_MAX #define CKMAXOPEN OPEN_MAX #else #ifdef FOPEN_MAX #define CKMAXOPEN FOPEN_MAX #else #define CKMAXOPEN 64 #endif /* FOPEN_MAX */ #endif /* OPEN_MAX */ #endif /* VMS */ #endif /* QNX */ #endif /* CKMAXOPEN */ /* Maximum channels for FOPEN = CKMAXOPEN minus logs, stdio, etc */ #ifndef Z_MINCHAN #define Z_MINCHAN 16 #endif /* Z_MINCHAN */ #ifndef Z_MAXCHAN #define Z_MAXCHAN (CKMAXOPEN-ZNFILS-5) #endif /* Z_MAXCHAN */ #endif /* pdp11 */ /* New-format nzltor() and nzrtol() functions that handle pathnames */ #ifndef NZLTOR #ifdef UNIX #define NZLTOR #else #ifdef VMS #define NZLTOR #else #ifdef OS2 #define NZLTOR #else #ifdef STRATUS #define NZLTOR #endif /* STRATUS */ #endif /* OS2 */ #endif /* VMS */ #endif /* UNIX */ #endif /* NZLTOR */ #ifdef NZLTOR _PROTOTYP( VOID nzltor, (char *, char *, int, int, int) ); _PROTOTYP( VOID nzrtol, (char *, char *, int, int, int) ); #endif /* NZLTOR */ /* Implementations with a zrmdir() function */ #ifndef ZRMDIR #ifdef OS2 #define ZRMDIR #else /* OS2 */ #ifdef UNIX #define ZRMDIR #else #ifdef VMS #define ZRMDIR #else /* VMS */ #ifdef STRATUS #define ZRMDIR #endif /* STRATUS */ #endif /* VMS */ #endif /* UNIX */ #endif /* OS2 */ #endif /* ZRMDIR */ #ifdef ZRMDIR _PROTOTYP( int zrmdir, (char *) ); #endif /* ZRMDIR */ #ifndef FILECASE #ifdef UNIXOROSK #define FILECASE 1 #else #define FILECASE 0 #endif /* UNIXOROSK */ #ifndef CKCMAI extern int filecase; #endif /* CKCMAI */ #endif /* FILECASE */ /* Funny names for library functions department... */ #ifdef ZILOG #define setjmp setret #define longjmp longret #define jmp_buf ret_buf #define getcwd curdir #endif /* ZILOG */ #ifdef STRATUS /* The C-runtime conflicts with things we do in Stratus VOS ckltio.c ... */ #define printf vosprtf _PROTOTYP( int vosprtf, (char *fmt, ...) ); #define perror(txt) printf("%s\n", txt) /* char_varying is a string type from PL/I that VOS uses extensively */ #define CV char_varying #endif /* STRATUS */ #ifdef NT #ifndef VER_PLATFORM_WIN32_WINDOWS /* Visual C++ 2.0 and older don't define this (Win95 wasn't released yet) */ #define VER_PLATFORM_WIN32_WINDOWS 1 #endif extern int OSVer; #define isWin95() (OSVer==VER_PLATFORM_WIN32_WINDOWS) #else #define isWin95() (0) #endif /* NT */ #ifndef BPRINT #ifdef OS2 #define BPRINT #endif /* OS2 */ #endif /* BPRINT */ #ifndef SESLIMIT #ifdef OS2 #define SESLIMIT #endif /* OS2 */ #endif /* SESLIMIT */ #ifndef NOTERM #ifndef PCTERM #ifdef NT #define PCTERM #endif /* NT */ #endif /* PCTERM */ #endif /* NOTERM */ #ifdef BEOSORBEBOX #define query ckquery #endif /* BEOSORBEBOX */ #ifndef PTYORPIPE /* NETCMD and/or NETPTY defined */ #ifdef NETCMD #define PTYORPIPE #else #ifdef NETPTY #define PTYORPIPE #endif /* NETPTY */ #endif /* NETCMD */ #endif /* PTYORPIPE */ /* mktemp() and mkstemp() */ #ifndef NOMKTEMP #ifndef MKTEMP #ifdef OS2ORUNIX #define MKTEMP #endif /* OS2ORUNIX */ #endif /* MKTEMP */ #ifdef MKTEMP #ifndef NOMKSTEMP #ifndef MKSTEMP #ifdef BSD44 #define MKSTEMP #else #ifdef __linux__ #define MKSTEMP #endif /* __linux__ */ #endif /* BSD44 */ #endif /* MKSTEMP */ #endif /* NOMKSTEMP */ #endif /* MKTEMP */ #endif /* NOMKTEMP */ /* Platforms that have memcpy() -- only after all headers included */ #ifndef USE_MEMCPY #ifdef VMS #define USE_MEMCPY #else #ifdef NEXT #define USE_MEMCPY #else #ifdef OS2 #define USE_MEMCPY #else #ifdef __linux__ #define USE_MEMCPY #else #ifdef SOLARIS #define USE_MEMCPY #else #ifdef SUNOS4 #define USE_MEMCPY #else #ifdef AIXRS #define USE_MEMCPY #else #ifdef HPUX #define USE_MEMCPY #else #ifdef POSIX #define USE_MEMCPY #else #ifdef SVR4 #define USE_MEMCPY #else #ifdef OSF #define USE_MEMCPY #else #ifdef datageneral #define USE_MEMCPY #else #ifdef STRATUS #define USE_MEMCPY #endif /* STRATUS */ #endif /* datageneral */ #endif /* OSF */ #endif /* SVR4 */ #endif /* POSIX */ #endif /* HPUX */ #endif /* AIXRS */ #endif /* SUNOS4 */ #endif /* SOLARIS */ #endif /* __linux__ */ #endif /* OS2 */ #endif /* NEXT */ #endif /* VMS */ #endif /* USE_MEMCPY */ #ifndef USE_MEMCPY #define memcpy(a,b,c) ckmemcpy((a),(b),(c)) #else #ifdef CK_SCO32V4 /* Because the prototype isn't picked up in the normal header files */ _PROTOTYP( void *memcpy, (void *, const void *, size_t)); #endif /* CK_SCO32V4 */ #endif /* USE_MEMCPY */ /* User authentication for IKS -- So far K95 and UNIX only */ #ifdef NOICP #ifndef NOLOGIN #define NOLOGIN #endif /* NOLOGIN */ #endif /* NOICP */ #ifndef NOLOGIN #ifdef OS2ORUNIX #ifndef CK_LOGIN #define CK_LOGIN #ifndef NOSHADOW #ifdef CK_SCOV5 #define CK_SHADOW #endif /* CK_SCOV5 */ #endif /* NOSHADOW */ #endif /* CK_LOGIN */ #ifdef NT #define NTCREATETOKEN #endif /* NT */ #endif /* OS2ORUNIX */ #else /* NOLOGIN */ #ifdef CK_LOGIN #undef CK_LOGIN #endif /* CK_LOGIN */ #endif /* NOLOGIN */ #ifdef OS2 #define CKSPINNER #endif /* OS2 */ #ifdef CK_LOGIN /* Telnet protocol required */ #ifndef TNCODE /* for login to IKSD. */ #define TNCODE #endif /* TNCODE */ #endif /* CK_LOGIN */ #ifdef CK_AUTHENTICATION #ifdef NOSENDUID #undef NOSENDUID #endif /* NOSENDUID */ #endif /* CK_AUTHENTICATION */ #ifdef TNCODE /* Should TELNET send user ID? */ #ifndef NOSENDUID #ifndef CKSENDUID #define CKSENDUID #endif /* CKSENDUID */ #endif /* NOSENDUID */ #endif /* TNCODE */ /* UNIX platforms that don't have getusershell() */ #ifdef UNIX #ifndef NOGETUSERSHELL #ifdef IRIX #define NOGETUSERSHELL #else #ifdef PTX #define NOGETUSERSHELL #else #ifdef AIXRS #define NOGETUSERSHELL #else #ifdef SINIX #define NOGETUSERSHELL #else #ifdef UNIXWARE #define NOGETUSERSHELL #else #ifdef COHERENT #define NOGETUSERSHELL #endif /* COHERENT */ #endif /* UNIXWARE */ #endif /* SINIX */ #endif /* AIXRS */ #endif /* PTX */ #endif /* IRIX */ #endif /* NOGETUSERSHELL */ #endif /* UNIX */ #ifdef CK_LOGIN #ifdef NT #ifndef NOSYSLOG #ifndef CKSYSLOG #define CKSYSLOG #endif /* CKSYSLOG */ #endif /* NOSYSLOG */ #endif /* NT */ #ifdef UNIX #ifndef NOSYSLOG #ifndef CKSYSLOG #define CKSYSLOG #endif /* CKSYSLOG */ #endif /* NOSYSLOG */ #ifndef NOWTMP #ifndef CKWTMP #define CKWTMP #endif /* CKWTMP */ #endif /* NOWTMP */ #ifndef NOGETUSERSHELL #ifndef GETUSERSHELL #define GETUSERSHELL #endif /* GETUSERSHELL */ #endif /* NOGETUSERSHELL */ #endif /* UNIX */ _PROTOTYP( int ckxlogin, (CHAR *, CHAR *, CHAR *, int)); _PROTOTYP( int ckxlogout, (VOID)); #endif /* CK_LOGIN */ #ifndef NOZLOCALTIME /* zlocaltime() available. */ #ifdef OS2ORUNIX #define ZLOCALTIME _PROTOTYP( char * zlocaltime, (char *) ); #endif /* OS2ORUNIX */ #endif /* NOZLOCALTIME */ #ifdef CKSYSLOG /* Syslogging levels */ #define SYSLG_NO 0 /* No logging */ #define SYSLG_LI 1 /* Login/out */ #define SYSLG_DI 2 /* Dialing out */ #define SYSLG_AC 3 /* Making any kind of connection */ #define SYSLG_PR 4 /* Protocol Operations */ #define SYSLG_FC 5 /* File creation */ #define SYSLG_FA 6 /* File reading */ #define SYSLG_CM 7 /* Top-level commands */ #define SYSLG_CX 8 /* All commands */ #define SYSLG_DB 9 /* Debug */ #define SYSLGMAX 9 /* Highest level */ #define SYSLG_DF SYSLG_FA /* Default level */ /* Logging function */ _PROTOTYP(VOID cksyslog,(int, int, char *, char *, char *)); #endif /* CKSYSLOG */ #ifndef CKCMAI extern int ckxlogging, ckxsyslog, ikdbopen; #endif /* CKCMAI */ #ifndef CK_KEYTAB #define CK_KEYTAB /* Keyword Table Template */ /* Note: formerly defined in ckucmd.h but now more widely used */ struct keytab { /* Keyword table */ char *kwd; /* Pointer to keyword string */ int kwval; /* Associated value */ int flgs; /* Flags (as defined above) */ }; #endif /* CK_KEYTAB */ #ifdef UNIX _PROTOTYP( int isalink, (char *)); #endif /* UNIX */ #ifdef NETPTY _PROTOTYP( int do_pty, (int *, char *, int)); _PROTOTYP( VOID end_pty, (void)); #endif /* NETPTY */ #ifdef CKROOT _PROTOTYP( int zsetroot, (char *) ); _PROTOTYP( char * zgetroot, (void) ); _PROTOTYP( int zinroot, (char *) ); #endif /* CKROOT */ /* Local Echo Buffer prototypes */ _PROTOTYP( VOID le_init, (void) ); _PROTOTYP( VOID le_clean, (void)); _PROTOTYP( int le_inbuf, (void)); _PROTOTYP( int le_putstr, (CHAR *)); _PROTOTYP( int le_puts, (CHAR *, int)); _PROTOTYP( int le_putchar, (CHAR)); _PROTOTYP( int le_getchar, (CHAR *)); /* #ifndef NOHTTP */ #ifndef NOCMDATE2TM #ifndef CMDATE2TM #ifdef OS2ORUNIX #define CMDATE2TM #endif /* OS2ORUNIX */ #ifdef VMS #define CMDATE2TM #endif /* VMS */ #endif /* CMDATE2TM */ #endif /* NOCMDATE2TM */ #ifndef NOLOCALE #ifdef BSD44ORPOSIX #ifndef NO_NL_LANGINFO #ifndef HAVE_LOCALE #define HAVE_LOCALE #include #endif /* HAVE_LOCALE */ #endif /* NO_NL_LANGINFO */ #endif /* BSD44ORPOSIX */ #endif /* NOLOCALE */ #ifdef CMDATE2TM _PROTOTYP( struct tm * cmdate2tm, (char *,int)); #endif /* CMDATE2TM */ /* #endif */ /* NOHTTP */ #ifndef NOSETTIME /* This would be set in CFLAGS */ #ifdef SVR4ORPOSIX /* Defined in IEEE 1003.1-1996 */ #ifndef UTIMEH /* and in SVID for SVR4 */ #define UTIMEH #endif /* UTIMEH */ #else /* SVR4ORPOSIX */ #ifdef OSF /* Verified by Lucas Hart */ #ifndef UTIMEH #define UTIMEH #endif /* UTIMEH */ #else /* OSF */ #ifdef SUNOS41 /* Verified by Lucas Hart */ #ifndef UTIMEH #define UTIMEH #endif /* UTIMEH */ #else /* SUNOS41 */ #ifdef OS2 #ifndef SYSUTIMEH #define SYSUTIMEH #endif /* SYSUTIMEH */ #else /* OS2 */ #ifdef VMS #ifndef UTIMEH #define UTIMEH #endif /* UTIMEH */ #endif /* VMS */ #endif /* OS2 */ #endif /* SUNOS41 */ #endif /* OSF */ #endif /* SVR4ORPOSIX */ #endif /* NOSETTIME */ #ifdef NEWFTP _PROTOTYP( int ftpisconnected, (void)); _PROTOTYP( int ftpisloggedin, (void)); _PROTOTYP( int ftpissecure, (void)); #endif /* NEWFTP */ /* -DNOTCPIP = Build with no TCP/IP support, which unexpectedly turned out not to be a major task. - fdc May 2022 */ #ifdef NOTCPIP #ifdef TCPSOCKET #undef TCPSOCKET #endif /* TCPSOCKET */ #ifndef NOFTP /* No TCP means no FTP... */ #define NOFTP #endif /* NOFTP */ #ifdef NEWFTP #undef NEWFTP #endif /* NEWFTP */ #ifdef SYSFTP #undef SYSFTP #endif /* SYSFTP */ #ifdef SFTP #undef SFTP #endif /* SFTP */ #ifdef SFTP_BUILTIN #undef SFTP_BUILTIN #endif /* SFTP_BUILTIN */ #ifdef TELNET /* No Telnet */ #undef TELNET #endif /* TELNET */ #ifdef TNCODE #undef TNCODE #endif /* TNCODE */ #ifdef TN_COMPORT /* No Telnet terminal server */ #undef TN_COMPORT #endif /* TN_COMPORT */ #ifndef NOHTTP /* no HTTP... */ #define NOHTTP #endif /* NOHTTP */ #ifndef NOBROWSER /* no Web browser... */ #define NOBROWSER #endif /* NOBROWSER */ #ifndef NORLOGIN /* no Rlogin... */ #define NORLOGIN #endif /* NORLOGIN */ #ifdef IKSD /* No Internet Kermit Server */ #undef IKSD #endif /* IKSD */ #ifdef IKSDB #undef IKSDB #endif /* IKSDB */ #ifdef IKSDCONF #undef IKSDCONF #endif /* IKSDCONF */ #ifndef NOIKSD /* Internet Kermit Service */ #define NOIKSD #endif /* NOIKSD */ #ifdef IKS_OPTION #undef IKS_OPTION #endif /* IKS_OPTION */ #ifdef CK_LOGIN #undef CK_LOGIN #endif /* CK_LOGIN */ #ifdef CKSYSLOG #undef CKSYSLOG #endif /* CKSYSLOG */ #ifndef NOWTMP #define NOWTMP #endif /* NOWTMP */ #ifdef CKWTMP #undef CKWTMP #endif /* CKWTMP */ #ifdef CK_AUTHENTICATION /* No Internet security protocols */ #undef CK_AUTHENTICATION #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION #undef CK_ENCRYPTION #endif /* CK_ENCRYPTION */ #ifdef CK_SSL #undef CK_SSL #endif /* CK_SSL */ #ifndef NOSSL #define NOSSL #endif /* NOSSL */ #ifdef CK_SNDLOC #undef CK_SNDLOC #endif /* CK_SNDLOC */ #ifdef SSHBUILTIN /* No built-in SSH client */ #undef SSHBUILTIN #endif /* SSHBUILTIN */ #ifdef SSHTEST #undef SSHTEST #endif /* SSHTEST */ #else #ifndef NETCONN #define NETCONN #endif /* NETCONN */ #endif /* NOTCPIP */ _PROTOTYP( int readpass, (char *, char *, int)); _PROTOTYP( int readtext, (char *, char *, int)); #ifdef OS2 _PROTOTYP(int ck_auth_loaddll, (VOID)); _PROTOTYP(int ck_auth_unloaddll, (VOID)); #endif /* OS2 */ #ifdef NT _PROTOTYP(DWORD ckGetLongPathname,(LPCSTR lpFileName, LPSTR lpBuffer, DWORD cchBuffer)); _PROTOTYP(DWORD ckGetShortPathName,(LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer)); #ifndef CK_HAVE_INTPTR_T /* Any windows compiler too old to support this will be 32-bits (or less) */ #ifndef _INTPTR_T_DEFINED typedef int intptr_t; #endif /* _INTPTR_T_DEFINED */ typedef unsigned long DWORD_PTR; #define CK_HAVE_INTPTR_T #endif /* CK_HAVE_INTPTR_T */ #endif /* NT */ /* * On Windows, ttyfd is frequently used to hold HANDLEs which are a kind of pointer. * So on ttyfd must be of a sufficient size to hold a pointer. */ #ifdef OS2 #ifdef CK_HAVE_INTPTR_T #ifdef NT #define CK_TTYFD_T intptr_t #else /* NT */ #define CK_TTYFD_T int #endif /* NT */ #else /* CK_HAVE_INTPTR_T */ #define CK_TTYFD_T int #endif /* CK_HAVE_INTPTR_T */ #else /* OS2 */ /* Not on Windows or OS/2? its just an int */ #define CK_TTYFD_T int #endif /* OS2 */ #include "ckclib.h" #ifdef COMMENT /* This was a first attempt to prototypes for over 400 functions that never had them before, which are needed now since compilers like Clang complains about every single function that does not have prototype, and claims this will be a fatal error in a forthcoming release. The new prototypes are in the new header file ckcfnp.h: 436 of them to start. But the prototypes need to know about typedefs that haven't been made yet, since ckcdeb.h is #included before the other headers where that happened. I thought maybe I could include them here, but it was a rabbit hole. The only way to insure the prototypes work without messing everything else up is to put "#include ckcfnp.h" in every single Kermit module AFTER what was the last #include. - fdc, 23 March 2023 */ #ifndef NOANSI #ifdef __STDC__ #ifdef CK_ANSIC /* New C-Kermit 10.0 Beta.09 */ #include "ckucmd.h" /* For typedefs */ #include "ckcnet.h" /* For typedefs */ #include "ckuath.h" /* For typedefs */ #include "ckucmd.h" /* For typedefs */ #include "ckcker.h" /* For typedefs */ #include "ckuusr.h" /* For typedefs */ #include "ckctel.h" /* For typedefs */ #include "ckcfnp.h" /* Prototypes for all functions */ /* ckcsig.h */ /* ckusig.h */ #endif /* CK_ANSIC */ #endif /* __STDC__ */ #endif /* NOANSI */ #endif /* COMMENT */ /* End of ckcdeb.h */ #endif /* CKCDEB_H */ ckcfn2.c000664 045065 024037 00000311537 14767401626 012524 0ustar00fdckermit000000 000000 /* C K C F N 2 -- System-independent Kermit protocol support functions... */ /* ...Part 2 (continued from ckcfns.c) */ /* Author: Frank da Cruz , Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Update: Fri Sep 23 15:23:24 2022 CR -> CK_CR Update: Sat Apr 15 13:16:31 2023 ANSI function declarations and prototypes */ /* Note -- if you change this file, please amend the version number and date at the top of ckcfns.c accordingly. */ #include "ckcsym.h" /* Compilation options */ #include "ckcdeb.h" /* Debugging and other symbols */ #include "ckcasc.h" /* ASCII symbols */ #include "ckcker.h" /* Kermit symbols */ #include "ckcxla.h" /* Translation */ #include "ckcnet.h" /* IKS and VMS #define TCPSOCKET */ #include "ckucmd.h" /* xx_strp */ #include "ckuusr.h" /* mtab */ #include "ckcfnp.h" /* Prototypes */ #ifdef TCPSOCKET /* For TELNET business in spack() */ extern int tn_nlm, ttnproto, tn_b_nlm; #endif /* TCPSOCKET */ extern int parity, network, local, interrupted, fatalio, wasclosed; int kstartactive = 0; /* Flag for kstart() in a packet */ static CHAR p_tbl[] = { /* Even parity table for dopar(). */ (CHAR) '\000', /* ANSI C casts '\ooo' constants */ (CHAR) '\201', /* to signed char, so we have to */ (CHAR) '\202', /* cast back to unsigned char... */ (CHAR) '\003', (CHAR) '\204', (CHAR) '\005', (CHAR) '\006', (CHAR) '\207', (CHAR) '\210', (CHAR) '\011', (CHAR) '\012', (CHAR) '\213', (CHAR) '\014', (CHAR) '\215', (CHAR) '\216', (CHAR) '\017', (CHAR) '\220', (CHAR) '\021', (CHAR) '\022', (CHAR) '\223', (CHAR) '\024', (CHAR) '\225', (CHAR) '\226', (CHAR) '\027', (CHAR) '\030', (CHAR) '\231', (CHAR) '\232', (CHAR) '\033', (CHAR) '\234', (CHAR) '\035', (CHAR) '\036', (CHAR) '\237', (CHAR) '\240', (CHAR) '\041', (CHAR) '\042', (CHAR) '\243', (CHAR) '\044', (CHAR) '\245', (CHAR) '\246', (CHAR) '\047', (CHAR) '\050', (CHAR) '\251', (CHAR) '\252', (CHAR) '\053', (CHAR) '\254', (CHAR) '\055', (CHAR) '\056', (CHAR) '\257', (CHAR) '\060', (CHAR) '\261', (CHAR) '\262', (CHAR) '\063', (CHAR) '\264', (CHAR) '\065', (CHAR) '\066', (CHAR) '\267', (CHAR) '\270', (CHAR) '\071', (CHAR) '\072', (CHAR) '\273', (CHAR) '\074', (CHAR) '\275', (CHAR) '\276', (CHAR) '\077', (CHAR) '\300', (CHAR) '\101', (CHAR) '\102', (CHAR) '\303', (CHAR) '\104', (CHAR) '\305', (CHAR) '\306', (CHAR) '\107', (CHAR) '\110', (CHAR) '\311', (CHAR) '\312', (CHAR) '\113', (CHAR) '\314', (CHAR) '\115', (CHAR) '\116', (CHAR) '\317', (CHAR) '\120', (CHAR) '\321', (CHAR) '\322', (CHAR) '\123', (CHAR) '\324', (CHAR) '\125', (CHAR) '\126', (CHAR) '\327', (CHAR) '\330', (CHAR) '\131', (CHAR) '\132', (CHAR) '\333', (CHAR) '\134', (CHAR) '\335', (CHAR) '\336', (CHAR) '\137', (CHAR) '\140', (CHAR) '\341', (CHAR) '\342', (CHAR) '\143', (CHAR) '\344', (CHAR) '\145', (CHAR) '\146', (CHAR) '\347', (CHAR) '\350', (CHAR) '\151', (CHAR) '\152', (CHAR) '\353', (CHAR) '\154', (CHAR) '\355', (CHAR) '\356', (CHAR) '\157', (CHAR) '\360', (CHAR) '\161', (CHAR) '\162', (CHAR) '\363', (CHAR) '\164', (CHAR) '\365', (CHAR) '\366', (CHAR) '\167', (CHAR) '\170', (CHAR) '\371', (CHAR) '\372', (CHAR) '\173', (CHAR) '\374', (CHAR) '\175', (CHAR) '\176', (CHAR) '\377' }; /* D O P A R -- Add an appropriate parity bit to a character */ CHAR #ifdef CK_ANSIC dopar(register CHAR ch) #else dopar(ch) register CHAR ch; #endif /* CK_ANSIC */ { register unsigned int a; if (!parity #ifdef TCPSOCKET || (network && (ttnproto == NP_TELNET) && (TELOPT_ME(TELOPT_BINARY))) #ifndef NOXFER || (!local && sstelnet) /* TELNET BINARY MODE */ #endif /* NOXFER */ #endif /* TCPSOCKET */ ) return((CHAR) (ch & 255)); else a = ch & 127; switch (parity) { case 'e': return(p_tbl[a]); /* Even */ case 'm': return((CHAR) (a | 128)); /* Mark */ case 'o': return((CHAR) (p_tbl[a] ^ 128)); /* Odd */ case 's': return((CHAR) a); /* Space */ default: return((CHAR) a); /* Something illegal */ } } #ifndef NOXFER /* Rest of this file... */ #define NEWDPL /* New dynamic packet length method */ #ifdef VMS extern int batch; #else extern int backgrd; #endif /* VMS */ #ifdef DYNAMIC extern struct pktinfo *s_pkt; /* array of pktinfo structures */ extern struct pktinfo *r_pkt; /* array of pktinfo structures */ #else extern struct pktinfo s_pkt[]; /* array of pktinfo structures */ extern struct pktinfo r_pkt[]; /* array of pktinfo structures */ #endif /* DYNAMIC */ extern int sseqtbl[], rseqtbl[], sbufuse[], sacktbl[], wslots, winlo, wslotn, sbufnum, rbufnum, pktpaus, reliable; #ifdef STREAMING static int dontsend = 0; extern int streaming; #endif /* STREAMING */ extern int ttprty; /* from ck*tio.c */ extern int autopar; extern int spsiz, spmax, rpsiz, timint, timef, npad, bestlen, maxsend; extern int rpt, rptq, rptflg, capas, spsizf, en_fin, tsecs, flow; extern int pktnum, sndtyp, rcvtyp, bctr, bctu, bctf, bctl, rsn, rln, maxtry; extern int size, osize, maxsize, spktl, rpktl, nfils, stdouf, fsecs; extern int turn, turnch, displa, pktlog, seslog, xflg, mypadn; extern int hcflg, server, cxseen, czseen, discard, slostart; extern int nakstate, quiet, success, xitsta, what, filestatus; extern int spackets, rpackets, timeouts, retrans, crunched, urpsiz; extern int carrier, fdispla, srvidl; #ifdef GFTIMER extern CKFLOAT fptsecs, fpfsecs, fpxfsecs; #endif /* GFTIMER */ extern long filcnt, filrej, speed, filcps, tfcps; extern CK_OFF_T ffc, flci, flco, tlci, tlco, tfc; extern char *cmarg, filnam[]; extern CHAR padch, mypadc, eol, seol, ctlq, sstate; extern CHAR *recpkt, *data, myinit[]; extern CHAR *srvptr, stchr, mystch, *rdatap; extern CHAR padbuf[]; extern CHAR * epktmsg; extern int epktrcvd, epktsent; #ifdef OS2 /* AUTODOWNLOAD parameters */ extern int adl_kmode, adl_zmode; /* Match Packet to signal download */ extern char * adl_kstr; /* KERMIT Download String */ extern char * adl_zstr; /* ZMODEM Download String */ #endif /* OS2 */ #ifdef CK_AUTODL CHAR ksbuf[96] = { NUL, NUL }; /* Autodownload "Kermit Start" buf */ #endif /* CK_AUTODL */ int numerrs = 0; /* Number of packet errors so far */ int rcvtimo = 0; /* Timeout for receiving a packet */ int idletmo = 0; /* Flag for idle timeout */ long filcps = 0L; /* CPS most recent file transferred */ long tfcps = 0L; /* CPS most recent transaction */ long xfsecs = 0L; /* Elapsed time for most recent file */ #ifdef GFTIMER CKFLOAT fpxfsecs = 0.0; /* Ditto, but floating point */ #endif /* GFTIMER */ #ifdef CK_TIMERS int rrttbl[64], srttbl[64]; /* Packet timestamp tables */ extern int rttflg; #define RTT_SCALE 1000 long rttsamples, /* Round trip time samples */ rttdelay, /* RTT delay */ pktintvl, /* Interpacket arrival time */ rttvariance, /* RTT variance */ rttstddev; /* RTT standard deviation */ #endif /* CK_TIMERS */ /* CRC generation tables */ long crcta[16] = { 0L, 010201L, 020402L, 030603L, 041004L, 051205L, 061406L, 071607L, 0102010L, 0112211L, 0122412L, 0132613L, 0143014L, 0153215L, 0163416L, 0173617L }; long crctb[16] = { 0L, 010611L, 021422L, 031233L, 043044L, 053655L, 062466L, 072277L, 0106110L, 0116701L, 0127532L, 0137323L, 0145154L, 0155745L, 0164576L, 0174367L }; #ifdef CK_TIMERS /* Round-trip timer calculations adapted from Tim Kientzle's article, "Improving Kermit Performance", Dr Dobb's Journal, February 1996. */ /* R T T I N I T -- Initialize timers at start of transaction */ VOID rttinit() { /* Initialize round-trip timing */ int i; if (timint == 0) return; rttsamples = 0L; /* Samples (packets) */ rttvariance = 0L; /* Variance in delay */ rttdelay = (long) timint * RTT_SCALE; /* Delay */ pktintvl = (long) timint * RTT_SCALE; /* Delay */ rttstddev = (long) timint * RTT_SCALE; /* Standard deviation of delay */ /* Tables of timestamps indexed by packet sequence number */ for (i = 0; i < 64; i++) { rrttbl[i] = -1; /* Time each packet was received */ srttbl[i] = -1; /* Time each packet was sent */ } rcvtimo = timint; /* Initial timeout is what user said */ } /* G E T R T T -- Get packet round trip time */ /* Call with nakstate == 0 if file sender, nonzero if receiver, and n == packet sequence number of the packet we just received. Returns: -1 on failure with rcvtimo set to timint (what the user said), or: 0 on success with rcvtimo set to dynamically calculated value: 1 <= rcvtimo <= timint * 3. */ int #ifdef CK_ANSIC getrtt( int nakstate, int n ) #else getrtt(nakstate, n) int nakstate, n; #endif /* CK_ANSIC */ { extern int mintime, maxtime; static int prevz = 0, prevr = 0; int x, y, yy, z = 0, zz = 0; /* How long did it take to get here? */ rcvtimo = timint; /* Default timeout is what user said */ if (timint == 0) /* We're not timing out. */ return(0); if (!rttflg) /* Not supposed to be doing this? */ return(-1); /* So don't */ if (!RTT_SCALE) /* Paranoia... */ return(-1); /* rtimer() (reset timer) is not called until 1st data packet */ #ifdef GFTIMER /* rftimer(); */ #endif /* GFTIMER */ /* S (F [ A ] D* Z)* B */ /* NOTE: we calculate both the round-trip time AND the packet */ /* arrival rate. We don't use the RTT for anything, we just display it. */ /* Timeouts are based on the packet arrival rate. */ if (spackets > 3) { /* Don't start till 4th packet */ if (nakstate) { /* File receiver */ x = rrttbl[n]; /* Time when I got packet n */ y = rrttbl[n > 0 ? n - 1 : 63]; /* Time when I got packet n-1 */ yy = srttbl[n > 0 ? n - 1 : 63]; /* Time when I sent ACK(n-1) */ if (x > -1 && y > -1) { /* Be careful */ z = x - y; /* Packet rate */ zz = x - yy; /* Round trip time */ z++; /* So sender & receiver differ */ debug(F101,"RTT RECV","",z); } else { /* This shouldn't happen */ debug(F101,"RTT RECV ERROR spackets","",spackets); debug(F101,"RTT RECV ERROR sequence","",n); return(-1); } } else { /* File sender */ x = rrttbl[n]; /* Time when I got ACK(n) */ y = rrttbl[n > 0 ? n - 1 : 63]; /* Time when I got packet n-1 */ yy = srttbl[n]; /* Time when I sent n */ if (x > -1 && y > -1) { z = x - y; /* Packet rate */ zz = x - yy; /* Round trip time */ debug(F101,"RTT SEND","",z); } else { debug(F100,"RTT SEND ERROR","",0); return(-1); } } if (z < 1) /* For fast connections */ z = RTT_SCALE / 2; /* Convert to scale... */ else z *= RTT_SCALE; debug(F101,"RTT z scaled","",z); if (zz < 1) /* For fast connections */ zz = RTT_SCALE / 2; /* Convert to scale... */ else zz *= RTT_SCALE; rttdelay = zz; /* Round trip time of this packet */ #ifdef COMMENT /* This was used in C-Kermit 7.0 (and 6.0?) but not only is it overkill, it also can produce ridiculously long timeouts under certain conditions. Replaced in 8.0 by a far simpler and more aggressive strategy. */ if (rttsamples++ == 0L) { /* First sample */ pktintvl = z; } else { /* Subsequent samples */ long oldavg = pktintvl; long rttdiffsq; if (rttsamples > 30) /* Use real average for first 30 */ rttsamples = 30; /* then decaying average. */ /* Average delay, difference squared, variance, std deviation */ pktintvl += (z - pktintvl) / rttsamples; rttdiffsq = (z - oldavg) * (z - oldavg); rttvariance += (rttdiffsq - rttvariance) / rttsamples; debug(F101,"RTT stddev1","",rttstddev); if (rttstddev < 1L) /* It can be zero, in which case */ rttstddev = RTT_SCALE / 3; /* set it to something small... */ rttstddev = (rttstddev + rttvariance / rttstddev) / 2; } debug(F101,"RTT stddev2","",rttstddev); debug(F101,"RTT delay ","",pktintvl); rcvtimo = (pktintvl + (3L * rttstddev)) / RTT_SCALE + 1; if (rpackets < 32) /* Allow for slow start */ rcvtimo += rcvtimo + 2; else if (rpackets < 64) rcvtimo += rcvtimo / 2 + 1; /* On a reliable link, don't try too hard to time out. */ /* Especially on fast local network connections. */ if (server && what == W_NOTHING) /* Server command wait */ rcvtimo = rcvtimo; /* == srvtim */ else if (reliable == SET_ON && rcvtimo > 0) /* Reliable */ rcvtimo = rcvtimo +15; /* and not server command wait */ else /* Not reliable or server cmd wait */ rcvtimo = rcvtimo; if (rcvtimo < mintime) /* Lower bound */ rcvtimo = mintime; if (maxtime > 0) { /* User specified an upper bound */ if (rcvtimo > maxtime) rcvtimo = maxtime; } else if (maxtime == 0) { /* User didn't specify */ if (rcvtimo > timint * 6) rcvtimo = timint * 6; } #else /* COMMENT */ #ifdef CKFLOAT { CKFLOAT x; x = (CKFLOAT)(prevz + z + z) / 3.0; rcvtimo = (int)((((CKFLOAT)x * 2.66) / RTT_SCALE) + 0.5); debug(F101,"RTT rcvtimo (float)","",rcvtimo); } #else rcvtimo = (prevz + z + z) / RTT_SCALE; debug(F101,"RTT rcvtimo (int)","",rcvtimo); #endif /* CKFLOAT */ #endif /* COMMENT */ zz = (rttdelay + 500) / 1000; if (rcvtimo > (zz * 3)) rcvtimo = zz * 3; if (rcvtimo < 1) rcvtimo = 1; if (mintime > 0) { if (rcvtimo < mintime) /* Lower bound */ rcvtimo = mintime; } if (maxtime > 0) { /* Upper bound */ if (rcvtimo > maxtime) rcvtimo = maxtime; } if (rcvtimo == (prevr - 1)) rcvtimo++; debug(F101,"RTT final rcvtimo","",rcvtimo); } prevz = z; prevr = rcvtimo; return(0); } #endif /* CK_TIMERS */ /* I N P U T -- Attempt to read packet number 'pktnum'. */ /* This is the function that feeds input to Kermit's finite state machine, in the form of a character in the range 32-126, normally a packet type (uppercase letter) or pseudo-packet-type (lowercase letter). If a special start state is in effect, that state is returned as if it were the type of an incoming packet. */ int input() { int type = 0, acktype; /* Received packet type */ int x, y, k; /* Workers */ int z, pi, nf; /* Worker, packet index, NAK flag */ int nak2ack = 0; debug(F000,"input sstate","",sstate); debug(F101,"input nakstate","",nakstate); debug(F000,"input sndtyp","",sndtyp); debug(F101,"input xitsta","",xitsta); debug(F101,"input what","",what); while (1) { /* Big loop... */ /* It is ttchk()'s responsibility to tell us if the connection is broken, and to do so instantly and nondestructively -- no blocking, etc, that would slow down file transfer. */ if (ttchk() < 0) { debug(F100,"input CONNECTION BROKEN","",0); fatalio = 1; return('q'); } if (sstate != 0) { /* If a start state is in effect, */ type = sstate; /* return it like a packet type, */ sstate = 0; /* and then nullify it. */ numerrs = 0; /* (PWP) no errors so far */ return(type); } if (nakstate) { /* This section for file receiver. */ if (wslots > 1) { /* If we're doing windows, */ x = rseqtbl[winlo]; /* see if desired packet already in. */ debug(F101,"input winlo","",winlo); debug(F101,"input rseqtbl[winlo]","",rseqtbl[winlo]); if (x > -1) { /* Already there? */ if (r_pkt[x].pk_seq == winlo) { /* (double check) */ rsn = winlo; /* Yes, return its info */ debug(F101,"input return pre-stashed packet","",rsn); dumprbuf(); rdatap = r_pkt[x].pk_adr; /* like rpack would do. */ rln = (int)strlen((char *) rdatap); type = r_pkt[x].pk_typ; break; } } } type = rpack(); /* Try to read a packet. */ debug(F101,"input rpack","",type); while (type == 'e') { /* Handle echoes */ debug(F101,"input echo discarded","",type); type = rpack(); } #ifdef DEBUG if (deblog) { if (type == 'D') debug(F011,"input type D=",(char *)rdatap,39); else debug(F000,"input type",(char *)rdatap,type); } #endif /* DEBUG */ #ifndef OLDCHKINT if (type == 'z') { epktrcvd = 1; errpkt((CHAR *)"User cancelled."); type = 'E'; break; } #endif /* OLDCHKINT */ if (type < -1) { char * s; s = (type == -2) ? "FAILED - Interrupted" : "FAILED - Connection lost"; xxscreen(SCR_PT,'q',0L,s); dologend(); return('q'); /* Ctrl-C or connection lost */ } if (type < 0) { /* Receive window full */ /* Another thing to do here would be to delete */ /* the highest packet and NAK winlo. But that */ /* shouldn't be necessary since the other Kermit */ /* should not have sent a packet outside the window. */ #ifdef COMMENT char foo[256]; ckmakxmsg(foo,256,"Receive window full (rpack): wslots=", ckitoa(wslots)," winlo=",ckitoa(winlo)," pktnum=", ckitoa(pktnum), NULL,NULL,NULL,NULL,NULL,NULL); errpkt((CHAR *)foo); debug(F100,foo,"",0); #else errpkt((CHAR *)"Receive window full"); debug(F101,"rpack receive window full","",0); debug(F101," wslots","",wslots); debug(F101," winlo","",winlo); debug(F101," pktnum","",pktnum); #endif dumprbuf(); type = 'E'; break; } dumprbuf(); #ifdef OLDCHKINT if (chkint() < 0) { /* Check for console interrupts. */ errpkt((CHAR *)"User cancelled."); /* (old way) */ type = 'E'; break; } #endif /* OLDCHKINT */ #ifdef STREAMING if (streaming) { /* Streaming */ if (type == 'Q' || type == 'T') { /* Errors are fatal. */ crunched++; /* For statistics */ errpkt((CHAR *)"Transmission error on reliable link."); type = 'E'; } } #endif /* STREAMING */ if (type == 'E') { debug(F101,"input got E, nakstate","",nakstate); break; /* Error packet */ } if (type == 'Q') { /* Crunched packet. */ crunched++; numerrs++; /* Packet arrived damaged. It was most likely the packet we were expecting next, so we send a NAK for that packet. Prior to 5A(189), we always NAK'd winlo here, but that was bad because if two (or more) different packets were damaged, we would keep NAKing the first one and never NAK the other ones, which could result in a lengthy series of timeouts. Now we NAK the oldest as-yet-unNAK'd missing packet. */ #ifdef CK_TIMERS rcvtimo++; /* Stretch the timeout a little */ #endif /* CK_TIMERS */ z = (winlo + wslots) % 64; /* Search from winlo to z */ debug(F101,"ZZZ crunched z","",z); nf = 0; /* NAK flag not set yet */ for (x = winlo; x != z; x = (x + 1) % 64) { debug(F101,"ZZZ x","",x); if (rseqtbl[x] > -1) /* Have I received packet x? */ continue; /* Yes, go on. */ debug(F101,"ZZZ x not recd yet","",x); pi = sseqtbl[x]; /* No, have I NAK'd it yet? */ if (pi < 0 || s_pkt[pi].pk_rtr == 0) { debug(F101,"ZZZ x not NAK'd yet","",x); nack(x); /* No, NAK it now. */ nf = 1; /* Flag that I did. */ break; } } if (!nf) { /* If we didn't NAK anything above, */ debug(F101,"ZZZ NAKing winlo","",winlo); if (nack(winlo) < 0) { /* we have to NAK winlo (again) */ errpkt((CHAR *)"Too many retries."); /* Too many */ type = 'E'; break; } } continue; } if (type == 'T') { /* Timeout */ #ifndef OS2 /* K95 does this its own way */ if (server && srvidl) { idletmo = 1; debug(F101,"SERVER IDLE TIMEOUT","",srvidl); return('q'); } #endif /* OS2 */ #ifdef CK_TIMERS rcvtimo++; /* Stretch the timeout a little */ #endif /* CK_TIMERS */ timeouts++; debug(F101,"input receive-state timeout, winlo","",winlo); /* NAK only the packet at window-low */ debug(F101,"input sending NAK for winlo","",winlo); x = ttchk(); if (x > 0) /* Don't give up if there is still */ continue; /* something to read. */ else if (x < 0) { dologend(); fatalio = 1; return('q'); /* Connection Lost */ } if (nack(winlo) < 0) { debug(F101,"input sent too many naks","",winlo); errpkt((CHAR *)"Too many retries."); type = 'E'; break; } else continue; } if (rsn == winlo) { /* Got the packet we want, done. */ #ifdef CK_TIMERS if (rttflg && timint) /* Dynamic round trip timers? */ getrtt(nakstate, rsn); /* yes, do it. */ else /* JHD 20100208 */ rcvtimo = timint; /* JHD 20100208 */ #endif /* CK_TIMERS */ debug(F101,"input rsn=winlo","",rsn); break; } /* Got a packet out of order. */ debug(F101,"input out of sequence, rsn","",rsn); k = rseqtbl[rsn]; /* Get window slot of this packet. */ debug(F101,"input rseqtbl[rsn]","",k); if (k < 0) { debug(F101,"input recv can't find index for rcvd pkt","",rsn); /* Was "Internal error 21" */ /* This should not happen */ errpkt((CHAR *)"Sliding windows protocol error."); type = 'E'; break; } y = chkwin(rsn,winlo,wslots); /* See what window it's in. */ debug(F101,"input recv chkwin","",y); if (y == 1) { /* From previous window. */ #ifdef STREAMING if (!streaming) /* NO RESEND IF STREAMING! */ #endif /* STREAMING */ resend(rsn); /* Resend the ACK (might have data) */ freerpkt(rsn); /* Get rid of received packet */ continue; /* Back to wait for another packet */ } else { /* In this window or out of range */ if (y < 0) /* If out of range entirely, */ freerpkt(rsn); /* release its buffer */ #ifdef STREAMING if (streaming) { /* Streaming (this shouldn't happen) */ errpkt((CHAR *)"Sequence error on reliable link."); type = 'E'; break; } #endif /* STREAMING */ /* If our receive window is full, NAK window-low */ if (rbufnum < 1) { /* Receive window full? */ if (nack(winlo) < 0) { /* No choice, must NAK winlo. */ errpkt((CHAR *)"Too many retries."); /* Too many */ type = 'E'; break; } else continue; } /* Receive window not full. This is a packet in the current window but it is not the desired packet at winlo. So therefore there are gaps before this packet. So we find the "lowest" unNAK'd missing packet, if any, between winlo and this one, and NAK it. If there are no as-yet-unNAK'd missing packets in the window, then we send nothing and go wait for another packet. In theory, this could result in a timeout, but in practice it is likely that the already-NAK'd missing packets are already on their way. Note, we do not NAK ahead of ourselves, as that only creates unnecessary retransmissions. */ for (x = winlo; x != rsn; x = (x + 1) % 64) { if (rseqtbl[x] > -1) /* Have I received packet x? */ continue; /* Yes, check next sequence number. */ pi = sseqtbl[x]; /* No, have I NAK'd it yet? */ if (pi < 0 || s_pkt[pi].pk_rtr == 0) { nack(x); /* No, NAK it now. */ break; } } } /*!!!*/ } else { /* Otherwise file sender... */ #ifdef STREAMING if (streaming && sndtyp == 'D') { debug(F101,"STREAMING input streaming","",streaming); debug(F000,"STREAMING input sndtyp","",sndtyp); rsn = winlo; type = 'Y'; /* Pretend we got an ACK */ } #endif /* STREAMING */ if (!nak2ack) { /* NAK(n+1) = ACK(n) */ if (wslots > 1) { /* Packet at winlo already ACK'd? */ if (sacktbl[winlo]) { /* If so, */ sacktbl[winlo] = 0; /* Turn off the ACK'd flag */ winlo = (winlo + 1) % 64; /* Rotate the window */ type = 'Y'; /* And return ACK */ debug(F101, "input send returning pre-stashed ACK","", winlo-1); break; } } #ifdef STREAMING if (!(streaming && sndtyp == 'D')) { /* Not streaming | data */ type = rpack(); /* Try to read an acknowledgement */ } else { /* Streaming and in Data phase */ type = 'Y'; /* Assume all is normal */ if (chkint() < 0) /* Check for console interrupts. */ type = 'z'; else if (ttchk() > 4 + bctu) /* Check for return traffic */ type = rpack(); debug(F000,"input streaming type","",type); } #endif /* STREAMING */ debug(F111,"input send",(char *) rdatap,(int) type); while (type == 'e') { /* Handle echoes */ debug(F000,"echo discarded","",type); type = rpack(); } #ifndef OLDCHKINT if (type == 'z') { epktrcvd = 1; errpkt((CHAR *)"User cancelled."); type = 'E'; break; } #endif /* OLDCHKINT */ if (type < -1) { xxscreen(SCR_PT,'q',0L, ((char *)((type == -2) ? "Interrupted" : "Connection lost")) ); if (type != -2) dologend(); return('q'); /* Ctrl-C or connection lost */ } if (type == -1) { #ifdef COMMENT char foo[256]; ckmakxmsg(foo,256, "Receive window full (error 18): wslots=", ckitoa(wslots), " winlo=",ckitoa(winlo)," pktnum=", ckitoa(pktnum), NULL,NULL,NULL,NULL,NULL,NULL); errpkt((CHAR *)foo); debug(F100,foo,"",0); #else errpkt((CHAR *)"Receive window full"); /* was "internal */ debug(F101," wslots","",wslots); /* error 18" */ debug(F101," winlo","",winlo); debug(F101," pktnum","",pktnum); #endif /* COMMENT */ dumprbuf(); type = 'E'; break; } dumprbuf(); /* Debugging */ #ifdef OLDCHKINT if (chkint() < 0) { /* Check for console interrupts. */ errpkt((CHAR *)"User cancelled."); return(type = 'E'); } #endif /* OLDCHKINT */ /* Got a packet */ #ifdef STREAMING if (streaming) { /* Streaming */ if (type == 'Q' || type == 'T') { /* Errors are fatal. */ crunched++; /* For statistics */ errpkt((CHAR *)"Transmission error on reliable link."); type = 'E'; } } #endif /* STREAMING */ if (type == 'E') { debug(F101,"input send got E, nakstate","",nakstate); break; /* Error packet */ } if (type == 'Q') { /* Crunched packet */ crunched++; /* For statistics */ numerrs++; /* For packet resizing */ x = resend(winlo); /* Resend window-low */ if (x < 0) { type = 'E'; errpkt((CHAR *)"Too many retries"); break; } continue; } if (type == 'T') { /* Timeout waiting for ACKs. */ timeouts++; /* Count it */ numerrs++; /* Count an error too */ debug(F101,"input send state timeout, winlo","",winlo); /* Retransmit the oldest un-ACK'd packet. */ debug(F101,"input send resending winlo","",winlo); if (resend(winlo) < 0) { /* Check retries */ debug(F101,"input send too many resends","",maxtry); errpkt((CHAR *)"Too many retries"); return(type = 'E'); } #ifdef NEWDPL /* Reduce prevailing packet length */ x = sseqtbl[winlo]; /* Get length of packet we want ACKd */ if (x > -1) { /* Only if we have a valid index */ if (s_pkt[x].pk_typ == 'D') { /* only for D packets */ spsiz = (s_pkt[x].pk_len + 8) >> 1; /* halve it */ if (spsiz < 20) spsiz = 20; /* within reason */ debug(F101,"input T cut packet length","",spsiz); } } #endif /* NEWDPL */ continue; } } /* Got an actual normal packet */ nak2ack = 0; /* Unset this flag. */ y = chkwin(rsn,winlo,wslots); /* Is it in the window? */ debug(F101,"input send rsn","",rsn); debug(F101,"input send winlo","",winlo); debug(F101,"input send chkwin","",y); if (type == 'Y') { /* Got an ACK */ if (y == 0) { /* In current window */ if (spackets < 4) /* Error counter doesn't count */ numerrs = 0; /* until data phase. */ sacktbl[rsn]++; /* Mark the packet as ACK'd */ x = sseqtbl[rsn]; /* Get ACK'd packet's buffer index */ debug(F101,"bestlen ack x","",x); #ifdef NEWDPL if (x > -1) { acktype = s_pkt[x].pk_typ; /* Get type */ debug(F000,"bestlen ack type","",acktype); if (acktype == 'D') { /* Adjust data packet length */ if (spsiz > bestlen) { bestlen = spsiz; debug(F101,"bestlen B","",bestlen); } #ifdef DEBUG if (deblog) { debug(F101,"bestlen retry","",s_pkt[x].pk_rtr); debug(F101,"bestlen len","",s_pkt[x].pk_len); debug(F101,"bestlen spackets","",spackets); } #endif /* DEBUG */ /* Set new best length */ if (s_pkt[x].pk_rtr == 0 && s_pkt[x].pk_len + 8 > bestlen) { bestlen = s_pkt[x].pk_len + 8; if (bestlen > spmax) bestlen = spmax; debug(F101,"bestlen A","",bestlen); } #ifdef DEBUG if (deblog) { debug(F101,"bestlen wslots","",wslots); debug(F101,"bestlen maxsend","",maxsend); } #endif /* DEBUG */ /* Slow start */ if (slostart && (maxsend <= spmax) && (rpackets < 11) && (numerrs == 0)) { spsiz = spsiz << 1; debug(F101,"bestlen spsiz A","",spsiz); /* Creep up to best length */ } else if ((spackets > 5) && (spsiz < bestlen - 8)) { spsiz += (bestlen - spsiz) / 3; debug(F101,"bestlen spsiz B","",spsiz); /* Push the envelope */ } else if ((spackets % (wslots + 1) == 0) && (spackets > 6) && (bestlen < spmax - 8) && (spsiz < spmax)) { spsiz += (spmax - bestlen) / 3; debug(F101,"bestlen spsiz C","",spsiz); } /* But not too far */ if (spsiz > spmax) { spsiz = spmax; debug(F101,"bestlen spsiz D","",spsiz); } } } #endif /* NEWDPL */ #ifdef CK_TIMERS if (rttflg && timint) /* If doing dynamic timers */ getrtt(nakstate, rsn); /* call routine to set it. */ else /* JHD 20100208 */ rcvtimo = timint; /* JHD 20100208 */ #endif /* CK_TIMERS */ /* NOTE: The following statement frees the buffer of the ACK we just got. But the upper layers still need the data, like if it's the ACK to an I, S, F, D, Z, or just about any kind of packet. So for now, freerbuf() deallocates the buffer, but does not erase the data or destroy the pointer to it. There's no other single place where these receive buffers can be correctly freed (?) ... */ freerpkt(rsn); /* Free the ACK's buffer */ freesbuf(rsn); /* *** Free the sent packet's buffer */ if (rsn == winlo) { /* Got the one we want */ sacktbl[winlo] = 0; winlo = (winlo + 1) % 64; debug(F101,"input send rotated send window","",winlo); break; /* Return the ACK */ } else { debug(F101,"input send mark pkt","",rsn); continue; /* Otherwise go read another packet */ } } else if (y == 1 && wslots < 2) { /* (190) ACK for previous */ numerrs++; /* == NAK for current, count error */ debug(F101,"input send ACK for previous","",rsn); freerpkt(rsn); /* Free NAK's buffer */ x = resend(winlo); /* Resend current packet */ if (x < 0) { type = 'E'; errpkt((CHAR *)"Too many retries"); break; } else continue; /* Resend ok, go read another packet */ } else { /* Other cases, just ignore */ debug(F101,"input send ACK out of window","",rsn); freerpkt(rsn); continue; } } if (type == 'N') { /* NAK */ numerrs++; /* Count an error */ #ifdef STREAMING if (streaming) { /* Streaming */ errpkt((CHAR *)"NAK received on reliable link."); type = 'E'; break; } #endif /* STREAMING */ debug(F101,"input send NAK","",rsn); #ifdef NEWDPL /* Reduce prevailing packet length */ x = sseqtbl[rsn]; /* Length of packet that was NAK'd */ if (x > -1) { /* If it's a Data packet we've sent */ if (s_pkt[x].pk_typ == 'D') { spsiz = (s_pkt[x].pk_len + 8) >> 1; /* Halve length */ #ifdef COMMENT /* This might be a good idea -- haven't tried it ... */ if (bestlen > 0 && spsiz > bestlen) spsiz = bestlen; #endif /* COMMENT */ if (spsiz < 20) spsiz = 20; debug(F101,"input N cut packet length","",spsiz); } } #endif /* NEWDPL */ freerpkt(rsn); /* Free buffer where NAK lies. */ if (y == 0) { /* In current window */ debug(F100," in window","",0); k = sseqtbl[rsn]; /* Get pointer to NAK'd packet. */ if (k < 0 || (k > -1 && s_pkt[k].pk_typ == ' ')) { x = resend(winlo); /* Packet we haven't sent yet. */ } else { x = resend(rsn); /* Resend requested packet. */ } if (x < 0) { /* Resend error is fatal. */ type = 'E'; errpkt((CHAR *)"Too many retries"); break; } else continue; /* Resend ok, go read another packet */ } else if (rsn == ((pktnum + 1) % 64)) { /* NAK for next pkt */ if (wslots > 1) { debug( F101,"NAK for next packet, windowing","",rsn); x = resend(winlo); /* Resend window-low */ if (x < 0) { type = 'E'; errpkt((CHAR *)"Too many retries"); break; } continue; /* Go back and read another pkt */ } debug(F101,"NAK for next packet, no windowing","",rsn); x = (rsn == 0) ? 63 : rsn - 1; if (x == 0 && (sndtyp == 'S' || sndtyp == 'I')) { resend(0); /* ACK for S or I packet missing */ continue; /* so resend the S or I */ } rsn = x; /* Else, treat NAK(n+1) as ACK(n) */ nak2ack = 1; /* Go back and process the ACK */ continue; } else if (y > 0) { /* NAK for pkt we can't resend */ debug(F101," NAK out of window","",rsn); /* bad... */ type = 'E'; errpkt((CHAR *)"NAK out of window"); break; } else continue; /* Ignore other NAKs */ } /* End of file-sender NAK handler */ if (rsn == winlo) { /* Not ACK, NAK, timeout, etc. */ /* BEGIN NEW 6 August 2023 */ if (type == 'V') /* END NEW 6 August 2023 */ debug(F000,"input send unexpected type","",type); break; } } /* End of file-sender section */ } /* End of input() while() loop */ /* When the window size is 1 and we have the packet we want, there can not possibly be anything waiting for us on the connection that is useful to us. However, there might be redundant copies of a packet we already got, which would cause needless cycles of repeated packets. Therefore we flush the communications input buffer now to try to get rid of undesired and unneeded packets that we have not read yet. Actually, the first sentence above is not entirely true: there could be an Error packet waiting to be read. Flushing an E packet is bad because it will not be resent, and we'll go into a cycle of timing out and retransmitting up to the retry limit. - fdc 2007/03/02 */ if (wslotn == 1 /* (not wslots!) */ #ifdef STREAMING && !streaming /* But not when streaming */ #endif /* STREAMING */ ) { debug(F100,"input about to flush","",0); ttflui(); /* Got what we want, clear input buffer. */ } #ifndef NEWDPL if (!nakstate) /* When sending */ rcalcpsz(); /* recalculate size every packet */ #endif /* NEWDPL */ if (type == 'E') xitsta |= (what ? what : 1); /* Remember what failed. */ debug(F101,"input winlo","",winlo); debug(F101,"input rsn","",rsn); debug(F000,"input returning type","",type); return(rcvtyp = type); /* Success, return packet type. */ } #ifdef PARSENSE /* P A R C H K -- Check if Kermit packet has parity */ /* Call with s = pointer to packet, start = packet start character, n = length. Returns 0 if packet has no parity, -1 on error, or, if packet has parity: 'e' for even, 'o' for odd, 'm' for mark. Space parity cannot be sensed. So a return value of 0 really means either space or none. Returns -2 if parity has already been checked during this protocol operation. */ int #ifdef CK_ANSIC parchk(CHAR *s, CHAR start, int n) #else parchk(s,start,n) CHAR *s, start; int n; #endif /* CK_ANSIC */ /* parchk */ { CHAR s0, s1, s2, s3; debug(F101,"parchk n","",n); debug(F101,"parchk start","",start); s0 = s[0] & 0x7f; /* Mark field (usually Ctrl-A) */ if (s0 != start || n < 5) return(-1); /* Not a valid packet */ /* Look at packet control fields, which never have 8th bit set */ /* First check for no parity, most common case. */ if (((s[0] | s[1] | s[2] | s[3]) & 0x80) == 0) return(0); /* No parity or space parity */ /* Check for mark parity */ if (((s[0] & s[1] & s[2] & s[3]) & 0x80) == 0x80) return('m'); /* Mark parity */ /* Packet has some kind of parity */ /* Make 7-bit copies of control fields */ s1 = s[1] & 0x7f; /* LEN */ s2 = s[2] & 0x7f; /* SEQ */ s3 = s[3] & 0x7f; /* TYPE */ /* Check for even parity */ if ((s[0] == p_tbl[s0]) && (s[1] == p_tbl[s1]) && (s[2] == p_tbl[s2]) && (s[3] == p_tbl[s3])) return('e'); /* Check for odd parity */ if ((s[0] != p_tbl[s0]) && (s[1] != p_tbl[s1]) && (s[2] != p_tbl[s2]) && (s[3] != p_tbl[s3])) return('o'); /* Otherwise it's probably line noise. Let checksum calculation catch it. */ return(-1); } #endif /* PARSENSE */ /* Check to make sure timeout intervals are long enough to allow maximum length packets to get through before the timer goes off. If not, the timeout interval is adjusted upwards. This routine is called at the beginning of a transaction, before we know anything about the delay characteristics of the line. It works only for serial communication devices; it trusts the speed reported by the operating system. Call with a timout interval. Returns it, adjusted if necessary. */ int #ifdef CK_ANSIC chktimo( int timo, int flag ) #else chktimo(timo,flag) int timo, flag; #endif /* CK_ANSIC */ { long cps, z; int x, y; #ifdef STREAMING debug(F101,"chktimo streaming","",streaming); if (streaming) return(0); #endif /* STREAMING */ debug(F101,"chktimo timo","",timo); /* Timeout before adjustment */ debug(F101,"chktimo flag","",flag); if (flag) /* Don't change timeout if user */ return(timo); /* gave SET SEND TIMEOUT command. */ debug(F101,"chktimo spmax","",spmax); debug(F101,"chktimo urpsiz","",urpsiz); if (!network) { /* On serial connections... */ speed = ttgspd(); /* Get current speed. */ if (speed > 0L) { cps = speed / 10L; /* Convert to chars per second */ if (cps > 0L) { long plen; /* Maximum of send and rcv pkt size */ z = cps * (long) timo; /* Chars per timeout interval */ z -= z / 10L; /* Less 10 percent */ plen = spmax; if (urpsiz > spmax) plen = urpsiz; debug(F101,"chktimo plen","",plen); if (z < plen) { /* Compare with packet size */ x = (int) ((long) plen / cps); /* Adjust if necessary */ y = x / 10; /* Add 10 percent for safety */ if (y < 2) y = 2; /* Or 2 seconds, whichever is more */ x += y; if (x > timo) /* If this is greater than current */ timo = x; /* timeout, change the timeout */ debug(F101,"chktimo new timo","",timo); } } } } return(timo); } /* S P A C K -- Construct and send a packet */ /* spack() sends a packet of the given type, sequence number n, with len data characters pointed to by d, in either a regular or extended- length packet, depending on len. Returns the number of bytes actually sent, or else -1 upon failure. Uses global npad, padch, mystch, bctu, data. Leaves packet fully built and null-terminated for later retransmission by resend(). Updates global sndpktl (send-packet length). NOTE: The global pointer "data" is assumed to point into the 7th position of a character array (presumably in packet buffer for the current packet). It was used by getpkt() to build the packet data field. spack() fills in the header to the left of the data pointer (the data pointer is defined in getsbuf() in ckcfn3.c). If the address "d" is the same as "data", then the packet's data field has been built "in place" and need not be copied. */ int #ifdef CK_ANSIC spack(char pkttyp, int n, int len, CHAR *d) #else spack(pkttyp,n,len,d) char pkttyp; int n, len; CHAR *d; #endif /* CK_ANSIC */ /* spack */ { register int i; extern int lpcapu; /* Long packet capability negotiated */ int ix, j, k, x, lp, longpkt, copy, loglen; #ifdef GFTIMER CKFLOAT t1 = 0.0, t2 = 0.0; #endif /* GFTIMER */ register CHAR *cp, *mydata; unsigned crc; copy = (d != data); /* Flag whether data must be copied */ #ifdef DEBUG if (deblog) { /* Save lots of function calls! */ debug(F101,"SPACK n","",n); #ifdef COMMENT if (pkttyp != 'D') { /* Data packets would be too long */ debug(F111,"SPACK data",data,data); debug(F111,"SPACK d",d,d); } #endif /* COMMENT */ debug(F101,"SPACK data len","",len); debug(F101,"SPACK copy","",copy); } #endif /* DEBUG */ /* Decide whether to send as a long packet. Fixed to check negotiation result before doing this. Otherwise there's a border case where the sent packet is one byte too long because of extra control fields in a long packet. - fdc 13 September 2022 */ debug(F101,"SPACK LP decision lpcapu","",lpcapu); debug(F101,"SPACK LP decision len","",len); debug(F101,"SPACK LP decision bctl","",bctl); debug(F101,"SPACK LP decision len+bctl","",len+bctl); longpkt = 0; if (lpcapu > 0) { /* Only if long packet capability has been negotiated */ longpkt = (len + bctl + 2) > 96; /* Len + Seq + Type + Data + Blockcheck */ /* 1 1 2 n 1-3 */ } debug(F101,"SPACK LP decision longpkt","",longpkt); mydata = data - 7 + (longpkt ? 0 : 3); /* Starting position of header */ k = sseqtbl[n]; /* Packet structure info for pkt n */ #ifdef COMMENT #ifdef DEBUG if (deblog) { /* Save 2 more function calls... */ debug(F101,"SPACK mydata","",mydata); debug(F101,"SPACK sseqtbl[n]","",k); if (k < 0) { #ifdef STREAMING if (!streaming) #endif /* STREAMING */ debug(F101,"spack sending packet out of window","",n); } } #endif /* DEBUG */ #endif /* COMMENT */ if (k > -1) { s_pkt[k].pk_adr = mydata; /* Remember address of packet. */ s_pkt[k].pk_seq = n; /* Record sequence number */ s_pkt[k].pk_typ = pkttyp; /* Record packet type */ } spktl = 0; /* Initialize length of this packet */ i = 0; /* and position in packet. */ /* Now fill the packet */ mydata[i++] = mystch; /* MARK */ lp = i++; /* Position of LEN, fill in later */ mydata[i++] = tochar(n); /* SEQ field */ mydata[i++] = pkttyp; /* TYPE field */ j = len + bctl; /* Length of data + block check */ debug(F101,"SPACK len","",len); debug(F101,"SPACK bctl","",bctl); debug(F101,"SPACK j","",j); debug(F101,"SPACK longpkt","",longpkt); if (longpkt) { /* Long packet? */ int x; /* Yes, work around SCO Xenix/286 */ #ifdef CKTUNING unsigned int chk; #endif /* CKTUNING */ debug(F100,"SPACK doing long packet","",0); x = j / 95; /* compiler bug... */ mydata[lp] = tochar(0); /* Set LEN to zero */ mydata[i++] = tochar(x); /* Extended length, high byte */ mydata[i++] = tochar(j % 95); /* Extended length, low byte */ #ifdef CKTUNING /* Header checksum - skip the function calls and loops */ chk = (unsigned) mydata[lp] + (unsigned) mydata[lp+1] + (unsigned) mydata[lp+2] + (unsigned) mydata[lp+3] + (unsigned) mydata[lp+4] ; mydata[i++] = tochar((CHAR) ((((chk & 0300) >> 6) + chk) & 077)); #else mydata[i] = '\0'; /* Terminate for header checksum */ mydata[i++] = tochar(chk1(mydata+lp,5)); #endif /* CKTUNING */ } else { /* Short packets */ mydata[lp] = tochar(j+2); /* LEN includes Seq and Type */ debug(F101,"SPACK j+2","",j+2); debug(F101,"SPACK j+2 encoded","",tochar(j+2)); } /* When sending a file, the data is already in the right place. If it weren't, it might make sense to optimize this section by using memcpy or bcopy (neither of which are portable), but only if our packets were rather long. When receiving, we're only sending ACKs so it doesn't matter. So count the following loop as a sleeping dog. */ if (copy) /* Data field built in place? */ for ( ; len--; i++) mydata[i] = *d++; /* No, must copy. */ else /* Otherwise, */ i += len; /* Just skip past data field. */ mydata[i] = '\0'; /* Null-terminate for checksum calc. */ switch (bctu) { /* Block check */ case 1: /* 1 = 6-bit chksum */ ix = i - lp; /* Avoid "order of operation" error */ mydata[i++] = tochar(chk1(mydata+lp,ix)); break; case 2: /* 2 = 12-bit chksum */ j = chk2(mydata+lp,i-lp); mydata[i++] = (unsigned)tochar((j >> 6) & 077); mydata[i++] = (unsigned)tochar(j & 077); break; case 3: /* 3 = 16-bit CRC */ crc = chk3(mydata+lp,i-lp); mydata[i++] = (unsigned)tochar(((crc & 0170000)) >> 12); mydata[i++] = (unsigned)tochar((crc >> 6) & 077); mydata[i++] = (unsigned)tochar(crc & 077); break; case 4: /* 2 = 12-bit chksum, blank-free */ j = chk2(mydata+lp,i-lp); mydata[i++] = (unsigned)(tochar((unsigned)(((j >> 6) & 077) + 1))); mydata[i++] = (unsigned)(tochar((unsigned)((j & 077) + 1))); break; } loglen = i; mydata[i++] = seol; /* End of line (packet terminator) */ #ifdef TCPSOCKET /* If TELNET connection and packet terminator is carriage return, we must stuff either LF or NUL, according to SET TELNET NEWLINE-MODE (tn_nlm), to meet the TELNET NVT specification, unless user said RAW. If NEWLINE-MODE is set to LF instead of CR, we still send CR-NUL on a NVT connection and CR on a binary connection. */ if ( #ifdef STREAMING !dontsend && #endif /* STREAMING */ ((network && ttnproto == NP_TELNET) || (!local && sstelnet)) && seol == CK_CR) { switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) { case TNL_CR: /* NVT or BINARY */ break; case TNL_CRNUL: mydata[i++] = NUL; break; case TNL_CRLF: mydata[i++] = LF; break; } } #endif /* TCPSOCKET */ mydata[i] = '\0'; /* Terminate string */ if ( #ifdef STREAMING !dontsend && #endif /* STREAMING */ pktlog ) /* Save a function call! */ logpkt('s',n,mydata,loglen); /* Log the packet */ /* (PWP) add the parity quickly at the end */ if (parity) { switch (parity) { case 'e': /* Even */ for (cp = &mydata[i-1]; cp >= mydata; cp--) *cp = p_tbl[*cp]; break; case 'm': /* Mark */ for (cp = &mydata[i-1]; cp >= mydata; cp--) *cp |= 128; break; case 'o': /* Odd */ for (cp = &mydata[i-1]; cp >= mydata; cp--) *cp = p_tbl[*cp] ^ 128; break; case 's': /* Space */ for (cp = &mydata[i-1]; cp >= mydata; cp--) *cp &= 127; break; } } if (pktpaus) msleep(pktpaus); /* Pause if requested */ x = 0; if (npad) { #ifdef STREAMING if (dontsend) x = 0; else #endif /* STREAMING */ x = ttol(padbuf,npad); /* Send any padding */ } if (x > -1) { #ifdef CK_TIMERS if (timint > 0) { if (pkttyp == 'N') srttbl[n > 0 ? n-1 : 63] = gtimer(); else srttbl[n] = gtimer(); } #endif /* CK_TIMERS */ spktl = i; /* Remember packet length */ if (k > -1) s_pkt[k].pk_len = spktl; /* also in packet info structure */ #ifdef DEBUG #ifdef GFTIMER /* This code shows (in the debug log) how long it takes write() to execute. Sometimes on a congested TCP connection, it can surprise you -- 90 seconds or more... */ if ( #ifdef STREAMING !dontsend && #endif /* STREAMING */ deblog ) t1 = gftimer(); #endif /* GFTIMER */ #endif /* DEBUG */ #ifdef STREAMING if (dontsend) { debug(F000,"STREAMING spack skipping","",pkttyp); x = 0; } else #endif /* STREAMING */ x = ttol(mydata,spktl); /* Send the packet */ } #ifdef STREAMING if (!dontsend) { #endif /* STREAMING */ debug(F101,"SPACK spktl","",spktl); debug(F101,"SPACK ttol returns","",x); if (x < 0) { /* Failed. */ if (local && x < -1) { xxscreen(SCR_ST,ST_ERR,0L,"FAILED: Connection lost"); /* We can't send an E packet because the connection is lost. */ epktsent = 1; /* So pretend we sent one. */ fatalio = 1; /* Remember we got a fatal i/o error */ dologend(); ckstrncpy((char *)epktmsg,"Connection lost",PKTMSGLEN); } return(x); } if (spktl > maxsend) /* Keep track of longest packet sent */ maxsend = spktl; #ifdef DEBUG #ifdef GFTIMER if (deblog) { /* Log elapsed time for write() */ t2 = gftimer(); debug(F101,"SPACK ttol msec","",(long)((t2-t1)*1000.0)); } #endif /* GFTIMER */ #endif /* DEBUG */ #ifdef STREAMING } #endif /* STREAMING */ sndtyp = pkttyp; /* Remember packet type for echos */ #ifdef STREAMING if (!dontsend) { /* If really sent, */ spackets++; /* count it. */ flco += spktl; /* Count the characters */ tlco += spktl; /* for statistics... */ #ifdef DEBUG if (deblog) { /* Save two function calls! */ dumpsbuf(); /* Dump send buffers to debug log */ debug(F111,"SPACK calling screen, mydata=",mydata,n); } #endif /* DEBUG */ } #endif /* STREAMING */ if (local) { int x = 0; if (fdispla != XYFD_N) x = 1; if ((fdispla == XYFD_B) && (pkttyp == 'D' || pkttyp == 'Y')) x = 0; if (x) xxscreen(SCR_PT,pkttyp,(long)n,(char *)mydata); /* Update screen */ } return(spktl); /* Return length */ } /* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */ int #ifdef CK_ANSIC chk1( register CHAR *pkt, register int len ) #else chk1(pkt,len) register CHAR *pkt; register int len; #endif /* CK_ANSIC */ { register unsigned int chk; #ifdef CKTUNING #ifdef COMMENT register unsigned int m; /* Avoid function call */ m = (parity) ? 0177 : 0377; for (chk = 0; len-- > 0; pkt++) chk += *pkt & m; #else chk = 0; while (len-- > 0) chk += (unsigned) *pkt++; #endif /* COMMENT */ #else chk = chk2(pkt,len); #endif /* CKTUNING */ chk = (((chk & 0300) >> 6) + chk) & 077; debug(F111,"chk1","1-byte block check encoded code",chk); return((int) chk); } /* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */ unsigned int #ifdef CK_ANSIC chk2( register CHAR *pkt, register int len ) #else chk2(pkt,len) register CHAR *pkt; register int len; #endif /* CK_ANSIC */ { register long chk; #ifdef COMMENT register unsigned int m; m = (parity) ? 0177 : 0377; for (chk = 0; len-- > 0; pkt++) chk += *pkt & m; #else /* Parity has already been stripped */ chk = 0L; while (len-- > 0) chk += (unsigned) *pkt++; #endif /* COMMENT */ debug(F101,"chk2","",(unsigned int) (chk & 07777)); return((unsigned int) (chk & 07777)); } /* C H K 3 -- Compute a type-3 Kermit block check. */ /* Calculate the 16-bit CRC-CCITT of a null-terminated string using a lookup table. Assumes the argument string contains no embedded nulls. */ #ifdef COMMENT unsigned int #ifdef CK_ANSIC chk3( register CHAR *pkt, int parity, register int len ) #else chk3(pkt,parity,len) register CHAR *pkt; int parity; register int len; #endif /* CK_ANSIC */ { register long c, crc; register unsigned int m; m = (parity) ? 0177 : 0377; for (crc = 0; len-- > 0; pkt++) { c = crc ^ (long)(*pkt & m); crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]); } return((unsigned int) (crc & 0xFFFF)); } #else unsigned int #ifdef CK_ANSIC chk3( register CHAR *pkt, register int len ) #else chk3(pkt,len) register CHAR *pkt; register int len; #endif /* CK_ANSIC */ { register long c, crc; for (crc = 0; len-- > 0; pkt++) { c = crc ^ (long)(*pkt); crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]); } debug(F101,"chk3","",(unsigned int) (crc & 0xFFFF)); return((unsigned int) (crc & 0xFFFF)); } #endif /* COMMENT */ /* N X T P K T -- Next Packet */ /* Get packet number of next packet to send and allocate a buffer for it. Returns: 0 on success, with global pktnum set to the packet number; -1 on failure to allocate buffer (fatal); -2 if resulting packet number is outside the current window. */ int nxtpkt() { /* Called by file sender */ int j, n, x; debug(F101,"nxtpkt pktnum","",pktnum); debug(F101,"nxtpkt winlo ","",winlo); n = (pktnum + 1) % 64; /* Increment packet number mod 64 */ debug(F101,"nxtpkt n","",n); #ifdef STREAMING if (!streaming) { x = chkwin(n,winlo,wslots); /* Don't exceed window boundary */ debug(F101,"nxtpkt chkwin","",x); if (x) return(-2); j = getsbuf(n); /* Get a buffer for packet n */ if (j < 0) { debug(F101,"nxtpkt getsbuf failure","",j); return(-1); } } #endif /* STREAMING */ pktnum = n; return(0); } /* Functions for sending ACKs and NAKs */ /* Note, we should only ACK the packet at window-low (winlo) */ /* However, if an old packet arrives again (e.g. because the ACK we sent */ /* earlier was lost), we ACK it again. */ int ack() { /* Acknowledge the current packet. */ return(ackns(winlo,(CHAR *)"")); } #ifdef STREAMING int fastack() { /* Acknowledge packet n */ int j, k, n, x; n = winlo; k = rseqtbl[n]; /* First find received packet n. */ debug(F101,"STREAMING fastack k","",k); freesbuf(n); /* Free current send-buffer, if any */ if ((j = getsbuf(n)) < 0) { /* This can happen if we have to re-ACK an old packet that has */ /* already left the window. It does no harm. */ debug(F101,"STREAMING fastack can't getsbuf","",n); } dontsend = 1; x = spack('Y',n,0,(CHAR *)""); /* Now send it (but not really) */ dontsend = 0; if (x < 0) return(x); debug(F101,"STREAMING fastack x","",x); if (k > -1) freerbuf(k); /* don't need it any more */ if (j > -1) freesbuf(j); /* and don't need to keep ACK either */ winlo = (winlo + 1) % 64; return(0); } #endif /* STREAMING */ int #ifdef CK_ANSIC ackns( int n, CHAR *s ) /* Acknowledge packet n */ #else ackns(n,s) int n; CHAR *s; #endif /* CK_ANSIC */ { int j, k, x; debug(F111,"ackns",s,n); k = rseqtbl[n]; /* First find received packet n. */ debug(F101,"ackns k","",k); freesbuf(n); /* Free current send-buffer, if any */ if ((j = getsbuf(n)) < 0) { /* This can happen if we have to re-ACK an old packet that has */ /* already left the window. It does no harm. */ debug(F101,"ackns can't getsbuf","",n); } x = spack('Y',n,(int)strlen((char *)s),s); /* Now send it. */ if (x < 0) return(x); debug(F101,"ackns winlo","",winlo); debug(F101,"ackns n","",n); if (n == winlo) { /* If we're acking winlo */ if (k > -1) freerbuf(k); /* don't need it any more */ if (j > -1) freesbuf(j); /* and don't need to keep ACK either */ winlo = (winlo + 1) % 64; } return(0); } int #ifdef CK_ANSIC ackn( int n ) /* Send ACK for packet number n */ #else ackn(n) int n; #endif /* CK_ANSIC */ { return(ackns(n,(CHAR *)"")); } int #ifdef CK_ANSIC ack1( CHAR *s ) #else ack1(s) CHAR *s; #endif /* CK_ANSIC */ { if (!s) s = (CHAR *)""; debug(F110,"ack1",(char *)s,0); return(ackns(winlo,s)); } /* N A C K -- Send a Negative ACKnowledgment. */ /* Call with the packet number, n, to be NAK'd. Returns -1 if that packet has been NAK'd too many times, otherwise 0. Btw, it is not right to return 0 under error conditions. This is done because the -1 code is used for cancelling the file transfer. More work is needed here. */ int #ifdef CK_ANSIC nack( int n ) #else nack(n) int n; #endif /* CK_ANSIC */ { int i, x; if (n < 0 || n > 63) { debug(F101,"nack bad pkt num","",n); return(0); } else debug(F101,"nack","",n); if ((i = sseqtbl[n]) < 0) { /* If necessary */ if (getsbuf(n) < 0) { /* get a buffer for this NAK */ debug(F101,"nack can't getsbuf","",n); return(0); } else i = sseqtbl[n]; /* New slot number */ } if (maxtry > 0 && s_pkt[i].pk_rtr++ > maxtry) /* How many? */ return(-1); /* Too many... */ /* Note, don't free this buffer. Eventually an ACK will come, and that */ /* will set it free. If not, well, it's back to ground zero anyway... */ x = spack('N',n,0,(CHAR *) ""); /* NAKs never have data. */ return(x); } #ifndef NEWDPL /* This routine no longer used */ /* * (PWP) recalculate the optimal packet length in the face of errors. * This is a modified version of the algorithm by John Chandler in Kermit/370, * see "Dynamic Packet Size Control", Kermit News, V2 #1, June 1988. * * This implementation minimizes the total overhead equation, which is * * Total chars = file_chars + (header_len * num_packs) * + (errors * (header_len + packet_len)) * * Differentiate with respect to number of chars, solve for packet_len, get: * * packet_len = sqrt (file_chars * header_len / errors) */ /* (FDC) New super-simple algorithm. If there was an error in the most recent packet exchange, cut the send-packet size in half, down to a minimum of 20. If there was no error, increase the size by 5/4, up to the maximum negotiated length. Seems to be much more responsive than previous algorithm, which took forever to recover the original packet length, and it also went crazy under certain conditions. Here's another idea for packet length resizing that keeps a history of the last n packets. Push a 1 into the left end of an n-bit shift register if the current packet is good, otherwise push a zero. The current n-bit value, w, of this register is a weighted sum of the noise hits for the last n packets, with the most recent weighing the most. The current packet length is some function of w and the negotiated packet length, like: (2^n - w) / (2^n) * (negotiated length) If the present resizing method causes problems, think about this one a little more. */ VOID #ifdef CK_ANSIC rcalcpsz( void ) { #else rcalcpsz() #endif /* CK_ANSIC */ { #ifdef COMMENT /* Old way */ register long x, q; if (numerrs == 0) return; /* bounds check just in case */ /* overhead on a data packet is npad+5+bctr, plus 3 if extended packet */ /* an ACK is 5+bctr */ /* first set x = per packet overhead */ if (wslots > 1) /* Sliding windows */ x = (long) (npad+5+bctr); /* packet only, don't count ack */ else /* Stop-n-wait */ x = (long) (npad+5+3+bctr+5+bctr); /* count packet and ack. */ /* then set x = packet length ** 2 */ x = x * ( ffc / (CK_OFF_T) numerrs); /* careful of overflow */ /* calculate the long integer sqrt(x) quickly */ q = 500; q = (q + x/q) >> 1; q = (q + x/q) >> 1; q = (q + x/q) >> 1; q = (q + x/q) >> 1; /* should converge in about 4 steps */ if ((q > 94) && (q < 130)) /* break-even point for long packets */ q = 94; if (q > spmax) q = spmax; /* maximum bounds */ if (q < 10) q = 10; /* minimum bounds */ spsiz = q; /* set new send packet size */ debug(F101,"rcalcpsiz","",q); #else /* New way */ debug(F101,"rcalcpsiz numerrs","",numerrs); debug(F101,"rcalcpsiz spsiz","",spsiz); if (spackets < 3) { numerrs = 0; return; } if (numerrs) spsiz = spsiz / 2; else spsiz = (spsiz / 4) * 5; if (spsiz < 20) spsiz = 20; if (spsiz > spmax) spsiz = spmax; debug(F101,"rcalcpsiz new spsiz","",spsiz); numerrs = 0; #endif /* COMMENT */ } #endif /* NEWDPL */ /* R E S E N D -- Retransmit packet n. */ /* Returns 0 or positive on success (the number of retries for packet n). On failure, returns a negative number, and an error message is placed in recpkt. */ int #ifdef CK_ANSIC resend( int n ) /* Send packet n again. */ #else resend(n) int n; #endif /* CK_ANSIC */ { int j, k, x; #ifdef GFTIMER CKFLOAT t1 = 0.0, t2 = 0.0; #endif /* GFTIMER */ debug(F101,"resend seq","",n); k = chkwin(n,winlo,wslots); /* See if packet in current window */ j = -1; /* Assume it's lost */ if (k == 0) j = sseqtbl[n]; /* See if we still have a copy of it */ if (k != 0 || j < 0) { /* If not.... */ if (nakstate && k == 1) { /* Packet n is in the previous window and we are the file receiver. We already sent the ACK and deallocated its buffer so we can't just retransmit the ACK. Rather than give up, we try some tricks... */ if (n == 0 && spackets < 63 && myinit[0]) { /* ACK to Send-Init */ /* If the packet number is 0, and we're at the beginning of a protocol operation (spackets < 63), then we have to resend the ACK to an I or S packet, complete with parameters in the data field. So we take a chance and send a copy of the parameters in an ACK packet with block check type 1. (Or 3 if SET BLOCK 5.) */ if (bctf) { /* Force Type 3 on all packets? */ x = spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit); if (x < 0) return(x); logpkt('#',n,(CHAR *)"",0); /* Log it */ } else { /* Regular Kermit protocol */ int bctlsav; /* Temporary storage */ int bctusav; bctlsav = bctl; /* Save current block check length */ bctusav = bctu; /* and type */ bctu = bctl = 1; /* Set block check to 1 */ x = spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit); if (x < 0) return(x); logpkt('#',n,(CHAR *)"",0); /* Log it */ bctu = bctusav; /* Restore block check type */ bctl = bctlsav; /* and length */ } } else { /* Not the first packet */ /* It's not the first packet of the protocol operation. It's some other packet that we have already ACK'd and forgotten about. So we take a chance and send an empty ACK using the current block-check type. Usually this will work out OK (like when acking Data packets), and no great harm will be done if it was some other kind of packet (F, etc). If we are requesting an interruption of the file transfer, the flags are still set, so we'll catch up on the next packet. */ x = spack('Y',n,0,(CHAR *) ""); if (x < 0) return(x); } retrans++; xxscreen(SCR_PT,'%',(long)pktnum,"Retransmission"); return(0); } else { /* Packet number is not in current or previous window. We seem to hit this code occasionally at the beginning of a transaction, for apparently no good reason. Let's just log it for debugging, send nothing, and try to proceed with the protocol rather than killing it. */ debug(F101,"resend PKT NOT IN WINDOW","",n); debug(F101,"resend k","",k); return(0); } } /* OK, it's in the window and it's not lost. */ debug(F101,"resend pktinfo index","",k); if (maxtry > 0 && s_pkt[j].pk_rtr++ > maxtry) { /* Over retry limit */ xitsta |= what; return(-1); } debug(F101,"resend retry","",s_pkt[j].pk_rtr); /* OK so far */ dumpsbuf(); /* (debugging) */ if (s_pkt[j].pk_typ == ' ') { /* Incompletely formed packet */ if (nakstate) { /* (This shouldn't happen any more) */ nack(n); retrans++; xxscreen(SCR_PT,'%',(long)pktnum,"(resend)"); return(s_pkt[j].pk_rtr); } else { /* No packet to resend! */ #ifdef COMMENT /* This happened (once) while sending a file with 2 window slots and typing X to the sender to cancel the file. But since we're cancelling anyway, there's no need to give a scary message. */ sprintf((char *)epktmsg, "resend logic error: NPS, n=%d, j=%d.",n,j); return(-2); #else /* Just ignore it. */ return(0); #endif /* COMMENT */ } } #ifdef DEBUG #ifdef GFTIMER if (deblog) t1 = gftimer(); #endif /* GFTIMER */ #endif /* DEBUG */ /* Everything ok, send the packet */ #ifdef CK_TIMERS if (timint > 0) srttbl[n] = gtimer(); /* Update the timer */ #endif /* CK_TIMERS */ x = ttol(s_pkt[j].pk_adr,s_pkt[j].pk_len); #ifdef DEBUG #ifdef GFTIMER if (deblog) { t2 = gftimer(); debug(F101,"resend ttol msec","",(long)((t2-t1)*1000.0)); } #endif /* GFTIMER */ #endif /* DEBUG */ debug(F101,"resend ttol returns","",x); retrans++; /* Count a retransmission */ xxscreen(SCR_PT,'%',(long)pktnum,"(resend)"); /* Tell user about resend */ logpkt('S',n,s_pkt[j].pk_adr, s_pkt[j].pk_len); /* Log the resent packet */ return(s_pkt[j].pk_rtr); /* Return the number of retries. */ } /* E R R P K T -- Send an Error Packet */ int #ifdef CK_ANSIC errpkt( CHAR *reason ) /* ...containing the reason given */ #else errpkt(reason) CHAR *reason; #endif /* CK_ANSIC */ { extern int rtimo, state, justone; int x, y; czseen = 1; /* Also cancels batch */ state = 0; /* Reset protocol state */ debug(F110,"errpkt",reason,0); tlog(F110,"Protocol Error:",(char *)reason,0L); xxscreen(SCR_EM,0,0L,reason); encstr(reason); x = spack('E',pktnum,size,data); ckstrncpy((char *)epktmsg,(char *)reason,PKTMSGLEN); y = quiet; quiet = 1; epktsent = 1; /* Close files silently. */ clsif(); clsof(1); quiet = y; /* I just sent an E-packet. I'm in local mode, I was receiving a file, I'm not a server, and sliding windows are in use. Therefore, there are likely to be a bunch of packets already "in the pipe" on their way to me by the time the remote sender gets the E-packet. So the next time I CONNECT or try to start another protocol operation, I am likely to become terribly confused by torrents of incoming material. To prevent this, the following code soaks up packets from the connection until there is an error or timeout, without wasting too much time waiting. Exactly the same problem occurs when I am in remote mode or if I am in server mode with the justone flag set. In remote mode not only does the packet data potentially get echo'd back to the sender which is confusing to the user in CONNECT mode, but it also may result in the host performing bizarre actions such as suspending the process if ^Z is unprefixed, etc. Furthermore, thousands of packets bytes in the data stream prevent the client from being able to process Telnet Kermit Option negotiations properly. */ #ifdef STREAMING /* Because streaming sets the timeout to 0... */ if (streaming) { timint = rcvtimo = rtimo; streaming = 0; } #endif /* STREAMING */ if (what & W_RECV && (!server || (server && justone)) && (wslots > 1 #ifdef STREAMING || streaming #endif /* STREAMING */ )) { #ifdef GFTIMER CKFLOAT oldsec, sec = (CKFLOAT) 0.0; #else int oldsec, sec = 0; #endif /* GFTIMER */ debug(F101,"errpkt draining","",wslots); xxscreen(SCR_ST,ST_MSG,0l,"Draining incoming packets, wait..."); while (x > -1) { /* Don't bother if no connection */ oldsec = sec; #ifdef GFTIMER sec = gftimer(); if (oldsec != (CKFLOAT) 0.0) timint = rcvtimo = (int) (sec - oldsec + 0.5); #else sec = gtimer(); if (oldsec != 0) timint = rcvtimo = sec - oldsec + 1; #endif /* GFTIMER */ if (timint < 1) timint = rcvtimo = 1; msleep(50); /* Allow a bit of slop */ x = rpack(); /* Read a packet */ if (x == 'T' || x == 'z') /* Timed out means we're done */ break; xxscreen(SCR_PT,x,rsn,""); /* Let user know */ } xxscreen(SCR_ST,ST_MSG,0l,"Drain complete."); } if ((x = (what & W_KERMIT))) xitsta |= x; /* Remember what failed. */ success = 0; return(y); } /* scmd() -- Send a packet of the given type */ int #ifdef CK_ANSIC scmd(char t, CHAR *dat) #else scmd(t,dat) char t; CHAR *dat; #endif /* CK_ANSIC */ /* scmd */ { int x; extern char * srimsg; debug(F000,"scmd",dat,t); if (encstr(dat) < 0) { /* Encode the command string */ srimsg = "String too long"; return(-1); } x = spack(t,pktnum,size,data); debug(F101,"scmd spack","",x); return(x); } /* Compose and Send GET packet */ struct opktparm { /* O-Packet item list */ CHAR * opktitem; struct opktparm * opktnext; }; struct opktparm * opkthead = NULL; /* Linked list of O-packet fields */ int opktcnt = 0; /* O-Packet counter */ char * srimsg = NULL; /* GET-Packet error message */ /* S O P K T -- Send O-Packet */ /* Sends one O-Packet each time called, using first-fit method of filling the packet from linked list of parameters pointed to by opkthead. To be called repeatedly until list is empty or there is an error. Returns: -1 on failure. 0 on success and no more fields left to send. 1 on success but with more fields left to be sent. */ int sopkt() { int n = 0; /* Field number in this packet */ int rc = 0; /* Return code */ int len = 0; /* Data field length */ char c = NUL; struct opktparm * o = NULL; struct opktparm * t = NULL; struct opktparm * prev = NULL; CHAR * dsave = data; int x, ssave = spsiz; srimsg = NULL; /* Error message */ o = opkthead; /* Point to head of list */ if (!o) { /* Oops, no list... */ srimsg = "GET Packet Internal Error 1"; debug(F100,"sopkt NULL list","",0); return(-1); } while (o) { /* Go thru linked list... */ c = *(o->opktitem); /* Parameter code */ debug(F000,"sopkt",o->opktitem,c); x = encstr((CHAR *)o->opktitem); debug(F111,"sopkt encstr",dsave,x); if (x < 0) { /* Encode this item */ if (n == 0) { /* Failure, first field in packet */ debug(F100,"sopkt overflow","",0); spsiz = ssave; /* Restore these */ data = dsave; o = opkthead; /* Free linked list */ while (o) { if (o->opktitem) free(o->opktitem); t = o->opktnext; free((char *)o); o = t; } opkthead = NULL; srimsg = "GET Packet Too Long for Server"; return(-1); /* Fail */ } else { /* Not first field in packet */ debug(F110,"sopkt leftover",o->opktitem,0); prev = o; /* Make this one the new previous */ o = o->opktnext; /* Get next */ c = NUL; /* So we know we're not done */ *data = NUL; /* Erase any partial encoding */ continue; /* We can try this one again later */ } } n++; /* Encoding was successful */ debug(F111,"sopkt field",data,x); len += x; /* Total data field length */ data += x; /* Set up for next field... */ spsiz -= x; free(o->opktitem); /* Free item just encoded */ if (o == opkthead) { /* If head */ opkthead = o->opktnext; /* Move head to next */ free((char *)o); /* Free this list node */ o = opkthead; } else { /* If not head */ o = o->opktnext; /* Get next */ prev->opktnext = o; /* Link previous to next */ } if (c == '@') /* Loop exit */ break; if (!o && !opkthead) { /* Set up End Of Parameters Field */ o = (struct opktparm *)malloc(sizeof(struct opktparm)); if (o) { opkthead = o; if (!(o->opktitem = (CHAR *)malloc(3))) { free((char *)o); srimsg = "GET Packet Internal Error 8"; return(-1); } ckstrncpy((char *)(o->opktitem), "@ ", 3); debug(F111,"sopkt o->opktitem",o->opktitem, strlen((char *)(o->opktitem))); o->opktnext = NULL; } } } data = dsave; /* Restore globals */ spsiz = ssave; debug(F110,"sopkt data",data,0); debug(F101,"sopkt opktcnt","",opktcnt); if (opktcnt++ > 0) { if (nxtpkt() < 0) { /* Get next packet number and buffer */ srimsg = "GET Packet Internal Error 9"; return(-1); } } debug(F101,"sopkt pktnum","",pktnum); rc = spack((char)'O',pktnum,len,data); /* Send O-Packet */ debug(F101,"sopkt spack","",rc); if (rc < 0) /* Failed */ srimsg = "Send Packet Failure"; /* Set message */ else /* Succeeded */ rc = (c == '@') ? 0 : 1; /* 1 = come back for more, 0 = done */ debug(F101,"sopkt rc","",rc); return(rc); } /* S R I N I T -- Send GET packet */ /* Sends the appropriate GET-Class packet. Returns: -1 on error 0 if packet sent successfully and we can move on to the next state 1 if an O-packet was sent OK but more O packets still need to be sent. */ int #ifdef CK_ANSIC srinit( int reget, int retrieve, int opkt ) #else srinit(reget, retrieve, opkt) int reget, retrieve, opkt; #endif /* CK_ANSIC */ { int x = 0, left = 0; extern int oopts, omode; CHAR * p = NULL; #ifdef RECURSIVE extern int recursive; debug(F101,"srinit recursive","",recursive); #endif /* RECURSIVE */ debug(F101,"srinit reget","",reget); debug(F101,"srinit retrieve","",retrieve); debug(F101,"srinit opkt","",opkt); debug(F101,"srinit oopts","",oopts); debug(F101,"srinit omode","",omode); debug(F110,"srinit cmarg",cmarg,0); srimsg = NULL; opktcnt = 0; if (!cmarg) cmarg = ""; if (!*cmarg) { srimsg = "GET with no filename"; debug(F100,"srinit null cmarg","",0); return(-1); } if (opkt) { /* Extended GET is totally different */ char buf[16]; struct opktparm * o = NULL; struct opktparm * prev = NULL; buf[0] = NUL; /* Build O-Packet fields and send (perhaps first) O-Packet */ if (oopts > -1) { /* Write Option flags */ o = (struct opktparm *)malloc(sizeof(struct opktparm)); if (!o) { srimsg = "GET Packet Internal Error 2"; debug(F100,"srinit malloc fail O1","",0); return(-1); } sprintf(buf,"Ox%d",oopts); /* safe */ x = (int) strlen(buf+2); buf[1] = tochar(x); o->opktitem = (CHAR *)malloc(x + 3); if (!o->opktitem) { srimsg = "GET Packet Internal Error 3"; debug(F100,"srinit malloc fail O2","",0); return(-1); } ckstrncpy((char *)(o->opktitem),buf,x+3); o->opktnext = NULL; if (!opkthead) opkthead = o; prev = o; } if (omode > -1) { /* If Xfer Mode specified, write it */ o = (struct opktparm *)malloc(sizeof(struct opktparm)); if (!o) { srimsg = "GET Packet Internal Error 4"; debug(F100,"srinit malloc fail M1","",0); return(-1); } sprintf(buf,"Mx%d",omode); /* safe */ x = (int) strlen(buf+2); buf[1] = tochar(x); o->opktitem = (CHAR *)malloc(x + 3); if (!o->opktitem) { srimsg = "GET Packet Internal Error 5"; debug(F100,"srinit malloc fail O2","",0); return(-1); } ckstrncpy((char *)(o->opktitem),buf,x+3); o->opktnext = NULL; if (!opkthead) opkthead = o; else prev->opktnext = o; prev = o; } /* Same deal for oname and opath eventually but not needed now... */ x = strlen(cmarg); /* Now do filename */ if (x > spsiz - 4) { srimsg = "GET Packet Too Long for Server"; return(-1); } o = (struct opktparm *)malloc(sizeof(struct opktparm)); if (!o) { srimsg = "GET Packet Internal Error 6"; debug(F100,"srinit malloc fail F1","",0); return(-1); } left = x + 6; o->opktitem = (CHAR *)malloc(left + 1); if (!o->opktitem) { srimsg = "GET Packet Internal Error 7"; debug(F100,"srinit malloc fail F2","",0); return(-1); } p = o->opktitem; *p++ = 'F'; left--; if (x > 94) { /* Too long for normal length */ *p++ = SYN; /* Escape length with Ctrl-V */ *p++ = tochar(x / 95); *p++ = tochar(x % 95); left -= 3; } else { /* Normal encoding for 94 or less */ *p++ = tochar(x); left--; } ckstrncpy((char *)p,cmarg,left); /* Copy the filename */ o->opktnext = NULL; if (!opkthead) opkthead = o; else prev->opktnext = o; prev = o; /* End of Parameters */ prev->opktnext = NULL; /* End of list. */ return(sopkt()); } /* Not Extended GET */ if (encstr((CHAR *)cmarg) < 0) { /* Encode the filename. */ srimsg = "GET Packet Too Long for Server"; return(-1); } if (retrieve) { /* Send the packet. */ #ifdef RECURSIVE if (recursive) x = spack((char)'W',pktnum,size,data); /* GET /DELETE /RECURSIVE */ else #endif /* RECURSIVE */ x = spack((char)'H',pktnum,size,data); /* GET /DELETE */ } #ifdef RECURSIVE else if (recursive) x = spack((char)'V',pktnum,size,data); /* GET /RECURSIVE */ #endif /* RECURSIVE */ else x = spack((char)(reget ? 'J' : 'R'),pktnum,size,data); /* GET */ if (x < 0) srimsg = "Send Packet Failure"; return(x < 0 ? x : 0); } /* K S T A R T -- Checks for a Kermit packet while in terminal mode. */ /* (or command mode...) */ #ifdef CK_AUTODL int #ifdef CK_ANSIC kstart(CHAR ch) #else kstart(ch) CHAR ch; #endif /* CK_ANSIC */ /* kstart */ { static CHAR * p = NULL; #ifdef OS2 static CHAR * pk = NULL; #endif /* OS2 */ ch &= 0177; /* Strip 8th bit */ /* Because we're in cooked mode at the command prompt... */ if (ch == LF) { debug(F110,"kstart","ch == LF",0); if ((what == W_COMMAND || what == W_INIT || what == W_NOTHING)) { if (eol == CK_CR) { ch = eol; debug(F110,"kstart","ch = CR",0); } } } #ifdef OS2 if (adl_kmode == ADL_STR) { if (!ch) return(0); if (!pk) pk = adl_kstr; if (ch == *pk) { pk++; if (*pk == '\0') { pk = adl_kstr; debug(F100, "kstart Kermit Start String","",0); return(PROTO_K + 1); } } else pk = adl_kstr; } #endif /* OS2 */ if (ch == stchr) { /* Start of packet */ kstartactive = 1; p = ksbuf; *p = ch; debug(F101,"kstart SOP","",ch); } else if (ch == eol) { /* End of packet */ kstartactive = 0; if (p) { debug(F101,"kstart EOL","",ch); p++; if (p - ksbuf < 94 ) { int rc = 0; *p++ = ch; *p = NUL; rc = chkspkt((char *)ksbuf); debug(F111,"kstart EOP chkspkt", ksbuf, rc); p = NULL; if (!rc) return(0); if (rc == 2) rc = -1; debug(F111,"kstart ksbuf",ksbuf,rc); return(rc); } else { debug(F110,"kstart","p - ksbuf >= 94",0); p = NULL; } } } else if (p) { if (ch < SP) kstartactive = 0; p++; if (p - ksbuf < 94) { *p = ch; } else { p = NULL; debug(F110,"kstart","p - ksbuf >= 94",0); } } return(0); } #ifdef CK_XYZ /* Z S T A R T -- Checks for a ZMODEM packet while in terminal mode. */ int #ifdef CK_ANSIC zstart(CHAR ch) #else zstart(ch) CHAR ch; #endif /* CK_ANSIC */ /* zstart */ { static CHAR * matchstr = (CHAR *) "\030B00"; /* "rz\r**\030B00000000000000\r\033J\021"; */ static CHAR * p = NULL; extern int inserver; if (inserver) return(0); if (!ch) return(0); if (!p) { #ifdef OS2 p = adl_zmode == ADL_PACK ? matchstr : adl_zstr; #else p = matchstr; #endif /* OS2 */ } if (ch == *p) { p++; if (*p == '\0') { #ifdef OS2 if (adl_zmode == ADL_PACK) { p = matchstr; debug(F100, "zstart Zmodem SOP","",0); } else { p = adl_zstr; debug(F100, "zstart Zmodem Start String","",0); } #else p = matchstr; debug(F100, "zstart Zmodem SOP","",0); #endif /* OS2 */ return(PROTO_Z + 1); } } else { #ifdef OS2 p = adl_zmode == ADL_PACK ? matchstr : adl_zstr; #else p = matchstr; #endif /* OS2 */ } return(0); } #endif /* CK_XYZ */ #ifndef NOICP #ifdef CK_APC /* A U T O D O W N */ #ifdef CK_ANSIC VOID autodown(int ch) #else VOID autodown(ch) int ch; #endif /* CK_ANSIC */ /* autodown */ { /* The Kermit and Zmodem Auto-download calls go here */ extern int justone; /* From protocol module */ extern int debses, protocol, apcactive, autodl, inautodl; #ifdef DCMDBUF extern char *apcbuf; #else extern char apcbuf[]; #endif /* DCMDBUF */ #ifdef OS2 extern int apclength, term_io; #endif /* OS2 */ int k = 0; if ((autodl || inautodl #ifdef IKS_OPTION || TELOPT_SB(TELOPT_KERMIT).kermit.me_start #endif /* IKS_OPTION */ ) && !debses) { #ifdef CK_XYZ #ifdef XYZ_INTERNAL extern int p_avail; #else int p_avail = 1; #endif /* XYZ_INTERNAL */ if (p_avail && zstart((CHAR) ch)) { debug(F100, "Zmodem download","",0); #ifdef OS2 #ifndef NOTERM apc_command(APC_LOCAL,"receive /protocol:zmodem"); #endif /* NOTERM */ #else /* OS2 */ ckstrncpy(apcbuf,"receive /protocol:zmodem",APCBUFLEN); apcactive = APC_LOCAL; #endif /* OS2 */ return; } #endif /* CK_XYZ */ /* First try... */ k = kstart((CHAR) ch); if ( #ifdef NOSERVER k > 0 #else /* NOSERVER */ k #endif /* NOSERVER */ ) { /* We saw a valid S or I packet */ if (k < 0) { /* Stuff RECEIVE into APC buffer */ justone = 1; switch (protocol) { #ifdef CK_XYZ case PROTO_G: ckstrncpy(apcbuf, "set proto kermit, server, set protocol g", APCBUFLEN ); break; case PROTO_X: ckstrncpy(apcbuf, "set proto kermit,server,set proto xmodem", APCBUFLEN ); break; case PROTO_XC: ckstrncpy(apcbuf, "set proto kermit,server,set proto xmodem-crc", APCBUFLEN ); break; case PROTO_Y: ckstrncpy(apcbuf, "set proto kermit,server, set protocol y", APCBUFLEN ); break; case PROTO_Z: ckstrncpy(apcbuf, "set proto kermit,server,set proto zmodem", APCBUFLEN ); break; #endif /* CK_XYZ */ case PROTO_K: ckstrncpy(apcbuf,"server",APCBUFLEN); break; } } else { justone = 0; ckstrncpy(apcbuf,"receive /protocol:kermit",APCBUFLEN); } #ifdef OS2 #ifndef NOTERM apc_command(APC_LOCAL,apcbuf); #endif /* NOTERM */ #else /* OS2 */ ckstrncpy(apcbuf,"receive /protocol:zmodem",APCBUFLEN); apcactive = APC_LOCAL; #endif /* OS2 */ return; } } } #endif /* CK_APC */ #endif /* NOICP */ /* C H K S P K T -- Check if buf contains a valid S or I packet */ int #ifdef CK_ANSIC chkspkt( char *packet ) #else chkspkt(packet) char *packet; #endif /* CK_ANSIC */ { int buflen; int len = -1; CHAR chk; char type = 0; char *s = NULL; char *buf = NULL; char tmpbuf[100]; /* Longest S/I packet is about 30 */ if (!packet) return(0); buflen = ckstrncpy(tmpbuf,packet,100); /* Make a pokeable copy */ if (buflen < 5) return(0); /* Too short */ if (buflen > 100) return(0); /* Too long to be an S or I packet */ s = buf = tmpbuf; /* Point to beginning of copy */ if (*s++ != stchr) return(0); /* SOH */ len = xunchar(*s++); /* Length */ if (len < 0) return(0); if (*s++ != SP) return(0); /* Sequence number */ type = *s++; /* Type */ if (type != 'S' && type != 'I') return(0); if (buflen < len + 2) return(0); s += (len - 3); /* Position of checksum */ chk = (CHAR) (*s); /* Checksum */ *s = NUL; /* Temporarily null-terminate data field */ if (xunchar(chk) != chk1((CHAR *)(buf+1),buflen-2)) { /* Check it */ /* In C-Kermit 9.0 and later, an S or I packet can have a Type 3 Block check ("help set block-check" for details). */ unsigned crc; /* Failed... Try Type 3 block check */ *s = chk; /* Replace last byte */ s -= 2; /* Back up two bytes */ crc = (xunchar(s[0]) << 12) /* Convert 3 bytes to numeric CRC */ | (xunchar(s[1]) << 6) | (xunchar(s[2])); chk = (CHAR)(*s); /* Copy 1st byte of 3-byte CRC */ *s = NUL; /* Null-terminate data field */ if (crc != chk3((CHAR *)(buf+1),strlen(buf+1))) return(0); } return(type == 'S' ? 1 : 2); } #endif /* CK_AUTODL */ /* R P A C K -- Read a Packet */ /* rpack reads a packet and returns the packet type, or else Q if the packet was invalid, or T if a timeout occurred. Upon successful return, sets the values of global rsn (received sequence number), rln (received data length), and rdatap (pointer to null-terminated data field), and returns the packet type. NOTE: This is an inner-loop function so must be efficient. Protect function calls by if-tests where possible, e.g. "if (pktlog) logpkt(...);". */ int rpack() { register int i, j, x, lp; /* Local variables */ #ifdef CKTUNING unsigned int chk; #endif /* CKTUNING */ int k, type, chklen; unsigned crc; CHAR pbc[5]; /* Packet block check */ CHAR *sohp; /* Pointer to SOH */ CHAR e; /* Packet end character */ #ifdef GFTIMER CKFLOAT t1 = 0.0, t2 = 0.0; #endif /* GFTIMER */ debug(F101,"rpack pktnum","",pktnum); #ifndef OLDCHKINT if (chkint() < 0) /* Check for console interrupts. */ return('z'); #endif /* OLDCHKINT */ k = getrbuf(); /* Get a new packet input buffer. */ debug(F101,"rpack getrbuf","",k); if (k < 0) { /* Return like this if none free. */ return(-1); } recpkt = r_pkt[k].bf_adr; *recpkt = '\0'; /* Clear receive buffer. */ sohp = recpkt; /* Initialize pointers to it. */ rdatap = recpkt; rsn = rln = -1; /* In case of failure. */ e = (turn) ? turnch : eol; /* Use any handshake char for eol */ /* Try to get a "line". */ #ifdef CK_AUTODL debug(F110,"rpack ksbuf",ksbuf,0); if (ksbuf[0]) { /* Kermit packet already */ int x; /* collected for us in CONNECT mode */ CHAR *s1 = recpkt, *s2 = ksbuf; j = 0; while (*s2) { /* Copy and get length */ *s1++ = *s2++; /* No point optimizing this since */ j++; /* it's never more than ~20 chars */ } *s1 = NUL; #ifdef PARSENSE x = parchk(recpkt, stchr, j); /* Check parity */ debug(F000,"autodownload parity","",parity); debug(F000,"autodownload parchk","",x); if (x > 0 && parity != x) { autopar = 1; parity = x; } #endif /* PARSENSE */ ksbuf[0] = NUL; /* Don't do this next time! */ } else { /* Normally go read a packet */ #endif /* CK_AUTODL */ #ifdef DEBUG if (deblog) { debug(F101,"rpack timint","",timint); debug(F101,"rpack rcvtimo","",rcvtimo); #ifdef STREAMING debug(F101,"rpack streaming","",streaming); #endif /* STREAMING */ #ifdef GFTIMER /* Measure how long it takes to read a packet */ t1 = gftimer(); #endif /* GFTIMER */ } #endif /* DEBUG */ /* JUST IN CASE (otherwise this could clobber streaming) */ if ((timint == 0 #ifdef STREAMING || streaming #endif /* STREAMING */ ) && (rcvtimo != 0)) { debug(F101,"rpack timint 0 || streaming but rcvtimo","",rcvtimo); rcvtimo = 0; } #ifdef PARSENSE #ifdef UNIX /* So far the final turn argument is only for ck[uvdl]tio.c. Should be added to the others too. (turn == handshake character.) */ j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); #else #ifdef VMS j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); #else #ifdef datageneral j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); #else #ifdef STRATUS j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); #else #ifdef OS2 j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); #else #ifdef OSK j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); #else j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr); #endif /* OSK */ #endif /* OS2 */ #endif /* STRATUS */ #endif /* datageneral */ #endif /* VMS */ #endif /* UNIX */ if (parity != 0 && parity != 's' && ttprty != 0) { if (parity != ttprty) autopar = 1; parity = ttprty; } #else /* !PARSENSE */ j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e); #endif /* PARSENSE */ #ifdef DEBUG if (deblog) { debug(F101,"rpack ttinl len","",j); #ifdef GFTIMER t2 = gftimer(); debug(F101,"rpack ttinl msec","",(long)((t2-t1)*1000.0)); #endif /* GFTIMER */ } #endif /* DEBUG */ #ifdef STREAMING if (streaming && sndtyp == 'D' && j == 0) return('Y'); #endif /* STREAMING */ if (j < 0) { /* -1 == timeout, -2 == ^C, -3 == connection lost or fatal i/o */ debug(F101,"rpack: ttinl fails","",j); /* Otherwise, */ freerbuf(k); /* Free this buffer */ if (j < -1) { /* Bail out if ^C^C typed. */ if (j == -2) { interrupted = 1; debug(F101,"rpack ^C server","",server); debug(F101,"rpack ^C en_fin","",en_fin); } else if (j == -3) { fatalio = 1; debug(F101,"rpack fatalio","",en_fin); } return(j); } if (nakstate) { /* j == -1 is a read timeout */ xxscreen(SCR_PT,'T',(long)winlo,""); } else { xxscreen(SCR_PT,'T',(long)pktnum,""); } logpkt('r',-1,(CHAR *)"",0); if (flow == 1) ttoc(XON); /* In case of Xoff blockage. */ return('T'); } #ifdef CK_AUTODL } #endif /* CK_AUTODL */ rpktl = j; tlci += j; /* All OK, Count the characters. */ flci += j; /* Find start of packet */ #ifndef PARSENSE for (i = 0; (recpkt[i] != stchr) && (i < j); i++) sohp++; /* Find mark */ if (i++ >= j) { /* Didn't find it. */ logpkt('r',-1,"",0); freerbuf(k); return('T'); } #else i = 1; /* ttinl does this for us */ #endif /* PARSENSE */ rpackets++; /* Count received packet. */ lp = i; /* Remember LEN position. */ if ((j = xunchar(recpkt[i++])) == 0) { /* Get packet length. */ if ((j = lp+5) > MAXRP) { /* Long packet */ return('Q'); /* Too long */ } #ifdef CKTUNING /* Save some function-call and loop overhead... */ #ifdef COMMENT /* ttinl() already removed parity */ if (parity) #endif /* COMMENT */ chk = (unsigned) ((unsigned) recpkt[i-1] + (unsigned) recpkt[i] + (unsigned) recpkt[i+1] + (unsigned) recpkt[i+2] + (unsigned) recpkt[i+3] ); #ifdef COMMENT else chk = (unsigned) ((unsigned) (recpkt[i-1] & 077) + (unsigned) (recpkt[i] & 077) + (unsigned) (recpkt[i+1] & 077) + (unsigned) (recpkt[i+2] & 077) + (unsigned) (recpkt[i+3] & 077) ); #endif /* COMMENT */ if (xunchar(recpkt[j]) != ((((chk & 0300) >> 6) + chk) & 077)) #else x = recpkt[j]; /* Header checksum. */ recpkt[j] = '\0'; /* Calculate & compare. */ if (xunchar(x) != chk1(recpkt+lp,5)) #endif /* CKTUNING */ { freerbuf(k); logpkt('r',-1,(CHAR *)"",0); xxscreen(SCR_PT,'%',(long)pktnum,"Bad packet header"); return('Q'); } #ifndef CKTUNING recpkt[j] = x; /* Checksum ok, put it back. */ #endif /* CKTUNING */ rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctl; j = 3; /* Data offset. */ } else if (j < 3) { debug(F101,"rpack packet length less than 3","",j); freerbuf(k); logpkt('r',-1,(CHAR *)"",0); xxscreen(SCR_PT,'%',(long)pktnum,"Bad packet length"); return('Q'); } else { rln = j - bctl - 2; /* Regular packet */ j = 0; /* No extended header */ } rsn = xunchar(recpkt[i++]); /* Sequence number */ if (pktlog) /* Save a function call! */ logpkt('r',rsn,sohp,rln+bctl+j+4); if (rsn < 0 || rsn > 63) { debug(F101,"rpack bad sequence number","",rsn); freerbuf(k); if (pktlog) logpkt('r',rsn,(CHAR *)"",0); xxscreen(SCR_PT,'%',(long)pktnum,"Bad sequence number"); return('Q'); } /* If this packet has the same type as the packet just sent, assume it is an echo and ignore it. Don't even bother with the block check calculation: even if the packet is corrupted, we don't want to NAK an echoed packet. Nor must we NAK an ACK or NAK. */ type = recpkt[i++]; /* Get packet's TYPE field */ if (type == sndtyp || (nakstate && (type == 'N' /* || type == 'Y' */ ))) { debug(F000,"rpack echo","",type); /* If it's an echo */ freerbuf(k); /* Free this buffer */ logpkt('#',rsn,(CHAR *)"",0); return('e'); /* Return special (lowercase) code */ } /* Separate the data from the block check, accounting for the case where a packet was retransmitted after the block check switched. The "Type 3 Forced" business is new to C-Kermit 9.0. */ if (bctf) { /* Type 3 forced on all packets */ bctl = chklen = 3; } else if ((type == 'I' || type == 'S')) { /* Otherwise... */ if (recpkt[11] == '5') { /* Sender is forcing Type 3 */ bctf = 1; /* So we will too */ bctl = chklen = 3; debug(F100,"RECOGNIZE BLOCK CHECK TYPE 5","",0); } else { /* Normal case */ /* I & S packets always have type 1 */ chklen = 1; rln = rln + bctl - 1; } } else if (type == 'N') { /* A NAK packet never has data */ chklen = xunchar(recpkt[lp]) - 2; if (chklen < 1 || chklen > 3) { /* JHD 13 Apr 2010 */ debug(F101,"rpack bad nak chklen","",chklen); freerbuf(k); logpkt('r',-1,(CHAR *)"",0); xxscreen(SCR_PT,'%',(long)pktnum,"(bad nak)"); return('Q'); } rln = rln + bctl - chklen; } else chklen = bctl; #ifdef DEBUG if (deblog) { /* Save 2 function calls */ debug(F101,"rpack bctl","",bctl); debug(F101,"rpack chklen","",chklen); } #endif /* DEBUG */ i += j; /* Buffer index of DATA field */ rdatap = recpkt+i; /* Pointer to DATA field */ if ((j = rln + i) > r_pkt[k].bf_len) { /* Make sure it fits */ debug(F101,"packet too long","",j); freerbuf(k); logpkt('r',rsn,(CHAR *)"",0); return('Q'); } for (x = 0; x < chklen; x++) /* Copy the block check */ pbc[x] = recpkt[j+x]; /* 3 bytes at most. */ pbc[x] = '\0'; /* Null-terminate block check string */ recpkt[j] = '\0'; /* and the packet Data field. */ if (chklen == 2 && bctu == 4) { /* Adjust for Blank-Free-2 */ chklen = 4; /* (chklen is now a misnomer...) */ debug(F100,"rpack block check B","",0); } switch (chklen) { /* Check the block check */ case 1: /* Type 1, 6-bit checksum */ if (xunchar(*pbc) != chk1(recpkt+lp,j-lp)) { #ifdef DEBUG if (deblog) { debug(F110,"checked chars",recpkt+lp,0); debug(F101,"block check (1)","",(int) xunchar(*pbc)); debug(F101,"should be (1)","",chk1(recpkt+lp,j-lp)); } #endif /* DEBUG */ freerbuf(k); logpkt('r',-1,(CHAR *)"",0); xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error"); return('Q'); } break; case 2: /* Type 2, 12-bit checksum */ x = xunchar(*pbc) << 6 | xunchar(pbc[1]); if (x != chk2(recpkt+lp,j-lp)) { /* No match */ if (type == 'E') { /* Allow E packets to have type 1 */ recpkt[j++] = pbc[0]; recpkt[j] = '\0'; if (xunchar(pbc[1]) == chk1(recpkt+lp,j-lp)) break; else recpkt[--j] = '\0'; } #ifdef DEBUG if (deblog) { debug(F110,"checked chars",recpkt+lp,0); debug(F101,"block check (2)","", x); debug(F101,"should be (2)","", (int) chk2(recpkt+lp,j-lp)); } #endif /* DEBUG */ freerbuf(k); logpkt('r',-1,(CHAR *)"",0); xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error"); return('Q'); } break; case 3: /* Type 3, 16-bit CRC */ crc = (xunchar(pbc[0]) << 12) | (xunchar(pbc[1]) << 6) | (xunchar(pbc[2])); if (crc != chk3(recpkt+lp,j-lp)) { if (type == 'E') { /* Allow E packets to have type 1 */ recpkt[j++] = pbc[0]; recpkt[j++] = pbc[1]; recpkt[j] = '\0'; if (xunchar(pbc[2]) == chk1(recpkt+lp,j-lp)) break; else { j -=2; recpkt[j] = '\0'; } } #ifdef DEBUG if (deblog) { debug(F110,"checked chars",recpkt+lp,0); debug(F101,"block check (3)","",crc); debug(F101,"should be (3)","",(int) chk3(recpkt+lp,j-lp)); } #endif /* DEBUG */ freerbuf(k); logpkt('r',-1,(CHAR *)"",0); xxscreen(SCR_PT,'%',(long)pktnum,"CRC error"); return('Q'); } break; case 4: /* Type 4 = Type 2, no blanks. */ x = (unsigned)((xunchar(*pbc) - 1) << 6) | (unsigned)(xunchar(pbc[1]) - 1); if (x != chk2(recpkt+lp,j-lp)) { if (type == 'E') { /* Allow E packets to have type 1 */ recpkt[j++] = pbc[0]; recpkt[j] = '\0'; if (xunchar(pbc[1]) == chk1(recpkt+lp,j-lp)) break; else recpkt[--j] = '\0'; } debug(F101,"bad type B block check","",x); freerbuf(k); logpkt('r',-1,(CHAR *)"",0); xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error"); return('Q'); } break; default: /* Shouldn't happen... */ freerbuf(k); logpkt('r',-1,(CHAR *)"",0); xxscreen(SCR_PT,'%',(long)pktnum,"(crunched)"); return('Q'); } debug(F101,"rpack block check OK","",rsn); /* Now we can believe the sequence number, and other fields. */ /* Here we violate strict principles of layering, etc, and look at the */ /* packet sequence number. If there's already a packet with the same */ /* number in the window, we remove this one so that the window will not */ /* fill up. */ if ((x = rseqtbl[rsn]) != -1) { /* Already a packet with this number */ retrans++; /* Count it for statistics */ debug(F101,"rpack got dup","",rsn); logpkt('r',rsn,(CHAR *)"",0); freerbuf(x); /* Free old buffer, keep new packet. */ r_pkt[k].pk_rtr++; /* Count this as a retransmission. */ } /* New packet, not seen before, enter it into the receive window. */ #ifdef CK_TIMERS if (timint > 0) rrttbl[rsn] = gtimer(); /* Timestamp */ #endif /* CK_TIMERS */ rseqtbl[rsn] = k; /* Make back pointer */ r_pkt[k].pk_seq = rsn; /* Record in packet info structure */ r_pkt[k].pk_typ = type; /* Sequence, type,... */ r_pkt[k].pk_adr = rdatap; /* pointer to data buffer */ if (local) { /* Save a function call! */ int x = 0; if (fdispla != XYFD_N) x = 1; if (fdispla == XYFD_B && (type == 'D' || sndtyp == 'D')) x = 0; if (x) /* Update screen */ xxscreen(SCR_PT,(char)type,(long)rsn,(char *)sohp); } return(type); /* Return packet type */ } /* L O G P K T -- Log packet number n, pointed to by s. */ /* c = 's' (send) or 'r' (receive) */ /* Packet log entry format: Byte 1: r or s Byte 2: hyphen Bytes 3-4: packet number Byte 5: hyphen Bytes 6-7: seconds elapsed since last packet Bytes 8-9: Start char, usually Ctrl-A, expressed as printable ^ and A Byte 10 The packet itself Last byte: Start char, usually Ctrl-M, expressed as printable ^ and M Example: s-00-01-^A9 S~/ @-#Y3~^>J)0___J"U1@C */ VOID #ifdef CK_ANSIC logpkt(char c,int n, CHAR *s, int len) #else logpkt(c,n,s,len) char c; int n; CHAR *s; int len; #endif /* CK_ANSIC */ /* logpkt */ { char plog[20]; if (!s) s = (CHAR *)""; if (pktlog) if (chkfn(ZPFILE) > 0) { if (n < 0) /* Construct entry header */ sprintf(plog,"%c-xx-%02d-",c,(gtimer()%60)); /* safe */ else sprintf(plog,"%c-%02d-%02d-",c,n,(gtimer()%60)); /* safe */ if (zsoutx(ZPFILE,plog,(int)strlen(plog)) < 0) { pktlog = 0; return; } else { if (len == 0) len = strlen((char *)s); if (len > 0) { char * p; /* Make SOP printable */ int x; /* so we can look at logs without */ p = dbchr(*s); /* triggering autodownload. */ x = strlen(dbchr(*s)); if (*s < 32 || (*s > 127 && *s < 160)) { if (zsoutx(ZPFILE,p,x) < 0) { pktlog = 0; return; } else { len--; s++; } } } if (zsoutx(ZPFILE,(char *)s,len) < 0) { pktlog = 0; return; } else if (zsoutx(ZPFILE, #ifdef UNIX "\n", 1 #else #ifdef datageneral "\n", 1 #else #ifdef OSK "\r", 1 #else #ifdef MAC "\r", 1 #else "\015\012", 2 #endif /* MAC */ #endif /* OSK */ #endif /* datageneral */ #endif /* UNIX */ ) < 0) { pktlog = 0; } } } } /* T S T A T S -- Record statistics in transaction log */ VOID tstats() { char *tp = NULL; #ifdef GFTIMER CKFLOAT xx; /* Elapsed time divisor */ #endif /* GFTIMER */ debug(F101,"tstats xfsecs","",xfsecs); debug(F101,"tstats filcnt","",filcnt); if (filcnt == 1) { /* Get timing for statistics */ tsecs = xfsecs; /* Single file, we already have it */ #ifdef GFTIMER debug(F101,"tstats fpxfsecs","",(int)fpxfsecs); fptsecs = fpxfsecs; #endif /* GFTIMER */ } else { /* Multiple files */ tsecs = gtimer(); /* Get current time */ #ifdef GFTIMER fptsecs = gftimer(); #endif /* GFTIMER */ } #ifdef GFTIMER if (fptsecs <= GFMINTIME) /* Calculate CPS */ fptsecs = (CKFLOAT) GFMINTIME; debug(F101,"tstats fptsecs","",(int)fptsecs); xx = (CKFLOAT) tfc / fptsecs; if (sizeof(long) <= 4) { /* doesn't account for 16-bit longs */ if (xx > 2147483647.0) tfcps = 2147483647L; /* 31 bits */ else tfcps = (long) xx; } else tfcps = (long) xx; #else if (tsecs < 2L) tsecs = 1L; debug(F101,"tstats tsecs","",tsecs); tfcps = tfc / tsecs; #endif /* GFTIMER */ ztime(&tp); /* Get time stamp */ tlog(F100,"","",0L); /* Leave a blank line */ tlog(F110,"Transaction complete",tp,0L); /* Record it */ if (filcnt < 1) return; /* If no files, done. */ /* If multiple files, record character totals for all files */ if (filcnt > 1) { tlog(F101," files transferred ","",filcnt - filrej); tlog(F101," total file characters ","",tfc); tlog(F101," communication line in ","",tlci); tlog(F101," communication line out ","",tlco); } /* Record timing info for one or more files */ #ifdef GFTIMER if (filcnt - filrej == 1) { tlog(F101," elapsed time (seconds) ","",(long) fpxfsecs); tlog(F101," effective data rate ","",filcps); } else { tlog(F101," elapsed time (seconds) ","",(long) fptsecs); tlog(F101," effective data rate ","",(long) xx); } #else tlog(F101," elapsed time (seconds) ","",tsecs); if (tsecs > 0) tlog(F101," effective data rate ","",(tfc / tsecs)); #endif /* GFTIMER */ tlog(F100,"","",0L); /* Leave a blank line */ } /* F S T A T S -- Record file statistics in transaction log */ VOID fcps() { #ifdef GFTIMER double xx; fpxfsecs = gftimer() - fpfsecs; if (fpxfsecs <= GFMINTIME) fpxfsecs = (CKFLOAT) GFMINTIME; xx = (CKFLOAT) ffc / fpxfsecs; if (sizeof(long) <= 4) { if (xx > 2147483647.0) tfcps = 2147483647L; /* 31 bits */ else filcps = (long) xx; } else filcps = (long) xx; if (sizeof(int) >= 4) xfsecs = (int) fpxfsecs; else if (fpxfsecs < 32768.0) xfsecs = (int) fpxfsecs; else xfsecs = 32767; #else /* GFTIMER */ xfsecs = gtimer() - fsecs; if (xfsecs < 1L) xfsecs = 1L; filcps = ffc / xfsecs; #endif /* GFTIMER */ } VOID fstats() { tfc += ffc; #ifdef DEBUG if (deblog) { debug(F101,"fstats tfc","",tfc); debug(F101,"fstats what","",what); debug(F110,"fstats epktmsg",epktmsg,0); } #endif /* DEBUG */ #ifdef TLOG if (!discard && !cxseen && !czseen && what != W_NOTHING && !*epktmsg) tlog(F101," complete, size","",ffc); #endif /* TLOG */ } #endif /* NOXFER */ ckcfn3.c000664 045065 024037 00000233032 14767401632 012513 0ustar00fdckermit000000 000000 /* C K C F N 3 -- Packet buffer management for C-Kermit */ /* (plus assorted functions tacked on at the end) */ /* Author: Frank da Cruz , Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Last update: 15 April 2023 */ /* Note -- if you change this file, please amend the version number and date at the top of ckcfns.c accordingly. */ #include "ckcsym.h" #include "ckcdeb.h" #include "ckcasc.h" #include "ckcker.h" #include "ckcxla.h" #include "ckucmd.h" /* xx_strp */ #include "ckuusr.h" /* mtab */ #include "ckcnet.h" /* struct sockaddr */ #include "ckcfnp.h" /* Prototypes */ /* C K M K D I R -- Create a directory */ /* Call with: int fc = 0 to create, nonzero to remove, a directory. char * s = pointer to name of directory to create or remove. char ** r = address of pointer to return name or message. int m = 1 to print error messages, 0 to be silent. int cvt = 1 means convert s from standard format to local format; 0 means use s as is. Returns: 0 on success (directory was created or removed). -1 when attempt to create the directory failed. -2 on internal error (e.g. no code for creating directories). On success, the name is pointed to by p. On failure, the reason is pointed to by p. */ #ifdef CK_MKDIR static char ckmkdbuf[CKMAXPATH+1]; #else #ifdef datageneral static char ckmkdbuf[CKMAXPATH+1]; #endif /* datageneral */ #endif /* CK_MKDIR */ #ifdef CK_MKDIR int #ifdef CK_ANSIC ckmkdir( int fc, char * s, char ** r, int m, int cvt ) #else ckmkdir(fc,s,r,m,cvt) int fc; char * s; char ** r; int m; int cvt; #endif /* CK_ANSIC */ { int x, rc = -2; char tmpbuf[CKMAXPATH+1]; char buf2[CKMAXPATH+1]; if (!s) s = ""; debug(F110,"ckmkdir 1 fc",s,fc); if (!*s) { ckmakmsg(ckmkdbuf, CKMAXPATH+1, (fc == 0) ? "mkdir" : "rmdir", ": no name given", NULL, NULL ); *r = ckmkdbuf; return(-2); } #ifdef datageneral /* Come back and make this nicer later if anybody notices */ if (fc == 0) { /* mkdir */ rc = createdir(s,0); } else { /* rmdir */ /* AOS/VS rmdir() is a no-op. */ ckmakmsg(tmpbuf,CKMAXPATH+1,"delete ",s,NULL,NULL); debug(F110,"ckmkdir 2",tmpbuf,0); rc = system(tmpbuf); } *r = NULL; #else /* not datageneral */ /* First make sure the name has an acceptable directory-name format */ #ifdef VMS { char *p = s; int lb = 0, rb = 0, sl = 0; while (*p) { if (*p == '[' || *p == '<') lb++; /* Count brackets */ else if (*p == ']' || *p == '>') rb++; else if (*p == '/') sl++; /* and slashes */ p++; } if (lb != 1 && rb != 1 && sl == 0 && p > s && *(p-1) != ':') { /* Probably just a word - convert to VMS format */ ckmakmsg(buf2, CKMAXPATH+1, "[", (*s == '.') ? "" : ".", s, "]" ); s = buf2; } else if (lb == 0 && rb == 0 && sl != 0 && p > s && *(p-1) != ':') { int flag = 0; /* Seems to be in UNIX format */ x = strlen(s); if (x > 0 && s[x-1] != '/') flag = 1; ckmakmsg(buf2,CKMAXPATH+1,s,flag ? "/" : "",NULL,NULL); s = buf2; } if (s == buf2) { ckstrncpy(tmpbuf,s,CKMAXPATH+1); s = tmpbuf; } debug(F110,"ckmkdir 2+VMS",s,0); } #else #ifdef UNIXOROSK #ifdef DTILDE s = tilde_expand(s); #endif /* DTILDE */ ckstrncpy(tmpbuf,s,CKMAXPATH+1); s = tmpbuf; x = strlen(s); if (x > 0 && s[x-1] != '/') { /* Must end in "/" for zmkdir() */ s[x] = '/'; s[x+1] = NUL; debug(F110,"ckmkdir 2+UNIXOROSK",s,0); } #else /* UNIXOROSK */ #ifdef OS2 ckstrncpy(tmpbuf,s,CKMAXPATH+1); s = tmpbuf; x = strlen(s); if (fc == 0 && x > 0 && s[x-1] != '/') { /* Must end in "/" for zmkdir() */ s[x] = '/'; s[x+1] = NUL; debug(F110,"ckmkdir 2+OS2",s,0); } #endif /* OS2 */ #endif /* UNIXOROSK */ #endif /* VMS */ #ifdef NZLTOR /* Server is calling us, so convert to local format if necessary */ if (cvt) { nzrtol(s,(char *)buf2,1,PATH_ABS,CKMAXPATH); s = buf2; debug(F110,"ckmkdir 3",s,0); } #endif /* NZLTOR */ debug(F110,"ckmkdir 4",s,0); if (fc == 0) { /* Making */ #ifdef CK_MKDIR rc = zmkdir(s); #else #ifdef NT rc = _mkdir(s); #else rc = mkdir(s,0777); #endif /* NT */ #endif /* CK_MKDIR */ } else { /* Removing */ #ifdef ZRMDIR rc = zrmdir(s); #else #ifdef NT rc = _rmdir(s); #else #ifdef OSK rc = -2; #else rc = rmdir(s); #endif /* OSK */ #endif /* NT */ #endif /* ZRMDIR */ } #endif /* datageneral */ debug(F101,"ckmkdir rc","",rc); if (rc == -2) { ckmakmsg(ckmkdbuf, CKMAXPATH, "Directory ", (fc == 0) ? "creation" : "removal", "not implemented in this version of C-Kermit", NULL ); *r = ckmkdbuf; if (m) printf("%s\n",*r); } else if (rc < 0) { if (m) perror(s); ckmakmsg(ckmkdbuf,CKMAXPATH,s,": ",ck_errstr(),NULL); *r = ckmkdbuf; } else if (fc == 0 && zfnqfp(s,CKMAXPATH,ckmkdbuf)) { *r = ckmkdbuf; } else if (fc != 0) { ckmakmsg(ckmkdbuf,CKMAXPATH,s,": removed",NULL,NULL); *r = ckmkdbuf; } return(rc); } #endif /* CK_MKDIR */ #ifndef NOXFER /* Rest of this file... */ #ifndef NODISPO #ifdef pdp11 #define NODISPO #endif /* pdpd11 */ #endif /* NODISPO */ extern int pipesend; #ifdef PIPESEND extern char ** sndfilter; #endif /* PIPESEND */ extern int unkcs, wmax, wcur, discard, bctu, bctl, local, fdispla, what, sendmode, opnerr, dest, epktrcvd, epktsent, filestatus, eofmethod, dispos, fncnv, fnrpath; extern char * ofn2; extern char * rfspec, * sfspec, * prfspec, * psfspec, * rrfspec, * prrfspec; extern char ofn1[]; extern int ofn1x; extern char * ofperms; #ifdef VMS extern int batch; #else extern int backgrd; #endif /* VMS */ extern int xflg, remfile, remappd; extern CHAR *data; extern char filnam[]; #ifndef NOFRILLS extern int rprintf, rmailf; /* REMOTE MAIL, PRINT */ char optbuf[OPTBUFLEN]; /* Options for MAIL or REMOTE PRINT */ #endif /* NOFRILLS */ extern int wslots; extern int fblksiz, frecl, forg, frecfm, fncact, fncsav, fcctrl, lf_opts; extern CHAR * srvcmd; extern int srvcmdlen; extern int binary, spsiz, rpsiz; extern int pktnum, cxseen, czseen, nfils, stdinf; extern int memstr, stdouf, keep, sndsrc, hcflg; extern int server, en_cwd, en_mai, en_pri; /* Attributes in/out enabled flags */ extern int atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko, attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso; #ifdef CK_PERMS extern int atlpri, atlpro, atgpri, atgpro; #endif /* CK_PERMS */ #ifdef STRATUS extern int atfrmi, atfrmo, atcrei, atcreo, atacti, atacto; #endif /* STRATUS */ #ifdef datageneral extern int quiet; #endif /* datageneral */ extern long filcnt; extern CK_OFF_T fsize, ffc, tfc, sendstart, calibrate; CK_OFF_T rs_len; #ifndef NOCSETS _PROTOTYP (VOID setxlate, (void)); extern int tcharset, fcharset; extern int ntcsets, xlatype, xfrxla; extern struct csinfo tcsinfo[], fcsinfo[]; #endif /* NOCSETS */ /* Variables global to Kermit that are defined in this module */ #ifdef CKXXCHAR /* DOUBLE / IGNORE char table */ int dblflag = 0; int ignflag = 0; short dblt[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; #endif /* CKXXCHAR */ int winlo; /* packet number at low window edge */ int sbufnum; /* number of free buffers */ int dum001 = 1234; /* protection... */ int sbufuse[MAXWS]; /* buffer in-use flag */ int dum003 = 1111; int rbufnum; /* number of free buffers */ int dum002 = 4321; /* more protection */ int rbufuse[MAXWS]; /* buffer in-use flag */ int sseqtbl[64]; /* sequence # to buffer # table */ int rseqtbl[64]; /* sequence # to buffer # table */ int sacktbl[64]; /* sequence # ack table */ int o_isopen = 0, i_isopen = 0; /* Input & output files are open */ #ifdef DYNAMIC struct pktinfo *s_pkt = NULL; /* array of pktinfo structures */ struct pktinfo *r_pkt = NULL; /* array of pktinfo structures */ #else struct pktinfo s_pkt[MAXWS]; /* array of pktinfo structures */ struct pktinfo r_pkt[MAXWS]; /* array of pktinfo structures */ #endif /* DYNAMIC */ #ifdef DEBUG char xbuf[200]; /* For debug logging */ #endif /* DEBUG */ #ifdef DYNAMIC CHAR *bigsbuf = NULL, *bigrbuf = NULL; #else char bigsbt[8]; /* Protection (shouldn't need this). */ /* BUT DON'T REMOVE IT! */ CHAR bigsbuf[SBSIZ + 5]; /* Send-packet buffer area */ char bigrbt[8]; /* Safety padding */ CHAR bigrbuf[RBSIZ + 5]; /* Receive-packet area */ #endif int bigsbsiz = SBSIZ; /* Sizes of big send & rcv buffers. */ int bigrbsiz = RBSIZ; #ifdef VMS int zchkpath(char *s); #endif /* VMS */ /* FUNCTIONS */ VOID dofast() { long maxbufsiz = RBSIZ; /* Configuration parameters */ int maxpktsiz = MAXSP; extern int spsizf, /* For bug in IRIX Telnet server */ rpsiz, urpsiz, spsizr, spmax, wslotr; extern struct ck_p ptab[]; if (maxpktsiz < 40) /* Long packet length */ maxpktsiz = 40; else if (maxpktsiz > 4000) maxpktsiz = 4000; wslotr = maxbufsiz / maxpktsiz; if (wslotr > MAXWS) /* Window slots */ wslotr = MAXWS; if (wslotr > 30) wslotr = 30; else if (wslotr < 1) wslotr = 1; urpsiz = adjpkl(maxpktsiz,wslotr,maxbufsiz); ptab[PROTO_K].rpktlen = urpsiz; rpsiz = (urpsiz > 94) ? 94 : urpsiz; /* Max non-long packet length */ debug(F111,"dofast","uprsiz",urpsiz); #ifdef IRIX #ifndef IRIX65 /* IRIX Telnet server chops off writes longer than 4K */ spsiz = spmax = spsizr = urpsiz; debug(F101,"doarg Q IRIX spsiz","",spsiz); spsizf = 1; #endif /* IRIX65 */ #endif /* IRIX */ #ifdef CK_SPEED setprefix(PX_CAU); /* Cautious unprefixing */ #endif /* CK_SPEED */ } /* For sanity, use "i" for buffer slots, "n" for packet numbers. */ /* I N I B U F S */ /* Allocates the big send and receive buffers. Call with size for big send buffer (s) and receive buffer (r). These sizes can be different. Attempts to allocate buffers of the requested size, but if it can't, it will allocate smaller ones. Sets global variables bigsbsiz and bigrbsiz to the actual sizes, and bigsbuf and bigrbuf pointing to the actual buffers. Designed to be called more than once. Returns 0 on success, -1 on failure. */ CHAR *bigbufp = NULL; int #ifdef CK_ANSIC inibufs( int s, int r ) #else inibufs(s,r) int s, r; #endif /* CK_ANSIC */ { #ifdef DYNAMIC unsigned int size; #ifdef OS2 unsigned /* Don't you wish everybody had unsigned long... */ #endif /* OS2 */ long z; int x; debug(F101,"inibufs s","",s); debug(F101,"inibufs r","",r); if (s < 80 || r < 80) return(-1); /* Validate arguments. */ if (!s_pkt) { /* Allocate packet info structures */ if (!(s_pkt = (struct pktinfo *) malloc(sizeof(struct pktinfo)*MAXWS))) fatal("ini_pkts: no memory for s_pkt"); } for (x = 0; x < MAXWS; x++) s_pkt[x].pk_adr = NULL; /* Initialize addresses */ if (!r_pkt) { if (!(r_pkt = (struct pktinfo *) malloc(sizeof(struct pktinfo)*MAXWS))) fatal("ini_pkts: no memory for s_pkt"); } for (x = 0; x < MAXWS; x++) r_pkt[x].pk_adr = NULL; /* Initialize addresses */ if (!srvcmd) { /* Allocate srvcmd buffer */ srvcmd = (CHAR *) malloc(r + 100); if (!srvcmd) return(-1); srvcmdlen = r + 99; *srvcmd = NUL; } if (bigbufp) { /* Free previous buffers, if any. */ free(bigbufp); bigbufp = NULL; } size = s + r + 40; /* Combined requested size + padding */ z = (unsigned) s + (unsigned) r + 40; debug(F101,"inibufs size 1","",size); debug(F101,"inibufs size z","",z); if ((long) size != z) { debug(F100,"inibufs overflow","",0); size = 65535; } /* Try to get the space. If malloc fails, try to get a little less. */ /* (Obviously, this algorithm can be refined.) */ while (!(bigbufp = (CHAR *) malloc(size))) { debug(F101,"inibufs bigbuf malloc failed","",size); size = (size * 2) / 3; /* Failed, cut size by 1/3. */ if (size < 200) /* Try again until too small. */ return(-1); } debug(F101,"inibufs size 2","",size); /* OK, we got some space. */ /* Now divide the allocated space between the send and receive buffers in the requested proportion. The natural formula would be (s / (s + r)) * size (for the send buffer), but that doesn't work with integer arithmetic and we can't use floating point because some machines don't have it. This can be rearranged as (s * size) / (s + r). But (s * size) can be VERY large, too large for 32 bits. So let's do it this way. This arithmetic works for buffer sizes up to about 5,000,000. */ #define FACTOR 20L z = ( (long) s * FACTOR ) / ( (long) s + (long) r ); x = ( z * ( (long) size / FACTOR ) ); if (x < 0) return(-1); /* Catch overflow */ bigsbsiz = x - 5; /* Size of send buffer */ bigsbuf = bigbufp; /* Address of send buffer */ debug(F101,"inibufs bigsbsiz","",bigsbsiz); bigrbsiz = size - x - 5; /* Size of receive buffer */ bigrbuf = bigbufp + x; /* Addresss of receive buffer */ debug(F101,"inibufs bigrbsiz","",bigrbsiz); return(0); /* Success */ #else /* No dynamic allocation */ bigsbsiz = SBSIZ; /* Just use the symbols */ bigrbsiz = RBSIZ; /* ... */ return(0); /* Success. */ #endif /* DYNAMIC */ } /* M A K E B U F -- Makes and clears a new buffers. */ /* Call with: */ /* slots: number of buffer slots to make, 1 to 32 */ /* bufsiz: size of the big buffer */ /* buf: address of the big buffer */ /* xx: pointer to array of pktinfo structures for these buffers */ /* Subdivides the big buffer into "slots" buffers. */ /* Returns: */ /* -1 if too many or too few slots requested, */ /* -2 if slots would be too small. */ /* n (positive) on success = size of one buffer. */ /* with pktinfo structure initialized for this set of buffers. */ int #ifdef CK_ANSIC makebuf( int slots, int bufsiz, CHAR buf[], struct pktinfo *xx ) #else makebuf(slots,bufsiz,buf,xx) int slots, bufsiz; CHAR buf[]; struct pktinfo *xx; #endif /* CK_ANSIC */ { /* makebuf */ CHAR *a; int i, size; debug(F101,"makebuf","",slots); debug(F101,"makebuf bufsiz","",bufsiz); debug(F101,"makebuf MAXWS","",MAXWS); if (slots > MAXWS || slots < 1) return(-1); if (bufsiz < slots * 10 ) return(-2); size = bufsiz / slots; /* Divide up the big buffer. */ a = buf; /* Address of first piece. */ for (i = 0; i < slots; i++) { struct pktinfo *x = &xx[i]; x->bf_adr = a; /* Address of this buffer */ x->bf_len = size; /* Length of this buffer */ x->pk_len = 0; /* Length of data field */ x->pk_typ = ' '; /* packet type */ x->pk_seq = -1; /* packet sequence number */ x->pk_rtr = 0; /* retransmissions */ *a = '\0'; /* Clear the buffer */ a += size; /* Position to next buffer slot */ } return(size); } /* M A K S B U F -- Makes the send-packet buffer */ int #ifdef CK_ANSIC mksbuf( int slots ) #else mksbuf(slots) int slots; #endif /* CK_ANSIC */ { int i, x; sbufnum = 0; if ((x = makebuf(slots,bigsbsiz,bigsbuf,s_pkt)) < 0) { debug(F101,"mksbuf makebuf return","",x); return(x); } debug(F101,"mksbuf makebuf return","",x); for (i = 0; i < 64; i++) { /* Initialize sequence-number- */ sseqtbl[i] = -1; /* to-buffer-number table. */ sacktbl[i] = 0; } for (i = 0; i < MAXWS; i++) sbufuse[i] = 0; /* Mark each buffer as free */ sbufnum = slots; wcur = 0; return(x); } /* M A K R B U F -- Makes the receive-packet buffer */ int #ifdef CK_ANSIC mkrbuf( int slots ) #else mkrbuf(slots) int slots; #endif /* CK_ANSIC */ { int i, x; rbufnum = 0; if ((x = makebuf(slots,bigrbsiz,bigrbuf,r_pkt)) < 0) { debug(F101,"mkrbuf makebuf return","",x); return(x); } debug(F101,"mkrbuf makebuf return","",x); for (i = 0; i < 64; i++) { /* Initialize sequence-number- */ rseqtbl[i] = -1; /* to-buffer-number table. */ } for (i = 0; i < MAXWS; i++) rbufuse[i] = 0; /* Mark each buffer as free */ rbufnum = slots; wcur = 0; return(x); } /* W I N D O W -- Resize the window to n */ int #ifdef CK_ANSIC window( int n ) #else window(n) int n; #endif /* CK_ANSIC */ { debug(F101,"window","",n); if (n < 1 || n > MAXWS) return(-1); if (mksbuf(n) < 0) return(-1); if (mkrbuf(n) < 0) return(-1); wslots = n; #ifdef DEBUG if (deblog) dumpsbuf(); if (deblog) dumprbuf(); #endif /* DEBUG */ return(0); } /* G E T S B U F -- Allocate a send-buffer. */ /* Call with packet sequence number to allocate buffer for. */ /* Returns: */ /* -4 if argument is invalid (negative, or greater than 63) */ /* -3 if buffers were thought to be available but really weren't (bug!) */ /* -2 if the number of free buffers is negative (bug!) */ /* -1 if no free buffers. */ /* 0 or positive, packet sequence number, with buffer allocated for it. */ int #ifdef CK_ANSIC getsbuf( int n ) /* Allocate a send-buffer */ #else getsbuf(n) int n; #endif /* CK_ANSIC */ { int i; CHAR * p = NULL; if (n < 0 || n > 63) { debug(F101,"getsbuf bad arg","",n); return(-4); /* Bad argument */ } debug(F101,"getsbuf packet","",n); /* debug(F101,"getsbuf, sbufnum","",sbufnum); */ if (sbufnum == 0) return(-1); /* No free buffers. */ if (sbufnum < 0) return(-2); /* Shouldn't happen. */ for (i = 0; i < wslots; i++) /* Find the first one not in use. */ if (sbufuse[i] == 0) { /* Got one? */ sbufuse[i] = 1; /* Mark it as in use. */ sbufnum--; /* One less free buffer. */ *s_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */ s_pkt[i].pk_seq = n; /* Put in the sequence number */ sseqtbl[n] = i; /* Back pointer from sequence number */ sacktbl[n] = 0; /* ACK flag */ s_pkt[i].pk_len = 0; /* Data field length now zero. */ s_pkt[i].pk_typ = ' '; /* Blank the packet type too. */ s_pkt[i].pk_rtr = 0; /* Zero the retransmission count */ p = s_pkt[i].bf_adr + 7; /* Set global "data" address. */ debug(F101,"getsbuf p","",0); data = p; if (!data) { debug(F100,"getsbuf data == NULL","",0); return(-3); } if ((what & (W_SEND|W_REMO)) && (++wcur > wmax)) wmax = wcur; /* For statistics. */ /* debug(F101,"getsbuf wcur","",wcur); */ return(n); /* Return its index. */ } sbufnum = 0; /* Didn't find one. */ return(-3); /* Shouldn't happen! */ } int getrbuf() { /* Allocate a receive buffer */ int i; #ifdef COMMENT /* This code is pretty stable by now... */ /* Looks like we might need this after all */ debug(F101,"getrbuf rbufnum","",rbufnum); debug(F101,"getrbuf wslots","",wslots); debug(F101,"getrbuf dum002","",dum002); debug(F101,"getrbuf dum003","",dum003); #endif /* COMMENT */ if (rbufnum == 0) return(-1); /* No free buffers. */ if (rbufnum < 0) return(-2); /* Shouldn't happen. */ for (i = 0; i < wslots; i++) /* Find the first one not in use. */ if (rbufuse[i] == 0) { /* Got one? */ rbufuse[i] = 1; /* Mark it as in use. */ *r_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */ rbufnum--; /* One less free buffer. */ debug(F101,"getrbuf new rbufnum","",rbufnum); if ((what & W_RECV) && (++wcur > wmax)) wmax = wcur; /* For statistics. */ /* debug(F101,"getrbuf wcur","",wcur); */ return(i); /* Return its index. */ } /* debug(F101,"getrbuf foulup","",i); */ rbufnum = 0; /* Didn't find one. */ return(-3); /* Shouldn't happen! */ } /* F R E E S B U F -- Free send-buffer for given packet sequence number */ /* Returns: */ /* 1 upon success */ /* -1 if specified buffer does not exist */ int #ifdef CK_ANSIC freesbuf( int n ) /* Release send-buffer for packet n. */ #else freesbuf(n) int n; #endif /* CK_ANSIC */ { int i; debug(F101,"freesbuf","",n); if (n < 0 || n > 63) /* No such packet. */ return(-1); i = sseqtbl[n]; /* Get the window slot number. */ if (i > -1 && i <= wslots) { sseqtbl[n] = -1; /* If valid, remove from seqtbl */ sbufnum++; /* and count one more free buffer */ sbufuse[i] = 0; /* and mark it as free, */ if (what & (W_SEND|W_REMO)) /* decrement active slots */ wcur--; /* for statistics and display. */ } else { debug(F101," sseqtbl[n]","",sseqtbl[n]); return(-1); } /* The following is done only so dumped buffers will look right. */ if (1) { *s_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */ s_pkt[i].pk_seq = -1; /* Invalidate the sequence number */ s_pkt[i].pk_len = 0; /* Data field length now zero. */ s_pkt[i].pk_typ = ' '; /* Blank the packet type too. */ s_pkt[i].pk_rtr = 0; /* And the retries field. */ } return(1); } int #ifdef CK_ANSIC freerbuf( int i ) /* Release receive-buffer slot "i". */ #else freerbuf(i) int i; #endif /* CK_ANSIC */ { int n; /* NOTE !! Currently, this function frees the indicated buffer, but */ /* does NOT erase the data. The program counts on this. Will find a */ /* better way later.... */ /* debug(F101,"freerbuf, slot","",i); */ if (i < 0 || i >= wslots) { /* No such slot. */ debug(F101,"freerbuf no such slot","",i); return(-1); } n = r_pkt[i].pk_seq; /* Get the packet sequence number */ debug(F101,"freerbuf packet","",n); if (n > -1 && n < 64) /* If valid, remove from seqtbl */ rseqtbl[n] = -1; if (rbufuse[i] != 0) { /* If really allocated, */ rbufuse[i] = 0; /* mark it as free, */ rbufnum++; /* and count one more free buffer. */ if (what & W_RECV) /* Keep track of current slots */ wcur--; /* for statistics and display */ debug(F101,"freerbuf rbufnum","",rbufnum); } /* The following is done only so dumped buffers will look right. */ if (1) { /* *r_pkt[i].bf_adr = '\0'; */ /* Zero the buffer data field */ r_pkt[i].pk_seq = -1; /* And from packet list */ r_pkt[i].pk_len = 0; /* Data field length now zero. */ r_pkt[i].pk_typ = ' '; /* Blank the packet type too. */ r_pkt[i].pk_rtr = 0; /* And the retries field. */ } return(1); } /* This is like freerbuf, except it's called with a packet sequence number */ /* rather than a packet buffer index. */ VOID #ifdef CK_ANSIC freerpkt( int seq ) #else freerpkt(seq) int seq; #endif /* CK_ANSIC */ { int k; debug(F101,"freerpkt seq","",seq); k = rseqtbl[seq]; /* debug(F101,"freerpkt k","",k); */ if (k > -1) { k = freerbuf(k); /* debug(F101,"freerpkt freerbuf","",k); */ } } /* C H K W I N -- Check if packet n is in window. */ /* Returns: */ /* 0 if it is in the current window, */ /* +1 if it would have been in previous window (e.g. if ack was lost), */ /* -1 if it is outside any window (protocol error), */ /* -2 if either of the argument packet numbers is out of range. */ /* Call with packet number to check (n), lowest packet number in window */ /* (bottom), and number of slots in window (slots). */ int #ifdef CK_ANSIC chkwin( int n, int bottom, int slots ) #else chkwin(n,bottom,slots) int n, bottom, slots; #endif /* CK_ANSIC */ { int top, prev; debug(F101,"chkwin packet","",n); debug(F101,"chkwin winlo","",bottom); debug(F101,"chkwin slots","",slots); /* First do the easy and common cases, where the windows are not split. */ if (n < 0 || n > 63 || bottom < 0 || bottom > 63) return(-2); if (n == bottom) return(0); /* In a perfect world... */ top = bottom + slots; /* Calculate window top. */ if (top < 64 && n < top && n >= bottom) return(0); /* In current window. */ prev = bottom - slots; /* Bottom of previous window. */ if (prev > -1 && n < bottom && n > prev) return(1); /* In previous. */ /* Now consider the case where the current window is split. */ if (top > 63) { /* Wraparound... */ top -= 64; /* Get modulo-64 sequence number */ if (n < top || n >= bottom) { return(0); /* In current window. */ } else { /* Not in current window. */ if (n < bottom && n >= prev) /* Previous window can't be split. */ return(1); /* In previous window. */ else return(-1); /* Not in previous window. */ } } /* Now the case where current window not split, but previous window is. */ if (prev < 0) { /* Is previous window split? */ prev += 64; /* Yes. */ if (n < bottom || n >= prev) return(1); /* In previous window. */ } else { /* Previous window not split. */ if (n < bottom && n >= prev) return(1); /* In previous window. */ } /* It's not in the current window, and not in the previous window... */ return(-1); /* So it's not in any window. */ } int dumpsbuf() { /* Dump send-buffers */ #ifdef DEBUG int j, x, z; /* to debug log. */ if (! deblog) return(0); x = zsoutl(ZDFILE,"SEND BUFFERS:"); if (x < 0) { deblog = 0; return(0); } x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries"); if (x < 0) { deblog = 0; return(0); } for (j = 0; j < wslots; j++) { if (!sbufuse[j]) continue; z = ((unsigned long)(s_pkt[j].bf_adr)) & 0xffff; sprintf(xbuf, /* safe (200) */ "%4d%6d%10d%5d%6d%4c%5d%6d\n", j, sbufuse[j], /* Avoid warnings when addresses are bigger than ints */ z, s_pkt[j].bf_len, s_pkt[j].pk_len, s_pkt[j].pk_typ, s_pkt[j].pk_seq, s_pkt[j].pk_rtr ); if (zsout(ZDFILE,xbuf) < 0) { deblog = 0; return(0); } if (s_pkt[j].pk_adr) { x = (int)strlen((char *) s_pkt[j].pk_adr); if (x) sprintf(xbuf, /* safe (checked) */ "[%.72s%s]\n",s_pkt[j].pk_adr, x > 72 ? "..." : ""); else sprintf(xbuf,"[(empty string)]\n"); /* safe (200) */ } else { sprintf(xbuf,"[(null pointer)]\n"); /* safe (200) */ } if (zsout(ZDFILE,xbuf) < 0) { deblog = 0; return(0); } } sprintf(xbuf,"free: %d, winlo: %d\n", sbufnum, winlo); /* safe (200) */ if (zsout(ZDFILE,xbuf) < 0) { deblog = 0; return(0); } #endif /* DEBUG */ return(0); } int dumprbuf() { /* Dump receive-buffers */ #ifdef DEBUG int j, x, z; if (! deblog) return(0); if (zsoutl(ZDFILE,"RECEIVE BUFFERS:") < 0) { deblog = 0; return(0); } x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries"); if (x < 0) { deblog = 0; return(0); } for ( j = 0; j < wslots; j++ ) { if (!rbufuse[j]) continue; z = ((unsigned long)(r_pkt[j].bf_adr)) & 0xffff; sprintf(xbuf, /* 200, safe */ "%4d%6d%10d%5d%6d%4c%5d%6d\n", j, rbufuse[j], /* Avoid warnings when addresses are bigger than ints */ z, r_pkt[j].bf_len, r_pkt[j].pk_len, r_pkt[j].pk_typ, r_pkt[j].pk_seq, r_pkt[j].pk_rtr ); if (zsout(ZDFILE,xbuf) < 0) { deblog = 0; return(0); } x = (int)strlen((char *)r_pkt[j].bf_adr); sprintf(xbuf, /* safe (checked) */ "[%.72s%s]\n",r_pkt[j].bf_adr, x > 72 ? "..." : ""); if (zsout(ZDFILE,xbuf) < 0) { deblog = 0; return(0); } } sprintf(xbuf,"free: %d, winlo: %d\n", rbufnum, winlo); /* safe (200) */ if (zsout(ZDFILE,xbuf) < 0) { deblog = 0; return(0); } #endif /* DEBUG */ return(0); } /* S A T T R -- Send an Attribute Packet */ /* Sends attribute packet(s) for the current file. If the info will not fit into one packet, it can be called repeatedly until all the fields that will fit are sent. Call with: xp == 0 if we're sending a real file (F packet), or: xp != 0 for screen data (X packet). And: flag == 1 for first A packet flag == 0 for subsequent A packets. Returns: 1 or greater if an A packet was sent, or: 0 if an S-packet was not sent because there was no data to send or there was no data left that was short enough to send, or: -1 on any kind of error. */ /* (don't) #define TSOFORMAT */ /* which was only for making C-Kermit send TSO-Kermit-like A packets */ /* to try to track down a problem somebody reported... */ int #ifdef CK_ANSIC sattr( int xp, int flag ) /* Send Attributes */ #else sattr(xp, flag) int xp, flag; #endif /* CK_ANSIC */ { static int max; /* Maximum length for Attributes */ static short done[95]; /* Field-complete array */ static struct zattr x; /* File attribute struct */ static char xdate[24]; extern char * cksysid; /* Some extra flags are used because the "done" array is sparse */ int i, j, rc, aln, left = 0, numset = 0, xbin = 0; /* Workers */ int notafile = 0; char *tp, c; notafile = sndarray || pipesend || #ifdef PIPESEND sndfilter || #endif /* PIPESEND */ calibrate; debug(F101,"sattr flag","",flag); if (!flag) /* No more attributes to send */ if (done[xunchar('@')]) return(0); /* Initialize Attribute mechanism */ if (flag) { /* First time here for this file? */ initattr(&x); /* Blank out all the fields. */ for (j = 0; j < 95; j++) /* Init array of completed fields */ done[j] = 0; #ifdef COMMENT /* 28 October 2021: This is an administrative packet, it must not be truncated because of user command SET SEND PACKET-LENGTH 10 or other small number. (Even though attributes can be sent in multiple packets, any given attribute might be longer than spsiz, e.g. date-time.) */ max = maxdata(); /* Get maximum data field length */ #else max = rpsiz; /* Get maximum data field length */ #endif /* COMMENT */ if (notafile || xp == 1) { /* Is it not a real file? */ extern char * zzndate(); char * p; int i; #ifdef CALIBRATE if (calibrate) { /* Calibration run... */ x.lengthk = calibrate / 1024L; /* We know the length */ x.length = calibrate; } #endif /* CALIBRATE */ x.systemid.val = cksysid; /* System ID */ x.systemid.len = (int)strlen(cksysid); ckstrncpy(xdate,zzndate(),24); xdate[8] = SP; ztime(&p); for (i = 11; i < 19; i++) /* copy hh:mm:ss */ xdate[i - 2] = p[i]; /* to xdate */ xdate[17] = NUL; /* terminate */ x.date.val = xdate; x.date.len = 17; debug(F111,"sattr notafile date",x.date.val,x.date.len); } else { /* Real file */ rc = zsattr(&x); /* Get attributes for this file */ debug(F101,"sattr zsattr","",rc); if (rc < 0) /* Can't get 'em so don't send 'em */ return(0); debug(F101,"sattr init max","",max); } } if (nxtpkt() < 0) /* Got 'em, get next packet number */ return(-1); /* Bad news if we can't */ i = 0; /* Init data field character number */ /* Do each attribute using first-fit method, marking as we go */ /* This is rather long and repititious - could be done more cleverly */ if (atsido && !done[xunchar(c = '.')]) { /* System type */ if (max - i >= x.systemid.len + 2) { /* Enough space ? */ data[i++] = c; /* Yes, add parameter */ data[i++] = tochar(x.systemid.len); /* Add length */ for (j = 0; j < x.systemid.len; j++) /* Add data */ data[i++] = x.systemid.val[j]; numset++; /* Count that we did at least one */ done[xunchar(c)] = 1; /* Mark this attribute as done */ } else /* No */ left++; /* so mark this one left to do */ } #ifdef STRATUS if (atcreo && !done[xunchar(c = '$')]) { /* Creator */ if (max - i >= x.creator.len + 2) { /* Enough space ? */ data[i++] = c; data[i++] = tochar(x.creator.len); for (j = 0; j < x.creator.len; j++) data[i++] = x.creator.val[j]; numset++; done[xunchar(c)] = 1; } else left++; } if (atacto && !done[xunchar(c = '%')]) { /* File account */ if (max - i >= x.account.len + 2) { data[i++] = c; data[i++] = tochar(x.account.len); for (j = 0; j < x.account.len; j++) data[i++] = x.account.val[j]; numset++; done[xunchar(c)] = 1; } else left++; } if (atfrmo && !done[xunchar(c = '/')]) { /* Packet data format */ if (max - i >= x.recfm.len + 2) { data[i++] = c; data[i++] = tochar(x.recfm.len); /* Copy from attr structure */ for (j = 0; j < x.recfm.len; j++) data[i++] = x.recfm.val[j]; numset++; done[xunchar(c)] = 1; } else left++; } #endif /* STRATUS */ xbin = /* Is the transfer in binary mode? */ #ifdef VMS binary == XYFT_I || binary == XYFT_L || /* IMAGE or LABELED */ !strncmp(x.recfm.val,"F",1) /* or RECFM=Fxxxxxx */ #else binary /* User said SET FILE TYPE BINARY */ #endif /* VMS */ ; if (attypo && !done[xunchar(c = '"')]) { /* File type */ if (max - i >= 5) { /* Max length for this field */ data[i++] = c; if (xbin) { /* Binary */ data[i++] = tochar(2); /* Two characters */ data[i++] = 'B'; /* B for Binary */ data[i++] = '8'; /* 8-bit bytes (note assumption...) */ #ifdef CK_LABELED if (binary != XYFT_L #ifdef VMS && binary != XYFT_I #endif /* VMS */ ) binary = XYFT_B; #endif /* CK_LABELED */ } else { /* Text */ #ifdef TSOFORMAT data[i++] = tochar(1); /* One character */ data[i++] = 'A'; /* A = (extended) ASCII with CRLFs */ #else data[i++] = tochar(3); /* Three characters */ data[i++] = 'A'; /* A = (extended) ASCII with CRLFs */ data[i++] = 'M'; /* M for carriage return */ data[i++] = 'J'; /* J for linefeed */ #endif /* TSOFORMAT */ #ifdef VMS binary = XYFT_T; /* We automatically detected text */ #endif /* VMS */ } numset++; done[xunchar(c)] = 1; } else left++; } #ifdef TSOFORMAT if (attypo && !xbin && !done[xunchar(c = '/')]) { /* Record format */ if (max - i >= 5) { data[i++] = c; data[i++] = tochar(3); /* Three characters */ data[i++] = 'A'; /* A = variable with CRLFs */ data[i++] = 'M'; /* M for carriage return */ data[i++] = 'J'; /* J for linefeed */ } } #endif /* TSOFORMAT */ if (attypo && !xbin && !done[xunchar(c = '*')]) { /* Text encoding */ #ifdef NOCSETS if (max - i >= 3) { data[i++] = c; data[i++] = tochar(1); /* Length of value is 1 */ data[i++] = 'A'; /* A for ASCII */ numset++; done[xunchar(c)] = 1; } else left++; #else if (tcharset == TC_TRANSP || !xfrxla) { /* Transfer character set */ if (max - i >= 3) { data[i++] = c; /* Encoding */ data[i++] = tochar(1); /* Length of value is 1 */ data[i++] = 'A'; /* A for ASCII (i.e. text) */ numset++; done[xunchar(c)] = 1; } else left++; } else { tp = tcsinfo[tcharset].designator; if (!tp) tp = ""; aln = strlen(tp); if (aln > 0) { if (max - i >= aln + 2) { data[i++] = c; /* Encoding */ data[i++] = tochar(aln+1); /* Length of designator. */ data[i++] = 'C'; /* Text in specified charset. */ for (j = 0; j < aln; j++) /* Copy designator */ data[i++] = *tp++; /* Example: *&I6/100 */ numset++; done[xunchar(c)] = 1; } else left++; } else done[xunchar(c)] = 1; } #endif /* NOCSETS */ } if (atdato && !done[xunchar(c = '#')] && /* Creation date, if any */ (aln = x.date.len) > 0) { if (max - i >= aln + 2) { data[i++] = c; data[i++] = tochar(aln); for (j = 0; j < aln; j++) data[i++] = x.date.val[j]; numset++; done[xunchar(c)] = 1; } else left++; } /* File length in K */ if (atleno && !done[xunchar(c = '!')] && x.lengthk > (CK_OFF_T)-1) { #ifdef COMMENT sprintf((char *) &data[i+2],"%ld",x.lengthk); /* safe */ #else ckstrncpy((char *)&data[i+2],ckfstoa(x.lengthk),32); #endif /* COMMENT */ aln = (int)strlen((char *)(data+i+2)); if (max - i >= aln + 2) { data[i] = c; data[i+1] = tochar(aln); i += aln + 2; numset++; done[xunchar(c)] = 1; } else { data[i] = NUL; left++; } } /* File length in bytes */ if (atleno && !done[xunchar(c = '1')] && x.length > (CK_OFF_T)-1) { #ifdef COMMENT sprintf((char *) &data[i+2],"%ld",x.length); /* safe */ #else ckstrncpy((char *)&data[i+2],ckfstoa(x.length),32); #endif /* COMMENT */ aln = (int)strlen((char *)(data+i+2)); if (max - i >= aln + 2) { data[i] = c; data[i+1] = tochar(aln); i += aln + 2; numset++; done[xunchar(c)] = 1; } else { data[i] = NUL; left++; } } #ifdef CK_PERMS if (atlpro && !done[xunchar(c = ',')] && /* Local protection */ (aln = x.lprotect.len) > 0 && !notafile && xp == 0) { if (max - i >= aln + 2) { data[i++] = c; data[i++] = tochar(aln); for (j = 0; j < aln; j++) data[i++] = x.lprotect.val[j]; numset++; done[xunchar(c)] = 1; } else left++; } if (atgpro && !done[xunchar(c = '-')] && /* Generic protection */ (aln = x.gprotect.len) > 0 && !notafile && xp == 0) { if (max - i >= aln + 2) { data[i++] = c; data[i++] = tochar(aln); for (j = 0; j < aln; j++) data[i++] = x.gprotect.val[j]; numset++; done[xunchar(c)] = 1; } else left++; } #endif /* CK_PERMS */ if (atblko && fblksiz && !done[xunchar(c = '(')] && !notafile && xp == 0) { /* Blocksize */ sprintf((char *) &data[i+2],"%d",fblksiz); /* safe */ aln = (int)strlen((char *)(data+i+2)); if (max - i >= aln + 2) { data[i] = c; data[i+1] = tochar(aln); i += aln + 2; numset++; done[xunchar(c)] = 1; } else { data[i] = NUL; left++; } } #ifndef NOFRILLS if ((rprintf || rmailf) && atdiso && /* MAIL, or REMOTE PRINT? */ !done[xunchar(c = '+')]) { aln = (int) strlen(optbuf) + 1; /* Options, if any */ if (max - i >= aln + 2) { data[i++] = c; /* Disposition */ data[i++] = tochar(aln); /* Options, if any */ if (rprintf) data[i++] = 'P'; /* P for Print */ else data[i++] = 'M'; /* M for Mail */ for (j = 0; optbuf[j]; j++) /* Copy any options */ data[i++] = optbuf[j]; numset++; done[xunchar(c)] = 1; } else { data[i] = NUL; left++; } } #endif /* NOFRILLS */ #ifdef CK_RESEND if (sendmode == SM_RESEND && !done[xunchar(c = '+')]) { if (max - i >= 3) { data[i++] = c; /* Disposition */ data[i++] = tochar(1); data[i++] = 'R'; /* is RESEND */ numset++; done[xunchar(c)] = 1; } else left++; } #endif /* CK_RESEND */ /* End of Attributes -- to be sent only after sending all others */ debug(F111,"sattr","@",i); debug(F101,"sattr numset","",numset); debug(F101,"sattr left","",left); if ((left == 0 || numset == 0) && !done[xunchar(c = '@')]) { if (max - i >= 3) { data[i++] = c; /* End of Attributes */ data[i++] = SP; /* Length 0 */ data[i] = NUL; /* Make sure it's null-terminated */ numset++; done[xunchar(c)] = 1; } } /* Finished - send the packet off if we have anything in it */ if (numset) { data[i] = NUL; /* Terminate last good field */ debug(F111,"sattr sending",data,left); aln = (int)strlen((char *)data); /* Get overall length of attributes */ return(spack('A',pktnum,aln,data)); /* Send it */ } else return(0); } static char *refused = ""; static char *reason[] = { "size", "type", "date", "creator", "account", "area", "password", "blocksize", "access", "encoding", "disposition", "protection", "protection", "origin", "format", "sys-dependent", /* 0 */ "size", /* 1 */ "2", /* 2 */ "3", /* 3 */ "4", /* 4 */ "5", /* 5 */ "6", /* 6 */ "7", /* 7 */ "8", /* 8 */ "9", /* 9 */ ":", /* : */ ";", /* ; */ "<", /* < */ "=", /* = */ ">", /* > */ "name", /* ? */ "@" }; static int nreason = sizeof(reason) / sizeof(char *); int rejection = -1; char * #ifdef CK_ANSIC getreason( char *s ) /* Decode attribute refusal reason */ #else getreason(s) char *s; #endif /* CK_ANSIC */ { char c, *p; if (rejection == 1) /* Kludge for SET FIL COLL DISCARD */ return("name"); /* when other Kermit doesn't... */ p = s; if (*p++ != 'N') return(""); /* Should start with N */ else if ((c = *p) > SP) { /* get reason, */ rejection = c; /* remember it, */ c -= '!'; /* get offset */ p = ((unsigned int) ((CHAR) c) <= (unsigned int) nreason) ? reason[c] : "unknown"; } return(p); } int #ifdef CK_ANSIC rsattr( CHAR *s ) /* Read response to attribute packet */ #else rsattr(s) CHAR *s; #endif /* CK_ANSIC */ { debug(F111,"rsattr",s,*s); if (*s == 'N') { /* If it's 'N' followed by anything, */ refused = getreason((char *)s); /* they are refusing, get reason. */ debug(F110,"rsattr refused",refused,0); tlog(F110," refused:",refused,0L); return(-1); } #ifdef CK_RESEND if (sendmode == SM_RESEND && *s == '1') { /* RESEND length */ int n; CK_OFF_T z; CHAR *p; p = s + 1; n = xunchar(*p++); debug(F101,"rsattr RESEND n","",n); z = (CK_OFF_T)0; while (n-- > 0) /* We assume the format is good. */ z = (CK_OFF_T)10 * z + (CK_OFF_T)(*p++ - '0'); debug(F101,"rsattr RESEND z","",z); if (z > (CK_OFF_T)0) sendstart = z; debug(F101,"rsattr RESEND sendstart","",sendstart); if (sendstart > (CK_OFF_T)0) if (zfseek(sendstart) < 0) /* Input file is already open. */ return(0); #ifdef CK_CURSES if (fdispla == XYFD_C) xxscreen(SCR_FS,0,fsize,""); /* Refresh file transfer display */ #endif /* CK_CURSES */ } #endif /* CK_RESEND */ refused = ""; return(0); } /* Get attributes from incoming A packet. Returns: 0 on success, file is to be accepted -1 on failure, file is to be refused */ int #ifdef CK_ANSIC gattr( CHAR *s, struct zattr *yy ) /* Read incoming attribute packet */ #else gattr(s, yy) CHAR *s; struct zattr *yy; #endif /* CK_ANSIC */ { char c, d; char *ff; int aln, i, overflow = 0; #ifndef NOCSETS extern int r_cset, axcset[]; #endif /* NOCSETS */ #define ABUFL 40 /* Temporary buffer for conversions */ char abuf[ABUFL+1]; #define RFBUFL 10 /* Record-format buffer */ static char rfbuf[RFBUFL+1]; #define FTBUFL 10 /* File type buffer */ static char ftbuf[FTBUFL+1]; #define DTBUFL 40 /* File creation date */ static char dtbuf[DTBUFL+1]; #define TSBUFL 10 /* Transfer syntax */ static char tsbuf[TSBUFL+1]; #define IDBUFL 10 /* System ID */ static char idbuf[IDBUFL+1]; #ifndef DYNAMIC #define DSBUFL 100 /* Disposition */ static char dsbuf[DSBUFL+1]; #define SPBUFL 512 /* System-dependent parameters */ static char spbuf[SPBUFL+1]; #else #define DSBUFL 100 /* Disposition */ static char *dsbuf = NULL; #define SPBUFL 512 /* System-dependent parameters */ static char *spbuf = NULL; #endif /* DYNAMIC */ #define RPBUFL 20 /* Attribute reply */ static char rpbuf[RPBUFL+1]; #ifdef CK_PERMS static char lprmbuf[CK_PERMLEN+1]; static char gprmbuf[2]; #endif /* CK_PERMS */ char *rp; /* Pointer to reply buffer */ int retcode; /* Return code */ d = SP; /* Initialize disposition */ ff = filnam; /* Filename returned by rcvfil */ if (fncact == XYFX_R && ofn1x && ofn1[0]) /* But watch out for FC=RENAME */ ff = ofn1; /* because we haven't renamed it yet */ /* Fill in the attributes we have received */ rp = rpbuf; /* Initialize reply buffer */ *rp++ = 'N'; /* for negative reply. */ *rp = NUL; retcode = 0; /* Initialize return code. */ if (dest == DEST_P) { /* SET DESTINATION PRINTER */ #ifdef DYNAMIC if (!dsbuf) if ((dsbuf = malloc(DSBUFL+1)) == NULL) fatal("gtattr: no memory for dsbuf"); #endif /* DYNAMIC */ dsbuf[0] = 'P'; dsbuf[1] = '\0'; yy->disp.val = dsbuf; yy->disp.len = 1; } while ((c = *s++)) { /* Get attribute tag */ aln = xunchar(*s++); /* Length of attribute string */ switch (c) { #ifdef COMMENT /* This case combined with '1' below */ case '!': /* File length in K */ for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */ abuf[i] = *s++; abuf[i] = '\0'; /* Terminate with null */ if (i < aln) s += (aln - i); /* If field was too long for buffer */ yy->lengthk = ckatofs(abuf); /* Convert to number */ break; #endif /* COMMENT */ case '/': /* Record format */ rfbuf[1] = NUL; rfbuf[2] = NUL; for (i = 0; (i < aln) && (i < RFBUFL); i++) /* Copy it */ rfbuf[i] = *s++; rfbuf[i] = NUL; /* Terminate with null */ yy->recfm.val = rfbuf; /* Pointer to string */ yy->recfm.len = i; /* Length of string */ if ((rfbuf[0] != 'A') || (rfbuf[1] && rfbuf[1] != 'M') || (rfbuf[2] && rfbuf[2] != 'J')) { debug(F110,"gattr bad recfm",rfbuf,0); *rp++ = c; retcode = -1; } break; case '"': /* File type (text, binary, ...) */ for (i = 0; (i < aln) && (i < FTBUFL); i++) ftbuf[i] = *s++; /* Copy it into a static string */ ftbuf[i] = '\0'; if (i < aln) s += (aln - i); /* TYPE attribute is enabled? */ if (attypi) { yy->type.val = ftbuf; /* Pointer to string */ yy->type.len = i; /* Length of string */ debug(F111,"gattr file type", ftbuf, i); debug(F101,"gattr binary 1","",binary); /* Unknown type? */ if ((*ftbuf != 'A' && *ftbuf != 'B' && *ftbuf != 'I') #ifdef CK_LABELED /* ... Or our FILE TYPE is LABELED and the incoming file is text... */ || (binary == XYFT_L && *ftbuf == 'A' && !xflg) #endif /* CK_LABELED */ ) { retcode = -1; /* Reject the file */ *rp++ = c; if (!opnerr) tlog(F100," refused: type","",0); break; } /* The following code moved here from opena() so we set binary mode as soon as requested by the attribute packet. That way when the first data packet comes, the mode of transfer can be displayed correctly before opena() is called. */ if (yy->type.val[0] == 'A') { /* Check received attributes. */ #ifdef VMS if (binary != XYFT_I) /* VMS IMAGE overrides this */ #endif /* VMS */ binary = XYFT_T; /* Set current type to Text. */ debug(F101,"gattr binary 2","",binary); } else if (yy->type.val[0] == 'B') { #ifdef CK_LABELED if (binary != XYFT_L #ifdef VMS && binary != XYFT_U /* VMS special case */ #endif /* VMS */ ) #endif /* CK_LABELED */ #ifdef MAC if (binary != XYFT_M) /* If not MacBinary... */ #endif /* MAC */ binary = XYFT_B; debug(F101,"gattr binary 3","",binary); } } break; case '#': /* File creation date */ for (i = 0; (i < aln) && (i < DTBUFL); i++) dtbuf[i] = *s++; /* Copy it into a static string */ if (i < aln) s += (aln - i); dtbuf[i] = '\0'; if (atdati && !xflg) { /* Real file and dates enabled */ yy->date.val = dtbuf; /* Pointer to string */ yy->date.len = i; /* Length of string */ if (fncact == XYFX_U) { /* Receiving in update mode? */ if (zstime(ff,yy,1) > 0) { /* Compare dates */ *rp++ = c; /* Discard if older, reason = date. */ if (!opnerr) tlog(F100," refused: date","",0); retcode = -1; /* Rejection notice. */ } } } break; case '(': /* File Block Size */ for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */ abuf[i] = *s++; abuf[i] = '\0'; /* Terminate with null */ if (i < aln) s += (aln - i); if (atblki) yy->blksize = atol(abuf); /* Convert to number */ break; case '*': /* Encoding (transfer syntax) */ for (i = 0; (i < aln) && (i < TSBUFL); i++) tsbuf[i] = *s++; /* Copy it into a static string */ if (i < aln) s += (aln - i); tsbuf[i] = '\0'; #ifndef NOCSETS xlatype = XLA_NONE; /* Assume no translation */ #endif /* NOCSETS */ if (atenci) { char * ss; yy->encoding.val = tsbuf; /* Pointer to string */ yy->encoding.len = i; /* Length of string */ debug(F101,"gattr encoding",tsbuf,i); ss = tsbuf+1; switch (*tsbuf) { #ifndef NOCSETS case 'A': /* Normal, nothing special */ tcharset = TC_TRANSP; /* Transparent chars untranslated */ debug(F110,"gattr sets tcharset TC_TRANSP","A",0); break; case 'C': /* Specified character set */ if (!xfrxla) { /* But translation disabled */ tcharset = TC_TRANSP; debug(F110,"gattr sets tcharset TC_TRANSP","C",0); break; } #ifdef UNICODE if (!strcmp("I196",ss)) /* Treat I196 (UTF-8 no level) */ ss = "I190"; /* as I190 (UTF-8 Level 1) */ #endif /* UNICODE */ if (!strcmp("I6/204",ss)) /* Treat "Latin-1 + Euro" */ ss = "I6/100"; /* as I6/100 (regular Latin-1) */ for (i = 0; i < ntcsets; i++) { if (!strcmp(tcsinfo[i].designator,ss)) break; } debug(F101,"gattr xfer charset lookup","",i); if (i == ntcsets) { /* If unknown character set, */ debug(F110,"gattr: xfer charset unknown",ss,0); if (!unkcs) { /* and SET UNKNOWN DISCARD, */ retcode = -1; /* reject the file. */ *rp++ = c; if (!opnerr) tlog(F100," refused: character set","",0); } } else { tcharset = tcsinfo[i].code; /* it's known, use it */ debug(F101,"gattr switch tcharset","",tcharset); debug(F101,"gattr fcharset","",fcharset); if (r_cset == XMODE_A) { /* Automatic switching? */ if (tcharset > -1 && tcharset <= MAXTCSETS) { int x; x = axcset[tcharset]; if (x > 0 && x <= MAXFCSETS) { fcharset = x; debug(F101,"gattr switch fcharset","",x); } } } /* Set up translation type and function */ setxlatype(tcharset,fcharset); } break; #endif /* NOCSETS */ default: /* Something else. */ debug(F110,"gattr unk encoding attribute",tsbuf,0); if (!unkcs) { /* If SET UNK DISC */ retcode = -1; *rp++ = c; if (!opnerr) tlog(F100," refused: encoding","",0); } break; } } break; case '+': /* Disposition */ #ifdef DYNAMIC if (!dsbuf) if ((dsbuf = malloc(DSBUFL+1)) == NULL) fatal("gtattr: no memory for dsbuf"); #endif /* DYNAMIC */ for (i = 0; (i < aln) && (i < DSBUFL); i++) dsbuf[i] = *s++; /* Copy it into a separate string */ dsbuf[i] = '\0'; if (i < aln) s += (aln - i); rs_len = (CK_OFF_T)0; if (atdisi) { /* We are doing this attribute */ /* Copy it into the attribute structure */ yy->disp.val = dsbuf; /* Pointer to string */ yy->disp.len = i; /* Length of string */ d = *dsbuf; #ifndef NODISPO /* Define NODISPO to disable receipt of mail or print files and of RESEND. */ if ( #ifndef datageneral /* MAIL supported only for */ #ifndef OS2 /* UNIX, VMS, and OS-9 */ #ifndef MAC #ifndef GEMDOS #ifndef AMIGA d != 'M' && /* MAIL */ #endif /* AMIGA */ #endif /* GEMDOS */ #endif /* MAC */ #endif /* OS/2 */ #endif /* datageneral */ #ifdef CK_RESEND d != 'R' && /* RESEND */ #endif /* CK_RESEND */ d != 'P') { /* PRINT */ retcode = -1; /* Unknown/unsupported disposition */ *rp++ = c; if (!opnerr) tlog(F101," refused: bad disposition","",d); } dispos = d; debug(F000,"gattr dispos","",dispos); switch (d) { #ifndef NOFRILLS case 'M': if (!en_mai) { retcode = -1; *rp++ = c; if (!opnerr) tlog(F100," refused: mail disabled","",0); dispos = 0; } break; #endif /* NOFRILLS */ case 'P': if (!en_pri) { retcode = -1; *rp++ = c; if (!opnerr) tlog(F100," refused: print disabled","",0); dispos = 0; } break; case 'R': dispos = 0; #ifdef CK_RESEND rs_len = zgetfs(ff); /* Get length of file */ debug(F111,"gattr RESEND",ff,rs_len); #ifdef VMS rs_len &= (long) -512; /* Ensure block boundary if VMS */ rs_len -= 512; /* In case last block not complete */ debug(F111,"gattr rs_len",ff,rs_len); #endif /* VMS */ #ifdef COMMENT if (rs_len < 0L) /* Local file doesn't exist */ rs_len = 0L; #endif /* COMMENT */ /* Another possibility here (or later, really) would be to check if the two file lengths are the same, and if so, keep the prevailing collision action as is (note: rs_len == length of existing file; yy->length == fsize == length of incoming file). This could be complicated, though, since (a) we might not have received the length attribute yet, and in fact it might even be in a subsequent A-packet, yet (b) we have to accept or reject the Recover attribute now. So better to leave as-is. Anyway, it's probably more useful this way. */ if (rs_len > (CK_OFF_T)0) { fncsav = fncact; /* Save collision action */ fncact = XYFX_A; /* Switch to APPEND */ } #else retcode = -1; /* This shouldn't happen */ *rp++ = c; /* 'cause it wasn't negotiated. */ if (!opnerr) tlog(F100," refused: resend","",0); #endif /* CK_RESEND */ } #else /* NODISPO */ retcode = -1; *rp++ = c; if (!opnerr) tlog(F100," refused: NODISPO","",0); #endif /* NODISPO */ } break; case '.': /* Sender's system ID */ for (i = 0; (i < aln) && (i < IDBUFL); i++) idbuf[i] = *s++; /* Copy it into a static string */ idbuf[i] = '\0'; if (i < aln) s += (aln - i); if (atsidi) { yy->systemid.val = idbuf; /* Pointer to string */ yy->systemid.len = i; /* Length of string */ } break; case '0': /* System-dependent parameters */ #ifdef DYNAMIC if (!spbuf && !(spbuf = malloc(SPBUFL))) fatal("gattr: no memory for spbuf"); #endif /* DYNAMIC */ for (i = 0; (i < aln) && (i < SPBUFL); i++) spbuf[i] = *s++; /* Copy it into a static string */ spbuf[i] = '\0'; if (i < aln) s += (aln - i); if (atsysi) { yy->sysparam.val = spbuf; /* Pointer to string */ yy->sysparam.len = i; /* Length of string */ } break; case '!': /* File length in K */ case '1': { /* File length in bytes */ char * l2; CK_OFF_T xlen; for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */ abuf[i] = *s++; abuf[i] = '\0'; /* Terminate with null */ if (i < aln) s += (aln - i); if (rdigits(abuf)) { /* Make sure string is all digits */ xlen = ckatofs(abuf); /* Convert to number */ l2 = ckfstoa(xlen); /* Convert number back to string */ if (c == '1') debug(F111,"gattr length",abuf,xlen); else debug(F111,"gattr lengthk",abuf,xlen); if (ckstrcmp(abuf,l2,-1,1)) { /* This is how we check... */ xlen = (CK_OFF_T)-2; /* -2 = unk, possibly too long */ overflow++; debug(F111,"gattr overflow", (c == '1') ? "length" : "lengthk", xlen); } if (c == '1') { yy->length = xlen; debug(F101,"gattr length","",xlen); } else { yy->lengthk = xlen; debug(F101,"gattr lengthk","",xlen); } } /* If the length field is not numeric accept the file */ /* anyway but with an unknown length */ break; } #ifdef CK_PERMS case ',': /* System-dependent protection code */ for (i = 0; (i < aln) && (i < CK_PERMLEN); i++) lprmbuf[i] = *s++; /* Just copy it - decode later */ lprmbuf[i] = '\0'; /* Terminate with null */ if (i < aln) s += (aln - i); if (atlpri) { yy->lprotect.val = (char *)lprmbuf; yy->lprotect.len = i; } else lprmbuf[0] = NUL; break; case '-': /* Generic "world" protection code */ gprmbuf[0] = NUL; /* Just 1 byte by definition */ for (i = 0; i < aln; i++) /* But allow for more... */ if (i == 0) gprmbuf[0] = *s++; gprmbuf[1] = NUL; if (atgpri) { yy->gprotect.val = (char *)gprmbuf; yy->gprotect.len = gprmbuf[0] ? 1 : 0; } else gprmbuf[0] = NUL; break; #endif /* CK_PERMS */ default: /* Unknown attribute */ s += aln; /* Just skip past it */ break; } } /* Check space now, because we also need to know the file type */ /* in case zchkspa() differentiates text and binary (VMS version does) */ if (atleni && !calibrate) { /* Length attribute enabled? */ if (yy->length > (CK_OFF_T)-1) { /* Length-in-bytes attribute rec'd? */ if (!zchkspa(ff,(yy->length))) { /* Check space */ retcode = -1; /* Not enuf */ *rp++ = '1'; if (!opnerr) tlog(F100," refused: length bytes","",0); } } else if (yy->lengthk > (CK_OFF_T)-1) { /* Length in K received? */ long xlen; xlen = yy->lengthk * 1024; if (!zchkspa(ff,xlen)) { retcode = -1; /* Check space */ *rp++ = '!'; if (!opnerr) tlog(F100," refused: length K","",0); } } } if (retcode > -1L) { /* Remember the file size */ if (yy->length > (CK_OFF_T)-1) { fsize = yy->length; } else if (yy->lengthk > (CK_OFF_T)-1 && !overflow) { fsize = yy->lengthk * 1024L; } else fsize = yy->length; /* (e.g. -2L) */ } #ifdef DEBUG if (deblog) { #ifdef COMMENT sprintf(abuf,"%ld",fsize); /* safe */ #else ckstrncpy(abuf,ckfstoa(fsize),ABUFL); #endif /* COMMENT */ debug(F110,"gattr fsize",abuf,0); } #endif /* DEBUG */ if (retcode == 0) rp = rpbuf; /* Null reply string if accepted */ *rp = '\0'; /* End of reply string */ #ifdef CK_RESEND if (d == 'R') { /* Receiving a RESEND? */ debug(F101,"gattr RESEND","",retcode); /* We ignore retcodes because this overrides */ if (binary != XYFT_B) { /* Reject if not binary */ retcode = -1; /* in case type field came */ ckstrncpy(rpbuf,"N+",RPBUFL); /* after the disposition field */ debug(F111,"gattr RESEND not binary",rpbuf,binary); } else { /* Binary mode */ retcode = 0; /* Accept the file */ discard = 0; /* If SET FILE COLLISION DISCARD */ #ifdef COMMENT sprintf(rpbuf+2,"%ld",rs_len); /* Reply with length of file */ #else ckstrncpy(rpbuf+2,ckfstoa(rs_len),RPBUFL-2); #endif /* COMMENT */ rpbuf[0] = '1'; /* '1' means Length in Bytes */ rpbuf[1] = tochar((int)strlen(rpbuf+2)); /* Length of length */ debug(F111,"gattr RESEND OK",rpbuf,retcode); } } #endif /* CK_RESEND */ if (retcode == 0 && discard != 0) { /* Do we still have a discard flag? */ ckstrncpy(rpbuf,"N?",RPBUFL); /* Yes, must be filename collision */ retcode = -1; /* "?" = name (reply-only code) */ } yy->reply.val = rpbuf; /* Add it to attribute structure */ yy->reply.len = (int)strlen(rpbuf); if (retcode < 0) { /* If we are rejecting */ discard = 1; /* remember to discard the file */ rejection = rpbuf[1]; /* and use the first reason given. */ if (fncsav != -1) { fncact = fncsav; fncsav = -1; } } debug(F111,"gattr return",rpbuf,retcode); return(retcode); } /* I N I T A T T R -- Initialize file attribute structure */ int #ifdef CK_ANSIC initattr( struct zattr *yy ) #else initattr(yy) struct zattr *yy; #endif /* CK_ANSIC */ { yy->lengthk = yy->length = (CK_OFF_T)-1; yy->type.val = ""; yy->type.len = 0; yy->date.val = ""; yy->date.len = 0; yy->encoding.val = ""; yy->encoding.len = 0; yy->disp.val = ""; yy->disp.len = 0; yy->systemid.val = ""; yy->systemid.len = 0; yy->sysparam.val = ""; yy->sysparam.len = 0; yy->creator.val = ""; yy->creator.len = 0; yy->account.val = ""; yy->account.len = 0; yy->area.val = ""; yy->area.len = 0; yy->password.val = ""; yy->password.len = 0; yy->blksize = -1L; yy->xaccess.val = ""; yy->xaccess.len = 0; #ifdef CK_PERMS if (!ofperms) ofperms = ""; debug(F110,"initattr ofperms",ofperms,0); yy->lprotect.val = ofperms; yy->lprotect.len = 0 - strlen(ofperms); /* <-- NOTE! */ /* A negative length indicates that we have a permissions string but it has been inherited from a previously existing file rather than picked up from an incoming A-packet. */ #else yy->lprotect.val = ""; yy->lprotect.len = 0; #endif /* CK_PERMS */ yy->gprotect.val = ""; yy->gprotect.len = 0; yy->recfm.val = ""; yy->recfm.len = 0; yy->reply.val = ""; yy->reply.len = 0; #ifdef OS2 yy->longname.len = 0 ; yy->longname.val = "" ; #endif /* OS2 */ return(0); } /* A D E B U -- Write attribute packet info to debug log */ int #ifdef CK_ANSIC adebu( char *f, struct zattr *zz ) #else adebu(f,zz) char *f; struct zattr *zz; #endif /* CK_ANSIC */ { #ifdef DEBUG if (deblog == 0) return(0); debug(F110,"Attributes for incoming file ",f,0); debug(F101," length in K","",(int) zz->lengthk); debug(F111," file type",zz->type.val,zz->type.len); debug(F111," creation date",zz->date.val,zz->date.len); debug(F111," creator",zz->creator.val,zz->creator.len); debug(F111," account",zz->account.val,zz->account.len); debug(F111," area",zz->area.val,zz->area.len); debug(F111," password",zz->password.val,zz->password.len); debug(F101," blksize","",(int) zz->blksize); debug(F111," access",zz->xaccess.val,zz->xaccess.len); debug(F111," encoding",zz->encoding.val,zz->encoding.len); debug(F111," disposition",zz->disp.val,zz->disp.len); debug(F111," lprotection",zz->lprotect.val,zz->lprotect.len); debug(F111," gprotection",zz->gprotect.val,zz->gprotect.len); debug(F111," systemid",zz->systemid.val,zz->systemid.len); debug(F111," recfm",zz->recfm.val,zz->recfm.len); debug(F111," sysparam",zz->sysparam.val,zz->sysparam.len); debug(F101," length","",(int) zz->length); debug(F110," reply",zz->reply.val,0); #endif /* DEBUG */ return(0); } /* O P E N A -- Open a file, with attributes. */ /* This function tries to open a new file to put the arriving data in. The filename is the one in the srvcmd buffer. File collision actions are: OVERWRITE (the existing file is overwritten), RENAME (the new file is renamed), BACKUP (the existing file is renamed), DISCARD (the new file is refused), UPDATE (the incoming file replaces the existing file only if the incoming file has a newer creation date). Returns 0 on failure, nonzero on success. */ extern char *rf_err; int #ifdef CK_ANSIC opena( char *f, struct zattr *zz ) #else opena(f,zz) char *f; struct zattr *zz; #endif /* CK_ANSIC */ { int x, dispos = 0; static struct filinfo fcb; /* Must be static! */ debug(F110,"opena f",f,0); debug(F101,"opena discard","",discard); adebu(f,zz); /* Write attributes to debug log */ ffc = (CK_OFF_T)0; /* Init file-character counter */ #ifdef PIPESEND if (pipesend) /* Receiving to a pipe - easy. */ return(openo(f,zz,&fcb)); /* Just open the pipe. */ #endif /* PIPESEND */ /* Receiving to a file - set up file control structure */ fcb.bs = fblksiz; /* Blocksize */ #ifndef NOCSETS fcb.cs = fcharset; /* Character set */ #else fcb.cs = 0; /* Character set */ #endif /* NOCSETS */ fcb.rl = frecl; /* Record Length */ fcb.fmt = frecfm; /* Record Format */ fcb.org = forg; /* Organization */ fcb.cc = fcctrl; /* Carriage control */ fcb.typ = binary; /* Type */ debug(F101,"opena xflg","",xflg); debug(F101,"opena remfile","",remfile); debug(F101,"opena remappd","",remappd); if (xflg && remfile && remappd) /* REMOTE output redirected with >> */ fcb.dsp = XYFZ_A; else fcb.dsp = (fncact == XYFX_A) ? XYFZ_A : XYFZ_N; /* Disposition */ debug(F101,"opena disp","",fcb.dsp); fcb.os_specific = ""; /* OS-specific info */ #ifdef CK_LABELED fcb.lblopts = lf_opts; /* Labeled file options */ #else fcb.lblopts = 0; #endif /* CK_LABELED */ if (zz->disp.len > 0) { /* Incoming file has a disposition? */ debug(F111,"open disposition",zz->disp.val,zz->disp.len); dispos = (int) (*(zz->disp.val)); } if (!dispos && xflg && remfile && remappd) /* REMOTE redirect append ? */ dispos = fcb.dsp; debug(F101,"opena dispos","",dispos); if (!dispos) { /* No special disposition? */ if (fncact == XYFX_B && ofn1x && ofn2) { /* File collision = BACKUP? */ if (zrename(ofn1,ofn2) < 0) { /* Rename existing file. */ debug(F110,"opena rename fails",ofn1,0); rf_err = "Can't create backup file"; return(0); } else debug(F110,"opena rename ok",ofn2,0); } } else if (dispos == 'R') { /* Receiving a RESEND */ debug(F101,"opena remote len","",zz->length); debug(F101,"opena local len","",rs_len); #ifdef COMMENT if (fncact == XYFX_R) /* and file collision = RENAME */ if (ofn1x) #endif /* COMMENT */ if (ofn1[0]) f = ofn1; /* use original name. */ if (fncact == XYFX_R) /* if file collision is RENAME */ ckstrncpy(filnam,ofn1,CKMAXPATH+1); /* restore the real name */ xxscreen(SCR_AN,0,0L,f); /* update name on screen */ if (zz->length == rs_len) /* Local and remote lengths equal? */ return(-17); /* Secret code */ } debug(F111,"opena [file]=mode: ",f,fcb.dsp); if ((x = openo(f,zz,&fcb))) { /* Try to open the file. */ #ifdef pdp11 tlog(F110," local name:",f,0L); /* OK, open, record local name. */ makestr(&prfspec,f); /* New preliminary name */ #else #ifndef ZFNQFP tlog(F110," local name:",f,0L); makestr(&prfspec,f); #else { /* Log full local pathname */ char *p = NULL, *q = f; if ((p = malloc(CKMAXPATH+1))) if (zfnqfp(filnam, CKMAXPATH, p)) q = p; tlog(F110," local name:",q,0L); makestr(&prfspec,q); if (p) free(p); } #endif /* ZFNQFP */ #endif /* pdp11 */ if (binary) { /* Log file mode in transaction log */ tlog(F101," mode: binary","",(long) binary); } else { /* If text mode, check character set */ tlog(F100," mode: text","",0L); #ifndef NOCSETS if (xfrxla) { if (fcharset > -1 && fcharset <= MAXFCSETS) tlog(F110," file character-set:",fcsinfo[fcharset].name,0L); if (tcharset > -1 && tcharset <= MAXTCSETS) tlog(F110," xfer character-set:",tcsinfo[tcharset].name,0L); } else { tlog(F110," character-set:","transparent",0L); } #endif /* NOCSETS */ debug(F111,"opena charset",zz->encoding.val,zz->encoding.len); } debug(F101,"opena binary","",binary); #ifdef COMMENT if (fsize >= 0) #endif /* COMMENT */ xxscreen(SCR_FS,0,fsize,""); #ifdef datageneral /* Need to turn on multi-tasking console interrupt task here, since multiple files may be received (huh?) ... */ if ((local) && (!quiet)) /* Only do this if local & not quiet */ consta_mt(); /* Start the async read task */ #endif /* datageneral */ } else { /* Did not open file OK. */ rf_err = ck_errstr(); /* Get system error message */ if (*rf_err) { xxscreen(SCR_EM,0,0l,rf_err); } else { xxscreen(SCR_EM,0,0l,"Can't open output file"); } tlog(F110,"Failure to open",f,0L); tlog(F110,"Error:",rf_err,0L); debug(F110,"opena error",rf_err,0); } return(x); /* Pass on return code from openo */ } /* O P E N C -- Open a command (in place of a file) for output */ int #ifdef CK_ANSIC openc( int n, char * s ) #else openc(n,s) int n; char * s; #endif /* CK_ANSIC */ { int x; #ifndef NOPUSH x = zxcmd(n,s); #else x = 0; #endif /* NOPUSH */ debug(F111,"openc zxcmd",s,x); o_isopen = (x > 0) ? 1 : 0; return(x); } /* C A N N E D -- Check if current file transfer cancelled */ int #ifdef CK_ANSIC canned( CHAR *buf ) #else canned(buf) CHAR *buf; #endif /* CK_ANSIC */ { extern int interrupted; if (*buf == 'X') cxseen = 1; if (*buf == 'Z') czseen = 1; if (czseen || cxseen) interrupted = 1; debug(F101,"canned: cxseen","",cxseen); debug(F101," czseen","",czseen); return((czseen || cxseen) ? 1 : 0); } /* O P E N I -- Open an existing file for input */ int #ifdef CK_ANSIC openi( char *name ) #else openi(name) char *name; #endif /* CK_ANSIC */ { #ifndef NOSERVER extern int fromgetpath; #endif /* NOSERVER */ int x, filno; char *name2; extern CHAR *epktmsg; epktmsg[0] = NUL; /* Initialize error message */ if (memstr || sndarray) { /* Just return if "file" is memory. */ i_isopen = 1; return(1); } debug(F110,"openi name",name,0); debug(F101,"openi sndsrc","",sndsrc); filno = (sndsrc == 0) ? ZSTDIO : ZIFILE; /* ... */ debug(F101,"openi file number","",filno); #ifndef NOSERVER /* If I'm a server and CWD is disabled and name is not from GET-PATH... */ if (server && !en_cwd && !fromgetpath) { zstrip(name,&name2); if ( /* ... check if pathname included. */ #ifdef VMS zchkpath(name) #else strcmp(name,name2) #endif /* VMS */ ) { tlog(F110,name,"access denied",0L); debug(F110,"openi CD disabled",name,0); ckstrncpy((char *)epktmsg,"Access denied",PKTMSGLEN); return(0); } else name = name2; } #endif /* NOSERVER */ #ifdef PIPESEND debug(F101,"openi pipesend","",pipesend); if (pipesend) { int x; #ifndef NOPUSH x = zxcmd(ZIFILE,name); #else x = 0; #endif /* NOPUSH */ i_isopen = (x > 0) ? 1 : 0; if (!i_isopen) ckstrncpy((char *)epktmsg,"Command or pipe failure",PKTMSGLEN); debug(F111,"openi pipesend zxcmd",name,x); return(i_isopen); } #endif /* PIPESEND */ #ifdef CALIBRATE if (calibrate) { i_isopen = 1; return(1); } #endif /* CALIBRATE */ x = zopeni(filno,name); /* Otherwise, try to open it. */ debug(F111,"openi zopeni 1",name,x); if (x) { i_isopen = 1; return(1); } else { /* If not found, */ char xname[CKMAXPATH]; /* convert the name */ #ifdef NZLTOR nzrtol(name,xname,fncnv,fnrpath,CKMAXPATH); #else zrtol(name,xname); /* to local form and then */ #endif /* NZLTOR */ x = zopeni(filno,xname); /* try opening it again. */ debug(F111,"openi zopeni 2",xname,x); if (x) { i_isopen = 1; return(1); /* It worked. */ } else { char * s; s = ck_errstr(); if (s) if (!s) s = NULL; if (!s) s = "Can't open file"; ckstrncpy((char *)epktmsg,s,PKTMSGLEN); tlog(F110,xname,s,0L); debug(F110,"openi failed",xname,0); debug(F110,"openi message",s,0); i_isopen = 0; return(0); } } } /* O P E N O -- Open a new file for output. */ int #ifdef CK_ANSIC openo( char *name, struct zattr *zz, struct filinfo *fcb ) #else openo(name,zz,fcb) char *name; struct zattr *zz; struct filinfo *fcb; #endif /* CK_ANSIC */ { char *name2; #ifdef DTILDE char *dirp; #endif /* DTILDE */ int channel, x; if (stdouf) { /* Receiving to stdout? */ x = zopeno(ZSTDIO,"",zz,NULL); o_isopen = (x > 0); debug(F101,"openo stdouf zopeno","",x); return(x); } debug(F110,"openo: name",name,0); if (cxseen || czseen || discard) { /* If interrupted, get out before */ debug(F100," open cancelled","",0); /* destroying existing file. */ return(1); /* Pretend to succeed. */ } channel = ZOFILE; /* SET DESTINATION DISK or PRINTER */ #ifdef PIPESEND debug(F101,"openo pipesend","",pipesend); if (pipesend) { int x; #ifndef NOPUSH x = zxcmd(ZOFILE,(char *)srvcmd); #else x = 0; #endif /* NOPUSH */ o_isopen = x > 0; debug(F101,"openo zxcmd","",x); return(x); } #endif /* PIPESEND */ if (dest == DEST_S) { /* SET DEST SCREEN... */ channel = ZCTERM; fcb = NULL; } #ifdef DTILDE if (*name == '~') { dirp = tilde_expand(name); if (*dirp) ckstrncpy(name,dirp,CKMAXPATH+1); } #endif /* DTILDE */ if (server && !en_cwd) { /* If running as server */ zstrip(name,&name2); /* and CWD is disabled, */ if (strcmp(name,name2)) { /* check if pathname was included. */ tlog(F110,name,"authorization failure",0L); debug(F110,"openo CD disabled",name,0); return(0); } else name = name2; } if (zopeno(channel,name,zz,fcb) <= 0) { /* Try to open the file */ o_isopen = 0; debug(F110,"openo failed",name,0); /* tlog(F110,"Failure to open",name,0L); */ return(0); } else { o_isopen = 1; debug(F110,"openo ok, name",name,0); return(1); } } /* O P E N T -- Open the terminal for output, in place of a file */ int #ifdef CK_ANSIC opent( struct zattr *zz ) #else opent(zz) struct zattr *zz; #endif /* CK_ANSIC */ { int x; ffc = tfc = (CK_OFF_T)0; x = zopeno(ZCTERM,"",zz,NULL); debug(F101,"opent zopeno","",x); if (x >= 0) { o_isopen = 1; binary = XYFT_T; } else return(0); return(x); } /* O P E N X -- Open nothing (incoming file to be accepted but ignored) */ int #ifdef CK_ANSIC ckopenx( struct zattr *zz ) #else ckopenx(zz) struct zattr *zz; #endif /* CK_ANSIC */ { ffc = tfc = (CK_OFF_T)0; /* Reset counters */ o_isopen = 1; debug(F101,"ckopenx fsize","",fsize); xxscreen(SCR_FS,0,fsize,""); /* Let screen display know the size */ return(1); } /* C L S I F -- Close the current input file. */ int #ifdef CK_ANSIC clsif( void ) #else clsif() #endif /* CK_ANSIC */ { extern int xferstat, success; int x = 0; fcps(); /* Calculate CPS quickly */ #ifdef datageneral if ((local) && (!quiet)) /* Only do this if local & not quiet */ if (nfils < 1) /* More files to send ... leave it on! */ connoi_mt(); #endif /* datageneral */ debug(F101,"clsif i_isopen","",i_isopen); if (i_isopen) { /* If input file is open... */ if (memstr) { /* If input was memory string, */ memstr = 0; /* indicate no more. */ } else { x = zclose(ZIFILE); /* else close input file. */ } #ifdef DEBUG if (deblog) { debug(F101,"clsif zclose","",x); debug(F101,"clsif success","",success); debug(F101,"clsif xferstat","",xferstat); debug(F101,"clsif fsize","",fsize); debug(F101,"clsif ffc","",ffc); debug(F101,"clsif cxseen","",cxseen); debug(F101,"clsif czseen","",czseen); debug(F101,"clsif discard","",czseen); } #endif /* DEBUG */ if ((cxseen || czseen) && !epktsent) { /* If interrupted */ xxscreen(SCR_ST,ST_INT,0l,""); /* say so */ #ifdef TLOG if (tralog && !tlogfmt) doxlog(what,psfspec,fsize,binary,1,"Interrupted"); #endif /* TLOG */ } else if (discard && !epktsent) { /* If I'm refusing */ xxscreen(SCR_ST,ST_REFU,0l,refused); /* say why */ #ifdef TLOG if (tralog && !tlogfmt) { char buf[128]; ckmakmsg(buf,128,"Refused: ",refused,NULL,NULL); doxlog(what,psfspec,fsize,binary,1,buf); } #endif /* TLOG */ } else if (!epktrcvd && !epktsent && !cxseen && !czseen) { CK_OFF_T zz; zz = ffc; #ifdef CK_RESEND if (sendmode == SM_RESEND || sendmode == SM_PSEND) zz += sendstart; #endif /* CK_RESEND */ debug(F101,"clsif fstats","",zz); fstats(); /* Update statistics */ if ( /* Was the whole file sent? */ #ifdef VMS 0 /* Not a reliable check in VMS */ #else #ifdef STRATUS 0 /* Probably not for VOS either */ #else zz < fsize #ifdef CK_CTRLZ && ((eofmethod != XYEOF_Z && !binary) || binary) #endif /* CK_CTRLZ */ #endif /* STRATUS */ #endif /* VMS */ ) { xxscreen(SCR_ST,ST_INT,0l,""); #ifdef TLOG if (tralog && !tlogfmt) doxlog(what,psfspec,fsize,binary,1,"Incomplete"); #endif /* TLOG */ } else { #ifdef COMMENT /* Not yet -- we don't have confirmation from the receiver */ xxscreen(SCR_ST,ST_OK,0l,""); #endif /* COMMENT */ #ifdef TLOG if (tralog && !tlogfmt) doxlog(what,psfspec,fsize,binary,0,""); #endif /* TLOG */ } } } i_isopen = 0; hcflg = 0; /* Reset flags */ sendstart = (CK_OFF_T)0; /* Don't do this again! */ #ifdef COMMENT /* This prevents a subsequent call to clsof() from deleting the file when given the discard flag. */ *filnam = '\0'; /* and current file name */ #endif /* COMMENT */ return(x); } /* C L S O F -- Close an output file. */ /* Call with disp != 0 if file is to be discarded. */ /* Returns -1 upon failure to close, 0 or greater on success. */ int #ifdef CK_ANSIC clsof( int disp ) #else clsof(disp) int disp; #endif /* CK_ANSIC */ { int x = 0; extern int success; fcps(); /* Calculate CPS quickly */ debug(F101,"clsof disp","",disp); debug(F101,"clsof cxseen","",cxseen); debug(F101,"clsof success","",success); debug(F101,"clsof o_isopen","",o_isopen); if (fncsav != -1) { /* Saved file collision action... */ fncact = fncsav; /* Restore it. */ fncsav = -1; /* Unsave it. */ } #ifdef datageneral if ((local) && (!quiet)) /* Only do this if local & not quiet */ connoi_mt(); #endif /* datageneral */ if (o_isopen && !calibrate) { if ((x = zclose(ZOFILE)) < 0) { /* Try to close the file */ tlog(F100,"Failure to close",filnam,0L); xxscreen(SCR_ST,ST_ERR,0l,"Can't close file"); #ifdef TLOG if (tralog && !tlogfmt) doxlog(what,prfspec,fsize,binary,1,"Can't close file"); #endif /* TLOG */ } else if (disp) { /* Interrupted or refused */ if (keep == 0 || /* If not keeping incomplete files */ (keep == SET_AUTO && binary == XYFT_T) ) { if (*filnam && (what & W_RECV)) /* AND we're receiving */ zdelet(filnam); /* ONLY THEN, delete it */ if (what & W_KERMIT) { debug(F100,"clsof incomplete discarded","",0); tlog(F100," incomplete: discarded","",0L); if (!epktrcvd && !epktsent) { xxscreen(SCR_ST,ST_DISC,0l,""); #ifdef TLOG if (tralog && !tlogfmt) doxlog(what,prfspec,fsize,binary,1,"Discarded"); #endif /* TLOG */ } } } else { /* Keep incomplete copy */ debug(F100,"clsof fstats 1","",0); fstats(); if (!discard) { /* Unless discarding for other reason... */ if (what & W_KERMIT) { debug(F100,"closf incomplete kept","",0); tlog(F100," incomplete: kept","",0L); } } if (what & W_KERMIT) { if (!epktrcvd && !epktsent) { xxscreen(SCR_ST,ST_INC,0l,""); #ifdef TLOG if (tralog && !tlogfmt) doxlog(what,prfspec,fsize,binary,1,"Incomplete"); #endif /* TLOG */ } } } } } if (o_isopen && x > -1 && !disp) { debug(F110,"clsof OK",rfspec,0); makestr(&rfspec,prfspec); makestr(&rrfspec,prrfspec); fstats(); if (!epktrcvd && !epktsent && !cxseen && !czseen) { xxscreen(SCR_ST,ST_OK,0L,""); #ifdef TLOG if (tralog && !tlogfmt) doxlog(what,rfspec,fsize,binary,0,""); #endif /* TLOG */ } } rs_len = (CK_OFF_T)0; o_isopen = 0; /* The file is not open any more. */ cxseen = 0; /* Reset per-file interruption flag */ return(x); /* Send back zclose() return code. */ } #ifdef SUNOS4S5 tolower(c) char c; { return((c)-'A'+'a'); } toupper(c) char c; { return((c)-'a'+'A'); } #endif /* SUNOS4S5 */ #endif /* NOXFER */ ckcfnp.h000664 045065 024037 00000040354 14767401665 012626 0ustar00fdckermit000000 000000 /* ckcfnp.h, new to C-Kermit 10.0 as of 23 March 2023. Frank da Cruz Most recent update: 5 February 2024 (remove locate_srv_dns()) Prototypes for functions that previously were not prototyped. Used only for ANSI-C builds in which __STDC__ is defined. ckcfnp.h must be included in each C source file as the LAST #include. Prototype format: return-type function-name ( arguments ); If no arguments, "void" appears in the parentheses, e.g. "( void )". If one argument, its type appears, e.g. "( int )". If more than one argument, the type of each, separated by commas. The argument names are omitted; K&R second edition says: "Parameter names need not agree (and) are optional". Note: Functions that *were* already prototyped are scattered throughout the ck*.c and ck*.h files using a macro _PROTOTYP; I'm not changing those, they've been working just fine on both K&R and ANSI builds for decades, they coexist with this file, and we don't "fix what ain't broke". */ #ifndef CKCFNP_H #define CKCFNP_H #ifndef NOANSI #ifdef __STDC__ #ifdef CK_ANSIC /* #include ckcker.h was added 27 April 2023 because certain builds (like "linux+ssl") were failing. ckcker.h defines data types and other symbols referenced in this file. It should be included by every module before including this one. But just in case there's an omission, including it here too does no harm because the ck*.h files protect themselves against multiple inclusion. ckcdeb.h added 3 may 2023, because the mainname definition was moved from here (where non-ansi builds would never see it) to ckcdeb.h. ckuusr.h added 12 May 2023 for MINIX / ckucon.c / struct m[x,xx]tab. */ #include "ckcdeb.h" #include "ckcker.h" #include "ckucmd.h" #include "ckuusr.h" /* Prototype for main()/Main() */ MAINTYPE MAINNAME( int argc, char ** argv ); /* PROTOTYPES ADDED 6 May 2023... */ #ifdef CK_AUTHENTICATION int show_auth( int ); #endif /* CK_AUTHENTICATION */ /* PROTOTYPES ADDED 11-14 April 2023... */ int hasnopath ( char * ); VOID puschcmd ( char * ); VOID newerrmsg ( char * ); char * getdm ( int ); /* PROTOTYPES ADDED 26 March 2023... */ void docmdline( void * ); void failcmdline( void * ); void failtakeini( void * ); void dotakeini( void * ); void failtakeini( void * ); void doicp( void * ); void failicp( void * ); void docmdfile( void * ); void failcmdfile( void * ); char * getsysid( char * ); int getsysix( char * ); int isabsolute( char * path ); int is_a_tty( int ); void initxlist ( void ); void initflow ( void ); void makever ( void ); void dourl ( void ); int getiobs ( void ); #ifndef NOSPL /* struct mtab [] exists only if NOSPL isn't defined */ int mlook( struct mtab [], char *, int ); int mxlook( struct mtab [], char *, int ); int mxxlook ( struct mtab [], char *, int ); #endif /* NOSPL */ int savhistory (char *, int); char * ckltoa ( long ); char * ckultoa ( unsigned long ); char * ckltox ( long ); char * ckitoa ( int ); char * ckfstoa ( CK_OFF_T ); char * ckitox( int ); CK_OFF_T ckatofs(char * s); char * ckctoa(char c); char * ckctox(CHAR c, int flag); int dquote( char * fn, int len, int flag ); void makestr(char **p, const char *s); void xmakestr(char **p, const char *s); CKFLOAT ckround( CKFLOAT, int, char *, int ); int chknum( char * ); int rdigits( char * s ); char * parnam( char c ); char * hhmmss ( long x ); char * ulongtohex( unsigned long z, int n ); int ckhexbytetoint( char * s ); struct stringarray * cksplit(int fc,int n1,char * s1,char * s2,char * s3, int n2,int n3,int n4,int n5); /* PROTOTYPES ADDED 24 March 2023... */ CK_OFF_T z_count( int, int ); CK_OFF_T z_getline( int ); CK_OFF_T z_getpos( int ); CK_OFF_T zchki( char * ); CK_OFF_T zgetfs( char * ); SIGTYP timerh( int ); SIGTYP xtimerh( int ); char * bldlen( char *, char *); char * brstrip( char * ); char * chk_ac( int, char [] ); char * ckaddr2name( char * ); char * ckcvtdate( char *, int ); char * ckferror( int ); char * ckname2addr( char * ); char * ckradix( char *, int, int ); char * ckstrpbrk( char *, char * ); char * ckstrstr( char *, char * ); char * ckuitoa( unsigned int ); char * cmcvtdate( char *, int ); char * cmdelta( int,int,int,int,int,int,int,int,int,int,int,int,int ); char * cmdiffdate( char *, char * ); char * cmgetcmd( char * ); char * dbchr( int ); char * dosexp( char * ); char * evala( char * ); char * evalx( char * ); char * fpformat( CKFLOAT, int, int ); char * getbasename( char * ); char * getdnum( int ); char * getsysid( char * ); char * gfmode( int, int ); char * gskreason( int ); char * jzdate( char * ); char * locale_dayname( int, int ); char * locale_monthname( int, int ); char * nvlook( char * ); char * pncvt( char * ); char * rlookup( struct keytab [], int, int ); char * sgetsave( char * ); char * showoff( int ); char * showooa( int ); char * showstring( char * ); char * shuffledate( char *, int ); char * tilde_expand( char * ); char * z_getname( int ); char * zfcdat( char * ); char * zgperm( char * ); char * ziperm( char * ); char * zjdate( char * ); char * zlocaltime( char * ); int rlog_ctrl( unsigned char *, int ); int addlocal( char * ); int addmac( char *, char * ); int addmmac( char *, char * [] ); int adebu( char *, struct zattr * ); int adjpkl( int, int, int ); int arraybounds( char *, int *, int * ); int arraynam( char *, int *, int * ); int b64tob8( char *, int, char *, int ); int b8tob64( char *, int, char *, int ); int bkupnum( char *, int * ); int boolexp( int ); int canned( CHAR * ); int chk1( register CHAR *, register int ); int chkarray( int, int ); int chkfn( int ); int chkspkt( char * ); int chktimo( int, int ); int chktok( char * ); int chkvar( char * ); int chkwin( int, int, int ); int cisalphanum( CHAR ); int ck_curpos( int, int ); int ck_linger( int, int, int ); int ckcgetc( int ); int ckcputc( int ); int ckdial( char *, int, int, int, int ); int ckindex( char *, char *, int, int, int ); int cklower( char * ); int ckmatch( char *, char *, int, int ); int ckmkdir( int, char *, char **, int, int ); int ckopenx( struct zattr * ); int ckrchar( char * ); int ckstrcmp( char *, char *, register int, register int ); int ckstrpre( char *, char * ); int ckupper( char * ); int clsconnx( int ); int clskconnx( int ); int clsof( int ); int cmdate( char *, char *, char **, int, xx_strp ); int cmdir( char *, char *, char **, xx_strp ); int cmdirp( char *, char *, char **xp, char *, xx_strp ); int cmdlinput( int ); int cmdsquo( int ); int cmfdb( struct FDB * ); int cmfld( char *, char *, char **, xx_strp ); int cmifi( char *, char *, char **, int *, xx_strp f); int cmifi2( char *, char *, char **, int *, int, char *, xx_strp, int ); int cmifip( char *, char *, char **, int *, int, char *, xx_strp ); int cmiofi( char *, char *, char **, int *, xx_strp ); int cmkey( struct keytab [], int, char *, char *, xx_strp ); int cmkey2( struct keytab [], int, char *, char *, char *, xx_strp, int ); int cmkeyx( struct keytab [], int, char *, char *, xx_strp ); int cmnum( char *, char *, int, int *, xx_strp ); int cmnumw( char *, char *, int, CK_OFF_T *, xx_strp ); int cmofi( char *, char *, char **, xx_strp ); int cmrini( int ); int cmswi( struct keytab [], int, char *, char *, xx_strp ); int cmtxt( char *, char *, char **, xx_strp ); int coninc( int ); int conol( char * ); int conola( char * [] ); int conoll( char * ); int conxo( int, char * ); int cs_is_nrc( int ); int cs_is_std( int ); int cs_size( int ); int cwd( char * ); int cx_fail( int, char * ); int debopn( char *, int ); int delmac( char *, int ); int delta2sec( char *, long * ); int diaopn( char *, int, int fc ); int do_open( char * ); int do_pty( int *, char *, int ); int doask( int ); int docd( int ); int doclslog( int ); int docmd( int cx ); int doconect( int, int ); int dodef( int ); int dodial( int ); int dodir( int ); int dodo( int, char *, int ); int doenable( int, int ); int dofile( int ); int doftpget( int, int ); int doftprmt( int, int ); int doftptyp( int ); int dogoto( char *, int ); int dogta( int ); int dohfunc( int ); int dohlp( int ); int dohrmt( int ); int dohset( int ); int doif( int ); int doincr( int ); int doinput( int, char * [], int [], int, int ); int dolog( int ); int dologin( char * ); int domac( char *, char *, int ); int dontroute( int, int ); int dooutput( char *, int ); int dopaus( int ); int doprm( int, int ); int doputenv( char *, char * ); int doreinp( int, char *, int ); int doreturn( char * ); int dormt( int ); int dosave( int ); int doshift( int ); int doshow( int ); int dostat( int ); int dotake( char * ); int dotype( char *, int,int,int, char *, int, char *, int,int, char *, int ); int doundef( int ); int doxarg( char **, int ); int doxconn( int ); int doxget( int ); int doxsend( int ); int dquote( char *, int, int ); int filhelp( int, char *, char *, int, int ); int fnparse( char * ); int freeslot( int ); int ftpopen( char *, char *, int ); int gattr( CHAR *, struct zattr * ); int getlocalipaddrs( char *, int, int ); int getncm( char *, int ); int getnct( char *, int, FILE *, int ); int getok( int, int ); int getpkt( int, int ); int getptyslave( int *, int ); int getrtt( int, int ); int getsysix( char * ); int gettcs( int, int ); int gettoken( FILE * ); int getyesno( char *, int ); int gnirts( char *, char *, int ); #ifndef OS2 int hash( char * ); /* Conflicts with SRP support on Windows and OS/2 */ #endif /* OS2 */ int hmsg( char * ); int hmsga( char * [] ); int http_inc( int ); int http_tol( CHAR *, int ); int hupok( int ); int incvar( char *, CK_OFF_T, int ); int inibufs( int, int ); int initattr( struct zattr * ); int initslot( int ); int is_a_tty( int ); int isabsolute( char * ); int isalink( char * ); int isalphanum( char * ); int isdir( char *s ); int isfloat( char *, int ); int isin( char *, int c ); int isinternalmacro( int ); int ispattern( char * ); int iswild( char * ); int isword( int ); int keepalive( int, int ); int litcmd( char **, char **dest, int ); int lkup( char * ); int locate_txt_rr( char *, char *, char ** ); int lookup( struct keytab [], char *, int, int * ); int makebuf( int, int, CHAR [], struct pktinfo * ); int matchname( char *, int, int ); int mkrbuf( int ); int mksbuf( int ); int msleep( int ); int nack( int ); int netinc( int ); int netopen( char *, int *, int ); int nettol( CHAR *, int ); int netxin( int, CHAR * ); int nlookup( struct keytab [], char *, int, int * ); int no_delay( int, int ); int nonalphanum( char * ); int opena( char *f, struct zattr * ); int openc( int, char * ); int openi( char * ); int openo( char *, struct zattr *, struct filinfo * ); int opent( struct zattr * ); int parser( int ); int parsevar( char *, int *, int * ); int pktopn( char *, int ); int plogin( int ); int priv_opn( char *, int ); int prtopt( int *, char * ); int psuspend( int ); int pusharray( int, int ); int rcvfil( char * ); int rdigits( char * ); int readpass( char *, char *, int ); int readtext( char *, char *, int ); int recvbuf( int, int ); int remset( char * ); int remtxt( char ** ); int reof( char *, struct zattr * ); int savhistory( char *, int ); int savkeys( char *, int ); int scanfile( char *, int *, int ); int scanstring( char * ); int sendbuf( int, int ); int seof( int ); int sesopn( char *, int ); int setat( int ); int setcc( char *, int * ); int setfil( int ); int setlin( int, int, int ); int setnum( int *, int, int, int ); int seton( int * ); int setonaut( int * ); int setsr( int, int ); int sfile( int ); int shoesc( int ); int shoftp( int ); int shomac( char *, char * ); int shotcp( int ); int shotel( int ); int shotopt( int ); int shxpand( char *, char * [], int ); int slotdir( char *, char *); int slotstate( int, char *, char *, char * ); int snddel( char * ); int snddir( char * ); int sndstring( char * ); int sndtype( char * ); int srinit( int, int, int ); int sxeof( int ); int syscmd( char *, char * ); int szeof( CHAR * ); int tcpsrv_open( char *, int *, int, int ); int tinit( int ); int tn_siks( int ); int tn_sopt( int, int ); int tn_ssbopt( int, int sub, CHAR *, int ); int traopn( char *, int ); int ttinc( int ); int ttol( CHAR *, int ); int ttopen( char *, int *, int, int ); int ttptycmd( char * ); int ttpushback( CHAR *, int ); int ttruncmd( char * ); int ttscarr( int ); int ttsetflow( int ); int ttsspd( int ); int ttwait( int, int ); int ttxin( int, CHAR * ); int untabify( char *, char *, int ); int updslot( int ); #ifndef NOURL int urlparse( char *, struct urldata * ); #endif /* NOURL */ int varval( char *, CK_OFF_T * ); int window( int ); int xarray( char * ); int xdelmac( int ); int xlate( char *, char *, int, int ); int xlookup( struct keytab [], char *, int, int * ); int xxdormt( int ); int yystring( char *, char ** ); int z_close( int ); int z_flush( int ); int z_getfnum( int ); int z_getmode( int ); int z_in( int, char *, int, int, int ); int z_open( char *, int ); int z_out( int, char *, int, int); int zchdir( char * ); int zchin( int, int * ); int zchko( char * ); int zclose( int ); int zclosf( int ); int zcmpfn( char *, char * ); int zcopy( char *, char * ); int zdelet( char * ); int zmkdir( char * ); int znext( char * ); int zopeni( int, char * ); int zopeno( int, char *, struct zattr *, struct filinfo * ); int zprint( char *, char * ); int zrename( char *, char * ); int zrmdir( char * ); int zsattr( struct zattr * ); int zsetfil( int, int ); int zsetperm( char *, int ); int zshcmd( char * ); int zsinl( int, char *, int ); int zsout( int, char * ); int zsoutl( int, char * ); int zsoutx( int, char *, int ); int zstime( char *, struct zattr *, int ); int zsyscmd( char * ); int zvpass( char * ); int zvuser( char * ); int zxcmd( int, char * ); int zxin( int, char *, int ); int zzstring( char *, char **, int * ); #ifndef NOLOCAL long dologshow( int ); #endif /* NOLOCAL */ long hextoulong( char *, int ); long mjd( char * ); long pty_cleanup( char *, int, int ); long pty_initialize_slave ( int ); long pty_open_ctty( char *, int *, int ); long pty_open_slave( char *, int *, int ); long tod2sec( char * ); struct passwd * sgetpwnam( char * ); struct stringarray * cksplit( int,int,char *, char *,char *, int,int,int,int ); struct zfnfp * zfnqfp( char *, int, char * ); time_t zstrdt( char *, int ); unsigned int chk2( register CHAR *, register int ); unsigned int chk3( register CHAR *, register int ); void addaction( int, int, int ); void addcmd( char * ); void ckhost( char *, int ); void cmini( int ); void cmsetp( char * ); void conbgt( int ); void copy_termbuf( char *, int ); void copyact( FILE *, FILE *, int ); void copyrest( FILE *, FILE * ); void doclean( int ); void doexit( int, int ); void doftpglobaltype( int ); void enter( char *, int ); void epilogue( FILE * ); void ermsg( char * ); void evalmacroarg( char ** ); void exec_cmd( char * ); void fatal( char * ); void fatal2( char *, char * ); void freelocal( int ); void freerpkt( int ); #ifndef NOLOCAL void fxdinit( int ); #endif /* NOLOCAL */ void init_termbuf( int ); void initial( FILE *, FILE * ); void initmdm( int ); void initproto( int, char *, char *, char *, char *, char *, char *, char * ); void initxlate( int, int ); void kwdhelp( struct keytab [], int, char *, char *, char *, int, int ); void logstr( char *, int ); void lset( char *, char *, int, int ); void makelist( char *, char * [], int ); void nettout( int ); void nzltor( char *, char *, int, int, int ); void nzrtol( char *, char *, int, int, int ); void prescan( int ); void prolog( FILE * ); void prompt( xx_strp ); void pty_make_raw( int ); void rdcmnt( FILE * ); void rdebu( CHAR *, int ); void rdstates( FILE *, FILE * ); void rdword( FILE *, char * ); void rinit( CHAR * ); void rset( char *, char *, int, int ); void sdebu( int ); void setautodl( int, int ); void setautolocus( int ); void setcmask( int ); void setdebses( int ); void setexitwarn( int ); void setlclcharset( int ); void setlocus( int, int ); void setprefix( int ); void setremcharset( int, int ); void setseslog( int ); void setxlatype( int, int ); void sh_sort( char **, char **, int, int, int, int ); void shods( char * ); #ifdef OS2 void shokeycode( int, int ); #else void shokeycode( int ); #endif /* OS2 */ void shostrdef( CHAR * ); void shotcs( int, int ); void tn_debug( char * ); void untab( char * ); void warray( FILE *, char *, int [], int, char * ); void writetbl( FILE * ); void xwords( char *, int, char * [], int ); void zltor( char *, char * ); void znewn( char *, char **s ); void zrtol( char *, char * ); void zstrip( char *, char ** ); void ztime( char ** ); #endif /* CK_ANSIC */ #endif /* __STDC__ */ #endif /* NOANSI */ #endif /* CKCFNP_H */ ckcfns.c000664 045065 024037 00000667614 14767402305 012632 0ustar00fdckermit000000 000000 char *fnsv = "C-Kermit functions, 10.0.247, 6 Feb 2024"; char *nm[] = { "Disabled", "Local only", "Remote only", "Enabled" }; /* C K C F N S -- System-independent Kermit protocol support functions. */ /* ...Part 1 (others moved to ckcfn2,3 to make this module smaller) */ /* Author: Frank da Cruz , Columbia University Academic Information Systems, New York City (1974-2011) The Kermit Project, Bronx NY (2011-????) Copyright (C) 1985, 2024, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Updated: Fri Sep 23 15:27:55 2022 (CR -> CK_CR and space unsigned long -> CK_OFF_T) Last update: Fri Feb 2 15:55:27 2024 Implementation of REMOTE STATUS. */ /* System-dependent primitives defined in: ck?tio.c -- terminal (communications) i/o cx?fio.c -- file i/o, directory structure */ #include "ckcsym.h" /* Needed for Stratus VOS */ #include "ckcasc.h" /* ASCII symbols */ #include "ckcdeb.h" /* Debug formats, typedefs, etc. */ #include "ckcker.h" /* Symbol definitions for Kermit */ #include "ckcxla.h" /* Character set symbols */ #include "ckcnet.h" /* VMS definition of TCPSOCKET */ #ifdef OS2 #ifdef OS2ONLY #include #undef COMMENT #endif /* OS2ONLY */ #include "ckocon.h" #endif /* OS2 */ int docrc = 0; /* Accumulate CRC for \v(crc16) */ long crc16 = 0L; /* File CRC = \v(crc16) */ int gnferror = 0; /* gnfile() failure reason */ extern CHAR feol; extern int byteorder, xflg, what, fmask, cxseen, czseen, nscanfile, sysindex; extern int xcmdsrc, dispos, matchfifo; extern int inserver; extern int nolinks; #ifdef VMSORUNIX extern int zgfs_dir; #ifdef CKSYMLINK extern int zgfs_link; #endif /* CKSYMLINK */ #endif /* VMSORUNIX */ #ifndef NOXFER #ifndef NOICP #ifndef NOSPL extern char * clcmds; extern int haveurl; #ifdef CK_APC extern int apcactive, adl_ask; #endif /* CK_APC */ #endif /* NOSPL */ #endif /* NOICP */ extern int remfile; /* (move these prototypes to the appropriate .h files...) */ #ifdef COMMENT /* Not used */ #ifdef VMS _PROTOTYP( int getvnum, (char *) ); #endif /* VMS */ #endif /* COMMENT */ _PROTOTYP( static int bgetpkt, (int) ); #ifndef NOCSETS _PROTOTYP( int lookup, (struct keytab[], char *, int, int *) ); #endif /* NOCSETS */ #ifndef NOSPL _PROTOTYP( int zzstring, (char *, char **, int *) ); #endif /* NOSPL */ #ifdef OS2 #include #ifdef OS2ONLY #include #undef COMMENT #endif /* OS2ONLY */ #endif /* OS2 */ #include "ckucmd.h" #include "ckuusr.h" #include "ckcfnp.h" /* Prototypes */ /* Externals from ckcmai.c */ extern int srvcdmsg, srvidl, idletmo; extern char * cdmsgfile[]; extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg, rpt, rptq, rptflg, capas, keep, fncact, pkttim, autopar, spsizr, xitsta; extern int pktnum, bctr, bctu, bctf, bctl, clfils, sbufnum, protocol, size, osize, spktl, nfils, ckwarn, timef, spsizf, sndtyp, rcvtyp, success; extern int parity, turn, network, whatru, fsecs, justone, slostart, ckdelay, displa, mypadn, moving, recursive, nettype; extern int rpsizf; extern long filcnt; extern CK_OFF_T tfc, fsize, sendstart, rs_len, flci, flco, tlci, tlco, calibrate; extern long filrej, oldcps, cps, peakcps, ccu, ccp, filestatus; extern int fblksiz, frecl, frecfm, forg, fcctrl, fdispla, skipbup; extern int spackets, rpackets, timeouts, retrans, crunched, wmax, wcur; extern int hcflg, binary, fncnv, b_save, f_save, server; extern int nakstate, discard, rejection, local, xfermode, interrupted; extern int rq, rqf, sq, wslots, wslotn, wslotr, winlo, urpsiz, rln; extern int fnspath, fnrpath, eofmethod, diractive, whatru2, wearealike; extern int atcapr, atcapb, atcapu; extern int lpcapr, lpcapb, lpcapu; extern int swcapr, swcapb, swcapu; extern int lscapr, lscapb, lscapu; extern int rscapr, rscapb, rscapu; extern int rptena, rptmin; extern int sseqtbl[]; extern int numerrs, nzxopts; extern long rptn; extern int maxtry; extern int stdouf; extern int sendmode; extern int carrier, ttprty; extern int g_fnrpath; #ifdef TCPSOCKET extern int ttnproto; #endif /* TCPSOCKET */ #ifndef NOSPL extern int sndxin, sndxhi, sndxlo; #endif /* NOSPL */ extern int g_binary, g_fncnv; #ifdef GFTIMER extern CKFLOAT fpfsecs; #endif /* GFTIMER */ #ifdef OS2 extern struct zattr iattr; #endif /* OS2 */ #ifdef PIPESEND extern int usepipes; #endif /* PIPESEND */ extern int pipesend; #ifdef STREAMING extern int streamrq, streaming, streamed, streamok; #endif /* STREAMING */ extern int reliable, clearrq, cleared, urclear; extern int atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko, attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso; extern int bigsbsiz, bigrbsiz; extern char *versio; extern char *filefile; extern char whoareu[], * cksysid; extern char *fdate; #ifndef NOSERVER extern int ngetpath; extern char * getpath[]; extern int fromgetpath; #endif /* NOSERVER */ #ifdef CK_LOGIN extern int isguest; #endif /* CK_LOGIN */ extern int srvcmdlen; extern CHAR *srvcmd, * epktmsg; extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate, myrptq; extern CHAR *data, padbuf[], stchr, mystch; extern CHAR *srvptr; extern CHAR *rdatap; extern char *cmarg, *cmarg2, **cmlist, filnam[], ofilnam[]; extern char *rfspec, *prfspec, *rrfspec, *prrfspec, *sfspec, *psfspec, *rfspec; extern char fspec[]; extern int fspeclen; #ifndef NOMSEND extern struct filelist * filehead, * filenext; extern int addlist; #endif /* NOMSEND */ _PROTOTYP( int lslook, (unsigned int b) ); /* Locking Shift Lookahead */ _PROTOTYP( int szeof, (CHAR *s) ); _PROTOTYP( VOID fnlist, (void) ); #endif /* NOXFER */ extern CK_OFF_T ffc; /* Character set Translation */ #ifndef NOCSETS extern int tcharset, fcharset, dcset7, dcset8; extern int fcs_save, tcs_save; extern int ntcsets, xlatype, cseqtab[]; extern struct csinfo tcsinfo[], fcsinfo[]; extern int r_cset, s_cset, afcset[]; #ifdef UNICODE extern int ucsorder, fileorder; #endif /* UNICODE */ _PROTOTYP( CHAR ident, (CHAR) ); /* Identity translation function */ /* Arrays of and pointers to character translation functions */ #ifdef CK_ANSIC extern CHAR (*rx)(CHAR); /* Pointer to input character translation function */ extern CHAR (*sx)(CHAR); /* Pointer to output character translation function */ extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Byte-to-Byte Send */ extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Byte-to-Byte Recv */ #ifdef UNICODE extern int (*xut)(USHORT); /* Translation function UCS to TCS */ extern int (*xuf)(USHORT); /* Translation function UCS to FCS */ extern USHORT (*xtu)(CHAR); /* Translation function TCS to UCS */ extern USHORT (*xfu)(CHAR); /* Translation function FCS to UCS */ #endif /* UNICODE */ #else /* The same declarations again for non-ANSI comilers... */ extern CHAR (*rx)(); extern CHAR (*sx)(); extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); #ifdef UNICODE extern int (*xut)(); extern int (*xuf)(); extern USHORT (*xtu)(); extern USHORT (*xfu)(); #endif /* UNICODE */ #endif /* CK_ANSIC */ #endif /* NOCSETS */ /* (PWP) external def. of things used in buffered file input and output */ #ifdef DYNAMIC extern char *zinbuffer, *zoutbuffer; #else extern char zinbuffer[], zoutbuffer[]; #endif /* DYNAMIC */ extern char *zinptr, *zoutptr; extern int zincnt, zoutcnt, zobufsize, xfrxla; extern long crcta[], crctb[]; /* CRC-16 generation tables */ extern int rseqtbl[]; /* Rec'd-packet sequence # table */ #ifndef NOXFER /* Criteria used by gnfile()... */ char sndafter[19] = { NUL, NUL }; char sndbefore[19] = { NUL, NUL }; char sndnafter[19] = { NUL, NUL }; char sndnbefore[19] = { NUL, NUL }; char *sndexcept[NSNDEXCEPT] = { NULL, NULL }; char *rcvexcept[NSNDEXCEPT] = { NULL, NULL }; CK_OFF_T sndsmaller = (CK_OFF_T)-1; CK_OFF_T sndlarger = (CK_OFF_T)-1; /* Variables defined in this module but shared by other modules. */ int xfrbel = 1; char * ofperms = ""; /* Output file permissions */ int autopath = 0; /* SET RECEIVE PATHNAMES AUTO flag */ #ifdef CALIBRATE #define CAL_O 3 #define CAL_M 253 int cal_j = 0; CHAR cal_a[] = { 16, 45, 98, 3, 52, 41, 14, 7, 76,165,122, 11,104, 77,166, 15, 160, 93, 18, 19,112, 85, 54, 23,232,213, 90, 27, 12, 81,126, 31, 4,205, 34, 35,144, 73,110, 39, 28,133,218, 43,156, 65,102, 47, 84, 61, 50, 51,208,117, 86, 55, 8,245, 74, 59, 44,125,222, 63, 80, 1,162, 67,116,105,206, 71,120, 9,250, 75, 88, 97, 6, 79, 100,221, 82, 83, 36, 89, 94, 87, 40, 21,106, 91,236,145,150, 95, 228, 33,130, 99,148,137,198,103,108,169, 42,107,184,129, 78,111, 0, 49,114,115, 32,121,254,119,172, 57,138,123,152,177, 22,127, 240,193, 2,131,176, 5, 38,135,204,229, 10,139,200,161,174,143, 128, 17,146,147, 68,153, 30,151, 72,217,170,155, 24,209, 62,159, 64,225,194,163,244,201, 70,167,216,197,234,171,188,109,230,175, 212,113,178,179,132,185,190,183,136,249,202,187, 92,241,118,191, 48,237, 66,195, 96,233,142,199,248, 37, 58,203, 60, 13,134,207, 20, 29,210,211,164,149,182,215,220, 25, 26,219,124,157,246,223, 180,141,226,227,192,101,238,231, 56, 69,154,235,252,173, 46,239, 224,253,242,243,196, 53,214,247,168,181,186,251,140,189,158,255 }; #endif /* CALIBRATE */ char * rf_err = "Error receiving file"; /* rcvfil() error message */ #ifdef CK_SPEED short ctlp[256] = { /* Control-Prefix table */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* C0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* G0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* DEL */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* C1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* G1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 /* 255 */ }; #endif /* CK_SPEED */ int sndsrc; /* Flag for where to get names of files to send: */ /* -1: znext() function */ /* 0: stdin */ /* >0: list in cmlist or other list */ /* -9: calibrate */ int memstr; /* Flag for input from memory string */ int funcstr; /* Flag for input from function */ int bestlen = 0; int maxsend = 0; int gnf_binary = 0; /* Prevailing xfer mode for gnfile */ #ifdef pdp11 #define MYINITLEN 32 #else #define MYINITLEN 100 #endif /* pdp11 */ CHAR myinit[MYINITLEN]; /* Copy of my Send-Init data */ /* Variables local to this module */ #ifdef TLOG #ifndef XYZ_INTERNAL static #endif /* XYZ_INTERNAL */ char *fncnam[] = { "rename", "replace", "backup", "append", "discard", "ask", "update", "dates-differ", "" }; #endif /* TLOG */ static char *memptr; /* Pointer for memory strings */ #ifdef VMS extern int batch; #else extern int backgrd; #endif /* VMS */ #ifdef CK_CTRLZ static int lastchar = 0; #endif /* CK_CTRLZ */ #ifdef CK_ANSIC static int (*funcptr)(void); /* Pointer for function strings */ #else static int (*funcptr)(); #endif /* CK_ANSIC */ #ifdef pdp11 #define CMDSTRL 50 static char cmdstr[50]; /* System command string. */ #else #ifdef BIGBUFOK #define CMDSTRL 6144 #else #define CMDSTRL 1024 #endif /* BIGBUFOK */ static char cmdstr[CMDSTRL+1]; #endif /* pdp11 */ static int drain; /* For draining stacked-up ACKs. */ static int first; /* Flag for first char from input */ static CHAR t; /* Current character */ #ifdef COMMENT static CHAR next; /* Next character */ #endif /* COMMENT */ static int ebqsent = 0; /* 8th-bit prefix bid that I sent */ static int lsstate = 0; /* Locking shift state */ static int lsquote = 0; /* Locking shift quote */ extern int quiet; /* E N C S T R -- Encode a string from memory. */ /* Call this instead of getpkt() if source is a string, rather than a file. Note: Character set translation is never done in this case. */ #ifdef COMMENT #define ENCBUFL 200 #ifndef pdp11 CHAR encbuf[ENCBUFL]; #else /* This is gross, but the pdp11 root segment is out of space */ /* Will allocate it in ckuusr.c. */ extern CHAR encbuf[]; #endif /* pdp11 */ #endif /* COMMENT */ /* Encode packet data from a string in memory rather than from a file; thus this routine is used for administrative packets, not with Data packets. Returns the length of the encoded string on success, -1 if the string could not be completely encoded into the currently negotiated data field length. */ int #ifdef CK_ANSIC encstr(CHAR *s) #else /* CK_ANSIC */ encstr(s) CHAR* s; #endif /* CK_ANSIC */ { /* Recoded 30 Jul 1994 to use the regular data buffer and the negotiated maximum packet size. Previously we were limited to the length of encbuf[]. Also, to return a failure code if the entire encoded string would not fit. Modified 14 Jul 1998 to return length of encoded string. Modified 18 Oct 2021 to not truncate filename in F packet. */ int m, rc, slen; char *p; /* data is a pointer to send-packet data declared in ckcmai.c */ if (!data) { /* Watch out for null pointers. */ debug(F100,"SERIOUS ERROR: encstr data == NULL","",0); return(-1); } if (!s) s = (CHAR *)""; /* Our argument string */ slen = strlen((char *)s); /* Length of source string */ debug(F111,"encstr",s,slen); rc = 0; /* Return code. */ m = memstr; p = memptr; /* Save these. */ memptr = (char *)s; /* Point to the string. */ /* debug(F101,"encstr memptr 1","",memptr); */ memstr = 1; /* Flag memory string as source. */ first = 1; /* Initialize character lookahead. */ *data = NUL; /* In case s is empty */ debug(F101,"encstr pktnum","",pktnum); /* (apparently not reliable) */ debug(F101,"encstr spsiz","",spsiz); #ifndef COMMENT /* 28 October 2021: If the user gives a command like SET SEND PACKET-LENGTH 10, the filename will be truncated if it's longer than that. Now we use the packet size our Kermit partner is willing to accept (rpsiz). This can still be truncated but much less likely because filenames tend to be shorter then 90 bytes. */ debug(F101,"encstr rpsiz","",rpsiz); debug(F101,"encstr urpsiz","",urpsiz); rc = getpkt(rpsiz,0); /* Fill a packet from the string. */ #else rc = getpkt(spsiz,0); /* (this can truncate) */ #endif /* COMMENT */ debug(F101,"encstr getpkt rc","",rc); if (rc > -1 && memptr < (char *)(s + slen)) { /* Means we didn't encode */ rc = -1; /* the whole string. */ debug(F101,"encstr string too big","",size); } debug(F101,"encstr getpkt rc","",rc); memstr = m; /* Restore memory string flag */ memptr = p; /* and pointer */ first = 1; /* Put this back as we found it. */ return(rc); } /* Output functions passed to 'decode': */ int /* Put character in server command buffer */ #ifdef CK_ANSIC putsrv(char c) #else putsrv(c) register char c; #endif /* CK_ANSIC */ /* putsrv */ { *srvptr++ = c; *srvptr = '\0'; /* Make sure buffer is null-terminated */ return(0); } int /* Output character to console. */ #ifdef CK_ANSIC puttrm(char c) #else puttrm(c) register char c; #endif /* CK_ANSIC */ /* puttrm */ { extern int rcdactive; #ifndef NOSPL extern char * qbufp; /* If REMOTE QUERY active, */ extern int query, qbufn; /* also store response in */ if (query && qbufn++ < 1024) { /* query buffer. */ *qbufp++ = c; *qbufp = NUL; } if (!query || !xcmdsrc) #endif /* NOSPL */ /* This routine is used (among other things) for printing the server's answer to a REMOTE command. But REMOTE CD is special because it isn't really asking for an answer from the server. Thus some people want to suppress the confirmation message (e.g. when the server sends back the actual path of the directory CD'd to), and expect to be able to do this with SET QUIET ON. But they would not want SET QUIET ON to suppress the other server replies, which are pointless without their answers. Thus the "rcdactive" flag (REMOTE CD command is active). Thu Oct 10 16:38:21 2002 */ if (!(quiet && rcdactive)) /* gross, yuk */ conoc(c); return(0); } #endif /* NOXFER */ int /* Output char to file. */ #ifdef CK_ANSIC putmfil(char c) /* Just like putfil but to ZMFILE */ #else /* rather than ZOFILE... */ putmfil(c) register char c; #endif /* CK_ANSIC */ /* putmfil */ { debug(F000,"putfil","",c); if (zchout(ZMFILE, (char) (c & fmask)) < 0) { czseen = 1; debug(F101,"putfil zchout write error, setting czseen","",1); return(-1); } return(0); } int /* Output char to nowhere. */ #ifdef CK_ANSIC putnowhere(char c) #else putnowhere(c) register char c; #endif /* CK_ANSIC */ /* putnowhere */ { return(0); } int /* Output char to file. */ #ifdef CK_ANSIC putfil(char c) #else putfil(c) register char c; #endif /* CK_ANSIC */ /* putfil */ { debug(F000,"putfil","",c); if (zchout(ZOFILE, (char) (c & fmask)) < 0) { czseen = 1; /* If write error... */ debug(F101,"putfil zchout write error, setting czseen","",1); return(-1); } return(0); } /* The following function is a wrapper for putfil(). The only reason for its existence is to be passed as a function pointer to decode(), which treats putfil() itself specially -- bypassing it and using an internal macro instead to speed things up. Use zputfil() instead of putfil() in cases where we do not want this to happen, e.g. when we need to send output to the file with a mixture of zchout() and zsout()/zsoutl() calls (as is the case with incoming short-form REMOTE command replies redirected to a file), which would otherwise result in data written to the file out of order. */ int #ifdef CK_ANSIC zputfil(char c) #else zputfil(c) register char c; #endif /* CK_ANSIC */ /* zputfil */ { return(putfil(c)); } #ifndef NOXFER /* D E C O D E -- Kermit packet decoding procedure */ /* Call with string to be decoded and an output function. Returns 0 on success, -1 on failure (e.g. disk full). This is the "inner loop" when receiving files, and must be coded as efficiently as possible. Note some potential problems: if a packet is badly formed, having a prefixed sequence ending prematurely, this function, as coded, could read past the end of the packet. This has never happened, thus the additional (time-consuming) tests have not been added. */ static CHAR *xdbuf; /* Global version of decode()'s buffer pointer */ /* for use by translation functions. */ /* Function for pushing a character onto decode()'s input stream. */ VOID #ifdef CK_ANSIC zdstuff(CHAR c) #else zdstuff(c) CHAR c; #endif /* CK_ANSIC */ /* zdstuff */ { xdbuf--; /* Back up the pointer. */ *xdbuf = c; /* Stuff the character. */ } #ifdef CKTUNING /* Trimmed-down packet decoder for binary-mode no-parity transfers. decode() is the full version. */ int #ifdef CK_ANSIC bdecode(CHAR *buf, int (*fn)(char)) #else bdecode(buf,fn) register CHAR *buf; register int (*fn)(); #endif /* CK_ANSIC */ /* bdecode */ { register unsigned int a, a7; /* Various copies of current char */ int ccpflg; /* For Ctrl-unprefixing stats */ int t; /* Int version of character */ int len; long z; /* For CRC calculation */ CHAR c; /* Current character */ if (!binary || parity || fn != putfil) /* JUST IN CASE */ return(decode(buf,fn,1)); debug(F100,"BDECODE","",0); xdbuf = buf; /* Global copy of source pointer. */ len = rln; /* Number of bytes in data field */ while (len > 0) { a = *xdbuf++ & 0xff; /* Get next character */ len--; rpt = 0; /* Initialize repeat count. */ if (a == rptq && rptflg) { /* Got a repeat prefix? */ rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */ rptn += rpt; a = *xdbuf++ & 0xFF; /* and get the prefixed character. */ len -= 2; } ccpflg = 0; /* Control prefix flag. */ if (a == ctlq) { /* If control prefix, */ a = *xdbuf++ & 0xFF; /* get its operand */ len--; a7 = a & 0x7F; /* and its low 7 bits. */ if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') { /* Controllify */ a = ctl(a); /* if in control range. */ a7 = a & 0x7F; ccpflg = 1; /* Note that we did this */ ccp++; /* Count for stats */ } } else a7 = a & 0x7f; /* Not control quote */ if (a7 < 32 || a7 == 127) /* A bare control character? */ if (!ccpflg) ccu++; /* Count it */ if (!rpt) rpt = 1; for (; rpt > 0; rpt--) { /* Output the char RPT times */ #ifdef CALIBRATE if (calibrate) { ffc++; continue; } #endif /* CALIBRATE */ #ifdef OS2 if (xflg && !remfile) { /* Write to virtual screen */ char _a; _a = a & fmask; t = conoc(_a); if (t < 1) t = -1; } else #endif /* OS2 */ t = zmchout(a & fmask); /* zmchout is a macro */ if (t < 0) { debug(F101,"bdecode write error - errno","",errno); return(-1); } ffc++; /* Count the character */ if (docrc && !remfile) { /* Update file CRC */ c = a; /* Force conversion to unsigned char */ z = crc16 ^ (long)c; crc16 = (crc16 >> 8) ^ (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]); } } #ifdef CK_CTRLZ lastchar = a; #endif /* CK_CTRLZ */ } return(0); } #endif /* CKTUNING */ #endif /* NOXFER */ /* P N B Y T E -- Output next byte to file or other destination */ static CK_OFF_T offc = 0L; static int #ifdef CK_ANSIC pnbyte(CHAR c, int (*fn)(char)) #else pnbyte(c,fn) CHAR c; int (*fn)(); #endif /* CK_ANSIC */ /* pnbyte */ { int rc; long z; #ifdef OS2 #ifndef NOXFER if (xflg && !remfile) { /* Write to virtual screen */ char _a; _a = c & fmask; rc = conoc(_a); if (rc < 1) return(-1); } else #endif /* NOXFER */ #endif /* OS2 */ { if (fn == putfil) { /* Execute output function */ rc = zmchout(c); /* to-file macro (fast) */ } else if (!fn) { rc = putchar(c); /* to-screen macro (fast) */ } else { rc = (*fn)(c); /* function call (not as fast) */ } if (rc < 0) return(rc); } /* Both xgnbyte() and xpnbyte() increment ffc (the file byte counter). During file transfer, only one of these functions is called. However, the TRANSLATE command is likely to call them both. offc, therefore, contains the output byte count, necessary for handling the UCS-2 BOM. NOTE: It might be safe to just test for W_SEND, FTP or not. */ if ((what & (W_FTP|W_SEND)) != (W_FTP|W_SEND)) { offc++; /* Count the byte */ ffc++; /* Count the byte */ } #ifndef NOXFER if (docrc && !xflg && !remfile) { /* Update file CRC */ z = crc16 ^ (long)c; crc16 = (crc16 >> 8) ^ (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]); } #endif /* NOXFER */ return(1); } /* X P N B Y T E -- Translate and put next byte to file. Only for Unicode. Call with next untranslated byte from incoming byte stream, which can be in any Transfer Character Set: UCS-2, UTF-8, Latin-1, Latin-Hebrew, etc. Translates to the file character set and writes bytes to the output file. Call with character to translate as an int, plus the transfer character set (to translate from) and the file character set (to translate to), or -1,0,0 to reset the UCS-2 byte number (which should be done at the beginning of a file). If the transfer (source) character-set is UCS-2, bytes MUST arrive in Big-Endian order. Returns: -1: On error 0: Nothing to write (mid-sequence) >0: Number of bytes written. */ #ifdef KANJI static int jstate = 0, jx = 0; /* For outputting JIS-7 */ static char jbuf[16] = { NUL, NUL }; #endif /* KANJI */ int #ifdef CK_ANSIC xpnbyte(int a, int tcs, int fcs, int (*fn)(char)) #else xpnbyte(a,tcs,fcs,fn) int a, tcs, fcs; int (*fn)(); #endif /* CK_ANSIC */ /* xpnbyte */ { #ifdef UNICODE extern int ucsbom; /* Byte order */ #endif /* UNICODE */ /* CHAR c; */ /* Unsigned char worker */ static union ck_short uc, eu, sj; /* UCS-2, EUC, and Shift-JIS workers */ USHORT ch; /* ditto... */ USHORT * us = NULL; /* ditto... */ int c7, rc, haveuc = 0; /* Return code and UCS-2 flag */ int utferror = 0; /* UTF-8 error */ static int bn = 0; /* UCS-2 byte number */ int swapping = 0; /* Swapping UCS bytes to output? */ /* swapping must be 0 or 1 */ if (a == -1 && (tcs | fcs) == 0) { /* Reset in case previous run */ bn = 0; /* left bn at 1... */ offc = (CK_OFF_T)0; debug(F101,"xpnbyte RESET","",bn); return(0); } debug(F001,"xpnbyte a","",a); #ifdef UNICODE /* byteorder = hardware byte order of this machine. ucsorder = override by SET FILE UCS BYTE-ORDER command. fileorder = byte order of UCS-2 input file detected from BOM. swapping applies only when output charset is UCS-2. */ if (ucsorder != 1 && ucsorder != 0) /* Also just in case... */ ucsorder = byteorder; if ((byteorder && !ucsorder) || (!byteorder && fileorder)) swapping = 1; /* Swapping bytes to output */ #ifdef COMMENT debug(F101,"xpnbyte ucsorder","",ucsorder); debug(F101,"xpnbyte swapping","",swapping); #endif /* COMMENT */ if (tcs == TC_UTF8) { /* 'a' is from a UTF-8 stream */ ch = a; if (fcs == TC_UTF8) /* Output is UTF-8 too */ return(pnbyte(ch,fn)); /* so just copy. */ rc = utf8_to_ucs2(ch,&us); /* Otherwise convert to UCS-2 */ if (rc == 0) { /* Done with this sequence */ uc.x_short = *us; /* We have a Unicode */ haveuc = 1; } else if (rc < 0) { /* Error */ debug(F101,"xpnbyte UTF-8 conversion error","",rc); haveuc = 1; /* Replace by U+FFFD */ uc.x_short = *us; utferror = 1; } else /* Sequence incomplete */ return(0); } else if (tcs == TC_UCS2) { /* 'a' is UCS-2 */ /* Here we have incoming UCS-2 in guaranteed Big Endian order */ /* so we must exchange bytes if local machine is Little Endian. */ switch (bn) { /* Which byte? */ case 0: /* High... */ uc.x_char[byteorder] = (unsigned)a & 0xff; bn++; return(0); /* Wait for next */ case 1: /* Low... */ uc.x_char[1-byteorder] = (unsigned)a & 0xff; bn = 0; /* Done with sequence */ haveuc = 1; /* Have a Unicode */ } } else #endif /* UNICODE */ #ifdef KANJI /* Whether UNICODE is defined or not */ if (tcs == TC_JEUC) { /* Incoming Japanese EUC */ int bad = 0; static int kanji = 0; /* Flags set in case 0 for case 1 */ static int kana = 0; switch (bn) { /* Byte number */ case 0: /* Byte 0 */ eu.x_short = 0; if ((a & 0x80) == 0) { sj.x_short = (unsigned)a & 0xff; /* Single byte */ kanji = kana = 0; } else { /* Double byte */ c7 = a & 0x7f; if (c7 > 0x20 && c7 < 0x7f) { /* Kanji */ eu.x_char[byteorder] = (CHAR) a; /* Store first byte */ bn++; /* Set up for second byte */ kanji = 1; kana = 0; return(0); } else if (a == 0x8e) { /* SS2 -- Katakana prefix */ eu.x_char[byteorder] = (CHAR) a; /* Save it */ bn++; kana = 1; kanji = 0; return(0); } else { bad++; } } break; case 1: /* Byte 1 */ bn = 0; if (kanji) { eu.x_char[1-byteorder] = (CHAR) a; sj.x_short = eu_to_sj(eu.x_short); break; } else if (kana) { sj.x_short = (CHAR) (a | 0x80); break; } else { /* (shouldn't happen) */ bad++; } } /* Come here with one Shift-JIS character */ #ifdef UNICODE if (bad) { uc.x_short = 0xfffd; } else { uc.x_short = sj_to_un(sj.x_short); /* Convert to Unicode */ } haveuc = 1; #endif /* UNICODE */ } else #endif /* KANJI */ #ifdef UNICODE uc.x_short = (unsigned)a & 0xff; /* Latin-1 or whatever... */ /* Come here with uc = the character to be translated. */ /* If (haveuc) it's UCS-2 in native order, otherwise it's a byte. */ debug(F101,"xpnbyte haveuc","",haveuc); if (haveuc) { /* If we have a Unicode... */ debug(F001,"xpnbyte uc.x_short","[A]",uc.x_short); debug(F101,"xpnbyte feol","",feol); if (what & W_XFER) { /* If transferring a file */ if (feol && uc.x_short == CK_CR) { /* handle eol conversion. */ return(0); } else if (feol && uc.x_short == LF) { uc.x_short = feol; } } debug(F001,"xpnbyte uc.x_short","[B]",uc.x_short); if (fcs == FC_UCS2) { /* And FCS is UCS-2 */ /* Write out the bytes in the appropriate byte order */ int count = 0; #ifndef IKSDONLY #ifdef OS2 extern int k95stdout,wherex[],wherey[]; extern unsigned char colorcmd; union { USHORT ucs2; UCHAR bytes[2]; } output; #endif /* OS2 */ #endif /* IKSDONLY */ if (!offc && ucsbom) { /* Beginning of file? */ #ifndef IKSDONLY #ifdef OS2 if (fn == NULL && !k95stdout && !inserver) { offc++; #ifdef COMMENT /* Don't print the BOM to the display */ output.bytes[0] = (!ucsorder ? 0xff : 0xfe); output.bytes[1] = (!ucsorder ? 0xfe : 0xff); VscrnWrtUCS2StrAtt(VCMD, &output.ucs2, 1, wherey[VCMD], wherex[VCMD], &colorcmd ); #endif /* COMMENT */ } else #endif /* OS2 */ #endif /* IKSDONLY */ { if ((rc = pnbyte((ucsorder ? 0xff : 0xfe),fn)) < 0) return(rc); /* BOM */ if ((rc = pnbyte((ucsorder ? 0xfe : 0xff),fn)) < 0) return(rc); } count += 2; } if (utferror) { #ifndef IKSDONLY #ifdef OS2 if (fn == NULL && !k95stdout && !inserver) { offc++; output.bytes[0] = (!ucsorder ? 0xfd : 0xff); output.bytes[1] = (!ucsorder ? 0xff : 0xfd); VscrnWrtUCS2StrAtt(VCMD, &output.ucs2, 1, wherey[VCMD], wherex[VCMD], &colorcmd ); } else #endif /* OS2 */ #endif /* IKSDONLY */ { if ((rc = pnbyte((ucsorder ? 0xfd : 0xff),fn)) < 0) return(rc); if ((rc = pnbyte((ucsorder ? 0xff : 0xfd),fn)) < 0) return(rc); } count += 2; } #ifndef IKSDONLY #ifdef OS2 if (fn == NULL && !k95stdout && !inserver) { offc++; output.bytes[0] = uc.x_char[swapping]; output.bytes[1] = uc.x_char[1-swapping]; VscrnWrtUCS2StrAtt(VCMD, &output.ucs2, 1, wherey[VCMD], wherex[VCMD], &colorcmd ); } else #endif /* OS2 */ #endif /* IKSDONLY */ { if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0) return(rc); if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0) return(rc); } count += 2; return(count); } else if (fcs == FC_UTF8) { /* Convert to UTF-8 */ CHAR * buf = NULL; int i, count; if (utferror) { if ((rc = pnbyte((ucsorder ? 0xbd : 0xff),fn)) < 0) return(rc); if ((rc = pnbyte((ucsorder ? 0xff : 0xbd),fn)) < 0) return(rc); } if ((count = ucs2_to_utf8(uc.x_short,&buf)) < 1) return(-1); debug(F011,"xpnbyte buf",buf,count); for (i = 0; i < count; i++) if ((rc = pnbyte(buf[i],fn)) < 0) return(rc); if (utferror) count += 2; return(count); } else { /* Translate UCS-2 to byte */ if (uc.x_short == 0x2028 || uc.x_short == 0x2029) { if (utferror) pnbyte(UNK,fn); if (feol) return(pnbyte((CHAR)feol,fn)); if ((rc = pnbyte((CHAR)CK_CR,fn)) < 0) return(rc); if ((rc = pnbyte((CHAR)LF,fn)) < 0) return(rc); else return(utferror ? 3 : 2); } else if (xuf) { /* UCS-to-FCS function */ int x = 0; if (utferror) pnbyte(UNK,fn); if ((rc = (*xuf)(uc.x_short)) < 0) /* These can fail... */ ch = UNK; else ch = (unsigned)((unsigned)rc & 0xffff); x = pnbyte(ch,fn); if (x < 0) return(x); else if (utferror) x++; return(x); #ifdef KANJI /* Also see the non-Unicode Kanji section further down in this function. */ } else if (fcsinfo[fcs].alphabet == AL_JAPAN) { /* Translate UCS-2 to Japanese set */ debug(F001,"xpnbyte uc","",uc.x_short); sj.x_short = un_to_sj(uc.x_short); /* First to Shift-JIS */ debug(F001,"xpnbyte sj","",sj.x_short); switch (fcs) { /* File character set */ case FC_SHJIS: /* Shift-JIS -- just output it */ if (sj.x_char[byteorder]) /* But not high byte if zero */ if ((rc = pnbyte((CHAR)sj.x_char[byteorder],fn)) < 0) return(rc); if ((rc = pnbyte((CHAR)sj.x_char[1-byteorder],fn)) < 0) return(rc); return(2); case FC_JEUC: /* EUC-JP */ eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */ debug(F001,"xpnbyte eu","",eu.x_short); if (eu.x_short == 0xffff) { /* Bad */ if ((rc = pnbyte(UNK,fn)) < 0) return(rc); return(1); } else { /* Good */ int count = 0; /* Write high byte if not zero */ if (eu.x_char[byteorder]) { if ((rc=pnbyte((CHAR)eu.x_char[byteorder],fn)) < 0) return(rc); count++; } /* Always write low byte */ if ((rc = pnbyte((CHAR)eu.x_char[1-byteorder],fn)) < 0) return(rc); count++; return(count); } break; case FC_JIS7: /* JIS-7 */ case FC_JDEC: /* DEC Kanji */ eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */ if (eu.x_short == 0xffff) { /* Bad */ debug(F001,"xpnbyte bad eu","",eu.x_short); if ((rc = pnbyte(UNK,fn)) < 0) return(rc); return(1); } else { /* Good */ int i; /* Use another name - 'a' hides parameter */ /* It's OK as is but causes compiler warnings */ char a = eu.x_char[1-byteorder]; /* Low byte */ debug(F001,"xpnbyte eu","",eu.x_short); if (eu.x_char[byteorder] == 0) { /* Roman */ switch (jstate) { case 1: /* Current state is Katakana */ jbuf[0] = 0x0f; /* SI */ jbuf[1] = a; jx = 2; break; case 2: /* Current state is Kanji */ jbuf[0] = 0x1b; /* ESC */ jbuf[1] = 0x28; /* ( */ jbuf[2] = 0x4a; /* J */ jbuf[3] = a; jx = 4; break; default: /* Current state is Roman */ jbuf[0] = a; jx = 1; break; } jstate = 0; /* New state is Roman */ } else if (eu.x_char[byteorder] == 0x8e) { /* Kana */ jx = 0; switch (jstate) { case 2: /* from Kanji */ jbuf[jx++] = 0x1b; /* ESC */ jbuf[jx++] = 0x28; /* ( */ jbuf[jx++] = 0x4a; /* J */ case 0: /* from Roman */ jbuf[jx++] = 0x0e; /* SO */ default: /* State is already Kana*/ jbuf[jx++] = (a & 0x7f); /* and the char */ break; } jstate = 1; /* New state is Katakana */ } else { /* Kanji */ jx = 0; switch (jstate) { case 1: /* Current state is Katakana */ jbuf[jx++] = 0x0f; /* SI */ case 0: /* Current state is Roman */ jbuf[jx++] = 0x1b; /* ESC */ jbuf[jx++] = 0x24; /* $ */ jbuf[jx++] = 0x42; /* B */ default: /* Current state is already Kanji */ jbuf[jx++] = eu.x_char[byteorder] & 0x7f; jbuf[jx++] = eu.x_char[1-byteorder] & 0x7f; break; } jstate = 2; /* Set state to Kanji */ } for (i = 0; i < jx; i++) /* Output the result */ if ((rc = pnbyte(jbuf[i],fn)) < 0) return(rc); return(jx); /* Return its length */ } } #endif /* KANJI */ } else { /* No translation function */ int count = 0; if (utferror) { if ((rc = pnbyte((ucsorder ? 0xfd : 0xff),fn)) < 0) return(rc); if ((rc = pnbyte((ucsorder ? 0xff : 0xfd),fn)) < 0) return(rc); count += 2; } if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0) return(rc); if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0) return(rc); count += 2; return(count); } } } else { /* Byte to Unicode */ if (xtu) { /* TCS-to-UCS function */ if (((tcsinfo[tcs].size > 128) && (uc.x_short & 0x80)) || tcsinfo[tcs].size <= 128) uc.x_short = (*xtu)(uc.x_short); } if (fcs == FC_UCS2) { /* And FCS is UCS-2 */ /* Write out the bytes in the appropriate byte order */ if (!offc && ucsbom) { /* Beginning of file? */ if ((rc = pnbyte((ucsorder ? 0xff : 0xfe),fn)) < 0) /* BOM */ return(rc); if ((rc = pnbyte((ucsorder ? 0xfe : 0xff),fn)) < 0) return(rc); } if ((rc = pnbyte(uc.x_char[swapping],fn)) < 0) return(rc); if ((rc = pnbyte(uc.x_char[1-swapping],fn)) < 0) return(rc); return(2); } else if (fcs == FC_UTF8) { /* Convert to UTF-8 */ CHAR * buf = NULL; int i, count; if ((count = ucs2_to_utf8(uc.x_short,&buf)) < 1) return(-1); for (i = 0; i < count; i++) if ((rc = pnbyte(buf[i],fn)) < 0) return(rc); return(count); } else { debug(F100,"xpnbyte impossible combination","",0); return(-1); } } #else #ifdef KANJI /* This almost, but not quite, duplicates the Kanji section above. There is no doubt a way to combine the sections more elegantly, but probably only at the expense of additional execution overhead. As matters stand, be careful to reflect any changes in this section to the other Kanji section above. */ if (tcs == TC_JEUC) { /* Incoming Japanese EUC */ int count = 0; switch (fcs) { /* File character set */ case FC_SHJIS: /* Shift-JIS -- just output it */ if (sj.x_char[byteorder]) /* But not high byte if zero */ if ((rc = pnbyte((CHAR)sj.x_char[byteorder],fn)) < 0) return(rc); count++; if ((rc = pnbyte((CHAR)sj.x_char[1-byteorder],fn)) < 0) return(rc); count++; return(count); case FC_JEUC: /* EUC-JP */ eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */ debug(F001,"xpnbyte FC_JEUC eu","",eu.x_short); if (eu.x_short == 0xffff) { /* Bad */ if ((rc = pnbyte(UNK,fn)) < 0) return(rc); return(1); } else { /* Good */ int count = 0; /* Write high byte if not zero */ if (eu.x_char[byteorder]) { if ((rc = pnbyte((CHAR)eu.x_char[byteorder],fn)) < 0) return(rc); count++; } /* Always write low byte */ if ((rc = pnbyte((CHAR)eu.x_char[1-byteorder],fn)) < 0) return(rc); count++; return(count); } break; case FC_JIS7: /* JIS-7 */ case FC_JDEC: /* DEC Kanji */ eu.x_short = sj_to_eu(sj.x_short); /* Shift-JIS to EUC */ if (eu.x_short == 0xffff) { /* Bad */ debug(F001,"xpnbyte FC_JIS7 bad eu","",eu.x_short); if ((rc = pnbyte(UNK,fn)) < 0) return(rc); return(1); } else { /* Good */ int i; char a = eu.x_char[1-byteorder]; /* Low byte */ debug(F001,"xpnbyte FC_JIS7 eu","",eu.x_short); if (eu.x_char[byteorder] == 0) { /* Roman */ switch (jstate) { case 1: /* Current state is Katakana */ jbuf[0] = 0x0f; /* SI */ jbuf[1] = a; jx = 2; break; case 2: /* Current state is Kanji */ jbuf[0] = 0x1b; /* ESC */ jbuf[1] = 0x28; /* ( */ jbuf[2] = 0x4a; /* J */ jbuf[3] = a; jx = 4; break; default: /* Current state is Roman */ jbuf[0] = a; jx = 1; break; } jstate = 0; /* New state is Roman */ } else if (eu.x_char[byteorder] == 0x8e) { /* Kana */ jx = 0; switch (jstate) { case 2: /* from Kanji */ jbuf[jx++] = 0x1b; /* ESC */ jbuf[jx++] = 0x28; /* ( */ jbuf[jx++] = 0x4a; /* J */ case 0: /* from Roman */ jbuf[jx++] = 0x0e; /* SO */ default: /* State is already Kana*/ jbuf[jx++] = (a & 0x7f); /* and the char */ break; } jstate = 1; /* New state is Katakana */ } else { /* Kanji */ jx = 0; switch (jstate) { case 1: /* Current state is Katakana */ jbuf[jx++] = 0x0f; /* SI */ case 0: /* Current state is Roman */ jbuf[jx++] = 0x1b; /* ESC */ jbuf[jx++] = 0x24; /* $ */ jbuf[jx++] = 0x42; /* B */ default: /* Current state is already Kanji */ jbuf[jx++] = eu.x_char[byteorder] & 0x7f; jbuf[jx++] = eu.x_char[1-byteorder] & 0x7f; break; } jstate = 2; /* Set state to Kanji */ } for (i = 0; i < jx; i++) /* Output the result */ if ((rc = pnbyte(jbuf[i],fn)) < 0) return(rc); return(jx); /* Return its length */ } default: if (sj.x_short < 0x80) return(sj.x_short); else return('?'); } } #endif /* KANJI */ #endif /* UNICODE */ debug(F100,"xpnbyte BAD FALLTHRU","",0); return(-1); } #ifndef NOXFER /* D E C O D E -- Kermit Data-packet decoder */ int #ifdef CK_ANSIC decode(CHAR *buf, int (*fn)(char), int xlate) #else decode(buf,fn,xlate) register CHAR *buf; register int (*fn)(); int xlate; #endif /* CK_ANSIC */ /* decode */ { register unsigned int a, a7, a8, b8; /* Various copies of current char */ int t; /* Int version of character */ int ssflg; /* Character was single-shifted */ int ccpflg; /* For Ctrl-unprefixing stats */ int len; long z; CHAR c; /* Catch the case in which we are asked to decode into a file that is not open, for example, if the user interrupted the transfer, but the other Kermit keeps sending. */ if ((cxseen || czseen || discard) && (fn == putfil)) return(0); #ifdef COMMENT #ifdef CKTUNING if (binary && !parity) return(bdecode(buf,fn)); #endif /* CKTUNING */ #endif /* COMMENT */ debug(F100,"DECODE","",0); xdbuf = buf; /* Make global copy of pointer. */ rpt = 0; /* Initialize repeat count. */ len = rln; /* Number of bytes in data field */ while (len > 0) { /* Loop for each byte */ a = *xdbuf++ & 0xff; /* Get next character */ len--; if (a == rptq && rptflg) { /* Got a repeat prefix? */ rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */ rptn += rpt; a = *xdbuf++ & 0xFF; /* and get the prefixed character. */ len -= 2; } b8 = lsstate ? 0200 : 0; /* 8th-bit value from SHIFT-STATE */ if (ebqflg && a == ebq) { /* Have 8th-bit prefix? */ b8 ^= 0200; /* Yes, invert the 8th bit's value, */ ssflg = 1; /* remember we did this, */ a = *xdbuf++ & 0xFF; /* and get the prefixed character. */ len--; } else ssflg = 0; ccpflg = 0; if (a == ctlq) { /* If control prefix, */ a = *xdbuf++ & 0xFF; /* get its operand */ len--; a7 = a & 0x7F; /* and its low 7 bits. */ if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') { /* Controllify */ a = ctl(a); /* if in control range. */ a7 = a & 0x7F; ccpflg = 1; /* Note that we did this */ ccp++; /* Count for stats */ } } else a7 = a & 0x7f; /* Not control quote */ if (a7 < 32 || a7 == 127) { /* Control character? */ if (!ccpflg) ccu++; /* A bare one, count it */ if (lscapu) { /* If doing locking shifts... */ if (lsstate) /* If SHIFTED */ a8 = (a & ~b8) & 0xFF; /* Invert meaning of 8th bit */ else /* otherwise */ a8 = a | b8; /* OR in 8th bit */ /* If we're not in a quoted sequence */ if (!lsquote && (!lsstate || !ssflg)) { if (a8 == DLE) { /* Check for DLE quote */ lsquote = 1; /* prefixed by single shift! */ continue; } else if (a8 == SO) { /* Check for Shift-Out */ lsstate = 1; /* SHIFT-STATE = SHIFTED */ continue; } else if (a8 == SI) { /* or Shift-In */ lsstate = 0; /* SHIFT-STATE = UNSHIFTED */ continue; } } else lsquote = 0; } } a |= b8; /* OR in the 8th bit */ if (rpt == 0) rpt = 1; /* If no repeats, then one */ #ifndef NOCSETS if (!binary) { /* If in text mode, */ if (tcharset != TC_UCS2) { if (feol && a == CK_CR) /* Convert CRLF to newline char */ continue; if (feol && a == LF) a = feol; } if (xlatype == XLA_BYTE) /* Byte-for-byte - do it now */ if (xlate && rx) a = (*rx)((CHAR) a); } #endif /* NOCSETS */ /* (PWP) Decoding speedup via buffered output and a macro... */ if (fn == putfil) { for (; rpt > 0; rpt--) { /* Output the char RPT times */ #ifdef CALIBRATE if (calibrate) { ffc++; continue; } #endif /* CALIBRATE */ /* Note: The Unicode and Kanji sections can probably be combined now; */ /* the Unicode method (xpnbyte()) covers Kanji too. */ #ifdef UNICODE if (!binary && xlatype == XLA_UNICODE) t = xpnbyte((unsigned)((unsigned)a & 0xff), tcharset, fcharset, fn ); else #endif /* UNICODE */ #ifdef KANJI if (!binary && tcharset == TC_JEUC && fcharset != FC_JEUC) { /* Translating from J-EUC */ if (!ffc) xkanjf(); if (xkanji(a,fn) < 0) /* to something else? */ return(-1); else t = 1; } else #endif /* KANJI */ { #ifdef OS2 if (xflg && !remfile) { /* Write to virtual screen */ char _a; _a = a & fmask; t = conoc(_a); if (t < 1) t = -1; } else #endif /* OS2 */ t = zmchout(a & fmask); /* zmchout is a macro */ } if (t < 0) { debug(F101,"decode write errno","",errno); return(-1); } #ifdef UNICODE if (xlatype != XLA_UNICODE || binary) { ffc++; /* Count the character */ if (docrc && !xflg && !remfile) { /* Update file CRC */ c = a; /* Force conversion to unsigned char */ z = crc16 ^ (long)c; crc16 = (crc16 >> 8) ^ (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]); } } #endif /* UNICODE */ } } else { /* Output to something else. */ a &= fmask; /* Apply file mask */ for (; rpt > 0; rpt--) { /* Output the char RPT times */ #ifdef CALIBRATE if (calibrate) { ffc++; continue; } #endif /* CALIBRATE */ if ((*fn)((char) a) < 0) return(-1); /* Send to output func. */ } } #ifdef CK_CTRLZ lastchar = a; #endif /* CK_CTRLZ */ } return(0); } /* G E T P K T -- Fill a packet data field */ /* Gets characters from the current source -- file or memory string. Encodes the data into the packet, filling the packet optimally. Set first = 1 when calling for the first time on a given input stream (string or file). Call with: bufmax -- current send-packet size xlate -- flag: 0 to skip character-set translation, 1 to translate Uses global variables: t -- current character. first -- flag: 1 to start up, 0 for input in progress, -1 for EOF. next -- next character (not used any more). data -- pointer to the packet data buffer. size -- number of characters in the data buffer. memstr - flag that input is coming from a memory string instead of a file. memptr - pointer to string in memory. (*sx)() character set translation function Returns: The size as value of the function, and also sets global "size", and fills (and null-terminates) the global data array. Returns: 0 on EOF. -1 on fatal (internal) error. -3 on timeout (e.g. when reading data from a pipe). Rewritten by Paul W. Placeway (PWP) of Ohio State University, March 1989. Incorporates old getchx() and encode() inline to reduce function calls, uses buffered input for much-improved efficiency, and clears up some confusion with line termination (CRLF vs LF vs CR). Rewritten again by Frank da Cruz to incorporate locking shift mechanism, May 1991. And again in 1998 for efficiency, etc, with a separate bgetpkt() split out for binary-mode no-parity transfers. */ /* Note: Separate Kanji support dates from circa 1991 and now (1999) can most likely be combined with the Unicode support: the xgnbyte()/xpnbyte() mechanism works for both Unicode and Kanji. */ #ifdef KANJI int kgetf( #ifdef CK_ANSIC VOID #endif /* CK_ANSIC */ ) { if (funcstr) return((*funcptr)()); else return(zminchar()); } int kgetm( #ifdef CK_ANSIC VOID #endif /* CK_ANSIC */ ) { int x; if ((x = *memptr++)) return(x); else return(-1); } #endif /* KANJI */ /* Lookahead function to decide whether locking shift is worth it. Looks at the next four input characters to see if all of their 8th bits match the argument. Call with 0 or 0200. Returns 1 on match, 0 if they don't match. If we don't happen to have at least 4 more characters waiting in the input buffer, returns 1. Note that zinptr points two characters ahead of the current character because of repeat-count lookahead. */ int #ifdef CK_ANSIC lslook( unsigned int b ) /* Locking Shift Lookahead */ #else lslook(b) unsigned int b; #endif /* CK_ANSIC */ { int i; if (zincnt < 3) /* If not enough chars in buffer, */ return(1); /* force shift-state switch. */ b &= 0200; /* Force argument to proper form. */ for (i = -1; i < 3; i++) /* Look at next 5 characters to */ if (((*(zinptr+i)) & 0200) != b) /* see if all their 8th bits match. */ return(0); /* They don't. */ return(1); /* They do. */ } /* Routine to compute maximum data length for packet to be filled */ int maxdata() { /* Get maximum data length */ int n, len; debug(F101,"maxdata spsiz 1","",spsiz); if (spsiz < 0) /* How could this happen? */ spsiz = DSPSIZ; debug(F101,"maxdata spsiz 2","",spsiz); n = spsiz - 5; /* Space for Data and Checksum */ if (n > 92 && n < 96) n = 92; /* "Short" Long packets don't pay */ if (n > 92 && lpcapu == 0) /* If long packets needed, */ n = 92; /* make sure they've been negotiated */ len = n - bctl; /* Space for data */ if (n > 92) len -= 3; /* Long packet needs header chksum */ debug(F101,"maxdata len 1","",len); if (len < 0) len = 10; debug(F101,"maxdata len 2","",len); return(len); } static CHAR leftover[9] = { '\0','\0','\0','\0','\0','\0','\0','\0','\0' }; static int nleft = 0; #ifdef CKTUNING /* When CKTUNING is defined we use this special trimmed-down version of getpkt to speed up binary-mode no-parity transfers. When CKTUNING is not defined, or for text-mode or parity transfers, we use the regular getpkt() function. Call just like getpkt() but test first for transfer mode and parity. NOTE: This routine is only to be called when sending a real file -- not for filenames, server responses, etc, because it only reads from the input file. See getpkt() for more detailed commentary. */ static int #ifdef CK_ANSIC bgetpkt( int bufmax ) #else bgetpkt(bufmax) int bufmax; #endif /* CK_ANSIC */ { register CHAR rt = t, rnext; register CHAR *dp, *odp, *p1, *p2; register int x = 0, a7; CHAR xxrc, xxcq; /* Pieces of prefixed sequence */ long z; /* A long worker (for CRC) */ if (!binary || parity || memstr) /* JUST IN CASE caller didn't test */ return(getpkt(bufmax,!binary)); if (!data) { debug(F100,"SERIOUS ERROR: bgetpkt data == NULL","",0); return(-1); } dp = data; /* Point to packet data buffer */ size = 0; /* And initialize its size */ #ifdef COMMENT /* No - bufmax is a parameter */ bufmax = maxdata(); /* Get maximum data length */ #endif #ifdef DEBUG if (deblog) debug(F101,"bgetpkt bufmax","",bufmax); #endif /* DEBUG */ if (first == 1) { /* If first character of this file.. */ ffc = (CK_OFF_T)0; /* reset file character counter */ #ifdef COMMENT /* Moved to below */ first = 0; /* Next character won't be first */ #endif /* COMMENT */ *leftover = '\0'; /* Discard any interrupted leftovers */ nleft = 0; /* Get first character of file into rt, watching out for null file */ #ifdef CALIBRATE if (calibrate) { #ifdef NORANDOM rt = 17; #else rt = cal_a[rand() & 0xff]; #endif /* NORANDOM */ first = 0; } else #endif /* CALIBRATE */ if ((x = zminchar()) < 0) { /* EOF or error */ if (x == -3) { /* Timeout. */ size = (dp - data); debug(F101,"bgetpkt timeout size","",size); return((size == 0) ? x : size); } first = -1; size = 0; if (x == -2) { /* Error */ debug(F100,"bgetpkt: input error","",0); cxseen = 1; /* Interrupt the file transfer */ } else { debug(F100,"bgetpkt empty file","",0); } return(0); } first = 0; /* Next char will not be the first */ ffc++; /* Count a file character */ rt = (CHAR) x; /* Convert int to char */ if (docrc && (what & W_SEND)) { /* Accumulate file crc */ z = crc16 ^ (long)rt; crc16 = (crc16 >> 8) ^ (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]); } rt &= fmask; /* Apply SET FILE BYTESIZE mask */ } else if (first == -1 && nleft == 0) { /* EOF from last time */ return(size = 0); } /* Here we handle characters that were encoded for the last packet but did not fit, and so were saved in the "leftover" array. */ if (nleft) { for (p1 = leftover; nleft > 0; nleft--) /* Copy leftovers */ *dp++ = *p1++; *leftover = '\0'; /* Delete leftovers */ nleft = 0; } if (first == -1) /* Handle EOF */ return(size = (dp - data)); /* Now fill up the rest of the packet. */ rpt = 0; /* Initialize character repeat count */ while (first > -1) { /* Until EOF... */ #ifdef CALIBRATE if (calibrate) { /* We generate our own "file" */ if (ffc >= calibrate) { /* EOF */ first = -1; ffc--; } else { /* Generate next character */ if (cal_j > CAL_M * ffc) cal_j = cal_a[ffc & 0xff]; x = (unsigned)cal_a[(cal_j & 0xff)]; if (x == rt) x ^= 2; } ffc++; cal_j += (unsigned int)(ffc + CAL_O); } else #endif /* CALIBRATE */ if ((x = zminchar()) < 0) { /* Check for EOF */ if (x == -3) { /* Timeout. */ t = rt; size = (dp-data); debug(F101,"bgetpkt timeout size","",size); return((size == 0) ? x : size); } first = -1; /* Flag eof for next time. */ if (x == -2) cxseen = 1; /* If error, cancel this file. */ } else { ffc++; /* Count the character */ if (docrc && (what & W_SEND)) { /* Accumulate file crc */ z = crc16 ^ (long)((CHAR)x & 0xff); crc16 = (crc16 >> 8) ^ (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]); } } rnext = (CHAR) (x & fmask); /* Apply file mask */ /* At this point, the character we just read is in rnext, and the character we are about to encode into the packet is in rt. */ odp = dp; /* Remember where we started. */ xxrc = xxcq = NUL; /* Clear these. */ /* Now encode the character according to the options that are in effect: ctlp[]: whether this control character needs prefixing. rptflg: repeat counts enabled. Other options don't apply in this routine. */ if (rptflg && (rt == rnext) && (first == 0)) { /* Got a run... */ if (++rpt < 94) { /* Below max, just count */ continue; /* go back and get another */ } else if (rpt == 94) { /* Reached max, must dump */ xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */ rptn += rpt; /* Accumulate it for statistics */ rpt = 0; /* And reset it */ } } else if (rpt > 0) { /* End of run */ xxrc = (CHAR)tochar(++rpt); /* The count */ rptn += rpt; /* For stats */ rpt = 0; /* Reset repeat count */ } a7 = rt & 0177; /* Get low 7 bits of character */ if ( #ifdef CK_SPEED ctlp[(unsigned)(rt & 0xff)] /* Lop off any "sign" extension */ #else (a7 < SP) || (a7 == DEL) #endif /* CK_SPEED */ ) { /* Do control prefixing if necessary */ xxcq = myctlq; /* The prefix */ ccp++; /* Count it */ rt = (CHAR) ctl(rt); /* Uncontrollify the character */ } #ifdef CK_SPEED else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */ ccu++; #endif /* CK_SPEED */ if (a7 == myctlq) /* Always prefix the control prefix */ xxcq = myctlq; if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */ xxcq = myctlq; /* prefix it if doing repeat counts */ /* Now construct the prefixed sequence */ if (xxrc) { /* Repeat count */ #ifdef COMMENT if (xxrc == (CHAR) '"' && !xxcq) { /* 2 in a row & not prefixed */ *dp++ = rt; /* So just do this */ } else { /* More than two or prefixed */ *dp++ = (CHAR) rptq; *dp++ = xxrc; /* Emit repeat sequence */ } #else /* CHECK THIS */ if (xxrc == (CHAR) '"' && !xxcq) { /* 2 in a row & not prefixed */ if (dp == data) { *dp++ = rt; /* So just do this */ } else if (*(dp-1) == rt) { *dp++ = (CHAR) rptq; *dp++ = xxrc; /* Emit repeat sequence */ } else { *dp++ = rt; /* So just do this */ } } else { /* More than two or prefixed */ *dp++ = (CHAR) rptq; *dp++ = xxrc; /* Emit repeat sequence */ } #endif /* COMMENT */ } if (xxcq) { *dp++ = myctlq; } /* Control prefix */ *dp++ = rt; /* Finally, the character itself */ rt = rnext; /* Next character is now current. */ /* Done encoding the character. Now take care of packet buffer overflow. */ size = dp - data; /* How many bytes we put in buffer. */ if (size >= bufmax) { /* If too big, save some for next. */ *dp = '\0'; /* Mark the end. */ if (size > bufmax) { /* if packet is overfull */ /* Copy the part that doesn't fit into the leftover buffer, */ /* taking care not to split a prefixed sequence. */ int i; nleft = dp - odp; p1 = leftover; p2 = odp; for (i = 0; i < nleft; i++) *p1++ = *p2++; size = odp - data; /* Return truncated packet. */ *odp = '\0'; /* Mark the new end */ } t = rt; /* Save for next time */ return(size); } } /* Otherwise, keep filling. */ size = dp - data; /* End of file */ *dp = '\0'; /* Mark the end of the data. */ return(size); /* Return partially filled last packet. */ } #endif /* CKTUNING */ VOID #ifdef CK_ANSIC dofilcrc( int c ) /* Accumulate file crc */ #else dofilcrc(c) int c; #endif /* CK_ANSIC */ { long z; z = crc16 ^ (long)c; crc16 = (crc16 >> 8) ^ (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]); } /* For SENDing from an array... */ int agnbyte() { /* Get next byte from array */ #ifndef NOSPL char c; static int save = 0; /* For CRLF */ static char ** ap = NULL; /* Array pointer */ static char * p = NULL; /* Character pointer */ static int i = 0, n = 0; /* Array index and limit */ extern int a_dim[]; /* Array dimension */ if (!ap) { /* First time thru */ ap = sndarray; /* Set up array pointers */ if (!ap || (i = sndxlo) > a_dim[sndxin]) { sndarray = NULL; ap = NULL; return(-1); } p = ap[i]; /* Point to first element in range */ n = sndxhi; /* Index of last element in range */ if (sndxhi > a_dim[sndxin]) /* Adjust if necessary */ n = a_dim[sndxin]; } if (save) { /* If anything saved */ c = save; /* unsave it */ save = 0; /* and return it */ return(c & 0xff); } if (i > n) { /* No more elements */ sndarray = NULL; ap = NULL; return(-1); } if (!p) /* Source pointer is NULL */ c = NUL; /* this means an empty line */ else /* Source pointer not NULL */ c = *p++; /* Next char */ if (!c) { /* Char is empty? */ if (!binary) { /* Text: end of line. */ if (feol) { /* Supply NL */ c = feol; } else { /* or CRLF */ save = LF; c = CK_CR; } p = ap[++i]; return(c & 0xff); } while (i++ < n) { /* Binary - get next element */ p = ap[i]; if (!p) /* Empty line? */ continue; /* Ignore it and get another */ c = *p++; /* Get next char */ if (!c) /* Emtpy char? */ continue; /* Ignore it and get another */ return(c & 0xff); /* Not empty - return it */ } sndarray = NULL; ap = NULL; return(-1); /* Done */ } return(c & 0xff); /* Char is not empty */ #else sndarray = NULL; return(-1); #endif /* NOSPL */ } #endif /* NOXFER */ #ifndef NOCSETS static CHAR xlabuf[32] = { 0, 0, 0, 0, 0, 0, 0, 0 }; static int xlacount = 0; static int xlaptr = 0; /* static USHORT lastucs2 = 0; */ /* X G N B Y T E -- Get next translated byte from the input file. Returns the next byte that is to be put into the packet, already translated. This isolates getpkt() from having to know anything about translation, single- vs multibyte character sets, one-to-many vs many-to-one, etc, but it has rather high overhead, so don't call it unless you know translation is needed to or from Unicode, Japanese, or other multibyte character set. Call with: fcs: File character set (source, file we are reading from) tcs: Target character set (use an FC_xxx code, not a TC_xxx code) Returns: >= 0: A translated byte suitable for writing. < 0: Fatal error (such as EOF on input source). As of Sat Sep 7 18:37:41 2002: When the output character-set is UCS-2, bytes are ALWAYS returned in big-endian order (previously they could also be returned in LE order under certain conditions, which was just way too confusing). */ int #ifdef CK_ANSIC xgnbyte(int tcs, int fcs, int (*fn)(void)) #else /* CK_ANSIC */ xgnbyte(tcs,fcs,fn) int tcs, fcs, (*fn)(); #endif /* CK_ANSIC */ /* xgnbyte */ { _PROTOTYP( int (*xx), (USHORT) ) = NULL; int haveuc = 0; /* Flag for have Unicode character */ #ifdef KANJI int havesj = 0; /* Have Shift-JIS character */ int haveeu = 0; /* Have EUC-JP character */ #endif /* KANJI */ int rc = -1, x = 0, flag = 0; int utferror = 0; int eolflag = 0; unsigned int xc, thischar; static int swapping = 0; CHAR rt; /* USHORT ch; */ #ifdef UNICODE union ck_short uc; #endif /* UNICODE */ #ifdef KANJI union ck_short sj, eu; /* Shift-JIS character */ #endif /* KANJI */ #ifdef KANJI sj.x_short = 0; #endif /* KANJI */ #ifdef DEBUG if (deblog && !ffc) { debug(F101,"xgnbyte initial swap","",swapping); } #endif /* DEBUG */ if (xlacount-- > 0) { /* We already have some */ x = xlabuf[xlaptr++]; debug(F001,"xgnbyte from buf","",x); return(x); } if (xlatype != XLA_NONE) { /* Not not translating... */ haveuc = 0; #ifdef UNICODE if (fcs == FC_UCS2) { /* UCS-2: Read two bytes */ if (!ffc) /* Beginning of file? */ swapping = 0; /* Reset byte-swapping flag */ uc.x_short = 0; bomskip: x = fn ? (*fn)() : zminchar(); /* Get first byte */ debug(F001,"zminchar swapping","",swapping); debug(F001,"zminchar C0","",x); flag = 1; /* Remember we called zminchar() */ if (x > -1) { /* Didn't fail */ ffc++; /* Count a file byte */ uc.x_char[swapping] = x & 0xff; #ifndef NOXFER if (docrc && (what & W_SEND)) dofilcrc(x); #endif /* NOXFER */ x = fn ? (*fn)() : zminchar(); /* Get second byte */ if (x > -1) { /* If didn't fail */ debug(F001,"zminchar C1","",x); ffc++; /* count another file byte */ uc.x_char[1-swapping] = x & 0xff; haveuc = 1; /* And remember we have Unicode */ #ifndef NOXFER if (docrc && (what & W_SEND)) dofilcrc(x); #endif /* NOXFER */ if (ffc == (CK_OFF_T)2) { /* Second char of file */ debug(F001,"xgnbyte 1st UCS2","",uc.x_short); debug(F111,"xgnbyte fileorder","A",fileorder); if (fileorder < 0) /* Byte order of this file */ fileorder = ucsorder; /* Default is ucsorder */ if (fileorder > 1) fileorder = 1; debug(F111,"xgnbyte fileorder","B",fileorder); if (uc.x_short == (USHORT)0xfeff) { swapping = 0; debug(F101, "xgnbyte UCS2 goodbom swap","",swapping); fileorder = byteorder; /* Note: NOT 0 */ goto bomskip; } else if (uc.x_short == (USHORT)0xfffe) { swapping = 1; debug(F101, "xgnbyte UCS2 badbom swap","",swapping); fileorder = (1 - byteorder); /* Note: NOT 1 */ goto bomskip; } else if ((byteorder && !fileorder) || /* No BOM */ (!byteorder && fileorder > 0)) { /* fileorder might have been set by scanfile() */ CHAR c; c = uc.x_char[0]; uc.x_char[0] = uc.x_char[1]; uc.x_char[1] = c; swapping = 1; debug(F111,"xgnbyte UCS2 noBOM swap","A",swapping); } else { swapping = 0; debug(F111,"xgnbyte UCS2 noBOM swap","B",swapping); } debug(F111,"xgnbyte fileorder","C",fileorder); } } else return(x); } else return(x); debug(F001,"xgnbyte UCS2","",uc.x_short); } else if (fcs == FC_UTF8) { /* File is UTF-8 */ CHAR ch = 0; /* Data types needed for API... */ USHORT * us = NULL; uc.x_short = 0; flag = 1; /* We (will) have called zminchar() */ /* Read source bytes */ while ((x = fn ? (*fn)() : zminchar()) > -1) { ffc++; /* Got a byte - count it */ #ifndef NOXFER if (docrc && (what & W_SEND)) dofilcrc(x); #endif /* NOXFER */ ch = x; rc = utf8_to_ucs2(ch,&us); /* Convert to UCS-2 */ if (rc == 0) { /* Done */ uc.x_short = *us; haveuc = 1; break; } else if (rc < 0) { /* Error */ utferror = 1; debug(F101,"xgnbyte UTF-8 input error","",rc); haveuc = 1; uc.x_short = *us; break; } } if (x < 0) return(x); debug(F001,"xgnbyte UTF8->UCS2","",uc.x_short); } #endif /* UNICODE */ #ifdef KANJI #ifdef UNICODE else #endif /* UNICODE */ if (fcsinfo[fcs].alphabet == AL_JAPAN) { /* Japanese source file */ int c7, x, y; if (fcs == FC_JIS7) { /* If file charset is JIS-7 */ if (!ffc) /* If first byte of file */ j7init(); /* Initialize JIS-7 parser */ x = getj7(); /* Get a JIS-7 byte */ } else /* Otherwise */ x = fn ? (*fn)() : zminchar(); /* Just get byte */ if (x < 0) { /* Propogate EOF or error */ debug(F100,"XGNBYTE EOF","",0); return(x); } debug(F001,"XGNBYTE x","",x); ffc++; /* Count */ #ifndef NOXFER if (docrc && (what & W_SEND)) dofilcrc(x); /* Do CRC */ #endif /* NOXFER */ switch (fcs) { /* What next depends on charset */ case FC_SHJIS: /* Shift-JIS */ if ((x <= 0x80) || /* Any 7-bit char... */ (x >= 0xa0 && x <= 0xdf)) { /* or halfwidth Katakana */ sj.x_short = (USHORT) x; /* we read one byte. */ } else { /* Anything else */ if ((y = fn ? (*fn)() : zminchar()) < 0) /* get another */ return(y); #ifndef NOXFER if (docrc && (what & W_SEND)) dofilcrc(y); #endif /* NOXFER */ ffc++; sj.x_char[byteorder] = (CHAR) x; sj.x_char[1-byteorder] = (CHAR) y; } break; case FC_JIS7: /* JIS-7 */ case FC_JDEC: /* DEC Kanji */ case FC_JEUC: /* EUC-JP */ if ((x & 0x80) == 0) { /* Convert to Shift-JIS */ sj.x_short = (USHORT) x; /* C0 or G0: one byte */ eu.x_short = (USHORT) x; haveeu = 1; } else { c7 = x & 0x7f; if (c7 > 0x20 && c7 < 0x7f) { /* Kanji: two bytes */ if ((y = (fcs == FC_JEUC) ? (fn ? (*fn)() : zminchar()) : getj7() /* ^^^ */ ) < 0) return(y); ffc++; #ifndef NOXFER if (docrc && (what & W_SEND)) dofilcrc(y); #endif /* NOXFER */ eu.x_char[byteorder] = (CHAR) x; eu.x_char[1-byteorder] = (CHAR) y; sj.x_short = eu_to_sj(eu.x_short); haveeu = 1; } else if (x == 0x8e) { /* SS2 Katakana prefix: 2 bytes */ if ((y = (fcs == FC_JIS7) ? getj7() : /* ^^^ */ (fn ? (*fn)() : zminchar()) ) < 0) return(y); ffc++; #ifndef NOXFER if (docrc && (what & W_SEND)) dofilcrc(y); #endif /* NOXFER */ sj.x_short = y | 0x80; debug(F001,"XGNBYTE KANA SJ","",sj.x_short); } else { /* Something that translates to U+FFFD */ sj.x_short = UNKSJIS; } } break; } havesj = 1; /* Have Shift-JIS */ #ifdef UNICODE uc.x_short = sj_to_un(sj.x_short); /* Translate to UCS-2 */ haveuc = 1; /* Have Unicode */ #endif /* UNICODE */ flag = 1; /* Have a char */ } #endif /* KANJI */ } if (!flag) { /* If no character was read yet... */ if ((x = (fn ? (*fn)() : zminchar())) > -1) /* read one now */ ffc++; debug(F101,"xgnbyte zminchar 1","",x); if (x < 0) return(x); haveuc = 0; } #ifdef UNICODE if (haveuc) { thischar = uc.x_short; /* lastucs2 = uc.x_short; */ } else #endif /* UNICODE */ thischar = x; debug(F001,"xgnbyte thischar",haveuc ? "[UNICODE]" : "[other]",thischar); #ifdef CK_CTRLZ /* SET EOF CTRLZ */ if (eofmethod == XYEOF_Z && !binary && thischar == 26) { debug(F100,"xgnbyte EOF on Ctrl-Z 1","",0); return(-1); } #endif /* CK_CTRLZ */ #ifdef UNICODE if (!haveuc) /* If not Unicode... */ #endif /* UNICODE */ x &= fmask; /* Apply SET FILE BYTESIZE mask */ switch (xlatype) { /* Translation type... */ #ifdef UNICODE case XLA_UNICODE: { /* Unicode is involved */ xc = 0; /* Here we must choose the appropriate translation function. If we are being called by getpkt() (i.e. when transferring a file), we are translating from Unicode to the Transfer Character Set and therefore must use the function pointed to by xut. Otherwise, e.g. during TRANSLATE, CONNECT, TRANSMIT, etc, we are translating from Unicode to the File Character Set and so must call the function pointed to by xuf. There might be a cleaner way to set this up but I don't think so. For example, setxlatype() might have been called too soon and so might not have known whether it was a file transfer or a local operation. */ /* (Many years later...) In testing this code I noticed that TRANSLATE'ing Russian text from UTF-8 to ISO Latin/Cyrillic produced all question marks. Rereading the previous paragraph it seems to me we are (I am) overloading this function with responsibilites, satisfying the needs of file transfer (local file charset -> transfer charset for outbound packet) and local file conversion. In the case of TRANSLATE, we call (xgnbyte(), xpnbyte()) in a loop, expecting the xgnbyte() will feed UCS2 to xpnbyte(). But the following code does what xpnbyte() is going to do, returning (in this case) an ISO Latin/Cyrillic byte stream, which xpnbyte() believes to be UCS2, and comes up with nonsense. Not wanting to rip the whole thing apart and start over, I made the following change that should do no harm, upon observing that if the input character set is UTF-8 or UCS-2, then when we get here it has already been converted to UCS2, so if we are not transferring a file, we don't need to do anything else except put the bytes in the right place to be returned, which is done further along. */ #ifdef COMMENT /* Previous code */ xx = (what & W_SEND) ? xut : xuf; #else /* New code 2011-06-03 */ if (what & W_SEND) { xx = xut; } else { if (fcs == FC_UCS2 || fcs == FC_UTF8) xx = NULL; else xx = xuf; } #endif /* COMMENT */ eolflag = 0; if (haveuc) { /* File is Unicode */ /* See Unicode TR13, "Converting to Other Character Sets" */ if (uc.x_short == 0x2028 || /* Line Separator? */ uc.x_short == 0x2029 || /* Paragraph Separator */ (feol && (uc.x_short == (USHORT)feol)) ) { debug(F001,"xgnbyte uc eol","",uc.x_short); rc = 0; eolflag = 1; /* Don't translate and handle later */ } if (xx && !eolflag) { /* UCS-to-TCS function (UCS->byte) */ rc = (*xx)(uc.x_short); /* These can fail... */ debug(F101,"xgnbyte xx rc","",rc); if (rc < 0) /* If it can't be translated */ uc.x_short = UNK; /* Put unknown-character symbol */ else uc.x_short = (unsigned)((unsigned)rc & 0xffff); debug(F101,"xgnbyte xx uc","",uc.x_short); } #ifdef KANJI if (tcs == FC_JEUC) { /* Translating to EUC-JP */ USHORT sj = 0; union ck_short eu; debug(F001,"xgnbyte UCS->EUC UCS","",uc.x_short); if (!havesj) /* If we don't already have it */ sj = un_to_sj(uc.x_short); /* convert to Shift-JIS */ eu.x_short = sj_to_eu(sj); debug(F001,"xgnbyte UCS->EUC EUC","",eu.x_short); xlaptr = 0; xlacount = 0; if (eolflag) { if (what & W_SEND) { xlabuf[xlacount++] = LF; return(CK_CR); } else { return(feol); } } if (eu.x_char[byteorder]) { /* Two bytes */ rc = eu.x_char[byteorder]; xlabuf[xlacount++] = eu.x_char[1-byteorder]; debug(F001,"xgnbyte UCS->EUC xlabuf[0]","",xlabuf[0]); } else { /* One byte */ rc = eu.x_char[1-byteorder]; } debug(F101,"xgnbyte UCS->EUC xlacount","",xlacount); debug(F001,"xgnbyte UCS->EUC rc","",rc); return(rc); } else #endif /* KANJI */ if (tcs != FC_UCS2 && tcs != FC_UTF8) { if (uc.x_short & 0xff00) { /* Decoding error */ debug(F001,"xgnbyte decoding error","",uc.x_short); return(-2); } else return((unsigned int)(uc.x_short & 0xff)); } xc = uc.x_short; } else { /* File is not Unicode */ USHORT ch; /* Translate from single FCS byte to UCS-2 */ /* This is a bit nonobvious... The blah_u() (Blah-to-Unicode) routines are called only with pieces of character sets, in the ISO 2022 sense. So, for example, if ch is a Latin-1 character, we call the translation routine only if it is in the right half; if it's in the left half, it isn't translated, and in fact will give the wrong result if sent to the translation function. That's because those functions were designed for use with the ISO 2022 G0..G3 sets, not for file transfer. On the other hand, if it's a 7-bit character set, we *do* call the translation function. (To put it another way, the left half of any 8-bit character set is ASCII and therefore doesn't need to be translated but 7-bit sets such as ISO 646 German do need translation). */ ch = (unsigned)(thischar & 0xff); if (((fcsinfo[fcs].size > 128) && (ch & 0x80)) || fcsinfo[fcs].size <= 128) { if (xfu) { /* FCS-to-UCS function */ ch = (*xfu)(ch); } } xc = ch; } /* At this point we have a UCS-2 character in native format */ /* (Big Endian or Little Endian) in xc, which is an unsigned int. */ debug(F001,"xgnbyte xc","",xc); if (tcs == FC_UTF8) { /* Now convert to UTF-8 */ USHORT c; /* NOTE: this is FC_UTF8 on purpose! */ CHAR * buf = NULL; int i, k = 0, x; xlaptr = 0; if (utferror) { xlabuf[k++] = 0xff; xlabuf[k++] = 0xbd; } if (eolflag) { /* We detected EOL in source file */ if (what & W_SEND) { /* Convert to CRLF */ xlabuf[k++] = LF; xlacount = k; return((unsigned int)CK_CR); #ifdef COMMENT } else { /* Or to local line-end */ xlacount = k; return((unsigned int)feol); #endif /* COMMENT */ } } c = xc; if ((x = ucs2_to_utf8(c,&buf)) < 1) { debug(F101,"xgnbyte ucs2_to_utf8 error","",c); return(-2); } debug(F101,"xgnbyte UTF8 buf[0]","",buf[0]); for (i = 1; i < x; i++) { xlabuf[k+i-1] = buf[i]; debug(F111,"xgnbyte UTF8 xlabuf",ckitoa(i-1),buf[i]); } xlaptr = 0; xlacount = x - 1; debug(F101,"xgnbyte UTF8 xlacount","",xlacount); return((unsigned int)buf[0]); } else { /* Or keep it as UCS-2 */ int k = 0; CHAR c; xlaptr = 0; if (utferror) { xlabuf[k++] = 0xff; xlabuf[k++] = 0xfd; debug(F101,"xgnbyte error","",k); } if (eolflag) { /* We detected EOL in source file */ if (what & W_SEND) { /* Convert to CRLF */ xlabuf[k++] = CK_CR; xlabuf[k++] = NUL; xlabuf[k++] = LF; xlacount = k; debug(F101,"xgnbyte send CRLF","",k); return(0); /* Return NUL */ } else { /* Or to local line-end */ #ifdef COMMENT /* This bypasses byte swapping that we might need */ xlabuf[k++] = (CHAR)feol; xlacount = k; debug(F101,"xgnbyte send feol","",k); return(0); /* Return NUL */ #else xc = (CHAR)feol; #endif /* COMMENT */ } } /* In which order should we return the bytes? */ #ifdef COMMENT if ( (what & W_SEND) || (what & W_FTP) || (fileorder == 0)) { #endif /* COMMENT */ /* ALWAYS RETURN IN BIG ENDIAN ORDER... 7 Sep 2002 */ /* xgnbyte() is almost always used to feed xpnbyte() */ /* which requires bytes in BE order. In cases where */ /* xgnbyte is used in isolation, the caller can swap */ /* bytes itself afterwards. */ xlabuf[k++] = (xc >> 8) & 0xff; /* Big Endian */ xlabuf[k++] = xc & 0xff; debug(F001,"xgnbyte->UCS2BE", ckitox((int)xlabuf[0]),xlabuf[1]); #ifdef COMMENT } else { /* Little Endian */ xlabuf[k++] = xc & 0xff; xlabuf[k++] = (xc >> 8) & 0xff; debug(F001,"xgnbyte->UCS2LE", ckitox((int)xlabuf[0]),xlabuf[1]); } #endif /* COMMENT */ c = xlabuf[0]; xlaptr = 1; xlacount = k-1; debug(F101,"xgnbyte c","",c); debug(F101,"xgnbyte xlaptr","",xlaptr); debug(F011,"xgnbyte xlabuf",xlabuf,xlacount); return((unsigned int)c); } } #endif /* UNICODE */ case XLA_NONE: return((fn ? (*fn)() : zminchar())); case XLA_BYTE: /* Byte-for-Byte translation */ rt = x; if (sx) rt = (*sx)(rt); #ifdef UNICODE if (utferror) { xlaptr = 0; xlacount = 1; xlabuf[0] = rt; return(UNK); } else #endif /* UNICODE */ return((unsigned int)rt); #ifdef KANJI case XLA_JAPAN: /* Come here with Shift-JIS */ if (tcs == FC_JEUC) { /* It better be... */ xlaptr = 0; xlacount = 0; if (!havesj) { printf("BAD BAD\n"); return(-2); } if (!haveeu) /* We might already have EUC too */ eu.x_short = sj_to_eu(sj.x_short); if (eu.x_char[byteorder]) { xlabuf[xlacount++] = eu.x_char[1-byteorder]; return(eu.x_char[byteorder]); } else { return(eu.x_char[1-byteorder]); } break; } #endif /* KANJI */ default: debug(F101,"xgnbyte bad xlatype","",xlatype); return(-2); } #ifdef COMMENT /* If there is a return() statement here, some compilers complain about "statement not reached". If there is no return() statement, other compilers complain that "Non-void function should return a value". There is no path through this function that falls through to here. */ debug(F100,"xgnbyte switch failure","",0); return(-2); #endif /* COMMENT */ } #endif /* NOCSETS */ #ifndef NOXFER /* G E T P K T -- Fill a packet data field from the indicated source. */ /* Parameters: bufmax: Maximum length of entire packet. xlate: Flag for whether to translate charsets when in text mode. Returns: Number of characters written to packet data field, 0 or more, Or -1 on failure (internal error), or -3 on timeout (e.g. when reading from a pipe). This is the full version allowing for parity and text-mode conversions; i.e. it works in all cases. Also see bgetpkt(), a special lean/mean/fast packet encoder that works only for binary-mode no-parity transfers. */ static int uflag = 0; int #ifdef CK_ANSIC getpkt( int bufmax, int xlate ) /* Fill one packet buffer */ #else getpkt(bufmax,xlate) int bufmax, xlate; #endif /* CK_ANSIC */ { register CHAR rt = t, rnext = NUL; /* Register shadows of the globals */ register CHAR *dp, *odp, *odp2, *p1, *p2; /* pointers... */ register int x; /* Loop index. */ register int a7; /* Low 7 bits of character */ CHAR xxls, xxdl, xxrc, xxss, xxcq; /* Pieces of prefixed sequence */ #ifdef COMMENT debug(F000,"getpkt sstate","",sstate); /* It's always NUL - why??? */ #endif /* COMMENT */ if (binary) xlate = 0; /* We don't translate if binary */ if (!data) { debug(F100,"SERIOUS ERROR: getpkt data == NULL","",0); return(-1); } dp = data; /* Point to packet data buffer */ size = 0; /* And initialize its size */ /* Assume bufmax is the receiver's total receive-packet buffer length. Our whole packet has to fit into it, so we adjust the data field length. We also decide optimally whether it is better to use a short-format or long-format packet when we're near the borderline. */ #ifdef COMMENT /* bufmax is a parameter - don't override it! */ bufmax = maxdata(); /* Get maximum data length */ #endif /* COMMENT */ if (first == 1) { /* If first character of this file.. */ #ifdef UNICODE /* Special end-of-line handling for Unicode */ if (tcharset == TC_UCS2 || tcharset == TC_UTF8) uflag = 1; #endif /* UNICODE */ debug(F101,"getpkt first uflag","",uflag); debug(F101,"getpkt first rt","",rt); if (!memstr && !funcstr) /* and real file... */ ffc = (CK_OFF_T)0; /* reset file character counter */ #ifdef COMMENT /* Moved to below... */ first = 0; /* Next character won't be first */ #endif /* COMMENT */ *leftover = '\0'; /* Discard any interrupted leftovers */ nleft = 0; #ifndef NOCSETS setxlatype(tcharset,fcharset); /* Set up charset translations */ #endif /* NOCSETS */ /* Get first character of file into rt, watching out for null file */ #ifdef CALIBRATE if (calibrate && !memstr) { #ifdef NORANDOM x = rt = 53; #else x = rt = cal_a[rand() & 0xff]; #endif /* NORANDOM */ first = 0; ffc++; } else #endif /* CALIBRATE */ #ifdef KANJI if (xlate && tcharset == TC_JEUC) { /* Kanji text */ x = zkanjf(); if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) { first = -1; size = 0; if (x == -2) { debug(F100,"getpkt zkanji: input error","",0); cxseen = 1; } else debug(F100,"getpkt zkanji: empty string/file","",0); return(0); } rt = x; first = 0; if (!memstr) { ffc++; if (docrc && (what & W_SEND)) /* Accumulate file crc */ dofilcrc((int)rt); } } else { /* Not Kanji text */ #endif /* KANJI */ if (memstr) { /* Reading data from memory string */ /* This will not be Unicode */ if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */ first = -1; size = 0; debug(F100,"getpkt: empty string","",0); return(0); } first = 0; } else if (funcstr) { /* Reading data from a function */ /* This will not be Unicode */ if ((x = (*funcptr)()) < 0) { /* End of input */ first = -1; size = 0; /* Empty */ return(0); } ffc++; /* Count a file character */ rt = (CHAR) x; /* Convert int to char */ first = 0; debug(F000,"getpkt funcstr","",rt); } else { /* Reading data from a file */ #ifndef NOCSETS if (xlate && !binary) { /* Could be Unicode */ if (xlatype == XLA_UNICODE) { /* Get next translated byte */ x = xgnbyte(cseqtab[tcharset],fcharset,NULL); debug(F101,"getpkt xgnbyte","",x); } else { /* Not Unicode */ x = zminchar(); /* Get next byte, translate below */ debug(F101,"getpkt zminchar A","",x); } } else { /* Just get next byte */ #endif /* NOCSETS */ x = zminchar(); debug(F101,"getpkt zminchar B","",x); #ifndef NOCSETS } #endif /* NOCSETS */ if (x < 0) { /* End of file or input error */ if (x == -3) { /* Timeout. */ size = (dp-data); debug(F101,"getpkt timeout size","",size); return((size == 0) ? x : size); } first = -1; size = 0; if (x == -2) { /* Error */ debug(F100,"getpkt: input error","",0); cxseen = 1; /* Interrupt the file transfer */ } else { debug(F100,"getpkt empty file","",0); } return(0); } first = 0; /* Next character won't be first */ rt = (CHAR) x; /* Convert int to char */ #ifndef NOCSETS if (xlatype != XLA_UNICODE || binary) { ffc++; if (sx) rt = (*sx)(rt); if (docrc && (what & W_SEND)) dofilcrc(x); } #endif /* NOCSETS */ #ifdef DEBUG if (deblog) debug(F101,"getpkt 1st char","",rt); #endif /* DEBUG */ if (/* !haveuc && */ docrc && (what & W_SEND)) /* File CRC */ dofilcrc(x); } #ifdef KANJI } #endif /* KANJI */ /* PWP: handling of feol is done later (in the while loop)... */ } else if ((first == -1) && (nleft == 0)) { /* EOF from last time */ #ifdef DEBUG if (deblog) { debug(F101,"getpkt eof crc16","",crc16); debug(F101,"getpkt eof ffc","",ffc); } #endif /* DEBUG */ return(size = 0); } /* Here we handle characters that were encoded for the last packet but did not fit, and so were saved in the "leftover" array. */ debug(F101,"getpkt nleft","",nleft); if (nleft) { for (p1 = leftover; nleft > 0; nleft--) /* Copy leftovers */ *dp++ = *p1++; *leftover = '\0'; /* Delete leftovers */ nleft = 0; } if (first == -1) /* Handle EOF */ return(size = (dp - data)); /* Now fill up the rest of the packet. */ rpt = 0; /* Initialize character repeat count */ while (first > -1) { /* Until EOF... */ #ifdef CALIBRATE if (calibrate && !memstr) { /* We generate our own "file" */ if (ffc >= calibrate) { /* EOF */ first = -1; ffc--; } else { /* Generate next character */ if (cal_j > CAL_M * ffc) cal_j = cal_a[ffc & 0xff]; x = (unsigned)cal_a[(cal_j & 0xff)]; if (x == rt) x ^= 2; } cal_j += (unsigned int)(ffc + CAL_O); ffc++; } else #endif /* CALIBRATE */ #ifdef KANJI if (xlate && tcharset == TC_JEUC) { if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) { first = -1; if (x == -2) cxseen = 1; } else if (!memstr) ffc++; rnext = (CHAR) (x & fmask); } else { #endif /* KANJI */ if (memstr) { /* Get next char from memory string */ if ((x = *memptr++) == '\0') /* End of string means EOF */ first = -1; /* Flag EOF for next time. */ rnext = (CHAR) (x & fmask); /* Apply file mask */ } else if (funcstr) { /* Get next char from function */ if ((x = (*funcptr)()) < 0) /* End of string means EOF */ first = -1; /* Flag EOF for next time. */ rnext = (CHAR) (x & fmask); /* Apply file mask */ } else { /* From file... */ #ifndef NOCSETS if (xlate && !binary) { /* Could be Unicode */ if (xlatype == XLA_UNICODE) { /* Get next translated byte */ x = xgnbyte(cseqtab[tcharset],fcharset,NULL); } else { /* Not Unicode */ x = zminchar(); /* Get next byte, translate below */ /* debug(F101,"xgnbyte B zminchar","",x); */ } } else { /* Just get next byte */ #endif /* NOCSETS */ x = zminchar(); /* debug(F101,"xgnbyte C zminchar","",x); */ #ifndef NOCSETS } #endif /* NOCSETS */ if (x < 0) { /* Check for EOF */ if (x == -3) { /* Timeout reading from pipe */ t = rt; size = (dp-data); debug(F101,"getpkt timeout size","",size); return((size == 0) ? x : size); } first = -1; /* Flag eof for next time. */ if (x == -2) cxseen = 1; /* If error, cancel this file. */ } rnext = (CHAR) (x & fmask); /* Apply file mask */ #ifndef NOCSETS if (xlatype != XLA_UNICODE) { #endif /* NOCSETS */ ffc++; #ifndef NOCSETS if (sx) rt = (*sx)(rt); #endif /* NOCSETS */ if (docrc && (what & W_SEND)) dofilcrc(x); #ifndef NOCSETS } #endif /* NOCSETS */ } #ifdef KANJI } #endif /* KANJI */ /* At this point, the character we just read is in rnext, and the character we are about to encode into the packet is in rt. */ odp = dp; /* Remember where we started. */ xxls = xxdl = xxrc = xxss = xxcq = NUL; /* Clear these. */ /* Now encode the character according to the options that are in effect: ctlp[]: whether this control character needs prefixing. binary: text or binary mode. rptflg: repeat counts enabled. ebqflg: 8th-bit prefixing enabled. lscapu: locking shifts enabled. */ if (rptflg) { /* Repeat processing is on? */ if (!uflag && /* * If the next char is really CRLF, then we cannot * be doing a repeat (unless CR,CR,LF which becomes * "~ CR CR LF", which is OK but not most efficient). * I just plain don't worry about this case. The actual * conversion from NL to CRLF is done after the rptflg if... */ (!feol || binary || (feol && (rnext != feol))) && (rt == rnext) && (first == 0)) { /* Got a run... */ if (++rpt < 94) { /* Below max, just count */ continue; /* go back and get another */ } else if (rpt == 94) { /* Reached max, must dump */ xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */ rptn += rpt; /* Accumulate it for statistics */ rpt = 0; /* And reset it */ } } else if (rpt > 1) { /* More than two */ xxrc = (CHAR) tochar(++rpt); /* and count. */ rptn += rpt; rpt = 0; /* Reset repeat counter. */ } /* If (rpt == 1) we must encode exactly two characters. This is done later, after the first character is encoded. */ } /* If it's the newline character... */ if (!uflag && !binary && feol && (rt == feol)) { if (lscapu && lsstate) { /* If SHIFT-STATE is SHIFTED */ if (ebqflg) { /* If single shifts enabled, */ *dp++ = (CHAR) ebq; /* insert a single shift. */ } else { /* Otherwise must shift in. */ *dp++ = myctlq; /* Insert shift-out code */ *dp++ = 'O'; lsstate = 0; /* Change shift state */ } } #ifdef CK_SPEED if (ctlp[CK_CR]) { *dp++ = myctlq; /* Insert carriage return directly */ *dp++ = 'M'; ccp++; } else { *dp++ = CK_CR; /* Perhaps literally */ ccu++; } #else /* !CK_SPEED */ *dp++ = myctlq; /* Insert carriage return directly */ *dp++ = 'M'; ccp++; #endif /* CK_SPEED */ rt = LF; /* Now make next char be linefeed. */ } /* Now handle the 8th bit of the file character. If we have an 8-bit connection, we preserve the 8th bit. If we have a 7-bit connection, we employ either single or locking shifts (if they are enabled). */ a7 = rt & 0177; /* Get low 7 bits of character */ if (rt & 0200) { /* 8-bit character? */ if (lscapu) { /* Locking shifts enabled? */ if (!lsstate) { /* Not currently shifted? */ x = lslook(0200); /* Look ahead */ if (x != 0 || ebqflg == 0) { /* Locking shift decision */ xxls = 'N'; /* Need locking shift-out */ lsstate = 1; /* and change to shifted state */ } else if (ebqflg) { /* Not worth it */ xxss = (CHAR) ebq; /* Use single shift */ } } rt = (CHAR) a7; /* Replace character by 7-bit value */ } else if (ebqflg) { /* 8th bit prefixing is on? */ xxss = (CHAR) ebq; /* Insert single shift */ rt = (CHAR) a7; /* Replace character by 7-bit value */ } /* In case we have a 7-bit connection and this is an 8-bit character, AND neither locking shifts nor single shifts are enabled, then the character's 8th bit will be destroyed in transmission, and a block check error will occur. */ } else if (lscapu) { /* 7-bit character */ if (lsstate) { /* Comes while shifted out? */ x = lslook(0); /* Yes, look ahead */ if (x || ebqflg == 0) { /* Time to shift in. */ xxls = 'O'; /* Set shift-in code */ lsstate = 0; /* Exit shifted state */ } else if (ebqflg) { /* Not worth it, stay shifted out */ xxss = (CHAR) ebq; /* Insert single shift */ } } } /* If data character is significant to locking shift protocol... */ if (lscapu && (a7 == SO || a7 == SI || a7 == DLE)) xxdl = 'P'; /* Insert datalink escape */ if ( #ifdef CK_SPEED /* Thwart YET ANOTHER unwanted, unneeded, and unloved sign extension. This one was particularly nasty because it prevented 255 (Telnet IAC) from being prefixed on some platforms -- e.g. VMS with VAX C -- but not others, thus causing file transfers to fail on Telnet connections by sending bare IACs. Not to mention the stray memory reference. Signed chars are a BAD idea. */ ctlp[(unsigned)(rt & 0xff)] /* Lop off any "sign" extension */ #else (a7 < SP) || (a7 == DEL) #endif /* CK_SPEED */ ) { /* Do control prefixing if necessary */ xxcq = myctlq; /* The prefix */ ccp++; /* Count it */ rt = (CHAR) ctl(rt); /* Uncontrollify the character */ } #ifdef CK_SPEED else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */ ccu++; #endif /* CK_SPEED */ if (a7 == myctlq) /* Always prefix the control prefix */ xxcq = myctlq; if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */ xxcq = myctlq; /* prefix it if doing repeat counts */ if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th-bit prefix */ xxcq = myctlq; /* if doing 8th-bit prefixes */ /* Now construct the entire sequence */ if (xxls) { *dp++ = myctlq; *dp++ = xxls; } /* Locking shift */ odp2 = dp; /* (Save this place) */ if (xxdl) { *dp++ = myctlq; *dp++ = xxdl; } /* Datalink escape */ if (xxrc) { *dp++ = (CHAR) rptq; *dp++ = xxrc; } /* Repeat count */ if (xxss) { *dp++ = (CHAR) ebq; } /* Single shift */ if (xxcq) { *dp++ = myctlq; } /* Control prefix */ *dp++ = rt; /* Finally, the character itself */ if (rpt == 1) { /* Exactly two copies? */ rpt = 0; p2 = dp; /* Save place temporarily */ for (p1 = odp2; p1 < p2; p1++) /* Copy the old chars over again */ *dp++ = *p1; if ((p2-data) <= bufmax) odp = p2; /* Check packet bounds */ if ((p2-data) < bufmax) odp = p2; /* Check packet bounds */ } rt = rnext; /* Next character is now current. */ /* Done encoding the character. Now take care of packet buffer overflow. */ if ((dp-data) >= bufmax) { /* If too big, save some for next. */ debug(F000,"getpkt EOP","",rt); size = (dp-data); /* Calculate the size. */ *dp = '\0'; /* Mark the end. */ if (memstr) { /* No leftovers for memory strings */ if (rt) /* Char we didn't encode yet */ memptr--; /* (for encstr()) */ return(size); } if ((dp-data) > bufmax) { /* if packet is overfull */ /* copy the part that doesn't fit into the leftover buffer, */ /* taking care not to split a prefixed sequence. */ int i; nleft = dp - odp; for (i = 0, p1 = leftover, p2 = odp; i < nleft; i++) { *p1++ = *p2++; if (memstr) memptr--; /* (for encstr) */ } debug(F111,"getpkt leftover",leftover,size); debug(F101,"getpkt osize","",(odp-data)); size = (odp-data); /* Return truncated packet. */ *odp = '\0'; /* Mark the new end */ } t = rt; /* Save for next time */ return(size); } } /* Otherwise, keep filling. */ size = (dp-data); /* End of file */ *dp = '\0'; /* Mark the end of the data. */ debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */ return(size); /* return partially filled last packet. */ } /* T I N I T -- Initialize a transaction */ int epktrcvd = 0, epktsent = 0; /* Call with 1 to reset everything before S/I/Y negotiation, or 0 to reset only the things that are not set in the S/I/Y negotiation. Returns -1 on failure (e.g. to create packet buffers), 0 on success. */ int #ifdef CK_ANSIC tinit( int flag ) #else tinit(flag) int flag; #endif /* CK_ANSIC */ { int x; #ifdef CK_TIMERS extern int rttflg; #endif /* CK_TIMERS */ extern int rcvtimo; extern int fatalio; debug(F101,"tinit flag","",flag); *epktmsg = NUL; epktrcvd = 0; epktsent = 0; ofperms = ""; diractive = 0; /* DIR / REMOTE DIR not active */ interrupted = 0; /* Not interrupted */ fatalio = 0; /* No fatal i/o error */ if (server) { moving = 0; pipesend = 0; /* This takes care of multiple GETs sent to a server. */ } bestlen = 0; /* For packet length optimization */ maxsend = 0; /* Biggest data field we can send */ #ifdef STREAMING streamok = 0; /* Streaming negotiated */ streaming = 0; /* Streaming being done now */ #endif /* STREAMING */ binary = b_save; /* ... */ gnf_binary = binary; /* Per-file transfer mode */ retrans = 0; /* Packet retransmission count */ sndtyp = 0; /* No previous packet */ xflg = 0; /* Reset x-packet flag */ memstr = 0; /* Reset memory-string flag */ memptr = NULL; /* and buffer pointer */ funcstr = 0; /* Reset "read from function" flag */ funcptr = NULL; /* and function pointer */ autopar = 0; /* Automatic parity detection flag */ /* This stuff is only for BEFORE S/I/Y negotiation, not after */ if (flag) { if (bctf) { /* Force Block Check 3 on all packets */ bctu = bctl = 3; /* Set block check type to 3 */ } else { bctu = bctl = 1; /* Reset block check type to 1 */ } myinit[0] = '\0'; /* Haven't sent init string yet */ rqf = -1; /* Reset 8th-bit-quote request flag */ ebq = MYEBQ; /* Reset 8th-bit quoting stuff */ ebqflg = 0; /* 8th bit quoting not enabled */ ebqsent = 0; /* No 8th-bit prefix bid sent yet */ sq = 'Y'; /* 8th-bit prefix bid I usually send */ spsiz = spsizr; /* Initial send-packet size */ debug(F101,"tinit spsiz","",spsiz); wslots = 1; /* One window slot */ wslotn = 1; /* No window negotiated yet */ justone = 0; /* (should this be zero'd here?) */ whoareu[0] = NUL; /* Partner's system type */ sysindex = -1; wearealike = 0; what = W_INIT; /* Doing nothing so far... */ } fncnv = f_save; /* Back to what user last said */ pktnum = 0; /* Initial packet number to send */ cxseen = czseen = discard = 0; /* Reset interrupt flags */ *filnam = '\0'; /* Clear file name */ spktl = 0; /* And its length */ nakstate = 0; /* Assume we're not in a NAK state */ numerrs = 0; /* Transmission error counter */ idletmo = 0; /* No idle timeout yet */ if (server) { /* If acting as server, */ if (srvidl > 0) /* If an idle timeout is given */ timint = srvidl; else timint = srvtim; /* use server timeout interval. */ } else { /* Otherwise */ timint = chktimo(rtimo,timef); /* and use local timeout value */ } debug(F101,"tinit timint","",timint); #ifdef CK_TIMERS if (rttflg && timint > 0) /* Using round-trip timers? */ rttinit(); else #endif /* CK_TIMERS */ rcvtimo = timint; winlo = 0; /* Packet 0 is at window-low */ debug(F101,"tinit winlo","",winlo); x = mksbuf(1); /* Make a 1-slot send-packet buffer */ if (x < 0) return(x); x = getsbuf(0); /* Allocate first send-buffer. */ debug(F101,"tinit getsbuf","",x); if (x < 0) return(x); dumpsbuf(); x = mkrbuf(wslots); /* & a 1-slot receive-packet buffer. */ if (x < 0) return(x); lsstate = 0; /* Initialize locking shift state */ if (autopath) { /* SET RECEIVE PATHNAMES AUTO fixup */ fnrpath = PATH_AUTO; autopath = 0; } return(0); } VOID pktinit() { /* Initialize packet sequence */ pktnum = 0; /* number & window low. */ winlo = 0; debug(F101,"pktinit winlo","",winlo); } /* R I N I T -- Respond to S or I packet */ VOID #ifdef CK_ANSIC rinit( CHAR *d ) #else rinit(d) CHAR *d; #endif /* CK_ANSIC */ { char *tp = NULL; ztime(&tp); tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */ tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L); tlog(F110,"Collision action:", fncnam[fncact],0); tlog(F100,"","",0); debug(F101,"rinit fncact","",fncact); filcnt = filrej = 0; /* Init file counters */ spar(d); ack1(rpar()); #ifdef datageneral if ((local) && (!quiet)) /* Only do this if local & not quiet */ consta_mt(); /* Start the asynch read task */ #endif /* datageneral */ } /* R E S E T C -- Reset per-transaction character counters */ VOID resetc() { rptn = 0; /* Repeat counts */ fsecs = flci = flco = (CK_OFF_T)0; /* File chars in and out */ #ifdef GFTIMER fpfsecs = 0.0; #endif /* GFTIMER */ tfc = tlci = tlco = (CK_OFF_T)0; /* Total file, line chars in & out */ ccu = ccp = 0L; /* Control-char statistics */ #ifdef COMMENT fsize = (CK_OFF_T)-1; /* File size */ #else if (!(what & W_SEND)) fsize = (CK_OFF_T)-1; debug(F101,"resetc fsize","",fsize); #endif /* COMMENT */ timeouts = retrans = 0; /* Timeouts, retransmissions */ spackets = rpackets = 0; /* Packet counts out & in */ crunched = 0; /* Crunched packets */ wcur = 0; /* Current window size */ wmax = 0; /* Maximum window size used */ peakcps = 0; /* Peak chars per second */ } /* S I N I T -- Get & verify first file name, then send Send-Init packet */ /* Returns: 1 if send operation begins successfully 0 if send operation fails */ #ifdef DYNAMIC char *cmargbuf = NULL; #else char cmargbuf[CKMAXPATH+1]; #endif /* DYNAMIC */ char *cmargp[2]; VOID fnlist() { if (!calibrate) sndsrc = (nfils < 0) ? -1 : nfils; /* Source for filenames */ #ifdef DYNAMIC if (!cmargbuf && !(cmargbuf = malloc(CKMAXPATH+1))) fatal("fnlist: no memory for cmargbuf"); #endif /* DYNAMIC */ cmargbuf[0] = NUL; /* Initialize name buffer */ debug(F101,"fnlist nfils","",nfils); debug(F110,"fnlist cmarg",cmarg,0); debug(F110,"fnlist cmarg2",cmarg2,0); if (!cmarg2) cmarg2 = ""; if (nfils == 0) { /* Sending from stdin or memory. */ if ((cmarg2 != NULL) && (*cmarg2)) { cmarg = cmarg2; /* If F packet, "as-name" is used */ cmarg2 = ""; /* if provided */ } else cmarg = "stdin"; /* otherwise just use "stdin" */ ckstrncpy(cmargbuf,cmarg,CKMAXPATH+1); cmargp[0] = cmargbuf; cmargp[1] = ""; cmlist = cmargp; nfils = 1; } } int sinit() { int x; /* Worker int */ char *tp, *xp, *m; /* Worker string pointers */ filcnt = filrej = 0; /* Initialize file counters */ fnlist(); xp = ""; if (nfils < 0) { #ifdef PIPESEND if (usepipes && protocol == PROTO_K && *cmarg == '!') { pipesend = 1; cmarg++; } #endif /* PIPESEND */ xp = cmarg; } else { #ifndef NOMSEND if (addlist) xp = filehead->fl_name; else #endif /* NOMSEND */ if (filefile) xp = filefile; else if (calibrate) xp = "Calibration"; else xp = *cmlist; } debug(F110,"sinit xp",xp,0); x = gnfile(); /* Get first filename. */ debug(F111,"sinit gnfile",ckitoa(gnferror),x); if (x == 0) x = gnferror; /* If none, get error reason */ m = NULL; /* Error message pointer */ debug(F101,"sinit gnfil","",x); switch (x) { case -6: m = "No files meet selection criteria"; break; case -5: m = "Too many files match wildcard"; break; case -4: m = "Cancelled"; break; case -3: m = "Read access denied"; break; case -2: m = "File is not readable"; break; #ifdef COMMENT case -1: m = iswild(filnam) ? "No files match" : "File not found"; break; case 0: m = "No filespec given!"; break; #else case 0: case -1: m = iswild(filnam) ? "No files match" : "File not found"; break; #endif /* COMMENT */ default: break; } debug(F101,"sinit nfils","",nfils); debug(F110,"sinit filnam",filnam,0); if (x < 1) { /* Didn't get a file. */ debug(F111,"sinit msg",m,x); if (server) { /* Doing GET command */ errpkt((CHAR *)m); /* so send Error packet. */ } else if (!local) { /* Doing SEND command */ interrupted = 1; /* (To suppress hint) */ printf("?%s\r\n",m); } else { xxscreen(SCR_EM,0,0l,m); /* so print message. */ } tlog(F110,xp,m,0L); /* Make transaction log entry. */ freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */ return(0); /* Return failure code */ } if (!local && !server && ckdelay > 0) /* OS-9 sleep(0) == infinite */ sleep(ckdelay); /* Delay if requested */ #ifdef datageneral if ((local) && (!quiet)) /* Only do this if local & not quiet */ consta_mt(); /* Start the async read task */ #endif /* datageneral */ freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */ sipkt('S'); /* Send the Send-Init packet. */ ztime(&tp); /* Get current date/time */ tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */ tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L); tlog(F100,"","",0); debug(F111,"sinit ok",filnam,0); return(1); } int #ifdef CK_ANSIC sipkt(char c) /* Send S or I packet. */ #else sipkt(c) char c; #endif /* sipkt */ { CHAR *rp; int k, x; extern int sendipkts; debug(F101,"sipkt pktnum","",pktnum); /* (better be 0...) */ ttflui(); /* Flush pending input. */ /* If this is an I packet and SET SEND I-PACKETS is OFF, don't send it; set sstate to 'Y' which makes the next input() call return 'Y' as if we had received an ACK to the I packet we didn't send. This is to work around buggy Kermit servers that can't handle I packets. */ if ((sendipkts == 0) && (c == 'I')) { /* I packet but don't send I pkts? */ sstate = 'Y'; /* Yikes! */ return(0); /* (see input()..)*/ } k = sseqtbl[pktnum]; /* Find slot for this packet */ if (k < 0) { /* No slot? */ k = getsbuf(winlo = pktnum); /* Make one. */ debug(F101,"sipkt getsbuf","",k); } rp = rpar(); /* Get protocol parameters. */ debug(F110,"sipkt rp",rp,0); /* last 2 args fixed 2022-05-05 */ if (!rp) rp = (CHAR *)""; x = spack(c,pktnum,(int)strlen((char *)rp),rp); /* Send them. */ return(x); } /* X S I N I T -- Retransmit S-packet */ /* For use in the GET-SEND sequence, when we start to send, but receive another copy of the GET command because the receiver didn't get our S packet. This retransmits the S packet and frees the receive buffer for the ACK. This special case is necessary because packet number zero is being re-used. */ VOID xsinit() { int k; k = rseqtbl[0]; debug(F101,"xsinit k","",k); if (k > -1) freerbuf(k); resend(0); } /* R C V F I L -- Receive a file */ /* Incoming filename is in data field of F packet. This function decodes it into the srvcmd buffer, substituting an alternate "as-name", if one was given. Then it does any requested transformations (like converting to lowercase), and finally if a file of the same name already exists, takes the desired collision action. Returns: 1 on success. 0 on failure. */ char ofn1[CKMAXPATH+4]; /* Buffer for output file name */ char * ofn2; /* Pointer to backup file name */ int ofn1x; /* Flag output file already exists */ CK_OFF_T ofn1len = (CK_OFF_T)0; int opnerr; /* Flag for open error */ int /* Returns success ? 1 : 0 */ #ifdef CK_ANSIC rcvfil( char *n ) #else rcvfil(n) char *n; #endif /* CK_ANSIC */ { extern int en_cwd; int i, skipthis; char * n2; #ifdef OS2ONLY char *zs, *longname, *newlongname, *pn; /* OS/2 long name items */ #endif /* OS2ONLY */ #ifdef DTILDE char *dirp; #endif /* DTILDE */ int dirflg; #ifdef PIPESEND extern char * rcvfilter; #endif /* PIPESEND */ #ifdef CALIBRATE extern int dest; CK_OFF_T csave; csave = calibrate; /* So we can decode filename */ calibrate = (CK_OFF_T)0; #endif /* CALIBRATE */ ofperms = ""; /* Reset old-file permissions */ opnerr = 0; /* No open error (yet) */ ofn2 = NULL; /* No new name (yet) */ lsstate = 0; /* Cancel locking-shift state */ srvptr = srvcmd; /* Decode file name from packet. */ #ifdef UNICODE xpnbyte(-1,0,0,NULL); /* Reset UCS-2 byte counter. */ #endif /* UNICODE */ debug(F110,"rcvfil rdatap",rdatap,0); decode(rdatap,putsrv,0); /* Don't xlate charsets. */ #ifdef CALIBRATE calibrate = csave; if (dest == DEST_N) { calibrate = 1; cmarg2 = "CALIBRATE"; } #endif /* CALIBRATE */ if (*srvcmd == '\0') /* Watch out for null F packet. */ ckstrncpy((char *)srvcmd,"NONAME",srvcmdlen); makestr(&prrfspec,(char *)srvcmd); /* New preliminary filename */ #ifdef DTILDE if (*srvcmd == '~') { dirp = tilde_expand((char *)srvcmd); /* Expand tilde, if any. */ if (*dirp != '\0') ckstrncpy((char *)srvcmd,dirp,srvcmdlen); } #else #ifdef OS2 if (isalpha(*srvcmd) && srvcmd[1] == ':' && srvcmd[2] == '\0') ckstrncat((char *)srvcmd,"NONAME",srvcmdlen); #endif /* OS2 */ #endif /* DTILDE */ #ifndef NOICP #ifndef NOSPL /* File dialog when downloading... */ if ( #ifdef CK_APC (apcactive == APC_LOCAL && adl_ask) || /* Autodownload with ASK */ #endif /* CK_APC */ (clcmds && haveurl) /* Or "kermit:" or "iksd:" URL */ ) { int x; char fnbuf[CKMAXPATH+1]; /* Result buffer */ char * preface; if (clcmds && haveurl) preface = "\r\nIncoming file from Kermit server...\r\n\ Please confirm output file specification or supply an alternative:"; else preface = "\r\nIncoming file from remote Kermit...\r\n\ Please confirm output file specification or supply an alternative:"; x = uq_file(preface, /* Preface */ NULL, /* Prompt (let uq_file() built it) */ 3, /* Output file */ NULL, /* Help text */ (char *)srvcmd, /* Default */ fnbuf, /* Result buffer */ CKMAXPATH+1 /* Size of result buffer */ ); if (x < 1) { /* Refused */ rf_err = "Refused by user"; return(0); } ckstrncpy((char *)srvcmd,fnbuf,CKMAXPATH+1); if (isabsolute((char *)srvcmd)) { /* User gave an absolute path */ g_fnrpath = fnrpath; /* Save current RECEIVE PATHNAMES */ fnrpath = PATH_ABS; /* switch to ABSOLUTE */ } } #endif /* NOSPL */ #endif /* NOICP */ if (!ENABLED(en_cwd)) { /* CD is disabled */ zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */ if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */ rf_err = "Access denied"; return(0); } } #ifdef COMMENT /* Wrong place for this -- handle cmarg2 first -- see below... */ if (zchko((char *)srvcmd) < 0) { /* Precheck for write access */ debug(F110,"rcvfil access denied",srvcmd,0); rf_err = "Write access denied"; discard = opnerr = 1; return(0); } xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */ debug(F110,"rcvfil srvcmd 1",srvcmd,0); tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */ #endif /* COMMENT */ skipthis = 0; /* This file in our exception list? */ for (i = 0; i < NSNDEXCEPT; i++) { if (!rcvexcept[i]) { break; } if (ckmatch(rcvexcept[i],(char *)srvcmd,filecase,1)) { skipthis = 1; break; } } #ifdef DEBUG if (deblog && skipthis) { debug(F111,"rcvfil rcvexcept",rcvexcept[i],i); debug(F110,"rcvfil skipping",srvcmd,0); } #endif /* DEBUG */ if (skipthis) { /* Skipping this file */ discard = 1; rejection = 1; rf_err = "Exception list"; debug(F101,"rcvfil discard","",discard); tlog(F100," refused: exception list","",0); return(1); } /* File is not in exception list */ if (!cmarg2) /* No core dumps please */ cmarg2 = ""; debug(F110,"rcvfil cmarg2",cmarg2,0); if (*cmarg2) { /* Check for alternate name */ #ifndef NOSPL int y; char *s; /* Pass it thru the evaluator */ extern int cmd_quoting; if (cmd_quoting) { y = MAXRP; ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* for \v(filename) */ s = (char *)srvcmd; zzstring(cmarg2,&s,&y); } else *srvcmd = NUL; if (!*srvcmd) /* If we got something */ #endif /* NOSPL */ ckstrncpy((char *)srvcmd,cmarg2,srvcmdlen); } debug(F110,"rcvfil srvcmd 2",srvcmd,0); #ifdef PIPESEND /* If it starts with "bang", it's a pipe, not a file. */ if (usepipes && protocol == PROTO_K && *srvcmd == '!' && !rcvfilter) { CHAR *s; s = srvcmd+1; /* srvcmd[] is not a pointer. */ while (*s) { /* So we have to slide the contents */ *(s-1) = *s; /* over 1 space to the left. */ s++; } *(s-1) = NUL; pipesend = 1; } #endif /* PIPESEND */ #ifdef COMMENT /* This is commented out because we need to know whether the name we are using was specified by the local user as an override, or came from the incoming packet. In the former case, we don't do stuff to it (like strip the pathname) that we might do to it in the latter. */ cmarg2 = ""; /* Done with alternate name */ #endif /* COMMENT */ if ((int)strlen((char *)srvcmd) > CKMAXPATH) /* Watch out for overflow */ *(srvcmd + CKMAXPATH - 1) = NUL; /* At this point, srvcmd[] contains the incoming filename or as-name. */ /* So NOW we check for write access. */ if (zchko((char *)srvcmd) < 0) { /* Precheck for write access */ debug(F110,"rcvfil access denied",srvcmd,0); rf_err = "Write access denied"; discard = opnerr = 1; return(0); } xxscreen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */ debug(F110,"rcvfil srvcmd 1",srvcmd,0); tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */ #ifdef CK_LABELED #ifdef VMS /* If we have an as-name, this overrides the internal name if we are doing a labeled-mode transfer. */ if (*cmarg2) { extern int lf_opts; lf_opts &= ~LBL_NAM; } #endif /* VMS */ #endif /* CK_LABELED */ debug(F111,"rcvfil pipesend",srvcmd,pipesend); #ifdef PIPESEND /* Skip all the filename manipulation and collision actions */ if (pipesend) { dirflg = 0; ofn1[0] = '!'; ckstrncpy(&ofn1[1],(char *)srvcmd,CKMAXPATH+1); ckstrncpy(n,ofn1,CKMAXPATH+1); ckstrncpy(fspec,ofn1,CKMAXPATH+1); makestr(&prfspec,fspec); /* New preliminary filename */ debug(F110,"rcvfil pipesend",ofn1,0); goto rcvfilx; } #endif /* PIPESEND */ /* This is to avoid passing email subjects through nzrtol(). We haven't yet received the A packet so we don't yet know it's e-mail, so in fact we go ahead and convert it anyway, but later we get the original back from ofilnam[]. */ dispos = 0; ckstrncpy(ofilnam,(char *)srvcmd,CKMAXPATH+1); #ifdef NZLTOR if (*cmarg2) ckstrncpy((char *)ofn1,(char *)srvcmd,CKMAXPATH+1); else nzrtol((char *)srvcmd, /* Filename from packet */ (char *)ofn1, /* Where to put result */ fncnv, /* Filename conversion */ fnrpath, /* Pathname handling */ CKMAXPATH /* Size of result buffer */ ); #else debug(F101,"rcvfil fnrpath","",fnrpath); /* Handle pathnames */ if (fnrpath == PATH_OFF && !*cmarg2) { /* RECEIVE PATHNAMES OFF? */ char *t; /* Yes. */ zstrip((char *)srvcmd,&t); /* If there is a pathname, strip it */ debug(F110,"rcvfil PATH_OFF zstrip",t,0); if (!t) /* Be sure we didn't strip too much */ sprintf(ofn1,"FILE%02ld",filcnt); else if (*t == '\0') sprintf(ofn1,"FILE%02ld",filcnt); else ckstrncpy(ofn1,t,CKMAXPATH+1); ckstrncpy((char *)srvcmd,ofn1,srvcmdlen); /* Now copy it back. */ } /* SET RECEIVE PATHNAMES RELATIVE... The following doesn't belong here but doing it right would require defining and implementing a new file routine for all ck?fio.c modules. So for now... */ #ifdef UNIXOROSK else if (fnrpath == PATH_REL && !*cmarg2) { if (isabsolute((char *)srvcmd)) { ofn1[0] = '.'; ckstrncpy(&of1n[1],(char *)srvcmd,CKMAXPATH+1); ckstrncpy((char *)srvcmd,ofn1,srvcmdlen); debug(F110,"rcvfil PATH_REL",ofn1,0); } } #else #ifdef OS2 else if (fnrpath == PATH_REL && !*cmarg2) { if (isabsolute((char *)srvcmd)) { char *p = (char *)srvcmd; if (isalpha(*p) && *(p+1) == ':') p += 2; if (*p == '\\' || *p == '/') p++; ckstrncpy(ofn1,p,CKMAXPATH+1); ckstrncpy((char *)srvcmd,ofn1,srvcmdlen); debug(F110,"rcvfil OS2 PATH_REL",ofn1,0); } } #endif /* OS2 */ #endif /* UNIXOROSK */ /* Now srvcmd contains incoming filename with path possibly stripped */ if (fncnv) /* FILE NAMES CONVERTED? */ zrtol((char *)srvcmd,(char *)ofn1); /* Yes, convert to local form */ else ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* No, copy literally. */ #endif /* NZLTOR */ #ifdef PIPESEND if (rcvfilter) { char * p = NULL, * q; int nn = MAXRP; pipesend = 1; debug(F110,"rcvfil rcvfilter ",rcvfilter,0); #ifndef NOSPL if ((p = (char *) malloc(nn + 1))) { q = p; #ifdef COMMENT /* We have already processed srvcmd and placed it into ofn1 */ ckstrncpy(ofn1,(char *)srvcmd,CKMAXPATH+1); /* For \v(filename) */ #endif /* COMMENT */ debug(F110,"rcvfile pipesend filter",rcvfilter,0); zzstring(rcvfilter,&p,&nn); debug(F111,"rcvfil pipename",q,nn); if (nn <= 0) { printf( "?Sorry, receive filter + filename too long, %d max.\n", CKMAXPATH ); rf_err = "Name too long"; free(q); return(0); } ckstrncpy((char *)srvcmd,q,MAXRP); free(q); } #endif /* NOSPL */ } #endif /* PIPESEND */ /* Now the incoming filename, possibly converted, is in ofn1[]. */ #ifdef OS2 /* Don't refuse the file just because the name is illegal. */ if (!IsFileNameValid(ofn1)) { /* Name is OK for OS/2? */ #ifdef OS2ONLY char *zs = NULL; zstrip(ofn1, &zs); /* Not valid, strip unconditionally */ if (zs) { if (iattr.longname.len && /* Free previous longname, if any */ iattr.longname.val) free(iattr.longname.val); iattr.longname.len = strlen(zs); /* Store in attribute structure */ iattr.longname.val = (char *) malloc(iattr.longname.len + 1); if (iattr.longname.val) /* Remember this (illegal) name */ strcpy(iattr.longname.val, zs); /* safe */ } #endif /* OS2ONLY */ debug(F110,"rcvfil: invalid file name",ofn1,0); ChangeNameForFAT(ofn1); /* Change to an acceptable name */ debug(F110,"rcvfil: FAT file name",ofn1,0); } else { /* Name is OK. */ debug(F110,"rcvfil: valid file name",ofn1,0); #ifdef OS2ONLY if (iattr.longname.len && iattr.longname.val) /* Free previous longname, if any */ free(iattr.longname.val); iattr.longname.len = 0; iattr.longname.val = NULL; /* This file doesn't need a longname */ #endif /* OS2ONLY */ } #endif /* OS2 */ debug(F110,"rcvfil as",ofn1,0); /* Filename collision action section. */ dirflg = /* Is it a directory name? */ #ifdef CK_TMPDIR isdir(ofn1) #else 0 #endif /* CK_TMPDIR */ ; debug(F101,"rcvfil dirflg","",dirflg); ofn1len = zchki(ofn1); /* File already exists? */ debug(F111,"rcvfil ofn1len",ofn1,ofn1len); ofn1x = (ofn1len != (CK_OFF_T)-1); if ( ( #ifdef UNIX strcmp(ofn1,"/dev/null") && /* It's not the null device? */ #else #ifdef OSK strcmp(ofn1,"/nil") && #endif /* OSK */ #endif /* UNIX */ !stdouf ) && /* Not copying to standard output? */ ofn1x || /* File of same name exists? */ dirflg ) { /* Or file is a directory? */ debug(F111,"rcvfil exists",ofn1,fncact); #ifdef CK_PERMS ofperms = zgperm((char *)ofn1); /* Get old file's permissions */ debug(F110,"rcvfil perms",ofperms,0); #endif /* CK_PERMS */ debug(F101,"rcvfil fncact","",fncact); switch (fncact) { /* Yes, do what user said. */ case XYFX_A: /* Append */ ofperms = ""; debug(F100,"rcvfil append","",0); if (dirflg) { rf_err = "Can't append to a directory"; tlog(F100," error - can't append to directory","",0); discard = opnerr = 1; return(0); } tlog(F110," appending to",ofn1,0); break; #ifdef COMMENT case XYFX_Q: /* Query (Ask) */ break; /* not implemented */ #endif /* COMMENT */ case XYFX_B: /* Backup (rename old file) */ if (dirflg) { rf_err = "Can't rename existing directory"; tlog(F100," error - can't rename directory","",0); discard = opnerr = 1; return(0); } znewn(ofn1,&ofn2); /* Get new unique name */ tlog(F110," backup:",ofn2,0); debug(F110,"rcvfil backup ofn1",ofn1,0); debug(F110,"rcvfil backup ofn2",ofn2,0); #ifdef CK_LABELED #ifdef OS2ONLY /* In case this is a FAT file system, we can't change only the FAT name, we also have to change the longname from the extended attributes block. Otherwise, we'll have many files with the same longname and if we copy them to an HPFS volume, only one will survive. */ if (os2getlongname(ofn1, &longname) > -1) { if (strlen(longname)) { char tmp[10]; extern int ck_znewn; sprintf(tmp,".~%d~",ck_znewn); newlongname = (char *) malloc(strlen(longname) + strlen(tmp) + 1); if (newlongname) { strcpy(newlongname, longname); /* safe (prechecked) */ strcat(newlongname, tmp); /* safe (prechecked) */ os2setlongname(ofn1, newlongname); free(newlongname); newlongname = NULL; } } } else debug(F100,"rcvfil os2getlongname failed","",0); #endif /* OS2ONLY */ #endif /* CK_LABELED */ #ifdef COMMENT /* Do this later, in opena()... */ if (zrename(ofn1,ofn2) < 0) { rf_err = "Can't transform filename"; debug(F110,"rcvfil rename fails",ofn1,0); discard = opnerr = 1; return(0); } #endif /* COMMENT */ break; case XYFX_D: /* Discard (refuse new file) */ ofperms = ""; discard = 1; rejection = 1; /* Horrible hack: reason = name */ debug(F101,"rcvfil discard","",discard); tlog(F100," refused: name","",0); break; case XYFX_R: /* Rename incoming file */ znewn(ofn1,&ofn2); /* Make new name for it */ #ifdef OS2ONLY if (iattr.longname.len) { char tmp[10]; extern int ck_znewn; sprintf(tmp,".~%d~",ck_znewn); newlongname = (char *) malloc(iattr.longname.len + strlen(tmp) + 1); if (newlongname) { strcpy(newlongname, iattr.longname.val); /* safe */ strcat(newlongname, tmp); /* safe */ debug(F110, "Rename Incoming: newlongname",newlongname,0); if (iattr.longname.len && iattr.longname.val) free(iattr.longname.val); iattr.longname.len = strlen(newlongname); iattr.longname.val = newlongname; /* free(newlongname) here ? */ } } #endif /* OS2ONLY */ break; case XYFX_X: /* Replace old file */ debug(F100,"rcvfil overwrite","",0); if (dirflg) { rf_err = "Can't overwrite existing directory"; tlog(F100," error - can't overwrite directory","",0); discard = opnerr = 1; #ifdef COMMENT return(0); #else break; #endif /* COMMENT */ } tlog(F110,"overwriting",ofn1,0); break; case XYFX_U: /* Refuse if older */ debug(F110,"rcvfil update",ofn1,0); if (dirflg) { rf_err = "File has same name as existing directory"; tlog(F110," error - directory exists:",ofn1,0); discard = opnerr = 1; #ifdef COMMENT /* Don't send an error packet, just refuse the file */ return(0); #endif /* COMMENT */ } break; /* Not here, we don't have */ /* the attribute packet yet. */ default: ofperms = ""; debug(F101,"rcvfil bad collision action","",fncact); break; } } debug(F110,"rcvfil ofn1",ofn1,0); debug(F110,"rcvfil ofn2",ofn2,0); debug(F110,"rcvfil ofperms",ofperms,0); if (fncact == XYFX_R && ofn1x && ofn2) { /* Renaming incoming file? */ xxscreen(SCR_AN,0,0l,ofn2); /* Display renamed name */ ckstrncpy(n, ofn2, CKMAXPATH+1); /* Return it */ } else { /* No */ xxscreen(SCR_AN,0,0l,ofn1); /* Display regular name */ ckstrncpy(n, ofn1, CKMAXPATH+1); /* and return it. */ } #ifdef CK_MKDIR /* Create directory(s) if necessary. */ if (!discard && fnrpath != PATH_OFF) { /* RECEIVE PATHAMES ON? */ int x; debug(F110,"rcvfil calling zmkdir",ofn1,0); /* Yes */ if ((x = zmkdir(ofn1)) < 0) { debug(F100,"zmkdir fails","",0); tlog(F110," error - directory creation failure:",ofn1,0); rf_err = "Directory creation failure."; discard = 1; return(0); } #ifdef TLOG else if (x > 0) tlog(F110," path created:",ofn1,0); #endif /* TLOG */ } #else debug(F110,"rcvfil CK_MKDIR not defined",ofn1,0); #endif /* CK_MKDIR */ if (calibrate) ckstrncpy(fspec,ofn1,CKMAXPATH+1); else zfnqfp(ofn1,fspeclen,fspec); debug(F110,"rcvfil fspec",fspec,0); #ifdef COMMENT /* See comments with VMS zfnqfp()... */ #ifdef VMS /* zfnqfp() does not return the version number */ if (!calibrate) { int x, v; x = strlen(ofn1); if (x > 0) { if (ofn1[x-1] == ';') { v = getvnum(ofn1); ckstrncpy(&ofn1[x],ckitoa(v),CKMAXPATH-x); } } } #endif /* VMS */ #endif /* COMMENT */ fspec[fspeclen] = NUL; makestr(&prfspec,fspec); /* New preliminary filename */ #ifdef PIPESEND rcvfilx: #endif /* PIPESEND */ debug(F110,"rcvfilx: n",n,0); debug(F110,"rcvfilx: ofn1",ofn1,0); ffc = (CK_OFF_T)0; /* Init per-file counters */ cps = oldcps = 0L; rs_len = (CK_OFF_T)0; rejection = -1; fsecs = gtimer(); /* Time this file started */ #ifdef GFTIMER fpfsecs = gftimer(); debug(F101,"rcvfil fpfsecs","",fpfsecs); #endif /* GFTIMER */ filcnt++; intmsg(filcnt); return(1); /* Successful return */ } /* R E O F -- Receive End Of File packet for incoming file */ /* Closes the received file. Returns: 0 on success. -1 if file could not be closed. 2 if disposition was mail, mail was sent, but temp file not deleted. 3 if disposition was print, file was printed, but not deleted. -2 if disposition was mail and mail could not be sent -3 if disposition was print and file could not be printed -4 if MOVE-TO: failed -5 if RENAME-TO: failed */ int #ifdef CK_ANSIC reof( char *f, struct zattr *yy ) #else reof(f,yy) char *f; struct zattr *yy; #endif /* CK_ANSIC */ { extern char * rcv_move, * rcv_rename; extern int o_isopen; int rc = 0; /* Return code */ char *p; char c; debug(F111,"reof fncact",f,fncact); debug(F101,"reof discard","",discard); success = 1; /* Assume status is OK */ lsstate = 0; /* Cancel locking-shift state */ if (discard) { /* Handle attribute refusals, etc. */ debug(F101,"reof discarding","",0); success = 0; /* Status = failed. */ if (rejection == '#' || /* Unless rejection reason is */ rejection == 1 || /* date or name (SET FILE COLLISION */ rejection == '?') /* UPDATE or DISCARD) */ success = 1; debug(F101,"reof success","",success); filrej++; /* Count this rejection. */ discard = 0; /* We never opened the file, */ return(0); /* so we don't close it. */ } #ifdef DEBUG if (deblog) { debug(F101,"reof cxseen","",cxseen); debug(F101,"reof czseen","",czseen); debug(F110,"reof rdatap",rdatap,0); } #endif /* DEBUG */ if (cxseen == 0) /* Got cancel directive? */ cxseen = (*rdatap == 'D'); if (cxseen || czseen) /* (for hints) */ interrupted = 1; success = (cxseen || czseen) ? 0 : 1; /* Set SUCCESS flag appropriately */ if (!success) /* "Uncount" this file */ filrej++; debug(F101,"reof o_isopen","",o_isopen); if (o_isopen) { /* If an output file was open... */ #ifdef CK_CTRLZ if (success) { debug(F101,"reof lastchar","",lastchar); if (!binary && eofmethod == XYEOF_Z && lastchar != 26 && (!xflg || (xflg && remfile))) pnbyte((char)26,putfil); } #endif /* CK_CTRLZ */ rc = clsof(cxseen || czseen); /* Close the file (resets cxseen) */ debug(F101,"reof closf","",rc); if (rc < 0) { /* If failure to close, FAIL */ if (success) filrej++; success = 0; } if (!calibrate) { /* Set file modification date and/or permissions */ if (success) zstime(f,yy,0); #ifdef OS2ONLY #ifdef CK_LABELED if (success && yy->longname.len) os2setlongname(f, yy->longname.val); #endif /* CK_LABELED */ #endif /* OS2ONLY */ } if (success == 0) { /* And program return code */ xitsta |= W_RECV; } else if (success == 1) { /* File rec'd successfully */ makestr(&rrfspec,prrfspec); /* Record it for wheremsg */ makestr(&rfspec,prfspec); } /* Handle dispositions from attribute packet... */ c = NUL; #ifndef NOFRILLS if (!calibrate && yy->disp.len != 0) { p = yy->disp.val; c = *p++; #ifndef UNIX /* See ckcpro.c. In UNIX we don't use temp files any more -- we pipe the stuff right into mail or lpr. */ if (c == 'M') { /* Mail to user. */ rc = zmail(p,filnam); /* Do the system's mail command */ if (rc < 0) success = 0; /* Remember status */ tlog(F110,"mailed",filnam,0L); tlog(F110," to",p,0L); zdelet(filnam); /* Delete the file */ } else if (c == 'P') { /* Print the file. */ rc = zprint(p,filnam); /* Do the system's print command */ if (rc < 0) success = 0; /* Remember status */ tlog(F110,"printed",filnam,0L); tlog(F110," with options",p,0L); #ifndef VMS #ifndef STRATUS /* spooler deletes file after print complete in VOS & VMS */ if (zdelet(filnam) && rc == 0) rc = 3; /* Delete the file */ #endif /* STRATUS */ #endif /* VMS */ } #endif /* UNIX */ } #endif /* NOFRILLS */ if (success && !pipesend && !calibrate && c != 'M' && c != 'P') { if (rcv_move) { /* If /MOVE-TO was given... */ char * p = rcv_move; #ifdef COMMENT /* No need for this - it's a directory name */ char tmpbuf[CKMAXPATH+1]; extern int cmd_quoting; /* for \v(filename) */ if (cmd_quoting) { /* But only if cmd_quoting is on */ int n; n = CKMAXPATH; p = tmpbuf; debug(F111,"reof /move-to",rcv_move,0); zzstring(rcv_move,&p,&n); p = tmpbuf; } #endif /* COMMENT */ /* Here we could create the directory if it didn't exist (and it was relative) but there would have to be a user-settable option to say whether to do this. */ rc = zrename(filnam,p); debug(F111,"reof MOVE zrename",rcv_move,rc); if (rc > -1) { tlog(F110," moving received file to",rcv_move,0); } else { rc = -4; tlog(F110," FAILED to move received file to",rcv_move,0); } } else if (rcv_rename) { /* Or /RENAME-TO: */ char *s = rcv_rename; /* This is the renaming string */ #ifndef NOSPL char tmpnam[CKMAXPATH+16]; extern int cmd_quoting; /* for \v(filename) */ if (cmd_quoting) { /* But only if cmd_quoting is on */ int n; /* Pass it thru the evaluator */ n = CKMAXPATH; s = (char *)tmpnam; zzstring(rcv_rename,&s,&n); s = (char *)tmpnam; } #endif /* NOSPL */ if (s) if (*s) { rc = zrename(filnam,s); debug(F111,"reof RENAME zrename",s,rc); if (rc > -1) { tlog(F110," renaming received file to",s,0); } else { rc = -5; tlog(F110," FAILED to rename received file to",s,0); } } } } } debug(F101,"reof success","",success); debug(F101,"reof returns","",rc); filnam[0] = NUL; /* Erase the filename */ return(rc); } /* R E O T -- Receive End Of Transaction */ VOID reot() { cxseen = czseen = discard = 0; /* Reset interruption flags */ tstats(); /* Finalize transfer statistics */ } /* S F I L E -- Send File header or teXt header packet */ /* Call with x nonzero for X packet, zero for F packet. If X == 0, filename to send is in filnam[], and if cmarg2 is not null or empty, the file should be sent under this name rather than filnam[]. If sndfilter not NULL, it is the name of a send filter. Returns 1 on success, 0 on failure. */ int #ifdef CK_ANSIC sfile( int x ) #else sfile(x) int x; #endif /* CK_ANSIC */ { #ifdef pdp11 #define PKTNL 64 #else #define PKTNL 256 #endif /* pdp11 */ char pktnam[PKTNL+1]; /* Local copy of name */ char *s; int rc; int notafile = 0; extern int filepeek; #ifdef PIPESEND extern char * sndfilter; if (sndfilter) { pipesend = 1; debug(F110,"sfile send filter ",sndfilter,0); } #endif /* PIPESEND */ notafile = calibrate || sndarray || pipesend || x; debug(F101,"sfile x","",x); debug(F101,"sfile notafile","",notafile); #ifndef NOCSETS if (tcs_save > -1) { /* Character sets */ tcharset = tcs_save; tcs_save = -1; debug(F101,"sfile restored tcharset","",tcharset); } if (fcs_save > -1) { fcharset = fcs_save; fcs_save = -1; debug(F101,"sfile restored fcharset","",fcharset); } setxlatype(tcharset,fcharset); /* Translation type */ #endif /* NOCSETS */ /* cmarg2 or filnam (with that precedence) have the file's name */ lsstate = 0; /* Cancel locking-shift state */ #ifdef COMMENT /* Do this after making sure we can open the file */ if (nxtpkt() < 0) return(0); /* Bump packet number, get buffer */ #endif /* COMMENT */ pktnam[0] = NUL; /* Buffer for name we will send */ if (x == 0) { /* F-Packet setup */ if (!cmarg2) cmarg2 = ""; #ifdef DEBUG if (deblog) { /* debug(F111,"sfile cmarg2",cmarg2,cmarg2); */ debug(F101,"sfile binary 1","",binary); debug(F101,"sfile wearealike","",wearealike); debug(F101,"sfile xfermode","",xfermode); debug(F101,"sfile filepeek","",filepeek); #ifndef NOCSETS debug(F101,"sfile s_cset","",s_cset); debug(F101,"sfile tcharset","",tcharset); debug(F101,"sfile xfrxla","",xfrxla); #endif /* NOCSETS */ } #endif /* DEBUG */ if (xfermode == XMODE_A /* TRANSFER MODE AUTOMATIC */ #ifndef NOMSEND && !addlist /* And not working from a SEND-LIST */ #endif /* NOMSEND */ ) { /* Other Kermit is on a like system and no charset translation */ if (wearealike #ifndef NOCSETS && (tcharset == TC_TRANSP || xfrxla == 0) #endif /* NOCSETS */ ) { #ifdef VMS if (binary != XYFT_I) #endif /* VMS */ #ifdef CK_LABELED if (binary != XYFT_L) #endif /* CK_LABELED */ binary = XYFT_B; /* Send all files in binary mode */ } /* Otherwise select transfer mode based on file info */ else if (!notafile /* but not if sending from pipe */ #ifdef CK_LABELED && binary != XYFT_L /* and not if FILE TYPE LABELED */ #endif /* CK_LABELED */ #ifdef VMS && binary != XYFT_I /* or FILE TYPE IMAGE */ #endif /* VMS */ ) { #ifdef UNICODE fileorder = -1; /* File byte order */ #endif /* UNICODE */ if (filepeek && !notafile) { /* Real file, FILE SCAN is ON */ int k, x; k = scanfile(filnam,&x,nscanfile); /* Scan the file */ debug(F101,"sfile scanfile","",k); switch (k) { case FT_TEXT: /* Unspecified text */ debug(F100,"sfile scanfile text","",0); binary = XYFT_T; /* SET FILE TYPE TEXT */ break; #ifndef NOCSETS case FT_7BIT: /* 7-bit text */ binary = XYFT_T; /* SET FILE TYPE TEXT */ /* If SEND CHARSET-SELECTION AUTO */ /* and SET TRANSFER TRANSLATION is ON */ debug(F100,"sfile scanfile text7","",0); if (s_cset == XMODE_A && xfrxla) { if (fcsinfo[fcharset].size != 128) { fcs_save = fcharset; /* Current FCS not 7bit */ fcharset = dcset7; /* Use default 7bit set */ debug(F101,"sfile scanfile 7 fcharset", "",fcharset); } /* And also switch to appropriate TCS */ if (afcset[fcharset] > -1 && afcset[fcharset] <= MAXTCSETS) { tcs_save = tcharset; tcharset = afcset[fcharset]; debug(F101,"sfile scanfile 7 tcharset","", tcharset); } setxlatype(tcharset,fcharset); } break; case FT_8BIT: /* 8-bit text */ binary = XYFT_T; /* SET FILE TYPE TEXT */ /* If SEND CHARSET-SELEC AUTO */ /* and SET TRANSFER TRANSLATION is ON */ debug(F100,"sfile scanfile text8","",0); if (s_cset == XMODE_A && xfrxla) { if (fcsinfo[fcharset].size != 256) { fcs_save = fcharset; /* Current FCS not 8bit */ fcharset = dcset8; /* Use default 8bit set */ debug(F101,"sfile scanfile 8 fcharset", "",fcharset); } /* Switch to corresponding transfer charset */ if (afcset[fcharset] > -1 && afcset[fcharset] <= MAXTCSETS) { tcs_save = tcharset; tcharset = afcset[fcharset]; debug(F101,"sfile scanfile 8 tcharset","", tcharset); } setxlatype(tcharset,fcharset); } break; #ifdef UNICODE case FT_UTF8: /* UTF-8 text */ case FT_UCS2: /* UCS-2 text */ debug(F101,"sfile scanfile Unicode","",k); binary = XYFT_T; /* If SEND CHARSET-SELEC AUTO */ /* and SET TRANSFER TRANSLATION is ON */ if (s_cset == XMODE_A && xfrxla) { fcs_save = fcharset; tcs_save = tcharset; fcharset = (k == FT_UCS2) ? FC_UCS2 : FC_UTF8; if (k == FT_UCS2 && x > -1) fileorder = x; } /* Switch to associated transfer charset if any */ if (afcset[fcharset] > -1 && afcset[fcharset] <= MAXTCSETS) tcharset = afcset[fcharset]; if (tcharset == TC_TRANSP) /* If none */ tcharset = TC_UTF8; /* use UTF-8 */ setxlatype(tcharset,fcharset); debug(F101,"sfile Unicode tcharset","",tcharset); break; #endif /* UNICODE */ #endif /* NOCSETS */ case FT_BIN: debug(F101,"sfile scanfile binary","",k); binary = XYFT_B; break; /* Default: Don't change anything */ } } } debug(F101,"sfile binary 2","",binary); debug(F101,"sfile sendmode","",sendmode); } if (*cmarg2) { /* If we have a send-as name... */ int y; char *s; #ifndef NOSPL /* and a script programming language */ extern int cmd_quoting; if (cmd_quoting) { /* and it's not turned off */ y = PKTNL; /* pass as-name thru the evaluator */ s = pktnam; zzstring(cmarg2,&s,&y); #ifdef COMMENT /* This ruins macros like BSEND */ if (!pktnam[0]) /* and make sure result is not empty */ sprintf(pktnam,"FILE%02ld",filcnt); #endif /* COMMENT */ } else #endif /* NOSPL */ ckstrncpy(pktnam,cmarg2,PKTNL); /* copy it literally, */ debug(F110,"sfile pktnam",pktnam,0); #ifdef COMMENT /* We don't do this any more because now we have filename templates */ cmarg2 = ""; /* and blank it out for next time. */ #endif /* COMMENT */ } if (!*pktnam) { /* No as-name... */ #ifdef NZLTOR int xfncnv, xpath; debug(F101,"sfile fnspath","",fnspath); debug(F101,"sfile fncnv","",fncnv); xfncnv = fncnv; xpath = fnspath; if (notafile) { /* If not an actual file */ xfncnv = 0; /* Don't convert name */ xpath = PATH_OFF; /* Leave path off */ } else if (xfncnv && (!strcmp(whoareu,"U1") || !strcmp(whoareu,"UN")) ) { /* Less-strict conversion if partner is UNIX or Win32 */ xfncnv = -1; } debug(F101,"sfile xpath","",xpath); debug(F101,"sfile xfncnv","",xfncnv); nzltor(filnam,pktnam,xfncnv,xpath,PKTNL); #else /* Not NZLTOR */ debug(F101,"sfile fnspath","",fnspath); if (fnspath == PATH_OFF /* Stripping path names? */ && (!notafile) /* (of actual files) */ ) { char *t; /* Yes. */ zstrip(filnam,&t); /* Strip off the path. */ debug(F110,"sfile zstrip",t,0); if (!t) t = "UNKNOWN"; /* Be cautious... */ else if (*t == '\0') t = "UNKNOWN"; ckstrncpy(pktnam,t,PKTNL); /* Copy stripped name literally. */ } else if (fnspath == PATH_ABS && !notafile) { /* Converting to absolute form */ zfnqfp(filnam,PKTNL,pktnam); } else ckstrncpy(pktnam,filnam,PKTNL); /* pktnam[] has the packet name, filnam[] has the original name. */ /* But we still need to convert pktnam if FILE NAMES CONVERTED. */ debug(F101,"sfile fncnv","",fncnv); if (fncnv && !notafile) { /* If converting names of files */ zltor(pktnam,(char *)srvcmd); /* convert it to common form, */ ckstrncpy(pktnam,(char *)srvcmd,PKTNL); *srvcmd = NUL; } #endif /* NZLTOR */ } if (!*pktnam) /* Failsafe... */ sprintf(pktnam,"FILE%02ld",filcnt); debug(F110,"sfile filnam 1",filnam,0); debug(F110,"sfile pktnam 1",pktnam,0); #ifdef PIPESEND /* If we have a send filter, substitute the current filename into it */ if (sndfilter) { char * p = NULL, * q; int n = CKMAXPATH; #ifndef NOSPL if ((p = (char *) malloc(n + 1))) { q = p; debug(F110,"sfile pipesend filter",sndfilter,0); zzstring(sndfilter,&p,&n); debug(F111,"sfile pipename",q,n); if (n <= 0) { printf( "?Sorry, send filter + filename too long, %d max.\n", CKMAXPATH ); free(q); return(0); } ckstrncpy(filnam,q,CKMAXPATH+1); free(q); } #endif /* NOSPL */ } #endif /* PIPESEND */ debug(F110,"sfile filnam 2",filnam,0); /* Log debugging info */ debug(F110,"sfile pktnam 2",pktnam,0); if (openi(filnam) == 0) /* Try to open the input file */ return(0); #ifdef CK_RESEND /* The following check is done after openi() is called, since openi() itself can change the transfer mode (as in VMS). */ if ((binary == XYFT_T #ifdef VMS || binary == XYFT_L #endif /* VMS */ ) && sendmode == SM_RESEND) { /* Trying to RESEND/REGET a file first sent in TEXT mode. */ debug(F111,"sfile error - Recover vs Text",filnam,binary); /* Set appropriate error messages and make log entries here */ #ifdef VMS if (binary == XYFT_L) ckmakmsg((char *)epktmsg, PKTMSGLEN, "Recovery attempted in LABELED mode: ", filnam, NULL, NULL ); else #endif /* VMS */ ckmakmsg((char *)epktmsg, PKTMSGLEN, "Recovery attempted in TEXT mode: ", filnam, NULL, NULL ); return(0); } if (sendmode == SM_PSEND) /* PSENDing? */ if (sendstart > (CK_OFF_T)0) /* Starting position */ if (zfseek(sendstart) < 0) /* seek to it... */ return(0); #endif /* CK_RESEND */ s = pktnam; /* Name for packet data field */ #ifdef OS2 /* Never send a disk letter. */ if (isalpha(*s) && (*(s+1) == ':')) s += 2; #endif /* OS2 */ } else { /* X-packet setup, not F-packet. */ binary = XYFT_T; /* Text always */ debug(F110,"sfile X packet",cmdstr,0); /* Log debugging info */ s = cmdstr; /* Name for data field */ } /* Now s points to the string that goes in the packet data field. */ debug(F101,"sfile binary","",binary); /* Log debugging info */ encstr((CHAR *)s); /* Encode the name. */ /* Send the F or X packet */ /* If the encoded string did not fit into the packet, it was truncated. */ if (nxtpkt() < 0) return(0); /* Bump packet number, get buffer */ rc = spack((char) (x ? 'X' : 'F'), pktnum, size, data); if (rc < 0) return(rc); #ifndef NOCSETS setxlatype(tcharset,fcharset); /* Set up charset translations */ #endif /* NOCSETS */ if (x == 0) { /* Display for F packet */ if (displa) { /* Screen */ xxscreen(SCR_FN,'F',(long)pktnum,filnam); xxscreen(SCR_AN,0,0L,pktnam); xxscreen(SCR_FS,0,calibrate ? calibrate : fsize,""); } #ifdef pdp11 tlog(F110,"Sending",filnam,0L); /* Transaction log entry */ makestr(&psfspec,filnam); /* New filename */ #else #ifndef ZFNQFP tlog(F110,"Sending",filnam,0L); makestr(&psfspec,filnam); /* New filename */ #else if (notafile) { /* If not a file log simple name */ tlog(F110,"Sending", filnam, 0L); } else { /* Log fully qualified filename */ #ifdef COMMENT /* This section generates bad code in SCO 3.2v5.0.5's cc */ char *p = NULL, *q = filnam; debug(F101,"sfile CKMAXPATH","",CKMAXPATH); if ((p = malloc(CKMAXPATH+1))) { debug(F111,"sfile calling zfnqfp",filnam,strlen(filnam)); if (zfnqfp(filnam, CKMAXPATH, p)) { debug(F111,"sfile zfnqfp ok",p,strlen(p)); q = p; } } #else char tmpbuf[CKMAXPATH+1]; char *p = tmpbuf, *q = filnam; if (zfnqfp(filnam, CKMAXPATH, p)) q = p; #endif /* COMMENT */ debug(F111,"sfile q",q,strlen(q)); tlog(F110,"Sending",q,0L); makestr(&psfspec,q); /* New preliminary filename */ #ifdef COMMENT if (p) free(p); #endif /* COMMENT */ } #endif /* ZFNQFP */ #endif /* pdp11 */ tlog(F110," as",pktnam,0L); if (binary) { /* Log file mode in transaction log */ tlog(F101," mode: binary","",(long) binary); } else { /* If text mode, check character set */ tlog(F100," mode: text","",0L); #ifndef NOCSETS if (tcharset == TC_TRANSP || xfrxla == 0) { tlog(F110," character set","transparent",0L); } else { tlog(F110," xfer character set",tcsinfo[tcharset].name,0L); tlog(F110," file character set",fcsinfo[fcharset].name,0L); } #endif /* NOCSETS */ } } else { /* Display for X-packet */ xxscreen(SCR_XD,'X',(long)pktnum,cmdstr); /* Screen */ tlog(F110,"Sending from:",cmdstr,0L); /* Transaction log */ } intmsg(++filcnt); /* Count file, give interrupt msg */ first = 1; /* Init file character lookahead. */ ffc = (CK_OFF_T)0; /* Init file character counter. */ cps = oldcps = 0L; /* Init cps statistics */ rejection = -1; fsecs = gtimer(); /* Time this file started */ #ifdef GFTIMER fpfsecs = gftimer(); debug(F101,"SFILE fpfsecs","",fpfsecs); #endif /* GFTIMER */ debug(F101,"SFILE fsecs","",fsecs); return(1); } /* S D A T A -- Send a data packet */ /* Returns -1 if no data to send (end of file), -2 if connection is broken. If there is data, a data packet is sent, and sdata() returns 1. In the streaming case, the window is regarded as infinite and we keep sending data packets until EOF or there appears to be a Kermit packet on the reverse channel. When not streaming and the window size is greater than 1, we keep sending data packets until window is full or characters start to appear from the other Kermit. In the windowing or streaming case, when there is no more data left to send (or when sending has been interrupted), sdata() does nothing and returns 0 each time it is called until the acknowledgement sequence number catches up to the last data packet that was sent. */ int sdata() { int i, x, len; char * s; debug(F101,"sdata entry, first","",first); debug(F101,"sdata drain","",drain); /* The "drain" flag is used with window size > 1. It means we have sent our last data packet. If called and drain is not zero, then we return 0 as if we had sent an empty data packet, until all data packets have been ACK'd, then then we can finally return -1 indicating EOF, so that the protocol can switch to seof state. This is a kludge, but at least it's localized... */ if (first == 1) drain = 0; /* Start of file, init drain flag. */ if (drain) { /* If draining... */ debug(F101,"sdata draining, winlo","",winlo); if (winlo == pktnum) /* If all data packets are ACK'd */ return(-1); /* return EOF indication */ else /* otherwise */ return(0); /* pretend we sent a data packet. */ } debug(F101,"sdata sbufnum","",sbufnum); for (i = sbufnum; i > 0 #ifdef STREAMING || streaming #endif /* STREAMING */ ; i--) { if (i < 0) break; debug(F101,"sdata countdown","",i); #ifdef STREAMING if (streaming) { pktnum = (pktnum + 1) % 64; winlo = pktnum; debug(F101,"sdata streaming pktnum","",pktnum); } else { #endif /* STREAMING */ x = nxtpkt(); /* Get next pkt number and buffer */ debug(F101,"sdata nxtpkt pktnum","",pktnum); if (x < 0) return(0); #ifdef STREAMING } #endif /* STREAMING */ debug(F101,"sdata packet","",pktnum); if (chkint() < 0) /* Especially important if streaming */ return(-9); if (cxseen || czseen) { /* If interrupted, done. */ if (wslots > 1) { drain = 1; debug(F100,"sdata cx/zseen windowing","",0); return(0); } else { debug(F100,"sdata cx/zseen nonwindowing","",0); return(-1); } } #ifdef DEBUG if (deblog) { debug(F101,"sdata spsiz","",spsiz); debug(F101,"sdata binary","",binary); debug(F101,"sdata parity","",parity); } #endif /* DEBUG */ /* This avoids some edge cases where a longer block check or other factors might push the packet over the edge, causing (for example) the LEN field of a short packet to be out of range. - fdc, 14 September 2022 */ if (spsiz <= 94 && spsiz > 90) spsiz = 90; #ifdef CKTUNING if (binary && !parity && !memstr && !funcstr) len = bgetpkt(spsiz); else len = getpkt(spsiz,1); #else len = getpkt(spsiz,1); #endif /* CKTUNING */ s = (char *)data; if (len == -3) { /* Timed out (e.g.reading from pipe) */ s = ""; /* Send an empty data packet. */ len = 0; } else if (len == 0) { /* Done if no data. */ if (pktnum == winlo) return(-1); drain = 1; /* But can't return -1 until all */ debug(F101,"sdata eof, drain","",drain); return(0); /* ACKs are drained. */ } debug(F101,"sdata pktnum","",pktnum); debug(F101,"sdata len","",len); debug(F011,"sdata data",data,52); x = spack('D',pktnum,len,(CHAR *)s); /* Send the data packet. */ debug(F101,"sdata spack","",x); if (x < 0) { /* Error */ ttchk(); /* See if connection is still there */ return(-2); } #ifdef STREAMING if (streaming) /* What an ACK would do. */ winlo = pktnum; #endif /* STREAMING */ x = ttchk(); /* Peek at input buffer. */ debug(F101,"sdata ttchk","",x); /* ACKs waiting, maybe? */ if (x < 0) /* Or connection broken? */ return(-2); /* Here we check to see if any ACKs or NAKs have arrived, in which case we break out of the D-packet-sending loop and return to the state switcher to process them. This is what makes our windows slide instead of lurch. */ if ( #ifdef GEMDOS /* In the Atari ST version, ttchk() can only return 0 or 1. But note: x will probably always be > 0, since the as-yet-unread packet terminator from the last packet is probably still in the buffer, so sliding windows will probably never happen when the Atari ST is the file sender. The alternative is to say "if (0)", in which case the ST will always send a window full of packets before reading any ACKs or NAKs. */ x > 0 #else /* !GEMDOS */ /* In most other versions, ttchk() returns the actual count. It can't be a Kermit packet if it's less than five bytes long. */ x > 4 + bctu #endif /* GEMDOS */ ) return(1); /* Yes, stop sending data packets */ } /* and go try to read the ACKs. */ return(1); } /* S E O F -- Send an End-Of-File packet */ /* Call with a string pointer to character to put in the data field, */ /* or else a null pointer or "" for no data. */ /* There are two "send-eof" functions. seof() is used to send the normal eof packet at the end of a file's data (even if the file has no data), or when a file transfer is interrupted. sxeof() is used to send an EOF packet that occurs because of attribute refusal or interruption prior to entering data state. The difference is purely a matter of buffer allocation and packet sequence number management. Both functions act as "front ends" to the common send-eof function, szeof(). */ /* Code common to both seof() and sxeof() */ int #ifdef CK_ANSIC szeof( CHAR *s ) #else szeof(s) CHAR *s; #endif /* CK_ANSIC */ { int x; lsstate = 0; /* Cancel locking-shift state */ if (!s) s = (CHAR *)""; debug(F111,"szeof",s,pktnum); if (*s) { x = spack('Z',pktnum,1,s); xitsta |= W_SEND; #ifdef COMMENT tlog(F100," *** interrupted, sending discard request","",0L); #endif /* COMMENT */ filrej++; } else { x = spack('Z',pktnum,0,(CHAR *)""); } if (x < 0) return(x); #ifdef COMMENT /* No, too soon */ discard = 0; /* Turn off per-file discard flag */ #endif /* COMMENT */ /* If we were sending from a pipe, we're not any more... */ pipesend = 0; return(0); } int #ifdef CK_ANSIC seof( int x ) #else seof(x) int x; #endif /* CK_ANSIC */ { char * s; /* ckcpro.c, before calling seof(), sets window size back to 1 and then calls window(), which clears out the old buffers. This is OK because the final data packet for the file has been ACK'd. However, sdata() has already called nxtpkt(), which set the new value of pktnum which seof() will use. So all we need to do here is is allocate a new send-buffer. */ s = x ? "D" : ""; debug(F111,"seof",s,pktnum); if (getsbuf(pktnum) < 0) { /* Get a buffer for packet n */ debug(F101,"seof can't get s-buffer","",pktnum); return(-1); } return(szeof((CHAR *)s)); } /* Version of seof() to be called when sdata() has not been called before. The difference is that this version calls nxtpkt() to allocate a send-buffer and get the next packet number. */ int #ifdef CK_ANSIC sxeof( int x ) #else sxeof(x) int x; #endif /* CK_ANSIC */ { char * s; s = x ? "D" : ""; if (nxtpkt() < 0) /* Get next pkt number and buffer */ debug(F101,"sxeof nxtpkt fails","",pktnum); else debug(F101,"sxeof packet","",pktnum); return(szeof((CHAR *)s)); } /* S E O T -- Send an End-Of-Transaction packet */ int seot() { int x; x = nxtpkt(); debug(F101,"seot nxtpkt","",x); if (x < 0) return(-1); /* Bump packet number, get buffer */ x = spack('B',pktnum,0,(CHAR *)""); /* Send the EOT packet */ if (x < 0) return(x); cxseen = czseen = discard = 0; /* Reset interruption flags */ tstats(); /* Log timing info */ return(0); } /* R P A R -- Fill the data array with my send-init parameters */ int q8flag = 0; CHAR dada[32]; /* Use this instead of data[]. */ /* To avoid some kind of weird */ /* addressing foulup in spack()... */ /* (which might be fixed now...) */ CHAR * rpar() { char *p; int i, x, max; extern int sprmlen; #ifdef COMMENT max = maxdata(); /* Biggest data field I can send */ #else max = 94; #endif /* COMMENT */ /* sprmlen is for interacting with Kermits that have malfunctioning parameter negotiations, set by user command. */ debug(F101, "rpar rpsiz","",rpsiz); debug(F101, "rpar max 1","",max); debug(F101, "rpar sprmlen","",sprmlen); if (sprmlen > 1 && sprmlen < max) /* User override */ max = sprmlen; debug(F101, "rpar max 2","",max); if (rpsiz > MAXPACK) /* Biggest normal packet I want. */ dada[0] = (char) tochar(MAXPACK); /* If > 94, use 94, but specify */ else /* extended packet length below... */ dada[0] = (char) tochar(rpsiz); /* else use what the user said. */ dada[1] = (char) tochar(chktimo(pkttim,0)); /* When to time me out */ dada[2] = (char) tochar(mypadn); /* How much padding I need (none) */ dada[3] = (char) ctl(mypadc); /* Padding character I want */ dada[4] = (char) tochar(eol); /* End-Of-Line character I want */ dada[5] = myctlq; /* Control-Quote character I send */ if (max < 6) { dada[6] = NUL; rqf = 0; ebq = sq = NUL; return(dada); } switch (rqf) { /* 8th-bit prefix (single-shift) */ case -1: /* I'm opening the bids */ case 1: /* Other Kermit already bid 'Y' */ if (parity) ebq = sq = MYEBQ; /* So I reply with '&' if parity */ break; /* otherwise with 'Y'. */ case 2: /* Other Kermit sent a valid prefix */ if (q8flag) sq = ebq; /* Fall through on purpose */ case 0: /* Other Kermit bid nothing */ break; /* So I reply with 'Y'. */ } debug(F000,"rpar 8bq sq","",sq); debug(F000,"rpar 8bq ebq","",ebq); if (lscapu == 2) /* LOCKING-SHIFT FORCED */ dada[6] = 'N'; /* requires no single-shift */ else /* otherwise send prefix or 'Y' */ dada[6] = (char) sq; ebqsent = dada[6]; /* And remember what I really sent */ if (max < 7) { dada[7] = NUL; bctr = 1; return(dada); } dada[7] = (char) (bctr == 4) ? 'B' : bctr + '0'; /* Block check type */ if (max < 8) { dada[8] = NUL; rptflg = 0; return(dada); } if (rptena) { if (rptflg) /* Run length encoding */ dada[8] = (char) rptq; /* If receiving, agree */ else /* by replying with same character. */ dada[8] = (char) (rptq = myrptq); /* When sending use this. */ } else dada[8] = SP; /* Not enabled, put a space here. */ /* CAPAS mask */ if (max < 9) { dada[9] = NUL; atcapr = 0; lpcapr = 0; swcapr = 0; rscapr = 0; return(dada); } dada[9] = (char) tochar((lscapr ? lscapb : 0) | /* Locking shifts */ (atcapr ? atcapb : 0) | /* Attribute packets */ (lpcapr ? lpcapb : 0) | /* Long packets */ (swcapr ? swcapb : 0) | /* Sliding windows */ (rscapr ? rscapb : 0)); /* RESEND */ if (max < 10) { wslotr = 1; return(dada); } dada[10] = (char) tochar(swcapr ? wslotr : 1); /* CAPAS+1 = Window size */ if (max < 12) { rpsiz = 80; return(dada); } if (urpsiz > 94) rpsiz = urpsiz - 1; /* Long packets ... */ dada[11] = (char) tochar(rpsiz / 95); /* Long packet size, big part */ dada[12] = (char) tochar(rpsiz % 95); /* Long packet size, little part */ if (max < 16) return(dada); dada[13] = '0'; /* CAPAS+4 = WONT CHKPNT */ dada[14] = '_'; /* CAPAS+5 = CHKINT (reserved) */ dada[15] = '_'; /* CAPAS+6 = CHKINT (reserved) */ dada[16] = '_'; /* CAPAS+7 = CHKINT (reserved) */ if (max < 17) return(dada); #ifndef WHATAMI dada[17] = ' '; #else x = 0; if (server) x |= WMI_SERVE; /* Whether I am a server */ if (binary) x |= WMI_FMODE; /* My file transfer mode is ... */ if (fncnv) x |= WMI_FNAME; /* My filename conversion is ... */ #ifdef STREAMING if (streamrq == SET_ON) x |= WMI_STREAM; else if (streamrq == SET_AUTO && reliable == SET_ON) x |= WMI_STREAM; /* Always offer to stream when in remote mode and STREAMING is AUTO and RELIABLE is not OFF (i.e. is ON or AUTO). */ else if (!local && streamrq == SET_AUTO && reliable != SET_OFF) x |= WMI_STREAM; #endif /* STREAMING */ #ifdef TCPSOCKET if (clearrq == SET_ON) x |= WMI_CLEAR; else if (clearrq == SET_AUTO && /* SET CLEAR-CHANNEL AUTO */ ((network && nettype == NET_TCPB /* TCP/IP */ #ifdef RLOGCODE && ttnproto != NP_RLOGIN/* Rlogin is not clear */ && !(ttnproto >= NP_K4LOGIN && ttnproto <= NP_EK5LOGIN) #endif /* RLOGCODE */ ) #ifdef SSHBUILTIN || (network && nettype == NET_SSH) #endif /* SSHBUILTIN */ #ifdef IKSD || inserver /* We are IKSD */ #endif /* IKSD */ )) x |= WMI_CLEAR; #endif /* TCPSOCKET */ x |= WMI_FLAG; dada[17] = (char) tochar(x); #endif /* WHATAMI */ i = 18; /* Position of next field */ p = cksysid; /* WHOAMI (my system ID) */ x = strlen(p); if (max - i < x + 1) return(dada); if (x > 0) { dada[i++] = (char) tochar(x); while (*p) dada[i++] = *p++; } if (max < i+1) return(dada); #ifndef WHATAMI /* WHATAMI2 */ dada[i++] = ' '; #else debug(F101,"rpar xfermode","",xfermode); x = WMI2_FLAG; /* Is-Valid flag */ if (xfermode != XMODE_A) /* If TRANSFER MODE is MANUAL */ x |= WMI2_XMODE; /* set the XFERMODE bit */ if (recursive > 0) /* If this is a recursive transfer */ x |= WMI2_RECU; /* set the RECURSIVE bit */ dada[i++] = tochar(x); debug(F101,"rpar whatami2","",x); #endif /* WHATAMI */ dada[i] = '\0'; /* Terminate the init string */ #ifdef DEBUG if (deblog) { debug(F110,"rpar",dada,0); rdebu(dada,(int)strlen((char *)dada)); } #endif /* DEBUG */ ckstrncpy((char *)myinit,(char *)dada,MYINITLEN); return(dada); /* Return pointer to string. */ } /* S P A R -- Set my sending parameters from the data field of the other Kermit's S or I packet, or its ACK to my S or I packet. */ int #ifdef CK_ANSIC spar( CHAR *s ) /* Set parameters */ #else spar(s) CHAR *s; #endif /* CK_ANSIC */ { int x, y, lpsiz, biggest; extern int rprmlen, lastspmax; extern struct sysdata sysidlist[]; whatru = 0; whoareu[0] = NUL; #ifdef STREAMING streamok = 0; streaming = 0; #endif /* STREAMING */ biggest = rln; debug(F101, "spar biggest 1","",biggest); debug(F101, "spar rprmlen","",rprmlen); if (rprmlen > 1 && rprmlen < biggest) biggest = rprmlen; debug(F101, "rpar biggest 2","",biggest); debug(F110,"spar packet",s,0); s--; /* Line up with field numbers. */ /* Limit on size of outbound packets */ x = (biggest >= 1) ? xunchar(s[1]) : 80; lpsiz = spsizr; /* Remember what they SET. */ if (spsizf) { /* SET-command override? */ if (x < spsizr) spsiz = x; /* Ignore LEN unless smaller */ } else { /* otherwise */ spsiz = (x < 10) ? 80 : x; /* believe them if reasonable */ } spmax = spsiz; /* Remember maximum size */ /* Timeout on inbound packets */ if (timef) { timint = rtimo; /* SET SEND TIMEOUT value overrides */ } else { /* Otherwise use requested value, */ x = (biggest >= 2) ? xunchar(s[2]) : rtimo; /* if it is legal. */ timint = (x < 0) ? rtimo : x; } timint = chktimo(timint,timef); /* Adjust if necessary */ /* Outbound Padding */ npad = 0; padch = '\0'; if (biggest >= 3) { npad = xunchar(s[3]); if (biggest >= 4) padch = (CHAR) ctl(s[4]); else padch = 0; } if (npad) { int i; for (i = 0; i < npad; i++) padbuf[i] = dopar(padch); } /* Outbound Packet Terminator */ seol = (CHAR) (biggest >= 5) ? xunchar(s[5]) : CK_CR; if ((seol < 1) || (seol > 31)) seol = CK_CR; /* Control prefix that the other Kermit is sending */ x = (biggest >= 6) ? s[6] : '#'; ctlq = (CHAR) (((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#'); /* 8th-bit prefix */ /* NOTE: Maybe this could be simplified using rcvtyp. If rcvtyp == 'Y' then we're reading the ACK, otherwise we're reading the other Kermit's initial bid. But his horrendous code has been working OK for years, so... */ rq = (biggest >= 7) ? s[7] : 0; if (rq == 'Y') rqf = 1; else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2; else rqf = 0; debug(F000,"spar 8bq rq","",rq); debug(F000,"spar 8bq sq","",sq); debug(F000,"spar 8bq ebq","",ebq); debug(F101,"spar 8bq rqf","",rqf); switch (rqf) { case 0: /* Field is missing from packet. */ ebqflg = 0; /* So no 8th-bit prefixing. */ break; case 1: /* Other Kermit sent 'Y' = Will Do. */ /* When I am the file receiver, ebqsent is 0 because I didn't send a negotiation yet. If my parity is set to anything other than NONE, either because my user SET PARITY or because I detected parity bits on this packet, I reply with '&', otherwise 'Y'. When I am the file sender, ebqsent is what I just sent in rpar(), which can be 'Y', 'N', or '&'. If I sent '&', then this 'Y' means the other Kermit agrees to do 8th-bit prefixing. If I sent 'Y' or 'N', but then detected parity on the ACK packet that came back, then it's too late: there is no longer any way for me to tell the other Kermit that I want to do 8th-bit prefixing, so I must not do it, and in that case, if there is any 8-bit data in the file to be transferred, the transfer will fail because of block check errors. The following clause covers all of these situations: */ if (parity && (ebqsent == 0 || ebqsent == '&')) { ebqflg = 1; ebq = MYEBQ; } break; case 2: /* Other Kermit sent a valid prefix */ ebqflg = (ebq == sq || sq == 'Y'); if (ebqflg) { ebq = rq; debug(F101,"spar setting parity to space","",ebq); if (!parity) parity = ttprty = 's'; } } if (lscapu == 2) { /* But no single-shifts if LOCKING-SHIFT FORCED */ ebqflg = 0; ebq = 'N'; } /* Block check */ x = 1; if (biggest >= 8) { if (s[8] == 'B') x = 4; else x = s[8] - '0'; if ((x < 1) || (x > 5)) x = 1; /* "5" 20110605 */ } bctr = x; /* Repeat prefix */ rptflg = 0; /* Assume no repeat-counts */ if (biggest >= 9) { /* Is there a repeat-count field? */ char t; /* Yes. */ t = s[9]; /* Get its contents. */ /* If I'm sending files, then I'm reading these parameters from an ACK, and so this character must agree with what I sent. */ if (rptena) { /* If enabled ... */ if ((char) rcvtyp == 'Y') { /* Sending files, reading ACK. */ if (t == myrptq) rptflg = 1; } else { /* I'm receiving files */ if ((t > 32 && t < 63) || (t > 95 && t < 127)) { rptflg = 1; rptq = t; } } } else rptflg = 0; } /* Capabilities */ atcapu = lpcapu = swcapu = rscapu = 0; /* Assume none of these. */ if (lscapu != 2) lscapu = 0; /* Assume no LS unless forced. */ y = 11; /* Position of next field, if any */ if (biggest >= 10) { x = xunchar(s[10]); /* s[10] is the CAPAS bitmask */ debug(F101,"spar capas","",x); atcapu = (x & atcapb) && atcapr; /* Attributes */ lpcapu = (x & lpcapb) && lpcapr; /* Long packets */ swcapu = (x & swcapb) && swcapr; /* Sliding windows */ rscapu = (x & rscapb) && rscapr; /* RESEND */ debug(F101,"spar lscapu","",lscapu); debug(F101,"spar lscapr","",lscapr); debug(F101,"spar ebqflg","",ebqflg); if (lscapu != 2) lscapu = ((x & lscapb) && lscapr && ebqflg) ? 1 : 0; debug(F101,"spar swcapr","",swcapr); debug(F101,"spar swcapu","",swcapu); debug(F101,"spar lscapu","",lscapu); /* Check whether there are additional CAPAS bytes. If so, this code doesn't know what's in them so it just skips past them to the next byte (if any), which should be the Window Slots field. CAPAS byte is continued if its low-order bit is 1. */ for (y = 10; (xunchar(s[y]) & 1) && (biggest >= y); y++); debug(F101,"spar y","",y); /* Position of WSLOTS byte */ } /* Now we have read and decoded the CAPAS byte; amend the maximum outbound packet size if a long-format max packet length given. */ debug(F101,">>> spar spsizf","",spsizf); /* SET RECEIVE PACKET-LENGTH */ debug(F101,">>> spar urpsiz","",urpsiz); /* value specified by user */ debug(F101,">>> spar biggest","",biggest); /* Position of last parameter */ debug(F101,">>> spar lpcapu","",lpcapu); /* Long-packet capability */ if (lpcapu) { /* If long packets have been negotiated.. */ int lpspsiz = spsiz; /* Max short packet size negotiated above */ debug(F101,">>> spar lpspsiz","",lpspsiz); if (biggest > y+1) { /* If MAXLX1-2 bytes are present */ x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]); /* Extended length */ debug(F101,">>> spar extended packet max length","",x); x -= 2; /* fdc 20220917 Safety margin for edge cases */ debug(F101,">>> spar previous with safety margin","",x); if (spsizf) { /* If overriding negotiations */ spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */ } else { /* otherwise */ spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */ } /* If a SET RECEIVE PACKET LENGTH x command was given, and: the size x is greater than what the receiver requested, then: the size becomes the receiver's requested size - 1, and: lpcapu (Long Packet capability was negotiated) is set to zero. - fdc 17 September 2022 */ if (rpsizf) { /* SET RECEIVE PACKET-LEN given? */ if (spsiz > urpsiz) { /* This packet > requested size? */ spsiz = urpsiz - 1; /* Set it to requested length */ debug(F101,">>> spar spsiz set to URPSIZ", "", spsiz); if (spsiz < 96) { /* If shorter than SP/LP cutoff */ lpcapu = 0; /* unset LP flag */ debug(F101,">>> spar lpcapu set to zero", "", lpcapu); } } } debug(F101,">>> spar adjusted according to spsizf","",spsiz); if (spsiz < 10) spsiz = 80; /* Be defensive... */ } } /* (PWP) save current send packet size for optimal packet size calcs */ spmax = spsiz; /* Maximum negotiated length */ lastspmax = spsiz; /* For stats */ if (slostart && spsiz > 499) /* Slow start length */ spsiz = 244; debug(F101,"spar slow-start spsiz","",spsiz); debug(F101,"spar lp spmax","",spmax); timint = chktimo(timint,timef); /* Recalculate the packet timeout */ /* Sliding Windows... */ if (swcapr) { /* Only if requested... */ if (biggest > y) { /* See what other Kermit says */ x = xunchar(s[y+1]); debug(F101,"spar window","",x); wslotn = (x > MAXWS) ? MAXWS : x; /* wslotn = negotiated size (from other Kermit's S or I packet). wslotr = requested window size (from this Kermit's SET WINDOW command). */ if (wslotn > wslotr) /* Use the smaller of the two */ wslotn = wslotr; if (wslotn < 1) /* Watch out for bad negotiation */ wslotn = 1; if (wslotn > 1) { swcapu = 1; /* We do windows... */ if (wslotn > maxtry) /* Retry limit must be greater */ maxtry = wslotn + 1; /* than window size. */ } debug(F101,"spar window after adjustment","",x); } else { /* No window size specified. */ wslotn = 1; /* We don't do windows... */ debug(F101,"spar window","",x); swcapu = 0; debug(F101,"spar no windows","",wslotn); } } /* Now recalculate packet length based on number of windows. */ /* The nogotiated number of window slots will be allocated, */ /* and the maximum packet length will be reduced if necessary, */ /* so that a windowful of packets can fit in the big buffer. */ if (wslotn > 1) { /* Shrink to fit... */ x = adjpkl(spmax,wslotn,bigsbsiz); if (x < spmax) { spmax = x; lastspmax = spsiz; if (slostart && spsiz > 499) spsiz = 244; /* Slow start again */ debug(F101,"spar sending, redefine spmax","",spmax); } } #ifdef WHATAMI debug(F101,"spar biggest","",biggest); if (biggest > y+7) { /* Get WHATAMI info if any */ whatru = xunchar(s[y+8]); debug(F101,"spar whatru","",whatru); } if (whatru & WMI_FLAG) { /* Only valid if this bit is set */ #ifdef STREAMING if (whatru & WMI_STREAM) { if (streamrq == SET_ON || (streamrq == SET_AUTO && (reliable == SET_ON || (reliable == SET_AUTO && !local) #ifdef TN_COMPORT && !istncomport() #endif /* TN_COMPORT */ #ifdef IKSD || inserver #endif /* IKSD */ ))) { streamok = 1; /* Streaming negotiated */ slostart = 0; /* Undo slow-start machinations */ spsiz = lastspmax; } } streamed = streamok; debug(F101,"spar streamok","",streamok); debug(F101,"spar clearrq","",clearrq); if (clearrq == SET_ON || (clearrq == SET_AUTO && ((network && nettype == NET_TCPB #ifdef RLOGCODE && ttnproto != NP_RLOGIN/* Rlogin is not clear */ && !(ttnproto >= NP_K4LOGIN && ttnproto <= NP_EK5LOGIN) #endif /* RLOGCODE */ #ifdef TN_COMPORT && !istncomport() #endif /* TN_COMPORT */ ) #ifdef SSHBUILTIN || (network && nettype == NET_SSH) #endif /* SSHBUILTIN */ #ifdef IKSD || inserver #endif /* IKSD */ ))) urclear = (whatru & WMI_CLEAR); debug(F101,"spar urclear","",urclear); #ifdef CK_SPEED if (urclear) setprefix(PX_NON); #endif /* CK_SPEED */ cleared = urclear; #endif /* STREAMING */ } #endif /* WHATAMI */ if (biggest > y+8) { /* Get WHOAREYOU info if any */ int x, z; x = xunchar(s[y+9]); /* Length of it */ z = y; y += (9 + x); debug(F101,"spar sysindex x","",x); debug(F101,"spar sysindex y","",y); debug(F101,"spar sysindex biggest","",biggest); if (x > 0 && x < 16 && biggest >= y) { strncpy(whoareu,(char *)s+z+10,x); /* Other Kermit's system ID */ debug(F111,"spar whoareyou",whoareu,whoareu[0]); if (whoareu[0]) { /* Got one? */ sysindex = getsysix((char *)whoareu); debug(F101,"spar sysindex",whoareu,sysindex); } } } else goto xspar; #ifdef WHATAMI y++; /* Advance pointer */ if (biggest >= y) { whatru2 = xunchar(s[y]); /* Next field is WHATAMI2 */ debug(F101,"spar whatru2","",whatru2); if (whatru2 & WMI2_FLAG) { /* Valid only if this bit is set */ if (server) { /* Server obeys client's xfer mode */ xfermode = (whatru2 & WMI2_XMODE) ? XMODE_M : XMODE_A; debug(F101,"spar whatru2 xfermode","",xfermode); } if (whatru2 & WMI2_RECU) { /* RECURSIVE transfer */ if (fnrpath == PATH_AUTO) { /* If REC PATH AUTO */ fnrpath = PATH_REL; /* Set it to RELATIVE */ autopath = 1; /* and remember we did this */ } } } } #endif /* WHATAMI */ xspar: if (sysindex > -1) { char * p; p = sysidlist[sysindex].sid_name; tlog(F110,"Remote system type: ",p,0L); if (sysindex > 0) { /* If partner's system type known */ whoarewe(); /* see if we are a match. */ #ifdef CK_SPEED /* Never unprefix XON and XOFF when sending to VMS */ debug(F111,"proto whoareu",whoareu,sysindex); if (!strcmp((char *)whoareu,"D7")) { debug(F111,"proto special VMS prefixing","",0); ctlp[XON] = ctlp[XOFF] = 1; ctlp[XON+128] = ctlp[XOFF+128] = 1; ctlp[3] = 1; /* Ctrl-C might be dangerous too */ ctlp[14] = ctlp[15] = 1; /* And SO/SI */ ctlp[24] = ctlp[25] = 1; /* And ^X/^Y */ ctlp[141] = 1; /* And CR+128 */ } #endif /* CK_SPEED */ } } /* Record parameters in debug log */ #ifdef DEBUG if (deblog) sdebu(biggest); #endif /* DEBUG */ numerrs = 0; /* Start counting errors here. */ return(0); } /* G N F I L E -- Get name of next file to send */ /* Expects global sndsrc to be: -9: if we are generating a file internally for calibration. -1: next filename to be obtained by calling znext(). 0: no next file name 1: (or greater) next filename to be obtained from **cmlist, or if addlist != 0, from the "filehead" linked list, or if filefile pointer not null from that file (which is already open). Returns: 1, with name of next file in filnam. 0, no more files, with filnam set to empty string. -1, file not found -2, file is not readable (but then we just skip to the next one if any) -3, read access denied -4, cancelled -5, too many files match wildcard -6, no files selected NOTE: If gnfile() returns 0, then the global variable gnferror should be checked to find out the most recent gnfile() error, and use that instead of the return code (for reasons too hard to explain). */ int gnfile() { int i = 0, x = 0; CK_OFF_T filesize = 0; int dodirstoo = 0; int retcode = 0; char fullname[CKMAXPATH+1]; dodirstoo = ((what & (W_FTP|W_SEND)) == (W_FTP|W_SEND)) && recursive; debug(F101,"gnfile sndsrc","",sndsrc); debug(F101,"gnfile filcnt","",filcnt); debug(F101,"gnfile what","",what); debug(F101,"gnfile recursive","",recursive); debug(F101,"gnfile dodirstoo","",dodirstoo); gnferror = 0; fsize = (CK_OFF_T)-1; /* Initialize file size */ fullname[0] = NUL; #ifdef VMS /* In VMS, zopeni() sets binary 0/1 automatically from the file attributes. Don't undo it here. */ debug(F101,"gnfile VMS binary","",binary); #else /* VMS */ if (!(what & W_REMO) && (xfermode == XMODE_A) #ifndef NOMSEND && !addlist #endif /* NOMSEND */ ) { extern int stdinf; if (!stdinf) /* Not if sending from stdin */ #ifdef WHATAMI /* We don't do this in server mode because it undoes WHATAMI */ if (!server || (server && ((whatru & WMI_FLAG) == 0))) #endif /* WHATAMI */ binary = gnf_binary; /* Restore prevailing transfer mode */ debug(F101,"gnfile binary = gnf_binary","",gnf_binary); } #endif /* VMS */ #ifdef PIPESEND debug(F101,"gnfile pipesend","",pipesend); if (pipesend) { /* First one */ if (filcnt == 0) { ckstrncpy(filnam,cmarg,CKMAXPATH+1); return(1); } else { /* There's only one... */ *filnam = NUL; pipesend = 0; return(0); } } #endif /* PIPESEND */ #ifdef CALIBRATE if (sndsrc == -9) { debug(F100,"gnfile calibrate","",0); ckstrncpy(filnam,"CALIBRATION",CKMAXPATH); nfils = 0; cal_j = 0; fsize = calibrate; sndsrc = 0; /* For next time */ nfils = 0; return(1); } #endif /* CALIBRATE */ #ifndef NOSPL if (sndarray) { /* Sending from an array */ extern char sndxnam[]; /* Pseudo filename */ debug(F100,"gnfile array","",0); nfils = 0; fsize = (CK_OFF_T)-1; /* Size unknown */ sndsrc = 0; ckstrncpy(filnam,sndxnam,CKMAXPATH); return(1); } #endif /* NOSPL */ if (sndsrc == 0) { /* It's not really a file */ if (nfils > 0) { /* It's a pipe, or stdin */ ckstrncpy(filnam,*cmlist,CKMAXPATH+1); /* Copy its "name" */ nfils = 0; /* There is no next file */ return(1); /* OK this time */ } else return(0); /* but not next time */ } /* If file group interruption (C-Z) occurred, fail. */ if (czseen) { tlog(F100,"Transaction cancelled","",0L); debug(F100,"gnfile czseen","",0); return(-4); } /* Loop through file list till we find a readable, sendable file */ filesize = (CK_OFF_T)-1; /* Loop exit (file size) variable */ while (filesize < 0) { /* Keep trying till we get one... */ retcode = 0; if (sndsrc > 0) { /* File list in cmlist or file */ if (filefile) { /* Reading list from file... */ if (zsinl(ZMFILE,filnam,CKMAXPATH) < 0) { /* Read a line */ zclose(ZMFILE); /* Failed */ debug(F110,"gnfile filefile EOF",filefile,0); makestr(&filefile,NULL); return(0); } debug(F110,"gnfile filefile filnam",filnam,0); } debug(F101,"gnfile nfils","",nfils); if (nfils-- > 0 || filefile) { /* Still some left? */ #ifndef NOMSEND if (addlist) { if (filenext && filenext->fl_name) { ckstrncpy(filnam,filenext->fl_name,CKMAXPATH+1); cmarg2 = filenext->fl_alias ? filenext->fl_alias : ""; binary = filenext->fl_mode; } else { printf("?Internal error expanding ADD list\n"); return(-5); } filenext = filenext->fl_next; debug(F111,"gnfile addlist filnam",filnam,nfils); } else if (sndsrc > 0 && !filefile) { #endif /* NOMSEND */ ckstrncpy(filnam,*cmlist++,CKMAXPATH+1); debug(F111,"gnfile cmlist filnam",filnam,nfils); #ifdef COMMENT /* BEGIN: NEW 6 August 2023 */ /* This doesn't work. Suppose the client said "get /recursive foo", where foo is a directory. It cd's to foo ok, but then there is no file list left. */ if (recursive && fileno == 1) { int itisadir = 0; itisadir = isdir(filnam); if (itisadir) { int x; debug(F111,"gnfile zchdir",filnam,itisadir); x = zchdir(fullname); debug(F111,"gnfile zchdir result",filnam,x); fileno = 0; ckstrncpy("*",*cmlist++,CKMAXPATH+1); continue; } } /* END: NEW 6 August 2023 */ #endif /* COMMENT */ #ifndef NOMSEND } #endif /* NOMSEND */ i = 0; #ifndef NOSERVER debug(F101,"gnfile ngetpath","",ngetpath); #endif /* NOSERVER */ nextinpath: #ifndef NOSERVER fromgetpath = 0; if (server && !isabsolute(filnam) && (ngetpath > i)) { ckstrncpy(fullname,getpath[i],CKMAXPATH+1); ckstrncat(fullname,filnam,CKMAXPATH); debug(F111,"gnfile getpath",fullname,i); fromgetpath = 1; i++; } else { i = ngetpath + 1; #else i = 1; /* ? */ #endif /* NOSERVER */ ckstrncpy(fullname,filnam,CKMAXPATH+1); debug(F110,"gnfile absolute",fullname,0); #ifndef NOSERVER } #endif /* NOSERVER */ if (iswild(fullname) #ifdef RECURSIVE || recursive > 0 || !strcmp(fullname,".") #endif /* RECURSIVE */ ) { /* It looks wild... */ /* First check if a file with this name exists */ debug(F110,"gnfile wild",fullname,0); if (zchki(fullname) >= 0) { /* Here we have a file whose name actually contains wildcard characters. */ goto gotnam; } #ifdef COMMENT nzxopts = ZX_FILONLY; /* (was 0: 25 Jul 2001 fdc) */ #else nzxopts = recursive ? 0 : ZX_FILONLY; /* 30 Jul 2001 */ #endif /* COMMENT */ if (nolinks) nzxopts |= ZX_NOLINKS; /* (26 Jul 2001 fdc) */ #ifdef UNIXOROSK if (matchdot) nzxopts |= ZX_MATCHDOT; #endif /* UNIXOROSK */ if (recursive) nzxopts |= ZX_RECURSE; x = nzxpand(fullname,nzxopts); /* Expand wildcards */ debug(F101,"gnfile nzxpand","",x); if (x == 1) { int xx; xx = znext(fullname); debug(F111,"gnfile znext A",fullname,xx); goto gotnam; } if (x == 0) { /* None match */ #ifndef NOSERVER if (server && ngetpath > i) goto nextinpath; #endif /* NOSERVER */ retcode = -1; debug(F101,"gnfile gnferror A","",gnferror); gnferror = -1; continue; } if (x < 0) { /* Too many to expand */ debug(F101,"gnfile gnferror B","",gnferror); gnferror = -5; return(-5); } sndsrc = -1; /* Change send-source to znext() */ } } else { /* We're out of files. */ debug(F111,"gnfile done",ckitoa(gnferror),nfils); *filnam = '\0'; return(0); } } /* Otherwise, step to next element of internal wildcard expansion list. */ if (sndsrc == -1) { int xx = 0; while (1) { debug(F111,"gnfile znext X",filnam,xx); xx = znext(filnam); debug(F111,"gnfile znext B",filnam,xx); if (!filnam[0]) break; if (dodirstoo) { debug(F111,"gnfile FTP MPUT /RECURSIVE",filnam,xx); break; } if (!isdir(filnam)) break; } debug(F111,"gnfile znext C",filnam,x); if (!filnam[0]) { /* If no more, */ sndsrc = 1; /* go back to previous list */ debug(F101,"gnfile setting sndsrc back","",sndsrc); continue; } else ckstrncpy(fullname,filnam,CKMAXPATH+1); } /* Get here with a filename. */ gotnam: debug(F110,"gnfile fullname",fullname,0); if (fullname[0]) { #ifdef DTILDE char * dirp = ""; if (fullname[0] == '~') { dirp = tilde_expand((char *)fullname); if (*dirp) ckstrncpy(fullname,dirp,CKMAXPATH+1); } #endif /* DTILDE */ filesize = zchki(fullname); /* Check if file readable */ debug(F111,"gnfile zchki",fullname,filesize); retcode = filesize; /* Possible return code */ if (filesize == (CK_OFF_T)-2 && dodirstoo) { filesize = 0; } if (filesize < 0) { gnferror = (int)filesize; debug(F101,"gnfile gnferror C","",gnferror); } if (filesize == (CK_OFF_T)-1) { /* If not found */ debug(F100,"gnfile -1","",0); #ifndef NOSERVER if (server && ngetpath > i) goto nextinpath; #endif /* NOSERVER */ debug(F110,"gnfile skipping:",fullname,0); tlog(F110,fullname,": open failure - skipped",0); xxscreen(SCR_FN,0,0l,fullname); xxscreen(SCR_ST,ST_SKIP,SKP_ACC,fullname); #ifdef TLOG if (tralog && !tlogfmt) doxlog(what,fullname,fsize,binary,1,"Skipped"); #endif /* TLOG */ continue; /* BEGIN: NEW 6 August 2023 */ } else if (filesize == (CK_OFF_T)-2) { /* It's a directory name */ if (recursive) { debug(F110,"gnfile zchdir",fullname,0); zchdir(fullname); return(-2); } /* END: NEW 6 August 2023 */ } else if (filesize < 0) { if (filesize == (CK_OFF_T)-3) { /* Exists but not readable */ debug(F100,"gnfile -3","",0); filrej++; /* Count this one as not sent */ tlog(F110,"Read access denied",fullname,0); /* Log this */ xxscreen(SCR_FN,0,0l,fullname); xxscreen(SCR_ST,ST_SKIP,SKP_ACC,fullname); /* Display it */ #ifdef TLOG if (tralog && !tlogfmt) doxlog(what,fullname,fsize,binary,1,"Skipped"); #endif /* TLOG */ } continue; } else { int xx; fsize = filesize; /* +++ */ debug(F111,"gnfile sndsmaller",ckfstoa(sndsmaller),sndsmaller); debug(F111,"gnfile sndlarger",ckfstoa(sndlarger),sndlarger); debug(F111,"gnfile (CK_OFF_T)-1",ckfstoa((CK_OFF_T)-1),(CK_OFF_T)-1); xx = fileselect(fullname, sndafter, sndbefore, sndnafter,sndnbefore, sndsmaller,sndlarger, skipbup, NSNDEXCEPT,sndexcept); debug(F111,"gnfile fileselect",fullname,xx); if (!xx) { filesize = (CK_OFF_T)-1; gnferror = -6; debug(F101,"gnfile gnferror D","",gnferror); continue; } ckstrncpy(filnam,fullname,CKMAXPATH+1); return(1); } #ifdef COMMENT /* This can't be right! */ } else { /* sndsrc is 0... */ if (!fileselect(fullname, sndafter, sndbefore, sndnafter,sndnbefore, sndsmaller,sndlarger, skipbup, NSNDEXCEPT,sndexcept)) { gnferror = -6; debug(F111,"gnfile fileselect",fullname,gnferror); filesize = (CK_OFF_T)-1; continue; } ckstrncpy(filnam,fullname,CKMAXPATH+1); return(1); #endif /* COMMENT */ } } debug(F101,"gnfile result","",retcode); *filnam = '\0'; return(0); } /* The following bunch of routines feed internally generated data to the server to send to the client in response to REMOTE commands like DIRECTORY, DELETE, and so on. We have to write these lines in the format appropriate to our platform, so they can be converted to generic (CRLF) text format by the packetizer. */ #ifdef UNIX char * endline = "\12"; #else #ifdef datageneral char * endline = "\12"; #else #ifdef MAC char * endline = "\15"; #else #ifdef OSK char * endline = "\15"; #else char * endline = "\15\12"; #endif /* OSK */ #endif /* MAC */ #endif /* datageneral */ #endif /* UNIX */ #ifdef MAC #define FNCBUFL 256 #else #ifdef CKSYMLINK #define FNCBUFL (CKMAXPATH + CKMAXPATH + 64) #else #define FNCBUFL (CKMAXPATH + 64) #endif /* CKSYMLINK */ #endif /* MAC */ /* NB: The minimum FNCBUFL is 255 */ static CHAR funcbuf[FNCBUFL]; static int funcnxt = 0; static int funclen = 0; static int nxpnd = -1; static long ndirs = 0; static long nfiles = 0; static CK_OFF_T nbytes = 0; int #ifdef CK_ANSIC sndstring( char * p ) #else sndstring(p) char * p; #endif /* CK_ANSIC */ { #ifndef NOSERVER nfils = 0; /* No files, no lists. */ xflg = 1; /* Flag we must send X packet. */ ckstrncpy(cmdstr,versio,CMDSTRL); /* Data for X packet. */ first = 1; /* Init getchx lookahead */ memstr = 1; /* Just set the flag. */ memptr = p; /* And the pointer. */ binary = XYFT_T; /* Text mode for this. */ return(sinit()); #else return(0); #endif /* NOSERVER */ } /* S N D H L P -- Routine to send builtin help */ static int srvhlpnum = 0; #ifdef IKSD static char *nmx[] = { "Disabled", "Disabled", "Enabled", "Enabled" }; #endif /* IKSD */ static char * #ifdef CK_ANSIC xnm( int x ) #else xnm(x) int x; #endif /* CK_ANSIC */ { #ifdef IKSD if (inserver) return(nmx[x]); else #endif /* IKSD */ return(nm[x]); } static int nxthlp( #ifdef CK_ANSIC void #endif /* CK_ANSIC */ ) { int x = 0; extern int en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai, en_pri, en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who, /* en_ret, */ en_mkd, en_rmd, en_asg, en_que, en_xit, x_login, x_logged, xfinish; extern char * ckxsys; if (funcnxt < funclen) return (funcbuf[funcnxt++]); switch (srvhlpnum++) { case 0: x = ckstrncpy((char *)funcbuf, "Client Command Status Description\n", FNCBUFL ); if (x_login && !x_logged) { x += ckstrncat((char *)funcbuf, " REMOTE LOGIN required\n", FNCBUFL ); } if (FNCBUFL - x > 74) sprintf((char *)(funcbuf+x)," GET %-14s%s\n", xnm(en_get), "Transfer file(s) from server to client." ); break; /* NOTE: The minimum funcbuf[] size is 255; all of the following are safe. */ case 1: sprintf((char *)funcbuf," SEND %-14s%s\n", xnm(en_sen), "Transfer file(s) from client to server." ); break; case 2: sprintf((char *)funcbuf," MAIL %-14s%s\n", xnm(inserver ? 0 : en_mai), "Send file(s) as e-mail." ); break; case 3: #ifndef NOSPL sprintf((char *)funcbuf," REMOTE ASSIGN %-14s%s\n", xnm(en_asg), "Assign value to server variable or macro." ); #else sprintf((char *)funcbuf," REMOTE ASSIGN not configured\n"); #endif /* NOSPL */ break; case 4: sprintf((char *)funcbuf," REMOTE CD %-14s%s\n", xnm(en_cwd), "Change server's directory." ); break; case 5: #ifdef ZCOPY sprintf((char *)funcbuf," REMOTE COPY %-14s%s\n", xnm(en_cpy), "Copy a file on the server." ); #else sprintf((char *)funcbuf," REMOTE COPY not configured\n"); #endif /* ZCOPY */ break; case 6: sprintf((char *)funcbuf," REMOTE DELETE %-14s%s\n", xnm(en_del), "Delete a file on the server." ); break; case 7: sprintf((char *)funcbuf," REMOTE DIRECTORY %-14s%s\n", xnm(en_dir), "List files on the server." ); break; case 8: sprintf((char *)funcbuf," REMOTE EXIT %-14s%s\n", xnm(en_xit), "Exit from Kermit server program." ); break; case 9: sprintf((char *)funcbuf," REMOTE HOST %-14s%s\n", xnm(inserver ? 0 : en_hos), #ifdef datageneral "Execute a CLI command on the server." #else #ifdef VMS "Execute a DCL command on the server." #else "Execute a shell command on the server." #endif /* VMS */ #endif /* datageneral */ ); break; case 10: sprintf((char *)funcbuf," REMOTE PRINT %-14s%s\n", xnm(inserver ? 0 : en_pri), "Send a file to the server for printing." ); break; case 11: #ifndef NOSPL sprintf((char *)funcbuf," REMOTE QUERY %-14s%s\n", xnm(en_que), "Get value of server variable or macro." ); #else sprintf((char *)funcbuf," REMOTE QUERY not configured\n"); #endif /* NOSPL */ break; case 12: sprintf((char *)funcbuf," REMOTE MKDIR %-14s%s\n", xnm(en_mkd), "Create a directory on the server." ); break; case 13: sprintf((char *)funcbuf," REMOTE RMDIR %-14s%s\n", xnm(en_rmd), "Remove a directory on the server." ); break; case 14: sprintf((char *)funcbuf," REMOTE RENAME %-14s%s\n", xnm(en_ren), "Rename a file on the server." ); break; case 15: sprintf((char *)funcbuf," REMOTE SET %-14s%s\n", xnm(en_set), "Set a parameter on the server" ); break; case 16: sprintf((char *)funcbuf," REMOTE SPACE %-14s%s\n", xnm(en_spa), "Inquire about disk space on the server." ); break; case 17: sprintf((char *)funcbuf," REMOTE TYPE %-14s%s\n", xnm(en_typ), "Display a server file on your screen." ); break; case 18: sprintf((char *)funcbuf," REMOTE WHO %-14s%s\n", xnm(inserver ? 0 : en_who), "List who is logged in to the server." ); break; case 19: sprintf((char *)funcbuf," FINISH %-14s%s\n", xnm(en_fin), xfinish ? "Exit from Kermit server program." : "Return the server to its command prompt." ); break; case 20: sprintf((char *)funcbuf," BYE %-14s%s\n\n", xnm(en_bye), "Log the server out and disconnect." ); break; default: return(-1); } funcnxt = 0; funclen = strlen((char *)funcbuf); return(funcbuf[funcnxt++]); } int sndhlp() { #ifndef NOSERVER extern char * ckxsys; first = 1; /* Init getchx lookahead */ nfils = 0; /* No files, no lists. */ xflg = 1; /* Flag we must send X packet. */ ckstrncpy(cmdstr,"REMOTE HELP",CMDSTRL); /* Data for X packet. */ sprintf((char *)funcbuf, "C-Kermit %s,%s\n\n", versio, ckxsys); funclen = strlen((char *)funcbuf); #ifdef IKSD if (inserver) { sprintf((char *)(funcbuf+funclen), "Internet Kermit Service\n\n"); funclen = strlen((char *)funcbuf); } #endif /* IKSD */ funcnxt = 0; funcptr = nxthlp; funcstr = 1; srvhlpnum = 0; binary = XYFT_T; /* Text mode for this. */ return(sinit()); #else return(0); #endif /* NOSERVER */ } static int srvstatusnum = 0; static int nxtstatus( #ifdef CK_ANSIC void #endif /* CK_ANSIC */ ) { extern char * ck_s_xver; char * filesize; int x = 0; if (funcnxt < funclen) return (funcbuf[funcnxt++]); switch (srvstatusnum++) { case 0: debug(F101,"nxtstatus case","",0); sprintf((char *)funcbuf, " OPEN SOURCE\n C-Kermit full version number: %s\n", ck_s_xver); break; case 1: { #ifdef TCPSOCKET extern char myipaddr[]; debug(F101,"nxtstatus case","",1); if (!myipaddr[0]) getlocalipaddr(); if (myipaddr[0]) { sprintf((char *)funcbuf," Hostname: %s (%s)\n", nvlook("host"), myipaddr); } else { #endif /* TCPSOCKET */ sprintf((char *)funcbuf," Hostname: %s\n", nvlook("host")); #ifdef TCPSOCKET } #endif /* TCPSOCKET */ break; } case 2: debug(F101,"nxtstatus case","",2); sprintf((char *)funcbuf," Server hardware: %s (%s bits)\n", nvlook("cpu"), nvlook("bits")); break; case 3: debug(F101,"nxtstatus case","",3); sprintf((char *)funcbuf," Server operating system family: %s\n", nvlook("system")); break; case 4: debug(F101,"nxtstatus case","",4); sprintf((char *)funcbuf," Current directory on server: %s\n", nvlook("directory")); break; case 5: /* Last file sent by server */ debug(F101,"nxtstatus case","",5); if (sfspec == NULL) { /* If there isn't one */ debug(F100,"nxtstatus no file sent yet","",0); sprintf((char *)funcbuf, " Last file sent by server: (none)\n"); } else { /* At least one */ CK_OFF_T z; /* Variable for file size */ z = zchki(sfspec); /* Get file size */ filesize = ckfstoa(z); /* convert to string for sprintf() */ /* Note: zfcdat gets the file date */ sprintf((char *)funcbuf, /* Send name, size, and date-time */ " Last file sent by server:\n %s %s %s\n", sfspec, filesize, zfcdat(sfspec)); debug(F100,"nxtstatus case 5 sprintf ok","",0); } break; case 6: /* Last file received by server */ debug(F101,"nxtstatus case","",6); if (rfspec == NULL) { /* If there isn't one */ debug(F100,"nxtstatus no file received yet","",0); sprintf((char *)funcbuf, " Last file received by server: (none)\n"); } else { /* At least one */ CK_OFF_T z; /* Variable for file size */ z = zchki(rfspec); /* Get file size */ filesize = ckfstoa(z); /* convert to string for sprintf() */ sprintf((char *)funcbuf, /* Send name, size, and date-time */ " Last file received by server:\n %s %s %s\n", rfspec, filesize, zfcdat(rfspec)); debug(F100,"nxtstatus case 6 sprintf ok","",0); } break; case 7: { debug(F101,"nxtstatus case","",7); #ifdef CKMAXNAM sprintf((char *)funcbuf, " Filename length limit: %d\n", CKMAXNAM); #else *funcbuf = '\0'; #endif /* def CKMAXNAM [else] */ break; } case 8: { debug(F101,"nxtstatus case","",8); #ifdef CKMAXPATH sprintf((char *)funcbuf, " Pathname length limit: %d\n\n", CKMAXPATH); #else *funcbuf = '\0'; #endif /* def CKMAXPATH [else] */ break; } default: return(-1); } funcnxt = 0; funclen = strlen((char *)funcbuf); return(funcbuf[funcnxt++]); } int sndstatus() { /* REMOTE STATUS handler */ #ifndef NOSERVER extern char * ckxsys; first = 1; /* Init getchx lookahead */ nfils = 0; /* No files, no lists. */ xflg = 1; /* Flag we must send X packet. */ ckstrncpy(cmdstr,"REMOTE STATUS",CMDSTRL); /* Data for X packet. */ sprintf((char *)funcbuf, "\n SERVER: %s,%s\n", versio, ckxsys); funclen = strlen((char *)funcbuf); #ifdef IKSD if (inserver) { sprintf((char *)(funcbuf+funclen), "Internet Kermit Service\n\n"); funclen = strlen((char *)funcbuf); } #endif /* IKSD */ funcstr = 1; /* Data input is from a function */ funcptr = nxtstatus; /* Name of the function is nxtstatus */ funcnxt = 0; /* and we start at the beginning */ srvstatusnum = 0; binary = XYFT_T; /* Use text mode for this. */ return(sinit()); #else return(0); #endif /* NOSERVER */ } /* Returns the next available character, -1 if no more data. */ static int nxttype( #ifdef CK_ANSIC void #endif /* CK_ANSIC */ ) { int c; if (zchin(ZIFILE,&c) < 0) { zclose(ZIFILE); return(-1); } else { return((unsigned)c); } } /* S N D T Y P -- TYPE a file to remote client */ int #ifdef CK_ANSIC sndtype( char * file ) #else sndtype(file) char * file; #endif /* CK_ANSIC */ { #ifndef NOSERVER char name[CKMAXPATH+1]; #ifdef OS2 char * p = NULL; if (*file) { ckstrncpy(name, file, CKMAXPATH+1); /* change / to \. */ p = name; while (*p) { /* Change them back to \ */ if (*p == '/') *p = '\\'; p++; } } else return(0); #else ckstrncpy(name, file, CKMAXPATH+1); #endif /* OS2 */ funcnxt = 0; funclen = strlen((char *)funcbuf); if (zchki(name) == -2) { /* Found a directory */ return(0); } if (!zopeni(ZIFILE,name)) return(0); nfils = 0; /* No files, no lists. */ xflg = 1; /* Flag we must send X packet. */ ckstrncpy(cmdstr,"type",CMDSTRL); /* Data for X packet. */ first = 1; /* Init getchx lookahead */ funcstr = 1; /* Just set the flag. */ funcptr = nxttype; /* And the pointer. */ binary = XYFT_T; /* Text mode for this */ return(sinit()); #else return(0); #endif /* NOSERVER */ } /* N X T D I R -- Provide data for senddir() Returns the next available character or -1 if no more data. */ #ifndef NOICP /* Directory listing parameters set by the user interface, if any. */ extern int dir_head, dir_dots, dir_back; #endif /* NOICP */ static int sd_hdg, sd_bkp, sd_dot; /* Local listing parameters */ static int nxtdir( #ifdef CK_ANSIC void #endif /* CK_ANSIC */ ) { char name[CKMAXPATH+1], dbuf[24], *p = NULL; char *dstr = NULL, * lnk = ""; CHAR c, * linebuf = funcbuf; #ifdef OSK /* Work around bugs in OSK compiler */ char *dirtag = "directories"; char *filetag = "files"; char *bytetag = "bytes"; #endif /* OSK */ CK_OFF_T len = 0; int x, itsadir = 0, gotone = 0; #ifdef DEBUG if (deblog) { debug(F101,"nxtdir funcnxt","",funcnxt); debug(F101,"nxtdir funclen","",funclen); debug(F110,"nxtdir funcbuf",funcbuf+funcnxt,0); } #endif /* DEBUG */ if (funcnxt < funclen) { /* Return next character from buffer */ c = funcbuf[funcnxt++]; debug(F000,"nxtdir return 1","",(unsigned)(c & 0xff)); return((unsigned)(c & 0xff)); } while (nxpnd > 0) { /* Buffer needs refill */ nxpnd--; znext(name); /* Get next filename */ if (!name[0]) { /* None left - done */ nxpnd = 0; return(nxtdir()); } if (sd_bkp) { /* Showing backup files? */ gotone = 1; /* Yes, no need to check. */ break; } x = ckmatch( /* No - see if this is one */ #ifdef CKREGEX "*.~[0-9]*~" /* Not perfect but close enough. */ #else "*.~*~" /* Less close. */ #endif /* CKREGEX */ ,name,filecase,1); debug(F111,"nxtdir ckmatch",name,x); if (x) { continue; /* It's a backup file - skip it */ } else { gotone = 1; /* It's not, break from loop. */ break; } } if (gotone) { len = zgetfs(name); /* Get file size */ debug(F111,"nxtdir zgetfs",name,len); #ifdef VMSORUNIX itsadir = zgfs_dir; /* See if it's a directory */ #else itsadir = (len == -2 || isdir(name)); #endif /* VMSORUNIX */ dstr = zfcdat(name); debug(F111,"nxtdir zcfdat",dstr,0); if (!dstr) dstr = "0000-00-00 00:00:00"; if (!*dstr) { dstr = "0000-00-00 00:00:00"; } else { dbuf[0] = dstr[0]; dbuf[1] = dstr[1]; dbuf[2] = dstr[2]; dbuf[3] = dstr[3]; dbuf[4] = '-'; dbuf[5] = dstr[4]; dbuf[6] = dstr[5]; dbuf[7] = '-'; dbuf[8] = dstr[6]; dbuf[9] = dstr[7]; strcpy(dbuf+10,dstr+8); dstr = dbuf; } #ifdef CK_PERMS #ifdef VMSORUNIX p = ziperm(name); /* Get permissions */ #else p = zgperm(name); #endif /* VMSORUNIX */ #else p = NULL; #endif /* CK_PERMS */ debug(F110,"domydir perms",p,0); #ifdef VMS /* Make name relative */ ckstrncpy(name,zrelname(name,zgtdir()),CKMAXPATH+1); #endif /* VMS */ if (itsadir) { ndirs++; } else { nfiles++; nbytes += len; } lnk = ""; #ifdef UNIX #ifdef CKSYMLINK if (zgfs_link) { extern char linkname[]; lnk = linkname; } debug(F111,"nxtdir linkname",lnk,zgfs_link); #endif /* CKSYMLINK */ #endif /* UNIX */ /* The following sprintf's are safe; linebuf is a pointer to funcbuf, which is 64 bytes larger than CKMAXPATH (or double CKMAXPATH when symlinks are possible). 64 allows for the fixed-field portions of the file listing line: permissions, size, and date. CKMAXPATH allows for the longest possible pathname. */ if (itsadir && len < 0) { /* Directory */ #ifdef VMS sprintf((char *)linebuf, "%-22s%-10s %s %s\n",p,"",dstr,name); #else if (p) sprintf((char *)linebuf, "%10s%-10s %s %s\n",p,"",dstr,name); else sprintf((char *)linebuf, "%-10s %s %s\n", "", dstr, name); #endif /* VMS */ } else { /* Regular file */ #ifdef VMS sprintf((char *)linebuf, "%-22s%10s %s %s\n", p, ckfstoa(len), dstr, name); #else if (p) sprintf((char *)linebuf, "%10s%10s %s %s%s%s\n", p, ckfstoa(len), dstr, name, *lnk ? " -> " : "", lnk ); else sprintf((char *)linebuf, "%10s %s %s%s%s\n", ckfstoa(len), dstr, name, *lnk ? " -> " : "", lnk ); #endif /* VMS */ } funcnxt = 0; funclen = strlen((char *)funcbuf); } else if (sd_hdg && nxpnd == 0) { /* Done, send summary */ char *blankline = ""; /* At beginning of summary */ /* The idea is to prevent (a) unnecessary multiple blanklines, and (b) prompt-stomping. Preventing (b) is practically impossible, because it depends on the client so for now always include that final CRLF. */ if (!ndirs || !nbytes || !nfiles) blankline = endline; #ifdef OSK /* Workaround bugs in OS-9 compiler... */ if (ndirs == 1) dirtag = "directory"; if (nfiles == 1) filetag = "file"; if (nbytes == (CK_OFF_T)1) bytetag = "byte"; sprintf((char *)funcbuf, "%sSummary: %ld %s, %ld %s, %s %s%s", blankline, ndirs, dirtag, nfiles, filetag, ckfstoa(nbytes), bytetag, endline); #else sprintf((char *)funcbuf, "%sSummary: %ld director%s, %ld file%s, %s byte%s%s", blankline, ndirs, (ndirs == 1) ? "y" : "ies", nfiles, (nfiles == 1) ? "" : "s", ckfstoa(nbytes), (nbytes == (CK_OFF_T)1) ? "" : "s", endline ); #endif /* OSK */ nxpnd--; funcnxt = 0; funclen = strlen((char *)funcbuf); } else { funcbuf[0] = '\0'; funcnxt = 0; funclen = 0; } debug(F101,"nxtdir funclen","",funclen); if (funcnxt < funclen) { /* If we have data to send... */ c = funcbuf[funcnxt++]; debug(F000,"nxtdir return 2","",(unsigned)(c & 0xff)); return((unsigned)(c & 0xff)); } else return(-1); /* Nothing left, done. */ } /* S N D D I R -- send directory listing */ int #ifdef CK_ANSIC snddir( char * spec ) #else snddir(spec) char * spec; #endif /* CK_ANSIC */ { #ifndef NOSERVER char * p = NULL, name[CKMAXPATH+1]; int rc = 0; char fnbuf[CKMAXPATH+1]; debug(F111,"snddir matchdot",spec,matchdot); #ifndef NOICP debug(F111,"snddir dir_dots",spec,dir_dots); sd_hdg = dir_head > 0; /* Import listing parameters if any */ sd_bkp = dir_back > 0; if (dir_dots > -1) sd_dot = dir_dots; else sd_dot = matchdot; #else sd_hdg = 1; /* Or use hardwired defaults */ sd_bkp = 1; sd_dot = matchdot; #endif /* NOICP */ if (!spec) spec = ""; debug(F111,"snddir sd_dot",spec,sd_dot); if (*spec) { #ifdef COMMENT zfnqfp(spec,CKMAXPATH,name); debug(F110,"snddir zfnqfp",name,0); #else ckstrncpy(name,spec,CKMAXPATH+1); debug(F110,"snddir name",name,0); #endif /* COMMENT */ } else { #ifdef OS2 strcpy(name, "*"); #else #ifdef UNIXOROSK strcpy(name, "./*"); #else #ifdef VMS strcpy(name, "*.*"); #else #ifdef datageneral strcpy(name, "+"); #else debug(F101,"snddir quit (no filespec)","",0); return(0); #endif /* datageneral */ #endif /* VMS */ #endif /* UNIX */ #endif /* OS2 */ } debug(F110,"snddir name 1",name,0); ndirs = 0L; nfiles = 0L; nbytes = (CK_OFF_T)0; if (zfnqfp(name,CKMAXPATH,fnbuf)) debug(F110,"snddir name 2",name,0); p = name + strlen(name); /* Move it to end of list */ /* sprintf safe because funcbuf size >= max path len + 64 */ if (sd_hdg) { sprintf((char *)funcbuf,"Listing files: %s%s%s",fnbuf,endline,endline); funcnxt = 0; funclen = strlen((char *)funcbuf); } diractive = 1; #ifdef OS2 if (zchki(name) == -2) { /* Found a directory */ p--; if (*p == '\\' || *p == '/') ckstrncat(name, "*", CKMAXPATH); else if (*p == ':') ckstrncat(name, ".", CKMAXPATH); else ckstrncat(name, "\\*", CKMAXPATH); debug(F110,"snddir directory",name,0); } #else if (!iswild(name) && isdir(name)) { char * s = name; p--; #ifdef UNIXOROSK if (*p == '/') /* So append wildcard to it */ ckstrncat(s, "*", CKMAXPATH); else ckstrncat(s, "/*", CKMAXPATH); #else #ifdef VMS if (*p == ']' || *p == '>' || *p == ':') ckstrncat(s, "*.*", CKMAXPATH); #else #ifdef datageneral if (*p == ':') ckstrncat(s, "+", CKMAXPATH); else ckstrncat(s, ":+", CKMAXPATH); #else #ifdef VOS if (*p == '>') ckstrncat(s, "*", CKMAXPATH); else ckstrncat(s, ">*", CKMAXPATH); #endif /* VOS */ #endif /* datageneral */ #endif /* VMS */ #endif /* UNIXOROSK */ debug(F110,"snddir directory",name,0); } #endif /* OS2 */ nzxopts = 0; #ifdef UNIX { extern char ** mtchs; debug(F111,"snddir sd_dot",spec,sd_dot); if (sd_dot > 0) nzxopts |= ZX_MATCHDOT; if (recursive) nzxopts |= ZX_RECURSE; debug(F111,"snddir nzxopts",spec,nzxopts); nxpnd = nzxpand(name,nzxopts); /* Get the array of names */ sh_sort(mtchs,NULL,nxpnd,0,0,1); /* Sort the array */ } #else if (recursive) nzxopts |= ZX_RECURSE; nxpnd = nzxpand(name,nzxopts); #endif /* UNIX */ debug(F101,"snddir nzxpand nxpnd","",nxpnd); if (nxpnd < 1) return(-1); nfils = 0; /* No files, no lists. */ xflg = 1; /* Flag we must send X packet. */ #ifndef V7MIN /* get scary warning even though it's 100% safe */ if ((int)strlen(name) < CMDSTRL - 11) /* Data for X packet. */ sprintf(cmdstr,"DIRECTORY %s",name); /* safe */ else #endif /* V7MIN */ ckstrncpy(cmdstr,"DIRECTORY",CMDSTRL); first = 1; /* Init getchx lookahead */ funcstr = 1; /* Just set the flag. */ funcptr = nxtdir; /* And the pointer. */ binary = XYFT_T; /* Text mode for this */ rc = sinit(); /* 26 Aug 2005 */ debug(F111,"snddir","sinit()",rc); return(rc); #else return(0); #endif /* NOSERVER */ } /* N X T D E L -- provide data for delete */ /* Returns the next available character or -1 if no more data */ static int nxtdel( #ifdef CK_ANSIC void #endif /* CK_ANSIC */ ) { char name[257], *p = NULL; int len = 0; if (funcnxt < funclen) return ((unsigned)funcbuf[funcnxt++]); if (nxpnd > 0) { nxpnd--; znext(name); if (!name[0]) { nxpnd = 0; return(nxtdel()); } len = zchki(name); /* Find just the name of the file */ for (p = name + strlen(name); p != name && *p != '/' ; p--) ; if (*p == '/') p++; /* sprintf's safe because size of funcbuf >= 64 + maxpathlen */ if (len > -1L) { if (zdelet(name)) { sprintf((char *)funcbuf," %10s: %s%s","skipping",p,endline); } else { nfiles++; nbytes += len; sprintf((char *)funcbuf," %10s: %s%s","deleted",p,endline); } } else sprintf((char *)funcbuf," directory: %s%s", p, endline); funcnxt = 0; funclen = strlen((char *)funcbuf); } else /* If done processing the expanded entries send a summary statement */ if (nxpnd == 0) { sprintf((char *)funcbuf, "%s%ld file%s deleted, %s byte%s freed%s", endline, nfiles, (nfiles == 1) ? "" : "s", ckfstoa(nbytes), (nbytes == (CK_OFF_T)1) ? "" : "s", endline ); nxpnd--; funcnxt = 0; funclen = strlen((char *)funcbuf); } else { funcbuf[0] = '\0'; funcnxt = 0; funclen = 0; } /* If we have data to send */ if (funcnxt < funclen) return ((unsigned)funcbuf[funcnxt++]); /* Return a character */ else return(-1); /* No more input */ } /* S N D D E L -- Send delete message */ int #ifdef CK_ANSIC snddel( char * spec ) #else snddel(spec) char * spec; #endif /* CK_ANSIC */ { #ifndef NOSERVER char name[CKMAXPATH+1]; #ifdef OS2 char * p = NULL; #endif /* #ifdef OS2 */ if (!*spec) return(0); ckstrncpy(name, spec, CKMAXPATH+1); #ifdef OS2 /* change / to \. */ p = name; while (*p) { /* Change them back to \ */ if (*p == '/') *p = '\\'; p++; } #endif /* OS2 */ nfiles = 0L; nbytes = (CK_OFF_T)0; sprintf((char *)funcbuf,"Deleting \"%s\"%s",name,endline); funcnxt = 0; funclen = strlen((char *)funcbuf); nzxopts = ZX_FILONLY; /* Files only */ #ifdef UNIXOROSK if (matchdot) nzxopts |= ZX_MATCHDOT; #endif /* UNIXOROSK */ #ifdef COMMENT /* Recursive deleting not supported yet */ if (recursive) nzxopts |= ZX_RECURSE; #endif /* COMMENT */ nxpnd = nzxpand(name,nzxopts); if (nxpnd < 1) return(-1); nfils = 0; /* No files, no lists. */ xflg = 1; /* Flag we must send X packet. */ ckstrncpy(cmdstr,"REMOTE DELETE",CMDSTRL); /* Data for X packet. */ first = 1; /* Init getchx lookahead */ funcstr = 1; /* Just set the flag. */ funcptr = nxtdel; /* And the pointer. */ binary = XYFT_T; /* Use text mode for this, */ return(sinit()); #else return(0); #endif /* NOSERVER */ } #ifdef OS2 /* S N D S P A C E -- send disk space message */ int sndspace(drive) int drive; { #ifndef NOSERVER static char spctext[64]; CK_OFF_T space; if (drive) { space = zdskspace(drive - 'A' + 1); if (space > 0 && space < 1024) sprintf(spctext, " Drive %c: unknown%s", drive, endline ); else sprintf(spctext, " Drive %c: %ldK free%s", drive, space / 1024L, endline ); } else { space = zdskspace(0); if (space > 0 && space < 1024) sprintf(spctext, " Free space: unknown%s", endline); else sprintf(spctext, " Free space: %ldK%s", space / 1024L, endline); } nfils = 0; /* No files, no lists. */ xflg = 1; /* Flag we must send X packet. */ ckstrncpy(cmdstr,"free space",CMDSTRL); /* Data for X packet. */ first = 1; /* Init getchx lookahead */ memstr = 1; /* Just set the flag. */ memptr = spctext; /* And the pointer. */ binary = XYFT_T; /* Text mode for this. */ return(sinit()); #else return(0); #endif /* NOSERVER */ } /* S N D W H O -- send who message */ int sndwho(who) char * who; { #ifndef NOSERVER nfils = 0; /* No files, no lists. */ xflg = 1; /* Flag we must send X packet. */ ckstrncpy(cmdstr,"who",CMDSTRL); /* Data for X packet. */ first = 1; /* Init getchx lookahead */ memstr = 1; /* Just set the flag. */ #ifdef NT memptr = "\15\12K95 SERVER\15\12"; /* And the pointer. */ #else memptr = "\15\12K/2 SERVER\15\12"; #endif /* NT */ binary = XYFT_T; /* Use text mode */ return(sinit()); #else return(0); #endif /* NOSERVER */ } #endif /* OS2 */ /* C W D -- Change server's working directory */ /* String passed has first byte as length of directory name, rest of string is name. Returns: 0 on failure. 1 on success after sending short-form response (ACK with name). 2 on success if a CD Message file is to be sent. */ int #ifdef CK_ANSIC cwd( char *vdir ) #else cwd(vdir) char *vdir; #endif /* CK_ANSIC */ { char *cdd, *dirp; vdir[xunchar(*vdir) + 1] = '\0'; /* Terminate string with a null */ dirp = vdir+1; tlog(F110,"Directory requested: ",dirp,0L); if (zchdir(dirp)) { /* Try to change */ cdd = zgtdir(); /* Get new working directory. */ debug(F110,"cwd",cdd,0); if (srvcdmsg) { /* Send orientation file? */ int i; for (i = 0; i < 8; i++) { if (zchki(cdmsgfile[i]) > -1) { xxscreen(SCR_CD,0,0l,cdd); tlog(F110,"Changed directory to",cdd,0L); return(2); } } } encstr((CHAR *)cdd); /* Send short-form reply */ ack1(data); /* containing directory name. */ xxscreen(SCR_CD,0,0l,cdd); tlog(F110,"Changed directory to",cdd,0L); return(1); } else { debug(F110,"cwd failed",dirp,0); tlog(F110,"Failed to change directory to",dirp,0L); return(0); } } /* S Y S C M D -- Do a system command */ /* Command string is formed by concatenating the two arguments. */ int #ifdef CK_ANSIC syscmd( char *prefix, char *suffix ) #else syscmd(prefix,suffix) char *prefix, *suffix; #endif /* CK_ANSIC */ { extern int i_isopen; #ifndef NOPUSH char *cp; i_isopen = 0; if (!prefix) return(0); if (!*prefix) return(0); for (cp = cmdstr; *prefix != '\0'; (*cp++ = *prefix++)); while ((*cp++ = *suffix++)) #ifdef OS2 /* This takes away more than we gain in convenience if (*(cp-1) == '/') *(cp-1) = '\\' */ #endif /* OS2 */ ; /* Copy suffix */ debug(F110,"syscmd",cmdstr,0); if (zxcmd(ZIFILE,cmdstr) > 0) { debug(F110,"syscmd zxcmd ok",cmdstr,0); nfils = sndsrc = 0; /* Flag that input is from stdin */ xflg = hcflg = 1; /* And special flags for pipe */ binary = XYFT_T; /* Go to text mode */ i_isopen = 1; return (sinit()); /* Send S packet */ } else { debug(F100,"syscmd zxcmd failed",cmdstr,0); i_isopen = 0; return(0); } #else debug(F100,"syscmd zxcmd NOPUSH",cmdstr,0); i_isopen = 0; return(0); #endif /* NOPUSH */ } /* R E M S E T -- Remote Set */ /* Called by server to set variables as commanded in REMOTE SET packets. */ /* Returns 1 on success, 0 on failure. */ int #ifdef CK_ANSIC remset( char *s ) #else remset(s) char *s; #endif /* CK_ANSIC */ { extern int c_save, en_del; int len, x, y; char *p; len = xunchar(*s++); /* Length of first field */ p = s + len; /* Pointer to second length field */ *p++ = '\0'; /* Zero out second length field */ x = atoi(s); /* Value of first field */ debug(F111,"remset",s,x); debug(F110,"remset",p,0); switch (x) { /* Do the right thing */ case 132: /* Attributes (all, in) */ atcapr = atoi(p); return(1); case 133: /* File length attributes */ case 233: /* IN/OUT combined */ case 148: /* Both kinds of lengths */ case 248: atleni = atleno = atoi(p); return(1); case 134: /* File Type (text/binary) */ case 234: attypi = attypo = atoi(p); return(1); case 135: /* File creation date */ case 235: atdati = atdato = atoi(p); return(1); case 139: /* File Blocksize */ case 239: atblki = atblko = atoi(p); return(1); case 141: /* Encoding / Character Set */ case 241: atenci = atenco = atoi(p); return(1); case 142: /* Disposition */ case 242: atdisi = atdiso = atoi(p); return(1); case 145: /* System ID */ case 245: atsidi = atsido = atoi(p); return(1); case 147: /* System-Dependent Info */ case 247: atsysi = atsyso = atoi(p); return(1); case 232: /* Attributes (all, out) */ atcapr = atoi(p); return(1); case 300: /* File type (text, binary) */ binary = atoi(p); b_save = binary; #ifndef NOICP g_binary = -1; #endif /* NOICP */ return(1); case 301: /* File name conversion */ fncnv = 1 - atoi(p); /* (oops) */ f_save = fncnv; #ifndef NOICP g_fncnv = -1; #endif /* NOICP */ return(1); case 302: /* File name collision */ #ifdef IKSD #ifdef CK_LOGIN if (inserver && isguest) /* May not be changed by guest */ return(0); #endif /* CK_LOGIN */ #endif /* IKSD */ x = atoi(p); if (!ENABLED(en_del) && (x == XYFX_X || x == XYFX_U)) return(0); if (x == XYFX_R) ckwarn = 1; /* Rename */ if (x == XYFX_X) ckwarn = 0; /* Replace */ fncact = x; return(1); case 310: /* Incomplete File Disposition */ keep = atoi(p); /* Keep, Discard, Auto */ return(1); case 311: /* Blocksize */ fblksiz = atoi(p); return(1); case 312: /* Record Length */ frecl = atoi(p); return(1); case 313: /* Record format */ frecfm = atoi(p); return(1); case 314: /* File organization */ forg = atoi(p); return(1); case 315: /* File carriage control */ fcctrl = atoi(p); return(1); case 330: /* Match dotfiles */ #ifndef NOICP dir_dots = -1; /* This undoes DIR /DOT option */ #endif /* NOICP */ matchdot = atoi(p); return(1); case 331: /* Match FIFOs */ matchfifo = atoi(p); return(1); case 400: /* Block check */ y = atoi(p); if (y < 5 && y > 0) { bctr = y; c_save = -1; return(1); } else if (*p == 'B') { bctr = 4; c_save = -1; return(1); } else if (*p == '5') { bctr = 3; c_save = -1; return(1); } return(0); case 401: /* Receive packet-length */ rpsiz = urpsiz = atoi(p); if (urpsiz > MAXRP) urpsiz = MAXRP; /* Max long-packet length */ if (rpsiz > 94) rpsiz = 94; /* Max short-packet length */ urpsiz = adjpkl(urpsiz,wslots,bigrbsiz); return(1); case 402: /* Receive timeout */ y = atoi(p); /* Client is telling us */ if (y > -1 && y < 999) { /* the timeout that it wants */ pkttim = chktimo(y,timef); /* us to tell it to use. */ return(1); } else return(0); case 403: /* Retry limit */ y = atoi(p); if (y > -1 && y < 95) { maxtry = y; return(1); } else return(0); case 404: /* Server timeout */ y = atoi(p); if (y < 0) return(0); srvtim = y; return(1); #ifndef NOCSETS case 405: { /* Transfer character set */ extern int s_cset, axcset[]; int i; for (i = 0; i < ntcsets; i++) { if (!strcmp(tcsinfo[i].designator,p)) break; } debug(F101,"remset tcharset lookup","",i); if (i == ntcsets) return(0); tcharset = tcsinfo[i].code; /* If known, use it */ debug(F101,"remset tcharset","",tcharset); if (s_cset == XMODE_A) if (axcset[tcharset] > -1 && axcset[tcharset] > MAXFCSETS) fcharset = axcset[tcharset]; /* Auto-pick file charset */ debug(F101,"remset tcharset fcharset","",fcharset); setxlatype(tcharset,fcharset); /* Set up charset translations */ debug(F101,"remset xlatype","",xlatype); debug(F101,"remset tcharset after setxlatype","",tcharset); tcs_save = -1; return(1); } case 320: { /* File character set */ extern struct keytab fcstab[]; extern int nfilc, s_cset, r_cset; x = lookup(fcstab,p,nfilc,&y); debug(F111,"RSET FILE CHAR name",p,x); if (x < 0) return(0); s_cset = XMODE_M; /* No automatic charset switching */ r_cset = XMODE_M; fcharset = x; /* Set file charset */ setxlatype(tcharset,fcharset); /* and translation type */ fcs_save = -1; return(1); } #endif /* NOCSETS */ case 406: /* Window slots */ y = atoi(p); if (y == 0) y = 1; if (y < 1 || y > MAXWS) return(0); wslotr = y; swcapr = 1; urpsiz = adjpkl(urpsiz,wslotr,bigrbsiz); return(1); case 410: /* Transfer mode */ y = atoi(p); /* 0 = automatic, nonzero = manual */ if (y != 0) y = 1; xfermode = y; debug(F101,"REMOTE SET xfermode","",xfermode); return(1); case 420: /* SERVER CD-MESSAGE { ON, OFF } */ y = atoi(p); /* 0 = automatic, nonzero = manual */ srvcdmsg = y; return(1); default: /* Anything else... */ return(0); } } /* Adjust packet length based on number of window slots and buffer size */ int #ifdef CK_ANSIC adjpkl( int pktlen, int slots, int bufsiz ) #else adjpkl(pktlen,slots,bufsiz) int pktlen, slots, bufsiz; #endif /* CK_ANSIC */ { if (protocol != PROTO_K) return(pktlen); debug(F101,"adjpkl len","",pktlen); debug(F101,"adjpkl slots","",slots); debug(F101,"adjpkl bufsiz","",bufsiz); if (((pktlen + 6) * slots) > bufsiz) pktlen = (bufsiz / slots) - 6; debug(F101,"adjpkl new len","",pktlen); return(pktlen); } /* Set transfer mode and file naming based on comparison of system types */ VOID whoarewe() { #ifndef NOICP extern int g_xfermode; #endif /* NOICP */ wearealike = 0; debug(F101,"whoarewe xfermode","",xfermode); #ifndef NOICP debug(F101,"whoarewe g_xfermode","",g_xfermode); #endif /* NOICP */ if (whoareu[0]) { /* If we know partner's system type */ char * p = (char *)whoareu; debug(F110,"whoarewe remote sysid",whoareu,0); if (!strcmp(p,cksysid)) /* Other system same as us */ wearealike = 1; #ifdef UNIX else if (!strcmp(p,"L3")) /* UNIX is sort of like AmigaDOS */ wearealike = 1; /* (same directory separator) */ else if (!strcmp(p,"N3")) /* UNIX like Aegis */ wearealike = 1; #else #ifdef AMIGA /* Like UNIX, but case distinctions are ignored and can begin with device:. */ else if (!strcmp(p,"U1")) /* Amiga is sort of like UNIX */ wearealike = 1; else if (!strcmp(p,"N3")) /* Amiga is sort of like Aegis */ wearealike = 1; #else #ifdef OS2 /* (Includes Windows 95/NT) */ /* DOS, GEMDOS, Windows 3.x, Windows 95, Windows NT */ /* All "the same" for FAT partitions but all bets off otherwise */ /* so this part needs some refinement ... */ else if (!strcmp(p,"U8")) /* MS-DOS */ wearealike = 1; else if (!strcmp(p,"UO")) /* OS/2 */ wearealike = 1; else if (!strcmp(p,"UN")) /* Windows NT or 95 */ wearealike = 1; else if (!strcmp(p,"K2")) /* GEMDOS */ wearealike = 1; #else #ifdef GEMDOS else if (!strcmp(p,"U8")) wearealike = 1; else if (!strcmp(p,"UO")) wearealike = 1; else if (!strcmp(p,"UN")) wearealike = 1; else if (!strcmp(p,"K2")) wearealike = 1; #endif /* GEMDOS */ #endif /* OS2 */ #endif /* AMIGA */ #endif /* UNIX */ /* Get here with wearealike == 1 if system types match */ debug(F101,"whoarewe wearealike","",wearealike); if (!wearealike) /* Not alike */ return; fncnv = XYFN_L; /* Alike, so literal filenames */ debug(F101,"whoarewe setting fncnv","",fncnv); if (xfermode == XMODE_A) { /* Current xfer mode is auto */ #ifdef VMS binary = XYFT_L; /* For VMS-to-VMS, use labeled */ #else #ifdef OS2 /* OS/2 but not Windows */ if (!strcmp(cksysid,"UO") && !strcmp((char *)whoareu,"UO")) binary = XYFT_L; /* For OS/2-to-OS/2, use labeled */ #else binary = XYFT_B; /* For all others use binary */ #endif /* OS2 */ #endif /* VMS */ gnf_binary = binary; /* Prevailing type for gnfile() */ debug(F101,"whoarewe setting binary","",binary); } } } #endif /* NOXFER */ ckcftp.c000664 045065 024037 00002153771 14767402355 012636 0ustar00fdckermit000000 000000 #define FTP_TIMEOUT /* C K C F T P -- FTP Client for C-Kermit */ char *ckftpv = "FTP Client, 10.0.281, 18 Sep 2023"; /* Authors: Jeffrey E Altman Secure Endpoints Inc., New York City Frank da Cruz , The Kermit Project, Columbia University. David Goodwin, New Zealand Copyright (C) 2000, 2023 Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Portions of conditionally included code Copyright Regents of the University of California and The Stanford SRP Authentication Project; see notices below. */ /* Pending... . Implement recursive NLST downloads by trying to CD to each filename. If it works, it's a directory; if not, it's a file -- GET it. But that won't work with servers like wu-ftpd that don't send directory names. Recursion with MLSD is done. . Make syslog entries for session? Files? . Messages are printed to stdout and stderr in random fashion. We should either print everything to stdout, or else be systematic about when to use stderr. . Implement mail (MAIL, MLFL, MSOM, etc) if any servers support it. . Adapt to VMS. Big job because of its record-oriented file system. RMS programmer required. There are probably also some VMS TCP/IP product-specific wrinkles, e.g. attribute preservation in VMS-to-VMS transfers using special options for Multinet or other FTP servers (find out about STRU VMS). */ /* Quick FTP command reference: RFC765 (1980) and earlier: MODE S(tream), B(lock), C(ompressed) STRU F(ILE), R(ECORD), P(AGE) TYPE A(SCII) , E(BCDIC) , I(MAGE), L(OCAL) PORT - Port PASV - Passive mode USER - User PASS - Password ACCT - Account CWD - Change Working Directory REIN - Logout but not disconnect QUIT - Bye RETR - Retreive STOR - Store APPE - Append ALLO - Allocate REST - Restart RNFR - Rename from RNTO - Rename to ABOR - Cancel DELE - Delete LIST - Directory NLST - Name List SITE - Site parameters or commands STAT - Status HELP - Help NOOP - Noop RFC959 (1985): CDUP - Change to Parent Directory SMNT - Structure Mount STOU - Store Unique RMD - Remove Directory MKD - Make Directory PWD - Print Directory SYST - System RFC2389 (1998): FEAT - List Features (done) OPTS - Send options (done) RFC2640 (1999): LANG - Specify language for messages (not done) Pending (Internet Drafts): SIZE - File size (done) MDTM - File modification date-time (done) MLST - File name and attribute list (single file) (not done) MLSD - File list with attributes (multiple files) (done) MAIL, MLFL, MSOM - mail delivery (not done) Alphabetical syntax list: ABOR ACCT ALLO [ R ] APPE CDUP CWD DELE FEAT HELP [ ] LANG [ ] LIST [ ] MKD MLSD [ ] MLST [ ] MODE NLST [ ] NOOP OPTS [ ] PASS PASV PORT PWD QUIT REIN REST RETR RMD RNFR RNTO SITE SIZE SMNT STAT [ ] STOR STOU STRU SYST TYPE USER */ #include "ckcsym.h" /* Standard includes */ #include "ckcdeb.h" #ifndef NOFTP /* NOFTP = no FTP */ #ifndef SYSFTP /* SYSFTP = use external ftp client */ #ifdef TCPSOCKET /* Build only if TCP/IP included */ #define CKCFTP_C /* Note: much of the following duplicates what was done in ckcdeb.h */ /* but let's not mess with it unless it causes trouble. */ #ifdef CK_ANSIC #include #else /* CK_ANSIC */ #include #endif /* CK_ANSIC */ #include #ifdef OS2 #ifdef OS2ONLY #define INCL_WINERRORS #include #undef COMMENT #endif /* OS2ONLY */ #include "ckowin.h" #include "ckocon.h" #endif /* OS2 */ #ifndef ZILOG #ifdef NT #include #ifdef NTSIG extern int TlsIndex; #endif /* NTSIG */ #else /* NT */ #include #endif /* NT */ #else #include #endif /* ZILOG */ #include "ckcsig.h" #ifdef VMS /* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */ #include #else /* def VMS */ #include #endif /* def VMS [else] */ #include #ifndef HPUXPRE65 #include /* Error number symbols */ #else #ifndef ERRNO_INCLUDED #include /* Error number symbols */ #endif /* ERRNO_INCLUDED */ #endif /* HPUXPRE65 */ #ifdef OS2 #ifndef NT #ifdef __WATCOMC__ #include #endif /* __WATCOMC__ */ #endif /* NT */ #endif /* OS2 */ #ifndef NOTIMEH #include #endif /* NOTIMEH */ #ifndef EPIPE #define EPIPE 32 /* Broken pipe error */ #endif /* EPIPE */ /* Kermit includes */ #include "ckcasc.h" #include "ckcker.h" #include "ckucmd.h" #include "ckuusr.h" #include "ckcnet.h" /* Includes ckctel.h */ #include "ckctel.h" /* (then why include it again?) */ #include "ckcxla.h" #ifdef CK_SSL #include "ckuath.h" /* SMS 2007/02/15 */ #endif /* def CK_SSL */ /* How to get the struct timeval definition so we can call select(). The xxTIMEH symbols are defined in ckcdeb.h, overridden in various makefile targets. The problem is: maybe we have already included some header file that defined struct timeval, and maybe we didn't. If we did, we don't want to include another header file that defines it again or the compilation will fail. If we didn't, we have to include the header file where it's defined. But in some cases even that won't work because of strict POSIX constraints or somesuch, or because this introduces other conflicts (e.g. struct tm multiply defined), in which case we have to define it ourselves, but this can work only if we didn't already encounter a definition. */ #ifndef DCLTIMEVAL #ifdef SV68R3V6 #define DCLTIMEVAL #else #ifdef SCO234 #define DCLTIMEVAL #endif /* SCO234 */ #endif /* SV68R3V6 */ #endif /* DCLTIMEVAL */ #ifdef DCLTIMEVAL /* Also maybe in some places the elements must be unsigned... */ struct timeval { long tv_sec; long tv_usec; }; #ifdef COMMENT /* Currently we don't use this... */ struct timezone { int tz_minuteswest; int tz_dsttime; }; #endif /* COMMENT */ #else /* !DCLTIMEVAL */ #ifndef NOSYSTIMEH #ifdef SYSTIMEH #include #endif /* SYSTIMEH */ #endif /* NOSYSTIMEH */ #ifndef NOSYSTIMEBH #ifdef SYSTIMEBH #include #endif /* SYSTIMEBH */ #endif /* NOSYSTIMEBH */ #endif /* DCLTIMEVAL */ /* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */ #ifdef VMS #include #else /* def VMS */ #include #endif /* def VMS [else] */ #include #include #ifdef HAVE_STDLIB_H #include #endif /* HAVE_STDLIB_H */ #ifndef NOSETTIME #ifdef COMMENT /* This section moved to ckcdeb.h */ #ifdef POSIX #define UTIMEH #else #ifdef HPUX9 #define UTIMEH #else #ifdef OS2 #define SYSUTIMEH #endif /* OS2 */ #endif /* HPUX9 */ #endif /* POSIX */ #endif /* COMMENT */ #ifdef VMS /* SMS 2007/02/15 */ #include "ckvrtl.h" /* for utime() */ #else /* def VMS */ #ifdef SYSUTIMEH #include #else #ifdef UTIMEH #include #define SYSUTIMEH #endif /* UTIMEH */ #endif /* SYSUTIMEH */ #endif /* def VMS */ #endif /* NOSETTIME */ #ifndef SCO_OSR504 #ifdef SELECT_H #include #endif /* SELECT_H */ #endif /* SCO_OSR504 */ #ifdef OS2 #ifndef NT #ifdef __WATCOMC__ #include #endif /* __WATCOMC__ */ #endif /* NT */ _PROTOTYP(int ck_crypt_is_installed,(void)); ULONG gmstimer(); /* ckotio.c */ VOID ck_encrypt(char*); /* ckoetc.c */ #endif /* OS2 */ #ifdef NT #include "ckoreg.h" #ifdef CK_LOGIN VOID setntcreds(); #endif /* CK_LOGIN */ #endif /* NT */ #ifndef INADDR_NONE /* 2010-03-29 */ #define INADDR_NONE -1 #endif /* INADDR_NONE */ /* select() dialects... */ #ifdef UNIX #define BSDSELECT /* BSD select() syntax/semantics */ #ifndef FD_SETSIZE #define FD_SETSIZE 128 #endif /* FD_SETSIZE */ #ifdef HPUX6 /* For HP-UX 6.5 circa 1989 */ typedef long fd_mask; #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */ #ifndef howmany #define howmany(x, y) (((x)+((y)-1))/(y)) #endif /* howmany */ #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) #define FD_COPY(f, t) bcopy(f, t, sizeof(*(f))) #define FD_ZERO(p) bzero(p, sizeof(*(p))) #endif /* HPUX6 */ #else #ifdef OS2 /* OS/2 or Win32 */ #ifdef NT #define BSDSELECT #else /* NT */ #define IBMSELECT #endif /* NT */ #endif /* OS2 */ #endif /* UNIX */ #ifdef VMS #define BSDSELECT /* SMS 2007/02/15 */ #endif /* def VMS */ /* Other select() peculiarities */ #ifdef HPUX #ifndef HPUX10 /* HP-UX 9.xx and earlier */ #ifndef HPUX1100 /* The three interior args to select() are (int *) rather than (fd_set *) */ #ifndef INTSELECT #define INTSELECT #endif /* INTSELECT */ #endif /* HPUX1100 */ #endif /* HPUX10 */ #endif /* HPUX */ #ifdef CK_SOCKS /* SOCKS Internet relay package */ #ifdef CK_SOCKS5 /* SOCKS 5 */ #define accept SOCKSaccept #define bind SOCKSbind #define connect SOCKSconnect #define getsockname SOCKSgetsockname #define listen SOCKSlisten #else /* Not SOCKS 5 */ #define accept Raccept #define bind Rbind #define connect Rconnect #define getsockname Rgetsockname #define listen Rlisten #endif /* CK_SOCKS5 */ #endif /* CK_SOCKS */ #ifndef NOHTTP extern char * tcp_http_proxy; /* Name[:port] of http proxy server */ extern int tcp_http_proxy_errno; extern char * tcp_http_proxy_user; extern char * tcp_http_proxy_pwd; extern char * tcp_http_proxy_agent; #define HTTPCPYL 1024 static char proxyhost[HTTPCPYL]; #endif /* NOHTTP */ int ssl_ftp_proxy = 0; /* FTP over SSL/TLS Proxy Server */ /* Feature selection */ #ifndef USE_SHUTDOWN /* We don't use shutdown() because (a) we always call it just before close() so it's redundant and unnecessary, and (b) it introduces a long pause on some platforms like SV/68 R3. */ /* #define USE_SHUTDOWN */ #endif /* USE_SHUTDOWN */ #ifndef NORESEND #ifndef NORESTART /* Restart / recover */ #ifndef FTP_RESTART #define FTP_RESTART #endif /* FTP_RESTART */ #endif /* NORESTART */ #endif /* NORESEND */ #ifndef NOUPDATE /* Update mode */ #ifndef DOUPDATE #define DOUPDATE #endif /* DOUPDATE */ #endif /* NOUPDATE */ #ifndef UNICODE /* Unicode required */ #ifndef NOCSETS /* for charset translation */ #define NOCSETS #endif /* NOCSETS */ #endif /* UNICODE */ #ifndef OS2 #ifndef HAVE_MSECS /* Millisecond timer */ #ifdef UNIX #ifdef GFTIMER #define HAVE_MSECS #endif /* GFTIMER */ #endif /* UNIX */ #endif /* HAVE_MSECS */ #endif /* OS2 */ #ifdef PIPESEND /* PUT from pipe */ #ifndef PUTPIPE #define PUTPIPE #endif /* PUTPIPE */ #endif /* PIPESEND */ #ifndef NOSPL /* PUT from array */ #ifndef PUTARRAY #define PUTARRAY #endif /* PUTARRAY */ #endif /* NOSPL */ /* Security... */ #ifdef CK_SRP #define FTP_SRP #endif /* CK_SRP */ #ifdef CK_KERBEROS #ifdef KRB4 /* There is a conflict between the Key Schedule formats used internally within the standalone MIT KRB4 library and that used by Eric Young in OpenSSL and his standalone DES library. Therefore, KRB4 FTP AUTH cannot be supported when either of those two packages are used. */ #ifdef KRB524 #define FTP_KRB4 #else /* KRB524 */ #ifndef CK_SSL #ifndef LIBDES #define FTP_KRB4 #endif /* LIBDES */ #endif /* CK_SSL */ #endif /* KRB524 */ #endif /* KRB4 */ #ifdef KRB5 #ifndef HEIMDAL #ifndef NOFTP_GSSAPI /* 299 */ #ifdef HAVE_GSSAPI /* fdc 22 November 2022 */ #define FTP_GSSAPI #endif /* HAVE_GSSAPI */ #endif /* NOFTP_GSSAPI */ #endif /* HEIMDAL */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ /* FTP_SECURITY is defined if any of the above is selected */ #ifndef FTP_SECURITY #ifdef FTP_GSSAPI #define FTP_SECURITY #else #ifdef FTP_KRB4 #define FTP_SECURITY #else #ifdef FTP_SRP #define FTP_SECURITY #else #ifdef CK_SSL #define FTP_SECURITY #endif /* CK_SSL */ #endif /* FTP_SRP */ #endif /* FTP_KRB4 */ #endif /* FTP_GSSAPI */ #endif /* FTP_SECURITY */ #ifdef CK_DES #ifdef CK_SSL #ifndef LIBDES #define LIBDES #endif /* LIBDES */ #endif /* CK_SSL */ #endif /* CK_DES */ #ifdef CRYPT_DLL #ifndef LIBDES #define LIBDES #endif /* LIBDES */ #endif /* CRYPT_DLL */ #ifdef FTP_KRB4 #define des_cblock Block #define des_key_schedule Schedule #ifdef KRB524 #ifdef NT #define _WINDOWS #endif /* NT */ #include "kerberosIV/krb.h" #else /* KRB524 */ #ifdef SOLARIS #ifndef sun /* For some reason lost in history the Makefile Solaris targets have -Usun */ #define sun #endif /* sun */ #endif /* SOLARIS */ #include "krb.h" #define krb_get_err_text_entry krb_get_err_text #endif /* KRB524 */ #endif /* FTP_KRB4 */ #ifdef CK_SSL #ifdef FTP_KRB4 #ifndef HEADER_DES_H #define HEADER_DES_H #endif /* HEADER_DES_H */ #endif /* FTP_KRB4 */ #include "ck_ssl.h" #endif /* CK_SSL */ #ifdef FTP_SRP #ifdef HAVE_PWD_H #include "pwd.h" #endif /* HAVE_PWD_H */ #include "t_pwd.h" #include "t_client.h" #include "krypto.h" #endif /* FTP_SRP */ #ifdef FTP_GSSAPI #include /* #include */ /* Need to include the krb5 file, because we're doing manual fallback from the v2 mech to the v1 mech. Once there's real negotiation, we can be generic again. */ #include #include static gss_ctx_id_t gcontext; #ifdef MACOSX /** exported constants defined in gssapi_krb5{,_nx}.h **/ /* these are bogus, but will compile */ /* * The OID of the draft krb5 mechanism, assigned by IETF, is: * iso(1) org(3) dod(5) internet(1) security(5) * kerberosv5(2) = 1.3.5.1.5.2 * The OID of the krb5_name type is: * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) * krb5(2) krb5_name(1) = 1.2.840.113554.1.2.2.1 * The OID of the krb5_principal type is: * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) * krb5(2) krb5_principal(2) = 1.2.840.113554.1.2.2.2 * The OID of the proposed standard krb5 mechanism is: * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) * krb5(2) = 1.2.840.113554.1.2.2 * The OID of the proposed standard krb5 v2 mechanism is: * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) * krb5v2(3) = 1.2.840.113554.1.2.3 * */ /* * Encoding rules: The first two values are encoded in one byte as 40 * * value1 + value2. Subsequent values are encoded base 128, most * significant digit first, with the high bit (\200) set on all octets * except the last in each value's encoding. */ static CONST gss_OID_desc ck_krb5_gss_oid_array[] = { /* this is the official, rfc-specified OID */ {9, "\052\206\110\206\367\022\001\002\002"}, /* this is the unofficial, wrong OID */ {5, "\053\005\001\005\002"}, /* this is the v2 assigned OID */ {9, "\052\206\110\206\367\022\001\002\003"}, /* these two are name type OID's */ {10, "\052\206\110\206\367\022\001\002\002\001"}, {10, "\052\206\110\206\367\022\001\002\002\002"}, { 0, 0 } }; static CONST gss_OID_desc * CONST gss_mech_krb5_v2 = ck_krb5_gss_oid_array+2; #ifdef MACOSX103 static CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0; #endif /* MACOSX103 */ #ifndef MACOSX static CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0; static CONST gss_OID_desc * CONST gss_mech_krb5_old = ck_krb5_gss_oid_array+1; static CONST gss_OID_desc * CONST gss_nt_krb5_name = ck_krb5_gss_oid_array+3; static CONST gss_OID_desc * CONST gss_nt_krb5_principal = ck_krb5_gss_oid_array+4; #endif /* MACOSX */ /* * See krb5/gssapi_krb5.c for a description of the algorithm for * encoding an object identifier. */ /* * The OID of user_name is: * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) * generic(1) user_name(1) = 1.2.840.113554.1.2.1.1 * machine_uid_name: * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) * generic(1) machine_uid_name(2) = 1.2.840.113554.1.2.1.2 * string_uid_name: * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) * generic(1) string_uid_name(3) = 1.2.840.113554.1.2.1.3 * service_name: * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) * generic(1) service_name(4) = 1.2.840.113554.1.2.1.4 * exported_name: * 1(iso), 3(org), 6(dod), 1(internet), 5(security), 6(nametypes), * 4(gss-api-exported-name) * host_based_service_name (v2): * iso (1) org (3), dod (6), internet (1), security (5), nametypes(6), * gss-host-based-services(2) */ static gss_OID_desc ck_oids[] = { {10, "\052\206\110\206\367\022\001\002\001\001"}, {10, "\052\206\110\206\367\022\001\002\001\002"}, {10, "\052\206\110\206\367\022\001\002\001\003"}, {10, "\052\206\110\206\367\022\001\002\001\004"}, { 6, "\053\006\001\005\006\004"}, { 6, "\053\006\001\005\006\002"}, }; static gss_OID ck_gss_nt_user_name = ck_oids+0; static gss_OID ck_gss_nt_machine_uid_name = ck_oids+1; static gss_OID ck_gss_nt_string_uid_name = ck_oids+2; static gss_OID ck_gss_nt_service_name = ck_oids+3; static gss_OID ck_gss_nt_exported_name = ck_oids+4; static gss_OID ck_gss_nt_service_name_v2 = ck_oids+5; #endif /* MACOSX */ #endif /* FTP_GSSAPI */ #ifdef OS2 #ifdef FTP_SRP #define MAP_KRYPTO #ifdef SRPDLL #define MAP_SRP #endif /* SRPDLL */ #endif /* FTP_SRP */ #ifdef FTP_KRB4 #define MAP_KRB4 #ifdef CK_ENCRYPTION #define MAP_DES #endif /* CK_ENCRYPTION */ #endif /* FTP_KRB4 */ #ifdef FTP_GSSAPI #define MAP_GSSAPI #define GSS_OIDS #endif /* FTP_GSSAPI */ #include "ckoath.h" #include "ckcfnp.h" /* Prototypes */ extern int k95stdout, wherex[], wherey[]; extern unsigned char colorcmd; #endif /* OS2 */ #ifdef FTP_KRB4 static char ftp_realm[REALM_SZ + 1]; static KTEXT_ST ftp_tkt; #ifdef OS2 static LEASH_CREDENTIALS ftp_cred; #else /* OS2 */ static CREDENTIALS ftp_cred; #endif /* OS2 */ static MSG_DAT ftp_msg_data; static des_key_schedule ftp_sched; static int foo[4] = {99,99,99,99}; #endif /* FTP_KRB4 */ /* getreply() function codes */ #define GRF_AUTH 1 /* Reply to AUTH command */ #define GRF_FEAT 2 /* Reply to FEAT command */ /* Operational definitions */ #define DEF_VBM 0 /* Default verbose mode */ /* #define SETVBM */ /* (see getreply) */ #define URL_ONEFILE /* GET, not MGET, for FTP URL */ #define FTP_BUFSIZ 10240 /* Max size for FTP cmds & replies */ #define SRVNAMLEN 32 /* Max length for server type name */ #define PWDSIZ 256 #define PASSBUFSIZ 256 #define PROMPTSIZ 256 #ifndef MGETMAX /* Max operands for MGET command */ #define MGETMAX 1000 #endif /* MGETMAX */ #ifdef FTP_SRP #define FUDGE_FACTOR 100 #endif /* FTP_SRP */ /* Amount of growth from cleartext to ciphertext. krb_mk_priv adds this number bytes. Must be defined for each auth type. GSSAPI appears to add 52 bytes, but I'm not sure it is a constant--hartmans 3DES requires 56 bytes. Lets use 96 just to be sure. */ #ifdef FTP_GSSAPI #ifndef FUDGE_FACTOR #define FUDGE_FACTOR 96 #endif /* FUDGE_FACTOR */ #endif /* FTP_GSSAPI */ #ifdef FTP_KRB4 #ifndef FUDGE_FACTOR #define FUDGE_FACTOR 32 #endif /* FUDGE_FACTOR */ #endif /* FTP_KRB4 */ #ifndef FUDGE_FACTOR /* In case no auth types define it */ #define FUDGE_FACTOR 0 #endif /* FUDGE_FACTOR */ #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif /* MAXHOSTNAMELEN */ #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1) /* Fascist compiler toadying */ #ifndef SENDARG2TYPE #ifdef COMMENT /* Might be needed here and there */ #define SENDARG2TYPE const char * #else #define SENDARG2TYPE char * #endif /* COMMENT */ #endif /* SENDARG2TYPE */ /* Common text messages */ static char *nocx = "?No FTP control connection\n"; static char *fncnam[] = { "rename", "overwrite", "backup", "append", "discard", "ask", "update", "dates-differ", "" }; /* Macro definitions */ /* Used to speed up text-mode PUTs */ #define zzout(fd,c) \ ((fd<0)?(-1):((nout>=ucbufsiz)?(zzsend(fd,c)):(ucbuf[nout++]=c))) #define CHECKCONN() if(!connected){printf("%s\n",nocx);return(-9);} /* Externals */ #ifdef CK_URL extern struct urldata g_url; #endif /* CK_URL */ #ifdef DYNAMIC extern char *zinbuffer, *zoutbuffer; /* Regular Kermit file i/o */ #else extern char zinbuffer[], zoutbuffer[]; #endif /* DYNAMIC */ extern char *zinptr, *zoutptr; extern int zincnt, zoutcnt, zobufsize, fncact; #ifdef CK_TMPDIR extern int f_tmpdir; /* Directory changed temporarily */ extern char savdir[]; /* For saving current directory */ extern char * dldir; #endif /* CK_TMPDIR */ extern char * rfspec, * sfspec, * srfspec, * rrfspec; /* For WHERE command */ extern xx_strp xxstring; extern struct keytab onoff[], txtbin[], rpathtab[]; extern int nrpathtab, xfiletype, patterns, gnferror, moving, what, pktnum; extern int success, nfils, sndsrc, quiet, nopush, recursive, inserver, binary; extern int filepeek, nscanfile, fsecs, xferstat, xfermode, lastxfer, tsecs; extern int backgrd, spackets, rpackets, spktl, rpktl, xaskmore, cmd_rows; extern int nolinks, msgflg, keep; extern CK_OFF_T fsize, ffc, tfc, sendstart, sndsmaller, sndlarger, rs_len; extern long filcnt, xfsecs, tfcps, cps, oldcps; #ifdef FTP_TIMEOUT int ftp_timed_out = 0; long ftp_timeout = 0; #endif /* FTP_TIMEOUT */ #ifdef GFTIMER extern CKFLOAT fptsecs, fpfsecs, fpxfsecs; #else extern long xfsecs; #endif /* GFTIMER */ extern char filnam[], * filefile, myhost[]; extern char * snd_move, * rcv_move, * snd_rename, * rcv_rename; extern int g_skipbup, skipbup, sendmode; extern int g_displa, fdispla, displa; #ifdef LOCUS extern int locus, autolocus; #endif /* LOCUS */ #ifndef NOCSETS extern int nfilc, dcset7, dcset8, fileorder; extern struct csinfo fcsinfo[]; extern struct keytab fcstab[]; extern int fcharset; #endif /* NOCSETS */ extern char sndbefore[], sndafter[], *sndexcept[]; /* Selection criteria */ extern char sndnbefore[], sndnafter[], *rcvexcept[]; extern CHAR feol; extern char * remdest; extern int remfile, remappd, rempipe; #ifndef NOSPL extern int cmd_quoting; #ifdef PUTARRAY extern int sndxlo, sndxhi, sndxin; extern char sndxnam[]; extern char **a_ptr[]; /* Array pointers */ extern int a_dim[]; /* Array dimensions */ #endif /* PUTARRAY */ #endif /* NOSPL */ #ifndef NOMSEND /* MPUT and ADD SEND-LIST lists */ extern char *msfiles[]; extern int filesinlist; extern struct filelist * filehead; extern struct filelist * filetail; extern struct filelist * filenext; extern int addlist; extern char fspec[]; /* Most recent filespec */ extern int fspeclen; /* Length of fspec[] buffer */ #endif /* NOMSEND */ extern int pipesend; #ifdef PIPESEND extern char * sndfilter, * rcvfilter; #endif /* PIPESEND */ #ifdef CKROOT extern int ckrooterr; #endif /* CKROOT */ #ifdef KRB4 extern int krb4_autoget; _PROTOTYP(char * ck_krb4_realmofhost,(char *)); #endif /* KRB4 */ #ifdef KRB5 extern int krb5_autoget; extern int krb5_d_no_addresses; _PROTOTYP(char * ck_krb5_realmofhost,(char *)); #endif /* KRB5 */ #ifdef DCMDBUF extern char *atmbuf; /* Atom buffer (malloc'd) */ extern char *cmdbuf; /* Command buffer (malloc'd) */ extern char *line; /* Big string buffer #1 */ extern char *tmpbuf; /* Big string buffer #2 */ #else extern char atmbuf[]; /* The same, but static */ extern char cmdbuf[]; extern char line[]; extern char tmpbuf[]; #endif /* DCMDBUF */ extern char * cmarg, * cmarg2, ** cmlist; /* For setting up file lists */ /* Public variables declared here */ #ifdef NOXFER int ftpget = 1; /* GET/PUT/REMOTE orientation FTP */ #else int ftpget = 2; /* GET/PUT/REMOTE orientation AUTO */ #endif /* NOXFER */ int ftpcode = -1; /* Last FTP response code */ int ftp_cmdlin = 0; /* FTP invoked from command line */ int ftp_fai = 0; /* FTP failure count */ int ftp_deb = 0; /* FTP debugging */ int ftp_dis = -1; /* FTP display style */ int ftp_log = 1; /* FTP Auto-login */ int sav_log = -1; int ftp_action = 0; /* FTP action from command line */ int ftp_dates = 1; /* Set file dates from server */ int ftp_xfermode = XMODE_A; /* FTP-specific transfer mode */ char ftp_reply_str[FTP_BUFSIZ] = ""; /* Last line of previous reply */ char ftp_srvtyp[SRVNAMLEN] = { NUL, NUL }; /* Server's system type */ char ftp_user_host[MAX_DNS_NAMELEN]= ""; /* FTP hostname specified by user */ char * ftp_host = NULL; /* FTP hostname */ char * ftp_logname = NULL; /* FTP username */ char * ftp_rdir = NULL; /* Remote directory from cmdline */ char * ftp_apw = NULL; /* Anonymous password */ /* Definitions and typedefs needed for prototypes */ /* #define sig_t my_sig_t I don't understand the statement above, which has been in this code going back to at least C-Kermit 8.0, because my_sig_t is not defined anywhere. And yet sig_t is used below with no complaint, no matter whether the the above #define is commented out or not. However, if I #define sig_t SIGTYP (which is what it should be according to ckcdeb.h), all hell breaks loose. Same if I replace all references to sig_t by SIGTYPE. On the other hand, if I remove the sig_t definition, there is no complaint, so where is the sig_t definition coming from? I find this in Ubuntu signal.h: 4.4 BSD uses the name 'sig_t' for this. typedef __sighandler_t sig_t; In NetBSD I find this in sys/signal.h: typedef void (*sig_t)(int); Can we really count on sig_t being defined in some nook or cranny on every single Unix, VMS, and Windows system? Jeff Altman says to use sighandler_t, which is ok on Ubuntu but not on (say) NetBSD. So I can't do this: #ifndef sig_t #define sig_t sighandler_t #endif I think the only alternative is to leave my_sig_t undefined and then see who squawks. Since the previous 'my_sig_t' definition apparently had no effect, I'm hoping there will be no change in behavior after commenting it out. -fdc Fri Jun 23 06:53:23 2023 P.S. All this is aside from the fact that signal() has long since been "deprecated" in favor of sigaction(), defined in POSIX.1-1988; see: https://man7.org/linux/man-pages/man2/signal.2.html https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html but C-Kermit can't be switched over because it has to build and run on pre-POSIX operating systems that don't have sigaction(0) (despite the fact that C-Kermit's ckupty.c function ptyint_vhangup() calls it... how did *that* happen?). */ #define sigtype SIGTYP #ifdef CK_ANSIC typedef sigtype (*sig_t)(int); #else typedef sigtype (*sig_t)(); #endif /* CK_ANSIC */ /* Made this global static -fdc 21 June 2023 */ /* It's used in many ckcftp.c routines but wasn't declared in all of them */ static sig_t oldintr; /* Prototypes for static functions defined in ckcftp.c */ #ifdef CK_ANSIC #ifdef COMMENT static VOID bytswap( int *, int * ); #endif /* COMMENT */ static VOID cancel_remote( int ); static VOID changetype( int, int ); static VOID dbtime( char *, struct tm * ); static VOID ftscreen( int, char, CK_OFF_T, char * ); static char * ftp_hookup( char *, int, int ); static char * radix_error( int ); #ifdef FTP_SECURITY static char * shopl( int ); #endif /* FTP_SECURITY */ static char * strval( char *, char * ); static int check_data_connection( int, int ); static int chkmodtime( char *, char *, int ); static int dataconn( char * ); static int doftpcwd( char *, int ); static int doftpdir( int ); static int doftpxmkd( char *, int ); static int ftp_login( char * ); static int ftp_rename( char *, char * ); static int ftp_umask( char * ); static int ftp_user( char *, char *, char * ); static int ftpcmd( char *, char *, int, int, int ); #ifdef FTP_SECURITY static int fts_cpl( int ); static int fts_dpl( int ); #endif /* FTP_SECURITY */ static int getfile( char *, char *, int, int, char *, int, int, int ); static int getreply( int, int, int, int, int ); static int ispathsep( int ); static int looping_read(int, register char *, register int ); static int looping_write( int, register CONST char *, int ); static int openftp( char *, int ); static int putfile( int, char *, char *, int, int, char *, char *, char *, int, int, int, int, int, int, int ); static int recvrequest(char *, char *, char *, char *, int, int, char *, int, int, int ); static int secure_flush( int ); static int secure_getbyte( int, int ); static int secure_read( int fd, char *, int ); static int sendrequest( char *, char *, char *, int, int, int, int ); static int syncdir( char *, int ); static int tmcompare( struct tm *, struct tm * ); static int xlatec( int, int, int, int ); static sigtype cancelrecv( int ); static sigtype cancelsend( int ); static sigtype cmdcancel( int ); #endif /* CK_ANSIC */ /* Static global variables */ static char ftpsndbuf[FTP_BUFSIZ+64]; static char * fts_sto = NULL; static int ftpsndret = 0; static struct _ftpsnd { sig_t oldintr, oldintp; int reply; int incs, outcs; char * cmd, * local, * remote; int bytes; int restart; int xlate; char * lmode; } ftpsnd; /* This is just a first stab -- these strings should match how the corresponding FTP servers identify themselves. */ #ifdef UNIX static char * myostype = "UNIX"; #else #ifdef VMS /* not yet... */ static char * myostype = "VMS"; #else #ifdef OS2 #ifdef NT static char * myostype = "WIN32"; #else static char * myostype = "OS/2"; #endif /* NT */ #else static char * myostype = "UNSUPPORTED"; #endif /* OS2 */ #endif /* VMS */ #endif /* UNIX */ static int noinit = 0; /* Don't send REST, STRU, MODE */ static int alike = 0; /* Client/server like platforms */ static int local = 1; /* Shadows Kermit global 'local' */ static int dout = -1; /* Data connection file descriptor */ static int dpyactive = 0; /* Data transfer is active */ static int globaldin = -1; /* Data connection f.d. */ static int out2screen = 0; /* GET output is to screen */ static int forcetype = 0; /* Force text or binary mode */ static int cancelfile = 0; /* File canceled */ static int cancelgroup = 0; /* Group canceled */ static int anonymous = 0; /* Logging in as anonymous */ static int loggedin = 0; /* Logged in (or not) */ static int puterror = 0; /* What to do on PUT error */ static int geterror = 0; /* What to do on GET error */ static int rfrc = 0; /* remote_files() return code */ static int okrestart = 0; /* Server understands REST */ static int printlines = 0; /* getreply()should print data lines */ static int haveurl = 0; /* Invoked by command-line FTP URL */ static int mdtmok = 1; /* Server supports MDTM */ static int sizeok = 1; static int featok = 1; static int mlstok = 1; static int stouarg = 1; static int typesent = 0; static int havesigint = 0; static long havetype = 0; static CK_OFF_T havesize = (CK_OFF_T)-1; static char * havemdtm = NULL; static int mgetmethod = 0; /* NLST or MLSD */ static int mgetforced = 0; static int i, /* j, k, */ x, y, z; /* Volatile temporaries */ static int c0, c1; /* Temp variables for characters */ static char putpath[CKMAXPATH+1] = { NUL, NUL }; static char asnambuf[CKMAXPATH+1] = { NUL, NUL }; #define RFNBUFSIZ 4096 /* Remote filename buffer size */ static unsigned int maxbuf = 0, actualbuf = 0; static CHAR *ucbuf = NULL; static int ucbufsiz = 0; static unsigned int nout = 0; /* Number of chars in ucbuf */ static jmp_buf recvcancel; static jmp_buf sendcancel; #ifdef NOT_USED static jmp_buf jcancel; #endif /* NOT_USED */ #ifdef FTP_PROXY static jmp_buf ptcancel; static int ptabflg = 0; #endif /* FTP_PROXY */ /* Protection level symbols */ #define FPL_CLR 1 /* Clear */ #define FPL_SAF 2 /* Safe */ #define FPL_PRV 3 /* Private */ #define FPL_CON 4 /* Confidential */ /* Symbols for file types returned by MLST/MLSD */ #define FTYP_FILE 1 /* Regular file */ #define FTYP_DIR 2 /* Directory */ #define FTYP_CDIR 3 /* Current directory */ #define FTYP_PDIR 4 /* Parent directory */ /* File type symbols keyed to the file-type symbols from ckcker.h */ #define FTT_ASC XYFT_T /* ASCII (text) */ #define FTT_BIN XYFT_B /* Binary (image) */ #define FTT_TEN XYFT_X /* TENEX (TOPS-20) */ /* Server feature table - sfttab[0] > 0 means server supports FEAT and OPTS */ static int sfttab[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; #define SFT_AUTH 1 /* FTP server feature codes */ #define SFT_LANG 2 #define SFT_MDTM 3 #define SFT_MLST 4 #define SFT_PBSZ 5 #define SFT_PROT 6 #define SFT_REST 7 #define SFT_SIZE 8 #define SFT_TVFS 9 #define SFT_UTF8 10 #define CNV_AUTO 2 /* FTP filename conversion */ #define CNV_CNV 1 #define CNV_LIT 0 /* SET FTP values */ static int /* SET FTP values... */ ftp_aut = 1, /* Auto-authentication */ #ifdef FTP_SECURITY ftp_cry = 1, /* Auto-encryption */ ftp_cfw = 0, /* Credential forwarding */ #endif /* FTP_SECURITY */ ftp_cpl = FPL_CLR, /* Command protection level */ ftp_dpl = FPL_CLR, /* Data protection level */ #ifdef FTP_PROXY ftp_prx = 0, /* Use proxy */ #endif /* FTP_PROXY */ sav_psv = -1, /* For saving passive mode */ ftp_psv = 1, /* Passive mode */ ftp_spc = 1, /* Send port commands */ ftp_typ = FTT_ASC, /* Type */ get_auto = 1, /* Automatic type switching for GET */ tenex = 0, /* Type is Tenex */ ftp_usn = 0, /* Unique server names */ ftp_prm = 0, /* Permissions */ ftp_cnv = CNV_AUTO, /* Filename conversion (2 = auto) */ ftp_vbm = DEF_VBM, /* Verbose mode */ ftp_vbx = DEF_VBM, /* Sticky version of same */ ftp_err = 0, /* Error action */ ftp_fnc = -1; /* Filename collision action */ #ifdef CK_SSL static int ftp_bug_use_ssl_v2 = 0; /* use SSLv2 for AUTH SSL */ static int ftp_bug_use_ssl_v3 = 0; /* use SSLv3 for AUTH SSL */ #endif /* CK_SSL */ static int #ifdef NOCSETS ftp_csr = -1, /* Remote (server) character set */ #else ftp_csr = FC_UTF8, #endif /* NOCSETS */ ftp_xla = 0; /* Character-set translation on/off */ int ftp_csx = -1, /* Remote charset currently in use */ ftp_csl = -1; /* Local charset currently in use */ static int g_ftp_typ = FTT_ASC; /* For saving and restoring ftp_typ */ char * ftp_nml = NULL; /* /NAMELIST */ char * ftp_tmp = NULL; /* Temporary string */ static char * ftp_acc = NULL; /* Account string */ static char * auth_type = NULL; /* Authentication type */ static char * srv_renam = NULL; /* Server-rename string */ FILE * fp_nml = NULL; /* Namelist file pointer */ static int csocket = -1; /* Control socket */ static int connected = 0; /* Connected to FTP server */ /* static unsigned short ftp_port = 0; */ /* FTP port */ /* static int ftp_port = 0; */ /* SMS 2007/02/15 */ static int ftp_port = 0; /* fdc 2007/08/30 */ #ifdef FTPHOST static int hostcmd = 0; /* Has HOST command been sent */ #endif /* FTPHOST */ static int form, mode, stru, bytesize, curtype = FTT_ASC; static char bytename[8]; /* For parsing replies to FTP server command */ static char *reply_parse, reply_buf[FTP_BUFSIZ], *reply_ptr; #ifdef FTP_PROXY static int proxy, unix_proxy #endif /* FTP_PROXY */ static char pasv[64]; /* Passive-mode port */ static int passivemode = 0; static int sendport = 0; static int servertype = 0; /* FTP server's OS type */ static int testing = 0; static char ftpcmdbuf[FTP_BUFSIZ]; /* Macro definitions */ #define UC(b) ckitoa(((int)b)&0xff) #define nz(x) ((x) == 0 ? 1 : (x)) /* Command tables and definitions */ #define FTP_ACC 1 /* FTP command keyword codes */ #define FTP_APP 2 #define FTP_CWD 3 #define FTP_CHM 4 #define FTP_CLS 5 #define FTP_DEL 6 #define FTP_DIR 7 #define FTP_GET 8 #define FTP_IDL 9 #define FTP_MDE 10 #define FTP_MDI 11 #define FTP_MGE 12 #define FTP_MKD 13 #define FTP_MOD 14 #define FTP_MPU 15 #define FTP_OPN 16 #define FTP_PUT 17 #define FTP_PWD 18 #define FTP_RGE 19 #define FTP_REN 20 #define FTP_RES 21 #define FTP_HLP 22 #define FTP_RMD 23 #define FTP_STA 24 #define FTP_SIT 25 #define FTP_SIZ 26 #define FTP_SYS 27 #define FTP_UMA 28 #define FTP_GUP 29 #define FTP_USR 30 #define FTP_QUO 31 #define FTP_TYP 32 #define FTP_FEA 33 #define FTP_OPT 34 #define FTP_CHK 35 #define FTP_VDI 36 #define FTP_ENA 37 #define FTP_DIS 38 #define FTP_REP 39 struct keytab gprtab[] = { /* GET-PUT-REMOTE keywords */ { "auto", 2, 0 }, { "ftp", 1, 0 }, { "kermit", 0, 0 } }; static struct keytab qorp[] = { /* QUIT or PROCEED keywords */ { "proceed", 0, 0 }, /* 0 = proceed */ { "quit", 1, 0 } /* 1 = quit */ }; static struct keytab ftpcmdtab[] = { /* FTP command table */ { "account", FTP_ACC, 0 }, { "append", FTP_APP, 0 }, { "bye", FTP_CLS, 0 }, { "cd", FTP_CWD, 0 }, { "cdup", FTP_GUP, 0 }, { "check", FTP_CHK, 0 }, { "chmod", FTP_CHM, 0 }, { "close", FTP_CLS, 0 }, { "cwd", FTP_CWD, CM_INV }, { "delete", FTP_MDE, 0 }, { "directory", FTP_DIR, 0 }, { "disable", FTP_DIS, 0 }, { "enable", FTP_ENA, 0 }, { "features", FTP_FEA, 0 }, { "get", FTP_GET, 0 }, { "help", FTP_HLP, 0 }, { "idle", FTP_IDL, 0 }, { "login", FTP_USR, CM_INV }, { "mdelete", FTP_MDE, CM_INV }, { "mget", FTP_MGE, 0 }, { "mkdir", FTP_MKD, 0 }, { "modtime", FTP_MOD, 0 }, { "mput", FTP_MPU, 0 }, { "open", FTP_OPN, 0 }, { "opt", FTP_OPT, CM_INV|CM_ABR }, { "opts", FTP_OPT, CM_INV }, { "options", FTP_OPT, 0 }, { "put", FTP_PUT, 0 }, { "pwd", FTP_PWD, 0 }, { "quit", FTP_CLS, CM_INV }, { "quote", FTP_QUO, 0 }, { "reget", FTP_RGE, 0 }, { "rename", FTP_REN, 0 }, { "reput", FTP_REP, 0 }, { "resend", FTP_REP, CM_INV }, { "reset", FTP_RES, 0 }, { "rmdir", FTP_RMD, 0 }, { "send", FTP_PUT, CM_INV }, { "site", FTP_SIT, 0 }, { "size", FTP_SIZ, 0 }, { "status", FTP_STA, 0 }, { "system", FTP_SYS, 0 }, { "type", FTP_TYP, 0 }, { "umask", FTP_UMA, 0 }, { "up", FTP_GUP, CM_INV }, { "user", FTP_USR, 0 }, { "vdirectory",FTP_VDI, 0 }, { "", 0, 0 } }; static int nftpcmd = (sizeof(ftpcmdtab) / sizeof(struct keytab)) - 1; #define OPN_ANO 1 /* FTP OPEN switch codes */ #define OPN_PSW 2 #define OPN_USR 3 #define OPN_ACC 4 #define OPN_ACT 5 #define OPN_PSV 6 #define OPN_TLS 7 #define OPN_NIN 8 #define OPN_NOL 9 #ifdef FTP_SECURITY #ifdef CK_SSL #define USETLSTAB static struct keytab tlstab[] = { /* FTP SSL/TLS switches */ { "/ssl", OPN_TLS, 0 }, { "/tls", OPN_TLS, 0 }, { "", 0, 0 } }; static int ntlstab = (sizeof(tlstab) / sizeof(struct keytab)) - 1; #endif /* CK_SSL */ #endif /* FTP_SECURITY */ static struct keytab ftpswitab[] = { /* FTP command switches */ { "/account", OPN_ACC, CM_ARG }, { "/active", OPN_ACT, 0 }, { "/anonymous", OPN_ANO, 0 }, { "/noinit", OPN_NIN, 0 }, { "/nologin", OPN_NOL, 0 }, { "/passive", OPN_PSV, 0 }, { "/password", OPN_PSW, CM_ARG }, { "/user", OPN_USR, CM_ARG }, { "", 0, 0 } }; static int nftpswi = (sizeof(ftpswitab) / sizeof(struct keytab)) - 1; /* FTP { ENABLE, DISABLE } items */ #define ENA_FEAT 1 #define ENA_MDTM 2 #define ENA_MLST 3 #define ENA_SIZE 4 #define ENA_AUTH 5 static struct keytab ftpenatab[] = { { "AUTH", ENA_AUTH, 0 }, { "FEAT", ENA_FEAT, 0 }, { "MDTM", ENA_MDTM, 0 }, { "ML", ENA_MLST, CM_INV|CM_ABR }, { "MLS", ENA_MLST, CM_INV|CM_ABR }, { "MLSD", ENA_MLST, CM_INV }, { "MLST", ENA_MLST, 0 }, { "SIZE", ENA_SIZE, 0 }, { "", 0, 0 } }; static int nftpena = (sizeof(ftpenatab) / sizeof(struct keytab)) - 1; /* SET FTP command keyword indices */ #define FTS_AUT 1 /* Autoauthentication */ #define FTS_CRY 2 /* Encryption */ #define FTS_LOG 3 /* Autologin */ #define FTS_CPL 4 /* Command protection level */ #define FTS_CFW 5 /* Credentials forwarding */ #define FTS_DPL 6 /* Data protection level */ #define FTS_DBG 7 /* Debugging */ #define FTS_PSV 8 /* Passive mode */ #define FTS_SPC 9 /* Send port commands */ #define FTS_TYP 10 /* (file) Type */ #define FTS_USN 11 /* Unique server names (for files) */ #define FTS_VBM 12 /* Verbose mode */ #define FTS_ATP 13 /* Authentication type */ #define FTS_CNV 14 /* Filename conversion */ #define FTS_TST 15 /* Test (progress) messages */ #define FTS_PRM 16 /* (file) Permissions */ #define FTS_XLA 17 /* Charset translation */ #define FTS_CSR 18 /* Server charset */ #define FTS_ERR 19 /* Error action */ #define FTS_FNC 20 /* Collision */ #define FTS_SRP 21 /* SRP options */ #define FTS_GFT 22 /* GET automatic file-type switching */ #define FTS_DAT 23 /* Set file dates */ #define FTS_STO 24 /* Server time offset */ #define FTS_APW 25 /* Anonymous password */ #define FTS_DIS 26 /* File-transfer display style */ #define FTS_BUG 27 /* Bug(s) */ #define FTS_TMO 28 /* Timeout */ /* FTP BUGS */ #define FTB_SV2 1 /* use SSLv2 */ #define FTB_SV3 2 /* use SSLv3 */ static struct keytab ftpbugtab[] = { { "use-ssl-v2", FTB_SV2, 0 }, { "use-ssl-v3", FTB_SV3, 0 } }; static int nftpbug = (sizeof(ftpbugtab) / sizeof(struct keytab)); /* FTP PUT options (mutually exclusive, not a bitmask) */ #define PUT_UPD 1 /* Update */ #define PUT_RES 2 /* Restart */ #define PUT_SIM 4 /* Simulation */ #define PUT_DIF 8 /* Dates Differ */ static struct keytab ftpcolxtab[] = { /* SET FTP COLLISION options */ #ifndef MAC { "append", XYFX_A, 0 }, /* append to old file */ #endif /* MAC */ #ifdef COMMENT { "ask", XYFX_Q, 0 }, /* ask what to do (not implemented) */ #endif { "backup", XYFX_B, 0 }, /* rename old file */ #ifndef MAC { "dates-differ", XYFX_M, 0 }, /* accept if dates differ */ { "discard", XYFX_D, 0 }, /* don't accept new file */ { "no-supersede", XYFX_D, CM_INV }, /* ditto (MSK compatibility) */ #endif /* MAC */ { "overwrite", XYFX_X, 0 }, /* overwrite the old file */ { "rename", XYFX_R, 0 }, /* rename the incoming file */ #ifndef MAC /* This crashes Mac Kermit. */ { "update", XYFX_U, 0 }, /* replace if newer */ #endif /* MAC */ { "", 0, 0 } }; static int nftpcolx = (sizeof(ftpcolxtab) / sizeof(struct keytab)) - 1; #ifdef FTP_SECURITY /* FTP authentication options */ #define FTA_AUTO 0 /* Auto */ #define FTA_SRP 1 /* SRP */ #define FTA_GK5 2 /* Kerberos 5 */ #define FTA_K4 3 /* Kerberos 4 */ #define FTA_SSL 4 /* SSL */ #define FTA_TLS 5 /* TLS */ /* FTP authentication types */ #define FTPATYPS 8 static int ftp_auth_type[FTPATYPS] = { #ifdef FTP_GSSAPI FTA_GK5, /* GSSAPI Kerberos 5 */ #endif /* FTP_GK5 */ #ifdef FTP_SRP FTA_SRP, /* SRP */ #endif /* FTP_SRP */ #ifdef FTP_KRB4 FTA_K4, /* Kerberos 4 */ #endif /* FTP_KRB4 */ #ifdef CK_SSL FTA_TLS, /* TLS */ FTA_SSL, /* SSL */ #endif /* CK_SSL */ 0 }; static struct keytab ftpauth[] = { /* SET FTP AUTHTYPE cmd table */ { "automatic", FTA_AUTO, CM_INV }, #ifdef FTP_GSSAPI { "gssapi-krb5", FTA_GK5, 0 }, #endif /* FTP_GSSAPI */ #ifdef FTP_KRB4 { "k4", FTA_K4, CM_INV }, #endif /* FTP_KRB4 */ #ifdef FTP_GSSAPI { "k5", FTA_GK5, CM_INV }, #endif /* FTP_GSSAPI */ #ifdef FTP_KRB4 { "kerberos4", FTA_K4, 0 }, #endif /* FTP_KRB4 */ #ifdef FTP_GSSAPI { "kerberos5", FTA_GK5, CM_INV }, #endif /* FTP_GSSAPI */ #ifdef FTP_KRB4 { "kerberos_iv",FTA_K4, CM_INV }, #endif /* FTP_KRB4 */ #ifdef FTP_GSSAPI { "kerberos_v", FTA_GK5, CM_INV }, #endif /* FTP_GSSAPI */ #ifdef FTP_KRB4 { "krb4", FTA_K4, CM_INV }, #endif /* FTP_KRB4 */ #ifdef FTP_GSSAPI { "krb5", FTA_GK5, CM_INV }, #endif /* FTP_GSSAPI */ #ifdef FTP_SRP { "srp", FTA_SRP, 0 }, #endif /* FTP_SRP */ #ifdef CK_SSL { "ssl", FTA_SSL, 0 }, { "tls", FTA_TLS, 0 }, #endif /* CK_SSL */ { "", 0, 0 } }; static int nftpauth = (sizeof(ftpauth) / sizeof(struct keytab)) - 1; #ifdef FTP_SRP #define SRP_CIPHER 1 #define SRP_HASH 2 static struct keytab ftpsrp[] = { /* SET FTP SRP command table */ { "cipher", SRP_CIPHER, 0 }, { "hash", SRP_HASH, 0 }, { "", 0, 0 } }; static int nftpsrp = (sizeof(ftpsrp) / sizeof(struct keytab)) - 1; #endif /* FTP_SRP */ #endif /* FTP_SECURITY */ static struct keytab ftpset[] = { /* SET FTP commmand table */ { "anonymous-password", FTS_APW, 0 }, #ifdef FTP_SECURITY { "authtype", FTS_ATP, 0 }, { "autoauthentication", FTS_AUT, 0 }, { "autoencryption", FTS_CRY, 0 }, #endif /* FTP_SECURITY */ { "autologin", FTS_LOG, 0 }, { "bug", FTS_BUG, 0 }, #ifndef NOCSETS { "character-set-translation",FTS_XLA, 0 }, #endif /* NOCSETS */ { "collision", FTS_FNC, 0 }, #ifdef FTP_SECURITY { "command-protection-level", FTS_CPL, 0 }, { "cpl", FTS_CPL, CM_INV }, { "credential-forwarding", FTS_CFW, 0 }, { "da", FTS_DAT, CM_INV|CM_ABR }, { "data-protection-level", FTS_DPL, 0 }, #endif /* FTP_SECURITY */ { "dates", FTS_DAT, 0 }, { "debug", FTS_DBG, 0 }, { "display", FTS_DIS, 0 }, #ifdef FTP_SECURITY { "dpl", FTS_DPL, CM_INV }, #endif /* FTP_SECURITY */ { "error-action", FTS_ERR, 0 }, { "filenames", FTS_CNV, 0 }, { "get-filetype-switching", FTS_GFT, 0 }, { "passive-mode", FTS_PSV, 0 }, { "pasv", FTS_PSV, CM_INV }, { "permissions", FTS_PRM, 0 }, { "progress-messages", FTS_TST, 0 }, { "send-port-commands", FTS_SPC, 0 }, #ifndef NOCSETS { "server-character-set", FTS_CSR, 0 }, #endif /* NOCSETS */ { "server-time-offset", FTS_STO, 0 }, #ifdef FTP_SRP { "srp", FTS_SRP, 0 }, #else { "srp", FTS_SRP, CM_INV }, #endif /* FTP_SRP */ #ifdef FTP_TIMEOUT { "timeout", FTS_TMO, 0 }, #endif /* FTP_TIMEOUT */ { "type", FTS_TYP, 0 }, { "unique-server-names", FTS_USN, 0 }, { "verbose-mode", FTS_VBM, 0 }, { "", 0, 0 } }; static int nftpset = (sizeof(ftpset) / sizeof(struct keytab)) - 1; /* GET and PUT switches are approximately the same as Kermit GET and SEND, and use the same SND_xxx definitions, but hijack a couple for FTP use. Don't just make up new ones, since the number of SND_xxx options must be known in advance for the switch-parsing arrays. */ #define SND_USN SND_PRO /* /UNIQUE instead of /PROTOCOL */ #define SND_PRM SND_PIP /* /PERMISSIONS instead of /PIPES */ #define SND_TEN SND_CAL /* /TENEX instead of /CALIBRATE */ static struct keytab putswi[] = { /* FTP PUT switch table */ { "/after", SND_AFT, CM_ARG }, #ifdef PUTARRAY { "/array", SND_ARR, CM_ARG }, #endif /* PUTARRAY */ { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR }, { "/as-name", SND_ASN, CM_ARG }, { "/ascii", SND_TXT, CM_INV }, { "/b", SND_BIN, CM_INV|CM_ABR }, { "/before", SND_BEF, CM_ARG }, { "/binary", SND_BIN, 0 }, #ifdef PUTPIPE { "/command", SND_CMD, CM_PSH }, #endif /* PUTPIPE */ #ifdef COMMENT /* This works but it's dangerous */ #ifdef DOUPDATE { "/dates-differ", SND_DIF, CM_INV }, #endif /* DOUPDATE */ #endif /* COMMENT */ { "/delete", SND_DEL, 0 }, #ifdef UNIXOROSK { "/dotfiles", SND_DOT, 0 }, #endif /* UNIXOROSK */ { "/error-action", SND_ERR, CM_ARG }, { "/except", SND_EXC, CM_ARG }, { "/filenames", SND_NAM, CM_ARG }, #ifdef PIPESEND #ifndef NOSPL { "/filter", SND_FLT, CM_ARG|CM_PSH }, #endif /* NOSPL */ #endif /* PIPESEND */ #ifdef CKSYMLINK { "/followlinks", SND_LNK, 0 }, #endif /* CKSYMLINK */ #ifdef VMS { "/image", SND_IMG, 0 }, #else { "/image", SND_BIN, CM_INV }, #endif /* VMS */ { "/larger-than", SND_LAR, CM_ARG }, { "/listfile", SND_FIL, CM_ARG }, #ifndef NOCSETS { "/local-character-set", SND_CSL, CM_ARG }, #endif /* NOCSETS */ #ifdef CK_TMPDIR { "/move-to", SND_MOV, CM_ARG }, #endif /* CK_TMPDIR */ { "/nobackupfiles", SND_NOB, 0 }, #ifdef UNIXOROSK { "/nodotfiles", SND_NOD, 0 }, #endif /* UNIXOROSK */ #ifdef CKSYMLINK { "/nofollowlinks", SND_NLK, 0 }, #endif /* CKSYMLINK */ { "/not-after", SND_NAF, CM_ARG }, { "/not-before", SND_NBE, CM_ARG }, #ifdef UNIX { "/permissions", SND_PRM, CM_ARG }, #else { "/permissions", SND_PRM, CM_ARG|CM_INV }, #endif /* UNIX */ { "/quiet", SND_SHH, 0 }, #ifdef FTP_RESTART { "/recover", SND_RES, 0 }, #endif /* FTP_RESTART */ #ifdef RECURSIVE { "/recursive", SND_REC, 0 }, #endif /* RECURSIVE */ { "/rename-to", SND_REN, CM_ARG }, #ifdef FTP_RESTART { "/restart", SND_RES, CM_INV }, #endif /* FTP_RESTART */ #ifndef NOCSETS { "/server-character-set", SND_CSR, CM_ARG }, #endif /* NOCSETS */ { "/server-rename-to", SND_SRN, CM_ARG }, { "/simulate", SND_SIM, 0 }, { "/since", SND_AFT, CM_INV|CM_ARG }, { "/smaller-than", SND_SMA, CM_ARG }, #ifdef COMMENT { "/starting-at", SND_STA, CM_ARG }, #endif /* COMMENT */ #ifdef RECURSIVE { "/subdirectories", SND_REC, CM_INV }, #endif /* RECURSIVE */ { "/tenex", SND_TEN, 0 }, { "/text", SND_TXT, 0 }, #ifndef NOCSETS { "/transparent", SND_XPA, 0 }, #endif /* NOCSETS */ { "/type", SND_TYP, CM_ARG }, #ifdef DOUPDATE { "/update", SND_UPD, 0 }, #endif /* DOUPDATE */ { "/unique-server-names", SND_USN, 0 }, { "", 0, 0 } }; static int nputswi = (sizeof(putswi) / sizeof(struct keytab)) - 1; static struct keytab getswi[] = { /* FTP [M]GET switch table */ { "/after", SND_AFT, CM_INV }, { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR }, { "/as-name", SND_ASN, CM_ARG }, { "/ascii", SND_TXT, CM_INV }, { "/before", SND_BEF, CM_INV }, { "/binary", SND_BIN, 0 }, { "/collision", SND_COL, CM_ARG }, #ifdef PUTPIPE { "/command", SND_CMD, CM_PSH }, #endif /* PUTPIPE */ { "/delete", SND_DEL, 0 }, { "/error-action", SND_ERR, CM_ARG }, { "/except", SND_EXC, CM_ARG }, { "/filenames", SND_NAM, CM_ARG }, #ifdef PIPESEND #ifndef NOSPL { "/filter", SND_FLT, CM_ARG|CM_PSH }, #endif /* NOSPL */ #endif /* PIPESEND */ #ifdef VMS { "/image", SND_IMG, 0 }, #else { "/image", SND_BIN, CM_INV }, #endif /* VMS */ { "/larger-than", SND_LAR, CM_ARG }, { "/listfile", SND_FIL, CM_ARG }, #ifndef NOCSETS { "/local-character-set", SND_CSL, CM_ARG }, #endif /* NOCSETS */ { "/match", SND_PAT, CM_ARG }, { "/ml", SND_MLS, CM_INV|CM_ABR }, { "/mls", SND_MLS, CM_INV|CM_ABR }, { "/mlsd", SND_MLS, 0 }, { "/mlst", SND_MLS, CM_INV }, #ifdef CK_TMPDIR { "/move-to", SND_MOV, CM_ARG }, #endif /* CK_TMPDIR */ { "/namelist", SND_NML, CM_ARG }, { "/nlst", SND_NLS, 0 }, { "/nobackupfiles", SND_NOB, 0 }, { "/nodotfiles", SND_NOD, 0 }, #ifdef DOUPDATE { "/dates-differ", SND_DIF, CM_INV }, #endif /* DOUPDATE */ { "/not-after", SND_NAF, CM_INV }, { "/not-before", SND_NBE, CM_INV }, { "/permissions", SND_PRM, CM_INV }, { "/quiet", SND_SHH, 0 }, #ifdef FTP_RESTART { "/recover", SND_RES, 0 }, #endif /* FTP_RESTART */ #ifdef RECURSIVE { "/recursive", SND_REC, 0 }, #endif /* RECURSIVE */ { "/rename-to", SND_REN, CM_ARG }, #ifdef FTP_RESTART { "/restart", SND_RES, CM_INV }, #endif /* FTP_RESTART */ #ifndef NOCSETS { "/server-character-set", SND_CSR, CM_ARG }, #endif /* NOCSETS */ { "/server-rename-to", SND_SRN, CM_ARG }, { "/smaller-than", SND_SMA, CM_ARG }, #ifdef RECURSIVE { "/subdirectories", SND_REC, CM_INV }, #endif /* RECURSIVE */ { "/text", SND_TXT, 0 }, { "/tenex", SND_TEN, 0 }, #ifndef NOCSETS { "/transparent", SND_XPA, 0 }, #endif /* NOCSETS */ { "/to-screen", SND_MAI, 0 }, #ifdef DOUPDATE { "/update", SND_UPD, CM_INV }, #endif /* DOUPDATE */ { "", 0, 0 } }; static int ngetswi = (sizeof(getswi) / sizeof(struct keytab)) - 1; static struct keytab delswi[] = { /* FTP [M]DELETE switch table */ { "/error-action", SND_ERR, CM_ARG }, { "/except", SND_EXC, CM_ARG }, { "/filenames", SND_NAM, CM_ARG }, { "/larger-than", SND_LAR, CM_ARG }, { "/nobackupfiles", SND_NOB, 0 }, #ifdef UNIXOROSK { "/nodotfiles", SND_NOD, 0 }, #endif /* UNIXOROSK */ { "/quiet", SND_SHH, 0 }, #ifdef RECURSIVE { "/recursive", SND_REC, 0 }, #endif /* RECURSIVE */ { "/smaller-than", SND_SMA, CM_ARG }, #ifdef RECURSIVE { "/subdirectories", SND_REC, CM_INV }, #endif /* RECURSIVE */ { "", 0, 0 } }; static int ndelswi = (sizeof(delswi) / sizeof(struct keytab)) - 1; static struct keytab fntab[] = { /* Filename conversion keyword table */ { "automatic", 2, CNV_AUTO }, { "converted", 1, CNV_CNV }, { "literal", 0, CNV_LIT } }; static int nfntab = (sizeof(fntab) / sizeof(struct keytab)); static struct keytab ftptyp[] = { /* SET FTP TYPE table */ { "ascii", FTT_ASC, 0 }, { "binary", FTT_BIN, 0 }, { "tenex", FTT_TEN, 0 }, { "text", FTT_ASC, CM_INV }, { "", 0, 0 } }; static int nftptyp = (sizeof(ftptyp) / sizeof(struct keytab)) - 1; #ifdef FTP_SECURITY static struct keytab ftppro[] = { /* SET FTP PROTECTION-LEVEL table */ { "clear", FPL_CLR, 0 }, { "confidential", FPL_CON, 0 }, { "private", FPL_PRV, 0 }, { "safe", FPL_SAF, 0 }, { "", 0, 0 } }; static int nftppro = (sizeof(ftppro) / sizeof(struct keytab)) - 1; #endif /* FTP_SECURITY */ /* Definitions for FTP from RFC765. */ /* Reply codes */ #define REPLY_PRELIM 1 /* Positive preliminary */ #define REPLY_COMPLETE 2 /* Positive completion */ #define REPLY_CONTINUE 3 /* Positive intermediate */ #define REPLY_TRANSIENT 4 /* Transient negative completion */ #define REPLY_ERROR 5 /* Permanent negative completion */ #define REPLY_SECURE 6 /* Security encoded message */ /* Form codes and names */ #define FORM_N 1 /* Non-print */ #define FORM_T 2 /* Telnet format effectors */ #define FORM_C 3 /* Carriage control (ASA) */ /* Structure codes and names */ #define STRU_F 1 /* File (no record structure) */ #define STRU_R 2 /* Record structure */ #define STRU_P 3 /* Page structure */ /* Mode types and names */ #define MODE_S 1 /* Stream */ #define MODE_B 2 /* Block */ #define MODE_C 3 /* Compressed */ /* Protection levels and names */ #define PROT_C 1 /* Clear */ #define PROT_S 2 /* Safe */ #define PROT_P 3 /* Private */ #define PROT_E 4 /* Confidential */ #ifdef COMMENT /* Not used */ #ifdef FTP_NAMES char *strunames[] = {"0", "File", "Record", "Page" }; char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" }; char *modenames[] = {"0", "Stream", "Block", "Compressed" }; char *levelnames[] = {"0", "Clear", "Safe", "Private", "Confidential" }; #endif /* FTP_NAMES */ /* Record Tokens */ #define REC_ESC '\377' /* Record-mode Escape */ #define REC_EOR '\001' /* Record-mode End-of-Record */ #define REC_EOF '\002' /* Record-mode End-of-File */ /* Block Header */ #define BLK_EOR 0x80 /* Block is End-of-Record */ #define BLK_EOF 0x40 /* Block is End-of-File */ #define BLK_REPLY_ERRORS 0x20 /* Block might have errors */ #define BLK_RESTART 0x10 /* Block is Restart Marker */ #define BLK_BYTECOUNT 2 /* Bytes in this block */ #endif /* COMMENT */ #define RADIX_ENCODE 0 /* radix_encode() function codes */ #define RADIX_DECODE 1 /* The default setpbsz() value in the Unix FTP client is 1<<20 (1MB). This results in a serious performance degradation due to the increased number of page faults and the inability to overlap encrypt/decrypt, file i/o, and network i/o. So instead we set the value to 1<<13 (8K), about half the size of the typical TCP window. Maybe we should add a command to allow the value to be changed. */ #define DEFAULT_PBSZ 1<<13 /* Prototypes */ _PROTOTYP(int remtxt, (char **) ); _PROTOTYP(char * gskreason, (int) ); _PROTOTYP(static int ftpclose,(void)); _PROTOTYP(static int zzsend, (int, CHAR)); _PROTOTYP(static int getreply,(int,int,int,int,int)); _PROTOTYP(static int radix_encode,(CHAR[], CHAR[], int, int *, int)); _PROTOTYP(static int setpbsz,(unsigned int)); _PROTOTYP(static int recvrequest,(char *,char *,char *,char *, int,int,char *,int,int,int)); _PROTOTYP(static int ftpcmd,(char *,char *,int,int,int)); #ifdef FTP_SECURITY _PROTOTYP(static int fts_cpl,(int)); _PROTOTYP(static int fts_dpl,(int)); _PROTOTYP(static int ftp_auth, (void)); #endif /* FTP_SECURITY */ _PROTOTYP(static int ftp_user, (char *, char *, char *)); _PROTOTYP(static int ftp_login, (char *)); _PROTOTYP(static int ftp_reset, (void)); _PROTOTYP(static int ftp_rename, (char *, char *)); _PROTOTYP(static int ftp_umask, (char *)); _PROTOTYP(static int secure_flush, (int)); #ifdef COMMENT _PROTOTYP(static int secure_putc, (char, int)); #endif /* COMMENT */ _PROTOTYP(static int secure_write, (int, CHAR *, unsigned int)); _PROTOTYP(static int scommand, (char *)); _PROTOTYP(static int secure_putbuf, (int, CHAR *, unsigned int)); _PROTOTYP(static int secure_getc, (int, int)); _PROTOTYP(static int secure_getbyte, (int, int)); _PROTOTYP(static int secure_read, (int, char *, int)); _PROTOTYP(static int initconn, (void)); _PROTOTYP(static int dataconn, (char *)); _PROTOTYP(static int setprotbuf,(unsigned int)); _PROTOTYP(static int sendrequest, (char *, char *, char *, int,int,int,int)); _PROTOTYP(static char * radix_error,(int)); _PROTOTYP(static char * ftp_hookup,(char *, int, int)); _PROTOTYP(static CHAR * remote_files, (int, CHAR *, CHAR *, int)); _PROTOTYP(static VOID mlsreset, (void)); _PROTOTYP(static VOID secure_error, (char *fmt, ...)); _PROTOTYP(static VOID lostpeer, (void)); _PROTOTYP(static VOID cancel_remote, (int)); _PROTOTYP(static VOID changetype, (int, int)); _PROTOTYP(static sigtype cmdcancel, (int)); #ifdef FTP_SRP _PROTOTYP(static int srp_reset, ()); _PROTOTYP(static int srp_ftp_auth, (char *,char *,char *)); _PROTOTYP(static int srp_put, (CHAR *, CHAR **, int, int *)); _PROTOTYP(static int srp_get, (CHAR **, CHAR **, int *, int *)); _PROTOTYP(static int srp_encode, (int, CHAR *, CHAR *, unsigned int)); _PROTOTYP(static int srp_decode, (int, CHAR *, CHAR *, unsigned int)); _PROTOTYP(static int srp_selcipher, (char *)); _PROTOTYP(static int srp_selhash, (char *)); #endif /* FTP_SRP */ #ifdef FTP_GSSAPI _PROTOTYP(static void user_gss_error,(OM_uint32, OM_uint32,char *)); #endif /* FTP_GSSAPI */ /* D O F T P A R G -- Do an FTP command-line argument. */ #ifdef FTP_SECURITY #ifndef NOICP #define FT_NOGSS 1 #define FT_NOK4 2 #define FT_NOSRP 3 #define FT_NOSSL 4 #define FT_NOTLS 5 #define FT_CERTFI 6 #define FT_OKCERT 7 #define FT_DEBUG 8 #define FT_KEY 9 #define FT_SECURE 10 #define FT_VERIFY 11 static struct keytab ftpztab[] = { { "!gss", FT_NOGSS, 0 }, { "!krb4", FT_NOK4, 0 }, { "!srp", FT_NOSRP, 0 }, { "!ssl", FT_NOSSL, 0 }, { "!tls", FT_NOTLS, 0 }, { "cert", FT_CERTFI, CM_ARG }, { "certsok", FT_OKCERT, 0 }, { "debug", FT_DEBUG, 0 }, { "key", FT_KEY, CM_ARG }, { "nogss", FT_NOGSS, 0 }, { "nokrb4", FT_NOK4, 0 }, { "nosrp", FT_NOSRP, 0 }, { "nossl", FT_NOSSL, 0 }, { "notls", FT_NOTLS, 0 }, #ifdef COMMENT { "secure", FT_SECURE, 0 }, #endif /* COMMENT */ { "verify", FT_VERIFY, CM_ARG }, { "", 0, 0 } }; static int nftpztab = sizeof(ftpztab) / sizeof(struct keytab) - 1; /* The following cipher and hash tables should be replaced with dynamicly created versions based upon the linked library. */ #define SRP_BLOWFISH_ECB 1 #define SRP_BLOWFISH_CBC 2 #define SRP_BLOWFISH_CFB64 3 #define SRP_BLOWFISH_OFB64 4 #define SRP_CAST5_ECB 5 #define SRP_CAST5_CBC 6 #define SRP_CAST5_CFB64 7 #define SRP_CAST5_OFB64 8 #define SRP_DES_ECB 9 #define SRP_DES_CBC 10 #define SRP_DES_CFB64 11 #define SRP_DES_OFB64 12 #define SRP_DES3_ECB 13 #define SRP_DES3_CBC 14 #define SRP_DES3_CFB64 15 #define SRP_DES3_OFB64 16 static struct keytab ciphertab[] = { { "blowfish_ecb", SRP_BLOWFISH_ECB, 0 }, { "blowfish_cbc", SRP_BLOWFISH_CBC, 0 }, { "blowfish_cfb64", SRP_BLOWFISH_CFB64, 0 }, { "blowfish_ofb64", SRP_BLOWFISH_OFB64, 0 }, { "cast5_ecb", SRP_CAST5_ECB, 0 }, { "cast5_cbc", SRP_CAST5_CBC, 0 }, { "cast5_cfb64", SRP_CAST5_CFB64, 0 }, { "cast5_ofb64", SRP_CAST5_OFB64, 0 }, { "des_ecb", SRP_DES_ECB, 0 }, { "des_cbc", SRP_DES_CBC, 0 }, { "des_cfb64", SRP_DES_CFB64, 0 }, { "des_ofb64", SRP_DES_OFB64, 0 }, { "des3_ecb", SRP_DES3_ECB, 0 }, { "des3_cbc", SRP_DES3_CBC, 0 }, { "des3_cfb64", SRP_DES3_CFB64, 0 }, { "des3_ofb64", SRP_DES3_OFB64, 0 }, { "none", 0, 0 }, { "", 0, 0 } }; static int nciphertab = sizeof(ciphertab) / sizeof(struct keytab) - 1; #define SRP_MD5 1 #define SRP_SHA 2 static struct keytab hashtab[] = { { "md5", SRP_MD5, 0 }, { "none", 0, 0 }, { "sha", SRP_SHA, 0 }, { "", 0, 0 } }; static int nhashtab = sizeof(hashtab) / sizeof(struct keytab) - 1; #endif /* NOICP */ #endif /* FTP_SECURITY */ static char * #ifdef CK_ANSIC strval( char * s1, char * s2 ) #else strval(s1,s2) char * s1, * s2; #endif /* CK_ANSIC */ { if (!s1) s1 = ""; if (!s2) s2 = ""; return(*s1 ? s1 : (*s2 ? s2 : "(none)")); } #ifndef NOCSETS static char * rfnptr = NULL; static int rfnlen = 0; static char rfnbuf[RFNBUFSIZ]; /* Remote filename translate buffer */ static char * xgnbp = NULL; static int /* Helper function for xgnbyte() */ #ifdef CK_ANSIC strgetc(void) #else strgetc() #endif /* CK_ANSIC */ { int c; if (!xgnbp) return(-1); if (!*xgnbp) return(-1); c = (unsigned) *xgnbp++; return(((unsigned) c) & 0xff); } static int /* Helper function for xpnbyte() */ #ifdef CK_ANSIC strputc(char c) #else strputc(c) char c; #endif /* CK_ANSIC */ { rfnlen = rfnptr - rfnbuf; if (rfnlen >= (RFNBUFSIZ - 1)) return(-1); *rfnptr++ = c; *rfnptr = NUL; return(0); } #ifdef COMMENT static int #ifdef CK_ANSIC xprintc(char c) #else xprintc(c) char c; #endif /* CK_ANSIC */ { printf("%c",c); return(0); } #endif /* COMMENT */ #ifdef COMMENT /* K95: Check whether we need this */ static VOID #ifdef CK_ANSIC bytswap( int * c0, int * c1 ) #else bytswap(c0,c1) int * c0, * c1; #endif /* CK_ANSIC */ { int t; t = *c0; *c0 = *c1; *c1 = t; } #endif /* COMMENT */ #endif /* NOCSETS */ #ifdef CKLOGDIAL char ftplogbuf[CXLOGBUFL] = { NUL, NUL }; /* Connection Log */ int ftplogactive = 0; long ftplogprev = 0L; VOID ftplogend() { extern int dialog; extern char diafil[]; long d1, d2, t1, t2; char buf[32], * p; debug(F111,"ftp cx log active",ckitoa(dialog),ftplogactive); debug(F110,"ftp cx log buf",ftplogbuf,0); if (!ftplogactive || !ftplogbuf[0]) /* No active record */ return; ftplogactive = 0; /* Record is not active */ d1 = mjd((char *)ftplogbuf); /* Get start date of this session */ ckstrncpy(buf,ckdate(),31); /* Get current date */ d2 = mjd(buf); /* Convert them to mjds */ p = ftplogbuf; /* Get start time */ p[11] = NUL; p[14] = NUL; /* Convert to seconds */ t1 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15); p[11] = ':'; p[14] = ':'; p = buf; /* Get end time */ p[11] = NUL; p[14] = NUL; t2 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15); t2 = ((d2 - d1) * 86400L) + (t2 - t1); /* Compute elapsed time */ if (t2 > -1L) { ftplogprev = t2; p = hhmmss(t2); ckstrncat(ftplogbuf,"E=",CXLOGBUFL); /* Append to log record */ ckstrncat(ftplogbuf,p,CXLOGBUFL); } else ftplogprev = 0L; debug(F101,"ftp cx log dialog","",dialog); if (dialog) { /* If logging */ int x; x = diaopn(diafil,1,1); /* Open log in append mode */ if (x > 0) { debug(F101,"ftp cx log open","",x); x = zsoutl(ZDIFIL,ftplogbuf); /* Write the record */ debug(F101,"ftp cx log write","",x); x = zclose(ZDIFIL); /* Close the log */ debug(F101,"ftp cx log close","",x); } } } VOID dologftp() { ftplogend(); /* Previous session not closed out? */ ftplogprev = 0L; ftplogactive = 1; /* Record is active */ ckmakxmsg(ftplogbuf,CXLOGBUFL, ckdate()," ",strval(ftp_logname,NULL)," ",ckgetpid(), " T=FTP N=", strval(ftp_host,NULL)," H=",myhost, " P=", ckitoa(ftp_port)," "); /* SMS 2007/02/15 */ debug(F110,"ftp cx log begin",ftplogbuf,0); } #endif /* CKLOGDIAL */ static char * dummy[2] = { NULL, NULL }; static struct keytab modetab[] = { { "active", 0, 0 }, { "passive", 1, 0 } }; #ifndef NOCMDL int /* Called from ckuusy.c */ #ifdef CK_ANSIC doftparg(char c) #else doftparg(c) char c; #endif /* CK_ANSIC */ /* doftparg */ { char *xp; extern char **xargv, *xarg0; extern int xargc, stayflg, haveftpuid; extern char uidbuf[]; xp = *xargv+1; /* Pointer for bundled args */ while (c) { if (ckstrchr("MuDPkcHzm",c)) { /* Options that take arguments */ if (*(xp+1)) { fatal("?Invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { fatal("?Required argument missing"); } } switch (c) { /* Big switch on arg */ case 'h': /* help */ printf("C-Kermit's FTP client command-line personality. Usage:\n"); printf(" %s [ options ] host [ port ] [-pg files ]\n\n",xarg0); printf("Options:\n"); printf(" -h = help (this message)\n"); printf(" -m mode = \"passive\" (default) or \"active\"\n"); printf(" -u name = username for autologin (or -M)\n"); printf(" -P password = password for autologin (RISKY)\n"); printf(" -A = autologin anonymously\n"); printf(" -D directory = cd after autologin\n"); printf(" -b = force binary mode\n"); printf(" -a = force text (\"ascii\") mode (or -T)\n"); printf(" -d = debug (double to add timestamps)\n"); printf(" -n = no autologin\n"); printf(" -v = verbose (default)\n"); printf(" -q = quiet\n"); printf(" -S = Stay (issue command prompt when done)\n"); printf(" -Y = do not execute Kermit init file\n"); printf(" -p files = files to put after autologin (or -s)\n"); printf(" -g files = files to get after autologin\n"); printf(" -R = recursive (for use with -p)\n"); #ifdef FTP_SECURITY printf("\nSecurity options:\n"); printf(" -k realm = Kerberos 4 realm\n"); printf(" -f = Kerboros 5 credentials forwarding\n"); printf(" -x = autoencryption mode\n"); printf(" -c cipher = SRP cipher type\n"); printf(" -H hash = SRP encryption hash\n"); printf(" -z option = Security options\n"); #endif /* FTP_SECURITY */ printf("\n-p or -g, if given, should be last. Example:\n"); printf(" ftp -A kermit.columbia.edu -D kermit -ag TESTFILE\n"); doexit(GOOD_EXIT,-1); break; case 'R': /* Recursive */ recursive = 1; break; case 'd': /* Debug */ #ifdef DEBUG if (deblog) { extern int debtim; debtim = 1; } else { deblog = debopn("debug.log",0); debok = 1; } #endif /* DEBUG */ /* fall thru on purpose */ case 't': /* Trace */ ftp_deb++; break; case 'n': /* No autologin */ ftp_log = 0; break; case 'i': /* No prompt */ case 'v': /* Verbose */ break; /* (ignored) */ case 'q': /* Quiet */ quiet = 1; break; case 'S': /* Stay */ stayflg = 1; break; case 'M': case 'u': /* My User Name */ if ((int)strlen(*xargv) > 63) { fatal("username too long"); } ckstrncpy(uidbuf,*xargv,UIDBUFLEN); haveftpuid = 1; break; case 'A': ckstrncpy(uidbuf,"anonymous",UIDBUFLEN); haveftpuid = 1; break; case 'T': /* Text */ case 'a': /* "ascii" */ case 'b': /* Binary */ binary = (c == 'b') ? FTT_BIN : FTT_ASC; ftp_xfermode = XMODE_M; filepeek = 0; patterns = 0; break; case 'g': /* Get */ case 'p': /* Put */ case 's': { /* Send (= Put) */ int havefiles, rc; if (ftp_action) { fatal("Only one FTP action at a time please"); } if (*(xp+1)) { fatal("invalid argument bundling after -s"); } nfils = 0; /* Initialize file counter */ havefiles = 0; /* Assume nothing to send */ cmlist = xargv + 1; /* Remember this pointer */ while (++xargv, --xargc > 0) { /* Traverse the list */ if (c == 'g') { havefiles++; nfils++; continue; } #ifdef RECURSIVE if (!strcmp(*xargv,".")) { havefiles = 1; nfils++; recursive = 1; } else #endif /* RECURSIVE */ if ((rc = zchki(*xargv)) > -1 || (rc == -2)) { if (rc != -2) havefiles = 1; nfils++; } else if (iswild(*xargv) && nzxpand(*xargv,0) > 0) { havefiles = 1; nfils++; } } xargc++, xargv--; /* Adjust argv/argc */ if (!havefiles) { if (c == 'g') { fatal("No files to put"); } else { fatal("No files to get"); } } ftp_action = c; break; } case 'D': /* Directory */ makestr(&ftp_rdir,*xargv); break; case 'm': /* Mode (Active/Passive */ ftp_psv = lookup(modetab,*xargv,2,NULL); if (ftp_psv < 0) fatal("Invalid mode"); break; case 'P': makestr(&ftp_tmp,*xargv); /* You-Know-What */ break; case 'Y': /* No initialization file */ break; /* (already done in prescan) */ #ifdef CK_URL case 'U': { /* URL */ /* These are set by urlparse() - any not set are NULL */ if (g_url.hos) { /* Kermit has accepted host:port notation since many years before URLs were invented. Unfortunately, URLs conflict with this notation. Thus "ftp host:449" looks like a URL and results in service = host and host = 449. Here we try to catch this situation transparently to the user. */ if (ckstrcmp(g_url.svc,"ftp",-1,0) #ifdef CK_SSL && ckstrcmp(g_url.svc,"ftps",-1,0) #endif /* CK_SSL */ ) { if (!g_url.usr && !g_url.psw && !g_url.por && !g_url.pth) { g_url.por = g_url.hos; g_url.hos = g_url.svc; g_url.svc = "ftp"; } else { ckmakmsg(tmpbuf,TMPBUFSIZ,"Non-FTP URL: service=", g_url.svc," host=",g_url.hos); fatal(tmpbuf); } } makestr(&ftp_host,g_url.hos); if (g_url.usr) { haveftpuid = 1; ckstrncpy(uidbuf,g_url.usr,UIDBUFLEN); makestr(&ftp_logname,uidbuf); } if (g_url.psw) { makestr(&ftp_tmp,g_url.psw); } if (g_url.pth) { if (!g_url.usr) { haveftpuid = 1; ckstrncpy(uidbuf,"anonymous",UIDBUFLEN); makestr(&ftp_logname,uidbuf); } if (ftp_action) { fatal("Only one FTP action at a time please"); } if (!stayflg) quiet = 1; nfils = 1; dummy[0] = g_url.pth; cmlist = dummy; ftp_action = 'g'; } xp = NULL; haveurl = 1; } break; } #endif /* CK_URL */ #ifdef FTP_SECURITY case 'k': { /* K4 Realm */ #ifdef FTP_KRB4 ckstrncpy(ftp_realm,*xargv, REALM_SZ); #endif /* FTP_KRB4 */ if (ftp_deb) printf("K4 Realm = [%s]\n",*xargv); break; } case 'f': { #ifdef FTP_GSSAPI ftp_cfw = 1; if (ftp_deb) printf("K5 Credentials Forwarding\n"); #else /* FTP_GSSAPI */ printf("K5 Credentials Forwarding not supported\n"); #endif /* FTP_GSSAPI */ break; } case 'x': { ftp_cry = 1; if (ftp_deb) printf("Autoencryption\n"); break; } case 'c': { /* Cipher */ #ifdef FTP_SRP if (!srp_selcipher(*xargv)) { if (ftp_deb) printf("SRP cipher type: \"%s\"\n",*xargv); } else printf("?Invalid SRP cipher type: \"%s\"\n",*xargv); #else /* FTP_SRP */ printf("?SRP not supported\n"); #endif /* FTP_SRP */ break; } case 'H': { #ifdef FTP_SRP if (!srp_selhash(*xargv)) { if (ftp_deb) printf("SRP hash type: \"%s\"\n",*xargv); } else printf("?Invalid SRP hash type: \"%s\"\n",*xargv); #else /* FTP_SRP */ printf("?SRP not supported\n"); #endif /* FTP_SRP */ break; } case 'z': { /* *xargv contains a value of the form tag=value */ /* we need to lookup the tag and save the value */ char * p = NULL, * q = NULL; int x, z; makestr(&p,*xargv); y = ckindex("=",p,0,0,1); if (y > 0) p[y-1] = '\0'; x = lookup(ftpztab,p,nftpztab,&z); if (x < 0) { printf("?Invalid security option: \"%s\"\n",p); } else { if (ftp_deb) printf("Security option: \"%s",p); if (ftpztab[z].flgs & CM_ARG) { if (y <= 0) fatal("?Missing required value"); q = &p[y]; if (!*q) fatal("?Missing required value"); if (ftp_deb) printf("=%s\"",q); } switch (ftpztab[z].kwval) { /* -z options w/args */ case FT_NOGSS: #ifdef FTP_GSSAPI for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) { if (ftp_auth_type[z] == FTA_GK5) { for (y = z; y < (FTPATYPS-1) && ftp_auth_type[y]; y++ ) ftp_auth_type[y] = ftp_auth_type[y+1]; ftp_auth_type[FTPATYPS-1] = 0; break; } } #endif /* FTP_GSSAPI */ break; case FT_NOK4: #ifdef FTP_KRB4 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) { if (ftp_auth_type[z] == FTA_K4) { for (y = z; y < (FTPATYPS-1) && ftp_auth_type[y]; y++ ) ftp_auth_type[y] = ftp_auth_type[y+1]; ftp_auth_type[FTPATYPS-1] = 0; break; } } #endif /* FTP_KRB4 */ break; case FT_NOSRP: #ifdef FTP_SRP for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) { if (ftp_auth_type[z] == FTA_SRP) { for (y = z; y < (FTPATYPS-1) && ftp_auth_type[y]; y++ ) ftp_auth_type[y] = ftp_auth_type[y+1]; ftp_auth_type[FTPATYPS-1] = 0; break; } } #endif /* FTP_SRP */ break; case FT_NOSSL: #ifdef CK_SSL for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) { if (ftp_auth_type[z] == FTA_SSL) { for (y = z; y < (FTPATYPS-1) && ftp_auth_type[y]; y++ ) ftp_auth_type[y] = ftp_auth_type[y+1]; ftp_auth_type[FTPATYPS-1] = 0; break; } } #endif /* CK_SSL */ break; case FT_NOTLS: #ifdef CK_SSL for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) { if (ftp_auth_type[z] == FTA_TLS) { for (y = z; y < (FTPATYPS-1) && ftp_auth_type[y]; y++ ) ftp_auth_type[y] = ftp_auth_type[y+1]; ftp_auth_type[FTPATYPS-1] = 0; break; } } #endif /* CK_SSL */ break; case FT_CERTFI: #ifdef CK_SSL makestr(&ssl_rsa_cert_file,q); #endif /* CK_SSL */ break; case FT_OKCERT: #ifdef CK_SSL ssl_certsok_flag = 1; #endif /* CK_SSL */ break; case FT_DEBUG: #ifdef DEBUG if (deblog) { extern int debtim; debtim = 1; } else { deblog = debopn("debug.log",0); } #endif /* DEBUG */ break; case FT_KEY: #ifdef CK_SSL makestr(&ssl_rsa_key_file,q); #endif /* CK_SSL */ break; case FT_SECURE: /* no equivalent */ break; case FT_VERIFY: #ifdef CK_SSL if (!rdigits(q)) printf("?Bad number: %s\n",q); ssl_verify_flag = atoi(q); #endif /* CK_SSL */ break; } } if (ftp_deb) printf("\"\n"); free(p); break; } #endif /* FTP_SECURITY */ default: fatal2(*xargv, "unknown command-line option, type \"ftp -h\" for help" ); } if (!xp) break; c = *++xp; /* See if options are bundled */ } return(0); } #endif /* NOCMDL */ int ftpisconnected() { return(connected); } int ftpisloggedin() { return(connected ? loggedin : 0); } int ftpissecure() { return((ftp_dpl == FPL_CLR && !ssl_ftp_proxy) ? 0 : 1); } static VOID #ifdef CK_ANSIC ftscreen(int n, char c, CK_OFF_T z, char *s) #else ftscreen(n, c, z, s) int n; char c; CK_OFF_T z; char * s; #endif /* CK_ANSIC */ { if (displa && fdispla && !backgrd && !quiet && !out2screen) { if (!dpyactive) { ckscreen(SCR_PT,'S',(CK_OFF_T)0,""); dpyactive = 1; } ckscreen(n,c,z,s); } } #ifndef OS2 /* g m s t i m e r -- Millisecond timer */ long gmstimer() { #ifdef HAVE_MSECS /* For those versions of ztime() that also set global ztmsec. */ char *p = NULL; long z; ztime(&p); if (!p) return(0L); if (!*p) return(0L); z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17); return(z * 1000 + ztmsec); #else return((long)time(NULL) * 1000L); #endif /* HAVE_MSECS */ } #endif /* OS2 */ /* d o s e t f t p -- The SET FTP command */ int dosetftp() { int cx; if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0) /* Set what? */ return(cx); switch (cx) { case FTS_FNC: /* Filename collision action */ if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); ftp_fnc = x; return(1); case FTS_CNV: /* Filename conversion */ if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); ftp_cnv = x; return(1); case FTS_DBG: /* Debug messages */ return(seton(&ftp_deb)); case FTS_LOG: /* Auto-login */ return(seton(&ftp_log)); case FTS_PSV: /* Passive mode */ return(dosetftppsv()); case FTS_SPC: /* Send port commands */ x = seton(&ftp_spc); if (x > 0) sendport = ftp_spc; return(x); case FTS_TYP: /* Type */ if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); ftp_typ = x; g_ftp_typ = x; tenex = (ftp_typ == FTT_TEN); return(1); case FTS_USN: /* Unique server names */ return(seton(&ftp_usn)); case FTS_VBM: /* Verbose mode */ if ((x = seton(&ftp_vbm)) < 0) /* Per-command copy */ return(x); ftp_vbx = ftp_vbm; /* Global sticky copy */ return(x); case FTS_TST: /* "if (testing)" messages */ return(seton(&testing)); case FTS_PRM: /* Send permissions */ return(setonaut(&ftp_prm)); case FTS_AUT: /* Auto-authentication */ return(seton(&ftp_aut)); case FTS_ERR: /* Error action */ if ((x = cmkey(qorp,2,"","",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); ftp_err = x; return(success = 1); #ifndef NOCSETS case FTS_XLA: /* Translation */ return(seton(&ftp_xla)); case FTS_CSR: /* Server charset */ if ((x = cmkey(fcstab,nfilc,"character-set","utf8",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); ftp_csr = x; ftp_xla = 1; /* Also enable translation */ return(success = 1); #endif /* NOCSETS */ case FTS_GFT: return(seton(&get_auto)); /* GET-filetype-switching */ case FTS_DAT: return(seton(&ftp_dates)); /* Set file dates */ #ifdef FTP_TIMEOUT case FTS_TMO: /* Timeout */ if ((x = cmnum("Number of seconds","0",10,&z,xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); ftp_timeout = z; return(success = 1); #endif /* FTP_TIMEOUT */ case FTS_STO: { /* Server time offset */ char * s, * p = NULL; long k; if ((x = cmfld("[+-]hh[:mm[:ss]]","+0",&s,xxstring)) < 0) return(x); if (!strcmp(s,"+0")) { s = NULL; } else if ((x = delta2sec(s,&k)) < 0) { /* Check format */ printf("?Invalid time offset\n"); return(-9); } makestr(&p,s); /* Make a safe copy the string */ if ((x = cmcfm()) < 0) { /* Get confirmation */ if (p) makestr(&p,NULL); return(x); } fts_sto = p; /* Confirmed - set the string. */ return(success = 1); } case FTS_APW: { char * s; if ((x = cmtxt("Text", "", &s, xxstring)) < 0) return(x); makestr(&ftp_apw, *s ? s : NULL); return(success = 1); } case FTS_BUG: { if ((x = cmkey(ftpbugtab,nftpbug,"","",xxstring)) < 0) return(x); switch (x) { #ifdef CK_SSL case FTB_SV2: return seton(&ftp_bug_use_ssl_v2); case FTB_SV3: return seton(&ftp_bug_use_ssl_v3); #endif /* CK_SSL */ default: return(-2); } } #ifdef FTP_SECURITY case FTS_CRY: /* Auto-encryption */ return(seton(&ftp_cry)); case FTS_CFW: /* Credential-forwarding */ return(seton(&ftp_cfw)); case FTS_CPL: /* Command protection level */ if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); success = fts_cpl(x); return(success); case FTS_DPL: /* Data protection level */ if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); success = fts_dpl(x); return(success); case FTS_ATP: { /* FTP Auth Type */ int i, j, atypes[8]; for (i = 0; i < 8; i++) { if ((y = cmkey(ftpauth,nftpauth,"", (i == 0) ? "automatic" : "", xxstring)) < 0) { if (y == -3) break; return(y); } if (i > 0 && (y == FTA_AUTO)) { printf("?Choice may only be used in first position.\r\n"); return(-9); } for (j = 0; j < i; j++) { if (atypes[j] == y) { printf("\r\n?Choice has already been used.\r\n"); return(-9); } } atypes[i] = y; if (y == FTA_AUTO) { i++; break; } } if (i < 8) atypes[i] = 0; if ((z = cmcfm()) < 0) return(z); if (atypes[0] == FTA_AUTO) { i = 0; #ifdef FTP_GSSAPI ftp_auth_type[i++] = FTA_GK5; #endif /* FTP_GSSAPI */ #ifdef FTP_SRP ftp_auth_type[i++] = FTA_SRP; #endif /* FTP_SRP */ #ifdef FTP_KRB4 ftp_auth_type[i++] = FTA_K4; #endif /* FTP_KRB4 */ #ifdef CK_SSL ftp_auth_type[i++] = FTA_TLS; ftp_auth_type[i++] = FTA_SSL; #endif /* CK_SSL */ ftp_auth_type[i] = 0; } else { for (i = 0; i < 8; i++) ftp_auth_type[i] = atypes[i]; } return(success = 1); } case FTS_SRP: #ifdef FTP_SRP if ((x = cmkey(ftpsrp,nftpsrp,"","",xxstring)) < 0) return(x); switch (x) { case SRP_CIPHER: if ((x = cmkey(ciphertab,nciphertab,"","",xxstring)) < 0) return(x); if ((z = cmcfm()) < 0) return(z); success = !srp_selcipher(ciphertab[x].kwd); return(success); case SRP_HASH: if ((x = cmkey(hashtab,nhashtab,"","",xxstring)) < 0) return(x); if ((z = cmcfm()) < 0) return(z); success = !srp_selhash(hashtab[x].kwd); return(success = 1); default: if ((z = cmcfm()) < 0) return(z); return(-2); } #else /* FTP_SRP */ if ((z = cmcfm()) < 0) return(z); return(-2); #endif /* FTP_SRP */ #endif /* FTP_SECURITY */ case FTS_DIS: doxdis(2); /* 2 == ftp */ return(success = 1); default: return(-2); } } int ftpbye() { int x; if (!connected) return(1); if (testing) printf(" ftp closing %s...\n",ftp_host); x = ftpclose(); return((x > -1) ? 1 : 0); } /* o p e n f t p -- Parse FTP hostname & port and open */ static int #ifdef CK_ANSIC openftp( char * s, int opn_tls ) #else openftp(s,opn_tls) char * s; int opn_tls; #endif /* CK_ANSIC */ { char c, * p, * hostname = NULL, *hostsave = NULL, * service = NULL; int i, n, havehost = 0, getval = 0, rc = -9, opn_psv = -1, nologin = 0; int haveuser = 0; struct FDB sw, fl, cm; extern int nnetdir; /* Network services directory */ extern int nhcount; /* Lookup result */ extern char *nh_p[]; /* Network directory entry pointers */ extern char *nh_p2[]; /* Network directory entry nettype */ if (!s) return(-2); if (!*s) return(-2); makestr(&hostname,s); hostsave = hostname; makestr(&ftp_logname,NULL); anonymous = 0; noinit = 0; debug(F110,"ftp open",hostname,0); if (sav_psv > -1) { /* Restore prevailing active/passive */ ftp_psv = sav_psv; /* selection in case it was */ sav_psv = -1; /* temporarily overriden by a switch */ } if (sav_log > -1) { /* Ditto for autologin */ ftp_log = sav_log; sav_log = -1; } cmfdbi(&sw, /* Switches */ _CMKEY, "Service name or port;\n or switch", "", /* default */ "", /* addtl string data */ nftpswi, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: none */ xxstring, /* Processing function */ ftpswitab, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* A host name or address */ _CMFLD, /* fcode */ "", /* help */ "xYzBoo", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, &cm ); cmfdbi(&cm, /* Command confirmation */ _CMCFM, "", "", "", 0, 0, NULL, NULL, NULL ); for (n = 0;; n++) { rc = cmfdb(&sw); /* Parse a service name or a switch */ if (rc < 0) goto xopenftp; if (cmresult.fcode == _CMCFM) { /* Done? */ break; } else if (cmresult.fcode == _CMFLD) { /* Port */ if (ckstrcmp("xYzBoo",cmresult.sresult,-1,1)) makestr(&service,cmresult.sresult); else makestr(&service,opn_tls?"ftps":"ftp"); } else if (cmresult.fcode == _CMKEY) { /* Have a switch */ c = cmgbrk(); /* get break character */ getval = (c == ':' || c == '='); rc = -9; if (getval && !(cmresult.kflags & CM_ARG)) { printf("?This switch does not take arguments\n"); goto xopenftp; } if (!getval && (cmresult.kflags & CM_ARG)) { printf("?This switch requires an argument\n"); goto xopenftp; } switch (cmresult.nresult) { /* Switch */ case OPN_ANO: /* /ANONYMOUS */ anonymous++; nologin = 0; break; case OPN_NIN: /* /NOINIT */ noinit++; break; case OPN_NOL: /* /NOLOGIN */ nologin++; anonymous = 0; makestr(&ftp_logname,NULL); break; case OPN_PSW: /* /PASSWORD */ if (!anonymous) /* Don't log real passwords */ debok = 0; rc = cmfld("Password for FTP server","",&p,xxstring); if (rc == -3) { makestr(&ftp_tmp,NULL); } else if (rc < 0) { goto xopenftp; } else { makestr(&ftp_tmp,brstrip(p)); nologin = 0; } break; case OPN_USR: /* /USER */ rc = cmfld("Username for FTP server","",&p,xxstring); if (rc == -3) { makestr(&ftp_logname,NULL); } else if (rc < 0) { goto xopenftp; } else { nologin = 0; anonymous = 0; haveuser = 1; makestr(&ftp_logname,brstrip(p)); } break; case OPN_ACC: rc = cmfld("Account for FTP server","",&p,xxstring); if (rc == -3) { makestr(&ftp_acc,NULL); } else if (rc < 0) { goto xopenftp; } else { makestr(&ftp_acc,brstrip(p)); } break; case OPN_ACT: opn_psv = 0; break; case OPN_PSV: opn_psv = 1; break; case OPN_TLS: opn_tls = 1; break; default: break; } } if (n == 0) { /* After first time through */ cmfdbi(&sw, /* accept only switches */ _CMKEY, "\nCarriage return to confirm to command, or switch", "", "", nftpswi, 4, xxstring, ftpswitab, &cm ); } } #ifdef COMMENT debug(F100,"ftp openftp while exit","",0); rc = cmcfm(); debug(F101,"ftp openftp cmcfm rc","",rc); if (rc < 0) goto xopenftp; #endif /* COMMENT */ if (opn_psv > -1) { /* /PASSIVE or /ACTIVE switch given */ sav_psv = ftp_psv; ftp_psv = opn_psv; } if (nologin || haveuser) { /* /NOLOGIN or /USER switch given */ sav_log = ftp_log; ftp_log = haveuser ? 1 : 0; } if (*hostname == '=') { /* Bypass directory lookup */ hostname++; /* if hostname starts with '=' */ havehost++; } else if (isdigit(*hostname)) { /* or if it starts with a digit */ havehost++; } if (!service) makestr(&service,opn_tls?"ftps":"ftp"); #ifndef NODIAL if (!havehost && nnetdir > 0) { /* If there is a networks directory */ lunet(hostname); /* Look up the name */ debug(F111,"ftp openftp lunet",hostname,nhcount); if (nhcount == 0) { if (testing) printf(" ftp open trying \"%s %s\"...\n",hostname,service); success = ftpopen(hostname,service,opn_tls); debug(F101,"ftp openftp A ftpopen success","",success); rc = success; } else { int found = 0; for (i = 0; i < nhcount; i++) { if (nh_p2[i]) /* If network type specified */ if (ckstrcmp(nh_p2[i],"tcp/ip",strlen(nh_p2[i]),0)) continue; found++; makestr(&hostname,nh_p[i]); debug(F111,"ftpopen lunet substitution",hostname,i); if (testing) printf(" ftp open trying \"%s %s\"...\n",hostname,service); success = ftpopen(hostname,service,opn_tls); debug(F101,"ftp openftp B ftpopen success","",success); rc = success; if (success) break; } if (!found) { /* E.g. if no network types match */ if (testing) printf(" ftp open trying \"%s %s\"...\n",hostname,service); success = ftpopen(hostname,service,opn_tls); debug(F101,"ftp openftp C ftpopen success","",success); rc = success; } } } else { #endif /* NODIAL */ if (testing) printf(" ftp open trying \"%s %s\"...\n",hostname,service); success = ftpopen(hostname,service,opn_tls); debug(F111,"ftp openftp D ftpopen success",hostname,success); debug(F111,"ftp openftp D ftpopen connected",hostname,connected); rc = success; #ifndef NODIAL } #endif /* NODIAL */ xopenftp: debug(F101,"ftp openftp xopenftp rc","",rc); if (hostsave) free(hostsave); if (service) free(service); if (rc < 0 && ftp_logname) { free(ftp_logname); ftp_logname = NULL; } if (ftp_tmp) { free(ftp_tmp); ftp_tmp = NULL; } return(rc); } VOID /* 12 Aug 2007 */ #ifdef CK_ANSIC doftpglobaltype( int x ) #else doftpglobaltype(x) int x; #endif /* CK_ANSIC */ { ftp_xfermode = XMODE_M; /* Set manual FTP transfer mode */ ftp_typ = x; /* Used by top-level BINARY and */ g_ftp_typ = x; /* ASCII commands. */ get_auto = 0; forcetype = 1; } int doftpacct() { int x; char * s; if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0) return(x); CHECKCONN(); makestr(&ftp_acc,brstrip(s)); if (testing) printf(" ftp account: \"%s\"\n",ftp_acc); success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE); return(success); } int doftpusr() { /* Log in as USER */ extern char uidbuf[]; extern char pwbuf[]; extern int pwflg, pwcrypt; int x; char *s, * acct = ""; debok = 0; /* Don't log */ if ((x = cmfld("Remote username or ID",uidbuf,&s,xxstring)) < 0) return(x); ckstrncpy(line,brstrip(s),LINBUFSIZ); /* brstrip: 15 Jan 2003 */ if ((x = cmfld("Remote password","",&s,xxstring)) < 0) { if (x == -3) { /* no input */ if ( pwbuf[0] && pwflg ) { ckstrncpy(tmpbuf,(char *)pwbuf,TMPBUFSIZ); #ifdef OS2 if ( pwcrypt ) ck_encrypt((char *)tmpbuf); #endif /* OS2 */ } } else { return(x); } } else { ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ); } if ((x = cmtxt("Remote account\n or Enter or CR to confirm the command", "", &s, xxstring)) < 0) return(x); CHECKCONN(); if (*s) { x = strlen(tmpbuf); if (x > 0) { acct = &tmpbuf[x+2]; ckstrncpy(acct,brstrip(s),TMPBUFSIZ - x - 2); } } if (testing) printf(" ftp user \"%s\" password \"%s\"...\n",line,tmpbuf); success = ftp_user(line,tmpbuf,acct); #ifdef CKLOGDIAL dologftp(); #endif /* CKLOGDIAL */ return(success); } /* DO (various FTP commands)... */ int #ifdef CK_ANSIC doftptyp( int type ) /* TYPE */ #else doftptyp(type) int type; #endif /* CK_ANSIC */ { CHECKCONN(); ftp_typ = type; changetype(ftp_typ,ftp_vbm); debug(F101,"doftptyp changed type","",type); return(1); } static int #ifdef CK_ANSIC doftpxmkd( char * s, int vbm ) /* MKDIR action */ #else doftpxmkd(s,vbm) char * s; int vbm; #endif /* CK_ANSIC */ { int lcs = -1, rcs = -1; #ifndef NOCSETS if (ftp_xla) { lcs = ftp_csl; if (lcs < 0) lcs = fcharset; rcs = ftp_csx; if (rcs < 0) rcs = ftp_csr; } #endif /* NOCSETS */ debug(F110,"ftp doftpmkd",s,0); if (ftpcmd("MKD",s,lcs,rcs,vbm) == REPLY_COMPLETE) return(success = 1); if (ftpcode == 500 || ftpcode == 502) { if (!quiet) printf("MKD command not recognized, trying XMKD\n"); if (ftpcmd("XMKD",s,lcs,rcs,vbm) == REPLY_COMPLETE) return(success = 1); } return(success = 0); } static int #ifdef CK_ANSIC doftpmkd( void ) /* MKDIR parse */ #else doftpmkd() #endif /* CK_ANSIC */ { int x; char * s; if ((x = cmtxt("Remote directory name", "", &s, xxstring)) < 0) return(x); CHECKCONN(); ckstrncpy(line,s,LINBUFSIZ); if (testing) printf(" ftp mkdir \"%s\"...\n",line); return(success = doftpxmkd(line,-1)); } static int doftprmd() { /* RMDIR */ int x, lcs = -1, rcs = -1; char * s; if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0) return(x); CHECKCONN(); ckstrncpy(line,s,LINBUFSIZ); if (testing) printf(" ftp rmdir \"%s\"...\n",line); #ifndef NOCSETS if (ftp_xla) { lcs = ftp_csl; if (lcs < 0) lcs = fcharset; rcs = ftp_csx; if (rcs < 0) rcs = ftp_csr; } #endif /* NOCSETS */ if (ftpcmd("RMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE) return(success = 1); if (ftpcode == 500 || ftpcode == 502) { if (!quiet) printf("RMD command not recognized, trying XMKD\n"); success = (ftpcmd("XRMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE); } else success = 0; return(success); } static int doftpren() { /* RENAME */ int x; char * s; if ((x = cmfld("Remote filename","",&s,xxstring)) < 0) return(x); ckstrncpy(line,s,LINBUFSIZ); if ((x = cmfld("New name for remote file","",&s,xxstring)) < 0) return(x); ckstrncpy(tmpbuf,s,TMPBUFSIZ); if ((x = cmcfm()) < 0) return(x); CHECKCONN(); if (testing) printf(" ftp rename \"%s\" (to) \"%s\"...\n",line,tmpbuf); success = ftp_rename(line,tmpbuf); return(success); } int doftpres() { /* RESET (log out without close) */ int x; if ((x = cmcfm()) < 0) return(x); CHECKCONN(); if (testing) printf(" ftp reset...\n"); return(success = ftp_reset()); } static int doftpxhlp() { /* HELP */ int x; char * s; if ((x = cmtxt("Command name", "", &s, xxstring)) < 0) return(x); CHECKCONN(); ckstrncpy(line,s,LINBUFSIZ); if (testing) printf(" ftp help \"%s\"...\n",line); /* No need to translate -- all FTP commands are ASCII */ return(success = (ftpcmd("HELP",line,0,0,1) == REPLY_COMPLETE)); } static int #ifdef CK_ANSIC doftpdir( int cx ) /* [V]DIRECTORY */ #else doftpdir(cx) int cx; #endif /* CK_ANSIC */ { int x, lcs = 0, rcs = 0, xlate = 0; char * p, * s, * m = ""; if (cx == FTP_VDI) { switch (servertype) { case SYS_VMS: case SYS_DOS: case SYS_TOPS10: case SYS_TOPS20: m = "*.*"; break; default: m = "*"; } } if ((x = cmtxt("Remote filespec",m,&s,xxstring)) < 0) return(x); if ((x = remtxt(&s)) < 0) return(x); #ifdef NOCSETS xlate = 0; #else xlate = ftp_xla; #endif /* NOCSETS */ line[0] = NUL; ckstrncpy(line,s,LINBUFSIZ); s = line; CHECKCONN(); #ifndef NOCSETS if (xlate) { /* SET FTP CHARACTER-SET-TRANSLATION */ lcs = ftp_csl; /* Local charset */ if (lcs < 0) lcs = fcharset; if (lcs < 0) xlate = 0; } if (xlate) { /* Still ON? */ rcs = ftp_csx; /* Remote (Server) charset */ if (rcs < 0) rcs = ftp_csr; if (rcs < 0) xlate = 0; } #endif /* NOCSETS */ if (testing) { p = s; if (!p) p = ""; if (*p) printf("Directory of files %s at %s:\n", line, ftp_host); else printf("Directory of files at %s:\n", ftp_host); } debug(F111,"doftpdir",s,cx); if (cx == FTP_DIR) { /* Translation of line[] is done inside recvrequest() */ /* when it calls ftpcmd(). */ return(success = (recvrequest("LIST","-",s,"wb",0,0,NULL,xlate,lcs,rcs) == 0)); } success = 1; /* VDIR - one file at a time... */ p = (char *)remote_files(1,(CHAR *)s,NULL,0); /* Get the file list */ cancelgroup = 0; if (!ftp_vbm && !quiet) printlines = 1; while (p && !cancelfile && !cancelgroup) { /* STAT one file */ if (ftpcmd("STAT",p,lcs,rcs,ftp_vbm) < 0) { success = 0; break; } p = (char *)remote_files(0,NULL,NULL,0); /* Get next file */ debug(F110,"ftp vdir file",s,0); } return(success); } static int doftppwd() { /* PWD */ int x, lcs = -1, rcs = -1; #ifndef NOCSETS if (ftp_xla) { lcs = ftp_csl; if (lcs < 0) lcs = fcharset; rcs = ftp_csx; if (rcs < 0) rcs = ftp_csr; } #endif /* NOCSETS */ if ((x = cmcfm()) < 0) return(x); CHECKCONN(); if (ftpcmd("PWD",NULL,lcs,rcs,1) == REPLY_COMPLETE) { success = 1; } else if (ftpcode == 500 || ftpcode == 502) { if (ftp_deb) printf("PWD command not recognized, trying XPWD\n"); success = (ftpcmd("XPWD",NULL,lcs,rcs,1) == REPLY_COMPLETE); } return(success); } static int #ifdef CK_ANSIC doftpcwd( char * s, int vbm ) /* CD (CWD) */ #else doftpcwd(s,vbm) char * s; int vbm; #endif /* CK_ANSIC */ { int lcs = -1, rcs = -1; #ifndef NOCSETS if (ftp_xla) { lcs = ftp_csl; if (lcs < 0) lcs = fcharset; rcs = ftp_csx; if (rcs < 0) rcs = ftp_csr; } #endif /* NOCSETS */ debug(F110,"ftp doftpcwd",s,0); if (ftpcmd("CWD",s,lcs,rcs,vbm) == REPLY_COMPLETE) return(success = 1); if (ftpcode == 500 || ftpcode == 502) { if (!quiet) printf("CWD command not recognized, trying XCWD\n"); if (ftpcmd("XCWD",s,lcs,rcs,vbm) == REPLY_COMPLETE) return(success = 1); } return(success = 0); } static int doftpcdup() { /* CDUP */ debug(F100,"ftp doftpcdup","",0); if (ftpcmd("CDUP",NULL,0,0,1) == REPLY_COMPLETE) return(success = 1); if (ftpcode == 500 || ftpcode == 502) { if (!quiet) printf("CDUP command not recognized, trying XCUP\n"); if (ftpcmd("XCUP",NULL,0,0,1) == REPLY_COMPLETE) return(success = 1); } return(success = 0); } /* s y n c d i r -- Synchronizes client & server directories */ /* Call with: local = pointer to pathname of local file to be sent. sim = 1 for simulation, 0 for real uploading. Returns 0 on failure, 1 on success. The 'local' argument is relative to the initial directory of the MPUT, i.e. the root of the tree being uploaded. If the directory of the argument file is different from the directory of the previous file (which is stored in global putpath[]), this routine does the appropriate CWDs, CDUPs, and/or MKDIRs to position the FTP server in the same place. */ static int cdlevel = 0, cdsimlvl = 0; /* Tree-level trackers */ static int #ifdef CK_ANSIC syncdir( char * local, int sim ) #else syncdir(local,sim) char * local; int sim; #endif /* CK_ANSIC */ { char buf[CKMAXPATH+1]; char tmp[CKMAXPATH+1]; char msgbuf[CKMAXPATH+64]; char c, * p = local, * s = buf, * q = buf, * psep, * ssep; int i, k = 0, done = 0, itsadir = 0, saveq; debug(F110,"ftp syncdir local (new)",local,0); debug(F110,"ftp syncdir putpath (old)",putpath,0); itsadir = isdir(local); /* Is the local file a directory? */ saveq = quiet; while ((*s = *p)) { /* Copy the argument filename */ if (++k == CKMAXPATH) /* so we can poke it. */ return(-1); if (*s == '/') /* Pointer to rightmost dirsep */ q = s; s++; p++; } if (!itsadir) /* If it's a regular file */ *q = NUL; /* keep just the path part */ debug(F110,"ftp syncdir buf",buf,0); if (!strcmp(buf,putpath)) { /* Same path as previous file? */ if (itsadir) { /* This file is a directory? */ if (doftpcwd(local,0)) { /* Try to CD to it */ doftpcdup(); /* Worked - CD back up */ } else if (sim) { /* Simulating... */ if (fdispla == XYFD_B) { printf("WOULD CREATE DIRECTORY %s\n",local); } else if (fdispla) { ckmakmsg(msgbuf,CKMAXPATH, "WOULD CREATE DIRECTORY",local,NULL,NULL); ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf); } /* See note above */ return(0); } else if (!doftpxmkd(local,0)) { /* Can't CD - try to create */ return(0); } else { /* Remote directory created OK */ if (fdispla == XYFD_B) { printf("CREATED DIRECTORY %s\n",local); } else if (fdispla) { ckmakmsg(msgbuf,CKMAXPATH+64, "CREATED DIRECTORY ",local,NULL,NULL); ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf); } } } debug(F110,"ftp syncdir no change",buf,0); return(1); /* Yes, done. */ } ckstrncpy(tmp,buf,CKMAXPATH+1); /* Make a safe (pre-poked) copy */ debug(F110,"ftp syncdir new path",buf,0); /* for later (see end) */ p = buf; /* New */ s = putpath; /* Old */ debug(F110,"ftp syncdir A (old) s",s,0); /* Previous */ debug(F110,"ftp syncdir A (new) p",p,0); /* New */ psep = buf; ssep = putpath; while (*p != NUL && *s != NUL && *p == *s) { if (*p == '/') { psep = p+1; ssep = s+1; } p++,s++; } /* psep and ssep point to the first path segment that differs. We have to do as many CDUPs as there are path segments in ssep. then we have to do as many MKDs and CWDs as there are segments in psep. */ s = ssep; p = psep; debug(F110,"ftp syncdir B (old) s",s,0); /* Previous */ debug(F110,"ftp syncdir B (new) p",p,0); /* New */ /* p and s now point to the leftmost spot where the paths differ */ if (*s) { /* We have to back up */ k = 1; /* How many levels counting this one */ while ((c = *s++)) { /* Count dirseps remaining in prev */ if (c == '/' && *s) k++; } debug(F101,"ftp syncdir levels up","",k); for (i = 1; i <= k; i++) { /* Do that many CDUPs */ debug(F111,"ftp syncdir CDUP A",p,i); if (fdispla == XYFD_B) printf(" CDUP\n"); if (sim && cdsimlvl) { cdsimlvl--; } else { if (!doftpcdup()) { quiet = saveq; return(0); } } cdlevel--; } if (!*p) /* If we don't have to go down */ goto xcwd; /* we're done. */ } #ifdef COMMENT while (p > buf && *p && *p != '/') /* If in middle of segment */ p--; /* back up to beginning */ if (*p == '/') /* and terminate there */ p++; #endif /* COMMENT */ debug(F110,"ftp syncdir NEW PATH",p,0); s = p; /* Point to start of new down path. */ while (1) { /* Loop through characters. */ if (*s == '/' || !*s) { /* Have a segment. */ if (!*s) /* If end of string, */ done++; /* after this segment we're done. */ else *s = NUL; /* NUL out the separator. */ if (*p) { /* If segment is not empty */ debug(F110,"ftp syncdir down segment",p,0); if (!doftpcwd(p,0)) { /* Try to CD to it */ if (sim) { if (fdispla == XYFD_B) { printf(" WOULD CREATE DIRECTORY %s\n",local); } else if (fdispla) { ckmakmsg(msgbuf,CKMAXPATH, "WOULD CREATE DIRECTORY", local,NULL,NULL); ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf); } cdsimlvl++; } else { if (!doftpxmkd(p,0)) { /* Can't CD - try to create */ debug(F110,"ftp syncdir mkdir failed",p,0); /* Suppose we are executing SEND /RECURSIVE. Locally we have a directory FOO but the remote has a regular file with the same name. We can't CD to it, can't MKDIR it either. There's no way out but to fail and let the user handle the problem. */ quiet = saveq; return(0); } debug(F110,"ftp syncdir mkdir OK",p,0); if (fdispla == XYFD_B) { printf(" CREATED DIRECTORY %s\n",p); } else if (fdispla) { ckmakmsg(msgbuf,CKMAXPATH, "CREATED DIRECTORY ",p,NULL,NULL); ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf); } if (!doftpcwd(p,0)) { /* Try again to CD */ debug(F110,"ftp syncdir CD failed",p,0); quiet = saveq; return(0); } if (fdispla == XYFD_B) printf(" CWD %s\n",p); debug(F110,"ftp syncdir CD OK",p,0); } } cdlevel++; } if (done) /* Quit if no next segment */ break; p = s+1; /* Point to next segment */ } s++; /* Point to next source char */ } xcwd: ckstrncpy(putpath,tmp,CKMAXPATH+1); /* All OK - make this the new path */ quiet = saveq; return(1); } #ifdef DOUPDATE #ifdef DEBUG static VOID #ifdef CK_ANSIC dbtime( char * s, struct tm * xx ) /* Write struct tm to debug log */ #else dbtime(s,xx) char * s; struct tm * xx; #endif /* CK_ANSIC */ { if (deblog) { debug(F111,"ftp year ",s,xx->tm_year); debug(F111,"ftp month",s,xx->tm_mon); debug(F111,"ftp day ",s,xx->tm_mday); debug(F111,"ftp hour ",s,xx->tm_hour); debug(F111,"ftp min ",s,xx->tm_min); debug(F111,"ftp sec ",s,xx->tm_sec); } } #endif /* DEBUG */ /* t m c o m p a r e -- Compare two struct tm's */ /* Like strcmp() but for struct tm's */ /* Returns -1 if xx < yy, 0 if they are equal, 1 if xx > yy */ static int #ifdef CK_ANSIC tmcompare( struct tm * xx, struct tm * yy ) #else tmcompare(xx,yy) struct tm * xx, * yy; #endif /* CK_ANSIC */ { if (xx->tm_year < yy->tm_year) /* First year less than second */ return(-1); if (xx->tm_year > yy->tm_year) /* First year greater than second */ return(1); /* Years are equal so compare months */ if (xx->tm_mon < yy->tm_mon) /* And so on... */ return(-1); if (xx->tm_mon > yy->tm_mon) return(1); if (xx->tm_mday < yy->tm_mday) return(-1); if (xx->tm_mday > yy->tm_mday) return(1); if (xx->tm_hour < yy->tm_hour) return(-1); if (xx->tm_hour > yy->tm_hour) return(1); if (xx->tm_min < yy->tm_min) return(-1); if (xx->tm_min > yy->tm_min) return(1); if (xx->tm_sec < yy->tm_sec) return(-1); if (xx->tm_sec > yy->tm_sec) return(1); return(0); } #endif /* DOUPDATE */ #ifndef HAVE_TIMEGM /* For platforms that do not have timegm() */ static CONST int MONTHDAYS[] = { /* Number of days in each month. */ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; /* Macro for whether a given year is a leap year. */ #define ISLEAP(year) \ (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0)) #endif /* HAVE_TIMEGM */ /* m k u t i m e -- Like mktime() but argument is already UTC */ static time_t #ifdef CK_ANSIC mkutime(struct tm * tm) #else mkutime(tm) struct tm * tm; #endif /* CK_ANSIC */ /* mkutime */ { #ifdef HAVE_TIMEGM return(timegm(tm)); /* Have system service, use it. */ #else /* Contributed by Russ Allbery (rra@stanford.edu), used by permission. Given a struct tm representing a calendar time in UTC, convert it to seconds since epoch. Returns (time_t) -1 if the time is not convertable. Note that this function does not canonicalize the provided struct tm, nor does it allow out-of-range values or years before 1970. Result should be identical with timegm(). */ time_t result = 0; int i; /* We do allow some ill-formed dates, but we don't do anything special with them and our callers really shouldn't pass them to us. Do explicitly disallow the ones that would cause invalid array accesses or other algorithm problems. */ #ifdef DEBUG if (deblog) { debug(F101,"mkutime tm_mon","",tm->tm_mon); debug(F101,"mkutime tm_year","",tm->tm_year); } #endif /* DEBUG */ if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 70) return((time_t) -1); /* Convert to time_t. */ for (i = 1970; i < tm->tm_year + 1900; i++) result += 365 + ISLEAP(i); for (i = 0; i < tm->tm_mon; i++) result += MONTHDAYS[i]; if (tm->tm_mon > 1 && ISLEAP(tm->tm_year + 1900)) result++; result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour; result = 60 * result + tm->tm_min; result = 60 * result + tm->tm_sec; debug(F101,"mkutime result","",result); return(result); #endif /* HAVE_TIMEGM */ } /* s e t m o d t i m e -- Set file modification time. f = char * filename; t = time_t date/time to set (Secs since 19700101 0:00:00 UTC, NOT local) UNIX-specific; isolates mainline code from hideous #ifdefs. Returns: 0 on success, -1 on error. */ static int #ifdef CK_ANSIC setmodtime(char * f, time_t t) #else setmodtime(f,t) char * f; time_t t; #endif /* CK_ANSIC */ /* setmodtime */ { #ifdef NT struct _stat sb; #else /* NT */ struct stat sb; #endif /* NT */ int x, rc = 0; #ifdef BSD44 struct timeval tp[2]; #else /* def BSD44 */ #ifdef V7 struct utimbuf { time_t timep[2]; } tp; #else /* def V7 */ #ifdef SYSUTIMEH #ifdef NT struct _utimbuf tp; #else /* NT */ struct utimbuf tp; #endif /* NT */ #else /* def SYSUTIMEH */ #ifdef VMS struct utimbuf tp; #define SYSUTIMEH /* Our utimbuf matches this one. */ #else /* def VMS */ struct utimbuf { time_t atime; time_t mtime; } tp; #endif /* def VMS [else] */ #endif /* def SYSUTIMEH [else] */ #endif /* def V7 [else] */ #endif /* def BSD44 [else] */ if (stat(f,&sb) < 0) { debug(F111,"setmodtime stat failure",f,errno); return(-1); } #ifdef BSD44 tp[0].tv_sec = sb.st_atime; /* Access time first */ tp[1].tv_sec = t; /* Update time second */ debug(F111,"setmodtime BSD44",f,t); #else #ifdef V7 tp.timep[0] = t; /* Set modif. time to creation date */ tp.timep[1] = sb.st_atime; /* Don't change the access time */ debug(F111,"setmodtime V7",f,t); #else #ifdef SYSUTIMEH tp.modtime = t; /* Set modif. time to creation date */ tp.actime = sb.st_atime; /* Don't change the access time */ debug(F111,"setmodtime SYSUTIMEH",f,t); #else tp.mtime = t; /* Set modif. time to creation date */ tp.atime = sb.st_atime; /* Don't change the access time */ debug(F111,"setmodtime (other)",f,t); #endif /* SYSUTIMEH */ #endif /* V7 */ #endif /* BSD44 */ /* Try to set the file date */ #ifdef BSD44 x = utimes(f,tp); debug(F111,"setmodtime utimes()","BSD44",x); #else #ifdef IRIX65 { /* The following produces the nonsensical warning: Argument of type "const struct utimbuf *" is incompatible with parameter of type "const struct utimbuf *". If you can make it go away, be my guest. */ const struct utimbuf * t2 = &tp; x = utime(f,t2); } #else x = utime(f,&tp); debug(F111,"setmodtime utime()","other",x); #endif /* IRIX65 */ #endif /* BSD44 */ if (x) rc = -1; debug(F101,"setmodtime result","",rc); return(rc); } /* c h k m o d t i m e -- Check/Set file modification time. fc = function code: 0 = Check; returns: -1 on error, 0 if local older than remote, 1 if modtimes are equal, 2 if local newer than remote. 1 = Set (local file's modtime from remote's); returns: -1 on error, 0 on success. */ static int #ifdef CK_ANSIC chkmodtime( char * local, char * remote, int fc ) #else chkmodtime(local,remote,fc) char * local, * remote; int fc; #endif /* CK_ANSIC */ { #ifdef NT struct _stat statbuf; #else /* NT */ struct stat statbuf; #endif /* NT */ struct tm * tmlocal = NULL; struct tm tmremote; int rc = 0, havedate = 0, lcs = -1, rcs = -1, flag = 0; char * s, timebuf[64]; debug(F111,"chkmodtime",local,mdtmok); if (!mdtmok) /* Server supports MDTM? */ return(-1); /* No don't bother. */ #ifndef NOCSETS if (ftp_xla) { lcs = ftp_csl; if (lcs < 0) lcs = fcharset; rcs = ftp_csx; if (rcs < 0) rcs = ftp_csr; } #endif /* NOCSETS */ if (fc == 0) { rc = stat(local,&statbuf); if (rc == 0) { /* Get local file's mod time */ /* Convert to struct tm */ tmlocal = gmtime((time_t *)&statbuf.st_mtime); #ifdef DEBUG if (tmlocal) { dbtime(local,tmlocal); } #endif /* DEBUG */ } } /* Get remote file's mod time as yyyymmddhhmmss */ if (havemdtm) { /* Already got it from MLSD? */ s = havemdtm; flag++; } else if (ftpcmd("MDTM",remote,lcs,rcs,0) == REPLY_COMPLETE) { char c; bzero((char *)&tmremote, sizeof(struct tm)); s = ftp_reply_str; while ((c = *s++)) { /* Skip past response code */ if (c == SP) { flag++; break; } } } if (flag) { debug(F111,"ftp chkmodtime string",s,flag); if (fts_sto) { /* User gave server time offset? */ char * p; debug(F110,"ftp chkmodtime offset",fts_sto,0); ckmakmsg(timebuf,64,s," ",fts_sto,NULL); /* Build delta time */ if ((p = cmcvtdate(timebuf,1))) { /* Apply delta time */ ckstrncpy(timebuf,p,64); /* Convert to MDTM format */ timebuf[8] = timebuf[9]; /* h */ timebuf[9] = timebuf[10]; /* h */ timebuf[10] = timebuf[12]; /* m */ timebuf[11] = timebuf[13]; /* m */ timebuf[12] = timebuf[12]; /* s */ timebuf[13] = timebuf[13]; /* s */ timebuf[14] = NUL; s = timebuf; debug(F110,"ftp chkmodtime adjust",s,0); } } if (flag) { /* Convert to struct tm */ char * pat; int y2kbug = 0; /* Seen in Kerberos 4 FTP servers */ if (!ckstrcmp(s,"191",3,0)) { pat = "%05d%02d%02d%02d%02d%02d"; y2kbug++; debug(F110,"ftp chkmodtime Y2K BUG detected",s,0); } else { pat = "%04d%02d%02d%02d%02d%02d"; } if (sscanf(s, /* Parse into struct tm */ pat, &(tmremote.tm_year), &(tmremote.tm_mon), &(tmremote.tm_mday), &(tmremote.tm_hour), &(tmremote.tm_min), &(tmremote.tm_sec) ) == 6) { tmremote.tm_year -= (y2kbug ? 19000 : 1900); debug(F101,"ftp chkmodtime year","",tmremote.tm_year); tmremote.tm_mon--; #ifdef DEBUG debug(F100,"SERVER TIME FOLLOWS:","",0); dbtime(remote,&tmremote); #endif /* DEBUG */ if (havedate > -1) havedate = 1; } } } else { /* Failed */ debug(F101,"ftp chkmodtime ftpcode","",ftpcode); if (ftpcode == 500 || /* Command unrecognized */ ftpcode == 502 || /* Command not implemented */ ftpcode == 202) /* Command superfluous */ mdtmok = 0; /* Don't ask this server again */ return(-1); } if (fc == 0) { /* Compare */ if (havedate == 1) { /* Only if we have both file dates */ /* Compare with local file's time. We don't use clock time (time_t) here in case of signed/unsigned confusion, etc. */ int xx; #ifdef COMMENT #ifdef DEBUG if (deblog) { dbtime("LOCAL",tmlocal); dbtime("REMOT",&tmremote); } #endif /* DEBUG */ #endif /* COMMENT */ xx = tmcompare(tmlocal,&tmremote); debug(F101,"chkmodtime tmcompare","",xx); return(xx + 1); } } else if (ftp_dates) { /* Set */ /* Here we must convert struct tm to time_t without applying timezone conversion, for which there is no portable API. The method is hidden in mkutime(), defined above. */ time_t utc; utc = mkutime(&tmremote); debug(F111,"ftp chkmodtime mkutime",remote,utc); if (utc != (time_t)-1) return(setmodtime(local,utc)); } return(-1); } /* getfile() returns: -1 on error, 0 if file received, 1 if file skipped */ static int #ifdef CK_ANSIC getfile( char * remote, char * local, int recover, int append, char * pipename, int xlate, int fcs, int rcs ) #else getfile(remote,local,recover,append,pipename,xlate,fcs,rcs) char * local, * remote, * pipename; int recover, append, xlate, fcs, rcs; #endif /* CK_ANSIC */ { int rc = -1; ULONG t0, t1; #ifdef GFTIMER CKFLOAT sec; #else int sec = 0; #endif /* GFTIMER */ char fullname[CKMAXPATH+1]; debug(F110,"ftp getfile remote A",remote,0); debug(F110,"ftp getfile local A",local,0); debug(F110,"ftp getfile pipename",pipename,0); if (!remote) remote = ""; #ifdef PATTERNS /* Automatic type switching? */ if (ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype) { int x; x = matchname(remote,0,servertype); debug(F111,"ftp getfile matchname",remote,x); switch (x) { case 0: ftp_typ = FTT_ASC; break; case 1: ftp_typ = tenex ? FTT_TEN : FTT_BIN; break; default: if (g_ftp_typ > -1) ftp_typ = g_ftp_typ; } changetype(ftp_typ,ftp_vbm); binary = ftp_typ; /* For file-transfer display */ } #endif /* PATTERNS */ #ifndef NOCSETS ftp_csx = -1; /* For file-transfer display */ ftp_csl = -1; /* ... */ if (rcs > -1) /* -1 means no translation */ if (ftp_typ == FTT_ASC) /* File type is "ascii"? */ if (fcs < 0) /* File charset not forced? */ fcs = fcharset; /* use prevailing FILE CHARACTER-SET */ if (fcs > -1 && rcs > -1) { /* Set up translation functions */ debug(F110,"ftp getfile","initxlate",0); initxlate(rcs,fcs); /* NB: opposite order of PUT */ ftp_csx = rcs; ftp_csl = fcs; } else xlate = 0; #endif /* NOCSETS */ if (!local) local = ""; if (!pipename && !*local) local = remote; out2screen = !strcmp(local,"-"); fullname[0] = NUL; if (pipename) { ckstrncpy(fullname,pipename,CKMAXPATH+1); } else { zfnqfp(local,CKMAXPATH,fullname); if (!fullname[0]) ckstrncpy(fullname,local,CKMAXPATH+1); } if (!out2screen && displa && fdispla) { /* Screen */ ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,remote); ftscreen(SCR_AN,0,(CK_OFF_T)0,fullname); ftscreen(SCR_FS,0,fsize,""); } tlog(F110,ftp_typ ? "ftp get BINARY:" : "ftp get TEXT:", remote, 0); tlog(F110," as",fullname,0); debug(F111,"ftp getfile size",remote,fsize); debug(F111,"ftp getfile local",local,out2screen); ckstrncpy(filnam, pipename ? remote : local, CKMAXPATH); t0 = gmstimer(); /* Start time */ debug(F111,"ftp getfile t0",remote,t0); /* ^^^ */ rc = recvrequest("RETR", local, remote, append ? "ab" : "wb", 0, recover, pipename, xlate, fcs, rcs ); t1 = gmstimer(); /* End time */ debug(F111,"ftp getfile t1",remote,t1); debug(F111,"ftp getfile sec",remote,(t1-t0)/1000); #ifdef GFTIMER sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */ fpxfsecs = sec; /* (for doxlog()) */ #else sec = (t1 - t0) / 1000; xfsecs = (int)sec; #endif /* GFTIMER */ #ifdef FTP_TIMEOUT if (ftp_timed_out) rc = -4; #endif /* FTP_TIMEOUT */ debug(F111,"ftp recvrequest rc",remote,rc); if (cancelfile || cancelgroup) { debug(F111,"ftp get canceled",ckitoa(cancelfile),cancelgroup); ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,""); } else if (rc > 0) { debug(F111,"ftp get skipped",ckitoa(cancelfile),cancelgroup); ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,cmarg); } else if (rc < 0) { switch (ftpcode) { case -4: /* Network error */ case -2: /* File error */ ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,ck_errstr()); break; case -3: ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0, "Failure to make data connection"); break; case -1: /* (should be covered above) */ ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,""); break; default: ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]); } } else { /* Tudo bem */ ftscreen(SCR_PT,'Z',(CK_OFF_T)0,""); if (rc == 0) { ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,""); /* For screen */ makestr(&rrfspec,remote); /* For WHERE command */ makestr(&rfspec,fullname); } } if (rc > -1) { if (ftp_dates) /* If FTP DATES ON... */ if (!pipename && !out2screen) /* and it's a real file */ if (rc < 1 && rc != -3) /* and it wasn't skipped */ if (connected) /* and we still have a connection */ if (zchki(local) > -1) { /* and the file wasn't discarded */ chkmodtime(local,remote,1); /* set local file date */ debug(F110,"ftp get set date",local,0); } filcnt++; /* Used by \v(filenum) */ } #ifdef TLOG if (tralog) { if (rc > 0) { tlog(F100," recovery skipped","",0); } else if (rc == 0) { tlog(F101," complete, size", "", fsize); } else if (cancelfile) { tlog(F100," canceled by user","",0); #ifdef FTP_TIMEOUT } else if (ftp_timed_out) { tlog(F100," timed out","",0); #endif /* FTP_TIMEOUT */ } else { tlog(F110," failed:",ftp_reply_str,0); } if (!tlogfmt) doxlog(what,local,fsize,ftp_typ,rc,""); } #endif /* TLOG */ return(rc); } /* putfile() returns: -1 on error, >0 if file not selected, 0 on success. */ /* Positive return value is Skip Reason, SKP_xxx, from ckcker.h. */ static int #ifdef CK_ANSIC putfile(int cx, char * local, char * remote, int force, int moving, char * mvto, char * rnto, char * srvrn, int x_cnv, int x_usn, int xft, int prm, int fcs, int rcs, int flg ) #else putfile(cx, local,remote,force,moving,mvto,rnto,srvrn,x_cnv,x_usn,xft,prm,fcs,rcs,flg) char * local, * remote, * mvto, *rnto, *srvrn; int cx, force, moving, x_cnv, x_usn, xft, fcs, rcs, flg, prm; #endif /* CK_ANSIC */ { char asname[CKMAXPATH+1]; char fullname[CKMAXPATH+1]; int k = -1, x = 0, y = 0, o = -1, rc = 0, nc = 0; int xlate = 0, restart = 0, mt = -1; char * s = NULL, * cmd = NULL; ULONG t0 = 0, t1 = 0; /* Times for stats */ int ofcs = 0, orcs = 0; #ifdef GFTIMER CKFLOAT sec = 0.0; #else int sec = 0; #endif /* GFTIMER */ debug(F111,"ftp putfile flg",local,flg); debug(F110,"ftp putfile srv_renam",srvrn,0); debug(F101,"ftp putfile fcs","",fcs); debug(F101,"ftp putfile rcs","",rcs); ofcs = fcs; /* Save charset args */ orcs = rcs; sendstart = (CK_OFF_T)0; restart = flg & PUT_RES; if (!remote) remote = ""; /* FTP protocol command to send to server */ cmd = (cx == FTP_APP) ? "APPE" : (x_usn ? "STOU" : "STOR"); if (x_cnv == SET_AUTO) { /* Name conversion is auto */ if (alike) { /* If server & client are alike */ nc = 0; /* no conversion */ } else { /* If they are different */ if (servertype == SYS_UNIX || servertype == SYS_WIN32) nc = -1; /* only minimal conversions needed */ else /* otherwise */ nc = 1; /* full conversion */ } } else /* Not auto - do what user said */ nc = x_cnv; /* If Transfer Mode is Automatic, determine file type */ if (ftp_xfermode == XMODE_A && filepeek && !pipesend) { if (isdir(local)) { /* If it's a directory */ k = FT_BIN; /* skip the file scan */ } else { debug(F110,"FTP PUT calling scanfile",local,0); k = scanfile(local,&o,nscanfile); /* Scan the file */ } debug(F111,"FTP PUT scanfile",local,k); if (k > -1 && !forcetype) { ftp_typ = (k == FT_BIN) ? 1 : 0; if (xft > -1 && ftp_typ != xft) { if (flg & PUT_SIM) tlog(F110,"ftp put SKIP (Type):", local, 0); return(SKP_TYP); } if (ftp_typ == 1 && tenex) /* User said TENEX? */ ftp_typ = FTT_TEN; } } #ifndef NOCSETS ftp_csx = -1; /* For file-transfer display */ ftp_csl = -1; /* ... */ if (rcs > -1) { /* -1 means no translation */ if (ftp_typ == 0) { /* File type is "ascii"? */ if (fcs < 0) { /* File charset not forced? */ if (k < 0) { /* If we didn't scan */ fcs = fcharset; /* use prevailing FILE CHARACTER-SET */ } else { /* If we did scan, use scan result */ switch (k) { case FT_TEXT: /* Unknown text */ fcs = fcharset; break; case FT_7BIT: /* 7-bit text */ fcs = dcset7; break; case FT_8BIT: /* 8-bit text */ fcs = dcset8; break; case FT_UTF8: /* UTF-8 */ fcs = FC_UTF8; break; case FT_UCS2: /* UCS-2 */ fcs = FC_UCS2; if (o > -1) /* Input file byte order */ fileorder = o; break; default: rcs = -1; } } } } } if (fcs > -1 && rcs > -1) { /* Set up translation functions */ debug(F110,"ftp putfile","initxlate",0); initxlate(fcs,rcs); debug(F111,"ftp putfile rcs",fcsinfo[rcs].keyword,rcs); xlate = 1; ftp_csx = rcs; ftp_csl = fcs; } #endif /* NOCSETS */ binary = ftp_typ; /* For file-transfer display */ asname[0] = NUL; if (recursive) { /* If sending recursively, */ if (!syncdir(local,flg & PUT_SIM)) /* synchronize directories. */ return(-1); /* Don't PUT if it fails. */ else if (isdir(local)) /* It's a directory */ return(0); /* Don't send it! */ } if (*remote) { /* If an as-name template was given */ #ifndef NOSPL if (cmd_quoting) { /* and COMMAND QUOTING is ON */ y = CKMAXPATH; /* evaluate it for this file */ s = asname; zzstring(remote,&s,&y); } else #endif /* NOSPL */ ckstrncpy(asname,remote,CKMAXPATH); /* (or take it literally) */ } else { /* No as-name */ nzltor(local,asname,nc,0,CKMAXPATH); /* use local name strip path */ debug(F110,"FTP PUT nzltor",asname,0); } /* Preliminary messages and log entries */ fullname[0] = NUL; zfnqfp(local,CKMAXPATH,fullname); if (!fullname[0]) ckstrncpy(fullname,local,CKMAXPATH+1); fullname[CKMAXPATH] = NUL; if (displa && fdispla) { /* Screen */ ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,local); ftscreen(SCR_AN,0,(CK_OFF_T)0,asname); ftscreen(SCR_FS,0,fsize,""); } #ifdef DOUPDATE if (flg & (PUT_UPD|PUT_DIF)) { /* Date-checking modes... */ mt = chkmodtime(fullname,asname,0); debug(F111,"ftp putfile chkmodtime",asname,mt); if (mt == 0 && ((flg & PUT_DIF) == 0)) { /* Local is older */ tlog(F110,"ftp put /update SKIP (Older modtime): ",fullname,0); /* Skip this one */ ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_DAT,fullname); filcnt++; return(SKP_DAT); } else if (mt == 1) { /* Times are equal */ tlog(F110,"ftp put /update SKIP (Equal modtime): ",fullname,0); ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_EQU,fullname); /* Skip it */ filcnt++; return(SKP_DAT); } /* Local file is newer */ tlog(F110,ftp_typ ? "ftp put /update BINARY:" : "ftp put /update TEXT:", fullname, 0); } else if (flg & PUT_RES) { tlog(F110,ftp_typ ? "ftp put /recover BINARY:" : "ftp put /recover TEXT:", fullname, 0); } else { tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0); } #else tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0); #endif /* DOUPDATE */ tlog(F110," as",asname,0); #ifndef NOCSETS if (xlate) { debug(F111,"ftp putfile fcs",fcsinfo[fcs].keyword,fcs); tlog(F110," file character set:",fcsinfo[fcs].keyword,0); tlog(F110," server character set:",fcsinfo[rcs].keyword,0); } else if (!ftp_typ) { tlog(F110," character sets:","no conversion",0); fcs = ofcs; /* Binary file but we still must */ rcs = orcs; /* translate its name */ } #endif /* NOCSETS */ /* PUT THE FILE */ t0 = gmstimer(); /* Start time */ if (flg & PUT_SIM) { /* rc > 0 is a skip reason code */ if (flg & (PUT_UPD|PUT_DIF)) { /* (see SKP_xxx in ckcker.h) */ rc = (mt < 0) ? /* Update mode... */ SKP_XNX : /* Remote file doesn't exist */ SKP_XUP; /* Remote file is older */ } else { rc = SKP_SIM; /* "Would be sent", period. */ } } else { rc = sendrequest(cmd,local,asname,xlate,fcs,rcs,restart); } t1 = gmstimer(); /* End time */ filcnt++; /* File number */ #ifdef GFTIMER sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */ fpxfsecs = sec; /* (for doxlog()) */ #else sec = (t1 - t0) / 1000; xfsecs = (int)sec; #endif /* GFTIMER */ debug(F111,"ftp sendrequest rc",local,rc); if (cancelfile || cancelgroup) { debug(F111,"ftp put canceled",ckitoa(cancelfile),cancelgroup); ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,""); } else if (rc > 0) { debug(F101,"ftp put skipped",local,rc); ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)rc,fullname); } else if (rc < 0) { debug(F111,"ftp put error",local,ftpcode); ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]); } else { debug(F111,"ftp put not canceled",ckitoa(displa),fdispla); ftscreen(SCR_PT,'Z',(CK_OFF_T)0,""); debug(F111,"ftp put ST_OK",local,rc); ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,""); debug(F110,"ftp put old sfspec",sfspec,0); makestr(&sfspec,fullname); /* For WHERE command */ debug(F110,"ftp put new sfspec",sfspec,0); debug(F110,"ftp put old srfspec",srfspec,0); makestr(&srfspec,asname); debug(F110,"ftp put new srfspec",srfspec,0); } /* Final log entries */ #ifdef TLOG if (tralog) { if (rc > 0) { switch (rc) { case SKP_XNX: tlog(F100," /simulate: WOULD BE SENT:","no remote file",0); break; case SKP_XUP: tlog(F100," /simulate: WOULD BE SENT:","remote file older",0); break; case SKP_SIM: tlog(F100," /simulate: WOULD BE SENT","",0); break; default: tlog(F110," skipped:",gskreason(rc),0); } } else if (rc == 0) { tlog(F101," complete, size", "", fsize); } else if (cancelfile) { tlog(F100," canceled by user","",0); } else { tlog(F110," failed:",ftp_reply_str,0); } if (!tlogfmt) doxlog(what,local,fsize,ftp_typ,rc,""); } #endif /* TLOG */ if (rc < 0) /* PUT did not succeed */ return(-1); /* so done. */ if (flg & PUT_SIM) /* Simulating, skip the rest. */ return(SKP_SIM); #ifdef UNIX /* Set permissions too? */ if (prm) { /* Change permissions? */ s = zgperm(local); /* Get perms of local file */ if (!s) s = ""; x = strlen(s); if (x > 3) s += (x - 3); if (rdigits(s)) { ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,s," ",asname,NULL); x = ftpcmd("SITE CHMOD",ftpcmdbuf,fcs,rcs,ftp_vbm) == REPLY_COMPLETE; tlog(F110, x ? " chmod" : " chmod failed", s, 0 ); if (!x) return(-1); } } #endif /* UNIX */ /* Disposition of source file */ if (moving) { x = zdelet(local); tlog(F110, (x > -1) ? " deleted" : " failed to delete", local, 0 ); if (x < 0) return(-1); } else if (mvto) { x = zrename(local,mvto); tlog(F110, (x > -1) ? " moved source to" : " failed to move source to", mvto, 0 ); if (x < 0) return(-1); /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,mvto); */ } else if (rnto) { char * s = rnto; #ifndef NOSPL int y; /* Pass it thru the evaluator */ extern int cmd_quoting; /* for \v(filename) */ if (cmd_quoting) { /* But only if cmd_quoting is on */ y = CKMAXPATH; s = (char *)asname; zzstring(rnto,&s,&y); s = (char *)asname; } #endif /* NOSPL */ if (s) if (*s) { int x; x = zrename(local,s); tlog(F110, (x > -1) ? " renamed source file to" : " failed to rename source file to", s, 0 ); if (x < 0) return(-1); /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,s); */ } } /* Disposition of destination file */ if (srvrn) { /* /SERVER-RENAME: */ char * s = srvrn; #ifndef NOSPL int y; /* Pass it thru the evaluator */ extern int cmd_quoting; /* for \v(filename) */ debug(F111,"ftp putfile srvrn",s,1); if (cmd_quoting) { /* But only if cmd_quoting is on */ y = CKMAXPATH; s = (char *)fullname; /* We can recycle this buffer now */ zzstring(srvrn,&s,&y); s = (char *)fullname; } #endif /* NOSPL */ debug(F111,"ftp putfile srvrn",s,2); if (s) if (*s) { int x; x = ftp_rename(asname,s); debug(F111,"ftp putfile ftp_rename",asname,x); tlog(F110, (x > 0) ? " renamed destination file to" : " failed to rename destination file to", s, 0 ); if (x < 1) return(-1); } } return(0); } /* xxout must only be used for ASCII transfers */ static int #ifdef CK_ANSIC xxout(char c) #else xxout(c) char c; #endif /* CK_ANSIC */ { #ifndef OS2 #ifndef VMS #ifndef MAC #ifndef OSK /* For Unix, DG, Stratus, Amiga, Gemdos, other */ if (c == '\012') { if (zzout(dout,(CHAR)'\015') < 0) return(-1); ftpsnd.bytes++; } #else /* OSK */ if (c == '\015') { c = '\012'; if (zzout(dout,(CHAR)'\015') < 0) return(-1); ftpsnd.bytes++; } #endif /* OSK */ #else /* MAC */ if (c == '\015') { c = '\012'; if (zzout(dout,(CHAR)'\015') < 0) return(-1); ftpsnd.bytes++; } #endif /* MAC */ #endif /* VMS */ #endif /* OS2 */ if (zzout(dout,(CHAR)c) < 0) return(-1); ftpsnd.bytes++; return(0); } static int #ifdef CK_ANSIC scrnout(char c) #else scrnout(c) char c; #endif /* CK_ANSIC */ { return(putchar(c)); } static int #ifdef CK_ANSIC pipeout(char c) #else pipeout(c) char c; #endif /* CK_ANSIC */ { return(zmchout(c)); } static int #ifdef CK_ANSIC ispathsep( int c ) #else ispathsep(c) int c; #endif /* CK_ANSIC */ { switch (servertype) { case SYS_VMS: case SYS_TOPS10: case SYS_TOPS20: return(((c == ']') || (c == '>') || (c == ':')) ? 1 : 0); case SYS_OS2: case SYS_WIN32: case SYS_DOS: return(((c == '\\') || (c == '/') || (c == ':')) ? 1 : 0); case SYS_VOS: return((c == '>') ? 1 : 0); default: return((c == '/') ? 1 : 0); } } static int iscanceled() { #ifdef CK_CURSES extern int ck_repaint(); #endif /* CK_CURSES */ int x, rc = 0; char c = 0; if (cancelfile) return(1); x = conchk(); /* Any chars waiting at console? */ if (x-- > 0) { /* Yes... */ c = coninc(5); /* Get one */ switch (c) { case 032: /* Ctrl-X or X */ case 'z': case 'Z': cancelgroup++; /* fall thru on purpose */ case 030: /* Ctrl-Z or Z */ case 'x': case 'X': cancelfile++; rc++; break; #ifdef CK_CURSES case 'L': case 'l': case 014: /* Ctrl-L or L or Ctrl-W */ case 027: ck_repaint(); /* Refresh screen */ #endif /* CK_CURSES */ } } while (x-- > 0) /* Soak up any rest */ c = coninc(1); return(rc); } #ifdef FTP_TIMEOUT /* fc = 0 for read; 1 for write */ static int #ifdef CK_ANSIC check_data_connection( int fd, int fc ) #else check_data_connection(fd,fc) int fd, fc; #endif /* CK_ANSIC */ { int x; #ifdef BSDSELECT struct timeval tv; fd_set in, out, err; if (ftp_timeout < 1L) return(0); FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&err); FD_SET(fd,fc ? &out : &in); tv.tv_sec = ftp_timeout; /* Time limit */ tv.tv_usec = 0L; #ifdef INTSELECT x = select(FD_SETSIZE,(int *)&in,(int *)&out,(int *)&err,&tv); #else x = select(FD_SETSIZE,&in,&out,&err,&tv); #endif /* INTSELECT */ #else /* BSDSELECT */ #ifdef IBMSELECT if (ftp_timeout < 1L) return(0); if (fc) { /* write */ x = select(&fd, 0, 1, 0, ftp_timeout * 1000L); } else { /* read */ x = select(&fd, 1, 0, 0, ftp_timeout * 1000L); } #endif /* IBMSELECT */ #endif /* BSDSELECT */ if (x == 0) { #ifdef EWOULDBLOCK errno = EWOULDBLOCK; #else #ifdef EAGAIN errno = EAGAIN; #else errno = 11; #endif /* EAGAIN */ #endif /* EWOULDBLOCK */ debug(F100,"ftp check_data_connection TIMOUT","",0); return(-3); } return(0); } #endif /* FTP_TIMEOUT */ /* zzsend - used by buffered output macros. */ static int #ifdef CK_ANSIC zzsend(int fd, CHAR c) #else zzsend(fd,c) int fd; CHAR c; #endif /* CK_ANSIC */ { int rc; debug(F101,"zzsend ucbufsiz","",ucbufsiz); debug(F101,"zzsend nout","",nout); debug(F111,"zzsend","secure?",ftpissecure()); if (iscanceled()) /* Check for cancellation */ return(-9); #ifdef FTP_TIMEOUT ftp_timed_out = 0; if (check_data_connection(fd,1) < 0) { ftp_timed_out = 1; return(-3); } #endif /* FTP_TIMEOUT */ rc = (!ftpissecure()) ? send(fd, (SENDARG2TYPE)ucbuf, nout, 0) : secure_putbuf(fd, ucbuf, nout); ucbuf[nout] = NUL; nout = 0; ucbuf[nout++] = c; spackets++; pktnum++; if (rc > -1 && fdispla != XYFD_B) { spktl = nout; ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL); } return(rc); } /* c m d l i n p u t -- Command-line PUT */ int #ifdef CK_ANSIC cmdlinput( int stay ) #else cmdlinput(stay) int stay; #endif /* CK_ANSIC */ { int x, rc = 0, done = 0, good = 0, status = 0; ULONG t0, t1; /* Times for stats */ #ifdef GFTIMER CKFLOAT sec; #else int sec = 0; #endif /* GFTIMER */ if (quiet) { /* -q really means quiet */ displa = 0; fdispla = 0; } else { displa = 1; fdispla = XYFD_B; } testing = 0; out2screen = 0; dpyactive = 0; what = W_FTP|W_SEND; #ifndef NOSPL cmd_quoting = 0; #endif /* NOSPL */ sndsrc = nfils; t0 = gmstimer(); /* Record starting time */ while (!done && !cancelgroup) { /* Loop for all files */ cancelfile = 0; x = gnfile(); /* Get next file from list(s) */ if (x == 0) /* (see gnfile() comments...) */ x = gnferror; switch (x) { case 1: /* File to send */ rc = putfile(FTP_PUT, /* Function (PUT, APPEND) */ filnam, /* Local file to send */ filnam, /* Remote name for file */ forcetype, /* Text/binary mode forced */ 0, /* Not moving */ NULL, /* No move-to */ NULL, /* No rename-to */ NULL, /* No server-rename */ ftp_cnv, /* Filename conversion */ 0, /* Unique-server-names */ -1, /* All file types */ 0, /* No permissions */ -1, /* No character sets */ -1, /* No character sets */ 0 /* No update or restart */ ); if (rc > -1) { good++; status = 1; } if (cancelfile) { continue; /* Or break? */ } if (rc < 0) { ftp_fai++; } continue; /* Or break? */ case 0: /* No more files, done */ done++; continue; case -2: case -1: printf("?%s: file not found - \"%s\"\n", puterror ? "Fatal" : "Warning", filnam ); continue; /* or break? */ case -3: printf("?Warning access denied - \"%s\"\n", filnam); continue; /* or break? */ case -5: printf("?Too many files match\n"); done++; break; case -6: if (good < 1) printf("?No files selected\n"); done++; break; default: printf("?getnextfile() - unknown failure\n"); done++; } } if (status > 0) { if (cancelgroup) status = 0; else if (cancelfile && good < 1) status = 0; } success = status; x = success; if (x > -1) { lastxfer = W_FTP|W_SEND; xferstat = success; } t1 = gmstimer(); /* End time */ #ifdef GFTIMER sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */ if (!sec) sec = 0.001; fptsecs = sec; #else sec = (t1 - t0) / 1000; if (!sec) sec = 1; #endif /* GFTIMER */ tfcps = (long) (tfc / sec); tsecs = (int)sec; lastxfer = W_FTP|W_SEND; xferstat = success; if (dpyactive) ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, ""); if (!stay) doexit(success ? GOOD_EXIT : BAD_EXIT, -1); return(success); } /* d o f t p p u t -- Parse and execute PUT, MPUT, and APPEND */ int #ifdef CK_ANSIC doftpput(int cx, int who) /* who == 1 for ftp, 0 for kermit */ #else doftpput(cx,who) int cx, who; #endif /* CK_ANSIC */ { struct FDB sf, fl, sw, cm; int n, rc, confirmed = 0, wild = 0, getval = 0, mput = 0, done = 0; int x_cnv = 0, x_usn = 0, x_prm = 0, putflags = 0, status = 0, good = 0; char * s, * s2; int x_csl, x_csr = -1; /* Local and remote charsets */ int x_xla = 0; int x_recurse = 0; char c, * p; /* Workers */ #ifdef PUTARRAY int range[2]; /* Array range */ char ** ap = NULL; /* Array pointer */ int arrayx = -1; /* Array index */ #endif /* PUTARRAY */ ULONG t0 = 0L, t1 = 0L; /* Times for stats */ #ifdef GFTIMER CKFLOAT sec; #else int sec = 0; #endif /* GFTIMER */ struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */ success = 0; /* Assume failure */ forcetype = 0; /* No /TEXT or /BINARY given yet */ out2screen = 0; /* Not outputting file to screen */ putflags = 0; /* PUT options */ x_cnv = ftp_cnv; /* Filename conversion */ x_usn = ftp_usn; /* Unique server names */ x_prm = ftp_prm; /* Permissions */ if (x_prm == SET_AUTO) /* Permissions AUTO */ x_prm = alike; #ifndef NOCSETS x_csr = ftp_csr; /* Inherit global server charset */ x_csl = ftp_csl; if (x_csl < 0) x_csl = fcharset; x_xla = ftp_xla; #endif /* NOCSETS */ makestr(&filefile,NULL); /* No filename list file yet. */ makestr(&srv_renam,NULL); /* Clear /SERVER-RENAME: */ makestr(&snd_rename,NULL); /* PUT /RENAME */ makestr(&snd_move,NULL); /* PUT /MOVE */ putpath[0] = NUL; /* Initialize for syncdir(). */ puterror = ftp_err; /* Inherit global error action. */ what = W_SEND|W_FTP; /* What we're doing (sending w/FTP) */ asnambuf[0] = NUL; /* Clear as-name buffer */ if (g_ftp_typ > -1) { /* Restore TYPE if saved */ ftp_typ = g_ftp_typ; /* g_ftp_typ = -1; */ } for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */ pv[i].sval = NULL; /* to null pointers */ pv[i].ival = -1; /* and -1 int values */ pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */ } if (who == 0) { /* Called with unprefixed command */ switch (cx) { case XXRSEN: pv[SND_RES].ival = 1; break; case XXCSEN: pv[SND_CMD].ival = 1; break; case XXMOVE: pv[SND_DEL].ival = 1; break; case XXMMOVE: pv[SND_DEL].ival = 1; /* fall thru */ case XXMSE: mput++; break; } } else { if (cx == FTP_REP) pv[SND_RES].ival = 1; if (cx == FTP_MPU) mput++; } cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Filename, or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nputswi, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ putswi, /* Keyword table */ &sf /* Pointer to next FDB */ ); cmfdbi(&fl, /* 3rd FDB - local filespec */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, &cm ); cmfdbi(&cm, /* 4th FDB - Confirmation */ _CMCFM, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, NULL, NULL ); again: cmfdbi(&sf, /* 2nd FDB - file to send */ _CMIFI, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ /* 0 = parse files, 1 = parse files or dirs, 2 = skip symlinks */ nolinks | x_recurse, /* addtl numeric data 1 */ 0, /* dirflg 0 means "not dirs only" */ xxstring, NULL, #ifdef COMMENT mput ? &cm : &fl #else &fl #endif /* COMMENT */ ); while (1) { /* Parse zero or more switches */ x = cmfdb(&sw); /* Parse something */ debug(F101,"ftp put cmfdb A","",x); debug(F101,"ftp put fcode A","",cmresult.fcode); if (x < 0) /* Error */ goto xputx; /* or reparse needed */ if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */ break; c = cmgbrk(); /* Get break character */ getval = (c == ':' || c == '='); /* to see how they ended the switch */ if (getval && !(cmresult.kflags & CM_ARG)) { printf("?This switch does not take arguments\n"); x = -9; goto xputx; } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); x = -9; goto xputx; } n = cmresult.nresult; /* Numeric result = switch value */ debug(F101,"ftp put switch","",n); switch (n) { /* Process the switch */ case SND_AFT: /* Send /AFTER:date-time */ case SND_BEF: /* Send /BEFORE:date-time */ case SND_NAF: /* Send /NOT-AFTER:date-time */ case SND_NBE: /* Send /NOT-BEFORE:date-time */ if (!getval) break; if ((x = cmdate("File date-time","",&s,0,xxstring)) < 0) { if (x == -3) { printf("?Date-time required\n"); x = -9; } goto xputx; } pv[n].ival = 1; makestr(&(pv[n].sval),s); break; case SND_ASN: /* /AS-NAME: */ debug(F101,"ftp put /as-name getval","",getval); if (!getval) break; if ((x = cmfld("Name to send under","",&s,NULL)) < 0) { if (x == -3) { printf("?name required\n"); x = -9; } goto xputx; } makestr(&(pv[n].sval),brstrip(s)); debug(F110,"ftp put /as-name 1",pv[n].sval,0); if (pv[n].sval) pv[n].ival = 1; break; #ifdef PUTARRAY case SND_ARR: /* /ARRAY */ if (!getval) break; ap = NULL; if ((x = cmfld("Array name (a single letter will do)", "", &s, NULL )) < 0) { if (x == -3) break; else return(x); } if ((x = arraybounds(s,&(range[0]),&(range[1]))) < 0) { printf("?Bad array: %s\n",s); return(-9); } if (!(ap = a_ptr[x])) { printf("?No such array: %s\n",s); return(-9); } pv[n].ival = 1; pv[SND_CMD].ival = 0; /* Undo any conflicting ones... */ pv[SND_RES].ival = 0; pv[SND_FIL].ival = 0; arrayx = x; break; #endif /* PUTARRAY */ case SND_BIN: /* /BINARY */ case SND_TXT: /* /TEXT or /ASCII */ case SND_TEN: /* /TENEX */ pv[SND_BIN].ival = 0; pv[SND_TXT].ival = 0; pv[SND_TEN].ival = 0; pv[n].ival = 1; break; #ifdef PUTPIPE case SND_CMD: /* These take no args */ if (nopush) { printf("?Sorry, system command access is disabled\n"); x = -9; goto xputx; } #ifdef PIPESEND else if (sndfilter) { printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n"); x = -9; goto xputx; } #endif /* PIPESEND */ sw.hlpmsg = "Command, or switch"; /* Change help message */ pv[n].ival = 1; /* Just set the flag */ pv[SND_ARR].ival = 0; break; #endif /* PUTPIPE */ #ifdef CKSYMLINK case SND_LNK: nolinks = 0; goto again; /* Because CMIFI params changed... */ case SND_NLK: nolinks = 2; goto again; #endif /* CKSYMLINK */ #ifdef FTP_RESTART case SND_RES: /* /RECOVER (resend) */ pv[SND_ARR].ival = 0; /* fall thru on purpose... */ #endif /* FTP_RESTART */ case SND_NOB: case SND_DEL: /* /DELETE */ case SND_SHH: /* /QUIET */ case SND_UPD: /* /UPDATE */ case SND_SIM: /* /UPDATE */ case SND_USN: /* /UNIQUE */ pv[n].ival = 1; /* Just set the flag */ break; case SND_REC: /* /RECURSIVE */ recursive = 2; /* Must be set before cmifi() */ x_recurse = 1; goto again; /* Because CMIFI params changed... */ break; #ifdef UNIXOROSK case SND_DOT: /* /DOTFILES */ matchdot = 1; break; case SND_NOD: /* /NODOTFILES */ matchdot = 0; break; #endif /* UNIXOROSK */ case SND_ERR: /* /ERROR-ACTION */ if ((x = cmkey(qorp,2,"","",xxstring)) < 0) goto xputx; pv[n].ival = x; break; case SND_EXC: /* Excludes */ if (!getval) break; if ((x = cmfld("Pattern","",&s,xxstring)) < 0) { if (x == -3) { printf("?Pattern required\n"); x = -9; } goto xputx; } if (s) if (!*s) s = NULL; makestr(&(pv[n].sval),s); if (pv[n].sval) pv[n].ival = 1; break; case SND_PRM: /* /PERMISSIONS */ if (!getval) x = 1; else if ((x = cmkey(onoff,2,"","on",xxstring)) < 0) goto xputx; pv[SND_PRM].ival = x; break; #ifdef PIPESEND case SND_FLT: /* /FILTER */ debug(F101,"ftp put /filter getval","",getval); if (!getval) break; if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) { if (x == -3) s = ""; else goto xputx; } if (*s) s = brstrip(s); y = strlen(s); for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */ if (s[x] != '\\') continue; if (s[x+1] == 'v') break; } if (x == y) { printf( "?Filter must contain a replacement variable for filename.\n" ); x = -9; goto xputx; } if (s) if (!*s) s = NULL; makestr(&(pv[n].sval),s); if (pv[n].sval) pv[n].ival = 1; break; #endif /* PIPESEND */ case SND_NAM: /* /FILENAMES */ if (!getval) break; if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0) goto xputx; debug(F101,"ftp put /filenames","",x); pv[n].ival = x; break; case SND_SMA: /* Smaller / larger than */ case SND_LAR: { CK_OFF_T y; if (!getval) break; if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0) goto xputx; pv[n].wval = y; break; } case SND_FIL: /* Name of file containing filenames */ if (!getval) break; if ((x = cmifi("Name of file containing list of filenames", "",&s,&y,xxstring)) < 0) { if (x == -3) { printf("?Filename required\n"); x = -9; } goto xputx; } else if (y && iswild(s)) { printf("?Wildcards not allowed\n"); x = -9; goto xputx; } if (s) if (!*s) s = NULL; makestr(&(pv[n].sval),s); if (pv[n].sval) { pv[n].ival = 1; pv[SND_ARR].ival = 0; } else { pv[n].ival = 0; } mput = 0; break; case SND_MOV: /* MOVE after */ case SND_REN: /* RENAME after */ case SND_SRN: { /* SERVER-RENAME after */ char * m = ""; switch (n) { case SND_MOV: m = "device and/or directory for source file after sending"; break; case SND_REN: m = "new name for source file after sending"; break; case SND_SRN: m = "new name for destination file after sending"; break; } if (!getval) break; if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) { if (x == -3) { printf("%s\n", n == SND_MOV ? "?Destination required" : "?New name required" ); x = -9; } goto xputx; } if (s) if (!*s) s = NULL; makestr(&(pv[n].sval),s ? brstrip(s) : NULL); pv[n].ival = (pv[n].sval) ? 1 : 0; break; } case SND_STA: /* Starting position (= PSEND) */ if (!getval) break; if ((x = cmnum("0-based position","0",10,&y,xxstring)) < 0) goto xputx; pv[n].ival = y; break; case SND_TYP: /* /TYPE */ if (!getval) break; if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0) goto xputx; pv[n].ival = (x == 2) ? -1 : x; break; #ifndef NOCSETS case SND_CSL: /* Local character set */ case SND_CSR: /* Remote (server) charset */ if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0) { return((x == -3) ? -2 : x); } if (n == SND_CSL) x_csl = x; else x_csr = x; x_xla = 1; /* Overrides global OFF setting */ break; case SND_XPA: /* Transparent */ x_xla = 0; x_csr = -1; x_csl = -1; break; #endif /* NOCSETS */ } } #ifdef PIPESEND if (pv[SND_RES].ival > 0) { /* /RECOVER */ if (sndfilter || pv[SND_FLT].ival > 0) { printf("?Sorry, no /RECOVER or /START if SEND FILTER selected\n"); x = -9; goto xputx; } if (sfttab[0] > 0 && sfttab[SFT_REST] == 0) printf("WARNING: Server says it doesn't support REST.\n"); } #endif /* PIPESEND */ cmarg = ""; cmarg2 = asnambuf; line[0] = NUL; s = line; wild = 0; switch (cmresult.fcode) { /* How did we get out of switch loop */ case _CMIFI: /* Input filename */ if (pv[SND_FIL].ival > 0) { printf("?You may not give a PUT filespec and a /LISTFILE\n"); x = -9; goto xputx; } ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Name */ if (pv[SND_ARR].ival > 0) ckstrncpy(asnambuf,line,CKMAXPATH); else wild = cmresult.nresult; /* Wild flag */ debug(F111,"ftp put wild",line,wild); if (!wild && !recursive && !mput) nolinks = 0; break; case _CMFLD: /* Field */ /* Only allowed with /COMMAND and /ARRAY */ if (pv[SND_FIL].ival > 0) { printf("?You may not give a PUT filespec and a /LISTFILE\n"); x = -9; goto xputx; } /* For MPUT it's OK to have filespecs that don't match any files */ if (mput) break; if (pv[SND_CMD].ival < 1 && pv[SND_ARR].ival < 1) { #ifdef CKROOT if (ckrooterr) printf("?Off limits: %s\n",cmresult.sresult); else #endif /* CKROOT */ printf("?%s - \"%s\"\n", iswild(cmresult.sresult) ? "No files match" : "File not found", cmresult.sresult ); x = -9; goto xputx; } ckstrncpy(line,cmresult.sresult,LINBUFSIZ); if (pv[SND_ARR].ival > 0) ckstrncpy(asnambuf,line,CKMAXPATH); break; case _CMCFM: /* Confirmation */ confirmed = 1; break; default: printf("?Unexpected function code: %d\n",cmresult.fcode); x = -9; goto xputx; } debug(F110,"ftp put string",s,0); debug(F101,"ftp put confirmed","",confirmed); /* Save and change protocol and transfer mode */ /* Global values are restored in main parse loop */ g_displa = fdispla; if (ftp_dis > -1) fdispla = ftp_dis; g_skipbup = skipbup; if (pv[SND_NOB].ival > -1) { /* /NOBACKUP (skip backup file) */ g_skipbup = skipbup; skipbup = 1; } if (pv[SND_TYP].ival > -1) { /* /TYPE */ xfiletype = pv[SND_TYP].ival; if (xfiletype == 2) xfiletype = -1; } if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */ forcetype = 1; /* So skip file scan */ ftp_typ = FTT_BIN; /* Set binary */ } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */ forcetype = 1; ftp_typ = FTT_ASC; } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/ forcetype = 1; ftp_typ = FTT_TEN; } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) { forcetype = 1; ftp_typ = binary; g_ftp_typ = binary; } #ifdef PIPESEND if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */ debug(F110,"PUT /COMMAND before stripping",s,0); s = brstrip(s); debug(F110,"PUT /COMMAND after stripping",s,0); if (!*s) { printf("?Sorry, a command to send from is required\n"); x = -9; goto xputx; } cmarg = s; } #endif /* PIPESEND */ /* Set up /MOVE and /RENAME */ if (pv[SND_DEL].ival > 0 && (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) { printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n"); x = -9; goto xputx; } #ifdef CK_TMPDIR if (pv[SND_MOV].ival > 0) { int len; char * p = pv[SND_MOV].sval; len = strlen(p); if (!isdir(p)) { /* Check directory */ #ifdef CK_MKDIR char * s = NULL; s = (char *)malloc(len + 4); if (s) { strcpy(s,p); /* safe */ #ifdef datageneral if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; } #else if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; } #endif /* datageneral */ s[len++] = 'X'; s[len] = NUL; #ifdef NOMKDIR x = -1; #else x = zmkdir(s); #endif /* NOMKDIR */ free(s); if (x < 0) { printf("?Can't create \"%s\"\n",p); x = -9; goto xputx; } } #else printf("?Directory \"%s\" not found\n",p); x = -9; goto xputx; #endif /* CK_MKDIR */ } makestr(&snd_move,p); } #endif /* CK_TMPDIR */ if (pv[SND_REN].ival > 0) { /* /RENAME */ char * p = pv[SND_REN].sval; if (!p) p = ""; if (!*p) { printf("?New name required for /RENAME\n"); x = -9; goto xputx; } p = brstrip(p); #ifndef NOSPL /* If name given is wild, rename string must contain variables */ if (wild) { char * s = tmpbuf; x = TMPBUFSIZ; zzstring(p,&s,&x); if (!strcmp(tmpbuf,p)) { printf( "?/RENAME for file group must contain variables such as \\v(filename)\n" ); x = -9; goto xputx; } } #endif /* NOSPL */ makestr(&snd_rename,p); debug(F110,"FTP snd_rename",snd_rename,0); } if (pv[SND_SRN].ival > 0) { /* /SERVER-RENAME */ char * p = pv[SND_SRN].sval; if (!p) p = ""; if (!*p) { printf("?New name required for /SERVER-RENAME\n"); x = -9; goto xputx; } p = brstrip(p); #ifndef NOSPL if (wild) { char * s = tmpbuf; x = TMPBUFSIZ; zzstring(p,&s,&x); if (!strcmp(tmpbuf,p)) { printf( "?/SERVER-RENAME for file group must contain variables such as \\v(filename)\n" ); x = -9; goto xputx; } } #endif /* NOSPL */ makestr(&srv_renam,p); debug(F110,"ftp put srv_renam",srv_renam,0); } if (!confirmed) { /* CR not typed yet, get more fields */ char * lp; if (mput) { /* MPUT or MMOVE */ nfils = 0; /* We already have the first one */ #ifndef NOMSEND if (cmresult.fcode == _CMIFI) { /* First filespec is valid */ msfiles[nfils++] = line; /* Store pointer */ lp = line + (int)strlen(line) + 1; /* Point past it */ debug(F111,"ftp put mput",msfiles[nfils-1],nfils-1); } else { /* First filespec matches no files */ debug(F110,"ftp put mput skipping first filespec", cmresult.sresult, 0 ); lp = line; } /* Parse a filespec, a "field", or confirmation */ cmfdbi(&sf, /* 1st FDB - file to send */ _CMIFI, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nolinks | x_recurse, /* addtl numeric data 1 */ 0, /* dirflg 0 means "not dirs only" */ xxstring, NULL, &fl ); cmfdbi(&fl, /* 2nd FDB - local filespec */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, &cm ); cmfdbi(&cm, /* 3rd FDB - Confirmation */ _CMCFM, /* fcode */ "", "", "", 0, 0, NULL, NULL, NULL ); while (!confirmed) { /* Get more filenames */ x = cmfdb(&sf); /* Parse something */ debug(F101,"ftp put cmfdb B","",x); debug(F101,"ftp put fcode B","",cmresult.fcode); if (x < 0) /* Error */ goto xputx; /* or reparse needed */ switch (cmresult.fcode) { case _CMCFM: /* End of command */ confirmed++; if (nfils < 1) { debug(F100,"ftp put mput no files match","",0); printf("?No files match MPUT list\n"); x = -9; goto xputx; } break; case _CMFLD: /* No match */ debug(F110,"ftp put mput skipping",cmresult.sresult,0); continue; case _CMIFI: /* Good match */ s = cmresult.sresult; msfiles[nfils++] = lp; /* Got one, count, point to it, */ p = lp; /* remember pointer, */ while ((*lp++ = *s++)) /* and copy it into buffer */ if (lp > (line + LINBUFSIZ)) { /* Avoid memory leak */ printf("?MPUT list too long\n"); line[0] = NUL; x = -9; goto xputx; } debug(F111,"ftp put mput adding",msfiles[nfils-1],nfils-1); if (nfils == 1) /* Take care of \v(filespec) */ fspec[0] = NUL; #ifdef ZFNQFP zfnqfp(p,TMPBUFSIZ,tmpbuf); p = tmpbuf; #endif /* ZFNQFP */ if (((int)strlen(fspec) + (int)strlen(p) + 1) < fspeclen) { strcat(fspec,p); /* safe */ strcat(fspec," "); /* safe */ } else { #ifdef COMMENT printf("WARNING - \\v(filespec) buffer overflow\n"); #else debug(F101,"doxput filespec buffer overflow","",0); #endif /* COMMENT */ } } } #endif /* NOMSEND */ } else { /* Regular PUT */ nfils = -1; if ((x = cmtxt(wild ? "\nOptional as-name template containing replacement variables \ like \\v(filename)" : "Optional name to send it with", "",&p,NULL)) < 0) goto xputx; if (p) if (!*p) p = NULL; p = brstrip(p); if (p && *p) { makestr(&(pv[SND_ASN].sval),p); if (pv[SND_ASN].sval) pv[SND_ASN].ival = 1; debug(F110,"ftp put /as-name 2",pv[SND_ASN].sval,0); } } } /* Set cmarg2 from as-name, however we got it. */ CHECKCONN(); if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) { char * p; p = brstrip(pv[SND_ASN].sval); ckstrncpy(asnambuf,p,CKMAXPATH+1); } debug(F110,"ftp put asnambuf",asnambuf,0); if (pv[SND_FIL].ival > 0) { if (confirmed) { if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) { debug(F110,"ftp put can't open",pv[SND_FIL].sval,0); printf("?Failure to open %s\n",pv[SND_FIL].sval); x = -9; goto xputx; } makestr(&filefile,pv[SND_FIL].sval); /* Open, remember name */ debug(F110,"ftp PUT /LISTFILE opened",filefile,0); wild = 1; } } if (confirmed && !line[0] && !filefile) { #ifndef NOMSEND if (filehead) { /* OK if we have a SEND-LIST */ nfils = filesinlist; sndsrc = nfils; /* Like MSEND */ addlist = 1; /* But using a different list... */ filenext = filehead; goto doput; } #endif /* NOMSEND */ printf("?Filename required but not given\n"); x = -9; goto xputx; } #ifndef NOMSEND addlist = 0; /* Don't use SEND-LIST. */ #endif /* NOMSEND */ if (mput) { /* MPUT (rather than PUT) */ #ifndef NOMSEND cmlist = msfiles; /* List of filespecs */ sndsrc = nfils; /* rather filespec and as-name */ #endif /* NOMSEND */ pipesend = 0; } else if (filefile) { /* File contains list of filenames */ s = ""; cmarg = ""; line[0] = NUL; nfils = 1; sndsrc = 1; } else if (pv[SND_ARR].ival < 1 && pv[SND_CMD].ival < 1) { /* Not MSEND, MMOVE, /LIST, or /ARRAY */ nfils = sndsrc = -1; if (!wild) { if (zchki(s) < 0) { printf("?Read access denied - \"%s\"\n", s); x = -9; goto xputx; } } if (s != line) /* We might already have done this. */ ckstrncpy(line,s,LINBUFSIZ); /* Copy of string just parsed. */ #ifdef DEBUG else debug(F110,"doxput line=s",line,0); #endif /* DEBUG */ cmarg = line; /* File to send */ } #ifndef NOMSEND zfnqfp(cmarg,fspeclen,fspec); /* Get full name */ #endif /* NOMSEND */ if (!mput) { /* For all but MPUT... */ #ifdef PIPESEND if (pv[SND_CMD].ival > 0) /* /COMMAND sets pipesend flag */ pipesend = 1; debug(F101,"ftp put /COMMAND pipesend","",pipesend); if (pipesend && filefile) { printf("?Invalid switch combination\n"); x = -9; goto xputx; } #endif /* PIPESEND */ #ifndef NOSPL /* If as-name given and filespec is wild, as-name must contain variables */ if ((wild || mput) && asnambuf[0]) { char * s = tmpbuf; x = TMPBUFSIZ; zzstring(asnambuf,&s,&x); if (!strcmp(tmpbuf,asnambuf)) { printf( "?As-name for file group must contain variables such as \\v(filename)\n" ); x = -9; goto xputx; } } #endif /* NOSPL */ } doput: if (pv[SND_SHH].ival > 0) { /* SEND /QUIET... */ fdispla = 0; debug(F101,"ftp put display","",fdispla); } else { displa = 1; if (ftp_deb) fdispla = XYFD_B; } #ifdef PUTARRAY /* SEND /ARRAY... */ if (pv[SND_ARR].ival > 0) { if (!ap) { x = -2; goto xputx; } /* (shouldn't happen) */ if (range[0] == -1) /* If low end of range not specified */ range[0] = 1; /* default to 1 */ if (range[1] == -1) /* If high not specified */ range[1] = a_dim[arrayx]; /* default to size of array */ if ((range[0] < 0) || /* Check range */ (range[0] > a_dim[arrayx]) || (range[1] < range[0]) || (range[1] > a_dim[arrayx])) { printf("?Bad array range - [%d:%d]\n",range[0],range[1]); x = -9; goto xputx; } sndarray = ap; /* Array pointer */ sndxin = arrayx; /* Array index */ sndxlo = range[0]; /* Array range */ sndxhi = range[1]; sndxnam[7] = (char)((sndxin == 1) ? 64 : sndxin + ARRAYBASE); if (!asnambuf[0]) ckstrncpy(asnambuf,sndxnam,CKMAXPATH); cmarg = ""; } #endif /* PUTARRAY */ moving = 0; if (pv[SND_ARR].ival < 1) { /* File selection & disposition... */ if (pv[SND_DEL].ival > 0) /* /DELETE was specified */ moving = 1; if (pv[SND_AFT].ival > 0) /* Copy SEND criteria */ ckstrncpy(sndafter,pv[SND_AFT].sval,19); if (pv[SND_BEF].ival > 0) ckstrncpy(sndbefore,pv[SND_BEF].sval,19); if (pv[SND_NAF].ival > 0) ckstrncpy(sndnafter,pv[SND_NAF].sval,19); if (pv[SND_NBE].ival > 0) ckstrncpy(sndnbefore,pv[SND_NBE].sval,19); if (pv[SND_EXC].ival > 0) makelist(pv[SND_EXC].sval,sndexcept,NSNDEXCEPT); if (pv[SND_SMA].ival > -1) sndsmaller = pv[SND_SMA].wval; if (pv[SND_LAR].ival > -1) sndlarger = pv[SND_LAR].wval; if (pv[SND_NAM].ival > -1) x_cnv = pv[SND_NAM].ival; if (pv[SND_USN].ival > -1) x_usn = pv[SND_USN].ival; if (pv[SND_ERR].ival > -1) puterror = pv[SND_ERR].ival; #ifdef DOUPDATE if (pv[SND_UPD].ival > 0) { if (x_usn) { printf("?Conflicting switches: /UPDATE /UNIQUE\n"); x = -9; goto xputx; } putflags |= PUT_UPD; ftp_dates |= 2; } #ifdef COMMENT /* This works but it's useless, maybe dangerous */ if (pv[SND_DIF].ival > 0) { if (x_usn) { printf("?Conflicting switches: /DATES-DIFFER /UNIQUE\n"); x = -9; goto xputx; } putflags |= PUT_DIF; ftp_dates |= 2; } #endif /* COMMENT */ #endif /* DOUPDATE */ if (pv[SND_SIM].ival > 0) putflags |= PUT_SIM; if (pv[SND_PRM].ival > -1) { #ifdef UNIX if (x_usn) { printf("?Conflicting switches: /PERMISSIONS /UNIQUE\n"); x = -9; goto xputx; } x_prm = pv[SND_PRM].ival; #else /* UNIX */ printf("?/PERMISSIONS switch is not supported\n"); #endif /* UNIX */ } #ifdef FTP_RESTART if (pv[SND_RES].ival > 0) { if (!sizeok) { printf("?PUT /RESTART can't be used because SIZE disabled.\n"); x = -9; goto xputx; } if (x_usn || putflags) { printf("?Conflicting switches: /RECOVER %s\n", x_usn && putflags ? "/UNIQUE /UPDATE" : (x_usn ? "/UNIQUE" : "/UPDATE") ); x = -9; goto xputx; } #ifndef NOCSETS if (x_xla && (x_csl == FC_UCS2 || x_csl == FC_UTF8 || x_csr == FC_UCS2 || x_csr == FC_UTF8)) { printf("?/RECOVER can not be used with Unicode translation\n"); x = -9; goto xputx; } #endif /* NOCSETS */ putflags = PUT_RES; } #endif /* FTP_RESTART */ } debug(F101,"ftp PUT restart","",putflags & PUT_RES); debug(F101,"ftp PUT update","",putflags & PUT_UPD); #ifdef PIPESEND if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */ if (!pv[SND_FLT].sval) { sndfilter = NULL; } else { sndfilter = (char *) malloc((int) strlen(pv[SND_FLT].sval) + 1); if (sndfilter) strcpy(sndfilter,pv[SND_FLT].sval); /* safe */ } debug(F110,"ftp put /FILTER", sndfilter, 0); } if (sndfilter || pipesend) /* No /UPDATE or /RESTART */ if (putflags) /* with pipes or filters */ putflags = 0; #endif /* PIPESEND */ tfc = (CK_OFF_T)0; /* Initialize stats and counters */ filcnt = 0; pktnum = 0; spackets = 0L; if (wild) /* (is this necessary?) */ cx = FTP_MPU; t0 = gmstimer(); /* Record starting time */ done = 0; /* Loop control */ cancelgroup = 0; cdlevel = 0; cdsimlvl = 0; while (!done && !cancelgroup) { /* Loop for all files */ /* or until canceled. */ #ifdef FTP_PROXY /* If we are using a proxy, we don't use the local file list; instead we use the list on the remote machine which we want sent to someone else, and we use remglob() to get the names. But in that case we shouldn't even be executing this routine; see ftp_mput(). */ #endif /* FTP_PROXY */ cancelfile = 0; x = gnfile(); /* Get next file from list(s) */ if (x == 0) /* (see gnfile() comments...) */ x = gnferror; debug(F111,"FTP PUT gnfile",filnam,x); debug(F111,"FTP PUT binary",filnam,binary); switch (x) { case 1: /* File to send */ s2 = asnambuf; #ifndef NOSPL if (asnambuf[0]) { /* As-name */ int n; char *p; /* to be evaluated... */ n = TMPBUFSIZ; p = tmpbuf; zzstring(asnambuf,&p,&n); s2 = tmpbuf; debug(F110,"ftp put asname",s2,0); } #endif /* NOSPL */ rc = putfile(cx, /* Function (PUT, APPEND) */ filnam, s2, /* Name to send, as-name */ forcetype, moving, /* Parameters from switches... */ snd_move, snd_rename, srv_renam, x_cnv, x_usn, xfiletype, x_prm, #ifndef NOCSETS x_csl, (!x_xla ? -1 : x_csr), #else -1, -1, #endif /* NOCSETS */ putflags ); debug(F111,"ftp put putfile rc",filnam,rc); debug(F111,"ftp put putfile cancelfile",filnam,cancelfile); debug(F111,"ftp put putfile cancelgroup",filnam,cancelgroup); if (rc > -1) { good++; status = 1; } if (cancelfile) continue; if (rc < 0) { ftp_fai++; if (puterror) { status = 0; printf("?Fatal upload error: %s\n",filnam); done++; } } continue; case 0: /* No more files, done */ done++; continue; case -1: printf("?%s: file not found - \"%s\"\n", puterror ? "Fatal" : "Warning", filnam ); if (puterror) { status = 0; done++; break; } continue; case -2: if (puterror) { printf("?Fatal: file not found - \"%s\"\n", filnam); status = 0; done++; break; } continue; /* Not readable, keep going */ case -3: if (puterror) { printf("?Fatal: Read access denied - \"%s\"\n", filnam); status = 0; done++; break; } printf("?Warning access denied - \"%s\"\n", filnam); continue; #ifdef COMMENT case -4: /* Canceled */ done++; break; #endif /* COMMENT */ case -5: printf("?Too many files match\n"); done++; break; case -6: if (good < 1) printf("?No files selected\n"); done++; break; default: printf("?getnextfile() - unknown failure\n"); done++; } } if (cdlevel > 0) { while (cdlevel--) { if (cdsimlvl) { cdsimlvl--; } else if (!doftpcdup()) break; } } if (status > 0) { if (cancelgroup) status = 0; else if (cancelfile && good < 1) status = 0; } success = status; x = success; xputx: if (x > -1) { #ifdef GFTIMER t1 = gmstimer(); /* End time */ sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */ if (!sec) sec = 0.001; fptsecs = sec; #else sec = (t1 - t0) / 1000; if (!sec) sec = 1; #endif /* GFTIMER */ tfcps = (long) (tfc / sec); tsecs = (int)sec; lastxfer = W_FTP|W_SEND; xferstat = success; if (dpyactive) ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, ""); } for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */ if (pv[i].sval) free(pv[i].sval); } ftreset(); /* Undo switch effects */ dpyactive = 0; return(x); } static char ** mgetlist = NULL; /* For MGET */ static int mgetn = 0, mgetx = 0; static char xtmpbuf[4096]; /* c m d l i n g e t Get files specified by -g command-line option. File list is set up in cmlist[] by ckuusy.c; nfils is length of list. */ int #ifdef CK_ANSIC cmdlinget( int stay ) #else cmdlinget(stay) int stay; #endif /* CK_ANSIC */ { int x, rc = 0, done = 0, good = 0, status = 0, append = 0; int lcs = -1, rcs = -1, xlate = 0; int first = 1; int mget = 1; int nc; char * s, * s2, * s3; ULONG t0, t1; /* Times for stats */ #ifdef GFTIMER CKFLOAT sec; #else int sec = 0; #endif /* GFTIMER */ if (quiet) { /* -q really means quiet */ displa = 0; fdispla = 0; } else { displa = 1; fdispla = XYFD_B; } testing = 0; dpyactive = 0; out2screen = 0; what = W_FTP|W_RECV; mgetmethod = 0; mgetforced = 0; havetype = 0; havesize = (CK_OFF_T)-1; makestr(&havemdtm,NULL); if (ftp_fnc < 0) ftp_fnc = fncact; #ifndef NOSPL cmd_quoting = 0; #endif /* NOSPL */ debug(F101,"ftp cmdlinget nfils","",nfils); if (ftp_cnv == CNV_AUTO) { /* Name conversion is auto */ if (alike) { /* If server & client are alike */ nc = 0; /* no conversion */ } else { /* If they are different */ if (servertype == SYS_UNIX || servertype == SYS_WIN32) nc = -1; /* only minimal conversions needed */ else /* otherwise */ nc = 1; /* full conversion */ } } else /* Not auto - do what user said */ nc = ftp_cnv; if (nfils < 1) doexit(BAD_EXIT,-1); t0 = gmstimer(); /* Starting time for this batch */ #ifndef NOCSETS if (xlate) { /* SET FTP CHARACTER-SET-TRANSLATION */ lcs = ftp_csl; /* Local charset */ if (lcs < 0) lcs = fcharset; if (lcs < 0) xlate = 0; } if (xlate) { /* Still ON? */ rcs = ftp_csx; /* Remote (Server) charset */ if (rcs < 0) rcs = ftp_csr; if (rcs < 0) xlate = 0; } #endif /* NOCSETS */ /* If we have only one file and it is a directory, then we ask for a listing of its contents, rather than retrieving the directory file itself. This is what (e.g.) Netscape does. */ if (nfils == 1) { if (doftpcwd((char *)cmlist[mgetx],-1)) { /* If we can CD to it, it must be a directory */ if (recursive) { cmlist[mgetx] = "*"; } else { status = (recvrequest("LIST","-","","wb",0,0,NULL,xlate,lcs,rcs)==0); done = 1; } } } /* The following is to work around UNIX servers which, when given a command like "NLST path/blah" (not wild) returns the basename without the path. */ if (!done && servertype == SYS_UNIX && nfils == 1) { mget = iswild(cmlist[mgetx]); } if (!mget && !done) { /* Invoked by command-line FTP URL */ if (ftp_deb) printf("DOING GET...\n"); done++; cancelfile = 0; /* This file not canceled yet */ s = cmlist[mgetx]; rc = 0; /* Initial return code */ fsize = (CK_OFF_T)-1; if (sizeok) { x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm); /* Get remote file's size */ if (x == REPLY_COMPLETE) fsize = ckatofs(&ftp_reply_str[4]); } ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */ debug(F111,"ftp cmdlinget filnam",filnam,fsize); nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */ s2 = tmpbuf; /* If local file already exists, take collision action */ if (zchki(s2) > -1) { switch (ftp_fnc) { case XYFX_A: /* Append */ append = 1; break; case XYFX_R: /* Rename */ case XYFX_B: { /* Backup */ char * p = NULL; int x = -1; znewn(s2,&p); /* Make unique name */ debug(F110,"ftp cmdlinget znewn",p,0); if (ftp_fnc == XYFX_B) { /* Backup existing file */ x = zrename(s2,p); debug(F111,"ftp cmdlinget backup zrename",p,x); } else { /* Rename incoming file */ x = ckstrncpy(tmpbuf,p,CKMAXPATH+1); s2 = tmpbuf; debug(F111,"ftp cmdlinget rename incoming",p,x); } if (x < 0) { printf("?Backup/Rename failed\n"); return(success = 0); } break; } case XYFX_D: /* Discard */ ftscreen(SCR_FN,'F',(CK_OFF_T)0,s); ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s); tlog(F100," refused: name","",0); debug(F110,"ftp cmdlinget skip name",s2,0); goto xclget; case XYFX_X: /* Overwrite */ case XYFX_U: /* Update (already handled above) */ case XYFX_M: /* ditto */ break; } } rc = getfile(s, /* Remote name */ s2, /* Local name */ 0, /* Recover/Restart */ append, /* Append */ NULL, /* Pipename */ 0, /* Translate charsets */ -1, /* File charset (none) */ -1 /* Server charset (none) */ ); debug(F111,"ftp cmdlinget rc",s,rc); debug(F111,"ftp cmdlinget cancelfile",s,cancelfile); debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup); if (rc < 0 && haveurl && s[0] == '/') /* URL failed - try again */ rc = getfile(&s[1], /* Remote name without leading '/' */ s2, /* Local name */ 0, /* Recover/Restart */ append, /* Append */ NULL, /* Pipename */ 0, /* Translate charsets */ -1, /* File charset (none) */ -1 /* Server charset (none) */ ); if (rc > -1) { good++; status = 1; } if (cancelfile) goto xclget; if (rc < 0) { ftp_fai++; #ifdef FTP_TIMEOUT if (ftp_timed_out) status = 0; #endif /* FTP_TIMEOUT */ if (geterror) { status = 0; done++; } } } if (ftp_deb && !done) printf("DOING MGET...\n"); while (!done && !cancelgroup) { cancelfile = 0; /* This file not canceled yet */ s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0); if (!s) s = ""; if (!*s) { first = 1; mgetx++; if (mgetx < nfils) s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0); else s = NULL; debug(F111,"ftp cmdlinget remote_files B",s,0); if (!s) { done = 1; break; } } /* The semantics of NLST are ill-defined. Suppose we have just sent NLST /path/[a-z]*. Most servers send back names like /path/foo, /path/bar, etc. But some send back only foo and bar, and subsequent RETR commands based on the pathless names are not going to work. */ if (servertype == SYS_UNIX && !ckstrchr(s,'/')) { if ((s3 = ckstrrchr(cmlist[mgetx],'/'))) { int len, left = 4096; char * tmp = xtmpbuf; len = s3 - cmlist[mgetx] + 1; ckstrncpy(tmp,cmlist[mgetx],left); tmp += len; left -= len; ckstrncpy(tmp,s,left); s = xtmpbuf; debug(F111,"ftp cmdlinget remote_files X",s,0); } } first = 0; /* Not first any more */ debug(F111,"ftp cmdlinget havetype",s,havetype); if (havetype > 0 && havetype != FTYP_FILE) { /* Server says not file */ debug(F110,"ftp cmdlinget not-a-file",s,0); continue; } rc = 0; /* Initial return code */ if (havesize > (CK_OFF_T)-1) { /* Already have file size? */ fsize = havesize; } else { /* No - must ask server */ /* Prior to sending the NLST command we necessarily put the server into ASCII mode. We must now put it back into the the requested mode so the upcoming SIZE command returns right kind of size; this is especially important for GET /RECOVER; otherwise the server returns the "ASCII" size of the file, rather than its true size. */ changetype(ftp_typ,0); /* Change to requested type */ fsize = (CK_OFF_T)-1; if (sizeok) { x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm); if (x == REPLY_COMPLETE) fsize = ckatofs(&ftp_reply_str[4]); } } ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */ debug(F111,"ftp cmdlinget filnam",filnam,fsize); nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */ s2 = tmpbuf; /* If local file already exists, take collision action */ if (zchki(s2) > -1) { switch (ftp_fnc) { case XYFX_A: /* Append */ append = 1; break; case XYFX_R: /* Rename */ case XYFX_B: { /* Backup */ char * p = NULL; int x = -1; znewn(s2,&p); /* Make unique name */ debug(F110,"ftp cmdlinget znewn",p,0); if (ftp_fnc == XYFX_B) { /* Backup existing file */ x = zrename(s2,p); debug(F111,"ftp cmdlinget backup zrename",p,x); } else { /* Rename incoming file */ x = ckstrncpy(tmpbuf,p,CKMAXPATH+1); s2 = tmpbuf; debug(F111,"ftp cmdlinget rename incoming",p,x); } if (x < 0) { printf("?Backup/Rename failed\n"); return(success = 0); } break; } case XYFX_D: /* Discard */ ftscreen(SCR_FN,'F',(CK_OFF_T)0,s); ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s); tlog(F100," refused: name","",0); debug(F110,"ftp cmdlinget skip name",s2,0); continue; case XYFX_X: /* Overwrite */ case XYFX_U: /* Update (already handled above) */ case XYFX_M: /* ditto */ break; } } /* ^^^ ADD CHARSET STUFF HERE ^^^ */ rc = getfile(s, /* Remote name */ s2, /* Local name */ 0, /* Recover/Restart */ append, /* Append */ NULL, /* Pipename */ 0, /* Translate charsets */ -1, /* File charset (none) */ -1 /* Server charset (none) */ ); debug(F111,"ftp cmdlinget rc",s,rc); debug(F111,"ftp cmdlinget cancelfile",s,cancelfile); debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup); if (rc > -1) { good++; status = 1; } if (cancelfile) continue; if (rc < 0) { ftp_fai++; #ifdef FTP_TIMEOUT if (ftp_timed_out) status = 0; #endif /* FTP_TIMEOUT */ if (geterror) { status = 0; done++; } } } xclget: if (cancelgroup) mlsreset(); if (status > 0) { if (cancelgroup) status = 0; else if (cancelfile && good < 1) status = 0; } success = status; #ifdef GFTIMER t1 = gmstimer(); /* End time */ sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */ if (!sec) sec = 0.001; fptsecs = sec; #else sec = (t1 - t0) / 1000; if (!sec) sec = 1; #endif /* GFTIMER */ tfcps = (long) (tfc / sec); tsecs = (int)sec; lastxfer = W_FTP|W_RECV; xferstat = success; if (dpyactive) ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, ""); if (!stay) doexit(success ? GOOD_EXIT : BAD_EXIT, -1); return(success); } /* d o f t p g e t -- Parse and execute GET, MGET, MDELETE, ... */ /* Note: if we wanted to implement /AFTER:, /BEFORE:, etc, we could use zstrdat() to convert to UTC-based time_t. But it doesn't make sense from the user-interface perspective, since the server's directory listings show its own local times and since we don't know what timezone it's in, there's no way to reconcile our local times with the server's. */ int #ifdef CK_ANSIC doftpget( int cx, int who ) /* who == 1 for ftp, 0 for kermit */ #else doftpget(cx,who) int cx, who; #endif /* CK_ANSIC */ { struct FDB fl, sw, cm; int i, n, rc, getval = 0, mget = 0, done = 0, pipesave = 0; int x_cnv = 0, x_prm = 0, restart = 0, status = 0, good = 0; int x_fnc = 0, first = 0, skipthis = 0, append = 0, selected = 0; int renaming = 0, mdel = 0, listfile = 0, updating = 0, getone = 0; int moving = 0, deleting = 0, toscreen = 0, haspath = 0; int gotsize = 0; CK_OFF_T getlarger = (CK_OFF_T)-1; CK_OFF_T getsmaller = (CK_OFF_T)-1; char * msg, * s, * s2, * nam, * pipename = NULL, * pn = NULL; char * src = "", * local = ""; int x_csl = -1, x_csr = -1; /* Local and remote charsets */ int x_xla = 0; char c; /* Worker char */ ULONG t0 = 0L, t1; /* Times for stats */ #ifdef GFTIMER CKFLOAT sec; #else int sec = 0; #endif /* GFTIMER */ struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */ success = 0; /* Assume failure */ forcetype = 0; /* No /TEXT or /BINARY given yet */ restart = 0; /* No restart yet */ out2screen = 0; /* No TO-SCREEN switch given yet */ mgetmethod = 0; /* No NLST or MLSD switch yet */ mgetforced = 0; g_displa = fdispla; if (ftp_dis > -1) fdispla = ftp_dis; x_cnv = ftp_cnv; /* Filename conversion */ if (x_cnv == CNV_AUTO) { /* Name conversion is auto */ if (alike) { /* If server & client are alike */ x_cnv = 0; /* no conversion */ } else { /* If they are different */ if (servertype == SYS_UNIX || servertype == SYS_WIN32) x_cnv = -1; /* only minimal conversions needed */ else /* otherwise */ x_cnv = 1; /* full conversion */ } } else /* Not auto - do what user said */ x_cnv = ftp_cnv; x_prm = ftp_prm; /* Permissions */ if (x_prm == SET_AUTO) /* Permissions AUTO */ x_prm = alike; #ifndef NOCSETS x_csr = ftp_csr; /* Inherit global server charset */ x_csl = ftp_csl; /* Inherit global local charset */ if (x_csl < 0) /* If none, use current */ x_csl = fcharset; /* file character-set. */ x_xla = ftp_xla; /* Translation On/Off */ #endif /* NOCSETS */ geterror = ftp_err; /* Inherit global error action. */ asnambuf[0] = NUL; /* No as-name yet. */ pipesave = pipesend; pipesend = 0; havetype = 0; havesize = (CK_OFF_T)-1; makestr(&havemdtm,NULL); if (g_ftp_typ > -1) { /* Restore TYPE if saved */ ftp_typ = g_ftp_typ; /* g_ftp_typ = -1; */ } for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */ pv[i].sval = NULL; /* to null pointers */ pv[i].ival = -1; /* and -1 int values */ pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */ } zclose(ZMFILE); /* In case it was left open */ x_fnc = ftp_fnc > -1 ? ftp_fnc : fncact; /* Filename collision action */ if (fp_nml) { /* Reset /NAMELIST */ if (fp_nml != stdout) fclose(fp_nml); fp_nml = NULL; } makestr(&ftp_nml,NULL); /* Initialize list of remote filespecs */ if (!mgetlist) { mgetlist = (char **)malloc(MGETMAX * sizeof(char *)); if (!mgetlist) { printf("?Memory allocation failure - MGET list\n"); return(-9); } for (i = 0; i < MGETMAX; i++) mgetlist[i] = NULL; } mgetn = 0; /* Number of mget arguments */ mgetx = 0; /* Current arg */ if (who == 0) { /* Called with unprefixed command */ if (cx == XXGET || cx == XXREGET || cx == XXRETR) getone++; switch (cx) { case XXREGET: pv[SND_RES].ival = 1; break; case XXRETR: pv[SND_DEL].ival = 1; break; case XXGET: case XXMGET: mget++; break; } } else { /* FTP command */ if (cx == FTP_GET || cx == FTP_RGE) getone++; switch (cx) { case FTP_DEL: /* (fall thru on purpose) */ case FTP_MDE: mdel++; /* (ditto) */ case FTP_GET: /* (ditto) */ case FTP_MGE: mget++; break; case FTP_RGE: pv[SND_RES].ival = 1; break; } } cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Remote filename;\n or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ mdel ? ndelswi : ngetswi, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ mdel ? delswi : getswi, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* 2nd FDB - remote filename */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, &cm ); cmfdbi(&cm, /* 3rd FDB - Confirmation */ _CMCFM, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, NULL, NULL ); while (1) { /* Parse 0 or more switches */ x = cmfdb(&sw); /* Parse something */ debug(F101,"ftp get cmfdb","",x); if (x < 0) /* Error */ goto xgetx; /* or reparse needed */ if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */ break; c = cmgbrk(); /* Get break character */ getval = (c == ':' || c == '='); /* to see how they ended the switch */ if (getval && !(cmresult.kflags & CM_ARG)) { printf("?This switch does not take arguments\n"); x = -9; goto xgetx; } n = cmresult.nresult; /* Numeric result = switch value */ debug(F101,"ftp get switch","",n); if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); x = -9; goto xgetx; } switch (n) { /* Process the switch */ case SND_ASN: /* /AS-NAME: */ debug(F101,"ftp get /as-name getval","",getval); if (!getval) break; if ((x = cmfld("Name to store it under","",&s,NULL)) < 0) { if (x == -3) { printf("?name required\n"); x = -9; } goto xgetx; } s = brstrip(s); if (!*s) s = NULL; makestr(&(pv[n].sval),s); pv[n].ival = 1; break; case SND_BIN: /* /BINARY */ case SND_TXT: /* /TEXT or /ASCII */ case SND_TEN: /* /TENEX */ pv[SND_BIN].ival = 0; pv[SND_TXT].ival = 0; pv[SND_TEN].ival = 0; pv[n].ival = 1; break; #ifdef PUTPIPE case SND_CMD: /* These take no args */ if (nopush) { printf("?Sorry, system command access is disabled\n"); x = -9; goto xgetx; } #ifdef PIPESEND else if (rcvfilter) { printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n"); x = -9; goto xgetx; } #endif /* PIPESEND */ sw.hlpmsg = "Command, or switch"; /* Change help message */ pv[n].ival = 1; /* Just set the flag */ pv[SND_ARR].ival = 0; break; #endif /* PUTPIPE */ case SND_SHH: /* /QUIET */ case SND_RES: /* /RECOVER (reget) */ case SND_NOB: /* /NOBACKUPFILES */ case SND_DEL: /* /DELETE */ case SND_UPD: /* /UPDATE */ case SND_USN: /* /UNIQUE */ case SND_NOD: /* /NODOTFILES */ case SND_REC: /* /RECOVER */ case SND_MAI: /* /TO-SCREEN */ pv[n].ival = 1; /* Just set the flag */ break; case SND_DIF: /* /DATES-DIFFER */ pv[SND_COL].ival = XYFX_M; /* Now it's a collision option */ pv[n].ival = 1; break; case SND_COL: /* /COLLISION: */ if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0) goto xgetx; if (x == XYFX_M) pv[SND_DIF].ival = 1; /* (phase this out) */ pv[n].ival = x; /* this should be sufficient */ break; case SND_ERR: /* /ERROR-ACTION */ if ((x = cmkey(qorp,2,"","",xxstring)) < 0) goto xgetx; pv[n].ival = x; break; case SND_EXC: /* Exception list */ if (!getval) break; if ((x = cmfld("Pattern","",&s,xxstring)) < 0) { if (x == -3) { printf("?Pattern required\n"); x = -9; } goto xgetx; } if (s) if (!*s) s = NULL; makestr(&(pv[n].sval),s); if (pv[n].sval) pv[n].ival = 1; break; #ifdef PIPESEND case SND_FLT: debug(F101,"ftp get /filter getval","",getval); if (!getval) break; if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) { if (x == -3) s = ""; else goto xgetx; } s = brstrip(s); if (pv[SND_MAI].ival < 1) { y = strlen(s); /* Make sure they included "\v(...)" */ for (x = 0; x < y; x++) { if (s[x] != '\\') continue; if (s[x+1] == 'v') break; } if (x == y) { printf( "?Filter must contain a replacement variable for filename.\n" ); x = -9; goto xgetx; } } if (*s) { pv[n].ival = 1; makestr(&(pv[n].sval),s); } else { pv[n].ival = 0; makestr(&(pv[n].sval),NULL); } break; #endif /* PIPESEND */ case SND_NAM: if (!getval) break; if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0) goto xgetx; debug(F101,"ftp get /filenames","",x); pv[n].ival = x; break; case SND_SMA: /* Smaller / larger than */ case SND_LAR: { CK_OFF_T y; if (!getval) break; if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0) goto xgetx; pv[n].wval = y; break; } case SND_FIL: /* Name of file containing filnames */ if (!getval) break; if ((x = cmifi("Name of file containing list of filenames", "",&s,&y,xxstring)) < 0) { if (x == -3) { printf("?Filename required\n"); x = -9; } goto xgetx; } else if (y && iswild(s)) { printf("?Wildcards not allowed BBB\n"); x = -9; goto xgetx; } if (s) if (!*s) s = NULL; makestr(&(pv[n].sval),s); if (pv[n].sval) pv[n].ival = 1; break; case SND_MOV: /* MOVE after */ case SND_REN: /* RENAME after */ case SND_SRN: { /* SERVER-RENAME */ char * m = ""; switch (n) { case SND_MOV: m = "Device and/or directory for incoming file after reception"; break; case SND_REN: m = "New name for incoming file after reception"; break; case SND_SRN: m = "New name for source file on server after reception"; break; } if (!getval) break; if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) { if (x == -3) { printf("%s\n", n == SND_MOV ? "?Destination required" : "?New name required" ); x = -9; } goto xgetx; } makestr(&(pv[n].sval),*s ? brstrip(s) : NULL); pv[n].ival = (pv[n].sval) ? 1 : 0; break; } #ifndef NOCSETS case SND_CSL: /* Local character set */ case SND_CSR: /* Remote (server) charset */ if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0) return((x == -3) ? -2 : x); if (n == SND_CSL) x_csl = x; else x_csr = x; x_xla = 1; /* Overrides global OFF setting */ break; case SND_XPA: /* Transparent */ x_xla = 0; x_csr = -1; x_csl = -1; break; #endif /* NOCSETS */ case SND_NML: if ((x = cmofi("Local filename","-",&s,xxstring)) < 0) goto xgetx; makestr(&ftp_nml,s); break; case SND_PAT: /* /PATTERN: */ if (!getval) break; if ((x = cmfld("Pattern","*", &s, xxstring)) < 0) goto xgetx; makestr(&(pv[n].sval),*s ? brstrip(s) : NULL); pv[n].ival = (pv[n].sval) ? 1 : 0; break; case SND_NLS: /* /NLST */ pv[n].ival = 1; /* Use NLST */ pv[SND_MLS].ival = 0; /* Don't use MLSD */ break; case SND_MLS: /* /MLSD */ pv[n].ival = 1; /* Use MLSD */ pv[SND_NLS].ival = 0; /* Don't use NLST */ break; default: /* /AFTER, /PERMISSIONS, etc... */ printf("?Sorry, \"%s\" works only with [M]PUT\n",atmbuf); x = -9; goto xgetx; } } line[0] = NUL; cmarg = line; cmarg2 = asnambuf; s = line; /* For GET, we want to parse an optional as-name, like with PUT. For MGET, we must parse a list of names, and then send NLST or MLSD commands for each name separately. */ switch (cmresult.fcode) { /* How did we get out of switch loop */ case _CMFLD: /* Field */ if (!getone) { s = brstrip(cmresult.sresult); makestr(&(mgetlist[mgetn++]),s); while ((x = cmfld("Remote filename","",&s,xxstring)) != -3) { if (x < 0) goto xgetx; makestr(&(mgetlist[mgetn++]),brstrip(s)); if (mgetn >= MGETMAX) { printf("?Too many items in MGET list\n"); goto xgetx; } } if ((x = cmcfm()) < 0) goto xgetx; } else { s = brstrip(cmresult.sresult); ckstrncpy(line,s,LINBUFSIZ); if ((x = cmfld("Name to store it under","",&s,xxstring)) < 0) if (x != -3) goto xgetx; s = brstrip(s); ckstrncpy(asnambuf,s,CKMAXPATH+1); if ((x = cmcfm()) < 0) goto xgetx; } break; case _CMCFM: /* Confirmation */ break; default: printf("?Unexpected function code: %d\n",cmresult.fcode); x = -9; goto xgetx; } if (pv[SND_REC].ival > 0) /* /RECURSIVE */ recursive = 2; if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */ forcetype = 1; /* So skip the name-pattern match */ ftp_typ = XYFT_B; /* Set binary */ } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */ forcetype = 1; ftp_typ = XYFT_T; } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/ forcetype = 1; ftp_typ = FTT_TEN; } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) { forcetype = 1; ftp_typ = binary; g_ftp_typ = binary; } if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) { char * p; p = brstrip(pv[SND_ASN].sval); /* As-name */ ckstrncpy(asnambuf,p,CKMAXPATH+1); } debug(F110,"ftp get asnambuf",asnambuf,0); #ifdef PIPESEND if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */ char * p; p = asnambuf; debug(F110,"GET /COMMAND before stripping",p,0); p = brstrip(p); debug(F110,"GET /COMMAND after stripping",p,0); if (!*p) { printf("?Sorry, a command to write to is required\n"); x = -9; goto xgetx; } pipename = p; pipesend = 1; } #endif /* PIPESEND */ /* Set up /MOVE and /RENAME */ #ifdef COMMENT /* Conflict exists only for PUT - removed 13 Mar 2006 - fdc */ if (pv[SND_DEL].ival > 0 && (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) { printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n"); x = -9; goto xgetx; } #endif /* COMMENT */ #ifdef CK_TMPDIR if (pv[SND_MOV].ival > 0 && pv[SND_MOV].sval) { int len; char * p = pv[SND_MOV].sval; len = strlen(p); if (!isdir(p)) { /* Check directory */ #ifdef CK_MKDIR char * s = NULL; s = (char *)malloc(len + 4); if (s) { strcpy(s,p); /* safe */ #ifdef datageneral if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; } #else if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; } #endif /* datageneral */ s[len++] = 'X'; s[len] = NUL; #ifdef NOMKDIR x = -1; #else x = zmkdir(s); #endif /* NOMKDIR */ free(s); if (x < 0) { printf("?Can't create \"%s\"\n",p); x = -9; goto xgetx; } } #else printf("?Directory \"%s\" not found\n",p); x = -9; goto xgetx; #endif /* CK_MKDIR */ } makestr(&rcv_move,p); moving = 1; } #endif /* CK_TMPDIR */ if (pv[SND_REN].ival > 0) { /* /RENAME */ char * p = pv[SND_REN].sval; if (!p) p = ""; if (!*p) { printf("?New name required for /RENAME\n"); x = -9; goto xgetx; } p = brstrip(p); #ifndef NOSPL /* If name given is wild, rename string must contain variables */ if (mget && !getone) { char * s = tmpbuf; x = TMPBUFSIZ; zzstring(p,&s,&x); if (!strcmp(tmpbuf,p)) { printf( "?/RENAME for file group must contain variables such as \\v(filename)\n" ); x = -9; goto xgetx; } } #endif /* NOSPL */ renaming = 1; makestr(&rcv_rename,p); debug(F110,"FTP rcv_rename",rcv_rename,0); } if (!cmarg[0] && mgetn == 0 && getone && pv[SND_FIL].ival < 1) { printf("?Filename required but not given\n"); x = -9; goto xgetx; } else if ((cmarg[0] || mgetn > 0) && pv[SND_FIL].ival > 0) { printf("?You can't give both /LISTFILE and a remote filename\n"); x = -9; goto xgetx; } CHECKCONN(); /* Check connection */ if (pv[SND_COL].ival > -1) x_fnc = pv[SND_COL].ival; #ifndef NOSPL /* If as-name given for MGET, as-name must contain variables */ if (mget && !getone && asnambuf[0] && x_fnc != XYFX_A) { char * s = tmpbuf; x = TMPBUFSIZ; zzstring(asnambuf,&s,&x); if (!strcmp(tmpbuf,asnambuf)) { printf( "?As-name for MGET must contain variables such as \\v(filename)\n" ); x = -9; goto xgetx; } } #endif /* NOSPL */ /* doget: */ if (pv[SND_SHH].ival > 0 || ftp_nml) { /* GET /QUIET... */ fdispla = 0; } else { displa = 1; if (mdel || ftp_deb) fdispla = XYFD_B; } deleting = 0; if (pv[SND_DEL].ival > 0) /* /DELETE was specified */ deleting = 1; if (pv[SND_EXC].ival > 0) makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT); if (pv[SND_SMA].wval > -1) getsmaller = pv[SND_SMA].wval; if (pv[SND_LAR].wval > -1) getlarger = pv[SND_LAR].wval; if (pv[SND_NAM].ival > -1) x_cnv = pv[SND_NAM].ival; if (pv[SND_ERR].ival > -1) geterror = pv[SND_ERR].ival; if (pv[SND_MAI].ival > -1) toscreen = 1; if (pv[SND_NLS].ival > 0) { /* Force NLST or MLSD? */ mgetmethod = SND_NLS; mgetforced = 1; } else if (pv[SND_MLS].ival > 0) { mgetmethod = SND_MLS; mgetforced = 1; } #ifdef FTP_RESTART if (pv[SND_RES].ival > 0) { if (!ftp_typ) { printf("?Sorry, GET /RECOVER requires binary mode\n"); x = -9; goto xgetx; #ifdef COMMENT /* Not true - the fact that the initial REST fails does not mean */ /* it will fail here. */ } else if (!okrestart) { printf("WARNING: Server might not support restart...\n"); #endif /* COMMENT */ } restart = 1; } #endif /* FTP_RESTART */ #ifdef PIPESEND if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */ if (pipesend) { printf("?Switch conflict: /FILTER and /COMMAND\n"); x = -9; goto xgetx; } makestr(&rcvfilter,pv[SND_FLT].sval); debug(F110,"ftp get /FILTER", rcvfilter, 0); } if (rcvfilter || pipesend) { /* /RESTART */ #ifdef FTP_RESTART if (restart) { /* with pipes or filters */ printf("?Switch conflict: /FILTER or /COMMAND and /RECOVER\n"); x = -9; goto xgetx; } #endif /* FTP_RESTART */ if (pv[SND_UPD].ival > 0 || x_fnc == XYFX_M || x_fnc == XYFX_U) { printf( "?Switch conflict: /FILTER or /COMMAND and Date Checking\n"); x = -9; goto xgetx; } } #endif /* PIPESEND */ tfc = (CK_OFF_T)0; /* Initialize stats and counters */ filcnt = 0; pktnum = 0; rpackets = 0L; if (pv[SND_FIL].ival > 0) { if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) { debug(F111,"ftp get can't open listfile",pv[SND_FIL].sval,errno); printf("?Failure to open listfile - \"%s\"\n",pv[SND_FIL].sval); x = -9; goto xgetx; } if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) { /* Read a line */ zclose(ZMFILE); /* Failed */ debug(F110,"ftp get listfile EOF",pv[SND_FIL].sval,0); printf("?Empty listfile - \"%s\"\n",pv[SND_FIL].sval); x = -9; goto xgetx; } listfile = 1; debug(F110,"ftp get listfile first",tmpbuf,0); makestr(&(mgetlist[0]),tmpbuf); } t0 = gmstimer(); /* Record starting time */ updating = 0; /* Checking dates? */ if (pv[SND_UPD].ival > 0 || (!mdel && x_fnc == XYFX_U)) updating = 1; if (pv[SND_DIF].ival > 0 || x_fnc == XYFX_M) updating = 2; if (updating) /* These switches force FTP DATES ON */ ftp_dates |= 2; what = mdel ? W_FTP|W_FT_DELE : W_RECV|W_FTP; /* What we're doing */ cancelgroup = 0; /* Group not canceled yet */ if (!(ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype)) changetype(ftp_typ,0); /* Change to requested type */ binary = ftp_typ; /* For file-transfer display */ first = 1; /* For MGET list */ done = 0; /* Loop control */ #ifdef CK_TMPDIR if (dldir && !f_tmpdir) { /* If they have a download directory */ if ((s = zgtdir())) { /* Get current directory */ if (zchdir(dldir)) { /* Change to download directory */ ckstrncpy(savdir,s,TMPDIRLEN); f_tmpdir = 1; /* Remember that we did this */ } } } #endif /* CK_TMPDIR */ if (ftp_nml) { /* /NAMELIST */ debug(F110,"ftp GET ftp_nml",ftp_nml,0); if (ftp_nml[0] == '-' && ftp_nml[1] == 0) fp_nml = stdout; else fp_nml = fopen(ftp_nml, "wb"); if (!fp_nml) { printf("?%s: %s\n",ftp_nml,ck_errstr()); goto xgetx; } } while (!done && !cancelgroup) { /* Loop for all files */ /* or until canceled. */ #ifdef FTP_PROXY /* do something here if proxy */ #endif /* FTP_PROXY */ rs_len = (CK_OFF_T)0; /* REGET position */ cancelfile = 0; /* This file not canceled yet */ haspath = 0; /* Recalculate this each time thru */ if (getone) { /* GET */ s = line; src = line; /* Server name */ done = 1; debug(F111,"ftp get file",s,0); } else if (mget) { /* MGET */ src = mgetlist[mgetx]; debug(F111,"ftp mget remote_files A",src,first); s = (char *)remote_files(first, (CHAR *)mgetlist[mgetx], (CHAR *)pv[SND_PAT].sval, 0 ); debug(F110,"ftp mget remote_files B",s,0); if (!s) s = ""; if (!*s) { first = 1; if (listfile) { /* Names from listfile */ again: tmpbuf[0] = NUL; while (!tmpbuf[0]) { if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) { zclose(ZMFILE); debug(F110,"ftp get listfile EOF", pv[SND_FIL].sval,0); makestr(&(mgetlist[0]),NULL); s = NULL; done = 1; break; } } if (done) continue; makestr(&(mgetlist[0]),tmpbuf); debug(F110,"ftp get listfile next",tmpbuf,0); s = (char *)remote_files(first, (CHAR *)mgetlist[0], (CHAR *)pv[SND_PAT].sval, 0 ); debug(F110,"ftp mget remote_files C",s,0); if (!s) { ftscreen(SCR_FN,'F',(CK_OFF_T)0,s); ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,"File not found"); tlog(F110,"ftp get file not found:",s,0); goto again; } } else { /* Names from command line */ mgetx++; if (mgetx < mgetn) s = (char *)remote_files(first, (CHAR *)mgetlist[mgetx], (CHAR *)pv[SND_PAT].sval, 0 ); else s = NULL; if (!s) mgetx++; debug(F111,"ftp mget remote_files D",s,mgetx); } if (!s) { if (!first || mgetx >= mgetn) { done = 1; break; } else if (geterror) { status = 0; done = 1; break; } else { continue; } } } } debug(F111,"ftp mget remote_files E",s,0); /* The semantics of NLST are ill-defined. Suppose we have just sent NLST /path/[a-z]*. Most servers send back names like /path/foo, /path/bar, etc. But some send back only foo and bar, and subsequent RETR commands based on the pathless names are not going to work. */ if (servertype == SYS_UNIX && !ckstrchr(s,'/')) { char * s3; if ((s3 = ckstrrchr(mgetlist[mgetx],'/'))) { int len, left = 4096; char * tmp = xtmpbuf; len = s3 - mgetlist[mgetx] + 1; ckstrncpy(tmp,mgetlist[mgetx],left); tmp += len; left -= len; ckstrncpy(tmp,s,left); s = xtmpbuf; debug(F111,"ftp mget remote_files F",s,0); } } first = 0; skipthis = 0; /* File selection... */ msg = ""; nam = s; /* Filename (without path) */ rc = 0; /* Initial return code */ s2 = ""; if (!getone && !skipthis) { /* For MGET and MDELETE... */ char c, * p = s; int srvpath = 0; int usrpath = 0; int i, k = 0; debug(F111,"ftp mget havetype",s,havetype); if (havetype > 0 && havetype != FTYP_FILE) { /* Server says it's not file... */ debug(F110,"ftp mget not-a-file",s,0); continue; } /* Explanation: Some ftp servers (such as wu-ftpd) return a recursive list. But if the client did not ask for a recursive list, we have to ignore any server files that include a pathname that extends beyond any path that was included in the user's request. User's filespec is blah or path/blah (or other non-UNIX syntax). We need to get the user's path segment. Then, for each incoming file, if it begins with the same path segment, we must strip it (point past it). */ src = mgetlist[mgetx]; /* In case it moved! */ if (src) { for (i = 0; src[i]; i++) { /* Find rightmost path separator */ if (ispathsep(src[i])) /* in user's pathname */ k = i + 1; } } else { src = ""; } usrpath = k; /* User path segment length */ debug(F111,"ftp get usrpath",src,usrpath); p = s; /* Server filename */ while ((c = *p++)) { /* Look for path in server filename */ if (ispathsep(c)) { /* haspath++; */ nam = p; /* Pathless name (for ckmatch) */ srvpath = p - s; /* Server path segment length */ } } debug(F111,"ftp get srvpath",s,srvpath); if (usrpath == 0) { /* Here we handle the case where the user said "mget foo" where foo is a directory name, and the server is sending back names like "foo/file1", "foo/file2", etc. This is a nasty trick but it's necessary because the user can't compensate by typing "mget foo/" because then the server is likely to send back "foo//file1, foo//file2" etc, and we still won't get a match... */ int srclen = 0, srvlen = 0; if (src) srclen = strlen(src); if (s) srvlen = strlen(s); if (src && (srvlen > srclen)) { if (!strncmp(src,s,srclen) && ispathsep(s[srclen])) { char * tmpsrc = NULL; tmpsrc = (char *)malloc(srclen + 2); strncpy(tmpsrc,src,srclen); tmpsrc[srclen] = s[srclen]; tmpsrc[srclen+1] = NUL; free(mgetlist[mgetx]); mgetlist[mgetx] = tmpsrc; tmpsrc = NULL; src = mgetlist[mgetx]; usrpath = srclen+1; } } } /* If as-name not given and server filename includes path that matches the pathname from the user's file specification, we must trim the common path prefix from the server's name when constructing the local name. */ if (src && /* Wed Sep 25 17:27:48 2002 */ !asnambuf[0] && !recursive && /* Thu Sep 19 16:11:59 2002 */ (srvpath > 0) && !strncmp(src,s,usrpath)) { s2 = s + usrpath; /* Local name skips past remote path */ } #ifdef COMMENT /* This doesn't work if the path prefix contains wildcards! */ haspath = (srvpath > usrpath); #else { /* Count path segments instead */ int x1 = 0, x2 = 0; char *p; for (p = s; *p; p++) if (ispathsep(*p)) x1++; for (p = src; *p; p++) { if (ispathsep(*p)) x2++; } haspath = recursive ? x1 || x2 : x1 > x2; debug(F111,"ftp get server path segments",s,x1); debug(F111,"ftp get user path segments",src,x2); } #endif /* COMMENT */ debug(F111,"ftp get haspath",s+usrpath,haspath); if (haspath) { /* Server file has path segments? */ if (!recursive) { /* [M]GET /RECURSIVE? */ /* We did not ask for a recursive listing, but the server is sending us one anyway (as wu-ftpd is wont to do). We get here if the current filename includes a path segment beyond any path segment we asked for in our non-recursive [M]GET command. We MUST skip this file. */ debug(F111,"ftp get skipping because of path",s,0); continue; } } } else if (getone && !skipthis) { /* GET (not MGET) */ char * p = nam; while ((c = *p++)) { /* Handle path in local name */ if (ispathsep(c)) { if (recursive) { /* If recursive, keep it */ haspath = 1; break; } else { /* Otherwise lose it. */ nam = p; } } } s2 = nam; } if (!*nam) /* Name without path */ nam = s; if (!skipthis && pv[SND_NOD].ival > 0) { /* /NODOTFILES */ if (nam[0] == '.') continue; } if (!skipthis && rcvexcept[0]) { /* /EXCEPT: list */ int xx; for (i = 0; i < NSNDEXCEPT; i++) { if (!rcvexcept[i]) { break; } xx = ckmatch(rcvexcept[i], nam, servertype == SYS_UNIX, 1); debug(F111,"ftp mget /except match",rcvexcept[i],xx); if (xx) { tlog(F100," refused: exception list","",0); msg = "Refused: Exception List"; skipthis++; break; } } } if (!skipthis && pv[SND_NOB].ival > 0) { /* /NOBACKUPFILES */ if (ckmatch( #ifdef CKREGEX "*.~[0-9]*~" #else "*.~*~" #endif /* CKREGEX */ ,nam,0,1) > 0) continue; } if (!x_xla) { /* If translation is off */ x_csl = -2; /* unset the charsets */ x_csr = -2; } ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */ if (!*s2) /* Local name */ s2 = asnambuf; /* As-name */ if (!*s2) /* Sat Nov 16 19:19:39 2002 */ s2 = recursive ? s : nam; /* Fri Jan 10 13:15:19 2003 */ debug(F110,"ftp get filnam ",s,0); debug(F110,"ftp get asname A",s2,0); /* Receiving to real file */ if (!pipesend && #ifdef PIPESEND !rcvfilter && #endif /* PIPESEND */ !toscreen) { #ifndef NOSPL /* Do this here so we can decide whether to skip */ if (cmd_quoting && !skipthis && asnambuf[0]) { int n; char *p; n = TMPBUFSIZ; p = tmpbuf; zzstring(asnambuf,&p,&n); s2 = tmpbuf; debug(F111,"ftp get asname B",s2,updating); } #endif /* NOSPL */ local = *s2 ? s2 : s; if (!skipthis && x_fnc == XYFX_D) { /* File Collision = Discard */ CK_OFF_T x; x = zchki(local); debug(F111,"ftp get DISCARD zchki",local,x); if (x > -1) { skipthis++; debug(F110,"ftp get skip name",local,0); tlog(F100," refused: name","",0); msg = "Refused: Name"; } } #ifdef DOUPDATE if (!skipthis && updating) { /* If updating and not yet skipping */ if (zchki(local) > -1) { x = chkmodtime(local,s,0); #ifdef DEBUG if (deblog) { if (updating == 2) debug(F111,"ftp get /dates-diff chkmodtime",local,x); else debug(F111,"ftp get /update chkmodtime",local,x); } #endif /* DEBUG */ if ((updating == 1 && x > 0) || /* /UPDATE */ (updating == 2 && x == 1)) { /* /DATES-DIFFER */ skipthis++; tlog(F100," refused: date","",0); msg = "Refused: Date"; debug(F110,"ftp get skip date",local,0); } } } #endif /* DOUPDATE */ } /* Initialize file size to -1 in case server doesn't understand */ /* SIZE command, so xxscreen() will know we don't know the size */ fsize = (CK_OFF_T)-1; /* Ask for size now only if we need it for selection */ /* because if you're going thru a list 100,000 files to select */ /* a small subset, 100,000 SIZE commands can take hours... */ gotsize = 0; if (!mdel && !skipthis && /* Don't need size for DELE... */ (getsmaller >= (CK_OFF_T)0 || getlarger >= (CK_OFF_T)0)) { if (havesize >= (CK_OFF_T)0) { /* Already have file size? */ fsize = havesize; gotsize = 1; } else { /* No - must ask server */ /* Prior to sending the NLST command we necessarily put the server into ASCII mode. We must now put it back into the the requested mode so the upcoming SIZE command returns right kind of size; this is especially important for GET /RECOVER; otherwise the server returns the "ASCII" size of the file, rather than its true size. */ changetype(ftp_typ,0); /* Change to requested type */ fsize = (CK_OFF_T)-1; if (sizeok) { x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm); if (x == REPLY_COMPLETE) { fsize = ckatofs(&ftp_reply_str[4]); gotsize = 1; } } } if (gotsize) { if (getsmaller >= (CK_OFF_T)0 && fsize >= getsmaller) skipthis++; if (getlarger >= (CK_OFF_T)0 && fsize <= getlarger) skipthis++; if (skipthis) { debug(F111,"ftp get skip size",s,fsize); tlog(F100," refused: size","",0); msg = "Refused: Size"; } #ifdef COMMENT } else if (getone) { /* SIZE can fail for many reasons. Does the file exist? */ x = ftpcmd("NLST",s,x_csl,x_csr,ftp_vbm); if (x != REPLY_COMPLETE) { printf(">>> FILE NOT FOUND: %s\n",s); break; } #endif /* COMMENT */ } } if (skipthis) { /* Skipping this file? */ ftscreen(SCR_FN,'F',(CK_OFF_T)0,s); if (msg) ftscreen(SCR_ST,ST_ERR,(CK_OFF_T)0,msg); else ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,s); continue; } if (fp_nml) { /* /NAMELIST only - no transfer */ fprintf(fp_nml,"%s\n",s); continue; } if (recursive && haspath && !pipesend #ifdef PIPESEND && !rcvfilter #endif /* PIPESEND */ ) { int x; #ifdef NOMKDIR x = -1; #else x = zmkdir(s); /* Try to make the directory */ #endif /* NOMKDIR */ if (x < 0) { rc = -1; /* Failure is fatal */ if (geterror) { status = 0; ftscreen(SCR_EM,0,(CK_OFF_T)0, "Directory creation failure"); break; } } } /* Not skipping */ selected++; /* Count this file as selected */ pn = NULL; if (!gotsize && !mdel) { /* Didn't get size yet */ if (havesize > (CK_OFF_T)-1) { /* Already have file size? */ fsize = havesize; gotsize = 1; } else { /* No - must ask server */ fsize = (CK_OFF_T)-1; if (sizeok) { x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm); if (x == REPLY_COMPLETE) { fsize = ckatofs(&ftp_reply_str[4]); gotsize = 1; } } } } if (mdel) { /* [M]DELETE */ if (displa && !ftp_vbm) printf(" %s...",s); rc = (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE) ? 1 : -1; if (rc > -1) { tlog(F110,"ftp mdelete",s,0); if (displa && !ftp_vbm) printf("OK\n"); } else { tlog(F110,"ftp mdelete failed:",s,0); if (displa) printf("Failed\n"); } #ifndef NOSPL #ifdef PIPESEND } else if (rcvfilter) { /* [M]GET with filter */ int n; char * p; n = CKMAXPATH; p = tmpbuf; /* Safe - no asname with filter */ zzstring(rcvfilter,&p,&n); if (n > -1) pn = tmpbuf; debug(F111,"ftp get rcvfilter",pn,n); #endif /* PIPESEND */ #endif /* NOSPL */ if (toscreen) s2 = "-"; } else if (pipesend) { /* [M]GET /COMMAND */ int n; char * p; n = CKMAXPATH; p = tmpbuf; /* Safe - no asname with filter */ zzstring(pipename,&p,&n); if (n > -1) pn = tmpbuf; debug(F111,"ftp get pipename",pipename,n); if (toscreen) s2 = "-"; } else { /* [M]GET with no pipes or filters */ debug(F111,"ftp get s2 A",s2,x_cnv); if (toscreen) { s2 = "-"; /* (hokey convention for stdout) */ } else if (!*s2) { /* No asname? */ if (x_cnv) { /* If converting */ nzrtol(s,tmpbuf,x_cnv,1,CKMAXPATH); /* convert */ s2 = tmpbuf; debug(F110,"ftp get nzrtol",s2,0); } else /* otherwise */ s2 = s; /* use incoming file's name */ } debug(F110,"ftp get s2 B",s2,0); /* If local file already exists, take collision action */ if (!pipesend && #ifdef PIPESEND !rcvfilter && #endif /* PIPESEND */ !toscreen) { CK_OFF_T x; x = zchki(s2); debug(F111,"ftp get zchki",s2,x); debug(F111,"ftp get x_fnc",s2,x_fnc); if (x > (CK_OFF_T)-1 && !restart) { int x = -1; char * newname = NULL; switch (x_fnc) { case XYFX_A: /* Append */ append = 1; break; case XYFX_R: /* Rename */ case XYFX_B: /* Backup */ znewn(s2,&newname); /* Make unique name */ debug(F110,"ftp get znewn",newname,0); if (x_fnc == XYFX_B) { /* Backup existing file */ x = zrename(s2,newname); debug(F111,"ftp get backup zrename",newname,x); } else { /* Rename incoming file */ x = ckstrncpy(tmpbuf,newname,CKMAXPATH+1); s2 = tmpbuf; debug(F111,"ftp get rename incoming",newname,x); } if (x < 0) { ftscreen(SCR_EM,0,(CK_OFF_T)0, "Backup/Rename failed"); x = 0; goto xgetx; } break; case XYFX_D: /* Discard (already handled above) */ case XYFX_U: /* Update (ditto) */ case XYFX_M: /* Update (ditto) */ case XYFX_X: /* Overwrite */ break; } } } } if (!mdel) { #ifdef PIPESEND debug(F111,"ftp get pn",pn,rcvfilter ? 1 : 0); #endif /* PIPESEND */ if (pipesend && !toscreen) s2 = NULL; #ifdef DEBUG if (deblog) { debug(F101,"ftp get x_xla","",x_xla); debug(F101,"ftp get x_csl","",x_csl); debug(F101,"ftp get x_csr","",x_csr); debug(F101,"ftp get append","",append); } #endif /* DEBUG */ rc = getfile(s,s2,restart,append,pn,x_xla,x_csl,x_csr); #ifdef DEBUG if (deblog) { debug(F111,"ftp get rc",s,rc); debug(F111,"ftp get ftp_timed_out",s,ftp_timed_out); debug(F111,"ftp get cancelfile",s,cancelfile); debug(F111,"ftp get cancelgroup",s,cancelgroup); debug(F111,"ftp get renaming",s,renaming); debug(F111,"ftp get moving",s,moving); } #endif /* DEBUG */ } if (rc > -1) { good++; status = 1; if (!cancelfile) { if (deleting) { /* GET /DELETE (source file) */ rc = (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE) ? 1 : -1; tlog(F110, (rc > -1) ? " deleted" : " failed to delete", s, 0); } if (renaming && rcv_rename && !toscreen) { char *p; /* Rename downloaded file */ #ifndef NOSPL char tmpbuf[CKMAXPATH+1]; int n; n = CKMAXPATH; p = tmpbuf; debug(F111,"ftp get /rename",rcv_rename,0); zzstring(rcv_rename,&p,&n); debug(F111,"ftp get /rename",rcv_rename,0); p = tmpbuf; #else p = rcv_rename; #endif /* NOSPL */ rc = (zrename(s2,p) < 0) ? -1 : 1; debug(F111,"doftpget /RENAME zrename",p,rc); tlog(F110, (rc > -1) ? " renamed to" : " failed to rename to", p, 0 ); } else if (moving && rcv_move && !toscreen) { char *p; /* Move downloaded file */ #ifndef NOSPL char tmpbuf[CKMAXPATH+1]; int n; n = TMPBUFSIZ; p = tmpbuf; debug(F111,"ftp get /move-to",rcv_move,0); zzstring(rcv_move,&p,&n); p = tmpbuf; #else p = rcv_move; #endif /* NOSPL */ debug(F111,"ftp get /move-to",p,0); rc = (zrename(s2,p) < 0) ? -1 : 1; debug(F111,"doftpget /MOVE zrename",p,rc); tlog(F110, (rc > -1) ? " moved to" : " failed to move to", p, 0); } if (pv[SND_SRN].ival > 0 && pv[SND_SRN].sval) { char * s = pv[SND_SRN].sval; char * srvrn = pv[SND_SRN].sval; char tmpbuf[CKMAXPATH+1]; #ifndef NOSPL int y; /* Pass it thru the evaluator */ extern int cmd_quoting; /* for \v(filename) */ debug(F111,"ftp get srv_renam",s,1); if (cmd_quoting) { y = CKMAXPATH; s = (char *)tmpbuf; zzstring(srvrn,&s,&y); s = (char *)tmpbuf; } #endif /* NOSPL */ debug(F111,"ftp get srv_renam",s,1); if (s) if (*s) { int x; x = ftp_rename(s2,s); debug(F111,"ftp get ftp_rename",s2,x); tlog(F110, (x > 0) ? " renamed source file to" : " failed to rename source file to", s, 0 ); if (x < 1) return(-1); } } } } if (cancelfile) continue; if (rc < 0) { ftp_fai++; #ifdef FTP_TIMEOUT debug(F101,"ftp get ftp_timed_out","",ftp_timed_out); if (ftp_timed_out) { status = 0; ftscreen(SCR_EM,0,(CK_OFF_T)0,"GET timed out"); } #endif /* FTP_TIMEOUT */ if (geterror) { status = 0; ftscreen(SCR_EM,0,(CK_OFF_T)0,"Fatal download error"); done++; } } } #ifdef DEBUG if (deblog) { debug(F101,"ftp get status","",status); debug(F101,"ftp get cancelgroup","",cancelgroup); debug(F101,"ftp get cancelfile","",cancelfile); debug(F101,"ftp get selected","",selected); debug(F101,"ftp get good","",good); } #endif /* DEBUG */ if (selected == 0) { /* No files met selection criteria */ status = 1; /* which is a kind of success. */ } else if (status > 0) { /* Some files were selected */ if (cancelgroup) /* but MGET was canceled */ status = 0; /* so MGET failed */ else if (cancelfile && good < 1) /* If file was canceled */ status = 0; /* MGET failed if it got no files */ } success = status; x = success; debug(F101,"ftp get success","",success); xgetx: pipesend = pipesave; /* Restore global pipe selection */ if (fp_nml) { /* Close /NAMELIST */ if (fp_nml != stdout) fclose(fp_nml); fp_nml = NULL; } if ( #ifdef COMMENT x > -1 #else success #endif /* COMMENT */ ) { /* Download successful */ #ifdef GFTIMER t1 = gmstimer(); /* End time */ sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */ if (!sec) sec = 0.001; fptsecs = sec; #else sec = (t1 - t0) / 1000; if (!sec) sec = 1; #endif /* GFTIMER */ tfcps = (long) (tfc / sec); tsecs = (int)sec; lastxfer = W_FTP|W_RECV; xferstat = success; } if (dpyactive) ftscreen(success > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, ""); #ifdef CK_TMPDIR if (f_tmpdir) { /* If we changed to download dir */ zchdir((char *) savdir); /* Go back where we came from */ f_tmpdir = 0; } #endif /* CK_TMPDIR */ for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */ if (pv[i].sval) free(pv[i].sval); } for (i = 0; i < mgetn; i++) /* MGET list too */ makestr(&(mgetlist[i]),NULL); if (cancelgroup) /* Clear temp-file stack */ mlsreset(); ftreset(); /* Undo switch effects */ dpyactive = 0; return(x); } static struct keytab ftprmt[] = { { "cd", XZCWD, 0 }, { "cdup", XZCDU, 0 }, { "cwd", XZCWD, CM_INV }, { "delete", XZDEL, 0 }, { "directory", XZDIR, 0 }, { "exit", XZXIT, 0 }, { "help", XZHLP, 0 }, { "login", XZLGI, 0 }, { "logout", XZLGO, 0 }, { "mkdir", XZMKD, 0 }, { "pwd", XZPWD, 0 }, { "rename", XZREN, 0 }, { "rmdir", XZRMD, 0 }, { "type", XZTYP, 0 }, { "", 0, 0 } }; static int nftprmt = (sizeof(ftprmt) / sizeof(struct keytab)) - 1; int doftpsite() { /* Send a SITE command */ int reply; char * s; int lcs = -1, rcs = -1; int save_vbm = ftp_vbm; #ifndef NOCSETS if (ftp_xla) { lcs = ftp_csl; if (lcs < 0) lcs = fcharset; rcs = ftp_csx; if (rcs < 0) rcs = ftp_csr; } #endif /* NOCSETS */ if ((x = cmtxt("Command", "", &s, xxstring)) < 0) return(x); CHECKCONN(); ckstrncpy(line,s,LINBUFSIZ); if (testing) printf(" ftp site \"%s\"...\n",line); if (!ftp_vbm) ftp_vbm = !ckstrcmp("HELP",line,4,0); if ((reply = ftpcmd("SITE",line,lcs,rcs,ftp_vbm)) == REPLY_PRELIM) { do { reply = getreply(0,lcs,rcs,ftp_vbm,0); } while (reply == REPLY_PRELIM); } ftp_vbm = save_vbm; return(success = (reply == REPLY_COMPLETE)); } int dosetftppsv() { /* Passive mode */ x = seton(&ftp_psv); if (x > 0) passivemode = ftp_psv; return(x); } /* d o f t p r m t -- Parse and execute REMOTE commands */ int #ifdef CK_ANSIC doftprmt( int cx, int who ) /* who == 1 for ftp, 0 for kermit */ #else doftprmt(cx,who) int cx, who; #endif /* CK_ANSIC */ { /* cx == 0 means REMOTE */ /* cx != 0 is a XZxxx value */ char * s; if (who != 0) return(0); if (cx == 0) { if ((x = cmkey(ftprmt,nftprmt,"","",xxstring)) < 0) return(x); cx = x; } switch (cx) { case XZCDU: /* CDUP */ if ((x = cmcfm()) < 0) return(x); return(doftpcdup()); case XZCWD: /* RCD */ if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0) return(x); ckstrncpy(line,s,LINBUFSIZ); s = brstrip(line); return(doftpcwd(s,1)); case XZPWD: /* RPWD */ return(doftppwd()); case XZDEL: /* RDEL */ return(doftpget(FTP_MDE,1)); case XZDIR: /* RDIR */ return(doftpdir(FTP_DIR)); case XZHLP: /* RHELP */ return(doftpxhlp()); case XZMKD: /* RMKDIR */ return(doftpmkd()); case XZREN: /* RRENAME */ return(doftpren()); case XZRMD: /* RRMDIR */ return(doftprmd()); case XZLGO: /* LOGOUT */ return(doftpres()); case XZXIT: /* EXIT */ return(ftpbye()); } printf("?Not usable with FTP - \"%s\"\n", atmbuf); return(-9); } int doxftp() { /* Command parser for built-in FTP */ int cx; struct FDB kw, fl; char * s; int usetls = 0; int lcs = -1, rcs = -1; #ifndef NOCSETS if (ftp_xla) { lcs = ftp_csl; if (lcs < 0) lcs = fcharset; rcs = ftp_csx; if (rcs < 0) rcs = ftp_csr; } #endif /* NOCSETS */ if (inserver) /* FTP not allowed in IKSD. */ return(-2); if (g_ftp_typ > -1) { /* Restore TYPE if saved */ ftp_typ = g_ftp_typ; /* g_ftp_typ = -1; */ } #ifdef COMMENT /* We'll set the collision action locally in doftpget() based on whether ftp_fnc was ever set to a value. if not, we'll use the fncact value. */ if (ftp_fnc < 0) /* Inherit global collision action */ ftp_fnc = fncact; /* if none specified for FTP */ #endif /* COMMENT */ /* Restore global verbose mode */ if (ftp_deb) ftp_vbm = 1; else if (quiet) ftp_vbm = 0; else ftp_vbm = ftp_vbx; ftp_dates &= 1; /* Undo any previous /UPDATE switch */ dpyactive = 0; /* Reset global transfer-active flag */ printlines = 0; /* Reset printlines */ if (fp_nml) { /* Reset /NAMELIST */ if (fp_nml != stdout) fclose(fp_nml); fp_nml = NULL; } makestr(&ftp_nml,NULL); cmfdbi(&kw, /* First FDB - commands */ _CMKEY, /* fcode */ "Hostname; or FTP command", /* help */ "", /* default */ "", /* addtl string data */ nftpcmd, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: none */ xxstring, /* Processing function */ ftpcmdtab, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* A host name or address */ _CMFLD, /* fcode */ "Hostname or address", /* help */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); x = cmfdb(&kw); /* Parse a hostname or a keyword */ if (x == -3) { printf("?ftp what? \"help ftp\" for hints\n"); return(-9); } if (x < 0) return(x); if (cmresult.fcode == _CMFLD) { /* If hostname */ return(openftp(cmresult.sresult,0)); /* go open the connection */ } else { cx = cmresult.nresult; } switch (cx) { case FTP_ACC: /* ACCOUNT */ if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0) return(x); CHECKCONN(); makestr(&ftp_acc,s); if (testing) printf(" ftp account: \"%s\"\n",ftp_acc); success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE); return(success); case FTP_GUP: /* Go UP */ if ((x = cmcfm()) < 0) return(x); CHECKCONN(); if (testing) printf(" ftp cd: \"(up)\"\n"); return(success = doftpcdup()); case FTP_CWD: /* CD */ if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0) return(x); CHECKCONN(); ckstrncpy(line,s,LINBUFSIZ); if (testing) printf(" ftp cd: \"%s\"\n", line); return(success = doftpcwd(line,1)); case FTP_CHM: /* CHMOD */ if ((x = cmfld("Permissions or protection code","",&s,xxstring)) < 0) return(x); ckstrncpy(tmpbuf,s,TMPBUFSIZ); if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0) return(x); CHECKCONN(); ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,tmpbuf," ",s,NULL); if (testing) printf(" ftp chmod: %s\n",ftpcmdbuf); success = (ftpcmd("SITE CHMOD",ftpcmdbuf,lcs,rcs,ftp_vbm) == REPLY_COMPLETE); return(success); case FTP_CLS: /* CLOSE FTP connection */ if ((y = cmcfm()) < 0) return(y); CHECKCONN(); if (testing) printf(" ftp closing...\n"); ftpclose(); return(success = 1); case FTP_DIR: /* DIRECTORY of remote files */ case FTP_VDI: return(doftpdir(cx)); case FTP_GET: /* GET a remote file */ case FTP_RGE: /* REGET */ case FTP_MGE: /* MGET */ case FTP_MDE: /* MDELETE */ return(doftpget(cx,1)); case FTP_IDL: /* IDLE */ if ((x = cmnum("Number of seconds","-1",10,&z,xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); CHECKCONN(); if (z < 0) { /* Display idle timeout */ if (testing) printf(" ftp query idle timeout...\n"); success = (ftpcmd("SITE IDLE",NULL,0,0,1) == REPLY_COMPLETE); } else { /* Set idle timeout */ if (testing) printf(" ftp idle timeout set: %d...\n",z); success = (ftpcmd("SITE IDLE",ckitoa(z),0,0,1) == REPLY_COMPLETE); } return(success); case FTP_MKD: /* MKDIR */ return(doftpmkd()); case FTP_MOD: /* MODTIME */ if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0) return(x); CHECKCONN(); ckstrncpy(line,s,LINBUFSIZ); if (testing) printf(" ftp modtime \"%s\"...\n",line); success = 0; if (ftpcmd("MDTM",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE) { success = 1; mdtmok = 1; if (!quiet) { int flag = 0; char c, * s; struct tm tmremote; bzero((char *)&tmremote, sizeof(struct tm)); s = ftp_reply_str; while ((c = *s++)) { if (c == SP) { flag++; break; } } if (flag) { if (sscanf(s, "%04d%02d%02d%02d%02d%02d", &tmremote.tm_year, &tmremote.tm_mon, &tmremote.tm_mday, &tmremote.tm_hour, &tmremote.tm_min, &tmremote.tm_sec ) == 6) { printf(" %s %04d-%02d-%02d %02d:%02d:%02d GMT\n", line, tmremote.tm_year, tmremote.tm_mon, tmremote.tm_mday, tmremote.tm_hour, tmremote.tm_min, tmremote.tm_sec ); } else { success = 0; } } } } return(success); case FTP_OPN: /* OPEN connection */ #ifdef COMMENT x = cmfld("IP hostname or address","",&s,xxstring); if (x < 0) { success = 0; return(x); } ckstrncpy(line,s,LINBUFSIZ); s = line; return(openftp(s,0)); #else { /* OPEN connection */ char name[TTNAMLEN+1], *p; extern int network; extern char ttname[]; #ifdef USETLSTAB int n; #endif /* USETLSTAB */ if (network) /* If we have a current connection */ ckstrncpy(name,ttname,LINBUFSIZ); /* get the host name */ else *name = '\0'; /* as default host */ for (p = name; *p; p++) /* Remove ":service" from end. */ if (*p == ':') { *p = '\0'; break; } #ifndef USETLSTAB x = cmfld("IP hostname or address",name,&s,xxstring); #else cmfdbi(&kw, /* First FDB - commands */ _CMKEY, /* fcode */ "Hostname or switch", /* help */ "", /* default */ "", /* addtl string data */ ntlstab, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: none */ xxstring, /* Processing function */ tlstab, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* A host name or address */ _CMFLD, /* fcode */ "Hostname or address", /* help */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); for (n = 0;; n++) { x = cmfdb(&kw); /* Parse a hostname or a keyword */ if (x == -3) { printf("?ftp open what? \"help ftp\" for hints\n"); return(-9); } if (x < 0) break; if (cmresult.fcode == _CMFLD) { /* Hostname */ s = cmresult.sresult; break; } else if (cmresult.nresult == OPN_TLS) { usetls = 1; } } #endif /* USETLSTAB */ if (x < 0) { success = 0; return(x); } ckstrncpy(line,s,LINBUFSIZ); s = line; return(openftp(s,usetls)); } #endif /* COMMENT */ case FTP_PUT: /* PUT */ case FTP_MPU: /* MPUT */ case FTP_APP: /* APPEND */ case FTP_REP: /* REPUT */ return(doftpput(cx,1)); case FTP_PWD: /* PWD */ x = doftppwd(); if (x > -1) success = x; return(x); case FTP_REN: /* RENAME */ return(doftpren()); case FTP_RES: /* RESET */ return(doftpres()); case FTP_HLP: /* (remote) HELP */ return(doftpxhlp()); case FTP_RMD: /* RMDIR */ return(doftprmd()); case FTP_STA: /* STATUS */ if ((x = cmtxt("Command", "", &s, xxstring)) < 0) return(x); CHECKCONN(); ckstrncpy(line,s,LINBUFSIZ); if (testing) printf(" ftp status \"%s\"...\n",line); success = (ftpcmd("STAT",line,lcs,rcs,1) == REPLY_COMPLETE); return(success); case FTP_SIT: { /* SITE */ return(doftpsite()); } case FTP_SIZ: /* (ask for) SIZE */ if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0) return(x); CHECKCONN(); ckstrncpy(line,s,LINBUFSIZ); if (testing) printf(" ftp size \"%s\"...\n",line); success = (ftpcmd("SIZE",line,lcs,rcs,1) == REPLY_COMPLETE); if (success) sizeok = 1; return(success); case FTP_SYS: /* Ask for server's SYSTEM type */ if ((x = cmcfm()) < 0) return(x); CHECKCONN(); if (testing) printf(" ftp system...\n"); success = (ftpcmd("SYST",NULL,0,0,1) == REPLY_COMPLETE); return(success); case FTP_UMA: /* Set/query UMASK */ if ((x = cmfld("Umask to set or nothing to query","",&s,xxstring)) < 0) if (x != -3) return(x); ckstrncpy(tmpbuf,s,TMPBUFSIZ); if ((x = cmcfm()) < 0) return(x); CHECKCONN(); if (testing) { if (tmpbuf[0]) printf(" ftp umask \"%s\"...\n",tmpbuf); else printf(" ftp query umask...\n"); } success = ftp_umask(tmpbuf); return(success); case FTP_USR: return(doftpusr()); case FTP_QUO: if ((x = cmtxt("FTP protocol command", "", &s, xxstring)) < 0) return(x); CHECKCONN(); success = (ftpcmd(s,NULL,0,0,ftp_vbm) == REPLY_COMPLETE); return(success); case FTP_TYP: /* Type */ if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); CHECKCONN(); ftp_typ = x; g_ftp_typ = x; tenex = (ftp_typ == FTT_TEN); changetype(ftp_typ,ftp_vbm); return(1); case FTP_CHK: /* Check if remote file(s) exist(s) */ if ((x = cmtxt("remote filename", "", &s, xxstring)) < 0) return(x); CHECKCONN(); success = remote_files(1,(CHAR *)s,(CHAR *)s,0) ? 1 : 0; return(success); case FTP_FEA: /* RFC2389 */ if ((y = cmcfm()) < 0) return(y); CHECKCONN(); success = (ftpcmd("FEAT",NULL,0,0,1) == REPLY_COMPLETE); if (success) { if (sfttab[0] > 0) { ftp_aut = sfttab[SFT_AUTH]; sizeok = sfttab[SFT_SIZE]; mdtmok = sfttab[SFT_MDTM]; mlstok = sfttab[SFT_MLST]; } } return(success); case FTP_OPT: /* RFC2389 */ /* Perhaps this should be a keyword list... */ if ((x = cmfld("FTP command","",&s,xxstring)) < 0) return(x); CHECKCONN(); ckstrncpy(line,s,LINBUFSIZ); if ((x = cmtxt("Options for this command", "", &s, xxstring)) < 0) return(x); success = (ftpcmd("OPTS",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE); return(success); case FTP_ENA: /* FTP ENABLE */ case FTP_DIS: /* FTP DISABLE */ if ((x = cmkey(ftpenatab,nftpena,"","",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); switch (x) { case ENA_AUTH: /* OK to use autoauthentication */ ftp_aut = (cx == FTP_ENA) ? 1 : 0; sfttab[SFT_AUTH] = ftp_aut; break; case ENA_FEAT: /* OK to send FEAT command */ featok = (cx == FTP_ENA) ? 1 : 0; break; case ENA_MLST: /* OK to use MLST/MLSD */ mlstok = (cx == FTP_ENA) ? 1 : 0; sfttab[SFT_MLST] = mlstok; break; case ENA_MDTM: /* OK to use MDTM */ mdtmok = (cx == FTP_ENA) ? 1 : 0; sfttab[SFT_MDTM] = mdtmok; break; case ENA_SIZE: /* OK to use SIZE */ sizeok = (cx == FTP_ENA) ? 1 : 0; sfttab[SFT_SIZE] = sizeok; break; } return(success = 1); } return(-2); } #ifndef NOSHOW #ifdef FTP_SECURITY static char * #ifdef CK_ANSIC shopl( int x ) #else shopl(x) int x; #endif /* CK_ANSIC */ { switch (x) { case FPL_CLR: return("clear"); case FPL_PRV: return("private"); case FPL_SAF: return("safe"); case 0: return("(not set)"); default: return("(unknown)"); } } #endif /* FTP_SECURITY */ int #ifdef CK_ANSIC shoftp( int brief ) #else shoftp(brief) int brief; #endif /* CK_ANSIC */ { char * s = "?"; int n, x; if (g_ftp_typ > -1) { /* Restore TYPE if saved */ ftp_typ = g_ftp_typ; /* g_ftp_typ = -1; */ } printf("\n"); printf("FTP connection: %s\n",connected ? ftp_host : "(none)" ); n = 2; if (connected) { n++; printf("FTP server type: %s\n", ftp_srvtyp[0] ? ftp_srvtyp : "(unknown)"); } if (loggedin) printf("Logged in as: %s\n", strval(ftp_logname,"(unknown)")); else printf("Not logged in\n"); n++; if (brief) return(0); printf("\nSET FTP values:\n\n"); n += 3; printf(" ftp anonymous-password: %s\n", ftp_apw ? ftp_apw : "(default)" ); printf(" ftp auto-login: %s\n",showoff(ftp_log)); printf(" ftp auto-authentication: %s\n",showoff(ftp_aut)); switch (ftp_typ) { case FTT_ASC: s = "text"; break; case FTT_BIN: s = "binary"; break; case FTT_TEN: s = "tenex"; break; } #ifdef FTP_TIMEOUT printf(" ftp timeout: %ld\n",ftp_timeout); #endif /* FTP_TIMEOUT */ printf(" ftp type: %s\n",s); printf(" ftp get-filetype-switching: %s\n",showoff(get_auto)); printf(" ftp dates: %s\n",showoff(ftp_dates)); printf(" ftp error-action: %s\n",ftp_err ? "quit":"proceed"); printf(" ftp filenames: %s\n", ftp_cnv == CNV_AUTO ? "auto" : (ftp_cnv ? "converted" : "literal") ); printf(" ftp debug %s\n",showoff(ftp_deb)); printf(" ftp passive-mode: %s\n",showoff(ftp_psv)); printf(" ftp permissions: %s\n",showooa(ftp_prm)); printf(" ftp verbose-mode: %s\n",showoff(ftp_vbx)); printf(" ftp send-port-commands: %s\n",showoff(ftp_psv)); printf(" ftp unique-server-names: %s\n",showoff(ftp_usn)); #ifdef COMMENT /* See note in doxftp() */ if (ftp_fnc < 0) ftp_fnc = fncact; #endif /* COMMENT */ printf(" ftp collision: %s\n", fncnam[ftp_fnc > -1 ? ftp_fnc : fncact]); printf(" ftp server-time-offset: %s\n", fts_sto ? fts_sto : "(none)"); n += 15; #ifndef NOCSETS printf(" ftp character-set-translation: %s\n",showoff(ftp_xla)); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } printf(" ftp server-character-set: %s\n",fcsinfo[ftp_csr].keyword); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } printf(" file character-set: %s\n",fcsinfo[fcharset].keyword); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } #endif /* NOCSETS */ x = ftp_dis; if (x < 0) x = fdispla; switch (x) { case XYFD_N: s = "none"; break; case XYFD_R: s = "serial"; break; case XYFD_C: s = "fullscreen"; break; case XYFD_S: s = "crt"; break; case XYFD_B: s = "brief"; break; } printf(" ftp display: %s\n",s); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } if (mlstok || featok || mdtmok || sizeok || ftp_aut) { printf(" enabled: "); if (ftp_aut) printf(" AUTH"); if (featok) printf(" FEAT"); if (mdtmok) printf(" MDTM"); if (mlstok) printf(" MLST"); if (sizeok) printf(" SIZE"); printf("\n"); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } } if (!mlstok || !featok || !mdtmok || !sizeok || !ftp_aut) { printf(" disabled: "); if (!ftp_aut) printf(" AUTH"); if (!featok) printf(" FEAT"); if (!mdtmok) printf(" MDTM"); if (!mlstok) printf(" MLST"); if (!sizeok) printf(" SIZE"); printf("\n"); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } } switch (ftpget) { case 0: s = "kermit"; break; case 1: s = "ftp"; break; case 2: s = "auto"; break; default: s = "?"; } printf(" get-put-remote: %s\n",s); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } printf("\n"); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } #ifdef FTP_SECURITY printf("Available security methods: "); #ifdef FTP_GSSAPI printf("GSSAPI "); #endif /* FTP_GSSAPI */ #ifdef FTP_KRB4 printf("Kerberos4 "); #endif /* FTP_KRB4 */ #ifdef FTP_SRP printf("SRP "); #endif /* FTP_SRP */ #ifdef FTP_SSL printf("SSL "); #endif /* FTP_SSL */ n++; printf("\n\n"); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } printf(" ftp authtype: %s\n",strval(auth_type,NULL)); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } printf(" ftp auto-encryption: %s\n",showoff(ftp_cry)); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } printf(" ftp credential-forwarding: %s\n",showoff(ftp_cfw)); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } printf(" ftp command-protection-level: %s\n",shopl(ftp_cpl)); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } printf(" ftp data-protection-level: %s\n",shopl(ftp_dpl)); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } printf(" ftp secure proxy: %s\n",shopl(ssl_ftp_proxy)); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } #else printf("Available security methods: (none)\n"); if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; } #endif /* FTP_SECURITY */ if (n <= cmd_rows - 3) printf("\n"); return(0); } #endif /* NOSHOW */ #ifndef NOHELP /* FTP HELP text strings */ static char * fhs_ftp[] = { "Syntax: FTP subcommand [ operands ]", " Makes an FTP connection, or sends a command to the FTP server.", " To see a list of available FTP subcommands, type \"ftp ?\".", " and then use HELP FTP xxx to get help about subcommand xxx.", " Also see HELP SET FTP, HELP SET GET-PUT-REMOTE, and HELP FIREWALL.", "" }; static char * fhs_acc[] = { /* ACCOUNT */ "Syntax: FTP ACCOUNT text", " Sends an account designator to an FTP server that needs one.", " Most FTP servers do not use accounts; some use them for other", " other purposes, such as disk-access passwords.", "" }; static char * fhs_app[] = { /* APPEND */ "Syntax: FTP APPEND filname", " Equivalent to [ FTP ] PUT /APPEND. See HELP FTP PUT.", "" }; static char * fhs_cls[] = { /* BYE, CLOSE */ "Syntax: [ FTP ] BYE", " Logs out from the FTP server and closes the FTP connection.", " Also see HELP SET GET-PUT-REMOTE. Synonym: [ FTP ] CLOSE.", "" }; static char * fhs_cwd[] = { /* CD, CWD */ "Syntax: [ FTP ] CD directory", " Asks the FTP server to change to the given directory.", " Also see HELP SET GET-PUT-REMOTE. Synonyms: [ FTP ] CWD, RCD, RCWD.", "" }; static char * fhs_gup[] = { /* CDUP, UP */ "Syntax: FTP CDUP", " Asks the FTP server to change to the parent directory of its current", " directory. Also see HELP SET GET-PUT-REMOTE. Synonym: FTP UP.", "" }; static char * fhs_chm[] = { /* CHMOD */ "Syntax: FTP CHMOD filename permissions", " Asks the FTP server to change the permissions, protection, or mode of", " the given file. The given permissions must be in the syntax of the", " the server's file system, e.g. an octal number for UNIX. Also see", " FTP PUT /PERMISSIONS", "" }; static char * fhs_mde[] = { /* DELETE */ "Syntax: FTP DELETE [ switches ] filespec", " Asks the FTP server to delete the given file or files.", " Synonym: MDELETE (Kermit makes no distinction between single and", " multiple file deletion). Optional switches:", " ", " /ERROR-ACTION:{PROCEED,QUIT}", " /EXCEPT:pattern", " /FILENAMES:{AUTO,CONVERTED,LITERAL}", " /LARGER-THAN:number", #ifdef UNIXOROSK " /NODOTFILES", #endif /* UNIXOROSK */ " /QUIET", #ifdef RECURSIVE " /RECURSIVE (depends on server)", " /SUBDIRECTORIES", #endif /* RECURSIVE */ " /SMALLER-THAN:number", "" }; static char * fhs_dir[] = { /* DIRECTORY */ "Syntax: FTP DIRECTORY [ filespec ]", " Asks the server to send a directory listing of the files that match", " the given filespec, or if none is given, all the files in its current", " directory. The filespec, including any wildcards, must be in the", " syntax of the server's file system. Also see HELP SET GET-PUT-REMOTE.", " Synonym: RDIRECTORY.", "" }; static char * fhs_vdi[] = { /* VDIRECTORY */ "Syntax: FTP VDIRECTORY [ filespec ]", " Asks the server to send a directory listing of the files that match", " the given filespec, or if none is given, all the files in its current", " directory. VDIRECTORY is needed for getting verbose directory", " listings from certain FTP servers, such as on TOPS-20. Try it if", " FTP DIRECTORY lists only filenames without details.", "" }; static char * fhs_fea[] = { /* FEATURES */ "Syntax: FTP FEATURES", " Asks the FTP server to list its special features. Most FTP servers", " do not recognize this command.", "" }; static char * fhs_mge[] = { /* MGET */ "Syntax: [ FTP ] MGET [ options ] filespec [ filespec [ filespec ... ] ]", " Download a single file or multiple files. Asks the FTP server to send", " the given file or files. Also see FTP GET. Optional switches:", " ", " /AS-NAME:text", " Name under which to store incoming file.", " Pattern required for for multiple files.", " /BINARY", /* /IMAGE */ " Force binary mode. Synonym: /IMAGE.", " /COLLISION:{BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE}", " What to do if an incoming file has the same name as an existing file.", #ifdef PUTPIPE " /COMMAND", " Specifies that the as-name is a command to which the incoming file", " is to be piped as standard input.", #endif /* PUTPIPE */ #ifdef DOUPDATE " /DATES-DIFFER", " Download only those files whose modification date-times differ from", " those of the corresponding local files, or that do not already", " exist on the local computer.", #endif /* DOUPDATE */ " /DELETE", " Specifies that each file is to be deleted from the server after,", " and only if, it is successfully downloaded.", " /ERROR-ACTION:{PROCEED,QUIT}", " When downloading a group of files, what to do upon failure to", " transfer a file: quit or proceed to the next one.", " /EXCEPT:pattern", " Exception list: don't download any files that match this pattern.", " See HELP WILDCARD for pattern syntax.", " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}", " Whether to convert incoming filenames to local syntax.", #ifdef PIPESEND #ifndef NOSPL " /FILTER:command", " Pass incoming files through the given command.", #endif /* NOSPL */ #endif /* PIPESEND */ " /LARGER-THAN:number", " Only download files that are larger than the given number of bytes.", " /LISTFILE:filename", " Obtain the list of files to download from the given file.", #ifndef NOCSETS " /LOCAL-CHARACTER-SET:name", " When downloading in text mode and character-set conversion is", " desired, this specifies the target set.", #endif /* NOCSETS */ " /MATCH:pattern", " Specifies a pattern to be used to select filenames locally from the", " server's list.", " /MLSD", " Forces sending of MLSD (rather than NLST) to get the file list.", #ifdef CK_TMPDIR " /MOVE-TO:directory", " Each file that is downloaded is to be moved to the given local", " directory immediately after, and only if, it has been received", " successfully.", #endif /* CK_TMPDIR */ " /NAMELIST:filename", " Instead of downloading the files, stores the list of files that", " would be downloaded in the given local file, one filename per line.", " /NLST", " Forces sending of NLST (rather than MLSD) to get the file list.", " /NOBACKUPFILES", " Don't download any files whose names end with .~~.", " /NODOTFILES", " Don't download any files whose names begin with period (.).", " /QUIET", " Suppress the file-transfer display.", #ifdef FTP_RESTART " /RECOVER", /* /RESTART */ " Resume a download that was previously interrupted from the point of", " failure. Works only in binary mode. Not supported by all servers.", " Synonym: /RESTART.", #endif /* FTP_RESTART */ #ifdef RECURSIVE " /RECURSIVE", /* /SUBDIRECTORIES */ " Create subdirectories automatically if the server sends files", " recursively and includes pathnames (most don't).", #endif /* RECURSIVE */ " /RENAME-TO:text", " Each file that is downloaded is to be renamed as indicated just,", " after, and only if, it has arrived successfully.", #ifndef NOCSETS " /SERVER-CHARACTER-SET:name", " When downloading in text mode and character-set conversion is desired" , " this specifies the original file's character set on the server.", #endif /* NOCSETS */ " /SERVER-RENAME:text", " Each server source file is to be renamed on the server as indicated", " immediately after, but only if, it has arrived successfully.", " /SMALLER-THAN:number", " Download only those files smaller than the given number of bytes.", " /TEXT", /* /ASCII */ " Force text mode. Synonym: /ASCII.", " /TENEX", " Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).", #ifndef NOCSETS " /TRANSPARENT", " When downloading in text mode, do not convert chracter-sets.", #endif /* NOCSETS */ " /TO-SCREEN", " The downloaded file is to be displayed on the screen.", #ifdef DOUPDATE " /UPDATE", " Equivalent to /COLLISION:UPDATE. Download only those files that are", " newer than than their local counterparts, or that do not exist on", " the local computer.", #endif /* DOUPDATE */ "" }; static char * fhs_hlp[] = { /* HELP */ "Syntax: FTP HELP [ command [ subcommand... ] ]", " Asks the FTP server for help about the given command. First use", " FTP HELP by itself to get a list of commands, then use HELP FTP xxx", " to get help for command \"xxx\". Synonyms: REMOTE HELP, RHELP.", "" }; static char * fhs_idl[] = { /* IDLE */ "Syntax: FTP IDLE [ number ]", " If given without a number, this asks the FTP server to tell its", " current idle-time limit. If given with a number, it asks the server", " to change its idle-time limit to the given number of seconds.", "" }; static char * fhs_usr[] = { /* USER, LOGIN */ "Syntax: FTP USER username [ password [ account ] ]", " Log in to the FTP server. To be used when connected but not yet", " logged in, e.g. when SET FTP AUTOLOGIN is OFF or autologin failed.", " If you omit the password, and one is required by the server, you are", " prompted for it. If you omit the account, no account is sent.", " Synonym: FTP LOGIN.", "" }; static char * fhs_get[] = { /* GET */ "Syntax: [ FTP ] GET [ options ] filename [ as-name ]", " Download a single file. Asks the FTP server to send the given file.", " The optional as-name is the name to store it under when it arrives;", " if omitted, the file is stored with the name it arrived with, as", " modified according to the FTP FILENAMES setting or /FILENAMES: switch", " value. Aside from the file list and as-name, syntax and options are", " the same as for FTP MGET, which is used for downloading multiple files." , "" }; static char * fhs_mkd[] = { /* MKDIR */ "Syntax: FTP MKDIR directory", " Asks the FTP server to create a directory with the given name,", " which must be in the syntax of the server's file system. Synonyms:", " REMOTE MKDIR, RMKDIR.", "" }; static char * fhs_mod[] = { /* MODTIME */ "Syntax: FTP MODTIME filename", " Asks the FTP server to send the modification time of the given file,", " to be displayed on the screen. The date-time format is all numeric:", " yyyymmddhhmmssxxx... (where xxx... is 0 or more digits indicating", " fractions of seconds).", "" }; static char * fhs_mpu[] = { /* MPUT */ "Syntax: [ FTP ] MPUT [ switches ] filespec [ filespec [ filespec ... ] ]", " Uploads files. Sends the given file or files to the FTP server.", " Also see FTP PUT. Optional switches are:", " ", " /AFTER:date-time", " Uploads only those files newer than the given date-time.", " HELP DATE for info about date-time formats. Synonym: /SINCE.", #ifdef PUTARRAY " /ARRAY:array-designator", " Tells Kermit to upload the contents of the given array, rather than", " a file.", #endif /* PUTARRAY */ " /AS-NAME:text", " Name under which to send files.", " Pattern required for for multiple files.", " /BEFORE:date-time", " Upload only those files older than the given date-time.", " /BINARY", " Force binary mode. Synonym: /IMAGE.", #ifdef PUTPIPE " /COMMAND", " Specifies that the filespec is a command whose standard output is", " to be sent.", #endif /* PUTPIPE */ #ifdef COMMENT #ifdef DOUPDATE " /DATES-DIFFER", " Upload only those files whose modification date-times differ from", " those on the server, or that don't exist on the server at all.", #endif /* DOUPDATE */ #endif /* COMMENT */ " /DELETE", " Specifies that each source file is to be deleted after, and only if,", " it is successfully uploaded.", " /DOTFILES", " Include files whose names begin with period (.).", " /ERROR-ACTION:{PROCEED,QUIT}", " When uploading a group of files, what to do upon failure to", " transfer a file: quit or proceed to the next one.", " /EXCEPT:pattern", " Exception list: don't upload any files that match this pattern.", " See HELP WILDCARD for pattern syntax.", " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}", " Whether to convert outbound filenames to common syntax.", #ifdef PIPESEND #ifndef NOSPL " /FILTER:command", " Pass outbound files through the given command.", #endif /* NOSPL */ #endif /* PIPESEND */ #ifdef CKSYMLINK " /FOLLOWINKS", " Send files that are pointed to by symbolic links.", " /NOFOLLOWINKS", " Skip over symbolic links (default).", #endif /* CKSYMLINK */ " /LARGER-THAN:number", " Only upload files that are larger than the given number of bytes.", " /LISTFILE:filename", " Obtain the list of files to upload from the given file.", #ifndef NOCSETS " /LOCAL-CHARACTER-SET:name", " When uploading in text mode and character-set conversion is", " desired, this specifies the source-file character set.", #endif /* NOCSETS */ #ifdef CK_TMPDIR " /MOVE-TO:directory", " Each source file that is uploaded is to be moved to the given local", " directory when, and only if, the transfer is successful.", #endif /* CK_TMPDIR */ " /NOBACKUPFILES", " Don't upload any files whose names end with .~~.", #ifdef UNIXOROSK " /NODOTFILES", " Don't upload any files whose names begin with period (.).", #endif /* UNIXOROSK */ " /NOT-AFTER:date-time", " Upload only files that are not newer than the given date-time", " /NOT-BEFORE:date-time", " Upload only files that are not older than the given date-time", #ifdef UNIX " /PERMISSIONS", " Ask the server to set the permissions of each file it receives", " according to the source file's permissions.", #endif /* UNIX */ " /QUIET", " Suppress the file-transfer display.", #ifdef FTP_RESTART " /RECOVER", " Resume an upload that was previously interrupted from the point of", " failure. Synonym: /RESTART.", #endif /* FTP_RESTART */ #ifdef RECURSIVE " /RECURSIVE", " Send files from the given directory and all the directories beneath", " it. Synonym: /SUBDIRECTORIES.", #endif /* RECURSIVE */ " /RENAME-TO:text", " Each source file that is uploaded is to be renamed on the local", " local computer as indicated when and only if, the transfer completes", " successfully.", #ifndef NOCSETS " /SERVER-CHARACTER-SET:name", " When uploading in text mode and character-set conversion is desired,", " this specifies the character set to which the file should be", " converted for storage on the server.", #endif /* NOCSETS */ " /SERVER-RENAME:text", " Each file that is uploaded is to be renamed as indicated on the", " server after, and only if, if arrives successfully.", " /SIMULATE", " Show which files would be sent without actually sending them.", " /SMALLER-THAN:number", " Upload only those files smaller than the given number of bytes.", " /TEXT", " Force text mode. Synonym: /ASCII.", " /TENEX", " Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).", #ifndef NOCSETS " /TRANSPARENT", " When uploading in text mode, do not convert chracter-sets.", #endif /* NOCSETS */ " /TYPE:{TEXT,BINARY}", " Upload only files of the given type.", #ifdef DOUPDATE " /UPDATE", " If a file of the same name exists on the server, upload only if", " the local file is newer.", #endif /* DOUPDATE */ " /UNIQUE-SERVER-NAMES", " Ask the server to compute new names for any incoming file that has", " the same name as an existing file.", "" }; static char * fhs_opn[] = { /* OPEN */ #ifdef CK_SSL "Syntax: FTP [ OPEN ] [ { /SSL, /TLS } ] hostname [ port ] [ switches ]", " Opens a connection to the FTP server on the given host. The default", " TCP port is 21 (990 if SSL/TLS is used), but a different port number", " can be supplied if necessary. Optional switches are:", #else /* CK_SSL */ "Syntax: FTP [ OPEN ] hostname [ port ] [ switches ]", " Opens a connection to the FTP server on the given host. The default", " TCP port is 21, but a different port number can be supplied if", " necessary. Optional switches are:", #endif /* CK_SSL */ " ", " /ANONYMOUS", " Logs you in anonymously.", " /USER:text", " Supplies the given text as your username.", " /PASSWORD:text", " Supplies the given text as your password. If you include a username", " but omit this switch and the server requires a password, you are", " prompted for it.", " /ACCOUNT:text", " Supplies the given text as your account, if required by the server.", " /ACTIVE", " Forces an active (rather than passive) connection.", " /PASSIVE", " Forces a passive (rather than active) connection.", " /NOINIT", " Inhibits sending initial REST, STRU, and MODE commands, which are", " well-known standard commands, but to which some servers react badly.", " /NOLOGIN", " Inhibits autologin for this connection only.", "" }; static char * fhs_opt[] = { /* OPTS, OPTIONS */ "Syntax: FTP OPTIONS", " Asks the FTP server to list its current options. Advanced, new,", " not supported by most FTP servers.", "" }; static char * fhs_put[] = { /* PUT, SEND */ "Syntax: [ FTP ] PUT [ switches ] filespec [ as-name ]", " Like FTP MPUT, but only one filespec is allowed, and if it is followed", " by an additional field, this is interpreted as the name under which", " to send the file or files. See HELP FTP MPUT.", "" }; static char * fhs_reput[] = { /* REPUT, RESEND */ "Syntax: [ FTP ] REPUT [ switches ] filespec [ as-name ]", " Synonym for FTP PUT /RECOVER. Recovers an interrupted binary-mode", " upload from the point of failure if the FTP server supports recovery.", " Synonym: [ FTP ] RESEND. For details see HELP FTP MPUT.", "" }; static char * fhs_pwd[] = { /* PWD */ "Syntax: FTP PWD", " Asks the FTP server to reveal its current working directory.", " Synonyms: REMOTE PWD, RPWD.", "" }; static char * fhs_quo[] = { /* QUOTE */ "Syntax: FTP QUOTE text", " Sends an FTP protocol command to the FTP server. Use this command", " for sending commands that Kermit might not support.", "" }; static char * fhs_rge[] = { /* REGET */ "Syntax: FTP REGET", " Synonym for FTP GET /RECOVER.", "" }; static char * fhs_ren[] = { /* RENAME */ "Syntax: FTP RENAME name1 name1", " Asks the FTP server to change the name of the file whose name is name1", " and which resides in the FTP server's file system, to name2. Works", " only for single files; wildcards are not accepted.", "" }; static char * fhs_res[] = { /* RESET */ "Syntax: FTP RESET", " Asks the server to log out your session, terminating your access", " rights, without closing the connection.", "" }; static char * fhs_rmd[] = { /* RMDIR */ "Syntax: FTP RMDIR directory", " Asks the FTP server to remove the directory whose name is given.", " This usually requires the directory to be empty. Synonyms: REMOTE", " RMDIR, RRMDIR.", "" }; static char * fhs_sit[] = { /* SITE */ "Syntax: FTP SITE text", " Sends a site-specific command to the FTP server.", "" }; static char * fhs_siz[] = { /* SIZE */ "Syntax: FTP SIZE filename", " Asks the FTP server to send a numeric string representing the size", " of the given file.", "" }; static char * fhs_sta[] = { /* STATUS */ "Syntax: FTP STATUS [ filename ]", " Asks the FTP server to report its status. If a filename is given,", " the FTP server should report details about the file.", "" }; static char * fhs_sys[] = { /* SYSTEM */ "Syntax: FTP SYSTEM", " Asks the FTP server to report its operating system type.", "" }; static char * fhs_typ[] = { /* TYPE */ "Syntax: FTP TYPE { TEXT, BINARY, TENEX }", " Puts the client and server in the indicated transfer mode.", " ASCII is a synonym for TEXT. TENEX is used only for uploading 8-bit", " binary files to a 36-bit platforms such as TENEX or TOPS-20 and/or", " downloading files from TENEX or TOPS-20 that have been uploaded in", " TENEX mode.", "" }; static char * fhs_uma[] = { /* UMASK */ "Syntax: FTP UMASK number", " Asks the FTP server to set its file creation mode mask. Applies", " only (or mainly) to UNIX-based FTP servers.", "" }; static char * fhs_chk[] = { /* CHECK */ "Syntax: FTP CHECK remote-filespec", " Asks the FTP server if the given file or files exist. If the", " remote-filespec contains wildcards, this command fails if no server", " files match, and succeeds if at least one file matches. If the", " remote-filespec does not contain wildcards, this command succeeds if", " the given file exists and fails if it does not.", "" }; static char * fhs_ena[] = { /* ENABLE */ "Syntax: FTP ENABLE { AUTH, FEAT, MDTM, MLST, SIZE }", " Enables the use of the given FTP protocol command in case it has been", " disabled (but this is no guarantee that the FTP server understands it)." , " Use SHOW FTP to see which of these commands is enabled and disabled.", " Also see FTP DISABLE.", "" }; static char * fhs_dis[] = { /* DISABLE */ "Syntax: FTP DISABLE { AUTH, FEAT, MDTM, MLST, SIZE }", " Disables the use of the given FTP protocol command.", " Also see FTP ENABLE.", "" }; #endif /* NOHELP */ int doftphlp() { int cx; if ((cx = cmkey(ftpcmdtab,nftpcmd,"","",xxstring)) < 0) if (cx != -3) return(cx); if ((x = cmcfm()) < 0) return(x); #ifdef NOHELP printf("Sorry, no help available\n"); #else switch (cx) { case -3: return(hmsga(fhs_ftp)); case FTP_ACC: /* ACCOUNT */ return(hmsga(fhs_acc)); case FTP_APP: /* APPEND */ return(hmsga(fhs_app)); case FTP_CLS: /* BYE, CLOSE */ return(hmsga(fhs_cls)); case FTP_CWD: /* CD, CWD */ return(hmsga(fhs_cwd)); case FTP_GUP: /* CDUP, UP */ return(hmsga(fhs_gup)); case FTP_CHM: /* CHMOD */ return(hmsga(fhs_chm)); case FTP_MDE: /* DELETE, MDELETE */ return(hmsga(fhs_mde)); case FTP_DIR: /* DIRECTORY */ return(hmsga(fhs_dir)); case FTP_VDI: /* VDIRECTORY */ return(hmsga(fhs_vdi)); case FTP_FEA: /* FEATURES */ return(hmsga(fhs_fea)); case FTP_GET: /* GET */ return(hmsga(fhs_get)); case FTP_HLP: /* HELP */ return(hmsga(fhs_hlp)); case FTP_IDL: /* IDLE */ return(hmsga(fhs_idl)); case FTP_USR: /* USER, LOGIN */ return(hmsga(fhs_usr)); case FTP_MGE: /* MGET */ return(hmsga(fhs_mge)); case FTP_MKD: /* MKDIR */ return(hmsga(fhs_mkd)); case FTP_MOD: /* MODTIME */ return(hmsga(fhs_mod)); case FTP_MPU: /* MPUT */ return(hmsga(fhs_mpu)); case FTP_OPN: /* OPEN */ return(hmsga(fhs_opn)); case FTP_OPT: /* OPTS, OPTIONS */ return(hmsga(fhs_opt)); case FTP_PUT: /* PUT, SEND */ return(hmsga(fhs_put)); case FTP_REP: /* REPUT, RESEND */ return(hmsga(fhs_reput)); case FTP_PWD: /* PWD */ return(hmsga(fhs_pwd)); case FTP_QUO: /* QUOTE */ return(hmsga(fhs_quo)); case FTP_RGE: /* REGET */ return(hmsga(fhs_rge)); case FTP_REN: /* RENAME */ return(hmsga(fhs_ren)); case FTP_RES: /* RESET */ return(hmsga(fhs_res)); case FTP_RMD: /* RMDIR */ return(hmsga(fhs_rmd)); case FTP_SIT: /* SITE */ return(hmsga(fhs_sit)); case FTP_SIZ: /* SIZE */ return(hmsga(fhs_siz)); case FTP_STA: /* STATUS */ return(hmsga(fhs_sta)); case FTP_SYS: /* SYSTEM */ return(hmsga(fhs_sys)); case FTP_TYP: /* TYPE */ return(hmsga(fhs_typ)); case FTP_UMA: /* UMASK */ return(hmsga(fhs_uma)); case FTP_CHK: /* CHECK */ return(hmsga(fhs_chk)); case FTP_ENA: return(hmsga(fhs_ena)); case FTP_DIS: return(hmsga(fhs_dis)); default: printf("Sorry, help available for this command.\n"); break; } #endif /* NOHELP */ return(success = 0); } int dosetftphlp() { int cx; if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0) if (cx != -3) return(cx); if (cx != -3) ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ); if ((x = cmcfm()) < 0) return(x); #ifdef NOHELP printf("Sorry, no help available\n"); #else switch (cx) { case -3: printf("\nSyntax: SET FTP parameter value\n"); printf(" Type \"help set ftp ?\" for a list of parameters.\n"); printf(" Type \"help set ftp xxx\" for information about setting\n"); printf(" parameter xxx. Type \"show ftp\" for current values.\n\n"); return(0); case FTS_BUG: printf("\nSyntax: SET FTP BUG {ON, OFF}\n"); printf( " Activates a workaround for the named bug in the FTP server.\n"); printf(" Type SET FTP BUG ? for a list of names.\n"); printf(" For each bug, the default is OFF\n\n"); return(0); #ifdef FTP_SECURITY case FTS_ATP: /* "authtype" */ printf("\nSyntax: SET FTP AUTHTYPE list\n"); printf(" Specifies an ordered list of authentication methods to be\n" ); printf(" when FTP AUTOAUTHENTICATION is ON. The default list is:\n"); printf(" GSSAPI-KRB5, SRP, KERBEROS_V4, TLS, SSL.\n\n"); return(0); case FTS_AUT: /* "autoauthentication" */ printf("\nSyntax:SET FTP AUTOAUTHENTICATION { ON, OFF }\n"); printf(" Tells whether authentication should be negotiated by the\n"); printf(" FTP OPEN command. Default is ON.\n\n"); break; case FTS_CRY: /* "autoencryption" */ printf("\nSET FTP AUTOENCRYPTION { ON, OFF }\n"); printf(" Tells whether encryption (privacy) should be negotiated\n"); printf(" by the FTP OPEN command. Default is ON.\n\n"); break; #endif /* FTP_SECURITY */ case FTS_LOG: /* "autologin" */ printf("\nSET FTP AUTOLOGIN { ON, OFF }\n"); printf(" Tells Kermit whether to try to log you in automatically\n"); printf(" as part of the connection process.\n\n"); break; case FTS_DIS: printf("\nSET FTP DISPLAY { BRIEF, FULLSCREEN, CRT, ... }\n"); printf(" Chooses the file-transfer display style for FTP.\n"); printf(" Like SET TRANSFER DISPLAY but applies only to FTP.\n\n"); break; #ifndef NOCSETS case FTS_XLA: /* "character-set-translation" */ printf("\nSET FTP CHARACTER-SET-TRANSLATION { ON, OFF }\n"); printf(" Whether to translate character sets when transferring\n"); printf(" text files with FTP. OFF by default.\n\n"); break; #endif /* NOCSETS */ case FTS_FNC: /* "collision" */ printf("\n"); printf( "Syntax: SET FTP COLLISION { BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE }\n" ); printf(" Tells what do when an incoming file has the same name as\n"); printf(" an existing file when downloading with FTP.\n\n"); break; #ifdef FTP_SECURITY case FTS_CPL: /* "command-protection-level" */ printf("\n"); printf( "Syntax: SET FTP COMMAND-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }" ); printf("\n"); printf( " Tells what level of protection is applied to the FTP command channel.\n\n"); break; case FTS_CFW: /* "credential-forwarding" */ printf("\nSyntax: SET FTP CREDENTIAL-FORWARDING { ON, OFF }\n"); printf(" Tells whether end-user credentials are to be forwarded\n"); printf(" to the server if supported by the authentication method\n"); printf(" (GSSAPI-KRB5 only).\n\n"); break; case FTS_DPL: /* "data-protection-level" */ printf("\n"); printf( "Syntax: SET FTP DATA-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }" ); printf("\n"); printf( " Tells what level of protection is applied to the FTP data channel.\n\n"); break; #endif /* FTP_SECURITY */ case FTS_DBG: /* "debug" */ printf("\nSyntax: SET FTP DEBUG { ON, OFF }\n"); printf(" Whether to print FTP protocol messages.\n\n"); return(0); case FTS_ERR: /* "error-action" */ printf("\nSyntax: SET FTP ERROR-ACTION { QUIT, PROCEED }\n"); printf(" What to do when an error occurs when transferring a group\n") ; printf(" of files: quit and fail, or proceed to the next file.\n\n"); return(0); case FTS_CNV: /* "filenames" */ printf("\nSyntax: SET FTP FILENAMES { AUTO, CONVERTED, LITERAL }\n"); printf(" What to do with filenames: convert them, take and use them\n" ); printf(" literally; or choose what to do automatically based on the\n" ); printf(" OS type of the server. The default is AUTO.\n\n"); return(0); case FTS_PSV: /* "passive-mode" */ printf("\nSyntax: SET FTP PASSIVE-MODE { ON, OFF }\n"); printf(" Whether to use passive mode, which helps to get through\n"); printf(" firewalls. ON by default.\n\n"); return(0); case FTS_PRM: /* "permissions" */ printf("\nSyntax: SET FTP PERMISSIONS { AUTO, ON, OFF }\n"); printf(" Whether to try to send file permissions when uploading.\n"); printf(" OFF by default. AUTO means only if client and server\n"); printf(" have the same OS type.\n\n"); return(0); case FTS_TST: /* "progress-messages" */ printf("\nSyntax: SET FTP PROGRESS-MESSAGES { ON, OFF }\n"); printf(" Whether Kermit should print locally-generated feedback\n"); printf(" messages for each non-file-transfer command."); printf(" ON by default.\n\n"); return(0); case FTS_SPC: /* "send-port-commands" */ printf("\nSyntax: SET FTP SEND-PORT-COMMANDS { ON, OFF }\n"); printf(" Whether Kermit should send a new PORT command for each"); printf(" task.\n\n"); return(0); #ifndef NOCSETS case FTS_CSR: /* "server-character-set" */ printf("\nSyntax: SET FTP SERVER-CHARACTER-SET name\n"); printf(" The name of the character set used for text files on the\n"); printf(" server. Enter a name of '?' for a menu.\n\n"); return(0); #endif /* NOCSETS */ case FTS_STO: /* "server-time-offset */ printf( "\nSyntax: SET FTP SERVER-TIME-OFFSET +hh[:mm[:ss]] or -hh[:mm[:ss]]\n"); printf( " Specifies an offset to apply to the server's file timestamps.\n"); printf( " Use this to correct for misconfigured server time or timezone.\n"); printf( " Format: must begin with + or - sign. Hours must be given; minutes\n"); printf( " and seconds are optional: +4 = +4:00 = +4:00:00 (add 4 hours).\n\n"); return(0); case FTS_TYP: /* "type" */ printf("\nSyntax: SET FTP TYPE { TEXT, BINARY, TENEX }\n"); printf(" Establishes the default transfer mode.\n"); printf(" TENEX is used for uploading 8-bit binary files to 36-bit\n"); printf(" platforms such as TENEX and TOPS-20 and for downloading\n"); printf(" them again. ASCII is a synonym for TEXT. Normally each\n"); printf(" file's type is determined automatically from its contents\n" ); printf(" or its name; SET FTP TYPE does not prevent that, it only\n"); printf(" tells which mode to use when the type can't be determined\n" ); printf(" automatically. To completely disable automatic transfer-\n" ); printf(" mode switching and force either text or binary mode, give\n" ); printf(" the top-level command ASCII or BINARY, as in traditional\n"); printf(" FTP clients.\n\n"); return(0); #ifdef FTP_TIMEOUT case FTS_TMO: printf("\nSyntax: SET FTP TIMEOUT number-of-seconds\n"); printf(" Establishes a timeout for FTP transfers.\n"); printf(" The timeout applies per network read or write on the data\n"); printf(" connection, not to the whole transfer. By default the\n"); printf(" timeout value is 0, meaning no timeout. Use a positive\n"); printf(" number to escape gracefully from hung data connections or\n"); printf(" directory listings.\n\n"); return(0); #endif /* FTP_TIMEOUT */ #ifdef PATTERNS case FTS_GFT: printf("\nSyntax: SET FTP GET-FILETYPE-SWITCHING { ON, OFF }\n"); printf(" Tells whether GET and MGET should automatically switch\n"); printf(" the appropriate file type, TEXT, BINARY, or TENEX, by\n"); printf(" matching the name of each incoming file with its list of\n"); printf(" FILE TEXT-PATTERNS and FILE BINARY-PATTERNS. ON by\n"); printf(" default. SHOW PATTERNS displays the current pattern\n"); printf(" list. HELP SET FILE to see how to change it.\n"); break; #endif /* PATTERNS */ case FTS_USN: /* "unique-server-names" */ printf("\nSyntax: SET FTP UNIQUE-SERVER-NAMES { ON, OFF }\n"); printf(" Tells whether to ask the server to create unique names\n"); printf(" for any uploaded file that has the same name as an\n"); printf(" existing file. Default is OFF.\n\n"); return(0); case FTS_VBM: /* "verbose-mode" */ printf("\nSyntax: SET FTP VERBOSE-MODE { ON, OFF }\n"); printf(" Whether to display all responses from the FTP server.\n"); printf(" OFF by default.\n\n"); return(0); case FTS_DAT: printf("\nSyntax: SET FTP DATES { ON, OFF }\n"); printf(" Whether to set date of incoming files from the file date\n"); printf(" on the server. ON by default. Note: there is no way to\n") ; printf(" set the date on files uploaded to the server. Also note\n"); printf(" that not all servers support this feature.\n\n"); return(0); case FTS_APW: printf("\nSyntax: SET FTP ANONYMOUS-PASSWORD [ text ]\n"); printf(" Password to supply automatically on anonymous FTP\n"); printf(" connections instead of the default user@host.\n"); printf(" Omit optional text to restore default.\n\n"); return(0); default: printf("Sorry, help not available for \"set ftp %s\"\n",tmpbuf); } #endif /* NOHELP */ return(0); } #ifndef L_SET #define L_SET 0 #endif /* L_SET */ #ifndef L_INCR #define L_INCR 1 #endif /* L_INCR */ #ifdef FTP_SRP char srp_user[BUFSIZ]; /* where is BUFSIZ defined? */ char *srp_pass; char *srp_acct; #endif /* FTP_SRP */ static int kerror; /* Needed for all auth types */ static struct sockaddr_in hisctladdr; static struct sockaddr_in hisdataaddr; static struct sockaddr_in data_addr; static int data = -1; #ifdef FTP_PROXY static int ptflag = 0; #endif /* FTP_PROXY */ static struct sockaddr_in myctladdr; #ifdef COMMENT #ifndef OS2 UID_T getuid(); #endif /* OS2 */ #endif /* COMMENT */ static int cpend = 0; /* No pending replies */ #ifdef CK_SSL extern SSL *ssl_ftp_con; extern SSL_CTX *ssl_ftp_ctx; extern SSL *ssl_ftp_data_con; extern int ssl_ftp_active_flag; extern int ssl_ftp_data_active_flag; #endif /* CK_SSL */ /* f t p c m d -- Send a command to the FTP server */ /* Call with: char * cmd: The command to send. char * arg: The argument (e.g. a filename). int lcs: The local character set index. int rcs: The remote (server) character set index. int vbm: Verbose mode: 0 = force verbosity off >0 = force verbosity on If arg is given (not NULL or empty) and lcs != rcs and both are > -1, and neither lcs or rcs is UCS-2, the arg is translated from the local character set to the remote one before sending the result to the server. Returns: 0 on failure with ftpcode = -1 >= 0 on success (getreply() result) with ftpcode = 0. */ static char xcmdbuf[RFNBUFSIZ]; static int #ifdef CK_ANSIC ftpcmd( char * cmd, char * arg, int lcs, int rcs, int vbm ) #else ftpcmd(cmd,arg,lcs,rcs,vbm) char * cmd, * arg; int lcs, rcs, vbm; #endif /* CK_ANSIC */ { char * s = NULL; int r = 0, x = 0, fc = 0, len = 0, cmdlen = 0, q = -1; if (ftp_deb) /* DEBUG */ vbm = 1; else if (quiet || dpyactive) /* QUIET or File Transfer Active */ vbm = 0; else if (vbm < 0) /* VERBOSE */ vbm = ftp_vbm; cancelfile = 0; if (!cmd) cmd = ""; if (!arg) arg = ""; cmdlen = (int)strlen(cmd); len = cmdlen + (int)strlen(arg) + 1; if (ftp_deb /* && !dpyactive */ ) { #ifdef FTP_PROXY if (ftp_prx) printf("%s ", ftp_host); #endif /* FTP_PROXY */ printf("---> "); if (!anonymous && strcmp("PASS",cmd) == 0) printf("PASS XXXX"); else printf("%s %s",cmd,arg); printf("\n"); } /* bzero(xcmdbuf,RFNBUFSIZ); */ ckmakmsg(xcmdbuf,RFNBUFSIZ, cmd, *arg ? " " : "", arg, NULL); #ifdef DEBUG if (deblog) { debug(F110,"ftpcmd cmd",cmd,0); debug(F110,"ftpcmd arg",arg,0); debug(F101,"ftpcmd lcs","",lcs); debug(F101,"ftpcmd rcs","",rcs); } #endif /* DEBUG */ if (csocket == -1) { perror("No control connection for command"); ftpcode = -1; return(0); } havesigint = 0; oldintr = signal(SIGINT, cmdcancel); #ifndef NOCSETS if (*arg && /* If an arg was given */ lcs > -1 && /* and a local charset */ rcs > -1 && /* and a remote charset */ lcs != rcs && /* and the two are not the same */ lcs != FC_UCS2 && /* and neither one is UCS-2 */ rcs != FC_UCS2 /* ... */ ) { initxlate(lcs,rcs); /* Translate arg from lcs to rcs */ xgnbp = arg; /* Global pointer to input string */ rfnptr = rfnbuf; /* Global pointer to output buffer */ while (1) { if ((c0 = xgnbyte(FC_UCS2,lcs,strgetc)) < 0) break; if (xpnbyte(c0,TC_UCS2,rcs,strputc) < 0) break; } /* We have to copy here instead of translating directly into xcmdbuf[] so strputc() can check length. Alternatively we could write yet another xpnbyte() output function. */ if ((int)strlen(rfnbuf) > (RFNBUFSIZ - (cmdlen+1))) { printf("?FTP command too long: %s + arg\n",cmd); ftpcode = -1; return(0); } x = ckstrncpy(&xcmdbuf[cmdlen+1], rfnbuf, RFNBUFSIZ - (cmdlen+1)); } #endif /* NOCSETS */ s = xcmdbuf; /* Command to send to server */ #ifdef DEBUG if (deblog) { /* Log it */ if (!anonymous && !ckstrcmp(s,"PASS ",5,0)) { /* But don't log passwords */ debug(F110,"FTP SENT ","PASS XXXX",0); } else { debug(F110,"FTP SENT ",s,0); } } #endif /* DEBUG */ #ifdef CK_ENCRYPTION again: #endif /* CK_ENCRYPTION */ if (scommand(s) == 0) { /* Send it. */ signal(SIGINT, oldintr); return(0); } cpend = 1; x = !strcmp(cmd,"QUIT"); /* Is it the QUIT command? */ if (x) /* In case we're interrupted */ connected = 0; /* while waiting for the reply... */ fc = 0; /* Function code for getreply() */ if (!strncmp(cmd,"AUTH ",5) /* Must parse AUTH reply */ #ifdef FTPHOST && strncmp(cmd, "HOST ",5) #endif /* FTPHOST */ ) { fc = GRF_AUTH; } else if (!ckstrcmp(cmd,"FEAT",-1,0)) { /* Must parse FEAT reply */ fc = GRF_FEAT; /* But FEAT not widely understood */ if (!ftp_deb) /* So suppress error messages */ vbm = 9; } r = getreply(x, /* Expect connection to close */ lcs,rcs, /* Charsets */ vbm, /* Verbosity */ fc /* Function code */ ); if (q > -1) quiet = q; #ifdef CK_ENCRYPTION if (ftpcode == 533 && ftp_cpl == FPL_PRV) { fprintf(stderr, "ENC command not supported at server; retrying under MIC...\n"); ftp_cpl = FPL_SAF; goto again; } #endif /* CK_ENCRYPTION */ #ifdef COMMENT if (cancelfile && oldintr != SIG_IGN) (*oldintr)(SIGINT); #endif /* COMMENT */ signal(SIGINT, oldintr); return(r); } static VOID lostpeer() { debug(F100,"lostpeer","",0); if (connected) { if (csocket != -1) { #ifdef CK_SSL if (ssl_ftp_active_flag) { SSL_shutdown(ssl_ftp_con); SSL_free(ssl_ftp_con); ssl_ftp_proxy = 0; ssl_ftp_active_flag = 0; ssl_ftp_con = NULL; } #endif /* CK_SSL */ #ifdef TCPIPLIB socket_close(csocket); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(csocket, 1+1); #endif /* USE_SHUTDOWN */ close(csocket); #endif /* TCPIPLIB */ csocket = -1; } if (data != -1) { #ifdef CK_SSL if (ssl_ftp_data_active_flag) { SSL_shutdown(ssl_ftp_data_con); SSL_free(ssl_ftp_data_con); ssl_ftp_data_active_flag = 0; ssl_ftp_data_con = NULL; } #endif /* CK_SSL */ #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = -1; globaldin = -1; } connected = 0; anonymous = 0; loggedin = 0; auth_type = NULL; ftp_cpl = ftp_dpl = FPL_CLR; #ifdef CKLOGDIAL ftplogend(); #endif /* CKLOGDIAL */ #ifdef LOCUS if (autolocus) /* Auotomatic locus switching... */ setlocus(1,1); /* Switch locus to local. */ #endif /* LOCUS */ #ifdef OS2 DialerSend(OPT_KERMIT_HANGUP, 0); #endif /* OS2 */ } #ifdef FTP_PROXY pswitch(1); if (connected) { if (csocket != -1) { #ifdef TCPIPLIB socket_close(csocket); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(csocket, 1+1); #endif /* USE_SHUTDOWN */ close(csocket); #endif /* TCPIPLIB */ csocket = -1; } connected = 0; anonymous = 0; loggedin = 0; auth_type = NULL; ftp_cpl = ftp_dpl = FPL_CLR; } proxflag = 0; pswitch(0); #endif /* FTP_PROXY */ } int ftpisopen() { return(connected); } static int ftpclose() { extern int quitting; if (!connected) return(0); ftp_xfermode = xfermode; if (!ftp_vbm && !quiet) printlines = 1; ftpcmd("QUIT",NULL,0,0,ftp_vbm); if (csocket) { #ifdef CK_SSL if (ssl_ftp_active_flag) { SSL_shutdown(ssl_ftp_con); SSL_free(ssl_ftp_con); ssl_ftp_proxy = 0; ssl_ftp_active_flag = 0; ssl_ftp_con = NULL; } #endif /* CK_SSL */ #ifdef TCPIPLIB socket_close(csocket); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(csocket, 1+1); #endif /* USE_SHUTDOWN */ close(csocket); #endif /* TCPIPLIB */ } csocket = -1; connected = 0; anonymous = 0; loggedin = 0; mdtmok = 1; sizeok = 1; featok = 1; stouarg = 1; typesent = 0; data = -1; globaldin = -1; #ifdef FTP_PROXY if (!proxy) macnum = 0; #endif /* FTP_PROXY */ auth_type = NULL; ftp_dpl = FPL_CLR; #ifdef CKLOGDIAL ftplogend(); #endif /* CKLOGDIAL */ #ifdef LOCUS /* Unprefixed file management commands are executed locally */ if (autolocus && !ftp_cmdlin && !quitting) { setlocus(1,1); } #endif /* LOCUS */ #ifdef OS2 DialerSend(OPT_KERMIT_HANGUP, 0); #endif /* OS2 */ return(0); } int #ifdef CK_ANSIC ftpopen( char * remote, char * service, int use_tls ) #else ftpopen(remote, service, use_tls) char * remote, * service; int use_tls; #endif /* CK_ANSIC */ { char * host; if (connected) { printf("?Already connected to %s, use FTP CLOSE first.\n", ftp_host); ftpcode = -1; return(0); } #ifdef FTPHOST hostcmd = 0; #endif /* FTPHOST */ alike = 0; ftp_srvtyp[0] = NUL; if (!service) service = ""; if (!*service) service = use_tls ? "ftps" : "ftp"; if (!isdigit(service[0])) { struct servent *destsp; destsp = getservbyname(service, "tcp"); if (!destsp) { if (!ckstrcmp(service,"ftp",-1,0)) { ftp_port = 21; } else if (!ckstrcmp(service,"ftps",-1,0)) { ftp_port = 990; } else { printf("?Bad port name - \"%s\"\n", service); ftpcode = -1; return(0); } } else { ftp_port = destsp->s_port; ftp_port = ntohs((unsigned short)ftp_port); /* SMS 2007/02/15 */ } } else ftp_port = atoi(service); if (ftp_port <= 0) { printf("?Bad port name - \"%s\"\n", service); ftpcode = -1; return(0); } host = ftp_hookup(remote, ftp_port, use_tls); if (host) { ckstrncpy(ftp_user_host,remote,MAX_DNS_NAMELEN); connected = 1; /* Set FTP defaults */ ftp_cpl = ftp_dpl = FPL_CLR; curtype = FTT_ASC; /* Server uses ASCII mode */ form = FORM_N; mode = MODE_S; stru = STRU_F; strcpy(bytename, "8"); bytesize = 8; #ifdef FTP_SECURITY if (ftp_aut) { if (ftp_auth()) { if (ftp_cry #ifdef OS2 && ck_crypt_is_installed() #endif /* OS2 */ ) { if (!quiet) printf("FTP Command channel is Private (encrypted)\n"); ftp_cpl = FPL_PRV; if (setpbsz(DEFAULT_PBSZ) < 0) { /* a failure here is most likely caused by a mixup */ /* in the session key used by client and server */ printf("?Protection buffer size negotiation failed\n"); return(0); } if (ftpcmd("PROT P",NULL,0,0,ftp_vbm) == REPLY_COMPLETE) { if (!quiet) printf("FTP Data channel is Private (encrypted)\n"); ftp_dpl = FPL_PRV; } else printf("?Unable to enable encryption on data channel\n"); } else { ftp_cpl = FPL_SAF; } } if (!connected) goto fail; } #endif /* FTP_SECURITY */ if (ftp_log) /* ^^^ */ ftp_login(remote); if (!connected) goto fail; ftp_xfermode = xfermode; #ifdef CKLOGDIAL dologftp(); #endif /* CKLOGDIAL */ #ifdef OS2 DialerSend(OPT_KERMIT_CONNECT, 0); #endif /* OS2 */ passivemode = ftp_psv; sendport = ftp_spc; mdtmok = 1; sizeok = 1; stouarg = 1; typesent = 0; if (ucbuf == NULL) { actualbuf = DEFAULT_PBSZ; while (actualbuf && (ucbuf = (CHAR *)malloc(actualbuf)) == NULL) actualbuf >>= 2; } if (!maxbuf) ucbufsiz = actualbuf - FUDGE_FACTOR; debug(F101,"ftpopen ucbufsiz","",ucbufsiz); return(1); } fail: printf("?Can't FTP connect to %s:%s\n",remote,service); ftpcode = -1; return(0); } #ifdef CK_SSL int ssl_auth() { int i; char* p; CONST SSL_METHOD *client_method; if (ssl_debug_flag) { fprintf(stderr,"SSL DEBUG ACTIVE\n"); fflush(stderr); /* for the moment I want the output on screen */ } if (ssl_ftp_data_con != NULL) { SSL_free(ssl_ftp_data_con); ssl_ftp_data_con = NULL; } if (ssl_ftp_con != NULL) { SSL_free(ssl_ftp_con); ssl_ftp_con=NULL; } if (ssl_ftp_ctx != NULL) { SSL_CTX_free(ssl_ftp_ctx); ssl_ftp_ctx = NULL; } /* The SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS * was added to OpenSSL 0.9.6e and 0.9.7. It does not exist in previous * versions */ #ifndef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS #define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0L #endif /* Pick allowed SSL/TLS versions according to enabled bugs. Modified 5 Feb 2015 to default to TLS 1.0 if no bugs are enabled, instead of to SSL 3.0, which has the POODLE vulnerability. Modified 7 Sep 2022 to use the best version of TLS available (DG) */ if (ftp_bug_use_ssl_v2) { /* allow SSL 2.0 or later */ client_method = SSLv23_client_method(); #ifndef OPENSSL_NO_SSL3 } else if (ftp_bug_use_ssl_v3) { /* allow SSL 3.0 ONLY - previous default */ client_method = SSLv3_client_method(); #endif /* OPENSSL_NO_SSL3 */ } else { /* default - use the best version of TLS we can */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* OpenSSL >= 1.1.0: Negotiate the best TLS version possible */ client_method = TLS_client_method(); #else /* OPENSSL_VERSION_NUMBER < 0x10100000L */ #if OPENSSL_VERSION_NUMBER >= 0x10001000L /* OpenSSL >= 1.0.1: Use TLS 1.2 - not yet deprecated as of 2022-09-06 */ client_method = TLSv1_2_client_method(); #else /* OpenSSL 0.9.8 and 1.0.0 can't handle anything newer than TSL 1.0 */ client_method = TLSv1_client_method(); #endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */ #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ } if (auth_type && !strcmp(auth_type,"TLS")) { ssl_ftp_ctx=SSL_CTX_new(client_method); if (!ssl_ftp_ctx) return(0); SSL_CTX_set_options(ssl_ftp_ctx, SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA ); } else { ssl_ftp_ctx = SSL_CTX_new(client_method); if (!ssl_ftp_ctx) return(0); SSL_CTX_set_options(ssl_ftp_ctx, (ftp_bug_use_ssl_v2 ? 0 : SSL_OP_NO_SSLv2)| SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA ); } SSL_CTX_set_default_passwd_cb(ssl_ftp_ctx, (pem_password_cb *)ssl_passwd_callback); SSL_CTX_set_info_callback(ssl_ftp_ctx,ssl_client_info_callback); SSL_CTX_set_session_cache_mode(ssl_ftp_ctx,SSL_SESS_CACHE_CLIENT); #ifdef OS2 #ifdef NT /* The defaults in the SSL crypto library are not appropriate for OS/2 */ { char path[CKMAXPATH]; extern char exedir[]; ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL); if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) { debug(F110,"ftp ssl_auth unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-dir: %s\r\n",path); } ckmakmsg(path,CKMAXPATH, GetAppData(1),"kermit 95/certs",NULL,NULL); if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) { debug(F110,"ftp ssl_auth unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-dir: %s\r\n",path); } ckmakmsg(path,CKMAXPATH, GetAppData(0),"kermit 95/certs",NULL,NULL); if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) { debug(F110,"ftp ssl_auth unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-dir: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL); if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) { debug(F110,"ftp ssl_auth unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-file: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,GetAppData(1), "kermit 95/ca_certs.pem",NULL,NULL); if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) { debug(F110,"ftp ssl_auth unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-file: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,GetAppData(0), "kermit 95/ca_certs.pem",NULL,NULL); if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) { debug(F110,"ftp ssl_auth unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-file: %s\r\n",path); } } #else /* NT */ /* The defaults in the SSL crypto library are not appropriate for OS/2 */ { char path[CKMAXPATH]; extern char exedir[]; ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL); if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) { debug(F110,"ftp ssl_auth unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-dir: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL); if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) { debug(F110,"ftp ssl_auth unable to load path",path,0); if (ssl_debug_flag) printf("?Unable to load verify-file: %s\r\n",path); } } #endif /* NT */ #else /* OS2 */ SSL_CTX_set_default_verify_paths(ssl_ftp_ctx); #endif /* OS2 */ if (ssl_verify_file && SSL_CTX_load_verify_locations(ssl_ftp_ctx,ssl_verify_file,NULL) == 0) { debug(F110, "ftp ssl auth unable to load ssl_verify_file", ssl_verify_file, 0 ); if (ssl_debug_flag) printf("?Unable to load verify-file: %s\r\n",ssl_verify_file); } if (ssl_verify_dir && SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,ssl_verify_dir) == 0) { debug(F110, "ftp ssl auth unable to load ssl_verify_dir", ssl_verify_dir, 0 ); if (ssl_debug_flag) printf("?Unable to load verify-dir: %s\r\n",ssl_verify_dir); } /* set up the new CRL Store */ crl_store = (X509_STORE *)X509_STORE_new(); if (crl_store) { #ifdef OS2 char path[CKMAXPATH]; extern char exedir[]; ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL); if (X509_STORE_load_locations(crl_store,NULL,path) == 0) { debug(F110,"ftp ssl auth unable to load dir",path,0); if (ssl_debug_flag) printf("?Unable to load crl-dir: %s\r\n",path); } #ifdef NT ckmakmsg(path,CKMAXPATH, (char *)GetAppData(1),"kermit 95/crls",NULL,NULL); if (X509_STORE_load_locations(crl_store,NULL,path) == 0) { debug(F110,"ftp ssl auth unable to load dir",path,0); if (ssl_debug_flag) printf("?Unable to load crl-dir: %s\r\n",path); } ckmakmsg(path,CKMAXPATH, (char *)GetAppData(0),"kermit 95/crls",NULL,NULL); if (X509_STORE_load_locations(crl_store,NULL,path) == 0) { debug(F110,"ftp ssl auth unable to load dir",path,0); if (ssl_debug_flag) printf("?Unable to load crl-dir: %s\r\n",path); } #endif /* NT */ ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL); if (X509_STORE_load_locations(crl_store,path,NULL) == 0) { debug(F110,"ftp ssl auth unable to load file",path,0); if (ssl_debug_flag) printf("?Unable to load crl-file: %s\r\n",path); } #ifdef NT ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1), "kermit 95/ca_crls.pem",NULL,NULL); if (X509_STORE_load_locations(crl_store,path,NULL) == 0) { debug(F110,"ftp ssl auth unable to load file",path,0); if (ssl_debug_flag) printf("?Unable to load crl-file: %s\r\n",path); } ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0), "kermit 95/ca_crls.pem",NULL,NULL); if (X509_STORE_load_locations(crl_store,path,NULL) == 0) { debug(F110,"ftp ssl auth unable to load file",path,0); if (ssl_debug_flag) printf("?Unable to load crl-file: %s\r\n",path); } #endif /* NT */ #endif /* OS2 */ if (ssl_crl_file || ssl_crl_dir) { if (ssl_crl_file && X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 0) { debug(F110, "ftp ssl auth unable to load ssl_crl_file", ssl_crl_file, 0 ); if (ssl_debug_flag) printf("?Unable to load crl-file: %s\r\n",ssl_crl_file); } if (ssl_crl_dir && X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 0) { debug(F110, "ftp ssl auth unable to load ssl_crl_dir", ssl_crl_dir, 0 ); if (ssl_debug_flag) printf("?Unable to load crl-dir: %s\r\n",ssl_crl_dir); } } else { X509_STORE_set_default_paths(crl_store); } } SSL_CTX_set_verify(ssl_ftp_ctx,ssl_verify_flag, ssl_client_verify_callback); ssl_verify_depth = -1; ssl_ftp_con=(SSL *)SSL_new(ssl_ftp_ctx); tls_load_certs(ssl_ftp_ctx,ssl_ftp_con,0); SSL_set_fd(ssl_ftp_con,csocket); SSL_set_verify(ssl_ftp_con,ssl_verify_flag,NULL); if (ssl_cipher_list) { SSL_set_cipher_list(ssl_ftp_con,ssl_cipher_list); } else { char * p; if ((p = getenv("SSL_CIPHER"))) { SSL_set_cipher_list(ssl_ftp_con,p); } else { SSL_set_cipher_list(ssl_ftp_con,DEFAULT_CIPHER_LIST); } } if (ssl_debug_flag) { fprintf(stderr,"=>START SSL/TLS connect on COMMAND\n"); fflush(stderr); } if (SSL_connect(ssl_ftp_con) <= 0) { static char errbuf[1024]; ckmakmsg(errbuf,1024,"ftp: SSL/TLS connect COMMAND error: ", ERR_error_string(ERR_get_error(),NULL),NULL,NULL); fprintf(stderr,"%s\n", errbuf); fflush(stderr); ssl_ftp_active_flag=0; SSL_free(ssl_ftp_con); ssl_ftp_con = NULL; } else { ssl_ftp_active_flag = 1; if (!ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER) && /* JEA 2013-12-10 */ !tls_is_krb5(1)) { char *subject = ssl_get_subject_name(ssl_ftp_con); if (!subject) { if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { debug(F110,"ssl_auth","[SSL - FAILED]",0); return(ssl_ftp_active_flag = 0); } else { if (uq_ok("Warning: Server didn't provide a certificate\n", "Continue? (Y/N)",3,NULL,0) <= 0) { debug(F110, "ssl_auth","[SSL - FAILED]",0); return(ssl_ftp_active_flag = 0); } } } else if (ssl_check_server_name(ssl_ftp_con, ftp_user_host)) { debug(F110,"ssl_auth","[SSL - FAILED]",0); return(ssl_ftp_active_flag = 0); } } debug(F110,"ssl_auth","[SSL - OK]",0); ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag); } if (ssl_debug_flag) { fprintf(stderr,"=>DONE SSL/TLS connect on COMMAND\n"); fflush(stderr); } return(ssl_ftp_active_flag); } #endif /* CK_SSL */ static sigtype #ifdef CK_ANSIC cmdcancel( int sig ) #else cmdcancel(sig) int sig; #endif /* CK_ANSIC */ { #ifdef OS2 /* In Unix we "chain" to trap(), which prints this */ printf("^C...\n"); #endif /* OS2 */ debug(F100,"ftp cmdcancel caught SIGINT ","",0); fflush(stdout); secure_getc(0,1); /* Initialize net input buffers */ cancelfile++; cancelgroup++; mlsreset(); #ifndef OS2 #ifdef FTP_PROXY if (ptflag) /* proxy... */ longjmp(ptcancel,1); #endif /* FTP_PROXY */ debug(F100,"ftp cmdcancel chain to trap()...","",0); trap(SIGINT); /* NOTREACHED */ debug(F100,"ftp cmdcancel return from trap()...","",0); #else debug(F100,"ftp cmdcancel PostCtrlCSem()...","",0); PostCtrlCSem(); #endif /* OS2 */ } static int #ifdef CK_ANSIC scommand(char * s) /* Was secure_command() */ #else scommand(s) char * s; #endif /* CK_ANSIC */ { int length = 0, len2; char in[FTP_BUFSIZ], out[FTP_BUFSIZ]; #ifdef CK_SSL if (ssl_ftp_active_flag) { int error, rc; length = strlen(s) + 2; length = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL); rc = SSL_write(ssl_ftp_con,out,length); error = SSL_get_error(ssl_ftp_con,rc); switch (error) { case SSL_ERROR_NONE: return(1); case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_SYSCALL: #ifdef NT { int gle = GetLastError(); } #endif /* NT */ case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: lostpeer(); } return(0); } #endif /* CK_SSL */ if (auth_type && ftp_cpl != FPL_CLR) { #ifdef FTP_SRP if (ck_srp_is_installed() && (strcmp(auth_type,"SRP") == 0)) if ((length = srp_encode(ftp_cpl == FPL_PRV, (CHAR *)s, (CHAR *)out, strlen(s))) < 0) { fprintf(stderr, "SRP failed to encode message\n"); return(0); } #endif /* FTP_SRP */ #ifdef FTP_KRB4 if (ck_krb4_is_installed() && (strcmp(auth_type, "KERBEROS_V4") == 0)) { if (ftp_cpl == FPL_PRV) { length = krb_mk_priv((CHAR *)s, (CHAR *)out, strlen(s), ftp_sched, #ifdef KRB524 ftp_cred.session, #else /* KRB524 */ &ftp_cred.session, #endif /* KRB524 */ &myctladdr, &hisctladdr); } else { length = krb_mk_safe((CHAR *)s, (CHAR *)out, strlen(s), #ifdef KRB524 ftp_cred.session, #else /* KRB524 */ &ftp_cred.session, #endif /* KRB524 */ &myctladdr, &hisctladdr); } if (length == -1) { fprintf(stderr, "krb_mk_%s failed for KERBEROS_V4\n", ftp_cpl == FPL_PRV ? "priv" : "safe"); return(0); } } #endif /* FTP_KRB4 */ #ifdef FTP_GSSAPI /* Scommand (based on level) */ if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) { gss_buffer_desc in_buf, out_buf; OM_uint32 maj_stat, min_stat; int conf_state; in_buf.value = s; in_buf.length = strlen(s) + 1; maj_stat = gss_seal(&min_stat, gcontext, (ftp_cpl==FPL_PRV), /* private */ GSS_C_QOP_DEFAULT, &in_buf, &conf_state, &out_buf); if (maj_stat != GSS_S_COMPLETE) { /* Generally need to deal */ user_gss_error(maj_stat, min_stat, (ftp_cpl==FPL_PRV)? "gss_seal ENC didn't complete": "gss_seal MIC didn't complete"); } else if ((ftp_cpl == FPL_PRV) && !conf_state) { fprintf(stderr, "GSSAPI didn't encrypt message"); } else { if (ftp_deb) fprintf(stderr, "sealed (%s) %d bytes\n", ftp_cpl==FPL_PRV?"ENC":"MIC", out_buf.length); memcpy(out, out_buf.value, length=out_buf.length); gss_release_buffer(&min_stat, &out_buf); } } #endif /* FTP_GSSAPI */ /* Other auth types go here ... */ len2 = FTP_BUFSIZ; if ((kerror = radix_encode((CHAR *)out, (CHAR *)in, length, &len2, RADIX_ENCODE)) ) { fprintf(stderr,"Couldn't base 64 encode command (%s)\n", radix_error(kerror)); return(0); } if (ftp_deb) fprintf(stderr, "scommand(%s)\nencoding %d bytes\n", s, length); len2 = ckmakmsg(out, FTP_BUFSIZ, ftp_cpl == FPL_PRV ? "ENC " : "MIC ", in, "\r\n", NULL ); send(csocket,(SENDARG2TYPE)out,len2,0); } else { char out[FTP_BUFSIZ]; int len = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL); send(csocket,(SENDARG2TYPE)out,len,0); } return(1); } static int mygetc() { static char inbuf[4096]; static int bp = 0, ep = 0; int rc; if (bp == ep) { bp = ep = 0; #ifdef CK_SSL if (ssl_ftp_active_flag) { int error; rc = SSL_read(ssl_ftp_con,inbuf,4096); error = SSL_get_error(ssl_ftp_con,rc); switch (error) { case SSL_ERROR_NONE: break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: return(0); case SSL_ERROR_SYSCALL: if (rc == 0) { /* EOF */ break; } else { #ifdef NT int gle = GetLastError(); #endif /* NT */ break; } case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: break; } } else #endif /* CK_SSL */ rc = recv(csocket,(char *)inbuf,4096,0); if (rc <= 0) return(EOF); ep = rc; } return(inbuf[bp++]); } /* x l a t e c -- Translate a character */ /* Call with: fc = Function code: 0 = translate, 1 = initialize. c = Character (as int). incs = Index of charset to translate from. outcs = Index of charset to translate to. Returns: 0: OK -1: Error */ static int #ifdef CK_ANSIC xlatec( int fc, int c, int incs, int outcs ) #else xlatec(fc,c,incs,outcs) int fc, c, incs, outcs; #endif /* CK_ANSIC */ { #ifdef NOCSETS return(c); #else static char buf[128]; static int cx; int c0; if (fc == 1) { /* Initialize */ cx = 0; /* Catch-up buffer write index */ xgnbp = buf; /* Catch-up buffer read pointer */ buf[0] = NUL; /* Buffer is empty */ return(0); } if (cx >= 127) { /* Catch-up buffer full */ debug(F100,"xlatec overflow","",0); /* (shouldn't happen) */ printf("?Translation buffer overflow\n"); return(-1); } /* Add char to buffer. */ /* The buffer won't grow unless incs is a multibyte set, e.g. UTF-8. */ debug(F000,"xlatec buf",ckitoa(cx),c); buf[cx++] = c; buf[cx] = NUL; while ((c0 = xgnbyte(FC_UCS2,incs,strgetc)) > -1) { if (xpnbyte(c0,TC_UCS2,outcs,NULL) < 0) /* (NULL was xprintc) */ return(-1); } /* If we're caught up, reinitialize the buffer */ return((cx == (xgnbp - buf)) ? xlatec(1,0,0,0) : 0); #endif /* NOCSETS */ } /* p a r s e f e a t */ /* Note: for convenience we align keyword values with table indices */ /* If you need to insert a new keyword, adjust the SFT_xxx definitions */ static struct keytab feattab[] = { { "$$$$", 0, 0 }, /* Dummy for sfttab[0] */ { "AUTH", SFT_AUTH, 0 }, { "LANG", SFT_LANG, 0 }, { "MDTM", SFT_MDTM, 0 }, { "MLST", SFT_MLST, 0 }, { "PBSZ", SFT_PBSZ, 0 }, { "PROT", SFT_PROT, 0 }, { "REST", SFT_REST, 0 }, { "SIZE", SFT_SIZE, 0 }, { "TVFS", SFT_TVFS, 0 }, { "UTF8", SFT_UTF8, 0 } }; static int nfeattab = (sizeof(feattab) / sizeof(struct keytab)); #define FACT_CSET 1 #define FACT_CREA 2 #define FACT_LANG 3 #define FACT_MTYP 4 #define FACT_MDTM 5 #define FACT_PERM 6 #define FACT_SIZE 7 #define FACT_TYPE 8 #define FACT_UNIQ 9 static struct keytab facttab[] = { { "CHARSET", FACT_CSET, 0 }, { "CREATE", FACT_CREA, 0 }, { "LANG", FACT_LANG, 0 }, { "MEDIA-TYPE", FACT_MTYP, 0 }, { "MODIFY", FACT_MDTM, 0 }, { "PERM", FACT_PERM, 0 }, { "SIZE", FACT_SIZE, 0 }, { "TYPE", FACT_TYPE, 0 }, { "UNIQUE", FACT_UNIQ, 0 } }; static int nfacttab = (sizeof(facttab) / sizeof(struct keytab)); static struct keytab ftyptab[] = { { "CDIR", FTYP_CDIR, 0 }, { "DIR", FTYP_DIR, 0 }, { "FILE", FTYP_FILE, 0 }, { "PDIR", FTYP_PDIR, 0 } }; static int nftyptab = (sizeof(ftyptab) / sizeof(struct keytab)); static VOID #ifdef CK_ANSIC parsefeat( char * s ) /* Parse a FEATURE response */ #else parsefeat(s) char * s; #endif /* CK_ANSIC */ { char kwbuf[8]; int i, x; if (!s) return; if (!*s) return; while (*s < '!') s++; for (i = 0; i < 4; i++) { if (s[i] < '!') break; kwbuf[i] = s[i]; } if (s[i] && s[i] != SP && s[i] != CK_CR && s[i] != LF) return; kwbuf[i] = NUL; /* xlookup requires a full (but case independent) match */ i = xlookup(feattab,kwbuf,nfeattab,&x); debug(F111,"ftp parsefeat",s,i); if (i < 0 || i > 15) return; switch (i) { case SFT_MDTM: /* Controlled by ENABLE/DISABLE */ sfttab[i] = mdtmok; if (mdtmok) sfttab[0]++; break; case SFT_MLST: /* ditto */ sfttab[i] = mlstok; if (mlstok) sfttab[0]++; break; case SFT_SIZE: /* ditto */ sfttab[i] = sizeok; if (sizeok) sfttab[0]++; break; case SFT_AUTH: /* ditto */ sfttab[i] = ftp_aut; if (ftp_aut) sfttab[0]++; break; default: /* Others */ sfttab[0]++; sfttab[i]++; } } static char * #ifdef CK_ANSIC parsefacts( char * s ) /* Parse MLS[DT] File Facts */ #else parsefacts(s) char * s; #endif /* CK_ANSIC */ { char * p; int i, j, x; if (!s) return(NULL); if (!*s) return(NULL); /* Maybe we should make a copy of s so we can poke it... */ while ((p = ckstrchr(s,'='))) { *p = NUL; /* s points to fact */ i = xlookup(facttab,s,nfacttab,&x); debug(F111,"ftp parsefact fact",s,i); *p = '='; s = p+1; /* Now s points to arg */ p = ckstrchr(s,';'); if (!p) p = ckstrchr(s,SP); if (!p) { debug(F110,"ftp parsefact end-of-val search fail",s,0); break; } *p = NUL; debug(F110,"ftp parsefact valu",s,0); switch (i) { case FACT_CSET: /* Ignore these for now */ case FACT_CREA: case FACT_LANG: case FACT_PERM: case FACT_MTYP: case FACT_UNIQ: break; case FACT_MDTM: /* Modtime */ makestr(&havemdtm,s); debug(F110,"ftp parsefact mdtm",havemdtm,0); break; case FACT_SIZE: /* Size */ havesize = ckatofs(s); debug(F101,"ftp parsefact size","",havesize); break; case FACT_TYPE: /* Type */ j = xlookup(ftyptab,s,nftyptab,NULL); debug(F111,"ftp parsefact type",s,j); havetype = (j < 1) ? 0 : j; break; } *p = ';'; s = p+1; /* s points next fact or name */ } while (*s == SP) /* Skip past spaces. */ s++; if (!*s) /* Make sure we still have a name */ s = NULL; debug(F110,"ftp parsefact name",s,0); return(s); } /* g e t r e p l y -- (to an FTP command sent to server) */ /* vbm = 1 (verbose); 0 (quiet except for error messages); 9 (super quiet) */ static int #ifdef CK_ANSIC getreply( int expecteof, int lcs, int rcs, int vbm, int fc ) #else getreply(expecteof,lcs,rcs,vbm,fc) int expecteof, lcs, rcs, vbm, fc; #endif /* CK_ANSIC */ { /* lcs, rcs, vbm parameters as in ftpcmd() */ register int i, c, n; register int dig; register char *cp; int xlate = 0; int count = 0; int auth = 0; int originalcode = 0, continuation = 0; int pflag = 0; char *pt = pasv; char ibuf[FTP_BUFSIZ], obuf[FTP_BUFSIZ]; /* (these are pretty big...) */ int safe = 0; int xquiet = 0; auth = (fc == GRF_AUTH); #ifndef NOCSETS debug(F101,"ftp getreply lcs","",lcs); debug(F101,"ftp getreply rcs","",rcs); if (lcs > -1 && rcs > -1 && lcs != rcs) { xlate = 1; initxlate(rcs,lcs); xlatec(1,0,rcs,lcs); } #endif /* NOCSETS */ debug(F101,"ftp getreply fc","",fc); if (quiet) xquiet = 1; if (vbm == 9) { xquiet = 1; vbm = 0; } if (ftp_deb) /* DEBUG */ vbm = 1; else if (quiet || dpyactive) /* QUIET or File Transfer Active */ vbm = 0; else if (vbm < 0) /* VERBOSE */ vbm = ftp_vbm; ibuf[0] = '\0'; if (reply_parse) reply_ptr = reply_buf; havesigint = 0; oldintr = signal(SIGINT, cmdcancel); for (count = 0;; count++) { obuf[0] = '\0'; dig = n = ftpcode = i = 0; cp = ftp_reply_str; while ((c = ibuf[0] ? ibuf[i++] : mygetc()) != '\n') { if (c == IAC) { /* Handle telnet commands */ switch (c = mygetc()) { case WILL: case WONT: c = mygetc(); obuf[0] = IAC; obuf[1] = DONT; obuf[2] = c; obuf[3] = NUL; #ifdef CK_SSL if (ssl_ftp_active_flag) { int error, rc; rc = SSL_write(ssl_ftp_con,obuf,3); error = SSL_get_error(ssl_ftp_con,rc); switch (error) { case SSL_ERROR_NONE: break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: return(0); case SSL_ERROR_SYSCALL: if (rc == 0) { /* EOF */ break; } else { #ifdef NT int gle = GetLastError(); #endif /* NT */ break; } case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: break; } } else #endif /* CK_SSL */ send(csocket,(SENDARG2TYPE)obuf,3,0); break; case DO: case DONT: c = mygetc(); obuf[0] = IAC; obuf[1] = WONT; obuf[2] = c; obuf[3] = NUL; #ifdef CK_SSL if (ssl_ftp_active_flag) { int error, rc; rc = SSL_write(ssl_ftp_con,obuf,3); error = SSL_get_error(ssl_ftp_con,rc); switch (error) { case SSL_ERROR_NONE: break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: signal(SIGINT,oldintr); return(0); case SSL_ERROR_SYSCALL: if (rc == 0) { /* EOF */ break; } else { #ifdef NT int gle = GetLastError(); #endif /* NT */ break; } case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: break; } } else #endif /* CK_SSL */ send(csocket,(SENDARG2TYPE)obuf,3,0); break; default: break; } continue; } dig++; if (c == EOF) { if (expecteof) { signal(SIGINT,oldintr); ftpcode = 221; debug(F101,"ftp getreply EOF","",ftpcode); return(0); } lostpeer(); if (!xquiet) { if (ftp_deb) printf("421 "); printf( "Service not available, connection closed by server\n"); fflush(stdout); } signal(SIGINT,oldintr); ftpcode = 421; debug(F101,"ftp getreply EOF","",ftpcode); return(4); } if (n == 0) { /* First digit */ n = c; /* Save it */ } if (auth_type && #ifdef CK_SSL !ssl_ftp_active_flag && #endif /* CK_SSL */ !ibuf[0] && (n == '6' || continuation)) { if (c != '\r' && dig > 4) obuf[i++] = c; } else { if (auth_type && #ifdef CK_SSL !ssl_ftp_active_flag && #endif /* CK_SSL */ !ibuf[0] && dig == 1 && vbm) printf("Unauthenticated reply received from server:\n"); if (reply_parse) { *reply_ptr++ = c; *reply_ptr = NUL; } if ((!dpyactive || ftp_deb) && /* Don't mess up xfer display */ ftp_cmdlin < 2) { if ((c != '\r') && (ftp_deb || ((vbm || (!auth && n == '5')) && (dig > 4 || ( dig <= 4 && !isdigit(c) && ftpcode == 0 ))))) { #ifdef FTP_PROXY if (ftp_prx && (dig == 1 || (dig == 5 && vbm == 0))) printf("%s:",ftp_host); #endif /* FTP_PROXY */ if (!xquiet) { #ifdef NOCSETS printf("%c",c); #else if (xlate) { xlatec(0,c,rcs,lcs); } else { printf("%c",c); } #endif /* NOCSETS */ } } } } if (auth_type && #ifdef CK_SSL !ssl_ftp_active_flag && #endif /* CK_SSL */ !ibuf[0] && n != '6') continue; if (dig < 4 && isdigit(c)) ftpcode = ftpcode * 10 + (c - '0'); if (!pflag && ftpcode == 227) pflag = 1; if (dig > 4 && pflag == 1 && isdigit(c)) pflag = 2; if (pflag == 2) { if (c != '\r' && c != ')') *pt++ = c; else { *pt = '\0'; pflag = 3; } } if (dig == 4 && c == '-' && n != '6') { if (continuation) ftpcode = 0; continuation++; } if (cp < &ftp_reply_str[FTP_BUFSIZ - 1]) { *cp++ = c; *cp = NUL; } } if (deblog || #ifdef COMMENT /* Sometimes we need to print the server reply. printlines is nonzero for any command where the results are sent back on the control connection rather than the data connection, e.g. STAT. In the TOPS-20 case, each file line has ftpcode 213. But if you do this with a UNIX server, it sends "213-Start STAT", , "213-End" or somesuch. So when printlines is nonzero, we want the 213 lines from TOPS-20 and we DON'T want the 213 lines from UNIX. Further experimentation needed with other servers. Of course RFC959 is mute as to the format of the server reply. 'printlines' is also true for PWD and BYE. */ (printlines && ((ftpcode == 0) || (servertype == SYS_TOPS20))) #else /* No, we can't be that clever -- it breaks other things like RPWD... */ (printlines && (ftpcode != 631 && ftpcode != 632 && ftpcode != 633)) #endif /* COMMENT */ ) { char * q = cp; char *r = ftp_reply_str; *q-- = NUL; /* NUL-terminate */ while (*q < '!' && q > r) /* Strip CR, etc */ *q-- = NUL; if (!ftp_deb && printlines) { /* If printing */ if (ftpcode != 0) /* strip ftpcode if any */ r += 4; #ifdef NOCSETS printf("%s\n",r); /* and print */ #else if (!xlate) { printf("%s\n",r); } else { /* Translating */ xgnbp = r; /* Set up strgetc() */ while ((c0 = xgnbyte(FC_UCS2,rcs,strgetc)) > -1) { if (xpnbyte(c0,TC_UCS2,lcs,NULL) < 0) { /* (xprintc) */ signal(SIGINT,oldintr); return(-1); } } printf("\n"); } #endif /* NOCSETS */ } } debug(F110,"FTP RCVD ",ftp_reply_str,0); if (fc == GRF_FEAT) { /* Parsing FEAT command response? */ if (count == 0 && n == '2') { int i; /* (Re)-init server FEATure table */ debug(F100,"ftp getreply clearing feature table","",0); for (i = 0; i < 16; i++) sfttab[i] = 0; } else { parsefeat((char *)ftp_reply_str); } } if (auth_type && #ifdef CK_SSL !ssl_ftp_active_flag && #endif /* CK_SSL */ !ibuf[0] && n != '6') { signal(SIGINT,oldintr); return(getreply(expecteof,lcs,rcs,vbm,auth)); } ibuf[0] = obuf[i] = '\0'; if (ftpcode && n == '6') { if (ftpcode != 631 && ftpcode != 632 && ftpcode != 633) { printf("Unknown reply: %d %s\n", ftpcode, obuf); n = '5'; } else safe = (ftpcode == 631); } if (obuf[0] /* if there is a string to decode */ #ifdef CK_SSL && !ssl_ftp_active_flag /* and not SSL/TLS */ #endif /* CK_SSL */ ) { if (!auth_type) { printf("Cannot decode reply:\n%d %s\n", ftpcode, obuf); n = '5'; } #ifndef CK_ENCRYPTION else if (ftpcode == 632) { printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf); n = '5'; } #endif /* CK_ENCRYPTION */ #ifdef NOCONFIDENTIAL else if (ftpcode == 633) { printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf); n = '5'; } #endif /* NOCONFIDENTIAL */ else { int len = FTP_BUFSIZ; if ((kerror = radix_encode((CHAR *)obuf, (CHAR *)ibuf, 0, &len, RADIX_DECODE)) ) { printf("Can't decode base 64 reply %d (%s)\n\"%s\"\n", ftpcode, radix_error(kerror), obuf); n = '5'; } #ifdef FTP_SRP else if (strcmp(auth_type, "SRP") == 0) { int outlen; outlen = srp_decode(!safe, (CHAR *)ibuf, (CHAR *) ibuf, len); if (outlen < 0) { printf("Warning: %d reply %s!\n", ftpcode, safe ? "modified" : "garbled"); n = '5'; } else { ckstrncpy(&ibuf[outlen], "\r\n",FTP_BUFSIZ-outlen); if (ftp_deb) printf("%c:", safe ? 'S' : 'P'); continue; } } #endif /* FTP_SRP */ #ifdef FTP_KRB4 else if (strcmp(auth_type, "KERBEROS_V4") == 0) { if (safe) { kerror = krb_rd_safe((CHAR *)ibuf, len, #ifdef KRB524 ftp_cred.session, #else /* KRB524 */ &ftp_cred.session, #endif /* KRB524 */ &hisctladdr, &myctladdr, &ftp_msg_data ); } else { kerror = krb_rd_priv((CHAR *)ibuf, len, ftp_sched, #ifdef KRB524 ftp_cred.session, #else /* KRB524 */ &ftp_cred.session, #endif /* KRB524 */ &hisctladdr, &myctladdr, &ftp_msg_data ); } if (kerror != KSUCCESS) { printf("%d reply %s! (krb_rd_%s: %s)\n", ftpcode, safe ? "modified" : "garbled", safe ? "safe" : "priv", krb_get_err_text(kerror)); n = '5'; } else if (ftp_msg_data.app_length >= FTP_BUFSIZ - 3) { kerror = KFAILURE; n = '5'; printf("reply data too large for buffer\n"); } else { if (ftp_deb) printf("%c:", safe ? 'S' : 'P'); memcpy(ibuf,ftp_msg_data.app_data, ftp_msg_data.app_length); ckstrncpy(&ibuf[ftp_msg_data.app_length], "\r\n", FTP_BUFSIZ - ftp_msg_data.app_length); continue; } } #endif /* FTP_KRB4 */ #ifdef FTP_GSSAPI else if (strcmp(auth_type, "GSSAPI") == 0) { gss_buffer_desc xmit_buf, msg_buf; OM_uint32 maj_stat, min_stat; int conf_state; xmit_buf.value = ibuf; xmit_buf.length = len; /* decrypt/verify the message */ conf_state = safe; maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf, &msg_buf, &conf_state, NULL); if (maj_stat != GSS_S_COMPLETE) { user_gss_error(maj_stat, min_stat, "failed unsealing reply"); n = '5'; } else { memcpy(ibuf, msg_buf.value, msg_buf.length); ckstrncpy(&ibuf[msg_buf.length], "\r\n", FTP_BUFSIZ-msg_buf.length); gss_release_buffer(&min_stat,&msg_buf); if (ftp_deb) printf("%c:", safe ? 'S' : 'P'); continue; } } #endif /* FTP_GSSAPI */ /* Other auth types go here... */ } } else if ((!dpyactive || ftp_deb) && ftp_cmdlin < 2 && !xquiet && (vbm || (!auth && (n == '4' || n == '5')))) { #ifdef NOCSETS printf("%c",c); #else if (xlate) { xlatec(0,c,rcs,lcs); } else { printf("%c",c); } #endif /* NOCSETS */ fflush (stdout); } if (continuation && ftpcode != originalcode) { if (originalcode == 0) originalcode = ftpcode; continue; } *cp = '\0'; if (n != '1') cpend = 0; signal(SIGINT,oldintr); if (ftpcode == 421 || originalcode == 421) { lostpeer(); if (!xquiet && !ftp_deb) printf("%s\n",reply_buf); } if ((cancelfile != 0) && #ifndef ULTRIX3 /* Ultrix 3.0 cc objects violently to this clause */ (oldintr != cmdcancel) && #endif /* ULTRIX3 */ (oldintr != SIG_IGN)) { if (oldintr) (*oldintr)(SIGINT); } if (reply_parse) { *reply_ptr = '\0'; if ((reply_ptr = ckstrstr(reply_buf, reply_parse))) { reply_parse = reply_ptr + strlen(reply_parse); if ((reply_ptr = ckstrpbrk(reply_parse, " \r"))) *reply_ptr = '\0'; } else reply_parse = reply_ptr; } while (*cp < '!' && cp > ftp_reply_str) /* Remove trailing junk */ *cp-- = NUL; debug(F111,"ftp getreply",ftp_reply_str,n - '0'); return(n - '0'); } /* for (;;) */ } #ifdef BSDSELECT static int #ifdef CK_ANSIC empty(fd_set * mask, int sec) #else empty(mask, sec) fd_set * mask; int sec; #endif /* CK_ANSIC */ { struct timeval t; t.tv_sec = (long) sec; t.tv_usec = 0L; debug(F100,"ftp empty calling select...","",0); #ifdef INTSELECT x = select(32, (int *)mask, NULL, NULL, &t); #else x = select(32, mask, (fd_set *) 0, (fd_set *) 0, &t); #endif /* INTSELECT */ debug(F101,"ftp empty select","",x); return(x); } #else /* BSDSELECT */ #ifdef IBMSELECT static int empty(mask, cnt, sec) int * mask, sec; int cnt; { return(select(mask,cnt,0,0,sec*1000)); } #endif /* IBMSELECT */ #endif /* BSDSELECT */ static sigtype #ifdef CK_ANSIC cancelsend( int sig ) #else cancelsend(sig) int sig; #endif /* CK_ANSIC */ { havesigint++; cancelgroup++; cancelfile = 0; printf(" Canceled...\n"); secure_getc(0,1); /* Initialize net input buffers */ debug(F100,"ftp cancelsend caught SIGINT ","",0); fflush(stdout); #ifndef OS2 longjmp(sendcancel, 1); #else PostCtrlCSem(); #endif /* OS2 */ } static VOID #ifdef CK_ANSIC secure_error(char *fmt, ...) #else /* VARARGS1 */ secure_error(fmt, p1, p2, p3, p4, p5) char *fmt; int p1, p2, p3, p4, p5; #endif /* CK_ANSIC */ { #ifdef CK_ANSIC va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); #else fprintf(stderr, fmt, p1, p2, p3, p4, p5); #endif fprintf(stderr, "\n"); } /* * Internal form of settype; changes current type in use with server * without changing our notion of the type for data transfers. * Used to change to and from ascii for listings. */ static VOID #ifdef CK_ANSIC changetype( int newtype, int show ) #else changetype(newtype, show) int newtype, show; #endif /* CK_ANSIC */ { int rc; char * s; if ((newtype == curtype) && typesent++) return; switch (newtype) { case FTT_ASC: s = "A"; break; case FTT_BIN: s = "I"; break; case FTT_TEN: s = "L 8"; break; default: s = "I"; break; } rc = ftpcmd("TYPE",s,-1,-1,show); if (rc == REPLY_COMPLETE) curtype = newtype; } /* PUT a file. Returns -1 on error, 0 on success, 1 if file skipped */ static VOID #ifdef CK_ANSIC doftpsend(void * threadinfo) #else doftpsend(threadinfo) VOID * threadinfo; #endif { #ifdef NTSIG if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); debug(F100, "doftpsend called with threadinfo block","", 0); } else debug(F100, "doftpsend - threadinfo is NULL", "", 0); #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef IKSD #ifdef NT if (inserver) setntcreds(); #endif /* NT */ #endif /* IKSD */ #endif /* CK_LOGIN */ if (initconn()) { #ifndef NOHTTP int y = -1; /* debug(F101,"doftpsend","tcp_http_proxy",tcp_http_proxy); */ /* If the connection failed and we are using an HTTP Proxy * and the reason for the failure was an authentication * error, then we need to give the user to ability to * enter a username and password, just like a browser. * * I tried to do all of this within the netopen() call * but it is much too much work. */ while (y != 0 && tcp_http_proxy != NULL ) { if (tcp_http_proxy_errno == 401 || tcp_http_proxy_errno == 407 ) { char uid[UIDBUFLEN]; char pwd[PWDSIZ]; struct txtbox tb[2]; int ok; tb[0].t_buf = uid; tb[0].t_len = UIDBUFLEN; tb[0].t_lbl = "Proxy Userid: "; tb[0].t_dflt = NULL; tb[0].t_echo = 1; tb[1].t_buf = pwd; tb[1].t_len = 256; tb[1].t_lbl = "Proxy Passphrase: "; tb[1].t_dflt = NULL; tb[1].t_echo = 2; ok = uq_mtxt("Proxy Server Authentication Required\n", NULL, 2, tb); if (ok && uid[0]) { char * proxy_user, * proxy_pwd; proxy_user = tcp_http_proxy_user; proxy_pwd = tcp_http_proxy_pwd; tcp_http_proxy_user = uid; tcp_http_proxy_pwd = pwd; y = initconn(); debug(F101,"doftpsend","initconn",y); memset(pwd,0,PWDSIZ); tcp_http_proxy_user = proxy_user; tcp_http_proxy_pwd = proxy_pwd; } else break; } else break; } if ( y != 0 ) { #endif /* NOHTTP */ signal(SIGINT, ftpsnd.oldintr); #ifdef SIGPIPE if (ftpsnd.oldintp) signal(SIGPIPE, ftpsnd.oldintp); #endif /* SIGPIPE */ ftpcode = -1; zclose(ZIFILE); ftpsndret = -1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; #ifndef NOHTTP } #endif /* NOHTTP */ } ftpsndret = 0; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ } static VOID #ifdef CK_ANSIC failftpsend(void * threadinfo) #else failftpsend(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ { #ifdef NTSIG if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); debug(F100, "docmdfile called with threadinfo block","", 0); } else debug(F100, "docmdfile - threadinfo is NULL", "", 0); #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef IKSD #ifdef NT if (inserver) setntcreds(); #endif /* NT */ #endif /* IKSD */ #endif /* CK_LOGIN */ while (cpend) { ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0); debug(F111,"ftp sendrequest getreply","null command",ftpsnd.reply); } if (data >= 0) { #ifdef CK_SSL if (ssl_ftp_data_active_flag) { SSL_shutdown(ssl_ftp_data_con); SSL_free(ssl_ftp_data_con); ssl_ftp_data_active_flag = 0; ssl_ftp_data_con = NULL; } #endif /* CK_SSL */ #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = -1; globaldin = -1; } if (ftpsnd.oldintr) signal(SIGINT,ftpsnd.oldintr); #ifdef SIGPIPE if (ftpsnd.oldintp) signal(SIGPIPE,ftpsnd.oldintp); #endif /* SIGPIPE */ ftpcode = -1; #ifndef OS2 /* TEST ME IN K95 */ if (havesigint) { havesigint = 0; debug(F100,"ftp failftpsend chain to trap()...","",0); if (ftpsnd.oldintr != SIG_IGN) (*ftpsnd.oldintr)(SIGINT); /* NOTREACHED (I hope!) */ debug(F100,"ftp failftpsend return from trap()...","",0); } #endif /* OS2 */ } static VOID #ifdef CK_ANSIC failftpsend2(void * threadinfo) #else failftpsend2(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ { #ifdef NTSIG if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); debug(F100, "docmdfile called with threadinfo block","", 0); } else debug(F100, "docmdfile - threadinfo is NULL", "", 0); #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef IKSD #ifdef NT if (inserver) setntcreds(); #endif /* NT */ #endif /* IKSD */ #endif /* CK_LOGIN */ debug(F101,"ftp sendrequest canceled","",ftpsnd.bytes); tfc += ffc; #ifdef GFTIMER fpfsecs = gftimer(); #endif /* GFTIMER */ zclose(ZIFILE); #ifdef PIPESEND if (sndfilter) pipesend = 0; #endif /* PIPESEND */ signal(SIGINT, ftpsnd.oldintr); #ifdef SIGPIPE if (ftpsnd.oldintp) signal(SIGPIPE, ftpsnd.oldintp); #endif /* SIGPIPE */ if (!cpend) { ftpcode = -1; ftpsndret = -1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } if (data >= 0) { #ifdef CK_SSL if (ssl_ftp_data_active_flag) { SSL_shutdown(ssl_ftp_data_con); SSL_free(ssl_ftp_data_con); ssl_ftp_data_active_flag = 0; ssl_ftp_data_con = NULL; } #endif /* CK_SSL */ #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = -1; globaldin = -1; } if (dout) { #ifdef TCPIPLIB socket_close(dout); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(dout, 1+1); #endif /* USE_SHUTDOWN */ close(dout); #endif /* TCPIPLIB */ } ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0); ftpcode = -1; ftpsndret = -1; #ifndef OS2 /* TEST ME IN K95 */ if (havesigint) { havesigint = 0; debug(F100,"ftp failftpsend2 chain to trap()...","",0); if (ftpsnd.oldintr != SIG_IGN) (*ftpsnd.oldintr)(SIGINT); /* NOTREACHED (I hope!) */ debug(F100,"ftp failftpsend2 return from trap()...","",0); } #endif /* OS2 */ } static VOID #ifdef CK_ANSIC doftpsend2(void * threadinfo) #else doftpsend2(threadinfo) VOID * threadinfo; #endif { register int c, d = 0; int n, x, notafile, unique = 0; char *buf, *bufp; #ifdef NTSIG if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); debug(F100, "doftpsend2 called with threadinfo block","", 0); } else debug(F100, "doftpsend2 - threadinfo is NULL", "", 0); #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef IKSD #ifdef NT if (inserver) setntcreds(); #endif /* NT */ #endif /* IKSD */ #endif /* CK_LOGIN */ buf = ftpsndbuf; /* (not on stack) */ unique = strcmp(ftpsnd.cmd,"STOU") ? 0 : 1; notafile = sndarray || pipesend; #ifdef FTP_RESTART if (ftpsnd.restart && ((curtype == FTT_BIN) || (alike > 0))) { char * p; changetype(FTT_BIN,0); /* Change to binary */ /* Ask for remote file's size */ x = ftpcmd("SIZE",ftpsnd.remote,ftpsnd.incs,ftpsnd.outcs,ftp_vbm); if (x == REPLY_COMPLETE) { /* Have ftpsnd.reply */ p = &ftp_reply_str[4]; /* Parse it */ while (isdigit(*p)) { sendstart = sendstart * 10 + (int)(*p - '0'); p++; } if (*p && *p != CK_CR) { /* Bad number */ debug(F110,"doftpsend2 bad size",ftp_reply_str,0); sendstart = (CK_OFF_T)0; } else if (sendstart > fsize) { /* Remote file bigger than local */ debug(F110,"doftpsend2 big size",ckfstoa(fsize),sendstart); sendstart = (CK_OFF_T)0; } /* Local is newer */ debug(F111,"doftpsend2 size",ftpsnd.remote,sendstart); if (chkmodtime(ftpsnd.local,ftpsnd.remote,0) == 2) { debug(F110,"doftpsend2 date mismatch",ftp_reply_str,0); sendstart = (CK_OFF_T)0; /* Send the whole file */ } } changetype(ftp_typ,0); /* Change back to appropriate type */ if (sendstart > (CK_OFF_T)0) { /* Still restarting? */ if (sendstart == fsize) { /* Same size - no need to send */ debug(F111,"doftpsend2 /restart SKIP", ckfstoa(fsize),sendstart); zclose(ZIFILE); ftpsndret = SKP_RES; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } errno = 0; /* Restart needed, seek to the spot */ if (zfseek((long)sendstart) < 0) { debug(F111,"doftpsend2 zfseek fails", ftpsnd.local,sendstart); fprintf(stderr, "FSEEK: %s: %s\n", ftpsnd.local, ck_errstr()); sendstart = 0; zclose(ZIFILE); ftpsndret = -1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } #ifdef COMMENT debug(F111,"doftpsend2 zfseek ok",ftpsnd.local,sendstart); x = ftpcmd("REST",ckltoa(sendstart),-1,-1,ftp_vbm); if (x != REPLY_CONTINUE) { sendstart = 0; zclose(ZIFILE); ftpsndret = -1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } else { ftpsnd.cmd = "STOR"; } #else sendmode = SM_RESEND; ftpsnd.cmd = "APPE"; #endif /* COMMENT */ /* sendstart = (CK_OFF_T)0; */ } } #endif /* FTP_RESTART */ if (unique && !stouarg) /* If we know STOU accepts no arg */ ftpsnd.remote = NULL; /* don't include one. */ x = ftpcmd(ftpsnd.cmd, ftpsnd.remote, ftpsnd.incs, ftpsnd.outcs, ftp_vbm); debug(F111,"doftpsend2 ftpcode",ftpsnd.cmd,ftpcode); debug(F101,"doftpsend2 ftpcmd","",x); if (x != REPLY_PRELIM && unique) { /* RFC959 says STOU does not take an argument. But every FTP server I've encountered but one accepts the arg and constructs the unique name from it, which is better than making up a totally random name for the file, which is what RFC959 calls for. Especially because there is no way for the client to find out the name chosen by the server. So we try STOU with the argument first, which works with most servers, and if it fails we retry it without the arg, for the benefit of the one picky server that is not "liberal in what it accepts" UNLESS the first STOU got a 502 code ("not implemented") which means STOU is not accepted, period. */ if ((x == 5) && stouarg && (ftpcode != 502)) { x = ftpcmd(ftpsnd.cmd,NULL,ftpsnd.incs,ftpsnd.outcs,ftp_vbm); if (x == REPLY_PRELIM) /* If accepted */ stouarg = 0; /* flag no STOU arg for this server */ } } if (x != REPLY_PRELIM) { signal(SIGINT, ftpsnd.oldintr); #ifdef SIGPIPE if (ftpsnd.oldintp) signal(SIGPIPE, ftpsnd.oldintp); #endif /* SIGPIPE */ debug(F101,"doftpsend2 not REPLY_PRELIM","",x); zclose(ZIFILE); #ifdef PIPESEND if (sndfilter) pipesend = 0; #endif /* PIPESEND */ ftpsndret = -1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } debug(F100,"doftpsend2 getting data connection...","",0); dout = dataconn(ftpsnd.lmode); /* Get data connection */ debug(F101,"doftpsend2 dataconn","",dout); if (dout == -1) { failftpsend2(threadinfo); #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } /* Initialize per-file stats */ ffc = (CK_OFF_T)0; /* Character counter */ cps = oldcps = 0L; /* Thruput */ n = 0; #ifdef GFTIMER rftimer(); /* reset f.p. timer */ #endif /* GFTIMER */ #ifdef SIGPIPE ftpsnd.oldintp = signal(SIGPIPE, SIG_IGN); #endif /* SIGPIPE */ debug(F101,"doftpsend2 curtype","",curtype); switch (curtype) { case FTT_BIN: /* Binary mode */ case FTT_TEN: errno = d = 0; #ifdef VMS /* This is because VMS zxin() is C-Library fread() but the file was opened with zopeni(), which is RMS. */ while (((c = zminchar()) > -1) && !cancelfile) { ffc++; if (zzout(dout,c) < 0) break; } #else /* VMS */ while ((n = zxin(ZIFILE,buf,FTP_BUFSIZ - 1)) > 0 && !cancelfile) { ftpsnd.bytes += n; ffc += n; debug(F111,"doftpsend2 zxin",ckltoa(n),ffc); ckhexdump("doftpsend2 zxin",buf,16); #ifdef CK_SSL if (ssl_ftp_data_active_flag) { for (bufp = buf; n > 0; n -= d, bufp += d) { if ((d = SSL_write(ssl_ftp_data_con, bufp, n)) <= 0) break; spackets++; pktnum++; if (fdispla != XYFD_B) { spktl = d; ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL); } } } else { #endif /* CK_SSL */ for (bufp = buf; n > 0; n -= d, bufp += d) { if (((d = secure_write(dout, (CHAR *)bufp, n)) <= 0) || iscanceled()) break; spackets++; pktnum++; if (fdispla != XYFD_B) { spktl = d; ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL); } } #ifdef CK_SSL } #endif /* CK_SSL */ if (d <= 0) break; } #endif /* VMS */ debug(F111,"doftpsend2 XX zxin",ckltoa(n),ffc); if (n < 0) fprintf(stderr, "local: %s: %s\n", ftpsnd.local, ck_errstr()); if (d < 0 || (d = secure_flush(dout)) < 0) { if (d == -1 && errno && errno != EPIPE) perror("netout"); ftpsnd.bytes = -1; } break; case FTT_ASC: /* Text mode */ #ifndef NOCSETS if (ftpsnd.xlate) { /* With translation */ initxlate(ftpsnd.incs,ftpsnd.outcs); while (!cancelfile) { if ((c0 = xgnbyte(FC_UCS2,ftpsnd.incs,NULL)) < 0) break; if ((x = xpnbyte(c0,TC_UCS2,ftpsnd.outcs,xxout)) < 0) break; } } else { #endif /* NOCSETS */ /* Text mode, no translation */ while (((c = zminchar()) > -1) && !cancelfile) { ffc++; if (xxout(c) < 0) break; } d = 0; #ifndef NOCSETS } #endif /* NOCSETS */ if (dout == -1 || (d = secure_flush(dout)) < 0) { if (d == -1 && errno && errno != EPIPE) perror("netout"); ftpsnd.bytes = -1; } break; } tfc += ffc; /* Total file chars */ #ifdef GFTIMER fpfsecs = gftimer(); #endif /* GFTIMER */ zclose(ZIFILE); /* Close input file */ #ifdef PIPESEND if (sndfilter) /* Undo this (it's per file) */ pipesend = 0; #endif /* PIPESEND */ #ifdef CK_SSL if (ssl_ftp_data_active_flag) { SSL_shutdown(ssl_ftp_data_con); SSL_free(ssl_ftp_data_con); ssl_ftp_data_active_flag = 0; ssl_ftp_data_con = NULL; } #endif /* CK_SSL */ #ifdef TCPIPLIB socket_close(dout); /* Close data connection */ #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(dout, 1+1); #endif /* USE_SHUTDOWN */ close(dout); #endif /* TCPIPLIB */ ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0); signal(SIGINT, ftpsnd.oldintr); /* Put back interrupts */ #ifdef SIGPIPE if (ftpsnd.oldintp) signal(SIGPIPE, ftpsnd.oldintp); #endif /* SIGPIPE */ if (ftpsnd.reply == REPLY_TRANSIENT || ftpsnd.reply == REPLY_ERROR) { debug(F101,"doftpsend2 ftpsnd.reply","",ftpsnd.reply); ftpsndret = -1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } else if (cancelfile) { debug(F101,"doftpsend2 canceled","",ftpsnd.bytes); ftpsndret = -1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } debug(F101,"doftpsend2 ok","",ftpsnd.bytes); ftpsndret = 0; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ } static int #ifdef CK_ANSIC sendrequest( char *cmd, char *local, char *remote, int xlate, int incs, int outcs, int restart ) #else sendrequest( cmd, local, remote, xlate, incs, outcs, restart ) char *cmd, *local, *remote; int xlate, incs, outcs, restart; #endif /* CK_ANSIC */ { if (!remote) remote = ""; /* Check args */ if (!*remote) remote = local; if (!local) local = ""; if (!*local) return(-1); if (!cmd) cmd = ""; if (!*cmd) cmd = "STOR"; debug(F111,"ftp sendrequest restart",local,restart); nout = 0; /* Init output buffer count */ ftpsnd.bytes = 0; /* File input byte count */ dout = -1; #ifdef FTP_PROXY if (proxy) { proxtrans(cmd, local, remote, !strcmp(cmd,"STOU")); return(0); } #endif /* FTP_PROXY */ changetype(ftp_typ,0); /* Change type for this file */ ftpsnd.oldintr = NULL; /* Set up interrupt handler */ ftpsnd.oldintp = NULL; ftpsnd.restart = restart; ftpsnd.xlate = xlate; ftpsnd.lmode = "wb"; #ifdef PIPESEND /* Use Kermit API for file i/o... */ if (sndfilter) { char * p = NULL, * q; #ifndef NOSPL int n = CKMAXPATH; if (cmd_quoting && (p = (char *) malloc(n + 1))) { q = p; debug(F110,"sendrequest pipesend filter",sndfilter,0); zzstring(sndfilter,&p,&n); debug(F111,"sendrequest pipename",q,n); if (n <= 0) { printf("?Sorry, send filter + filename too long, %d max.\n", CKMAXPATH ); free(q); return(-1); } ckstrncpy(filnam,q,CKMAXPATH+1); free(q); local = filnam; } #endif /* NOSPL */ } if (sndfilter) /* If sending thru a filter */ pipesend = 1; /* set this for open and i/o */ #endif /* PIPESEND */ #ifdef VMS debug(F101,"XXX before openi binary","",binary); debug(F101,"XXX before openi ftp_typ","",ftp_typ); #endif /* VMS */ if (openi(local) == 0) /* Try to open the input file */ return(-1); #ifdef VMS debug(F101,"XXX after openi binary","",binary); debug(F101,"XXX after openi ftp_typ","",ftp_typ); if (!forcetype) { if (binary != ftp_typ) { /* VMS zopeni() sets binary */ debug(F101,"XXX changing type","",binary); doftptyp(binary); debug(F101,"XXX after doftptyp","",ftp_typ); /* **** */ if (displa && fdispla) { /* Update file type display */ ftscreen(SCR_FN,'F',(CK_OFF_T)0,local); } } } #endif /* VMS */ ftpsndret = 0; ftpsnd.incs = incs; ftpsnd.outcs = outcs; ftpsnd.cmd = cmd; ftpsnd.local = local; ftpsnd.remote = remote; ftpsnd.oldintr = signal(SIGINT, cancelsend); havesigint = 0; if (cc_execute(ckjaddr(sendcancel), doftpsend, failftpsend) < 0) return(-1); if (ftpsndret < 0) return(-1); if (cc_execute(ckjaddr(sendcancel), doftpsend2, failftpsend2) < 0) return(-1); return(ftpsndret); } static sigtype #ifdef CK_ANSIC cancelrecv( int sig ) #else cancelrecv(sig) int sig; #endif /* CK_ANSIC */ { havesigint++; cancelfile = 0; cancelgroup++; secure_getc(0,1); /* Initialize net input buffers */ printf(" Canceling...\n"); debug(F100,"ftp cancelrecv caught SIGINT","",0); fflush(stdout); if (fp_nml) { if (fp_nml != stdout) fclose(fp_nml); fp_nml = NULL; } #ifndef OS2 longjmp(recvcancel, 1); #else PostCtrlCSem(); #endif /* OS2 */ } /* Argumentless front-end for secure_getc() */ static int #ifdef CK_ANSIC netgetc(void) /* Input function to point to... */ #else /* CK_ANSIC */ netgetc() #endif /* CK_ANSIC */ { return(secure_getc(globaldin,0)); } /* Returns -1 on failure, 0 on success, 1 if file skipped */ /* Sets ftpcode < 0 on failure if failure reason is not server reply code: -1: interrupted by user. -2: error opening or writing output file (reason in errno). -3: failure to make data connection. -4: network read error (reason in errno). */ struct xx_ftprecv { int reply; int fcs; int rcs; int recover; int xlate; int din; int is_retr; sig_t oldintr, oldintp; char * cmd; char * local; char * remote; char * lmode; char * pipename; int tcrflag; CK_OFF_T localsize; }; static struct xx_ftprecv ftprecv; static int ftprecvret = 0; static VOID #ifdef CK_ANSIC failftprecv(VOID * threadinfo) #else failftprecv(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ { #ifdef NTSIG if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); debug(F100, "docmdfile called with threadinfo block","", 0); } else debug(F100, "docmdfile - threadinfo is NULL", "", 0); #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef IKSD #ifdef NT if (inserver) setntcreds(); #endif /* NT */ #endif /* IKSD */ #endif /* CK_LOGIN */ while (cpend) { ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0); } if (data >= 0) { #ifdef CK_SSL if (ssl_ftp_data_active_flag) { SSL_shutdown(ssl_ftp_data_con); SSL_free(ssl_ftp_data_con); ssl_ftp_data_active_flag = 0; ssl_ftp_data_con = NULL; } #endif /* CK_SSL */ #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = -1; globaldin = -1; } if (ftprecv.oldintr) signal(SIGINT, ftprecv.oldintr); ftpcode = -1; ftprecvret = -1; #ifndef OS2 /* TEST ME IN K95 */ if (havesigint) { havesigint = 0; debug(F100,"ftp failftprecv chain to trap()...","",0); if (ftprecv.oldintr != SIG_IGN) (*ftprecv.oldintr)(SIGINT); /* NOTREACHED (I hope!) */ debug(F100,"ftp failftprecv return from trap()...","",0); } #endif /* OS2 */ return; } static VOID #ifdef CK_ANSIC doftprecv(VOID * threadinfo) #else doftprecv(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ { #ifdef NTSIG if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); debug(F100, "docmdfile called with threadinfo block","", 0); } else debug(F100, "docmdfile - threadinfo is NULL", "", 0); #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef IKSD #ifdef NT if (inserver) setntcreds(); #endif /* NT */ #endif /* IKSD */ #endif /* CK_LOGIN */ #ifndef COMMENT if (!out2screen && !ftprecv.pipename) { int x; char * local; local = ftprecv.local; x = zchko(local); if (x < 0) { if ((!dpyactive || ftp_deb)) fprintf(stderr, "Temporary file %s: %s\n", ftprecv.local, ck_errstr()); signal(SIGINT, ftprecv.oldintr); ftpcode = -2; ftprecvret = -1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } } #endif /* COMMENT */ changetype((!ftprecv.is_retr) ? FTT_ASC : ftp_typ, 0); if (initconn()) { /* Initialize the data connection */ signal(SIGINT, ftprecv.oldintr); ftpcode = -1; ftprecvret = -3; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } secure_getc(0,1); /* Initialize net input buffers */ ftprecvret = 0; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ } static VOID #ifdef CK_ANSIC failftprecv2(VOID * threadinfo) #else failftprecv2(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ { #ifdef NTSIG if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); debug(F100, "docmdfile called with threadinfo block","", 0); } else debug(F100, "docmdfile - threadinfo is NULL", "", 0); #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef IKSD #ifdef NT if (inserver) setntcreds(); #endif /* NT */ #endif /* IKSD */ #endif /* CK_LOGIN */ /* Cancel using RFC959 recommended IP,SYNC sequence */ debug(F100,"ftp recvrequest CANCEL","",0); #ifdef GFTIMER fpfsecs = gftimer(); #endif /* GFTIMER */ #ifdef SIGPIPE if (ftprecv.oldintp) signal(SIGPIPE, ftprecv.oldintr); #endif /* SIGPIPE */ signal(SIGINT, SIG_IGN); if (!cpend) { ftpcode = -1; signal(SIGINT, ftprecv.oldintr); ftprecvret = -1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } cancel_remote(ftprecv.din); #ifdef FTP_TIMEOUT if (ftp_timed_out && out2screen && !quiet) printf("\n?Timed out.\n"); #endif /* FTP_TIMEOUT */ if (ftpcode > -1) ftpcode = -1; if (data >= 0) { #ifdef CK_SSL if (ssl_ftp_data_active_flag) { SSL_shutdown(ssl_ftp_data_con); SSL_free(ssl_ftp_data_con); ssl_ftp_data_active_flag = 0; ssl_ftp_data_con = NULL; } #endif /* CK_SSL */ #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = -1; globaldin = -1; } if (!out2screen) { int x = 0; debug(F111,"ftp failrecv2 zclose",ftprecv.local,keep); zclose(ZOFILE); switch (keep) { /* which is... */ case SET_AUTO: /* AUTO */ if (curtype == FTT_ASC) /* Delete file if TYPE A. */ x = 1; break; case SET_OFF: /* DISCARD */ x = 1; /* Delete file, period. */ break; default: /* KEEP */ break; } if (x) { x = zdelet(ftprecv.local); debug(F111,"ftp failrecv2 delete incomplete",ftprecv.local,x); } } if (ftprecv.din) { #ifdef TCPIPLIB socket_close(ftprecv.din); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(ftprecv.din, 1+1); #endif /* USE_SHUTDOWN */ close(ftprecv.din); #endif /* TCPIPLIB */ } signal(SIGINT, ftprecv.oldintr); ftprecvret = -1; if (havesigint) { havesigint = 0; debug(F100,"FTP failftprecv2 chain to trap()...","",0); #ifdef OS2 debug(F100,"FTP failftprecv2 PostCtrlCSem()...","",0); PostCtrlCSem(); #else /* OS2 */ if (ftprecv.oldintr != SIG_IGN) (*ftprecv.oldintr)(SIGINT); /* NOTREACHED (I hope!) */ debug(F100,"ftp failftprecv2 return from trap()...","",0); #endif /* OS2 */ } } static VOID #ifdef CK_ANSIC doftprecv2(VOID * threadinfo) #else doftprecv2(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ { register int c, d; CK_OFF_T bytes = (CK_OFF_T)0; int bare_lfs = 0; int blksize = 0; ULONG start = 0L, stop; static char * rcvbuf = NULL; static int rcvbufsiz = 0; #ifdef CK_URL char newname[CKMAXPATH+1]; /* For file dialog */ #endif /* CK_URL */ extern int adl_ask; #ifdef FTP_TIMEOUT ftp_timed_out = 0; #endif /* FTP_TIMEOUT */ ftprecv.din = -1; #ifdef NTSIG if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); debug(F100, "docmdfile called with threadinfo block","", 0); } else debug(F100, "docmdfile - threadinfo is NULL", "", 0); #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef IKSD #ifdef NT if (inserver) setntcreds(); #endif /* NT */ #endif /* IKSD */ #endif /* CK_LOGIN */ if (ftprecv.recover) { /* Initiate recovery */ x = ftpcmd("REST",ckfstoa(ftprecv.localsize),-1,-1,ftp_vbm); debug(F111,"ftp reply","REST",x); if (x == REPLY_CONTINUE) { ftprecv.lmode = "ab"; rs_len = ftprecv.localsize; } else { ftprecv.recover = 0; } } /* IMPORTANT: No FTP commands can come between REST and RETR! */ debug(F111,"ftp recvrequest recover E",ftprecv.remote,ftprecv.recover); /* Send the command and get reply */ debug(F110,"ftp recvrequest cmd",ftprecv.cmd,0); debug(F110,"ftp recvrequest remote",ftprecv.remote,0); if (ftpcmd(ftprecv.cmd,ftprecv.remote,ftprecv.fcs,ftprecv.rcs,ftp_vbm) != REPLY_PRELIM) { signal(SIGINT, ftprecv.oldintr); /* Bad reply, fail. */ ftprecvret = -1; /* ftpcode is set by ftpcmd() */ #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } ftprecv.din = dataconn("r"); /* Good reply, open data connection */ globaldin = ftprecv.din; /* Global copy of file descriptor */ if (ftprecv.din == -1) { /* Check for failure */ ftpcode = -3; /* Code for no data connection */ ftprecvret = -1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } #ifdef CK_URL /* In K95 GUI put up a file box */ if (haveurl && g_url.pth && adl_ask ) { /* Downloading from a URL */ int x; char * preface = "\r\nIncoming file from FTP server...\r\n\ Please confirm output file specification or supply an alternative:"; x = uq_file(preface, /* K95 GUI: Put up file box. */ NULL, 4, NULL, ftprecv.local ? ftprecv.local : ftprecv.remote, newname, CKMAXPATH+1 ); if (x > 0) { ftprecv.local = newname; /* Substitute user's file name */ if (x == 2) /* And append if user said to */ ftprecv.lmode = "ab"; } } #endif /* CK_URL */ x = 1; /* Output file open OK? */ if (ftprecv.pipename) { /* Command */ x = zxcmd(ZOFILE,ftprecv.pipename); debug(F111,"ftp recvrequest zxcmd",ftprecv.pipename,x); } else if (!out2screen) { /* File */ struct filinfo xx; xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0; xx.typ = 0; xx.os_specific = ""; xx.lblopts = 0; /* Append or New */ xx.dsp = !strcmp(ftprecv.lmode,"ab") ? XYFZ_A : XYFZ_N; x = zopeno(ZOFILE,ftprecv.local,NULL,&xx); debug(F111,"ftp recvrequest zopeno",ftprecv.local,x); } if (x < 1) { /* Failure to open output file */ if ((!dpyactive || ftp_deb)) fprintf(stderr, "local(2): %s: %s\n", ftprecv.local, ck_errstr()); ftprecvret = -1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } blksize = FTP_BUFSIZ; /* Allocate input buffer */ debug(F101,"ftp recvrequest blksize","",blksize); debug(F101,"ftp recvrequest rcvbufsiz","",rcvbufsiz); if (rcvbufsiz < blksize) { /* if necessary */ if (rcvbuf) { free(rcvbuf); rcvbuf = NULL; } rcvbuf = (char *)malloc((unsigned)blksize); if (!rcvbuf) { debug(F100,"ftp get rcvbuf malloc failed","",0); ftpcode = -2; #ifdef ENOMEM errno = ENOMEM; #endif /* ENOMEM */ if ((!dpyactive || ftp_deb)) perror("malloc"); rcvbufsiz = 0; ftprecvret = -1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } debug(F101,"ftp get rcvbuf malloc ok","",blksize); rcvbufsiz = blksize; } debug(F111,"ftp get rcvbufsiz",ftprecv.local,rcvbufsiz); ffc = (CK_OFF_T)0; /* Character counter */ cps = oldcps = 0L; /* Thruput */ start = gmstimer(); /* Start time (msecs) */ #ifdef GFTIMER rftimer(); /* Start time (float) */ #endif /* GFTIMER */ debug(F111,"ftp get type",ftprecv.local,curtype); debug(F101,"ftp recvrequest ftp_dpl","",ftp_dpl); switch (curtype) { case FTT_BIN: /* Binary mode */ case FTT_TEN: /* TENEX mode */ d = 0; while (1) { errno = 0; c = secure_read(ftprecv.din, rcvbuf, rcvbufsiz); if (cancelfile) { failftprecv2(threadinfo); #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } if (c < 1) break; #ifdef printf /* (What if it isn't?) */ if (out2screen && !ftprecv.pipename) { int i; for (i = 0; i < c; i++) printf("%c",rcvbuf[i]); } else #endif /* printf */ { register int i; i = 0; errno = 0; while (i < c) { if (zmchout(rcvbuf[i++]) < 0) { d = i; break; } } } bytes += c; ffc += c; } #ifdef FTP_TIMEOUT if (c == -3) { debug(F100,"ftp recvrequest timeout","",0); bytes = (CK_OFF_T)-1; ftp_timed_out = 1; ftpcode = -3; } else #endif /* FTP_TIMEOUT */ if (c < 0) { debug(F111,"ftp recvrequest errno",ckitoa(c),errno); if (c == -1 && errno != EPIPE) if ((!dpyactive || ftp_deb)) perror("netin"); bytes = (CK_OFF_T)-1; ftpcode = -4; } if (d < c) { ftpcode = -2; if ((!dpyactive || ftp_deb)) { char * p; p = ftprecv.local ? ftprecv.local : ftprecv.pipename; if (d < 0) fprintf(stderr, "local(3): %s: %s\n", ftprecv.local, ck_errstr()); else fprintf(stderr, "%s: short write\n", ftprecv.local); } } break; case FTT_ASC: /* Text mode */ debug(F101,"ftp recvrequest TYPE A xlate","",ftprecv.xlate); #ifndef NOCSETS if (ftprecv.xlate) { #ifdef CK_ANSIC int (*fn)(char); #else int (*fn)(); #endif /* CK_ANSIC */ debug(F110,"ftp recvrequest (data)","initxlate",0); initxlate(ftprecv.rcs,ftprecv.fcs); /* (From,To) */ if (ftprecv.pipename) { fn = pipeout; debug(F110,"ftp recvrequest ASCII","pipeout",0); } else { fn = out2screen ? scrnout : putfil; debug(F110,"ftp recvrequest ASCII", out2screen ? "scrnout" : "putfil",0); } while (1) { /* Get byte from net */ c0 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc); if (cancelfile) { failftprecv2(threadinfo); #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } if (c0 < 0) break; /* Second byte from net */ c1 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc); if (cancelfile) { failftprecv2(threadinfo); #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } if (c1 < 0) break; #ifdef COMMENT /* K95: Check whether we need this */ if (fileorder > 0) /* Little Endian */ bytswap(&c0,&c1); /* swap bytes*/ #endif /* COMMENT */ #ifdef OS2 if ( out2screen && /* we're translating to UCS-2 */ !k95stdout && !inserver) /* for the real screen... */ { union { USHORT ucs2; UCHAR bytes[2]; } output; output.bytes[0] = c1; output.bytes[1] = c0; VscrnWrtUCS2StrAtt(VCMD, &output.ucs2, 1, wherey[VCMD], wherex[VCMD], &colorcmd ); } else #endif /* OS2 */ { if ((x = xpnbyte(c0,TC_UCS2,ftprecv.fcs,fn)) < 0) break; if ((x = xpnbyte(c1,TC_UCS2,ftprecv.fcs,fn)) < 0) break; } } } else { #endif /* NOCSETS */ while (1) { c = secure_getc(ftprecv.din,0); if (cancelfile #ifdef FTP_TIMEOUT || ftp_timed_out #endif /* FTP_TIMEOUT */ ) { failftprecv2(threadinfo); #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } if (c < 0 || c == EOF) break; #ifdef UNIX /* Record format conversion for Unix */ /* SKIP THIS FOR WINDOWS! */ if (c == '\n') bare_lfs++; while (c == '\r') { bytes++; if ((c = secure_getc(ftprecv.din,0)) != '\n' || ftprecv.tcrflag) { if (cancelfile) { failftprecv2(threadinfo); #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } if (c < 0 || c == EOF) break; if (c == '\0') { bytes++; break; } } } if (c < 0 || c == EOF) break; if (c == '\0') continue; #endif /* UNX */ if (out2screen && !ftprecv.pipename) #ifdef printf printf("%c",(char)c); #else putchar((char)c); #endif /* printf */ else if ((d = zmchout(c)) < 0) break; bytes++; ffc++; } if (bare_lfs && (!dpyactive || ftp_deb)) { printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs); printf("File might not have transferred correctly.\n"); } if (ftprecv.din == -1) { bytes = (CK_OFF_T)-1; } if (c == -2) bytes = (CK_OFF_T)-1; break; #ifndef NOCSETS } #endif /* NOCSETS */ } if (ftprecv.pipename || !out2screen) { zclose(ZOFILE); /* Close the file */ debug(F111,"doftprecv2 zclose ftpcode",ftprecv.local,ftpcode); if (ftpcode < 0) { /* If download failed */ int x = 0; switch (keep) { /* which is... */ case SET_AUTO: /* AUTO */ if (curtype == FTT_ASC) /* Delete file if TYPE A. */ x = 1; break; case SET_OFF: /* DISCARD */ x = 1; /* Delete file, period. */ break; default: /* KEEP */ break; } if (x) { x = zdelet(ftprecv.local); debug(F111,"ftp get delete incomplete",ftprecv.local,x); } } } signal(SIGINT, ftprecv.oldintr); #ifdef SIGPIPE if (ftprecv.oldintp) signal(SIGPIPE, ftprecv.oldintp); #endif /* SIGPIPE */ stop = gmstimer(); #ifdef GFTIMER fpfsecs = gftimer(); #endif /* GFTIMER */ tfc += ffc; #ifdef TCPIPLIB socket_close(ftprecv.din); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(ftprecv.din, 1+1); #endif /* USE_SHUTDOWN */ close(ftprecv.din); #endif /* TCPIPLIB */ ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0); ftprecvret = ((ftpcode < 0 || ftprecv.reply == REPLY_TRANSIENT || ftprecv.reply == REPLY_ERROR) ? -1 : 0); #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ } static int #ifdef CK_ANSIC recvrequest( char * cmd, char * local, char * remote, char * lmode, int printnames, int recover, char * pipename, int xlate, int fcs, int rcs) #else recvrequest(cmd,local,remote,lmode,printnames,recover,pipename,xlate,fcs,rcs) char *cmd, *local, *remote, *lmode, *pipename; int printnames, recover, xlate, fcs, rcs; #endif /* CK_ANSIC */ { #ifdef NT struct _stat stbuf; #else /* NT */ struct stat stbuf; #endif /* NT */ #ifdef DEBUG if (deblog) { debug(F111,"ftp recvrequest cmd",cmd,recover); debug(F110,"ftp recvrequest local ",local,0); debug(F111,"ftp recvrequest remote",remote,ftp_typ); debug(F110,"ftp recvrequest pipename ",pipename,0); debug(F101,"ftp recvrequest xlate","",xlate); debug(F101,"ftp recvrequest fcs","",fcs); debug(F101,"ftp recvrequest rcs","",rcs); } #endif /* DEBUG */ ftprecv.localsize = (CK_OFF_T)0; if (remfile) { /* See remcfm(), remtxt() */ if (rempipe) { pipename = remdest; } else { local = remdest; if (remappd) lmode = "ab"; } } out2screen = 0; if (!cmd) cmd = ""; /* Core dump prevention */ if (!remote) remote = ""; if (!lmode) lmode = ""; if (pipename) { /* No recovery for pipes. */ recover = 0; if (!local) local = pipename; } else { if (!local) /* Output to screen? */ local = "-"; out2screen = !strcmp(local,"-"); } debug(F101,"ftp recvrequest out2screen","",out2screen); #ifdef OS2 if ( ftp_xla && out2screen && !k95stdout && !inserver ) fcs = FC_UCS2; #endif /* OS2 */ if (out2screen) /* No recovery to screen */ recover = 0; if (!ftp_typ) /* No recovery in text mode */ recover = 0; ftprecv.is_retr = (strcmp(cmd, "RETR") == 0); if (!ftprecv.is_retr) /* No recovery except for RETRieve */ recover = 0; #ifdef COMMENT if (!out2screen && !pipename && ftprecv.is_retr) { /* To real file */ if (recursive && ckstrchr(local,'/')) { } } #endif /* COMMENT */ ftprecv.localsize = (CK_OFF_T)0; /* Local file size */ rs_len = (CK_OFF_T)0; /* Recovery point */ debug(F101,"ftp recvrequest recover","",recover); if (recover) { /* Recovering... */ if (stat(local, &stbuf) < 0) { /* Can't stat local file */ debug(F101,"ftp recvrequest recover stat failed","",errno); recover = 0; /* So cancel recovery */ } else { /* Have local file info */ ftprecv.localsize = stbuf.st_size; /* Get size */ /* Remote file smaller than local */ if (fsize < ftprecv.localsize) { debug(F101,"ftp recvrequest recover remote smaller","",fsize); recover = 0; /* Recovery can't work */ } else if (fsize == ftprecv.localsize) { /* Sizes are equal */ debug(F111,"ftp recvrequest recover equal size", remote,ftprecv.localsize); return(1); } #ifdef COMMENT /* The problem here is that the original partial file never got its date set, either because FTP DATES was OFF, or because the partial file was downloaded by some other program that doesn't set local file dates, or because Kermit only sets the file's date when the download was complete and successful. In all these cases, the local file has a later time than the remote. */ if (recover) { /* Remote is bigger */ x = chkmodtime(local,remote,0); /* Check file dates */ debug(F111,"ftp recvrequest chkmodtime",remote,x); if (x != 1) /* Dates must be equal! */ recover = 0; /* If not, get whole file */ } #endif /* COMMENT */ } debug(F111,"ftp recvrequest recover",remote,recover); } #ifdef FTP_PROXY if (proxy && ftprecv.is_retr) return(proxtrans(cmd, local ? local : remote, remote)); #endif /* FTP_PROXY */ ftprecv.tcrflag = (feol != CK_CR) && ftprecv.is_retr; ftprecv.reply = 0; ftprecv.fcs = fcs; ftprecv.rcs = rcs; ftprecv.recover = recover; ftprecv.xlate = xlate; ftprecv.cmd = cmd; ftprecv.local = local; ftprecv.remote = remote; ftprecv.lmode = lmode; ftprecv.pipename = pipename; ftprecv.oldintp = NULL; ftpcode = 0; havesigint = 0; ftprecv.oldintr = signal(SIGINT, cancelrecv); if (cc_execute(ckjaddr(recvcancel), doftprecv, failftprecv) < 0) return -1; #ifdef FTP_TIMEOUT debug(F111,"ftp recvrequest ftprecvret",remote,ftprecvret); debug(F111,"ftp recvrequest ftp_timed_out",remote,ftp_timed_out); if (ftp_timed_out) ftprecvret = -1; #endif /* FTP_TIMEOUT */ if (ftprecvret < 0) return -1; if (cc_execute(ckjaddr(recvcancel), doftprecv2, failftprecv2) < 0) return -1; return ftprecvret; } /* * Need to start a listen on the data channel before we send the command, * otherwise the server's connect may fail. */ static int initconn() { register char *p, *a; int result, tmpno = 0; int on = 1; GSOCKNAME_T len; #ifndef NO_PASSIVE_MODE int a1,a2,a3,a4,p1,p2; if (passivemode) { data = socket(AF_INET, SOCK_STREAM, 0); globaldin = data; if (data < 0) { perror("ftp: socket"); return(-1); } if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) { printf("Passive mode refused\n"); passivemode = 0; return(initconn()); } /* Now we have a string of comma-separated one-byte unsigned integer values, The first four are the an IP address. The fifth is the MSB of the port number, the sixth is the LSB. From that we can make a sockaddr_in. */ if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2) != 6) { printf("Passive mode address scan failure\n"); return(-1); }; #ifndef NOHTTP if (tcp_http_proxy) { #ifdef OS2 char * agent = "Kermit 95"; /* Default user agent */ #else char * agent = "C-Kermit"; #endif /* OS2 */ register struct hostent *hp = 0; struct servent *destsp; char host[512], *p, *q; #ifdef IP_TOS #ifdef IPTOS_THROUGHPUT int tos; #endif /* IPTOS_THROUGHPUT */ #endif /* IP_TOS */ #ifdef DEBUG extern int debtim; int xdebtim; xdebtim = debtim; debtim = 1; #endif /* DEBUG */ ckmakxmsg(proxyhost,HTTPCPYL,ckuitoa(a1),".",ckuitoa(a2), ".",ckuitoa(a3),".",ckuitoa(a4),":",ckuitoa((p1<<8)|p2), NULL,NULL,NULL ); memset((char *)&hisctladdr, 0, sizeof (hisctladdr)); for (p = tcp_http_proxy, q=host; *p != '\0' && *p != ':'; p++, q++) *q = *p; *q = '\0'; hisctladdr.sin_addr.s_addr = inet_addr(host); if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */ { debug(F110,"initconn A",host,0); hisctladdr.sin_family = AF_INET; } else { debug(F110,"initconn B",host,0); hp = gethostbyname(host); #ifdef HADDRLIST hp = ck_copyhostent(hp); /* make safe copy that won't change */ #endif /* HADDRLIST */ if (hp == NULL) { fprintf(stderr, "ftp: %s: Unknown host\n", host); ftpcode = -1; #ifdef DEBUG debtim = xdebtim; #endif /* DEBUG */ return(0); } hisctladdr.sin_family = hp->h_addrtype; #ifdef HADDRLIST memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0], sizeof(hisctladdr.sin_addr)); #else /* HADDRLIST */ memcpy((char *)&hisctladdr.sin_addr, hp->h_addr, sizeof(hisctladdr.sin_addr)); #endif /* HADDRLIST */ } data = socket(hisctladdr.sin_family, SOCK_STREAM, 0); debug(F101,"initconn socket","",data); if (data < 0) { perror("ftp: socket"); ftpcode = -1; #ifdef DEBUG debtim = xdebtim; #endif /* DEBUG */ return(0); } if (*p == ':') p++; else p = "http"; destsp = getservbyname(p,"tcp"); if (destsp) hisctladdr.sin_port = destsp->s_port; else if (p) hisctladdr.sin_port = htons(atoi(p)); else hisctladdr.sin_port = htons(80); errno = 0; #ifdef HADDRLIST debug(F100,"initconn HADDRLIST","",0); while #else debug(F100,"initconn no HADDRLIST","",0); if #endif /* HADDRLIST */ (connect(data, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) { debug(F101,"initconn connect failed","",errno); #ifdef HADDRLIST if (hp && hp->h_addr_list[1]) { int oerrno = errno; fprintf(stderr, "ftp: connect to address %s: ", inet_ntoa(hisctladdr.sin_addr) ); errno = oerrno; perror("ftphookup"); hp->h_addr_list++; memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0], sizeof(hisctladdr.sin_addr)); fprintf(stdout, "Trying %s...\n", inet_ntoa(hisctladdr.sin_addr)); #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ close(data); #endif /* TCPIPLIB */ data = socket(hisctladdr.sin_family, SOCK_STREAM, 0); if (data < 0) { perror("ftp: socket"); ftpcode = -1; #ifdef DEBUG debtim = xdebtim; #endif /* DEBUG */ return(0); } continue; } #endif /* HADDRLIST */ perror("ftp: connect"); ftpcode = -1; goto bad; } if (http_connect(data, tcp_http_proxy_agent ? tcp_http_proxy_agent : agent, NULL, tcp_http_proxy_user, tcp_http_proxy_pwd, 0, proxyhost ) < 0) { #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ close(data); #endif /* TCPIPLIB */ perror("ftp: connect"); ftpcode = -1; goto bad; } } else #endif /* NOHTTP */ { data_addr.sin_family = AF_INET; data_addr.sin_addr.s_addr = htonl((a1<<24)|(a2<<16)|(a3<<8)|a4); data_addr.sin_port = htons((p1<<8)|p2); if (connect(data, (struct sockaddr *)&data_addr, sizeof(data_addr)) < 0 ) { perror("ftp: connect"); return(-1); } } debug(F100,"initconn connect ok","",0); #ifdef IP_TOS #ifdef IPTOS_THROUGHPUT on = IPTOS_THROUGHPUT; if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) perror("ftp: setsockopt TOS (ignored)"); #endif /* IPTOS_THROUGHPUT */ #endif /* IP_TOS */ memcpy(&hisdataaddr,&data_addr,sizeof(struct sockaddr_in)); return(0); } #endif /* NO_PASSIVE_MODE */ noport: memcpy(&data_addr,&myctladdr,sizeof(struct sockaddr_in)); if (sendport) data_addr.sin_port = 0; /* let system pick one */ if (data != -1) { #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ } data = socket(AF_INET, SOCK_STREAM, 0); globaldin = data; if (data < 0) { perror("ftp: socket"); if (tmpno) sendport = 1; return(-1); } if (!sendport) { if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on) ) < 0 ) { perror("ftp: setsockopt (reuse address)"); goto bad; } } if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) { perror("ftp: bind"); goto bad; } len = sizeof (data_addr); if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) { perror("ftp: getsockname"); goto bad; } if (listen(data, 1) < 0) { perror("ftp: listen"); goto bad; } if (sendport) { a = (char *)&data_addr.sin_addr; p = (char *)&data_addr.sin_port; ckmakxmsg(ftpcmdbuf,FTP_BUFSIZ,"PORT ", UC(a[0]),",",UC(a[1]),",", UC(a[2]),",", UC(a[3]),",", UC(p[0]),",", UC(p[1])); result = ftpcmd(ftpcmdbuf,NULL,0,0,ftp_vbm); if (result == REPLY_ERROR && sendport) { sendport = 0; tmpno = 1; goto noport; } return(result != REPLY_COMPLETE); } if (tmpno) sendport = 1; #ifdef IP_TOS #ifdef IPTOS_THROUGHPUT on = IPTOS_THROUGHPUT; if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) perror("ftp: setsockopt TOS (ignored)"); #endif #endif return(0); bad: #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = -1; globaldin = data; if (tmpno) sendport = 1; return(-1); } #ifdef CK_SSL static int ssl_dataconn() { if (ssl_ftp_data_con!=NULL) { /* Do SSL */ SSL_free(ssl_ftp_data_con); ssl_ftp_data_con=NULL; } ssl_ftp_data_con=(SSL *)SSL_new(ssl_ftp_ctx); SSL_set_fd(ssl_ftp_data_con,data); SSL_set_verify(ssl_ftp_data_con,ssl_verify_flag,NULL); SSL_copy_session_id(ssl_ftp_data_con,ssl_ftp_con); if (ssl_debug_flag) { fprintf(stderr,"=>START SSL connect on DATA\n"); fflush(stderr); } if (SSL_connect(ssl_ftp_data_con) <= 0) { static char errbuf[1024]; ckmakmsg(errbuf,1024,"ftp: SSL_connect DATA error: ", ERR_error_string(ERR_get_error(),NULL),NULL,NULL); fprintf(stderr,"%s\n", errbuf); fflush(stderr); #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = -1; globaldin = data; return(-1); } else { ssl_ftp_data_active_flag=1; if (!ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER) && /* JEA 2013-12-10 */ !tls_is_krb5(2)) { char *subject = ssl_get_subject_name(ssl_ftp_data_con); if (!subject) { if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { debug(F110,"dataconn","[SSL _- FAILED]",0); ssl_ftp_data_active_flag = 0; #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = -1; globaldin = data; return(-1); } else { if (!out2screen && displa && fdispla) { ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled"); /* fdispla = XYFD_B; */ } if (uq_ok( "Warning: Server didn't provide a certificate on data connection\n", "Continue with file transfer? (Y/N)", 3,NULL,0) <= 0) { debug(F110, "dataconn","[SSL - FAILED]",0); ssl_ftp_data_active_flag = 0; #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = -1; globaldin = data; return(-1); } } } else { if (!out2screen && displa && fdispla == XYFD_C) { ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled"); /* fdispla = XYFD_B; */ } if (ssl_check_server_name(ssl_ftp_data_con,ftp_user_host)) { debug(F110,"dataconn","[SSL - FAILED]",0); ssl_ftp_data_active_flag = 0; #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = -1; globaldin = data; return(-1); } } } debug(F110,"dataconn","[SSL - OK]",0); #ifdef COMMENT /* This messes up the full screen file transfer display */ ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag); #endif /* COMMENT */ } if (ssl_debug_flag) { fprintf(stderr,"=>DONE SSL connect on DATA\n"); fflush(stderr); } return(data); } #endif /* CK_SSL */ static int #ifdef CK_ANSIC dataconn( char *lmode ) #else dataconn(lmode) char *lmode; #endif /* CK_ANSIC */ { int s; #ifdef IP_TOS #ifdef IPTOS_THROUGHPUT int tos; #endif /* IPTOS_THROUGHPUT */ #endif /* IP_TOS */ #ifdef UCX50 static u_int fromlen; #else static SOCKOPT_T fromlen; #endif /* UCX50 */ fromlen = sizeof(hisdataaddr); #ifndef NO_PASSIVE_MODE if (passivemode) { #ifdef CK_SSL ssl_ftp_data_active_flag=0; if (ssl_ftp_active_flag && (ssl_ftp_proxy || ftp_dpl == FPL_PRV)) return(ssl_dataconn()); #endif /* CK_SSL */ return(data); } #endif /* NO_PASSIVE_MODE */ s = accept(data, (struct sockaddr *) &hisdataaddr, &fromlen); if (s < 0) { perror("ftp: accept"); #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = -1; globaldin = data; return(-1); } #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = s; globaldin = data; #ifdef IP_TOS #ifdef IPTOS_THROUGHPUT tos = IPTOS_THROUGHPUT; if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) perror("ftp: setsockopt TOS (ignored)"); #endif /* IPTOS_THROUGHPUT */ #endif /* IP_TOS */ #ifdef CK_SSL ssl_ftp_data_active_flag=0; if (ssl_ftp_active_flag && (ssl_ftp_proxy || ftp_dpl == FPL_PRV)) return(ssl_dataconn()); #endif /* CK_SSL */ return(data); } #ifdef FTP_PROXY static sigtype pscancel(sig) int sig; { cancelfile++; } static VOID pswitch(flag) int flag; { extern int proxy; static struct comvars { int connect; char name[MAXHOSTNAMELEN]; struct sockaddr_in mctl; struct sockaddr_in hctl; FILE *in; FILE *out; int tpe; int curtpe; int cpnd; int sunqe; int runqe; int mcse; int ntflg; char nti[17]; char nto[17]; int mapflg; char mi[CKMAXPATH]; char mo[CKMAXPATH]; char *authtype; int clvl; int dlvl; #ifdef FTP_KRB4 des_cblock session; des_key_schedule ftp_sched; #endif /* FTP_KRB4 */ #ifdef FTP_GSSAPI gss_ctx_id_t gcontext; #endif /* GSSAPI */ } proxstruct, tmpstruct; struct comvars *ip, *op; cancelfile = 0; oldintr = signal(SIGINT, pscancel); if (flag) { if (proxy) return; ip = &tmpstruct; op = &proxstruct; proxy++; } else { if (!proxy) return; ip = &proxstruct; op = &tmpstruct; proxy = 0; } ip->connect = connected; connected = op->connect; if (ftp_host) { strncpy(ip->name, ftp_host, MAXHOSTNAMELEN - 1); ip->name[MAXHOSTNAMELEN - 1] = '\0'; ip->name[strlen(ip->name)] = '\0'; } else ip->name[0] = 0; ftp_host = op->name; ip->hctl = hisctladdr; hisctladdr = op->hctl; ip->mctl = myctladdr; myctladdr = op->mctl; ip->in = csocket; csocket = op->in; ip->out = csocket; csocket = op->out; ip->tpe = ftp_typ; ftp_typ = op->tpe; ip->curtpe = curtype; curtype = op->curtpe; ip->cpnd = cpend; cpend = op->cpnd; ip->sunqe = ftp_usn; ftp_usn = op->sunqe; ip->mcse = mcase; mcase = op->mcse; ip->ntflg = ntflag; ntflag = op->ntflg; strncpy(ip->nti, ntin, 16); (ip->nti)[strlen(ip->nti)] = '\0'; strcpy(ntin, op->nti); strncpy(ip->nto, ntout, 16); (ip->nto)[strlen(ip->nto)] = '\0'; strcpy(ntout, op->nto); ip->mapflg = mapflag; mapflag = op->mapflg; strncpy(ip->mi, mapin, CKMAXPATH - 1); (ip->mi)[strlen(ip->mi)] = '\0'; strcpy(mapin, op->mi); strncpy(ip->mo, mapout, CKMAXPATH - 1); (ip->mo)[strlen(ip->mo)] = '\0'; strcpy(mapout, op->mo); ip->authtype = auth_type; auth_type = op->authtype; ip->clvl = ftp_cpl; ftp_cpl = op->clvl; ip->dlvl = ftp_dpl; ftp_dpl = op->dlvl; if (!ftp_cpl) ftp_cpl = FPL_CLR; if (!ftp_dpl) ftp_dpl = FPL_CLR; #ifdef FTP_KRB4 memcpy(ip->session, ftp_cred.session, sizeof(ftp_cred.session)); memcpy(ftp_cred.session, op->session, sizeof(ftp_cred.session)); memcpy(ip->schedule, ftp_sched, sizeof(ftp_sched)); memcpy(ftp_sched, op->schedule, sizeof(ftp_sched)); #endif /* FTP_KRB4 */ #ifdef FTP_GSSAPI ip->gcontext = gcontext; gcontext = op->gcontext; #endif /* GSSAPI */ signal(SIGINT, oldintr); if (cancelfile) { cancelfile = 0; debug(F101,"pswitch cancelfile B","",cancelfile); (*oldintr)(SIGINT); } } static sigtype #ifdef CK_ANSIC cancelpt( int sig ) #else cancelpt(sig) int sig; #endif /* CK_ANSIC */ { printf("\n"); fflush(stdout); ptabflg++; cancelfile = 0; #ifndef OS2 longjmp(ptcancel, 1); #else PostCtrlCSem(); #endif /* OS2 */ } void proxtrans(cmd, local, remote, unique) char *cmd, *local, *remote; int unique; { int secndflag = 0, prox_type, nfnd; char *cmd2; #ifdef BSDSELECT fd_set mask; #endif /* BSDSELECT */ sigtype cancelpt(); if (strcmp(cmd, "RETR")) cmd2 = "RETR"; else cmd2 = unique ? "STOU" : "STOR"; if ((prox_type = type) == 0) { if (servertype == SYS_UNIX && unix_proxy) prox_type = FTT_BIN; else prox_type = FTT_ASC; } if (curtype != prox_type) changetype(prox_type, 1); if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) { printf("Proxy server does not support third party transfers.\n"); return; } pswitch(0); if (!connected) { printf("No primary connection\n"); pswitch(1); ftpcode = -1; return; } if (curtype != prox_type) changetype(prox_type, 1); if (ftpcmd("PORT",pasv,-1,-1,ftp_vbm) != REPLY_COMPLETE) { pswitch(1); return; } /* Replace with calls to cc_execute() */ if (setjmp(ptcancel)) goto cancel; oldintr = signal(SIGINT, cancelpt); if (ftpcmd(cmd,remote,-1,-1,ftp_vbm) != PRELIM) { signal(SIGINT, oldintr); pswitch(1); return; } sleep(2000); pswitch(1); secndflag++; if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) goto cancel; ptflag++; getreply(0,-1,-1,ftp_vbm,0); pswitch(0); getreply(0,-1,-1,ftp_vbm,0); signal(SIGINT, oldintr); pswitch(1); ptflag = 0; return; cancel: signal(SIGINT, SIG_IGN); ptflag = 0; if (strcmp(cmd, "RETR") && !proxy) pswitch(1); else if (!strcmp(cmd, "RETR") && proxy) pswitch(0); if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) { pswitch(0); if (cpend) cancel_remote(0); } pswitch(1); if (ptabflg) ftpcode = -1; signal(SIGINT, oldintr); return; } if (cpend) cancel_remote(0); pswitch(!proxy); if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) { pswitch(0); if (cpend) cancel_remote(0); pswitch(1); if (ptabflg) ftpcode = -1; signal(SIGINT, oldintr); return; } } if (cpend) cancel_remote(0); pswitch(!proxy); if (cpend) { #ifdef BSDSELECT FD_ZERO(&mask); FD_SET(csocket, &mask); if ((nfnd = empty(&mask, 10)) <= 0) { if (nfnd < 0) { perror("cancel"); } if (ptabflg) ftpcode = -1; lostpeer(); } #else /* BSDSELECT */ #ifdef IBMSELECT if ((nfnd = empty(&csocket, 1, 10)) <= 0) { if (nfnd < 0) { perror("cancel"); } if (ptabflg) ftpcode = -1; lostpeer(); } #endif /* IBMSELECT */ #endif /* BSDSELECT */ getreply(0,-1,-1,ftp_vbm,0); getreply(0,-1,-1,ftp_vbm,0); } if (proxy) pswitch(0); pswitch(1); if (ptabflg) ftpcode = -1; signal(SIGINT, oldintr); } #endif /* FTP_PROXY */ #ifdef FTP_SECURITY #ifdef FTP_GSSAPI #ifdef COMMENT /* ck_gss_mech_krb5 is not declared anywhere */ struct { CONST gss_OID_desc * CONST * mech_type; char *service_name; } gss_trials[] = { { &ck_gss_mech_krb5, "ftp" }, { &ck_gss_mech_krb5, "host" }, }; #else /* This matches what is declared above */ struct { CONST gss_OID_desc * CONST * mech_type; char *service_name; } gss_trials[] = { { &gss_mech_krb5, "ftp" }, { &gss_mech_krb5, "host" }, }; #endif /* COMMENT */ int n_gss_trials = sizeof(gss_trials)/sizeof(gss_trials[0]); #endif /* FTP_GSSAPI */ static int ftp_auth() { extern int setsafe(); int j = 0, n; #ifdef FTP_KRB4 char *service, inst[INST_SZ]; ULONG cksum; ULONG checksum = (ULONG) getpid(); CHAR out_buf[FTP_BUFSIZ]; int i; #else /* FTP_KRB4 */ #ifdef FTP_GSSAPI CHAR out_buf[FTP_BUFSIZ]; int i; #endif /* FTP_GSSAPI */ #endif /* FTP_KRB4 */ if (ssl_ftp_proxy) /* Do not allow AUTH over SSL proxy */ return(0); if (auth_type) return(1); /* auth already succeeded */ /* Try each auth type as specified by the end user */ for (j = 0; j < 8 && ftp_auth_type[j] != 0; j++) { #ifdef FTP_GSSAPI if (ftp_auth_type[j] == FTA_GK5 && ck_gssapi_is_installed()) { n = ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm); if (n == REPLY_CONTINUE) { OM_uint32 maj_stat, min_stat; gss_name_t target_name; gss_buffer_desc send_tok, recv_tok, *token_ptr; char stbuf[FTP_BUFSIZ]; int comcode, trial; struct gss_channel_bindings_struct chan; char * realm = NULL; char tgt[256]; chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */ chan.initiator_address.length = 4; chan.initiator_address.value = &myctladdr.sin_addr.s_addr; chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */ chan.acceptor_address.length = 4; chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr; chan.application_data.length = 0; chan.application_data.value = 0; if (!quiet) printf("GSSAPI accepted as authentication type\n"); realm = ck_krb5_realmofhost(ftp_user_host); if (realm) { ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm); debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0); if ( krb5_autoget && !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) || (ck_krb5_is_tgt_valid() > 0)) ) ck_krb5_autoget_TGT(realm); } /* Blob from gss-client */ for (trial = 0; trial < n_gss_trials; trial++) { /* ftp@hostname first, the host@hostname */ /* the V5 GSSAPI binding canonicalizes this for us... */ ckmakmsg(stbuf,FTP_BUFSIZ, gss_trials[trial].service_name, "@", ftp_user_host, NULL ); if (ftp_deb) fprintf(stderr, "Authenticating to <%s>...\n", stbuf); send_tok.value = stbuf; send_tok.length = strlen(stbuf); maj_stat = gss_import_name(&min_stat, &send_tok, gss_nt_service_name, &target_name ); if (maj_stat != GSS_S_COMPLETE) { user_gss_error(maj_stat, min_stat, "parsing name"); secure_error("name parsed <%s>\n", stbuf); continue; } token_ptr = GSS_C_NO_BUFFER; gcontext = GSS_C_NO_CONTEXT; /* structure copy */ do { if (ftp_deb) fprintf(stderr, "calling gss_init_sec_context\n"); maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &gcontext, target_name, (gss_OID) * gss_trials[trial].mech_type, GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | (ftp_cfw ? GSS_C_DELEG_FLAG : 0), 0, /* channel bindings */ (krb5_d_no_addresses ? GSS_C_NO_CHANNEL_BINDINGS : &chan), token_ptr, NULL, /* ignore mech type */ &send_tok, NULL, /* ignore ret_flags */ NULL ); /* ignore time_rec */ if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) { if (trial == n_gss_trials-1) user_gss_error(maj_stat, min_stat, "initializing context" ); gss_release_name(&min_stat, &target_name); /* maybe we missed on the service name */ goto outer_loop; } if (send_tok.length != 0) { int len; reply_parse = "ADAT="; /* for ftpcmd() later */ len = FTP_BUFSIZ; kerror = radix_encode(send_tok.value, out_buf, send_tok.length, &len, RADIX_ENCODE ); if (kerror) { fprintf(stderr, "Base 64 encoding failed: %s\n", radix_error(kerror) ); goto gss_complete_loop; } comcode = ftpcmd("ADAT",out_buf,-1,-1,0); if (comcode != REPLY_COMPLETE && comcode != REPLY_CONTINUE /* (335) */ ) { if (trial == n_gss_trials-1) { fprintf(stderr, "GSSAPI ADAT failed\n"); /* force out of loop */ maj_stat = GSS_S_FAILURE; } /* Backoff to the v1 gssapi is still possible. Send a new AUTH command. If that fails, terminate the loop. */ if (ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm) != REPLY_CONTINUE) { fprintf(stderr, "GSSAPI ADAT failed, AUTH restart failed\n"); /* force out of loop */ maj_stat = GSS_S_FAILURE; } goto outer_loop; } if (!reply_parse) { fprintf(stderr, "No authentication data received from server\n"); if (maj_stat == GSS_S_COMPLETE) { fprintf(stderr, "...but no more was needed\n"); goto gss_complete_loop; } else { user_gss_error(maj_stat, min_stat, "no reply, huh?" ); goto gss_complete_loop; } } len = FTP_BUFSIZ; kerror = radix_encode(reply_parse,out_buf,i,&len, RADIX_DECODE); if (kerror) { fprintf(stderr, "Base 64 decoding failed: %s\n", radix_error(kerror)); goto gss_complete_loop; } /* everything worked */ token_ptr = &recv_tok; recv_tok.value = out_buf; recv_tok.length = len; continue; /* get out of loop clean */ gss_complete_loop: trial = n_gss_trials-1; gss_release_buffer(&min_stat, &send_tok); gss_release_name(&min_stat, &target_name); goto outer_loop; } } while (maj_stat == GSS_S_CONTINUE_NEEDED); outer_loop: if (maj_stat == GSS_S_COMPLETE) break; } if (maj_stat == GSS_S_COMPLETE) { printf("GSSAPI authentication succeeded\n"); reply_parse = NULL; auth_type = "GSSAPI"; return(1); } else { fprintf(stderr, "GSSAPI authentication failed\n"); reply_parse = NULL; } } else { if (ftp_deb) fprintf(stderr, "GSSAPI rejected as an authentication type\n"); if (ftpcode == 500 || ftpcode == 502) return(0); } } #endif /* FTP_GSSAPI */ #ifdef FTP_SRP if (ftp_auth_type[j] == FTA_SRP && ck_srp_is_installed()) { if (srp_ftp_auth(ftp_user_host,NULL,NULL)) return(1); else if (ftpcode == 500 || ftpcode == 502) return(0); } #endif /* FTP_SRP */ #ifdef FTP_KRB4 if (ftp_auth_type[j] == FTA_K4 && ck_krb4_is_installed()) { n = ftpcmd("AUTH KERBEROS_V4",NULL,0,0,ftp_vbm); if (n == REPLY_CONTINUE) { char tgt[4*REALM_SZ+1]; int rc; if (!quiet) printf("KERBEROS_V4 accepted as authentication type\n"); ckstrncpy(inst, (char *) krb_get_phost(ftp_user_host),INST_SZ); ckstrncpy(ftp_realm, (char *)ck_krb4_realmofhost(ftp_user_host), REALM_SZ ); ckmakmsg(tgt,sizeof(tgt),"krbtgt.",ftp_realm,"@",ftp_realm); rc = ck_krb4_tkt_isvalid(tgt); if (rc <= 0 && krb4_autoget) ck_krb4_autoget_TGT(ftp_realm); service = "ftp"; kerror = krb_mk_req(&ftp_tkt,service,inst,ftp_realm,checksum); if (kerror == KDC_PR_UNKNOWN) { service = "rcmd"; kerror = krb_mk_req(&ftp_tkt, service, inst, ftp_realm, checksum ); } if (kerror) fprintf(stderr, "Kerberos V4 krb_mk_req failed: %s\n", krb_get_err_text(kerror)); if (!kerror) { kerror = krb_get_cred(service, inst, ftp_realm,&ftp_cred); if (kerror) fprintf(stderr, "Kerberos V4 krb_get_cred failed: %s\n", krb_get_err_text(kerror)); } if (!kerror) { int rc; rc = des_key_sched(ftp_cred.session, ftp_sched); if (rc == -1) { printf("?Invalid DES key specified in credentials\r\n"); debug(F110,"ftp_auth", "invalid DES Key specified in credentials",0); } else if ( rc == -2 ) { printf("?Weak DES key specified in credentials\r\n"); debug(F110,"ftp_auth", "weak DES Key specified in credentials",0); } else if ( rc != 0 ) { printf("?DES Key Schedule not set by credentials\r\n"); debug(F110,"ftp_auth", "DES Key Schedule not set by credentials",0); } reply_parse = "ADAT="; i = FTP_BUFSIZ; kerror = radix_encode(ftp_tkt.dat, out_buf, ftp_tkt.length, &i, RADIX_ENCODE); if (kerror) { fprintf(stderr, "Base 64 encoding failed: %s\n", radix_error(kerror)); goto krb4_err; } if (i > FTP_BUFSIZ - 6) printf("?ADAT data too long\n"); if (ftpcmd("ADAT",out_buf,-1,-1,0) != REPLY_COMPLETE) { fprintf(stderr, "Kerberos V4 authentication failed\n"); goto krb4_err; } if (!reply_parse) { fprintf(stderr, "No authentication data received from server\n"); goto krb4_err; } i = sizeof(out_buf); kerror = radix_encode(reply_parse, out_buf, 0, &i, RADIX_DECODE); if (kerror) { fprintf(stderr, "Base 64 decoding failed: %s\n", radix_error(kerror)); goto krb4_err; } kerror = krb_rd_safe(out_buf, i, #ifdef KRB524 ftp_cred.session, #else /* KRB524 */ &ftp_cred.session, #endif /* KRB524 */ &hisctladdr, &myctladdr, &ftp_msg_data ); if (kerror) { fprintf(stderr, "Kerberos V4 krb_rd_safe failed: %s\n", krb_get_err_text(kerror)); goto krb4_err; } /* fetch the (modified) checksum */ memcpy(&cksum, ftp_msg_data.app_data, sizeof(cksum)); if (ntohl(cksum) == checksum + 1) { if (ftp_vbm) printf("Kerberos V4 authentication succeeded\n"); reply_parse = NULL; auth_type = "KERBEROS_V4"; return(1); } else fprintf(stderr, "Kerberos V4 mutual authentication failed\n"); krb4_err: reply_parse = NULL; } } else { if (ftp_deb) fprintf(stderr, "KERBEROS_V4 rejected as an authentication type\n"); if (ftpcode == 500 || ftpcode == 502) return(0); } } #endif /* FTP_KRB4 */ #ifdef CK_SSL if (ftp_auth_type[j] == FTA_TLS && ck_ssleay_is_installed()) { #ifdef FTPHOST if (!hostcmd) { ftpcmd("HOST",ftp_user_host,0,0,0); hostcmd = 1; } #endif /* FTPHOST */ n = ftpcmd("AUTH TLS",NULL,0,0,ftp_vbm); if (n != REPLY_COMPLETE) n = ftpcmd("AUTH TLS-P",NULL,0,0,ftp_vbm); if (n == REPLY_COMPLETE) { if (!quiet) printf("TLS accepted as authentication type\n"); auth_type = "TLS"; ssl_auth(); if (ssl_ftp_active_flag ) { ftp_dpl = FPL_CLR; ftp_cpl = FPL_PRV; return(1); } else { fprintf(stderr,"TLS authentication failed\n"); auth_type = NULL; #ifdef TCPIPLIB socket_close(csocket); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(csocket, 1+1); #endif /* USE_SHUTDOWN */ close(csocket); #endif /* TCPIPLIB */ csocket = -1; if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL) return(0); } } else { if (ftp_deb) fprintf(stderr,"TLS rejected as an authentication type\n"); if (ftpcode == 500 || ftpcode == 502) return(0); } } if (ftp_auth_type[j] == FTA_SSL && ck_ssleay_is_installed()) { #ifdef FTPHOST if (!hostcmd) { ftpcmd("HOST",ftp_user_host,0,0,0); hostcmd = 1; } #endif /* FTPHOST */ n = ftpcmd("AUTH SSL",NULL,0,0,ftp_vbm); if (n == REPLY_CONTINUE || n == REPLY_COMPLETE) { if (!quiet) printf("SSL accepted as authentication type\n"); auth_type = "SSL"; ssl_auth(); if (ssl_ftp_active_flag) { ftp_dpl = FPL_PRV; ftp_cpl = FPL_PRV; setprotbuf(1<<20); return(1); } else { fprintf(stderr,"SSL authentication failed\n"); auth_type = NULL; #ifdef TCPIPLIB socket_close(csocket); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(csocket, 1+1); #endif /* USE_SHUTDOWN */ close(csocket); #endif /* TCPIPLIB */ csocket = -1; if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL) return(0); } } else { if (ftp_deb) fprintf(stderr, "SSL rejected as an authentication type\n"); if (ftpcode == 500 || ftpcode == 502) return(0); } } #endif /* CK_SSL */ /* Other auth types go here ... */ } /* for (j;;) */ return(0); } static int #ifdef CK_ANSIC setprotbuf(unsigned int size) #else setprotbuf(size) unsigned int size; #endif /* CK_ANSIC */ /* setprotbuf */ { if (ucbuf) free(ucbuf); ucbuf = NULL; ucbufsiz = 0; actualbuf = size; while ((ucbuf = (CHAR *)malloc(actualbuf)) == NULL) { if (actualbuf) actualbuf /= 2; else return(0); } ucbufsiz = actualbuf - FUDGE_FACTOR; debug(F101,"setprotbuf ucbufsiz","",ucbufsiz); if (ucbufsiz < 128) { printf("WARNING: tiny ucbufsiz: %d\n",ucbufsiz); } else if (ucbufsiz < 0) { printf("ERROR: ucbuf allocation failure\n"); return(-1); } maxbuf = actualbuf; return(1); } static int #ifdef CK_ANSIC setpbsz(unsigned int size) #else setpbsz(size) unsigned int size; #endif /* CK_ANSIC */ /* setpbsz */ { if (!setprotbuf(size)) { perror("?Error while trying to malloc PROT buffer:"); #ifdef FTP_SRP srp_reset(); #endif /* FTP_SRP */ ftpclose(); return(-1); } reply_parse = "PBSZ="; ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,"PBSZ ", #ifdef CK_SSL ssl_ftp_active_flag ? "0" : #endif /* CK_SSL */ ckuitoa(actualbuf),NULL,NULL); if (ftpcmd(ftpcmdbuf,NULL,0,0,0) != REPLY_COMPLETE) { if (connected) { printf("?Unable to negotiate PROT buffer size with FTP server\n"); ftpclose(); } return(-1); } if (reply_parse) { if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf) maxbuf = actualbuf; } else maxbuf = actualbuf; ucbufsiz = maxbuf - FUDGE_FACTOR; debug(F101,"setpbsz ucbufsiz","",ucbufsiz); reply_parse = NULL; return(0); } #endif /* FTP_SECURITY */ static VOID #ifdef CK_ANSIC cancel_remote( int din ) #else cancel_remote(din) int din; #endif /* CK_ANSIC */ { CHAR buf[FTP_BUFSIZ]; int x, nfnd; #ifdef BSDSELECT fd_set mask; #endif /* BSDSELECT */ #ifdef IBMSELECT int fds[2], fdcnt = 0; #endif /* IBMSELECT */ #ifdef DEBUG extern int debtim; int xdebtim; xdebtim = debtim; debtim = 1; #endif /* DEBUG */ debug(F100,"ftp cancel_remote entry","",0); #ifdef CK_SSL if (ssl_ftp_active_flag) { /* * Send Telnet IP, Telnet DM but do so inline and within the * TLS channel */ int count, error; buf[0] = IAC; buf[1] = TN_IP; buf[2] = IAC; buf[3] = TN_DM; buf[4] = NUL; count = SSL_write(ssl_ftp_con, buf, 4); debug(F111,"ftp cancel_remote","SSL_write(IAC IP IAC DM)",count); error = SSL_get_error(ssl_ftp_con,count); debug(F111,"ftp cancel_remote","SSL_get_error()",error); switch (error) { case SSL_ERROR_NONE: break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_SYSCALL: #ifdef NT { int gle = GetLastError(); } #endif /* NT */ case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: lostpeer(); return; } } else #endif /* CK_SSL */ { /* * send IAC in urgent mode instead of DM because 4.3BSD places oob mark * after urgent byte rather than before as is protocol now. */ buf[0] = IAC; buf[1] = TN_IP; buf[2] = IAC; buf[3] = NUL; if ((x = send(csocket, (SENDARG2TYPE)buf, 3, MSG_OOB)) != 3) perror("cancel"); debug(F101,"ftp cancel_remote send 1","",x); buf[0] = TN_DM; x = send(csocket,(SENDARG2TYPE)buf,1,0); debug(F101,"ftp cancel_remote send 2","",x); } x = scommand("ABOR"); debug(F101,"ftp cancel_remote scommand","",x); #ifdef BSDSELECT FD_ZERO(&mask); FD_SET(csocket, &mask); if (din) { FD_SET(din, &mask); } nfnd = empty(&mask, 10); debug(F101,"ftp cancel_remote empty","",nfnd); if ((nfnd) <= 0) { if (nfnd < 0) { perror("cancel"); } #ifdef FTP_PROXY if (ptabflg) ftpcode = -1; #endif /* FTP_PROXY */ lostpeer(); } debug(F110,"ftp cancel_remote","D",0); if (din && FD_ISSET(din, &mask)) { /* Security: No threat associated with this read. */ /* But you can't simply read the TLS data stream */ #ifdef CK_SSL if (ssl_ftp_data_active_flag) { int count, error; while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0) /* LOOP */ ; } else #endif /* CK_SSL */ { while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0) /* LOOP */ ; } } debug(F110,"ftp cancel_remote","E",0); #else /* BSDSELECT */ #ifdef IBMSELECT fds[0] = csocket; fdcnt++; if (din) { fds[1] = din; fdcnt++; } nfnd = empty(fds, fdcnt, 10); debug(F101,"ftp cancel_remote empty","",nfnd); if ((nfnd) <= 0) { if (nfnd < 0) { perror("cancel"); } #ifdef FTP_PROXY if (ptabflg) ftpcode = -1; #endif /* FTP_PROXY */ lostpeer(); } debug(F110,"ftp cancel_remote","D",0); if (din && select(&din, 1,0,0,1) ) { #ifdef CK_SSL if (ssl_ftp_data_active_flag) { int count, error; while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0) /* LOOP */ ; } else #endif /* CK_SSL */ { while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0) /* LOOP */ ; } } debug(F110,"ftp cancel_remote","E",0); #else /* IBMSELECT */ Some form of select is required. #endif /* IBMSELECT */ #endif /* BSDSELECT */ if (getreply(0,-1,-1,ftp_vbm,0) == REPLY_ERROR && ftpcode == 552) { debug(F110,"ftp cancel_remote","F",0); /* 552 needed for NIC style cancel */ getreply(0,-1,-1,ftp_vbm,0); debug(F110,"ftp cancel_remote","G",0); } debug(F110,"ftp cancel_remote","H",0); getreply(0,-1,-1,ftp_vbm,0); debug(F110,"ftp cancel_remote","I",0); #ifdef DEBUG debtim = xdebtim; #endif /* DEBUG */ } #ifdef FTP_SECURITY static int #ifdef CK_ANSIC fts_dpl( int x ) #else fts_dpl(x) int x; #endif /* CK_ANSIC */ { if (!auth_type #ifdef OS2 || !ck_crypt_is_installed() #endif /* OS2 */ ) { switch ( x ) { case FPL_PRV: printf("?Cannot set protection level to PRIVATE\n"); return(0); case FPL_SAF: printf("?Cannot set protection level to SAFE\n"); return(0); } ftp_dpl = x; return(1); } #ifdef CK_SSL if (x == FPL_SAF && (!strcmp(auth_type,"SSL") || !strcmp(auth_type,"TLS"))) { printf("Cannot set protection level to safe\n"); return(0); } #endif /* CK_SSL */ /* Start with a PBSZ of 1 meg */ if (x != FPL_CLR) { if (setpbsz(DEFAULT_PBSZ) < 0) return(0); } y = ftpcmd(x == FPL_CLR ? "PROT C" : (x == FPL_SAF ? "PROT S" : "PROT P"), NULL, 0, 0,ftp_vbm); if (y == REPLY_COMPLETE) { ftp_dpl = x; return(1); } return(0); } static int #ifdef CK_ANSIC fts_cpl( int x ) #else fts_cpl(x) int x; #endif /* CK_ANSIC */ { if (!auth_type #ifdef OS2 || !ck_crypt_is_installed() #endif /* OS2 */ ) { switch ( x ) { case FPL_PRV: printf("?Cannot set protection level to PRIVATE\n"); return(0); case FPL_SAF: printf("?Cannot set protection level to SAFE\n"); return(0); } ftp_cpl = x; return(1); } if (x == FPL_CLR) { y = ftpcmd("CCC",NULL,0,0,ftp_vbm); if (y == REPLY_COMPLETE) { ftp_cpl = x; return(1); } return(0); } ftp_cpl = x; return(1); } #endif /* FTP_SECURITY */ #ifdef FTP_GSSAPI static VOID user_gss_error(maj_stat, min_stat, s) OM_uint32 maj_stat, min_stat; char *s; { /* a lot of work just to report the error */ OM_uint32 gmaj_stat, gmin_stat, msg_ctx; gss_buffer_desc msg; msg_ctx = 0; while (!msg_ctx) { gmaj_stat = gss_display_status(&gmin_stat, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &msg ); if ((gmaj_stat == GSS_S_COMPLETE)|| (gmaj_stat == GSS_S_CONTINUE_NEEDED)) { fprintf(stderr, "GSSAPI error major: %s\n", (char*)msg.value); gss_release_buffer(&gmin_stat, &msg); } if (gmaj_stat != GSS_S_CONTINUE_NEEDED) break; } msg_ctx = 0; while (!msg_ctx) { gmaj_stat = gss_display_status(&gmin_stat, min_stat, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &msg ); if ((gmaj_stat == GSS_S_COMPLETE)|| (gmaj_stat == GSS_S_CONTINUE_NEEDED)) { fprintf(stderr, "GSSAPI error minor: %s\n", (char*)msg.value); gss_release_buffer(&gmin_stat, &msg); } if (gmaj_stat != GSS_S_CONTINUE_NEEDED) break; } fprintf(stderr, "GSSAPI error: %s\n", s); } #endif /* FTP_GSSAPI */ #ifndef NOMHHOST #ifdef datageneral #define NOMHHOST #else #ifdef HPUX5WINTCP #define NOMHHOST #endif /* HPUX5WINTCP */ #endif /* datageneral */ #endif /* NOMHHOST */ #ifdef INADDRX static struct in_addr inaddrx; #endif /* INADDRX */ #ifdef CK_ANSIC #else #endif /* CK_ANSIC */ static char * #ifdef CK_ANSIC ftp_hookup( char * host, int port, int tls ) #else ftp_hookup(host, port, tls) char * host; int port; int tls; #endif /* CK_ANSIC */ { register struct hostent *hp = 0; #ifdef IP_TOS #ifdef IPTOS_THROUGHPUT int tos; #endif /* IPTOS_THROUGHPUT */ #endif /* IP_TOS */ int s; GSOCKNAME_T len; static char hostnamebuf[MAXHOSTNAMELEN]; char hostname[MAXHOSTNAMELEN] /* , *p, *q */ ; int cport; #ifdef DEBUG extern int debtim; int xdebtim; xdebtim = debtim; debtim = 1; #endif /* DEBUG */ debug(F111,"ftp_hookup",host,port); #ifndef NOHTTP if (tcp_http_proxy) { struct servent *destsp; char *p, *q; ckmakmsg(proxyhost,HTTPCPYL,host,":",ckuitoa(port),NULL); for (p = tcp_http_proxy, q = hostname; *p != '\0' && *p != ':'; p++, q++ ) *q = *p; *q = '\0'; if (*p == ':') p++; else p = "http"; destsp = getservbyname(p,"tcp"); if (destsp) cport = ntohs(destsp->s_port); else if (p) { cport = atoi(p); } else cport = 80; } else #endif /* NOHTTP */ { ckstrncpy(hostname,host,MAXHOSTNAMELEN); cport = port; } memset((char *)&hisctladdr, 0, sizeof (hisctladdr)); hisctladdr.sin_addr.s_addr = inet_addr(host); if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */ { debug(F110,"ftp hookup A",hostname,0); hisctladdr.sin_family = AF_INET; ckstrncpy(hostnamebuf, hostname, MAXHOSTNAMELEN); } else { debug(F110,"ftp hookup B",hostname,0); hp = gethostbyname(hostname); #ifdef HADDRLIST hp = ck_copyhostent(hp); /* make safe copy that won't change */ #endif /* HADDRLIST */ if (hp == NULL) { fprintf(stderr, "ftp: %s: Unknown host\n", host); ftpcode = -1; #ifdef DEBUG debtim = xdebtim; #endif /* DEBUG */ return((char *) 0); } hisctladdr.sin_family = hp->h_addrtype; #ifdef HADDRLIST memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0], sizeof(hisctladdr.sin_addr)); #else /* HADDRLIST */ memcpy((char *)&hisctladdr.sin_addr, hp->h_addr, sizeof(hisctladdr.sin_addr)); #endif /* HADDRLIST */ ckstrncpy(hostnamebuf, hp->h_name, MAXHOSTNAMELEN); } debug(F110,"ftp hookup C",hostnamebuf,0); ftp_host = hostnamebuf; s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); debug(F101,"ftp hookup socket","",s); if (s < 0) { perror("ftp: socket"); ftpcode = -1; #ifdef DEBUG debtim = xdebtim; #endif /* DEBUG */ return(0); } hisctladdr.sin_port = htons(cport); errno = 0; #ifdef COMMENT printf("hisctladdr=%d\n",sizeof(hisctladdr)); printf("hisctladdr.sin_addr=%d\n",sizeof(hisctladdr.sin_addr)); printf("sockaddr_in=%d\n",sizeof(struct sockaddr_in)); printf("hisctladdr.sin_addr.s_addr=%d\n",sizeof(hisctladdr.sin_addr.s_addr)); #endif /* COMMENT */ #ifdef HADDRLIST debug(F100,"ftp hookup HADDRLIST","",0); while #else debug(F100,"ftp hookup no HADDRLIST","",0); if #endif /* HADDRLIST */ (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) { debug(F101,"ftp hookup connect failed","",errno); #ifdef HADDRLIST if (hp && hp->h_addr_list[1]) { int oerrno = errno; fprintf(stderr, "ftp: connect to address %s: ", inet_ntoa(hisctladdr.sin_addr)); errno = oerrno; perror((char *) 0); hp->h_addr_list++; memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0], sizeof(hisctladdr.sin_addr)); fprintf(stdout, "Trying %s...\n", inet_ntoa(hisctladdr.sin_addr)); #ifdef TCPIPLIB socket_close(s); #else /* TCPIPLIB */ close(s); #endif /* TCPIPLIB */ s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); if (s < 0) { perror("ftp: socket"); ftpcode = -1; #ifdef DEBUG debtim = xdebtim; #endif /* DEBUG */ return(0); } continue; } #endif /* HADDRLIST */ perror("ftp: connect"); ftpcode = -1; goto bad; } debug(F100,"ftp hookup connect ok","",0); len = sizeof (myctladdr); errno = 0; if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) { debug(F101,"ftp hookup getsockname failed","",errno); perror("ftp: getsockname"); ftpcode = -1; goto bad; } debug(F100,"ftp hookup getsockname ok","",0); #ifndef NOHTTP if (tcp_http_proxy) { #ifdef OS2 char * agent = "Kermit 95"; /* Default user agent */ #else char * agent = "C-Kermit"; #endif /* OS2 */ if (http_connect(s,agent,NULL, tcp_http_proxy_user, tcp_http_proxy_pwd, 0, proxyhost ) < 0) { char * foo = NULL; #ifdef TCPIPLIB socket_close(s); #else /* TCPIPLIB */ close(s); #endif /* TCPIPLIB */ while (foo == NULL && tcp_http_proxy != NULL ) { if (tcp_http_proxy_errno == 401 || tcp_http_proxy_errno == 407 ) { char uid[UIDBUFLEN]; char pwd[PWDSIZ]; struct txtbox tb[2]; int ok; tb[0].t_buf = uid; tb[0].t_len = UIDBUFLEN; tb[0].t_lbl = "Proxy Userid: "; tb[0].t_dflt = NULL; tb[0].t_echo = 1; tb[1].t_buf = pwd; tb[1].t_len = 256; tb[1].t_lbl = "Proxy Passphrase: "; tb[1].t_dflt = NULL; tb[1].t_echo = 2; ok = uq_mtxt("Proxy Server Authentication Required\n", NULL, 2, tb); if (ok && uid[0]) { char * proxy_user, * proxy_pwd; proxy_user = tcp_http_proxy_user; proxy_pwd = tcp_http_proxy_pwd; tcp_http_proxy_user = uid; tcp_http_proxy_pwd = pwd; foo = ftp_hookup(host, port, 0); debug(F110,"ftp_hookup()",foo,0); memset(pwd,0,PWDSIZ); tcp_http_proxy_user = proxy_user; tcp_http_proxy_pwd = proxy_pwd; } else break; } else break; } if (foo != NULL) return(foo); perror("ftp: connect"); ftpcode = -1; goto bad; } ckstrncpy(hostnamebuf, proxyhost, MAXHOSTNAMELEN); } #endif /* NOHTTP */ csocket = s; #ifdef CK_SSL if (tls) { /* FTP over SSL * If the connection is over an SSL proxy then the * auth_type will be NULL. However, I'm not sure * whether we should protect the data channel in * that case or not. */ debug(F100,"ftp hookup use_tls","",0); if (!ssl_auth()) { debug(F100,"ftp hookup ssl_auth failed","",0); auth_type = NULL; ftpcode = -1; csocket = -1; goto bad; } ssl_ftp_proxy = 1; } #endif /* CK_SSL */ #ifdef IP_TOS #ifdef IPTOS_LOWDELAY tos = IPTOS_LOWDELAY; if (setsockopt(csocket, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) perror("ftp: setsockopt TOS (ignored)"); #endif #endif if (!quiet) printf("Connected to %s.\n", host); /* Read greeting from server */ if (getreply(0,ftp_csl,ftp_csr,ftp_vbm,0) > 2) { debug(F100,"ftp hookup bad reply","",0); #ifdef TCPIPLIB socket_close(csocket); #else /* TCPIPLIB */ close(csocket); #endif /* TCPIPLIB */ ftpcode = -1; goto bad; } #ifdef SO_OOBINLINE { int on = 1; errno = 0; if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) { perror("ftp: setsockopt"); debug(F101,"ftp hookup setsockopt failed","",errno); } #ifdef DEBUG else debug(F100,"ftp hookup setsockopt ok","",0); #endif /* DEBUG */ } #endif /* SO_OOBINLINE */ #ifdef DEBUG debtim = xdebtim; #endif /* DEBUG */ return(ftp_host); bad: debug(F100,"ftp hookup bad","",0); #ifdef TCPIPLIB socket_close(s); #else /* TCPIPLIB */ close(s); #endif /* TCPIPLIB */ #ifdef DEBUG debtim = xdebtim; #endif /* DEBUG */ csocket = -1; return((char *)0); } static VOID ftp_init() { int i, n; /* The purpose of the initial REST 0 is not clear, but other FTP */ /* clients do it. In any case, failure of this command is not a */ /* reliable indication that the server does not support Restart. */ okrestart = 0; if (!noinit) { n = ftpcmd("REST 0",NULL,0,0,0); if (n == REPLY_COMPLETE) okrestart = 1; #ifdef COMMENT else if (ftp_deb) printf("WARNING: Unable to restore file pointer.\n"); #endif /* COMMENT */ } n = ftpcmd("SYST",NULL,0,0,0); /* Get server system type */ if (n == REPLY_COMPLETE) { register char *cp, c = NUL; cp = ckstrchr(ftp_reply_str+4,' '); /* Get first word of reply */ if (cp == NULL) cp = ckstrchr(ftp_reply_str+4,'\r'); if (cp) { if (cp[-1] == '.') cp--; c = *cp; /* Save this char */ *cp = '\0'; /* Replace it with NUL */ } if (!quiet) printf("Remote system type is %s.\n",ftp_reply_str+4); ckstrncpy(ftp_srvtyp,ftp_reply_str+4,SRVNAMLEN); if (cp) /* Put back saved char */ *cp = c; } alike = !ckstrcmp(ftp_srvtyp,myostype,-1,0); if (!ckstrcmp(ftp_srvtyp,"UNIX",-1,0)) servertype = SYS_UNIX; else if (!ckstrcmp(ftp_srvtyp,"WIN32",-1,0)) servertype = SYS_WIN32; else if (!ckstrcmp(ftp_srvtyp,"OS/2",-1,0)) servertype = SYS_WIN32; else if (!ckstrcmp(ftp_srvtyp,"VMS",-1,0)) servertype = SYS_VMS; else if (!ckstrcmp(ftp_srvtyp,"DOS",-1,0)) servertype = SYS_DOS; else if (!ckstrcmp(ftp_srvtyp,"TOPS20",-1,0)) servertype = SYS_TOPS20; else if (!ckstrcmp(ftp_srvtyp,"TOPS10",-1,0)) servertype = SYS_TOPS10; #ifdef FTP_PROXY unix_proxy = 0; if (servertype == SYS_UNIX && proxy) unix_proxy = 1; #endif /* FTP_PROXY */ if (ftp_cmdlin && ftp_xfermode == XMODE_M) ftp_typ = binary; /* Type given on command line */ else /* Otherwise set it automatically */ ftp_typ = alike ? FTT_BIN : FTT_ASC; changetype(ftp_typ,0); /* Change to this type */ g_ftp_typ = ftp_typ; /* Make it the global type */ if (!quiet) printf("Default transfer mode is %s\n", ftp_typ ? "BINARY" : "TEXT (\"ASCII\")" ); for (i = 0; i < 16; i++) /* Init server FEATure table */ sfttab[i] = 0; if (!noinit) { n = ftpcmd("MODE S",NULL,0,0,0); /* We always send in Stream mode */ #ifdef COMMENT if (n != REPLY_COMPLETE) printf("WARNING: Server does not accept MODE S(TREAM)\n"); #endif /* COMMENT */ n = ftpcmd("STRU F",NULL,0,0,0); /* STRU File (not Record or Page) */ #ifdef COMMENT if (n != REPLY_COMPLETE) printf("WARNING: Server does not accept STRU F(ILE)\n"); #endif /* COMMENT */ if (featok) { n = ftpcmd("FEAT",NULL,0,0,0); /* Ask server about features */ if (n == REPLY_COMPLETE) { debug(F101,"ftp_init FEAT","",sfttab[0]); if (deblog || ftp_deb) { int i; for (i = 1; i < 16 && i < nfeattab; i++) { debug(F111,"ftp_init FEAT",feattab[i].kwd,sfttab[i]); if (ftp_deb) printf(" Server %s %s\n", sfttab[i] ? "supports" : "does not support", feattab[i].kwd ); } /* Deal with disabled MLST opts here if necessary */ /* But why would it be? */ } } } } } static int #ifdef CK_ANSIC ftp_login( char * host ) /* (also called from ckuusy.c) */ #else ftp_login(host) char * host; #endif /* CK_ANSIC */ { static char ftppass[PASSBUFSIZ]=""; char tmp[PASSBUFSIZ]; char *user = NULL, *pass = NULL, *acct = NULL; int n, aflag = 0; extern char uidbuf[]; extern char pwbuf[]; extern int pwflg, pwcrypt; debug(F111,"ftp_login",ftp_logname,ftp_log); if (!ckstrcmp(ftp_logname,"anonymous",-1,0)) anonymous = 1; if (!ckstrcmp(ftp_logname,"ftp",-1,0)) anonymous = 1; #ifdef FTP_SRP if (auth_type && !strcmp(auth_type, "SRP")) { user = srp_user; pass = srp_pass; acct = srp_acct; } else #endif /* FTP_SRP */ if (anonymous) { user = "anonymous"; if (ftp_tmp) { /* They gave a password */ pass = ftp_tmp; } else if (ftp_apw) { /* SET FTP ANONYMOUS-PASSWORD */ pass = ftp_apw; } else { /* Supply user@host */ ckmakmsg(tmp,PASSBUFSIZ,whoami(),"@",myhost,NULL); pass = tmp; } debug(F110,"ftp anonymous",pass,0); } else { #ifdef USE_RUSERPASS if (ruserpass(host, &user, &pass, &acct) < 0) { ftpcode = -1; return(0); } #endif /* USE_RUSERPASS */ if (ftp_logname) { user = ftp_logname; pass = ftp_tmp; } else if (uidbuf[0] && (ftp_tmp || pwbuf[0] && pwflg)) { user = uidbuf; if (ftp_tmp) { pass = ftp_tmp; } else if (pwbuf[0] && pwflg) { ckstrncpy(ftppass,pwbuf,PASSBUFSIZ); #ifdef OS2 if ( pwcrypt ) ck_encrypt((char *)ftppass); #endif /* OS2 */ pass = ftppass; } } acct = ftp_acc; while (user == NULL) { char *myname, prompt[PROMPTSIZ]; int ok; myname = whoami(); if (myname) ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ", NULL,NULL,NULL,NULL,NULL,NULL,NULL); else ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL); tmp[0] = '\0'; ok = uq_txt(NULL,prompt,1,NULL,tmp,PASSBUFSIZ,NULL, DEFAULT_UQ_TIMEOUT); if (!ok || *tmp == '\0') user = myname; else user = brstrip(tmp); } } n = ftpcmd("USER",user,-1,-1,ftp_vbm); if (n == REPLY_COMPLETE) { /* determine if we need to send a dummy password */ if (ftpcmd("PWD",NULL,0,0,0) != REPLY_COMPLETE) ftpcmd("PASS dummy",NULL,0,0,1); } else if (n == REPLY_CONTINUE) { #ifdef CK_ENCRYPTION int oldftp_cpl; #endif /* CK_ENCRYPTION */ if (pass == NULL) { int ok; setint(); ok = uq_txt(NULL," Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL, DEFAULT_UQ_TIMEOUT); if (ok) pass = brstrip(ftppass); } #ifdef CK_ENCRYPTION oldftp_cpl = ftp_cpl; ftp_cpl = FPL_PRV; #endif /* CK_ENCRYPTION */ n = ftpcmd("PASS",pass,-1,-1,1); if (!anonymous && pass) { char * p = pass; while (*p++) *(p-1) = NUL; makestr(&ftp_tmp,NULL); } #ifdef CK_ENCRYPTION /* level may have changed */ if (ftp_cpl == FPL_PRV) ftp_cpl = oldftp_cpl; #endif /* CK_ENCRYPTION */ } if (n == REPLY_CONTINUE) { aflag++; if (acct == NULL) { static char ftpacct[80]; int ok; setint(); ok = uq_txt(NULL," Account: ",2,NULL,ftpacct,80,NULL, DEFAULT_UQ_TIMEOUT); if (ok) acct = brstrip(ftpacct); } n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm); } if (n != REPLY_COMPLETE) { fprintf(stderr, "FTP login failed.\n"); if (haveurl) doexit(BAD_EXIT,-1); return(0); } if (!aflag && acct != NULL) { ftpcmd("ACCT",acct,-1,-1,ftp_vbm); } makestr(&ftp_logname,user); loggedin = 1; #ifdef LOCUS /* Unprefixed file management commands go to server */ if (autolocus && !ftp_cmdlin) { setlocus(0,1); } #endif /* LOCUS */ ftp_init(); if (anonymous && !quiet) { printf(" Logged in as anonymous (%s)\n",pass); memset(pass, 0, strlen(pass)); } if (ftp_rdir) { if (doftpcwd(ftp_rdir,-1) < 1) doexit(BAD_EXIT,-1); } #ifdef FTP_PROXY if (proxy) return(1); #endif /* FTP_PROXY */ return(1); } static int ftp_reset() { int rc; #ifdef BSDSELECT int nfnd = 1; fd_set mask; FD_ZERO(&mask); while (nfnd > 0) { FD_SET(csocket, &mask); if ((nfnd = empty(&mask,0)) < 0) { perror("reset"); ftpcode = -1; lostpeer(); return(0); } else if (nfnd) { getreply(0,-1,-1,ftp_vbm,0); } } #else /* BSDSELECT */ #ifdef IBMSELECT int nfnd = 1; while (nfnd > 0) { if ((nfnd = empty(&csocket,1,0)) < 0) { perror("reset"); ftpcode = -1; lostpeer(); return(0); } else if (nfnd) { getreply(0,-1,-1,ftp_vbm,0); } } #endif /* IBMSELECT */ #endif /* BSDSELECT */ rc = (ftpcmd("REIN",NULL,0,0,ftp_vbm) == REPLY_COMPLETE); if (rc > 0) loggedin = 0; return(rc); } static int #ifdef CK_ANSIC ftp_rename( char * from, char * to ) #else ftp_rename(from, to) char * from, * to; #endif /* CK_ANSIC */ { int lcs = -1, rcs = -1; #ifndef NOCSETS if (ftp_xla) { lcs = ftp_csl; if (lcs < 0) lcs = fcharset; rcs = ftp_csx; if (rcs < 0) rcs = ftp_csr; } #endif /* NOCSETS */ if (ftpcmd("RNFR",from,lcs,rcs,ftp_vbm) == REPLY_CONTINUE) { return(ftpcmd("RNTO",to,lcs,rcs,ftp_vbm) == REPLY_COMPLETE); } return(0); /* Failure */ } static int #ifdef CK_ANSIC ftp_umask( char * mask ) #else ftp_umask(mask) char * mask; #endif /* CK_ANSIC */ { int rc; rc = (ftpcmd("SITE UMASK",mask,-1,-1,1) == REPLY_COMPLETE); return(rc); } static int #ifdef CK_ANSIC ftp_user( char * user, char * pass, char * acct ) #else ftp_user(user,pass,acct) char * user, * pass, * acct; #endif /* CK_ANSIC */ { int n = 0, aflag = 0; char pwd[PWDSIZ]; if (!auth_type && ftp_aut) { #ifdef FTP_SRP if (ck_srp_is_installed()) { if (srp_ftp_auth( NULL, user, pass)) { makestr(&pass,srp_pass); } } #endif /* FTP_SRP */ } n = ftpcmd("USER",user,-1,-1,ftp_vbm); if (n == REPLY_COMPLETE) n = ftpcmd("PASS dummy",NULL,0,0,1); else if (n == REPLY_CONTINUE) { #ifdef CK_ENCRYPTION int oldftp_cpl; #endif /* CK_ENCRYPTION */ if (pass == NULL || !pass[0]) { int ok; pwd[0] = '\0'; setint(); ok = uq_txt(NULL," Password: ",2,NULL,pwd,PWDSIZ,NULL, DEFAULT_UQ_TIMEOUT); if (ok) pass = brstrip(pwd); } #ifdef CK_ENCRYPTION if ((oldftp_cpl = ftp_cpl) == PROT_S) ftp_cpl = PROT_P; #endif /* CK_ENCRYPTION */ n = ftpcmd("PASS",pass,-1,-1,1); memset(pass, 0, strlen(pass)); #ifdef CK_ENCRYPTION /* level may have changed */ if (ftp_cpl == PROT_P) ftp_cpl = oldftp_cpl; #endif /* CK_ENCRYPTION */ } if (n == REPLY_CONTINUE) { if (acct == NULL || !acct[0]) { int ok; pwd[0] = '\0'; setint(); ok = uq_txt(NULL," Account: ",2,NULL,pwd,PWDSIZ,NULL, DEFAULT_UQ_TIMEOUT); if (ok) acct = pwd; } n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm); aflag++; } if (n != REPLY_COMPLETE) { printf("Login failed.\n"); return(0); } if (!aflag && acct != NULL && acct[0]) { n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm); } if (n == REPLY_COMPLETE) { makestr(&ftp_logname,user); loggedin = 1; ftp_init(); return(1); } return(0); } char * ftp_authtype() { if (!connected) return("NULL"); return(auth_type ? auth_type : "NULL"); } char * ftp_cpl_mode() { switch (ftp_cpl) { case FPL_CLR: return("clear"); case FPL_SAF: return("safe"); case FPL_PRV: return("private"); case FPL_CON: return("confidential"); default: return("(error)"); } } char * ftp_dpl_mode() { switch (ftp_dpl) { case FPL_CLR: return("clear"); case FPL_SAF: return("safe"); case FPL_PRV: return("private"); case FPL_CON: return("confidential"); default: return("(error)"); } } /* remote_files() */ /* Returns next remote filename on success; NULL on error or no more files with global rfrc set to: -1: Bad argument -2: Server error response to NLST, e.g. file not found -3: No more files -9: Internal error */ #define FTPNAMBUFLEN CKMAXPATH+1024 /* Check: ckmaxfiles CKMAXOPEN */ #define MLSDEPTH 128 /* Stack of open temp files */ static int mlsdepth = 0; /* Temp file stack depth */ static FILE * tmpfilptr[MLSDEPTH+1] = { NULL, NULL }; /* Temp file pointers */ static char * tmpfilnam[MLSDEPTH+1] = { NULL, NULL }; /* Temp file names */ static VOID mlsreset() { /* Reset MGET temp-file stack */ int i; for (i = 0; i <= mlsdepth; i++) { if (tmpfilptr[i]) { fclose(tmpfilptr[i]); tmpfilptr[i] = NULL; if (tmpfilnam[i]) { #ifdef OS2 unlink(tmpfilnam[i]); #endif /* OS2 */ free(tmpfilnam[i]); } } } mlsdepth = 0; } static CHAR * #ifdef CK_ANSIC remote_files(int new_query, CHAR * arg, CHAR * pattern, int proxy_switch) #else /* CK_ANSIC */ remote_files(new_query, arg, pattern, proxy_switch) int new_query; CHAR * arg; /* That we send to the server */ CHAR * pattern; /* That we use locally */ int proxy_switch; #endif /* CK_ANSIC */ /* remote_files */ { static CHAR buf[FTPNAMBUFLEN]; CHAR *cp, *whicharg; char * cdto = NULL; char * p; int x, forced = 0; int lcs = 0, rcs = 0, xlate = 0; debug(F101,"ftp remote_files new_query","",new_query); debug(F110,"ftp remote_files arg",arg,0); debug(F110,"ftp remote_files pattern",pattern,0); rfrc = -1; if (pattern) /* Treat empty pattern same as NULL */ if (!*pattern) pattern = NULL; if (arg) /* Ditto for arg */ if (!*arg) arg = NULL; again: if (new_query) { if (tmpfilptr[mlsdepth]) { fclose(tmpfilptr[mlsdepth]); tmpfilptr[mlsdepth] = NULL; #ifdef OS2 if (!ftp_deb && !deblog) unlink(tmpfilnam[mlsdepth]); #endif /* OS2 */ } } if (tmpfilptr[mlsdepth] == NULL) { extern char * tempdir; char * p; debug(F110,"ftp remote_files tempdir",tempdir,0); if (tempdir) { p = tempdir; } else { #ifdef OS2 #ifdef NT p = getenv("K95TMP"); #else p = getenv("K2TMP"); #endif /* NT */ if (!p) #endif /* OS2 */ p = getenv("CK_TMP"); if (!p) p = getenv("TMPDIR"); if (!p) p = getenv("TEMP"); if (!p) p = getenv("TMP"); #ifdef OS2ORUNIX if (p) { int len = strlen(p); if (p[len-1] != '/' #ifdef OS2 && p[len-1] != '\\' #endif /* OS2 */ ) { static char foo[CKMAXPATH]; ckstrncpy(foo,p,CKMAXPATH); ckstrncat(foo,"/",CKMAXPATH); p = foo; } } else #else /* OS2ORUNIX */ if (!p) #endif /* OS2ORUNIX */ #ifdef UNIX /* Systems that have a standard */ p = "/tmp/"; /* temporary directory... */ #else #ifdef datageneral p = ":TMP:"; #else p = ""; #endif /* datageneral */ #endif /* UNIX */ } debug(F110,"ftp remote_files p",p,0); /* Get temp file */ if ((tmpfilnam[mlsdepth] = (char *)malloc(CKMAXPATH+1))) { ckmakmsg((char *)tmpfilnam[mlsdepth], CKMAXPATH+1,p,"ckXXXXXX",NULL,NULL); } else { printf("?Malloc failure: remote_files()\n"); return(NULL); } #ifdef NT { char * tmpfil = mktemp((char *)tmpfilnam[mlsdepth]); if ( tmpfil ) ckstrncpy(tmpfilnam[mlsdepth],tmpfil,CKMAXPATH+1); } #else /* NT */ #ifdef MKTEMP #ifdef MKSTEMP x = mkstemp((char *)tmpfilnam[mlsdepth]); if (x > -1) close(x); /* We just want the name. */ #else mktemp((char *)tmpfilnam[mlsdepth]); #endif /* MKSTEMP */ /* if no mktmpnam() the name will just be "ckXXXXXX"... */ #endif /* MKTEMP */ #endif /* NT */ debug(F111,"ftp remote_files tmpfilnam[mlsdepth]", tmpfilnam[mlsdepth],mlsdepth); #ifdef FTP_PROXY if (proxy_switch) { pswitch(!proxy); } #endif /* FTP_PROXY */ debug(F101,"ftp remote_files ftp_xla","",ftp_xla); debug(F101,"ftp remote_files ftp_csl","",ftp_csl); debug(F101,"ftp remote_files ftp_csr","",ftp_csr); #ifndef NOCSETS xlate = ftp_xla; /* SET FTP CHARACTER-SET-TRANSLATION */ if (xlate) { /* ON? */ lcs = ftp_csl; /* Local charset */ if (lcs < 0) lcs = fcharset; if (lcs < 0) xlate = 0; } if (xlate) { /* Still ON? */ rcs = ftp_csx; /* Remote (Server) charset */ if (rcs < 0) rcs = ftp_csr; if (rcs < 0) xlate = 0; } #endif /* NOCSETS */ forced = mgetforced; /* MGET method forced? */ if (!forced || !mgetmethod) /* Not forced... */ mgetmethod = (sfttab[0] && sfttab[SFT_MLST]) ? /* so pick one */ SND_MLS : SND_NLS; /* User's Command: Result: mget /nlst NLST (NULL) mget /nlst foo NLST foo mget /nlst *.txt NLST *.txt mget /nlst /match:*.txt NLST (NULL) mget /nlst /match:*.txt foo NLST foo mget /mlsd MLSD (NULL) mget /mlsd foo MLSD foo mget /mlsd *.txt MLSD (NULL) mget /mlsd /match:*.txt MLSD (NULL) mget /mlsd /match:*.txt foo MLSD foo */ x = -1; while (x < 0) { if (pattern) { /* Don't simplify this! */ whicharg = arg; } else if (mgetmethod == SND_MLS) { if (arg) whicharg = iswild((char *)arg) ? NULL : arg; else whicharg = NULL; } else { whicharg = arg; } debug(F110,"ftp remote_files mgetmethod", mgetmethod == SND_MLS ? "MLSD" : "NLST", 0); debug(F110,"ftp remote_files whicharg",whicharg,0); x = recvrequest((mgetmethod == SND_MLS) ? "MLSD" : "NLST", (char *)tmpfilnam[mlsdepth], (char *)whicharg, "wb", 0, 0, NULL, xlate, lcs, rcs ); if (x < 0) { /* Chosen method wasn't accepted */ if (forced) { if (ftpcode > 500 && ftpcode < 505 && !quiet) printf("?%s: Not supported by server\n", mgetmethod == SND_MLS ? "MLSD" : "NLST" ); rfrc = -2; /* Fail */ return(NULL); } /* Not forced - if MLSD failed, try NLST */ if (mgetmethod == SND_MLS) { /* Server lied about MLST */ sfttab[SFT_MLST] = 0; /* So disable it */ mlstok = 0; /* and */ mgetmethod = SND_NLS; /* try NLST */ continue; } rfrc = -2; return(NULL); } } #ifdef FTP_PROXY if (proxy_switch) { pswitch(!proxy); } #endif /* FTP_PROXY */ tmpfilptr[mlsdepth] = fopen((char *)tmpfilnam[mlsdepth], "r"); #ifndef OS2 if (tmpfilptr[mlsdepth]) { if (!ftp_deb && !deblog) unlink(tmpfilnam[mlsdepth]); } #endif /* OS2 */ /*notemp:*/ if (!tmpfilptr[mlsdepth]) { debug(F110,"ftp remote_files open fail",tmpfilnam[mlsdepth],0); if ((!dpyactive || ftp_deb)) printf("?Can't find list of remote files, oops\n"); rfrc = -9; return(NULL); } if (ftp_deb) printf("LISTFILE: %s\n",tmpfilnam[mlsdepth]); } buf[0] = NUL; buf[FTPNAMBUFLEN-1] = NUL; buf[FTPNAMBUFLEN-2] = NUL; /* We have to redo all this because the first time was only for */ /* for getting the file list, now it's for getting each file */ if (arg && mgetmethod == SND_MLS) { /* MLSD */ if (!pattern && iswild((char *)arg)) { pattern = arg; /* Wild arg is really a pattern */ if (pattern) if (!*pattern) pattern = NULL; arg = NULL; /* and not an arg */ } if (new_query) { /* Initial query? */ cdto = (char *)arg; /* (nonwild) arg given? */ if (cdto) if (!*cdto) cdto = NULL; if (cdto) /* If so, then CD to it */ doftpcwd(cdto,0); } } new_query = 0; if (fgets((char *)buf, FTPNAMBUFLEN, tmpfilptr[mlsdepth]) == NULL) { fclose(tmpfilptr[mlsdepth]); tmpfilptr[mlsdepth] = NULL; #ifdef OS2 if (!ftp_deb && !deblog) unlink(tmpfilnam[mlsdepth]); #endif /* OS2 */ if (ftp_deb && !deblog) { printf("(Temporary file %s NOT deleted)\n", (char *)tmpfilnam[mlsdepth]); } if (mlsdepth <= 0) { /* EOF at depth 0 */ rfrc = -3; /* means we're done */ return(NULL); } printf("POPPING(%d)...\n",mlsdepth-1); if (tmpfilnam[mlsdepth]) free(tmpfilnam[mlsdepth]); mlsdepth--; doftpcdup(); zchdir(".."); /* <-- Not portable */ goto again; } if (buf[FTPNAMBUFLEN-1]) { printf("?BUFFER OVERFLOW -- FTP NLST or MLSD string longer than %d\n", FTPNAMBUFLEN ); debug(F101,"remote_files buffer overrun","",FTPNAMBUFLEN); return(NULL); } /* debug(F110,"ftp remote_files buf 1",buf,0); */ if ((cp = (CHAR *)ckstrchr((char *)buf,'\n')) != NULL) *cp = '\0'; if ((cp = (CHAR *)ckstrchr((char *)buf,'\r')) != NULL) *cp = '\0'; debug(F110,"ftp remote_files buf",buf,0); rfrc = 0; if (ftp_deb) printf("[%s]\n",(char *)buf); havesize = (CK_OFF_T)-1; /* Initialize file facts... */ havetype = 0; makestr(&havemdtm,NULL); p = (char *)buf; if (mgetmethod == SND_NLS) { /* NLST... */ if (pattern) { if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1)) goto again; } } else { /* MLSD... */ p = parsefacts((char *)buf); switch (havetype) { case FTYP_FILE: /* File: Get it if it matches */ if (pattern) { if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1)) goto again; } break; case FTYP_CDIR: /* Current directory */ case FTYP_PDIR: /* Parent directory */ goto again; /* Skip */ case FTYP_DIR: /* (Sub)Directory */ if (!recursive) /* If not /RECURSIVE */ goto again; /* Skip */ if (mlsdepth < MLSDEPTH) { char * p2 = NULL; mlsdepth++; printf("RECURSING [%s](%d)...\n",p,mlsdepth); if (doftpcwd(p,0) > 0) { int x; if (!ckstrchr(p,'/')) { /* zmkdir() needs dirsep */ if ((p2 = (char *)malloc((int)strlen(p) + 2))) { strcpy(p2,p); /* SAFE */ strcat(p2,"/"); /* SAFE */ p = p2; } } #ifdef NOMKDIR x = -1; #else x = zmkdir(p); #endif /* NOMKDIR */ if (x > -1) { zchdir(p); p = (char *)remote_files(1,arg,pattern,0); if (p2) free(p2); } else { printf("?mkdir failed: [%s] Depth=%d\n", p, mlsdepth ); mlsreset(); if (p2) free(p2); return(NULL); } } else { printf("?CWD failed: [%s] Depth=%d\n",p,mlsdepth); mlsreset(); return(NULL); } } else { printf("MAX DIRECTORY STACK DEPTH EXCEEDED: %d\n", mlsdepth ); mlsreset(); return(NULL); } } } #ifdef DEBUG if (deblog) { debug(F101,"remote_files havesize","",havesize); debug(F101,"remote_files havetype","",havetype); debug(F110,"remote_files havemdtm",havemdtm,0); debug(F110,"remote_files name",p,0); } #endif /* DEBUG */ return((CHAR *)p); } /* N O T P O R T A B L E !!! */ #if (SIZEOF_SHORT == 4) typedef unsigned short ftp_uint32; typedef short ftp_int32; #else #if (SIZEOF_INT == 4) typedef unsigned int ftp_uint32; typedef int ftp_int32; #else #if (SIZEOF_LONG == 4) typedef ULONG ftp_uint32; typedef long ftp_int32; #endif #endif #endif /* Perhaps use these in general, certainly use them for GSSAPI */ #ifndef looping_write #define ftp_int32 int #define ftp_uint32 unsigned int static int #ifdef CK_ANSIC looping_write( int fd, register CONST char *buf, int len ) #else looping_write(fd, buf, len) int fd; register CONST char *buf; int len; #endif /* CK_ANSIC */ { int cc; register int wrlen = len; do { cc = send(fd, (SENDARG2TYPE)buf, wrlen, 0); if (cc < 0) { if (errno == EINTR) continue; return(cc); } else { buf += cc; wrlen -= cc; } } while (wrlen > 0); return(len); } #endif #ifndef looping_read static int #ifdef CK_ANSIC looping_read( int fd, register char *buf, register int len ) #else looping_read(fd, buf, len) int fd; register char *buf; register int len; #endif /* CK_ANSIC */ { int cc, len2 = 0; do { cc = recv(fd, (char *)buf, len,0); if (cc < 0) { if (errno == EINTR) continue; return(cc); /* errno is already set */ } else if (cc == 0) { return(len2); } else { buf += cc; len2 += cc; len -= cc; } } while (len > 0); return(len2); } #endif /* looping_read */ #define ERR -2 #ifdef COMMENT static #ifdef CK_ANSIC secure_putbyte( int fd, CHAR c ) #else secure_putbyte(fd, c) int fd; CHAR c; #endif /* CK_ANSIC */ { int ret; ucbuf[nout++] = c; if (nout == (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR) { nout = 0; if (!ftpissecure()) ret = send(fd, (SENDARG2TYPE)ucbuf, (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR, 0); else ret = secure_putbuf(fd, ucbuf, (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR ); return(ret?ret:c); } return(c); } #endif /* COMMENT */ /* returns: * 0 on success * -1 on error (errno set) * -2 on security error */ static int #ifdef CK_ANSIC secure_flush( int fd ) #else secure_flush(fd) int fd; #endif /* CK_ANSIC */ { int rc = 0; int len = 0; if (nout > 0) { len = nout; if (!ftpissecure()) { rc = send(fd, (SENDARG2TYPE)ucbuf, nout, 0); nout = 0; goto xflush; } else { rc = secure_putbuf(fd, ucbuf, nout); if (rc) goto xflush; } } rc = (!ftpissecure()) ? 0 : secure_putbuf(fd, (CHAR *)"", nout = 0); xflush: if (rc > -1 && len > 0 && fdispla != XYFD_B) { spackets++; spktl = len; ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL); } return(rc); } #ifdef COMMENT /* (not used) */ /* returns: * c>=0 on success * -1 on error * -2 on security error */ static int #ifdef CK_ANSIC secure_putc(char c, int fd) #else secure_putc(c, fd) char c; int fd; #endif /* CK_ANSIC */ /* secure_putc */ { return(secure_putbyte(fd, (CHAR) c)); } #endif /* COMMENT */ /* returns: * nbyte on success * -1 on error (errno set) * -2 on security error */ static int #ifdef CK_ANSIC secure_write(int fd, CHAR * buf, unsigned int nbyte) #else secure_write(fd, buf, nbyte) int fd; CHAR * buf; unsigned int nbyte; #endif /* CK_ANSIC */ { int ret; #ifdef FTP_TIMEOUT ftp_timed_out = 0; if (check_data_connection(fd,1) < 0) { ftp_timed_out = 1; return(-3); } #endif /* FTP_TIMEOUT */ if (!ftpissecure()) { if (nout > 0) { if ((ret = send(fd, (SENDARG2TYPE)ucbuf, nout, 0)) < 0) return(ret); nout = 0; } return(send(fd,(SENDARG2TYPE)buf,nbyte,0)); } else { int ucbuflen = (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR; int bsent = 0; while (bsent < nbyte) { int b2cp = ((nbyte - bsent) > (ucbuflen - nout) ? (ucbuflen - nout) : (nbyte - bsent)); #ifdef DEBUG if (deblog) { debug(F101,"secure_write ucbuflen","",ucbuflen); debug(F101,"secure_write ucbufsiz","",ucbufsiz); debug(F101,"secure_write bsent","",bsent); debug(F101,"secure_write b2cp","",b2cp); } #endif /* DEBUG */ memcpy(&ucbuf[nout],&buf[bsent],b2cp); nout += b2cp; bsent += b2cp; if (nout == ucbuflen) { nout = 0; ret = secure_putbuf(fd, ucbuf, ucbuflen); if (ret < 0) return(ret); } } return(bsent); } } /* returns: * 0 on success * -1 on error (errno set) * -2 on security error */ static int #ifdef CK_ANSIC secure_putbuf(int fd, CHAR * buf, unsigned int nbyte) #else secure_putbuf(fd, buf, nbyte) int fd; CHAR * buf; unsigned int nbyte; #endif /* CK_ANSIC */ { static char *outbuf = NULL; /* output ciphertext */ #ifdef FTP_SECURITY static unsigned int bufsize = 0; /* size of outbuf */ #endif /* FTP_SECURITY */ ftp_int32 length = 0; ftp_uint32 net_len = 0; /* Other auth types go here ... */ #ifdef CK_SSL if (ssl_ftp_data_active_flag) { int count, error; /* there is no need to send an empty buffer when using SSL/TLS */ if ( nbyte == 0 ) return(0); count = SSL_write(ssl_ftp_data_con, buf, nbyte); error = SSL_get_error(ssl_ftp_data_con,count); switch (error) { case SSL_ERROR_NONE: return(0); case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_SYSCALL: #ifdef NT { int gle = GetLastError(); if (gle == 0) return(0); debug(F111,"secure_putbuf","SSL_ERROR_SYSCALL",gle); } #endif /* NT */ case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: SSL_shutdown(ssl_ftp_data_con); SSL_free(ssl_ftp_data_con); ssl_ftp_data_active_flag = 0; ssl_ftp_data_con = NULL; #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = -1; globaldin = data; return(-1); } return(-1); } #endif /* CK_SSL */ #ifdef FTP_SRP if (ck_srp_is_installed() && (strcmp(auth_type, "SRP") == 0)) { if (bufsize < nbyte + FUDGE_FACTOR) { if (outbuf? (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))): (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) { bufsize = nbyte + FUDGE_FACTOR; } else { bufsize = 0; secure_error("%s (in malloc of PROT buffer)", ck_errstr()); return(ERR); } } if ((length = srp_encode(ftp_dpl == FPL_PRV, (CHAR *) buf, (CHAR *) outbuf, nbyte ) ) < 0) { secure_error ("srp_encode failed"); return ERR; } } #endif /* FTP_SRP */ #ifdef FTP_KRB4 if (ck_krb4_is_installed() && (strcmp(auth_type, "KERBEROS_V4") == 0)) { struct sockaddr_in myaddr, hisaddr; GSOCKNAME_T len; len = sizeof(myaddr); if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) { secure_error("secure_putbuf: getsockname failed"); return(ERR); } len = sizeof(hisaddr); if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) { secure_error("secure_putbuf: getpeername failed"); return(ERR); } if (bufsize < nbyte + FUDGE_FACTOR) { if (outbuf ? (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))): (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) { bufsize = nbyte + FUDGE_FACTOR; } else { bufsize = 0; secure_error("%s (in malloc of PROT buffer)", ck_errstr()); return(ERR); } } if (ftp_dpl == FPL_PRV) { length = krb_mk_priv(buf, (CHAR *) outbuf, nbyte, ftp_sched, #ifdef KRB524 ftp_cred.session, #else /* KRB524 */ &ftp_cred.session, #endif /* KRB524 */ &myaddr, &hisaddr ); } else { length = krb_mk_safe(buf, (CHAR *) outbuf, nbyte, #ifdef KRB524 ftp_cred.session, #else /* KRB524 */ &ftp_cred.session, #endif /* KRB524 */ &myaddr, &hisaddr ); } if (length == -1) { secure_error("krb_mk_%s failed for KERBEROS_V4", ftp_dpl == FPL_PRV ? "priv" : "safe"); return(ERR); } } #endif /* FTP_KRB4 */ #ifdef FTP_GSSAPI if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) { gss_buffer_desc in_buf, out_buf; OM_uint32 maj_stat, min_stat; int conf_state; in_buf.value = buf; in_buf.length = nbyte; maj_stat = gss_seal(&min_stat, gcontext, (ftp_dpl == FPL_PRV), /* confidential */ GSS_C_QOP_DEFAULT, &in_buf, &conf_state, &out_buf ); if (maj_stat != GSS_S_COMPLETE) { /* generally need to deal */ /* ie. should loop, but for now just fail */ user_gss_error(maj_stat, min_stat, ftp_dpl == FPL_PRV? "GSSAPI seal failed": "GSSAPI sign failed"); return(ERR); } if (bufsize < out_buf.length) { if (outbuf ? (outbuf = realloc(outbuf, (unsigned) out_buf.length)): (outbuf = malloc((unsigned) out_buf.length))) { bufsize = out_buf.length; } else { bufsize = 0; secure_error("%s (in malloc of PROT buffer)", ck_errstr()); return(ERR); } } memcpy(outbuf, out_buf.value, length=out_buf.length); gss_release_buffer(&min_stat, &out_buf); } #endif /* FTP_GSSAPI */ net_len = htonl((ULONG) length); if (looping_write(fd, (char *)&net_len, 4) == -1) return(-1); if (looping_write(fd, outbuf, length) != length) return(-1); return(0); } /* fc = 0 means to get a byte; nonzero means to initialize buffer pointers */ static int #ifdef CK_ANSIC secure_getbyte( int fd, int fc ) #else secure_getbyte(fd,fc) int fd,fc; #endif /* CK_ANSIC */ { /* number of chars in ucbuf, pointer into ucbuf */ static unsigned int nin = 0, bufp = 0; int kerror; ftp_uint32 length; if (fc) { nin = bufp = 0; ucbuf[0] = NUL; return(0); } if (nin == 0) { if (iscanceled()) return(-9); #ifdef FTP_TIMEOUT if (check_data_connection(fd,0) < 0) return(-3); #endif /* FTP_TIMEOUT */ #ifdef CK_SSL if (ssl_ftp_data_active_flag) { int count, error; count = SSL_read(ssl_ftp_data_con, ucbuf, ucbufsiz); error = SSL_get_error(ssl_ftp_data_con,count); #ifdef DEBUG if (error != SSL_ERROR_NONE) debug(F101,"ftp secure_getbyte error","",error); if (count == 0) debug(F101,"ftp secure_getbyte count","",count); #endif /* DEBUG */ switch (error) { case SSL_ERROR_NONE: if (count > 0) { nin = bufp = count; rpackets++; pktnum++; if (fdispla != XYFD_B) { rpktl = count; ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL); } break; } case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_SYSCALL: #ifdef NT { int gle = GetLastError(); } #endif /* NT */ case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: nin = bufp = count = 0; SSL_shutdown(ssl_ftp_data_con); SSL_free(ssl_ftp_data_con); ssl_ftp_data_active_flag = 0; ssl_ftp_data_con = NULL; #ifdef TCPIPLIB socket_close(data); #else /* TCPIPLIB */ #ifdef USE_SHUTDOWN shutdown(data, 1+1); #endif /* USE_SHUTDOWN */ close(data); #endif /* TCPIPLIB */ data = -1; globaldin = data; break; } } else #endif /* CK_SSL */ { kerror = looping_read(fd, (char *)&length, sizeof(length)); if (kerror != sizeof(length)) { secure_error("Couldn't read PROT buffer length: %d/%s", kerror, kerror == -1 ? ck_errstr() : "premature EOF" ); return(ERR); } debug(F101,"secure_getbyte length","",length); debug(F101,"secure_getbyte ntohl(length)","",ntohl(length)); length = (ULONG) ntohl(length); if (length > maxbuf) { secure_error("Length (%d) of PROT buffer > PBSZ=%u", length, maxbuf ); return(ERR); } if ((kerror = looping_read(fd,(char *)ucbuf,length)) != length) { secure_error("Couldn't read %u byte PROT buffer: %s", length, kerror == -1 ? ck_errstr() : "premature EOF" ); return(ERR); } /* Other auth types go here ... */ #ifdef FTP_SRP if (strcmp(auth_type, "SRP") == 0) { if ((nin = bufp = srp_decode (ftp_dpl == FPL_PRV, (CHAR *) ucbuf, ucbuf, length ) ) == -1) { secure_error ("srp_encode failed" ); return ERR; } } #endif /* FTP_SRP */ #ifdef FTP_KRB4 if (strcmp(auth_type, "KERBEROS_V4") == 0) { struct sockaddr_in myaddr, hisaddr; GSOCKNAME_T len; len = sizeof(myaddr); if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) { secure_error("secure_putbuf: getsockname failed"); return(ERR); } len = sizeof(hisaddr); if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) { secure_error("secure_putbuf: getpeername failed"); return(ERR); } if (ftp_dpl) { kerror = krb_rd_priv(ucbuf, length, ftp_sched, #ifdef KRB524 ftp_cred.session, #else /* KRB524 */ &ftp_cred.session, #endif /* KRB524 */ &hisaddr, &myaddr, &ftp_msg_data); } else { kerror = krb_rd_safe(ucbuf, length, #ifdef KRB524 ftp_cred.session, #else /* KRB524 */ &ftp_cred.session, #endif /* KRB524 */ &hisaddr, &myaddr, &ftp_msg_data); } if (kerror) { secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)", ftp_dpl == FPL_PRV ? "priv" : "safe", krb_get_err_text(kerror)); return(ERR); } memcpy(ucbuf,ftp_msg_data.app_data,ftp_msg_data.app_length); nin = bufp = ftp_msg_data.app_length; } #endif /* FTP_KRB4 */ #ifdef FTP_GSSAPI if (strcmp(auth_type, "GSSAPI") == 0) { gss_buffer_desc xmit_buf, msg_buf; OM_uint32 maj_stat, min_stat; int conf_state; xmit_buf.value = ucbuf; xmit_buf.length = length; conf_state = (ftp_dpl == FPL_PRV); /* decrypt/verify the message */ maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf, &msg_buf, &conf_state, NULL); if (maj_stat != GSS_S_COMPLETE) { user_gss_error(maj_stat, min_stat, (ftp_dpl == FPL_PRV)? "failed unsealing ENC message": "failed unsealing MIC message"); return ERR; } memcpy(ucbuf, msg_buf.value, nin = bufp = msg_buf.length); gss_release_buffer(&min_stat, &msg_buf); } #endif /* FTP_GSSAPI */ /* Other auth types go here ... */ /* Update file transfer display */ rpackets++; pktnum++; if (fdispla != XYFD_B) { rpktl = nin; ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL); } } } if (nin == 0) return(EOF); else return(ucbuf[bufp - nin--]); } /* secure_getc(fd,fc) * Call with: * fd = file descriptor for connection. * fc = 0 to get a character, fc != 0 to initialize buffer pointers. * Returns: * c>=0 on success (character value) * -1 on EOF * -2 on security error * -3 on timeout (if built with FTP_TIMEOUT defined) */ static int #ifdef CK_ANSIC secure_getc( int fd, int fc ) /* file descriptor, function code */ #else secure_getc(fd,fc) int fd,fc; #endif /* CK_ANSIC */ { if (!ftpissecure()) { static unsigned int nin = 0, bufp = 0; if (fc) { nin = bufp = 0; ucbuf[0] = NUL; return(0); } if (nin == 0) { if (iscanceled()) return(-9); #ifdef FTP_TIMEOUT if (check_data_connection(fd,0) < 0) { debug(F100,"secure_getc TIMEOUT","",0); nin = bufp = 0; ftp_timed_out = 1; return(-3); } #endif /* FTP_TIMEOUT */ nin = bufp = recv(fd,(char *)ucbuf,actualbuf,0); if ((nin == 0) || (nin == (unsigned int)-1)) { debug(F111,"secure_getc recv errno",ckitoa(nin),errno); debug(F101,"secure_getc returns EOF","",EOF); nin = bufp = 0; return(EOF); } debug(F101,"ftp secure_getc recv","",nin); ckhexdump("ftp secure_getc recv",ucbuf,16); rpackets++; pktnum++; if (fdispla != XYFD_B) { rpktl = nin; ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL); } } return(ucbuf[bufp - nin--]); } else return(secure_getbyte(fd,fc)); } /* returns: * n>0 on success (n == # of bytes read) * 0 on EOF * -1 on error (errno set), only for FPL_CLR * -2 on security error */ static int #ifdef CK_ANSIC secure_read( int fd, char *buf, int nbyte ) #else secure_read(fd, buf, nbyte) int fd; char *buf; int nbyte; #endif /* CK_ANSIC */ { static int c = 0; int i; debug(F101,"secure_read bytes requested","",nbyte); if (c == EOF) return(c = 0); for (i = 0; nbyte > 0; nbyte--) { c = secure_getc(fd,0); switch (c) { case -9: /* Canceled from keyboard */ debug(F101,"ftp secure_read interrupted","",c); return(0); case ERR: debug(F101,"ftp secure_read error","",c); return(c); case EOF: debug(F101,"ftp secure_read EOF","",c); if (!i) c = 0; return(i); #ifdef FTP_TIMEOUT case -3: debug(F101,"ftp secure_read timeout","",c); return(c); #endif /* FTP_TIMEOUT */ default: buf[i++] = c; } } return(i); } #ifdef USE_RUSERPASS /* BEGIN_RUSERPASS * * Copyright (c) 1985 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char sccsid[] = "@(#)ruserpass.c 5.3 (Berkeley) 3/1/91"; #endif /* not lint */ #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif char * renvlook(); static FILE * cfile; #define DEFAULT 1 #define LOGIN 2 #define PASSWD 3 #define ACCOUNT 4 #define MACDEF 5 #define ID 10 #define MACH 11 static char tokval[100]; static struct toktab { char *tokstr; int tval; } toktab[]= { "default", DEFAULT, "login", LOGIN, "password", PASSWD, "passwd", PASSWD, "account", ACCOUNT, "machine", MACH, "macdef", MACDEF, 0, 0 }; static int token() { char *cp; int c; struct toktab *t; if (feof(cfile)) return(0); while ((c = getc(cfile)) != EOF && (c == '\n' || c == '\t' || c == ' ' || c == ',')) continue; if (c == EOF) return(0); cp = tokval; if (c == '"') { while ((c = getc(cfile)) != EOF && c != '"') { if (c == '\\') c = getc(cfile); *cp++ = c; } } else { *cp++ = c; while ((c = getc(cfile)) != EOF && c != '\n' && c != '\t' && c != ' ' && c != ',') { if (c == '\\') c = getc(cfile); *cp++ = c; } } *cp = 0; if (tokval[0] == 0) return(0); for (t = toktab; t->tokstr; t++) if (!strcmp(t->tokstr, tokval)) return(t->tval); return(ID); } ruserpass(host, aname, apass, aacct) char *host, **aname, **apass, **aacct; { char *hdir, buf[FTP_BUFSIZ], *tmp; char myname[MAXHOSTNAMELEN], *mydomain; int t, i, c, usedefault = 0; #ifdef NT struct _stat stb; #else /* NT */ struct stat stb; #endif /* NT */ hdir = getenv("HOME"); if (hdir == NULL) hdir = "."; ckmakmsg(buf,FTP_BUFSIZ,hdir,"/.netrc",NULL,NULL); cfile = fopen(buf, "r"); if (cfile == NULL) { if (errno != ENOENT) perror(buf); return(0); } if (gethostname(myname, MAXHOSTNAMELEN) < 0) myname[0] = '\0'; if ((mydomain = ckstrchr(myname, '.')) == NULL) mydomain = ""; next: while ((t = token())) switch(t) { case DEFAULT: usedefault = 1; /* FALL THROUGH */ case MACH: if (!usedefault) { if (token() != ID) continue; /* * Allow match either for user's input host name * or official hostname. Also allow match of * incompletely-specified host in local domain. */ if (ckstrcmp(host, tokval,-1,1) == 0) goto match; if (ckstrcmp(ftp_host, tokval,-1,0) == 0) goto match; if ((tmp = ckstrchr(ftp_host, '.')) != NULL && ckstrcmp(tmp, mydomain,-1,1) == 0 && ckstrcmp(ftp_host, tokval, tmp-ftp_host,0) == 0 && tokval[tmp - ftp_host] == '\0') goto match; if ((tmp = ckstrchr(host, '.')) != NULL && ckstrcmp(tmp, mydomain,-1,1) == 0 && ckstrcmp(host, tokval, tmp - host, 0) == 0 && tokval[tmp - host] == '\0') goto match; continue; } match: while ((t = token()) && t != MACH && t != DEFAULT) switch(t) { case LOGIN: if (token()) if (*aname == 0) { *aname = malloc((unsigned) strlen(tokval) + 1); strcpy(*aname, tokval); /* safe */ } else { if (strcmp(*aname, tokval)) goto next; } break; case PASSWD: if (strcmp(*aname, "anonymous") && fstat(fileno(cfile), &stb) >= 0 && (stb.st_mode & 077) != 0) { fprintf(stderr, "Error - .netrc file not correct mode.\n"); fprintf(stderr, "Remove password or correct mode.\n"); goto bad; } if (token() && *apass == 0) { *apass = malloc((unsigned) strlen(tokval) + 1); strcpy(*apass, tokval); /* safe */ } break; case ACCOUNT: if (fstat(fileno(cfile), &stb) >= 0 && (stb.st_mode & 077) != 0) { fprintf(stderr, "Error - .netrc file not correct mode.\n"); fprintf(stderr, "Remove account or correct mode.\n"); goto bad; } if (token() && *aacct == 0) { *aacct = malloc((unsigned) strlen(tokval) + 1); strcpy(*aacct, tokval); /* safe */ } break; default: fprintf(stderr, "Unknown .netrc keyword %s\n", tokval); break; } goto done; } done: fclose(cfile); return(0); bad: fclose(cfile); return(-1); } #endif /* USE_RUSERPASS */ static char *radixN = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static char pad = '='; static int #ifdef CK_ANSIC #else #endif /* CK_ANSIC */ #ifdef CK_ANSIC radix_encode( CHAR inbuf[],CHAR outbuf[], int inlen, int *outlen, int decode ) #else radix_encode(inbuf, outbuf, inlen, outlen, decode) CHAR inbuf[], outbuf[]; int inlen, *outlen, decode; #endif /* CK_ANSIC */ { int i, j, D = 0; char *p; CHAR c = NUL; if (decode) { for (i = 0, j = 0; inbuf[i] && inbuf[i] != pad; i++) { if ((p = ckstrchr(radixN, inbuf[i])) == NULL) return(1); D = p - radixN; switch (i&3) { case 0: outbuf[j] = D<<2; break; case 1: outbuf[j++] |= D>>4; outbuf[j] = (D&15)<<4; break; case 2: outbuf[j++] |= D>>2; outbuf[j] = (D&3)<<6; break; case 3: outbuf[j++] |= D; } if (j == *outlen) return(4); } switch (i&3) { case 1: return(3); case 2: if (D&15) return(3); if (strcmp((char *)&inbuf[i], "==")) return(2); break; case 3: if (D&3) return(3); if (strcmp((char *)&inbuf[i], "=")) return(2); } *outlen = j; } else { for (i = 0, j = 0; i < inlen; i++) { switch (i%3) { case 0: outbuf[j++] = radixN[inbuf[i]>>2]; c = (inbuf[i]&3)<<4; break; case 1: outbuf[j++] = radixN[c|inbuf[i]>>4]; c = (inbuf[i]&15)<<2; break; case 2: outbuf[j++] = radixN[c|inbuf[i]>>6]; outbuf[j++] = radixN[inbuf[i]&63]; c = 0; } if (j == *outlen) return(4); } if (i%3) outbuf[j++] = radixN[c]; switch (i%3) { case 1: outbuf[j++] = pad; case 2: outbuf[j++] = pad; } outbuf[*outlen = j] = '\0'; } return(0); } static char * #ifdef CK_ANSIC radix_error( int e ) #else radix_error(e) int e; #endif /* CK_ANSIC */ { switch (e) { case 0: return("Success"); case 1: return("Bad character in encoding"); case 2: return("Encoding not properly padded"); case 3: return("Decoded # of bits not a multiple of 8"); case 4: return("Output buffer too small"); default: return("Unknown error"); } } /* END_RUSERPASS */ #ifdef FTP_SRP /*---------------------------------------------------------------------------+ | | | Package: srpftp | | Author: Eugene Jhong | | | +---------------------------------------------------------------------------*/ /* * Copyright (c) 1997-1999 The Stanford SRP Authentication Project * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * In addition, the following conditions apply: * * 1. Any software that incorporates the SRP authentication technology * must display the following acknowlegment: * "This product uses the 'Secure Remote Password' cryptographic * authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)." * * 2. Any software that incorporates all or part of the SRP distribution * itself must also display the following acknowledgment: * "This product includes software developed by Tom Wu and Eugene * Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)." * * 3. Redistributions in source or binary form must retain an intact copy * of this copyright notice and list of conditions. */ #define SRP_PROT_VERSION 1 #ifdef CK_ENCRYPTION #define SRP_DEFAULT_CIPHER CIPHER_ID_CAST5_CBC #else #define SRP_DEFAULT_CIPHER CIPHER_ID_NONE #endif /* CK_ENCRYPTION */ #define SRP_DEFAULT_HASH HASH_ID_SHA CHAR srp_pref_cipher = CIPHER_ID_DES3_ECB; CHAR srp_pref_hash = HASH_ID_SHA; static struct t_client *tc = NULL; static CHAR *skey = NULL; static krypto_context *incrypt = NULL; static krypto_context *outcrypt = NULL; typedef unsigned int srp_uint32; /*--------------------------------------------------------------+ | srp_selcipher: select cipher | +--------------------------------------------------------------*/ static int srp_selcipher (cname) char *cname; { cipher_desc *cd; if (!(cd = cipher_getdescbyname (cname))) { int i; CHAR *list = cipher_getlist (); fprintf (stderr, "ftp: supported ciphers:\n\n"); for (i = 0; i < strlen (list); i++) fprintf (stderr, " %s\n", (cipher_getdescbyid(list[i]))->name); fprintf (stderr, "\n"); return -1; } srp_pref_cipher = cd->id; return 0; } /*--------------------------------------------------------------+ | srp_selhash: select hash | +--------------------------------------------------------------*/ static int srp_selhash (hname) char *hname; { hash_desc *hd; if (!(hd = hash_getdescbyname (hname))) { int i; CHAR *list = hash_getlist (); fprintf (stderr, "ftp: supported hash functions:\n\n"); for (i = 0; i < strlen (list); i++) fprintf (stderr, " %s\n", (hash_getdescbyid(list[i]))->name); fprintf (stderr, "\n"); return -1; } srp_pref_hash = hd->id; return 0; } /*--------------------------------------------------------------+ | srp_userpass: get username and password | +--------------------------------------------------------------*/ static int srp_userpass (host) char *host; { char tmp[BUFSIZ], prompt[PROMPTSIZ]; char *user; user = NULL; #ifdef USE_RUSERPASS ruserpass (host, &user, &srp_pass, &srp_acct); #endif /* USE_RUSERPASS */ while (user == NULL) { char *myname; int ok; myname = whoami(); if (!myname) myname = ""; if (myname[0]) ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ", NULL,NULL,NULL,NULL,NULL,NULL,NULL); else ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL); tmp[0] = '\0'; ok = uq_txt(NULL,prompt,1,NULL,tmp,BUFSIZ,NULL, DEFAULT_UQ_TIMEOUT); if (!ok || *tmp == '\0') user = myname; else user = brstrip(tmp); } ckstrncpy (srp_user, user,BUFSIZ); return(0); } /*--------------------------------------------------------------+ | srp_reset: reset srp information | +--------------------------------------------------------------*/ static int srp_reset () { if (tc) { t_clientclose (tc); tc = NULL; } if (incrypt) { krypto_delete (incrypt); incrypt = NULL; } if (outcrypt) { krypto_delete (outcrypt); outcrypt = NULL; } return(0); } /*--------------------------------------------------------------+ | srp_ftp_auth: perform srp authentication | +--------------------------------------------------------------*/ static int srp_ftp_auth(host, user, pass) char *host; char *user; char *pass; { struct t_num *wp; struct t_num N; struct t_num g; struct t_num s; struct t_num yp; CHAR buf[FTP_BUFSIZ]; CHAR tmp[FTP_BUFSIZ]; CHAR *bp, *cp; int n, e, clen, blen, len, i; CHAR cid = 0; CHAR hid = 0; srp_pass = srp_acct = 0; n = ftpcmd("AUTH SRP",NULL,0,0,ftp_vbm); if (n != REPLY_CONTINUE) { if (ftp_deb) fprintf(stderr, "SRP rejected as an authentication type\n"); return(0); } else { /* Send protocol version */ CHAR vers[4]; memset (vers, 0, 4); vers[3] = SRP_PROT_VERSION; if (!quiet) printf ("SRP accepted as authentication type.\n"); bp = tmp; blen = 0; srp_put (vers, &bp, 4, &blen); len = FTP_BUFSIZ; if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE)) goto encode_error; reply_parse = "ADAT="; n = ftpcmd("ADAT",buf,-1,-1,0); } if (n == REPLY_CONTINUE) { /* Get protocol version */ bp = buf; if (!reply_parse) goto data_error; blen = FTP_BUFSIZ; if (e = radix_encode(reply_parse, bp, 0, &blen, RADIX_DECODE)) goto decode_error; if (srp_get (&bp, &cp, &blen, &clen) != 4) goto data_error; if (host) { /* Get username/password if needed */ srp_userpass (host); } else { ckstrncpy (srp_user, user, BUFSIZ); srp_pass = pass; } bp = tmp; blen = 0; /* Send username */ srp_put (srp_user, &bp, strlen (srp_user), &blen); len = FTP_BUFSIZ; if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE)) goto encode_error; reply_parse = "ADAT="; n = ftpcmd("ADAT",buf,-1,-1,0); } if (n == REPLY_CONTINUE) { /* Get N, g and s */ bp = buf; if (!reply_parse) goto data_error; blen = FTP_BUFSIZ; if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE)) goto decode_error; if (srp_get (&bp, &(N.data), &blen, &(N.len)) < 0) goto data_error; if (srp_get (&bp, &(g.data), &blen, &(g.len)) < 0) goto data_error; if (srp_get (&bp, &(s.data), &blen, &(s.len)) < 0) goto data_error; if ((tc = t_clientopen (srp_user, &N, &g, &s)) == NULL) { fprintf (stderr, "Unable to open SRP client structure.\n"); goto bad; } wp = t_clientgenexp (tc); /* Send wp */ bp = tmp; blen = 0; srp_put (wp->data, &bp, wp->len, &blen); len = FTP_BUFSIZ; if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE)) goto encode_error; reply_parse = "ADAT="; n = ftpcmd("ADAT",buf,-1,-1,0); } if (n == REPLY_CONTINUE) { /* Get yp */ bp = buf; if (!reply_parse) goto data_error; blen = FTP_BUFSIZ; if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE)) goto decode_error; if (srp_get (&bp, &(yp.data), &blen, &(yp.len)) < 0) goto data_error; if (!srp_pass) { static char ftppass[PASSBUFSIZ]; int ok; setint(); ok = uq_txt(NULL," SRP Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL, DEFAULT_UQ_TIMEOUT); if (ok) srp_pass = brstrip(ftppass); } t_clientpasswd (tc, srp_pass); memset (srp_pass, 0, strlen (srp_pass)); skey = t_clientgetkey (tc, &yp); /* Send response */ bp = tmp; blen = 0; srp_put (t_clientresponse (tc), &bp, 20, &blen); len = FTP_BUFSIZ; if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE)) goto encode_error; reply_parse = "ADAT="; n = ftpcmd("ADAT",buf,-1,-1,0); } if (n == REPLY_CONTINUE) { /* Get response */ bp = buf; if (!reply_parse) goto data_error; blen = FTP_BUFSIZ; if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE)) goto encode_error; if (srp_get (&bp, &cp, &blen, &clen) != 20) goto data_error; if (t_clientverify (tc, cp)) { fprintf (stderr, "WARNING: bad response to client challenge.\n"); goto bad; } bp = tmp; blen = 0; /* Send nothing */ srp_put ("\0", &bp, 1, &blen); len = FTP_BUFSIZ; if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE)) goto encode_error; reply_parse = "ADAT="; n = ftpcmd("ADAT",buf,-1,-1,0); } if (n == REPLY_CONTINUE) { /* Get cipher & hash lists, seqnum */ CHAR seqnum[4]; CHAR *clist; CHAR *hlist; CHAR *p1; int clist_len, hlist_len; bp = buf; if (!reply_parse) goto data_error; blen = FTP_BUFSIZ; if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE)) goto encode_error; if (srp_get (&bp, &clist, &blen, &clist_len) < 0) goto data_error; if (srp_get (&bp, &hlist, &blen, &hlist_len) < 0) goto data_error; if (srp_get (&bp, &cp, &blen, &clen) != 4) goto data_error; memcpy (seqnum, cp, 4); if (cipher_supported (clist, srp_pref_cipher)) /* Choose cipher */ cid = srp_pref_cipher; if (!cid && cipher_supported (clist, SRP_DEFAULT_CIPHER)) cid = SRP_DEFAULT_CIPHER; if (!cid) { CHAR *loclist = cipher_getlist (); for (i = 0; i < strlen (loclist); i++) if (cipher_supported (clist, loclist[i])) { cid = loclist[i]; break; } } if (!cid) { fprintf (stderr, "Unable to agree on cipher.\n"); goto bad; } /* Choose hash */ if (srp_pref_hash && hash_supported (hlist, srp_pref_hash)) hid = srp_pref_hash; if (!hid && hash_supported (hlist, SRP_DEFAULT_HASH)) hid = SRP_DEFAULT_HASH; if (!hid) { CHAR *loclist = hash_getlist (); for (i = 0; i < strlen (loclist); i++) if (hash_supported (hlist, loclist[i])) { hid = loclist[i]; break; } } if (!hid) { fprintf (stderr, "Unable to agree on hash.\n"); goto bad; } /* Set incrypt */ if (!(incrypt = krypto_new (cid, hid, skey, 20, NULL, 0, seqnum, KRYPTO_DECODE))) goto bad; /* Generate random number for outkey and outseqnum */ t_random (seqnum, 4); /* Send cid, hid, outkey, outseqnum */ bp = tmp; blen = 0; srp_put (&cid, &bp, 1, &blen); srp_put (&hid, &bp, 1, &blen); srp_put (seqnum, &bp, 4, &blen); len = FTP_BUFSIZ; if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE)) goto encode_error; reply_parse = "ADAT="; n = ftpcmd("ADAT",buf,-1,-1,0); /* Set outcrypt */ if (!(outcrypt = krypto_new (cid, hid, skey+20, 20, NULL, 0, seqnum, KRYPTO_ENCODE))) goto bad; t_clientclose (tc); tc = NULL; } if (n != REPLY_COMPLETE) goto bad; if (ftp_vbm) { if (ftp_deb) printf("\n"); printf ("SRP authentication succeeded.\n"); printf ("Using cipher %s and hash function %s.\n", (cipher_getdescbyid(cid))->name, (hash_getdescbyid(hid))->name ); } reply_parse = NULL; auth_type = "SRP"; return(1); encode_error: fprintf (stderr, "Base 64 encoding failed: %s.\n", radix_error (e)); goto bad; decode_error: fprintf (stderr, "Base 64 decoding failed: %s.\n", radix_error (e)); goto bad; data_error: fprintf (stderr, "Unable to unmarshal authentication data.\n"); goto bad; bad: fprintf (stderr, "SRP authentication failed, trying regular login.\n"); reply_parse = NULL; return(0); } /*--------------------------------------------------------------+ | srp_put: put item to send buffer | +--------------------------------------------------------------*/ static int srp_put (in, out, inlen, outlen) CHAR *in; CHAR **out; int inlen; int *outlen; { srp_uint32 net_len; net_len = htonl (inlen); memcpy (*out, &net_len, 4); *out += 4; *outlen += 4; memcpy (*out, in, inlen); *out += inlen; *outlen += inlen; return(0); } /*--------------------------------------------------------------+ | srp_get: get item from receive buffer | +--------------------------------------------------------------*/ static int srp_get (in, out, inlen, outlen) CHAR **in; CHAR **out; int *inlen; int *outlen; { srp_uint32 net_len; if (*inlen < 4) return -1; memcpy (&net_len, *in, 4); *inlen -= 4; *in += 4; *outlen = ntohl (net_len); if (*inlen < *outlen) return -1; *out = *in; *inlen -= *outlen; *in += *outlen; return *outlen; } /*--------------------------------------------------------------+ | srp_encode: encode control message | +--------------------------------------------------------------*/ static int srp_encode (private, in, out, len) int private; CHAR *in; CHAR *out; unsigned len; { if (private) return krypto_msg_priv (outcrypt, in, out, len); else return krypto_msg_safe (outcrypt, in, out, len); } /*--------------------------------------------------------------+ | srp_decode: decode control message | +--------------------------------------------------------------*/ static int srp_decode (private, in, out, len) int private; CHAR *in; CHAR *out; unsigned len; { if (private) return krypto_msg_priv (incrypt, in, out, len); else return krypto_msg_safe (incrypt, in, out, len); } #endif /* FTP_SRP */ #ifdef NOT_USED /* The following code is from the Unix FTP client. Be sure to make sure that the functionality is not lost. Especially the Proxy stuff even though we have not yet implemented it. */ /* Send multiple files */ static int ftp_mput(argc, argv) int argc; char **argv; { register int i; int ointer; char *tp; sigtype mcancel(); if (argc < 2 && !another(&argc, &argv, "local-files")) { printf("usage: %s local-files\n", argv[0]); ftpcode = -1; return; } mname = argv[0]; mflag = 1; oldintr = signal(SIGINT, mcancel); /* Replace with calls to cc_execute() */ setjmp(jcancel); #ifdef FTP_PROXY if (proxy) { char *cp, *tp2, tmpbuf[CKMAXPATH]; while ((cp = remglob(argv,0)) != NULL) { if (*cp == 0) { mflag = 0; continue; } if (mflag && confirm(argv[0], cp)) { tp = cp; if (mcase) { while (*tp && !islower(*tp)) { tp++; } if (!*tp) { tp = cp; tp2 = tmpbuf; while ((*tp2 = *tp) != 0) { if (isupper(*tp2)) { *tp2 = 'a' + *tp2 - 'A'; } tp++; tp2++; } } tp = tmpbuf; } if (ntflag) { tp = dotrans(tp); } if (mapflag) { tp = domap(tp); } sendrequest((sunique) ? "STOU" : "STOR", cp, tp, 0, -1, -1, 0); if (!mflag && fromatty) { ointer = interactive; interactive = 1; if (confirm("Continue with","mput")) { mflag++; } interactive = ointer; } } } signal(SIGINT, oldintr); mflag = 0; return; } #endif /* FTP_PROXY */ for (i = 1; i < argc; i++) { register char **cpp, **gargs; if (mflag && confirm(argv[0], argv[i])) { tp = argv[i]; sendrequest((ftp_usn) ? "STOU" : "STOR", argv[i], tp, 0,-1,-1, 0); if (!mflag && fromatty) { ointer = interactive; interactive = 1; if (confirm("Continue with","mput")) { mflag++; } interactive = ointer; } } continue; gargs = ftpglob(argv[i]); if (globerr != NULL) { printf("%s\n", globerr); if (gargs) { blkfree(gargs); free((char *)gargs); } continue; } for (cpp = gargs; cpp && *cpp != NULL; cpp++) { if (mflag && confirm(argv[0], *cpp)) { tp = *cpp; sendrequest((sunique) ? "STOU":"STOR", *cpp, tp, 0, -1, -1, 0); if (!mflag && fromatty) { ointer = interactive; interactive = 1; if (confirm("Continue with","mput")) { mflag++; } interactive = ointer; } } } if (gargs != NULL) { blkfree(gargs); free((char *)gargs); } } signal(SIGINT, oldintr); mflag = 0; } /* Get multiple files */ static int ftp_mget(argc, argv) int argc; char **argv; { int rc = -1; int ointer; char *cp, *tp, *tp2, tmpbuf[CKMAXPATH]; sigtype mcancel(); if (argc < 2 && !another(&argc, &argv, "remote-files")) { printf("usage: %s remote-files\n", argv[0]); ftpcode = -1; return(-1); } mname = argv[0]; mflag = 1; oldintr = signal(SIGINT,mcancel); /* Replace with calls to cc_execute() */ setjmp(jcancel); while ((cp = remglob(argv,proxy)) != NULL) { if (*cp == '\0') { mflag = 0; continue; } if (mflag && confirm(argv[0], cp)) { tp = cp; if (mcase) { while (*tp && !islower(*tp)) { tp++; } if (!*tp) { tp = cp; tp2 = tmpbuf; while ((*tp2 = *tp) != 0) { if (isupper(*tp2)) { *tp2 = 'a' + *tp2 - 'A'; } tp++; tp2++; } } tp = tmpbuf; } rc = (recvrequest("RETR", tp, cp, "wb", tp != cp || !interactive) == 0,0,NULL,0,0,0); if (!mflag && fromatty) { ointer = interactive; interactive = 1; if (confirm("Continue with","mget")) { mflag++; } interactive = ointer; } } } signal(SIGINT,oldintr); mflag = 0; return(rc); } /* Delete multiple files */ static int mdelete(argc, argv) int argc; char **argv; { int ointer; char *cp; sigtype mcancel(); if (argc < 2 && !another(&argc, &argv, "remote-files")) { printf("usage: %s remote-files\n", argv[0]); ftpcode = -1; return(-1); } mname = argv[0]; mflag = 1; oldintr = signal(SIGINT, mcancel); /* Replace with calls to cc_execute() */ setjmp(jcancel); while ((cp = remglob(argv,0)) != NULL) { if (*cp == '\0') { mflag = 0; continue; } if (mflag && confirm(argv[0], cp)) { rc = (ftpcmd("DELE",cp,-1,-1,ftp_vbm) == REPLY_COMPLETE); if (!mflag && fromatty) { ointer = interactive; interactive = 1; if (confirm("Continue with", "mdelete")) { mflag++; } interactive = ointer; } } } signal(SIGINT, oldintr); mflag = 0; return(rc); } /* Get a directory listing of multiple remote files */ static int mls(argc, argv) int argc; char **argv; { int ointer, i; char *cmd, mode[1], *dest; sigtype mcancel(); int rc = -1; if (argc < 2 && !another(&argc, &argv, "remote-files")) goto usage; if (argc < 3 && !another(&argc, &argv, "local-file")) { usage: printf("usage: %s remote-files local-file\n", argv[0]); ftpcode = -1; return(-1); } dest = argv[argc - 1]; argv[argc - 1] = NULL; if (strcmp(dest, "-") && *dest != '|') if (!globulize(&dest) || !confirm("output to local-file:", dest)) { ftpcode = -1; return(-1); } cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; mname = argv[0]; mflag = 1; oldintr = signal(SIGINT, mcancel); /* Replace with calls to cc_execute() */ setjmp(jcancel); for (i = 1; mflag && i < argc-1; ++i) { *mode = (i == 1) ? 'w' : 'a'; rc = recvrequest(cmd, dest, argv[i], mode, 0,0,NULL,0,0,0); if (!mflag && fromatty) { ointer = interactive; interactive = 1; if (confirm("Continue with", argv[0])) { mflag ++; } interactive = ointer; } } signal(SIGINT, oldintr); mflag = 0; return(rc); } static char * remglob(argv,doswitch) char *argv[]; int doswitch; { char temp[16]; static char buf[CKMAXPATH]; static FILE *ftemp = NULL; static char **args; int oldhash; char *cp, *mode; if (!mflag) { if (!doglob) { args = NULL; } else { if (ftemp) { (void) fclose(ftemp); ftemp = NULL; } } return(NULL); } if (!doglob) { if (args == NULL) args = argv; if ((cp = *++args) == NULL) args = NULL; return(cp); } if (ftemp == NULL) { (void) strcpy(temp, _PATH_TMP); #ifdef MKTEMP #ifndef MKSTEMP (void) mktemp(temp); #endif /* MKSTEMP */ #endif /* MKTEMP */ verbose = 0; oldhash = hash, hash = 0; #ifdef FTP_PROXY if (doswitch) { pswitch(!proxy); } #endif /* FTP_PROXY */ for (mode = "wb"; *++argv != NULL; mode = "ab") recvrequest ("NLST", temp, *argv, mode, 0); #ifdef FTP_PROXY if (doswitch) { pswitch(!proxy); } #endif /* FTP_PROXY */ hash = oldhash; ftemp = fopen(temp, "r"); unlink(temp); if (ftemp == NULL && (!dpyactive || ftp_deb)) { printf("Can't find list of remote files, oops\n"); return(NULL); } } if (fgets(buf, CKMAXPATH, ftemp) == NULL) { fclose(ftemp), ftemp = NULL; return(NULL); } if ((cp = ckstrchr(buf,'\n')) != NULL) *cp = '\0'; return(buf); } #endif /* NOT_USED */ #endif /* TCPSOCKET (top of file) */ #endif /* SYSFTP (top of file) */ #endif /* NOFTP (top of file) */ ckcftp.h000664 045065 024037 00000003500 14767401700 012612 0ustar00fdckermit000000 000000 /* Prototypes for static functions defined in ckcftp.c */ #ifdef CK_ANSIC static VOID bytswap( int *, int * ); static VOID cancel_remote( int ); static VOID changetype( int, int ); static VOID dbtime( char *, struct tm * ); static VOID ftscreen( int, char, CK_OFF_T, char * ); static char * ftp_hookup( char *, int, int ); static char * radix_error( int ); static char * shopl( int ); static char * strval( char *, char * ); static int check_data_connection( int, int ); static int chkmodtime( char *, char *, int ); static int dataconn( char * ); static int doftpcwd( char *, int ); static int doftpdir( int ); static int doftpxmkd( char *, int ); static int ftp_login( char * ); static int ftp_rename( char *, char * ); static int ftp_umask( char * ); static int ftp_user( char *, char *, char * ); static int ftpcmd( char *, char *, int, int, int ); static int fts_cpl( int ); static int fts_dpl( int ); static int getfile( char *, char *, int, int, char *, int, int, int ); static int getreply( int, int, int, int, int ); static int ispathsep( int ); static int looping_read(int, register char *, register int ); static int looping_write( int, register CONST char *, int ); static int openftp( char *, int ); static int putfile( int, char *, char *, int, int, char *, char *, char *, int, int, int, int, int, int, int ); static int recvrequest(char *, char *, char *, char *, int, int, char *, int, int, int ); static int secure_flush( int ); static int secure_getbyte( int, int ); static int secure_read( int fd, char *, int ); static int sendrequest( char *, char *, char *, int, int, int, int ); static int syncdir( char *, int ); static int tmcompare( struct tm *, struct tm * ); static int xlatec( int, int, int, int ); static sigtype cancelrecv( int ); static sigtype cancelsend( int ); static sigtype cmdcancel( int ); #endif /* CK_ANSIC */ ckcker.h000664 045065 024037 00000133202 14767401703 012610 0ustar00fdckermit000000 000000 /* ckcker.h -- Symbol and macro definitions for C-Kermit */ /* Author: Frank da Cruz , Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 2024 Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ #ifndef CKCKER_H #define CKCKER_H #define I_AM_KERMIT 0 /* Personalities */ #define I_AM_TELNET 1 #define I_AM_RLOGIN 2 #define I_AM_IKSD 3 #define I_AM_FTP 4 #define I_AM_HTTP 5 #define I_AM_SSHSUB 6 #define I_AM_SSH 7 #ifndef NOSTREAMING #ifndef STREAMING #define STREAMING #endif /* STREAMING */ #endif /* NOSTREAMING */ /* If NEWDEFAULTS is defined then: - RECEIVE PACKET-LENGTH is 4095 rather than 90 - WINDOW is 30 rather than 1 - BLOCK-CHECK is 3 rather than 1 - FILE TYPE is BINARY rather than TEXT */ #ifdef BIGBUFOK /* (was OS2) */ #ifndef NEWDEFAULTS #define NEWDEFAULTS #endif /* NEWDEFAULTS */ #endif /* BIGBUFOK */ #ifdef NOICP /* No Interactive Command Parser */ #ifndef NOSPL /* implies... */ #define NOSPL /* No Script Programming Language */ #endif /* NOSPL */ #ifndef NOCSETS /* No character-set translation */ #define NOCSETS /* because the only way to set it up */ #endif /* NOCSETS */ /* is with interactive commands */ #endif /* NOICP */ #ifdef pdp11 /* There is a maximum number of */ #ifndef NOCKSPEED /* of -D's allowed on the CC */ #define NOCKSPEED /* command line, so some of them */ #endif /* NOCKSPEED */ /* have to go here... */ #ifndef NOREDIRECT #define NOREDIRECT #endif /* NOREDIRECT */ #ifdef WHATAMI #undef WHATAMI #endif /* WHATAMI */ #endif /* pdp11 */ #ifdef UIDBUFLEN #define LOGINLEN UIDBUFLEN #else #define LOGINLEN 32 /* Length of server login field */ #endif /* UIDBUFLEN */ /* Bell values */ #define XYB_NONE 0 /* No bell */ #define XYB_AUD 1 /* Audible bell */ #define XYB_VIS 2 /* Visible bell */ #define XYB_BEEP 0 /* Audible Beep */ #define XYB_SYS 4 /* Audible System Sounds */ /* File status bits */ #define FS_OK 1 /* File transferred OK */ #define FS_REFU 2 /* File was refused */ #define FS_DISC 4 /* File was discarded */ #define FS_INTR 8 /* Transfer was interrupted by user */ #define FS_ERR 16 /* Fatal error during transfer */ /* Control-character (un)prefixing options */ #define PX_ALL 0 /* Prefix all control chars */ #define PX_CAU 1 /* Unprefix cautiously */ #define PX_WIL 2 /* Unprefix with wild abandon */ #define PX_NON 3 /* Unprefix all (= prefix none) */ /* Destination codes */ #define DEST_D 0 /* DISK */ #define DEST_S 1 /* SCREEN */ #define DEST_P 2 /* PRINTER */ #define DEST_N 3 /* NOWHERE (calibration run) */ /* File transfer protocols */ #define PROTO_K 0 /* Kermit */ #ifdef CK_XYZ #define PROTO_X 1 /* XMODEM */ #define PROTO_XC 2 /* XMODEM-CRC */ #define PROTO_Y 3 /* YMODEM */ #define PROTO_G 4 /* YMODEM-g */ #define PROTO_Z 5 /* ZMODEM */ #define PROTO_O 6 /* OTHER */ #define NPROTOS 7 /* How many */ #else #define NPROTOS 1 /* How many */ #endif /* CK_XYZ */ struct ck_p { /* C-Kermit Protocol info structure */ char * p_name; /* Protocol name */ int rpktlen; /* Packet length - receive */ int spktlen; /* Packet length - send */ int spktflg; /* ... */ int winsize; /* Window size */ int prefix; /* Control-char prefixing options */ int fnca; /* Filename collision action */ int fncn; /* Filename conversion */ int fnsp; /* Send filename path stripping */ int fnrp; /* Receive filename path stripping */ char * h_b_init; /* Host receive initiation string - text */ char * h_t_init; /* Host receive initiation string - binary */ char * h_x_init; /* Host server string */ char * p_b_scmd; /* SEND cmd for external protocol - text */ char * p_t_scmd; /* SEND cmd for external protocol - binary */ char * p_b_rcmd; /* RECV cmd for external protocol - text */ char * p_t_rcmd; /* RECV cmd for external protocol - binary */ }; struct filelist { /* Send-file list element */ char * fl_name; /* Filename */ int fl_mode; /* Transfer mode */ char * fl_alias; /* Name to send the file under */ struct filelist * fl_next; /* Pointer to next element */ }; /* Kermit system IDs and associated properties... */ struct sysdata { char *sid_code; /* Kermit system ID code */ char *sid_name; /* Descriptive name */ short sid_unixlike; /* Tree-structured directory with separators */ char sid_dirsep; /* Directory separator character if unixlike */ short sid_dev; /* Can start with dev: */ short sid_case; /* Bit mapped: 1 = case matters, 2 = case preserved */ short sid_recfm; /* Text record separator */ /* 0 = unknown or nonstream 1 = cr 2 = lf 3 = crlf */ }; struct ssh_pf { /* SSH port forwarding */ int p1; /* port to be forwarded */ char * host; /* host */ int p2; /* port */ }; #define SET_ON 1 /* General values for settings that can be ON */ #define SET_OFF 0 /* OFF, */ #define SET_AUTO 2 /* or AUTO */ #define PATH_OFF 0 /* Pathnames off (to be stripped) */ #define PATH_REL 1 /* Pathnames on, left relative if possible */ #define PATH_ABS 2 /* Pathnames absolute always */ #define PATH_AUTO 4 /* Pathnames handled automatically */ /* GET Options */ #define GOPT_DEL 1 /* Delete source file */ #define GOPT_REC 2 /* Recursive */ #define GOPT_RES 4 /* Recover (Resend) */ #define GOPT_CMD 8 /* Filename is a Command */ /* GET Transfer Modes */ #define GMOD_TXT 0 /* Text */ #define GMOD_BIN 1 /* Binary */ #define GMOD_AUT 2 /* Auto */ #define GMOD_LBL 3 /* Labeled */ /* GET Filename Options */ #define GNAM_LIT 0 /* Literal */ #define GNAM_CNV 1 /* Converted */ /* GET Pathname Options */ #define GPTH_OFF 0 /* Pathnames Off */ #define GPTH_REL 1 /* Pathnames Relative */ #define GPTH_ABX 2 /* Pathnames Absolute */ #ifndef NOSPL /* The IF REMOTE-ONLY command is available only in versions that actually can be used in remote mode, and only if we have an interactive command parser. */ #define CK_IFRO #ifdef MAC #undef CK_IFRO #else #ifdef GEMDOS #undef CK_IFRO #endif /* GEMDOS */ #endif /* MAC */ #endif /* NOSPL */ /* Systems whose CONNECT modules can execute Application Program Commands */ #ifdef NOSPL /* Script programming language */ #ifdef CK_APC /* is required for APC. */ #undef CK_APC #endif /* CK_APC */ #ifndef NOAPC #define NOAPC #endif /* NOAPC */ #ifndef NOAUTODL #define NOAUTODL #endif /* NOAUTODL */ #endif /* NOSPL */ #ifndef NOAPC /* Unless they said NO APC */ #ifndef CK_APC /* And they didn't already define it */ #ifdef OS2 /* OS/2 gets it */ #define CK_APC #endif /* OS2 */ #ifdef UNIX /* UNIX gets it */ #define CK_APC #endif /* UNIX */ #ifdef VMS /* VMS too */ #define CK_APC #endif /* VMS */ #endif /* CK_APC */ #endif /* NOAPC */ #ifdef CK_APC /* APC buffer length */ #ifndef APCBUFLEN /* Should be no bigger than */ #ifdef NOSPL /* command buffer length */ #define APCBUFLEN 608 /* (see ckucmd.h) but we can't */ #else /* reference ckucmd.h symbols here */ #define APCBUFLEN 4096 #endif /* NOSPL */ #endif /* APCBUFLEN */ #define APC_OFF 0 /* APC OFF (disabled) */ #define APC_ON 1 /* APC ON (enabled for non-dangerous commands) */ #define APC_UNCH 2 /* APC UNCHECKED (enabled for ALL commands) bitmask */ #define APC_NOINP 4 /* APC (enabled with no input allowed - bitmask) */ #define APC_INACTIVE 0 /* APC not in use */ #define APC_REMOTE 1 /* APC in use from Remote */ #define APC_LOCAL 2 /* APC being used from within Kermit */ #ifndef NOAUTODL #ifndef CK_AUTODL /* Autodownload */ #ifdef OS2 #define CK_AUTODL #else #ifdef UNIX #define CK_AUTODL #else #ifdef VMS #define CK_AUTODL #else #ifdef CK_AUTODL #undef CK_AUTODL #endif /* CK_AUTODL */ #endif /* NOAUTODL */ #endif /* VMS */ #endif /* UNIX */ #endif /* OS2 */ #endif /* CK_AUTODL */ #else /* CK_APC not defined */ #ifdef NOICP #ifdef UNIX #ifndef CK_AUTODL #define CK_AUTODL #endif /* CK_AUTODL */ #endif /* UNIX */ #else /* Not NOICP... */ #ifdef CK_AUTODL #undef CK_AUTODL #endif /* CK_AUTODL */ #endif /* NOICP */ #endif /* CK_APC */ #ifdef NOAUTODL #ifdef CK_AUTODL #undef CK_AUTODL #endif /* CK_AUTODL */ #endif /* NOAUTODL */ /* Codes for what we are doing now - bit mask values */ #define W_NOTHING 0 /* Nothing */ #define W_INIT 1 /* Initializing protocol */ #define W_SEND 2 /* SENDing or MAILing */ #define W_RECV 4 /* RECEIVEing or GETting */ #define W_REMO 8 /* Doing a REMOTE command */ #define W_CONNECT 16 /* CONNECT mode */ #define W_COMMAND 32 /* Command mode */ #define W_DIALING 64 /* Dialing a modem */ #define W_FTP 128 /* FTP */ #define W_FT_DELE 64 /* FTP MDELETE */ #define W_KERMIT (W_INIT|W_SEND|W_RECV|W_REMO) /* Kermit protocol */ #define W_XFER (W_INIT|W_SEND|W_RECV|W_REMO|W_FTP) /* File xfer any protocol */ #ifndef NOWHATAMI #ifndef WHATAMI #define WHATAMI #endif /* WHATAMI */ #endif /* NOWHATAMI */ #ifdef WHATAMI /* Bit mask positions for WHATAMI */ #define WMI_SERVE 1 /* Server mode */ #define WMI_FMODE 2 /* File transfer mode */ #define WMI_FNAME 4 /* File name conversion */ #define WMI_STREAM 8 /* I have a reliable transport */ #define WMI_CLEAR 16 /* I have a clear channel */ #define WMI_FLAG 32 /* Flag that WHATAMI field is valid */ /* WHATAMI2 bits... */ #define WMI2_XMODE 1 /* Transfer mode auto(0)/manual(1) */ #define WMI2_RECU 2 /* Transfer is recursive */ #define WMI2_FLAG 32 /* Flag that WHATAMI2 field is valid */ #endif /* WHATAMI */ /* Terminal types */ #define VT100 0 /* Also for VT52 mode */ #define TEKTRONIX 1 /* Normal packet and window size */ #define MAXPACK 94 /* Maximum unextended packet size */ /* Can't be more than 94. */ #ifdef pdp11 /* Maximum sliding window slots */ #define MAXWS 8 #else #define MAXWS 32 /* Can't be more than 32. */ #endif /* pdp11 */ /* Maximum long packet size for sending packets */ /* Override these from cc command line via -DMAXSP=nnn */ #ifdef IRIX /* Irix 6.4 and earlier has */ #ifndef MAXSP /* Telnet server bug */ #ifdef IRIX65 #define MAXSP 9024 #else #define MAXSP 4000 #endif /* IRIX65 */ #endif /* MAXSP */ #endif /* IRIX */ #ifdef DYNAMIC #ifndef MAXSP #define MAXSP 9024 #endif /* MAXSP */ #else /* not DYNAMIC */ #ifndef MAXSP #ifdef pdp11 #define MAXSP 1024 #else #define MAXSP 2048 #endif /* pdp11 */ #endif /* MAXSP */ #endif /* DYNAMIC */ /* Maximum long packet size for receiving packets */ /* Override these from cc command line via -DMAXRP=nnn */ #ifdef DYNAMIC #ifndef MAXRP #define MAXRP 9024 #endif /* MAXRP */ #else /* not DYNAMIC */ #ifndef MAXRP #ifdef pdp11 #define MAXRP 1024 #else #define MAXRP 2048 #endif /* pdp11 */ #endif /* MAXRP */ #endif /* DYNAMIC */ /* Default sizes for windowed packet buffers. Override these from cc command line via -DSBSIZ=nnn, -DRBSIZ=nnn. Or just -DBIGBUFOK. */ #ifndef MAXGETPATH /* Maximum number of directories */ #ifdef BIGBUFOK /* for GET path... */ #define MAXGETPATH 128 #else #define MAXGETPATH 16 #endif /* BIGBUFOK */ #endif /* MAXGETPATH */ #ifndef NOSPL /* Query buffer length */ #ifdef OS2 #define QBUFL 4095 #else #ifdef BIGBUFOK #define QBUFL 4095 #else #define QBUFL 1023 #endif /* BIGBUFOK */ #endif /* OS2 */ #endif /* NOSPL */ #ifdef DYNAMIC #ifndef SBSIZ #ifdef BIGBUFOK /* If big buffers are safe... */ #define SBSIZ 290000 /* Allow for 10 x 9024 or 20 x 4096 */ #else /* Otherwise... */ #ifdef pdp11 #define SBSIZ 3020 #else #define SBSIZ 9050 /* Allow for 3 x 3000, etc. */ #endif /* pdp11 */ #endif /* BIGBUFOK */ #endif /* SBSIZ */ #ifndef RBSIZ #ifdef BIGBUFOK #define RBSIZ 290000 /* Allow for 10 x 9024 or 20 x 4096 */ #else #ifdef pdp11 #define RBSIZ 3020 #else #define RBSIZ 9050 #endif /* pdp11 */ #endif /* BIGBUFOK */ #endif /* RBSIZ */ #else /* not DYNAMIC */ #ifdef pdp11 #define SBSIZ 3020 #define RBSIZ 3020 #else #ifndef SBSIZ #define SBSIZ (MAXSP * (MAXWS + 1)) #endif /* SBSIZ */ #ifndef RBSIZ #define RBSIZ (MAXRP * (MAXWS + 1)) #endif /* RBSIZ */ #endif /* pdp11 */ #endif /* DYNAMIC */ #ifdef BIGBUFOK #define PKTMSGLEN 1023 #else #define PKTMSGLEN 80 #endif /* BIGBUFOK */ /* Kermit parameters and defaults */ #define CTLQ '#' /* Control char prefix I will use */ #define MYEBQ '&' /* 8th-Bit prefix char I will use */ #define MYRPTQ '~' /* Repeat count prefix I will use */ #define MAXTRY 10 /* Times to retry a packet */ #define MYPADN 0 /* How many padding chars I need */ #define MYPADC '\0' /* Which padding character I need */ #define DMYTIM 8 /* Initial timeout interval to use. */ #define URTIME 15 /* Timeout interval to use on me. */ #define DSRVTIM 0 /* Default server cmd wait timeout. */ #define DEFTRN 0 /* Default line turnaround handshake */ #define MYEOL CK_CR /* Incoming packet terminator. */ #ifdef NEWDEFAULTS #define DRPSIZ 4095 /* Default incoming packet size. */ #define DFWSIZ 30 /* Default window size */ #define DFBCT 3 /* Default block-check type */ #else #define DRPSIZ 90 /* Default incoming packet size. */ #define DFWSIZ 1 /* Default window size */ #define DFBCT 3 /* Default block-check type */ #endif /* NEWDEFAULTS */ /* The HP-UX 5 and 6 Telnet servers can only swallow 513 bytes at once */ #ifdef HPUX5 #ifdef DRPSIZ #undef DRPSIZ #endif /* DRPSIZ */ #define DRPSIZ 500 #else #ifdef HPUX6 #ifdef DRPSIZ #undef DRPSIZ #endif /* DRPSIZ */ #define DRPSIZ 500 #endif /* HPUX6 */ #endif /* HPUX5 */ #define DSPSIZ 90 /* Default outbound packet size. */ #define DDELAY 1 /* Default delay. */ #define DSPEED 9600 /* Default line speed. */ #ifdef OS2 /* Default CONNECT-mode */ #define DFESC 29 /* escape character */ #else #ifdef NEXT /* Ctrl-] for PC and NeXT */ #define DFESC 29 #else #ifdef GEMDOS /* And Atari ST */ #define DFESC 29 #else #define DFESC 28 /* Ctrl-backslash for others */ #endif /* GEMDOS */ #endif /* NEXT */ #endif /* OS2 */ #ifdef NOPUSH /* NOPUSH implies NOJC */ #ifndef NOJC /* (no job control) */ #define NOJC #endif /* NOJC */ #endif /* NOPUSH */ #ifdef UNIX /* Default for SET SUSPEND */ #ifdef NOJC /* UNIX but job control disabled */ #define DFSUSP 0 #else /* UNIX, job control enabled. */ #define DFSUSP 1 #endif /* NOJC */ #else #define DFSUSP 0 #endif /* UNIX */ #ifndef DFCDMSG #ifdef UNIXOROSK #define DFCDMSG "{{./.readme}{README.TXT}{READ.ME}}" #else #define DFCDMSG "{{README.TXT}{READ.ME}}" #endif /* UNIXOROSK */ #endif /* DFCDMSG */ #define NSNDEXCEPT 64 /* Max patterns for /EXCEPT: list */ /* Files */ #define ZCTERM 0 /* Console terminal */ #define ZSTDIO 1 /* Standard input/output */ #define ZIFILE 2 /* Current input file (SEND, etc) (in) */ #define ZOFILE 3 /* Current output file (RECEIVE, GET) (out) */ #define ZDFILE 4 /* Current debugging log file (out) */ #define ZTFILE 5 /* Current transaction log file (out) */ #define ZPFILE 6 /* Current packet log file (out) */ #define ZSFILE 7 /* Current session log file (out) */ #define ZSYSFN 8 /* Input/Output from a system function */ #define ZRFILE 9 /* Local file for READ (in) */ #define ZWFILE 10 /* Local file for WRITE (out) */ #define ZMFILE 11 /* Miscellaneous file, e.g. for XLATE */ #define ZDIFIL 12 /* DIAL log */ #define ZNFILS 13 /* How many predefined file numbers (old) */ #ifdef CKCHANNELIO /* File modes */ #define FM_REA 1 /* Read */ #define FM_WRI 2 /* Write */ #define FM_APP 4 /* Append */ #define FM_RWA 7 /* Read/Write/Append mask */ #define FM_BIN 8 /* Binary */ #define FM_RWB 15 /* Read/Write/Append/Binary mask */ #define FM_CMD 16 /* Command */ #define FM_EOF 64 /* (status) At EOF */ #define FM_STDIN 128 /* Standard input */ #define FM_STDOUT 256 /* Standard output */ #define FM_STDERR 512 /* Standard error */ #define FM_STDM 896 /* Standard in/out/err mask */ /* File errors */ #define FX_NER 0 /* No error */ #define FX_SYS -1 /* System error */ #define FX_EOF -2 /* End of file */ #define FX_NOP -3 /* Channel not open */ #define FX_CHN -4 /* Channel out of range */ #define FX_RNG -5 /* Argument range error */ #define FX_FNF -6 /* File not found */ #define FX_BFN -7 /* Bad or missing filename */ #define FX_NMF -8 /* No more files */ #define FX_FOP -9 /* Forbidden operation */ #define FX_ACC -10 /* Access denied */ #define FX_BOM -11 /* Bad combination of open modes */ #define FX_OFL -12 /* Buffer overflow */ #define FX_LNU -13 /* Current line number unknown */ #define FX_ROO -14 /* Set Root violation */ #define FX_NYI -99 /* Feature not implemented yet */ #define FX_UNK -999 /* Unknown error */ _PROTOTYP( int z_open, (char *, int) ); _PROTOTYP( int z_close, (int) ); _PROTOTYP( int z_out, (int, char *, int, int) ); _PROTOTYP( int z_in, (int, char *, int, int, int) ); _PROTOTYP( int z_flush, (int) ); _PROTOTYP( int z_seek, (int, CK_OFF_T) ); _PROTOTYP( int z_line, (int, CK_OFF_T) ); _PROTOTYP( int z_getmode, (int) ); _PROTOTYP( int z_getfnum, (int) ); _PROTOTYP( CK_OFF_T z_getpos, (int) ); _PROTOTYP( CK_OFF_T z_getline, (int) ); _PROTOTYP( CK_OFF_T z_count, (int, int) ); _PROTOTYP( char * z_getname, (int) ); _PROTOTYP( char * ckferror, (int) ); #endif /* CKCHANNELIO */ _PROTOTYP( int scanfile, (char *, int *, int) ); _PROTOTYP( int scanstring, (char *) ); /* Buffered file i/o ... */ #ifdef OS2 /* K-95 */ #define INBUFSIZE 32768 #define OBUFSIZE 32768 #else #ifdef pdp11 #define INBUFSIZE 512 #define OBUFSIZE 512 #else /* In VMS, allow for longest possible RMS record */ #ifdef VMS #define INBUFSIZE 32768 /* File input buffer size */ #define OBUFSIZE 32768 /* File output buffer size */ #else /* Not VMS */ #ifdef STRATUS #ifdef DYNAMIC #define INBUFSIZE 32767 /* File input buffer size */ #define OBUFSIZE 32767 /* File output buffer size */ #else /* STRATUS, not DYNAMIC */ #define INBUFSIZE 4096 /* File input buffer size */ #define OBUFSIZE 4096 /* File output buffer size */ #endif /* DYNAMIC */ #else /* not STRATUS */ #ifdef BIGBUFOK /* Systems with some memory */ #define INBUFSIZE 32768 /* 32K for packet buffers */ #define OBUFSIZE 32768 #else /* Not BIGBUFOK */ #define INBUFSIZE 1024 #define OBUFSIZE 1024 #endif /* BIGBUFOK */ #endif /* STRATUS */ #endif /* VMS */ #endif /* pdp11 */ #endif /* OS2 */ /* File-transfer character in/out macros for buffered i/o */ /* Get the next file byte */ #ifndef CKCMAI #ifndef NOXFER extern char ** sndarray; #endif /* NOXFER */ #endif /* CKCMAI */ #ifdef NOSPL #define zminchar() (((--zincnt)>=0) ? ((int)(*zinptr++) & 0377) : zinfill()) #else #ifdef NOXFER #define zminchar() (((--zincnt)>=0) ? ((int)(*zinptr++) & 0377) : zinfill()) #else #define zminchar() \ (sndarray?agnbyte():(((--zincnt)>=0) ? ((int)(*zinptr++) & 0377) : zinfill())) #endif /* NOXFER */ #endif /* NOSPL */ /* Stuff a character into the input buffer */ #define zmstuff(c) zinptr--, *zinptr = c, zincnt++ /* Put a character to a file */ #define zmchout(c) \ ((*zoutptr++=(char)(c)),(((++zoutcnt)>=zobufsize)?zoutdump():0)) /* Screen functions */ #define XYFD_N 0 /* File transfer display: None, Off */ #define XYFD_R 1 /* Regular, Dots */ #define XYFD_C 2 /* Cursor-positioning (e.g. curses) */ #define XYFD_S 3 /* CRT Screen */ #define XYFD_B 4 /* Brief */ #define XYFD_G 5 /* GUI */ #ifdef NODISPLAY #define xxscreen(a,b,c,d) #define ckscreen(a,b,c,d) #else _PROTOTYP( VOID ckscreen, (int, char, CK_OFF_T, char *) ); #ifdef VMS #define xxscreen(a,b,c,d) \ if (local && fdispla != XYFD_N) \ ckscreen((int)a,(char)b,(CK_OFF_T)c,(char *)d) #else #define xxscreen(a,b,c,d) \ if (local && !backgrd && fdispla != XYFD_N) \ ckscreen((int)a,(char)b,(CK_OFF_T)c,(char *)d) #endif /* VMS */ #endif /* NODISPLAY */ #define SCR_FN 1 /* filename */ #define SCR_AN 2 /* as-name */ #define SCR_FS 3 /* file-size */ #define SCR_XD 4 /* x-packet data */ #define SCR_ST 5 /* File status: */ #define ST_OK 0 /* Transferred OK */ #define ST_DISC 1 /* Discarded */ #define ST_INT 2 /* Interrupted */ #define ST_SKIP 3 /* Skipped */ #define ST_ERR 4 /* Fatal Error */ #define ST_REFU 5 /* Refused (use Attribute codes for reason) */ #define ST_INC 6 /* Incompletely received */ #define ST_MSG 7 /* Informational message */ #define ST_SIM 8 /* Transfer simulated (e.g. would be sent) */ #define SCR_PN 6 /* packet number */ #define SCR_PT 7 /* packet type or pseudotype */ #define SCR_TC 8 /* transaction complete */ #define SCR_EM 9 /* error message */ #define SCR_WM 10 /* warning message */ #define SCR_TU 11 /* arbitrary undelimited text */ #define SCR_TN 12 /* arbitrary new text, delimited at beginning */ #define SCR_TZ 13 /* arbitrary text, delimited at end */ #define SCR_QE 14 /* quantity equals (e.g. "foo: 7") */ #define SCR_CW 15 /* close screen window */ #define SCR_CD 16 /* display current directory */ #define SCR_MS 17 /* message from client */ /* Skip reasons */ #define SKP_DAT 1 /* Date-Time (Older) */ #define SKP_EQU 2 /* Date-Time (Equal) */ #define SKP_TYP 3 /* Type */ #define SKP_SIZ 4 /* Size */ #define SKP_NAM 5 /* Name collision */ #define SKP_EXL 6 /* Exception list */ #define SKP_DOT 7 /* Dot file */ #define SKP_BKU 8 /* Backup file */ #define SKP_RES 9 /* Recovery not needed */ #define SKP_ACC 10 /* Access denied */ #define SKP_NRF 11 /* Not a regular file */ #define SKP_SIM 12 /* Simulation (WOULD BE SENT) */ #define SKP_XUP 13 /* Simulation: Would be sent because remote file older */ #define SKP_XNX 14 /* Simulation: ditto, because remote file does not exist */ /* Macros */ #ifndef CKCMAI extern int tcp_incoming; /* Used by ENABLE macro */ #endif /* CKCMAI */ #ifndef TCPSOCKET /* ENABLED tells whether a server-side service is enabled. 0 = disabled, 1 = local, 2 = remote. A "set host *" connection is technically local but logically remote */ #define ENABLED(x) ((local && (x & 1)) || (!local && (x & 2))) #else #define ENABLED(x) (((local && !tcp_incoming) && (x & 1)) || \ ((!local || tcp_incoming) && (x&2))) #endif /* TCPSOCKET */ /* These are from the book */ #ifndef SP #define SP 32 #endif /* SP */ #define tochar(ch) (((ch) + SP ) & 0xFF ) /* Number to character */ #define xunchar(ch) (((ch) - SP ) & 0xFF ) /* Character to number */ #define ctl(ch) (((ch) ^ 64 ) & 0xFF ) /* Control/Uncontrol toggle */ #define unpar(ch) (((ch) & 127) & 0xFF ) /* Clear parity bit */ #ifndef NOLOCAL /* CONNECT return status codes */ /* Users will see the numbers so they can't be changed */ /* Numbers >= 100 indicate connection loss */ #define CSX_NONE 0 /* No CONNECT yet so no status */ #define CSX_ESCAPE 1 /* User Escaped back */ #define CSX_TRIGGER 2 /* Trigger was encountered */ #define CSX_IKSD 3 /* IKSD autosynchronization */ #define CSX_APC 4 /* Application Program Command */ #define CSX_IDLE 5 /* Idle limit exceeded */ #define CSX_TN_ERR 6 /* Telnet Error */ #define CSX_MACRO 7 /* Macro bound to keystroke */ #define CSX_TIME 8 /* Time Limit exceeded */ #define CSX_INTERNAL 100 /* Internal error */ #define CSX_CARRIER 101 /* Carrier required but not detected */ #define CSX_IOERROR 102 /* I/O error on connection */ #define CSX_HOSTDISC 103 /* Disconnected by host */ #define CSX_USERDISC 104 /* Disconnected by user */ #define CSX_SESSION 105 /* Session Limit exceeded */ #define CSX_TN_POL 106 /* Rejected due to Telnet Policy */ #define CSX_KILL_SIG 107 /* Received Kill Signal */ /* SET TERMINAL IDLE-ACTION values */ #define IDLE_RET 0 /* Return to prompt */ #define IDLE_EXIT 1 /* Exit from Kermit */ #define IDLE_HANG 2 /* Hangup the connection */ #define IDLE_OUT 3 /* OUTPUT a string */ #define IDLE_TNOP 4 /* TELNET NOP */ #define IDLE_TAYT 5 /* TELNET AYT */ #endif /* NOLOCAL */ /* Modem and dialing definitions */ #ifndef NODIAL /* Modem capabilities (bit values) */ #define CKD_AT 1 /* Hayes AT commands and responses */ #define CKD_V25 2 /* V.25bis commands and responses */ #define CKD_SB 4 /* Speed buffering */ #define CKD_EC 8 /* Error correction */ #define CKD_DC 16 /* Data compression */ #define CKD_HW 32 /* Hardware flow control */ #define CKD_SW 64 /* (Local) software flow control */ #define CKD_KS 128 /* Kermit spoofing */ #define CKD_TB 256 /* Made by Telebit */ #define CKD_ID 512 /* Has Caller ID */ /* DIAL command result codes */ #define DIA_UNK -1 /* No DIAL command given yet */ #define DIA_OK 0 /* DIAL succeeded */ #define DIA_NOMO 1 /* Modem type not specified */ #define DIA_NOLI 2 /* Communication line not spec'd */ #define DIA_OPEN 3 /* Line can't be opened */ #define DIA_NOSP 4 /* Speed not specified */ #define DIA_HANG 5 /* Hangup failure */ #define DIA_IE 6 /* Internal error (malloc, etc) */ #define DIA_IO 7 /* I/O error */ #define DIA_TIMO 8 /* Dial timeout expired */ #define DIA_INTR 9 /* Dialing interrupted by user */ #define DIA_NRDY 10 /* Modem not ready */ #define DIA_PART 11 /* Partial dial command OK */ #define DIA_DIR 12 /* Dialing directory error */ #define DIA_HUP 13 /* Modem was hung up OK */ #define DIA_NRSP 19 /* No response from modem */ #define DIA_ERR 20 /* Modem command error */ #define DIA_NOIN 21 /* Failure to initialize modem */ #define DIA_BUSY 22 /* Phone busy */ #define DIA_NOCA 23 /* No carrier */ #define DIA_NODT 24 /* No dialtone */ #define DIA_RING 25 /* Ring, incoming call */ #define DIA_NOAN 26 /* No answer */ #define DIA_DISC 27 /* Disconnected */ #define DIA_VOIC 28 /* Answered by voice */ #define DIA_NOAC 29 /* Access denied, forbidden call */ #define DIA_BLCK 30 /* Blacklisted */ #define DIA_DELA 31 /* Delayed */ #define DIA_FAX 32 /* Fax */ #define DIA_DIGI 33 /* Digital Line */ #define DIA_TAPI 34 /* TAPI dialing failure */ #define DIA_UERR 98 /* Unknown error */ #define DIA_UNSP 99 /* Unspecified failure detected by modem */ #define MDMINF struct mdminf MDMINF { /* Structure for modem-specific information */ char * name; /* Descriptive name */ char * pulse; /* Command to force pulse dialing */ char * tone; /* Command to force tone dialing */ int dial_time; /* Time modem allows for dialing (secs) */ char * pause_chars; /* Character(s) to tell modem to pause */ int pause_time; /* Time associated with pause chars (secs) */ char * wake_str; /* String to wakeup modem & put in cmd mode */ int wake_rate; /* Delay between wake_str characters (msecs) */ char * wake_prompt; /* String prompt after wake_str */ char * dmode_str; /* String to put modem in dialing mode */ char * dmode_prompt; /* String prompt for dialing mode */ char * dial_str; /* Dialing string, with "%s" for number */ int dial_rate; /* Interchar delay to modem (msec) */ int esc_time; /* Escape sequence guard time (msec) */ int esc_char; /* Escape character */ char * hup_str; /* Hangup string */ char * hwfc_str; /* Hardware flow control string */ char * swfc_str; /* Software flow control string */ char * nofc_str; /* No flow control string */ char * ec_on_str; /* Error correction on string */ char * ec_off_str; /* Error correction off string */ char * dc_on_str; /* Data compression on string */ char * dc_off_str; /* Data compression off string */ char * aa_on_str; /* Autoanswer on string */ char * aa_off_str; /* Autoanswer off string */ char * sb_on_str; /* Speed buffering on string */ char * sb_off_str; /* Speed buffering off string */ char * sp_on_str; /* Speaker on string */ char * sp_off_str; /* Speaker off string */ char * vol1_str; /* Volume low string */ char * vol2_str; /* Volume med string */ char * vol3_str; /* Volume high string */ char * ignoredt; /* Ignore dialtone string */ char * ini2; /* Last-minute init string */ long max_speed; /* Maximum interface speed */ long capas; /* Capability bits */ /* function to read modem's response string to a non-dialing command */ _PROTOTYP( int (*ok_fn), (int,int) ); }; #endif /* NODIAL */ /* Symbols for File Attributes */ #define AT_XALL 0 /* All of them */ #define AT_ALLY 1 /* All of them on (Yes) */ #define AT_ALLN 2 /* All of them off (no) */ #define AT_LENK 3 /* Length in K */ #define AT_FTYP 4 /* File Type */ #define AT_DATE 5 /* Creation date */ #define AT_CREA 6 /* Creator */ #define AT_ACCT 7 /* Account */ #define AT_AREA 8 /* Area */ #define AT_PSWD 9 /* Password for area */ #define AT_BLKS 10 /* Blocksize */ #define AT_ACCE 11 /* Access */ #define AT_ENCO 12 /* Encoding */ #define AT_DISP 13 /* Disposition */ #define AT_LPRO 14 /* Local Protection */ #define AT_GPRO 15 /* Generic Protection */ #define AT_SYSI 16 /* System ID */ #define AT_RECF 17 /* Record Format */ #define AT_SYSP 18 /* System-Dependent Parameters */ #define AT_LENB 19 /* Length in Bytes */ #define AT_EOA 20 /* End of Attributes */ /* Kermit packet information structure */ struct pktinfo { /* Packet information structure */ CHAR *bf_adr; /* buffer address */ int bf_len; /* buffer length */ CHAR *pk_adr; /* Packet address within buffer */ int pk_len; /* length of data within buffer */ int pk_typ; /* packet type */ int pk_seq; /* packet sequence number */ int pk_rtr; /* retransmission count */ }; /* Send Modes (indicating which type of SEND command was used) */ #define SM_SEND 0 #define SM_MSEND 1 #define SM_RESEND 2 #define SM_PSEND 3 #define SM_MAIL 4 #define SM_PRINT 5 #define OPTBUFLEN 256 /* File-related symbols and structures */ /* Used by SET FILE command but also by protocol and i/o modules */ #define XMODE_A 0 /* Transfer mode Automatic */ #define XMODE_M 1 /* Transfer mode Manual */ #define XYFILN 0 /* Naming */ #define XYFN_L 0 /* Literal */ #define XYFN_C 1 /* Converted */ #define XYFILT 1 /* Type */ #define XYFT_T 0 /* Text */ #define XYFT_B 1 /* Binary */ #define XYFT_I 2 /* Image or Block (VMS) */ #define XYFT_L 3 /* Labeled (tagged binary) (VMS or OS/2) */ #define XYFT_U 4 /* Binary Undefined (VMS) */ #define XYFT_M 5 /* MacBinary (Macintosh) */ #define XYFT_X 6 /* TENEX (FTP TYPE L 8) */ #define XYFT_D 99 /* Debug (for session logs) */ #define XYFILW 2 /* Warning */ #define XYFILD 3 /* Display */ #define XYFILC 4 /* Character set */ #define XYFILF 5 /* Record Format */ #define XYFF_S 0 /* Stream */ #define XYFF_V 1 /* Variable */ #define XYFF_VB 2 /* Variable with RCW's */ #define XYFF_F 3 /* Fixed length */ #define XYFF_U 4 /* Undefined */ #define XYFILR 6 /* Record length */ #define XYFILO 7 /* Organization */ #define XYFO_S 0 /* Sequential */ #define XYFO_I 1 /* Indexed */ #define XYFO_R 2 /* Relative */ #define XYFILP 8 /* Printer carriage control */ #define XYFP_N 0 /* Newline (imbedded control characters) */ #define XYFP_F 1 /* FORTRAN (space, 1, +, etc, in column 1 */ #define XYFP_P 2 /* Special printer carriage controls */ #define XYFP_X 4 /* None */ #define XYFILX 9 /* Collision Action */ #define XYFX_A 3 /* Append */ #define XYFX_Q 5 /* Ask */ #define XYFX_B 2 /* Backup */ #define XYFX_D 4 /* Discard */ #define XYFX_R 0 /* Rename */ #define XYFX_X 1 /* Replace */ #define XYFX_U 6 /* Update */ #define XYFX_M 7 /* Modtimes differ */ #define XYFILB 10 /* Blocksize */ #define XYFILZ 11 /* Disposition */ #define XYFZ_N 0 /* New, Create */ #define XYFZ_A 1 /* New, append if file exists, else create */ #define XYFZ_O 2 /* Old, file must exist */ #define XYFILS 12 /* File Byte Size */ #define XYFILL 13 /* File Label (VMS) */ #define XYFILI 14 /* File Incomplete */ #define XYFILQ 15 /* File path action (strip or not) */ #define XYFILG 16 /* File download directory */ #define XYFILA 17 /* Line terminator for local text files */ #define XYFA_L 012 /* LF (as in UNIX) */ #define XYFA_C 015 /* CR (as in OS-9 or Mac OS) */ #define XYFA_2 000 /* CRLF -- Note: this must be defined as 0 */ #define XYFILY 18 /* Destination */ #define XYFILV 19 /* EOF Detection Method */ #define XYEOF_L 0 /* File length */ #define XYEOF_Z 1 /* Ctrl-Z in file */ #define XYFILH 20 /* OUTPUT parameters - buffered, blocking, etc */ #define XYFIBP 21 /* BINARY-PATTERN */ #define XYFITP 22 /* TEXT-PATTERN */ #define XYFIPA 23 /* PATTERNS ON/OFF */ #define XYFILU 24 /* UCS ... */ #define XYF_PRM 25 /* PERMISSIONS, PROTECTION */ #define XYF_INSP 26 /* INSPECTION (SCAN) */ #define XYF_DFLT 27 /* DEFAULT (character sets) */ #define XYF_SSPA 28 /* STRINGSPACE */ #define XYF_LSIZ 29 /* LISTSIZE */ /* File Type (return code) definitions and corresponding name strings */ #define FT_7BIT 0 /* 7-bit text */ #define FT_8BIT 1 /* 8-bit text */ #define FT_UTF8 2 /* UTF8 */ #define FT_UCS2 3 /* UCS2 */ #define FT_TEXT 4 /* Unknown text */ #define FT_BIN 5 /* Binary */ #define SCANFILEBUF 49152 /* Size of file scan (48K) */ /* Connection closed reasons */ #define WC_REMO 0 /* Closed by remote */ #define WC_CLOS 1 /* Closed from our end */ #define WC_TELOPT 2 /* Telnet negotiation failure */ #ifdef BIGBUFOK #define FTPATTERNS 256 #else #define FTPATTERNS 64 #endif /* BIGBUFOK */ #define SYS_UNK 0 /* Selected server system types */ #define SYS_UNIX 1 #define SYS_WIN32 2 #define SYS_VMS 3 #define SYS_OS2 4 #define SYS_DOS 5 #define SYS_TOPS10 6 #define SYS_TOPS20 7 #define SYS_VOS 8 #define SYS_DG 9 #define SYS_OSK 10 #define SYS_MAX 11 #ifdef CK_SMALL #define PWBUFL 63 #else #define PWBUFL 255 #endif /* CK_SMALL */ #ifdef OS2 struct tt_info_rec { /* Terminal emulation info */ char *x_name; char *x_aliases[4]; char *x_id; }; #endif /* OS2 */ /* BEEP TYPES */ #define BP_BEL 0 /* Terminal bell */ #define BP_NOTE 1 /* Info */ #define BP_WARN 2 /* Warning */ #define BP_FAIL 3 /* Error */ #ifndef NOIKSD #ifdef IKSDB /* IKSD Database definitions */ /* Field values */ #define DBF_INUSE 1 /* Flag bits... In use */ #define DBF_USER 2 /* Real user (versus anonymous) */ #define DBF_LOGGED 4 /* Logged in (versus not) */ /* Data Definitions... */ /* Numeric fields, hex, right justified, 0-filled on left */ #define db_FLAGS 0 /* Field 0: Flags */ #define DB_FLAGS 0 /* Offset: 0 */ #define dB_FLAGS 4 /* Length: 4 (hex digits) */ #define db_ATYPE 1 /* Field 1: Authentication type */ #define DB_ATYPE 4 /* 4 hex digits */ #define dB_ATYPE 4 #define db_AMODE 2 /* Field 2: Authentication mode */ #define DB_AMODE 8 /* 4 hex digits */ #define dB_AMODE 4 #define db_STATE 3 /* Field 3: State - 4 hex digits*/ #define DB_STATE 12 /* 4 hex digits */ #define dB_STATE 4 #define db_MYPID 4 /* Field 4: My PID */ #define DB_MYPID 16 /* 16 hex digits left padded with 0 */ #define dB_MYPID 16 #define db_SADDR 5 /* Field 5: Server (my) IP address */ #define DB_SADDR 32 /* 16 hex digits left padded with 0 */ #define dB_SADDR 16 #define db_CADDR 6 /* Field 6: Client IP address */ #define DB_CADDR 48 /* 16 hex digits left padded with 0 */ #define dB_CADDR 16 /* Date-time fields (17 right-adjusted in 18 for Y10K readiness) */ #define db_START 7 /* Field 7: Session start date-time */ #define DB_START 65 /* 64 is leading space for Y10K */ #define dB_START 17 #define db_LASTU 8 /* Field 8: Last lastu date-time */ #define DB_LASTU 83 /* 82 is leading space for Y10K */ #define dB_LASTU 17 #define db_ULEN 9 /* Field 9: Length of Username */ #define DB_ULEN 100 /* 4 hex digits */ #define dB_ULEN 4 #define db_DLEN 10 /* Field 10: Length of Directory */ #define DB_DLEN 104 /* 4 hex digits */ #define dB_DLEN 4 #define db_ILEN 11 /* Field 11: Length of Info */ #define DB_ILEN 108 /* 4 hex digits */ #define dB_ILEN 4 #define db_PAD1 12 /* Field 12: (Reserved) */ #define DB_PAD1 112 /* filled with spaces */ #define dB_PAD1 912 /* String fields, all right-padded with blanks */ #define db_USER 13 /* Field 13: Username */ #define DB_USER 1024 /* right-padded with spaces */ #define dB_USER 1024 #define db_DIR 14 /* Field 14: Current directory */ #define DB_DIR 2048 /* right-padded with spaces */ #define dB_DIR 1024 #define db_INFO 15 /* Field 15: State-specific info */ #define DB_INFO 3072 /* right-padded with spaces */ #define dB_INFO 1024 #define DB_RECL 4096 /* Database record length */ /* Offset, length, and type of each field thru its db_XXX symbol */ #define DBT_HEX 1 /* Hexadecimal number */ #define DBT_STR 2 /* String */ #define DBT_DAT 3 /* Date-Time yyyymmdd hh:mm:ss */ #define DBT_UND 9 /* Undefined and blank */ struct iksdbfld { int off; /* Position (offset) */ int len; /* Length (bytes) */ int typ; /* Data type */ }; _PROTOTYP(int dbinit, (void)); _PROTOTYP(int initslot, (int)); _PROTOTYP(int getslot, (void)); _PROTOTYP(int freeslot, (int)); _PROTOTYP(int updslot, (int)); _PROTOTYP(int slotstate, (int, char *, char *, char *)); _PROTOTYP(int slotdir, (char *, char *)); #endif /* IKSDB */ #endif /* NOIKSD */ /* ANSI forward declarations for protocol-related functions. */ _PROTOTYP( int input, (void) ); _PROTOTYP( int inibufs, (int, int) ); /* _PROTOTYP( int makebuf, (int, int, CHAR [], struct pktinfo *) ); */ _PROTOTYP( int mksbuf, (int) ); _PROTOTYP( int mkrbuf, (int) ); _PROTOTYP( int spack, (char, int, int, CHAR *) ); _PROTOTYP( VOID proto, (void) ); _PROTOTYP( int rpack, (void) ); _PROTOTYP( int ack, (void) ); _PROTOTYP( int nack, (int) ); _PROTOTYP( int ackn, (int) ); _PROTOTYP( int ack1, (CHAR *) ); _PROTOTYP( int ackns, (int, CHAR *) ); #ifdef STREAMING _PROTOTYP( int fastack, (void) ); #endif /* STREAMING */ _PROTOTYP( int resend, (int) ); _PROTOTYP( int errpkt, (CHAR *) ); _PROTOTYP( VOID logpkt, (char, int, CHAR *, int) ); _PROTOTYP( CHAR dopar, (CHAR) ); _PROTOTYP( int chk1, (CHAR *, int) ); _PROTOTYP( unsigned int chk2, (CHAR *, int) ); _PROTOTYP( unsigned int chk3, (CHAR *, int) ); _PROTOTYP( int sipkt, (char) ); _PROTOTYP( int sopkt, (void) ); _PROTOTYP( int sinit, (void) ); _PROTOTYP( VOID rinit, (CHAR *) ); _PROTOTYP( int spar, (CHAR *) ); _PROTOTYP( int rcvfil, (char *) ); _PROTOTYP( CHAR * rpar, (void) ); _PROTOTYP( int gnfile, (void) ); _PROTOTYP( int getsbuf, (int) ); _PROTOTYP( int getrbuf, (void) ); _PROTOTYP( int freesbuf, (int) ); _PROTOTYP( int freerbuf, (int) ); _PROTOTYP( int dumpsbuf, (void) ); _PROTOTYP( int dumprbuf, (void) ); _PROTOTYP( VOID freerpkt, (int) ); _PROTOTYP( int chkwin, (int, int, int) ); _PROTOTYP( int rsattr, (CHAR *) ); _PROTOTYP( char *getreason, (char *) ); _PROTOTYP( int scmd, (char, CHAR *) ); _PROTOTYP( int encstr, (CHAR *) ); _PROTOTYP( int decode, (CHAR *, int (*)(char), int) ); _PROTOTYP( int bdecode, (CHAR *, int (*)(char)) ); _PROTOTYP( int fnparse, (char *) ); _PROTOTYP( int syscmd, (char *, char *) ); _PROTOTYP( int cwd, (char *) ); _PROTOTYP( int remset, (char *) ); _PROTOTYP( int initattr, (struct zattr *) ); _PROTOTYP( int gattr, (CHAR *, struct zattr *) ); _PROTOTYP( int adebu, (char *, struct zattr *) ); _PROTOTYP( int canned, (CHAR *) ); _PROTOTYP( int opent, (struct zattr *) ); _PROTOTYP( int ckopenx, (struct zattr *) ); _PROTOTYP( int opena, (char *, struct zattr *) ); _PROTOTYP( int openi, (char *) ); _PROTOTYP( int openo, (char *, struct zattr *, struct filinfo *) ); _PROTOTYP( int openc, (int, char *) ); _PROTOTYP( int reof, (char *, struct zattr *) ); _PROTOTYP( VOID reot, (void) ); _PROTOTYP( int sfile, (int) ); _PROTOTYP( int sattr, (int, int) ); _PROTOTYP( int sdata, (void) ); _PROTOTYP( int seof, (int) ); _PROTOTYP( int sxeof, (int) ); _PROTOTYP( int seot, (void) ); _PROTOTYP( int window, (int) ); _PROTOTYP( int clsif, (void) ); _PROTOTYP( int clsof, (int) ); _PROTOTYP( CHAR setgen, (char, char *, char *, char *) ); _PROTOTYP( int getpkt, (int, int) ); _PROTOTYP( int maxdata, (void) ); _PROTOTYP( int putsrv, (char) ); _PROTOTYP( int puttrm, (char) ); _PROTOTYP( int putque, (char) ); _PROTOTYP( int putfil, (char) ); _PROTOTYP( int putmfil, (char) ); _PROTOTYP( int zputfil, (char) ); _PROTOTYP( VOID zdstuff, (CHAR) ); _PROTOTYP( int tinit, (int) ); _PROTOTYP( VOID pktinit, (void) ); _PROTOTYP( VOID resetc, (void) ); _PROTOTYP( VOID xsinit, (void) ); _PROTOTYP( int adjpkl, (int,int,int) ); _PROTOTYP( int chktimo, (int,int) ); _PROTOTYP( int nxtpkt, (void) ); _PROTOTYP( VOID rcalcpsz, (void) ); _PROTOTYP( int srinit, (int, int, int) ); _PROTOTYP( VOID tstats, (void) ); _PROTOTYP( VOID fstats, (void) ); _PROTOTYP( VOID intmsg, (long) ); _PROTOTYP( VOID ermsg, (char *) ); _PROTOTYP( int chkint, (void) ); _PROTOTYP( VOID sdebu, (int) ); _PROTOTYP( VOID rdebu, (CHAR *, int) ); _PROTOTYP( char * dbchr, ( int ) ); #ifdef COMMENT _PROTOTYP( SIGTYP stptrap, (int, int) ); _PROTOTYP( SIGTYP trap, (int, int) ); #else _PROTOTYP( SIGTYP stptrap, (int) ); _PROTOTYP( SIGTYP trap, (int) ); #endif /* COMMENT */ _PROTOTYP( char * ck_errstr, (void) ); #ifndef NOXFER _PROTOTYP( int agnbyte, (void) ); #endif /* NOXFER */ _PROTOTYP( int xgnbyte, (int, int, int (*)(void)) ); _PROTOTYP( int xpnbyte, (int, int, int, int (*)(char)) ); /* User interface functions needed by main program, etc. */ _PROTOTYP( int doconect, (int,int) ); _PROTOTYP( VOID setflow, (void) ); _PROTOTYP( VOID prescan, (int) ); _PROTOTYP( VOID setint, (void) ); _PROTOTYP( VOID doinit, (void) ); _PROTOTYP( VOID dofast, (void) ); _PROTOTYP( VOID cmdini, (void) ); _PROTOTYP( int dotake, (char *) ); _PROTOTYP( int cmdlin, (void) ); #ifdef OS2 _PROTOTYP( int conect, (int) ); #else /* OS2 */ _PROTOTYP( int conect, (void) ); #endif /* OS2 */ #ifdef COMMENT /* Only used in Unix CONNECT module where it is defined before use */ _PROTOTYP( int ckcgetc, (int) ); #endif /* COMMENT */ _PROTOTYP( int ckcputc, (int) ); _PROTOTYP (int mdmhup, (void) ); _PROTOTYP( VOID herald, (void) ); _PROTOTYP( VOID fixcmd, (void) ); _PROTOTYP( int doarg, (char) ); _PROTOTYP( int doxarg, (char **, int) ); _PROTOTYP( VOID usage, (void) ); _PROTOTYP( VOID doclean, (int) ); _PROTOTYP( int sndhlp, (void) ); _PROTOTYP( int sndstatus, (void) ); _PROTOTYP( int sndstring, (char *) ); _PROTOTYP( VOID ckhost, (char *, int) ); _PROTOTYP( int gettcs, (int, int) ); _PROTOTYP( VOID getdialenv, (void) ); _PROTOTYP( VOID setprefix, (int) ); _PROTOTYP( VOID initpat, (void) ); _PROTOTYP( VOID initcsets, (void) ); #ifdef CK_TIMERS _PROTOTYP( VOID rttinit, (void) ); _PROTOTYP( int getrtt, (int, int) ); #endif /* CK_TIMERS */ _PROTOTYP( int is_a_tty, (int) ); _PROTOTYP( int snddir, (char *) ); _PROTOTYP( int snddel, (char *) ); _PROTOTYP( int sndtype, (char *) ); _PROTOTYP( int dooutput, (char *, int) ); _PROTOTYP( int isabsolute, (char *) ); _PROTOTYP( VOID whoarewe, (void) ); _PROTOTYP( int ckmkdir, (int, char *, char **, int, int) ); _PROTOTYP( int autoexitchk, (CHAR) ); _PROTOTYP( VOID fcps, (void) ); #ifdef OS2 _PROTOTYP( VOID logchar, (unsigned short) ); #else /* OS2 */ _PROTOTYP( VOID logchar, (char) ); #endif /* OS2 */ _PROTOTYP( VOID logstr, (char *, int) ); _PROTOTYP( VOID dologend, (void) ); #ifdef NOLOCAL #define dologshow() #else _PROTOTYP( long dologshow, (int) ); #endif /* NOLOCAL */ #ifdef NODISPLAY #define fxdinit(a) #else _PROTOTYP( VOID fxdinit, (int) ); #endif /* NODISPLAY */ _PROTOTYP( int fileselect, (char *, char *, char *, char *, char *, CK_OFF_T, CK_OFF_T, int, int, char **) ); _PROTOTYP( char * whoami, (void) ); _PROTOTYP( int shoesc, (int) ); #ifdef CK_APC _PROTOTYP( int chkspkt, (char *) ); _PROTOTYP( int kstart, (CHAR) ); _PROTOTYP( VOID autodown, (int)); #ifdef CK_XYZ _PROTOTYP( int zstart, (CHAR) ); #endif /* CK_XYZ */ #ifdef OS2 _PROTOTYP(void apc_command, (int, char*)); #endif /* OS2 */ #endif /* CK_APC */ /* User Query data structures and functions */ struct txtbox { char * t_buf; /* Destination buffer address */ int t_len; /* Destination buffer length */ char * t_lbl; /* Label for this field */ char * t_dflt; /* Default response for this field */ int t_echo; /* 0 = no, 1 = yes, 2 = asterisks */ }; #define DEFAULT_UQ_TIMEOUT 0 _PROTOTYP(int uq_ok, (char *,char *,int,char **,int) ); _PROTOTYP(int uq_txt, (char *,char *,int,char **,char *,int,char *,int)); _PROTOTYP(int uq_mtxt, (char *,char **,int,struct txtbox[]) ); _PROTOTYP(int uq_file, (char *,char *,int,char **,char *,char *,int)); #ifdef CK_URL struct urlopt { char * nam; char * val; }; #define MAX_URL_OPTS 16 struct urldata { char * sav; /* The URL itself */ char * svc; /* Service */ char * usr; /* User */ char * psw; /* Password */ char * hos; /* Host */ char * por; /* Port */ char * pth; /* Path */ int nopts; /* number of options */ struct urlopt opt[MAX_URL_OPTS]; /* options */ }; /* _PROTOTYP(int urlparse, (char *, struct urldata *)); */ #endif /* CK_URL */ #endif /* CKCKER_H */ /* End of ckcker.h */ ckclib.c000664 045065 024037 00000275147 14767411403 012605 0ustar00fdckermit000000 000000 char * cklibv = "C-Kermit library, 10.0.063, 02 May 2023"; #define CKCLIB_C /* C K C L I B . C -- C-Kermit Library routines. */ /* Author: Frank da Cruz , Columbia University Academic Information Systems, New York City. Copyright (C) 1999, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ /* General-purpose, system/platform/compiler-independent routines for use by all modules. Many are replacements for commonly used C library functions that are not found on every platform, and/or that lack needed functionality (e.g. caseless string search/compare) or safety features. ckstrncpy() - Similar to strncpy() but different (see comments). ckstrncat() - Similar to strncat() but different (see comments). chartostr() - Converts a char to a string (self or ctrl char name). ckstrchr() - Portable strchr(). ckstrpbrk() - Portable strpbrk(). cklower() - Lowercase a string (in place). ckupper() - Uppercase a string (in place). ckindex() - Left or right index. ckstrstr() - Portable strstr(). ckitoa() - Converts int to string. ckuitoa() - Converts unsigned int to string. ckltoa() - Converts long to string. ckultoa() - Converts unsigned long to string. ckfstoa() - Converts off_t-type integer (long or long long) to string. ckatofs() - Converts a numeric string to an off_t-type integer. ckctoa() - Converts char to string. ckmakmsg() - Constructs a message from 4 source strings. ckmakxmsg() - Constructs a message from 12 source strings. ckmatch() - Pattern matching. ckmemcpy() - Portable memcpy(). ckrchar() - Rightmost character of a string. ckstrcmp() - Possibly caseless string comparison. ckstrpre() - Caseless string prefix comparison. sh_sort() - Sorts an array of strings, many options. brstrip() - Strips enclosing braces (and doublequotes). makelist() - Splits "{{item}{item}...}" into an array. makestr() - Careful malloc() front end. xmakestr() - ditto (see comments). ckradix() - Convert number radix (2-36). b8tob64() - Convert data to base 64. b64tob8() - Convert base 64 to data. chknum() - Checks if string is a (possibly signed) integer. rdigits() - Checks if string is composed only of decimal digits. isfloat() - Checks if string is a valid floating-point number. ckround() - Rounds a floating-point number to desired precision. parnam() - Returns parity name string. hhmmss() - Converts seconds to hh:mm:ss string. lset() - Write fixed-length field left-adjusted into a record. rset() - Write fixed-length field right-adjusted into a record. ulongtohex() - Converts an unsigned long to a hex string. hextoulong() - Converts a hex string to an unsigned long. cksplit() - Splits a string into an array of words. ispattern() - Tells if argument string is a pattern. Prototypes are in ckclib.h. Note: This module should not contain any extern declarations. */ #include "ckcsym.h" #include "ckcdeb.h" #include "ckcasc.h" #include "ckcker.h" #include "ckucmd.h" #include "ckuusr.h" #include "ckcnet.h" /* for struct sockaddr */ #include "ckcfnp.h" /* Prototypes (must be last) */ /* Public variables */ int dblquo = 1; /* Nonzero if doublequotes can be used for grouping */ char * ccntab[] = { /* Names of ASCII (C0) control characters 0-31 */ "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" }; char * c1tab[] = { /* Names of ISO 6429 (C1) control characters 0-32 */ "XXX", "XXX", "BPH", "NBH", "IND", "NEL", "SSA", "ESA", "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3", "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA", "SOS", "XXX", "SCI", "CSI", "ST", "OSC", "PM", "APC", "NBS" }; #define RXRESULT 127 static char rxdigits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static char rxresult[RXRESULT+1]; /* C K S T R N C P Y */ /* Copies a NUL-terminated string into a buffer whose total length is given, ensuring that the result is NUL-terminated even if it has to be truncated. Call with: dest = pointer to destination buffer src = pointer to source string len = length of destination buffer (the actual length, not one less). Returns: int, The number of bytes copied, 0 or more. NOTE: This is NOT a replacement for strncpy(): . strncpy() does not require its source string to be NUL-terminated. . strncpy() does not necessarily NUL-terminate its result. . strncpy() treats the length argument as the number of bytes to copy. . ckstrncpy() treats the length argument as the size of the dest buffer. . ckstrncpy() doesn't dump core if given NULL string pointers. . ckstrncpy() returns a number. Use ckstrncpy() when you want to: . Copy a NUL-terminated string into a buffer without overrun, truncating it if necessary to fit in the buffer, and null-terminating it. . Get the length of the string back. Use strncpy() when you want to: . Copy a piece of a string. */ int #ifdef CK_ANSIC ckstrncpy(char * dest, const char * src, int len) #else ckstrncpy(dest,src,len) char * dest, * src; int len; #endif /* CK_ANSIC */ { int i; if (len < 1 || !src || !dest) { /* Nothing or nowhere to copy */ if (dest) *dest = NUL; return(0); } #ifndef NOCKSTRNCPY for (i = 0; src[i] && (i < len-1); i++) /* Args OK, copy */ dest[i] = src[i]; dest[i] = NUL; #else i = strlen(src); if (i > len) i = len; strncpy(dest,src,i); dest[len] = NUL; #endif /* NOCKSTRNCPY */ return(i); } /* C K S T R N C A T */ /* Appends a NUL-terminated string to a buffer whose total length is given, ensuring that the result is NUL-terminated even if it had to be truncated. Call with: dest = pointer to destination buffer containing a null-terminated string src = pointer to null-terminated source string len = length of destination buffer (the actual length, not one less). Returns: int, The number of bytes copied, 0 or more. */ int #ifdef CK_ANSIC ckstrncat(char * dest, const char * src, int len) #else ckstrncat(dest,src,len) char * dest, * src; int len; #endif /* CK_ANSIC */ { register int i, j; #ifdef NOCKSTRNCPY register char * s1, * s2; #endif /* NOCKSTRNCPY */ if (len < 1 || !src || !dest) { /* Nothing or nowhere to copy */ if (dest) *dest = NUL; return(0); } #ifndef NOCKSTRNCPY /* Args OK, copy */ for (i = 0, j = strlen(dest); src[i] && (i < len-j-1); i++) dest[i+j] = src[i]; dest[i+j] = NUL; #else j = 0; s1 = dest; while (*s1++) j++; /* j = strlen(dest); */ s1--; /* (back up over NUL) */ i = 0; s2 = (char *)src; while (*s2++) i++; /* i = strlen(src); */ if (i > (len-j)) i = len - j; if (i <= 0) return(0); #ifdef COMMENT strncpy(&dest[j],src,i); #else j = i; /* This should be a bit faster... */ s2 = (char *)src; /* depends on strcpy implementation; */ while ((*s1++ = *s2++) && j--) /* at least it shouldn't be slower. */ ; dest[len-1] = NUL; /* In case of early exit. */ #endif /* COMMENT */ #endif /* NOCKSTRNCPY */ return(i); } /* C K M A K M S G */ /* Constructs a message from up to 4 pieces with length checking. Result is always NUL terminated. Call with: buf: Pointer to buffer for constructing message. len: Length of buffer. s1-s4: String pointers (can be NULL). Returns: 0: Nothing was copied. n: (positive number) n bytes copied, all args copied successfully. -n: n bytes were copied, destination buffer not big enough for all. Also see: ckmakxmsg() -- accepts 12 string args. ckitoa(), ckltoa(), ckctoa(), ckitox(), etc. Use ckmak[x]msg() plus ck?to?() as a safe replacement for sprintf(). */ int #ifdef CK_ANSIC ckmakmsg(char * buf, int len, char *s1, char *s2, char *s3, char *s4) #else /* CK_ANSIC */ ckmakmsg(buf,len,s1,s2,s3,s4) char *buf, *s1, *s2, *s3, *s4; int len; #endif /* CK_ANSIC */ { int i, n = 0, m = 0; char *s; char *p, *a[4]; if (!buf) return(n); /* No destination */ if (len < 1) return(n); /* No size */ s = buf; /* Point to destination */ a[0] = s1; a[1] = s2; a[2] = s3; a[3] = s4; /* Array of source strings */ for (i = 0; i < 4; i++) { /* Loop thru array */ p = a[i]; /* Point to this element */ if (p) { /* If pointer not null */ n = ckstrncpy(s,p,len); /* Copy safely */ m += n; /* Accumulate total */ if (p[n]) /* Didn't get whole thing? */ return(-m); /* return indicating buffer full */ len -= n; /* Deduct from space left */ s += n; /* Otherwise advance dest pointer */ } } return(m); /* Return total bytes copied */ } /* C K M A K X M S G */ /* Exactly like ckmakmsg(), but accepts 12 string arguments. */ int #ifdef CK_ANSIC ckmakxmsg(char * buf, int len, char *s1, char *s2, char *s3, char *s4, char *s5, char *s6, char *s7, char *s8, char *s9, char *s10, char *s11, char *s12) #else /* CK_ANSIC */ ckmakxmsg(buf,len,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12) char *buf, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8, *s9, *s10, *s11, *s12; int len; #endif /* CK_ANSIC */ { int i, n = 0, m = 0; char *s; char *p, *a[12]; if (!buf) return(n); /* No destination */ if (len < 1) return(n); /* No size */ s = buf; /* Point to destination */ a[0] = s1; a[1] = s2; a[2] = s3; a[3] = s4; /* Source-string array */ a[4] = s5; a[5] = s6; a[6] = s7; a[7] = s8; a[8] = s9; a[9] = s10; a[10] = s11; a[11] = s12; for (i = 0; i < 12; i++) { /* Loop thru array */ p = a[i]; /* Point to this element */ if (p) { /* If pointer not null */ n = ckstrncpy(s,p,len); /* Copy safely */ m += n; /* Accumulate total */ if (p[n]) /* Didn't get whole thing? */ return(-m); /* return indicating buffer full */ len -= n; /* Deduct from space left */ s += n; /* Otherwise advance dest pointer */ } } return(m); /* Return total bytes copied */ } /* C H A R T O S T R */ /* Converts a character to a string, interpreting controls. */ char * #ifdef CK_ANSIC chartostr( int x ) /* Call with char x */ #else chartostr( x ) int x; #endif /* CK_ANSIC */ { static char buf[2]; /* Returns string pointer. */ if (x < 32) return(ccntab[x]); if (x == 127) return("DEL"); if (x > 127 && x < 161) return(c1tab[x - 128]); if (x == 0xAD) return("SHY"); buf[1] = NUL; buf[0] = (unsigned)(x & 0xff); return((char *)buf); } /* C K R C H A R */ /* Returns the rightmost character of the given null-terminated string */ int #ifdef CK_ANSIC ckrchar( char * s ) #else ckrchar(s) char * s; #endif /* CK_ANSIC */ { register CHAR c = '\0', *p; p = (CHAR *)s; if (!p) p = (CHAR *)""; /* Null pointer == empty string */ if (!*p) return(0); while (*p) /* Crawl to end of string */ c = *p++; return((unsigned)(c & 0xff)); /* Return final character */ } /* C K S T R C H R */ /* Replacement for strchr(), which is not universal. */ /* Call with: s = pointer to string to look in. c = character to look for. Returns: NULL if c not found in s or upon any kind of error, or: pointer to first occurrence of c in s, searching from left to right. */ char * #ifdef CK_ANSIC ckstrchr(char * s, char c) #else ckstrchr(s,c) char *s, c; #endif /* CK_ANSIC */ /* ckstrchr */ { if (!s) return(NULL); while (*s && *s != c) s++; return((*s == c) ? s : NULL); } /* C K S T R R C H R */ /* Replacement for strrchr(), which is not universal. */ /* Call with: s = pointer to string to look in. c = character to look for. Returns: NULL if c not found in s or upon any kind of error, or: pointer to first occurrence of c in s, searching from right to left. */ char * #ifdef CK_ANSIC ckstrrchr(char * s, char c) #else ckstrrchr(s,c) char *s, c; #endif /* CK_ANSIC */ /* ckstrchr */ { char * s2 = NULL; if (!s) return(NULL); while (*s) { if (*s == c) s2 = s; s++; } return(s2); } /* C K S T R P B R K -- Portable replacement for strpbrk() */ /* Returns pointer to first char in s1 that is also in s2, or NULL */ char * #ifdef CK_ANSIC ckstrpbrk(char * s1, char * s2) #else ckstrpbrk(s1, s2) char * s1, * s2; #endif /* CK_ANSIC */ { char c1, c2, * s3; if (!s1 || !s2) return(NULL); if (!*s1 || !*s2) return(NULL); while ((c1 = *s1++)) { s3 = s2; while ((c2 = *s3++)) { if (c2 == c1) return(s1-1); } } return(NULL); } /* C K L O W E R -- Lowercase a string IN PLACE */ /* Returns the length of the string */ int #ifdef CK_ANSIC cklower(char * s) #else cklower(s) char *s; #endif /* CK_ANSIC */ { int n = 0; if (!s) return(0); while (*s) { if (isupper(*s)) *s = (char) tolower(*s); s++, n++; } return(n); } /* C K U P P E R -- Uppercase a string IN PLACE */ /* Returns the length of the string */ int #ifdef CK_ANSIC ckupper(char * s) #else ckupper(s) char *s; #endif /* CK_ANSIC */ { int n = 0; if (!s) return(0); while (*s) { if (islower(*s)) *s = (char) toupper(*s); s++, n++; } return(n); } /* C K L T O A -- Long to string -- FOR DISCIPLINED USE ONLY */ #define NUMBUF 1024 static char numbuf[NUMBUF+32] = { NUL, NUL }; static int numbp = 0; /* ckltoa() and ckitoa() are like atol() and atoi() in the reverse direction, returning a pointer to the string representation of the given number without the caller having to worry about allocating or defining a buffer first. They manage their own internal buffer, so successive calls return different pointers. However, to keep memory consumption from growing without bound, the buffer recycles itself. So after several hundred calls (depending on the size of the numbers), some of the earlier pointers might well find themselves referencing something different. Moral: You can't win in C. Therefore, these routines are intended mainly for generating numeric strings for short-term use, e.g. for passing numbers in string form as parameters to functions. For long-term use, the result must be copied to a safe place. */ char * #ifdef CK_ANSIC ckltoa(long n) #else ckltoa(n) long n; #endif /* CK_ANSIC */ /* ckltoa */ { char buf[32]; /* Internal working buffer */ char * p, * s, * q; int k, x, len = 0, sign = 0; if (n < 0L) { /* Sign */ n = 0L - n; sign = 1; } buf[31] = NUL; for (k = 30; k > 0; k--) { /* Convert number to string */ x = n % 10L; buf[k] = x + '0'; n = n / 10L; if (!n) break; } if (sign) buf[--k] = '-'; /* Add sign if necessary */ len = 31 - k; if (len + numbp > NUMBUF) numbp = 0; p = numbuf + numbp; q = p; s = buf + k; while ((*p++ = *s++)) ; /* Copy */ *p++ = NUL; numbp += len+1; return(q); /* Return pointer */ } /* C K U L T O A -- Unsigned long to string */ char * #ifdef CK_ANSIC ckultoa(unsigned long n) #else ckultoa(n) unsigned long n; #endif /* CK_ANSIC */ /* ckultoa */ { char buf[32]; /* Internal working buffer */ char * p, * s, * q; int k, x, len = 0; buf[31] = NUL; for (k = 30; k > 0; k--) { /* Convert number to string */ x = n % 10L; buf[k] = x + '0'; n = n / 10L; if (!n) break; } len = 31 - k; if (len + numbp > NUMBUF) numbp = 0; p = numbuf + numbp; q = p; s = buf + k; while ((*p++ = *s++)) ; /* Copy */ numbp += len+1; return(q); /* Return pointer */ } char * #ifdef CK_ANSIC ckltox(long n) /* Long int to "0x.." hex string */ #else ckltox(n) long n; #endif /* CK_ANSIC */ /* ckltox */ { char buf[32]; /* Internal working buffer */ char *p, *q, *s, *bp = buf + 2; int k; buf[0] = '0'; buf[1] = 'x'; sprintf(bp, "%lx", n); k = strlen(bp); if (k&1) { sprintf(bp, "0%lx", n); k++; } k += 2; /* "0x" */ if (numbp + k >= NUMBUF) numbp = 0; p = numbuf + numbp; q = p; s = buf; while ((*p++ = *s++)) ; /* Copy */ *p++ = NUL; numbp += k+1; return(q); /* Return pointer */ } /* C K F S T O A -- File Size (or offset) to string */ /* This is just like ckltoa() except for the data type of the argument. */ /* It's mainly for printing file sizes without having to know their data */ /* type, so we don't have to hardwire "%ld" or "%lld" into printf()s. */ /* Works for 32 or 64 bits, according to CK_OFF_T definition. */ char * #ifdef CK_ANSIC ckfstoa(CK_OFF_T n) #else ckfstoa(n) CK_OFF_T n; #endif /* CK_ANSIC */ /* ckfstoa */ { char buf[32]; /* Internal working buffer */ char * p, * s, * q; int k, x, len = 0, sign = 0; if (n < (CK_OFF_T)0) { /* Sign */ n = (CK_OFF_T)0 - n; sign = 1; } buf[31] = NUL; /* 2^63-1 is about 20 decimal digits */ for (k = 30; k > 0; k--) { /* Convert number to string */ x = n % (CK_OFF_T)10; if (x < 0) { /* x += 10; */ ckstrncpy(&buf[23],"OVERFLOW",32); sign = 0; k = 23; break; } buf[k] = x + '0'; n = n / (CK_OFF_T)10; if (!n) break; } if (sign) buf[--k] = '-'; /* Add sign if necessary */ len = 31 - k; if (len + numbp > NUMBUF) numbp = 0; p = numbuf + numbp; q = p; s = buf + k; while ((*p++ = *s++)) ; /* Copy */ *p++ = NUL; numbp += len+1; return(q); /* Return pointer */ } /* C K A T O F S -- String to File Size (or offset) */ /* This is the inverse of ckfstoa(), a replacement for atol() that works */ /* for either 32-bit or 64-bit arguments, according to CK_OFF_T definition. */ /* Like atol(), there is no error indication. */ CK_OFF_T #ifdef CK_ANSIC ckatofs(char * s) #else ckatofs(s) char * s; #endif /* CK_ANSIC */ /* ckatofs */ { CK_OFF_T result = (CK_OFF_T)0; int minus = 0; while (*s && (*s == SP || *s == HT)) s++; if (*s == '+') s++; if (*s == '-') { minus = 1; s++; } while (isdigit(*s)) { result = (result * (CK_OFF_T)10) + (CK_OFF_T)(*s - '0'); s++; } return(minus ? -result : result); } /* C K I T O A -- Int to string -- FOR DISCIPLINED USE ONLY */ char * #ifdef CK_ANSIC ckitoa( int n ) #else ckitoa(n) int n; #endif /* CK_ANSIC */ { /* See comments with ckltoa(). */ long nn; nn = n; return(ckltoa(nn)); } char * /* Unsigned int to string */ #ifdef CK_ANSIC ckuitoa( unsigned int n ) #else ckuitoa(n) unsigned int n; #endif /* CK_ANSIC */ { unsigned long nn; nn = n; return(ckultoa(nn)); } char * #ifdef CK_ANSIC ckitox( int n ) /* Int to hex */ #else ckitox(n) int n; #endif /* CK_ANSIC */ { long nn; nn = n; return(ckltox(nn)); } char * #ifdef CK_ANSIC ckctoa(char c) /* Char to string */ #else ckctoa(c) char c; #endif /* ckctoa */ { static char buf[32]; static int current = 0; if (current >= 30) current = 0; buf[current++] = c; buf[current++] = '\0'; return((char *)(buf + current - 2)); } char * #ifdef CK_ANSIC ckctox(CHAR c, int flag) /* Unsigned char to hex */ #else ckctox(c, flag) CHAR c; int flag; #endif /* CK_ANSIC */ /* ckctox */ { static char buf[48]; static int current = 0; int x; char h; if (current > 45) current = 0; x = (c >> 4) & 0x0f; h = rxdigits[x]; if (!flag && isupper(rxdigits[x])) h = tolower(rxdigits[x]); buf[current++] = h; x = c & 0x0f; h = rxdigits[x]; if (!flag && isupper(rxdigits[x])) h = tolower(rxdigits[x]); buf[current++] = h; buf[current++] = '\0'; return((char *)(buf + current - 3)); } /* C K I N D E X -- C-Kermit's index function */ /* We can't depend on C libraries to have one, so here is our own. Call with: s1 - String to look for. s2 - String to look in. t - Offset from right or left of s2, 0 based; -1 for rightmost char in s2. r - 0 for left-to-right search, non-0 for right-to-left. icase 0 for case independence, non-0 if alphabetic case matters. Returns 0 if string not found, otherwise a 1-based result. Also returns 0 on any kind of error, e.g. junk parameters. */ int #ifdef CK_ANSIC ckindex(char * s1, char * s2, int t, int r, int icase ) #else ckindex(s1,s2,t,r,icase) char *s1, *s2; int t, r, icase; #endif /* CK_ANSIC */ { int len1 = 0, len2 = 0, i, j, x, ot = t; /* ot = original t */ char * s; if (!s1 || !s2) return(0); s = s1; while (*s++) len1++; /* length of string to look for */ s = s2; while (*s++) len2++; /* length of string to look in */ s = s2; if (t < 0) t = len2 - 1; j = len2 - len1; /* length difference */ if (j < 0 || (r == 0 && t > j)) /* search string is longer */ return(0); if (r == 0) { /* Index */ s = s2 + t; /* Point to beginning of target */ for (i = 0; i <= (j - t); i++) { /* Now compare */ x = ckstrcmp(s1,s,len1,icase); if (!x) return(i+1+t); s++; } } else { /* Reverse Index */ i = len2 - len1; /* Where to start looking */ if (ot > 0) /* Figure in offset if any */ i -= t; for (j = i; j > -1; j--) { if (!ckstrcmp(s1,&s2[j],len1,icase)) return(j+1); } } return(0); } /* C K S T R S T R -- Portable replacement for strstr() */ /* Returns pointer to first occurrence of s1 in s2, or NULL */ char * #ifdef CK_ANSIC ckstrstr(char * s1, char * s2 ) #else ckstrstr(s1, s2) char * s1, * s2; #endif /* CK_ANSIC */ { int k; k = ckindex(s2,s1,0,0,1); return((k < 1) ? NULL : &s1[k-1]); } /* B R S T R I P -- Strip enclosing braces from arg string, in place. */ /* Call with: Pointer to string that can be poked. Returns: Pointer to string without enclosing braces. If original string was not braced, this is the arg pointer; otherwise it is 1 + the arg pointer, with the matching closing brace zero'd out. If the string starts with a brace but does not end with a matching brace, the original pointer to the original string is returned. If the arg pointer is NULL, a pointer to an empty string is returned. */ #ifdef COMMENT /* This is the original version, handling only braces */ char * brstrip(p) char *p; { if (!p) return(""); if (*p == '{') { int x; x = (int)strlen(p) - 1; if (p[x] == '}') { p[x] = NUL; p++; } } return(p); } #else /* New version handles braces and doublequotes */ /* WARNING: this function writes into its argument, it always has. */ char * #ifdef CK_ANSIC brstrip( char * p ) #else brstrip(p) char *p; #endif /* CK_ANSIC */ { if (!p) return(""); if (*p == '{' || (*p == '"' && dblquo)) { int x; x = (int)strlen(p) - 1; if (x > 0) { if ((*p == '{' && p[x] == '}') || (*p == '"' && p[x] == '"')) { if (x > 0 && p[x-1] != CMDQ) { p[x] = NUL; p++; } } } } return(p); } #endif /* COMMENT */ #ifdef COMMENT /* Even newer experimental version -- breaks many things */ char * #ifdef CK_ANSIC fnstrip( char * ) #else fnstrip(p) char *p; #endif /* CK_ANSIC */ { int i, j, k, n, len; extern int cmd_quoting; /* Bad - no externs allowed! */ if (!p) return(""); if (*p == '{') { len = strlen(p); n = 0; for (j = 0; j < len; j++ ) { if (p[j] == '{' && (!cmd_quoting || j == 0 || p[j-1] != CMDQ)) { for (n = 1, i = j+1; i < len; i++ ) { if (p[i] == '{' && (!cmd_quoting || p[i-1] != CMDQ)) n++; else if (p[i] == '}' && (!cmd_quoting || p[i-1] != CMDQ)) { if (--n == 0) { for (k = j; k < i - 1; k++) p[k] = p[k+1]; for (; i < len; i++ ) p[i-1] = p[i+1]; len -= 2; j = i - 1; } } } } } if (n == 1) { /* Implied right brace at end of field */ for (k = j; k < len; k++) p[k] = p[k+1]; len -= 1; } } else if (*p == '"') { len = strlen(p); n = 0; for (j = 0; j < len; j++) { if (p[j] == '"' && (!cmd_quoting || j == 0 || p[j-1] != CMDQ)) { n++; for (i = j + 1; i < len; i++) { if (p[i] == '"' && (!cmd_quoting || p[i-1] != CMDQ)) { n--; for (k = j; k < i - 1; k++) p[k] = p[k+1]; for (; i < len; i++) p[i-1] = p[i+1]; len -= 2; j = i - 1; } } } } if (n == 1) { /* Implied double quote at end of field */ for (k = j; k < len; k++ ) p[k] = p[k+1]; len -= 1; } } return(p); } #endif /* COMMENT */ #ifdef COMMENT /* Not used -- Note: these not only write into their arg, but write past past the end. */ char * brace(fn) char *fn; { int spaces = 0; char * p, ch, ch2; for (p = fn; *p; p++) { if (*p == SP) { spaces = 1; break; } } if (spaces) { p = fn; ch = *p; *p = '{'; p++; while (*p) { ch2 = *p; *p = ch; ch = ch2; p++; } *p = ch; p++; *p = '}'; p++; *p = '\0'; } return(fn); } #endif /* COMMENT */ /* d q u o t e -- Puts doublequotes around arg in place. */ /* Call with: Pointer to buffer and its total length and flag = 0 to use doublequotes, 1 to use braces. Returns: Number: length of result. */ int #ifdef CK_ANSIC dquote( char * fn, int len, int flag ) #else dquote( fn, len, flag) char *fn; int len; int flag; #endif /* CK_ANSIC */ { int spaces = 0, k = 0; char * p, ch, ch2; if (!fn) return(0); k = strlen(fn); for (p = fn; *p; p++) { if (*p == SP) { spaces = 1; break; } } if (spaces) { if (k + 2 >= len) return(k); p = fn; ch = *p; *p = flag ? '{' : '"'; p++; while (*p) { ch2 = *p; *p = ch; ch = ch2; p++; } *p = ch; p++; *p = flag ? '}' : '"'; p++; *p = '\0'; } return(k+2); } /* U N T A B I F Y --- Untabify s1 into s2, assuming tabs every 8 space */ int #ifdef CK_ANSIC untabify(char * s1, char * s2, int max) #else untabify(s1,s2,max) char * s1, * s2; int max; #endif /* CK_ANSIC */ { int i, j, k, x, z; x = strlen(s1); for (i = 0, k = 0; k < x; k++) { if (s1[k] != '\t') { if (i >= max-1) { s2[max-1] = '\0'; return(-1); } s2[i++] = s1[k]; continue; } z = 8 - i%8; if (z == 0) z = 8; for (j = 0; j < z && i < max; j++) s2[i++] = ' '; } s2[i] = '\0'; return(0); } /* M A K E L I S T --- Breaks {{s1}{s2}..{sn}} into an array of strings */ /* Call with: s = pointer to string to break up. list = array of string pointers. len = number of elements in array. NOTE: The array must be preinitialized to all NULL pointers. If any array element is not NULL, it is assumed to have been malloc'd and is therefore freed. Do NOT call this function with an uninitialized array, or with an array that has had any static elements assigned to it. */ VOID #ifdef CK_ANSIC makelist( char * s, char * list[] , int len) #else makelist(s,list,len) char * s; char *list[]; int len; #endif /* CK_ANSIC */ { int i, n, q, bc = 0; char *p = NULL, *s2 = NULL; debug(F110,"makelist s",s,0); if (!s) { /* Check for null or empty string */ list[0] = NULL; return; } n = strlen(s); if (n == 0) { list[0] = NULL; return; } if ((s2 = (char *)malloc(n+1))) { /* Safe copy for poking */ strcpy(s2,s); /* (no need for ckstrncpy here) */ s = s2; } s = brstrip(s); /* Strip braces */ n = strlen(s); /* Get length */ if (*s != '{') { /* Outer braces only */ if ((p = (char *)malloc(n+1))) { /* So just one pattern */ strcpy(p,s); /* (no need for ckstrncpy here) */ if (list[0]) free(list[0]); list[0] = p; } if (s2) free(s2); return; } q = 0; /* Inner ones too */ i = 0; /* so a list of patterns. */ n = 0; while (*s && i < len) { if (*s == CMDQ) { /* Quote... */ q = 1; s++; n++; continue; } if (*s == '{' && !q) { /* Opening brace */ if (bc++ == 0) { /* Beginning of a group */ p = ++s; n = 0; } else { /* It's a brace inside the group */ n++; s++; } continue; } else if (*s == '}' && !q) { /* Closing brace */ if (--bc == 0) { /* End of a group */ *s++ = NUL; debug(F111,"makelist element",p,i); if (list[i]) free(list[i]); if ((list[i] = (char *)malloc(n+1))) { ckstrncpy(list[i],p,n+1); /* Note: n+1 */ i++; } while (*s == SP) s++; p = s; n = 0; continue; } else { /* Within a group */ n++; s++; } } else { /* Regular character */ q = 0; s++; n++; } } if (*p && i < len) { /* Last one */ if (list[i]) free(list[i]); if ((list[i] = (char *)malloc(n+1))) { ckstrncpy(list[i],p,n+1); debug(F111,"makelist last element",p,i); } } i++; /* Clear out the rest of the list */ for ( ; i < len; i++) { if (list[i]) free (list[i]); list[i] = NULL; } if (s2) free(s2); } /* M A K E S T R -- Creates a dynamically allocated string. Makes a new copy of string s and sets pointer p to its address. Handles degenerate cases, like when buffers overlap or are the same, one or both arguments are NULL, etc. The source string is assumed to be NUL-terminated. Therefore it can not be a UCS-2 string or arbitrary binary data. The target pointer must be either NULL or else a pointer to a previously malloc'ed buffer. If not, expect a core dump or segmentation fault. Note: The caller can tell whether this routine failed as follows: malloc(&p,q); if (q & !p) { makestr() failed }; Really this routine should have returned a length, but since it doesn't we set the global variable makestrlen to the length of the result string. */ int makestrlen = 0; VOID #ifdef CK_ANSIC makestr(char **p, const char *s) #else makestr(p,s) char **p, *s; #endif /* makestr */ { int x = 0; char *q = NULL; #ifdef CK_ANSIC register const char * s2; #else register char * s2; #endif /* CK_ANSIC */ register char * q2; if (*p == s) /* The two pointers are the same. */ return; /* Don't do anything. */ if (!s) { /* New definition is null? */ if (*p) /* Free old storage. */ free(*p); *p = NULL; /* Return null pointer. */ makestrlen = 0; return; } s2 = s; /* Maybe new string will fit */ #ifdef COMMENT /* This is a fairly big win, allowing us to skip the malloc() and free if the destination string already exists and is not shorter than the source string. But it doesn't allow for possible overlap of source and destination. */ if (*p) { /* into old storage... */ char * p2 = *p; char c; while (c = *p2) { if (!(*p2++ = *s2++)) break; x++; } makestrlen = x; if (c) return; } #endif /* COMMENT */ /* Didn't fit */ x = 0; while (*s2++) x++; /* Get (rest of) length of s. */ if (x >= 0) { /* Get length, even of empty string. */ q = malloc(x+1); /* Get and point to temp storage. */ if (q) { makestrlen = x; /* Remember length for stats */ s2 = s; /* Point back to beginning of source */ q2 = q; /* Copy dest pointer to increment... */ while ((*q2++ = *s2++)) ; /* Instead of calling strcpy(). */ /* Note: HP flexelint says that the above loop can result in creation (++) and access (*) of out-of-bounds pointers. I really don't see it. */ } #ifdef DEBUG else { /* This would be a really bad error */ char tmp[24]; /* So get a good record of it. */ if (x > 23) { ckstrncpy(tmp,s,20); strcpy(tmp+20,"..."); tmp[23] = NUL; } else { strcpy(tmp,s); /* We already checked the length */ } debug(F110,"MAKESTR MALLOC FAILURE ",tmp,0); } #endif /* DEBUG */ } else q = NULL; /* Length of string is zero */ if (*p) /* Now free the original storage. */ free(*p); *p = q; } /* X M A K E S T R -- Non-destructive makestr() if s is NULL. */ VOID #ifdef CK_ANSIC xmakestr(char **p, const char *s) #else xmakestr(p,s) char **p, *s; #endif /* xmakestr */ { if (s) makestr(p,s); } #ifndef USE_MEMCPY /* C K M E M C P Y -- Portable (but slow) memcpy() */ /* Copies n bytes from s to p, allowing for overlap. */ /* For use when real memcpy() not available. */ VOID #ifdef CK_ANSIC ckmemcpy( char * p, char * s, int n) #else ckmemcpy(p,s,n) char *p, *s; int n; #endif /* CK_ANSIC */ { char * q = NULL; register int i; int x; if (!s || !p || n <= 0 || p == s) /* Verify args */ return; x = p - s; /* Check for overlap */ if (x < 0) x = 0 - x; if (x < n) { /* They overlap */ q = p; if (!(p = (char *)malloc(n))) /* So use a temporary buffer */ return; } for (i = 0; i < n; i++) /* Copy n bytes */ p[i] = s[i]; if (q) { /* If we used a temporary buffer */ for (i = 0; i < n; i++) /* copy from it to destination */ q[i] = p[i]; if (p) free(p); /* and free the temporary buffer */ } } #endif /* USE_MEMCPY */ /* C K S T R C M P -- String comparison with case-matters selection */ /* Call with pointers to the two strings, s1 and s2, a length, n, and c == 0 for caseless comparison, nonzero for case matters. Call with n == -1 to compare without a length limit. Compares up to n characters of the two strings and returns: 1 if s1 > s2 0 if s1 = s2 -1 if s1 < s2 Note: case handling is only as good as isupper() and tolower(). Modifed 2013-12-06 to be somewhat locale-aware. */ int #ifdef CK_ANSIC ckstrcmp( char * s1, char * s2, register int n, register int c) #else ckstrcmp(s1,s2,n,c) char *s1, *s2; register int n, c; #endif /* CK_ANSIC */ { register CHAR t1, t2; #ifdef HAVE_LOCALE int rc; char t1buf[2], t2buf[2]; t1buf[1] = NUL; t2buf[1] = NUL; #endif /* HAVE_LOCALE */ /* These are too much... */ /* debug(F111,"CKSTRLEN s1",s1,n); */ if (n == 0) return(0); if (!s1) s1 = ""; /* Watch out for null pointers. */ if (!s2) s2 = ""; if (!*s1) return(*s2 ? -1 : 0); if (!*s2) return(1); /* debug(F111,"CKSTRLEN s2",s2,n); */ while (n--) { t1 = (CHAR) *s1++; /* Get next character from each. */ t2 = (CHAR) *s2++; if (!t1) return(t2 ? -1 : 0); if (!t2) return(1); if (!c) { /* If case doesn't matter */ if (isupper(t1)) t1 = tolower(t1); /* Convert case. */ if (isupper(t2)) t2 = tolower(t2); } /* debug(F111,"CKSTRLEN A","",0); */ #ifdef HAVE_LOCALE /* This only works for single-byte character sets but it's better than nothing, because previously this routine worked right only for ASCII. */ /* debug(F111,"CKSTRLEN B","",0); */ t1buf[0] = t1; /* Convert chars to strings */ t2buf[0] = t2; /* debug(F111,"CKSTRLEN B2","",0); */ if ((rc = strcoll(t1buf,t2buf))) return(rc); /* debug(F111,"CKSTRLEN C","",0); */ #else if (t1 < t2) return(-1); /* s1 < s2 */ if (t1 > t2) return(1); /* s1 > s2 */ /* debug(F111,"CKSTRLEN D","",0); */ #endif /* HAVE_LOCALE */ } /* debug(F111,"CKSTRLEN E","",0); */ return(0); /* They're equal */ } /* C K S T R P R E -- Caseless string prefix comparison */ /* Returns position of the first char in the 2 strings that doesn't match */ int #ifdef CK_ANSIC ckstrpre(char *s1, char *s2) #else ckstrpre(s1,s2) char *s1, *s2; #endif /* CK_ANSIC */ { CHAR t1, t2; int n = 0; if (!s1) s1 = ""; if (!s2) s2 = ""; while (1) { t1 = (CHAR) *s1++; t2 = (CHAR) *s2++; if (!t1 || !t2) return(n); if (isupper(t1)) t1 = tolower(t1); if (isupper(t2)) t2 = tolower(t2); if (t1 != t2) return(n); n++; } } #define GLOBBING /* C K M A T C H -- Match a string against a pattern */ /* Call with: pattern to be matched. string to look for the pattern in. icase is 1 if case-sensitive, 0 otherwise. opts is a bitmask: Bit 0 (=1): 1 = Match strings starting with '.' 0 = Don't match them (used with UNIX filenames). Bit 1 (=2): 1 = File globbing (dirseps are fences); 0 = Dirseps are not fences. Bit 2 (=4): 1 = Allow ^ and $ anchors at beginning and end of pattern. 0 = Don't allow them (normal case for filename matching). Bit 3 (and beyond): Undefined. Works only with NUL-terminated strings. Pattern may contain any number of ? and/or *. If CKREGEX is defined, also [abc], [a-z], and/or {string,string,...}. (Note: REGEX is a misnomer, see below.) Returns: 0 if string does not match pattern, >= 1, the 1-based position in the string where the match was found. To be done: Find a way to identify the piece of the string that matched the pattern, as in Snobol "LINE (PAT . RESULT)". This is now partially done by setting matchpos and matchend (except matchend needs some tuning). But these are useless unless a copy of the string is kept, or a copy of the matching part is made. But that would be too costly in performance -- this routine has to be fast because it's used for wildcard expansion. Note: Patterns are not the same as regular expressions, in which '*' means 0 or more repetitions of the preceding item. For example "a*b" as a pattern matches any string that starts with 'a' and ends with 'b'; as a regular expression it matches any string of zero or more a's followed by one b. Regular expressions are especially useful in matching strings of (say) digits, or letters, e.g. "[0-9]*" matches any string of digits. So far, Kermit doesn't do this. */ static char * mypat = NULL; /* For rewriting pattern */ static int matchpos = 0; int matchend = 0; static int matchdepth = 0; static int stringpos = 0; static char * ostring = NULL; #define MATCHRETURN(x,y) { rc=y; where=x; goto xckmatch; } static char * lastpat = NULL; static int xxflag = 0; /* Global bailout flag for ckmatch() */ int #ifdef CK_ANSIC ispattern( char * s ) #else ispattern(s) char * s; #endif /* CK_ANSIC */ { int quote = 0, sbflag = 0, sb = 0, cbflag = 0, cb = 0; char c = 0; if (*s == '^') return(1); while ((c = *s++)) { if (quote) { quote = 0; continue; } if (c == '\\') { quote = 1; continue; } if (c == '*') return(1); if (c == '?') return(1); /* Unquoted brackets or braces must match */ if (c == '[') { sbflag++; sb++; continue; } if (c == ']') { sb--; continue; } if (c == '{') { cbflag++; cb++; continue; } if (c == '}') { cb--; continue; } if (!*s && c == '$') return(1); } return(sbflag || cbflag); } int #ifdef CK_ANSIC ckmatch( char * pattern, char * string, int icase, int opts ) #else ckmatch( pattern, string, icase, opts) char *pattern,*string; int icase, opts; #endif /* CK_ANSIC */ { int q = 0, i = 0, k = -1, x, flag = 0; int rc = 0; /* Return code */ int havestar = 0; int where = -1; CHAR cp; /* Current character from pattern */ CHAR cs; /* Current character from string */ char * patstart; /* Start of pattern */ int plen, dot, globbing, xstar = 0; int bronly = 0; /* Whole pattern is {a,b,c,...} */ debug(F111,"CKMATCH ENTRY pat opt",pattern,opts); debug(F111,"CKMATCH ENTRY str dep",string,matchdepth); /* debug(F101,"CKMATCH ENTRY icase","",icase); */ globbing = opts & 2; if (!string) string = ""; if (!pattern) pattern = ""; if (!*pattern) { /* Empty pattern matches anything */ matchdepth++; /* (it wasn't incremented yet) */ MATCHRETURN(0,1); } else if (!*string) { MATCHRETURN(0,0); } patstart = pattern; /* Remember beginning of pattern */ if (matchdepth == 0) { /* Top-level call? */ xxflag = 0; stringpos = 0; /* Reset indices etc. */ matchpos = 0; matchend = 0; ostring = string; lastpat = pattern; if (*pattern == '{') /* Entire pattern is {a,b.c} */ bronly = 1; /* Maybe */ dot = (opts & 1) || /* Match leading dot (if file) */ ((opts & 2) == 0) || /* always if not file */ (pattern[0] == '.'); /* or if pattern starts with '.' */ plen = strlen(pattern); /* Length of pattern */ /* This would be used in calculating length of matching segment */ if (plen > 0) /* User's pattern ends with '*' */ if (pattern[plen - 1] == '*') xstar = 1; if (pattern[0] == '*') { /* User's pattern starts with '*' */ matchpos = 1; debug(F111,"CKMATCH 1",string, matchpos); } if (opts & 4) { /* ^..$ allowed (top level only) */ /* Rewrite pattern to account for ^..$ anchoring... */ if (mypat) free(mypat); /* Get space for "*pattern*" */ mypat = (char *)malloc(plen + 4); if (mypat) { /* Got space? */ char * s = pattern, * p = mypat; /* Set working pointers */ if (*s == '^') { /* First source char is ^ */ s++; /* so skip past it */ } else if (*s != '*') { /* otherwise */ *p++ = '*'; /* prepend '*' to pattern */ } while (*s) { /* Copy rest of pattern */ if (!*(s+1)) { /* Final pattern character? */ if (*s != '$') { /* If it's not '$' */ *p++ = *s; /* Copy it into the pattern */ if (*s++ != '*') /* And if it's also not '*' */ *p++ = '*'; /* append '*'. */ } break; /* Done */ } else /* Not final character */ *p++ = *s++; /* Just copy it */ } *p = NUL; /* Terminate the new pattern */ pattern = mypat; /* Make the switch */ } debug(F110,"CKMATCH INIT pat",pattern,0); } } matchdepth++; /* Now increment call depth */ #ifdef UNIX if (!dot) { /* For UNIX file globbing */ if (*string == '.' && *pattern != '.' && !matchdot) { if ( #ifdef CKREGEX *pattern != '{' && *pattern != '[' #else 1 #endif /* CKREGEX */ ) { debug(F110,"ckmatch skip",string,0); MATCHRETURN(1,0); } } } #endif /* UNIX */ while (1) { k++; cp = *pattern; /* Character from pattern */ cs = *string; /* Character from string */ #ifdef COMMENT debug(F000,"CKMATCH pat cp",pattern,cp); debug(F000,"CKMATCH str cs",string,cs); #endif /* COMMENT */ if (!cs) { /* End of string - done. */ x = (!cp || (cp == '*' && !*(pattern+1))) ? 1 : 0; if (x) { if (!matchpos) { matchpos = stringpos; debug(F111,"CKMATCH A",string, matchpos); } matchend = stringpos; MATCHRETURN(2,matchpos); } debug(F111,"CKMATCH ZERO d",string, matchpos); matchpos = 0; MATCHRETURN(16,matchpos); } if (!icase) { /* If ignoring case */ if (isupper(cp)) /* convert both to lowercase. */ cp = tolower(cp); if (isupper(cs)) cs = tolower(cs); } if (q) { /* This character was quoted */ debug(F000,"CKMATCH QUOTED",pattern,cp); q = 0; /* Turn off quote flag */ if (cs == cp) { /* Compare directly */ if (!matchpos) { /* Matches */ matchpos = stringpos; debug(F111,"CKMATCH \\ new match",string, matchpos); } pattern++; } else { /* Doesn't match */ pattern = lastpat; /* Back up the pattern */ matchpos = 0; debug(F111,"CKMATCH \\ no match",pattern, matchpos); } string++; stringpos++; continue; } if (cp == CMDQ && !q) { /* Quote in pattern */ debug(F000,"CKMATCH QUOTE",pattern,cp); q = 1; /* Set flag */ pattern++; /* Advance to next pattern character */ continue; /* and continue. */ } if (cs && cp == '?') { /* '?' matches any char */ if (!matchpos) { matchpos = stringpos; debug(F111,"CKMATCH D",string, matchpos); } debug(F110,"CKMATCH ? pat",pattern,0); debug(F110,"CKMATCH ? str",string,0); pattern++; string++; stringpos++; continue; #ifdef CKREGEX } else if (cp == '[') { /* Have bracket */ int q = 0; /* My own private q */ char * psave = NULL; /* and backup pointer */ CHAR clist[256]; /* Character list from brackets */ CHAR c, c1, c2; for (i = 0; i < 256; i++) /* memset() etc not portable */ clist[i] = NUL; psave = ++pattern; /* Where pattern starts */ debug(F111,"CKMATCH [] ",pattern-1, matchpos); for (flag = 0; !flag; pattern++) { /* Loop thru pattern */ c = (CHAR)*pattern; /* Current char */ debug(F000,">>> pattern char","",c); if (q) { /* Quote within brackets */ q = 0; clist[c] = 1; continue; } if (!icase) /* Case conversion */ if (isupper(c)) c = tolower(c); switch (c) { /* Handle unquoted character */ case NUL: /* End of string */ MATCHRETURN(4,0); /* No matching ']' so fail */ case CMDQ: /* Next char is quoted */ q = 1; /* Set flag */ continue; /* and continue. */ case '-': /* A range is specified */ c1 = (pattern > psave) ? (CHAR)*(pattern-1) : NUL; c2 = (CHAR)*(pattern+1); /* IGNORE OUT-OF-BOUNDS WARNING */ if (c2 == ']') c2 = NUL; /* (it can't happen) */ if (c1 == NUL) c1 = c2; for (c = c1; c <= c2; c++) { clist[c] = 1; if (!icase) { if (islower(c)) { clist[toupper(c)] = 1; } else if (isupper(c)) { clist[tolower(c)] = 1; } } } continue; case ']': /* End of bracketed sequence */ flag = 1; /* Done with FOR loop */ break; /* Compare what we have */ default: /* Just a char */ clist[c] = 1; /* Record it */ if (!icase) { if (islower(c)) { clist[toupper(c)] = 1; } else if (isupper(c)) { clist[tolower(c)] = 1; } } continue; } } debug(F000,">>> cs","",cs); debug(F101,">>> clist[cs]","",clist[cs]); debug(F000,">>> string",string,*string); if (!clist[(unsigned)cs]) { /* No match? */ if (!*string) { /* This clause 16 Jun 2005 */ MATCHRETURN(5,0); /* Nope, done. */ } /* We need to fail here if the [clist] is not allowed to float. The [clist] is not allowed to float if it is not preceded by an asterisk, right? 30 Dec 2005. */ if (!havestar) { MATCHRETURN(500,0); } string++; /* From here to end added 2005/6/15 */ stringpos++; pattern = lastpat; /* Back up pattern */ k = ckmatch(pattern,string,icase,opts); if (xxflag) MATCHRETURN(0,0); if (!matchpos && k > 0) matchpos = stringpos; MATCHRETURN(5, (*string) ? matchpos : 0); } if (!matchpos) { matchpos = stringpos; debug(F111,"CKMATCH [] match",string, matchpos); } string++; /* Yes, advance string pointer */ stringpos++; continue; /* and go on. */ } else if (cp == '{') { /* Braces enclosing list of strings */ char * p, * s, * s2, * buf = NULL; int n, bc = 0; int len = 0; debug(F111,"CKMATCH {} ",string, matchpos); for (p = pattern++; *p; p++) { if (*p == '{') bc++; if (*p == '}') bc--; if (bc < 1) break; } if (bc != 0) { /* Braces don't match */ MATCHRETURN(6,0); /* Fail */ } else { /* Braces do match */ int q = 0, done = 0; len = *p ? strlen(p+1) : 0; /* Length of rest of pattern */ if (len) bronly = 0; if (bronly && (matchdepth != 1)) bronly = 0; n = p - pattern; /* Size of list in braces */ if ((buf = (char *)malloc(n+1))) { /* Copy so we can poke it */ char * tp = NULL; int k, sofar; ckstrncpy(buf,pattern,n+1); sofar = string - ostring - matchpos + 1; if (sofar < 0) sofar = 0; debug(F111,"CKMATCH .. string",string,sofar); debug(F111,"CKMATCH .. ostring",ostring,sofar); n = 0; for (s = s2 = buf; 1; s++) { /* Loop through segments */ n++; if (q) { /* This char is quoted */ q = 0; if (!*s) done = 1; continue; } if (*s == CMDQ && !q) { /* Quote next char */ q = 1; continue; } if (!*s || *s == ',') { /* End of this segment */ int tplen = 0; if (!*s) /* If end of buffer */ done = 1; /* then end of last segment */ *s = NUL; /* Overwrite comma with NUL */ debug(F111,"CKMATCH {} segment",s2,done); tplen = n + len + sofar + 2; if (!*s2) { /* Empty segment, no advancement */ k = 0; } else if ((tp = (char *)malloc(tplen))) { int savpos, opts2; char * pp; pp = matchpos > 0 ? &ostring[matchpos-1] : ostring; if (bronly) { if (matchpos > 0) ckstrncpy(tp,pp,sofar+1); else ckstrncpy(tp,pp,sofar); } else { tp[0] = '*'; tp[1] = NUL; if (matchpos > 0) ckstrncpy(&tp[1],pp,sofar+1); else ckstrncpy(&tp[1],pp,sofar); } ckstrncat(tp,s2,tplen); /* Current segment */ ckstrncat(tp,p+1,tplen); /* rest of pattern */ debug(F101,"CKMATCH {} matchpos","",matchpos); savpos = matchpos; matchpos = 0; #ifdef DEBUG if (deblog) { debug(F111,"CKMATCH {} tp",tp,matchpos); debug(F111,"CKMATCH {} string", string,matchpos); debug(F111,"CKMATCH {} ostring", ostring,savpos); } #endif /* DEBUG */ /* If segment starts with dot */ /* then set matchdot option.. */ opts2 = opts; if (*s2 == '.') opts2 |= 1; debug(F111,"CKMATCH {} recursing",s2,opts2); k = ckmatch(tp, (string > ostring) ? &ostring[savpos-1] : string, icase,opts2); #ifdef DEBUG if (deblog) { debug(F101,"CKMATCH {} k","",k); debug(F101,"CKMATCH {} savpos","",savpos); } #endif /* DEBUG */ free(tp); tp = NULL; if (xxflag) MATCHRETURN(0,0); if (k == 0) { matchpos = savpos; } if (k > 0) { /* If it matched we're done */ MATCHRETURN(7,k); } } else { /* Malloc failure */ MATCHRETURN(14,0); } if (k) { /* Successful comparison */ if (!matchpos) { matchpos = stringpos; debug(F111,"CKMATCH {} match", string, matchpos); } string += n-1; /* Advance pointers */ pattern = p+1; break; } if (done) /* If no more segments */ break; /* break out of segment loop. */ s2 = s+1; /* Otherwise, on to next segment */ n = 0; } } free(buf); } } #endif /* CKREGEX */ } else if (cp == '*') { /* Pattern char is asterisk */ char * psave; char * p, * s = NULL; /* meaning match anything */ int k, n, q = 0; havestar++; /* The rest can float */ while (*pattern == '*') /* Collapse successive asterisks */ pattern++; psave = pattern; /* First non-asterisk after asterisk */ lastpat = pattern - 1; /* Ditto, global */ debug(F111,"CKMATCH * ",string,matchpos); for (n = 0, p = psave; *p; p++,n++) { /* Find next meta char */ if (!q) { if (*p == '?' || *p == '*' || *p == CMDQ #ifdef CKREGEX || *p == '[' || *p == '{' #endif /* CKREGEX */ ) break; #ifdef GLOBBING if (globbing #ifdef UNIXOROSK && *p == '/' #else #ifdef VMS && (*p == '.' || *p == ']' || *p == '<' || *p == '>' || *p == ':' || *p == ';') #else #ifdef datageneral && *p == ':' #else #ifdef STRATUS && *p == '>' #endif /* STRATUS */ #endif /* datageneral */ #endif /* VMS */ #endif /* UNIXOROSK */ ) break; #endif /* GLOBBING */ } } debug(F111,"CKMATCH * n string",string,n); debug(F111,"CKMATCH * n pattrn",pattern,n); debug(F111,"CKMATCH * n p",p,n); if (n > 0) { /* Literal string to match */ s = (char *)malloc(n+1); if (s) { ckstrncpy(s,psave,n+1); /* Copy cuz no poking original */ if (*p) { k = ckindex(s,string,0,0,icase); /* 1-based index() */ debug(F110,"CKMATCH * Index() string",string,0); debug(F110,"CKMATCH * Index() pattrn",s,0); debug(F101,"CKMATCH * Index() result","",k); } else { /* String is right-anchored */ k = ckindex(s,string,-1,1,icase); /* rindex() */ debug(F111,"CKMATCH * Rindex()",string,k); debug(F110,"CKMATCH * Rindex() pattrn",s,0); debug(F101,"CKMATCH * Rindex() result","",k); } free(s); if (k < 1) { MATCHRETURN(8,0); } debug(F111,"CKMATCH * stringpos matchpos", ckitoa(stringpos), matchpos); if (!matchpos) { matchpos = string - ostring + k; debug(F111,"CKMATCH * new match ", string, matchpos); } string += k + n - 1; stringpos += k + n - 1; pattern += n; debug(F111,"CKMATCH * new string", string, stringpos); debug(F110,"CKMATCH * new pattrn", pattern, 0); continue; } } else if (!*p) { /* Asterisk at end matches the rest */ if (!globbing) { /* (if not filename globbing) */ if (!matchpos) { matchpos = stringpos; debug(F111,"CKMATCH *$ ",string, matchpos); } matchend = stringpos; MATCHRETURN(9,matchpos); } #ifdef GLOBBING while (*string) { if (globbing /* Filespec so don't cross fields */ #ifdef OS2 && *string == '/' || *string == '\\' || *string == ':' #else #ifdef UNIXOROSK && *string == '/' #else #ifdef VMS && (*string == '.' || *string == ']' || *string == '<' || *string == '>' || *string == ':' || *string == ';') #else #ifdef datageneral && *string == ':' #else #ifdef STRATUS && *string == '>' #else && *string == '/' /* (catch-all) */ #endif /* STRATUS */ #endif /* datageneral */ #endif /* VMS */ #endif /* UNIXOROSK */ #endif /* OS2 */ ) { matchend = stringpos; MATCHRETURN(10,0); } if (!matchpos) { matchpos = stringpos; debug(F111,"CKMATCH *$ match",string, matchpos); } string++; stringpos++; } #endif /* GLOBBING */ if (!matchpos) { matchpos = stringpos; debug(F111,"CKMATCH ** match",string, matchpos); } matchend = stringpos; MATCHRETURN(11,matchpos); } else { /* A meta char follows asterisk */ if (!*string) MATCHRETURN(17, matchpos = 0); #ifdef COMMENT /* This is more elegant but it doesn't work. */ p--; string++; stringpos++; k = ckmatch(p,string,icase,opts); #else while (*string && ((k = ckmatch(p,string,icase,opts)) < 1)) { if (xxflag) MATCHRETURN(0,0); string++; stringpos++; } if (!*string && k < 1) { /* Definitely no match so we set a global flag to inibit further backing up and retrying by previous incarnations, since they don't see that the string and/or pattern, which are on the stack, have been exhausted at this level. */ xxflag++; debug(F111,"CKMATCH DEFINITELY NO MATCH",p,k); MATCHRETURN(91,0); } #endif /* COMMENT */ debug(F111,"CKMATCH * k",string, k); if (!matchpos && k > 0) { matchpos = stringpos; debug(F111,"CKMATCH * matchpos",string, matchpos); } MATCHRETURN(12, (*string) ? matchpos : 0); } } else if (cs == cp) { pattern++; string++; stringpos++; if (!matchpos) { matchpos = stringpos; debug(F111,"CKMATCH cs=cp",string, matchpos); } continue; } else { MATCHRETURN(13,0); } } xckmatch: { #ifdef DEBUG char msgbuf[256]; #endif /* DEBUG */ if (matchdepth > 0) matchdepth--; matchpos = rc; #ifdef DEBUG ckmakxmsg(msgbuf,256, "CKMATCH RETURN[", ckitoa(where), "] matchpos=", ckitoa(matchpos), " matchdepth=", ckitoa(matchdepth), " pat=",pattern, " string=",string,NULL,NULL ); debug(F110,msgbuf,string,0); #endif /* DEBUG */ return(rc); } } #ifdef CKFLOAT /* I S F L O A T -- Verify that arg represents a floating-point number */ /* Portable replacement for atof(), strtod(), scanf(), etc. Call with: s = pointer to string flag == 0 means entire string must be a (floating-pointing) number. flag != 0 means to terminate scan on first character that is not legal. Returns: 1 if result is a legal number; 2 if result has a fractional part; 0 if not or if string empty. Side effect: Sets global floatval to floating-point value if successful. Number need not contain a decimal point -- integer is subcase of float. Scientific notation not supported. */ CKFLOAT floatval = 0.0; /* For returning value */ int #ifdef CK_ANSIC isfloat( char *s, int flag ) #else isfloat(s,flag) char *s; int flag; #endif /* CK_ANSIC */ { int state = 0; int sign = 0; char c; CKFLOAT d = 0.0, f = 0.0; if (!s) return(0); if (!*s) return(0); while (isspace(*s)) s++; if (*s == '-') { /* Handle optional sign */ sign = 1; s++; } else if (*s == '+') s++; while ((c = *s++)) { /* Handle numeric part */ switch (state) { case 0: /* Mantissa... */ if (isdigit(c)) { f = f * 10.0 + (CKFLOAT)(c - '0'); continue; } else if (c == '.') { state = 1; d = 1.0; continue; } if (flag) /* Not digit or period */ goto done; /* break if flag != 0 */ return(0); /* otherwise fail. */ case 1: /* Fraction... */ if (isdigit(c)) { d *= 10.0; f += (CKFLOAT)(c - '0') / d; continue; } default: if (flag) /* Illegal character */ goto done; /* Break */ return(0); /* or fail, depending on flag */ } } done: if (sign) f = 0.0 - f; /* Apply sign to result */ floatval = f; /* Set result */ return(d ? 2 : 1); /* Succeed */ } /* c k r o u n d -- Rounds a floating point number or an integer. fpnum: Floating-point number to round. places: Positive...To how many decimal places. Zero.......Round to integer. Negative...-1 = nearest ten, -2 = nearest 100, -3 = nearest thousand, etc. obuf Output buffer for string result if desired. obuflen Length of output buffer. Returns: Result as CKFLOAT (which is not going to be as exact as the string result) And the exact result in the string output buffer, if one was specified. */ CKFLOAT #ifdef CK_ANSIC ckround(CKFLOAT fpnum, int places, char *obuf, int obuflen) #else ckround(fpnum,places,obuf,obuflen) CKFLOAT fpnum; int places, obuflen; char *obuf; #endif /* CK_ANSIC */ /* ckround */ { char *s, *s2, *d; int p, len, n; int carry = 0; int minus = 0; char buf[400]; char * number; CKFLOAT value; extern int fp_digits; /* Should use snprintf() here but it's not portable */ sprintf(buf,"%200.100f",fpnum); /* Make string version to work with. */ debug(F110,"ckround buf",buf,0); number = (char *) buf; /* Make pointer to it */ p = places; /* Precision */ d = (char *)0; /* Pointer to decimal or string end */ s = number; /* Fix number... */ while (*s == ' ' || *s == '\011') s++; /* Strip leading whitespace */ if (*s == '+') s++; /* Skip leading plus sign*/ number = s; /* Start of number */ if (*s == '-') { minus++; number++; s++; } /* Remember if negative */ s = number; /* Don't allow false precision */ n = 0; while (*s && *s != '.') s++, n++; /* Find decimal */ if (p + n > fp_digits) /* Too many digits */ p = fp_digits - n; /* Don't ask for bogus precision */ if (p < 0) p = 0; /* But don't ask for less than zero */ if (n > fp_digits) /* Integer part has too many digits */ *s = 0; /* but we can't truncate it */ else /* Magnitude is OK */ number[fp_digits+1] = 0; /* Truncate fractional part. */ len = (int)strlen(number); /* Length of non-bogus number */ d = s; /* Pointer to decimal point */ if (p > 0) { /* Rounding the fractional part */ if (n + p < len) { /* If it's not already shorter */ if (*s == '.') s++; /* Skip past decimal */ s += p; /* Go to desired spot */ if (*s > '4' && *s <= '9') /* Check value of digit */ carry = 1; *s = 0; /* And end the string */ s--; /* Point to last digit */ } } else if (p == 0) { /* Rounding to integer */ if (*s == '.') { *s = 0; /* erase the decimal point */ if (*(s+1)) { /* and there is a factional part */ if (*(s+1) > '4' && *(s+1) <= '9') /* Check for carry */ carry = 1; } s--; /* Point to last digit */ } } else { /* Rounding the integer part */ if (s + p > number) { /* as in "the nearest hundred" */ s += p; /* Go left to desired digit */ *d = 0; /* Discard fraction */ carry = 0; if (*s > '4') /* Check first digit of fraction */ carry = 1; /* and set carry flag */ s2 = s; while (s2 < d) /* Fill in the rest with zeros */ *s2++ = '0'; s--; /* Point to last digit */ } } if (carry) { /* Handle carry, if any */ while (s >= number) { if (*s == '.') { /* Skip backwards over decimal */ s--; continue; } *s += 1; /* Add 1 to current digit */ carry = 0; if (*s <= '9') /* If result is 9 or less */ break; /* we're done */ *s = '0'; /* Otherwise put 0 */ carry = 1; /* carry the 1 */ s--; /* and back up to next digit */ } } if (minus) number--; /* Back up to minus sign, if any. */ #ifdef FLT_NOT_DBL sscanf(number,"%f",&value); /* Convert back to floating point */ #else sscanf(number,"%lf",&value); /* Convert back to floating point */ #endif if (obuf) strncpy(obuf,number,obuflen); /* Set string result */ return(value); /* Return floating-point result */ } #endif /* CKFLOAT */ /* Sorting routines... */ /* S H _ S O R T -- Shell sort -- sorts string array s in place. */ /* Highly defensive and relatively quick. Uses shell sort algorithm. Args: s = pointer to array of strings. p = pointer to a second array to sort in parallel s, or NULL for none. n = number of elements in s. k = position of key. r = ascending lexical order if zero, reverse lexical order if nonzero. c = 0 for case independence, 1 for case matters, 2 for numeric. If k is past the right end of a string, the string is considered empty for comparison purposes. Hint: To sort a piece of an array, call with s pointing to the first element and n the number of elements to sort. Return value: None. Always succeeds, unless any of s[0]..s[n-1] are bad pointers, in which case memory violations are possible, but C offers no defense against this, so no way to gracefully return an error code. */ VOID #ifdef CK_ANSIC sh_sort( char ** s, char ** p, int n, int k, int r, int c ) #else sh_sort(s,p,n,k,r,c) char **s, **p; int n, k, r, c; #endif /* CK_ANSIC */ { int m, i, j, x; char *t, *t1, *t2, *u = NULL; #ifdef CKFLOAT CKFLOAT f1, f2; #else long n1, n2; #endif /* CKFLOAT */ if (!s) return; /* Nothing to sort? */ if (n < 2) return; /* Not enough elements to sort? */ if (k < 0) k = 0; /* Key */ m = n; /* Initial group size is whole array */ while (1) { m = m / 2; /* Divide group size in half */ if (m < 1) /* Small as can be, so done */ break; for (j = 0; j < n-m; j++) { /* Sort each group */ t = t2 = s[j+m]; /* Compare this one... */ if (!t) /* But if it's NULL */ t2 = ""; /* make it the empty string */ if (p) /* Handle parallel array, if any */ u = p[j+m]; if (k > 0 && *t2) { if ((int)strlen(t2) < k) /* If key too big */ t2 = ""; /* make key the empty string */ else /* Key is in string */ t2 = t + k; /* so point to key position */ } for (i = j; i >= 0; i -= m) { /* Loop thru comparands s[i..]*/ t1 = s[i]; if (!t1) /* Same deal */ t1 = ""; if (k > 0 && *t1) { if ((int)strlen(t1) < k) t1 = ""; else t1 = s[i]+k; } if (c == 2) { /* Numeric comparison */ x = 0; #ifdef CKFLOAT f2 = 0.0; f1 = 0.0; if (isfloat(t1,1)) { f1 = floatval; if (isfloat(t2,1)) f2 = floatval; else f1 = 0.0; } if (f2 < f1) x = 1; else x = -1; #else n2 = 0L; n1 = 0L; if (rdigits(t1)) { n1 = atol(t1); if (rdigits(t2)) n2 = atol(t2); else n1 = 0L; } if (n2 < n1) x = 1; else x = -1; #endif /* CKFLOAT */ } else { x = ckstrcmp(t1,t2,-1,c); /* Compare */ } if (r == 0 && x < 0) break; if (r != 0 && x > 0) break; s[i+m] = s[i]; if (p) p[i+m] = p[i]; } s[i+m] = t; if (p) p[i+m] = u; } } } /* C K R A D I X -- Radix converter */ /* Call with: s: a number in string format. in: int, specifying the radix of s, 2-36. out: int, specifying the radix to convert to, 2-36. Returns: NULL on error (illegal radix, illegal number, etc.). "-1" on overflow (number too big for unsigned long). Otherwise: Pointer to result. */ char * #ifdef CK_ANSIC ckradix( char * s, int in, int out) #else ckradix(s,in,out) char * s; int in, out; #endif /* CK_ANSIC */ { char c, *r = rxresult; int d, minus = 0; #ifdef COMMENT unsigned long zz = 0L; long z = 0L; #else /* To get 64 bits on 32-bit hardware we use off_t, but there is no unsigned version of off_t, so we lose the ability to detect overflow. */ CK_OFF_T zz = (CK_OFF_T)0; CK_OFF_T z = (CK_OFF_T)0; #endif /* COMMENT */ if (in < 2 || in > 36) /* Verify legal input radix */ return(NULL); if (out < 2 || out > 36) /* and output radix. */ return(NULL); if (*s == '+') { /* Get sign if any */ s++; } else if (*s == '-') { minus++; s++; } while (*s == SP || *s == '0') /* Trim leading blanks or 0's */ s++; /* For detecting overflow, we use a signed copy of the unsigned long accumulator. If it goes negative, we know we'll overflow NEXT time through the loop. */ for (; *s; s++) { /* Convert from input radix to */ c = *s; /* unsigned long */ if (islower(c)) c = toupper(c); if (c >= '0' && c <= '9') d = c - '0'; else if (c >= 'A' && c <= 'Z') d = c - 'A' + 10; else return(NULL); if (d >= in) /* Check for illegal digit */ return(NULL); zz = zz * in + d; if (z < 0L) /* Clever(?) overflow detector */ return("-1"); z = zz; } if (!zz) return("0"); r = &rxresult[RXRESULT]; /* Convert from unsigned long */ *r-- = NUL; /* to output radix. */ while (zz > 0 && r > rxresult) { d = zz % (unsigned)out; *r-- = rxdigits[d]; zz = zz / (unsigned)out; } if (minus) *r-- = '-'; /* Replace original sign */ return((char *)(r+1)); } #ifndef NOB64 /* Base-64 conversion routines */ static char b64[] = { /* Encoding vector */ #ifdef pdp11 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" #else 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S', 'T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l', 'm','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4', '5','6','7','8','9','+','/','=','\0' #endif /* pdp11 */ }; static int b64tbl[] = { /* Decoding vector */ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; /* B 8 T O B 6 4 -- Converts 8-bit data to Base64 encoding. Call with: s = Pointer to 8-bit data; n = Number of source bytes to encode (SEE NOTE). If it's a null-terminated string, you can use -1 here. out = Address of output buffer. len = Length of output buffer (should > 4/3 longer than input). Returns: >= 0 if OK, number of bytes placed in output buffer, with the subsequent byte set to NUL if space permits. -1 on error (output buffer space exhausted). NOTE: If this function is to be called repeatedly, e.g. to encode a data stream a chunk at a time, the source length must be a multiple of 3 in all calls but the final one to avoid the generation of extraneous pad characters that would throw the decoder out of sync. When encoding only a single string, this is not a consideration. No internal state is kept, so there is no reset function. */ int #ifdef CK_ANSIC b8tob64( char * s, int n, char * out, int len ) #else b8tob64(s,n,out,len) char * s,* out; int n, len; #endif /* CK_ANSIC */ { int b3, b4, i, x = 0; unsigned int t; if (n < 0) n = strlen(s); for (i = 0; i < n; i += 3,x += 4) { /* Loop through source bytes */ b3 = b4 = 0; t = (unsigned)((unsigned)((unsigned int)s[i] & 0xff) << 8); if (n - 1 > i) { /* Do we have another after this? */ t |= (unsigned)(s[i+1] & 0xff); /* Yes, OR it in */ b3 = 1; /* And remember */ } t <<= 8; /* Move over */ if (n - 2 > i) { /* Another one after that? */ t |= (unsigned)(s[i+2] & 0xff); /* Yes, OR it in */ b4 = 1; /* and remember */ } if (x + 4 > len) /* Check output space */ return(-1); out[x+3] = b64[b4 ? (t & 0x3f) : 64]; /* 64 = code for '=' */ t >>= 6; out[x+2] = b64[b3 ? (t & 0x3f) : 64]; t >>= 6; out[x+1] = b64[t & 0x3f]; t >>= 6; out[x] = b64[t & 0x3f]; } if (x < len) out[x] = NUL; /* Null-terminate the string */ return(x); } /* B 6 4 T O B 8 -- Converts Base64 string to 8-bit data. Call with: s = pointer to Base64 string (whitespace ignored). n = length of string, or -1 if null terminated, or 0 to reset. out = address of output buffer. len = length of output buffer. Returns: >= 0 if OK, number of bytes placed in output buffer, with the subsequent byte set to NUL if space permits. < 0 on error: -1 = output buffer too small for input. -2 = input contains illegal characters. -3 = internal coding error. NOTE: Can be called repeatedly to decode a Base64 stream, one chunk at a time. However, if it is to be called for multiple streams in succession, its internal state must be reset at the beginning of the new stream. */ int #ifdef CK_ANSIC b64tob8( char * s, int n, char * out, int len ) /* Decode */ #else b64tob8( s, n, out, len ) char * s; int n; char * out; int len; #endif /* CK_ANSIC */ { static int bits = 0; static unsigned int r = 0; int i, k = 0, x, t; unsigned char c; if (n == 0) { /* Reset state */ bits = 0; r = 0; return(0); } x = (n < 0) ? strlen(s) : n; /* Source length */ n = ((x + 3) / 4) * 3; /* Compute destination length */ if (x > 0 && s[x-1] == '=') n--; /* Account for padding */ if (x > 1 && s[x-2] == '=') n--; if (n > len) /* Destination not big enough */ return(-1); /* Fail */ for (i = 0; i < x; i++) { /* Loop thru source */ c = (CHAR)s[i]; /* Next char */ t = b64tbl[c]; /* Code for this char */ if (t == -2) { /* Whitespace or Ctrl */ n--; /* Ignore */ continue; } else if (t == -1) { /* Illegal code */ return(-2); /* Fail. */ } else if (t > 63 || t < 0) /* Illegal value */ return(-3); /* fail. */ bits += 6; /* Count bits */ r <<= 6; /* Make space */ r |= (unsigned) t; /* OR in new code */ if (bits >= 8) { /* Have a byte yet? */ bits -= 8; /* Output it */ c = (unsigned) ((r >> bits) & 0xff); out[k++] = c; } } if (k < len) out[k] = NUL; /* Null-terminate in case it's */ return(k); /* a text string */ } #endif /* NOB64 */ /* C H K N U M -- See if argument string is an integer */ /* Returns 1 if OK, zero if not OK */ /* If OK, string should be acceptable to atoi() or atol() or ckatofs() */ /* Allows leading space, sign */ int #ifdef CK_ANSIC chknum( char * s ) /* Check Numeric String */ #else chknum( s ) char * s; #endif /* CK_ANSIC */ { int x = 0; /* Flag for past leading space */ int y = 0; /* Flag for digit seen */ char c; debug(F110,"chknum",s,0); if (!s) return(0); if (!*s) return(0); while ((c = *s++)) { /* For each character in the string */ switch (c) { case SP: /* Allow leading spaces */ case HT: if (x == 0) continue; else return(0); case '+': /* Allow leading sign */ case '-': if (x == 0) x = 1; else return(0); break; default: /* After that, only decimal digits */ if (c >= '0' && c <= '9') { x = y = 1; continue; } else return(0); } } return(y); } /* R D I G I T S -- Verify that all characters in arg ARE DIGITS */ /* Returns 1 if so, 0 if not or if string is empty */ int #ifdef CK_ANSIC rdigits( char * s ) #else rdigits(s) char *s; #endif /* CK_ANSIC */ { if (!s) return(0); do { if (!isdigit(*s)) return(0); s++; } while (*s); return(1); } /* P A R N A M -- Return parity name */ char * #ifdef CK_ANSIC parnam(char c) #else parnam(c) char c; #endif /* CK_ANSIC */ /* parnam */ { switch (c) { case 'e': return("even"); case 'o': return("odd"); case 'm': return("mark"); case 's': return("space"); case 0: return("none"); default: return("invalid"); } } char * /* Convert seconds to hh:mm:ss */ #ifdef CK_ANSIC hhmmss(long x) #else hhmmss(x) long x; #endif /* CK_ANSIC */ /* hhmmss(x) */ { static char buf[60]; long s, h, m; h = x / 3600L; /* Hours */ x = x % 3600L; m = x / 60L; /* Minutes */ s = x % 60L; /* Seconds */ if (x > -1L) sprintf(buf,"%02ld:%02ld:%02ld",h,m,s); else buf[0] = NUL; return((char *)buf); } /* L S E T -- Set s into p, right padding to length n with char c; */ /* s is a NUL-terminated string. If length(s) > n, only n bytes are moved. The result is NOT NUL terminated unless c == NUL and length(s) < n. The intended of this routine is for filling in fixed-length record fields. */ VOID #ifdef CK_ANSIC lset( char * p, char * s, int n, int c ) #else lset(p,s,n,c) char *p; char *s; int n; int c; #endif /* CK_ANSIC */ { int x; #ifndef USE_MEMCPY int i; #endif /* USE_MEMCPY */ if (!s) s = ""; x = strlen(s); if (x > n) x = n; #ifdef USE_MEMCPY memcpy(p,s,x); if (n > x) memset(p+x,c,n-x); #else for (i = 0; i < x; i++) *p++ = *s++; for (; i < n; i++) *p++ = c; #endif /* USE_MEMCPY */ } /* R S E T -- Right-adjust s in p, left padding to length n with char c */ VOID #ifdef CK_ANSIC rset( char * p, char * s, int n, int c ) #else rset(p,s,n,c) char *p; char *s; int n; int c; #endif /* CK_ANSIC */ { int x; #ifndef USE_MEMCPY int i; #endif /* USE_MEMCPY */ if (!s) s = ""; x = strlen(s); if (x > n) x = n; #ifdef USE_MEMCPY memset(p,c,n-x); memcpy(p+n-x,s,x); #else for (i = 0; i < (n - x); i++) *p++ = c; for (; i < n; i++) *p++ = *s++; #endif /* USE_MEMCPY */ } /* U L O N G T O H E X -- Unsigned long to hex */ /* Converts unsigned long arg to hex and returns string pointer to rightmost n hex digits left padded with 0's. Allows for longs up to 64 bits. Returns pointer to result. */ char * #ifdef CK_ANSIC ulongtohex( unsigned long z, int n ) #else ulongtohex(z,n) unsigned long z; int n; #endif /* CK_ANSIC */ /* ulongtohex */ { static char hexbuf[17]; int i = 16, x, k = 0; hexbuf[16] = '\0'; if (n > 16) n = 16; k = 2 * (sizeof(long)); for (i = 0; i < n; i++) { if (i > k || z == 0) { hexbuf[15-i] = '0'; } else { x = z & 0x0f; z = z >> 4; hexbuf[15-i] = x + ((x < 10) ? '0' : 0x37); } } return((char *)(&hexbuf[16-i])); } /* H E X T O U L O N G -- Hex string to unsigned long */ /* Converts n chars from s from hex to unsigned long. Returns: 0L or positive, good result (0L is returned if arg is NULL or empty). -1L on error: non-hex arg or overflow. */ long #ifdef CK_ANSIC hextoulong(char * s, int n) #else hextoulong(s,n) char *s; int n; #endif /* CK_ANSIC */ { char buf[64]; unsigned long result = 0L; int d, count = 0; int flag = 0; if (!s) s = ""; if (!*s) { return(0L); } if (n < 1) return(0L); if (n > 63) n = 63; strncpy(buf,s,n); buf[n] = '\0'; s = buf; while (*s) { d = *s++; if ((d == '0' || d == ' ')) { if (!flag) continue; } else { flag = 1; } if (islower(d)) d = toupper(d); if (d >= '0' && d <= '9') { d -= 0x30; } else if (d >= 'A' && d <= 'F') { d -= 0x37; } else { return(-1L); } if (++count > (sizeof(long) * 2)) return(-1L); result = (result << 4) | (d & 0x0f); } return(result); } /* c k s p l i t -- Splits a string into words, or: extracts a given word from a string. Allows for grouping. Operates on a copy of the string; does not alter the original string. All strings NUL-terminated. Call with: fc = function code: 1 = split, 0 = word. n1 = desired word number if fc == 0. s1 = source string. s2 = break string (NULL to accept default = all non-alphanum). s3 = include string (NULL to accept default = all alphanum). n2 = grouping mask (OR desired ones together): 1 = doublequotes, 2 = braces, 4 = apostrophes, 8 = parens, 16 = brackets, 32 = angle brackets, -1 = 63 = all of these. n3 = if positive: group quote character, ASCII value, used and tested only for LISP quote, e.g. (a 'b c '(d e f)). n4 = 0 to collapse adjacent separators; nonzero not to collapse them. n5 - nonzero means '\' is not a quoting character. Returns: Pointer to struct stringarray, with size: -1 = memory allocation error. -2 = too many words in string. n = number of words (0 or more). With: wordarray = array of pointers to n words (n == 1 if fc == 0), 1-based. Each pointer is to a malloc'd string. This array is recycled upon each call; if you need to keep the strings, make copies of them. This routine must have control of allocation and deallocation. If a given character is included in the include list, it is not treated as a separator or as a grouping character. Groups may be nested only if they are formed with braces, parens, or brackets, but not with quotes or apostrophes since ASCII quotes have no intrinsic handedness. Group-start and end characters are treated as separators even in the absence of other separators, so a string such as "a{b}c" results in three words, not one. Sample call to split a string into an array: struct stringarray * q; q = cksplit(1,0,s1,s2,s3,-1,0); q->a_size = size (>=0) or failure code (<0) q->a_head = pointer to array (elements 0 thru q->asize - 1). Sample call to extract word n from a string: struct stringarray * q; q = cksplit(0,n,s1,s2,s3,-1,0); q->a_size = size (1) or failure code (<0) q->a_head = pointer to array (element 1 is the desired word). */ /* States */ #define ST_BW 0 /* Between Words */ #define ST_IW 1 /* In Word */ #define ST_IG 2 /* Start Group */ /* Character Classes (bitmap) */ #define CL_SEP 1 /* Separator */ #define CL_OPN 2 /* Group Open */ #define CL_CLS 4 /* Group Close */ #define CL_DAT 8 /* Data */ #define CL_QUO 16 /* Group quote */ #ifdef BIGBUFOK #ifndef MAXWORDS #define MAXWORDS 4096 /* Max number of words */ #endif /* MAXWORDS */ #ifndef NESTMAX #define NESTMAX 64 /* Maximum nesting level */ #endif /* NESTMAX */ #else #ifndef MAXWORDS #define MAXWORDS 128 /* Max number of words */ #endif /* MAXWORDS */ #ifndef NESTMAX #define NESTMAX 16 /* Maximum nesting level */ #endif /* NESTMAX */ #endif /* BIGBUFOK */ /* static */ char ** wordarray = NULL; /* Result array of word pointers */ static struct stringarray ck_sval = { /* Return value structure */ NULL, /* Pointer to array */ 0 /* Size */ }; static int * wordsize = NULL; static #ifdef CK_ANSIC void setword(int n, char * s, int len) #else VOID setword(n,s,len) int n; char * s; int len; #endif /* CK_ANSIC */ { register char * p; register int i, k; if (!s) s = ""; if (!wordarray) { /* Allocate result array (only once) */ if (!(wordarray = (char **)malloc((MAXWORDS+1) * sizeof(char *)))) return; if (!(wordsize = (int *)malloc((MAXWORDS+1) * sizeof(int)))) return; for (i = 0; i <= MAXWORDS; i++) { /* Initialize result array */ wordarray[i] = NULL; wordsize[i] = 0; } } if (wordsize[n] < len /* || !wordarray[n] */ ) { k = (len < 16) ? 16 : len + (len / 4); wordarray[n] = (char *) malloc(k+1); wordsize[n] = (wordarray[n]) ? k : 0; if (wordarray[n]) { p = wordarray[n]; while ((*p++ = *s++) && k-- > 0) ; } } else if (len > 0) { k = wordsize[n]; /* (In case len arg is a lie) */ p = wordarray[n]; while ((*p++ = *s++) && k-- > 0) { #ifdef COMMENT if ((*(s-1) == CMDQ) && *s != CMDQ) { k++; p--; } #endif /* COMMENT */ } } else if (wordarray[n]) { wordarray[n][0] = NUL; } } static char * splitbuf = NULL; static int nsplitbuf = 0; /* n4 = 1 to NOT collapse adjacent separators */ struct stringarray * #ifdef CK_ANSIC cksplit(int fc,int n1,char * s1,char * s2,char * s3, int n2,int n3,int n4,int n5) #else cksplit(fc,n1,s1,s2,s3,n2,n3,n4,n5) int fc,n1,n2,n3,n4,n5; char *s1, *s2, *s3; #endif /* CK_ANSIC */ { int splitting = 0; /* What I was asked to do */ int i, k, ko = 0, n, x, max = MAXWORDS; /* Workers */ char * s = NULL, * ss, * p; /* Workers */ char * sep = ""; /* Default break set */ char * notsep = ""; /* Default include set */ int grouping = 0; /* Grouping option */ char * gr_opn = "\"{'([<"; /* Group open brackets */ char * gr_cls = "\"}')]>"; /* Group close brackets */ int gr_stk[NESTMAX]; /* Nesting bracket stack */ int gr_lvl = 0; /* Nesting level */ int wordnum = 0; /* Current word number */ CHAR c = 'A'; /* Current char (dummy start value) */ int class = 0; /* Current character class */ int state = ST_BW; /* Current FSA state */ int len = 0; /* Length of current word */ int slen = 0; /* Length of s1 */ int gquote = 0; /* Quoted group */ int cquote = 0; /* Quoted character */ int collapse = 1; /* Collapse adjacent separators */ int all = 0; /* s3 == ALL */ int csv = 0; /* s3 == CSV */ int tsv = 0; /* s3 == TSV */ int prevstate = -1; unsigned int hex80 = 128; unsigned int hexff = 255; CHAR notsepbuf[256]; notsepbuf[0] = NUL; /* Keep set for "ALL" */ if (n4) collapse = 0; /* Don't collapse */ for (i = 0; i < NESTMAX; i++) /* Initialize nesting stack */ gr_stk[i] = 0; setword(1,NULL,0); ck_sval.a_head = wordarray; /* Initialize return value struct */ ck_sval.a_size = 0; if (!s1) s1 = ""; /* s1 = source string */ if (!*s1) { /* If none, nothing to do */ return(&ck_sval); } splitting = fc; /* Our job */ if (splitting) { /* If splitting n = word count */ n = 0; /* Initialize it */ } else { /* Otherwise */ if (n1 == 0) { /* If 0 */ ck_sval.a_size = 0; /* nothing to do. */ return(&ck_sval); } n = n1; /* n = desired word number. */ } slen = 0; /* Get length of s1 */ debug(F111,"cksplit",s1,n); p = s1; /* The idea is to just copy the string into splitbuf (if it exists). This gives us both the copy and the length so we only need to grovel through the string once in most cases. Only when splitbuf doesn't exist or is too short do we re-malloc(), which should be very infrequent so who cares if we have to go through the string again in that case. */ p = s1; s = splitbuf; if (splitbuf) { /* Make pokeable copy of s1 */ while ((*s++ = *p++) && (slen++ < nsplitbuf)) /* Try to copy */ ; } if (!splitbuf || slen >= nsplitbuf) { /* Need to do more... */ int xx; if (splitbuf) /* Free previous buf if any */ free(splitbuf); while (*p++) slen++; /* Get (rest of) length */ xx = (slen < 255) ? 255 : slen + (slen / 4); /* Size of new buffer */ splitbuf = (char *)malloc(xx+1); /* Allocate it */ if (!splitbuf) { /* Memory allocation failure... */ ck_sval.a_size = -1; return(&ck_sval); } nsplitbuf = xx; /* Remember (new) buffer size */ s = splitbuf; p = s1; while ((*s++ = *p++)) ; } s = splitbuf; sep = s2; /* s2 = break set */ if (!sep) sep = ""; debug(F110,"cksplit sep",sep,0); notsep = s3; /* s3 = include set */ debug(F110,"cksplit notsep",notsep,0); if (!notsep) { notsep = ""; } else if ((all = !ckstrcmp(notsep,"ALL",3,1)) || (csv = !ckstrcmp(notsep,"CSV",3,1)) || (tsv = !ckstrcmp(notsep,"TSV",3,1))) { int i, flag; CHAR c; int n = 0; char * ss = sep; if (!all && (csv || tsv)) { all = 1; collapse = 0; } debug(F101,"cksplit csv","",csv); debug(F101,"cksplit tsv","",tsv); debug(F101,"cksplit all","",all); debug(F110,"cksplit ss sep",ss,0); for (i = 1; i < 256; i++) { flag = 0; ss = sep; while ((c = *ss++) && !flag) { if (c == (CHAR)i) flag++; } if (!flag) { notsepbuf[n++] = (CHAR)i; } } notsepbuf[n] = NUL; notsep = (char *)notsepbuf; debug(F110,"CKMATCH SEPBUF ALL",sep,0); debug(F110,"CKMATCH NOTSEPBUF ALL",notsep,0); } if (*s && csv) { /* For CSV skip leading whitespace */ while (*s == SP || *s == HT) s++; c = *s; } if (n2 == 0 && csv) n2 = 1; /* CSV implies doublequote grouping */ if (n2 < 0) n2 = 63; /* n2 = grouping mask */ grouping = n2; p = ""; /* Pointer to current word */ /* TSV is a special case - no quoting or grouping or recursion */ if (tsv) { /* Tab-separated values list */ /* This block: 2014/01/31 - fdc */ if (!*sep) sep = "\011"; /* Default separator is Tab */ p = s; /* Point to first element */ } while (c) { /* Loop through string */ c = *s; /* Get next char */ if (tsv) { /* Tab-separated-value list? */ /* This block: 2014/01/31 - fdc */ ss = sep; /* Get break set */ while (*ss && *ss != c) ss++; /* See if c is in it */ if (*ss == c) { /* Is this the/a break character? */ *s = NUL; /* Yes, terminate this word */ wordnum++; /* Count it */ if (splitting) { /* fsplit().... */ setword(wordnum,p,len); /* Add a new element */ p = s+1; /* Point to beginning of next */ len = 0; /* and reset the length */ } else if (wordnum == n) { /* fword() counting from left... */ setword(1,p+1,len); ck_sval.a_size = 1; return(&ck_sval); } else if (n < 0 && (wordnum + n > -1)) { /* or from right */ char * s = wordarray[wordnum + n + 1]; if (!s) s = ""; setword(1,s,strlen(s)); ck_sval.a_size = 1; return(&ck_sval); } } else len++; goto nextc; } class = 0; if (!csv && !tsv && !n5) { /* fdc 2010-12-30..2017-04-26 */ /* In CSV and TSV splitting, backslash is not special */ if (!cquote && c == CMDQ) { /* If CMDQ */ cquote++; /* next one is quoted */ goto nextc; /* go get it */ } } if (cquote && c == CMDQ) { /* Quoted CMDQ is special */ if (state != ST_BW) { /* because it can still separate */ char * s2 = s-1; while (s2 > p) { *s2 = *(s2-1); s2--; } p++; } cquote = 0; } if (cquote) { /* Other quoted character */ if (state != ST_BW) { /* can't separate or group */ char * s2 = s-1; while (s2 > p) { *s2 = *(s2-1); s2--; } p++; } class = CL_DAT; /* so treat it as data */ cquote = 0; x = 1; } else { /* Character is not quoted */ if (!all && c < SP) { /* Get its class */ x = 0; /* x == 0 means "is separator" */ } else if (*sep) { /* Break set given */ ss = sep; while (*ss && *ss != c) ss++; /* (instead of ckstrchr()) */ x = (*ss != c); } else { /* Default break set is */ x = ((c >= 'a' && c <= 'z') || /* all but alphanumerics */ (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || ((unsigned int)c >= hex80 && (unsigned int)c <= hexff) ); } if (x == 0 && *notsep && c) { /* Include set if given */ ss = notsep; while (*ss && *ss != c) ss++; /* (instead of ckstrchr()) */ x = (*ss == c); } if (c == n3 && grouping && state == ST_BW) { /* Group quote? */ class = CL_QUO; } else { class = x ? CL_DAT : CL_SEP; /* Class = data or separator */ } if (grouping) { /* Grouping? */ int j; /* Look for group start */ for (k = 0; k < 6; k++) { /* Group-start char? */ j = 1 << k; /* Get its mask bit value */ if (grouping & j) { if (c == gr_opn[k]) { /* Selected group opener? */ ko = k; class |= CL_OPN; if (c == '"' || c == '\'') { /* These can also */ class |= CL_CLS; /* be closers */ break; } } else if (c == gr_cls[k]) { /* Group closer? */ class |= CL_CLS; break; } } } } } debug(F000,"cksplit char",s,c); debug(F101,"cksplit state","",state); debug(F101,"cksplit class","",class); switch (state) { /* State switcher... */ case ST_BW: /* BETWEENWORDS */ if (class & CL_OPN) { /* Group opener */ if (gr_lvl == 0 && !gquote) { /* If not in group */ p = s; /* point to beginning of word */ } gr_lvl++; /* Push closer on nesting stack */ if (gr_lvl >= NESTMAX) goto xxsplit; gr_stk[gr_lvl] = gr_cls[ko]; prevstate = state; state = ST_IG; /* Switch to INGROUP state */ } else if (class & CL_DAT) { /* Data character */ gr_lvl = 0; /* Clear group nesting stack */ gr_stk[gr_lvl] = 0; len = 0; p = s; /* Point to beginning of word */ if (gquote) { /* Adjust for quote */ len++; p--; gquote = 0; } prevstate = state; state = ST_IW; /* Switch to INWORD state */ } else if (class & CL_QUO) { /* Group quote */ gquote = gr_lvl+1; /* Remember quoted level */ p = s - 1; len = 1; } if (collapse) break; case ST_IW: /* INWORD (but not in a group) */ if (class & CL_SEP) { /* Ends on any kind of separator */ *s = NUL; /* Terminate this word */ if (csv) { /* If comma-separated list */ char * s2 = s; /* discard surrounding spaces */ while (s2 > splitbuf) { /* first backwards... */ s2--; if (*s2 == SP || *s2 == HT) *s2 = NUL; else break; } s2 = s+1; /* Then forwards... */ while (*s2 && (*s2 == SP || *s2 == HT)) { s2++; } s = s2-1; } if (!csv || prevstate != ST_IG) { wordnum++; /* Count it */ if (splitting || n < 0) { /* Dispose of it appropriately */ if (wordnum > max) { /* Add to array if splitting */ ck_sval.a_size = -2; return(&ck_sval); } /* This inelegant bit corrects an edge condition */ if (csv && !*p && (!c || !*(s+1))) { wordnum--; } else { setword(wordnum,p,len); } } else if (wordnum == n) { /* Searching for word n */ setword(1,p,len); ck_sval.a_size = 1; return(&ck_sval); } } prevstate = state; state = ST_BW; /* Switch to BETWEENWORDS state */ len = 0; } break; case ST_IG: /* INGROUP */ if (class & CL_CLS) { /* Have group closer? */ if (csv) { if (*(s+1) == c) { char *s2 = s; while ((*s2 = *(s2+1))) s2++; s++; c = *s; } } if (c == gr_stk[gr_lvl]) { /* Does it match current opener? */ gr_lvl--; /* Yes, pop stack */ if (gr_lvl < 0) /* Don't pop it too much */ gr_lvl = 0; if (gr_lvl == 0) { /* If at top of stack */ if (gquote) s++; c = *s; *s = NUL; /* we have word. */ wordnum++; /* Count and dispose of it. */ len--; if (splitting || n < 0) { if (wordnum > max) { ck_sval.a_size = -2; return(&ck_sval); } setword(wordnum,p+1,len); } else if (wordnum == n) { setword(1,p+1,len); ck_sval.a_size = 1; return(&ck_sval); } prevstate = state; state = ST_BW; /* Switch to BETWEENWORDS state */ len = 0; } if (gr_lvl < gquote) gquote = 0; } } else if (class & CL_OPN) { /* Have group opener */ gr_lvl++; /* Push on nesting stack */ if (gr_lvl >= NESTMAX) goto xxsplit; gr_stk[gr_lvl] = gr_cls[ko]; } } /* switch */ nextc: s++; /* Next char */ if (state) len++; } /* while (c) */ if (gr_lvl > 0) { /* In case of an unclosed group */ if (splitting || n < 0) { /* make it the last word. */ if (++wordnum > max) { ck_sval.a_size = -2; return(&ck_sval); } setword(wordnum,p+1,len); } else if (wordnum == n) { /* Counting from left */ setword(1,p+1,len); ck_sval.a_size = 1; return(&ck_sval); } else if (n < 0 && (wordnum + n > -1)) { /* Counting from right */ char * s = wordarray[wordnum + n + 1]; if (!s) s = ""; setword(1,s,strlen(s)); ck_sval.a_size = 1; return(&ck_sval); } } if (!splitting) { /* Fword... */ if (n < 0 && (wordnum + n > -1)) { /* Counting from right */ char * s = wordarray[wordnum + n + 1]; if (!s) s = ""; setword(1,s,strlen(s)); ck_sval.a_size = 1; return(&ck_sval); } setword(1,NULL,0); /* From left... */ ck_sval.a_size = 0; /* but there weren't n words */ return(&ck_sval); } else { /* Succeed otherwise */ ck_sval.a_size = wordnum; /* Always put a null element at the end of the array. It does no harm in the normal case, and it's required if we're making an argv[] array to pass to execvp(). This element is not included in the count. */ if (wordnum < MAXWORDS) setword(wordnum+1,NULL,0); } #ifdef DEBUG if (deblog) { for (i = 1; i <= wordnum; i++) debug(F111,"cksplit result",wordarray[i],i); } #endif /* DEBUG */ return(&ck_sval); xxsplit: /* Error return */ ck_sval.a_size = -2; return(&ck_sval); } /* ckhexbytetoint() expects a string of two hex characters, returns the int equivalent or -1 on error. */ int #ifdef CK_ANSIC ckhexbytetoint( char * s ) #else ckhexbytetoint(s) char * s; #endif /* CK_ANSIC */ { int i, c[2]; if (!s) return(-1); if ((int)strlen(s) != 2) return(-1); for (i = 0; i < 2; i++) { c[i] = *s++; if (!c[i]) return(-1); if (islower(c[i])) c[i] = toupper(c[i]); if (c[i] >= '0' && c[i] <= '9') { c[i] -= 0x30; } else if (c[i] >= 'A' && c[i] <= 'F') { c[i] -= 0x37; } else { return(-1); } } return(c[0] * 16 + c[1]); } /* End of ckclib.c */ ckclib.h000664 045065 024037 00000007113 14767401713 012577 0ustar00fdckermit000000 000000 /* ckclib.h -- C-Kermit library routine prototypes */ /* Author: Frank da Cruz , Columbia University Academic Information Systems, New York City. Copyright (C) 2002, 2009, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ #ifndef CKCLIB_H #define CKCLIB_H struct stringarray { char ** a_head; int a_size; }; #ifdef CK_ANSIC _PROTOTYP( int ckstrncpy, (char *, const char *, int) ); _PROTOTYP( int ckstrncat, (char *, const char *, int) ); #else _PROTOTYP( int ckstrncpy, (char *, char *, int) ); _PROTOTYP( int ckstrncat, (char *, char *, int) ); #endif /* CK_ANSIC */ _PROTOTYP( int ckmakmsg, (char *, int, char *, char *, char *, char *) ); _PROTOTYP( int ckmakxmsg, (char *, int, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *) ); _PROTOTYP( char * ckstrpbrk, (char *, char *) ); _PROTOTYP( char * ckstrstr, (char *, char *) ); _PROTOTYP( char * chartostr, (int) ); _PROTOTYP( int cklower, (char *) ); _PROTOTYP( int ckupper, (char *) ); _PROTOTYP( int ckindex, (char *, char *, int, int, int) ); _PROTOTYP( char * ckctoa, (char) ); _PROTOTYP( char * ckctox, (CHAR, int) ); _PROTOTYP( char * ckitoa, (int) ); _PROTOTYP( char * ckuitoa, (unsigned int) ); _PROTOTYP( char * ckltoa, (long) ); _PROTOTYP( char * ckultoa, (unsigned long) ); _PROTOTYP( char * ckfstoa, (CK_OFF_T) ); _PROTOTYP( CK_OFF_T ckatofs, (char *) ); _PROTOTYP( char * ckitox, (int) ); _PROTOTYP( char * ckltox, (long) ); _PROTOTYP( int ispattern, (char *) ); _PROTOTYP( int ckmatch, (char *, char *, int, int ) ); _PROTOTYP( VOID ckmemcpy, (char *, char *, int) ); _PROTOTYP( char * ckstrchr, (char *, char) ); _PROTOTYP( char * ckstrrchr, (char *, char) ); _PROTOTYP( int ckrchar, (char *) ); _PROTOTYP( int ckstrcmp, (char *, char *, int, int) ); #define xxstrcmp(a,b,c) ckstrcmp(a,b,c,0) _PROTOTYP( int ckstrpre, (char *, char *) ); _PROTOTYP( VOID sh_sort, (char **, char **, int, int, int, int) ); _PROTOTYP( char * brstrip, (char *) ); _PROTOTYP( char * fnstrip, (char *) ); #ifdef COMMENT _PROTOTYP( char * brace, (char *) ); #endif /* COMMENT */ _PROTOTYP( int dquote, (char *, int, int) ); _PROTOTYP( int untabify, (char *, char *, int) ); _PROTOTYP( VOID makelist, (char *, char *[], int) ); #ifndef CK_ANSIC _PROTOTYP( VOID makestr, (char **, char *) ); _PROTOTYP( VOID xmakestr, (char **, char *) ); #else /* CK_ANSIC */ _PROTOTYP( VOID makestr, (char **, const char *) ); _PROTOTYP( VOID xmakestr, (char **, const char *) ); #endif /* CK_ANSIC */ _PROTOTYP( int chknum, (char *) ); _PROTOTYP( int rdigits, (char *) ); _PROTOTYP( char * ckradix, (char *,int,int) ); /* Base-64 conversion needed for script programming and HTTP */ #ifndef NOB64 _PROTOTYP( int b8tob64, (char *,int,char *,int)); _PROTOTYP( int b64tob8, (char *,int,char *,int)); #endif /* NOB64 */ #ifdef CKFLOAT _PROTOTYP( int isfloat, (char *,int) ); #ifndef CKCLIB_C #ifndef CKWART_C extern CKFLOAT floatval; #endif /* CKWART_C */ #endif /* CKCLIB_C */ #endif /* CKFLOAT */ _PROTOTYP( char * parnam, (char) ); _PROTOTYP( char *hhmmss, (long) ); _PROTOTYP( VOID lset, (char *, char *, int, int) ); _PROTOTYP( VOID rset, (char *, char *, int, int) ); _PROTOTYP( char * ulongtohex, (unsigned long, int) ); _PROTOTYP( long hextoulong, (char *, int) ); _PROTOTYP( struct stringarray * cksplit, (int,int, char *,char *,char *,int,int,int,int) ); _PROTOTYP( int ckhexbytetoint, (char *) ); #endif /* CKCLIB_H */ ckcmai.c000664 045065 024037 00000375625 14767402570 012614 0ustar00fdckermit000000 000000 /* ckcmai.c - Main program for C-Kermit plus some miscellaneous functions */ #ifdef COMMENT #define EDITDATE "22 Mar 2025" /* Last edit date dd mmm yyyy */ #else #define EDITDATE "2025/03/22" /* Last edit date ISO format */ #endif /* COMMENT */ #define EDITNDATE "20250322" /* Keep them in sync */ /* Thu Aug 8 12:25:04 2024 */ /* As of 27 September 2022 BETATEST is defined in ckcdeb.h, not here, because it's also used in other modules. */ /* FOR NEW VERSION (development, alpha, beta, release candidate, formal release): . Change the 3 dates just above; . Change ck_cryear = "xxxx"; (copyright year) just below, if necessary; . For test versions change ck_s_test and ck_s_tver (below) appropriately: Dev, Alpha, Pre-Beta, Beta, or RC (Release Candidate); . Change makefile CKVER and BUILDID definitions and timestamp at top. If the version number has changed, also: . Change sccsid[] (below); . Change ck_s_ver, ck_l_ver (below). (these are version numbers without Dev, Alpha, or Beta test ID) . Increment ck_s_edit -- Must be larger than previous release. . Update the edit number in ck_s_xver to agree with ck_s_edit */ /* ckcsym.h is used for defining symbols that normally would be defined using -D or -d on the cc command line, for use with compilers that don't support this feature. Must come before any tests for preprocessor symbols. */ #include "ckcsym.h" /* The ckcdeb.h include was moved up here from further down so BETATEST definition will take effect before it is used. Previously BETATEST was defined in this module but since it was also used in other modules, it needed to be in ckcdeb.h, which, despite its name, has evolved into the principal C-Kermit header file, the only one that all modules #include. - fdc, 27 September 2022 */ #include "ckcdeb.h" /* Debug & other symbols */ char * ck_cryear = "2025"; /* C-Kermit copyright year */ /* Note: initialize ck_s_test to "" if this is not a test version. Use (*ck_s_test != '\0') to decide whether to print test-related messages. */ #ifdef OS2 /* Kermit 95 version numbers come from here */ #include "ckover.h" #endif #ifdef BETATEST #ifdef OS2 #ifdef __DATE__ #define BETADATE #endif /* __DATE__ */ /* Kermit 95 releases on a different schedule from C-Kermit on other platforms. As 3 March 2024 the Windows Beta is based on C-Kermit 10.0 Beta.11. */ char *ck_s_test = K95_TEST; char *ck_s_tver = K95_TEST_VER_S; #else /* Can also use "Pre-Beta" here for in between "daily" uploads */ char *ck_s_test = "Beta"; /* "Dev","Alpha","pre-Beta","Beta","RC", or "" */ char *ck_s_tver = "12"; /* Test version number */ #endif /* OS2 */ #else /* BETATEST */ char *ck_s_test = ""; /* Not development */ char *ck_s_tver = ""; #endif /* BETATEST */ #ifdef BETADATE /* Date of this version or edit */ char *ck_s_date = __DATE__; /* Compilation date */ #else char *ck_s_date = EDITDATE; /* See top */ #endif /* BETADATE */ char *buildid = EDITNDATE; /* See top */ #ifdef UNIX static char sccsid[] = "@(#)C-Kermit 10.0"; #endif /* UNIX */ int offtsize = 0; /* Size of OFF_T */ /* As of C-Kermit 10.0, we no longer use major.minor.edit version number, just major.minor. The C-Kermit Version number is major.minor.edit (integers). Major version always goes up. The Minor version is an artifact from the DECSYSTEM-20 versioning system and hasn't been used since C-Kermit 7.1. The Edit number is sequential, always goes up, but there can be gaps. For example there might be many edits between releases. The edit number is no longer shown as of C-Kermit 10.0, but we still need to keep it, and it should always be incremented, for the benefit of packagers like Debian who depend on it. Also the custom-format version numbers for the original 1980s Macintosh is gone as there is no more Mac Kermit (for the original Macintosh), just C-Kermit for each platform (except the original Mac) and Kermit 95. */ char *ck_s_ver = "10.0"; /* C-Kermit version string */ char *ck_s_edit = "416"; /* Edit number (for Debian package) */ char *ck_s_xver = "10.0.416"; /* eXtended version string */ long ck_l_ver = 1000415L; /* C-Kermit version number */ char *ck_s_name = "C-Kermit"; /* Name of this program */ char *ck_s_who = ""; /* Where customized, "" = not. */ char *ck_patch = ""; /* Patch info, if any. */ long ck_l_xver; #ifdef OS2 /* Kermit 95 for Windows and OS/2 */ char *ck_s_k95ver = K95_VERSION_MAJ_MIN_REV; /* Product-specific version string */ long ck_l_k95ver = K95_VERSION_L; /* Product-specific version number */ #ifdef IKSDONLY #ifdef NT char *ck_s_k95name = "IKS-NT"; #else /* NT */ char *ck_s_k95name = "IKS-OS/2"; #endif /* NT */ #else /* IKSDONLY */ char *ck_s_k95name = "Kermit 95"; /* Program name */ #endif /* IKSDONLY */ #endif /* OS2 */ #define CKVERLEN 128 char versiox[CKVERLEN]; /* Version string buffer */ char *versio = versiox; /* These are filled in at */ long vernum, xvernum; /* runtime from above. */ #define CKCMAI #include "ckcasc.h" /* ASCII character symbols */ char * myname = NULL; /* Name this program is called by */ #ifndef OS2 char * exedir = NULL; /* Directory I was executed from */ #endif /* OS2 */ char homedirpath[CKMAXPATH+1] = { NUL, NUL }; /* Home directory path */ char * myhome = NULL; /* Home directory override string */ #ifdef HAVE_LOCALE int nolocale = 0; /* Use Locale */ #else int nolocale = 1; /* Don't use Locale */ #endif /* HAVE_LOCALE */ /* C K C M A I -- C-Kermit Main program */ /* Principal Author: Frank da Cruz Columbia University 1974-2011; the Open Source Kermit Project 2011-2022. fdc@kermitproject.org OR fdc@columbia.edu. I am no longer at Columbia University as of 1 July 2011. The new Open Source Kermit Project website is the definitive source for Kermit software created or updated since that date: https://www.kermitproject.org The associated FTP site was ftp://ftp.kermitproject.org/ but FTP has been "deprecated" since 2021 so all downloads are now done by HTTP(S) links. Note that Columbia University holds the copyright to this software in perpetuity, but as of C-Kermit 9.0 the license has changed from the previous somewhat restrictive one to the Open Source Modified Berkeley 3-clause license, text just below (where %s is the year current at the last time this code compiled). If you're looking for the program start herald, it's in ckuus5.c, function herald(). COPYRIGHT NOTICE: */ char *copyright[] = { #ifdef pdp11 "Copyright (C) 1985, %s, Trustees of Columbia University, NYC.", "All rights reserved.", " ", #else "Copyright (C) 1985, %s,", " The Trustees of Columbia University in the City of New York.", " All rights reserved.", " ", "Redistribution and use in source and binary forms, with or without", "modification, are permitted provided that the following conditions", "are met:", " ", " + Redistributions of source code must retain the above copyright", " notice, this list of conditions and the following disclaimer.", " ", " + Redistributions in binary form must reproduce the above copyright", " notice, this list of conditions and the following disclaimer in", " the documentation and/or other materials provided with the", " distribution.", " ", " + Neither the name of Columbia University nor the names of its", " contributors may be used to endorse or promote products derived", " from this software without specific prior written permission.", " ", "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS", "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT", "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR", "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT", "HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,", "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT", "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,", "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY", "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT", "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE", "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", #endif /* pdp11 */ #ifdef OS2 "Portions Copyright (C) 2002-2005, Secure Endpoints Inc, New York NY USA.", #ifdef CK_XYZ "Portions Copyright (C) 1995, Oy Online Solutions Ltd., Jyvaskyla, Finland.", #endif /* CK_XYZ */ #endif /* OS2 */ #ifdef CK_AUTHENTICATION " ", "Portions Copyright (C) 1990, Massachusetts Institute of Technology.", #ifdef CK_ENCRYPTION "Portions Copyright (C) 1991, 1993 Regents of the University of California.", "Portions Copyright (C) 1991, 1992, 1993, 1994, 1995 by AT&T.", "Portions Copyright (C) 1995, 1997, Eric Young .", #endif /* CK_ENCRYPTION */ #ifdef CK_SRP "Portions Copyright (C) 1997, Stanford University.", #endif /* CK_SRP */ #endif /* CK_AUTHENTICATION */ #ifndef pdp11 " ", "For further information, visit the Kermit Project website:", "http://www.kermitproject.org/ .", #endif /* pdp11 */ ""}; /* Windows IKSD copyright used to be separate */ char *wiksdcpr = (char *) copyright; /* DOCUMENTATION: "Using C-Kermit" by Frank da Cruz and Christine M. Gianone, Digital Press / Butterworth-Heinemann, Woburn MA, USA. Second edition (1997), ISBN 1-55558-164-1. Plus updates on the Kermit website: http://www.kermitproject.org/ck90.html#doc For Kermit 95, also: "Kermit 95" by Christine M. Gianone and Frank da Cruz, Manning Publications, Greenwich CT, USA (1998) - Online here: http://www.kermitproject.org/k95manual/ ACKNOWLEDGMENTS: The Kermit file transfer protocol was developed at the Columbia University Center for Computing Activities (CUCCA), which was since renamed to Columbia University Academic Information Systems (AcIS) and after that Columbia University Information Technology (CUIT). Kermit is named after Kermit the Frog, star of the television series THE MUPPET SHOW; the name is used by permission of Henson Associates, Inc. Thanks to at least the following people for their contributions to this program over the years, and apologies to anyone who was inadvertantly omitted: Chris Adie, Edinburgh U, Scotland (OS/2) Robert Adsett, University of Waterloo, Canada Larry Afrin, Clemson U Russ Allbery, Stanford U Jeffrey Altman, (formerly of) Columbia University Greg Andrews, Telebit Corp Barry Archer, U of Missouri Robert Andersson, International Systems A/S, Oslo, Norway Chris Armstrong, Brookhaven National Lab (OS/2) William Bader, Software Consulting Services, Nazareth, PA Fuat Baran, Columbia U Stan Barber, Rice U Jim Barbour, U of Colorado Donn Baumgartner, Dell Ian Beckwith, Debian Project Nelson Beebe, U of Utah Gerry Belanger, Cognitronics Edward Berner Karl Berry, UMB Mark Berryman, SAIC Dean W Bettinger, SUNY Gary Bilkus Peter Binderup, Denmark David Bolen, Advanced Networks and Services, Inc. Joop Bonen Marc Boucher, U of Montreal Charles Brooks, EDN Bob Brown Mike Brown, Purdue U Rob Brown Jack Bryans, California State U at Long Beach Mark Buda, DEC (VMS) Fernando Cabral, Padrao iX, Brasilia Bjorn Carlsson, Stockholm University Computer Centre QZ, Sweden Bill Catchings, (formerly of) Columbia U Bob Cattani, Columbia U CS Dept Davide Cervone, Rochester U Seth Chaiklin, Denmark John Chandler, Harvard U / Smithsonian Astronomical Observatory Bernard Chen, UCLA Andrew A Chernov, RELCOM Team, Moscow John L Chmielewski, AT&T, Lisle, IL Howard Chu, U of Michigan Bill Coalson, McDonnell Douglas Bertie Coopersmith, London Christian Corti Chet Creider, U of Western Ontario Alan Crosswell, Columbia U Jeff Damens, (formerly of) Columbia U Mark Davies, Bath U, UK Sin-itirou Dezawa, Fujifilm, Japan Alexey Dokuchaev (FreeBSD) Joe R. Doupnik, Utah State U Frank Dreano, Honeywell John Dunlap, U of Washington Alex Dupuy, SMART.COM David Dyck, John Fluke Mfg Co. Stefaan A. Eeckels, Eurokom, Luxembourg Nick Efthymiou Paul Eggert, Twin Sun, Inc., El Segundo, CA Bernie Eiben, DEC Peter Eichhorn, Assyst International, Munich, Germany Kristoffer Eriksson, Peridot Konsult AB, Oerebro, Sweden John R. Evans, IRS, Kansas City Glenn Everhart, RCA Labs Charlie Finan, Cray Research Herm Fischer, Encino, CA (extensive contributions to version 4.0) Carl Fongheiser, CWRU Mike Freeman, Bonneville Power Authority Carl Friedberg Adam Friedlander Marcello Frutig, Catholic University, Sao Paulo, Brazil (X.25 support) Hirofumi Fujii, Japan Nat'l Lab for High Energy Physics, Tokyo (Kanji) Chuck Fuller, Westinghouse Corporate Computer Services Andy Fyfe, Caltech Christine M. Gianone, Columbia U David Goodwin, NZ John Gilmore, UC Berkeley Madhusudan Giyyarpuram, HP Rainer Glaschick, Siemens AG, Paderborn William H. Glass German Goldszmidt, IBM Chuck Goodhart, NASA Alistair Gorman, New Zealand Richard Gration, ADFA, Australia Chris Green, Essex U, UK Alan Grieg, Dundee Tech, Scotland Yekta Gursel, MIT Jim Guyton, Rand Corp Michael Haertel Bruno Haible Bob Hain, UMN Marion Hakanson, ORST Richard Hamilton John Hamilston, Iowa State U Simon Hania, Netherlands Stan Hanks, Rice U. Ken Harrenstein, SRI Eugenia Harris, Data General (AOS/VS) David Harrison, Kingston Warren Corp Lucas Hart, Oregon State University James Harvey, Indiana/Purdue U (VMS) Rob Healey Chuck Hedrick, Rutgers U Ron Heiby, Technical Systems Division, Motorola Computer Group Steve Hemminger, Tektronix Christian Hemsing, RWTH Aachen, Germany (OS-9) Randolph Herber, US DOE Andrew Herbert, Monash Univ, Australia Marcus Herbert, Germany Mike Hickey, ITI Dan Hildebrand, QNX Software Systems Inc, Kanata, ON (QNX) R E Hill Stephan Hoffman-Emden Sven Holmstrom, ABB Utilities AB, Sweden Bill Homer, Cray Research Ray Hunter, The Wollongong Group Randy Huntziger, National Library of Medicine Larry Jacobs, Transarc Steve Jenkins, Lancaster University, UK Dave Johnson, Gradient Technologies Mark B Johnson, Apple Computer Jyke Jokinen, Tampere University of Technology, Finland (QNX) Eric F Jones, AT&T Luke Jones, AT&T Peter Jones, U of Quebec Montreal Steven M Jones, the Living Computer Museum Phil Julian, SAS Institute Peter Kabal, U of Quebec Mic Kaczmarczik, U of Texas at Austin Sergey Kartashoff, Inst. of Precise Mechanics & Computer Equipment, Moscow Howie Kaye, Columbia U Rob Kedoin, Linotype Co, Hauppauge, NY (OS/2) Phil Keegstra Mark Kennedy, IBM Terry Kennedy, St Peter's College, Jersey City, NJ (VMS and more) "Carlo Kid", Technical University of Delft, Netherlands Tim Kientzle Paul Kimoto, Cornell U Douglas Kingston, morgan.com Lawrence Kirby, Wiltshire, UK Tom Kloos, Sequent Computer Systems Guenter Knauf Jim Knutson, U of Texas at Austin John T. Kohl (BSDI) Scott Kramer, SRI International, Menlo Park, CA John Kraynack, US Postal Service David Kricker, Encore Computer Thomas Krueger, UWM Bo Kullmar, ABC Klubben, Stockholm, and Central Bank of Sweden, Kista R. Brad Kummer, AT&T Bell Labs, Atlanta, GA John Kunze, UC Berkeley David Lane, BSSI / BellSouth (Stratus VOS, X.25) Bob Larson, USC (OS-9) Bert Laverman, Groningen U, Netherlands Steve Layton David Lawyer, UC Irvine Jason Lehr David LeVine, National Semiconductor Corporation Daniel S. Lewart, UIUC S.O. Lidie, Lehigh U Tor Lillqvist, Helsinki U, Finland David-Michael Lincke, U of St Gallen, Switzerland Robert Lipe (for SCO makefile entries & advice) Dr. Eberhard W Lisse, Namibia Dean Long Mike Long, Analog Devices, Norwood MA Kevin Lowey, U of Saskatchewan (OS/2) Andy Lowry, Columbia U James Lummel, Caprica Telecomputing Resources (QNX) Lewis McCarthy David MacKenzie, Environmental Defense Fund, U of Maryland John Mackin, University of Sidney, Australia Martin Maclaren, Bath U, UK Chris Maio, Columbia U CS Dept Montserrat Mane, HP, Grenoble, France Fulvio Marino, Olivetti, Ivrea, Italy Arthur Marsh, dircsa.org.au Peter Mauzey, Lucent Technologies Tye McQueen, Utah State U Ted Medin Hellmuth Michaelis, Hanseatischer Computerservice GmbH, Hamburg, Germany Leslie Mikesell, American Farm Bureau Todd Miller, Courtesan Consulting Gary Mills Martin Minow, DEC (VMS) Pawan Misra, Bellcore Ken Mizialko, IBM, Manassas, VA Wolfgang Moeller, DECUS Germany Ray Moody, Purdue U Bruce J Moore, Allen-Bradley Co, Highland Heights, OH (Atari ST) Steve Morley, Convex Peter Mossel, Columbia U Tony Movshon, NYU Lou Muccioli, Swanson Analysis Systems Dan Murphy Neal P. Murphy, Harsof Systems, Wonder Lake IL Gary Mussar John Nall, FSU Jack Nelson, U of Pittsburgh Jim Noble, Planning Research Corporation (Macintosh) Ian O'Brien, Bath U, UK Melissa O'Neill, SFU John Owens Thomas Pinkl, Health Business Systems Inc. Michael Pins, Iowa Computer Aided Engineering Network Andre' Pirard, University of Liege, Belgium Paul Placeway, Ohio State U Piet W. Plomp, ICCE, Groningen University, Netherlands Ken Poulton, HP Labs Manfred Prange, Oakland U Christopher Pratt, APV Baker, UK Frank Prindle, NADC Tony Querubin, U of Hawaii Jean-Pierre Radley Anton Rang Mike Rechtman Scott Ribe Alan Robiette, Oxford University, UK Michel Robitaille, U of Montreal (Mac) Huw Rogers, Schweizerische Kreditanstalt, Zuerich Nigel Roles, Cambridge, England Kai Uwe Rommel, Technische Universitaet Muenchen (OS/2) Larry Rosenman (Amiga) Jay Rouman, U of Michigan Jack Rouse, SAS Institute (Data General and/or Apollo) Stew Rubenstein, Harvard U (VMS) Gerhard Rueckle, FH Darmstadt, Fb. E/Automatisierungstechnik John Santos, EG&H Mark Sapiro Bill Schilit, Columbia U Ulli Schlueter, RWTH Aachen, Germany (OS-9, etc) Michael Schmidt, U of Paderborn, Germany Eric Schnoebelen, Convex Benn Schreiber, DEC Dan Schullman, DEC (modems, DIAL command, etc) John Schultz, 3M Steven Schultz, Contel (PDP-11) Steven Schweda APPP Scorer, Leeds Polytechnic, UK Gordon Scott, Micro Focus, Newbury UK Gisbert W. Selke, WIdO, Bonn, Germany Kijal Shah David Singer, IBM Almaden Research Labs David Sizeland, U of London Medical School Bruce Skelly Fridrik Skulason, Iceland Rick Sladkey (Linux) Dave Slate Bradley Smith, UCLA Eric Smith Fred Smith, Merk / Computrition Richard S Smith, Cal State Tim Sneddon Bernard Spil Ryan Stanisfer, UNT Bertil Stenstroem, Stockholm University Computer Centre (QZ), Sweden James Sturdevant, CAP GEMENI AMERICA, Minneapolis Peter Svanberg, Royal Techn. HS, Sweden James R. Swenson, Accu-Weather, Inc. Ted T'so, MIT (Linux) Andy Tanenbaum, Vrije U, Amsterdam, Netherlands Seth Theriault, Columbia U Glen Thobe Jake Thompson Markku Toijala, Helsinki U of Technology Teemu Torma, Helsinki U of Technology Linus Torvalds, Helsinki Rick Troxel, NIH Warren Tucker, Tridom Corp, Mountain Park, GA Dave Tweten, AMES-NAS G Uddeborg, Sweden Walter Underwood, Ford Aerospace Pieter Van Der Linden, Centre Mondial, Paris Ge van Geldorp, Netherlands Fred van Kempen, MINIX User Group, Voorhout, Netherlands Wayne Van Pelt, GE/CRD Mark Vasoll, Oklahoma State U (V7 UNIX) Konstantin Vinogradov, ICSTI, Moscow Paul Vixie, DEC Bernie Volz, Process Software Eduard Vopicka, Prague University of Economics, Czech Republic Martin Vorlaender Dimitri Vulis, CUNY Roger Wallace, Raytheon Stephen Walton, Calif State U, Northridge (Amiga) Jamie Watson, Adasoft, Switzerland (AIX) Rick Watson, U of Texas (Macintosh) Eric Weaver, Columbia U Scott Weikart (Association for Progressive Communications) Robert Weiner, Programming Plus, New York City Lauren Weinstein, Vortex Technlogy David Wexelblat, AT&T Clark Wierda, Illuminati Online Joachim Wiesel, U of Karlsruhe Lon Willett, U of Utah Michael Williams, UCLA Nate Williams, U of Montana David Wilson Joellen Windsor, U of Arizona Patrick Wolfe, Kuck & Associates, Inc. Gregg Wonderly, Oklahoma State U (V7 UNIX) Lawrence Woodman Farrell Woods, Concurrent (formerly Masscomp) Dave Woolley, CAP Communication Systems, London Jack Woolley, SCT Corp Frank Wortner Ken Yap, formerly of U of Rochester John Zeeff, Ann Arbor, MI */ #include "ckcker.h" /* Kermit symbols */ #include "ckcnet.h" /* Network symbols */ #ifdef CK_SSL #include "ck_ssl.h" #endif /* CK_SSL */ #include "ckuusr.h" #ifdef OS2ONLY #define INCL_VIO /* Needed for ckocon.h */ #include #include /* for getpid() */ #undef COMMENT #endif /* OS2ONLY */ #ifdef NT #include #include /* for getpid() */ #ifdef CK_TAPI #include #include "ckntap.h" #endif /* CK_TAPI */ int setOSVer(); /* ckotio.c */ int ttgcwsz(); /* ckocon.c */ #ifdef CK_LOGIN VOID setntcreds(); #endif /* CK_LOGIN */ #endif /* NT */ #ifndef NOSERVER /* Text message definitions.. each should be 256 chars long, or less. */ #ifdef MINIX char *srvtxt = "\r\n\ Entering server mode.\r\n\0"; #else #ifdef OLDMSG /* It seems there was a large installation that was using C-Kermit 5A(165) or thereabouts, which had deployed thousands of MS-DOS Kermit scripts in scattered locations that looked for strings in the old server message, which changed in 5A(183), August 1992. */ char *srvtxt = "\r\n\ C-Kermit server starting. Return to your local machine by typing\r\n\ its escape sequence for closing the connection, and issue further\r\n\ commands from there. To shut down the C-Kermit server, issue the\r\n\ FINISH or BYE command and then reconnect.\n\ \r\n\0"; #else #ifdef OSK char *srvtxt = "\r\012\ Entering server mode. If your local Kermit software is menu driven, use\r\012\ the menus to send commands to the server. Otherwise, enter the escape\r\012\ sequence to return to your local Kermit prompt and issue commands from\r\012\ there. Use SEND and GET for file transfer. Use REMOTE HELP for a list of\r\012\ other available services. Use BYE or FINISH to end server mode.\r\012\0"; #else /* UNIX, VMS, AOS/VS, and all others */ char *srvtxt = "\r\n\ Entering server mode. If your local Kermit software is menu driven, use\r\n\ the menus to send commands to the server. Otherwise, enter the escape\r\n\ sequence to return to your local Kermit prompt and issue commands from\r\n\ there. Use SEND and GET for file transfer. Use REMOTE HELP for a list of\r\n\ other available services. Use BYE or FINISH to end server mode.\r\n\0"; #endif /* OSK */ #endif /* OLDMSG */ #endif /* MINIX */ #else /* server mode disabled */ char *srvtxt = ""; #endif /* NOSERVER */ int initflg = 0; /* sysinit() has executed... */ int howcalled = I_AM_KERMIT; /* How I was called */ int hmtopline = 0; int quitting = 0; /* I'm in the act of quitting */ #ifdef IKSDCONF char * iksdconf = IKSDCONF; /* IKSD configuration file */ int iksdcf = 0; /* Has IKSD c.f. been processed? */ #endif /* IKSDCONF */ int srvcdmsg = 0; /* [Server] CD message */ char * cdmsgfile[8] = { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }; char * cdmsgstr = NULL; char * ckcdpath = NULL; #ifdef NLCHAR /* Text-file line terminator */ CHAR feol = NLCHAR; #else CHAR feol = 0; #endif /* NLCHAR */ int fblksiz = DBLKSIZ; /* File blocksize */ int frecl = DLRECL; /* File record length */ int frecfm = XYFF_S; /* File record format (default = stream) */ int forg = XYFO_S; /* File organization (sequential) */ int fcctrl = XYFP_N; /* File carriage control (ctrl chars) */ int filecase = FILECASE; /* Case matters in filenames */ int stathack = 1; /* Fast directory lookups by default */ char uidbuf[UIDBUFLEN] = { NUL, NUL }; /* User ID buffer */ int cfilef = 0; /* Application ("kerbang") file flag */ char cmdfil[CKMAXPATH + 1] = { NUL, NUL }; /* Application file name */ int haveurl = 0; /* URL given on command line */ #ifndef NOXFER /* Multi-protocol support */ struct ck_p ptab[NPROTOS] = { /* Initialize the Kermit part ... */ { "Kermit", DRPSIZ, /* Receive packet size */ DSPSIZ, /* Send packet size */ 0, /* Send-packet-size-set flag */ DFWSIZ, /* Window size */ #ifdef NEWDEFAULTS PX_CAU, /* Control char unprefixing... */ #else PX_ALL, #endif /* NEWDEFAULTS */ #ifdef VMS /* Default filename collision action */ XYFX_X, /* REPLACE for VAX/VMS */ #else XYFX_B, /* BACKUP for everybody else */ #endif /* VMS */ #ifdef OS2 /* Flag for file name conversion */ XYFN_L, /* Literal for OS2 */ #else XYFN_C, /* Converted for others */ #endif /* OS2 */ PATH_OFF, /* Send pathnames OFF */ PATH_AUTO, /* Receive pathnames AUTO */ NULL, /* Host receive initiation string (binary) */ NULL, /* Host receive initiation string (text) */ NULL, /* Host server string */ NULL, /* External protocol send command (binary) */ NULL, /* External protocol send command (text) */ NULL, /* External protocol receive command (bin) */ NULL } /* External protocol receive command (txt) */ #ifdef CK_XYZ , {"XMODEM", 128,128,-1,-1, 1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"XMODEM-CRC",128,128,-1,-1, -1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"YMODEM", -1, -1,-1,-1, -1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"YMODEM-g", -1, -1,-1,-1, -1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"ZMODEM", -1, -1,-1,-1,PX_WIL,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"Other", -1, -1,-1,-1, -1,-1,-1,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL} #endif /* CK_XYZ */ }; /* Declarations for Send-Init Parameters */ int spsiz = DSPSIZ, /* Current packet size to send */ spmax = DSPSIZ, /* Biggest packet size we can send */ lastspmax = DSPSIZ, /* Send-packet size last used */ spsizr = DSPSIZ, /* Send-packet size requested */ spsizf = 0, /* Flag to override size negotiation */ rpsiz = DRPSIZ, /* Biggest we want to receive */ rpsizf = 0, /* Flag to override size negotiation */ urpsiz = DRPSIZ, /* User-requested receive pkt size */ maxrps = MAXRP, /* Maximum incoming long packet size */ maxsps = MAXSP, /* Maximum outbound l.p. size */ maxtry = MAXTRY, /* Maximum retries per packet */ wslots = 1, /* Window size currently in use */ wslotr = DFWSIZ, /* Window size from SET WINDOW */ wslotn = 1, /* Window size negotiated in S-pkt */ timeouts = 0, /* For statistics reporting */ spackets = 0, /* ... */ rpackets = 0, /* ... */ retrans = 0, /* ... */ crunched = 0, /* ... */ wmax = 0, /* ... */ wcur = 0, /* ... */ srvidl = 0, /* Server idle timeout */ srvdis = 1, /* Server file xfer display */ srvtim = DSRVTIM, /* Server command wait timeout */ srvping = 1, /* Server keepalive */ /* timint is the timeout interval I use when waiting for a packet. pkttim is the SET RECEIVE TIMEOUT value, sent to the other Kermit. rtimo is the SET SEND TIMEOUT value. rtimo is the initial value of timint. timint is changed by the value in the incoming negotiation packet unless a SET SEND TIMEOUT command was given. */ timint = DMYTIM, /* Timeout interval I use */ pkttim = URTIME, /* Timeout I want you to use */ rtimo = DMYTIM, /* Normal packet wait timeout */ timef = 0, /* Flag to override what you ask */ #ifdef CK_TIMERS rttflg = 1, /* Use dynamic round-trip timers */ #else rttflg = 0, /* Use fixed timer */ #endif /* CK_TIMERS */ mintime = 1, /* Minimum timeout */ maxtime = 0, /* Maximum timeout */ npad = MYPADN, /* How much padding to send */ mypadn = MYPADN, /* How much padding to ask for */ bctr = DFBCT, /* Block check type requested */ bctu = 1, /* Block check type used */ bctl = 1, /* Block check length */ bctf = 0, /* Block check type 3 forced on all */ c_save = -1, /* Block check saving and restoring */ ss_save = -1, /* Slow-start saving and restoring */ ebq = MYEBQ, /* 8th bit prefix */ ebqflg = 0, /* 8th-bit quoting flag */ rqf = -1, /* Flag used in 8bq negotiation */ rq = 0, /* Received 8bq bid */ sq = 'Y', /* Sent 8bq bid */ rpt = 0, /* Repeat count */ rptq = MYRPTQ, /* Repeat prefix */ rptflg = 0, /* Repeat processing flag */ rptena = 1, /* Repeat processing enabled */ xfrcan = 1, /* Transfer cancellation enabled */ xfrint = 1, /* Transfer interruption enabled */ xfrchr = 3, /* Transfer cancel char = Ctrl-C */ xfrnum = 3, /* Need three of them by default */ g_xfrxla = -1; char * xfrmsg = NULL; /* Message for f.t. display screen */ #endif /* NOXFER */ #ifdef NOCSETS int xfrxla = 0; /* Character-set translation */ #else int xfrxla = 1; /* enabled or disabled */ #endif /* NOCSETS */ int havelfs = 0; /* Large file support available */ #ifndef NOXFER int epktflg = 0; /* E-PACKET command active */ int capas = 9, /* Position of Capabilities */ lpcapb = 2, /* Long Packet capability */ lpcapr = 1, /* requested */ lpcapu = 0, /* used */ swcapb = 4, /* Sliding Window capability */ swcapr = 1, /* requested (allowed) */ swcapu = 0, /* used */ atcapb = 8, /* Attribute capability */ atcapr = 1, /* requested */ atcapu = 0, /* used */ rscapb = 16, /* RESEND capability */ rscapr = 1, /* requested by default */ rscapu = 0, /* used */ lscapb = 32, /* Locking Shift capability */ lscapr = 1, /* requested by default */ lscapu = 0; /* used */ /* Flags for whether to use particular attributes */ int atenci = 1, /* Encoding in */ atenco = 1, /* Encoding out */ atdati = 1, /* Date in */ atdato = 1, /* Date out */ atdisi = 1, /* Disposition in/out */ atdiso = 1, atleni = 1, /* Length in/out (both kinds) */ atleno = 1, atblki = 1, /* Blocksize in/out */ atblko = 1, attypi = 1, /* File type in/out */ attypo = 1, atsidi = 1, /* System ID in/out */ atsido = 1, atsysi = 1, /* System-dependent parameters in/out */ atsyso = 1; int dispos = 0; /* Disposition */ #ifdef CK_PERMS int atlpri = 1, atlpro = 1, atgpri = 1, atgpro = 1; #endif /* CK_PERMS */ int atfrmi = 1, /* Record Format in/out */ atfrmo = 1; #ifdef STRATUS int atcrei = 1, /* Creator ID in/out */ atcreo = 1, atacti = 1, /* Account in/out */ atacto = 1; #endif /* STRATUS */ int sprmlen = -1; /* Send/Receive protocol parameter */ int rprmlen = -1; /* string length limits */ int sendipkts = 1; /* Send I packets */ CHAR padch = MYPADC, /* Padding character to send */ mypadc = MYPADC, /* Padding character to ask for */ seol = MYEOL, /* End-Of-Line character to send */ eol = MYEOL, /* End-Of-Line character to look for */ ctlq = CTLQ, /* Control prefix in incoming data */ myctlq = CTLQ, /* Outbound control character prefix */ myrptq = MYRPTQ; /* Repeat prefix I want to use */ int rptmin = 3; /* Repeat-count minimum */ int usepipes = 0, /* Used for xfer to/from pipes */ g_usepipes = -1; char * filefile = NULL; /* File containing list of filenames */ /* CD message filename list */ char whoareu[16] = { NUL, NUL }; /* System ID of other Kermit */ int sysindex = -1; /* and index to its system ID struct */ int myindex = -1; int wearealike = 0; /* 2 Kermits have compatible sysids */ char * cksysid = /* My system ID */ #ifdef UNIX "U1" #else #ifdef VMS "D7" #else #ifdef OSK "UD" #else #ifdef AMIGA "L3" #else #ifdef MAC "A3" #else #ifdef OS2 #ifdef NT "UN" #else /* NT */ "UO" #endif /* NT */ #else /* OS2 */ #ifdef datageneral "F3" #else #ifdef GEMDOS "K2" #else #ifdef STRATUS "MV" #else "" #endif /* STRATUS */ #endif /* GEMDOS */ #endif /* datageneral */ #endif /* OS2 */ #endif /* MAC */ #endif /* AMIGA */ #endif /* OSK */ #endif /* VMS */ #endif /* UNIX */ ; int oopts = -1; /* O-Packet Options */ int omode = -1; /* O-Packet Transfer Mode */ int oname = -1; /* O-Packet Filename Options */ int opath = -1; /* O-Packet Pathname Options */ struct zattr iattr; /* Incoming file attributes */ #ifdef VMS /* VMS labeled file default options - name only. */ int lf_opts = LBL_NAM; #else #ifdef OS2 /* OS/2 labeled file default options, all attributes but archived. */ unsigned long int lf_opts = LBL_EXT|LBL_HID|LBL_RO|LBL_SYS; #else int lf_opts = 0; #endif /* OS2 */ #endif /* VMS */ /* Packet-related variables */ int pktnum = 0, /* Current packet number */ sndtyp = 0, /* Type of packet just sent */ rcvtyp = 0, /* Type of packet just received */ rsn, /* Received packet sequence number */ rln, /* Received packet length */ size, /* Current size of output pkt data */ osize, /* Previous output packet data size */ maxsize, /* Max size for building data field */ spktl = 0, /* Length packet being sent */ rpktl = 0, /* Length of packet just received */ pktpaus = 0, /* Interpacket pause interval, msec */ rprintf, /* REMOTE PRINT flag */ rmailf, /* MAIL flag */ xferstat = -1, /* Status of last transaction */ filestatus = 0; /* Status of last file transfer */ CHAR pktmsgbuf[PKTMSGLEN+1]; CHAR *epktmsg = pktmsgbuf; #ifdef pdp11 int srvcmdlen = MAXRP; /* srvcmd buffer length */ #else #ifdef DYNAMIC int srvcmdlen = MAXRP; #else int srvcmdlen = 0; #endif /* DYNAMIC */ #endif /* pdp11 */ CHAR #ifdef pdp11 srvcmdbuf[MAXRP+4], *srvcmd = srvcmdbuf, #else #ifdef DYNAMIC *srvcmd = (CHAR *)0, /* Where to decode server command */ #else srvcmdbuf[MAXRP+4], *srvcmd = srvcmdbuf, #endif /* DYNAMIC */ #endif /* pdp11 */ padbuf[96], /* Buffer for send-padding */ *recpkt, *rdatap, /* Pointer to received packet data */ *data = (CHAR *)0, /* Pointer to send-packet data */ *srvptr, /* Pointer to srvcmd */ mystch = SOH, /* Outbound packet-start character */ stchr = SOH; /* Incoming packet-start character */ /* File-related variables */ #ifndef NOMSEND /* Multiple SEND */ struct filelist * filehead = NULL; /* SEND list */ struct filelist * filetail = NULL; struct filelist * filenext = NULL; int addlist = 0; #endif /* NOMSEND */ char filnam[CKMAXPATH + 1]; /* Name of current file. */ char ofilnam[CKMAXPATH + 1]; /* Original name. */ int pipesend = 0; /* Nonzero if sending from pipe */ #ifdef PIPESEND char * sndfilter = NULL; /* Send and receive filters */ char * rcvfilter = NULL; #endif /* PIPESEND */ char ** sndarray = NULL; /* SEND /ARRAY pointer and range */ #ifndef NOSPL int sndxlo = -1, sndxhi = -1, sndxin = -1; #endif /* NOSPL */ #endif /* NOXFER */ #ifndef NOSERVER int ngetpath = 0; /* GET search path */ int fromgetpath = 0; char * getpath[MAXGETPATH]; char * x_user = NULL; /* Server login information */ char * x_passwd = NULL; char * x_acct = NULL; #endif /* NOSERVER */ int x_login = 0; /* Login required */ int x_logged = 0; /* User is logged in */ extern int timelimit; #ifdef CK_LOGIN int logintimo = 300; /* Login timeout */ char * userfile = NULL; /* Forbidden user file */ #endif /* CK_LOGIN */ #ifdef IKSD char * anonfile = NULL; /* Anonymous login init file */ char * anonroot = NULL; /* Anonymous file-system root */ int iks_timo = 300; /* 5 minutes idle timo */ int iks_retry = 3; /* 3 attempts at login */ #endif /* IKSD */ #ifdef CKSYSLOG extern VOID zsyslog(); extern int ckxlogging, ckxsyslog; #endif /* CKSYSLOG */ CK_OFF_T fsize = (CK_OFF_T)0, /* Size of current file */ sendstart = (CK_OFF_T)0, /* SEND start position */ calibrate = (CK_OFF_T)0; /* Nonzero if calibration run */ int nzxopts = 0; /* Options for nzxpand() */ int nfils = 0; /* Number of files in file group */ int wildena = 1; /* Wildcard expansion enabled */ #ifdef UNIX int wildxpand = 0; /* Who expands wildcards, 0=Kermit.. */ #else /* UNIX */ #ifdef STRATUS int wildxpand = 1; /* 1=Shell. */ #endif /* STRATUS */ #endif /* UNIX */ #ifdef UNIXOROSK int matchdot = 0; /* Whether to match dot files */ #else int matchdot = 1; #endif /* UNIXOROSK */ int matchfifo = 0; /* Whether to match FIFO "files" */ int clfils = 0; /* Flag for command-line files */ int stayflg = 0; /* Flag for "stay", i.e. "-S" */ int xfinish = 0; /* Flag for FINISH = EXIT */ long ztusec = -1L; /* Used with ztime() */ long ztmsec = -1L; /* Ditto */ /* Communication device / connection variables */ char ttname[TTNAMLEN+1]; /* Name of communication device */ #ifdef MAC int connected = 0; /* True if connected */ int startconnected; /* initial state of connected */ #endif /* MAC */ long speed = -1L; /* Communication device speed */ int wasclosed = 0; /* Connection was just closed */ int whyclosed = WC_REMO; /* why it was closed */ int qnxportlock = 0; /* QNX port locking on/off */ #ifndef CLSONDISC #define CLSONDISC 0 #endif /* CLSONDISC */ int cxflow[CXT_MAX+1]; /* See initflow() */ #ifndef NOSHOW char * floname[] = { /* Flow control names */ "none", "xon/xoff", "rts/cts", "dtr/cd", "etx/ack", "string", "xxx1", "xxx2", "dtr/cts", "keep", "auto" }; int nfloname = (sizeof(floname) / sizeof(char *)); char * cxname[] = { /* Connection type names */ "remote", "direct-serial", "modem", "tcp/ip", "x.25", "decnet", "lat", "netbios", "named-pipe", "ssh", "pipe" }; int ncxname = (sizeof(cxname) / sizeof(char *)); #endif /* NOSHOW */ int parity = DEFPAR, /* Parity specified, 0,'e','o',etc */ hwparity = 0, /* Hardware parity for serial port */ stopbits = -1, /* Stop bits for serial port */ clsondisc = CLSONDISC, /* Serial port close on disconnect */ autopar = 0, /* Automatic parity change flag */ sosi = 0, /* Shift-In/Out flag */ flow = 0, /* Flow control (see initflow()) */ autoflow = 1, /* Automatic flow control */ turn = 0, /* Line turnaround handshake flag */ turnch = XON, /* Line turnaround character */ duplex = 0, /* Duplex, full by default */ escape = DFESC, /* Escape character for connect */ ckdelay = DDELAY, /* Initial delay before sending */ tnlm = 0; /* Terminal newline mode */ /* Networks for SET HOST */ #ifdef BIGBUFOK #define MYHOSTL 1024 #else #define MYHOSTL 100 #endif /* BIGBUFOK */ char myhost[MYHOSTL]; /* Local host name */ int network = 0; /* Network vs serial connection */ int inserver = 0; /* Running as an Internet server */ int isguest = 0; /* User is anonymous */ char * clienthost = NULL; /* Peer host name or address */ int tcp_incoming = 0; /* Incoming TCP connection? */ #ifdef NETCONN #ifdef TCPSOCKET int nettype = NET_TCPB; /* Default network type */ #else #ifdef SUNX25 int nettype = NET_SX25; #else #ifdef IBMX25 int nettype = NET_IX25; #else #ifdef HPX25 int nettype = NET_HX25; #else #ifdef STRATUSX25 int nettype = NET_VX25; #else #ifdef DECNET int nettype = NET_DEC; #else #ifdef SUPERLAT int nettype = NET_SLAT; #else int nettype = NET_NONE; #endif /* SUPERLAT */ #endif /* DECNET */ #endif /* STRATUSX25 */ #endif /* HPX25 */ #endif /* IBMX25 */ #endif /* SUNX25 */ #endif /* TCPSOCKET */ #else /* NETCONN */ int nettype = NET_NONE; #endif /* NETCONN */ #ifdef ANYX25 int revcall = 0; /* X.25 reverse call not selected */ int closgr = -1; /* X.25 closed user group */ int cudata = 0; /* X.25 call user data not specified */ char udata[MAXCUDATA]; /* X.25 call user data */ #ifdef IBMX25 /* I was unable to find any pre-defined MAX values for x25 addresses - the addresses that I've seen have been around 10-12 characters 32 is probably enough, 64 is hopefully safe for everyone. */ x25addr_t local_nua = {'\0'}; /* local x.25 address */ x25addr_t remote_nua = {'\0'}; /* remote x.25 address */ char x25name[32] = {'\0'}; /* x25 device name, sx25a0 or sx25a1 */ char x25dev[64] = "/dev/x25pkt"; /* x25 device in /dev */ int x25port = 0; /* port used for X.25 - AIX only */ #endif /* IBMX25 */ #ifndef IBMX25 /* This condition is unrelated to the above IBMX25 condition. IBM X.25 doesn't have PAD support. */ CHAR padparms[MAXPADPARMS+1]; /* X.3 parameters */ #endif /* IBMX25 */ #endif /* ANYX25 */ /* Other items */ int isinterrupted = 0; /* Used in exception handling */ int what = W_INIT; /* What I am doing */ int lastxfer = 0; /* Last transfer (send or receive) */ extern int mdmtyp; /* Modem (/network) type */ #ifdef NT extern int StartedFromDialer; #ifdef NTSIG extern int TlsIndex; #endif /* NTSIG */ #ifdef NTASM unsigned long ESPToRestore; /* Ditto */ #endif /* NTASM */ #endif /* NT */ #ifdef OS2PM int os2pm = 0; /* OS/2 Presentation Manager flag */ #endif /* OS2PM */ /* Terminal screen size, if known, -1 means unknown. */ #ifdef OS2 #include "ckocon.h" #ifdef KUI int tt_rows[VNUM] = {24,24,25,1}; /* Rows (height) */ int tt_cols[VNUM] = {80,80,80,80}; /* Columns (width) */ int cmd_rows = 24, cmd_cols = 80; /* Command/console screen dimensions */ #else /* KUI */ int tt_rows[VNUM] = {-1,24,25,1}; /* Rows (height) */ int tt_cols[VNUM] = {-1,80,80,80}; /* Columns (width) */ int cmd_rows = -1, cmd_cols = -1; /* Command/console screen dimensions */ #endif /* KUI */ int k95stdio = 0; /* Stdio threads */ int tt_bell = XYB_AUD | XYB_SYS; /* BELL AUDIBLE (system sounds) */ #else /* OS2 */ int tt_rows = -1; /* Rows (height) */ int tt_cols = -1; /* Columns (width) */ int cmd_rows = 24, cmd_cols = 80; /* Command/console screen dimensions */ int tt_bell = XYB_AUD; /* BELL ON */ #endif /* OS2 */ int tt_print = 0; /* Transparent print disabled */ int tt_escape = 1; /* Escaping back is enabled */ int tt_scroll = 1; /* Scrolling operations are enabled */ int tn_exit = 0; /* Exit on disconnect */ int exitonclose = 0; /* Exit on close */ int exithangup = 1; /* Hangup on exit */ int haveline = 0; /* SET LINE or SET HOST in effect */ int tlevel = -1; /* Take-file command level */ int hints = 1; /* Whether to give hints */ #ifdef NOLOCAL int remonly = 1; /* Remote-mode-only advisory (-R) */ int nolocal = 1; /* Remote-only strictly enforced */ #else int remonly = 0; int nolocal = 0; int cx_status = 0; /* CONNECT return status */ #endif /* NOLOCAL */ #ifndef NOSPL extern int cmdlvl; /* Command level */ extern int maclvl; /* Macro invocation level */ #endif /* NOSPL */ int protocol = PROTO_K; /* File transfer protocol = Kermit */ #ifdef NEWDEFAULTS int prefixing = PX_CAU; #else int prefixing = PX_ALL; #endif /* NEWDEFAULTS */ extern short ctlp[]; /* Control-prefix table */ int carrier = CAR_AUT; /* Pay attention to carrier signal */ int cdtimo = 0; /* Carrier wait timeout */ int xitsta = GOOD_EXIT; /* Program exit status */ #ifdef VMS /* Default filename collision action */ int fncact = XYFX_X; /* REPLACE for VMS */ #else int fncact = XYFX_B; /* BACKUP for everybody else */ #endif /* VMS */ int fncsav = -1; /* For saving & restoring the above */ int bgset = -1; /* BACKGROUND mode set explicitly */ int cmdint = 1; /* Interrupts are allowed */ #ifdef UNIX int xsuspend = DFSUSP; /* Whether SUSPEND command, etc, */ #else /* is to be allowed. */ int xsuspend = 0; #endif /* UNIX */ /* Statistics variables */ CK_OFF_T flci, /* Characters from line, current file */ flco, /* Chars to line, current file */ tlci, /* Chars from line in transaction */ tlco, /* Chars to line in transaction */ ffc, /* Chars to/from current file */ tfc; /* Chars to/from files in transaction */ long filcnt, /* Number of files in transaction */ filrej, /* Number of files rejected in transaction */ cps = 0L, /* Chars/sec last transfer */ peakcps = 0L, /* Peak chars/sec last transfer */ ccu, /* Control chars unprefixed in transaction */ ccp, /* Control chars prefixed in transaction */ rptn; /* Repeated characters compressed */ int tsecs = 0; /* Seconds for transaction */ int fsecs = 0; /* Per-file timer */ #ifdef GFTIMER CKFLOAT fpfsecs = 0.0, /* Floating point per-file timer */ fptsecs = 0.0; /* and per-transaction timer */ #endif /* GFTIMER */ /* Flags */ int deblog = 0, /* Debug log is open */ debok = 1, /* Debug log is not disabled */ debxlen = 54, /* Default length for debug strings */ debses = 0, /* Flag for DEBUG SESSION */ debtim = 0, /* Include timestamp in debug log */ debmsg = 0, /* Debug messages on/off */ pktlog = 0, /* Flag for packet logging */ seslog = 0, /* Session logging */ dialog = 0, /* DIAL logging */ tralog = 0, /* Transaction logging */ tlogfmt = 1, /* Transaction log format (verbose) */ tlogsep = (int)',', /* Transaction log field separator */ displa = 0, /* File transfer display on/off */ stdouf = 0, /* Flag for output to stdout */ stdinf = 0, /* Flag for input from stdin */ xflg = 0, /* Flag for X instead of F packet */ hcflg = 0, /* Doing Host command */ dest = DEST_D, /* Destination for packet data */ zchkod = 0, /* zchko() should work for dirs too? */ zchkid = 0, /* zchki() should work for dirs too? */ #ifdef VMS vms_text = VMSTFS, /* VMS text file dflt fmt: Stream_LF */ #endif /* VMS */ /* If you change this, also see struct ptab above... */ #ifdef OS2 /* Flag for file name conversion */ fncnv = XYFN_L, /* Default is Literal in OS/2, */ f_save = XYFN_L, /* (saved copy of same) */ #else fncnv = XYFN_C, /* elsewhere Convert them */ f_save = XYFN_C, /* (ditto) */ #endif /* OS2 */ fnspath = PATH_OFF, /* Send file path */ fnrpath = PATH_AUTO, /* Receive file path */ fackpath = 1, /* Send back path in ACK to F */ binary = XYFT_B, /* Default file transfer mode */ b_save = XYFT_B, /* Saved file mode */ eofmethod = 0, /* EOF detection method (length) */ #ifdef OS2 cursor_save = -1, /* Cursor state */ #endif /* OS2 */ xfermode = XMODE_A, /* Transfer mode, manual or auto */ xfiletype = -1, /* Transfer only text (or binary) */ recursive = 0, /* Recursive directory traversal */ nolinks = 2, /* Don't follow symbolic links */ skipbup = 0, /* Skip backup files when sending */ sendmode = SM_SEND, /* Which type of SEND operation */ slostart = 1, /* Slow start (grow packet lengths) */ cmask = 0377, /* CONNECT (terminal) byte mask */ fmask = 0377, /* File byte mask */ ckwarn = 0, /* Flag for file warning */ quiet = 0, /* Be quiet during file transfer */ local = 0, /* 1 = local mode, 0 = remote mode */ cxtype = CXT_REMOTE, /* Connection type */ server = 0, /* Flag for I Am Server */ query = 0, /* Flag for Query active */ justone = 0, /* Server should do Just One command */ urserver = 0, /* Flag for You Are Server */ bye_active = 0, /* Flag for BYE command active */ diractive = 0, /* Flag for DIRECTORY command active */ cdactive = 0, /* Flag for CD command active */ cflg = 0, /* Connect before transaction */ cnflg = 0, /* Connect after transaction */ cxseen = 0, /* Flag for cancelling a file */ czseen = 0, /* Flag for cancelling file group */ fatalio = 0, /* Flag for fatal i/o error */ discard = 0, /* Flag for file to be discarded */ keep = SET_AUTO, /* Keep incomplete files = AUTO */ unkcs = 1, /* Keep file w/unknown character set */ #ifdef VMS filepeek = 0, /* Inspection of files */ #else #ifdef datgeneral filepeek = 0, #else filepeek = 1, #endif /* datageneral */ #endif /* VMS */ nakstate = 0, /* In a state where we can send NAKs */ dblchar = -1, /* Character to double when sending */ moving = 0, /* MOVE = send, then delete */ reliable = SET_AUTO, /* Nonzero if transport is reliable */ xreliable = -1, setreliable = 0, urclear = 0, /* Nonzero for clear channel to you */ clearrq = SET_AUTO, /* SET CLEARCHANEL value */ cleared = 0, streaming = 0, /* Nonzero if streaming is active */ streamok = 0, /* Nonzero if streaming negotiated */ streamrq = SET_AUTO, /* SET STREAMING value */ streamed = -1; /* Whether we streamed last time */ char * snd_move = NULL; /* Move file after sending it */ char * snd_rename = NULL; /* Rename file after sending it */ char * rcv_move = NULL; /* Move file after receiving it */ char * rcv_rename = NULL; /* Rename file after receiving it */ char * g_snd_move = NULL; char * g_snd_rename = NULL; char * g_rcv_move = NULL; char * g_rcv_rename = NULL; #ifdef CK_TRIGGER char *tt_trigger[TRIGGERS] = { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }; CHAR *tt_trmatch[TRIGGERS] = { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }; char *triggerval = NULL; #endif /* CK_TRIGGER */ int ckxlogging = 0; /* Flag for syslogging active */ int ikdbopen = 0; /* Flag for IKSD database active */ int dbinited = 0; /* Flag for IKSDB record init'd */ #ifndef CKSYSLOG int ckxsyslog = 0; /* Logging level 0 */ #else #ifdef SYSLOGLEVEL int ckxsyslog = SYSLOGLEVEL; /* Logging level specified */ #else int ckxsyslog = SYSLG_DF; /* Default logging level */ #endif /* SYSLOGLEVEL */ #endif /* CKSYSLOG */ #ifndef NOHELP #ifndef NOCMDL _PROTOTYP( VOID iniopthlp, (void) ); /* Command-line help initializer */ #endif /* NOCMDL */ #endif /* NOHELP */ _PROTOTYP( VOID initfloat, (void) ); /* Floating-point initializer */ _PROTOTYP( VOID makever, (void) ); _PROTOTYP( VOID getexedir, (void) ); _PROTOTYP( int putnothing, (char) ); #ifdef IKSD _PROTOTYP( VOID doiksdinit, (void) ); _PROTOTYP( VOID iksdinit, (void) ); _PROTOTYP( VOID doiklog, (void) ); _PROTOTYP( int dbinit, (void) ); #endif /* IKSD */ /* Variables passed from command parser to protocol module */ #ifndef NOSPL #ifndef NOICP #ifdef CK_APC _PROTOTYP( VOID apconect, (void) ); #endif /* CK_APC */ #ifdef OS2 extern int initvik; #endif /* OS2 */ #endif /* NOICP */ #endif /* NOSPL */ char *clcmds = NULL; /* Pointer to command-line commands */ #ifndef NOSETKEY extern KEY *keymap; extern MACRO *macrotab; #endif /* NOSETKEY */ #ifndef NOPUSH int nopush = 0; /* PUSH enabled */ #else int nopush = 1; /* PUSH disabled */ #endif /* NOPUSH */ CHAR sstate = (CHAR) 0; /* Starting state for automaton */ CHAR zstate = (CHAR) 0; /* For remembering sstate */ char * printername = NULL; /* NULL if printer not redirected */ int printpipe = 0; /* For SET PRINTER */ int noprinter = 0; #ifndef NOXFER char *cmarg = ""; /* Pointer to command data */ char *cmarg2 = ""; /* Pointer to 2nd command data */ char **cmlist; /* Pointer to file list in argv */ #ifdef CK_AUTODL /* Autodownload */ int autodl = 1; /* Enabled by default */ #else int autodl = 0; /* (or if not implemented). */ #endif /* CK_AUTODL */ int adl_err = 1; /* 1 = stop on error */ #ifdef KUI int adl_ask = 1; /* 1 = file dialog on autodownload */ #else int adl_ask = 0; /* 0 = no file dialog */ #endif /* KUI */ #ifdef OS2 /* AUTODOWNLOAD parameters */ int adl_kmode = ADL_PACK, /* Match Packet to signal download */ adl_zmode = ADL_PACK; char * adl_kstr = NULL; /* KERMIT Download String */ char * adl_zstr = NULL; /* ZMODEM Download String */ #endif /* OS2 */ int remfile = 0, rempipe = 0, remappd = 0; /* REMOTE output redirection */ char * remdest = NULL; #ifndef NOSERVER /* Server services: 0 = disabled 1 = enabled in local mode 2 = enabled in remote mode 3 = enabled in both local and remote modes only as initial (default) values. */ int en_xit = 2; /* EXIT */ int en_cwd = 3; /* CD/CWD */ int en_cpy = 3; /* COPY */ int en_del = 2; /* DELETE */ int en_mkd = 3; /* MKDIR */ int en_rmd = 2; /* RMDIR */ int en_dir = 3; /* DIRECTORY */ int en_fin = 3; /* FINISH */ int en_get = 3; /* GET */ #ifndef NOPUSH int en_hos = 2; /* HOST enabled */ #else int en_hos = 0; /* HOST disabled */ #endif /* NOPUSH */ int en_ren = 3; /* RENAME */ int en_sen = 3; /* SEND */ int en_set = 3; /* SET */ int en_spa = 3; /* SPACE */ int en_typ = 3; /* TYPE */ int en_who = 3; /* WHO */ #ifdef datageneral /* Data General AOS/VS can't do this */ int en_bye = 0; /* BYE */ #else int en_bye = 2; /* PCs in local mode... */ #endif /* datageneral */ int en_asg = 3; /* ASSIGN */ int en_que = 3; /* QUERY */ int en_ret = 2; /* RETRIEVE */ int en_mai = 3; /* MAIL */ int en_pri = 3; /* PRINT */ int en_ena = 3; /* ENABLE */ #else int en_xit = 0, en_cwd = 0, en_cpy = 0, en_del = 0, en_mkd = 0, en_rmd = 0, en_dir = 0, en_fin = 0, en_get = 0, en_hos = 0, en_ren = 0, en_sen = 0, en_set = 0, en_spa = 0, en_typ = 0, en_who = 0, en_bye = 0, en_asg = 0, en_que = 0, en_ret = 0, en_mai = 0, en_pri = 0, en_ena = 0; #endif /* NOSERVER */ #endif /* NOXFER */ /* Miscellaneous */ char **xargv; /* Global copies of argv */ int xargc; /* and argc */ int xargs; /* an immutable copy of argc */ char *xarg0; /* and of argv[0] */ char *pipedata; /* Pointer to -P (pipe) data */ extern char *dftty; /* Default tty name from ck?tio.c */ extern int dfloc; /* Default location: remote/local */ extern int dfprty; /* Default parity */ extern int dfflow; /* Default flow control */ #ifdef TNCODE extern int tn_deb; #endif /* TNCODE */ /* Buffered file input and output buffers. See getpkt() in ckcfns.c and zoutdump() in the system-dependent file i/o module (usually ck?fio.c). */ #ifndef DYNAMIC /* Now we allocate them dynamically, see getiobs() at bottom. */ char zinbuffer[INBUFSIZE], zoutbuffer[OBUFSIZE]; #else char *zinbuffer = NULL, *zoutbuffer = NULL; #endif /* DYNAMIC */ char *zinptr, *zoutptr; int zincnt, zoutcnt; int zobufsize = OBUFSIZE; int zofbuffer = 1; int zofblock = 1; #ifdef SESLIMIT int seslimit = 0; #endif /* SESLIMIT */ #ifdef CK_AUTHENTICATION #include "ckuath.h" #endif /* CK_AUTHENTICATION */ _PROTOTYP( int getiobs, (VOID) ); /* M A I N -- C-Kermit main program */ #include #ifndef NOCCTRAP #include #include "ckcsig.h" ckjmpbuf cmjbuf; #ifdef GEMDOS /* Special for Atari ST */ cc_clean(); /* This can't be right? */ #endif /* GEMDOS */ #endif /* NOCCTRAP */ #ifdef TIMEH /* This had to be added for NetBSD 6.1 - it might have "effects" elsewhere */ /* Tue Sep 3 17:03:42 2013 */ #include #endif /* TIMEH */ #include "ckcfnp.h" /* Prototypes (must be last) */ #ifndef NOXFER /* Info associated with a system ID */ struct sysdata sysidlist[] = { /* Add others as needed... */ { "0", "anonymous", 0, NUL, 0, 0, 0 }, { "A1", "Apple II", 0, NUL, 0, 0, 3 }, /* fix this */ { "A3", "Macintosh", 1, ':', 0, 2, 1 }, { "D7", "VMS", 0, ']', 1, 0, 0 }, { "DA", "RSTS/E", 0, ']', 1, 0, 3 }, /* (i think...) */ { "DB", "RT11", 0, NUL, 1, 0, 3 }, /* (maybe...) */ { "F3", "AOS/VS", 1, ':', 0, 0, 2 }, { "I1", "VM/CMS", 0, NUL, 0, 0, 0 }, { "I2", "MVS/TSO", 0, NUL, 0, 0, 0 }, { "I4", "MUSIC", 0, NUL, 0, 0, 0 }, { "I7", "CICS", 0, NUL, 0, 0, 0 }, { "I9", "MVS/ROSCOE", 0, NUL, 0, 0, 0 }, { "K2", "Atari ST", 1, '\\', 1, 0, 3 }, { "L3", "Amiga", 1, '/', 1, 0, 2 }, { "MV", "Stratus VOS", 1, '>', 0, 1, 0 }, { "N3", "Apollo Aegis", 1, '/', 0, 3, 2 }, { "U1", "UNIX", 1, '/', 0, 3, 2 }, { "U8", "MS-DOS", 1, '\\', 1, 0, 3 }, { "UD", "OS-9", 1, '/', 0, 3, 2 }, { "UN", "MS-Windows", 1, '\\', 1, 2, 3 }, { "UO", "OS/2", 1, '\\', 1, 2, 3 } }; static int nxxsysids = (sizeof(sysidlist) / sizeof(struct sysdata)); /* Given a Kermit system ID code, return the associated name string */ /* and some properties of the filenames... */ char * #ifdef CK_ANSIC getsysid( char *s ) /* Get system-type name */ #else getsysid(s) char * s; #endif /* CK_ANSIC */ { int i; if (!s) return(""); for (i = 0; i < nxxsysids; i++) if (!strcmp(sysidlist[i].sid_code,s)) return(sysidlist[i].sid_name); return(s); } int #ifdef CK_ANSIC getsysix(char *s) #else getsysix(s) char *s; #endif /* CK_ANSIC */ { /* Get system-type index */ int i; if (!s) return(-1); for (i = 0; i < nxxsysids; i++) if (!strcmp(sysidlist[i].sid_code,s)) return(i); return(-1); } #endif /* NOXFER */ /* Tell if a pathname is absolute (versus relative) */ /* This should be parceled out to each of the ck*fio.c modules... */ /* VMS isabsolute() is now in ckvfio.c. */ #ifndef VMS int #ifdef CK_ANSIC isabsolute( char * path ) #else isabsolute(path) char * path; #endif /* CK_ANSIC */ { int rc = 0; int x; if (!path) return(0); if (!*path) return(0); x = (int) strlen(path); debug(F111,"isabsolute",path,x); #ifdef UNIX if (*path == '/' #ifdef DTILDE || *path == '~' #endif /* DTILDE */ ) rc = 1; #else /* def UNIX */ #ifdef OS2 if (*path == '/' || *path == '\\') rc = 1; else if (isalpha(*path) && x > 2) if (*(path+1) == ':' && (*(path +2) == '/' || *(path+2) == '\\')) rc = 1; #else /* def OS2 */ #ifdef AMIGA if (*path == '/' #ifdef DTILDE || *path == '~' #endif /* DTILDE */ ) rc = 1; #else /* def AMIGA */ #ifdef OSK if (*path == '/' #ifdef DTILDE || *path == '~' #endif /* DTILDE */ ) rc = 1; #else /* def OSK */ #ifdef datageneral if (*path == ':') rc = 1; #else /* def datageneral */ #ifdef MAC rc = 0; /* Fill in later... */ #else /* def MAC */ #ifdef STRATUS rc = 0; /* Fill in later... */ #else /* def STRATUS */ #ifdef GEMDOS if (*path == '/' || *path == '\\') rc = 1; else if (isalpha(*path) && x > 1) if (*(path+1) == ':') rc = 1; #endif /* GEMDOS */ #endif /* STRATUS */ #endif /* MAC */ #endif /* datageneral */ #endif /* OSK */ #endif /* AMIGA */ #endif /* OS2 */ #endif /* UNIX */ debug(F101,"isabsolute rc","",rc); return(rc); } #endif /* ndef VMS */ /* See if I have direct access to the keyboard */ int #ifdef CK_ANSIC is_a_tty( int n ) #else is_a_tty(n) int n; #endif /* CK_ANSIC */ { #ifdef UNIX extern int ttfdflg; if (ttfdflg > 0) return(1); #endif /* UNIX */ #ifdef KUI return 1; #else /* KUI */ #ifdef NT if (isWin95()) return(1); else return(_isatty(n)); #else #ifdef IKSD if (inserver) return(1); else #endif /* IKSD */ return(isatty(n)); #endif /* NT */ #endif /* KUI */ } #ifndef NOXFER #ifdef CK_ANSIC void initxlist( void ) #else VOID initxlist() #endif /* CK_ANSIC */ { extern char * sndexcept[], * rcvexcept[]; int i; for (i = 0; i < NSNDEXCEPT; i++) { sndexcept[i] = NULL; rcvexcept[i] = NULL; } } #endif /* NOXFER */ /* Initialize flow control table */ #ifdef CK_ANSIC void initflow( void ) #else VOID initflow() #endif /* CK_ANSIC */ { /* Default values for flow control */ #ifdef VMS /* for each kind of connection. */ /* The VMS telnet terminal driver treats "none" as request to lose chars */ cxflow[CXT_REMOTE] = FLO_XONX; /* Remote mode... */ #else #ifdef HPUX /* Ditto for HP-UX */ cxflow[CXT_REMOTE] = FLO_XONX; /* Remote mode... */ #else /* The temptation is to make this one FLO_KEEP but don't!!! */ /* It totally wrecks binary-file transfer when coming in via Telnet. */ /* In UNIX at least... */ cxflow[CXT_REMOTE] = FLO_NONE; #endif /* HPUX */ #endif /* VMS */ #ifdef VMS cxflow[CXT_DIRECT] = FLO_XONX; /* Direct serial connections... */ #else cxflow[CXT_DIRECT] = FLO_NONE; #endif /* VMS */ #ifdef CK_RTSCTS cxflow[CXT_MODEM] = FLO_RTSC; /* Modem connections... */ #else #ifdef VMS cxflow[CXT_MODEM] = FLO_XONX; #else cxflow[CXT_MODEM] = FLO_NONE; #endif /* VMS */ #endif /* CK_RTSCTS */ #ifdef VMS cxflow[CXT_TCPIP] = FLO_XONX; /* TCP/IP connections... */ #else cxflow[CXT_TCPIP] = FLO_NONE; #endif /* VMS */ cxflow[CXT_SSH] = FLO_NONE; cxflow[CXT_X25] = FLO_NONE; /* Other kinds of networks... */ cxflow[CXT_DECNET] = FLO_XONX; cxflow[CXT_LAT] = FLO_XONX; cxflow[CXT_NETBIOS] = FLO_NONE; cxflow[CXT_NPIPE] = FLO_NONE; cxflow[CXT_PIPE] = FLO_NONE; flow = cxflow[cxtype]; /* Initial flow setting. */ debug(F101,"initflow","",flow); } #ifndef NOXFER /* Initialize file transfer protocols */ VOID #ifdef CK_ANSIC initproto( int y, char * upbstr, char * uptstr, char * srvstr, char * sndbstr, char * sndtstr, char * rcvbstr, char * rcvtstr ) #else initproto(y, upbstr, uptstr, srvstr, sndbstr, sndtstr, rcvbstr, rcvtstr) int y; char * upbstr, * uptstr, * srvstr, * sndbstr, * sndtstr, * rcvbstr, * rcvtstr; #endif /* CK_ANSIC */ /* initproto */ { if (upbstr) /* Convert null strings */ if (!*upbstr) /* to null pointers */ upbstr = NULL; if (uptstr) /* Convert null strings */ if (!*uptstr) /* to null pointers */ uptstr = NULL; if (sndbstr) if (!*sndbstr) sndbstr = NULL; if (sndtstr) if (!*sndtstr) sndtstr = NULL; if (rcvbstr) if (!*rcvbstr) rcvbstr = NULL; if (rcvtstr) if (!*rcvtstr) rcvtstr = NULL; if (srvstr) if (!*srvstr) srvstr = NULL; protocol = y; /* Set protocol */ if (ptab[protocol].rpktlen > -1) urpsiz = ptab[protocol].rpktlen; if (ptab[protocol].spktflg > -1) spsizf = ptab[protocol].spktflg; if (ptab[protocol].spktlen > -1) { spsiz = ptab[protocol].spktlen; debug(F101,"initproto spsiz","",spsiz); if (spsizf) { spsizr = spmax = spsiz; debug(F101,"initproto spsizr","",spsizr); } } if (ptab[protocol].winsize > -1) wslotr = ptab[protocol].winsize; if (ptab[protocol].prefix > -1) prefixing = ptab[protocol].prefix; if (ptab[protocol].fnca > -1) fncact = ptab[protocol].fnca; if (ptab[protocol].fncn > -1) fncnv = ptab[protocol].fncn; if (ptab[protocol].fnsp > -1) fnspath = ptab[protocol].fnsp; if (ptab[protocol].fnrp > -1) fnrpath = ptab[protocol].fnrp; makestr(&(ptab[protocol].h_b_init),upbstr); makestr(&(ptab[protocol].h_t_init),uptstr); makestr(&(ptab[protocol].h_x_init),srvstr); makestr(&(ptab[protocol].p_b_scmd),sndbstr); makestr(&(ptab[protocol].p_t_scmd),sndtstr); makestr(&(ptab[protocol].p_b_rcmd),rcvbstr); makestr(&(ptab[protocol].p_t_rcmd),rcvtstr); } #endif /* NOXFER */ #ifndef NOCMDL VOID #ifdef CK_ANSIC docmdline(void * threadinfo) #else /* CK_ANSIC */ docmdline(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ { #ifdef NTSIG setint(); if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); debug( F100, "docmdline called with threadinfo block", "", 0 ); } else debug( F100, "docmdline threadinfo is NULL","",0); #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef NT #ifdef IKSD if (inserver) setntcreds(); #endif /* IKSD */ #endif /* NT */ #endif /* CK_LOGIN */ proto(); /* Take any requested action, then */ if (!quiet) /* put cursor back at left margin, */ conoll(""); #ifndef NOLOCAL if (cnflg) { /* Re-connect if requested */ cnflg = 0; doconect(0,0); if (ttchk() < 0) dologend(); } #endif /* NOLOCAL */ #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } #ifdef CK_ANSIC void ikslogin ( void ) #else VOID ikslogin ( ) #endif /* CK_ANSIC */ { if (sstelnet #ifdef IKSD || inserver /* Internet server */ #endif /* IKSD */ ) { char *s; extern int fdispla; /* File-transfer display format */ extern char * ikprompt; /* IKSD prompt */ #ifdef IKSD #ifdef CK_LOGIN if (inserver) { x_login = 1; /* Login required */ x_logged = 0; /* Not logged in yet */ cmsetp(ikprompt); /* Set up IKSD's prompt */ #ifndef NOSERVER en_mai = 0; /* MAIL is disabled */ en_who = 0; /* REMOTE WHO is disabled */ en_hos = 0; /* REMOTE HOST is disabled */ en_pri = 0; /* PRINT is disabled */ #endif /* NOSERVER */ } else { x_login = 0; /* Login not required */ x_logged = 1; /* Already logged in */ } #endif /* CK_LOGIN */ #endif /* IKSD */ nolocal = 1; /* SET LINE/HOST not allowed */ fdispla = XYFD_N; /* No file-transfer display */ #ifdef IKSD clienthost = ckgetpeer(); /* Get client's hostname */ debug(F110,"ikslogin clienthost",clienthost,0); #endif /* IKSD */ ztime(&s); /* Get current date and time */ #ifdef CK_LOGIN #ifdef CK_AUTHENTICATION if (x_login) { x_logged = ck_tn_auth_valid(); /* Did Telnet Auth succeed? */ debug(F111,"ikslogin","x_logged",x_logged); #ifdef NT /* On Windows 9x, we do not have the ability in */ /* zvuser() at present to determine if the name */ /* approved in a Kerberos principal is really a */ /* an account in the Windows Access Control List */ if (isWin95() && x_logged == AUTH_VALID && (ck_tn_authenticated() != AUTHTYPE_NTLM) #ifdef CK_SRP && (ck_tn_authenticated() != AUTHTYPE_SRP) #endif /* CK_SRP */ ) { auth_finished(AUTH_USER); x_logged = AUTH_USER; printf("WARNING:\r\n"); printf( " The Telnet authentication method used cannot provide for automated\r\n"); printf( " login to Windows 95 or Windows 98. A password must be entered\r\n"); printf( " locally to validate your userid. Telnet authentication (and encryption)\r\n" ); printf( " can be used to validate the host (and protect the privacy of your password.)\ \r\n" ); } #endif /* NT */ if (x_logged == AUTH_VALID) { #ifdef CK_SSL if ((ssl_active_flag || tls_active_flag) && (!TELOPT_U(TELOPT_AUTHENTICATION) || ck_tn_authenticated() == AUTHTYPE_NULL || ck_tn_authenticated() == AUTHTYPE_AUTO) ) { #ifdef SSL_KRB5 if (tls_is_krb5(0)) { printf("Authenticated using Kerberos 5\r\n"); #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_LI && ckxlogging) { extern char szUserNameAuthenticated[]; cksyslog(SYSLG_LI, 1, "AUTH_VALID", "Kerberos 5", szUserNameAuthenticated ); } #endif /* CKSYSLOG */ } else #endif /* SSL_KRB5 */ { printf("Authenticated using X.509 certificate\r\n"); #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_LI && ckxlogging) { extern char szUserNameAuthenticated[]; cksyslog(SYSLG_LI, 1, "AUTH_VALID", "X.509 certificate", szUserNameAuthenticated ); } #endif /* CKSYSLOG */ } } else #endif /* CK_SSL */ { printf("Authenticated using %s\r\n", AUTHTYPE_NAME(ck_tn_authenticated())); #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_LI && ckxlogging) { extern char szUserNameAuthenticated[]; cksyslog(SYSLG_LI, 1, "AUTH_VALID", AUTHTYPE_NAME(ck_tn_authenticated()), szUserNameAuthenticated ); } #endif /* CKSYSLOG */ } zvuser(uidbuf); if (zvpass("") == 0) x_logged = 0; } else if (x_logged == AUTH_USER && !strcmp(uidbuf,"anonymous")) { extern char szUserNameAuthenticated[]; zvuser(uidbuf); debug(F110,"szUserNameAuthenticated", szUserNameAuthenticated,0); if (zvpass(szUserNameAuthenticated) == 0) { /* Anonymous login failed. Force a username prompt. */ x_logged = 0; uidbuf[0] = '\0'; } else { #ifdef CK_SSL if ((ssl_active_flag || tls_active_flag) && (!TELOPT_U(TELOPT_AUTHENTICATION) || ck_tn_authenticated() == AUTHTYPE_NULL || ck_tn_authenticated() == AUTHTYPE_AUTO)) { printf("Authenticated using X.509 certificate\r\n"); #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_LI && ckxlogging) { extern char szUserNameAuthenticated[]; cksyslog(SYSLG_LI, 1, "AUTH_USER", "X.509 certificate", szUserNameAuthenticated ); } #endif /* CKSYSLOG */ } else #endif /* CK_SSL */ { printf("Authenticated using %s\r\n", AUTHTYPE_NAME(ck_tn_authenticated()) ); #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_LI && ckxlogging) { cksyslog(SYSLG_LI, 1, "AUTH_USER", AUTHTYPE_NAME(ck_tn_authenticated()), szUserNameAuthenticated ); } #endif /* CKSYSLOG */ } } } else { #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_LI && ckxlogging && x_logged == AUTH_USER) { extern char szUserNameAuthenticated[]; cksyslog(SYSLG_LI, 1, "AUTH_USER", AUTHTYPE_NAME(ck_tn_authenticated()), szUserNameAuthenticated ); } #endif /* CKSYSLOG */ x_logged = 0; if (!strcmp("(unknown)",uidbuf) #ifdef NT || !stricmp("administrator",uidbuf) #ifdef UNIX || !strcmp("root",uidbuf) #else #ifdef Plan9 || !strcmp("root",uidbuf) #else #ifdef OSK || !strcmp("root",uidbuf) #endif /* OSK */ #endif /* Plan9 */ #endif /* UNIX */ #endif /* NT */ ) uidbuf[0] = '\0'; } } #endif /* CK_AUTHENTICATION */ #endif /* CK_LOGIN */ #ifdef IKSD if (inserver) printf("\r\nInternet Kermit Service ready at %s%s\r\n",s,versio); else #endif /* IKSD */ printf("\r\nC-Kermit ready at %s%s\r\n",s,versio); if (*myhost) printf("%s\r\n", myhost); printf("\r\n"); } #ifdef CK_LOGIN #ifdef IKSD if (inserver) { int i; extern int arg_x; /* Flag for '-x' on command line */ #ifndef NOSPL extern struct mtab *mactab; /* For ON_LOGIN macro. */ extern int nmac; #endif /* NOSPL */ debug(F110,"MAIN clienthost",clienthost,0); srvidl = timelimit = logintimo; /* For interactive login */ rtimer(); /* Reset timer */ for (i = 0; i < iks_retry && !x_logged; i++) { /* Count retries */ if (gtimer() > logintimo) break; #ifdef TNCODE tn_wait("login loop"); tn_push(); #endif /* TNCODE */ debug(F101,"MAIN LOGIN try","",i); what = W_NOTHING; /* Because proto() changes this */ #ifdef IKS_OPTION debug(F111,"MAIN LOGIN", "TELOPT_SB(TELOPT_KERMIT).kermit.me_start", TELOPT_SB(TELOPT_KERMIT).kermit.me_start ); /* Kermit server negotiated */ if (TELOPT_SB(TELOPT_KERMIT).kermit.me_start) { debug(F101,"IKSD starting in server mode","",0); arg_x = 1; /* Enter server mode */ sstate = 'x'; #ifdef IKSDPOPBACK justone = 1; /* Execute one command at a time. */ #endif /* IKSDPOPBACK */ proto(); /* Enter protocol if requested. */ #ifdef NTSIG ck_ih(); #endif /* NTSIG */ if (x_logged) /* Logged in */ break; } else { /* Not in client/server mode */ #endif /* IKS_OPTION */ debug(F101,"IKSD starting with Username prompt","",0); x_logged = ckxlogin((CHAR *)uidbuf,NULL,NULL,1); if (sstate) { /* Received a packet at prompt */ #ifdef IKSDPOPBACK justone = 1; /* Go handle it */ #endif /* IKSDPOPBACK */ proto(); } if (!x_logged) { /* In case we are at the prompt... */ printf("Access denied.\n"); uidbuf[0] = '\0'; /* Forget the name if we have one */ } #ifdef IKS_OPTION } #endif /* IKS_OPTION */ } srvidl = timelimit = iks_timo; /* Reset command timelimit */ debug(F101,"MAIN LOGIN","",x_logged); if (!x_logged) { /* Logins failed. */ if (TELOPT_SB(TELOPT_KERMIT).kermit.me_start) errpkt((CHAR *)"Login Timeout"); msleep(500); doexit(BAD_EXIT,0); } what = W_NOTHING; /* Stay in known state */ #ifndef NOSERVER if (isguest) { en_pri = 0; /* No printing for anonymous users */ en_mai = 0; /* No email for anonymous users */ en_mkd = 0; /* Or directory creation */ en_rmd = 0; /* Or directory removal */ en_ena = 0; /* Or ENABLing DISABLEd items */ } #endif /* NOSERVER */ #ifndef NOSPL /* If a macro named "on_login" is defined, execute it. Also remove it from the macro table so the user cannot see what it does. Execute it as part of the iksd.conf file. */ if (nmac) { /* Any macros defined? */ int k; /* Yes */ char * cmd = "on_login"; /* MSVC 2.x compiler error */ k = mlook(mactab,cmd,nmac); /* Look up "on_login" */ if (k >= 0) { /* If found, */ #ifdef IKSDCONF int saved = iksdcf; iksdcf = 0; #endif /* IKSDCONF */ if (dodo(k,"",0) > -1) /* set it up, */ parser(1); /* execute it */ #ifdef IKSDCONF iksdcf = saved; #endif /* IKSDCONF */ delmac(cmd,1); /* and delete it */ } } #endif /* NOSPL */ } /* if (inserver) */ #else /* CK_LOGIN */ #ifdef IKSD if (inserver) srvidl = timelimit = iks_timo; /* Set idle limits for IKS */ #endif /* IKSD */ #endif /* CK_LOGIN */ #endif /* IKSD */ } VOID #ifdef CK_ANSIC failcmdline(void * foo) #else /* CK_ANSIC */ failcmdline(foo) VOID * foo; #endif /* CK_ANSIC */ { #ifdef GEMDOS cc_clean(); #endif /* GEMDOS */ #ifndef NOLOCAL if (cnflg) doconect(0,0); /* connect again if requested. */ if (ttchk() < 0) dologend(); #endif /* NOLOCAL */ } #endif /* NOCMDL */ #ifndef NOICP VOID #ifdef CK_ANSIC dotakeini(void * threadinfo) /* Execute init file. */ #else /* CK_ANSIC */ dotakeini(threadinfo) VOID * threadinfo; /* Execute init file. */ #endif /* CK_ANSIC */ /* dotakeini */ { #ifdef NTSIG setint(); if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); debug(F100, "dotakeini called with threadinfo block","", 0); } else debug(F100, "dotakeini - threadinfo is NULL", "", 0); #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef NT #ifdef IKSD if (inserver) setntcreds(); #endif /* IKSD */ #endif /* NT */ #endif /* CK_LOGIN */ cmdini(); /* Sets tlevel */ debug(F111,"dotakeini","inserver",inserver); debug(F111,"dotakeini","sstelnet",sstelnet); #ifdef COMMENT /* Wrong place for this... */ #ifndef NOXFER #ifdef CK_FAST dofast(); /* By now FAST defaults should be OK */ #endif /* CK_FAST */ #endif /* NOXFER */ #endif /* COMMENT */ doinit(); /* Now do the initialization file */ debug(F101,"main executing init file","",tlevel); while (tlevel > -1) { sstate = (CHAR) parser(1); /* Execute one command at a time. */ if (sstate) proto(); /* Enter protocol if requested. */ #ifdef NTSIG ck_ih(); #endif /* NTSIG */ } debug(F101,"main exits init file","",tlevel); #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } VOID #ifdef CK_ANSIC failtakeini(void * threadinfo) #else /* CK_ANSIC */ failtakeini(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ /* failtakeini */ { #ifdef GEMDOS cc_clean(); /* Atari: Clean up after ^C-trap. */ #endif /* GEMDOS */ fixcmd(); if (!cfilef) { conoll("Interrupted during initialization or \ command-line processing."); conoll("C-Kermit quitting..."); } doexit(BAD_EXIT,-1); /* Exit with bad status. */ } VOID #ifdef CK_ANSIC doicp(void * threadinfo) #else /* CK_ANSIC */ doicp(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ /* doicp */ { #ifdef NTSIG setint(); if (threadinfo) { /* Thread local storage... */ if (!TlsSetValue(TlsIndex,threadinfo)) debug(F101,"doicp TlsSetValue failed","",GetLastError()); debug(F101, "doicp a threadinfo block - TlsIndex", "", TlsIndex); } else { debug(F100, "doicp received a null threadinfo", "", 0); } #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef NT #ifdef IKSD if (inserver) setntcreds(); #endif /* IKSD */ #endif /* NT */ #endif /* CK_LOGIN */ #ifdef MAC while (1) { extern char *lfiles; /* Fake pointer cast */ if (connected) { debug(F100, "doicp: calling macparser", "", 0); sstate = newparser(1, 1, 0L); /* ignore null command state */ if (sstate == 'n') sstate = '\0'; if (sstate) proto(); } else { /* * process take files the finder gave us. */ if ((tlevel == -1) && lfiles) startlfile(); debug(F100, "doicp: calling parser", "", 0); sstate = (CHAR) parser(0); if (sstate == 'c') /* if MAC connect */ sstate = 0; if (sstate) proto(); } } #else /* Not MAC */ #ifndef NOSPL /* If interactive commands were given on the command line (using the -C "command, command, ..." option), assign them to a macro called "cl_commands", then execute the macro and leave it defined for subsequent re-execution if desired. */ if (clcmds) { /* Check for -C commands */ int x; x = addmac("cl_commands",clcmds); /* Put macro in table */ if (x > -1) { /* If successful, */ dodo(x,NULL,CF_CMDL); /* set up for macro execution */ while (maclvl > -1) { /* Loop getting macro commands. */ sstate = (CHAR) parser(1); if (sstate) proto(); /* Enter protocol if requested. */ #ifdef NTSIG ck_ih(); #endif /* NTSIG */ } } } #endif /* NOSPL */ while(1) { /* Loop getting commands. */ sstate = (CHAR) parser(0); if (sstate) proto(); /* Enter protocol if requested. */ #ifdef NTSIG ck_ih(); #endif /* NTSIG */ } #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ #endif /* MAC */ } VOID #ifdef CK_ANSIC failicp(void * threadinfo) #else /* CK_ANSIC */ failicp(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ { #ifdef GEMDOS cc_clean(); #endif /* GEMDOS */ fixcmd(); /* Pop command stacks, etc. */ clcmds = NULL; debug(F100,"ckcmai got interrupt","",0); } #endif /* NOICP */ #ifndef NOICP VOID #ifdef CK_ANSIC docmdfile(void * threadinfo) /* Execute application file */ #else /* CK_ANSIC */ docmdfile(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ /* docmdfile */ { #ifdef NTSIG concb((char)escape); setint(); if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); debug(F100, "docmdfile called with threadinfo block","", 0); } else debug(F100, "docmdfile - threadinfo is NULL", "", 0); #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef IKSD #ifdef NT if (inserver) setntcreds(); #endif /* NT */ #endif /* IKSD */ #endif /* CK_LOGIN */ debug(F110,"main cmdfil",cmdfil,0); #ifndef NOSPL addmac("\\%0",cmdfil); #endif /* NOSPL */ dotake(cmdfil); /* Set up the command file */ if (tlevel > -1) /* Remember we did this */ cfilef = 1; while (tlevel > -1) { /* Execute it until it runs out. */ sstate = parser(1); /* Loop getting commands. */ if (sstate) proto(); /* Enter protocol if requested. */ #ifdef NTSIG ck_ih(); #endif /* NTSIG */ } #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ return; } VOID #ifdef CK_ANSIC failcmdfile(void * threadinfo) #else /* CK_ANSIC */ failcmdfile(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ /* failcmdfile */ { #ifdef GEMDOS cc_clean(); /* Atari: Clean up after ^C-trap. */ #endif /* GEMDOS */ fixcmd(); if (!cfilef) { conoll("Interrupted during initialization or \ command-line processing."); conoll("C-Kermit quitting..."); } doexit(BAD_EXIT,-1); /* Exit with bad status. */ } #endif /* NOICP */ #ifndef NOXFER #ifdef CK_ANSIC /* Initial control-char prefixing */ void setprefix ( int z ) #else VOID setprefix(z) int z; #endif /* CK_ANSIC */ { #ifdef CK_SPEED int i, val; prefixing = z; ptab[protocol].prefix = prefixing; debug(F101,"setprefix","",prefixing); switch (z) { case PX_ALL: /* All */ #ifdef COMMENT /* Don't let Clear-Channel be dependent on prefixing */ clearrq = 0; /* Turn off clearchannel, fall thru */ #endif /* COMMENT */ case PX_NON: /* None */ val = (z == PX_ALL) ? 1 : 0; for (i = #ifdef UNPREFIXZERO 0 #else 1 #endif /* UNPREFIXZERO */ ; i < 32; i++) ctlp[i] = val; for (i = 127; i < 160; i++) ctlp[i] = val; ctlp[(unsigned)255] = val; if (z == PX_NON) { /* These are never safe */ if (network) { /* Assume network = telnet or rlogin */ ctlp[CK_CR] = 1; /* Prefix CR because of NVT rules */ ctlp[XON] = ctlp[XOFF] = 1; /* Because of Telnet server */ ctlp[127] = ctlp[255] = 1; /* Telnet IAC */ ctlp[mystch] = ctlp[mystch+128] = 1; /* Kermit packet start */ } else { ctlp[CK_CR] = ctlp[255] = ctlp[mystch] = ctlp[mystch+128] = 1; if (flow == FLO_XONX) /* Xon/Xoff forces prefixing */ ctlp[XON] = ctlp[XOFF] = ctlp[XON+128] = ctlp[XOFF+128] = 1; } } break; case PX_CAU: /* Cautious or Minimal */ #ifdef COMMENT /* Don't let CLEAR-CHANNEL be dependent on Prefixing */ clearrq = 0; /* Turn off clearchannel */ #endif /* COMMENT */ case PX_WIL: /* Minimal ("wild") */ ctlp[0] = 1; /* Does not include 0 */ for (i = 1; i < 32; i++) ctlp[i] = 0; for (i = 127; i < 160; i++) ctlp[i] = 0; ctlp[mystch] = ctlp[mystch+128] = 1; /* Kermit start of packet */ if (seol != 13) ctlp[seol] = ctlp[seol+128] = 1; /* Kermit end */ ctlp[13] = ctlp[141] = 1; /* In case of TELNET (NVT rules) */ ctlp[(unsigned)255] = 1; /* Ditto */ /* ^D, ^J, ^M, or ^U followed by tilde trigger Rlogin escape */ ctlp[4] = ctlp[4+128] = 1; /* In case of RLOGIN */ ctlp[10] = ctlp[10+128] = 1; /* In case of RLOGIN */ ctlp[21] = ctlp[21+128] = 1; /* In case of RLOGIN */ if (flow == FLO_XONX || /* Xon/Xoff forces prefixing these */ prefixing == PX_CAU || /* So does CAUTIOUS */ network) /* Networks too... */ ctlp[XON] = ctlp[XOFF] = ctlp[XON+128] = ctlp[XOFF+128] = 1; if (prefixing == PX_CAU) { /* Cautious - add some more */ #ifdef UNPREFIXZERO ctlp[0] = 1; #endif /* UNPREFIXZERO */ ctlp[3] = ctlp[16] = 1; /* ^C, DLE */ ctlp[14] = ctlp[15] = 1; /* SO/SI */ ctlp[24] = ctlp[25] = 1; /* VMS might need these */ ctlp[26] = ctlp[26+128] = 1; /* UNIX suspend */ ctlp[28] = ctlp[29] = ctlp[30] = 1; /* Assorted esc chars */ ctlp[131] = ctlp[141] = ctlp[144] = 1; /* and 8-bit versions */ ctlp[(unsigned)255] = ctlp[156] = ctlp[157] = ctlp[158] = 1; } break; } #endif /* CK_SPEED */ } #endif /* NOXFER */ #define MAXHERALDLEN 200 char myherald[MAXHERALDLEN+2]; /* for \v(herald) */ char myoptions[MAXHERALDLEN]; /* and extra bits like SSL etc */ #ifdef CK_ANSIC /* Make version string from pieces */ void makever ( void ) #else VOID makever ( ) #endif /* CK_ANSIC */ { extern int noherald, backgrd; extern char * ckxsys; int x, y; char * ssl; /* These moved from herald() */ char * krb4; char * krb5; char * b64; #ifdef OS2 ck_s_xver = ck_s_k95ver; ck_l_xver = ck_l_k95ver; ck_s_name = ck_s_k95name; #else /* OS2 */ ck_l_xver = ck_l_ver; #endif /* OS2 */ x = strlen(ck_s_name); y = strlen(ck_s_ver); if (y + x + 1 < CKVERLEN) { ckmakmsg(versio,CKVERLEN,ck_s_name," ",ck_s_xver,NULL); } else { ckstrncpy(versio,"C-Kermit",CKVERLEN); return; } x += y + 1; if (*ck_s_who) { y = strlen(ck_s_who); if (CKVERLEN < x + y + 1) return; ckstrncat(versio,"-",CKVERLEN); ckstrncat(versio,ck_s_who,CKVERLEN); } x += y + 1; y = strlen(ck_s_test); if (y > 0 && y + x + 1 < CKVERLEN) { ckstrncat(versio," ",CKVERLEN); ckstrncat(versio,ck_s_test,CKVERLEN); x += y + 1; y = strlen(ck_s_tver); if (y > 0 && y + x + 1 < CKVERLEN) { ckstrncat(versio,".",CKVERLEN); ckstrncat(versio,ck_s_tver,CKVERLEN); x += y + 1; } } y = strlen(ck_s_date); if (y > 0 && y + x + 2 < CKVERLEN) { ckstrncat(versio,", ",CKVERLEN); ckstrncat(versio,ck_s_date,CKVERLEN); } vernum = ck_l_ver; xvernum = ck_l_xver; debug(F110,"makever Kermit version",versio,0); #ifdef COMMENT /* The following generates bad code in SCO compilers. */ /* Observed in both OSR5 and Unixware 2 -- after executing this */ /* statement when all conditions are false, x has a value of -32. */ if (noherald || quiet || bgset > 0 || (bgset != 0 && backgrd != 0)) x = 1; #else x = 0; if (noherald || quiet) x = 1; else if (bgset > 0) x = 1; else if (bgset < 0 && backgrd > 0) x = 1; #endif /* COMMENT */ ssl = ""; krb4 = ""; krb5 = ""; #ifdef CK_64BIT b64 = " (64-bit)"; #else b64 = ""; #endif /* CK_64BIT */ #ifndef OS2 #ifdef CK_AUTHENTICATION #ifdef CK_SSL ssl = "+SSL"; #endif /* CK_SSL */ #ifdef KRB4 krb4 = "+KRB4"; #endif /* KRB4 */ #ifdef KRB5 krb5 = "+KRB5"; #endif /* KRB5 */ #endif /* CK_AUTHENTICATION */ #endif /* OS2 */ if (x == 0) { extern char *ck_s_name; extern char *ck_s_ver; ckmakxmsg(myherald, /* for \v(herald) */ MAXHERALDLEN, versio, ", for", ckxsys, ssl, krb4, krb5, b64, "", "", "", "", ""); } } union ck_short shortbytes; /* For determining byte order */ int byteorder = 0; /* 0 = Big Endian; 1 = Little Endian */ int bigendian = 1; /* NOTE: MUST BE 0 or 1 - nothing else */ #ifndef NOSPL #define SCRIPTLEN 10240 #endif /* NOSPL */ #ifdef NETCONN #ifndef NOTCPIP #ifndef NOCMDL #ifndef NOURL #ifdef CK_ANSIC VOID dourl( void ) #else VOID dourl() #endif /* CK_ANSIC */ { int rc = 0; char * port = NULL; extern int ttnproto; extern struct urldata g_url; #ifdef COMMENT /* NOTE: debug() doesn't work here - must use printf's */ printf("URL: %s\n",g_url.sav ? g_url.sav : "(none)"); printf("Type: %s\n",g_url.svc ? g_url.svc : "(none)"); printf("User: %s\n",g_url.usr ? g_url.usr : "(none)"); printf("Pass: %s\n",g_url.psw ? g_url.psw : "(none)"); printf("Host: %s\n",g_url.hos ? g_url.hos : "(none)"); /* printf("Port: %s\n",g_url.por ? g_url.por : "(none)"); */ printf("Path: %s\n",g_url.pth ? g_url.pth : "(none)"); #endif /* COMMENT */ if (!ckstrcmp(g_url.svc,"iksd",-1,0) || !ckstrcmp(g_url.svc,"kermit",-1,0)) { extern char pwbuf[]; extern int pwflg; #ifdef OS2 extern int pwcrypt; #endif /* OS2 */ if (!g_url.hos) { printf("?Incomplete IKSD URL\n"); doexit(BAD_EXIT,1); } if (!g_url.usr) makestr(&g_url.usr,"anonymous"); if (!g_url.psw) { char * tmpbuf = NULL; if (!(tmpbuf = (char *)malloc(1024))) fatal("dourl: out of memory"); if (!ckstrcmp(g_url.usr,"anonymous",-1,0)) { ckmakmsg(tmpbuf,1024,uidbuf,"@",myhost,NULL); makestr(&g_url.psw,tmpbuf); } else { readpass(" Password:",tmpbuf,1024); makestr(&g_url.psw,tmpbuf); } free(tmpbuf); } port = "kermit"; ttnproto = NP_TELNET; nettype = NET_TCPB; mdmtyp = -nettype; local = -1; ckstrncpy(uidbuf,g_url.usr,UIDBUFLEN); if (g_url.psw) { ckstrncpy(pwbuf,g_url.psw,PWBUFL); pwflg = 1; #ifdef OS2 pwcrypt = 0; #endif /* OS2 */ } ckmakmsg(ttname, TTNAMLEN, g_url.hos, ":", g_url.por ? g_url.por : port, NULL ); rc = ttopen(ttname,&local,mdmtyp,0); if (rc > -1) { network = 1; exitonclose = 1; #ifdef CKLOGDIAL dolognet(); #endif /* CKLOGDIAL */ } else { printf("?Connection failed: %s\n",g_url.sav); doexit(BAD_EXIT,1); } /* Also need to check here for secure authentication already done */ #ifdef NOSPL cflg = 1; #else { char * script = NULL; if (!(script = (char *)malloc(SCRIPTLEN))) fatal("dourl: out of memory"); if (!g_url.pth) { /* Write the appropriate script */ cflg = 1; ckmakxmsg(script,SCRIPTLEN, "if not eq {\\v(authstate)} {user} ", "if not eq {\\v(authstate)} {valid} { ", "remote login ", /* No path */ g_url.usr, /* Just log in and CONNECT */ " ", g_url.psw, ", if fail exit 1 {IKSD login failed} }", ", connect", NULL,NULL,NULL,NULL); /* printf("CLCMDS 1: %s\n",script); */ } else { /* does the path specify a file or a directory? */ int len = strlen(g_url.pth); if (ISDIRSEP(g_url.pth[len-1])) { ckmakxmsg(script,SCRIPTLEN, /* Directory name given */ "if not eq {\\v(authstate)} {user} \ if not eq {\\v(authstate)} {valid} { remote login ", g_url.usr, " ", g_url.psw, ", if fail exit 1 {IKSD login failed} }", ", set macro error on", ", set xfer displ brief", ", set xfer bell off", ", remote cd ", g_url.pth, ", lineout directory", ", connect" ); /* printf("CLCMDS 2: %s\n",script); */ } else { ckmakxmsg(script,SCRIPTLEN, /* Path given, try to GET */ "if not eq {\\v(authstate)} {user} \ if not eq {\\v(authstate)} {valid} { remote login ", g_url.usr, " ", g_url.psw, ", if fail exit 1 {IKSD login failed} }", ", set xfer displ brief", ", set xfer bell off", ", get ", g_url.pth, ", .rc := \\v(status)", ", if open connection bye", ", exit \\m(rc)" ); /* printf("CLCMDS 2: %s\n",script); */ } } clcmds = script; /* Make this our -C cmdline macro */ /* printf("HAVEURL=%d\n",haveurl); */ } #endif /* NOSPL */ } else { if (ckstrcmp(g_url.svc,"telnet",-1,0) && #ifdef SSHBUILTIN ckstrcmp(g_url.svc,"ssh",-1,0) && #endif /* SSHBUILTIN */ ckstrcmp(g_url.svc,"ftp",-1,0)) { printf("?Sorry, %s URLs not supported\n", g_url.svc ? g_url.svc : ""); doexit(BAD_EXIT,1); } } } #endif /* NOURL */ #endif /* NOCMDL */ #endif /* NOTCPIP */ #endif /* NETCONN */ /* main()... What is its name and what does it return? 03 May 2023: This is a major restructuring of the main routine declaration. All the complicated multilevel #ifdefs that have been here for decades were moved to the new C-Kermit 10.0 prototypes header, ckcfnp.h, which #defines MAINNAME and typedefs MAINTYPE. If when building C-Kermit you get a complaint about main()'s return type, edit MAINTYPE section ckcfnp.h. If you get "Attempt to return a value from a function of type void" then add -DMAINISVOID to the make command line. */ MAINTYPE #ifdef CK_ANSIC MAINNAME( int argc, char ** argv ) #else MAINNAME( argc, argv ) int argc; char **argv; #endif /* CK_ANSIC */ { char *p; #ifndef NOSETKEY int i; #endif /* NOSETKEY */ #ifdef datageneral short *pfha = 016000000036; /* Get around LANG_RT problem */ *pfha = (short) 0; /* No user protection fault handler */ #endif /* datageneral */ #ifdef UNIX int unbuf = 0; /* nonzero for unbuffered stdout */ /* setbuf has to be called on the file descriptor before it is used */ #ifdef NONOSETBUF /* Unbuffered console i/o */ unbuf++; /* as a compile-time option */ #endif /* NONOSETBUF */ if (!unbuf) { /* Or as a command-line selection */ int i, n; /* We have to pre-pre-scan for */ char * s; /* this one. */ for (i = 1; i < argc; i++) { s = argv[i]; if (!s) n = 0; else n = (int)strlen(s); if (n > 4) { if (!ckstrcmp("--unbuffered",s,n,0)) { unbuf++; break; } } } } if (unbuf) setbuf(stdout,NULL); #endif /* UNIX */ { /* Get OFF_T size for printf - fdc 06 Jan 2024 */ extern int offtsize; /* MUST be executed, which is why it's here */ short x1 = 1; int x2 = 2; long x3 = 3; CK_OFF_T x4 = 4; debug(F101,"sizeof short","",sizeof(x1)); debug(F101,"sizeof int","",sizeof(x2)); debug(F101,"sizeof long","",sizeof(x3)); debug(F101,"sizeof CK_OFF_T","",sizeof(x4)); offtsize = x4; debug(F101,"main offtsize","",offtsize); } /* Do some initialization */ #ifdef VMS #ifdef __DECC /* Get some RMS default settings. */ get_rms_defaults(); #endif /* def __DECC */ #endif /* def VMS */ #ifndef MAC xargc = xargs = argc; /* Make global copies of argc */ xargv = argv; /* ...and argv. */ xarg0 = argv[0]; #ifdef NT setOSVer(); #endif /* NT */ zstrip(argv[0],&p); /* Get name we were invoked with */ makestr(&myname,p); if (!ckstrcmp(myname,"telnet",-1,0)) howcalled = I_AM_TELNET; #ifdef CK_KERBEROS else if (!ckstrcmp(myname,"ktelnet",-1,0)) howcalled = I_AM_TELNET; #endif /* CK_KERBEROS */ else if (!ckstrcmp(myname,"rlogin",-1,0)) howcalled = I_AM_RLOGIN; else if (!ckstrcmp(myname,"iksd",-1,0)) howcalled = I_AM_IKSD; #ifdef NEWFTP else if (!ckstrcmp(myname,"ftp",-1,0)) howcalled = I_AM_FTP; #endif /* NEWFTP */ #ifndef NOHTTP else if (!ckstrcmp(myname,"http",-1,0)) howcalled = I_AM_HTTP; #endif /* NOHTTP */ #ifdef OS2 else if (!ckstrcmp(myname,"telnet.exe",-1,0)) howcalled = I_AM_TELNET; #ifdef SSHBUILTIN else if (!ckstrcmp(myname,"ssh",-1,0)) howcalled = I_AM_SSH; else if (!ckstrcmp(myname,"ssh.exe",-1,0)) howcalled = I_AM_SSH; #endif /* SSHBUILTIN */ #ifdef CK_KERBEROS else if (!ckstrcmp(myname,"ktelnet.exe",-1,0)) howcalled = I_AM_TELNET; #endif /* CK_KERBEROS */ else if (!ckstrcmp(myname,"rlogin.exe",-1,0)) howcalled = I_AM_RLOGIN; #ifdef NT else if (!ckstrcmp(myname,"iksdnt",-1,0)) howcalled = I_AM_IKSD; else if (!ckstrcmp(myname,"iksdnt.exe",-1,0)) howcalled = I_AM_IKSD; #endif /* NT */ #ifdef NEWFTP else if (!ckstrcmp(myname,"ftp.exe",-1,0)) howcalled = I_AM_FTP; #endif /* NEWFTP */ #ifndef NOHTTP else if (!ckstrcmp(myname,"http.exe",-1,0)) howcalled = I_AM_HTTP; #endif /* NOHTTP */ #endif /* OS2 */ else if (!ckstrcmp(myname,"kermit-sshsub",-1,0)) howcalled = I_AM_SSHSUB; #ifndef NOICP cmdini(); /* Must come before prescan */ debug(F100,"main cmdini() done","",0); #endif /* NOICP */ prescan(0); /* Pre-Check for debugging, etc */ #endif /* MAC */ debug(F101,"MAIN feol","",feol); makever(); /* Put together version strings */ #ifndef NOSPL { char scratch[TMPBUFSIZ]; extern char *tempdir; /* Initialize temporary directory */ char * tp = scratch; int x = TMPBUFSIZ; (void) zzstring("\\v(tmpdir)",&tp,&x); /* Expand builtin variable */ makestr(&tempdir,scratch); } #endif /* NOSPL */ #ifndef NOSETKEY /* Allocate & initialize the keymap */ /* This code was moved to before sysinit() for K95G */ if (!(keymap = (KEY *) malloc(sizeof(KEY)*KMSIZE))) fatal("main: no memory for keymap"); if (!(macrotab = (MACRO *) malloc(sizeof(MACRO)*KMSIZE))) fatal("main: no memory for macrotab"); for (i = 0; i < KMSIZE; i++) { keymap[i] = (KEY) i; macrotab[i] = NULL; } #endif /* NOSETKEY */ shortbytes.x_short = 0xABCD; /* Get Endianness */ if (shortbytes.x_char[0] == 0xCD) { /* 0 = Big Endian */ byteorder = 1; /* 1 = Little Endian */ bigendian = 0; /* (for clarity in programming) */ } else { byteorder = 0; /* Big Endian */ bigendian = 1; } if (sizeof(CK_OFF_T) == 8) /* Large files and ints? */ havelfs = 1; if (sysinit() < 0) /* System-dependent initialization. */ fatal("Can't initialize!"); else initflg = 1; /* Remember we did. */ #ifdef HAVE_LOCALE setlocale(LC_ALL, ""); /* Enable using non-C locales */ #endif /* HAVE_LOCALE */ debug(F111,"ckcmai myname",myname,howcalled); { /* Get home directory path */ char *h; _PROTOTYP( char * homedir, (void) ); h = homepath(); if (h) ckstrncpy(homedirpath,h,CKMAXPATH); } #ifdef GETEXEDIR getexedir(); /* Compute exedir variable */ #endif /* def GETEXEDIR */ #ifdef CKSYSLOG #ifdef SYSLOGLEVEL /* If built with -DSYSLOGLEVEL on cc command line, this means we always do syslogging at the indicated level. */ zsyslog(); /* Open syslog */ #else /* SYSLOGLEVEL */ #ifdef IKSD if (inserver) zsyslog(); /* Open syslog */ #endif /* IKSD */ #endif /* SYSLOGLEVEL */ #endif /* CKSYSLOG */ #ifdef CK_KERBEROS ini_kerb(); /* Initialize Kerberos data */ #endif /* CK_KERBEROS */ #ifdef CK_SSL ssl_once_init(); #endif /* CK_SSL */ #ifdef TNCODE tn_set_modes(); /* Init Telnet Option tables */ #endif /* TNCODE */ #ifdef CK_TTGWSIZ /* Initialize screen dimensions */ #ifdef OS2 ttgcwsz(); #else /* OS2 */ if (ttgwsiz() > 0) { if (tt_rows > 0 && tt_cols > 0) { cmd_rows = tt_rows; cmd_cols = tt_cols; } } #endif /* OS2 */ #endif /* CK_TTGWSIZ */ #ifndef OS2 #ifdef TCPSOCKET #ifdef CK_SOCKS SOCKSinit(argv[0]); /* Internet relay package... */ #endif /* CK_SOCKS */ #endif /* TCPSOCKET */ #endif /* OS2 */ initflow(); /* Initialize flow-control table */ #ifndef NOSPL #ifdef CKFLOAT initfloat(); /* Deduce floating-point precision */ #endif /* CKFLOAT */ #endif /* NOSPL */ #ifndef NOXFER initxlist(); /* Init exception lists */ #ifdef CK_XYZ /* Initialize protocols... */ #ifdef XYZ_INTERNAL /* XYZMODEM are internal ... */ #ifdef COMMENT /* Can't do this for XMODEM because if filename contains a "C" etc... */ initproto(PROTO_X, "rx %s","rx %s", NULL, NULL, NULL, NULL, NULL); initproto(PROTO_XC,"rc %s","rc %s", NULL, NULL, NULL, NULL, NULL); #else /* COMMENT */ initproto(PROTO_X, NULL, NULL, NULL, NULL, NULL, NULL, NULL); initproto(PROTO_XC,NULL, NULL, NULL, NULL, NULL, NULL, NULL); #endif /* COMMENT */ initproto(PROTO_Y, "rb","rb", NULL, NULL, NULL, NULL, NULL); initproto(PROTO_G, "rb","rb", NULL, NULL, NULL, NULL, NULL); initproto(PROTO_Z, "rz","rz", NULL, NULL, NULL, NULL, NULL); initproto(PROTO_K,"kermit -ir","kermit -r","kermit -x",NULL,NULL,NULL,NULL); /* Kermit Must be last */ #else /* XYZMODEM are external protocols ... */ /* s1 s2 s3 s4 s5 s6 s7 */ initproto(PROTO_X, "rx %s","rx %s",NULL,"sx %s","sx -a %s","rx %s", "rx %s"); initproto(PROTO_XC,"rc %s","rc %s",NULL,"sx %s","sx -a %s","rc %s", "rc %s"); initproto(PROTO_Y, "rb", "rb", NULL,"sb %s","sb -a %s","rb", "rb" ); initproto(PROTO_G, "rb", "rb", NULL,"sb %s","sb -a %s","rb", "rb" ); initproto(PROTO_Z, "rz", "rz", NULL,"sz %s","sz -a %s","rz", "rz" ); initproto(PROTO_K, "kermit -ir","kermit -r","kermit -x",NULL,NULL,NULL,NULL); /* Kermit must be last */ #endif /* XYZ_INTERNAL */ #else /* No XYZMODEM support */ initproto(PROTO_K,"kermit -ir","kermit -r","kermit -x",NULL,NULL,NULL,NULL); #endif /* CK_XYZ */ #endif /* NOXFER */ connoi(); /* Console interrupts off */ #ifndef NOXFER #ifdef OS2 /* Initialize Kermit and Zmodem Auto-Download Strings */ adl_kstr = strdup("KERMIT READY TO SEND..."); adl_zstr = strdup("rz\r"); #endif /* OS2 */ #ifdef PATTERNS initpat(); /* Initialize filename patterns */ #endif /* PATTERNS */ #endif /* NOXFER */ #ifndef NOCSETS initcsets(); /* Initialize character sets */ #endif /* NOCSETS */ #ifndef NOICP #ifdef DFCDMSG makestr(&cdmsgstr,DFCDMSG); makelist(cdmsgstr,cdmsgfile,8); /* Initialize CD message filenames */ #endif /* DFCDMSG */ #endif /* NOICP */ sstate = 0; /* No default start state. */ #ifdef DYNAMIC if (getiobs() < 0) fatal("Can't allocate i/o buffers!"); #endif /* DYNAMIC */ #ifndef NOSPL #ifndef NORANDOM { char stackdata[256]; unsigned int c = 1234, n; /* try to make a random unsigned int to feed srand() */ c = time(NULL); /* Get current time */ c *= getpid(); /* multiply it by our PID */ /* Referenced before set... DELIBERATELY */ for (n = 0; n < sizeof(stackdata); n++) /* IGNORE WARNING */ c += stackdata[n]; /* DELIBERATELY USED BEFORE SET */ srand((unsigned int)c); } #endif /* NORANDOM */ #endif /* NOSPL */ ckhost(myhost,MYHOSTL); /* Name of local host */ debug(F110,"main ckhost",myhost,0); #ifdef IKSD if (!inserver) { #endif /* IKSD */ ckstrncpy(ttname,dftty,TTNAMLEN); /* Set up default tty name. */ local = nolocal ? 0 : dfloc; /* And whether it's local or remote. */ parity = dfprty; /* Set initial parity, */ #ifndef NOXFER myindex = getsysix(cksysid); /* System index */ #endif /* NOXFER */ if (local) if (ttopen(ttname,&local,0,0) < 0) { #ifndef OS2 conol("Can't open device: "); conoll(ttname); #endif /* OS2 */ local = 0; ckstrncpy(ttname,CTTNAM,TTNAMLEN); } setflow(); /* Set appropriate flow control */ speed = ttgspd(); /* Get transmission speed. */ #ifdef IKSD } #endif /* IKSD */ #ifdef ANYX25 /* All X.25 implementations */ #ifndef IBMX25 /* except IBM have PAD support */ initpad(); /* Initialize X.25 PAD */ #endif /* IBMX25 */ #endif /* ANYX25 */ #ifndef NOXFER if (inibufs(SBSIZ,RBSIZ) < 0) /* Allocate packet buffers */ fatal("Can't allocate packet buffers!"); #ifndef NOCKSPEED setprefix(prefixing); /* Set up control char prefixing */ #endif /* NOCKSPEED */ #endif /* NOXFER */ #ifndef NOTCPIP #ifndef NOICP if (sstelnet #ifdef IKSD || inserver #endif /* IKSD */ ) { extern int ckxech, ttnet, ttnproto, cmdmsk; #ifdef SO_SNDBUF extern int tcp_sendbuf; #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF extern int tcp_recvbuf; #endif /* SO_RCVBUF */ #ifdef SO_KEEPALIVE extern int tcp_keepalive; #endif /* SO_KEEPALIVE */ #ifdef SO_LINGER extern int tcp_linger, tcp_linger_tmo; #endif /* SO_LINGER */ #ifdef SO_DONTROUTE extern int tcp_dontroute; #endif /* SO_DONTROUTE */ #ifdef TCP_NODELAY extern int tcp_nodelay; #endif /* TCP_NODELAY */ #ifdef IKSD extern int iklogopen; #endif /* IKSD */ extern int ttmdm; #ifdef UNIX if (isatty(0)) fatal("Internet Kermit Service cannot be started at a terminal."); #endif /* UNIX */ reliable = xreliable = SET_ON; /* IKSD has reliable connection */ #ifndef VMS flow = 0; /* No flow control needed */ #endif /* VMS */ bgset = 0; /* Not in background */ nopush = 1; /* No external processes */ parity = 0; /* 8 bits ... */ cmdmsk = 0xff; /* all the way */ cmask = 0xff; #ifdef IKSD if (inserver) { /* If IKSD */ doiksdinit(); /* Execute IKSD configuration file */ while (tlevel > -1) parser(1); /* (Ignore any file-xfer commands) */ iksdcf = 1; /* IKSD c.f. has been processed */ } if (!iklogopen) (VOID) doiklog(); /* Open Kermit-specific log */ #endif /* IKSD */ #ifdef UNIX setbuf(stdout,NULL); /* Don't buffer the output */ ckstrncpy(ttname,"0",TTNAMLEN); /* not "/dev/tty"... */ #endif /* UNIX */ local = 0; /* We are in remote mode */ ckxech = 1; /* We will echo */ #ifdef OS2 nettype = NET_TCPB; /* So ttopen() treats the connection */ mdmtyp = -nettype; /* as a network */ #endif /* OS2 */ debug(F100,"main about to call ttopen() inserver","",0); if (ttopen(ttname,&local,mdmtyp,0) < 0) { /* Open comm channel */ fatal("can't initialize i/o"); } #ifdef OS2 local = 0; network = 1; /* Does use networking code */ #else /* OS2 */ network = 0; /* Does not use networking code */ #endif /* OS2 */ ttmdm = -1; /* Does not use a modem */ sstelnet = 1; /* Do server-side Telnet negotations */ debug(F111,"MAIN","sstelnet",sstelnet); ttnet = NET_TCPB; /* Network type is TCP sockets */ ttnproto = NP_TELNET; /* Netword protocol is Telnet */ #ifdef IKSDB dbinit(); /* Initialize database record */ #endif /* IKSDB */ #ifndef OS2 #ifdef CK_AUTHENTICATION /* Before initializating Telnet/Rlogin negotiations, init Kerberos */ ck_auth_init(ckgetpeer(),"","",0); #endif /* CK_AUTHENTICATION */ #ifdef NON_BLOCK_IO { int on, x; on = 1; x = socket_ioctl(0,FIONBIO,&on); debug(F101,"main FIONBIO","",x); } #endif /* NON_BLOCK_IO */ #ifdef SO_OOBINLINE { int on, x; on = 1; x = setsockopt(0,SOL_SOCKET,SO_OOBINLINE,(char *)&on,sizeof(on)); debug(F101,"main SO_OOBINLINE","",x); } #endif /* SO_OOBINLINE */ #ifndef NOTCPOPTS #ifndef datageneral #ifdef SOL_SOCKET #ifdef TCP_NODELAY no_delay(0,tcp_nodelay); #endif /* TCP_NODELAY */ #ifdef SO_KEEPALIVE keepalive(0,tcp_keepalive); #endif /* SO_KEEPALIVE */ #ifdef SO_LINGER ck_linger(0,tcp_linger, tcp_linger_tmo); #endif /* SO_LINGER */ #ifdef SO_DONTROUTE dontroute(0,tcp_dontroute); #endif /* SO_DONTROUTE */ #ifdef SO_SNDBUF sendbuf(0,tcp_sendbuf); #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF recvbuf(0,tcp_recvbuf); #endif /* SO_RCVBUF */ #endif /* SOL_SOCKET */ #endif /* datageneral */ #endif /* NOTCPOPTS */ #ifdef CK_SSL if (ck_ssleay_is_installed()) { if (!ssl_tn_init(SSL_SERVER)) { if (bio_err != NULL) { BIO_printf(bio_err,"do_ssleay_init() failed\r\n"); ERR_print_errors(bio_err); } else { fflush(stderr); fprintf(stderr,"do_ssleay_init() failed\r\n"); ERR_print_errors_fp(stderr); } switch (ttnproto) { case NP_SSL: case NP_TLS: case NP_SSL_RAW: case NP_TLS_RAW: case NP_SSL_TELNET: case NP_TLS_TELNET: doexit(BAD_EXIT,1); } /* otherwise we will continue to accept the connection */ /* without SSL or TLS support unless required. */ if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU ) TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF; if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU ) TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF; if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU ) TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF; if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU ) TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF; } else { if ( ck_ssl_incoming(0) < 0 ) { doexit(BAD_EXIT,1); } } } #endif /* CK_SSL */ #ifdef TNCODE tn_ini(); /* Start Telnet negotiation now */ #endif /* TNCODE */ #endif /* OS2 */ } #endif /* NOTCPIP */ debug(F101,"main argc after prescan()","",argc); /* Now process any relevant environment variables */ #ifndef NODIAL getdialenv(); /* Dialing */ #ifdef NETCONN ndinit(); /* Initialize network directory info */ getnetenv(); /* Network directories */ #endif /* NETCONN */ #endif /* NODIAL */ #ifndef NOXFER #ifdef CK_FAST dofast(); /* By now FAST defaults should be OK */ #endif /* CK_FAST */ #endif /* NOXFER */ #ifndef NOCMDL #ifdef CK_LOGIN #ifdef IKSD ikslogin(); /* IKSD Login and other stuff */ #ifdef NT if ( inserver ) setntcreds(); #endif /* NT */ #endif /* IKSD */ #endif /* CK_LOGIN */ #endif /* NOCMDL */ if (howcalled == I_AM_SSHSUB) { reliable = 1; /* We say the connection is reliable */ xreliable = 1; /* And that we said it was */ setreliable = 1; /* And pretend the "user" did too */ xfinish = 1; /* For REMOTE HELP response */ mdmtyp = 0; /* For ttopen() */ ckstrncpy(ttname,"0",TTNAMLEN+1); /* Use file descriptor 0 */ local = 0; /* And force remote mode */ ttopen(ttname,&local,mdmtyp,0); /* Open the "connection" */ sstate = 'x'; /* Initial state is Server */ proto(); /* Enter protocol */ doexit(GOOD_EXIT,xitsta); /* Exit when done */ } debug(F111,"howcalled",myname,howcalled); #ifndef NOICP #ifdef NOCCTRAP dotakeini(0); #else /* NOCCTRAP */ debug(F100,"main about to cc_execute","",0); setint(); cc_execute( ckjaddr(cmjbuf), dotakeini, failtakeini ); #endif /* NOCCTRAP */ #endif /* NOICP */ debug(F111,"main 2 cfilef",cmdfil,cfilef); if (cmdfil[0]) { /* If we got one (see prescan())... */ #ifndef NOICP #ifdef NOCCTRAP docmdfile(0); /* execute it. */ #else /* NOCCTRAP */ setint(); cc_execute( ckjaddr(cmjbuf), docmdfile, failcmdfile ); #endif /* NOCCTRAP */ #endif /* NOICP */ } #ifndef OS2 /* Preserve name so we can delete it */ *cmdfil = '\0'; /* Done, nullify the file name */ #endif /* OS2 */ #endif /* NOICP */ #ifndef NOCMDL /* Look for a UNIX-style command line... */ what = W_NOTHING; debug(F101,"main argc","",argc); #ifndef NOHELP iniopthlp(); /* Initialize cmdline arg help */ #endif /* NOHELP */ if ( #ifdef COMMENT !cfilef && #endif /* COMMENT */ argc > 1) { /* Command line arguments? */ sstate = (CHAR) cmdlin(); /* Yes, parse. */ #ifdef NETCONN #ifdef HAVE_LOCALE if (nolocale) { /* --nolocale option on command line */ setlocale(LC_ALL, "C"); /* Restore our locale to default */ } #endif /* HAVE_LOCALE */ #ifndef NOTCPIP #ifndef NOURL if (haveurl) { /* Was a URL given? */ dourl(); /* if so, do it. */ } #endif /* NOURL */ #endif /* NOTCPIP */ #endif /* NETCONN */ #ifndef NOXFER zstate = sstate; /* Remember sstate around protocol */ debug(F101,"main zstate","",zstate); #endif /* NOXFER */ #ifndef NOLOCAL if (cflg) { /* Connect first if requested */ doconect(0,0); if (ttchk() < 0) dologend(); cflg = 0; } #endif /* NOLOCAL */ #ifndef NOXFER if (sstate) { #ifndef NOLOCAL if (displa) concb((char)escape); /* (for console "interrupts") */ #endif /* NOLOCAL */ #ifdef NOCCTRAP docmdline(1); #else /* NOCCTRAP */ setint(); cc_execute( ckjaddr(cmjbuf), docmdline, failcmdline ); #endif /* NOCCTRAP */ } #endif /* NOXFER */ #ifndef NOICP /* If a command-line action argument was given and -S ("stay") was not given, exit now. */ if ((cflg || cnflg || zstate) && !stayflg) #endif /* NOICP */ doexit(GOOD_EXIT,xitsta); /* Exit with good status */ #ifndef NOLOCAL #ifndef NOICP if (local) { #ifdef NETCONN if ((cflg || cnflg) && tn_exit && ttchk() < 0) doexit(GOOD_EXIT,xitsta); /* Exit with good status */ #endif /* NETCONN */ if (exitonclose && !network && (carrier != CAR_OFF && (ttgmdm() & BM_DCD) == 0)) doexit(GOOD_EXIT,xitsta); /* Exit with good status */ if (exitonclose && network && ttchk() < 0) doexit(GOOD_EXIT,xitsta); /* Exit with good status */ } #endif /* NOICP */ #endif /* NOLOCAL */ } #endif /* NOCMDL */ #ifdef NOICP /* No interactive command parser */ #ifndef NOCMDL else { /* Command-line-only version */ fatal("?No command-line options given - type 'kermit -h' for help"); } #else /* Neither one! */ sstate = 'x'; justone = 0; proto(); /* So go into server mode */ doexit(GOOD_EXIT,xitsta); /* exit with good status */ #endif /* NOCMDL */ #else /* not NOICP */ #ifdef HAVE_LOCALE if (!nolocale) { /* Can also disable locale processing by setting K_NOLOCALE=1 */ char *s = getenv("K_NOLOCALE"); /* environment variable */ if (s) if (rdigits(s)) if (atoi(s) != 0) { nolocale = 1; } if (!nolocale) { /* Locale not disabled */ setlocale(LC_ALL, ""); /* Enable using non-C locales */ } } #endif /* HAVE_LOCALE */ herald(); /* Display program herald (maybe) */ /* If no action requested on command line, or if -S ("stay") was included, enter the interactive command parser. */ #ifdef NOCCTRAP debug(F100,"main NOCCTRAP setting interrupt trap","",0); setint(); /* Set up command interrupt traps */ doicp(NULL); #else /* NOCCTRAP */ while (1) { debug(F100,"main setting interrupt trap","",0); setint(); /* Set up command interrupt traps */ if (!cc_execute(ckjaddr(cmjbuf), doicp, failicp)) break; } #endif /* NOCCTRAP */ #endif /* NOICP */ #ifndef MAINISVOID return(1); #endif /* MAINISVOID */ } #ifdef DYNAMIC /* Allocate file i/o buffers */ int #ifdef CK_ANSIC getiobs ( void ) #else getiobs ( ) #endif /* CK_ANSIC */ { zinbuffer = (char *)malloc(INBUFSIZE); if (!zinbuffer) return(-1); zoutbuffer = (char *)malloc(zobufsize); debug(F101,"zoutbuffer malloc","",zobufsize); if (!zoutbuffer) return(-1); debug(F100,"getiobs ok","",0); return(0); } #endif /* DYNAMIC */ ckcmdb.c000664 045065 024037 00000021056 14767401722 012570 0ustar00fdckermit000000 000000 /* C K C M D B . C -- malloc debugger. */ /* Author: Howie Kaye, Columbia University Center for Computing Activities. Copyright (C) 1985, 1999, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ /* Use the real ones in this module! */ #ifdef malloc #undef malloc #endif /* malloc */ #ifdef calloc #undef calloc #endif /* calloc */ #ifdef realloc #undef realloc #endif /* realloc */ #ifdef free #undef free #endif /* free */ #include "ckcsym.h" #include #include "ckcdeb.h" #include "ckcfnp.h" /* Prototypes (must be last) */ #ifdef COHERENT _PROTOTYP ( FILE * fdopen, (int, char *) ); #endif /* COHERENT */ /* memdebug: variable to control memory debugging. if memdebug == 1, then action is always taken. if memdebug == 0, then no action is taken. if memdebug == -1, then the user is asked (works well with gdb). */ int memdebug = -1; int disabled = 0; int inited = 0; /* To use this package, compile your program with: -Dmalloc=dmalloc -Dfree=dfree =Dcalloc=dcalloc ... -DMDEBUG and then link it with ckcmdb.c. */ #ifdef MDEBUG #ifndef M_SIZE_T #ifdef NEXT #define M_SIZE_T size_t #else #ifdef SUNOS41 #define M_SIZE_T unsigned #else #define M_SIZE_T int #endif /* SUNOS41 */ #endif /* NEXT */ #endif /* M_SIZE_T */ #ifdef CK_ANSIC _PROTOTYP( void free, (void *) ); _PROTOTYP( void * malloc, (size_t) ); _PROTOTYP( void * realloc, (void *, size_t) ); #else _PROTOTYP( VOID free, (char *) ); _PROTOTYP( char * malloc, (M_SIZE_T) ); _PROTOTYP( char * realloc, (char *, M_SIZE_T) ); #endif /* NEXT */ _PROTOTYP( VOID m_insert, (char *) ); _PROTOTYP( int m_delete, (char *) ); _PROTOTYP( char * dmalloc, (int) ); _PROTOTYP( char * dcalloc, (int, int) ); _PROTOTYP( char * drealloc, (char *, int) ); _PROTOTYP( char *set_range_check, (char *, int) ); _PROTOTYP( char *check_range, (char *) ); _PROTOTYP( static char *maybe_check_range, (char *) ); _PROTOTYP( static VOID maybe_quit, (char *) ); _PROTOTYP( static int ask, (char *) ); #ifndef min #define min(x,y) ((x) < (y) ? (x) : (y)) #endif /* min */ #define RANGE "ABCDEFGHIJKLMNOP" #define INTSIZE sizeof(int) #define LONGSIZE sizeof(long) #define RSIZE sizeof(RANGE) #define RFRONT min((RSIZE/2),LONGSIZE) #define RBACK min((RSIZE-RFRONT),LONGSIZE) char * dmalloc(size) int size; { char *cp; cp = malloc(size + RSIZE + INTSIZE); if (cp) { cp = set_range_check(cp, size); m_insert(cp); } return(cp); } char * dcalloc(nelem, elsize) int nelem, elsize; { char *cp; cp = dmalloc(nelem * elsize); if (cp) memset(cp, 0, nelem * elsize); return(cp); } char * drealloc(bp,size) char *bp; int size; { char *cp; if (bp == NULL) { maybe_quit("Freeing NULL pointer"); } else { m_delete(bp); cp = check_range(bp); } cp = realloc(cp, size + RSIZE + INTSIZE); if (cp) { cp = set_range_check(cp, size); m_insert(cp); } return(cp); } VOID dfree(cp) char *cp; { if (cp == NULL) maybe_quit("Freeing NULL pointer"); else { switch(m_delete(cp)) { case 0: cp = maybe_check_range(cp); break; case 1: cp = check_range(cp); break; case 2: break; } } #ifndef CK_ANSIC return(free(cp)); #endif /* CK_ANSIC */ } char * set_range_check(cp,size) char *cp; int size; { register int i; int tmp = size; for(i = 0; i < INTSIZE; i++) { /* set the size in the string */ cp[i] = tmp & 0xff; tmp >>= 8; } cp += INTSIZE; /* skip the size */ for(i = 0; i < RFRONT; i++) /* set the front of the range check */ cp[i] = RANGE[i]; /* string */ cp += RFRONT; /* skip the front range check */ for(i = 0; i < RBACK; i++) /* set the back odf the range check */ cp[i+size] = RANGE[i+RFRONT]; return(cp); } /* Put calls to this routine in your code any place where you want to check whether you've copied too many characters into a malloc'd space. */ char * check_range(cp) char *cp; { register char *bp = cp - RFRONT - INTSIZE; char *xp = bp; register int i; int size = 0; for(i = 0 ; i < INTSIZE; i++) { /* get the size out of the string */ size <<= 8; size |= bp[INTSIZE-i-1] & 0xff; } bp += INTSIZE; for(i = 0; i < RFRONT; i++) /* check front range check */ if (bp[i] != RANGE[i]) { maybe_quit("leftside malloc buffer overrun"); break; } bp += RFRONT; /* skip front range check */ for(i = 0; i < RBACK; i++) /* check back range check */ if (bp[i+size] != RANGE[i+RFRONT]) { maybe_quit("rightside malloc buffer overrun"); break; } return(xp); } static char * maybe_check_range(cp) char *cp; { register char *bp = cp - RFRONT - INTSIZE; char *xp = bp; register int i; int size = 0; for(i = 0 ; i < INTSIZE; i++) { /* get the size out of the string */ size <<= 8; size |= bp[INTSIZE-i-1] & 0xff; } bp += INTSIZE; for(i = 0; i < RFRONT; i++) /* check front range check */ if (bp[i] != RANGE[i]) { return(cp); } bp += RFRONT; /* skip front range check */ for(i = 0; i < RBACK; i++) /* check back range check */ if (bp[i+size] != RANGE[i+RFRONT]) { fprintf(stderr,"rightside malloc buffer overrun\n"); abort(); break; } return(xp); } #define BUCKETS 10000 char *m_used[BUCKETS]; char *m_used2[BUCKETS]; VOID m_insert(cp) register char *cp; { register int i; if (disabled) return; for(i = 0; i < BUCKETS; i++) if (m_used[i] == 0) { m_used[i] = cp; return; } disabled ++; } static VOID m_insert2(cp) register char *cp; { register int i; if (disabled) return; for(i = 0; i < BUCKETS; i++) if (m_used2[i] == 0) { m_used2[i] = cp; return; } disabled ++; } int m_delete(cp) register char *cp; { register int i; for(i = 0; i < BUCKETS; i++) if (m_used[i] == cp) { m_used[i] = 0; return(1); } for(i = 0; i < BUCKETS; i++) if (m_used2[i] == cp) { m_used2[i] = 0; return(2); } if (disabled) return(0); maybe_quit("Freeing unmalloc'ed pointer"); return(0); } VOID m_init() { register int i; inited = 1; disabled = 0; #ifdef NEXT malloc_debug(2+4+8+16); #endif /* NEXT */ for(i = 0; i < BUCKETS; i++) m_used[i] = 0; } VOID m_done() { register int i,j=0; if (disabled) return; for(i = 0; i < BUCKETS; i++) if (m_used[i] != 0) { if (memdebug) { if (j == 0) fprintf(stderr,"unfree'ed buffers, indices: "); fprintf(stderr,"%d, ", i); j++; } } if (j) fprintf(stderr,"\n"); for(i = 0; i < BUCKETS; i++) if (m_used2[i] != 0) { if (memdebug) { if (j == 0) fprintf(stderr,"unfree'ed registered buffers, indices: "); fprintf(stderr,"%d, ", i); j++; } } if (j) fprintf(stderr,"\n"); if (j) maybe_quit("Unfree'ed malloc buffers"); } VOID m_checkranges() { int i; for ( i = 0; i < BUCKETS; i++) if (m_used[i]) check_range(m_used[i]); } static VOID maybe_quit(str) char *str; { debug(F100,"mdebug maybe_quit","",0); if (memdebug == 0) return; fprintf(stderr,"%s\n",str); if (memdebug == 1) abort(); if (memdebug == -1) if (ask("Quit? ")) abort(); } static int ask(str) char *str; { char buf[100]; FILE *in; int fd; fd = dup(fileno(stdin)); in = fdopen(fd, "r"); while(1) { fprintf(stderr,str); fflush(stderr); if (fgets(buf, 99, in) == NULL) /* EOF? */ return(0); if (buf[0] == 'n' || buf[0] == 'N') { fclose(in); return(0); } if (buf[0] == 'y' || buf[0] == 'Y') { fclose(in); return(1); } fprintf(stderr,"please answer y/n.\n"); } } #endif /* MDEBUG */ ckcnet.c000664 045065 024037 00001571761 14767402757 012643 0ustar00fdckermit000000 000000 char *cknetv = "Network support, 10.0.304, 18 Sep 2023"; /* C K C N E T -- Network support */ /* Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ /* REMINDER: Any changes made to this file that other modules depend must also be made to cklnet.c (for VOS) until such time as cklnet.c and this module are merged back together. (Update 2022-12-06: VOS C-Kermit has not been released since 7.0.197 08 Feb 2000, so if the VOS version is ever to be resurrected, it should start with the current ckcnet.c and then merge back any VOS dependencies.) NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku) C-Kermit source files, must be compatible with C preprocessors that support only #ifdef, #else, #endif, #define, and #undef. Please do not use #if, logical operators, or other preprocessor features in this module. Also, don't use any ANSI C constructs except within #ifdef CK_ANSIC..#endif. Authors: Frank da Cruz (fdc@columbia.edu), Columbia University Academic Information Systems, New York City. Jeffrey E Altman (jaltman@secure-endpoints.com) -- Primary maintainer/developer since about 1996. netopen() routine for TCP/IP originally by Ken Yap, Rochester University (ken@cs.rochester.edu) (no longer at that address). Missing pieces for Excelan sockets library from William Bader. Telnet protocol by Frank da Cruz and Jeffrey Altman. Rlogin protocol by Jeffrey E Altman. SSL support adapted by Jeffrey E Altman from work done by Tim Hudson +61 7 32781581 TLS support by Jeffrey E Altman. HTTP support by Jeffrey E Altman. TGV MultiNet code by Frank da Cruz. MultiNet code adapted to WIN/TCP by Ray Hunter of TWG. MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz. TCP/IP support adapted to IBM TCP/IP 1.2.1,2.0 for OS/2 by Kai Uwe Rommel. CMU-OpenVMS/IP modifications by Mike O'Malley, Digital (DEC), with subsequent improvements by Steven M Schweda (SMS). X.25 support by Marcello Frutig, Catholic University, Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from Stefaan Eeckels, Eurokom, Luxembourg. David Lane added support for Stratus VOS X.25 1996 (in cklnet.c). Stephen Riehm added support for IBM AIX X.25 in April 1998. Other contributions as indicated in the code. */ #ifdef NORLOGIN #ifdef RLOGCODE #undef RLOGCODE #endif /* RLOGCODE */ #endif /* NORLOGIN */ #define CKCNET_C #include "ckcsym.h" #include "ckcdeb.h" #include "ckcker.h" #include "ckcasc.h" #ifdef I386IX /* Has to come before ckcnet.h in */ #include /* this version, but after in others */ #endif /* I386IX */ #include "ckcnet.h" /* which includes ckctel.h */ #include "ckuusr.h" #ifdef CK_SSL #include "ck_ssl.h" #endif /* CK_SSL */ #ifdef CK_DNS_SRV #ifdef OS2 #ifdef NT #include #else /* NT */ /* !Error OS/2 does not support DNS Service Records. */ #endif /* NT */ #else /* OS2 */ #include #ifdef USE_NAMESER_COMPAT #include #endif /* USE_NAMESER_COMPAT */ #ifdef MINIX3 #include #include #else #include #include #endif /* MINIX 3 */ #ifndef PS2AIX10 #ifndef BSD4 #ifndef I386IX #ifndef RTAIX #include #endif /* RTAIX */ #endif /* I386IX */ #endif /* BSD4 */ #endif /* PS2AIX10 */ #endif /* OS2 */ #ifndef T_SRV #define T_SRV 33 #endif /* T_SRV */ #ifndef T_TXT #define T_TXT 16 #endif /* T_TXT */ /* for old Unixes and friends ... */ #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif /* MAXHOSTNAMELEN */ #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1) #endif /* CK_DNS_SRV */ #ifdef NONET #ifdef TCPIPLIB #undef TCPIPLIB #endif /* TCPIPLIB */ #endif /* NONET */ #ifndef NOMHHOST #ifdef datageneral #define NOMHHOST #else #ifdef HPUX5WINTCP #define NOMHHOST #endif /* HPUX5WINTCP */ #endif /* datageneral */ #endif /* NOMHHOST */ #ifdef INADDRX struct in_addr inaddrx; #endif /* INADDRX */ int ttnet = NET_NONE; /* Network type */ int ttnproto = NP_DEFAULT; /* Network virtual terminal protocol */ /* 0 = don't lowercase username for Rlogin/Telnet protocol */ /* nonzero = do lowercase it. Add a SET command if necessary... */ #ifdef VMS int ck_lcname = 1; #else int ck_lcname = 0; #endif /* VMS */ extern int /* External variables */ duplex, debses, seslog, sessft, wasclosed, quiet, msgflg, what, nettype, ttmdm; extern CK_TTYFD_T ttyfd; #ifdef IKSD extern int inserver; #endif /* IKSD */ char myipaddr[20] = { '\0' }; /* Global copy of my IP address */ char hostipaddr[64] = { '\0' }; /* Global copy of remote IP address */ #ifdef NETCONN /* Don't need any of this if there is no network support. */ #ifndef OS2 /* Current fd-swapping hack is not thread-safe */ #define HTTP_BUFFERING #endif /* OS2 */ #ifdef HTTP_BUFFERING #define HTTP_INBUFLEN 8192 static char http_inbuf[HTTP_INBUFLEN]; static int http_bufp = 0, http_count; #endif /* HTTP_BUFFERING */ /* NETLEBUF is (must be) defined for those platforms that call this module to do network i/o (e.g. netinc(), nettchk(), etc) rather than doing it themselves (ttinc(), ttchk(), etc). In this case the Telnet local-echo buffers and routines are defined and referenced here, rather than in the ck?tio.c module. */ #ifdef NETLEBUF #define LEBUFSIZ 4096 int ttpush = -1, le_data = 0; /* These are seen from outside */ static CHAR le_buf[LEBUFSIZ]; /* These are used internally */ static int le_start = 0, le_end = 0; int tt_push_inited = 0; #endif /* NETLEBUF */ #ifdef CK_SOCKS /* SOCKS Internet relay package */ #ifdef CK_SOCKS5 /* SOCKS 5 */ #define accept SOCKSaccept #define bind SOCKSbind #define connect SOCKSconnect #define getsockname SOCKSgetsockname #define listen SOCKSlisten #else /* Not SOCKS 5 */ #define accept Raccept #define bind Rbind #define connect Rconnect #define getsockname Rgetsockname #define listen Rlisten #endif /* CK_SOCKS5 */ #endif /* CK_SOCKS */ #ifdef DEC_TCPIP #include #include #endif /* DEC_TCPIP */ /* Also see ckcnet.h -- hmmm, why don't we always include inet.h? */ #ifdef HPUX #ifndef HPUX7 /* HPUX 7.00 doesn't have it */ #ifndef HPUX6 /* HPUX 6.00 doesn't have it */ #include /* For inet_ntoa() prototype */ #endif /* HPUX6 */ #endif /* HPUX7 */ #endif /* HPUX */ #ifdef CMU_TCPIP #include #endif /* CMU_TCPIP */ #ifndef NODCLTIMEVAL #ifdef DCLTIMEVAL /* UnixWare 7 */ struct timeval { /* And define these ourselves. */ long tv_sec; /* (see comments in ckutio.c) */ long tv_usec; }; struct timezone { int tz_minuteswest; int tz_dsttime; }; #endif /* DCLTIMEVAL */ #endif /* NODCLTIMEVAL */ #ifdef WINTCP #include #include #include /* The WIN/TCP code path is the same as that for MultiNet. Only the routine names have changed ... */ #define socket_read netread #define socket_ioctl ioctl #define socket_write netwrite #define socket_close netclose #ifdef OLD_TWG /* some routines have evolved */ extern int vmserrno, uerrno; #define socket_errno uerrno #define socket_perror perror /* which uses errno, not uerrno! */ #else #define socket_errno errno #define socket_perror win$perror #endif /* OLD_TWG */ #else /* Not WINTCP */ #ifdef OSF13 #ifdef CK_ANSIC #ifdef _NO_PROTO #undef _NO_PROTO #endif /* _NO_PROTO */ #endif /* CK_ANSIC */ #endif /* OSF13 */ #ifndef OS2 #ifndef I386IX #ifndef HPUXPRE65 #include /* Error number symbols */ #else #ifndef ERRNO_INCLUDED #include /* Error number symbols */ #endif /* ERRNO_INCLUDED */ #endif /* HPUXPRE65 */ #endif /* I386IX */ #endif /* OS2 */ #ifdef OS2 #ifdef NT #include /* Error number symbols */ #else /* OS/2 */ #ifdef __WATCOMC__ /* WatcomC doesn't need errno.h (definitions conflict with some previous definition) #include */ #else #include /* Error number symbols */ #endif #endif /* NT */ #endif /* OS2 */ #include /* Everybody needs this */ #ifdef ZILOG /* Zilog has different name for this */ #include #else #include #endif /* ZILOG */ #endif /* WINTCP */ #ifdef datageneral /* Data General AOS/VS */ #include <:usr:include:vs_tcp_errno.h> #include <:usr:include:sys:vs_tcp_types.h> #ifdef SELECT /* NOTE: This can be compiled and linked OK with SELECT defined but it doesn't work at all. Anybody who cares and knows how to fix it, feel free. */ #include <:usr:include:sys:vs_tcp_time.h> #endif /* SELECT */ #include <:usr:include:sys:socket.h> #include <:usr:include:netinet:in.h> #include <:usr:include:netdb.h> #endif /* datageneral */ #ifndef socket_errno #define socket_errno errno #endif /* socket_errno */ #ifdef TNCODE extern int tn_deb; #endif /* TNCODE */ int tcp_rdns = /* Reverse DNS lookup */ #ifdef DEC_TCPIP_OLD SET_OFF /* Doesn't seem to work in UCX */ #else SET_AUTO #endif /* DEC_TCPIP */ ; #ifdef CK_DNS_SRV int tcp_dns_srv = SET_OFF; #endif /* CK_DNS_SRV */ _PROTOTYP( char * cmcvtdate, (char *, int) ); #ifdef RLOGCODE _PROTOTYP( int rlog_ctrl, (CHAR *, int) ); _PROTOTYP( static int rlog_oob, (CHAR *, int) ); #ifndef TCPIPLIB _PROTOTYP( static SIGTYP rlogoobh, ( int ) ); #endif /* TCPIPLIB */ _PROTOTYP( static int rlog_ini, (CHAR *, int, struct sockaddr_in *, struct sockaddr_in *) ); int rlog_mode = RL_COOKED; int rlog_stopped = 0; int rlog_inband = 0; #endif /* RLOGCODE */ #ifndef NOICP extern int doconx; /* CONNECT-class command active */ #endif /* NOICP */ #ifdef IBMX25 /* This variable should probably be generalised for true client/server * support - ie: the fd of the listening server, accepted calls should * be forked or at least handled via a second fd (for IBM's X.25 - * ttyfd always holds the active fd - ie the server becomes inactive * as long as a client is connected, and becomes active again when the * connection is closed) */ int x25serverfd = 0; /* extern in ckcnet.h */ int x25seqno = 0; /* Connection sequence number */ int x25lastmsg = -1; /* A cheapskate's state table */ #define X25_CLOSED 0 /* Default state: no connection, no STREAM */ #define X25_SETUP 1 /* X.25 has been set up (no connection) */ #define X25_CONNECTED 2 /* X.25 connection has been established */ int x25_state = X25_CLOSED; /* Default state */ #endif /* IBMX25 */ #ifndef DEBUG #define deblog 0 #endif /* DEBUG */ #ifdef CK_NAWS /* Negotiate About Window Size */ #ifdef RLOGCODE _PROTOTYP( int rlog_naws, (void) ); #endif /* RLOGCODE */ #endif /* CK_NAWS */ #ifdef OS2 /* For terminal type name string */ #include "ckuusr.h" #ifndef NT #define INCL_DOSSEMAPHORES #include #undef COMMENT #endif /* NT */ #include "ckocon.h" int os2socketerror(int); extern int tt_type, max_tt; extern struct tt_info_rec tt_info[]; extern char ttname[]; #else #ifdef CK_AUTHENTICATION #include "ckuusr.h" #endif /* CK_AUTHENTICATION */ #endif /* OS2 */ #ifdef NT #include extern int winsock_version; char * GetLocalUser(); /* defined in ckotio.c */ #ifdef CK_LOGIN VOID setntcreds(); #endif /* CK_LOGIN */ /* The NT 3.50 SDK defines try as __try */ #ifdef try #undef try #endif #endif /* NT */ #ifdef CK_AUTHENTICATION #include "ckuath.h" #endif /* CK_AUTHENTICATION */ #include "ckcsig.h" #ifndef OS2 /* For timeout longjumps */ static ckjmpbuf njbuf; #endif /* OS2 */ #define NAMECPYL 1024 /* Local copy of hostname */ char namecopy[NAMECPYL]; /* Referenced by ckctel.c */ char namecopy2[NAMECPYL]; /* Referenced by ckctel.c */ #ifndef NOHTTP char http_host_port[NAMECPYL]; /* orig host/port necessary for http */ char http_ip[20] = { '\0' }; /* ip address of host */ char http_port = 0; int http_ssl = 0; char * http_agent = 0; int httpfd = -1; /* socket for http connections */ int http_code = 0; #define HTTPBUFLEN 1024 char http_reply_str[HTTPBUFLEN] = ""; #endif /* NOHTTP */ char ipaddr[20] = { '\0' }; /* Global copy of IP address */ unsigned long myxipaddr = 0L; /* Ditto as a number */ #endif /* NETCONN */ char *tcp_address = NULL; /* Preferred IP Address */ extern char uidbuf[]; /* User ID buffer */ extern char pwbuf[]; /* Password buffer */ #ifndef NOHTTP char * tcp_http_proxy = NULL; /* Name[:port] of http proxy server */ int tcp_http_proxy_errno = 0; char * tcp_http_proxy_user = NULL; char * tcp_http_proxy_pwd = NULL; char * tcp_http_proxy_agent = NULL; #define HTTPCPYL 1024 static char proxycopy[HTTPCPYL]; #endif /* NOHTTP */ #ifdef OS2 extern int tt_rows[], tt_cols[]; extern int tt_status[VNUM]; #else /* OS2 */ extern int tt_rows, tt_cols; /* Everybody has this */ #endif /* OS2 */ extern int cmd_cols, cmd_rows; #ifdef STREAMING /* Use blocking writes for streaming */ extern int streaming; #endif /* STREAMING */ #ifdef NT extern int WSASafeToCancel; int win95selectbug = 0; /* For TCP/IP stacks whose select() */ /* always fails on write requests such as Cisco and Quarterdeck */ #define stricmp _stricmp #endif /* NT */ #ifndef NOTCPOPTS /* Skip all this if NOTCPOPTS specified. */ #ifdef SOL_SOCKET #ifdef TCP_NODELAY int tcp_nodelay = 0; /* Nagle algorithm TCP_NODELAY */ #endif /* TCP_NODELAY */ #ifdef SO_DONTROUTE int tcp_dontroute = 0; #endif /* SO_DONTROUTE */ #ifdef SO_LINGER int tcp_linger = 0; /* SO_LINGER */ int tcp_linger_tmo = 0; /* SO_LINGER timeout */ #endif /* SO_LINGER */ #ifdef HPUX /* But the data structures */ #ifndef HPUX8 /* needed for linger are not */ #ifndef HPUX9 /* defined in HP-UX versions */ #ifndef HPUX10 /* prior to 8.00. */ #ifdef SO_LINGER #undef SO_LINGER #endif /* SO_LINGER */ #endif /* HPUX10 */ #endif /* HPUX9 */ #endif /* HPUX8 */ #endif /* HPUX */ #ifndef SO_OOBINLINE /* Hopefully only HP-UX 7.0 */ #define SO_OOBINLINE 0x0100 #endif /* SO_OOBINLINE */ #ifndef TCPSNDBUFSIZ #ifdef VMS #ifdef __alpha #define TCPSNDBUFSIZ 16384 #endif /* __alpha */ #endif /* VMS */ #endif /* TCPSNDBUFSIZ */ #ifndef TCPSNDBUFSIZ #define TCPSNDBUFSIZ -1 #endif /* TCPSNDBUFSIZ */ #ifdef SO_SNDBUF int tcp_sendbuf = TCPSNDBUFSIZ; #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF int tcp_recvbuf = -1; #endif /* SO_RCVBUF */ #ifdef SO_KEEPALIVE int tcp_keepalive = 1; #endif /* SO_KEEPALIVE */ #endif /* SOL_SOCKET */ #endif /* NOTCPOPTS */ #ifndef NETCONN /* Network support not defined. Dummy functions here in case #ifdef's forgotten elsewhere. */ int /* Open network connection */ netopen(name, lcl, nett) char *name; int *lcl, nett; { return(-1); } int /* Close network connection */ netclos() { return(-1); } int /* Check network input buffer */ nettchk() { return(-1); } int /* Flush network input buffer */ netflui() { return(-1); } int /* Send network BREAK */ netbreak() { return(-1); } int /* Input character from network */ netinc(timo) int timo; { return(-1); } int /* Output character to network */ #ifdef CK_ANSIC nettoc(CHAR c) #else nettoc(c) CHAR c; #endif /* CK_ANSIC */ /* nettoc */ { return(-1); } int nettol(s,n) CHAR *s; int n; { return(-1); } #else /* NETCONN is defined (much of this module...) */ #ifdef NETLEBUF VOID le_init() { /* LocalEchoInit() */ int i; for (i = 0; i < LEBUFSIZ; i++) le_buf[i] = '\0'; le_start = 0; le_end = 0; le_data = 0; tt_push_inited = 1; } VOID le_clean() { /* LocalEchoCleanup() */ le_init(); return; } int le_inbuf() { int rc = 0; if (le_start != le_end) { rc = (le_end - le_start + LEBUFSIZ) % LEBUFSIZ; } return(rc); } int #ifdef CK_ANSIC le_putchar(CHAR ch) #else le_putchar(ch) CHAR ch; #endif /* CK_ANSIC */ /* le_putchar */ { if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) { debug(F110,"le_putchar","buffer is full",0); return(-1); } le_buf[le_end++] = ch; if (le_end == LEBUFSIZ) le_end = 0; le_data = 1; return(0); } int #ifdef CK_ANSIC le_puts(CHAR * s, int n) #else le_puts(s,n) CHAR * s; int n; #endif /* CK_ANSIC */ /* le_puts */ { int rc = 0; int i = 0; CHAR * p = (CHAR *)"le_puts"; ckhexdump(p,s,n); for (i = 0; i < n; i++) rc = le_putchar((char)s[i]); debug(F101,"le_puts","",rc); return(rc); } int #ifdef CK_ANSIC le_putstr(CHAR * s) #else le_putstr(s) CHAR * s; #endif /* CK_ANSIC */ /* le_puts */ { CHAR * p; int rc = 0; p = (CHAR *)"le_putstr"; ckhexdump(p,s,(int)strlen((char *)s)); for (p = s; *p && !rc; p++) rc = le_putchar(*p); return(rc); } int #ifdef CK_ANSIC le_getchar(CHAR * pch) #else /* CK_ANSIC */ le_getchar(pch) CHAR * pch; #endif /* CK_ANSIC */ /* le_gatchar */ { int rc = 0; if (le_start != le_end) { *pch = le_buf[le_start]; le_buf[le_start] = 0; le_start++; if (le_start == LEBUFSIZ) le_start = 0; if (le_start == le_end) { le_data = 0; } rc++; } else { *pch = 0; } return(rc); } #endif /* NETLEBUF */ #ifdef VMS /* In edit 190, we moved tn_ini() to be called from within netopen(). But tn_ini() calls ttol(), and ttol() checks to see if it's a net connection, but the flag for that isn't set until after netopen() is finished. Since, in this module, we are always doing network output anyway, we just call nettol() directly, instead of going thru ttol(). Only needed for VMS, since UNIX, AOS/VS, and VOS can handle net connections just like regular connections in ttol(), and OS/2 has a special routine for this. */ #define ttol nettol #endif /* VMS */ int tcpsrfd = -1; #ifdef CK_KERBEROS char * krb5_d_principal = NULL; /* Default principal */ char * krb5_d_instance = NULL; /* Default instance */ char * krb5_d_realm = NULL; /* Default realm */ char * krb5_d_cc = NULL; /* Default credentials cache */ char * krb5_d_srv = NULL; /* Default Service */ int krb5_d_lifetime = 600; /* Default lifetime (10 hours) */ int krb5_d_forwardable = 0; /* creds not forwardable */ int krb5_d_proxiable = 0; /* creds not proxiable */ int krb5_d_renewable = 0; /* creds not renewable (0 min) */ int krb5_autoget = 1; /* Autoget TGTs */ int krb5_autodel = 0; /* Auto delete TGTs */ int krb5_d_getk4 = 0; /* K5 Kinit gets K4 TGTs */ int krb5_checkaddrs = 1; /* Check TGT Addrs */ int krb5_d_no_addresses = 0; /* Do not include IP Addresses */ char * krb5_d_addrs[KRB5_NUM_OF_ADDRS+1]={NULL,NULL}; /* Addrs to include */ int krb5_errno = 0; /* Last K5 errno */ char * krb5_errmsg = NULL; /* Last K5 errmsg */ char * k5_keytab = NULL; char * krb4_d_principal = NULL; /* Default principal */ char * krb4_d_realm = NULL; /* Default realm */ char * krb4_d_srv = NULL; /* Default Service */ int krb4_d_lifetime = 600; /* Default lifetime (10 hours) */ int krb4_d_preauth = 1; /* Use preauth requests */ char * krb4_d_instance = NULL; /* Default instance */ int krb4_autoget = 1; /* Autoget TGTs */ int krb4_autodel = 0; /* Auto delete TGTs */ int krb4_checkaddrs = 1; /* Check TGT Addrs */ char * k4_keytab = NULL; int krb4_errno = 0; /* Last K4 errno */ char * krb4_errmsg = NULL; /* Last K4 errmsg */ struct krb_op_data krb_op = { /* Operational data structure */ 0, NULL /* (version, cachefile) */ }; struct krb4_init_data krb4_init = { /* Kerberos 4 INIT data structure */ 0, NULL, NULL, NULL, NULL }; struct krb5_init_data krb5_init = { /* Kerberos 5 INIT data structure */ 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, 0 }; struct krb5_list_cred_data krb5_lc = { /* List Credentials data structure */ 0, 0, 0 }; int krb_action = -1; /* Kerberos action to perform */ #ifndef CK_AUTHENTICATION char * ck_krb4_getrealm() { return(""); } char * ck_krb5_getrealm(cc) char * cc; { return(""); } char * ck_krb4_getprincipal() { return(""); } char * ck_krb5_getprincipal(cc) char * cc; { return(""); } #endif /* CK_AUTHENTICATION */ /* I N I _ K E R B -- Initialize Kerberos data */ VOID ini_kerb() { int i; krb_action = -1; /* No action specified */ krb_op.version = 0; /* Kerberos version (none) */ krb_op.cache = NULL; /* Cache file (none) */ /* Kerberos 5 */ krb5_init.forwardable = krb5_d_forwardable; /* Init switch values... */ krb5_init.proxiable = krb5_d_proxiable; krb5_init.lifetime = krb5_d_lifetime; krb5_init.renew = 0; krb5_init.renewable = krb5_d_renewable; krb5_init.validate = 0; krb5_init.no_addresses = krb5_d_no_addresses; krb5_init.getk4 = krb5_d_getk4; if (krb5_init.postdate) { free(krb5_init.postdate); krb5_init.postdate = NULL; } if (krb5_init.service) { free(krb5_init.service); krb5_init.service = NULL; } if (!krb5_d_cc || !krb5_d_cc[0]) { /* Set default cache */ char * p; p = ck_krb5_get_cc_name(); makestr(&krb5_d_cc,(p && p[0]) ? p : NULL); } if (!krb5_d_realm || !krb5_d_realm[0]) { /* Set default realm */ char * p; p = ck_krb5_getrealm(krb5_d_cc); makestr(&krb5_d_realm,(p && p[0]) ? p : NULL); } makestr(&krb5_init.instance,krb5_d_instance); makestr(&krb5_init.realm,krb5_d_realm); /* Set realm from default */ if (krb5_init.password) { memset(krb5_init.password,0xFF,strlen(krb5_init.password)); free(krb5_init.password); krb5_init.password = NULL; } if (!krb5_d_principal) { /* Default principal */ /* a Null principal indicates the user should be prompted */ char * p = ck_krb5_getprincipal(krb5_d_cc); if (!p || !(*p)) p = (char *)uidbuf; /* Principal = user */ makestr(&krb5_d_principal,(p && p[0]) ? p : NULL); } makestr(&krb5_init.principal,krb5_d_principal); for (i = 0; i <= KRB5_NUM_OF_ADDRS; i++) { if (krb5_init.addrs[i]) free(krb5_init.addrs[i]); krb5_init.addrs[i] = NULL; } for (i = 0; i <= KRB5_NUM_OF_ADDRS && krb5_d_addrs[i]; i++) { makestr(&krb5_init.addrs[i],krb5_d_addrs[i]); } /* Kerberos 4 */ krb4_init.lifetime = krb4_d_lifetime; krb4_init.preauth = krb4_d_preauth; makestr(&krb4_init.instance,krb4_d_instance); if (!krb4_d_realm || !krb4_d_realm[0]) {/* Set default realm */ char * p; p = ck_krb4_getrealm(); makestr(&krb4_d_realm,(p && p[0]) ? p : NULL); } makestr(&krb4_init.realm,krb4_d_realm); if (krb4_init.password) { memset(krb4_init.password,0xFF,strlen(krb4_init.password)); free(krb4_init.password); krb4_init.password = NULL; } if (!krb4_d_principal) { /* Default principal */ /* a Null principal indicates the user should be prompted */ char * p = ck_krb4_getprincipal(); if (!p || !(*p)) p = (char *)uidbuf; /* Principal = user */ makestr(&(krb4_d_principal),(p && p[0]) ? p : NULL); } makestr(&(krb4_init.principal),krb4_d_principal); } /* D O A U T H -- AUTHENTICATE action routine */ int doauth(cx) int cx; { /* AUTHENTICATE action routine */ int rc = 0; /* Return code */ #ifdef CK_AUTHENTICATION #ifdef OS2 if (!ck_security_loaddll()) /* Load various DLLs */ return(rc); #endif /* OS2 */ if (krb_op.version == 4) { /* Version = 4 */ #ifdef COMMENT sho_auth(AUTHTYPE_KERBEROS_V4); #endif /* COMMENT */ if (!ck_krb4_is_installed()) { printf("?Kerberos 4 is not installed\n"); return(0); } switch (krb_action) { /* Perform V4 functions */ case KRB_A_IN: /* INIT */ rc |= !(ck_krb4_initTGT(&krb_op,&krb4_init) < 0); break; case KRB_A_DE: /* DESTROY */ rc |= !(ck_krb4_destroy(&krb_op) < 0); break; case KRB_A_LC: /* LIST-CREDENTIALS */ rc |= !(ck_krb4_list_creds(&krb_op) < 0); break; } } if (krb_op.version == 5) { /* V5 functions */ #ifdef COMMENT sho_auth(AUTHTYPE_KERBEROS_V5); #endif /* COMMENT */ if (!ck_krb5_is_installed()) { printf("?Kerberos 5 is not installed\n"); return(0); } switch (krb_action) { case KRB_A_IN: /* INIT */ rc |= !(ck_krb5_initTGT(&krb_op,&krb5_init, krb5_init.getk4 ? &krb4_init : 0) < 0); break; case KRB_A_DE: /* DESTROY */ rc |= !(ck_krb5_destroy(&krb_op) < 0); break; case KRB_A_LC: /* LIST-CREDENTIALS */ if (krb_op.version == 0) printf("\n"); rc |= !(ck_krb5_list_creds(&krb_op,&krb5_lc) < 0); break; } } #else #ifndef NOICP #ifndef NOSHOW rc = sho_auth(0); /* Show all */ #endif /* NOSHOW */ #endif /* NOICP */ #endif /* CK_AUTHENTICATION */ return(rc); } #endif /* CK_KERBEROS */ #ifdef TCPSOCKET #ifndef OS2 #ifndef NOLISTEN /* For incoming connections */ #ifndef INADDR_ANY #define INADDR_ANY 0 #endif /* INADDR_ANY */ _PROTOTYP( int ttbufr, ( VOID ) ); _PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) ); static unsigned short tcpsrv_port = 0; #endif /* NOLISTEN */ #endif /* OS2 */ static char svcbuf[80]; /* TCP service string */ static int svcnum = 0; /* TCP port number */ #endif /* TCPSOCKET */ /* TCPIPLIB means use separate socket calls for i/o, while on UNIX the normal file system calls are used for TCP/IP sockets too. Means "DEC_TCPIP or MULTINET or WINTCP or OS2 or BEBOX" (see ckcnet.h), */ #ifdef TCPIPLIB /* For buffered network reads... */ /* If the buffering code is written right, it shouldn't matter how long this buffer is. */ #ifdef OS2 #ifdef NT #define TTIBUFL 64240 /* 44 * 1460 (MSS) */ #else #define TTIBUFL 32120 /* 22 * 1460 (MSS) */ #endif /* NT */ #else /* OS2 */ #define TTIBUFL 8191 /* Let's use 8K. */ #endif /* OS2 */ CHAR ttibuf[TTIBUFL+1]; /* select() is used in preference to alarm()/signal(), but different systems use different forms of select()... */ #ifndef NOSELECT /* Option to override BSDSELECT */ #ifdef BELLV10 /* Note: Although BELLV10 does have TCP/IP support, and does use the unique form of select() that is evident in this module (and in ckutio.c), it does not have a sockets library and so we can't build Kermit TCP/IP support for it. For this, somebody would have to write TCP/IP streams code. */ #define BELLSELECT #ifndef FD_SETSIZE #define FD_SETSIZE 128 #endif /* FD_SETSIZE */ #else #ifdef WINTCP /* VMS with Wollongong WIN/TCP */ #ifndef OLD_TWG /* TWG 3.2 has only select(read) */ #define BSDSELECT #endif /* OLD_TWG */ #else #ifdef CMU_TCPIP /* LIBCMU can do select */ #define BSDSELECT #else #ifdef DEC_TCPIP #define BSDSELECT #else #ifdef OS2 /* OS/2 with TCP/IP */ #ifdef NT #define BSDSELECT #else /* NT */ #define IBMSELECT #endif /* NT */ #endif /* OS2 */ #endif /* DEC_TCPIP */ #endif /* CMU_TCPIP */ #endif /* WINTCP */ #endif /* BELLV10 */ #endif /* NOSELECT */ /* Others (TGV, TCPware, ...) use alarm()/signal(). The BSDSELECT case does not compile at all; the IBMSELECT case compiles and links but crashes at runtime. NOTE: If any of these can be converted to select(), they should be for two reasons: (1) It's a lot faster; (2) certain sockets libraries do not like their socket_read() calls to be interrupted; subsequent socket_read()'s tend to fail with EBUSY. This happened in the UCX case before it was converted to use select(). */ #ifndef OS2 #ifndef VMS static /* These are used in CKVTIO.C */ #endif /* VMS */ /* And in CKONET.C */ #endif /* OS2 */ int ttibp = 0, ttibn = 0; /* Read bytes from network into internal buffer ttibuf[]. To be called when input buffer is empty, i.e. when ttibn == 0. Other network reading routines, like ttinc, ttinl, ttxin, should check the internal buffer first, and call this routine for a refill if necessary. Returns -1 on error, 0 if nothing happens. When data is read successfully, returns number of bytes read, and sets global ttibn to that number and ttibp (the buffer pointer) to zero. */ _PROTOTYP( int ttbufr, ( VOID ) ); int ttbufr() { /* TT Buffer Read */ int count; if (ttnet != NET_TCPB) /* First make sure current net is */ return(-1); /* TCP/IP; if not, do nothing. */ #ifdef OS2 RequestTCPIPMutex(SEM_INDEFINITE_WAIT); #endif /* OS2 */ if (ttibn > 0) { /* Our internal buffer is not empty, */ #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(ttibn); /* so keep using it. */ } if (ttyfd == -1) { /* No connection, error */ #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); } ttibp = 0; /* Else reset pointer to beginning */ #ifdef WINTCP count = 512; /* This works for WIN/TCP */ #else #ifdef DEC_TCPIP count = 512; /* UCX */ #else #ifdef OS2 count = TTIBUFL; #else /* Multinet, etc. */ count = ttchk(); /* Check network input buffer, */ if (ttibn > 0) { /* which can put a char there! */ debug(F111,"ttbufr","ttchk() returns",count); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(ttibn); } if (count < 0) { /* Read error - connection closed */ #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); } else if (count > TTIBUFL) /* Too many to read */ count = TTIBUFL; else if (count == 0) /* None, so force blocking read */ count = 1; #endif /* OS2 */ #endif /* DEC_TCPIP */ #endif /* WINTCP */ debug(F101,"ttbufr count 1","",count); #ifdef CK_SSL if (ssl_active_flag || tls_active_flag) { int error; ssl_read: if (ssl_active_flag) count = SSL_read(ssl_con, ttibuf, count); else count = SSL_read(tls_con, ttibuf, count); error = SSL_get_error(ssl_active_flag?ssl_con:tls_con,count); switch (error) { case SSL_ERROR_NONE: debug(F111,"ttbufr SSL_ERROR_NONE","count",count); if (count > 0) { ttibp = 0; /* Reset buffer pointer. */ ttibn = count; #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(ttibn); /* Return buffer count. */ } else if (count < 0) { #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); } else { netclos(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); } case SSL_ERROR_WANT_WRITE: debug(F100,"ttbufr SSL_ERROR_WANT_WRITE","",0); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); case SSL_ERROR_WANT_READ: debug(F100,"ttbufr SSL_ERROR_WANT_READ","",0); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); case SSL_ERROR_SYSCALL: if ( count == 0 ) { /* EOF */ netclos(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); } else { int rc = -1; #ifdef NT int gle = GetLastError(); debug(F111,"ttbufr SSL_ERROR_SYSCALL", "GetLastError()",gle); rc = os2socketerror(gle); if (rc == -1) rc = -2; else if ( rc == -2 ) rc = -1; #endif /* NT */ #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(rc); } case SSL_ERROR_WANT_X509_LOOKUP: debug(F100,"ttbufr SSL_ERROR_WANT_X509_LOOKUP","",0); netclos(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); case SSL_ERROR_SSL: if (bio_err!=NULL) { int len; extern char ssl_err[]; BIO_printf(bio_err,"ttbufr SSL_ERROR_SSL\n"); ERR_print_errors(bio_err); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; debug(F110,"ttbufr SSL_ERROR_SSL",ssl_err,0); if (ssl_debug_flag) printf(ssl_err); } else if (ssl_debug_flag) { debug(F100,"ttbufr SSL_ERROR_SSL","",0); fflush(stderr); fprintf(stderr,"ttbufr SSL_ERROR_SSL\n"); ERR_print_errors_fp(stderr); } #ifdef COMMENT netclos(); #endif /* COMMENT */ #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); case SSL_ERROR_ZERO_RETURN: debug(F100,"ttbufr SSL_ERROR_ZERO_RETURN","",0); netclos(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); default: debug(F100,"ttbufr SSL_ERROR_?????","",0); netclos(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); } } #endif /* CK_SSL */ #ifdef COMMENT /* This is for nonblocking reads, which we don't do any more. This code didn't work anyway, in the sense that a broken connection was never sensed. */ if ((count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count)) < 1) { if (count == -1 && socket_errno == EWOULDBLOCK) { debug(F100,"ttbufr finds nothing","",0); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(0); } else { debug(F101,"ttbufr socket_read error","",socket_errno); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); } } else if (count == 0) { debug(F100,"ttbufr socket eof","",0); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); } #else /* COMMENT */ /* This is for blocking reads */ #ifndef VMS #ifdef SO_OOBINLINE { int outofband = 0; #ifdef BELLSELECT if (select(128, NULL, NULL, efds, 0) > 0 && FD_ISSET(ttyfd, efds)) outofband = 1; #else #ifdef BSDSELECT fd_set efds; struct timeval tv; FD_ZERO(&efds); FD_SET(ttyfd, &efds); tv.tv_sec = tv.tv_usec = 0L; debug(F100,"Out-of-Band BSDSELECT","",0); #ifdef NT WSASafeToCancel = 1; #endif /* NT */ if (select(FD_SETSIZE, NULL, NULL, &efds, &tv) > 0 && FD_ISSET(ttyfd, &efds)) outofband = 1; #ifdef NT WSASafeToCancel = 0; #endif /* NT */ #else /* !BSDSELECT */ #ifdef IBMSELECT /* Is used by OS/2 ... */ /* ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set */ /* and timeval stuff since this is the only place where it is used. */ CK_TTYFD_T socket = ttyfd; debug(F100,"Out-of-Band IBMSELECT","",0); if ((select(&socket, 0, 0, 1, 0L) == 1) && (socket == ttyfd)) outofband = 1; #else /* !IBMSELECT */ /* If we can't use select(), then we use the regular alarm()/signal() timeout mechanism. */ debug(F101,"Out-of-Band data not supported","",0); outofband = 0; #endif /* IBMSELECT */ #endif /* BSDSELECT */ #endif /* BELLSELECT */ if (outofband) { /* Get the Urgent Data */ /* if OOBINLINE is disabled this should be only a single byte */ /* MS Winsock has a bug in Windows 95. Extra bytes are delivered */ /* That were never sent. */ #ifdef OS2 RequestTCPIPMutex(SEM_INDEFINITE_WAIT); #endif /* OS2 */ count = socket_recv(ttyfd,&ttibuf[ttibp+ttibn],count,MSG_OOB); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ if (count <= 0) { int s_errno = socket_errno; debug(F101, "ttbufr socket_recv MSG_OOB","",count); debug(F101, "ttbufr socket_errno","",s_errno); #ifdef OS2ONLY if (count < 0 && (s_errno == 0 || s_errno == 23)) { /* These appear in OS/2 - don't know why */ /* ignore it and read as normal data */ /* and break, then we will attempt to read */ /* the port using normal read() techniques */ debug(F100,"ttbufr handing as in-band data","",0); count = 1; } else { netclos(); /* *** *** */ #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); } #else /* OS2ONLY */ netclos(); /* *** *** */ #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); #endif /* OS2ONLY */ } else { /* we got out-of-band data */ ckhexdump("ttbufr out-of-band chars",&ttibuf[ttibp+ttibn],count); #ifdef BETADEBUG bleep(BP_NOTE); #endif /* BETADEBUG */ #ifdef RLOGCODE /* blah */ if (ttnproto == NP_RLOGIN || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN || ((ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) && !rlog_inband) ) { /* When urgent data is read with MSG_OOB and not OOBINLINE then urgent data and normal data are not mixed. So treat the entire buffer as urgent data. */ rlog_oob(&ttibuf[ttibp+ttibn], count); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return ttbufr(); } else #endif /* RLOGCODE */ /* blah */ #ifdef COMMENT /* I haven't written this yet, nor do I know what it should do */ if (ttnproto == NP_TELNET) { tn_oob(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return 0; } else #endif /* COMMENT */ { /* For any protocols we don't have a special out-of-band */ /* handler for, just put the bytes in the normal buffer */ /* and return */ ttibp += 0; /* Reset buffer pointer. */ ttibn += count; #ifdef DEBUG /* Got some bytes. */ debug(F101,"ttbufr count 2","",count); if (count > 0) ttibuf[ttibp+ttibn] = '\0'; debug(F111,"ttbufr ttibuf",ttibuf,ttibp); #endif /* DEBUG */ #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(ttibn); /* Return buffer count. */ } } } } #endif /* SO_OOBINLINE */ #endif /* VMS */ count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count); if (count <= 0) { int s_errno = socket_errno; debug(F101,"ttbufr socket_read","",count); debug(F101,"ttbufr socket_errno","",s_errno); #ifdef OS2 if (count == 0 || os2socketerror(s_errno) < 0) { netclos(); ReleaseTCPIPMutex(); return(-2); } ReleaseTCPIPMutex(); return(-1); #else /* OS2 */ netclos(); /* *** *** */ return(-2); #endif /* OS2 */ } #endif /* COMMENT */ /* (blocking vs nonblock reads...) */ else { ttibp = 0; /* Reset buffer pointer. */ ttibn += count; #ifdef DEBUG debug(F101,"ttbufr count 2","",count); /* Got some bytes. */ if (count > 0) ttibuf[ttibp+ttibn] = '\0'; debug(F111,"ttbufr ttibuf",&ttibuf[ttibp],ttibn); #endif /* DEBUG */ #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(ttibn); /* Return buffer count. */ } } #endif /* TCPIPLIB */ #ifndef IBMSELECT #ifndef BELLSELECT #ifndef BSDSELECT /* Non-TCPIPLIB case */ #ifdef SELECT #define BSDSELECT #endif /* SELECT */ #endif /* BSDSELECT */ #endif /* BELLSELECT */ #endif /* IBMSELECT */ #define TELNET_PORT 23 /* Should do lookup, but it won't change */ #define RLOGIN_PORT 513 #define KERMIT_PORT 1649 #define KLOGIN_PORT 543 #define EKLOGIN_PORT 2105 #ifndef NONET /* C-Kermit network open/close functions for BSD-sockets. Much of this code shared by SunLink X.25, which also uses the socket library. */ #ifdef TCPSOCKET struct hostent * #ifdef CK_ANSIC ck_copyhostent(struct hostent * h) #else /* CK_ANSIC */ ck_copyhostent(h) struct hostent * h; #endif /* CK_ANSIC */ { /* * The hostent structure is dynamic in nature. * struct hostent { * char * h_name; * char * * h_aliases; * short h_addrtype; * short h_length; * char * * h_addr_list; * #define h_addr h_addr_list[0] */ #define HOSTENTCNT 5 static struct hostent hosts[HOSTENTCNT] = {{NULL,NULL,0,0,NULL}, {NULL,NULL,0,0,NULL}, {NULL,NULL,0,0,NULL}, {NULL,NULL,0,0,NULL}, {NULL,NULL,0,0,NULL}}; static int next = 0; int i,cnt; char ** pp; if ( h == NULL ) return(NULL); if (next == HOSTENTCNT) next = 0; if ( hosts[next].h_name ) { free(hosts[next].h_name); hosts[next].h_name = NULL; } if ( hosts[next].h_aliases ) { pp = hosts[next].h_aliases; while ( *pp ) { free(*pp); pp++; } free(hosts[next].h_aliases); } #ifdef HADDRLIST if ( hosts[next].h_addr_list ) { pp = hosts[next].h_addr_list; while ( *pp ) { free(*pp); pp++; } free(hosts[next].h_addr_list); } #endif /* HADDRLIST */ makestr(&hosts[next].h_name,h->h_name); if (h->h_aliases) { for ( cnt=0,pp=h->h_aliases; pp && *pp; pp++,cnt++) ; /* The following can give warnings in non-ANSI builds */ hosts[next].h_aliases = (char **) malloc(sizeof(char *) * (cnt+1)); for ( i=0; ih_aliases[i]); } hosts[next].h_aliases[i] = NULL; } else hosts[next].h_aliases = NULL; hosts[next].h_addrtype = h->h_addrtype; hosts[next].h_length = h->h_length; #ifdef HADDRLIST #ifdef h_addr if (h->h_addr_list) { for ( cnt=0,pp=h->h_addr_list; pp && *pp; pp++,cnt++) ; /* The following can give warnings non-ANSI builds */ hosts[next].h_addr_list = (char **) malloc(sizeof(char *) * (cnt+1)); for ( i=0; ih_length); bcopy(h->h_addr_list[i],hosts[next].h_addr_list[i],h->h_length); } hosts[next].h_addr_list[i] = NULL; } else hosts[next].h_addr_list = NULL; #else bcopy(h->h_addr, &hosts[next].h_addr, h->h_length); #endif /* h_addr */ #else /* HADDRLIST */ bcopy(h->h_addr, &hosts[next].h_addr, h->h_length); #endif /* HADDRLIST */ return(&hosts[next++]); } #ifdef EXCELAN /* Most other BSD sockets implementations define these in header files and libraries. */ struct servent { unsigned short s_port; }; struct hostent { short h_addrtype; struct in_addr h_addr; int h_length; }; struct servent * getservbyname(service, connection) char *service,*connection; { static struct servent servrec; int port; port = 0; if (strcmp(service, "telnet") == 0) port = 23; else if (strcmp(service, "smtp") == 0) port = 25; else port = atoi(service); debug(F101,"getservbyname return port ","",port); if (port > 0) { servrec.s_port = htons(port); return(&servrec); } return((struct servent *) NULL); } struct hostent * gethostbyname(hostname) char *hostname; { return((struct hostent *) NULL); } unsigned long inet_addr(name) char *name; { unsigned long addr; addr = rhost(&name); debug(F111,"inet_addr ",name,(int)addr); return(addr); } char * inet_ntoa(in) struct in_addr in; { static char name[80]; ckmakxmsg(name, ckuitoa(in.s_net),".",ckuitoa(in.s_host),".", ckuitoa(in.s_lh),".", ckuitoa(in.s_impno)); return(name); } #else #ifdef DEC_TCPIP /* UCX */ int ucx_port_bug = 0; /* Explained below */ #ifdef OLDIP /* Very old VAXC or GCC */ /* Note that my oldest VAX C (V3.1-051) does not need (or want) OLDIP, hence the "Very old" in the comment - SMS, 2010/03/15. */ #define getservbyname my_getservbyname #ifdef CK_ANSIC globalref int (*C$$GA_UCX_GETSERVBYNAME)(); extern void C$$TRANSLATE(); extern void C$$SOCK_TRANSLATE(); #else globalref int (*C$$GA_UCX_GETSERVBYNAME)(); extern VOID C$$TRANSLATE(); extern VOID C$$SOCK_TRANSLATE(); #endif /* CK_ANSIC */ struct servent * my_getservbyname (service, proto) char *service, *proto; { static struct servent sent; struct iosb { union { unsigned long status; unsigned short st[2]; } sb; unsigned long spare; } s; struct { struct iosb *s; char *serv; char *prot; } par; unsigned long e; char sbuf[30], pbuf[30]; char *p; debug(F111,"UCX getservbyname",service,(int)C$$GA_UCX_GETSERVBYNAME); p = sbuf; ckstrncpy(p, service, 29); while (*p = toupper(*p), *p++) {} p = pbuf; ckstrncpy(p, proto, 29); while (*p = toupper(*p), *p++) {} par.s = &s; par.serv = ""; par.prot = ""; /* reset file pointer or something like that!?!? */ e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s); par.serv = sbuf; par.prot = pbuf; /* that is don't care */ e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s); if ((long)e == -1L) return NULL; if ((e & 1) == 0L) { C$$TRANSLATE(e); return NULL; } if ((s.sb.st[0] & 1) == 0) { C$$SOCK_TRANSLATE(&s.sb.st[0]); return NULL; } /* sent.s_port is supposed to be returned by UCX in network byte order. However, UCX 2.0 through 2.0C did not do this; 2.0D and later do it. But there is no way of knowing which UCX version, so we have a user-settable runtime variable. Note: UCX 2.0 was only for the VAX. */ debug(F101,"UCX getservbyname port","",sent.s_port); debug(F101,"UCX getservbyname ntohs(port)","",ntohs(sent.s_port)); if (ucx_port_bug) { sent.s_port = htons(sent.s_port); debug(F100,"UCX-PORT-BUG ON: swapping bytes","",0); debug(F101,"UCX swapped port","",sent.s_port); debug(F101,"UCX swapped ntohs(port)","",ntohs(sent.s_port)); } return &sent; } #endif /* def OLDIP */ #endif /* DEC_TCPIP */ #endif /* EXCELAN */ int gettcpport() { return(svcnum); } #endif /* TCPSOCKET */ #ifndef NOTCPOPTS #ifndef datageneral int #ifdef CK_ANSIC ck_linger( int sock, int onoff, int timo ) #else ck_linger(sock, onoff, timo) int sock; int onoff; int timo; #endif /* CK_ANSIC */ { /* The following, from William Bader, turns off the socket linger parameter, which makes a close() block until all data is sent. "I don't think that disabling linger can ever cause kermit to lose data, but you telnet to a flaky server (or to our modem server when the modem is in use), disabling linger prevents kermit from hanging on the close if you try to exit." Modified by Jeff Altman to be generally useful. */ #ifdef SOL_SOCKET #ifdef SO_LINGER struct linger set_linger_opt; struct linger get_linger_opt; SOCKOPT_T x; #ifdef IKSD if (!inserver) #endif /* IKSD */ if (sock == -1 || nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH || ttmdm >= 0) { tcp_linger = onoff; tcp_linger_tmo = timo; return(1); } x = sizeof(get_linger_opt); if (getsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&get_linger_opt, &x)) { debug(F111,"TCP ck_linger can't get SO_LINGER",ck_errstr(),errno); } else if (x != sizeof(get_linger_opt)) { #ifdef OS2 struct _linger16 { short s_linger; short s_onoff; } get_linger_opt16, set_linger_opt16; if ( x == sizeof(get_linger_opt16) ) { debug(F111,"TCP setlinger warning: SO_LINGER","len is 16-bit",x); if (getsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&get_linger_opt16, &x) ) { debug(F111, "TCP ck_linger can't get SO_LINGER",ck_errstr(),errno); } else if (get_linger_opt16.s_onoff != onoff || get_linger_opt16.s_linger != timo) { set_linger_opt16.s_onoff = onoff; set_linger_opt16.s_linger = timo; if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&set_linger_opt16, sizeof(set_linger_opt16)) ) { debug(F111, "TCP ck_linger can't set SO_LINGER", ck_errstr(), errno ); tcp_linger = get_linger_opt16.s_onoff; tcp_linger_tmo = get_linger_opt16.s_linger; } else { debug(F101, "TCP ck_linger new SO_LINGER","", set_linger_opt16.s_onoff); tcp_linger = set_linger_opt16.s_onoff; tcp_linger_tmo = set_linger_opt16.s_linger; return 1; } } else { debug(F101,"TCP ck_linger SO_LINGER unchanged","", get_linger_opt16.s_onoff); tcp_linger = get_linger_opt16.s_onoff; tcp_linger_tmo = get_linger_opt16.s_linger; return 1; } return(0); } #endif /* OS2 */ debug(F111,"TCP ck_linger error: SO_LINGER","len",x); debug(F111,"TCP ck_linger SO_LINGER", "expected len",sizeof(get_linger_opt)); debug(F111,"TCP ck_linger SO_LINGER","linger_opt.l_onoff", get_linger_opt.l_onoff); debug(F111,"TCP linger SO_LINGER","linger_opt.l_linger", get_linger_opt.l_linger); } else if (get_linger_opt.l_onoff != onoff || get_linger_opt.l_linger != timo) { set_linger_opt.l_onoff = onoff; set_linger_opt.l_linger = timo; if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&set_linger_opt, sizeof(set_linger_opt))) { debug(F111,"TCP ck_linger can't set SO_LINGER",ck_errstr(),errno); tcp_linger = get_linger_opt.l_onoff; tcp_linger_tmo = get_linger_opt.l_linger; } else { debug(F101, "TCP ck_linger new SO_LINGER", "", set_linger_opt.l_onoff ); tcp_linger = set_linger_opt.l_onoff; tcp_linger_tmo = set_linger_opt.l_linger; return 1; } } else { debug(F101,"TCP ck_linger SO_LINGER unchanged","", get_linger_opt.l_onoff); tcp_linger = get_linger_opt.l_onoff; tcp_linger_tmo = get_linger_opt.l_linger; return 1; } #else debug(F100,"TCP ck_linger SO_LINGER not defined","",0); #endif /* SO_LINGER */ #else debug(F100,"TCP ck_linger SO_SOCKET not defined","",0); #endif /* SOL_SOCKET */ return(0); } int #ifdef CK_ANSIC sendbuf( int sock, int size ) #else sendbuf(sock,size) int sock; int size; #endif /* CK_ANSIC */ { /* The following, from William Bader, allows changing of socket buffer sizes, in case that might affect performance. Modified by Jeff Altman to be generally useful. */ #ifdef SOL_SOCKET #ifdef SO_SNDBUF int i, j; SOCKOPT_T x; #ifdef IKSD if (!inserver) #endif /* IKSD */ if (sock == -1 || nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH || ttmdm >= 0) { tcp_sendbuf = size; return 1; } x = sizeof(i); if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) { debug(F111,"TCP sendbuf can't get SO_SNDBUF",ck_errstr(),errno); } else if (x != sizeof(i)) { #ifdef OS2 short i16,j16; if (x == sizeof(i16)) { debug(F111,"TCP sendbuf warning: SO_SNDBUF","len is 16-bit",x); if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&i16, &x) ) { debug(F111,"TCP sendbuf can't get SO_SNDBUF", ck_errstr(),errno); } else if (size <= 0) { tcp_sendbuf = i16; debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i16); return 1; } else if (i16 != size) { j16 = size; if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&j16, sizeof(j16)) ) { debug(F111,"TCP sendbuf can't set SO_SNDBUF", ck_errstr(),errno); } else { debug(F101,"TCP sendbuf old SO_SNDBUF","",i16); debug(F101,"TCP sendbuf new SO_SNDBUF","",j16); tcp_sendbuf = size; return 1; } } else { debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i16); tcp_sendbuf = size; return 1; } return(0); } #endif /* OS2 */ debug(F111,"TCP sendbuf error: SO_SNDBUF","len",x); debug(F111,"TCP sendbuf SO_SNDBUF","expected len",sizeof(i)); debug(F111,"TCP sendbuf SO_SNDBUF","i",i); } else if (size <= 0) { tcp_sendbuf = i; debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i); return 1; } else if (i != size) { j = size; if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&j, sizeof(j))) { debug(F111,"TCP sendbuf can't set SO_SNDBUF",ck_errstr(),errno); tcp_sendbuf = i; } else { debug(F101,"TCP sendbuf old SO_SNDBUF","",i); debug(F101,"TCP sendbuf new SO_SNDBUF","",j); tcp_sendbuf = size; return 1; } } else { debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i); tcp_sendbuf = size; return 1; } #else debug(F100,"TCP sendbuf SO_SNDBUF not defined","",0); #endif /* SO_SNDBUF */ #else debug(F100,"TCP sendbuf SO_SOCKET not defined","",0); #endif /* SOL_SOCKET */ return(0); } int #ifdef CK_ANSIC recvbuf( int sock, int size ) #else recvbuf(sock,size) int sock; int size; #endif /* CK_ANSIC */ { /* The following, from William Bader, allows changing of socket buffer sizes, in case that might affect performance. Modified by Jeff Altman to be generally useful. */ #ifdef SOL_SOCKET #ifdef SO_RCVBUF int i, j; SOCKOPT_T x; #ifdef IKSD if (!inserver) #endif /* IKSD */ if (sock == -1 || nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH || ttmdm >= 0) { tcp_recvbuf = size; return(1); } x = sizeof(i); if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) { debug(F111,"TCP recvbuf can't get SO_RCVBUF",ck_errstr(),errno); } else if (x != sizeof(i)) { #ifdef OS2 short i16,j16; if ( x == sizeof(i16) ) { debug(F111,"TCP recvbuf warning: SO_RCVBUF","len is 16-bit",x); if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&i16, &x) ) { debug(F111,"TCP recvbuf can't get SO_RCVBUF", ck_errstr(),errno); } else if (size <= 0) { tcp_recvbuf = i16; debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i16); return 1; } else if (i16 != size) { j16 = size; if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j16, sizeof(j16))) { debug(F111,"TCP recvbuf can' set SO_RCVBUF", ck_errstr(),errno); } else { debug(F101,"TCP recvbuf old SO_RCVBUF","",i16); debug(F101,"TCP recvbuf new SO_RCVBUF","",j16); tcp_recvbuf = size; return 1; } } else { debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i16); tcp_recvbuf = size; return 1; } return(0); } #endif /* OS2 */ debug(F111,"TCP recvbuf error: SO_RCVBUF","len",x); debug(F111,"TCP recvbuf SO_RCVBUF","expected len",sizeof(i)); debug(F111,"TCP recvbuf SO_RCVBUF","i",i); } else if (size <= 0) { tcp_recvbuf = i; debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i); return 1; } else if (i != size) { j = size; if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j, sizeof(j))) { debug(F111,"TCP recvbuf can't set SO_RCVBUF",ck_errstr(),errno); tcp_recvbuf = i; } else { debug(F101,"TCP recvbuf old SO_RCVBUF","",i); debug(F101,"TCP recvbuf new SO_RCVBUF","",j); tcp_recvbuf = size; return 1; } } else { debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i); tcp_recvbuf = size; return 1; } #else debug(F100,"TCP recvbuf SO_RCVBUF not defined","",0); #endif /* SO_RCVBUF */ #else debug(F100,"TCP recvbuf SO_SOCKET not defined","",0); #endif /* SOL_SOCKET */ return 0; } int #ifdef CK_ANSIC keepalive( int sock, int onoff ) #else keepalive(sock,onoff) int sock; int onoff; #endif /* CK_ANSIC */ { #ifdef SOL_SOCKET #ifdef SO_KEEPALIVE int get_keepalive_opt; int set_keepalive_opt; SOCKOPT_T x; debug(F111,"TCP keepalive","sock",sock); debug(F111,"TCP keepalive","nettype",nettype); debug(F111,"TCP keepalive","ttmdm",ttmdm); #ifdef IKSD if (!inserver) #endif /* IKSD */ if (sock == -1 || nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH || ttmdm >= 0) { tcp_keepalive = onoff; return 1; } x = sizeof(get_keepalive_opt); if (getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&get_keepalive_opt, &x)) { debug(F111,"TCP keepalive can't get SO_KEEPALIVE",ck_errstr(),errno); } else if (x != sizeof(get_keepalive_opt)) { #ifdef OS2 short get_keepalive_opt16; short set_keepalive_opt16; if (x == sizeof(get_keepalive_opt16)) { debug(F111,"TCP keepalive warning: SO_KEEPALIVE", "len is 16-bit",x); if (getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&get_keepalive_opt16, &x) ) { debug(F111, "TCP keepalive can't get SO_KEEPALIVE", ck_errstr(), errno ); } else if (get_keepalive_opt16 != onoff) { set_keepalive_opt16 = onoff; if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&set_keepalive_opt16, sizeof(set_keepalive_opt16)) ) { debug(F111, "TCP keepalive can't clear SO_KEEPALIVE", ck_errstr(), errno ); tcp_keepalive = get_keepalive_opt16; } else { debug(F101, "TCP keepalive new SO_KEEPALIVE","", set_keepalive_opt16); tcp_keepalive = set_keepalive_opt16; return 1; } } else { debug(F101,"TCP keepalive SO_KEEPALIVE unchanged","", get_keepalive_opt16); tcp_keepalive = onoff; return 1; } return(0); } #endif /* OS2 */ debug(F111,"TCP keepalive error: SO_KEEPALIVE","len",x); debug(F111, "TCP keepalive SO_KEEPALIVE", "expected len", sizeof(get_keepalive_opt) ); debug(F111, "TCP keepalive SO_KEEPALIVE", "keepalive_opt", get_keepalive_opt ); } else if (get_keepalive_opt != onoff) { set_keepalive_opt = onoff; if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&set_keepalive_opt, sizeof(set_keepalive_opt)) ) { debug(F111, "TCP keepalive can't clear SO_KEEPALIVE", ck_errstr(), errno ); tcp_keepalive = get_keepalive_opt; } else { debug(F101, "TCP keepalive new SO_KEEPALIVE", "", set_keepalive_opt ); tcp_keepalive = onoff; return 1; } } else { debug(F101,"TCP keepalive SO_KEEPALIVE unchanged", "", get_keepalive_opt ); tcp_keepalive = onoff; return 1; } #else debug(F100,"TCP keepalive SO_KEEPALIVE not defined","",0); #endif /* SO_KEEPALIVE */ #else debug(F100,"TCP keepalive SO_SOCKET not defined","",0); #endif /* SOL_SOCKET */ return(0); } int #ifdef CK_ANSIC dontroute( int sock, int onoff ) #else dontroute(sock,onoff) int sock; int onoff; #endif /* CK_ANSIC */ { #ifdef SOL_SOCKET #ifdef SO_DONTROUTE int get_dontroute_opt; int set_dontroute_opt; SOCKOPT_T x; #ifdef IKSD if (!inserver) #endif /* IKSD */ if (sock == -1 || nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH || ttmdm >= 0) { tcp_dontroute = onoff; return 1; } x = sizeof(get_dontroute_opt); if (getsockopt(sock, SOL_SOCKET, SO_DONTROUTE, (char *)&get_dontroute_opt, &x)) { debug(F111,"TCP dontroute can't get SO_DONTROUTE",ck_errstr(),errno); } else if (x != sizeof(get_dontroute_opt)) { #ifdef OS2 short get_dontroute_opt16; short set_dontroute_opt16; if (x == sizeof(get_dontroute_opt16)) { debug(F111,"TCP dontroute warning: SO_DONTROUTE", "len is 16-bit",x); if (getsockopt(sock, SOL_SOCKET, SO_DONTROUTE, (char *)&get_dontroute_opt16, &x) ) { debug(F111, "TCP dontroute can't get SO_DONTROUTE", ck_errstr(), errno ); } else if (get_dontroute_opt16 != onoff) { set_dontroute_opt16 = onoff; if (setsockopt(sock, SOL_SOCKET, SO_DONTROUTE, (char *)&set_dontroute_opt16, sizeof(set_dontroute_opt16)) ) { debug(F111, "TCP dontroute can't clear SO_DONTROUTE", ck_errstr(), errno ); tcp_dontroute = get_dontroute_opt16; } else { debug(F101, "TCP dontroute new SO_DONTROUTE","", set_dontroute_opt16); tcp_dontroute = set_dontroute_opt16; return 1; } } else { debug(F101,"TCP dontroute SO_DONTROUTE unchanged","", get_dontroute_opt16); tcp_dontroute = onoff; return 1; } return(0); } #endif /* OS2 */ debug(F111,"TCP dontroute error: SO_DONTROUTE","len",x); debug(F111, "TCP dontroute SO_DONTROUTE", "expected len", sizeof(get_dontroute_opt) ); debug(F111, "TCP dontroute SO_DONTROUTE", "dontroute_opt", get_dontroute_opt ); } else if (get_dontroute_opt != onoff) { set_dontroute_opt = onoff; if (setsockopt(sock, SOL_SOCKET, SO_DONTROUTE, (char *)&set_dontroute_opt, sizeof(set_dontroute_opt)) ) { debug(F111, "TCP dontroute can't clear SO_DONTROUTE", ck_errstr(), errno ); tcp_dontroute = get_dontroute_opt; } else { debug(F101, "TCP dontroute new SO_DONTROUTE", "", set_dontroute_opt ); tcp_dontroute = onoff; return 1; } } else { debug(F101,"TCP dontroute SO_DONTROUTE unchanged", "", get_dontroute_opt ); tcp_dontroute = onoff; return 1; } #else debug(F100,"TCP dontroute SO_DONTROUTE not defined","",0); #endif /* SO_DONTROUTE */ #else debug(F100,"TCP dontroute SO_SOCKET not defined","",0); #endif /* SOL_SOCKET */ return(0); } int #ifdef CK_ANSIC no_delay( int sock, int onoff ) #else no_delay(sock,onoff) int sock; int onoff; #endif /* CK_ANSIC */ { #ifdef SOL_SOCKET #ifdef TCP_NODELAY int get_nodelay_opt; int set_nodelay_opt; SOCKOPT_T x; #ifdef IKSD if (!inserver) #endif /* IKSD */ if (sock == -1 || nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH || ttmdm >= 0) { tcp_nodelay = onoff; return(1); } x = sizeof(get_nodelay_opt); if (getsockopt(sock,IPPROTO_TCP,TCP_NODELAY, (char *)&get_nodelay_opt,&x)) { debug(F111, "TCP no_delay can't get TCP_NODELAY", ck_errstr(), errno); } else if (x != sizeof(get_nodelay_opt)) { #ifdef OS2 short get_nodelay_opt16; short set_nodelay_opt16; if (x == sizeof(get_nodelay_opt16)) { debug(F111,"TCP no_delay warning: TCP_NODELAY","len is 16-bit",x); if (getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&get_nodelay_opt16, &x) ) { debug(F111, "TCP no_delay can't get TCP_NODELAY", ck_errstr(), errno); } else if (get_nodelay_opt16 != onoff) { set_nodelay_opt16 = onoff; if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&set_nodelay_opt16, sizeof(set_nodelay_opt16)) ) { debug(F111, "TCP no_delay can't clear TCP_NODELAY", ck_errstr(), errno); tcp_nodelay = get_nodelay_opt16; } else { debug(F101, "TCP no_delay new TCP_NODELAY", "", set_nodelay_opt16); tcp_nodelay = onoff; return 1; } } else { debug(F101,"TCP no_delay TCP_NODELAY unchanged","", get_nodelay_opt16); tcp_nodelay = onoff; return 1; } return(0); } #endif /* OS2 */ debug(F111,"TCP no_delay error: TCP_NODELAY","len",x); debug(F111,"TCP no_delay TCP_NODELAY","expected len", sizeof(get_nodelay_opt)); debug(F111,"TCP no_delay TCP_NODELAY","nodelay_opt",get_nodelay_opt); } else if (get_nodelay_opt != onoff) { set_nodelay_opt = onoff; if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&set_nodelay_opt, sizeof(set_nodelay_opt))) { debug(F111, "TCP no_delay can't clear TCP_NODELAY", ck_errstr(), errno ); tcp_nodelay = get_nodelay_opt; } else { debug(F101,"TCP no_delay new TCP_NODELAY","",set_nodelay_opt); tcp_nodelay = onoff; return 1; } } else { debug(F101,"TCP no_delay TCP_NODELAY unchanged","",get_nodelay_opt); tcp_nodelay = onoff; return(1); } #else debug(F100,"TCP no_delay TCP_NODELAY not defined","",0); #endif /* TCP_NODELAY */ #else debug(F100,"TCP no_delay SO_SOCKET not defined","",0); #endif /* SOL_SOCKET */ return 0; } #endif /* datageneral */ #endif /* NOTCPOPTS */ #ifdef SUNX25 #ifndef X25_WR_FACILITY /* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */ void bzero(s,n) char *s; int n; { memset(s,0,n); } #endif /* X25_WR_FACILITY */ #endif /* SUNX25 */ #ifdef TCPSOCKET #ifndef OS2 #ifndef NOLISTEN #ifdef BSDSELECT #ifndef VMS #ifndef BELLV10 #ifndef datageneral #ifdef hp9000s500 /* HP-9000/500 HP-U 5.21 */ #include #else /****** THIS SECTION ADDED BY STEVE RANCE - OS9 NETWORK SERVER * ------------------------------------------------------ * * Due to OS9's Lack of a select() call, the following seems to be * enough to fool the rest of the code into compiling. The only * effect that I can see is using control L to refresh the status * display gets qued up until some network packets arrive. * * This solution is by no means elegant but works enough to be * a (the) solution. * * Also with the defines I had specified in my makefile I had to * have an #endif right at the end of the file when compiling. * I did not bother speding time to find out why. * * COPTS = -to=osk -d=OSK -d=TCPSOCKET -d=SELECT -d=VOID=void -d=SIG_V \ * -d=DYNAMIC -d=PARSENSE -d=KANJI -d=MYCURSES -d=ZFCDAT \ * -d=CK_APC -d=CK_REDIR -d=RENAME -d=CK_TTYFD -d=NOOLDMODEMS \ * -d=CK_ANSIC -d=CK_XYZ -tp=68040d -l=netdb.l -l=socklib.l \ * -l=termlib.l -l=math.l -l=sys_clib.l * * stever@ozemail.com.au */ #ifdef OSK #define BSDSELECT /* switch on BSD select code */ #define FD_SETSIZE 32 /* Max # of paths in OS9 */ #define FD_ZERO(p) ((*p)=0) #define FD_SET(n,b) ((*b)|=(1<<(n))) #define FD_ISSET(n,b) 1 /* always say data is ready */ #define select(a,b,c,d,e) 1 /* always say 1 path has data */ typedef int fd_set; /* keep BSD Code Happy */ struct timeval {int tv_sec,tv_usec;}; /* keep BSD Code Happy */ /****** END OF OS9 MODS FROM STEVE RANCE **************************/ #endif /* OSK */ #include #endif /* hp9000s500 */ #endif /* datageneral */ #endif /* BELLV10 */ #endif /* VMS */ #ifdef SELECT_H #include #endif /* SELECT_H */ #endif /* BSDSELECT */ #ifdef SELECT #ifdef CK_SCOV5 #include #endif /* CK_SCOV5 */ #endif /* SELECT */ #ifdef NOTUSED /* T C P S O C K E T _ O P E N -- Open a preexisting socket number */ int tcpsocket_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo { int on = 1; static struct servent *service, servrec; static struct hostent *host; static struct sockaddr_in saddr; static #ifdef UCX50 unsigned #endif /* UCX50 */ int saddrlen; #ifdef BSDSELECT fd_set rfds; struct timeval tv; #else #ifdef BELLSELECT fd_set rfds; #else fd_set rfds; fd_set rfds; struct timeval { long tv_sec; long tv_usec; } tv; #endif /* BELLSELECT */ #endif /* BSDSELECT */ debug(F101,"tcpsocket_open nett","",nett); *ipaddr = '\0'; if (nett != NET_TCPB) return(-1); /* BSD socket support */ netclos(); /* Close any previous connection. */ ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */ #ifdef COMMENT /* Jeff's version from 30 Dec 2005 doesn't inhibit Telnet */ if (ttnproto != NP_TCPRAW && ttnproto != NP_SSL_RAW && ttnproto != NP_TLS_RAW) ttnproto = NP_NONE; /* No protocol selected yet. */ #else /* fdc's version from 4 Dec 2005 works ok */ if (ttnproto != NP_TCPRAW) ttnproto = NP_NONE; /* No protocol selected yet. */ #endif /* COMMENT */ debug(F110,"tcpsocket_open namecopy",namecopy,0); /* Assign the socket number to ttyfd and then fill in tcp structures */ ttyfd = atoi(&name[1]); debug(F111,"tcpsocket_open","ttyfd",ttyfd); #ifndef NOTCPOPTS #ifdef SOL_SOCKET setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #ifndef datageneral #ifdef TCP_NODELAY no_delay(ttyfd,tcp_nodelay); #endif /* TCP_NODELAY */ #ifdef SO_KEEPALIVE keepalive(ttyfd,tcp_keepalive); #endif /* SO_KEEPALIVE */ #ifdef SO_LINGER ck_linger(ttyfd,tcp_linger, tcp_linger_tmo); #endif /* SO_LINGER */ #ifdef SO_SNDBUF sendbuf(ttyfd,tcp_sendbuf); #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF recvbuf(ttyfd,tcp_recvbuf); #endif /* SO_RCVBUF */ #endif /* datageneral */ #endif /* SOL_SOCKET */ #endif /* NOTCPOPTS */ #ifdef NT_TCP_OVERLAPPED OverlappedWriteInit(); OverlappedReadInit(); #endif /* NT_TCP_OVERLAPPED */ /* Get the name of the host we are connected to */ saddrlen = sizeof(saddr); getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen); ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20); if (tcp_rdns == SET_ON #ifdef CK_KERBEROS || tcp_rdns == SET_AUTO && (ck_krb5_is_installed() || ck_krb4_is_installed()) #endif /* CK_KERBEROS */ #ifndef NOHTTP && (tcp_http_proxy == NULL) #endif /* NOHTTP */ #ifdef CK_SSL && !(ssl_only_flag || tls_only_flag) #endif /* CK_SSL */ ) { /* Reverse DNS */ if (!quiet) { printf(" Reverse DNS Lookup... "); fflush(stdout); } host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET); debug(F110,"tcpsocket_open gethostbyaddr",host ? "OK" : "FAILED",0); if (host) { host = ck_copyhostent(host); debug(F100,"tcpsocket_open gethostbyaddr != NULL","",0); if (!quiet) { printf("(OK)\n"); fflush(stdout); } ckstrncpy(name, host->h_name, 80); ckstrncat(name, ":", 80); ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)), 80); if (!quiet #ifndef NOICP && !doconx #endif /* NOICP */ ) printf("%s connected on port %d\n", host->h_name, ntohs(saddr.sin_port) ); } else if (!quiet) printf("Failed\n"); } else if (!quiet) printf("(OK)\n"); if (tcp_rdns != SET_ON || !host) { ckstrncpy(name,ipaddr,80); ckstrncat(name,":",80); ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80); if (!quiet #ifdef NOICP && !doconx #endif /* NOICP */ ) printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port)); } if (!quiet) fflush(stdout); ttnet = nett; /* TCP/IP (sockets) network */ #ifdef RLOGCODE if (ntohs(saddr.sin_port) == 513) ttnproto = NP_LOGIN; else #endif /* RLOGCODE */ /* Assume the service is TELNET. */ #ifdef COMMENT /* Jeff's code from 2005/12/30 */ if (ttnproto != NP_TCP_RAW && ttnproto != NP_SSL_RAW && ttnproto != NP_TLS_RAW) #else /* fdc's code from 2005/12/04 */ if (ttnproto != NP_TCPRAW) #endif /* COMMENT */ ttnproto = NP_TELNET; /* Yes, set global flag. */ #ifdef CK_SECURITY /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */ ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ? host->h_name : ipaddr, ipaddr, uidbuf, ttyfd ); #endif /* CK_SECURITY */ if (tn_ini() < 0) /* Start/Reset TELNET negotiations */ if (ttchk() < 0) /* Did it fail due to connect loss? */ return(-1); if (*lcl < 0) *lcl = 1; /* Local mode. */ return(0); /* Done. */ } #endif /* NOTUSED */ /* T C P S R V _ O P E N -- Open a TCP/IP Server connection */ /* Calling conventions same as ttopen(), except third argument is network type rather than modem type. */ int #ifdef CK_ANSIC tcpsrv_open( char * name, int * lcl, int nett, int timo ) #else tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; #endif /* CK_ANSIC */ { char *p; int i, x; SOCKOPT_T on = 1; int ready_to_accept = 0; static struct servent *service, *service2, servrec; static struct hostent *host; static struct sockaddr_in saddr; struct sockaddr_in l_addr; GSOCKNAME_T l_slen; #ifdef UCX50 static u_int saddrlen; #else static SOCKOPT_T saddrlen; #endif /* UCX50 */ #ifdef BSDSELECT fd_set rfds; struct timeval tv; #else #ifdef BELLSELCT fd_set rfds; #else fd_set rfds; struct timeval { long tv_sec; long tv_usec; } tv; #endif /* BELLSELECT */ #endif /* BSDSELECT */ #ifdef CK_SSL int ssl_failed = 0; #endif /* CK_SSL */ debug(F101,"tcpsrv_open nett","",nett); *ipaddr = '\0'; if (nett != NET_TCPB) return(-1); /* BSD socket support */ netclos(); /* Close any previous connection. */ ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */ /* Don't do this. */ #ifdef COMMENT /* fdc */ if (ttnproto != NP_TCPRAW) ttnproto = NP_NONE; /* No protocol selected yet. */ #endif /* COMMENT */ #ifdef COMMENT /* Jeff */ if (ttnproto != NP_TCP_RAW && ttnproto != NP_SSL_RAW && ttnproto != NP_TLS_RAW) ttnproto = NP_NONE; /* No protocol selected yet. */ #endif /* COMMENT */ debug(F110,"tcpsrv_open namecopy",namecopy,0); p = namecopy; /* Was a service requested? */ while (*p != '\0' && *p != ':') p++; /* Look for colon */ if (*p == ':') { /* Have a colon */ *p++ = '\0'; /* Get service name or number */ } else { /* Otherwise use kermit */ p = "kermit"; } debug(F110,"tcpsrv_open service requested",p,0); if (isdigit(*p)) { /* Use socket number without lookup */ service = &servrec; service->s_port = htons((unsigned short)atoi(p)); } else { /* Otherwise lookup the service name */ service = getservbyname(p, "tcp"); } if (!service && !strcmp("kermit",p)) { /* Use Kermit service port */ service = &servrec; service->s_port = htons(1649); } #ifdef RLOGCODE if (service && !strcmp("login",p) && service->s_port != htons(513)) { fprintf(stderr, " Warning: login service on port %d instead of port 513\n", ntohs(service->s_port)); fprintf(stderr, " Edit SERVICES file if RLOGIN fails to connect.\n"); debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port)); } #endif /* RLOGCODE */ if (!service) { fprintf(stderr, "Cannot find port for service: %s\n", p); debug(F111,"tcpsrv_open can't get service",p,errno); errno = 0; /* rather than mislead */ return(-1); } /* If we currently have a listen active but port has changed then close */ debug(F101,"tcpsrv_open checking previous connection","",tcpsrfd); debug(F101,"tcpsrv_open previous tcpsrv_port","",tcpsrv_port); if (tcpsrfd != -1 && tcpsrv_port != ntohs((unsigned short)service->s_port)) { debug(F100,"tcpsrv_open closing previous connection","",0); #ifdef TCPIPLIB socket_close(tcpsrfd); #else close(tcpsrfd); #endif /* TCPIPLIB */ tcpsrfd = -1; } debug(F100,"tcpsrv_open tcpsrfd","",tcpsrfd); if (tcpsrfd == -1) { /* Set up socket structure and get host address */ bzero((char *)&saddr, sizeof(saddr)); debug(F100,"tcpsrv_open bzero ok","",0); saddr.sin_family = AF_INET; if (tcp_address) { #ifdef INADDRX inaddrx = inet_addr(tcp_address); saddr.sin_addr.s_addr = *(unsigned long *)&inaddrx; #else saddr.sin_addr.s_addr = inet_addr(tcp_address); #endif /* INADDRX */ } else saddr.sin_addr.s_addr = INADDR_ANY; /* Get a file descriptor for the connection. */ saddr.sin_port = service->s_port; ipaddr[0] = '\0'; debug(F100,"tcpsrv_open calling socket","",0); if ((tcpsrfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("TCP socket error"); debug(F101,"tcpsrv_open socket error","",errno); return (-1); } errno = 0; /* Specify the Port may be reused */ debug(F100,"tcpsrv_open calling setsockopt","",0); x = setsockopt(tcpsrfd, SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof on); debug(F101,"tcpsrv_open setsockopt","",x); /* Now bind to the socket */ printf("\nBinding socket to port %d ...\n", ntohs((unsigned short)service->s_port)); if (bind(tcpsrfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { i = errno; /* Save error code */ #ifdef TCPIPLIB socket_close(tcpsrfd); #else /* TCPIPLIB */ close(tcpsrfd); #endif /* TCPIPLIB */ tcpsrfd = -1; tcpsrv_port = 0; ttyfd = -1; wasclosed = 1; errno = i; /* and report this error */ debug(F101,"tcpsrv_open bind errno","",errno); printf("?Unable to bind to socket (errno = %d)\n",errno); return(-1); } debug(F100,"tcpsrv_open bind OK","",0); printf("Listening ...\n"); if (listen(tcpsrfd, 15) < 0) { i = errno; /* Save error code */ #ifdef TCPIPLIB socket_close(tcpsrfd); #else /* TCPIPLIB */ close(tcpsrfd); #endif /* TCPIPLIB */ tcpsrfd = -1; tcpsrv_port = 0; ttyfd = -1; wasclosed = 1; errno = i; /* And report this error */ debug(F101,"tcpsrv_open listen errno","",errno); return(-1); } debug(F100,"tcpsrv_open listen OK","",0); tcpsrv_port = ntohs((unsigned short)service->s_port); } #ifdef CK_SSL if (ck_ssleay_is_installed()) { if (!ssl_tn_init(SSL_SERVER)) { ssl_failed = 1; if (bio_err!=NULL) { BIO_printf(bio_err,"do_ssleay_init() failed\n"); ERR_print_errors(bio_err); } else { fflush(stderr); fprintf(stderr,"do_ssleay_init() failed\n"); ERR_print_errors_fp(stderr); } if (tls_only_flag || ssl_only_flag) { #ifdef TCPIPLIB socket_close(ttyfd); socket_close(tcpsrfd); #else /* TCPIPLIB */ close(ttyfd); close(tcpsrfd); #endif /* TCPIPLIB */ ttyfd = -1; wasclosed = 1; tcpsrfd = -1; tcpsrv_port = 0; return(-1); } /* we will continue to accept the connection */ /* without SSL or TLS support unless required. */ if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU ) TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF; if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU ) TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF; if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU ) TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF; if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU ) TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF; } } #endif /* CK_SSL */ printf("\nWaiting to Accept a TCP/IP connection on port %d ...\n", ntohs((unsigned short)service->s_port)); saddrlen = sizeof(saddr); #ifdef BSDSELECT tv.tv_sec = tv.tv_usec = 0L; if (timo < 0) tv.tv_usec = (long) -timo * 10000L; else tv.tv_sec = timo; debug(F101,"tcpsrv_open BSDSELECT","",timo); #else debug(F101,"tcpsrv_open not BSDSELECT","",timo); #endif /* BSDSELECT */ if (timo) { while (!ready_to_accept) { #ifdef BSDSELECT FD_ZERO(&rfds); FD_SET(tcpsrfd, &rfds); ready_to_accept = ((select(FD_SETSIZE, #ifdef HPUX #ifdef HPUX1010 (fd_set *) #else (int *) #endif /* HPUX1010 */ #else #ifdef __DECC #ifdef INTSELECT (int *) #else /* def INTSELECT */ (fd_set *) #endif /* def INTSELECT [else] */ #endif /* __DECC */ #endif /* HPUX */ &rfds, NULL, NULL, &tv) > 0) && FD_ISSET(tcpsrfd, &rfds)); #else /* BSDSELECT */ #ifdef IBMSELECT #define ck_sleepint 250 ready_to_accept = (select(&tcpsrfd, 1, 0, 0, timo < 0 ? -timo : (timo > 0 ? timo * 1000L : ck_sleepint)) == 1 ); #else #ifdef BELLSELECT FD_ZERO(rfds); FD_SET(tcpsrfd, rfds); ready_to_accept = ((select(128, rfds, NULL, NULL, timo < 0 ? -timo : (timo > 0 ? timo * 1000L)) > 0) && FD_ISSET(tcpsrfd, rfds)); #else /* Try this - what's the worst that can happen... */ FD_ZERO(&rfds); FD_SET(tcpsrfd, &rfds); ready_to_accept = ((select(FD_SETSIZE, (fd_set *) &rfds, NULL, NULL, &tv) > 0) && FD_ISSET(tcpsrfd, &rfds)); #endif /* BELLSELECT */ #endif /* IBMSELECT */ #endif /* BSDSELECT */ } } if (ready_to_accept || timo == 0) { if ((ttyfd = accept(tcpsrfd, (struct sockaddr *)&saddr,&saddrlen)) < 0) { i = errno; /* save error code */ #ifdef TCPIPLIB socket_close(tcpsrfd); #else /* TCPIPLIB */ close(tcpsrfd); #endif /* TCPIPLIB */ ttyfd = -1; wasclosed = 1; tcpsrfd = -1; tcpsrv_port = 0; errno = i; /* and report this error */ debug(F101,"tcpsrv_open accept errno","",errno); return(-1); } setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #ifndef NOTCPOPTS #ifndef datageneral #ifdef SOL_SOCKET #ifdef TCP_NODELAY no_delay(ttyfd,tcp_nodelay); debug(F101,"tcpsrv_open no_delay","",tcp_nodelay); #endif /* TCP_NODELAY */ #ifdef SO_KEEPALIVE keepalive(ttyfd,tcp_keepalive); debug(F101,"tcpsrv_open keepalive","",tcp_keepalive); #endif /* SO_KEEPALIVE */ #ifdef SO_LINGER ck_linger(ttyfd,tcp_linger, tcp_linger_tmo); debug(F101,"tcpsrv_open linger","",tcp_linger_tmo); #endif /* SO_LINGER */ #ifdef SO_SNDBUF sendbuf(ttyfd,tcp_sendbuf); #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF recvbuf(ttyfd,tcp_recvbuf); #endif /* SO_RCVBUF */ #endif /* SOL_SOCKET */ #endif /* datageneral */ #endif /* NOTCPOPTS */ ttnet = nett; /* TCP/IP (sockets) network */ tcp_incoming = 1; /* This is an incoming connection */ sstelnet = 1; /* Do server-side Telnet protocol */ /* See if the service is TELNET. */ x = (unsigned short)service->s_port; service2 = getservbyname("telnet", "tcp"); if (service2 && x == service2->s_port) { #ifdef COMMENT /* Jeff 2005/12/30 */ if (ttnproto != NP_TCPRAW && /* Yes... */ ttnproto != NP_SSL_RAW && ttnproto != NP_TLS_RAW) /* and if raw port not requested */ #else /* fdc 2005/12/04 */ if (ttnproto != NP_TCPRAW) /* Yes and if raw port not requested */ #endif /* */ ttnproto = NP_TELNET; /* set protocol to TELNET. */ } ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20); if (tcp_rdns) { if (!quiet) { printf(" Reverse DNS Lookup... "); fflush(stdout); } if ((host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET))) { host = ck_copyhostent(host); debug(F100,"tcpsrv_open gethostbyaddr != NULL","",0); if (!quiet) { printf("(OK)\n"); fflush(stdout); } name[0] = '*'; ckstrncpy(&name[1],host->h_name,78); ckstrncat(name,":",80-strlen(name)); ckstrncat(name,p,80-strlen(name)); if (!quiet #ifndef NOICP && !doconx #endif /* NOICP */ ) printf("%s connected on port %s\n",host->h_name,p); } else { if (!quiet) printf("Failed.\n"); } } else if (!quiet) printf("(OK)\n"); if (!tcp_rdns || !host) { ckstrncpy(name,ipaddr,80); ckstrncat(name,":",80); ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80); if (!quiet #ifndef NOICP && !doconx #endif /* NOICP */ ) printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port)); } if (!quiet) fflush(stdout); #ifdef CK_SECURITY /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */ ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ? (char *)host->h_name : ipaddr, ipaddr, uidbuf, ttyfd ); #endif /* CK_SECURITY */ #ifdef CK_SSL if (ck_ssleay_is_installed() && !ssl_failed) { if (ck_ssl_incoming(ttyfd) < 0) { #ifdef TCPIPLIB socket_close(ttyfd); socket_close(tcpsrfd); #else /* TCPIPLIB */ close(ttyfd); close(tcpsrfd); #endif /* TCPIPLIB */ ttyfd = -1; wasclosed = 1; tcpsrfd = -1; tcpsrv_port = 0; return(-1); } } #endif /* CK_SSL */ #ifndef datageneral /* Find out our own IP address. */ l_slen = sizeof(l_addr); bzero((char *)&l_addr, l_slen); #ifndef EXCELAN if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) { char * s = (char *)inet_ntoa(l_addr.sin_addr); ckstrncpy(myipaddr, s,20); debug(F110,"getsockname",myipaddr,0); } #endif /* EXCELAN */ #endif /* datageneral */ if (tn_ini() < 0) /* Start TELNET negotiations. */ if (ttchk() < 0) { /* Disconnected? */ i = errno; /* save error code */ #ifdef TCPIPLIB socket_close(tcpsrfd); #else /* TCPIPLIB */ close(tcpsrfd); #endif /* TCPIPLIB */ ttyfd = -1; wasclosed = 1; tcpsrfd = -1; tcpsrv_port = 0; errno = i; /* and report this error */ debug(F101,"tcpsrv_open accept errno","",errno); return(-1); } debug(F101,"tcpsrv_open service","",x); if (*lcl < 0) /* Set local mode. */ *lcl = 1; #ifdef CK_KERBEROS #ifdef KRB5_U2U if ( ttnproto == NP_K5U2U ) { if (k5_user_to_user_server_auth() != 0) { i = errno; /* save error code */ #ifdef TCPIPLIB socket_close(tcpsrfd); #else /* TCPIPLIB */ close(tcpsrfd); #endif /* TCPIPLIB */ ttyfd = -1; wasclosed = 1; tcpsrfd = -1; tcpsrv_port = 0; errno = i; /* and report this error */ debug(F101,"tcpsrv_open accept errno","",errno); return(-1); } } #endif /* KRB5_U2U */ #endif /* CK_KERBEROS */ return(0); /* Done. */ } else { i = errno; /* save error code */ #ifdef TCPIPLIB socket_close(tcpsrfd); #else /* TCPIPLIB */ close(tcpsrfd); #endif /* TCPIPLIB */ ttyfd = -1; wasclosed = 1; tcpsrfd = -1; tcpsrv_port = 0; errno = i; /* and report this error */ debug(F101,"tcpsrv_open accept errno","",errno); return(-1); } } #endif /* NOLISTEN */ #endif /* OS2 */ #endif /* TCPSOCKET */ #endif /* NONET */ #ifdef TCPSOCKET char * #ifdef CK_ANSIC ckname2addr( char * name ) #else ckname2addr(name) char * name; #endif /* CK_ANSIC */ { #ifdef HPUX5 return(""); #else struct hostent *host; if (name == NULL || *name == '\0') return(""); host = gethostbyname(name); if ( host ) { host = ck_copyhostent(host); return(inet_ntoa(*((struct in_addr *) host->h_addr))); } return(""); #endif /* HPUX5 */ } char * #ifdef CK_ANSIC ckaddr2name( char * addr ) #else ckaddr2name(addr) char * addr; #endif /* CK_ANSIC */ { #ifdef HPUX5 return(""); #else struct hostent *host; struct in_addr sin_addr; if (addr == NULL || *addr == '\0') return(""); sin_addr.s_addr = inet_addr(addr); host = gethostbyaddr((char *)&sin_addr,4,AF_INET); if (host) { host = ck_copyhostent(host); return((char *)host->h_name); } return(""); #endif /* HPUX5 */ } #endif /* TCPSOCKET */ unsigned long peerxipaddr = 0L; char * ckgetpeer() { #ifdef TCPSOCKET static char namebuf[256]; static struct hostent *host; static struct sockaddr_in saddr; #ifdef GPEERNAME_T static GPEERNAME_T saddrlen; #else #ifdef PTX static size_t saddrlen; #else #ifdef AIX42 /* It's size_t in 4.2 but int in 4.1 and earlier. */ /* Note: the 4.2 man page lies; believe socket.h. */ static size_t saddrlen; #else #ifdef UNIXWARE static size_t saddrlen; #else /* UNIXWARE */ #ifdef DEC_TCPIP /* 2010-03-08 SMS. * Coincidentally, the condition for integer arguments in select(), * which is actually "defined( _DECC_V4_SOURCE)", works for an integer * argument in getpeername(). Sadly, due to a lack of foresight, * "defined( _DECC_V4_SOURCE)" doesn't work with DEC C V4.0, so the * user-specified INTSELECT is used instead. Most likely, "size_t" * should be used instead of "unsigned int", but I'm a coward. */ #ifdef INTSELECT static int saddrlen; #else /* def INTSELECT */ static unsigned int saddrlen; #endif /* def INTSELECT [else] */ #else #ifdef MACOSX10 static unsigned int saddrlen; #else #ifdef NT static int saddrlen; #else #ifdef CK_64BIT static socklen_t saddrlen; #else static int saddrlen; #endif /* CK_64BIT */ #endif /* NT */ #endif /* MACOSX10 */ #endif /* DEC_TCPIP */ #endif /* UNIXWARE */ #endif /* AIX42 */ #endif /* PTX */ #endif /* GPEERNAME_T */ saddrlen = sizeof(saddr); if (getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen) < 0) { debug(F111,"ckgetpeer failure",ckitoa(ttyfd),errno); return(NULL); } host = gethostbyaddr((char *)&saddr.sin_addr,4,AF_INET); if (host) { host = ck_copyhostent(host); ckstrncpy(namebuf,(char *)host->h_name,80); } else { ckstrncpy(namebuf,(char *)inet_ntoa(saddr.sin_addr),80); } peerxipaddr = ntohl(saddr.sin_addr.s_addr); debug(F111,"ckgetpeer",namebuf,peerxipaddr); return(namebuf); #else return(NULL); #endif /* TCPSOCKET */ } #ifndef NOTCPIP /* Get fully qualified IP hostname */ char * #ifdef CK_ANSIC ckgetfqhostname(char * name) #else ckgetfqhostname(name) char * name; #endif /* CK_ANSIC */ { #ifdef NOCKGETFQHOST return(name); #else /* If the following code dumps core, define NOCKGETFQHOST and rebuild. */ static char namebuf[256]; struct hostent *host=NULL; struct sockaddr_in r_addr; int i; debug(F110,"ckgetfqhn()",name,0); ckstrncpy(namebuf,name,256); namebuf[255] = '\0'; i = ckindex(":",namebuf,0,0,0); if (i) namebuf[i-1] = '\0'; bzero((char *)&r_addr, sizeof(r_addr)); host = gethostbyname(namebuf); if (host) { host = ck_copyhostent(host); debug(F100,"ckgetfqhn() gethostbyname != NULL","",0); r_addr.sin_family = host->h_addrtype; #ifdef HADDRLIST #ifdef h_addr /* This is for trying multiple IP addresses - see */ if (!(host->h_addr_list)) goto exit_func; bcopy(host->h_addr_list[0], (caddr_t)&r_addr.sin_addr, host->h_length ); #else bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length); #endif /* h_addr */ #else /* HADDRLIST */ bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length); #endif /* HADDRLIST */ #ifdef COMMENT #ifndef EXCELAN debug(F111,"BCOPY","host->h_addr",host->h_addr); #endif /* EXCELAN */ debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr", (caddr_t)&r_addr.sin_addr); #endif /* COMMENT */ debug(F111,"BCOPY","host->h_length",host->h_length); #ifdef NT /* Windows 95/98 requires a 1 second wait between calls to Microsoft */ /* provided DNS functions. Otherwise, the TTL of the DNS response */ /* is ignored. */ if (isWin95()) sleep(1); #endif /* NT */ host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET); if (host) { host = ck_copyhostent(host); debug(F100,"ckgetfqhn() gethostbyaddr != NULL","",0); ckstrncpy(namebuf, host->h_name, 256); } } #ifdef HADDRLIST #ifdef h_addr exit_func: #endif /* h_addr */ #endif /* HADDRLIST */ if (i > 0) ckstrncat(namebuf,&name[i-1],256-strlen(namebuf)-strlen(&name[i-1])); debug(F110,"ckgetfqhn()",namebuf,0); return(namebuf); #endif /* NOCKGETFQHOST */ } VOID #ifdef CK_ANSIC setnproto(char * p) #else setnproto(p) char * p; #endif /* CK_ANSIC */ { if (!isdigit(*p)) { if (!strcmp("kermit",p)) ttnproto = NP_KERMIT; else if (!strcmp("telnet",p)) ttnproto = NP_TELNET; else if (!strcmp("http",p)) ttnproto = NP_TCPRAW; #ifdef RLOGCODE else if (!strcmp("login",p)) ttnproto = NP_RLOGIN; #endif /* RLOGCODE */ #ifdef CK_SSL /* Commonly used SSL ports (might not be in services file) */ else if (!strcmp("https",p)) { ttnproto = NP_SSL_RAW; ssl_only_flag = 1; } else if (!strcmp("ssl-telnet",p)) { ttnproto = NP_TELNET; ssl_only_flag = 1; } else if (!strcmp("telnets",p)) { ttnproto = NP_TELNET; ssl_only_flag = 1; } #endif /* CK_SSL */ #ifdef CK_KERBEROS #ifdef RLOGCODE else if (!strcmp("klogin",p)) { if (ck_krb5_is_installed()) ttnproto = NP_K5LOGIN; else if (ck_krb4_is_installed()) ttnproto = NP_K4LOGIN; else ttnproto = NP_RLOGIN; } else if (!strcmp("eklogin",p)) { if (ck_krb5_is_installed()) ttnproto = NP_EK5LOGIN; else if (ck_krb4_is_installed()) ttnproto = NP_EK4LOGIN; else ttnproto = NP_RLOGIN; } #endif /* RLOGCODE */ #endif /* CK_KERBEROS */ else ttnproto = NP_NONE; } else { switch (atoi(p)) { case 23: /* Telnet */ ttnproto = NP_TELNET; break; case 513: ttnproto = NP_RLOGIN; break; case 1649: ttnproto = NP_KERMIT; break; #ifdef CK_SSL case 443: #ifdef COMMENT /* Jeff 2005/12/30 */ ttnproto = NP_SSL_RAW; #else /* fdc 2005/12/04 */ ttnproto = NP_SSL; #endif /* COMMENT */ ssl_only_flag = 1; break; case 151: case 992: ttnproto = NP_TELNET; ssl_only_flag = 1; break; #endif /* CK_SSL */ #ifdef CK_KERBEROS case 543: if (ck_krb5_is_installed()) ttnproto = NP_K5LOGIN; else if (ck_krb4_is_installed()) ttnproto = NP_K4LOGIN; else ttnproto = NP_RLOGIN; break; case 2105: if (ck_krb5_is_installed()) ttnproto = NP_EK5LOGIN; else if (ck_krb4_is_installed()) ttnproto = NP_EK4LOGIN; else ttnproto = NP_RLOGIN; break; #endif /* CK_KERBEROS */ case 80: /* HTTP */ ttnproto = NP_TCPRAW; break; default: ttnproto = NP_NONE; break; } } } /* ckgetservice() is used to determine the port number for a given */ /* service taking into account the use of DNS SRV records. */ static struct servent servrec; #ifdef CK_ANSIC /* prototype for static functions - fdc 01 December 2022 */ static struct servent * ckgetservice( char *, char *, char *, int ); #endif /* CK_ANSIC */ static struct servent * #ifdef CK_ANSIC ckgetservice( char *hostname, char * servicename, char * ip, int iplen ) #else ckgetservice(hostname, servicename, ip, iplen) char *hostname; char * servicename; char * ip; int iplen; #endif /* CK_ANSIC */ { struct servent * service = NULL; #ifdef CK_DNS_SRV struct sockaddr * dns_addrs = NULL; int dns_naddrs = 0; #endif /* CK_DNS_SRV */ if (isdigit(*servicename)) { /* Use socket number without lookup */ service = &servrec; service->s_port = htons((unsigned short)atoi(servicename)); } else { /* Otherwise lookup the service name */ #ifdef CK_DNS_SRV if (tcp_dns_srv && !quiet) { printf(" DNS SRV Lookup... "); fflush(stdout); } if (tcp_dns_srv && locate_srv_dns(hostname, servicename, "tcp", &dns_addrs, &dns_naddrs ) ) { /* Use the first one. Eventually we should cycle through all */ /* the returned IP addresses and port numbers. */ struct sockaddr_in *sin = NULL; #ifdef BETADEBUG int i; printf("\r\n"); for ( i=0;isin_addr), ntohs(sin->sin_port)); } #endif /* BETADEBUG */ sin = (struct sockaddr_in *) &dns_addrs[0]; if ( ip && iplen > 0 ) ckstrncpy(ip,(char *)inet_ntoa(sin->sin_addr),iplen); service = &servrec; service->s_port = sin->sin_port; free(dns_addrs); dns_addrs = NULL; dns_naddrs = 0; } else #endif /* CK_DNS_SRV */ service = getservbyname(servicename, "tcp"); } if (!service) { if (!ckstrcmp("kermit",servicename,-1,0)) { /* Kermit service port */ service = &servrec; service->s_port = htons(1649); } else if (!ckstrcmp("telnet",servicename,-1,0)) { /* Telnet port */ service = &servrec; service->s_port = htons(23); } else if (!ckstrcmp("http",servicename,-1,0)) { service = &servrec; service->s_port = htons(80); } #ifdef RLOGCODE else if (!ckstrcmp("login",servicename,-1,0)) { service = &servrec; service->s_port = htons(513); } #endif /* RLOGCODE */ #ifdef CK_SSL /* Commonly used SSL ports (might not be in services file) */ else if (!ckstrcmp("https",servicename,-1,0)) { service = &servrec; service->s_port = htons(443); } else if (!ckstrcmp("ssl-telnet",servicename,-1,0)) { service = &servrec; service->s_port = htons(151); } else if (!ckstrcmp("telnets",servicename,-1,0)) { service = &servrec; service->s_port = htons(992); } #endif /* CK_SSL */ #ifdef CK_KERBEROS #ifdef RLOGCODE else if (!ckstrcmp("klogin",servicename,-1,0)) { service = &servrec; service->s_port = htons(543); } else if (!ckstrcmp("eklogin",servicename,-1,0)) { service = &servrec; service->s_port = htons(2105); } #endif /* RLOGCODE */ #endif /* CK_KERBEROS */ } return(service); } #endif /* NOTCPIP */ /* N E T O P E N -- Open a network connection */ /* Calling conventions same as ttopen(), except third argument is network type rather than modem type. Designed to be called from within ttopen. Call with: name - name of host (or host:service), lcl - local-mode flag to be set if this function succeeds, nett - network type (value defined in ckcnet.h) */ #ifdef COMMENT #define XXNAMELEN 256 static char xxname[XXNAMELEN]; #endif /* COMMENT */ int #ifdef CK_ANSIC netopen( char *name, int *lcl, int nett ) #else netopen(name, lcl, nett) char *name; int *lcl, nett; #endif /* CK_ANSIC */ { char *p; int i, x, dns = 0; #ifdef SOLARIS int rc_inet_addr = 0; #endif /* SOLARIS */ #ifdef TCPSOCKET int isconnect = 0; #ifdef SO_OOBINLINE int on = 1; #endif /* SO_OOBINLINE */ struct servent *service=NULL; struct hostent *host=NULL; struct sockaddr_in r_addr; struct sockaddr_in sin; struct sockaddr_in l_addr; GSOCKNAME_T l_slen; #ifdef EXCELAN struct sockaddr_in send_socket; #endif /* EXCELAN */ #ifdef INADDRX /* inet_addr() is of type struct in_addr */ #ifdef datageneral extern struct in_addr inet_addr(); #else #ifdef HPUX5WINTCP extern struct in_addr inet_addr(); #endif /* HPUX5WINTCP */ #endif /* datageneral */ struct in_addr iax; #else #ifdef INADDR_NONE struct in_addr iax; #else /* INADDR_NONE */ long iax; #endif /* INADDR_NONE */ #endif /* INADDRX */ #endif /* TCPSOCKET */ #ifdef COMMENT /* This causes big trouble */ #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif /* INADDR_NONE */ #endif /* COMMENT */ #ifdef SUNX25 /* Code for SunLink X.25 support */ #define X29PID 1 /* X.29 Protocol ID */ _PROTOTYP(SIGTYP x25oobh, (int) ); CONN_DB x25host; #ifndef X25_WR_FACILITY FACILITY x25facil; #else FACILITY_DB x25facil; #endif /* X25_WR_FACILITY */ static int needh = 1; PID_T pid; extern int linkid, lcn, x25ver; #endif /* SUNX25 */ #ifdef ANYX25 extern int revcall, closgr, cudata; extern char udata[]; #endif /* ANYX25 */ #ifdef IBMX25 /* Variables for IBM X25 */ extern int x25port; /* Logical port to use */ extern x25addr_t local_nua; /* Local X.25 address */ extern x25addr_t remote_nua; /* Remote X.25 address */ extern char x25name[]; /* X25 device name (sx25a0) */ extern char x25dev[]; /* X25 device file /dev/x25pkt */ ulong bind_flags = 0; /* Flags for binding the X25 stream */ ulong token = 0; /* Temporary return code */ #endif /* IBMX25 */ debug(F101,"netopen nett","",nett); *ipaddr = '\0'; /* Initialize IP address string */ #ifdef SUNX25 if (nett == NET_SX25) { /* If network type is X.25 */ netclos(); /* Close any previous net connection */ ttnproto = NP_NONE; /* No protocol selected yet */ /* Set up host structure */ bzero((char *)&x25host,sizeof(x25host)); if ((x25host.hostlen = pkx121(name,x25host.host)) < 0) { fprintf (stderr,"Invalid X.121 host address %s\n",name); errno = 0; return (-1); } x25host.datalen = X29PIDLEN; x25host.data[0] = X29PID; /* Set call user data if specified */ if (cudata) { ckstrncpy((char *)x25host.data+X29PIDLEN,udata,(int)strlen(udata)); x25host.datalen += (int)strlen(udata); } /* Open SunLink X.25 socket */ if (!quiet && *name) { printf(" Trying %s... ", name); fflush(stdout); } if ((ttyfd = socket(AF_X25, SOCK_STREAM, 0)) < 0) { debug(F101,"netopen socket error","",errno); perror ("X.25 socket error"); return (-1); } /* Setting X.25 out-of-band data handler */ pid = getpid(); if (ioctl(ttyfd,SIOCSPGRP,&pid)) { perror("X.25 set process group id error"); return(-1); } (VOID) signal(SIGURG,x25oobh); /* Set reverse charge call and closed user group if requested */ bzero ((char *)&x25facil,sizeof(x25facil)); #ifndef X25_WR_FACILITY /* New SunLink (7.0 or 8.0, not sure which)... */ x25facil.type = T_REVERSE_CHARGE; /* Reverse Charge */ x25facil.f_reverse_charge = revcall ? 1 : 0; if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) { perror ("Setting X.25 reverse charge"); return (-1); } if (closgr > -1) { /* Closed User Group (Outgoing) */ bzero ((char *)&x25facil,sizeof(x25facil)); x25facil.type = T_CUG; x25facil.f_cug_req = CUG_REQ_ACS; x25facil.f_cug_index = closgr; if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) { perror ("Setting X.25 closed user group"); return (-1); } } #else /* Old SunLink 6.0 (or 7.0?)... */ if (revcall) x25facil.reverse_charge = revcall; if (closgr > -1) { x25facil.cug_req = 1; x25facil.cug_index = closgr; } if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) { perror ("Setting X.25 facilities"); return (-1); } #endif /* X25_WR_FACILITY */ /* Need X.25 header with bits Q and M */ if (ioctl (ttyfd,X25_HEADER,&needh) < 0) { perror ("Setting X.25 header"); return (-1); } /* Connects to remote host via SunLink X.25 */ if (connect(ttyfd,(struct sockaddr *)&x25host,sizeof(x25host)) < 0) { i = errno; debug(F101,"netopen connect errno","",i); if (i) { perror("netopen x25 connect"); x25diag(); } (VOID) netclos(); ttyfd = -1; wasclosed = 1; ttnproto = NP_NONE; errno = i; return (-1); } /* Get X.25 link identification used for the connection */ if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) { perror ("Getting X.25 link id"); return (-1); } /* Get X.25 logical channel number used for the connection */ if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) { perror ("Getting X.25 lcn"); return (-1); } /* Get SunLink X.25 version */ if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) { perror ("Getting SunLink X.25 version"); return (-1); } ttnet = nett; /* Sunlink X.25 network */ ttnproto = NP_X3; /* PAD X.3, X.28, X.29 protocol */ if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */ return(0); } else /* Note that SUNX25 support can coexist with TCP/IP support. */ #endif /* SUNX25 */ #ifdef IBMX25 /* riehm */ if (nett == NET_IX25) { /* IBM AIX X.25 */ netclos(); /* Close any previous net connection */ ttnproto = NP_NONE; /* No protocol selected yet */ /* find out who we are - this is not so easy on AIX */ /* riehm: need to write the code that finds this out * automatically, or at least allow it to be configured * somehow */ if (!local_nua[0] && !x25local_nua(local_nua)) { return(-1); } /* Initialise the X25 API (once per process? once per connection?) */ debug(F110, "Opening ", x25dev, 0 ); /* set O_NDELAY to allow polling? */ if ((ttyfd = open(x25dev, O_RDWR)) < 0) { perror ("X.25 device open error"); debug(F101,"netopen: device open error","",errno); return (-1); } /* push the NPI onto the STREAM */ if (ioctl(ttyfd,I_PUSH,"npi") < 0 ) { close(ttyfd); ttyfd = -1; wasclosed = 1; perror( "kermit: netopen(): couldn't push npi on the X25 stream" ); debug(F101,"netopen: can't push npi on the X25 stream","",errno); return (-1); } /* set up server mode - bind the x25 port and wait for * incoming connections */ if (name[0] == '*') { /* Server */ /* set up a server - see the warning in x25bind() */ bind_flags |= TOKEN_REQUEST; /* bind kermit to the local X25 address */ token = x25bind(ttyfd, local_nua, udata, (int)strlen( udata ), 1, x25port, bind_flags ); if (token < 0) { debug(F100,"netopen: couldn't bind to local X25 address","",0); netclos(); return(-1); } /* Currently not connected to a remote host */ remote_nua[0] = '\0'; /* store the fd so that incoming calls can have their own fd * This is almost support for a true server (ie: a'la ftpd) * but we're not quite there yet. * used in netclos() */ x25serverfd = ttyfd; /* * wait for an incoming call * this should happen in the "server" command and not in * the "set host *" command. */ if ((ttyfd = x25getcall(ttyfd)) < 0) { netclos(); return(-1); } } else { /* Client */ /* Bind kermit to the local X25 address */ token = x25bind( ttyfd, local_nua, (char *)NULL, 0, 0, x25port, bind_flags ); if (token < 0) { debug(F100,"netopen: couldn't bind to local X25 address","",0); netclos(); return(-1); } /* riehm: this should be done via the CONNECT command, not HOST! */ { x25serverfd = 0; /* call the remote host */ /* name == address of remote host as char* */ if (x25call(ttyfd, name, udata) < 0 ) { debug(F100, "netopen: couldn't connect to remote X25 address", "", 0); netclos(); return(-1); } strcpy(remote_nua, name); } } ttnet = nett; /* AIX X.25 network */ if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */ return(0); } else /* Note that IBMX25 support can coexist with TCP/IP support. */ #endif /* IBMX25 */ /* Add support for other networks here. */ if (nett != NET_TCPB) return(-1); /* BSD socket support */ #ifdef TCPSOCKET netclos(); /* Close any previous connection. */ ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */ debug(F110,"netopen namecopy",namecopy,0); #ifndef NOLISTEN if (name[0] == '*') return(tcpsrv_open(name, lcl, nett, 0)); #endif /* NOLISTEN */ p = namecopy; /* Was a service requested? */ while (*p != '\0' && *p != ':') p++; /* Look for colon */ if (*p == ':') { /* Have a colon */ debug(F110,"netopen name has colon",namecopy,0); *p++ = '\0'; /* Get service name or number */ #ifdef CK_URL /* Here we have to check for various popular syntaxes: host:port (our original syntax) URL such as telnet:host or telnet://host/ Or even telnet://user:password@host:port/path/ Or a malformed URL such as generated by Netscape 4.0 like: telnet:telnet or telnet::host. */ /* * REPLACE THIS CODE WITH urlparse() but not on the day of the * C-Kermit 8.0 RELEASE. */ if (*p == ':') /* a second colon */ *p++ = '\0'; /* get rid of that one too */ while (*p == '/') *p++ = '\0'; /* and slashes */ x = strlen(p); /* Length of remainder */ if (p[x-1] == '/') /* If there is a trailing slash */ p[x-1] = '\0'; /* remove it. */ debug(F110,"netopen namecopy after stripping",namecopy,0); debug(F110,"netopen p after stripping",p,0); service = getservbyname(namecopy,"tcp"); if (service || #ifdef RLOGCODE !ckstrcmp("rlogin",namecopy,NAMECPYL,0) || #endif /* RLOGCODE */ #ifdef CK_SSL !ckstrcmp("telnets",namecopy,NAMECPYL,0) || #endif /* CK_SSL */ !ckstrcmp("iksd",namecopy,NAMECPYL,0) ) { char temphost[256], tempservice[80], temppath[256]; char * q = p, *r = p, *w = p; int uidfound=0; extern char pwbuf[]; extern int pwflg, pwcrypt; if (ttnproto == NP_DEFAULT) setnproto(namecopy); /* Check for userid and possibly password */ while (*p != '\0' && *p != '@') p++; /* look for @ */ if (*p == '@') { /* found username and perhaps password */ debug(F110,"netopen namecopy found @","",0); *p = '\0'; p++; while (*w != '\0' && *w != ':') w++; if (*w == ':') *w++ = '\0'; /* r now points to username, save it and the password */ debug(F110,"netopen namecopy username",r,0); debug(F110,"netopen namecopy password",w,0); uidfound=1; if ( strcmp(uidbuf,r) || *w ) ckstrncpy(pwbuf,w,PWBUFL+1); ckstrncpy(uidbuf,r,UIDBUFLEN); pwflg = 1; pwcrypt = 0; q = p; /* Host after user and pwd */ } else { p = q; /* No username or password */ } /* Now we must look for the optional port. */ debug(F110,"netopen x p",p,0); debug(F110,"netopen x q",q,0); /* Look for the port/service or a file/directory path */ while (*p != '\0' && *p != ':' && *p != '/') p++; if (*p == ':') { debug(F110,"netopen found port",q,0); *p++ = '\0'; /* Found a port name or number */ r = p; /* Look for the end of port/service or a file/directory path */ while (*p != '\0' && *p != '/') p++; if (*p == '/') *p++ = '\0'; debug(F110,"netopen port",r,0); ckstrncpy(tempservice,r,80); ckstrncpy(temphost,q,256); ckstrncpy(temppath,p,256); ckstrncpy(namecopy,temphost,NAMECPYL); debug(F110,"netopen tempservice",tempservice,0); debug(F110,"netopen temphost",temphost,0); debug(F110,"netopen temppath",temppath,0); /* move port/service to a buffer that won't go away */ x = strlen(namecopy); p = namecopy + x + 1; ckstrncpy(p, tempservice, NAMECPYL - x); } else { /* Handle a path if we found one */ if (*p == '/') *p++ = '\0'; ckstrncpy(temppath,p,256); /* We didn't find another port, but if q is a service */ /* then assume that namecopy is actually a host. */ if (getservbyname(q,"tcp")) { p = q; } else { #ifdef RLOGCODE /* rlogin is not a valid service */ if (!ckstrcmp("rlogin",namecopy,6,0)) { ckstrncpy(namecopy,"login",NAMECPYL); } #endif /* RLOGCODE */ /* iksd is not a valid service */ if (!ckstrcmp("iksd",namecopy,6,0)) { ckstrncpy(namecopy,"kermit",NAMECPYL); } /* Reconstruct namecopy */ ckstrncpy(tempservice,namecopy,80); ckstrncpy(temphost,q,256); ckstrncpy(namecopy,temphost,NAMECPYL); debug(F110,"netopen tempservice",tempservice,0); debug(F110,"netopen temphost",temphost,0); debug(F110,"netopen temppath",temppath,0); /* move port/service to a buffer that won't go away */ x = strlen(namecopy); p = namecopy + x + 1; ckstrncpy(p, tempservice, NAMECPYL - x - 1); } } debug(F110,"netopen URL result: host",namecopy,0); debug(F110,"netopen URL result: service",p,0); debug(F110,"netopen URL result: path",temppath,0); #ifdef IKS_GET /* If we have set a path specified, we need to try to GET it */ /* But we have another problem, we have to login first. How */ /* do we specify that a login must be done before the GET? */ /* The user's name if specified is in 'userid' and the */ /* password if any is in 'pwbuf'. */ if ( temppath[0] ) { extern int action; extern char * cmarg; if ( !uidfound ) { /* If no userid was specified as part of the URL but * a path was specified, then we * set the user name to anonymous and the password * to the current userid. */ ckstrncpy(pwbuf,uidbuf,PWBUFL); ckstrncat(pwbuf,"@",PWBUFL); pwflg = 1; pwcrypt = 0; ckstrncpy(uidbuf,"anonymous",UIDBUFLEN); } /* * If a file path was specified we perform the GET * operation and then terminate the connection. * * If a directory was given instead of a file, then * we should REMOTE CD to the directory and list its * contents. But how do we tell the difference? */ makestr(&cmarg,temppath); action = 'r'; } #endif /* IKS_GET */ } #endif /* CK_URL */ } else { /* Otherwise use telnet */ p = "telnet"; } /* By the time we get here, namecopy[] should hold the null-terminated hostname or address, and p should point to the service name or number. */ debug(F110,"netopen host",namecopy,0); debug(F110,"netopen service requested",p,0); /* Use the service port to set the default protocol type if necessary */ if (ttnproto == NP_DEFAULT) setnproto(p); ckstrncpy(namecopy2,namecopy,NAMECPYL); service = ckgetservice(namecopy,p,namecopy,NAMECPYL); if (!service) { fprintf(stderr, "Can't find port for service %s\n", p); #ifdef TGVORWIN debug(F101,"netopen can't get service","",socket_errno); #else debug(F101,"netopen can't get service","",errno); #endif /* TGVORWIN */ errno = 0; /* (rather than mislead) */ return(-1); } else { if (!ckstrcmp(namecopy,namecopy2,-1,0)) namecopy2[0] = '\0'; ckstrncpy(svcbuf,ckuitoa(ntohs(service->s_port)),sizeof(svcbuf)); debug(F110,"netopen service ok",svcbuf,0); } #ifdef RLOGCODE if (service && !strcmp("login",p) && service->s_port != htons(513)) { fprintf(stderr, " Warning: login service on port %d instead of port 513\n", ntohs(service->s_port) ); fprintf(stderr, " Edit SERVICES file if RLOGIN fails to connect.\n"); debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port)); } #endif /* RLOGCODE */ #ifndef NOHTTP /* For HTTP connections we must preserve the original hostname and */ /* service requested so we can include them in the Host header. */ ckmakmsg(http_host_port,sizeof(http_host_port),namecopy,":", ckitoa(ntohs(service->s_port)),NULL); /* 'namecopy' contains the name of the host to which we want to connect */ /* 'svcbuf' contains the service name */ /* 'service->s_port' contains the port number in network byte order */ /* If we are using an http proxy, we need to create a buffer containing */ /* hostname:port-number */ /* to pass to the http_connect() function. Then we need to replace */ /* 'namecopy' with the name of the proxy server and the service->s_port */ /* with the port number of the proxy (default port 80). */ if ( tcp_http_proxy ) { ckmakmsg(proxycopy,sizeof(proxycopy),namecopy,":", ckuitoa(ntohs(service->s_port)),NULL); ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL); p = namecopy; /* Was a service requested? */ while (*p != '\0' && *p != ':') p++; /* Look for colon */ if (*p == ':') { /* Have a colon */ debug(F110,"netopen name has colon",namecopy,0); *p++ = '\0'; /* Get service name or number */ } else { strcpy(++p,"http"); } service = ckgetservice(namecopy,p,namecopy,NAMECPYL); if (!service) { fprintf(stderr, "Can't find port for service %s\n", p); #ifdef TGVORWIN debug(F101,"netopen can't get service for proxy","",socket_errno); #else debug(F101,"netopen can't get service for proxy","",errno); #endif /* TGVORWIN */ errno = 0; /* (rather than mislead) */ return(-1); } ckstrncpy(p,ckuitoa(ntohs(service->s_port)),NAMECPYL-(p-namecopy)); } #endif /* NOHTTP */ /* Set up socket structure and get host address */ bzero((char *)&r_addr, sizeof(r_addr)); debug(F100,"netopen bzero ok","",0); /* NOTE: Originally the inet_addr() check was #ifdef NT, but is enabled for all as of 20 Sep 97, to allow people to "set host" to a specific numeric IP address without going through the multihomed host sequence and winding up at a different place than the one requested. */ #ifdef INADDR_NONE debug(F101,"netopen INADDR_NONE defined","",INADDR_NONE); #else /* INADDR_NONE */ debug(F100,"netopen INADDR_NONE not defined","",0); #endif /* INADDR_NONE */ #ifdef INADDRX debug(F100,"netopen INADDRX defined","",0); #else /* INADDRX */ debug(F100,"netopen INADDRX not defined","",0); #endif /* INADDRX */ #ifndef NOMHHOST #ifdef INADDRX iax = inet_addr(namecopy); debug(F111,"netopen inet_addr",namecopy,iax.s_addr); #else /* INADDRX */ #ifdef INADDR_NONE iax.s_addr = inet_addr(namecopy); debug(F111,"netopen inet_addr",namecopy,iax.s_addr); #else /* INADDR_NONE */ #ifdef SOLARIS /* In Solaris inet_addr() is of type in_addr_t which is uint32_t */ /* (unsigned) yet it returns -1 (signed) on failure. */ /* It makes a difference in 64-bit builds. */ rc_inet_addr = inet_addr(namecopy); /* Assign return code to an int */ iax = (unsigned) rc_inet_addr; /* and from there to whatever.. */ debug(F111,"netopen rc_inet_addr",namecopy,rc_inet_addr); #else #ifndef datageneral iax = (unsigned int) inet_addr(namecopy); #else iax = -1L; #endif /* datageneral */ #endif /* SOLARIS */ debug(F111,"netopen inet_addr",namecopy,iax); #endif /* INADDR_NONE */ #endif /* INADDRX */ dns = 0; if ( /* This might give warnings on 64-bit platforms but they should be harmless */ /* because INADDR_NONE should be all 1's anyway, thus the OR part is */ /* probably superfluous -- not sure why it's even there, maybe it should be */ /* removed. */ #ifdef SOLARIS rc_inet_addr == -1 #else #ifdef INADDR_NONE iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */ #else /* INADDR_NONE */ iax < 0 #endif /* INADDR_NONE */ #endif /* SOLARIS */ ) { if (!quiet) { printf(" DNS Lookup... "); fflush(stdout); } if ((host = gethostbyname(namecopy)) != NULL) { debug(F110,"netopen gethostbyname != NULL",namecopy,0); host = ck_copyhostent(host); dns = 1; /* Remember we performed dns lookup */ r_addr.sin_family = host->h_addrtype; if (tcp_rdns && host->h_name && host->h_name[0] #ifndef NOHTTP && (tcp_http_proxy == NULL) #endif /* NOHTTP */ ) { #ifdef COMMENT ckstrncpy(xxname,host->h_name,XXNAMELEN); debug(F110,"netopen xxname[1]",xxname,0); if ((XXNAMELEN - (int)strlen(name)) > ((int)strlen(svcbuf)+1)){ ckstrncat(xxname,":",XXNAMELEN - (int)strlen(xxname)); ckstrncat(xxname,svcbuf,XXNAMELEN - (int)strlen(xxname)); debug(F110,"netopen xxname[2]",xxname,0); } name = (char *)xxname; #else ckstrncpy(name,host->h_name,80); /* Bad Bad Bad */ if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) { ckstrncat(name,":",80-strlen(name)); ckstrncat(name,svcbuf,80-strlen(name)); } #endif /* COMMENT */ } debug(F110,"netopen name after lookup",name,0); #ifdef HADDRLIST #ifdef h_addr /* This is for trying multiple IP addresses - see */ if (!(host->h_addr_list)) return(-1); bcopy(host->h_addr_list[0], (caddr_t)&r_addr.sin_addr, host->h_length ); #else bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length); #endif /* h_addr */ #else /* HADDRLIST */ #ifdef HPUX6 r_addr.sin_addr.s_addr = (u_long)host->h_addr; #else /* HPUX6 */ bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length); #endif /* HPUX6 */ #endif /* HADDRLIST */ #ifndef HPUX6 debug(F111,"BCOPY","host->h_length",host->h_length); #endif /* HPUX6 */ } } #endif /* NOMHHOST */ debug(F101,"netopen dns","",dns); if (!dns) { #ifdef INADDRX /* inet_addr() is of type struct in_addr */ struct in_addr ina; unsigned long uu; debug(F100,"netopen gethostbyname == NULL: INADDRX","",0); ina = inet_addr(namecopy); uu = *(unsigned int *)&ina; #else /* Not INADDRX */ /* inet_addr() is unsigned long */ unsigned long uu; debug(F100,"netopen gethostbyname == NULL: Not INADDRX","",0); uu = inet_addr(namecopy); #endif /* INADDRX */ debug(F101,"netopen uu","",uu); if ( #ifdef INADDR_NONE !(uu == INADDR_NONE || uu == (unsigned int) -1L) #else /* INADDR_NONE */ uu != ((unsigned long)-1) #endif /* INADDR_NONE */ ) { r_addr.sin_addr.s_addr = uu; r_addr.sin_family = AF_INET; } else { #ifdef VMS fprintf(stdout, "\r\n"); /* complete any previous message */ #endif /* VMS */ fprintf(stderr, "Can't get address for %s\n", namecopy); #ifdef TGVORWIN debug(F101,"netopen can't get address","",socket_errno); #else debug(F101,"netopen can't get address","",errno); #endif /* TGVORWIN */ errno = 0; /* Rather than mislead */ return(-1); } } /* Get a file descriptor for the connection. */ r_addr.sin_port = service->s_port; ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20); debug(F110,"netopen trying",ipaddr,0); if (!quiet && *ipaddr) { printf(" Trying %s... ", ipaddr); fflush(stdout); } /* Loop to try additional IP addresses, if any. */ do { #ifdef EXCELAN send_socket.sin_family = AF_INET; send_socket.sin_addr.s_addr = 0; send_socket.sin_port = 0; if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0, &send_socket, SO_REUSEADDR)) < 0) #else /* EXCELAN */ #ifdef NT #ifdef COMMENT_X /* Must make sure that all sockets are opened in Non-overlapped mode since we use the standard C RTL functions to read and write data. But it doesn't seem to work as planned. */ { int optionValue = SO_SYNCHRONOUS_NONALERT; if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &optionValue, sizeof(optionValue)) != NO_ERROR) return(-1); } #endif /* COMMENT */ #endif /* NT */ if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) #endif /* EXCELAN */ { #ifdef EXCELAN experror("TCP socket error"); #else #ifdef VMS fprintf(stdout, "\r\n"); /* complete any previous stdout */ #endif /* VMS */ #ifdef TGVORWIN #ifdef OLD_TWG errno = socket_errno; #endif /* OLD_TWG */ socket_perror("TCP socket error"); debug(F101,"netopen socket error","",socket_errno); #else perror("TCP socket error"); debug(F101,"netopen socket error","",errno); #endif /* TGVORWIN */ #endif /* EXCELAN */ return (-1); } errno = 0; #ifdef RLOGCODE /* Not part of the RLOGIN RFC, but the BSD implementation */ /* requires that the client port be a priviliged port (<1024) */ /* on a Unix system this would require SuperUser permissions */ /* thereby saying that the root of the Unix system has given */ /* permission for this connection to be created */ if (service->s_port == htons((unsigned short)RLOGIN_PORT)) { static unsigned short lport = 1024; /* max reserved port */ #ifdef OS2 int s_errno; #endif /* OS2 */ lport--; /* Make sure we do not reuse a port */ if (lport == 512) lport = 1023; sin.sin_family = AF_INET; if (tcp_address) { #ifdef INADDRX inaddrx = inet_addr(tcp_address); sin.sin_addr.s_addr = *(unsigned long *)&inaddrx; #else sin.sin_addr.s_addr = inet_addr(tcp_address); #endif /* INADDRX */ } else sin.sin_addr.s_addr = INADDR_ANY; while (1) { sin.sin_port = htons(lport); if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0) break; #ifdef OS2 s_errno = socket_errno; if (s_errno && /* OS2 bind fails with 0, if already in use */ #ifdef NT s_errno != WSAEADDRINUSE #else s_errno != SOCEADDRINUSE && s_errno != (SOCEADDRINUSE - SOCBASEERR) #endif /* NT */ ) #else /* OS2 */ #ifdef TGVORWIN if (socket_errno != EADDRINUSE) #else if (errno != EADDRINUSE) #endif /* TGVORWIN */ #endif /* OS2 */ { #ifdef COMMENT printf("\nBind failed with errno %d for port %d.\n", #ifdef OS2 s_errno #else #ifdef TGVORWIN socket_errno #else errno #endif /* TGVORWIN */ #endif /* OS2 */ , lport ); #ifdef OS2 debug(F101,"rlogin bind failed","",s_errno); #else #ifdef TGVORWIN debug(F101,"rlogin bind failed","",socket_errno); #ifdef OLD_TWG errno = socket_errno; #endif /* OLD_TWG */ socket_perror("rlogin bind"); #else debug(F101,"rlogin bind failed","",errno); perror("rlogin bind"); #endif /* TGVORWIN */ #endif /* OS2 */ #else /* COMMENT */ #ifdef OS2 debug(F101,"rlogin bind s_errno","",s_errno); perror("rlogin bind"); #else #ifdef VMS printf("\r\n"); /* complete any previous message */ #endif /* VMS */ #ifdef TGVORWIN debug(F101,"rlogin bind socket_errno","",socket_errno); #ifdef OLD_TWG errno = socket_errno; #endif /* OLD_TWG */ socket_perror("rlogin bind"); #else debug(F101,"rlogin bind errno","",errno); perror("rlogin bind"); #endif /* TGVORWIN */ #endif /* OS2 */ debug(F101,"rlogin local port","",lport); #endif /* COMMENT */ netclos(); return -1; } lport--; if (lport == 512 /* lowest reserved port to use */ ) { printf("\nNo reserved ports available.\n"); netclos(); return -1; } } debug(F101,"rlogin lport","",lport); ttnproto = NP_RLOGIN; } else #endif /* RLOGCODE */ /* If a specific TCP address on the local host is desired we */ /* must bind it to the socket. */ #ifndef datageneral if (tcp_address) { int s_errno; debug(F110,"netopen binding socket to",tcp_address,0); bzero((char *)&sin,sizeof(sin)); sin.sin_family = AF_INET; #ifdef INADDRX inaddrx = inet_addr(tcp_address); sin.sin_addr.s_addr = *(unsigned long *)&inaddrx; #else sin.sin_addr.s_addr = inet_addr(tcp_address); #endif /* INADDRX */ sin.sin_port = 0; if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { s_errno = socket_errno; /* Save error code */ #ifdef TCPIPLIB socket_close(ttyfd); #else /* TCPIPLIB */ close(ttyfd); #endif /* TCPIPLIB */ ttyfd = -1; wasclosed = 1; errno = s_errno; /* and report this error */ debug(F101,"netopen bind errno","",errno); return(-1); } } #endif /* datageneral */ /* Now connect to the socket on the other end. */ #ifdef EXCELAN if (connect(ttyfd, &r_addr) < 0) #else #ifdef NT WSASafeToCancel = 1; #endif /* NT */ if (connect(ttyfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0) #endif /* EXCELAN */ { #ifdef NT WSASafeToCancel = 0; #endif /* NT */ #ifdef OS2 i = socket_errno; #else /* OS2 */ #ifdef TGVORWIN i = socket_errno; #else i = errno; /* Save error code */ #endif /* TGVORWIN */ #endif /* OS2 */ #ifdef RLOGCODE if ( #ifdef OS2 i && /* OS2 bind fails with 0, if already in use */ #ifdef NT i == WSAEADDRINUSE #else (i == SOCEADDRINUSE || i == (SOCEADDRINUSE - SOCBASEERR)) #endif /* NT */ #else /* OS2 */ #ifdef TGVORWIN socket_errno == EADDRINUSE #else errno == EADDRINUSE #endif /* TGVORWIN */ #endif /* OS2 */ && ttnproto == NP_RLOGIN) { #ifdef TCPIPLIB socket_close(ttyfd); /* Close it. */ #else close(ttyfd); #endif /* TCPIPLIB */ continue; /* Try a different lport */ } #endif /* RLOGCODE */ #ifdef HADDRLIST #ifdef h_addr if (host && host->h_addr_list && host->h_addr_list[1]) { perror(""); host->h_addr_list++; bcopy(host->h_addr_list[0], (caddr_t)&r_addr.sin_addr, host->h_length); ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20); debug(F110,"netopen h_addr_list",ipaddr,0); if (!quiet && *ipaddr) { printf(" Trying %s... ", ipaddr); fflush(stdout); } #ifdef TCPIPLIB socket_close(ttyfd); /* Close it. */ #else close(ttyfd); #endif /* TCPIPLIB */ continue; } #endif /* h_addr */ #endif /* HADDRLIST */ netclos(); ttyfd = -1; wasclosed = 1; ttnproto = NP_NONE; errno = i; /* And report this error */ #ifdef EXCELAN if (errno) experror("netopen connect"); #else #ifdef TGVORWIN debug(F101,"netopen connect error","",socket_errno); /* if (errno) socket_perror("netopen connect"); */ #ifdef OLD_TWG errno = socket_errno; #endif /* OLD_TWG */ if (!quiet) socket_perror("netopen connect"); #else /* TGVORWIN */ debug(F101,"netopen connect errno","",errno); #ifdef VMS if (!quiet) perror("\r\nFailed"); #else if (!quiet) perror("Failed"); #endif /* VMS */ #ifdef DEC_TCPIP if (!quiet) perror("netopen connect"); #endif /* DEC_TCPIP */ #ifdef CMU_TCPIP if (!quiet) perror("netopen connect"); #endif /* CMU_TCPIP */ #endif /* TGVORWIN */ #endif /* EXCELAN */ return(-1); } #ifdef NT WSASafeToCancel = 0; #endif /* NT */ isconnect = 1; } while (!isconnect); #ifdef NON_BLOCK_IO on = 1; x = socket_ioctl(ttyfd,FIONBIO,&on); debug(F101,"netopen FIONBIO","",x); #endif /* NON_BLOCK_IO */ #ifdef NT_TCP_OVERLAPPED OverlappedWriteInit(); OverlappedReadInit(); #endif /* NT_TCP_OVERLAPPED */ ttnet = nett; /* TCP/IP (sockets) network */ #ifndef NOHTTP /* We have succeeded in connecting to the HTTP PROXY. So now we */ /* need to attempt to connect through the proxy to the actual host */ /* If that is successful, we have to pretend that we made a direct */ /* connection to the actual host. */ if ( tcp_http_proxy ) { #ifdef OS2 char * agent = "Kermit 95"; /* Default user agent */ #else char * agent = "C-Kermit"; #endif /* OS2 */ if (http_connect(ttyfd, tcp_http_proxy_agent ? tcp_http_proxy_agent : agent, NULL, tcp_http_proxy_user, tcp_http_proxy_pwd, 0, proxycopy ) < 0) { netclos(); return(-1); } ckstrncpy(namecopy,proxycopy,NAMECPYL); p = namecopy; /* Was a service requested? */ while (*p != '\0' && *p != ':') p++; /* Look for colon */ *p = '\0'; } #endif /* NOHTTP */ /* Jeff - Does this next block of code that set's the protocol */ /* need to be here anymore? 5/10/2000 */ /* There are certain magic port numbers that when used require */ /* the use of specific protocols. Check this now before we */ /* set the SO_OOBINLINE state or we might get it wrong. */ x = ntohs((unsigned short)service->s_port); svcnum = x; /* See if the service is TELNET. */ if (x == TELNET_PORT) { /* Yes, so if raw port not requested */ #ifdef COMMENT /* Jeff 2005/12/30 */ if (ttnproto != NP_TCPRAW && ttnproto != NP_SSL_RAW && ttnproto != NP_TLS_RAW && ttnproto != NP_NONE) #else /* fdc 2005/12/04 */ if (ttnproto != NP_TCPRAW && ttnproto != NP_NONE) #endif /* COMMENT */ ttnproto = NP_TELNET; /* Select TELNET protocol. */ } #ifdef RLOGCODE else if (x == RLOGIN_PORT) { ttnproto = NP_RLOGIN; } #ifdef CK_KERBEROS /* There is no good way to do this. If the user didn't tell */ /* which one to use up front. We may guess wrong if the user */ /* has both Kerberos versions installed and valid TGTs for each */ else if (x == KLOGIN_PORT && ttnproto != NP_K4LOGIN && ttnproto != NP_K5LOGIN) { if (ck_krb5_is_installed() && ck_krb5_is_tgt_valid()) ttnproto = NP_K5LOGIN; else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid()) ttnproto = NP_K4LOGIN; else ttnproto = NP_K4LOGIN; } else if (x == EKLOGIN_PORT && ttnproto != NP_EK4LOGIN && ttnproto != NP_EK5LOGIN) { if (ck_krb5_is_installed() && ck_krb5_is_tgt_valid()) ttnproto = NP_EK5LOGIN; else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid()) ttnproto = NP_EK4LOGIN; else ttnproto = NP_EK4LOGIN; } #endif /* CK_KERBEROS */ #endif /* RLOGCODE */ #ifdef IKS_OPTION else if (x == KERMIT_PORT) { /* IKS uses Telnet protocol */ if (ttnproto == NP_NONE) ttnproto = NP_KERMIT; } #endif /* IKS_OPTION */ #ifdef SO_OOBINLINE /* The symbol SO_OOBINLINE is not known to Ultrix 2.0. It means "leave out of band data inline". The normal value is 0x0100, but don't try this on systems where the symbol is undefined. */ /* Note from Jeff Altman: 12/13/95 In implementing rlogin protocol I have come to the conclusion that it is a really bad idea to read out-of-band data inline. At least Windows and OS/2 does not handle this well. And if you need to know that data is out-of-band, then it becomes absolutely pointless. Therefore, at least on OS2 and Windows (NT) I have changed the value of on to 0, so that out-of-band data stays out-of-band. 12/18/95 Actually, OOB data should be read inline when possible. Especially with protocols that don't care about the Urgent flag. This is true with Telnet. With Rlogin, you need to be able to catch OOB data. However, the best way to do this is to set a signal handler on SIGURG. This isn't possible on OS/2 and Windows. But it is in UNIX. We will also need OOB data for FTP so better create a general mechanism. The reason for making OOB data be inline is that the standard ttinc/ttoc calls can be used for reading that data on UNIX systems. If we didn't have the OOBINLINE option set then we would have to use recv(,MSG_OOB) to read it. */ #ifdef RLOGCODE #ifdef TCPIPLIB if (ttnproto == NP_RLOGIN #ifdef CK_KERBEROS || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN #endif /* CK_KERBEROS */ ) on = 0; #else /* TCPIPLIB */ if (ttnproto == NP_RLOGIN #ifdef CK_KERBEROS || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN #endif /* CK_KERBEROS */ ) { debug(F100,"Installing rlogoobh on SIGURG","",0); signal(SIGURG, rlogoobh); on = 0; } else { debug(F100,"Ignoring SIGURG","",0); signal(SIGURG, SIG_DFL); } #endif /* TCPIPLIB */ #endif /* RLOGCODE */ #ifdef datageneral setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef BSD43 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef OSF1 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef POSIX setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef MOTSV88R4 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef SOLARIS /* Maybe this applies to all SVR4 versions, but the other (else) way has been compiling and working fine on all the others, so best not to change it. */ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef OSK setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef OS2 { int rc; rc = setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof on ); debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc); } #else #ifdef VMS /* or, at least, VMS with gcc */ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef CLIX setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); #endif /* CLIX */ #endif /* VMS */ #endif /* OS2 */ #endif /* OSK */ #endif /* SOLARIS */ #endif /* MOTSV88R4 */ #endif /* POSIX */ #endif /* BSD43 */ #endif /* OSF1 */ #endif /* datageneral */ #endif /* SO_OOBINLINE */ #ifndef NOTCPOPTS #ifndef datageneral #ifdef SOL_SOCKET #ifdef TCP_NODELAY no_delay(ttyfd,tcp_nodelay); #endif /* TCP_NODELAY */ #ifdef SO_KEEPALIVE keepalive(ttyfd,tcp_keepalive); #endif /* SO_KEEPALIVE */ #ifdef SO_LINGER ck_linger(ttyfd,tcp_linger, tcp_linger_tmo); #endif /* SO_LINGER */ #ifdef SO_SNDBUF sendbuf(ttyfd,tcp_sendbuf); #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF recvbuf(ttyfd,tcp_recvbuf); #endif /* SO_RCVBUF */ #endif /* SOL_SOCKET */ #endif /* datageneral */ #endif /* NOTCPOPTS */ #ifndef datageneral /* Find out our own IP address. */ /* We need the l_addr structure for [E]KLOGIN. */ l_slen = sizeof(l_addr); bzero((char *)&l_addr, l_slen); #ifndef EXCELAN if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) { char * s = (char *)inet_ntoa(l_addr.sin_addr); ckstrncpy(myipaddr, s, 20); debug(F110,"getsockname",myipaddr,0); } #endif /* EXCELAN */ #endif /* datageneral */ /* This is really only needed for Kerberos IV but is useful information in any case. If we connect to a name that is really a pool, we need to get the name of the machine we are actually connecting to for K4 to authenticate properly. This way we also update the names properly. However, it is a security hole when used with insecure DNS. Note: This does not work on Windows 95 or Windows NT 3.5x. This is because of the Microsoft implementation of gethostbyaddr() in both Winsock 1.1 and Winsock 2.0 on those platforms. Their algorithm is: 1. Check the HOSTENT cache. 2. Check the HOSTS file at %SystemRoot%\System32\DRIVERS\ETC. 3. Do a DNS query if the DNS server is configured for name resolution. 4. Do an additional NetBIOS remote adapter status to an IP address for its NetBIOS name table. This step is specific only to the Windows NT version 3.51 implementation. The problem is the use of the HOSTENT cache. It means that gethostbyaddr() can not be used to resolve the real name of machine if it was originally accessed by an alias used to represent a cluster. */ if ((tcp_rdns && dns || tcp_rdns == SET_ON #ifdef CK_KERBEROS || tcp_rdns == SET_AUTO && (ck_krb5_is_installed() || ck_krb4_is_installed()) #endif /* CK_KERBEROS */ ) #ifndef NOHTTP && (tcp_http_proxy == NULL) #endif /* NOHTTP */ #ifdef CK_SSL && !(ssl_only_flag || tls_only_flag) #endif /* CK_SSL */ ) { #ifdef NT if (isWin95()) sleep(1); #endif /* NT */ if (!quiet) { printf(" Reverse DNS Lookup... "); fflush(stdout); } if ((host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET))) { char * s; host = ck_copyhostent(host); debug(F100,"netopen gethostbyname != NULL","",0); if (!quiet) { printf("(OK)\n"); fflush(stdout); } s = host->h_name; if (!s) { /* This can happen... */ debug(F100,"netopen host->h_name is NULL","",0); s = ""; } /* Something is wrong with inet_ntoa() on HPUX 10.xx */ /* The compiler says "Integral value implicitly converted to */ /* pointer in assignment." The prototype is right there */ /* in so what's the problem? */ /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */ if (!*s) { /* No name so substitute the address */ debug(F100,"netopen host->h_name is empty","",0); s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */ if (!s) /* Trust No 1 */ s = ""; if (*s) { /* If it worked, use this string */ ckstrncpy(ipaddr,s,20); } s = ipaddr; /* Otherwise stick with the IP */ if (!*s) /* or failing that */ s = namecopy; /* the name we were called with. */ } if (*s) { /* Copying into our argument? */ ckstrncpy(name,s,80); /* Bad Bad Bad */ if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) { ckstrncat(name,":",80-strlen(name)); ckstrncat(name,svcbuf,80-strlen(name)); } } if (!quiet && *s #ifndef NOICP && !doconx #endif /* NOICP */ ) { printf(" %s connected on port %s\n",s,p); #ifdef BETADEBUG /* This is simply for testing the DNS entries */ if (host->h_aliases) { char ** a = host->h_aliases; while (*a) { printf(" alias => %s\n",*a); a++; } } #endif /* BETADEBUG */ } } else { if (!quiet) printf("Failed.\n"); } } else if (!quiet) printf("(OK)\n"); if (!quiet) fflush(stdout); /* This should already have been done but just in case */ ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20); #ifdef CK_SECURITY /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */ #ifndef NOHTTP if (tcp_http_proxy) { for (i=strlen(proxycopy); i >= 0 ; i--) if ( proxycopy[i] == ':' ) proxycopy[i] = '\0'; } #endif /* NOHTTP */ ck_auth_init( #ifndef NOHTTP tcp_http_proxy ? proxycopy : #endif /* NOHTTP */ (tcp_rdns && host && host->h_name && host->h_name[0]) ? (char *)host->h_name : (namecopy2[0] ? namecopy2 : (namecopy[0] ? namecopy : ipaddr)), ipaddr, uidbuf, ttyfd ); #endif /* CK_SECURITY */ #ifdef CK_SSL if (ck_ssleay_is_installed()) { if (!ssl_tn_init(SSL_CLIENT)) { debug(F100,"netopen ssl_tn_init() failed","",0); if (bio_err!=NULL) { BIO_printf(bio_err,"ssl_tn_init() failed\n"); ERR_print_errors(bio_err); } else { fflush(stderr); fprintf(stderr,"ssl_tn_init() failed\n"); ERR_print_errors_fp(stderr); } if (tls_only_flag || ssl_only_flag) { debug(F100,"netopen ssl/tls required","",0); netclos(); return(-1); } /* we will continue to accept the connection */ /* without SSL or TLS support unless required. */ if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU ) TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF; if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU ) TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF; if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU ) TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF; if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU ) TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF; } else if ( ck_ssl_outgoing(ttyfd) < 0 ) { debug(F100,"ck_ssl_outgoing() failed","",0); netclos(); return(-1); } } #endif /* CK_SSL */ #ifdef RLOGCODE if (ttnproto == NP_RLOGIN #ifdef CK_KERBEROS || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN #endif /* CK_KERBEROS */ ) { /* Similar deal for rlogin */ if (rlog_ini(((tcp_rdns && host && host->h_name && host->h_name[0]) ? (CHAR *)host->h_name : (CHAR *)ipaddr), service->s_port, &l_addr,&r_addr ) < 0) { debug(F100,"rlogin initialization failed","",0); netclos(); return(-1); } } else #endif /* RLOGCODE */ if (tn_ini() < 0) { /* Start Telnet negotiations. */ netclos(); return(-1); /* Gone, so open failed. */ } if (ttchk() < 0) { netclos(); return(-1); } #ifdef CK_KERBEROS #ifdef KRB5_U2U if ( ttnproto == NP_K5U2U ) { if (k5_user_to_user_client_auth()) { netclos(); return(-1); } } #endif /* KRB5_U2U */ #endif /* CK_KERBEROS */ debug(F101,"netopen service","",svcnum); debug(F110,"netopen name",name,0); debug(F110,"netopen ipaddr",ipaddr,0); ckstrncpy(hostipaddr,ipaddr,63); if (lcl) if (*lcl < 0) /* Local mode. */ *lcl = 1; #endif /* TCPSOCKET */ return(0); /* Done. */ } /* N E T C L O S -- Close current network connection. */ #ifndef NOLOCAL #ifdef CK_SSL int tls_norestore = 0; #endif /* CK_SSL */ #endif /* NOLOCAL */ int netclos() { static int close_in_progress = 0; int x = 0; #ifdef VMS int y, z; #endif /* VMS */ debug(F101,"netclos","",ttyfd); #ifdef NETLEBUF if (!tt_push_inited) le_init(); #endif /* NETLEBUF */ if (ttyfd == -1) /* Was open? */ return(0); /* Wasn't. */ if (close_in_progress) return(0); close_in_progress = 1; /* Remember */ #ifndef NOLOCAL /* This function call should not be here since this is a direct call */ /* from an I/O routine to a user interface level function. However, */ /* the reality is that we do not have pure interfaces. If we ever */ /* decide to clean this up the UI level should assign this function */ /* via a pointer assignment. - Jeff 9/10/1999 */ #ifdef CK_SSL if (!tls_norestore) #endif /* CK_SSL */ slrestor(); #endif /* NOLOCAL */ #ifdef OS2 RequestTCPIPMutex(SEM_INDEFINITE_WAIT); #else /* OS2 */ if (ttyfd > -1) /* Was. */ #endif /* OS2 */ { #ifdef VMS y = 1; /* Turn on nonblocking reads */ z = socket_ioctl(ttyfd,FIONBIO,&y); debug(F111,"netclos FIONBIO","on",z); #endif /* VMS */ #ifdef TNCODE if (ttnproto == NP_TELNET) { if (!TELOPT_ME(TELOPT_LOGOUT) #ifdef COMMENT /* Jeff 2005/12/30 */ #ifdef CK_SSL && !ssl_raw_flag && !tls_raw_flag #endif /* CK_SSL */ #endif /* COMMENT */ ) { /* Send LOGOUT option before close */ if (tn_sopt(DO,TELOPT_LOGOUT) >= 0) { TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1; /* It would be nice to call tn_wait but we can't */ } } tn_push(); /* Place any waiting data into input*/ } #endif /* TNCODE */ #ifdef CK_SSL if (ssl_active_flag) { if (ssl_debug_flag) BIO_printf(bio_err,"calling SSL_shutdown\n"); SSL_shutdown(ssl_con); ssl_active_flag = 0; } if (tls_active_flag) { if (ssl_debug_flag) BIO_printf(bio_err,"calling SSL_shutdown\n"); SSL_shutdown(tls_con); tls_active_flag = 0; } #endif /* CK_SSL */ #ifdef VMS ck_cancio(); /* Cancel any outstanding reads. */ #endif /* VMS */ #ifdef TCPIPLIB x = socket_close(ttyfd); /* Close it. */ #else #ifndef OS2 #ifdef IBMX25 if (ttnet == NET_IX25) { /* riehm: should send a disc_req - but only if link is still OK */ x = x25clear(); close(ttyfd); if (x25serverfd) { /* we were the passive client of a server, now we * go back to being the normal client. * I hope that kermit can cope with the logic that * there can still be a connection after netclos * has been called. */ ttyfd = x25serverfd; x25serverfd = 0; /* * need to close the server connection too - because * all file descriptors connected to the NPI have the * same status. * * The problem is that any waiting connections get * lost, the client doesn't realise, and hangs. */ netclos(); } x25_state = X25_CLOSED; /* riehm: dead code? */ } else #endif /* IBMX25 */ x = close(ttyfd); #endif /* OS2 */ #endif /* TCPIPLIB */ } ttyfd = -1; /* Mark it as closed. */ wasclosed = 1; #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ #ifdef TNCODE #ifdef CK_FORWARD_X fwdx_close_all(); /* Shut down any Forward X sockets */ #endif /* CK_FORWARD_X */ tn_reset(); /* The Reset Telnet Option table. */ debug(F100,"netclose setting tn_init = 0","",0); tn_init = 0; /* Remember about telnet protocol... */ sstelnet = 0; /* Client-side Telnet */ #endif /* TNCODE */ *ipaddr = '\0'; /* Zero the IP address string */ tcp_incoming = 0; /* No longer incoming */ /* Don't reset ttnproto so that we can remember which protocol is in use */ #ifdef TCPIPLIB /* Empty the internal buffers so they won't be used as invalid input on the next connect attempt (rlogin). */ ttibp = 0; ttibn = 0; #endif /* TCPIPLIB */ #ifdef CK_KERBEROS /* If we are automatically destroying Kerberos credentials on Close */ /* do it now. */ #ifdef KRB4 if (krb4_autodel == KRB_DEL_CL) { extern struct krb_op_data krb_op; krb_op.version = 4; krb_op.cache = NULL; ck_krb4_destroy(&krb_op); } #endif /* KRB4 */ #ifdef KRB5 if (krb5_autodel == KRB_DEL_CL) { extern struct krb_op_data krb_op; extern char * krb5_d_cc; krb_op.version = 5; krb_op.cache = krb5_d_cc; ck_krb5_destroy(&krb_op); } #endif /* KRB5 */ #endif /* CK_KERBEROS */ close_in_progress = 0; /* Remember we are done. */ return(x); } #ifndef NOTCPIP #ifdef OS2 int os2socketerror( int s_errno ) { #ifdef OS2ONLY if (s_errno > 0 && s_errno <= SOCBASEERR) { /* in OS/2, there is a problem with threading in that * the value of errno is not thread safe. It can be * set to a value from a previous library call and if * it was not cleared it will appear here. Only treat * valid socket error codes as errors in this function. */ debug(F100,"os2socketerror errno.h","",0); socket_errno = 0; return(0); } #endif /* OS2ONLY */ switch (s_errno) { case 0: /* NO ERROR */ debug(F100,"os2socketerror NOERROR","",0); return(0); #ifdef NT case WSAECONNRESET: #else /* NT */ case SOCECONNRESET: case SOCECONNRESET - SOCBASEERR: #endif /* NT */ debug(F100,"os2socketerror ECONRESET","",0); tn_debug("ECONRESET"); netclos(); /* *** *** */ return(-1); /* Connection is broken. */ #ifdef NT case WSAECONNABORTED: #else /* NT */ case SOCECONNABORTED: case SOCECONNABORTED - SOCBASEERR: #endif /* NT */ debug(F100,"os2socketerror ECONNABORTED","",0); tn_debug("ECONNABORTED"); netclos(); /* *** *** */ return(-1); /* Connection is broken. */ #ifdef NT case WSAENETRESET: #else /* NT */ case SOCENETRESET: case SOCENETRESET - SOCBASEERR: #endif /* NT */ debug(F100,"os2socketerror ENETRESET","",0); tn_debug("ENETRESET"); netclos(); /* *** *** */ return(-1); /* Connection is broken. */ #ifdef NT case WSAENOTCONN: #else /* NT */ case SOCENOTCONN: case SOCENOTCONN - SOCBASEERR: #endif /* NT */ debug(F100,"os2socketerror ENOTCONN","",0); tn_debug("ENOTCONN"); netclos(); /* *** *** */ return(-1); /* Connection is broken. */ #ifdef NT case WSAESHUTDOWN: debug(F100,"os2socketerror ESHUTDOWN","",0); tn_debug("ESHUTDOWN"); netclos(); /* *** *** */ return(-1); /* Connection is broken. */ #endif /* NT */ #ifdef NT case WSAEWOULDBLOCK: #else case SOCEWOULDBLOCK: case SOCEWOULDBLOCK - SOCBASEERR: #endif /* NT */ debug(F100,"os2socketerror EWOULDBLOCK","",0); return(0); #ifdef NT case ERROR_IO_INCOMPLETE: case ERROR_IO_PENDING: case ERROR_OPERATION_ABORTED: return(0); #endif /* NT */ default: return(-2); } return(0); } #endif /* OS2 */ /* N E T T C H K -- Check if network up, and how many bytes can be read */ /* Returns number of bytes waiting, or -1 if connection has been dropped. */ int /* Check how many bytes are ready */ nettchk() { /* for reading from network */ #ifdef TCPIPLIB long count = 0; int x = 0, z; unsigned long uy; #ifndef OS2 char c; #endif /* OS2 */ int rc; #ifdef NT unsigned long ucount; extern int ionoblock; /* For Overlapped I/O */ #else long y; #endif /* NT */ debug(F101,"nettchk entry ttibn","",ttibn); debug(F101,"nettchk entry ttibp","",ttibp); #ifdef NETLEBUF { int n = 0; if (ttpush >= 0) n++; n += le_inbuf(); if (n > 0) return(n); } #endif /* NETLEBUF */ #ifndef OS2 #ifndef BEBOX socket_errno = 0; /* This is a function call in NT, and BeOS */ #endif /* BEBOX */ #endif /* OS2 */ if (ttyfd == -1) { debug(F100,"nettchk socket is closed","",0); return(-1); } /* Note: this socket_ioctl() call does NOT return an error if the connection has been broken. (At least not in MultiNet.) */ #ifdef COMMENT /* Another trick that can be tried here is something like this: */ if (ttnet == NET_TCPB) { char dummy; x = read(ttyfd,&dummy,0); /* Try to read nothing */ if (x < 0) { /* "Connection reset by peer" */ perror("TCP/IP"); /* or somesuch... */ ttclos(0); /* Close our end too. */ return(-1); } } #endif /* COMMENT */ #ifdef CK_SSL if (ssl_active_flag) { #ifndef IKSDONLY #ifdef OS2 if ( IsConnectMode() ) { debug(F101,"nettchk (ssl_active_flag) returns","",count); return(0); } #endif /* OS2 */ #endif /* IKSDONLY */ count = SSL_pending(ssl_con); if (count < 0) { debug(F111,"nettchk","SSL_pending error",count); netclos(); return(-1); } if ( count > 0 ) return(count); /* Don't perform a read */ } else if (tls_active_flag) { #ifndef IKSDONLY #ifdef OS2 if ( IsConnectMode() ) { debug(F101,"nettchk (tls_active_flag) returns","",count); return(0); } #endif /* OS2 */ #endif /* IKSDONLY */ count = SSL_pending(tls_con); if (count < 0) { debug(F111,"nettchk","TLS_pending error",count); netclos(); return(-1); } if ( count > 0 ) return(count); /* Don't perform a read */ } else #endif /* CK_SSL */ if (socket_ioctl(ttyfd,FIONREAD, #ifdef COMMENT /* Now we've changed the ioctl(..,..,x) prototype for DECC to (void *) */ #ifdef __DECC /* NOTE: "&count" might need to be "(char *)&count" in some settings. */ /* Cast needed for DECC 4.1 & later? */ /* Maybe, but __DECC_VER only exists in 5.0 and later */ (char *) #endif /* __DECC */ #endif /* COMMENT */ #ifdef NT &ucount #else &count #endif /* NT */ ) < 0) { debug(F101,"nettchk socket_ioctl error","",socket_errno); /* If the connection is gone, the connection is gone. */ netclos(); #ifdef NT /* Handle FIONREAD giving us a number larger than we can handle */ if (ucount > INT_MAX) ucount -= INT_MAX; count = ucount; #endif /* NT */ #ifdef NT_TCP_OVERLAPPED /* Is there anything in the overlapped I/O buffers? */ count += OverlappedDataWaiting(); #endif /* NT_TCP_OVERLAPPED */ count += ttibn; return(count>0?count:-1); } else { #ifdef NT /* Handle FIONREAD giving us a number larger than we can handle */ if (ucount > INT_MAX) ucount -= INT_MAX; count = ucount; #endif /* NT */ } debug(F101,"nettchk count","",count); #ifdef NT_TCP_OVERLAPPED /* Is there anything in the overlapped I/O buffers? */ count += OverlappedDataWaiting(); debug(F101,"nettchk count w/overlapped","",count); #endif /* NT_TCP_OVERLAPPED */ #ifdef OS2 #ifndef IKSDONLY if ( IsConnectMode() ) { debug(F101,"nettchk (FIONREAD) returns","",count); return(count); } #endif /* IKSDONLY */ #endif /* OS2 */ /* For the sake of efficiency, if there is still data in the ttibuf */ /* do not go to the bother of checking to see of the connection is */ /* still valid. The handle is still good, so just return the count */ /* of the bytes that we already have left to process. */ #ifdef OS2 if ( count > 0 || ttibn > 0 ) { count+=ttibn; debug(F101,"nettchk (count+ttibn > 0) returns","",count); return(count); } else { RequestTCPIPMutex(SEM_INDEFINITE_WAIT); if ( ttibn == 0 ) ttibp = 0; /* reset for next read */ } #else /* OS2 */ if ( count > 0 || ttibn > 0 ) { debug(F101,"nettchk returns","",count+ttibn); return(count+ttibn); } ttibn = ttibp = 0; #endif /* OS2 */ /* The following code works well in most settings, but messes things up in others, including CMU/Tek TCP/IP and UCX 2.0, where it somehow manages to make it impossible to ever make a new connection to the same host again with CONNECT, once it has been logged out from the first time. Not even if you HANGUP first, or SET HOST, or SET LINE. Reportedly, however, it does work OK in later releases of UCX. But there is no way we can accommodate both old and new -- we might have static linking or dynamic linking, etc etc. If we have static, I only have access to 2.0, where this doesn't work, etc etc blah blah. In the following lines, we define a symbol NOCOUNT for builds where we want to omit this code. By default, it is omitted for CMU/Tek. You can force omission of it for other combinations by defining NOCOUNT in CFLAGS. You can force inclusion of this code, even for CMU/Tek, by including NONOCOUNT in CFLAGS. */ #ifdef NONOCOUNT #ifdef NOCOUNT #undef NOCOUNT #endif /* NOCOUNT */ #else #ifndef NOCOUNT #ifdef CMU_TCPIP #define NOCOUNT #endif /* CMU_TCPIP */ #endif /* NOCOUNT */ #endif /* NONOCOUNT */ /* From this point forward we have a possible race condition in K95 * due to its use of multiple threads. Therefore, we must ensure * that only one thread attempt to read/write from the socket at a * time. Otherwise, it is possible for a buffer to be overwritten. */ /* we know now that count >= 0 and that ttibn == 0 */ if (count == 0 #ifdef RLOGCODE #ifdef CK_KERBEROS && ttnproto != NP_EK4LOGIN && ttnproto != NP_EK5LOGIN #endif /* CK_KERBEROS */ #endif /* RLOGCODE */ ) { int s_errno = 0; #ifndef NOCOUNT /* Here we need to tell the difference between a 0 count on an active connection, and a 0 count because the remote end of the socket broke the connection. There is no mechanism in TGV MultiNet (or WIN/TCP?) to query the status of the connection, so we have to do a read. -1 means there was no data available (socket_errno == EWOULDBLOCK), 0 means the connection is down. But if, by chance, we actually get a character, we have to put it where it won't be lost. */ #ifndef NON_BLOCK_IO #ifdef OS2 #ifdef CK_SSL RequestSSLMutex(SEM_INDEFINITE_WAIT); #endif /* CK_SSL */ #endif /* OS2 */ #ifdef NT uy = 1; /* Turn on nonblocking reads */ z = socket_ioctl(ttyfd,FIONBIO,&uy); #else y = 1; /* Turn on nonblocking reads */ z = socket_ioctl(ttyfd,FIONBIO,&y); #endif /* NT */ debug(F111,"nettchk FIONBIO","on",z); #ifdef OS2 #ifdef CK_SSL ReleaseSSLMutex(); #endif /* CK_SSL */ #endif /* OS2 */ #endif /* NON_BLOCK_IO */ #ifdef NT_TCP_OVERLAPPED ionoblock = 1; /* For Overlapped I/O */ #endif /* NT_TCP_OVERLAPPED */ #ifdef CK_SSL if ( ssl_active_flag || tls_active_flag ) { #ifdef OS2 ssl_read: x = SSL_read( ssl_active_flag?ssl_con:tls_con, &ttibuf[ttibp+ttibn], TTIBUFL-ttibp-ttibn ); switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) { case SSL_ERROR_NONE: debug(F111,"nettchk SSL_ERROR_NONE","x",x); break; case SSL_ERROR_WANT_WRITE: debug(F100,"nettchk SSL_ERROR_WANT_WRITE","",0); x = -1; break; case SSL_ERROR_WANT_READ: debug(F100,"nettchk SSL_ERROR_WANT_READ","",0); x = -1; break; case SSL_ERROR_SYSCALL: if ( x == 0 ) { /* EOF */ netclos(); rc = -1; goto nettchk_return; } else { #ifdef NT int gle = GetLastError(); #endif /* NT */ #ifndef NON_BLOCK_IO #ifdef OS2 #ifdef CK_SSL RequestSSLMutex(SEM_INDEFINITE_WAIT); #endif /* CK_SSL */ #endif /* OS2 */ #ifdef NT uy = 0; /* Turn off nonblocking reads */ z = socket_ioctl(ttyfd,FIONBIO,&uy); #else y = 0; /* Turn off nonblocking reads */ z = socket_ioctl(ttyfd,FIONBIO,&y); #endif debug(F111,"nettchk FIONBIO","off",z); #ifdef OS2 #ifdef CK_SSL ReleaseSSLMutex(); #endif /* CK_SSL */ #endif /* OS2 */ #endif /* NON_BLOCK_IO */ #ifdef NT_TCP_OVERLAPPED ionoblock = 0; /* For Overlapped I/O */ #endif /* NT_TCP_OVERLAPPED */ #ifdef NT debug(F111,"nettchk SSL_ERROR_SYSCALL", "GetLastError()",gle); rc = os2socketerror(gle); if (rc == -1) rc = -2; else if ( rc == -2 ) rc = -1; goto nettchk_return; #endif /* NT */ break; } case SSL_ERROR_WANT_X509_LOOKUP: debug(F100,"nettchk SSL_ERROR_WANT_X509_LOOKUP","",0); break; case SSL_ERROR_SSL: if (bio_err!=NULL) { int len; extern char ssl_err[]; BIO_printf(bio_err,"nettchk() SSL_ERROR_SSL\n"); ERR_print_errors(bio_err); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; debug(F110,"nettchk SSL_ERROR_SSL",ssl_err,0); if (ssl_debug_flag) printf(ssl_err); } else if (ssl_debug_flag) { debug(F100,"nettchk SSL_ERROR_SSL","",0); fflush(stderr); fprintf(stderr,"nettchk() SSL_ERROR_SSL\n"); ERR_print_errors_fp(stderr); } #ifdef COMMENT netclos(); rc = -1; goto nettchk_return; #else x = -1; break; #endif case SSL_ERROR_ZERO_RETURN: debug(F100,"nettchk SSL_ERROR_ZERO_RETURN","",0); netclos(); rc = -1; goto nettchk_return; default: debug(F100,"nettchk SSL_ERROR_?????","",0); netclos(); rc = -1; goto nettchk_return; } #else /* OS2 */ /* Do not block */ x = -1; #endif /* OS2 */ } else #endif /* CK_SSL */ { #ifdef OS2 x = socket_read(ttyfd,&ttibuf[ttibp+ttibn], TTIBUFL-ttibp-ttibn); /* Returns -1 if no data */ #else /* OS2 */ x = socket_read(ttyfd,&c,1); /* Returns -1 if no data */ #endif /* OS2 */ } s_errno = socket_errno; /* socket_errno may be a function */ debug(F101,"nettchk socket_read","",x); #ifndef NON_BLOCK_IO #ifdef OS2 #ifdef CK_SSL RequestSSLMutex(SEM_INDEFINITE_WAIT); #endif /* CK_SSL */ #endif /* OS2 */ #ifdef NT uy = 0; /* Turn off nonblocking reads */ z = socket_ioctl(ttyfd,FIONBIO,&uy); #else y = 0; /* Turn off nonblocking reads */ z = socket_ioctl(ttyfd,FIONBIO,&y); #endif /* NT */ debug(F111,"nettchk FIONBIO","off",z); #ifdef OS2 #ifdef CK_SSL ReleaseSSLMutex(); #endif /* CK_SSL */ #endif /* OS2 */ #endif /* NON_BLOCK_IO */ #ifdef NT_TCP_OVERLAPPED ionoblock = 0; /* For Overlapped I/O */ #endif /* NT_TCP_OVERLAPPED */ if (x == -1) { debug(F101,"nettchk socket_read errno","",s_errno); #ifdef OS2 if (os2socketerror(s_errno) < 0) { rc = -1; goto nettchk_return; } #endif /* OS2 */ } else if (x == 0) { debug(F100,"nettchk connection closed","",0); netclos(); /* *** *** */ rc = -1; goto nettchk_return; } if (x >= 1) { /* Oops, actually got a byte? */ #ifdef OS2 /* In OS/2 we read directly into ttibuf[] */ ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x); ttibn += x; #else /* OS2 */ #ifdef CK_SSL if ( ssl_active_flag || tls_active_flag ) { ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x); ttibn += x; } else #endif /* CK_SSL */ { debug(F101,"nettchk socket_read char","",c); debug(F101,"nettchk ttibp","",ttibp); debug(F101,"nettchk ttibn","",ttibn); /* In the case of Overlapped I/O the character would have come from the beginning of the buffer, so put it back. */ if (ttibp > 0) { ttibp--; ttibuf[ttibp] = c; ttibn++; } else { ttibuf[ttibp+ttibn] = c; ttibn++; } } #endif /* OS2 */ } #else /* NOCOUNT */ if (ttnet == NET_TCPB) { char dummy; x = read(ttyfd,&dummy,0); /* Try to read nothing */ if (x < 0) { /* "Connection reset by peer" */ perror("TCP/IP"); /* or somesuch... */ ttclos(0); /* Close our end too. */ rc = -1; goto nettchk_return; } } #endif /* NOCOUNT */ } #ifdef CK_KERBEROS #ifdef KRB4 #ifdef RLOGCODE if (ttnproto == NP_EK4LOGIN) count += krb4_des_avail(ttyfd); #endif /* RLOGCODE */ #endif /* KRB4 */ #ifdef KRB5 #ifdef RLOGCODE if (ttnproto == NP_EK5LOGIN) count += krb5_des_avail(ttyfd); #endif /* RLOGCODE */ #ifdef KRB5_U2U if (ttnproto == NP_K5U2U) count += krb5_u2u_avail(ttyfd); #endif /* KRB5_U2U */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ debug(F101,"nettchk returns","",count+ttibn); rc = count + ttibn; nettchk_return: #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(rc); #else /* Not TCPIPLIB */ /* UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor seem to work OK. */ return(ttchk()); #endif /* TCPIPLIB */ /* But what about X.25? */ } #ifndef OS2 VOID #ifdef CK_ANSIC nettout( int i ) /* Catch the alarm interrupts */ #else nettout(i) int i; #endif /* CK_ANSIC */ { debug(F100,"nettout caught timeout","",0); ttimoff(); cklongjmp(njbuf, -1); } #endif /* !OS2 */ #ifdef TCPIPLIB VOID #ifdef CK_ANSIC donetinc(void * threadinfo) #else /* CK_ANSIC */ donetinc(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ /* donetinc */ { #ifdef NTSIG extern int TlsIndex; setint(); if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); } #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef NT #ifdef IKSD if (inserver) setntcreds(); #endif /* IKSD */ #endif /* NT */ #endif /* CK_LOGIN */ while (1) { if (ttbufr() < 0) /* Keep trying to refill it. */ break; /* Till we get an error. */ if (ttibn > 0) /* Or we get a character. */ break; } } #endif /* TCPIPLIB */ VOID #ifdef CK_ANSIC failnetinc(void * threadinfo) #else /* CK_ANSIC */ failnetinc(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ /* failnetinc */ { ; /* Nothing to do on an error */ } /* N E T X I N -- Input block of characters from network */ int #ifdef CK_ANSIC netxin( int n, CHAR * buf ) #else netxin(n,buf) int n; CHAR * buf; #endif /* CK_ANSIC */ { int len; #ifdef TCPIPLIB int rc; #else int i, j; #endif /* TCPIPLIB */ if (ttyfd == -1) { debug(F100,"netxin socket is closed","",0); return(-2); } #ifdef CK_KERBEROS #ifdef KRB4 #ifdef RLOGCODE if (ttnproto == NP_EK4LOGIN) { if ((len = krb4_des_read(ttyfd,buf,n)) < 0) return(-1); else return(len); } #endif /* RLOGCODE */ #endif /* KRB4 */ #ifdef KRB5 #ifdef RLOGCODE if (ttnproto == NP_EK5LOGIN) { if ((len = krb5_des_read(ttyfd,(char *)buf,n,0)) < 0) return(-1); else return(len); } #endif /* RLOGCODE */ #ifdef KRB5_U2U if (ttnproto == NP_K5U2U) { if ((len = krb5_u2u_read(ttyfd,(char *)buf,n)) < 0) return(-1); else return(len); } #endif /* KRB5_U2U */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ #ifdef TCPIPLIB #ifdef OS2 RequestTCPIPMutex(SEM_INDEFINITE_WAIT); #endif /* OS2 */ if (ttibn == 0) if ((rc = ttbufr()) <= 0) { #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(rc); } if (ttibn <= n) { len = ttibn; memcpy(buf,&ttibuf[ttibp],len); /* safe */ ttibp += len; ttibn = 0; } else { memcpy(buf,&ttibuf[ttibp],n); /* safe */ ttibp += n; ttibn -= n; len = n; } #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ #else /* TCPIPLIB */ for (i = 0; i < n; i++) { if ((j = netinc(0)) < 0) { if (j < -1) return(j); else break; } buf[i] = j; } len = i; #endif /* TCPIPLIB */ #ifdef COMMENT #ifdef CK_ENCRYPTION /* This would be great if it worked. But what if the buffer we read */ /* contains a telnet negotiation that changes the state of the */ /* encryption. If so, we would be either decrypting unencrypted text */ /* or not decrypting encrypted text. So we must move this call to */ /* all functions that call ttxin(). In OS2 that means os2_netxin() */ /* where the Telnet Negotiations are handled. */ if (u_encrypt) ck_tn_decrypt(buf,len); #endif /* CK_ENCRYPTION */ #endif /* COMMENT */ return(len); } /* N E T I N C -- Input character from network */ #ifdef NETLEBUF #define LEBUF #endif /* NETLEBUF */ #ifdef TTLEBUF #define LEBUF #endif /* TTLEBUF */ #ifndef LEBUF #ifdef OS2 #define LEBUF #endif /* OS2 */ #endif /* LEBUF */ int #ifdef CK_ANSIC netinc( int timo ) #else netinc(timo) int timo; #endif /* CK_ANSIC */ { #ifdef TCPIPLIB int x; unsigned char c; /* The locals. */ #ifdef NETLEBUF if (ttpush >= 0) { debug(F111,"netinc","ttpush",ttpush); c = ttpush; ttpush = -1; return(c); } if (le_data) { if (le_getchar((CHAR *)&c) > 0) { debug(F111,"netinc le_getchar","c",c); return(c); } } #endif /* NETLEBUF */ if (ttyfd == -1) { debug(F100,"netinc socket is closed","",0); return(-2); } #ifdef CK_KERBEROS #ifdef KRB4 #ifdef RLOGCODE if (ttnproto == NP_EK4LOGIN) { if ((x = krb4_des_read(ttyfd,&c,1)) == 0) return(-1); else if (x < 0) return(-2); else return(c); } #endif /* RLOGCODE */ #endif /* KRB4 */ #ifdef KRB5 #ifdef RLOGCODE if (ttnproto == NP_EK5LOGIN) { if ((x = krb5_des_read(ttyfd,&c,1,0)) == 0) return(-1); else if (x < 0) return(-2); else return(c); } #endif /* RLOGCODE */ #ifdef KRB5_U2U if (ttnproto == NP_K5U2U) { if ((x = krb5_u2u_read(ttyfd,&c,1)) == 0) return(-1); else if (x < 0) return(-2); else return(c); } #endif /* KRB5_U2U */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ #ifdef OS2 RequestTCPIPMutex(SEM_INDEFINITE_WAIT); #endif /* OS2 */ if (ttibn > 0) { /* Something in internal buffer? */ #ifdef COMMENT debug(F100,"netinc char in buf","",0); /* Yes. */ #endif /* COMMENT */ x = 0; /* Success. */ } else { /* Else must read from network. */ x = -1; /* Assume failure. */ #ifdef DEBUG debug(F101,"netinc goes to net, timo","",timo); #endif /* DEBUG */ #ifdef CK_SSL /* * In the case of OpenSSL, it is possible that there is still * data waiting in the SSL session buffers that has not yet * been read by Kermit. If this is the case we must process * it without calling select() because select() will not return * with an indication that there is data to be read from the * socket. If there is no data pending in the SSL session * buffers then fall through to the select() code and wait for * some data to arrive. */ if (ssl_active_flag) { x = SSL_pending(ssl_con); if (x < 0) { debug(F111,"netinc","SSL_pending error",x); netclos(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); } else if ( x > 0 ) { if ( ttbufr() >= 0 ) { x = netinc(timo); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(x); } } x = -1; } else if (tls_active_flag) { x = SSL_pending(tls_con); if (x < 0) { debug(F111,"netinc","TLS_pending error",x); netclos(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); } else if ( x > 0 ) { if ( ttbufr() >= 0 ) { x = netinc(timo); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(x); } } x = -1; } #endif /* CK_SSL */ #ifndef LEBUF if (timo == 0) { /* Untimed case. */ while (1) { /* Wait forever if necessary. */ if (ttbufr() < 0) /* Refill buffer. */ break; /* Error, fail. */ if (ttibn > 0) { /* Success. */ x = 0; break; } } } else /* Timed case... */ #endif /* LEBUF */ { #ifdef NT_TCP_OVERLAPPED /* This code is for use on NT when we are using */ /* Overlapped I/O to handle reads. In the case */ /* of outstanding reads select() doesn't work */ if (WaitForOverlappedReadData(timo)) { while (1) { if (ttbufr() < 0) /* Keep trying to refill it. */ break; /* Till we get an error. */ if (ttibn > 0) { /* Or we get a character. */ x = 0; break; } } } #else /* NT_TCP_OVERLAPPED */ #ifdef BSDSELECT fd_set rfds; struct timeval tv; int timeout = timo < 0 ? -timo : 1000 * timo; debug(F101,"netinc BSDSELECT","",timo); for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) { int rc; debug(F111,"netinc","timeout",timeout); /* Don't move select() initialization out of the loop. */ FD_ZERO(&rfds); FD_SET(ttyfd, &rfds); tv.tv_sec = tv.tv_usec = 0L; if (timo) tv.tv_usec = (long) 100000L; else tv.tv_sec = 30; #ifdef NT WSASafeToCancel = 1; #endif /* NT */ rc = select(FD_SETSIZE, #ifdef __DECC #ifdef INTSELECT (int *) #else /* def INTSELECT */ (fd_set *) #endif /* def INTSELECT [else] */ #else /* def __DECC */ (fd_set *) #endif /* def __DECC [else] */ &rfds, NULL, NULL, &tv); if (rc < 0) { int s_errno = socket_errno; debug(F111,"netinc","select",rc); debug(F111,"netinc","socket_errno",s_errno); if (s_errno) { #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); } } debug(F111,"netinc","select",rc); /* * For some yet to be determined reason, on NT 3.1 the select() * call is claiming the socket isn't ready for reading - * !FD_ISSET(ttyfd, &rfds) == true && rc == 0 * this occurs even when ttchk() returns some number of bytes * ready for reading which should mean the socket is ready for * reading. And indeed if we go ahead and try to read when * ttchk() > 0 telnet suddenly works! * * So maybe there is some bug in the NT 3.1 Winsock * implementation? Or is K95 doing something that NT 3.1 doesn't * like? * * problem is, the API ttchk() relies on (FIONREAD) is slow and * potentially unreliable so its not really an acceptable * replacement for select() unless we're ok with really bad * performance * * Note: ttchk eventually arrives at nettchk further up in this file. * Line 5473 is about where the FIONREAD is. * */ #ifdef NT WSASafeToCancel = 0; #endif /* NT */ if (!FD_ISSET(ttyfd, &rfds)) { #ifdef LEBUF if (le_inbuf() > 0) { timeout = -1; break; } #endif /* LEBUF */ /* If waiting forever we have no way of knowing if the */ /* socket closed so try writing a 0-length TCP packet */ /* which should force an error if the socket is closed */ if (!timo) { if ((rc = socket_write(ttyfd,"",0)) < 0) { int s_errno = socket_errno; debug(F101,"netinc socket_write error","",s_errno); #ifdef OS2 if (os2socketerror(s_errno) < 0) { ReleaseTCPIPMutex(); return(-2); } ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); /* Call it an i/o error */ } } continue; } while (1) { if (ttbufr() < 0) { /* Keep trying to refill it. */ timeout = -1; break; /* Till we get an error. */ } if (ttibn > 0) { /* Or we get a character. */ x = 0; timeout = -1; break; } } } #ifdef NT WSASafeToCancel = 0; #endif /* NT */ #else /* !BSDSELECT */ #ifdef IBMSELECT /* Was used by OS/2, currently not used, but might come in handy some day... ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set and timeval stuff since this is the only place where it is used. */ int socket = ttyfd; int timeout = timo < 0 ? -timo : 1000 * timo; debug(F101,"netinc IBMSELECT","",timo); for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) { if (select(&socket, 1, 0, 0, 100L) == 1) { while (1) { if (ttbufr() < 0) { /* Keep trying to refill it. */ timeout = -1; break; /* Till we get an error. */ } if (ttibn > 0) { /* Or we get a character. */ x = 0; timeout = -1; break; } } } #ifdef LEBUF else if (le_inbuf() > 0) { timeout = -1; break; } #endif /* LEBUF */ } #else /* !IBMSELECT */ #ifdef WINSOCK /* Actually, under WinSock we have a better mechanism than select() */ /* for setting timeouts (SO_RCVTIMEO, SO_SNDTIMEO) */ SOCKET socket = ttyfd; debug(F101,"netinc NTSELECT","",timo); if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timo, sizeof(timo)) == NO_ERROR) while (1) { if (ttbufr() < 0) /* Keep trying to refill it. */ break; /* Till we get an error. */ if (ttibn > 0) { /* Or we get a character. */ x = 0; break; } } #else /* WINSOCK */ /* If we can't use select(), then we use the regular alarm()/signal() timeout mechanism. */ debug(F101,"netinc alarm","",timo); x = alrm_execute(ckjaddr(njbuf),timo,nettout,donetinc,failnetinc); ttimoff(); /* Timer off. */ #endif /* WINSOCK */ #endif /* IBMSELECT */ #endif /* BSDSELECT */ #endif /* NT_TCP_OVERLAPPED */ } } #ifdef LEBUF if (le_inbuf() > 0) { /* If data was inserted into the */ if (le_getchar((CHAR *)&c) > 0) {/* Local Echo buffer while the */ #ifdef OS2 /* was taking place do not mix */ ReleaseTCPIPMutex(); /* the le data with the net data */ #endif /* OS2 */ return(c); } } #endif /* LEBUF */ if (x < 0) { /* Return -1 if we failed. */ debug(F100,"netinc timed out","",0); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); } else { /* Otherwise */ c = ttibuf[ttibp]; /* Return the first char in ttibuf[] */ if (deblog) { #ifndef COMMENT debug(F101,"netinc returning","",c); #endif /* COMMENT */ if (c == 0) { debug(F101,"netinc 0 ttibn","",ttibn); debug(F101,"netinc 0 ttibp","",ttibp); #ifdef BETADEBUG { #ifdef OS2 extern int tt_type_mode; if ( !ISVTNT(tt_type_mode) ) #endif /* OS2 */ ckhexdump("netinc &ttbuf[ttibp]",&ttibuf[ttibp],ttibn); } #endif /* BETADEBUG */ } } ttibp++; ttibn--; #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ #ifdef CK_ENCRYPTION if (TELOPT_U(TELOPT_ENCRYPTION)) ck_tn_decrypt(&c,1); #endif /* CK_ENCRYPTION */ return(c); } #else /* Not using TCPIPLIB */ return(-1); #endif /* TCPIPLIB */ } /* N E T T O L -- Output a string of bytes to the network */ /* Call with s = pointer to string, n = length. Returns number of bytes actually written on success, or -1 on i/o error, -2 if called improperly. */ int #ifdef CK_ANSIC nettol( CHAR *s, int n ) #else nettol(s,n) CHAR *s; int n; #endif /* CK_ANSIC */ { #ifdef TCPIPLIB int count = 0; int len = n; int try = 0; if (ttyfd == -1) { debug(F100,"nettol socket is closed","",0); return -1; } debug(F101,"nettol TCPIPLIB ttnet","",ttnet); #ifdef COMMENT ckhexdump("nettol",s,n); #endif /* COMMENT */ #ifdef CK_KERBEROS #ifdef KRB4 #ifdef RLOGCODE if (ttnproto == NP_EK4LOGIN) { return(krb4_des_write(ttyfd,s,n)); } #endif /* RLOGCODE */ #endif /* KRB4 */ #ifdef KRB5 #ifdef RLOGCODE if (ttnproto == NP_EK5LOGIN) { return(krb5_des_write(ttyfd,s,n,0)); } #endif /* RLOGCODE */ #ifdef KRB5_U2U if (ttnproto == NP_K5U2U) { return(krb5_u2u_write(ttyfd,s,n)); } #endif /* KRB5_U2U */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ #ifdef CK_ENCRYPTION if (TELOPT_ME(TELOPT_ENCRYPTION)) ck_tn_encrypt(s,n); #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if (ssl_active_flag || tls_active_flag) { int error, r; /* Write using SSL */ ssl_retry: if (ssl_active_flag) r = SSL_write(ssl_con, s, len /* >1024?1024:len */); else r = SSL_write(tls_con, s, len /* >1024?1024:len */); switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,r)) { case SSL_ERROR_NONE: debug(F111,"nettol","SSL_write",r); if ( r == len ) return(n); s += r; len -= r; goto ssl_retry; case SSL_ERROR_WANT_WRITE: debug(F100,"nettol SSL_ERROR_WANT_WRITE","",0); return(-1); case SSL_ERROR_WANT_READ: debug(F100,"nettol SSL_ERROR_WANT_READ","",0); return(-1); case SSL_ERROR_SYSCALL: if ( r == 0 ) { /* EOF */ netclos(); return(-2); } else { int rc = -1; #ifdef NT int gle = GetLastError(); debug(F111,"nettol SSL_ERROR_SYSCALL", "GetLastError()",gle); rc = os2socketerror(gle); if (rc == -1) rc = -2; else if ( rc == -2 ) rc = -1; #endif /* NT */ return(rc); } case SSL_ERROR_WANT_X509_LOOKUP: debug(F100,"nettol SSL_ERROR_WANT_X509_LOOKUP","",0); netclos(); return(-2); case SSL_ERROR_SSL: debug(F100,"nettol SSL_ERROR_SSL","",0); if (bio_err!=NULL) { int len; extern char ssl_err[]; BIO_printf(bio_err,"nettol() SSL_ERROR_SSL\n"); ERR_print_errors(bio_err); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; debug(F110,"nettol SSL_ERROR_SSL",ssl_err,0); if (ssl_debug_flag) printf(ssl_err); } else if (ssl_debug_flag) { debug(F100,"nettol SSL_ERROR_SSL","",0); fflush(stderr); fprintf(stderr,"nettol() SSL_ERROR_SSL\n"); ERR_print_errors_fp(stderr); } #ifdef COMMENT netclos(); return(-2); #else return(-1); #endif case SSL_ERROR_ZERO_RETURN: debug(F100,"nettol SSL_ERROR_ZERO_RETURN","",0); netclos(); return(-2); default: debug(F100,"nettol SSL_ERROR_?????","",0); netclos(); return(-2); } } #endif /* CK_SSL */ nettol_retry: try++; /* Increase the try counter */ if (ttnet == NET_TCPB) { #ifdef BSDSELECT fd_set wfds; struct timeval tv; debug(F101,"nettol BSDSELECT","",0); tv.tv_usec = 0L; tv.tv_sec=30; #ifdef NT WSASafeToCancel = 1; #endif /* NT */ #ifdef STREAMING do_select: #endif /* STREAMING */ FD_ZERO(&wfds); FD_SET(ttyfd, &wfds); if (select(FD_SETSIZE, NULL, #ifdef __DECC #ifndef __DECC_VER (int *) #endif /* __DECC_VER */ #endif /* __DECC */ &wfds, NULL, &tv) < 0) { int s_errno = socket_errno; debug(F101,"nettol select failed","",s_errno); #ifdef BETADEBUG printf("nettol select failed: %d\n", s_errno); #endif /* BETADEBUG */ #ifdef NT WSASafeToCancel = 0; if (!win95selectbug) #endif /* NT */ return(-1); } if (!FD_ISSET(ttyfd, &wfds)) { #ifdef STREAMING if (streaming) goto do_select; #endif /* STREAMING */ debug(F111,"nettol","!FD_ISSET",ttyfd); #ifdef NT WSASafeToCancel = 0; if (!win95selectbug) #endif /* NT */ return(-1); } #ifdef NT WSASafeToCancel = 0; #endif /* NT */ #else /* BSDSELECT */ #ifdef IBMSELECT { int tries = 0; debug(F101,"nettol IBMSELECT","",0); while (select(&ttyfd, 0, 1, 0, 1000) != 1) { int count; if (tries++ >= 60) { /* if after 60 seconds we can't get permission to write */ debug(F101,"nettol select failed","",socket_errno); return(-1); } if ((count = nettchk()) < 0) { debug(F111,"nettol","nettchk()",count); return(count); } } } #endif /* IBMSELECT */ #endif /* BSDSELECT */ if ((count = socket_write(ttyfd,s,n)) < 0) { int s_errno = socket_errno; /* maybe a function */ debug(F101,"nettol socket_write error","",s_errno); #ifdef OS2 if (os2socketerror(s_errno) < 0) return(-2); #endif /* OS2 */ return(-1); /* Call it an i/o error */ } if (count < n) { debug(F111,"nettol socket_write",s,count); if (try > 25) { /* don't try more than 25 times */ debug(F100,"nettol tried more than 25 times","",0); return(-1); } if (count > 0) { s += count; n -= count; } debug(F111,"nettol retry",s,n); goto nettol_retry; } else { debug(F111,"nettol socket_write",s,count); return(len); /* success - return total length */ } } else return(-2); #else debug(F100,"nettol TCPIPLIB not defined","",0); return(-2); #endif /* TCPIPLIB */ } /* N E T T O C -- Output character to network */ /* Call with character to be transmitted. Returns 0 if transmission was successful, or -1 upon i/o error, or -2 if called improperly. */ int #ifdef CK_ANSIC nettoc(CHAR c) #else nettoc(c) CHAR c; #endif /* CK_ANSIC */ /* nettoc */ { #ifdef UNIX return(ttoc(c)); #else #ifdef TCPIPLIB unsigned char cc; if (ttyfd == -1) { debug(F100,"nettoc socket is closed","",0); return -1; } cc = c; debug(F101,"nettoc cc","",cc); #ifdef CK_KERBEROS #ifdef KRB4 #ifdef RLOGCODE if (ttnproto == NP_EK4LOGIN) { return(krb4_des_write(ttyfd,&cc,1)==1?0:-1); } #endif /* RLOGCODE */ #endif /* KRB4 */ #ifdef KRB5 #ifdef RLOGCODE if (ttnproto == NP_EK5LOGIN) { return(krb5_des_write(ttyfd,&cc,1,0)==1?0:-1); } #endif /* RLOGCODE */ #ifdef KRB5_U2U if (ttnproto == NP_K5U2U) { return(krb5_u2u_write(ttyfd,&cc,1)==1?0:-1); } #endif /* KRB5_U2U */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ #ifdef CK_ENCRYPTION if ( TELOPT_ME(TELOPT_ENCRYPTION) ) ck_tn_encrypt(&cc,1); #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if (ssl_active_flag || tls_active_flag) { int len, error; /* Write using SSL */ ssl_retry: if (ssl_active_flag) len = SSL_write(ssl_con, &cc, 1); else len = SSL_write(tls_con, &cc, 1); switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,len)) { case SSL_ERROR_NONE: debug(F111,"nettoc","SSL_write",len); return(len == 1 ? 0 : -1); case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: return(-1); case SSL_ERROR_SYSCALL: if ( len == 0 ) { /* EOF */ netclos(); return(-2); } else { int rc = -1; #ifdef NT int gle = GetLastError(); debug(F111,"nettoc SSL_ERROR_SYSCALL", "GetLastError()",gle); rc = os2socketerror(gle); if (rc == -1) rc = -2; else if ( rc == -2 ) rc = -1; #endif /* NT */ return(rc); } case SSL_ERROR_SSL: if (bio_err!=NULL) { int len; extern char ssl_err[]; BIO_printf(bio_err,"nettoc() SSL_ERROR_SSL\n"); ERR_print_errors(bio_err); len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ); ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0'; debug(F110,"nettoc SSL_ERROR_SSL",ssl_err,0); if (ssl_debug_flag) printf(ssl_err); } else if (ssl_debug_flag) { debug(F100,"nettoc SSL_ERROR_SSL","",0); fflush(stderr); fprintf(stderr,"nettoc() SSL_ERROR_SSL\n"); ERR_print_errors_fp(stderr); } return(-1); break; case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_ZERO_RETURN: default: netclos(); return(-2); } } #endif /* CK_SSL */ if (ttnet == NET_TCPB) { #ifdef BSDSELECT fd_set wfds; struct timeval tv; debug(F101,"nettoc BSDSELECT","",0); tv.tv_usec = 0L; tv.tv_sec = 30; #ifdef STREAMING do_select: #endif /* STREAMING */ FD_ZERO(&wfds); FD_SET(ttyfd, &wfds); if (select(FD_SETSIZE, NULL, #ifdef __DECC #ifndef __DECC_VER (int *) #endif /* __DECC_VER */ #endif /* __DECC */ &wfds, NULL, &tv) < 0) { int s_errno = socket_errno; debug(F101,"nettoc select failed","",s_errno); #ifdef BETADEBUG printf("nettoc select failed: %d\n", s_errno); #endif /* BETADEBUG */ #ifdef NT WSASafeToCancel = 0; if (!win95selectbug) #endif /* NT */ return(-1); } if (!FD_ISSET(ttyfd, &wfds)) { #ifdef STREAMING if (streaming) goto do_select; #endif /* STREAMING */ debug(F111,"nettoc","!FD_ISSET",ttyfd); #ifdef NT WSASafeToCancel = 0; if (!win95selectbug) #endif /* NT */ return(-1); } #ifdef NT WSASafeToCancel = 0; #endif /* NT */ #else /* BSDSELECT */ #ifdef IBMSELECT { int tries = 0; while (select(&ttyfd, 0, 1, 0, 1000) != 1) { int count; if (tries++ >= 60) { /* if after 60 seconds we can't get permission to write */ debug(F101,"nettoc select failed","",socket_errno); return(-1); } if ((count = nettchk()) < 0) { debug(F111,"nettoc","nettchk()",count); return(count); } } } #endif /* IBMSELECT */ #endif /* BSDSELECT */ if (socket_write(ttyfd,&cc,1) < 1) { int s_errno = socket_errno; /* maybe a function */ debug(F101,"nettoc socket_write error","",s_errno); #ifdef OS2 if (os2socketerror(s_errno) < 0) return(-2); #endif /* OS2 */ return(-1); } debug(F101,"nettoc socket_write","", cc); return(0); } else return(-2); #else return(-2); #endif /* TCPIPLIB */ #endif /* UNIX */ } /* N E T F L U I -- Flush network input buffer */ #ifdef TNCODE static int #ifdef CK_ANSIC netgetct(int timo) /* Input function to point to... */ #else /* CK_ANSIC */ netgetct(timo) int timo; #endif /* CK_ANSIC */ { /* ...in the tn_doop() call */ #ifdef TCPIPLIB return netinc(timo); #else /* TCPIPLIB */ return ttinc(timo); #endif /* TCPIPLIB */ } #endif /* TNCODE */ int netflui() { int n; int ch; #ifdef NETLEBUF ttpush = -1; /* Clear the peek-ahead char */ while (le_data && (le_inbuf() > 0)) { CHAR ch = '\0'; if (le_getchar(&ch) > 0) { debug(F101,"ttflui le_inbuf ch","",ch); } } #endif /* NETLEBUF */ #ifdef TCPIPLIB #ifdef OS2 RequestTCPIPMutex(SEM_INDEFINITE_WAIT); #endif /* OS2 */ #ifdef TNCODE if (ttnproto == NP_TELNET) { /* Netflui must process Telnet negotiations or get out of sync */ if ((n = nettchk()) <= 0) goto exit_flui; while (n-- > 0) { ch = netinc(1); if (ch == IAC) { extern int duplex; /* this really shouldn't be here but ... */ int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetct); if (tx == 1) duplex = 1; else if (tx == 2) duplex = 0; n = nettchk(); } } } else #endif /* TNCODE */ { ttibuf[ttibp+ttibn] = '\0'; debug(F111,"netflui 1",ttibuf,ttibn); #ifdef CK_ENCRYPTION if (TELOPT_U(TELOPT_ENCRYPTION)) { ck_tn_decrypt(&ttibuf[ttibp],ttibn); } #endif /* CK_ENCRYPTION */ ttibn = ttibp = 0; /* Flush internal buffer *FIRST* */ if (ttyfd < 1) goto exit_flui; if ((n = nettchk()) > 0) { /* Now see what's waiting on the net */ if (n > TTIBUFL) n = TTIBUFL; /* and sponge it up */ debug(F101,"netflui 2","",n); /* ... */ n = socket_read(ttyfd,ttibuf,n); /* into our buffer */ if (n >= 0) ttibuf[n] = '\0'; debug(F111,"netflui 3",ttibuf,n); #ifdef CK_ENCRYPTION if (TELOPT_U(TELOPT_ENCRYPTION)) { ck_tn_decrypt(&ttibuf[ttibp],n); } #endif /* CK_ENCRYPTION */ ttibuf[0] = '\0'; } } #else /* !TCPIPLIB */ if (ttyfd < 1) goto exit_flui; #ifdef TNCODE if (ttnproto == NP_TELNET) { if ((n = ttchk()) <= 0) goto exit_flui; while (n-- >= 0) { /* Netflui must process Telnet negotiations or get out of sync */ ch = ttinc(1); if (ch == IAC) { extern int duplex; /* this really shouldn't be here but ... */ int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetct); if (tx == 1) duplex = 1; else if (tx == 2) duplex = 0; n = ttchk(); } }; } else #endif /* TNCODE */ if ((n = ttchk()) > 0) { debug(F101,"netflui non-TCPIPLIB","",n); while ((n--) && ttinc(1) > -1) /* Don't worry, ttinc() is buffered */ ; /* and it handles the decryption... */ } #endif /* TCPIPLIB */ exit_flui: #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(0); } #ifdef CK_KERBEROS /* The following two functions are required for encrypted rlogin */ /* They are called with nettoc() or nettol() are transmitting */ /* encrypted data. They call a function to encrypt the data */ /* and that function needs to be able to write to/read from the */ /* network in an unimpeded manner. Hence, these two simple fns. */ int net_write(fd, buf, len) int fd; register const char *buf; int len; { int cc; register int wrlen = len; do { #ifdef TCPIPLIB cc = socket_write(fd, buf, wrlen); #else cc = write(fd,buf,wrlen); #endif /* TCPIPLIB */ if (cc < 0) { int s_errno = socket_errno; debug(F101,"net_write error","",s_errno); #ifdef OS2 if (os2socketerror(s_errno) < 0) return(-1); else continue; #else /* OS2 */ if (errno == EINTR) continue; return(-1); #endif /* OS2 */ } else { buf += cc; wrlen -= cc; } } while (wrlen > 0); return(len); } int net_read(fd, buf, len) int fd; register char *buf; register int len; { int cc, len2 = 0; do { #ifdef TCPIPLIB cc = socket_read(fd, buf, len); #else cc = read(fd,buf,len); #endif if (cc < 0) { int s_errno = socket_errno; debug(F101,"net_read error","",s_errno); #ifdef OS2 if (os2socketerror(s_errno) < 0) return(-1); #endif /* OS2 */ return(cc); /* errno is already set */ } else if (cc == 0) { netclos(); return(len2); } else { buf += cc; len2 += cc; len -= cc; } } while (len > 0); return(len2); } #endif /* CK_KERBEROS */ /* getlocalipaddr() attempts to resolve an IP Address for the local machine. * If the host is multi-homed it returns only one address. * * Two techniques are used. * (1) get the local host name and perform a DNS lookup, then take * the first entry; * (2) open a UDP socket, use it to connect to a fictitious host (it's OK, * no data is sent), then retrieve the local address from the socket. * Note: the second technique won't work on Microsoft systems. See * Article ID: Q129065 PRB: Getsockname() Returns IP Address 0.0.0.0 for UDP */ /* Technique number one cannot work reliably if the machine is a laptop * and the hostname is associated with a physical adapter which is not * installed and a PPP connection is being used instead. This is because * the hostname DNS lookup will succeed for the physical adapter even though * it would be impossible to use it. In NT4 SP4, the gethostbyname() * when given the result of gethostname() returns not the real DNS entries * for that name+domain. Instead it returns all of the static and dynamic * IP addresses assigned to any physical or virtual adapter defined in the * system regardless of whether or not it is installed. The order of the * addresses is fixed according to the binding order in the NT registry. */ /* * It appears that calling gethostbyname(NULL) is more reliable than * calling gethostbyname(gethostname()) on Windows. So on Windows we will * only call gethostbyname(NULL). */ int #ifdef CK_ANSIC getlocalipaddr( void ) #else getlocalipaddr() #endif /* CK_ANSIC */ { #ifndef datageneral struct sockaddr_in l_sa; struct sockaddr_in r_sa; GSOCKNAME_T slen = sizeof(struct sockaddr_in); int sock; int rc; /* if still not resolved, then try second strategy */ /* This second strategy does not work on Windows */ debug(F100,"getlocalipaddr","",0); memset(&l_sa,0,slen); memset(&r_sa,0,slen); /* get a UDP socket */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock != -1) { /* connect to arbirary port and address (NOT loopback) */ r_sa.sin_family = AF_INET; r_sa.sin_port = htons(IPPORT_ECHO); /* The following is an "illegal conversion" in AOS/VS */ /* (and who knows where else) */ #ifdef INADDRX inaddrx = inet_addr("128.127.50.1"); r_sa.sin_addr.s_addr = *(unsigned long *)&inaddrx; #else r_sa.sin_addr.s_addr = inet_addr("128.127.50.1"); #endif /* INADDRX */ rc = connect(sock, (struct sockaddr *) &r_sa, sizeof(struct sockaddr)); if (!rc) { /* get local address */ getsockname(sock,(struct sockaddr *)&l_sa,&slen); #ifdef TCPIPLIB socket_close(sock); /* We're done with the socket */ #else close(sock); #endif /* TCPIPLIB */ if (l_sa.sin_addr.s_addr != INADDR_ANY) { myxipaddr = ntohl(l_sa.sin_addr.s_addr); ckstrncpy(myipaddr,(char *)inet_ntoa(l_sa.sin_addr),20); debug(F110,"getlocalipaddr setting buf to",myipaddr,0); return(0); } } } return getlocalipaddrs(myipaddr,sizeof(myipaddr),0); #else /* datageneral */ return(-1); #endif /* datageneral */ } int #ifdef CK_ANSIC getlocalipaddrs( char * buf, int bufsz, int index ) #else getlocalipaddrs(buf,bufsz,index) char * buf; int bufsz; int index; #endif /* CK_ANSIC */ { #ifndef datageneral char localhost[256]; struct hostent * host=NULL; struct sockaddr_in l_sa; struct sockaddr_in r_sa; GSOCKNAME_T slen = sizeof(struct sockaddr_in); int rc; #ifdef COMMENT int sock; char messageBuf[60]; struct in_addr laddr; #endif /* COMMENT */ debug(F100,"getlocalipaddrs","",0); memset(&l_sa,0,slen); memset(&r_sa,0,slen); /* init local address (to zero) */ l_sa.sin_addr.s_addr = INADDR_ANY; #ifdef CKGHNLHOST rc = gethostname(localhost, 256); debug(F110,"getlocalipaddrs localhost",localhost,0); #else /* This doesn't work on some platforms, e.g. Solaris */ rc = 0; localhost[0] = '\0'; #ifdef NT if ( winsock_version < 20 ) { rc = gethostname(localhost, 256); debug(F110,"getlocalipaddrs localhost",localhost,0); } #endif /* NT */ #endif /* CKGHNLHOST */ if (!rc) { /* resolve host name for local address */ debug(F110,"getlocalipaddrs","calling gethostbyname()",0); host = gethostbyname(localhost); /* debug(F111,"getlocalipaddrs","gethostbyname() returned",host); */ if (host) { #ifdef HADDRLIST host = ck_copyhostent(host); if ( index < 0 || index > 63 || !host->h_addr_list[index] ) { buf[0] = '\0'; return(-1); } l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr_list[index])); ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),20); debug(F110,"getlocalipaddrs setting buf to",buf,0); #ifdef COMMENT /* This is for reporting multiple IP Address */ while (host->h_addr_list && host->h_addr_list[0]) { l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr_list[0])); ckstrncpy(messageBuf, (char *)inet_ntoa(l_sa.sin_addr),60); if (tcp_address) { if (!strcmp(messageBuf,tcp_address)) ckstrncpy(myipaddr,tcp_address,20); } debug(F110,"getlocalipaddrs ip address list", messageBuf, 0); host->h_addr_list++; } #endif /* COMMENT */ #else /* HADDRLIST */ if (index != 0) { buf[0] = '\0'; return(-1); } l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr)); ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),bufsz); debug(F110,"getlocalipaddrs setting buf to",buf,0); #endif /* HADDRLIST */ return(0); } else debug(F110, "getlocalipaddrs: gethostbyname() failed", localhost, 0 ); } #endif /* datageneral */ return(-1); } #ifdef RLOGCODE /* TCP/IP RLOGIN protocol support code */ #ifdef CK_NAWS int #ifdef CK_ANSIC rlog_naws( void ) #else rlog_naws() #endif /* CK_ANSIC */ { struct rlog_naws { unsigned char id[4]; unsigned short rows, cols, ypix, xpix; } nawsbuf; if (ttnet != NET_TCPB) return 0; if (ttnproto != NP_RLOGIN #ifdef CK_KERBEROS && ttnproto != NP_K4LOGIN && ttnproto != NP_EK4LOGIN && ttnproto != NP_K5LOGIN && ttnproto != NP_EK5LOGIN #endif /* CK_KERBEROS */ ) return 0; if (!TELOPT_ME(TELOPT_NAWS)) return 0; debug(F100,"rlogin Window Size sent","",0); nawsbuf.id[0] = nawsbuf.id[1] = 0377; nawsbuf.id[2] = nawsbuf.id[3] = 's'; #ifdef OS2 nawsbuf.rows = htons((unsigned short) (VscrnGetHeight(VTERM) -(tt_status[VTERM]?1:0))); nawsbuf.cols = htons((unsigned short) VscrnGetWidth(VTERM)); #else /* OS2 */ nawsbuf.rows = htons((unsigned short) tt_rows); nawsbuf.cols = htons((unsigned short) tt_cols); #endif /* OS2 */ nawsbuf.ypix = htons(0); /* y pixels */ nawsbuf.xpix = htons(0); /* x pixels */ if (ttol((CHAR *)(&nawsbuf), sizeof(nawsbuf)) < 0) return(-1); return(0); } #endif /* CK_NAWS */ #endif /* NOTCPIP */ #ifndef NORLOGIN #ifdef OS2ORUNIX #define RLOGOUTBUF #endif /* OS2 */ static int #ifdef CK_ANSIC rlog_ini(CHAR * hostname, int port, struct sockaddr_in * l_addr, struct sockaddr_in * r_addr) #else /* CK_ANSIC */ rlog_ini(hostname, port, l_addr, r_addr) CHAR * hostname; int port; struct sockaddr_in * l_addr; struct sockaddr_in * r_addr; #endif /* CK_ANSIC */ /* rlog_ini */ { #ifdef RLOGOUTBUF char outbuf[512]; int outbytes=0; #endif /* RLOGOUTBUF */ int flag = 0; #define TERMLEN 16 #define CONSPDLEN 16 CHAR localuser[UIDBUFLEN+1]; CHAR remoteuser[UIDBUFLEN+1]; int userlen = 0; CHAR term_speed[TERMLEN+CONSPDLEN+1]; #ifdef CONGSPD long conspd = -1L; #endif /* CONGSPD */ #ifdef OS2 extern int tt_type, max_tt; extern struct tt_info_rec tt_info[]; #endif /* OS2 */ int i, n; int rc = 0; tn_reset(); /* This call will reset all of the Telnet */ /* options and then quit. We need to do */ /* this since we use the Telnet options */ /* to hold various state information */ duplex = 0; /* Rlogin is always remote echo */ rlog_inband = 0; #ifdef CK_TTGWSIZ /* But compute the values anyway before the first read since the out- of-band NAWS request would arrive before the first data byte (NULL). */ #ifdef OS2 /* Console terminal screen rows and columns */ debug(F101,"rlog_ini tt_rows 1","",VscrnGetHeight(VTERM) -(tt_status[VTERM]?1:0)); debug(F101,"rlog_ini tt_cols 1","",VscrnGetWidth(VTERM)); /* Not known yet */ if (VscrnGetWidth(VTERM) < 0 || VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) < 0) { ttgwsiz(); /* Try to get screen dimensions */ } debug(F101, "rlog_ini tt_rows 2", "", VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) ); debug(F101,"rlog_ini tt_cols 2","",VscrnGetWidth(VTERM)); #else /* OS2 */ debug(F101,"rlog_ini tt_rows 1","",tt_rows); debug(F101,"rlog_ini tt_cols 1","",tt_cols); if (tt_rows < 0 || tt_cols < 0) { /* Not known yet */ ttgwsiz(); /* Try to find out */ } debug(F101,"rlog_ini tt_rows 2","",tt_rows); debug(F101,"rlog_ini tt_cols 2","",tt_cols); #endif /* OS2 */ #endif /* CK_TTGWSIZ */ ttflui(); /* Start by flushing the buffers */ rlog_mode = RL_COOKED; /* Determine the user's local username ... */ localuser[0] = '\0'; #ifdef NT { ckstrncpy((char *)localuser,GetLocalUser(),UIDBUFLEN); } if ( !localuser[0] ) #endif /* NT */ { char * user = getenv("USER"); if (!user) user = ""; userlen = strlen(user); debug(F111,"rlogin getenv(USER)",user,userlen); ckstrncpy((char *)localuser,user,UIDBUFLEN); debug(F110,"rlog_ini localuser 1",localuser,0); } if ( !localuser[0] ) strcpy((char *)localuser,"unknown"); else if (ck_lcname) { cklower((char *)localuser); debug(F110,"rlog_ini localuser 2",localuser,0); } /* And the username to login with */ if (uidbuf[0]) { ckstrncpy((char *)remoteuser,uidbuf,UIDBUFLEN); debug(F110,"rlog_ini remoteuser 1",remoteuser,0); } else if (localuser[0]) { ckstrncpy((char *)remoteuser,(char *)localuser,UIDBUFLEN); debug(F110,"rlog_ini remoteuser 2",remoteuser,0); } else { remoteuser[0] = '\0'; debug(F110,"rlog_ini remoteuser 3",remoteuser,0); } if (ck_lcname) cklower((char *)remoteuser); debug(F110,"rlog_ini remoteuser 4",remoteuser,0); /* The command to issue is the terminal type and speed */ term_speed[0] = '\0'; if (tn_term) { /* SET TELNET TERMINAL-TYPE value */ if (*tn_term) { /* (if any) takes precedence. */ ckstrncpy((char *)term_speed, tn_term, TERMLEN); flag = 1; } } else { /* Otherwise the local terminal type */ #ifdef OS2 /* In terminal-emulating versions, it's the SET TERM TYPE value */ ckstrncpy(term_speed, (tt_type >= 0 && tt_type <= max_tt) ? tt_info[tt_type].x_name : "network", TERMLEN); #else /* In the others, we just look at the TERM environment variable */ { char *p = getenv("TERM"); if (p) ckstrncpy((char *)term_speed,p,TERMLEN); else term_speed[0] = '\0'; #ifdef VMS for (p = (char *) term_speed; *p; p++) { if (*p == '-' && (!strcmp(p,"-80") || !strcmp(p,"-132"))) break; else if (isupper(*p)) *p = tolower(*p); } *p = '\0'; #endif /* VMS */ } #endif /* OS2 */ } n = strlen((char *)term_speed); if (n > 0) { /* We have a terminal type */ if (!flag) { /* If not user-specified */ for (i = 0; i < n; i++) /* then lowercase it. */ if (isupper(term_speed[i])) term_speed[i] = tolower(term_speed[i]); } debug(F110,"rlog_ini term_speed 1",term_speed,0); #ifdef CONGSPD /* conspd() is not yet defined in all ck*tio.c modules */ conspd = congspd(); if (conspd > 0L) { ckstrncat((char *)term_speed,"/",sizeof(term_speed)); ckstrncat((char *)term_speed,ckltoa(conspd),sizeof(term_speed)); } else #endif /* CONGSPD */ ckstrncat((char *)term_speed,"/19200",sizeof(term_speed)); debug(F110,"rlog_ini term_speed 2",term_speed,0); } else { term_speed[0] = '\0'; debug(F110,"rlog_ini term_speed 3",term_speed,0); } #ifdef CK_KERBEROS if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) { int kver, encrypt, rc; switch (ttnproto) { case NP_K4LOGIN: kver = 4; encrypt = 0; break; case NP_EK4LOGIN: kver = 4; encrypt = 1; break; case NP_K5LOGIN: kver = 5; encrypt = 0; break; case NP_EK5LOGIN: kver = 5; encrypt = 1; break; default: kver = 0; encrypt = 0; } rc = ck_krb_rlogin(hostname, port, localuser, remoteuser, term_speed, l_addr, r_addr, kver, encrypt); if (!rc) { /* success */ TELOPT_ME(TELOPT_NAWS) = 1; rc = rlog_naws(); } return(rc); } else #endif /* CK_KERBEROS */ if (ttnproto == NP_RLOGIN) { #ifdef RLOGOUTBUF /* * The rcmds start the connection with a series of init data: * * a port number upon which client is listening for stderr data * the user's name on the client machine * the user's name on the server machine * the terminal_type/speed or command to execute */ outbuf[outbytes++] = 0; strcpy((char *)outbuf+outbytes,(char *)localuser); outbytes += strlen((char *)localuser) + 1; strcpy((char *)outbuf+outbytes,(char *)remoteuser); outbytes += strlen((char *)remoteuser) + 1; strcpy((char *)outbuf+outbytes,(char *)term_speed); outbytes += strlen((char *)term_speed) + 1; rc = ttol((CHAR *)outbuf,outbytes); #else /* RLOGOUTBUF */ ttoc(0); /* Send an initial NUL as wake-up */ /* Send each variable with the trailing NUL */ rc = ttol(localuser,strlen((char *)localuser)+1); if (rc > 0) rc = ttol(remoteuser,strlen((char *)remoteuser)+1); if (rc > 0) rc = ttol(term_speed,strlen((char *)term_speed)+1); #endif /* RLOGOUTBUF */ /* Now we are supposed to get back a single NUL as confirmation */ errno = 0; rc = ttinc(60); debug(F101,"rlogin first ttinc","",rc); if (rc > 0) { debug(F101,"rlogin ttinc 1","",rc); printf( "Rlogin protocol error - 0x%x received instead of 0x00\n", rc); return(-1); } else if (rc < 0) { debug(F101,"rlogin ttinc errno","",errno); /* printf("Network error: %d\n", errno); */ return(-1); } } return(0); } /* two control messages are defined: a double flag byte of 'o' indicates a one-byte message which is identical to what was once carried out of band. a double flag byte of 'q' indicates a zero-byte message. This message is interpreted as two \377 data bytes. This is just a quote rule so that binary data from the server does not confuse the client. */ int #ifdef CK_ANSIC rlog_ctrl( unsigned char *cp, int n ) #else rlog_ctrl(cp, n) unsigned char *cp; int n; #endif /* CK_ANSIC */ { if ((n >= 5) && (cp[2] == 'o') && (cp[3] == 'o')) { if (rlog_oob(&cp[4],1)) return(-5); return(5); } else if ((n >= 4) && (cp[2] == 'q') && (cp[3] == 'q')) { /* this is somewhat of a hack */ cp[2] = '\377'; cp[3] = '\377'; return(2); } return(0); } static int #ifdef CK_ANSIC rlog_oob( CHAR * oobdata, int count ) #else rlog_oob(oobdata, count) CHAR * oobdata; int count; #endif /* CK_ANSIC */ { int i; int flush = 0; debug(F111,"rlogin out_of_band","count",count); for (i = 0; i MAXPADPARMS) x29err[i+2] = *ps; else padparms[*ps] = *(ps+1); ps += 2; } } } /* Read PAD parameters */ VOID readpad(s,n,r) CHAR *s; int n; CHAR *r; { int i; CHAR *ps = s; CHAR *pr = r; *pr++ = X29_PARAMETER_INDICATION; if (n > 0) { for (i = 0; i < n; i++, ps++) { if (*ps > MAXPADPARMS) { x29err[i+2] = *ps++; } else { *pr++ = *ps; *pr++ = padparms[*ps++]; } } } else { for (i = 1; i < MAXPADPARMS; i++) { *pr++ = i; *pr++ = padparms[i]; } } } int qbitpkt(s,n) CHAR *s; int n; { CHAR *ps = s; int x29cmd = *ps; CHAR *psa = s+1; CHAR x29resp[(MAXPADPARMS*2)+1]; switch (x29cmd) { case X29_SET_PARMS: setpad (ps+1,n/2); if ((int)strlen((char *)x29err) > 2) { ttol(x29err,(int)strlen((char *)x29err)); x29err[2] = '\0'; } return (-2); case X29_READ_PARMS: readpad (ps+1,n/2,x29resp); setqbit (); ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1)); if ((int)strlen((char *)x29err) > 2) { ttol(x29err,(int)strlen((char *)x29err)); x29err[2] = '\0'; } resetqbit(); break; case X29_SET_AND_READ_PARMS: setpad (ps+1,n/2); readpad (ps+1,n/2,x29resp); setqbit(); ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1)); if ((int)strlen((char *)x29err) > 2) { ttol (x29err,(int)strlen((char *)x29err)); x29err [2] = '\0'; } resetqbit(); return (-2); case X29_INVITATION_TO_CLEAR: (VOID) x25clear(); return (-1); case X29_INDICATION_OF_BREAK: break; } return (0); } /* PAD break action processor */ VOID breakact() { extern char x25obuf[MAXOX25]; extern int obufl; extern int active; extern unsigned char tosend; static CHAR indbrk[3] = { X29_INDICATION_OF_BREAK, PAD_SUPPRESSION_OF_DATA, 1 }; CHAR intudat, cause, diag; if (x25stat() < 0) return; /* Ignore if no virtual call established */ if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */ if (ttol((CHAR *)x25obuf,obufl) < 0) { perror ("\r\nCan't send characters"); active = 0; } else { bzero (x25obuf,sizeof(x25obuf)); obufl = 0; tosend = 0; }; switch (padparms[PAD_BREAK_ACTION]) { case 0 : break; /* do nothing */ case 1 : /* send interrupt packet with interrupt user data field = 1 */ intudat = 1; x25intr (intudat); break; case 2 : /* send reset packet with cause and diag = 0 */ cause = diag = 0; x25reset (cause,diag); break; case 5 : /* send interrupt packet with interrupt user data field = 0 */ intudat = 0; x25intr (intudat); setqbit (); /* send indication of break without a parameter field */ ttoc(X29_INDICATION_OF_BREAK); resetqbit (); break; case 8 : active = 0; /* leave data transfer */ conol ("\r\n"); break; case 21: /* send interrupt packet with interrupt user data field = 0 */ intudat = 0; x25intr (intudat); setpad (indbrk+1,2); /* set pad to discard input */ setqbit (); /* send indication of break with parameter field */ ttol (indbrk,sizeof(indbrk)); resetqbit (); break; } } /* X.25 support functions */ X25_CAUSE_DIAG diag; /* Convert a null-terminated string representing an X.121 address to a packed BCD form. */ int pkx121(str,bcd) char *str; CHAR *bcd; { int i, j; u_char c; i = j = 0; while (str[i]) { if (i >= 15 || str [i] < '0' || str [i] > '9') return (-1); c = str [i] - '0'; if (i & 1) bcd [j++] |= c; else bcd [j] = c << 4; i++; } return (i); } /* Reads and prints X.25 diagnostic */ int x25diag () { int i; bzero ((char *)&diag,sizeof(diag)); if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) { perror ("Reading X.25 diagnostic"); return(-1); } if (diag.datalen > 0) { printf ("X.25 Diagnostic :"); for (i = 0; i < (int)diag.datalen; i++) printf(" %02h",diag.data[i])+ printf ("\r\n"); } return(0); } /* X.25 Out-of-Band Signal Handler */ SIGTYP x25oobh(foo) int foo; { int oobtype; u_char oobdata; int t; (VOID) signal(SIGURG,x25oobh); do { if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) { perror ("Getting signal type"); return; } switch (oobtype) { case INT_DATA: if (recv(ttyfd,(char *)&oobdata,1,MSG_OOB) < 0) { perror ("Receiving X.25 interrupt data"); return; } t = oobdata; printf ("\r\nInterrupt received, data = %d\r\n", t); break; case VC_RESET: printf ("\r\nVirtual circuit reset\r\n"); x25diag (); break; case N_RESETS: printf ("\r\nReset timeout\r\n"); break; case N_CLEARS: printf ("\r\nClear timeout\r\n"); break; case MSG_TOO_LONG: printf ("\r\nMessage discarded, too long\r\n"); break; default: if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype); break; } } while (oobtype); } /* Send a X.25 interrupt packet */ int #ifdef CK_ANSIC x25intr(char intr) #else x25intr(intr) char intr; #endif /* CK_ANSIC */ /* x25intr */ { if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1); debug(F100,"X.25 intr","",0); return(0); } /* Reset X.25 virtual circuit */ int #ifdef CK_ANSIC x25reset(char cause, char diagn) #else x25reset(cause, diagn) char cause; char diagn; #endif /* CK_ANSIC */ /* x25reset */ { bzero ((char *)&diag,sizeof(diag)); diag.flags = 0; diag.datalen = 2; diag.data[0] = cause; diag.data[1] = diagn; if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0) return(-1); debug(F100,"X.25 reset","",0); return(0); } /* Clear X.25 virtual circuit */ int x25clear() { int i; debug(F100,"X.25 clear","",0); bzero ((char *)&diag,sizeof(diag)); diag.flags = (1 << DIAG_TYPE); diag.datalen = 2; diag.data[0] = 0; diag.data[1] = 0; ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */ return(ttclos(0)); /* Close socket */ } /* X.25 status */ int x25stat() { if (ttyfd == -1) return (-1); return(0); } /* Set Q_BIT on */ VOID setqbit() { static int qbiton = 1 << Q_BIT; ioctl (ttyfd,X25_SEND_TYPE,&qbiton); } /* Set Q_BIT off */ VOID resetqbit() { static int qbitoff = 0; ioctl (ttyfd,X25_SEND_TYPE,&qbitoff); } /* Read n characters from X.25 circuit into buf */ int x25xin(n,buf) int n; CHAR *buf; { register int x, c; int qpkt; do { x = read(ttyfd,buf,n); if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */ /* If return -1 : invitation to clear; -2 : PAD changes */ if ((c=qbitpkt(buf+1,x-2)) < 0) return(c); qpkt = 1; } else qpkt = 0; } while (qpkt); #ifdef COMMENT /* Disabled by Stephen Riehm 19.12.97 */ /* BUG! * if buf[] is full, then this null lands in nirvana! * I was unable to find any code which needs a trailing null in buf[] */ if (x > 0) buf[x] = '\0'; #endif /* COMMENT */ if (x < 1) x = -1; debug(F101,"x25xin x","",x); return(x); } #ifdef COMMENT /* NO LONGER NEEDED! */ /* X.25 read a line */ int #ifdef PARSENSE #ifdef CK_ANSIC x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start) #else x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start; #endif /* CK_ANSIC */ #else /* not PARSENSE */ #ifdef CK_ANSIC x25inl(CHAR *dest, int max,int timo, CHAR eol) #else x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol; #endif /* __SDTC__ */ #endif /*PARSENSE */ /* x25inl */ { CHAR *pdest; int pktype, goteol, rest, n; int i, flag = 0; extern int ttprty, ttpflg; int ttpmsk; ttpmsk = (ttprty) ? 0177 : 0377; /* Set parity stripping mask */ debug(F101,"x25inl max","",max); debug(F101,"x25inl eol","",eol); pdest = dest; rest = max; goteol = 0; do { n = read(ttyfd,pdest,rest); n--; pktype = *pdest & 0x7f; switch (pktype) { case 1 << Q_BIT: if (qbitpkt(pdest+1,--n) < 0) return(-2); break; default: if (flag == 0) { /* if not in packet, search start */ for (i = 1; (i < n) && !(flag = ((dest[i] & 0x7f) == start)); i++); if (flag == 0) { /* not found, discard junk */ debug(F101,"x25inl skipping","",n); continue; } else { /* found, discard junk before start */ int k; n = n - i + 1; for (k = 1; k <= n; k++, i++) dest[k] = dest[i]; } } for (i = 0; (i < n) && /* search for eol */ !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol)); i++,pdest++); *pdest = '\0'; rest -= n; } } while ((rest > 0) && (!goteol)); if (goteol) { n = max - rest; debug (F111,"x25inl X.25 got",(char *) dest,n); if (timo) ttimoff(); if (ttpflg++ == 0 && ttprty == 0) { if ((ttprty = parchk(dest,start,n)) > 0) { int j; debug(F101,"x25inl senses parity","",ttprty); debug(F110,"x25inl packet before",(char *)dest,0); ttpmsk = 0x7f; for (j = 0; j < n; j++) dest[j] &= 0x7f; /* Strip parity from packet */ debug(F110,"x25inl packet after ",dest,0); } else { debug(F101,"parchk","",ttprty); if (ttprty < 0) { ttprty = 0; n = -1; } } } ttimoff(); return(n); } ttimoff(); return(-1); } #endif /* COMMENT */ #endif /* SUNX25 */ #ifdef IBMX25 /* * IBM X25 support - using the NPI streams interface * written by Stephen Riehm, pc-plus, Munich Germany */ /* riehm: missing functions / TODO list */ /* x25intr() - Send an interrupt packet */ /* return an error message depending on packet type */ char * x25err(n) int n; { static char buf[30]; switch (n) { case NBADADDR: return "invalid address"; case NBADOPT: return "invalid options"; case NACCESS: return "no permission"; case NNOADDR: return "unable to allocate address"; case NOUTSTATE: return "invalid state"; case NBADSEQ: return "invalid sequence number"; case NSYSERR: return "system error"; case NBADDATA: return "invalid data size"; case NBADFLAG: return "invalid flag"; case NNOTSUPPORT: return "unsupported primitive"; case NBOUND: return "address in use"; case NBADQOSPARAM: return "bad QOS parameters"; case NBADQOSTYPE: return "bad QOS type"; case NBADTOKEN: return "bad token value"; case NNOPROTOID: return "protocol id could not be allocated"; case NODDCUD: return "odd length call user data"; default: ckmakmsg(buf,sizeof(buf),"Unknown NPI error ",ckitoa(n),NULL,NULL); return buf; } } /* turn a meaningless primitive number into a meaningful primitive name */ char * x25prim(n) int n; { static char buf[30]; switch(n) { case N_BIND_ACK: return "N_BIND_ACK"; case N_BIND_REQ: return "N_BIND_REQ"; case N_CONN_CON: return "N_CONN_CON"; case N_CONN_IND: return "N_CONN_IND"; case N_CONN_REQ: return "N_CONN_REQ"; case N_CONN_RES: return "N_CONN_RES"; case N_DATACK_IND: return "N_DATAACK_IND"; case N_DATACK_REQ: return "N_DATAACK_REQ"; case N_DATA_IND: return "N_DATA_IND"; case N_DATA_REQ: return "N_DATA_REQ"; case N_DISCON_IND: return "N_DISCON_IND"; case N_DISCON_REQ: return "N_DISCON_REQ"; case N_ERROR_ACK: return "N_ERROR_ACK"; case N_EXDATA_IND: return "N_EXDATA_IND"; case N_EXDATA_REQ: return "N_EXDATA_REQ"; case N_INFO_ACK: return "N_INFO_ACK"; case N_INFO_REQ: return "N_INFO_REQ"; case N_OK_ACK: return "N_OK_ACK"; case N_OPTMGMT_REQ: return "N_OPTMGMT_REQ"; case N_RESET_CON: return "N_RESET_CON"; case N_RESET_IND: return "N_RESET_IND"; case N_RESET_REQ: return "N_RESET_REQ"; case N_RESET_RES: return "N_RESET_RES"; case N_UDERROR_IND: return "N_UDERROR_IND"; case N_UNBIND_REQ: return "N_UNBIND_REQ"; case N_UNITDATA_REQ: return "N_UNITDATA_REQ"; case N_UNITDATA_IND: return "N_UNITDATA_IND"; default: ckmakmsg(buf,sizeof(buf),"UNKNOWN (",ckitoa(n),")",NULL); return buf; } } /***************************************************************************** * Function: x25getmsg() * Description: get a STREAMS message, and check it for errors * * Parameters: * fd - file descriptor to x25 device (opened) * control - control buffer (pre-allocated) * ctl_size - size of control buffer * data - data buffer (pre-allocated) * data_size - size of data buffer * flags - flags for getmsg() * expected - expected Primitive type * * Return Value: * >= 0 OK (size of data returned) * -1 error * */ int x25getmsg( fd, control, ctl_size, data, data_size, get_flags, expected ) int fd; /* X25 device (opened) */ N_npi_ctl_t *control; /* control buffer (pre-allocated) */ int ctl_size; /* size of control buffer */ N_npi_data_t *data; /* data buffer (pre-allocated) */ int data_size; /* size of data buffer */ int *get_flags; /* getmsg() flags */ int expected; /* expected primitive type */ /* x25getmsg */ { int rc = 0; /* return code */ struct strbuf *get_ctl=NULL; /* getmsg control */ struct strbuf *get_data=NULL; /* getmsg data */ int more = 0; /* flag for more data etc */ int file_status = -1; /* file async status */ N_npi_ctl_t * result; /* pointer to simplify switch() */ int packet_type = -1; /* unknown packet thus far */ #ifdef TRACE printf( "TRACE: entering x25getmsg\n" ); #endif /* TRACE */ debug( F110, "x25getmsg waiting for packet ", x25prim( expected ), 0); /* prepare the control structures for getmsg */ if (control) { if ((get_ctl = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL) { perror("kermit x25getmsg(): get_ctl malloc failed\n"); debug( F100, "x25getmsg malloc failed for get_ctl\n", "", 0); return(-1); } /* allow getmsg to return an unexpected packet type (which may be * larger than the expected one) */ get_ctl->maxlen = NPI_MAX_CTL; get_ctl->len = 0; get_ctl->buf = (char *)control; } else { printf( "kermit x25getmsg(): internal error. control buffer MUST be pre-allocated!\n" ); debug(F100,"x25getmsg internal error. no buffer pre-allocated","",0); return( -1 ); } if (data) { if ((get_data = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL) { perror("kermit x25getmsg(): get_data malloc failed\n"); debug( F100, "x25getmsg malloc failed for get_data\n", "", 0); return(-1); } get_data->maxlen = (NPI_MAX_DATA < data_size ) ? NPI_MAX_DATA : data_size; get_data->len = 0; get_data->buf = (char *)data; } /* get an X.25 packet - * it may be any kind of packet, so check for special cases * it may be split into multiple parts - so loop if necessary */ do { #ifdef DEBUG printf( "kermit: x25getmsg(): getting a message\n" ); #endif /* DEBUG */ errno = 0; if ((more = getmsg(fd, get_ctl, get_data, get_flags)) < 0) { #ifdef DEBUG printf( "kermit: x25getmsg(): getmsg returned an error\n" ); perror( "getmsg error was" ); #endif /* DEBUG */ debug(F101, "x25getmsg getmsg returned an error\n", "", errno); if ((errno == EAGAIN) && (get_data && (get_data->len > 0)) ) { /* was in non-blocking mode, nothing to get, but we're * already waiting for the rest of the packet - * switch to blocking mode for the next read. * file_status used to reset file status before returning */ if ((file_status = fcntl(fd, F_GETFL, 0)) < 0 || fcntl(fd, F_SETFL, file_status & ~O_NDELAY) < 0) { perror("x25getmsg(): couldn't change x25 blocking mode"); debug(F101, "x25getmsg fcntl returned an error\n", "", errno); /* netclos(); */ rc = -1; break; } else { /* loop again into a blocking getmsg() */ continue; } } else { /* no data to get in non-blocking mode - return empty handed */ perror( "x25getmsg(): getmsg failed" ); debug(F101,"x25getmsg getmsg returned an error\n", "", errno); rc = -1; break; } } else if (more & MORECTL) { /* panic - the control information was larger than the * maximum control buffer size! */ /* riehm: close connection? */ #ifdef DEBUG printf("x25getmsg(): received partial control packet - panic\n"); #endif /* DEBUG */ debug( F101, "x25getmsg getmsg bad control block\n", "", errno); rc = -1; break; } if (result = (N_npi_ctl_t *)control) { packet_type = result->bind_ack.PRIM_type; if (packet_type != N_OK_ACK) { x25lastmsg = packet_type; } } #ifdef DEBUG /* printf( "kermit: x25getmsg(): getting " ); */ if (get_ctl->len > 0) { x25dump_prim(result); } debug(F110, "x25getmsg got packet ", x25prim( result->bind_ack.PRIM_type ), 0 ); #endif /* DEBUG */ if (get_ctl->len >= (int)sizeof(result->bind_ack.PRIM_type)) { /* not as pretty as a switch(), but switch can't handle * runtime variable values :-( */ if (packet_type == expected ) { /* got what we wanted, special case for DATA_IND * packets though */ /* riehm: check Q-bit ? */ #ifdef DEBUG printf("x25getmsg(): got expected packet\nrc is %d\n", rc); #endif /* DEBUG */ if (packet_type == N_DATA_IND ) { /* data received. May be incomplete, even though * getmsg returned OK */ if (result->data_ind.DATA_xfer_flags & N_MORE_DATA_FLAG) more |= MOREDATA; if (result->data_ind.DATA_xfer_flags & N_RC_FLAG) printf( "x25getmsg(): data packet wants ack\n" ); } } else if( packet_type == N_DISCON_IND) { printf( "X25 diconnected\n" ); /* riehm: need to acknowledge a disconnection? */ x25clear(); /* x25unbind( ttyfd ); */ rc = -1; } else if( packet_type == N_ERROR_ACK) { errno = result->error_ack.UNIX_error; perror( "X25 error received" ); rc = -1; } else { printf("x25getmsg(): failed %s\n", x25err(packet_type)); rc = -1; } } #ifdef COMMENT else { /* Panic - no control data */ printf( "kermit: x25getmsg(): no control data with packet\n" ); rc = -1; } #endif /* COMMENT */ if (get_data && (get_data->len >= 0)) { get_data->buf += get_data->len; get_data->maxlen -= get_data->len; } } while ((rc == 0) && (get_data && (get_data->maxlen > 0)) && (more & MOREDATA) ); /* return the file status to its original value, unless its still * set to -1, or one of the fcntl's failed */ if ((file_status >= 0) && fcntl(fd, F_SETFL, file_status) < 0) rc = -1; /* * Verify that we received an expected primitive * there is apparantly an error case where the primitive is set * correctly, but there is not enough data in the control structure */ if ((packet_type != expected) && (get_ctl->len >= ctl_size) ) { fprintf(stderr, "x25getmsg(): %s NOT received. Primitive received was %s\n", x25prim( expected ), x25prim( packet_type )); debug(F110, "x25getmsg got an unexpected packet ", x25prim(packet_type), 0 ); rc = -1; } if (rc == 0) { if (get_data && ( get_data->len >= 0)) { rc = get_data->len; } } if (get_ctl) { free(get_ctl); get_ctl = NULL; } if (get_data) { free(get_data); get_data = NULL; } #ifdef COMMENT #ifdef DEBUG printf( "kermit x25getmsg(): returning %d\n", rc ); #endif /* DEBUG */ #endif /* COMMENT */ debug(F110, "x25getmsg returning packet ", x25prim( packet_type ), 0); #ifdef TRACE printf( "TRACE: leaving x25getmsg\n" ); #endif /* TRACE */ return(rc); } /***************************************************************************** * Function: x25putmsg() * * Description: * send a message to a X25 STREAM * * Parameters: * fd - file descriptor to x25 device (opened) * control - control buffer (pre-allocated) * data - data buffer (pre-allocated) * data_len - length of data to be transmitted * put_flags - flags for putmsg() * * Return Value: * >= 0 number of bytes transmitted * -1 error */ int x25putmsg(fd, control, data, data_len, put_flags) int fd; /* X25 device (opened) */ N_npi_ctl_t *control; /* control buffer (pre-allocated) */ N_npi_data_t *data; /* data buffer (pre-allocated) */ int data_len; /* length of data (not the size of the buffer) */ int *put_flags; /* putmsg() flags */ /* x25putmsg */ { int rc = 0; /* return code */ ulong type; /* primitive type */ struct strbuf *put_ctl = NULL; /* putmsg control */ struct strbuf *put_data = NULL; /* putmsg data */ #ifdef TRACE printf( "TRACE: entering x25putmsg\n" ); #endif /* TRACE */ #ifdef DEBUG printf( "kermit: x25putmsg(): putting " ); x25dump_prim( control ); printf( "\tdata:\t\t" ); x25dump_data( data, 0, data_len ); debug(F110,"x25putmsg: putting packet ",x25prim(control->PRIM_type),0); #endif /* DEBUG */ if (control) { put_ctl = (struct strbuf *)malloc( sizeof( struct strbuf ) ); if (put_ctl == NULL) { perror("kermit x25putmsg(): put_ctl malloc failed\n"); return(-1); } put_ctl->maxlen = 0; /* unused by putmsg */ put_ctl->len = NPI_MAX_CTL; put_ctl->buf = (char *)control; } if (data && ( data_len > 0)) { put_data = (struct strbuf *)malloc( sizeof( struct strbuf ) ); if( put_data == NULL) { perror("kermit x25putmsg(): put_data malloc failed\n"); return(-1); } put_data->maxlen = 0; /* unused by putmsg */ put_data->len = data_len; put_data->buf = (char *)data; } errno = 0; rc = putmsg (fd, put_ctl, put_data, 0); if (rc < 0) { printf("x25putmsg(): couldn't put %s\n",x25prim(control->PRIM_type)); perror("kermit: x25putmsg(): putmsg failed"); return(-1); } /* riehm: this should perhaps be discounted! */ x25lastmsg = control->PRIM_type; #ifdef COMMENT #ifdef DEBUG printf( "kermit debug: x25putmsg() returning %d\n", data_len ); #endif /* DEBUG */ #endif /* COMMENT */ debug( F101, "x25putmsg block size put ", "", data_len); #ifdef TRACE printf( "TRACE: leaving x25putmsg\n" ); #endif /* TRACE */ return( data_len ); } /***************************************************************************** * Function: x25bind * Description: The bind submitted to NPI provides the information required * by the packet layer for it to listen for suitable incoming * calls. * * WARNING: * * This routine needs to be called in a completely different manner for * the client and server side. When starting a client, the * num_waiting_calls and CUD information should all be set to 0! The * client's CUD must be inserted in the CONN_REQ data block. * When starting a server, the CUD must be set to a CUD pattern, and * the number of waiting calls should be set to a number other than 0. * (num waiting calls is the number of incomming calls which are to be * put on hold while the server is servicing another client.) * * Who invented this crap? * * Parameters: * fd - X25 device (opened) * addr - local address * cud - User Data (null terminated) * cud_len - User Data length * num_waiting_calls - number of outstanding calls allowed on this stream * line - logical port number (1) * flags - 0, DEFAULT_LISTENER or TOKEN_REQUEST * * Return Value: * if binding is successful, 0 is returned for a client, and a token is * returned for a server * * Return code: 0 if successful * -1 if unsuccessful *****************************************************************************/ ulong x25bind(fd, addr, cud, cud_len, num_waiting_calls, line, bind_flags) int fd; /* X25 device (opened) */ char * addr; /* local address */ char * cud; /* Call User Data (null terminated) */ int cud_len; /* User Data length */ int num_waiting_calls; /* Outstanding calls allowed */ int line; /* logical port number */ ulong bind_flags; /* 0, DEFAULT_LISTENER or TOKEN_REQUEST */ /* x25bind */ { ulong rc; /* return code */ int get_flags; /* priority flag passed to getmsg */ int put_flags = 0; /* output flags for putmsg, always 0 */ ulong type; /* primitive type */ N_bind_req_t *bind_req; /* pointer to N_BIND_REQ primitive */ N_bind_ack_t *bind_ack; /* pointer to N_BIND_ACK primitive */ char *addtl_info; /* pointer to info in addition to * the N_BIND_REQ primitive that is * passed in the control structure * to putmsg */ int addr_len = 0; /* length of address string */ ulong bind_req_t_size; /* for debugging only */ #ifdef TRACE printf("TRACE: entering x25bind\n" ); #endif /* TRACE */ #ifdef DEBUG printf("TRACE: x25bind( %d, %s, %s, %d, %d )\n", fd, addr, cud, line, bind_flags ); #endif /* DEBUG */ /* * Allocate and zero out space to hold the control portion of the * message passed to putmsg. This will contain the N_BIND_REQ * primitive and any additional info required for that. * * Note: allocated space is the size of the union typedef * N_npi_ctl_t to allow the use fo the generic x25putmsg routine. */ bind_req = (N_bind_req_t *) malloc(sizeof( N_npi_ctl_t)); if (bind_req == NULL) { perror("kermit: x25bind(): bind_req malloc failed"); debug(F100, "x25bind bind_req malloc failed", "", 0); return(-1); } bzero((char *)bind_req, sizeof(N_npi_ctl_t)); /* Build the Bind Request Primitive */ bind_req->PRIM_type = (ulong) N_BIND_REQ; /* Note that the address length is n+2 and NOT n. Two bytes MUST preceed * the actual address in an N_BIND_REQ. The first byte contains the * line number being used with this address, and the second byte is the * X.121 address prefix, which must be zero. */ addr_len = strlen(addr); bind_req->ADDR_length = (ulong) (addr_len + 2); bind_req->ADDR_offset = (ulong)(sizeof(N_bind_req_t)); bind_req->CONIND_number = (ulong)num_waiting_calls; /* server only */ bind_req->BIND_flags = (ulong) bind_flags; /* 0 in client */ bind_req->PROTOID_length = (ulong) cud_len; /* 0 in client */ if (cud_len == 0) { bind_req->PROTOID_offset = (ulong) 0; } else { /* need to remember the trailing NULL in the address - not * counted in the address length */ bind_req->PROTOID_offset = (ulong) (sizeof(N_bind_req_t) + bind_req->ADDR_length); } /* * Now fill in the additional information required with this primitive * (address and protocol information (Call User Data)) */ addtl_info = (char *) ((void *)bind_req + bind_req->ADDR_offset); /* * The bitwise "&" ensures that the line number is only one byte long */ *addtl_info++ = (char) line & 0xff; *addtl_info++ = (char) 0; /* X.121 format */ bcopy( addr, addtl_info, addr_len ); /* include trailing null */ addtl_info += addr_len; if (cud_len > 0) bcopy( cud, addtl_info, cud_len ); /* * Call putmsg() to put the bind request message on the stream */ if (x25putmsg(fd, (N_npi_ctl_t*)bind_req, (N_npi_data_t *)NULL, 0, &put_flags ) < 0) { printf( "kermit: x25bind(): x25putmsg failed\n" ); return(-1); } /* * Allocate and zero out space for the N_BIND_ACK primitive */ bind_ack = (N_bind_ack_t *) malloc(sizeof(N_npi_ctl_t)); if (bind_ack == NULL){ perror("kermit: x25bind(): bind_ack malloc failed"); return(-1); } bzero(bind_ack, sizeof(N_npi_ctl_t)); /* * Initialize the control structure and flag variable sent to getmsg */ get_flags=0; /* get the ACK for the bind */ #ifdef DEBUG printf( "kermit: x25bind() trying to get a BIND_ACK\n" ); #endif /* DEBUG */ rc = (ulong)x25getmsg( fd, (N_npi_ctl_t*)bind_ack, (int)sizeof( N_bind_ack_t ), (N_npi_data_t*)NULL, 0, &get_flags, N_BIND_ACK ); /* turn quantitive return code into a qualitative one */ if (rc > 0) rc = 0; /* if all went well, get the token from the acknowledgement packet */ if ((bind_flags & TOKEN_REQUEST ) && ( rc >= 0)) { rc = bind_ack->TOKEN_value; } /* free up the memory we allocated earlier */ free(bind_req); free(bind_ack); #ifdef TRACE printf( "TRACE: leaving x25bind\n" ); #endif /* TRACE */ return( rc ); } /***************************************************************************** * Function: x25call * Description: This routine builds and sends an N_CONN_REQ primitive, then * checks for an N_CONN_CON primitive in return. * * Parameters: * fd - file descriptor of stream * caddr - called address (remote address) * * Functions Referenced: * malloc() * bzero() * getmsg() * putmsg() * * Return code: * 0 - if successful * -1 if not successful *****************************************************************************/ int x25call(fd, remote_nua, cud) int fd; /* X25 device (opened) */ char * remote_nua; /* remote address to call */ char * cud; /* call user data */ /* x25call */ { int rc; /* return code */ int flags; /* Connection flags */ int get_flags; /* priority flags for getmsg */ ulong type; /* primitive type */ N_conn_req_t *connreq_ctl; /* pointer to N_CONN_REQ primitive */ N_npi_data_t *connreq_data; /* pointer to N_CONN_REQ data (CUD) */ int connreq_data_len; /* length of filled data buffer */ N_conn_con_t *conncon_ctl; /* pointer to N_CONN_CON primitive */ N_npi_data_t *conncon_data; /* pointer to any data associated with * the N_CONN_CON primitive */ char *addtl_info; /* pointer to additional info needed * for N_CONN_REQ primitive */ int addr_len; /* length of address */ #ifdef TRACE printf( "TRACE: entering x25call\n" ); #endif /* TRACE */ #ifdef DEBUG printf( "x25call( %d, %s )\n", fd, remote_nua ); printf( "connecting to %s on fd %d\n", remote_nua, fd ); #endif /* DEBUG */ /* * Allocate and zero out space for the N_CONN_REQ primitive * use the size of the generic NPI primitive control buffer */ connreq_ctl = (N_conn_req_t *) malloc(sizeof(N_npi_ctl_t)); if (connreq_ctl == NULL){ perror("kermit: x25call(): connreq_ctl malloc failed"); return(-1); } bzero(connreq_ctl,sizeof(N_npi_ctl_t)); /* * Build the Connection Request Primitive */ flags = 0; connreq_ctl->PRIM_type = (ulong) N_CONN_REQ; /* Note that the address length is nchai+1 and not n+2. The line number * is only passed with the address for the bind. The first byte of * the address for the N_CONN primitives contains the X.121 * address prefix, which must be zero. The remaining bytes are the * address itself. */ addr_len = strlen( remote_nua ); connreq_ctl->DEST_length = (ulong) (addr_len + 1); connreq_ctl->DEST_offset = (ulong) sizeof(N_conn_req_t); /* connreq_ctl->CONN_flags = (ulong)EX_DATA_OPT | REC_CONF_OPT; */ connreq_ctl->CONN_flags = (ulong) 0; connreq_ctl->QOS_length = (ulong) 0; /* unsupported in AIX 4.1 */ connreq_ctl->QOS_offset = (ulong) 0; /* unsupported in AIX 4.1 */ addtl_info = (char *) ((void*)connreq_ctl + connreq_ctl->DEST_offset); *addtl_info++ = (char) 0; /* X.121 format */ bcopy( remote_nua, addtl_info, addr_len ); /* * setup the data buffer for the connection request */ connreq_data = (N_npi_data_t *) malloc(sizeof(N_npi_data_t)); if (connreq_data == NULL){ perror("kermit: x25call(): connreq_data malloc failed"); return(-1); } bzero(connreq_data,sizeof(N_npi_data_t)); /* facility selection needs to be put in the front of connreq_data */ connreq_data_len = 0; connreq_data_len += x25facilities( (char *)connreq_data ); if (cud && *cud) { bcopy(cud, (char *)((char *)connreq_data + connreq_data_len), strlen(cud) ); connreq_data_len += strlen( cud ); } /* * Call putmsg() to put the connection request message on the stream */ rc = x25putmsg( fd, (N_npi_ctl_t*)connreq_ctl, connreq_data, connreq_data_len, &flags ); if (rc < 0) { return(-1); } /* * Allocate and zero out space for the N_CONN_CON primitive */ if ((conncon_ctl = (N_conn_con_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) { perror("kermit: x25call(): conncon_ctl malloc failed"); return(-1); } bzero(conncon_ctl, sizeof(N_npi_ctl_t)); /* * Allocate and zero out space for any data associated with N_CONN_CON */ if ( (conncon_data = (N_npi_data_t *) malloc(NPI_MAX_DATA)) == NULL) { perror("kermit: x25call(): conncon_data malloc failed"); return(-1); } bzero(conncon_data, NPI_MAX_DATA); /* Initialize and build the structures for getmsg */ get_flags=0; rc = x25getmsg( fd, (N_npi_ctl_t*)conncon_ctl, (int)sizeof( N_conn_con_t ), conncon_data, NPI_MAX_DATA, &get_flags, N_CONN_CON ); /* turn quantitive return code into a qualitative one */ if (rc > 0) rc = 0; /* Free the space that we no longer need */ if (connreq_ctl) { free(connreq_ctl); connreq_ctl = NULL; } if (conncon_ctl) { free(conncon_ctl); conncon_ctl = NULL; } if (conncon_data) { free(conncon_data); conncon_data = NULL; } #ifdef TRACE printf( "TRACE: leaving x25call\n" ); #endif /* TRACE */ return(rc); } /***************************************************************************** * Function: x25getcall * * Description: This routine checks for an incomming call, verified * that it is a CONNIND (connection indication) message, and then * accepts the call and returns the file descriptor of the new stream * * Parameters: * fd - file descriptor of listening stream * * Return Codes: * callfd - file descriptor of connected incomming call. * - set to -1 if an error occured * *****************************************************************************/ int x25getcall(fd) int fd; { int x25callfd; /* fd of incomming call */ N_conn_ind_t *connind_ctl; /* connind controll buffer */ N_npi_data_t *connind_data; /* connind data buffer */ int get_flags; /* flags for getmsg */ ulong flags; /* connection flags */ int rc; /* return code */ extern x25addr_t remote_nua; /* remote X.25 addr global var */ #ifdef TRACE printf( "TRACE: entering x25getcall\n" ); #endif /* TRACE */ /* allocate space for connection indication buffers */ if ((connind_ctl = (N_conn_ind_t *)malloc(sizeof(N_npi_ctl_t))) == NULL) { perror("kermit: x25getcall(): connind_ctl malloc failed"); return (-1); } bzero(connind_ctl, sizeof(N_npi_ctl_t)); if ((connind_data = (N_npi_data_t *)malloc(NPI_MAX_DATA)) == NULL) { perror("kermit: x25getcall(): connind_data malloc failed"); return (-1); } bzero(connind_data, NPI_MAX_DATA); /* initialise control structures */ get_flags = 0; /* call getmsg to check for a connection indication */ if (x25getmsg(fd, (N_npi_ctl_t*)connind_ctl, (int)sizeof(N_conn_ind_t), connind_data, NPI_MAX_DATA, &get_flags, N_CONN_IND ) < 0) { #ifdef DEBUG printf( "x25getcall(): errno is: %d\n", errno ); #endif /* DEBUG */ perror ("x25getcall(): getmsg failed"); return(-1); } /* a connection indication was received * - pull it to bits and answer the call */ x25seqno = connind_ctl->SEQ_number; flags = connind_ctl->CONN_flags; #ifdef DEBUG printf( "setting remote_nua to a new value due to incomming call\n" ); #endif /* DEBUG */ /* * no guarantee that the address is null terminated, ensure that * after copying that it is (assumption: remote_nua is longer than * the address + 1) */ bzero(remote_nua, sizeof(remote_nua)); /* note: connind_ctl contains a x121 address, which has a null as * the FIRST character - strip it off! */ ckstrncpy(remote_nua, (char*)((char*)connind_ctl + connind_ctl->SRC_offset + 1), connind_ctl->SRC_length - 1 ); #ifdef DEBUG printf( "remote_nua set to new value of %s\n", remote_nua ); #endif /* DEBUG */ /* errors handled by callee */ x25callfd = x25accept(x25seqno, flags); /* free the malloc'd buffers */ if (connind_ctl) { free(connind_ctl); connind_ctl = NULL; } if (connind_data) { free(connind_data); connind_data = NULL; } #ifdef TRACE printf( "TRACE: leaving x25getcall\n" ); #endif /* TRACE */ /* return the file descriptor (or error if < 0) */ return( x25callfd ); } /***************************************************************************** * Function: x25accept * * Description: accept an incomming call * This essentially means opening a new STREAM and sending * an acknowledge back to the caller. * * Parameters: * seqno - sequence number for acknowledgement * flags - flags passed to us by the caller * * Return Codes: * fd - file descriptor of new STREAM * set to -1 if an error occured * *****************************************************************************/ int x25accept(seqno,flags) ulong seqno; /* connection sequence number */ ulong flags; /* connection flags */ /* x25accept */ { int x25callfd; /* fd for incomming call */ int get_flags; /* priority flags for getmsg */ int put_flags = 0; /* flags for putmsg, always 0 */ int addr_len; /* length of local address */ ulong token; /* connection token */ N_conn_res_t *conn_res; /* N_CONN_RES primitive */ N_ok_ack_t *ok_ack; /* N_OK_ACK primitive */ char *addtl_info; /* temp pointer */ int rc; /* temporary return code */ /* global variables from ckcmai.c */ extern int revcall, closgr, cudata; extern char udata[]; extern x25addr_t local_nua; /* local X.25 address */ extern char x25name[]; /* x25 device name (sx25a0) */ extern char x25dev[]; /* x25 device file /dev/x25pkt */ extern int x25port; /* logical port to use */ ulong bind_flags = 0; /* flags for binding the X25 stream */ #ifdef TRACE printf( "TRACE: entering x25accept\n" ); #endif /* TRACE */ /* open a new packet level stream */ if ((x25callfd = open(x25dev, O_RDWR)) < 0) { perror ("kermit: x25accept(): X.25 device open error"); debug(F101,"x25accept() device open error","",errno); return(-1); } /* push the NPI onto the STREAM */ if (ioctl(x25callfd,I_PUSH,"npi") < 0) { perror( "kermit: x25accept(): couldn't push npi on the X25 stream" ); debug(F101,"x25accept can't push npi on the X25 stream","",errno); return (-1); } /* bind kermit server to the local X25 address */ /* taken from /usr/samples/sx25/npi/npiserver.c (AIX 4) */ bind_flags |= TOKEN_REQUEST; token = x25bind(x25callfd,local_nua,(char *)NULL,0,0,x25port,bind_flags); if (token < 0) { printf( "kermit: x25accept(): couldn't bind to local X25 address\n" ); netclos(); return(-1); } /* allocate connection response primitive */ if ((conn_res = (N_conn_res_t *)malloc( NPI_MAX_CTL )) == NULL) { perror("kermit: x25accept(): conn_res malloc failed"); return (-1); } bzero((char *)conn_res, NPI_MAX_CTL); /* setup connection response primitive */ addr_len = strlen( local_nua ); conn_res->PRIM_type = (ulong)N_CONN_RES; conn_res->TOKEN_value = token; /* note address length is n+1 to accomodate the X.121 address prefix */ conn_res->RES_length = (ulong)(addr_len + 1); conn_res->RES_offset = (ulong)sizeof( N_conn_res_t ); conn_res->SEQ_number = seqno; conn_res->CONN_flags = 0; conn_res->QOS_length = 0; /* unsupported - must be 0 (!?) */ conn_res->QOS_offset = 0; addtl_info = (char *)((char *)conn_res + conn_res->RES_offset); *addtl_info++ = (char)0; /* X.121 address prefix */ bcopy( local_nua, addtl_info, addr_len ); /* * send off the connect response */ if (x25putmsg(x25callfd, (N_npi_ctl_t*)conn_res, (N_npi_data_t *)NULL, 0, &put_flags ) < 0 ) { perror("kermit: x25accept(): putmsg connect response failed"); return(-1); } /* * Allocate and zero out space for the OK_ACK primitive */ if ((ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) { perror("kermit: x25call(): ok_ack malloc failed"); return(-1); } bzero(ok_ack, sizeof(N_npi_ctl_t)); /* Initialize and build the structures for getmsg */ get_flags=0; rc = (int)x25getmsg(x25callfd, (N_npi_ctl_t*)ok_ack, (int)sizeof(N_ok_ack_t), (N_npi_data_t*)NULL, 0, &get_flags, N_OK_ACK ); if (rc == 0) { /* sequence number is only for disconnecting when not connected !? */ x25seqno = 0; } /* free up malloc'ed buffer space */ if (conn_res) { free(conn_res); conn_res = NULL; } if (ok_ack) { free(ok_ack); ok_ack = NULL; } #ifdef TRACE printf( "TRACE: leaving x25accept\n" ); #endif /* TRACE */ return( ( rc >= 0 ) ? x25callfd : -1 ); } /***************************************************************************** * Function: x25unbind * * Description: This subroutine builds and sends an unbind request and gets * the acknowledgement for it. * * Parameters: * fd - File descriptor of the stream * * Functions Referenced: * getmsg() * putmsg() * malloc() * bzero() * * Return code: * 0 - if successful * -1 - if not successful *****************************************************************************/ int x25unbind(fd) int fd; { /* X25 device (opened) */ int rc; /* return code */ int flags; /* bind flags */ int get_flags; /* priority flag for getmsg */ ulong type; /* primitive type */ N_unbind_req_t *unbind_req; /* pointer to N_UNBIND_REQ */ N_ok_ack_t *ok_ack; /* pointer to N_OK_ACK */ #ifdef TRACE printf( "TRACE: entering x25unbind\n" ); #endif /* TRACE */ #ifdef DEBUG /* printf( "x25unbind( %d )\n", fd ); */ #endif /* DEBUG */ debug(F101,"x25unbind closing x25 connection #","",fd); /* Allocate and zero out space to hold the N_UNBIND_REQ primitive */ unbind_req = (N_unbind_req_t *) malloc(sizeof(N_npi_ctl_t)); if (unbind_req == NULL) { perror("kermit: x25unbind(): unbind_req malloc failed"); return(-1); } bzero(unbind_req, sizeof(N_npi_ctl_t)); /* * Build the Unbind Request Primitive */ flags = 0; unbind_req->PRIM_type = (ulong) N_UNBIND_REQ; /* * Call putmsg() to put the bind request message on the stream */ if (x25putmsg(fd, (N_npi_ctl_t*)unbind_req, (N_npi_data_t *)NULL, 0, &flags ) < 0) { perror ("kermit: x25unbind(): putmsg failed"); return(-1); } /* Allocate and Zero out space for the N_OK_ACK primitive */ ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t)); if (ok_ack == NULL) { perror("kermit x25unbind(): ok_ack malloc failed\n"); return(-1); } bzero(ok_ack, sizeof(N_npi_ctl_t)); /* Initialize and build the control structure for getmsg */ get_flags=0; /* Call getmsg() to check for an acknowledgement */ rc = x25getmsg(fd, (N_npi_ctl_t*)ok_ack, (int)sizeof(N_ok_ack_t), (N_npi_data_t*)NULL, 0, &get_flags, N_OK_ACK ); if (rc < 0) { perror ("kermit: x25unbind: getmsg failed"); return(-1); } /* Free up the space that we no longer need */ if (unbind_req) { free(unbind_req); unbind_req = NULL; } if (ok_ack) { free(ok_ack); ok_ack = NULL; } #ifdef TRACE printf( "TRACE: leaving x25unbind\n" ); #endif /* TRACE */ return(0); } /***************************************************************************** * Function: x25xin * * Description: * Read n characters from X.25 circuit into buf (AIX only) * * Parameters: * data_buf_len maximum size of data buffer * data_buf pointer to pre-allocated buffer space * * Return Value: * the number of characters actually read */ int x25xin(data_buf_len,data_buf) int data_buf_len; CHAR *data_buf; { struct strbuf getmsg_ctl; /* streams control structure */ struct strbuf getmsg_data; /* streams data structure */ int rc = 0; /* return code */ int getmsg_flags; /* packet priority flags */ char * ctl_buf; /* npi control buffer */ N_npi_ctl_t * result; /* pointer to simplify switch() */ #ifdef TRACE printf( "TRACE: entering x25xin\n" ); #endif /* TRACE */ /* ensure that no maximum's are overridden */ data_buf_len = (NPI_MAX_DATA < data_buf_len) ? NPI_MAX_DATA : data_buf_len; /* allocate space for packet control info */ if ((ctl_buf = (char *)malloc(NPI_MAX_CTL)) == NULL) { perror( "kermit: x25xin(): ctl_buf malloc" ); return(-1); } #ifdef COMMENT /* riehm: need zeroed buffer for getmsg? */ bzero( ctl_buf, NPI_MAX_CTL ); /* clear data buffer */ bzero( data_buf, data_buf_len ); #endif /* COMMENT */ getmsg_flags = 0; /* get the first packet available */ rc = x25getmsg(ttyfd, ctl_buf, NPI_MAX_CTL, data_buf, data_buf_len, &getmsg_flags, N_DATA_IND ); #ifdef COMMENT #ifdef DEBUG if (rc >= 0) { printf( "kermit: x25xin(): got " ); x25dump_data( data_buf, 0, rc ); } else { printf( "x25xin(): attempt to get data resulted in an error\n" ); } #endif /* DEBUG */ #endif /* COMMENT */ /* free buffers */ if (ctl_buf) { free(ctl_buf); ctl_buf = NULL; } #ifdef TRACE printf( "TRACE: leaving x25xi\n" ); #endif /* TRACE */ return(rc); } /***************************************************************************** * Function: x25write * * Description: * write a block of characters to the X25 STREAM (AIX) * * Parameters: * fd file descriptor to write to * databuf buffer containing data to write * databufsize size of the buffer to write * * Return Value: * size the number of bytes actually transmitted */ int x25write(fd, databuf, databufsize) int fd; /* X25 STREAMS file descriptor (ttyfd) */ char *databuf; /* buffer to write */ int databufsize; /* buffer size */ /* x25write */ { N_data_req_t *data_req_ctl; int rc; /* return code (size transmitted) */ int write_flags = 0; /* always 0 !? */ #ifdef TRACE printf( "TRACE: entering x25write\n" ); #endif /* TRACE */ if ((data_req_ctl = (N_data_req_t *)malloc(NPI_MAX_CTL) ) == NULL) { perror( "kermit: x25write(): data_req_ctl malloc" ); return(-1); } data_req_ctl->PRIM_type = N_DATA_REQ; data_req_ctl->DATA_xfer_flags = 0; /* riehm: possible extension * possibly need to think about splitting up the data buffer * into multiple parts if databufsize > NPI_MAX_DATA */ #ifdef COMMENT #ifdef DEBUG printf( "kermit: x25write(): writing data to x25 stream\n" ); printf( "\tdata:\t" ); x25dump_data(databuf, 0, databufsize); #endif /* DEBUG */ #endif /* COMMENT */ rc = x25putmsg(fd, (N_npi_ctl_t*)data_req_ctl, (N_npi_data_t*)databuf, databufsize, &write_flags ); if (data_req) { free(data_req_ctl); data_req = NULL; } #ifdef TRACE printf( "TRACE: leaving x25write\n" ); #endif /* TRACE */ return(rc); } /***************************************************************************** * Function: x25local_nua * * Description: * This routine is only interesting for IBM computers. In order * to set up a connection (see x25bind()) you need to know the * local NUA (x25 address). Unfortunately, you need all this code * to find that out, I just hope this works for everyone else! * * Parameters: * a pre-allocated character buffer, long enough to hold an X.25 address * and the tailing null. * * Return Value: * the length of the address string. * 0 = error */ int x25local_nua(char *buf) { struct CuAt *response; /* structure to fill with info from ODM */ CLASS_SYMBOL retClass; /* ODM class */ char query[64]; /* odm database query */ int rc = 0; /* return value (length of local NUA) */ extern char x25name[]; /* x25 device name (sx25a0) */ #ifdef TRACE printf( "TRACE: entering x25local_nua\n" ); #endif /* TRACE */ /* set up query string */ if (x25name[0] == '\0') { #ifdef DEBUG printf( "kermit: x25local_nua(): No x25 device set, trying sx25a0\n" ); #endif /* DEBUG */ strcpy( x25name, "sx25a0" ); } ckmakmsg(query, sizeof(query), "name like ",x25name, " and attribute like local_nua"); /* initialise ODM database */ odmerrno = 0; if (odm_initialize() == -1) { printf( "x25local_nua(): can't initialize ODM database"); switch (odmerrno) { case ODMI_INVALID_PATH: printf( "invalid path\n" ); break; case ODMI_MALLOC_ERR: printf( "malloc failed\n" ); break; default: printf( "unknown error %d\nPlease call IBM\n", odmerrno ); } return(rc); } /* open the CuAt class */ retClass = odm_open_class(CuAt_CLASS); if (((int)retClass) == -1) { printf( "kermit: x25local_nua(): can't open CuAt class in odm. " ); switch (odmerrno) { case ODMI_CLASS_DNE: printf( "CuAt class doesn't exist\n" ); break; case ODMI_CLASS_PERMS: printf( "permission to CuAt class file denied\n" ); break; case ODMI_MAGICNO_ERR: printf( "CuAt is an invalid ODM object class\n" ); break; case ODMI_OPEN_ERR: printf( "cannot open CuAt class - and don't know why!\n" ); break; case ODMI_INVALID_PATH: printf( "invalid path\n" ); break; case ODMI_TOOMANYCLASSES: printf( "too many object classes have been opened\n" ); break; default: printf( "unknown error %d\nPlease call IBM\n", odmerrno ); } return(rc); } #ifdef DEBUG printf("retClass= %d\n", retClass); #endif /* DEBUG */ response = (struct CuAt *)odm_get_first( retClass, query, NULL ); if (((int)response) == -1) { printf( "kermit: x25local_nua(): odm query failed " ); switch (odmerrno) { case ODMI_BAD_CRIT: /* Programming error */ printf( "bad search criteria\n" ); break; case ODMI_CLASS_DNE: printf( "CuAt class doesn't exist\n" ); break; case ODMI_CLASS_PERMS: printf( "permission to CuAt class file denied\n" ); break; case ODMI_INTERNAL_ERR: printf("odm internal error\nPlease contact your administrator\n" ); break; case ODMI_INVALID_CLXN: printf("CuAt is invalid or inconsistent odm class collection\n"); break; case ODMI_INVALID_PATH: printf( "invalid path\n" ); break; case ODMI_MAGICNO_ERR: printf( "CuAt is an invalid ODM object class\n" ); break; case ODMI_MALLOC_ERR: printf( "malloc failed\n" ); break; case ODMI_OPEN_ERR: printf( "cannot open CuAt class - and don't know why!\n" ); break; case ODMI_TOOMANYCLASSES: printf( "too many object classes have been opened\n" ); break; default: printf( "unknown error %d\nPlease call IBM\n", odmerrno ); } return(rc); } /* check for a meaningfull response */ if (response != NULL) { if (response->value != NULL) { strcpy(buf, response->value); rc = strlen( buf ); #ifdef DEBUG /* printf( "attribute name is: %s\n", (char *)response->attribute ); printf( "I think my address is %s\n", (char*)response->value ); */ #endif /* DEBUG */ } else { printf( "kermit: x25local_nua(): couldn't find the local NUA\n" ); } } else { switch (odmerrno) { case ODMI_BAD_CRIT: printf( "Error: ODMI_BAD_CRIT - bad criteria\n" ); break; case ODMI_CLASS_DNE: printf( "Error: ODMI_CLASS_DNE - class doesn't exist\n" ); break; case ODMI_CLASS_PERMS: printf( "Error: ODMI_CLASS_PERMS - class permissions\n" ); break; case ODMI_INTERNAL_ERR: printf( "Error: ODMI_INTERNAL_ERR - panic\n" ); break; case ODMI_INVALID_CLXN: printf( "Error: ODMI_INVALID_CLXN - invalid collection\n" ); break; case ODMI_INVALID_PATH: printf( "Error: ODMI_INVALID_PATH - invalid path - what path?\n" ); break; case ODMI_MAGICNO_ERR: printf( "Error: ODMI_MAGICNO_ERR - invalid object magic\n" ); break; case ODMI_MALLOC_ERR: printf( "Error: ODMI_MALLOC_ERR - malloc failed\n" ); break; case ODMI_OPEN_ERR: printf( "Error: ODMI_OPEN_ERR - cannot open class\n" ); break; case ODMI_TOOMANYCLASSES: printf( "Error: ODMI_TOOMANYCLASSES - too many classes\n" ); break; default: printf( "Unknown error!\n" ); } return(rc); } /* close the database again */ odm_close_class( retClass ); /* forget about ODM all together */ odm_terminate(); #ifdef TRACE printf( "TRACE: leaving x25local_nua\n" ); #endif /* TRACE */ debug(F110, "x25local_nua local address is ", buf, 0); return(rc); } /***************************************************************************** * Function: x25facilities * * Description: * build up the facilities data packet for a connection request * * Parameters: * a pre-allocated char buffer, normally NPI_MAX_DATA big. * * Return Value: * the number of characters inserted into the buffer */ int x25facilities(buffer) char *buffer; { extern int revcall; extern int closgr; char *p; /* temp pointer */ char *start; /* temp pointer */ #ifdef TRACE printf( "TRACE: entering x25facilities\n" ); #endif /* TRACE */ p = buffer + 1; start = p; #ifdef DEBUG printf( "kermit: x25facilities(): getting X25 facilities\n" ); #endif /* DEBUG */ if (revcall != 0) { #ifdef DEBUG printf("reverse charge: %d\n", revcall ); #endif /* DEBUG */ *++p = 0x01; *++p = revcall; } if (closgr > 0) { #ifdef DEBUG printf("closed user group: %d\n", closgr ); #endif /* DEBUG */ *++p = 0x03; *++p = closgr; } #ifdef DEBUG if (p == start) { printf( "no facilities\n" ); } #endif /* DEBUG */ /* set the size of the facilities buffer */ *buffer = (char)( p - start ) & 0xff; #ifdef DEBUG printf( "kermit: x25facilities(): returning %d\n", (int)(p - buffer) ); #endif /* DEBUG */ #ifdef TRACE printf( "TRACE: leaving x25facilities\n" ); #endif /* TRACE */ /* return the size of the facilities with size byte */ /* 1 == no facilities, 0 byte returned as facilities size */ return( (int)(p - buffer) ); } /* * reset the connection */ int x25reset(cause, diagn) char cause; char diagn; { /* not implemented */ #ifdef TRACE printf( "TRACE: entering x25reset\n" ); #endif /* TRACE */ #ifdef TRACE printf( "TRACE: leaving x25reset\n" ); #endif /* TRACE */ return(0); } /* * clear the x25 connection - ie: hang up */ int x25clear() { int get_flags = 0; /* priority flag for getmsg */ int put_flags = 0; /* send flags, always 0 */ ulong type; /* primitive type */ N_discon_req_t *discon_req; /* pointer to N_DISCON_REQ */ N_discon_ind_t *discon_ind; /* pointer to N_DISCON_IND */ N_npi_data_t *discon_data; /* pointer to N_DISCON_IND data */ int rc = 0; /* return code */ #ifdef TRACE printf( "TRACE: entering x25clear\n" ); #endif /* TRACE */ #ifdef DEBUG /* printf( "x25clear(): checking last msg: %s\n", x25prim(x25lastmsg)); */ #endif /* DEBUG */ /* * The following checks are used to ensure that we don't disconnect * or unbind twice - this seems to throw the NPI interface right out of * kilter. */ switch(x25lastmsg) { case N_BIND_ACK: case N_CONN_CON: case N_CONN_REQ: case N_DATA_REQ: case N_DATA_IND: { #ifdef DEBUG /* printf("x25clear(): actively disconnecting\n"); */ #endif /* DEBUG */ discon_req = (N_discon_req_t *)malloc(NPI_MAX_CTL); if (discon_req == NULL) { perror("kermit x25clear(): discon_req malloc failed\n"); /* fallthrough, try to unbind the NPI anyway */ } else { discon_req->PRIM_type = N_DISCON_REQ; discon_req->DISCON_reason = 0; /* not used by AIX */ discon_req->RES_length = 0; discon_req->RES_offset = (ulong)(sizeof(N_discon_req_t)); discon_req->SEQ_number = x25seqno; /* global */ if (x25putmsg(ttyfd, (N_npi_ctl_t*)discon_req, (N_npi_data_t*)NULL, 0, &put_flags ) < 0) { perror("x25putmsg failed in x25clear()"); } discon_ind = (N_discon_ind_t *)malloc(NPI_MAX_CTL); discon_data = (N_npi_data_t *)malloc(NPI_MAX_DATA); if((discon_ind == NULL) || (discon_data == NULL)) { perror("x25clear(): discon_ind malloc failed\n"); /* fallthrough, try to unbind the NPI anyway */ } else { if(x25getmsg(ttyfd, (N_npi_ctl_t*)discon_ind, NPI_MAX_CTL, (N_npi_data_t*)discon_data, NPI_MAX_DATA, &get_flags, N_OK_ACK ) < 0 ) { perror("x25getmsg failed in x25clear()"); /* fallthrough, try to unbind the NPI anyway */ } } } break; } } if (x25lastmsg != N_UNBIND_REQ) { rc = x25unbind(ttyfd); } #ifdef TRACE printf( "TRACE: leaving x25clear\n" ); #endif /* TRACE */ return(rc); } #ifdef DEBUG /* * only for debugging * * turn the internal representation of a datablock into something * half-way readable. Because the length is known, we can print * the string including null's etc (important, because the first(!) * byte of an X121 address is a null! (X121 addr == 0 + X25 addr) */ x25dump_data(char *addr, ulong offset, ulong length) { char *ptr = addr + offset; ulong i = length; /* allocate enough memory for all unprintable chars */ char *buf = (char *)malloc( length * 4 ); char *bptr = buf; /* pointer to current place in the print buffer */ while (i > 0) { if (isprint(*ptr)) { *bptr++ = *ptr; } else { *bptr++ = '['; strcpy(bptr,ckctox(*ptr,1)); bptr += 2; *bptr++ = ']'; } ptr++; i--; } if (length > 0) { *bptr = '\0'; printf( "%s", buf ); } printf( " (%d+%d)\n", offset, length ); if (buf) { free(buf); buf = NULL; } return; } /* * only for debugging * print as much useful information about a packet as possible */ x25dump_prim(primitive) N_npi_ctl_t *primitive; { printf("Primitive"); switch (primitive->PRIM_type) { case N_BIND_ACK: printf( "\tN_BIND_ACK\n\taddress:\t" ); x25dump_data( (char *)primitive, primitive->bind_ack.ADDR_offset, primitive->bind_ack.ADDR_length ); printf( "\tproto id:\t" ); x25dump_data( (char *)primitive, primitive->bind_ack.PROTOID_offset, primitive->bind_ack.PROTOID_length ); printf( "\tconnind:\t%d\n\ttoken:\t\t%d\n", primitive->bind_ack.CONIND_number, primitive->bind_ack.TOKEN_value ); break; case N_BIND_REQ: printf( "\tN_BIND_REQ\n\taddress:\t" ); x25dump_data( (char *)primitive, primitive->bind_req.ADDR_offset, primitive->bind_req.ADDR_length ); printf( "\tproto id:\t" ); x25dump_data( (char *)primitive, primitive->bind_req.PROTOID_offset, primitive->bind_req.PROTOID_length ); printf( "\tconnind:\t%d\n\tflags:\t\t%d\n", primitive->bind_req.CONIND_number, primitive->bind_req.BIND_flags ); break; case N_CONN_CON: printf( "\tN_CONN_CON\n" ); printf( "\tRES\t\t" ); x25dump_data( (char *)primitive, primitive->conn_con.RES_offset, primitive->conn_con.RES_length ); printf( "\tflags:\t%d\n", primitive->conn_con.CONN_flags ); break; case N_CONN_IND: printf( "\tN_CONN_IND\n" ); printf( "\tsource:\t\t" ); x25dump_data( (char *)primitive, primitive->conn_ind.SRC_offset, primitive->conn_ind.SRC_length ); printf( "\tdestination:\t" ); x25dump_data( (char *)primitive, primitive->conn_ind.DEST_offset, primitive->conn_ind.DEST_length ); printf( "\tSEQ_number:\t%d\n", primitive->conn_ind.SEQ_number ); printf( "\tflags:\t%d\n", primitive->conn_ind.CONN_flags ); break; case N_CONN_REQ: printf( "\tN_CONN_REQ\n\tdestination:\t" ); x25dump_data( (char *)primitive, primitive->conn_req.DEST_offset, primitive->conn_req.DEST_length ); printf( "\tflags:\t%d\n", primitive->conn_req.CONN_flags ); break; case N_CONN_RES: printf( "\tN_CONN_RES\n" ); printf( "\tTOKEN_value\t%d\n", primitive->conn_res.TOKEN_value ); printf( "\tSEQ_number\t%d\n", primitive->conn_res.SEQ_number ); printf( "\tCONN_flags\t%d\n", primitive->conn_res.CONN_flags ); printf( "\tRES\t\t" ); x25dump_data( (char *)primitive, primitive->conn_res.RES_offset, primitive->conn_res.RES_length ); break; case N_DATACK_IND: printf( "\tN_DATACK_IND\n" ); break; case N_DATACK_REQ: printf( "\tN_DATACK_REQ\n" ); printf( "\tflags:\t%d\n", primitive->data_req.DATA_xfer_flags ); break; case N_DATA_IND: printf( "\tN_DATA_IND\n" ); printf( "\tflags:\t%d\n", primitive->data_ind.DATA_xfer_flags ); break; case N_DATA_REQ: printf( "\tN_DATA_REQ\n" ); break; case N_DISCON_IND: printf( "\tN_DISCON_IND\n" ); printf( "\torigin:\t%d\n", primitive->discon_ind.DISCON_orig ); printf( "\treason:\t\t%d\n", primitive->discon_ind.DISCON_reason ); printf( "\tseq no:\t\t%d\n", primitive->discon_ind.SEQ_number ); printf( "\tRES:\t" ); x25dump_data( (char *)primitive, primitive->discon_ind.RES_offset, primitive->discon_ind.RES_length ); break; case N_DISCON_REQ: printf( "\tN_DISCON_REQ\n" ); printf( "\tDISCON_reason:\t%d\n", primitive->discon_req.DISCON_reason ); printf( "\tRES:\t" ); x25dump_data( (char *)primitive, primitive->discon_req.RES_offset, primitive->discon_req.RES_length ); printf( "\tSEQ_number:\t%d\n", primitive->discon_req.SEQ_number ); break; case N_ERROR_ACK: printf( "\tN_ERROR_ACK\n" ); printf( "\tCaused by:\t%s\n", x25prim( primitive->error_ack.ERROR_prim ) ); printf( "\tNPI error:\t%s\n", x25err( primitive->error_ack.NPI_error )); errno = primitive->error_ack.UNIX_error; perror( "\t" ); break; case N_EXDATA_IND: printf( "\tN_EXDATA_ACK\n" ); break; case N_EXDATA_REQ: printf( "\tN_EXDATA_REQ\n" ); break; case N_INFO_ACK: printf( "\tN_INFO_ACK\n" ); printf( "\tNSDU size:\t%d\n", primitive->info_ack.NSDU_size ); printf( "\tENSDU size:\t%d\n", primitive->info_ack.ENSDU_size ); printf( "\tCDATA size:\t%d\n", primitive->info_ack.CDATA_size ); printf( "\tDDATA size:\t%d\n", primitive->info_ack.DDATA_size ); printf( "\tADDR size:\t%d\n", primitive->info_ack.ADDR_size ); printf( "\tNIDU size:\t%d\n", primitive->info_ack.NIDU_size ); break; case N_INFO_REQ: printf( "\tN_INFO_REQ\n" ); break; case N_OK_ACK: printf( "\tN_OK_ACK\n" ); break; case N_OPTMGMT_REQ: printf( "\tN_OPTMGMT_REQ\n" ); break; case N_RESET_CON: printf( "\tN_RESET_CON\n" ); break; case N_RESET_IND: printf( "\tN_RESET_IND\n" ); printf( "\treason:\t\t%d\n", primitive->reset_ind.RESET_reason ); printf( "\torigin:\t\t%d\n", primitive->reset_ind.RESET_orig ); break; case N_RESET_REQ: printf( "\tN_RESET_REQ\n" ); printf( "\treason:\t\t%d\n", primitive->reset_req.RESET_reason ); break; case N_RESET_RES: printf( "\tN_RESET_RES\n" ); break; case N_UDERROR_IND: printf( "\tN_UDERROR_IND\n" ); break; case N_UNBIND_REQ: printf( "\tN_UNBIND_REQ\n" ); break; case N_UNITDATA_REQ: printf( "\tN_UNITDATA_REQ\n" ); break; case N_UNITDATA_IND: printf( "\tN_UNITDATA_IND\n" ); break; default: (void) printf( "Unknown NPI error %d", primitive->PRIM_type ); return 0; } } #endif /* DEBUG */ /* it looks like signal handling is not needed with streams! */ /* x25oobh() - handle SIGURG signals - take from isode ? */ #endif /* IBMX25 */ #ifndef NOHTTP /* Which time.h files to include... See ckcdeb.h for defaults. Note that 0, 1, 2, or all 3 of these can be included according to the symbol definitions. */ #ifndef NOTIMEH #ifdef TIMEH #include #endif /* TIMEH */ #endif /* NOTIMEH */ #ifndef NOSYSTIMEH #ifdef SYSTIMEH #include #endif /* SYSTIMEH */ #endif /* NOSYSTIMEH */ #ifndef NOSYSTIMEBH #ifdef SYSTIMEBH #include #endif /* SYSTIMEBH */ #endif /* NOSYSTIMEBH */ #ifndef TIMEH #ifndef SYSTIMEH #ifndef SYSTIMEBH #ifdef Plan9 #include #else #ifdef AIX41 #include #else #ifdef SUNOS4 #include #else #ifdef SYSTIMEH #include #else #ifdef POSIX #include #else #ifdef CLIX #include #else #ifdef OS2 #include #else #include /* #include */ #endif /* OS2 */ #endif /* CLIX */ #endif /* POSIX */ #endif /* SYSTIMEH */ #endif /* SUNOS4 */ #endif /* AIX41 */ #endif /* Plan9 */ #endif #endif #endif #ifdef OS2 #include #ifdef NT #define utimbuf _utimbuf #endif /* NT */ #define utime _utime #else #ifdef SYSUTIMEH /* if requested, */ #include /* for extra fields required by */ #else /* 88Open spec. */ #ifdef UTIMEH /* or if requested */ #include /* (SVR4, POSIX) */ #define SYSUTIMEH /* Use this for both cases. */ #endif /* UTIMEH */ #endif /* SYSUTIMEH */ #endif /* OS2 */ #ifdef VMS /* SMS 2007/02/15 */ #include "ckvrtl.h" #endif /* def VMS */ #ifndef HTTP_VERSION #define HTTP_VERSION "HTTP/1.1" #endif /* HTTP_VERSION */ #ifdef CMDATE2TM time_t #ifdef CK_ANSIC http_date(char * date) #else http_date(date) char * date; #endif /* CK_ANSIC */ /* http_date */ { /* HTTP dates are of the form: "Sun, 06 Oct 1997 20:11:47 GMT" */ /* There are two older formats which we are required to parse * that we currently do not: * * RFC 850: "Sunday, 06-Oct-97 20:11:47 GMT" * asctime(): "Sun Nov 6 20:11:47 1997" * * However, it is required that all dates be sent in the form we * do accept. The other two formats are for compatibility with * really old servers. */ extern char cmdatebuf[18]; struct tm t_tm; time_t t; char ldate[32]; int j; j = ckindex(",",date,0,0,0); ckstrncpy(ldate,&date[j+1],25); { /* cmcvtate() date changed to return a string pointer. fdc, 12 Aug 2001. */ char * dp; dp = (char *)cmcvtdate(ldate,0); /* Convert to normal form */ if (!dp) return(0); t_tm = *cmdate2tm(dp,1); } /* From Lucas Hart, 5 Dec 2001: "On the systems to which I have access (SunOS 4.1.1, Solaris 8, and Tru64), setting tm_isdst to -1 maintains the correct timezone offsets, i.e., writes the specified (GMT) time if the buffer size is 21, or the contemporaneous localtime if the buffer size is 25. Perhaps tm_isdst should be set in cmdate2tm(), rather than only in http_date." */ #ifndef NOTM_ISDST /* For platforms where */ t_tm.tm_isdst = -1; /* tm_isdst doesn't exist. */ #endif /* NOTM_ISDST */ t = mktime(&t_tm); /* NOT PORTABLE */ #ifdef XX_TIMEZONE t -= _timezone; #endif /* XX_TIMEZONE */ return(t); } #endif /* CMDATE2TM */ char * http_now() { static char nowstr[32]; #ifdef CMDATE2TM struct tm *gmt; time_t ltime; /* NOT PORTABLE */ time(<ime); gmt = gmtime(<ime); /* PROBABLY NOT PORTABLE */ strftime(nowstr,32,"%a, %d %b %Y %H:%M:%S GMT",gmt); /* NOT PORTABLE */ /* not only is it not portable but it's locale-dependent */ #else /* This is hopeless. First of all, it seems that HTTP wants Day and Month NAMES? In English? Whose idea was that? Even worse, the date/time must be expressed in Zulu (UTC (GMT)), and converting from local time to GMT is a nightmare. Every platform does it differently, if at all -- even if we restrict ourselves to UNIX. For example (quoting from recent C-Kermit edit history), "Fixed a longstanding bug in the BSDI version, in which incoming file dates were set in GMT rather than local time. It seems in 4.4BSD, localtime() does not return the local time, but rather Zero Meridian (Zulu) time (GMT), and must be adjusted by the tm_gmtoff value." Swell. For greater appreciation of the scope of the problem, just take a look at the time-related #ifdefs in ckutio.c. The only right way to do this is to add our own portable API for converting between local time and GMT/UTC/Zulu that shields us not only from UNIXisms like time_t and struct tm, but also the unbelievable amount of differences in time-related APIs -- e.g. is "timezone" an external variable or a function; which header file(s) do we include, etc etc etc. It's a major project. */ int x; x = cmcvtdate("",1); Evidently this code is not used -- if it is, it must be fixed to use new (aug 2001) cmcvtdate() calling conventions. if (x < 0) return(""); /* yyyymmdd hh:mm:ss */ /* 01234567890123456 */ nowstr[0] = 'X'; /* 1st letter of day */ nowstr[1] = 'x'; /* 2nd letter of day */ nowstr[2] = 'x'; /* 3rd letter of day */ nowstr[3] = ','; nowstr[4] = ' '; nowstr[5] = cmdate[6]; nowstr[6] = cmdate[7]; nowstr[7] = ' '; nowstr[8] = ' '; /* first letter of month */ nowstr[9] = ' '; /* second letter of month */ nowstr[10] = ' '; /* third letter of month */ nowstr[11] = ' '; nowstr[12] = cmdate[0]; nowstr[13] = cmdate[1]; nowstr[14] = cmdate[2]; nowstr[15] = cmdate[3]; nowstr[16] = ' '; nowstr[17] = cmdate[9]; nowstr[18] = cmdate[10]; nowstr[19] = cmdate[11]; nowstr[20] = cmdate[12]; nowstr[21] = cmdate[13]; nowstr[22] = cmdate[14]; nowstr[23] = cmdate[15]; nowstr[24] = cmdate[16]; nowstr[25] = ' '; nowstr[26] = 'G'; nowstr[27] = 'M'; nowstr[28] = 'T'; nowstr[29] = '\0'; #endif /* CMDATE2TM */ return(nowstr); } #ifndef OS2 #ifndef CK_AUTHENTICATION /* from ckuusr.h, which this module normally doesn't include */ _PROTOTYP( int dclarray, (char, int) ); #endif /* CK_AUTHENTICATION */ #endif /* OS2 */ /* Assign http response pairs to given array. For best results, response pairs should contain no spaces. Call with: resp = pointer to response list. n = size of response list. array = array letter. Returns: 0 on failure. >= 1, size of array, on success. */ static int #ifdef CK_ANSIC http_mkarray(char ** resp, int n, char array) #else http_mkarray(resp, n, array) char ** resp; int n; char array; #endif /* CK_ANSIC */ { #ifndef NOSPL int i, x; char ** ap; extern char ** a_ptr[]; extern int a_dim[]; if (!array || n <= 0) return(0); if ((x = dclarray(array,n)) < 0) { printf("?Array declaration failure\n"); return(-9); } /* Note: argument array is 0-based but Kermit array is 1-based */ ap = a_ptr[x]; ap[0] = NULL; /* 0th element is empty */ for (i = 1; i <= n; i++) { ap[i] = resp[i-1]; /* If resp elements were malloc'd */ resp[i-1] = NULL; } a_dim[x] = n; return(n); #else return(0); #endif /* NOSPL */ } #define HTTPHEADCNT 64 int http_get_chunk_len() { int len = 0; int i = 0, j = -1; char buf[24]; int ch; while ((ch = http_inc(0)) >= 0 && i < 24) { buf[i] = ch; if ( buf[i] == ';' ) /* Find chunk-extension (if any) */ j = i; if ( buf[i] == 10 ) { /* found end of line */ if (i > 0 && buf[i-1] == 13) i--; buf[i] = '\0'; break; } i++; } if ( i < 24 ) { /* buf now contains len in Hex */ len = hextoulong(buf, j == -1 ? i : j-1); } return(len); } int http_isconnected() { return(httpfd != -1); } char * http_host() { return(httpfd != -1 ? http_host_port : ""); } char * http_security() { if ( httpfd == -1 ) return("NULL"); #ifdef CK_SSL if (tls_http_active_flag) { SSL_CIPHER * cipher; const char *cipher_list; static char buf[128]; buf[0] = NUL; /* cast added by fdc 26 September 2022 */ cipher = (SSL_CIPHER *)SSL_get_current_cipher(tls_http_con); cipher_list = SSL_CIPHER_get_name(cipher); SSL_CIPHER_description(cipher,buf,sizeof(buf)); return(buf); } #endif /* CK_SSL */ return("NULL"); } int http_reopen() { int rc = 0; char * s = NULL; /* strdup is not portable */ if ( tcp_http_proxy ) { char * p; makestr(&s,(char *)http_host_port); p = s; while (*p != '\0' && *p != ':') p++; /* Look for colon */ if (*p == ':') { /* Have a colon */ *p++ = '\0'; /* Get service name or number */ } else { p="http"; } rc = http_open(s,p,http_ssl,NULL,0,http_agent); } else { makestr(&s,(char *)http_ip); rc = http_open(s,ckuitoa(http_port),http_ssl,NULL,0,http_agent); } free(s); return(rc); } int #ifdef CK_ANSIC http_open(char * hostname, char * svcname, int use_ssl, char * rdns_name, int rdns_len, char * agent) #else /* CK_ANSIC */ http_open(hostname, svcname, use_ssl, rdns_name, rdns_len, agent) char * hostname; char * svcname; int use_ssl; char * rdns_name; int rdns_len; char * agent; #endif /* CK_ANSIC */ { char namecopy[NAMECPYL]; char *p; int i, dns = 0; #ifdef NON_BLOCK_IO int x; #endif /* NON_BLOCK_IO */ #ifdef TCPSOCKET int isconnect = 0; #ifdef SO_OOBINLINE int on = 1; #endif /* SO_OOBINLINE */ struct servent *service=NULL; struct hostent *host=NULL; struct sockaddr_in r_addr; struct sockaddr_in sin; struct sockaddr_in l_addr; GSOCKNAME_T l_slen; #ifdef EXCELAN struct sockaddr_in send_socket; #endif /* EXCELAN */ #ifdef INADDRX /* inet_addr() is of type struct in_addr */ #ifdef datageneral extern struct in_addr inet_addr(); #else #ifdef HPUX5WINTCP extern struct in_addr inet_addr(); #endif /* HPUX5WINTCP */ #endif /* datageneral */ struct in_addr iax; #else #ifdef INADDR_NONE struct in_addr iax; #else /* INADDR_NONE */ long iax; #endif /* INADDR_NONE */ #endif /* INADDRX */ if ( rdns_name == NULL || rdns_len < 0 ) rdns_len = 0; *http_ip = '\0'; /* Initialize IP address string */ namecopy[0] = '\0'; #ifdef DEBUG if (deblog) { debug(F110,"http_open hostname",hostname,0); debug(F110,"http_open svcname",svcname,0); } #endif /* DEBUG */ if (!hostname) hostname = ""; if (!svcname) svcname = ""; if (!*hostname || !*svcname) return(-1); service = ckgetservice(hostname,svcname,http_ip,20); if (service == NULL) { if ( !quiet ) printf("?Invalid service: %s\r\n",svcname); return(-1); } /* For HTTP connections we must preserve the original hostname and */ /* service requested so we can include them in the Host header. */ ckmakmsg(http_host_port,sizeof(http_host_port),hostname,":", ckuitoa(ntohs(service->s_port)),NULL); http_port = ntohs(service->s_port); http_ssl = use_ssl; debug(F111,"http_open",http_host_port,http_port); /* 'http_ip' contains the IP address to which we want to connect */ /* 'svcnam' contains the service name */ /* 'service->s_port' contains the port number in network byte order */ /* If we are using an http proxy, we need to create a buffer containing */ /* hostname:port-number */ /* to pass to the http_connect() function. Then we need to replace */ /* 'namecopy' with the name of the proxy server and the service->s_port */ /* with the port number of the proxy (default port 80). */ if ( tcp_http_proxy ) { ckmakmsg(proxycopy,sizeof(proxycopy),hostname,":", ckuitoa(ntohs(service->s_port)),NULL); ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL); p = namecopy; /* Was a service requested? */ while (*p != '\0' && *p != ':') p++; /* Look for colon */ if (*p == ':') { /* Have a colon */ debug(F110,"http_open name has colon",namecopy,0); *p++ = '\0'; /* Get service name or number */ } else { strcpy(++p,"http"); } service = ckgetservice(namecopy,p,http_ip,20); if (!service) { fprintf(stderr, "Can't find port for service %s\n", p); #ifdef TGVORWIN debug(F101,"http_open can't get service for proxy","",socket_errno); #else debug(F101,"http_open can't get service for proxy","",errno); #endif /* TGVORWIN */ errno = 0; /* (rather than mislead) */ return(-1); } /* copy the proxyname and remove the service if any so we can use * it as the hostname */ ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL); p = namecopy; /* Was a service requested? */ while (*p != '\0' && *p != ':') p++; /* Look for colon */ if (*p == ':') { /* Have a colon */ *p = '\0'; /* terminate string */ } hostname = namecopy; /* use proxy as hostname */ } /* Set up socket structure and get host address */ bzero((char *)&r_addr, sizeof(r_addr)); debug(F100,"http_open bzero ok","",0); #ifdef INADDR_NONE debug(F101,"http_open INADDR_NONE defined","",INADDR_NONE); #else /* INADDR_NONE */ debug(F100,"http_open INADDR_NONE not defined","",0); #endif /* INADDR_NONE */ #ifdef INADDRX debug(F100,"http_open INADDRX defined","",0); #else /* INADDRX */ debug(F100,"http_open INADDRX not defined","",0); #endif /* INADDRX */ #ifndef NOMHHOST #ifdef INADDRX iax = inet_addr(http_ip[0]?http_ip:hostname); debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr); #else /* INADDRX */ #ifdef INADDR_NONE iax.s_addr = inet_addr(http_ip[0]?http_ip:hostname); debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr); #else /* INADDR_NONE */ #ifndef datageneral iax = (unsigned int) inet_addr(http_ip[0]?http_ip:hostname); #else iax = -1L; #endif /* datageneral */ debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax); #endif /* INADDR_NONE */ #endif /* INADDRX */ dns = 0; if ( #ifdef INADDR_NONE /* This might give warnings on 64-bit platforms but they should be harmless */ /* because INADDR_NONE should be all 1's anyway, thus the OR part is */ /* probably superfluous -- not sure why it's even there, maybe it should be */ /* removed. */ iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */ #else /* INADDR_NONE */ iax == -1 #endif /* INADDR_NONE */ ) { if (!quiet) { printf(" DNS Lookup... "); fflush(stdout); } if ((host = gethostbyname(http_ip[0] ? http_ip : hostname)) != NULL) { debug(F100,"http_open gethostbyname != NULL","",0); host = ck_copyhostent(host); dns = 1; /* Remember we performed dns lookup */ r_addr.sin_family = host->h_addrtype; if (tcp_rdns && host->h_name && host->h_name[0] && (rdns_len > 0) && (tcp_http_proxy == NULL) ) ckmakmsg(rdns_name,rdns_len,host->h_name,":",svcname,NULL); #ifdef HADDRLIST #ifdef h_addr /* This is for trying multiple IP addresses - see */ if (!(host->h_addr_list)) return(-1); bcopy(host->h_addr_list[0], (caddr_t)&r_addr.sin_addr, host->h_length ); #else bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length); #endif /* h_addr */ #else /* HADDRLIST */ bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length); #endif /* HADDRLIST */ #ifdef COMMENT #ifndef EXCELAN debug(F111,"BCOPY","host->h_addr",host->h_addr); #endif /* EXCELAN */ debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr", (caddr_t)&r_addr.sin_addr); debug(F111,"BCOPY"," r_addr.sin_addr.s_addr", r_addr.sin_addr.s_addr); #endif /* COMMENT */ debug(F111,"BCOPY","host->h_length",host->h_length); } } #endif /* NOMHHOST */ if (!dns) { #ifdef INADDRX /* inet_addr() is of type struct in_addr */ struct in_addr ina; unsigned long uu; debug(F100,"http_open gethostbyname == NULL: INADDRX","",0); ina = inet_addr(http_ip[0]?http_ip:hostname); uu = *(unsigned int *)&ina; #else /* Not INADDRX */ /* inet_addr() is unsigned long */ unsigned long uu; debug(F100,"http_open gethostbyname == NULL: Not INADDRX","",0); uu = inet_addr(http_ip[0]?http_ip:hostname); #endif /* INADDRX */ debug(F101,"http_open uu","",uu); if ( #ifdef INADDR_NONE !(uu == INADDR_NONE || uu == (unsigned int) -1L) #else /* INADDR_NONE */ uu != ((unsigned long)-1) #endif /* INADDR_NONE */ ) { r_addr.sin_addr.s_addr = uu; r_addr.sin_family = AF_INET; } else { #ifdef VMS fprintf(stdout, "\r\n"); /* complete any previous message */ #endif /* VMS */ fprintf(stderr, "Can't get address for %s\n", http_ip[0]?http_ip:hostname); #ifdef TGVORWIN debug(F101,"http_open can't get address","",socket_errno); #else debug(F101,"http_open can't get address","",errno); #endif /* TGVORWIN */ errno = 0; /* Rather than mislead */ return(-1); } } /* Get a file descriptor for the connection. */ r_addr.sin_port = service->s_port; ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20); debug(F110,"http_open trying",http_ip,0); if (!quiet && *http_ip) { printf(" Trying %s... ", http_ip); fflush(stdout); } /* Loop to try additional IP addresses, if any. */ do { #ifdef EXCELAN send_socket.sin_family = AF_INET; send_socket.sin_addr.s_addr = 0; send_socket.sin_port = 0; if ((httpfd = socket(SOCK_STREAM, (struct sockproto *)0, &send_socket, SO_REUSEADDR)) < 0) #else /* EXCELAN */ if ((httpfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) #endif /* EXCELAN */ { #ifdef EXCELAN experror("TCP socket error"); #else #ifdef TGVORWIN #ifdef OLD_TWG errno = socket_errno; #endif /* OLD_TWG */ socket_perror("TCP socket error"); debug(F101,"http_open socket error","",socket_errno); #else perror("TCP socket error"); debug(F101,"http_open socket error","",errno); #endif /* TGVORWIN */ #endif /* EXCELAN */ return (-1); } errno = 0; /* If a specific TCP address on the local host is desired we */ /* must bind it to the socket. */ #ifndef datageneral if (tcp_address) { int s_errno; debug(F110,"http_open binding socket to",tcp_address,0); bzero((char *)&sin,sizeof(sin)); sin.sin_family = AF_INET; #ifdef INADDRX inaddrx = inet_addr(tcp_address); sin.sin_addr.s_addr = *(unsigned long *)&inaddrx; #else sin.sin_addr.s_addr = inet_addr(tcp_address); #endif /* INADDRX */ sin.sin_port = 0; if (bind(httpfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { s_errno = socket_errno; /* Save error code */ #ifdef TCPIPLIB socket_close(httpfd); #else /* TCPIPLIB */ close(httpfd); #endif /* TCPIPLIB */ httpfd = -1; errno = s_errno; /* and report this error */ debug(F101,"http_open bind errno","",errno); return(-1); } } #endif /* datageneral */ /* Now connect to the socket on the other end. */ #ifdef EXCELAN if (connect(httpfd, &r_addr) < 0) #else #ifdef NT WSASafeToCancel = 1; #endif /* NT */ if (connect(httpfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0) #endif /* EXCELAN */ { #ifdef NT WSASafeToCancel = 0; #endif /* NT */ #ifdef OS2 i = socket_errno; #else /* OS2 */ #ifdef TGVORWIN i = socket_errno; #else i = errno; /* Save error code */ #endif /* TGVORWIN */ #endif /* OS2 */ #ifdef HADDRLIST #ifdef h_addr if (host && host->h_addr_list && host->h_addr_list[1]) { perror(""); host->h_addr_list++; bcopy(host->h_addr_list[0], (caddr_t)&r_addr.sin_addr, host->h_length); ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20); debug(F110,"http_open h_addr_list",http_ip,0); if (!quiet && *http_ip) { printf(" Trying %s... ", http_ip); fflush(stdout); } #ifdef TCPIPLIB socket_close(httpfd); /* Close it. */ #else close(httpfd); #endif /* TCPIPLIB */ continue; } #endif /* h_addr */ #endif /* HADDRLIST */ http_close(); httpfd = -1; errno = i; /* And report this error */ #ifdef EXCELAN if (errno) experror("http_open connect"); #else #ifdef TGVORWIN debug(F101,"http_open connect error","",socket_errno); /* if (errno) socket_perror("http_open connect"); */ #ifdef OLD_TWG errno = socket_errno; #endif /* OLD_TWG */ if (!quiet) socket_perror("http_open connect"); #else /* TGVORWIN */ debug(F101,"http_open connect errno","",errno); #ifdef VMS if (!quiet) perror("\r\nFailed"); #else if (!quiet) perror("Failed"); #endif /* VMS */ #ifdef DEC_TCPIP if (!quiet) perror("http_open connect"); #endif /* DEC_TCPIP */ #ifdef CMU_TCPIP if (!quiet) perror("http_open connect"); #endif /* CMU_TCPIP */ #endif /* TGVORWIN */ #endif /* EXCELAN */ return(-1); } #ifdef NT WSASafeToCancel = 0; #endif /* NT */ isconnect = 1; } while (!isconnect); #ifdef NON_BLOCK_IO on = 1; x = socket_ioctl(httpfd,FIONBIO,&on); debug(F101,"http_open FIONBIO","",x); #endif /* NON_BLOCK_IO */ /* We have succeeded in connecting to the HTTP PROXY. So now we */ /* need to attempt to connect through the proxy to the actual host */ /* If that is successful, we have to pretend that we made a direct */ /* connection to the actual host. */ if ( tcp_http_proxy ) { #ifdef OS2 if (!agent) agent = "Kermit 95"; /* Default user agent */ #else if (!agent) agent = "C-Kermit"; #endif /* OS2 */ if (http_connect(httpfd, tcp_http_proxy_agent ? tcp_http_proxy_agent : agent, NULL, tcp_http_proxy_user, tcp_http_proxy_pwd, 0, proxycopy ) < 0) { http_close(); return(-1); } } #ifdef SO_OOBINLINE /* See note on SO_OOBINLINE in netopen() */ #ifdef datageneral setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef BSD43 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef OSF1 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef POSIX setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef MOTSV88R4 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef SOLARIS /* Maybe this applies to all SVR4 versions, but the other (else) way has been compiling and working fine on all the others, so best not to change it. */ setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef OSK setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef OS2 { int rc; rc = setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof on ); debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc); } #else #ifdef VMS /* or, at least, VMS with gcc */ setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else #ifdef CLIX setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #else setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); #endif /* CLIX */ #endif /* VMS */ #endif /* OS2 */ #endif /* OSK */ #endif /* SOLARIS */ #endif /* MOTSV88R4 */ #endif /* POSIX */ #endif /* BSD43 */ #endif /* OSF1 */ #endif /* datageneral */ #endif /* SO_OOBINLINE */ #ifndef NOTCPOPTS #ifndef datageneral #ifdef SOL_SOCKET #ifdef TCP_NODELAY no_delay(ttyfd,tcp_nodelay); #endif /* TCP_NODELAY */ #ifdef SO_KEEPALIVE keepalive(ttyfd,tcp_keepalive); #endif /* SO_KEEPALIVE */ #ifdef SO_LINGER ck_linger(ttyfd,tcp_linger, tcp_linger_tmo); #endif /* SO_LINGER */ #ifdef SO_SNDBUF sendbuf(ttyfd,tcp_sendbuf); #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF recvbuf(ttyfd,tcp_recvbuf); #endif /* SO_RCVBUF */ #endif /* SOL_SOCKET */ #endif /* datageneral */ #endif /* NOTCPOPTS */ #ifndef datageneral /* Find out our own IP address. */ /* We need the l_addr structure for [E]KLOGIN. */ l_slen = sizeof(l_addr); bzero((char *)&l_addr, l_slen); #ifndef EXCELAN if (!getsockname(httpfd, (struct sockaddr *)&l_addr, &l_slen)) { char * s = (char *)inet_ntoa(l_addr.sin_addr); ckstrncpy(myipaddr, s, 20); debug(F110,"getsockname",myipaddr,0); } #endif /* EXCELAN */ #endif /* datageneral */ /* See note in netopen() on Reverse DNS lookups */ if (tcp_rdns == SET_ON) { #ifdef NT if (isWin95()) sleep(1); #endif /* NT */ if (!quiet) { printf(" Reverse DNS Lookup... "); fflush(stdout); } if ((host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET))) { char * s; host = ck_copyhostent(host); debug(F100,"http_open gethostbyname != NULL","",0); if (!quiet) { printf("(OK)\n"); fflush(stdout); } s = host->h_name; if (!s) { /* This can happen... */ debug(F100,"http_open host->h_name is NULL","",0); s = ""; } /* Something is wrong with inet_ntoa() on HPUX 10.xx */ /* The compiler says "Integral value implicitly converted to */ /* pointer in assignment." The prototype is right there */ /* in so what's the problem? */ /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */ if (!*s) { /* No name so substitute the address */ debug(F100,"http_open host->h_name is empty","",0); s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */ if (!s) /* Trust No 1 */ s = ""; if (*s) { /* If it worked, use this string */ ckstrncpy(http_ip,s,20); } s = http_ip; /* Otherwise stick with the IP */ if (!*s) /* or failing that */ s = http_host_port; /* the name we were called with. */ } if (*s) /* return the rdns name */ ckmakmsg(rdns_name,rdns_len,s,":",svcname,NULL); if (!quiet && *s #ifndef NOICP && !doconx #endif /* NOICP */ ) { printf(" %s connected on port %s\n",s, ckuitoa(ntohs(service->s_port))); #ifdef BETADEBUG /* This is simply for testing the DNS entries */ if (host->h_aliases) { char ** a = host->h_aliases; while (*a) { printf(" alias => %s\n",*a); a++; } } #endif /* BETADEBUG */ } } else { if (!quiet) printf("Failed.\n"); } } else if (!quiet) printf("(OK)\n"); if (!quiet) fflush(stdout); if ( tcp_http_proxy ) { /* Erase the IP address since we cannot reuse it */ http_ip[0] = '\0'; } else { /* This should already have been done but just in case */ ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20); } makestr(&http_agent,agent); #ifdef CK_SSL if (use_ssl && ck_ssleay_is_installed()) { if (!ssl_http_init(hostname)) { if (bio_err!=NULL) { BIO_printf(bio_err,"ssl_tn_init() failed\n"); ERR_print_errors(bio_err); } else { fflush(stderr); fprintf(stderr,"ssl_tn_init() failed\n"); ERR_print_errors_fp(stderr); } http_close(); return(-1); } else if ( ck_ssl_http_client(httpfd,hostname) < 0 ) { http_close(); return(-1); } } #endif /* CK_SSL */ #endif /* TCPSOCKET */ return(0); /* Done. */ } int #ifdef CK_ANSIC http_close(VOID) #else /* CK_ANSIC */ http_close() #endif /* CK_ANSIC */ { int x = 0; debug(F101,"http_close","",httpfd); #ifdef HTTP_BUFFERING http_count = 0; http_bufp = 0; #endif /* HTTP_BUFFERING */ if (httpfd == -1) /* Was open? */ return(0); /* Wasn't. */ #ifndef OS2 if (httpfd > -1) /* Was. */ #endif /* OS2 */ { #ifdef CK_SSL if (tls_http_active_flag) { if (ssl_debug_flag) BIO_printf(bio_err,"calling SSL_shutdown\n"); SSL_shutdown(tls_http_con); tls_http_active_flag = 0; } #endif /* CK_SSL */ #ifdef TCPIPLIB x = socket_close(httpfd); /* Close it. */ #else #ifndef OS2 x = close(httpfd); #endif /* OS2 */ #endif /* TCPIPLIB */ } httpfd = -1; /* Mark it as closed. */ /* do not erase http_host_port, http_ip, http_port so they */ /* can be used by http_reopen() */ return(x); } /* http_tol() * Call with s = pointer to string, n = length. * Returns number of bytes actually written on success, or * -1 on i/o error, -2 if called improperly. */ int #ifdef CK_ANSIC http_tol( CHAR *s, int n ) #else http_tol(s,n) CHAR *s; int n; #endif /* CK_ANSIC */ { int count = 0; int len = n; int try = 0; if (httpfd == -1) { debug(F100,"http_tol socket is closed","",0); return -1; } debug(F101,"http_tol TCPIPLIB ttnet","",ttnet); #ifdef COMMENT ckhexdump("http_tol",s,n); #endif /* COMMENT */ #ifdef CK_SSL if (tls_http_active_flag) { int error, r; /* Write using SSL */ ssl_retry: r = SSL_write(tls_http_con, s, len /* >1024?1024:len */); switch (SSL_get_error(tls_http_con,r)) { case SSL_ERROR_NONE: debug(F111,"http_tol","SSL_write",r); if ( r == len ) return(n); s += r; len -= r; goto ssl_retry; case SSL_ERROR_WANT_WRITE: debug(F100,"http_tol SSL_ERROR_WANT_WRITE","",0); return(-1); case SSL_ERROR_WANT_READ: debug(F100,"http_tol SSL_ERROR_WANT_READ","",0); return(-1); case SSL_ERROR_SYSCALL: if ( r == 0 ) { /* EOF */ http_close(); return(-2); } else { int rc = -1; #ifdef NT int gle = GetLastError(); debug(F111,"http_tol SSL_ERROR_SYSCALL", "GetLastError()",gle); rc = os2socketerror(gle); if (rc == -1) rc = -2; else if ( rc == -2 ) return -1; #endif /* NT */ return(rc); } case SSL_ERROR_WANT_X509_LOOKUP: debug(F100,"http_tol SSL_ERROR_WANT_X509_LOOKUP","",0); http_close(); return(-2); case SSL_ERROR_SSL: debug(F100,"http_tol SSL_ERROR_SSL","",0); http_close(); return(-2); case SSL_ERROR_ZERO_RETURN: debug(F100,"http_tol SSL_ERROR_ZERO_RETURN","",0); http_close(); return(-2); default: debug(F100,"http_tol SSL_ERROR_?????","",0); http_close(); return(-2); } } #endif /* CK_SSL */ http_tol_retry: try++; /* Increase the try counter */ { #ifdef BSDSELECT fd_set wfds; struct timeval tv; debug(F101,"http_tol BSDSELECT","",0); tv.tv_usec = 0L; tv.tv_sec=30; #ifdef NT WSASafeToCancel = 1; #endif /* NT */ #ifdef STREAMING do_select: #endif /* STREAMING */ FD_ZERO(&wfds); FD_SET(httpfd, &wfds); if (select(FD_SETSIZE, NULL, #ifdef __DECC #ifndef __DECC_VER (int *) #endif /* __DECC_VER */ #endif /* __DECC */ &wfds, NULL, &tv) < 0) { int s_errno = socket_errno; debug(F101,"http_tol select failed","",s_errno); #ifdef BETADEBUG printf("http_tol select failed: %d\n", s_errno); #endif /* BETADEBUG */ #ifdef NT WSASafeToCancel = 0; if (!win95selectbug) #endif /* NT */ return(-1); } if (!FD_ISSET(httpfd, &wfds)) { #ifdef STREAMING if (streaming) goto do_select; #endif /* STREAMING */ debug(F111,"http_tol","!FD_ISSET",ttyfd); #ifdef NT WSASafeToCancel = 0; if (!win95selectbug) #endif /* NT */ return(-1); } #ifdef NT WSASafeToCancel = 0; #endif /* NT */ #else /* BSDSELECT */ #ifdef IBMSELECT { int tries = 0; debug(F101,"http_tol IBMSELECT","",0); while (select(&httpfd, 0, 1, 0, 1000) != 1) { int count; if (tries++ >= 60) { /* if after 60 seconds we can't get permission to write */ debug(F101,"http_tol select failed","",socket_errno); return(-1); } #ifdef COMMENT if ((count = http_tchk()) < 0) { debug(F111,"http_tol","http_tchk()",count); return(count); } #endif /* COMMENT */ } } #endif /* IBMSELECT */ #endif /* BSDSELECT */ #ifdef TCPIPLIB if ((count = socket_write(httpfd,s,n)) < 0) { int s_errno = socket_errno; /* maybe a function */ debug(F101,"http_tol socket_write error","",s_errno); #ifdef OS2 if (os2socketerror(s_errno) < 0) return(-2); #endif /* OS2 */ return(-1); /* Call it an i/o error */ } #else /* TCPIPLIB */ if ((count = write(httpfd,s,n)) < 0) { debug(F101,"http_tol socket_write error","",errno); return(-1); /* Call it an i/o error */ } #endif /* TCPIPLIB */ if (count < n) { debug(F111,"http_tol socket_write",s,count); if (try > 25) { /* don't try more than 25 times */ debug(F100,"http_tol tried more than 25 times","",0); return(-1); } if (count > 0) { s += count; n -= count; } debug(F111,"http_tol retry",s,n); goto http_tol_retry; } else { debug(F111,"http_tol socket_write",s,count); return(len); /* success - return total length */ } } } int #ifdef CK_ANSIC http_inc( int timo ) #else http_inc(timo) int timo; #endif /* CK_ANSIC */ { int x=-1; unsigned char c; /* The locals. */ if (httpfd == -1) { #ifdef HTTP_BUFFERING http_count = 0; http_bufp = 0; #endif /* HTTP_BUFFERING */ debug(F100,"http_inc socket is closed","",0); return(-2); } #ifdef CK_SSL /* * In the case of OpenSSL, it is possible that there is still * data waiting in the SSL session buffers that has not yet * been read by Kermit. If this is the case we must process * it without calling select() because select() will not return * with an indication that there is data to be read from the * socket. If there is no data pending in the SSL session * buffers then fall through to the select() code and wait for * some data to arrive. */ if (tls_http_active_flag) { int error; x = SSL_pending(tls_http_con); if (x < 0) { debug(F111,"http_inc","SSL_pending error",x); http_close(); return(-1); } else if ( x > 0 ) { ssl_read: x = SSL_read(tls_http_con, &c, 1); error = SSL_get_error(tls_http_con,x); switch (error) { case SSL_ERROR_NONE: debug(F111,"http_inc SSL_ERROR_NONE","x",x); if (x > 0) { #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(c); /* Return character. */ } else if (x < 0) { #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); } else { http_close(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); } case SSL_ERROR_WANT_WRITE: debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); case SSL_ERROR_WANT_READ: debug(F100,"http_inc SSL_ERROR_WANT_READ","",0); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); case SSL_ERROR_SYSCALL: if ( x == 0 ) { /* EOF */ http_close(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); } else { int rc = -1; #ifdef NT int gle = GetLastError(); debug(F111,"http_inc SSL_ERROR_SYSCALL", "GetLastError()",gle); rc = os2socketerror(gle); if (rc == -1) rc = -2; else if ( rc == -2 ) rc = -1; #endif /* NT */ #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(rc); } case SSL_ERROR_WANT_X509_LOOKUP: debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0); http_close(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); case SSL_ERROR_SSL: debug(F100,"http_inc SSL_ERROR_SSL","",0); #ifdef COMMENT http_close(); #endif /* COMMENT */ #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); case SSL_ERROR_ZERO_RETURN: debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0); http_close(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); default: debug(F100,"http_inc SSL_ERROR_?????","",0); http_close(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); } } } #endif /* CK_SSL */ #ifdef HTTP_BUFFERING /* Skip all the select() stuff if we have bytes buffered locally */ if (http_count > 0) goto getfrombuffer; #endif /* HTTP_BUFFERING */ { #ifdef BSDSELECT fd_set rfds; struct timeval tv; int timeout = timo < 0 ? -timo : 1000 * timo; debug(F101,"http_inc BSDSELECT","",timo); for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) { int rc; debug(F111,"http_inc","timeout",timeout); /* Don't move select() initialization out of the loop. */ FD_ZERO(&rfds); FD_SET(httpfd, &rfds); tv.tv_sec = tv.tv_usec = 0L; if (timo) tv.tv_usec = (long) 100000L; else tv.tv_sec = 30; #ifdef NT WSASafeToCancel = 1; #endif /* NT */ rc = select(FD_SETSIZE, #ifndef __DECC (fd_set *) #endif /* __DECC */ &rfds, NULL, NULL, &tv); if (rc < 0) { int s_errno = socket_errno; debug(F111,"http_inc","select",rc); debug(F111,"http_inc","socket_errno",s_errno); #ifdef HTTP_BUFFERING http_count = 0; http_bufp = 0; #endif /* HTTP_BUFFERING */ if (s_errno) return(-1); } debug(F111,"http_inc","select",rc); #ifdef NT WSASafeToCancel = 0; #endif /* NT */ if (FD_ISSET(httpfd, &rfds)) { x = 0; break; } else { /* If waiting forever we have no way of knowing if the */ /* socket closed so try writing a 0-length TCP packet */ /* which should force an error if the socket is closed */ if (!timo) { #ifdef TCPIPLIB if ((rc = socket_write(httpfd,"",0)) < 0) { #ifdef HTTP_BUFFERING http_count = 0; http_bufp = 0; #endif /* HTTP_BUFFERING */ int s_errno = socket_errno; debug(F101,"http_inc socket_write error","",s_errno); #ifdef OS2 if (os2socketerror(s_errno) < 0) return(-2); #endif /* OS2 */ return(-1); /* Call it an i/o error */ } #else /* TCPIPLIB */ if ((rc = write(httpfd,"",0)) < 0) { #ifdef HTTP_BUFFERING http_count = 0; http_bufp = 0; #endif /* HTTP_BUFFERING */ debug(F101,"http_inc socket_write error","",errno); return(-1); /* Call it an i/o error */ } #endif /* TCPIPLIB */ } continue; } } #ifdef NT WSASafeToCancel = 0; #endif /* NT */ #else /* !BSDSELECT */ #ifdef IBMSELECT /* Was used by OS/2, currently not used, but might come in handy some day... ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set and timeval stuff since this is the only place where it is used. */ int socket = httpfd; int timeout = timo < 0 ? -timo : 1000 * timo; debug(F101,"http_inc IBMSELECT","",timo); for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) { if (select(&socket, 1, 0, 0, 100L) == 1) { x = 0; break; } } #endif /* IBMSELECT */ #endif /* BSDSELECT */ } if (timo && x < 0) { /* select() timed out */ #ifdef HTTP_BUFFERING http_count = 0; http_bufp = 0; #endif /* HTTP_BUFFERING */ debug(F100,"http_inc select() timed out","",0); return(-1); /* Call it an i/o error */ } #ifdef CK_SSL if ( tls_http_active_flag ) { int error; ssl_read2: x = SSL_read(tls_http_con, &c, 1); error = SSL_get_error(tls_http_con,x); switch (error) { case SSL_ERROR_NONE: debug(F111,"http_inc SSL_ERROR_NONE","x",x); if (x > 0) { #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(c); /* Return character. */ } else if (x < 0) { #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); } else { http_close(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); } case SSL_ERROR_WANT_WRITE: debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); case SSL_ERROR_WANT_READ: debug(F100,"http_inc SSL_ERROR_WANT_READ","",0); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-1); case SSL_ERROR_SYSCALL: if ( x == 0 ) { /* EOF */ http_close(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); } else { int rc = -1; #ifdef NT int gle = GetLastError(); debug(F111,"http_inc SSL_ERROR_SYSCALL", "GetLastError()",gle); rc = os2socketerror(gle); if (rc == -1) rc = -2; else if ( rc == -2 ) rc = -1; #endif /* NT */ #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(rc); } case SSL_ERROR_WANT_X509_LOOKUP: debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0); http_close(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); case SSL_ERROR_SSL: debug(F100,"http_inc SSL_ERROR_SSL","",0); #ifdef COMMENT http_close(); #endif /* COMMENT */ #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); case SSL_ERROR_ZERO_RETURN: debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0); http_close(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); default: debug(F100,"http_inc SSL_ERROR_?????","",0); http_close(); #ifdef OS2 ReleaseTCPIPMutex(); #endif /* OS2 */ return(-2); } } #endif /* CK_SSL */ #ifdef HTTP_BUFFERING /* Buffering code added by fdc 15 Dec 2005 for non-SSL case only because HTTP GETs were orders of magnitude too slow due to the single-byte read()s. The file-descriptor swapping is pretty gross, but the more elegant solution (calling a nettchk() like routine with the fd as a parameter) doesn't work, because nettchk() relies on too many other routines that, like itself, are hardwired for ttyfd. */ getfrombuffer: if (--http_count >= 0) { c = http_inbuf[http_bufp++]; x = 1; } else { int savefd; savefd = ttyfd; ttyfd = httpfd; x = nettchk(); ttyfd = savefd; debug(F101,"http_inc nettchk","",x); if (x > HTTP_INBUFLEN) x = HTTP_INBUFLEN; #ifdef TCPIPLIB x = socket_read(httpfd,http_inbuf,x); #else /* Not TCPIPLIB */ x = read(httpfd,http_inbuf,x); #endif /* TCPIPLIB */ http_count = 0; http_bufp = 0; if (x > 0) { c = http_inbuf[http_bufp++]; http_count = x - 1; } } #else /* Not HTTP_BUFFERING */ #ifdef TCPIPLIB x = socket_read(httpfd,&c,1); #else /* Not TCPIPLIB */ x = read(httpfd,&c,1); #endif /* TCPIPLIB */ #endif /* HTTP_BUFFERING */ if (x <= 0) { int s_errno = socket_errno; debug(F101,"ttbufr socket_read","",x); debug(F101,"ttbufr socket_errno","",s_errno); #ifdef OS2 if (x == 0 || os2socketerror(s_errno) < 0) { http_close(); ReleaseTCPIPMutex(); return(-2); } ReleaseTCPIPMutex(); return(-1); #else /* OS2 */ http_close(); /* *** *** */ return(-2); #endif /* OS2 */ } return(c); } void #ifdef CK_ANSIC http_set_code_reply(char * msg) #else http_set_code_reply(msg) char * msg; #endif /* CK_ANSIC */ { char * p = msg; char buf[16]; int i=0; while ( *p != SP && *p != NUL ) { buf[i] = *p; p++; i++; } http_code = atoi(buf); while ( *p == SP ) p++; ckstrncpy(http_reply_str,p,HTTPBUFLEN); } int #ifdef CK_ANSIC http_get(char * agent, char ** hdrlist, char * user, char * pwd, char array, char * local, char * remote, int stdio) #else http_get(agent, hdrlist, user, pwd, array, local, remote, stdio) char * agent; char ** hdrlist; char * user; char * pwd; char array; char * local; char * remote; int stdio; #endif /* CK_ANSIC */ { char * request = NULL; int i, j, len = 0, hdcnt = 0, rc = 0; int ch; int http_fnd = 0; char buf[HTTPBUFLEN], *p; int nullline; #ifdef OS2 struct utimbuf u_t; #else /* OS2 */ #ifdef SYSUTIMEH struct utimbuf u_t; #else struct utimbuf { time_t atime; time_t mtime; } u_t; #endif /* SYSUTIMH */ #endif /* OS2 */ time_t mod_t = 0; time_t srv_t = 0; time_t local_t = 0; char passwd[64]; char b64in[128]; char b64out[256]; char * headers[HTTPHEADCNT]; int closecon = 0; int chunked = 0; int zfile = 0; int first = 1; #ifdef DEBUG if (deblog) { debug(F101,"http_get httpfd","",httpfd); debug(F110,"http_agent",agent,0); debug(F110,"http_user",user,0); debug(F110,"http_local",local,0); debug(F110,"http_remote",remote,0); } #endif /* DEBUG */ if (!remote) remote = ""; if (httpfd == -1) return(-1); if (array) { for (i = 0; i < HTTPHEADCNT; i++) headers[i] = NULL; } len = 8; /* GET */ len += strlen(HTTP_VERSION); len += strlen(remote); len += 16; if (hdrlist) { for (i = 0; hdrlist[i]; i++) len += strlen(hdrlist[i]) + 2; } len += (int) strlen(http_host_port) + 8; if (agent) len += 13 + strlen(agent); if (user) { if (!pwd) { readpass("Password: ",passwd,64); pwd = passwd; } ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL); j = b8tob64(b64in,strlen(b64in),b64out,256); memset(pwd,0,strlen(pwd)); /* NOT PORTABLE */ if (j < 0) return(-1); b64out[j] = '\0'; len += j + 24; } #ifdef HTTP_CLOSE len += 19; /* Connection: close */ #endif len += 3; /* blank line + null */ request = malloc(len); if (!request) return(-1); sprintf(request,"GET %s %s\r\n",remote,HTTP_VERSION); /* safe */ ckstrncat(request,"Host: ", len); ckstrncat(request,http_host_port, len); ckstrncat(request,"\r\n",len); if (agent) { ckstrncat(request,"User-agent: ",len); ckstrncat(request,agent,len); ckstrncat(request,"\r\n",len); } if (user) { ckstrncat(request,"Authorization: Basic ",len); ckstrncat(request,b64out,len); ckstrncat(request,"\r\n",len); } if ( hdrlist ) { for (i = 0; hdrlist[i]; i++) { ckstrncat(request,hdrlist[i],len); ckstrncat(request,"\r\n",len); } } #ifdef HTTP_CLOSE ckstrncat(request,"Connection: close\r\n",len); #endif ckstrncat(request,"\r\n",len); getreq: if (http_tol((CHAR *)request,strlen(request)) < 0) { http_close(); if ( first ) { first--; http_reopen(); goto getreq; } rc = -1; goto getexit; } /* Process the headers */ local_t = time(NULL); nullline = 0; i = 0; len = -1; while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) { buf[i] = ch; if ( buf[i] == 10 ) { /* found end of line */ if (i > 0 && buf[i-1] == 13) i--; if (i < 1) nullline = 1; buf[i] = '\0'; if (array && !nullline && hdcnt < HTTPHEADCNT) makestr(&headers[hdcnt++],buf); if (!ckstrcmp(buf,"HTTP",4,0)) { http_fnd = 1; j = ckindex(" ",buf,0,0,0); p = &buf[j]; while ( isspace(*p) ) p++; switch ( p[0] ) { case '1': /* Informational message */ break; case '2': /* Success */ break; case '3': /* Redirection */ case '4': /* Client failure */ case '5': /* Server failure */ default: /* Unknown */ if (!quiet) printf("Failure: Server reports %s\n",p); rc = -1; local = NULL; } http_set_code_reply(p); #ifdef CMDATE2TM } else if (!ckstrcmp(buf,"Last-Modified",13,0)) { mod_t = http_date(&buf[15]); } else if (!ckstrcmp(buf,"Date",4,0)) { srv_t = http_date(&buf[4]); #endif /* CMDATE2TM */ } else if (!ckstrcmp(buf,"Connection:",11,0)) { if ( ckindex("close",buf,11,0,0) != 0 ) closecon = 1; } else if (!ckstrcmp(buf,"Content-Length:",15,0)) { len = atoi(&buf[16]); } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) { if ( ckindex("chunked",buf,18,0,0) != 0 ) chunked = 1; debug(F101,"http_get chunked","",chunked); } i = 0; } else { i++; } } if (ch < 0 && first) { first--; http_close(); http_reopen(); goto getreq; } if (http_fnd == 0) { rc = -1; closecon = 1; goto getexit; } /* Now we have the contents of the file */ if ( local && local[0] ) { if (zopeno(ZOFILE,local,NULL,NULL)) zfile = 1; else rc = -1; } if ( chunked ) { while ((len = http_get_chunk_len()) > 0) { while (len && (ch = http_inc(0)) >= 0) { len--; if ( zfile ) zchout(ZOFILE,(CHAR)ch); if ( stdio ) conoc((CHAR)ch); } if ((ch = http_inc(0)) != CK_CR) break; if ((ch = http_inc(0)) != LF) break; } } else { while (len && (ch = http_inc(0)) >= 0) { len--; if ( zfile ) zchout(ZOFILE,(CHAR)ch); if ( stdio ) conoc((CHAR)ch); } } if ( zfile ) zclose(ZOFILE); if ( chunked ) { /* Parse Trailing Headers */ nullline = 0; while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) { buf[i] = ch; if ( buf[i] == 10 ) { /* found end of line */ if (i > 0 && buf[i-1] == 13) i--; if (i < 1) nullline = 1; buf[i] = '\0'; if (array && !nullline && hdcnt < HTTPHEADCNT) makestr(&headers[hdcnt++],buf); #ifdef CMDATE2TM if (!ckstrcmp(buf,"Last-Modified",13,0)) { mod_t = http_date(&buf[15]); } else if (!ckstrcmp(buf,"Date",4,0)) { srv_t = http_date(&buf[4]); } #endif /* CMDATE2TM */ else if (!ckstrcmp(buf,"Connection:",11,0)) { if ( ckindex("close",buf,11,0,0) != 0 ) closecon = 1; } i = 0; } else { i++; } } } if ( zfile ) { /* Set timestamp */ #ifndef NOSETTIME #ifdef OS2 u_t.actime = srv_t ? srv_t : local_t; u_t.modtime = mod_t ? mod_t : local_t; #else /* OS2 */ #ifdef SYSUTIMEH u_t.actime = srv_t ? srv_t : local_t; u_t.modtime = mod_t ? mod_t : local_t; #else #ifdef BSD44 u_t[0].tv_sec = srv_t ? srv_t : local_t; u_t[1].tv_sec = mod_t ? mod_t : local_t; #else u_t.mtime = srv_t ? srv_t : local_t; u_t.atime = mod_t ? mod_t : local_t; #endif /* BSD44 */ #endif /* SYSUTIMEH */ #endif /* OS2 */ utime(local,&u_t); #endif /* NOSETTIME */ } getexit: if (array) http_mkarray(headers,hdcnt,array); if ( closecon ) http_close(); free(request); for (i = 0; i < hdcnt; i++) { if (headers[i]) free(headers[i]); } return(rc); } int #ifdef CK_ANSIC http_head(char * agent, char ** hdrlist, char * user, char * pwd, char array, char * local, char * remote, int stdio) #else http_head(agent, hdrlist, user, pwd, array, local, remote, stdio) char * agent; char ** hdrlist; char * user; char * pwd; char array; char * local; char * remote; int stdio; #endif /* CK_ANSIC */ { char * request = NULL; int i, j, len = 0, hdcnt = 0, rc = 0; int ch; int http_fnd = 0; char buf[HTTPBUFLEN], *p; int nullline; time_t local_t; char passwd[64]; char b64in[128]; char b64out[256]; char * headers[HTTPHEADCNT]; int closecon = 0; int first = 1; if (httpfd == -1) return(-1); if (array) { for (i = 0; i < HTTPHEADCNT; i++) headers[i] = NULL; } len = 9; /* HEAD */ len += strlen(HTTP_VERSION); len += strlen(remote); len += 16; if ( hdrlist ) { for (i = 0; hdrlist[i]; i++) len += strlen(hdrlist[i]) + 2; } len += strlen(http_host_port) + 8; if (agent) len += 13 + strlen(agent); if (user) { if (!pwd) { readpass("Password: ",passwd,64); pwd = passwd; } ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL); j = b8tob64(b64in,strlen(b64in),b64out,256); memset(pwd,0,strlen(pwd)); /* NOT PORTABLE */ if (j < 0) return(-1); b64out[j] = '\0'; len += j + 24; } #ifdef HTTP_CLOSE len += 19; /* Connection: close */ #endif len += 3; /* blank line + null */ request = (char *)malloc(len); if (!request) return(-1); sprintf(request,"HEAD %s %s\r\n",remote,HTTP_VERSION); ckstrncat(request,"Host: ", len); ckstrncat(request,http_host_port, len); ckstrncat(request,"\r\n",len); if (agent) { ckstrncat(request,"User-agent: ",len); ckstrncat(request,agent,len); ckstrncat(request,"\r\n",len); } if (user) { ckstrncat(request,"Authorization: Basic ",len); ckstrncat(request,b64out,len); ckstrncat(request,"\r\n",len); } if ( hdrlist ) { for (i = 0; hdrlist[i]; i++) { ckstrncat(request,hdrlist[i],len); ckstrncat(request,"\r\n",len); } } #ifdef HTTP_CLOSE ckstrncat(request,"Connection: close\r\n",len); #endif ckstrncat(request,"\r\n",len); if ( local && local[0] ) { if (!zopeno(ZOFILE,local,NULL,NULL)) { free(request); return(-1); } } headreq: if (http_tol((CHAR *)request,strlen(request)) < 0) { http_close(); if ( first ) { first--; http_reopen(); goto headreq; } rc = -1; goto headexit; } /* Process the headers */ local_t = time(NULL); nullline = 0; i = 0; while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) { buf[i] = ch; if (buf[i] == 10) { /* found end of line */ if (i > 0 && buf[i-1] == 13) i--; if (i < 1) nullline = 1; buf[i] = '\0'; if (array && !nullline && hdcnt < HTTPHEADCNT) makestr(&headers[hdcnt++],buf); if (!ckstrcmp(buf,"HTTP",4,0)) { http_fnd = 1; j = ckindex(" ",buf,0,0,0); p = &buf[j]; while (isspace(*p)) p++; switch (p[0]) { case '1': /* Informational message */ break; case '2': /* Success */ break; case '3': /* Redirection */ case '4': /* Client failure */ case '5': /* Server failure */ default: /* Unknown */ if (!quiet) printf("Failure: Server reports %s\n",p); rc = -1; } http_set_code_reply(p); } else { if (!ckstrcmp(buf,"Connection:",11,0)) { if ( ckindex("close",buf,11,0,0) != 0 ) closecon = 1; } if ( local && local[0] ) { zsout(ZOFILE,buf); zsout(ZOFILE,"\r\n"); } if (stdio) printf("%s\r\n",buf); } i = 0; } else { i++; } } if (ch < 0 && first) { first--; http_close(); http_reopen(); goto headreq; } if ( http_fnd == 0 ) rc = -1; if (array) http_mkarray(headers,hdcnt,array); headexit: if ( local && local[0] ) zclose(ZOFILE); if (closecon) http_close(); free(request); for (i = 0; i < hdcnt; i++) { if (headers[i]) free(headers[i]); } return(rc); } int #ifdef CK_ANSIC http_index(char * agent, char ** hdrlist, char * user, char * pwd, char array, char * local, char * remote, int stdio) #else http_index(agent, hdrlist, user, pwd, array, local, remote, stdio) char * agent; char ** hdrlist; char * user; char * pwd; char array; char * local; char * remote; int stdio; #endif /* CK_ANSIC */ { char * request = NULL; int i, j, len = 0, hdcnt = 0, rc = 0; int ch; int http_fnd = 0; char buf[HTTPBUFLEN], *p; int nullline; time_t local_t; char passwd[64]; char b64in[128]; char b64out[256]; char * headers[HTTPHEADCNT]; int closecon = 0; int chunked = 0; int zfile = 0; int first = 1; if (httpfd == -1) return(-1); if (array) { for (i = 0; i < HTTPHEADCNT; i++) headers[i] = NULL; } len = 10; /* INDEX */ len += strlen(HTTP_VERSION); len += strlen(remote); len += 16; if ( hdrlist ) { for (i = 0; hdrlist[i]; i++) len += strlen(hdrlist[i]) + 2; } len += strlen(http_host_port) + 8; if (agent) len += 13 + strlen(agent); if (user) { if (!pwd) { readpass("Password: ",passwd,64); pwd = passwd; } ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL); j = b8tob64(b64in,strlen(b64in),b64out,256); memset(pwd,0,strlen(pwd)); if (j < 0) return(-1); b64out[j] = '\0'; len += j + 24; } #ifdef HTTP_CLOSE len += 19; /* Connection: close */ #endif len += 3; /* blank line + null */ request = malloc(len); if (!request) return(-1); sprintf(request,"INDEX %s\r\n",HTTP_VERSION); ckstrncat(request,"Host: ", len); ckstrncat(request,http_host_port, len); ckstrncat(request,"\r\n",len); if (agent) { ckstrncat(request,"User-agent: ",len); ckstrncat(request,agent,len); ckstrncat(request,"\r\n",len); } if (user) { ckstrncat(request,"Authorization: Basic ",len); ckstrncat(request,b64out,len); ckstrncat(request,"\r\n",len); } if ( hdrlist ) { for (i = 0; hdrlist[i]; i++) { ckstrncat(request,hdrlist[i],len); ckstrncat(request,"\r\n",len); } } #ifdef HTTP_CLOSE ckstrncat(request,"Connection: close\r\n",len); #endif ckstrncat(request,"\r\n",len); indexreq: if (http_tol((CHAR *)request,strlen(request)) < 0) { http_close(); if ( first ) { first--; http_reopen(); goto indexreq; } rc = -1; goto indexexit; } /* Process the headers */ local_t = time(NULL); nullline = 0; i = 0; len = -1; while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) { buf[i] = ch; if (buf[i] == 10) { /* found end of line */ if (i > 0 && buf[i-1] == 13) i--; if (i < 1) nullline = 1; buf[i] = '\0'; if (array && !nullline && hdcnt < HTTPHEADCNT) makestr(&headers[hdcnt++],buf); if (!ckstrcmp(buf,"HTTP",4,0)) { http_fnd = 1; j = ckindex(" ",buf,0,0,0); p = &buf[j]; while (isspace(*p)) p++; switch ( p[0] ) { case '1': /* Informational message */ break; case '2': /* Success */ break; case '3': /* Redirection */ case '4': /* Client failure */ case '5': /* Server failure */ default: /* Unknown */ if (!quiet) printf("Failure: Server reports %s\n",p); rc = -1; } http_set_code_reply(p); } else if ( !nullline ) { if (!ckstrcmp(buf,"Connection:",11,0)) { if ( ckindex("close",buf,11,0,0) != 0 ) closecon = 1; } else if (!ckstrcmp(buf,"Content-Length:",15,0)) { len = atoi(&buf[16]); } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) { if ( ckindex("chunked",buf,18,0,0) != 0 ) chunked = 1; debug(F101,"http_index chunked","",chunked); } printf("%s\n",buf); } i = 0; } else { i++; } } if (ch < 0 && first) { first--; http_close(); http_reopen(); goto indexreq; } if ( http_fnd == 0 ) { rc = -1; closecon = 1; goto indexexit; } /* Now we have the contents of the file */ if ( local && local[0] ) { if (zopeno(ZOFILE,local,NULL,NULL)) zfile = 1; else rc = -1; } if ( chunked ) { while ((len = http_get_chunk_len()) > 0) { while (len && (ch = http_inc(0)) >= 0) { len--; if ( zfile ) zchout(ZOFILE,(CHAR)ch); if ( stdio ) conoc((CHAR)ch); } if ((ch = http_inc(0)) != CK_CR) break; if ((ch = http_inc(0)) != LF) break; } } else { while (len && (ch = http_inc(0)) >= 0) { len--; if ( zfile ) zchout(ZOFILE,(CHAR)ch); if ( stdio ) conoc((CHAR)ch); } } if ( zfile ) zclose(ZOFILE); if ( chunked ) { /* Parse Trailing Headers */ nullline = 0; while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) { buf[i] = ch; if ( buf[i] == 10 ) { /* found end of line */ if (i > 0 && buf[i-1] == 13) i--; if (i < 1) nullline = 1; buf[i] = '\0'; if (array && !nullline && hdcnt < HTTPHEADCNT) makestr(&headers[hdcnt++],buf); if (!ckstrcmp(buf,"Connection:",11,0)) { if ( ckindex("close",buf,11,0,0) != 0 ) closecon = 1; } i = 0; } else { i++; } } } rc = 0; indexexit: if (array) http_mkarray(headers,hdcnt,array); if (closecon) http_close(); free(request); for (i = 0; i < hdcnt; i++) { if (headers[i]) free(headers[i]); } return(rc); } int #ifdef CK_ANSIC http_put(char * agent, char ** hdrlist, char * mime, char * user, char * pwd, char array, char * local, char * remote, char * dest, int stdio) #else http_put(agent, hdrlist, mime, user, pwd, array, local, remote, dest, stdio) char * agent; char ** hdrlist; char * mime; char * user; char * pwd; char array; char * local; char * remote; char * dest; int stdio; #endif /* CK_ANSIC */ { char * request=NULL; int i, j, len = 0, hdcnt = 0, rc = 0; int ch; int http_fnd = 0; char buf[HTTPBUFLEN], *p; int nullline; time_t local_t; char passwd[64]; char b64in[128]; char b64out[256]; int filelen; char * headers[HTTPHEADCNT]; int closecon = 0; int chunked = 0; int first = 1; int zfile = 0; if (httpfd == -1) return(-1); if (!mime) mime = ""; if (!remote) remote = ""; if (!local) local = ""; if (!*local) return(-1); if (array) { for (i = 0; i < HTTPHEADCNT; i++) headers[i] = NULL; } filelen = zchki(local); if (filelen < 0) return(-1); /* Compute length of request header */ len = 8; /* PUT */ len += strlen(HTTP_VERSION); len += strlen(remote); len += 16; if ( hdrlist ) { for (i = 0; hdrlist[i]; i++) len += strlen(hdrlist[i]) + 2; } len += strlen(http_host_port) + 8; if (agent) len += 13 + strlen(agent); if (user) { if (!pwd) { readpass("Password: ",passwd,64); pwd = passwd; } ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL); j = b8tob64(b64in,strlen(b64in),b64out,256); memset(pwd,0,strlen(pwd)); if (j < 0) return(-1); b64out[j] = '\0'; len += j + 24; } len += 16 + strlen(mime); /* Content-type: */ len += 32; /* Content-length: */ len += 32; /* Date: */ #ifdef HTTP_CLOSE len += 19; /* Connection: close */ #endif len += 3; /* blank line + null */ request = malloc(len); if (!request) return(-1); sprintf(request,"PUT %s %s\r\n",remote,HTTP_VERSION); ckstrncat(request,"Date: ",len); #ifdef CMDATE2TM ckstrncat(request,http_now(),len); #else ckstrncat(request,...,len); #endif /* CMDATE2TM */ ckstrncat(request,"\r\n",len); ckstrncat(request,"Host: ", len); ckstrncat(request,http_host_port, len); ckstrncat(request,"\r\n",len); if (agent) { ckstrncat(request,"User-agent: ",len); ckstrncat(request,agent,len); ckstrncat(request,"\r\n",len); } if (user) { ckstrncat(request,"Authorization: Basic ",len); ckstrncat(request,b64out,len); ckstrncat(request,"\r\n",len); } if ( hdrlist ) { for (i = 0; hdrlist[i]; i++) { ckstrncat(request,hdrlist[i],len); ckstrncat(request,"\r\n",len); } } ckstrncat(request,"Content-type: ",len); ckstrncat(request,mime,len); ckstrncat(request,"\r\n",len); sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */ ckstrncat(request,buf,len); #ifdef HTTP_CLOSE ckstrncat(request,"Connection: close\r\n",len); #endif ckstrncat(request,"\r\n",len); /* Now we have the contents of the file */ if (zopeni(ZIFILE,local)) { putreq: /* Send request */ if (http_tol((CHAR *)request,strlen(request)) <= 0) { http_close(); if ( first ) { first--; http_reopen(); goto putreq; } zclose(ZIFILE); rc = -1; goto putexit; } /* Request headers have been sent */ i = 0; while (zchin(ZIFILE,&ch) == 0) { buf[i++] = ch; if (i == HTTPBUFLEN) { if (http_tol((CHAR *)buf,HTTPBUFLEN) <= 0) { http_close(); if ( first ) { first--; http_reopen(); goto putreq; } } i = 0; } } if (i > 0) { if (http_tol((CHAR *)buf,i) < 0) { http_close(); if ( first ) { first--; http_reopen(); goto putreq; } } } zclose(ZIFILE); /* Process the response headers */ local_t = time(NULL); nullline = 0; i = 0; len = -1; while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) { buf[i] = ch; if (buf[i] == 10) { /* found end of line */ if (i > 0 && buf[i-1] == 13) i--; if (i < 1) nullline = 1; buf[i] = '\0'; if (array && !nullline && hdcnt < HTTPHEADCNT) makestr(&headers[hdcnt++],buf); if (!ckstrcmp(buf,"HTTP",4,0)) { http_fnd = 1; j = ckindex(" ",buf,0,0,0); p = &buf[j]; while (isspace(*p)) p++; switch (p[0]) { case '1': /* Informational message */ break; case '2': /* Success */ break; case '3': /* Redirection */ case '4': /* Client failure */ case '5': /* Server failure */ default: /* Unknown */ if (!quiet) printf("Failure: Server reports %s\n",p); rc = -1; } http_set_code_reply(p); } else { if (!ckstrcmp(buf,"Connection:",11,0)) { if ( ckindex("close",buf,11,0,0) != 0 ) closecon = 1; } else if (!ckstrcmp(buf,"Content-Length:",15,0)) { len = atoi(&buf[16]); } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) { if ( ckindex("chunked",buf,18,0,0) != 0 ) chunked = 1; debug(F101,"http_put chunked","",chunked); } if ( stdio ) printf("%s\n",buf); } i = 0; } else { i++; } } if (ch < 0 && first) { first--; http_close(); http_reopen(); goto putreq; } if ( http_fnd == 0 ) { closecon = 1; rc = -1; goto putexit; } /* Any response data? */ if ( dest && dest[0] ) { if (zopeno(ZOFILE,dest,NULL,NULL)) zfile = 1; else rc = -1; } if ( chunked ) { while ((len = http_get_chunk_len()) > 0) { while (len && (ch = http_inc(0)) >= 0) { len--; if ( zfile ) zchout(ZOFILE,(CHAR)ch); if ( stdio ) conoc((CHAR)ch); } if ((ch = http_inc(0)) != CK_CR) break; if ((ch = http_inc(0)) != LF) break; } } else { while (len && (ch = http_inc(0)) >= 0) { len--; if ( zfile ) zchout(ZOFILE,(CHAR)ch); if ( stdio ) conoc((CHAR)ch); } } if ( zfile ) zclose(ZOFILE); if ( chunked ) { /* Parse Trailing Headers */ nullline = 0; while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) { buf[i] = ch; if ( buf[i] == 10 ) { /* found end of line */ if (i > 0 && buf[i-1] == 13) i--; if (i < 1) nullline = 1; buf[i] = '\0'; if (array && !nullline && hdcnt < HTTPHEADCNT) makestr(&headers[hdcnt++],buf); if (!ckstrcmp(buf,"Connection:",11,0)) { if ( ckindex("close",buf,11,0,0) != 0 ) closecon = 1; } i = 0; } else { i++; } } } } else { rc = -1; } putexit: if ( array ) http_mkarray(headers,hdcnt,array); if (closecon) http_close(); free(request); for (i = 0; i < hdcnt; i++) { if (headers[i]) free(headers[i]); } return(rc); } int #ifdef CK_ANSIC http_delete(char * agent, char ** hdrlist, char * user, char * pwd, char array, char * remote) #else http_delete(agent, hdrlist, user, pwd, array, remote) char * agent; char ** hdrlist; char * user; char * pwd; char array; char * remote; #endif /* CK_ANSIC */ { char * request=NULL; int i, j, len = 0, hdcnt = 0, rc = 0; int ch; int http_fnd = 0; char buf[HTTPBUFLEN], *p; int nullline; time_t local_t; char passwd[64]; char b64in[128]; char b64out[256]; char * headers[HTTPHEADCNT]; int closecon = 0; int chunked = 0; int first = 1; if (httpfd == -1) return(-1); if (array) { for (i = 0; i < HTTPHEADCNT; i++) headers[i] = NULL; } /* Compute length of request header */ len = 11; /* DELETE */ len += strlen(HTTP_VERSION); len += strlen(remote); len += 16; if ( hdrlist ) { for (i = 0; hdrlist[i]; i++) len += strlen(hdrlist[i]) + 2; } len += strlen(http_host_port) + 8; if (agent) len += 13 + strlen(agent); if (user) { if (!pwd) { readpass("Password: ",passwd,64); pwd = passwd; } ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL); j = b8tob64(b64in,strlen(b64in),b64out,256); memset(pwd,0,strlen(pwd)); if (j < 0) return(-1); b64out[j] = '\0'; len += j + 24; } len += 32; /* Date: */ #ifdef HTTP_CLOSE len += 19; /* Connection: close */ #endif len += 3; /* blank line + null */ request = malloc(len); if (!request) return(-1); sprintf(request,"DELETE %s %s\r\n",remote,HTTP_VERSION); ckstrncat(request,"Date: ",len); #ifdef CMDATE2TM ckstrncat(request,http_now(),len); #else ckstrncat(request,...,len); #endif /* CMDATE2TM */ ckstrncat(request,"\r\n",len); ckstrncat(request,"Host: ", len); ckstrncat(request,http_host_port, len); ckstrncat(request,"\r\n",len); if (agent) { ckstrncat(request,"User-agent: ",len); ckstrncat(request,agent,len); ckstrncat(request,"\r\n",len); } if (user) { ckstrncat(request,"Authorization: Basic ",len); ckstrncat(request,b64out,len); ckstrncat(request,"\r\n",len); } if ( hdrlist ) { for (i = 0; hdrlist[i]; i++) { ckstrncat(request,hdrlist[i],len); ckstrncat(request,"\r\n",len); } } #ifdef HTTP_CLOSE ckstrncat(request,"Connection: close\r\n",len); #endif ckstrncat(request,"\r\n",len); delreq: if (http_tol((CHAR *)request,strlen(request)) < 0) { http_close(); if ( first ) { first--; http_reopen(); goto delreq; } rc = -1; goto delexit; } /* Process the response headers */ local_t = time(NULL); nullline = 0; i = 0; len = -1; while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) { buf[i] = ch; if (buf[i] == 10) { /* found end of line */ if (i > 0 && buf[i-1] == 13) i--; if (i < 1) nullline = 1; buf[i] = '\0'; if (array && !nullline && hdcnt < HTTPHEADCNT) makestr(&headers[hdcnt++],buf); if (!ckstrcmp(buf,"HTTP",4,0)) { http_fnd = 1; j = ckindex(" ",buf,0,0,0); p = &buf[j]; while (isspace(*p)) p++; switch (p[0]) { case '1': /* Informational message */ break; case '2': /* Success */ break; case '3': /* Redirection */ case '4': /* Client failure */ case '5': /* Server failure */ default: /* Unknown */ if (!quiet) printf("Failure: Server reports %s\n",p); rc = -1; } http_set_code_reply(p); } else { if (!ckstrcmp(buf,"Connection:",11,0)) { if ( ckindex("close",buf,11,0,0) != 0 ) closecon = 1; } else if (!ckstrcmp(buf,"Content-Length:",15,0)) { len = atoi(&buf[16]); } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) { if ( ckindex("chunked",buf,18,0,0) != 0 ) chunked = 1; debug(F101,"http_delete chunked","",chunked); } printf("%s\n",buf); } i = 0; } else { i++; } } if (ch < 0 && first) { first--; http_close(); http_reopen(); goto delreq; } if ( http_fnd == 0 ) { rc = -1; closecon = 1; goto delexit; } /* Any response data? */ if ( chunked ) { while ((len = http_get_chunk_len()) > 0) { while (len && (ch = http_inc(0)) >= 0) { len--; conoc((CHAR)ch); } if ((ch = http_inc(0)) != CK_CR) break; if ((ch = http_inc(0)) != LF) break; } } else { while (len && (ch = http_inc(0)) >= 0) { len--; conoc((CHAR)ch); } } if ( chunked ) { /* Parse Trailing Headers */ nullline = 0; while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) { buf[i] = ch; if ( buf[i] == 10 ) { /* found end of line */ if (i > 0 && buf[i-1] == 13) i--; if (i < 1) nullline = 1; buf[i] = '\0'; if (array && !nullline && hdcnt < HTTPHEADCNT) makestr(&headers[hdcnt++],buf); if (!ckstrcmp(buf,"Connection:",11,0)) { if ( ckindex("close",buf,11,0,0) != 0 ) closecon = 1; } i = 0; } else { i++; } } } delexit: if (array) http_mkarray(headers,hdcnt,array); if (closecon) http_close(); free(request); for (i = 0; i < hdcnt; i++) { if (headers[i]) free(headers[i]); } return(rc); } int #ifdef CK_ANSIC http_post(char * agent, char ** hdrlist, char * mime, char * user, char * pwd, char array, char * local, char * remote, char * dest, int stdio) #else http_post(agent, hdrlist, mime, user, pwd, array, local, remote, dest, stdio) char * agent; char ** hdrlist; char * mime; char * user; char * pwd; char array; char * local; char * remote; char * dest; int stdio; #endif /* CK_ANSIC */ { char * request=NULL; int i, j, len = 0, hdcnt = 0, rc = 0; int ch; int http_fnd = 0; char buf[HTTPBUFLEN], *p; int nullline; time_t local_t; char passwd[64]; char b64in[128]; char b64out[256]; int filelen; char * headers[HTTPHEADCNT]; int closecon = 0; int chunked = 0; int zfile = 0; int first = 1; if (httpfd == -1) return(-1); if (array) { for (i = 0; i < HTTPHEADCNT; i++) headers[i] = NULL; } filelen = zchki(local); if (filelen < 0) return(-1); /* Compute length of request header */ len = 9; /* POST */ len += strlen(HTTP_VERSION); len += strlen(remote); len += 16; if ( hdrlist ) { for (i = 0; hdrlist[i]; i++) len += strlen(hdrlist[i]) + 2; } len += strlen(http_host_port) + 8; if (agent) len += 13 + strlen(agent); if (user) { if (!pwd) { readpass("Password: ",passwd,64); pwd = passwd; } ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL); j = b8tob64(b64in,strlen(b64in),b64out,256); memset(pwd,0,strlen(pwd)); if (j < 0) return(-1); b64out[j] = '\0'; len += j + 24; } len += 16 + strlen(mime); /* Content-type: */ len += 32; /* Content-length: */ len += 32; /* Date: */ #ifdef HTTP_CLOSE len += 19; /* Connection: close */ #endif len += 3; /* blank line + null */ request = malloc(len); if (!request) return(-1); sprintf(request,"POST %s %s\r\n",remote,HTTP_VERSION); ckstrncat(request,"Date: ",len); ckstrncat(request,http_now(),len); ckstrncat(request,"\r\n",len); ckstrncat(request,"Host: ", len); ckstrncat(request,http_host_port, len); ckstrncat(request,"\r\n",len); if (agent) { ckstrncat(request,"User-agent: ",len); ckstrncat(request,agent,len); ckstrncat(request,"\r\n",len); } if (user) { ckstrncat(request,"Authorization: Basic ",len); ckstrncat(request,b64out,len); ckstrncat(request,"\r\n",len); } if ( hdrlist ) { for (i = 0; hdrlist[i]; i++) { ckstrncat(request,hdrlist[i],len); ckstrncat(request,"\r\n",len); } } ckstrncat(request,"Content-type: ",len); ckstrncat(request,mime,len); ckstrncat(request,"\r\n",len); #ifdef HTTP_CLOSE ckstrncat(request,"Connection: close\r\n",len); #endif sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */ ckstrncat(request,buf,len); ckstrncat(request,"\r\n",len); #ifdef COMMENT /* This is apparently a mistake - the previous ckstrncat() already */ /* appended a blank line to the request. There should only be one. */ /* Servers are not required by RFC 2616 to ignore extraneous empty */ /* lines. -fdc, 28 Aug 2005. */ ckstrncat(request,"\r\n",len); #endif /* COMMENT */ /* Now we have the contents of the file */ postopen: if (zopeni(ZIFILE,local)) { postreq: if (http_tol((CHAR *)request,strlen(request)) < 0) { http_close(); if ( first ) { first--; http_reopen(); goto postreq; } rc = -1; zclose(ZIFILE); goto postexit; } i = 0; while (zchin(ZIFILE,&ch) == 0) { buf[i++] = ch; if (i == HTTPBUFLEN) { http_tol((CHAR *)buf,HTTPBUFLEN); i = 0; } } if (i > 0) http_tol((CHAR *)buf,HTTPBUFLEN); zclose(ZIFILE); /* Process the response headers */ local_t = time(NULL); nullline = 0; i = 0; len = -1; while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) { buf[i] = ch; if (buf[i] == 10) { /* found end of line */ if (i > 0 && buf[i-1] == 13) i--; if (i < 1) nullline = 1; buf[i] = '\0'; if (array && !nullline && hdcnt < HTTPHEADCNT) makestr(&headers[hdcnt++],buf); if (!ckstrcmp(buf,"HTTP",4,0)) { http_fnd = 1; j = ckindex(" ",buf,0,0,0); p = &buf[j]; while (isspace(*p)) p++; switch (p[0]) { case '1': /* Informational message */ break; case '2': /* Success */ break; case '3': /* Redirection */ case '4': /* Client failure */ case '5': /* Server failure */ default: /* Unknown */ if (!quiet) printf("Failure: Server reports %s\n",p); rc = -1; } http_set_code_reply(p); } else { if (!ckstrcmp(buf,"Connection:",11,0)) { if ( ckindex("close",buf,11,0,0) != 0 ) closecon = 1; } else if (!ckstrcmp(buf,"Content-Length:",15,0)) { len = atoi(&buf[16]); } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) { if ( ckindex("chunked",buf,18,0,0) != 0 ) chunked = 1; debug(F101,"http_post chunked","",chunked); } if (stdio) printf("%s\n",buf); } i = 0; } else { i++; } } if (ch < 0 && first) { first--; http_close(); http_reopen(); goto postopen; } if (http_fnd == 0) { rc = -1; closecon = 1; goto postexit; } /* Any response data? */ if ( dest && dest[0] ) { if (zopeno(ZOFILE,dest,NULL,NULL)) zfile = 1; else rc = -1; } if ( chunked ) { while ((len = http_get_chunk_len()) > 0) { while (len && (ch = http_inc(0)) >= 0) { len--; if ( zfile ) zchout(ZOFILE,(CHAR)ch); if ( stdio ) conoc((CHAR)ch); } if ((ch = http_inc(0)) != CK_CR) break; if ((ch = http_inc(0)) != LF) break; } } else { while (len && (ch = http_inc(0)) >= 0) { len--; if ( zfile ) zchout(ZOFILE,(CHAR)ch); if ( stdio ) conoc((CHAR)ch); } } if ( zfile ) zclose(ZOFILE); if ( chunked ) { /* Parse Trailing Headers */ nullline = 0; while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) { buf[i] = ch; if ( buf[i] == 10 ) { /* found end of line */ if (i > 0 && buf[i-1] == 13) i--; if (i < 1) nullline = 1; buf[i] = '\0'; if (array && !nullline && hdcnt < HTTPHEADCNT) makestr(&headers[hdcnt++],buf); if (!ckstrcmp(buf,"Connection:",11,0)) { if ( ckindex("close",buf,11,0,0) != 0 ) closecon = 1; } i = 0; } else { i++; } } } } else { rc = -1; } postexit: if (array) http_mkarray(headers,hdcnt,array); if (closecon) http_close(); free(request); for (i = 0; i < hdcnt; i++) { if (headers[i]) free(headers[i]); } return(rc); } int #ifdef CK_ANSIC http_connect(int socket, char * agent, char ** hdrlist, char * user, char * pwd, char array, char * host_port) #else http_connect(socket, agent, hdrlist, user, pwd, array, host_port) int socket; char * agent; char ** hdrlist; char * user; char * pwd; char array; char * host_port; #endif /* CK_ANSIC */ { char * request=NULL; int i, j, len = 0, hdcnt = 0, rc = 0; int http_fnd = 0; char buf[HTTPBUFLEN], *p, ch; int nullline; time_t local_t; char passwd[64]; char b64in[128]; char b64out[256]; char * headers[HTTPHEADCNT]; int connected = 0; tcp_http_proxy_errno = 0; if (socket == -1) return(-1); if (array) { for (i = 0; i < HTTPHEADCNT; i++) headers[i] = NULL; } /* Compute length of request header */ len = 12; /* CONNECT */ len += strlen(HTTP_VERSION); len += strlen(host_port); len += (int) strlen(http_host_port) + 8; len += 16; len += strlen("Proxy-Connection: Keep-Alive\r\n"); if ( hdrlist ) { for (i = 0; hdrlist[i]; i++) len += strlen(hdrlist[i]) + 2; } if (agent && agent[0]) len += 13 + strlen(agent); if (user && user[0]) { if (!pwd) { readpass("Password: ",passwd,64); pwd = passwd; } ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL); j = b8tob64(b64in,strlen(b64in),b64out,256); memset(pwd,0,strlen(pwd)); if (j < 0) return(-1); b64out[j] = '\0'; len += j + 72; } len += 32; /* Date: */ len += 3; /* blank line + null */ request = malloc(len); if (!request) return(-1); sprintf(request,"CONNECT %s %s\r\n",host_port,HTTP_VERSION); ckstrncat(request,"Date: ",len); #ifdef CMDATE2TM ckstrncat(request,http_now(),len); #else strcat(request,...); #endif /* CMDATE2TM */ ckstrncat(request,"\r\n",len); ckstrncat(request,"Host: ", len); ckstrncat(request,http_host_port, len); ckstrncat(request,"\r\n",len); if (agent && agent[0]) { ckstrncat(request,"User-agent: ",len); ckstrncat(request,agent,len); ckstrncat(request,"\r\n",len); } if (user && user[0]) { ckstrncat(request,"Proxy-authorization: Basic ",len); ckstrncat(request,b64out,len); ckstrncat(request,"\r\n",len); ckstrncat(request,"Extension: Security/Remote-Passphrase\r\n",len); } ckstrncat(request,"Proxy-Connection: Keep-Alive\r\n",len); if ( hdrlist ) { for (i = 0; hdrlist[i]; i++) { ckstrncat(request,hdrlist[i],len); ckstrncat(request,"\r\n",len); } } ckstrncat(request,"\r\n",len); len = strlen(request); #ifdef TCPIPLIB /* Send request */ if (socket_write(socket,(CHAR *)request,strlen(request)) < 0) { rc = -1; goto connexit; } #else if (write(socket,(CHAR *)request,strlen(request)) < 0) { /* Send request */ rc = -1; goto connexit; } #endif /* TCPIPLIB */ /* Process the response headers */ local_t = time(NULL); nullline = 0; i = 0; while (!nullline && #ifdef TCPIPLIB (socket_read(socket,&ch,1) == 1) && #else (read(socket,&ch,1) == 1) && #endif /* TCPIPLIB */ i < HTTPBUFLEN) { buf[i] = ch; if (buf[i] == 10) { /* found end of line */ if (i > 0 && buf[i-1] == 13) i--; if (i < 1) nullline = 1; buf[i] = '\0'; if (array && !nullline && hdcnt < HTTPHEADCNT) makestr(&headers[hdcnt++],buf); if (!ckstrcmp(buf,"HTTP",4,0)) { http_fnd = 1; j = ckindex(" ",buf,0,0,0); p = &buf[j]; while (isspace(*p)) p++; tcp_http_proxy_errno = atoi(p); switch (p[0]) { case '1': /* Informational message */ break; case '2': /* Success */ connected = 1; break; case '3': /* Redirection */ case '4': /* Client failure */ case '5': /* Server failure */ default: /* Unknown */ if (!quiet) printf("Failure: Server reports %s\n",p); rc = -1; } http_set_code_reply(p); } else { printf("%s\n",buf); } i = 0; } else { i++; } } if ( http_fnd == 0 ) rc = -1; if (array) http_mkarray(headers,hdcnt,array); connexit: if ( !connected ) { if ( socket == ttyfd ) { ttclos(0); } else if ( socket == httpfd ) { http_close(); } } free(request); for (i = 0; i < hdcnt; i++) { if (headers[i]) free(headers[i]); } return(rc); } #endif /* NOHTTP */ #ifdef CK_DNS_SRV #define INCR_CHECK(x,y) x += y; if (x > size + answer.bytes) goto dnsout #define CHECK(x,y) if (x + y > size + answer.bytes) goto dnsout #define NTOHSP(x,y) x[0] << 8 | x[1]; x += y #ifndef CKQUERYTYPE #ifdef UNIXWARE #ifndef UW7 #define CKQUERYTYPE CHAR #endif /* UW7 */ #endif /* UNIXWARE */ #endif /* CKQUERYTYPE */ #ifndef CKQUERYTYPE #define CKQUERYTYPE char #endif /* CKQUERYTYPE */ /* 1 is success, 0 is failure */ int #ifdef CK_ANSIC locate_srv_dns(char *host, char *service, char *protocol, struct sockaddr **addr_pp, int *naddrs ) #else locate_srv_dns(host, service, protocol, addr_pp, naddrs) char *host; char *service; char *protocol; struct sockaddr **addr_pp; int *naddrs; #endif /* CK_ANSIC */ { int nout, j, count; union { unsigned char bytes[2048]; HEADER hdr; } answer; unsigned char *p=NULL; CKQUERYTYPE query[MAX_DNS_NAMELEN]; #ifdef CK_ANSIC const char * h; #else char * h; #endif /* CK_ANSIC */ struct sockaddr *addr = NULL; struct sockaddr_in *sin = NULL; struct hostent *hp = NULL; int type, class; int priority, weight, size, len, numanswers, numqueries, rdlen; unsigned short port; #ifdef CK_ANSIC const #endif /* CK_ANSIC */ int hdrsize = sizeof(HEADER); struct srv_dns_entry { struct srv_dns_entry *next; int priority; int weight; unsigned short port; char *host; }; struct srv_dns_entry *head = NULL; struct srv_dns_entry *srv = NULL, *entry = NULL; char * s = NULL; nout = 0; addr = (struct sockaddr *) malloc(sizeof(struct sockaddr)); if (addr == NULL) return 0; count = 1; /* * First build a query of the form: * * service.protocol.host * * which will most likely be something like: * * _telnet._tcp.host * */ if (((int)strlen(service) + strlen(protocol) + strlen(host) + 5) > MAX_DNS_NAMELEN ) goto dnsout; /* Realm names don't (normally) end with ".", but if the query doesn't end with "." and doesn't get an answer as is, the resolv code will try appending the local domain. Since the realm names are absolutes, let's stop that. But only if a name has been specified. If we are performing a search on the prefix alone then the intention is to allow the local domain or domain search lists to be expanded. */ h = host + strlen (host); ckmakxmsg(query, sizeof(query), "_",service,"._",protocol,".", host, ((h > host) && (h[-1] != '.')?".":NULL), NULL,NULL,NULL,NULL,NULL); size = res_search(query, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes)); if (size < hdrsize) goto dnsout; /* We got a reply - See how many answers it contains. */ p = answer.bytes; numqueries = ntohs(answer.hdr.qdcount); numanswers = ntohs(answer.hdr.ancount); p += sizeof(HEADER); /* * We need to skip over all of the questions, so we have to iterate * over every query record. dn_expand() is able to tell us the size * of compressed DNS names, so we use it. */ while (numqueries--) { len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query)); if (len < 0) goto dnsout; INCR_CHECK(p, len + 4); } /* * We're now pointing at the answer records. Only process them if * they're actually T_SRV records (they might be CNAME records, * for instance). * * But in a DNS reply, if you get a CNAME you always get the associated * "real" RR for that CNAME. RFC 1034, 3.6.2: * * CNAME RRs cause special action in DNS software. When a name server * fails to find a desired RR in the resource set associated with the * domain name, it checks to see if the resource set consists of a CNAME * record with a matching class. If so, the name server includes the CNAME * record in the response and restarts the query at the domain name * specified in the data field of the CNAME record. The one exception to * this rule is that queries which match the CNAME type are not restarted. * * In other words, CNAMEs do not need to be expanded by the client. */ while (numanswers--) { /* First is the name; use dn_expand() to get the compressed size. */ len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query)); if (len < 0) goto dnsout; INCR_CHECK(p, len); CHECK(p,2); /* Query type */ type = NTOHSP(p,2); CHECK(p, 6); /* Query class */ class = NTOHSP(p,6); /* Also skip over 4-byte TTL */ CHECK(p,2); /* Record data length */ rdlen = NTOHSP(p,2); /* * If this is an SRV record, process it. Record format is: * * Priority * Weight * Port * Server name */ if (class == C_IN && type == T_SRV) { CHECK(p,2); priority = NTOHSP(p,2); CHECK(p, 2); weight = NTOHSP(p,2); CHECK(p, 2); port = NTOHSP(p,2); len = dn_expand(answer. bytes, answer.bytes + size, p, query, sizeof(query) ); if (len < 0) goto dnsout; INCR_CHECK(p, len); /* * We got everything. Insert it into our list, but make sure * it's in the right order. Right now we don't do anything * with the weight field */ srv = (struct srv_dns_entry *)malloc(sizeof(struct srv_dns_entry)); if (srv == NULL) goto dnsout; srv->priority = priority; srv->weight = weight; srv->port = port; makestr(&s,(char *)query); /* strdup() is not portable */ srv->host = s; if (head == NULL || head->priority > srv->priority) { srv->next = head; head = srv; } else /* * Confusing. Insert an entry into this spot only if: * . The next person has a higher priority (lower * priorities are preferred), or: * . There is no next entry (we're at the end) */ for (entry = head; entry != NULL; entry = entry->next) if ((entry->next && entry->next->priority > srv->priority) || entry->next == NULL) { srv->next = entry->next; entry->next = srv; break; } } else INCR_CHECK(p, rdlen); } /* * Now we've got a linked list of entries sorted by priority. * Start looking up A records and returning addresses. */ if (head == NULL) goto dnsout; for (entry = head; entry != NULL; entry = entry->next) { hp = gethostbyname(entry->host); if (hp != 0) { /* Watch out - memset() and memcpy() are not portable... */ switch (hp->h_addrtype) { case AF_INET: for (j = 0; hp->h_addr_list[j]; j++) { sin = (struct sockaddr_in *) &addr[nout++]; memset ((char *) sin, 0, sizeof (struct sockaddr)); sin->sin_family = hp->h_addrtype; sin->sin_port = htons(entry->port); memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[j], sizeof(struct in_addr)); /* safe */ if (nout + 1 >= count) { count += 5; addr = (struct sockaddr *) realloc((char *) addr, sizeof(struct sockaddr) * count); if (!addr) goto dnsout; } } break; default: break; } } } for (entry = head; entry != NULL;) { free(entry->host); entry->host = NULL; srv = entry; entry = entry->next; free(srv); srv = NULL; } dnsout: if (srv) free(srv); if (nout == 0) { /* No good servers */ if (addr) free(addr); return 0; } *addr_pp = addr; *naddrs = nout; return 1; } #undef INCR_CHECK #undef CHECK #undef NTOHSP #define INCR_CHECK(x, y) x += y; if (x > size + answer.bytes) \ return 0 #define CHECK(x, y) if (x + y > size + answer.bytes) \ return 0 #define NTOHSP(x, y) x[0] << 8 | x[1]; x += y int #ifdef CK_ANSIC locate_txt_rr( char *prefix, char *name, char **retstr ) #else locate_txt_rr(prefix, name, retstr) char *prefix, *name; char **retstr; #endif /* CK_ANSIC */ { union { unsigned char bytes[2048]; HEADER hdr; } answer; unsigned char *p; char host[MAX_DNS_NAMELEN], *h; int size; int type, class, numanswers, numqueries, rdlen, len; /* * Form our query, and send it via DNS */ if (name == NULL || name[0] == '\0') { strcpy(host,prefix); } else { if ( strlen(prefix) + strlen(name) + 3 > MAX_DNS_NAMELEN ) return 0; /* Realm names don't (normally) end with ".", but if the query doesn't end with "." and doesn't get an answer as is, the resolv code will try appending the local domain. Since the realm names are absolutes, let's stop that. But only if a name has been specified. If we are performing a search on the prefix alone then the intention is to allow the local domain or domain search lists to be expanded. */ h = host + strlen (host); ckmakmsg(host,sizeof(host),prefix, ".", name, ((h > host) && (h[-1] != '.'))?".":NULL); } size = res_search(host, C_IN, T_TXT, answer.bytes, sizeof(answer.bytes)); if (size < 0) return 0; p = answer.bytes; numqueries = ntohs(answer.hdr.qdcount); numanswers = ntohs(answer.hdr.ancount); p += sizeof(HEADER); /* * We need to skip over the questions before we can get to the answers, * which means we have to iterate over every query record. We use * dn_expand to tell us how long each compressed name is. */ while (numqueries--) { len = dn_expand(answer.bytes, answer.bytes + size, p, host, sizeof(host)); if (len < 0) return 0; INCR_CHECK(p, len + 4); /* Name plus type plus class */ } /* * We're now pointing at the answer records. Process the first * TXT record we find. */ while (numanswers--) { /* First the name; use dn_expand to get the compressed size */ len = dn_expand(answer.bytes, answer.bytes + size, p, host, sizeof(host)); if (len < 0) return 0; INCR_CHECK(p, len); /* Next is the query type */ CHECK(p, 2); type = NTOHSP(p,2); /* Next is the query class; also skip over 4 byte TTL */ CHECK(p,6); class = NTOHSP(p,6); /* Record data length - make sure we aren't truncated */ CHECK(p,2); rdlen = NTOHSP(p,2); if (p + rdlen > answer.bytes + size) return 0; /* * If this is a TXT record, return the string. Note that the * string has a 1-byte length in the front */ /* XXX What about flagging multiple TXT records as an error? */ if (class == C_IN && type == T_TXT) { len = *p++; if (p + len > answer.bytes + size) return 0; *retstr = malloc(len + 1); if (*retstr == NULL) return ENOMEM; strncpy(*retstr, (char *) p, len); (*retstr)[len] = '\0'; /* Avoid a common error. */ if ( (*retstr)[len-1] == '.' ) (*retstr)[len-1] = '\0'; return 1; } } return 0; } #undef INCR_CHECK #undef CHECK #undef NTOHSP #endif /* CK_DNS_SRV */ #ifdef TNCODE #ifdef CK_FORWARD_X #ifdef UNIX #include #define FWDX_UNIX_SOCK #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX #endif #ifndef PF_LOCAL #define PF_LOCAL PF_UNIX #endif #ifndef SUN_LEN /* Evaluate to actual length of the `sockaddr_un' structure. */ #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \ + strlen ((ptr)->sun_path)) #endif #endif /* UNIX */ #ifdef CK_ANSIC /* prototypes for static functions - fdc 30 November 2022 */ static SIGTYP rlogoobh( int ); static int rlog_oob( CHAR *, int ); #endif /* CK_ANSIC */ #include "ckcfnp.h" /* Prototypes (must be last) */ int #ifdef CK_ANSIC fwdx_create_listen_socket(int screen) #else fwdx_create_listen_socket(screen) int screen; #endif /* CK_ANSIC */ { #ifdef NOPUTENV return(-1); #else /* NOPUTENV */ struct sockaddr_in saddr; int display, port, sock=-1, i; static char env[512]; /* * X Windows Servers support multiple displays by listening on * one socket per display. Display 0 is port 6000; Display 1 is * port 6001; etc. * * We start by trying to open port 6001 so that display 0 is * reserved for the local X Windows Server. */ for ( display=1; display < 1000 ; display++ ) { if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { debug(F111,"fwdx_create_listen_socket()","socket() < 0",sock); return(-1); } port = 6000 + display; bzero((char *)&saddr, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = inet_addr(myipaddr); saddr.sin_port = htons(port); if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { i = errno; /* Save error code */ #ifdef TCPIPLIB socket_close(sock); #else /* TCPIPLIB */ close(sock); #endif /* TCPIPLIB */ sock = -1; debug(F110,"fwdx_create_listen_socket()","bind() < 0",0); continue; } debug(F100,"fdwx_create_listen_socket() bind OK","",0); break; } if ( display > 1000 ) { debug(F100,"fwdx_create_listen_socket() Out of Displays","",0); return(-1); } if (listen(sock, 5) < 0) { i = errno; /* Save error code */ #ifdef TCPIPLIB socket_close(sock); #else /* TCPIPLIB */ close(sock); #endif /* TCPIPLIB */ debug(F101,"fdwx_create_listen_socket() listen() errno","",errno); return(-1); } debug(F100,"fwdx_create_listen_socket() listen OK","",0); TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = sock; if (!myipaddr[0]) getlocalipaddr(); if ( myipaddr[0] ) ckmakxmsg(env,sizeof(env),"DISPLAY=",myipaddr,":", ckuitoa(display),":",ckuitoa(screen), NULL,NULL,NULL,NULL,NULL,NULL); else ckmakmsg(env,sizeof(env),"DISPLAY=",ckuitoa(display),":", ckuitoa(screen)); putenv(env); return(0); #endif /* NOPUTENV */ } int #ifdef CK_ANSIC fwdx_open_client_channel(int channel) #else fwdx_open_client_channel(channel) int channel; #endif /* CK_ANSIC */ { char * env; struct sockaddr_in saddr; #ifdef FWDX_UNIX_SOCK struct sockaddr_un saddr_un = { AF_LOCAL }; #endif /* FWDX_UNIX_SOCK */ int display, port, sock, i, screen; int family; char buf[256], * host=NULL, * rest=NULL; #ifdef TCP_NODELAY int on=1; #endif /* TCP_NODELAY */ debug(F111,"fwdx_create_client_channel()","channel",channel); for ( i=0; i */ if (!(host->h_addr_list)) return(-1); bcopy(host->h_addr_list[0], (caddr_t)&saddr.sin_addr, host->h_length ); #else bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length); #endif /* h_addr */ #else /* HADDRLIST */ bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length); #endif /* HADDRLIST */ } if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { debug(F111,"fwdx_create_client_channel()","socket() < 0",sock); return(-1); } if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { debug(F110,"fwdx_create_client_channel()","connect() failed",0); #ifdef TCPIPLIB socket_close(sock); #else /* TCPIPLIB */ close(sock); #endif /* TCPIPLIB */ return(-1); } #ifdef TCP_NODELAY setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on)); #endif /* TCP_NODELAY */ } for (i = 0; i < MAXFWDX; i++) { if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == -1) { TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = sock; TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = channel; TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 1; debug(F111,"fwdx_create_client_channel()","socket",sock); return(0); } } return(-1); } int fwdx_server_avail() { char * env; struct sockaddr_in saddr; #ifdef FWDX_UNIX_SOCK struct sockaddr_un saddr_un = { AF_LOCAL }; #endif /* FWDX_UNIX_SOCK */ int display, port, sock, screen; char buf[256], *host=NULL, *rest=NULL; int family; env = getenv("DISPLAY"); if ( !env ) env = (char *)tn_get_display(); if ( env ) ckstrncpy(buf,env,256); else ckstrncpy(buf,"127.0.0.1:0.0",256); bzero((char *)&saddr,sizeof(saddr)); saddr.sin_family = AF_INET; if (!fwdx_parse_displayname(buf,&family,&host,&display,&screen,&rest)) { if ( host ) free(host); if ( rest ) free(rest); return(0); } if (rest) free(rest); #ifndef FWDX_UNIX_SOCK /* if $DISPLAY indicates use of unix domain sockets, but we don't support it, * we change things to use inet sockets on the ip loopback interface instead, * and hope that it works. */ if (family == FamilyLocal) { family = FamilyInternet; if (host) free(host); if (host = malloc(strlen("localhost") + 1)) strcpy(host, "localhost"); else { return(-1); } } #else /* FWDX_UNIX_SOCK */ if (family == FamilyLocal) { debug(F100,"fwdx_server_avail() FamilyLocal","",0); if (host) free(host); sock = socket(PF_LOCAL, SOCK_STREAM, 0); if (sock < 0) return(0); ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL); strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path)); if (connect(sock,(struct sockaddr *)&saddr_un,SUN_LEN(&saddr_un)) < 0) return(0); close(sock); return(1); } #endif /* FWDX_UNIX_SOCK */ /* Otherwise, we are assuming FamilyInternet */ if (host) { ckstrncpy(buf,host,sizeof(buf)); free(host); } else ckstrncpy(buf,myipaddr,sizeof(buf)); debug(F111,"fwdx_server_avail()","display",display); port = 6000 + display; saddr.sin_port = htons(port); debug(F110,"fwdx_server_avail() ip-address",buf,0); saddr.sin_addr.s_addr = inet_addr(buf); if ( saddr.sin_addr.s_addr == (ADDR_TYPE) -1 #ifdef INADDR_NONE || saddr.sin_addr.s_addr == INADDR_NONE #endif /* INADDR_NONE */ ) { struct hostent *host; host = gethostbyname(buf); if ( host == NULL ) { debug(F110,"fwdx_server_avail() gethostbyname() failed", myipaddr,0); return(-1); } host = ck_copyhostent(host); #ifdef HADDRLIST #ifdef h_addr /* This is for trying multiple IP addresses - see */ if (!(host->h_addr_list)) return(-1); bcopy(host->h_addr_list[0], (caddr_t)&saddr.sin_addr, host->h_length ); #else bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length); #endif /* h_addr */ #else /* HADDRLIST */ bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length); #endif /* HADDRLIST */ } if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { debug(F111,"fwdx_server_avail()","socket() < 0",sock); return(0); } if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { debug(F110,"fwdx_server_avail()","connect() failed",0); #ifdef TCPIPLIB socket_close(sock); #else /* TCPIPLIB */ close(sock); #endif /* TCPIPLIB */ return(0); } #ifdef TCPIPLIB socket_close(sock); #else /* TCPIPLIB */ close(sock); #endif /* TCPIPLIB */ return(1); } int fwdx_open_server_channel() { int sock, ready_to_accept, sock2,channel; #ifdef TCP_NODELAY int on=1; #endif /* TCP_NODELAY */ #ifdef UCX50 static u_int saddrlen; #else static SOCKOPT_T saddrlen; #endif /* UCX50 */ struct sockaddr_in saddr; extern char tn_msg[]; #ifdef BSDSELECT fd_set rfds; struct timeval tv; #else #ifdef BELLSELCT fd_set rfds; #else fd_set rfds; struct timeval { long tv_sec; long tv_usec; } tv; #endif /* BELLSELECT */ #endif /* BSDSELECT */ sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket; try_again: #ifdef BSDSELECT tv.tv_sec = tv.tv_usec = 0L; tv.tv_usec = 50; FD_ZERO(&rfds); FD_SET(sock, &rfds); ready_to_accept = ((select(FD_SETSIZE, #ifdef HPUX #ifdef HPUX1010 (fd_set *) #else (int *) #endif /* HPUX1010 */ #else #ifdef __DECC (fd_set *) #endif /* __DECC */ #endif /* HPUX */ &rfds, NULL, NULL, &tv) > 0) && FD_ISSET(sock, &rfds)); #else /* BSDSELECT */ #ifdef IBMSELECT ready_to_accept = (select(&sock, 1, 0, 0, 50) == 1); #else #ifdef BELLSELECT FD_ZERO(rfds); FD_SET(sock, rfds); ready_to_accept = ((select(128, rfds, NULL, NULL, 50) > 0) && FD_ISSET(sock, rfds)); #else /* Try this - what's the worst that can happen... */ tv.tv_sec = tv.tv_usec = 0L; tv.tv_usec = 50; FD_ZERO(&rfds); FD_SET(sock, &rfds); ready_to_accept = ((select(FD_SETSIZE, (fd_set *) &rfds, NULL, NULL, &tv) > 0) && FD_ISSET(sock, &rfds)); #endif /* BELLSELECT */ #endif /* IBMSELECT */ #endif /* BSDSELECT */ if ( !ready_to_accept ) return(0); if ((sock2 = accept(sock,(struct sockaddr *)&saddr,&saddrlen)) < 0) { int i = errno; /* save error code */ debug(F101,"tcpsrv_open accept errno","",i); return(-1); } /* * Now we have the open socket. We must now find a channel to store * it in, and then notify the client. */ for ( channel=0;channel 0) { data += count; len -= count; } debug(F111,"fwdx_write_data_to_channel retry",data,len); if ( len > 0 ) goto fwdx_write_data_to_channel_retry; } debug(F111,"fwdx_write_data_to_channel complete",data,length); return(length); /* success - return total length */ } VOID fwdx_check_sockets(fd_set *ibits) { int x, sock, channel, bytes; static char buffer[32000]; debug(F100,"fwdx_check_sockets()","",0); if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) || !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) { debug(F110,"fwdx_check_sockets()","TELOPT_FORWARD_X not negotiated",0); return; } for (x = 0; x < MAXFWDX; x++) { if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd == -1 || TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend ) continue; sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd; if (FD_ISSET(sock, ibits)) { channel = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id; debug(F111,"fwdx_check_sockets()","channel set",channel); bytes = socket_read(sock, buffer, sizeof(buffer)); if (bytes > 0) fwdx_send_data_from_channel(channel, buffer, bytes); else if (bytes == 0) { fwdx_close_channel(channel); fwdx_send_close(channel); } } } } int fwdx_init_fd_set(fd_set *ibits) { int x,set=0,cnt=0; if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) || !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) { debug(F110,"fwdx_init_fd_set()","TELOPT_FORWARD_X not negotiated",0); return(0); } if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1) { set++; FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket, ibits); } for (x = 0; x < MAXFWDX; x++) { if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) { cnt++; if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend) continue; set++; FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd, ibits); } } if (set + cnt == 0) { return(-1); } else { return(set); } } #ifdef NT VOID fwdx_thread( VOID * dummy ) { fd_set ifds; struct timeval tv; extern int priority; int n; setint(); SetThreadPrty(priority,isWin95() ? 3 : 11); while ( !sstelnet && TELOPT_U(TELOPT_FORWARD_X) || sstelnet && TELOPT_ME(TELOPT_FORWARD_X)) { FD_ZERO(&ifds); n = fwdx_init_fd_set(&ifds); if (n > 0) { tv.tv_sec = 0; tv.tv_usec = 2500; if ( select(FD_SETSIZE, &ifds, NULL, NULL, &tv) > 0 ) fwdx_check_sockets(&ifds); } else if (n < 0) { TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0; ckThreadEnd(NULL); } else { sleep(1); } } } #endif /* NT */ #endif /* CK_FORWARD_X */ #endif /* TNCODE */ #endif /* NETCONN */ ckcnet.h000664 045065 024037 00000124062 14767401732 012623 0ustar00fdckermit000000 000000 /* ckcnet.h -- Symbol and macro definitions for C-Kermit network support */ /* Author: Frank da Cruz Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ #ifndef CKCNET_H #define CKCNET_H /* Network types */ #define NET_NONE 0 /* None */ #define NET_TCPB 1 /* TCP/IP Berkeley (socket) */ #define NET_TCPA 2 /* TCP/IP AT&T (streams) */ #define NET_SX25 3 /* SUNOS SunLink X.25 */ #define NET_DEC 4 /* DECnet */ #define NET_VPSI 5 /* VAX PSI */ #define NET_PIPE 6 /* LAN Manager Named Pipe */ #define NET_VX25 7 /* Stratus VOS X.25 */ #define NET_BIOS 8 /* IBM NetBios */ #define NET_SLAT 9 /* Meridian Technologies' SuperLAT */ #define NET_FILE 10 /* Read from a file */ #define NET_CMD 11 /* Read from a sub-process */ #define NET_DLL 12 /* Load a DLL for use as comm channel*/ #define NET_IX25 13 /* IBM AIX 4.1 X.25 */ #define NET_HX25 14 /* HP-UX 10 X.25 */ #define NET_PTY 15 /* Pseudoterminal */ #define NET_SSH 16 /* SSH */ #ifdef OS2 /* In OS/2, only the 32-bit */ #ifndef __32BIT__ /* version gets NETBIOS */ #ifdef CK_NETBIOS #undef CK_NETBIOS #endif /* CK_NETBIOS */ #endif /* __32BIT__ */ #endif /* OS2 */ #ifdef _M_PPC #ifdef SUPERLAT #undef SUPERLAT #endif /* SUPERLAT */ #endif /* _M_PPC */ #ifdef NPIPE /* For items in common to */ #define NPIPEORBIOS /* Named Pipes and NETBIOS */ #endif /* NPIPE */ #ifdef CK_NETBIOS #ifndef NPIPEORBIOS #define NPIPEORBIOS #endif /* NPIPEORBIOS */ #endif /* CK_NETBIOS */ /* Network virtual terminal protocols (for SET HOST connections) */ /* FTP, HTTP and SSH have their own stacks */ #define NP_DEFAULT 255 #define NP_NONE 0 /* None (async) */ #define NP_TELNET 1 /* TCP/IP telnet */ #define NP_VTP 2 /* ISO Virtual Terminal Protocol */ #define NP_X3 3 /* CCITT X.3 */ #define NP_X28 4 /* CCITT X.28 */ #define NP_X29 5 /* CCITT X.29 */ #define NP_RLOGIN 6 /* TCP/IP Remote login */ #define NP_KERMIT 7 /* TCP/IP Kermit */ #define NP_TCPRAW 8 /* TCP/IP Raw socket */ #define NP_TCPUNK 9 /* TCP/IP Unknown */ #define NP_SSL 10 /* TCP/IP SSLv23 */ #define NP_TLS 11 /* TCP/IP TLSv1 */ #define NP_SSL_TELNET 12 /* TCP/IP Telnet over SSLv23 */ #define NP_TLS_TELNET 13 /* TCP/IP Telnet over TLSv1 */ #define NP_K4LOGIN 14 /* TCP/IP Kerberized remote login */ #define NP_EK4LOGIN 15 /* TCP/IP Encrypted Kerberized ... */ #define NP_K5LOGIN 16 /* TCP/IP Kerberized remote login */ #define NP_EK5LOGIN 17 /* TCP/IP Encrypted Kerberized ... */ #define NP_K5U2U 18 /* TCP/IP Kerberos 5 User to User */ #define NP_CTERM 19 /* DEC CTERM */ #define NP_LAT 20 /* DEC LAT */ #define NP_SSL_RAW 21 /* SSL with no Telnet permitted */ #define NP_TLS_RAW 22 /* TLS with no Telnet permitted */ /* others here... */ #ifdef CK_SSL #define IS_TELNET() (nettype == NET_TCPB && (ttnproto == NP_TELNET \ || ttnproto == NP_SSL_TELNET \ || ttnproto == NP_TLS_TELNET \ || ttnproto == NP_KERMIT)) #else /* CK_SSL */ #define IS_TELNET() (nettype == NET_TCPB && (ttnproto == NP_TELNET \ || ttnproto == NP_KERMIT)) #endif /* CK_SSL */ #ifdef CK_KERBEROS #ifdef KRB5 #ifdef KRB4 #define IS_RLOGIN() (nettype == NET_TCPB && (ttnproto == NP_RLOGIN \ || ttnproto == NP_K5LOGIN \ || ttnproto == NP_EK5LOGIN \ || ttnproto == NP_K4LOGIN \ || ttnproto == NP_EK4LOGIN \ )) #else /* KRB4 */ #define IS_RLOGIN() (nettype == NET_TCPB && (ttnproto == NP_RLOGIN \ || ttnproto == NP_K5LOGIN \ || ttnproto == NP_EK5LOGIN \ )) #endif /* KRB4 */ #else /* KRB5 */ #ifdef KRB4 #define IS_RLOGIN() (nettype == NET_TCPB && (ttnproto == NP_RLOGIN \ || ttnproto == NP_K4LOGIN \ || ttnproto == NP_EK4LOGIN \ )) #else /* KRB4 */ KERBEROS defined without either KRB4 or KRB5 #endif /* KRB4 */ #endif /* KRB5 */ #else /* CK_KERBEROS */ #define IS_RLOGIN() (nettype == NET_TCPB && (ttnproto == NP_RLOGIN)) #endif /* CK_KERBEROS */ #define IS_SSH() (nettype == NET_SSH) /* RLOGIN Modes */ #define RL_RAW 0 /* Do Not Process XON/XOFF */ #define RL_COOKED 1 /* Do Process XON/XOFF */ /* Encryption types */ #define CX_NONE 999 #ifdef ENCTYPE_ANY #define CX_AUTO ENCTYPE_ANY #else #define CX_AUTO 0 #endif /* ENCTYPE_ANY */ #ifdef ENCTYPE_DES_CFB64 #define CX_DESC64 ENCTYPE_DES_CFB64 #else #define CX_DESC64 1 #endif /* ENCTYPE_DES_CFB64 */ #ifdef ENCTYPE_DES_OFB64 #define CX_DESO64 ENCTYPE_DES_OFB64 #else #define CX_DESO64 2 #endif /* ENCTYPE_DES_OFB64 */ #ifdef ENCTYPE_DES3_CFB64 #define CX_DES3C64 ENCTYPE_DES3_CFB64 #else #define CX_DES3C64 3 #endif /* ENCTYPE_DES_CFB64 */ #ifdef ENCTYPE_DES3_OFB64 #define CX_DESO64 ENCTYPE_DES3_OFB64 #else #define CX_DES3O64 4 #endif /* ENCTYPE_DES_OFB64 */ #ifdef ENCTYPE_CAST5_40_CFB64 #define CX_C540C64 ENCTYPE_CAST5_40_CFB64 #else #define CX_C540C64 8 #endif /* ENCTYPE_CAST5_40_CFB64 */ #ifdef ENCTYPE_CAST5_40_OFB64 #define CX_C540O64 ENCTYPE_CAST5_40_OFB64 #else #define CX_C540O64 9 #endif /* ENCTYPE_CAST5_40_OFB64 */ #ifdef ENCTYPE_CAST128_CFB64 #define CX_C128C64 ENCTYPE_CAST128_CFB64 #else #define CX_C128C64 10 #endif /* ENCTYPE_CAST128_CFB64 */ #ifdef ENCTYPE_CAST128_OFB64 #define CX_C128O64 ENCTYPE_CAST128_OFB64 #else #define CX_C128O64 11 #endif /* ENCTYPE_CAST128_OFB64 */ /* Basic network function prototypes, common to all. */ _PROTOTYP( int netopen, (char *, int *, int) ); _PROTOTYP( int netclos, (void) ); _PROTOTYP( int netflui, (void) ); _PROTOTYP( int nettchk, (void) ); _PROTOTYP( int netxchk, (int) ); _PROTOTYP( int netbreak, (void) ); _PROTOTYP( int netinc, (int) ); _PROTOTYP( int netxin, (int, CHAR *) ); _PROTOTYP( int nettol, (CHAR *, int) ); _PROTOTYP( int nettoc, (CHAR) ); _PROTOTYP( int net_read, (int fd, register char *buf, register int len) ); _PROTOTYP( int net_write, (int fd, register const char *buf, int len) ); _PROTOTYP( int rlog_ctrl, (unsigned char *cp, int n) ); _PROTOTYP( int locate_txt_rr, (char *prefix, char *name, char **retstr) ); #ifdef TCPSOCKET _PROTOTYP( int gettcpport, (void) ); _PROTOTYP( int gettcpport, (void) ); #endif /* TCPSOCKET */ /* SunLink X.25 support by Marcello Frutig, Catholic University, Rio de Janeiro, Brazil, 1990. Maybe this can be adapted to VAX PSI and other X.25 products too. */ #ifndef SUNOS4 /* Only valid for SUNOS4 */ #ifndef SOLARIS #ifdef SUNX25 #undef SUNX25 #endif /* SUNX25 */ #endif /* SOLARIS */ #endif /* SUNOS4 */ #ifdef STRATUSX25 #define ANYX25 #define MAX_USER_DATA 128 /* SUN defines this in a header file, I believe. */ #endif /* STRATUSX25 */ #ifdef SUNX25 #define ANYX25 #endif /* SUNX25 */ #ifdef IBMX25 /* AIX 4.1 X.25 */ #ifndef AIX41 #undef IBMX25 #else /* AIX41 */ #define ANYX25 #define MAX_USER_DATA NPI_MAX_DATA /* used for buffer sizes */ #endif /* AIX41 */ #endif /* IBMX25 */ #ifdef HPX25 /* HP-UX 10.* X.25 */ #ifndef HPUX10 #undef HPX25 #else /* HPUX10 */ #define ANYX25 #endif /* HPUX10 */ #endif /* HPX25 */ #ifdef ANYX25 #ifndef NETCONN /* ANYX25 implies NETCONN */ #define NETCONN #endif /* NETCONN */ #define MAXPADPARMS 22 /* Number of PAD parameters */ #define MAXCUDATA 12 /* Max length of X.25 call user data */ #define X29PID 1 /* X.29 protocol ID */ #define X29PIDLEN 4 /* X.29 protocol ID length */ #define X29_SET_PARMS 2 #define X29_READ_PARMS 4 #define X29_SET_AND_READ_PARMS 6 #define X29_INVITATION_TO_CLEAR 1 #define X29_PARAMETER_INDICATION 0 #define X29_INDICATION_OF_BREAK 3 #define X29_ERROR 5 #define INVALID_PAD_PARM 1 #define PAD_BREAK_CHARACTER 0 #define PAD_ESCAPE 1 #define PAD_ECHO 2 #define PAD_DATA_FORWARD_CHAR 3 #define PAD_DATA_FORWARD_TIMEOUT 4 #define PAD_FLOW_CONTROL_BY_PAD 5 #define PAD_SUPPRESSION_OF_SIGNALS 6 #define PAD_BREAK_ACTION 7 #define PAD_SUPPRESSION_OF_DATA 8 #define PAD_PADDING_AFTER_CR 9 #define PAD_LINE_FOLDING 10 #define PAD_LINE_SPEED 11 #define PAD_FLOW_CONTROL_BY_USER 12 #define PAD_LF_AFTER_CR 13 #define PAD_PADDING_AFTER_LF 14 #define PAD_EDITING 15 #define PAD_CHAR_DELETE_CHAR 16 #define PAD_BUFFER_DELETE_CHAR 17 #define PAD_BUFFER_DISPLAY_CHAR 18 #define MAXIX25 MAX_USER_DATA*7 #define MAXOX25 MAX_USER_DATA #endif /* ANYX25 */ #ifdef SUNX25 #ifdef SOLARIS25 /* and presumably SunLink 9.xx */ #include #include #include #include #include #include #include #include #include #include #else #include /* X.25 includes, Sun only */ #include #ifndef SOLARIS #include #endif /* SOLARIS */ #include #include #ifdef SOLARIS #include #else #include #endif /* SOLARIS */ #include #include #include #include #include #include #endif /* SOLARIS25 */ #endif /* SUNX25 */ #ifdef ANYX25 #ifdef IBMX25 /* X.25 includes, AIX only */ #include #include #include #include #include #define NPI_20 /* required to include the whole NPI */ #include #include #include #include /* required for access to the ODM */ #include /* database, needed to find out the */ /* local NUA. see x25local_nua() */ /* IBM X25 NPI generic primitive type */ typedef union N_npi_ctl_t { ulong PRIM_type; /* generic primitive type */ char buffer[NPI_MAX_CTL]; /* maximum primitive size */ N_bind_ack_t bind_ack; N_bind_req_t bind_req; N_conn_con_t conn_con; N_conn_ind_t conn_ind; N_conn_req_t conn_req; N_conn_res_t conn_res; N_data_req_t data_req; N_data_ind_t data_ind; N_discon_ind_t discon_ind; N_discon_req_t discon_req; N_error_ack_t error_ack; N_exdata_ind_t exdata_ind; N_info_ack_t info_ack; N_ok_ack_t ok_ack; N_reset_con_t reset_con; N_reset_req_t reset_req; N_reset_ind_t reset_ind; } N_npi_ctl_t; /* some extra definitions to help out */ typedef char x25addr_t[45]; /* max 40 defined by CCITT */ typedef char N_npi_data_t[NPI_MAX_DATA]; /* fd or server waiting for connections, used by netclos and netopen */ extern int x25serverfd; #endif /* IBMX25 */ #ifdef HPX25 /* X.25 includes, HP-UX only */ #include #include #include #include #include #include #include #include #endif /* HPX25 */ /* C-Kermit X.3 / X.25 / X.29 / X.121 support functions */ /* (riehm: this list of functions isn't quite right for AIX) */ _PROTOTYP( int shopad, (int) ); _PROTOTYP( int shox25, (int) ); _PROTOTYP( VOID initpad, (void) ); _PROTOTYP( VOID setpad, (CHAR *, int) ); _PROTOTYP( VOID readpad, (CHAR *, int, CHAR *) ); _PROTOTYP( int qbitpkt, (CHAR *, int) ); _PROTOTYP( VOID setqbit, (void) ); _PROTOTYP( VOID resetqbit, (void) ); _PROTOTYP( VOID breakact, (void) ); _PROTOTYP( int pkx121, (char *, CHAR *) ); _PROTOTYP( SIGTYP x25oobh, (int) ); _PROTOTYP( int x25diag, (void) ); _PROTOTYP( int x25intr, (char) ); _PROTOTYP( int x25reset, (char, char) ); _PROTOTYP( int x25clear, (void) ); _PROTOTYP( int x25stat, (void) ); _PROTOTYP( int x25in, (int, CHAR *) ); _PROTOTYP( int setpadp, (void) ); _PROTOTYP( int setx25, (void) ); _PROTOTYP( int x25xin, (int, CHAR *) ); _PROTOTYP( int x25inl, (CHAR *, int, int, CHAR) ); #ifdef IBMX25 /* setup x25 */ _PROTOTYP( ulong x25bind, (int, char *, char *, int, int, int, ulong) ); _PROTOTYP( int x25call, (int, char *, char *) ); /* connect to remote */ _PROTOTYP( int x25unbind, (int) ); /* disconnect */ _PROTOTYP( char *x25prim, (int) ); /* display primitives */ _PROTOTYP( int x25local_nua, (char *) ); /* find local NUA */ #endif /* IBMX25 */ #endif /* ANYX25 */ /* CMU-OpenVMS/IP */ #ifdef CMU_TCPIP /* CMU_TCPIP implies TCPSOCKET */ #ifndef TCPSOCKET #define TCPSOCKET #endif /* TCPSOCKET */ #ifndef TCPIPLIB #define TCPIPLIB #endif /* TCPIPLIB */ #endif /* CMU_TCPIP */ /* DEC TCP/IP for (Open)VMS, previously known as UCX */ #ifdef DEC_TCPIP /* DEC_TCPIP implies TCPSOCKET */ #ifndef TCPSOCKET #define TCPSOCKET #endif /* TCPSOCKET */ #ifndef TCPIPLIB #define TCPIPLIB #endif /* TCPIPLIB */ #endif /* DEC_TCPIP */ /* SRI/TGV/Cisco/Process MultiNet, TCP/IP for VAX/VMS */ #ifdef MULTINET /* MULTINET implies TCPSOCKET */ #ifndef TCPSOCKET #define TCPSOCKET #endif /* TCPSOCKET */ #ifndef TCPIPLIB #define TCPIPLIB #endif /* TCPIPLIB */ #ifndef TGVORWIN /* MULTINET and WINTCP */ #define TGVORWIN /* share a lot of code... */ #endif /* TGVORWIN */ #endif /* MULTINET */ /* Wollongong TCP/IP for VAX/VMS */ #ifdef WINTCP /* WINTCP implies TCPSOCKET */ #ifndef TCPSOCKET #define TCPSOCKET #endif /* TCPSOCKET */ #ifndef TCPIPLIB #define TCPIPLIB #endif /* TCPIPLIB */ #ifndef TGVORWIN /* WINTCP and MULTINET */ #define TGVORWIN /* share a lot of code... */ #endif /* TGVORWIN */ #endif /* WINTCP */ /* Wollongong TCP/IP for AT&T Sys V */ #ifdef WOLLONGONG /* WOLLONGONG implies TCPSOCKET */ #ifndef TCPSOCKET /* Don't confuse WOLLONGONG */ #define TCPSOCKET /* (which is for UNIX) with */ #endif /* TCPSOCKET */ /* WINTCP, which is for VMS! */ #endif /* WOLLONGONG */ #ifdef EXCELAN /* EXCELAN implies TCPSOCKET */ #ifndef TCPSOCKET #define TCPSOCKET #endif /* TCPSOCKET */ #endif /* EXCELAN */ #ifdef INTERLAN /* INTERLAN implies TCPSOCKET */ #ifndef TCPSOCKET #define TCPSOCKET #endif /* TCPSOCKET */ #endif /* INTERLAN */ #ifdef BEBOX #ifndef TCPSOCKET #define TCPSOCKET #endif /* TCPSOCKET */ #ifndef TCPIPLIB #define TCPIPLIB #endif /* TCPIPLIB */ #define socket_errno h_errno #define socket_read(x,y,z) recv(x,y,sizeof(char),z) #define socket_write(x,y,z) send(x,y,sizeof(char),z) #define socket_ioctl ioctl #define socket_close(x) closesocket(x) #ifndef FIONBIO #define FIONBIO 2 #endif /* FIONBIO */ #ifndef FIONREAD #define FIONREAD 1 #endif /* FIONREAD */ #ifndef SIOCATMARK #define SIOCATMARK 3 #endif /* SIOCATMARK */ #endif /* BEBOX */ #ifdef COMMENT /* no longer used but might come in handy again later... */ /* CK_READ0 can (and should) be defined if and only if: (a) read(fd,&x,0) can be used harmlessly on a TCP/IP socket connection. (b) read(fd,&x,0) returns 0 if the connection is up, -1 if it is down. */ #ifndef CK_READ0 #ifdef TCPSOCKET #ifdef SUNOS41 /* It works in SunOS 4.1 */ #define CK_READ0 #else #ifdef NEXT /* and NeXTSTEP */ #define CK_READ0 #endif /* NEXT */ #endif /* SUNOS41 */ #endif /* TCPSOCKET */ #endif /* CK_READ0 */ #endif /* COMMENT */ /* Telnet protocol */ #ifdef TCPSOCKET /* TCPSOCKET implies TNCODE */ #ifndef TNCODE /* Which means... */ #define TNCODE /* Compile in telnet code */ #endif /* TNCODE */ /* Platforms where we must call gethostname(buf,len) and then gethostbyname(buf) to get local IP address, rather than calling gethostbyname(""). */ #ifndef CKGHNLHOST #ifdef datageneral #define CKGHNLHOST #else #ifdef SOLARIS #define CKGHNLHOST #else #ifdef SUNOS4 #define CKGHNLHOST #else #ifdef UNIXWARE #define CKGHNLHOST #else #ifdef SINIX #define CKGHNLHOST #endif /* SINIX */ #endif /* UNIXWARE */ #endif /* SUNOS4 */ #endif /* SOLARIS */ #endif /* datageneral */ #endif /* CKGHNLHOST */ #ifndef RLOGCODE /* What about Rlogin? */ #ifndef NORLOGIN /* Rlogin can be enabled only for UNIX versions that have both SIGURG (SCO doesn't) and CK_TTGWSIZ (OSF/1 doesn't), so we don't assume that any others have these without verifying first. Not that it really makes much difference since you can only use Rlogin if you are root... */ #ifdef SUNOS41 #define RLOGCODE #else #ifdef SOLARIS #define RLOGCODE #else #ifdef HPUX9 #define RLOGCODE #else #ifdef HPUX10 #define RLOGCODE #else #ifdef OSF40 #define RLOGCODE #else #ifdef NEXT #define RLOGCODE #else #ifdef AIX41 #define RLOGCODE #else #ifdef UNIXWARE #define RLOGCODE #else #ifdef IRIX51 #define RLOGCODE #else #ifdef IRIX60 #define RLOGCODE #else #ifdef QNX #define RLOGCODE #else #ifdef __linux__ #define RLOGCODE #else #ifdef BSD44 #define RLOGCODE #endif /* BSD44 */ #endif /* __linux__ */ #endif /* QNX */ #endif /* IRIX60 */ #endif /* IRIX51 */ #endif /* UNIXWARE */ #endif /* AIX41 */ #endif /* NEXT */ #endif /* OSF40 */ #endif /* HPUX10 */ #endif /* HPUX9 */ #endif /* SOLARIS */ #endif /* SUNOS41 */ #endif /* NORLOGIN */ #ifdef VMS /* VMS */ #define RLOGCODE #endif /* VMS */ #endif /* RLOGCODE */ #endif /* TCPSOCKET */ #ifdef TNCODE /* Telnet local-echo buffer, used for saving up user data that can't be properly displayed and/or evaluated until pending Telnet negotiations are complete. TTLEBUF is defined for platforms (like UNIX) where net i/o is done by the same routines that do serial i/o (in which case the relevant code goes into the ck?tio.c module, in the ttinc(), ttchk(), etc, routines); NETLETBUF is defined for platforms (like VMS) that use different APIs for network and serial i/o, and enables the copies of the same routines that are in ckcnet.c. */ #ifndef TTLEBUF #ifdef UNIX #define TTLEBUF #else #ifdef datageneral #define TTLEBUF #endif /* datageneral */ #endif /* UNIX */ #endif /* TTLEBUF */ #ifndef NETLEBUF #ifdef VMS #define NETLEBUF #endif /* VMS */ #endif /* NETLEBUF */ #endif /* TNCODE */ #ifdef SUNX25 /* SUNX25 implies TCPSOCKET */ #ifndef TCPSOCKET /* But doesn't imply TNCODE */ #define TCPSOCKET #endif /* TCPSOCKET */ #endif /* SUNX25 */ #ifndef TCPSOCKET #ifndef NO_DNS_SRV #define NO_DNS_SRV #endif /* NO_DNS_SRV */ #endif /* TCPSOCKET */ /* This is another TCPSOCKET section... */ #ifdef TCPSOCKET #ifndef NETCONN /* TCPSOCKET implies NETCONN */ #define NETCONN #endif /* NETCONN */ #ifndef NO_DNS_SRV #ifdef NOLOCAL #define NO_DNS_SRV #endif /* NOLOCAL */ #ifdef OS2ONLY #define NO_DNS_SRV #endif /* OS2ONLY */ #ifdef NT #ifdef _M_PPC #define NO_DNS_SRV #endif /* _M_DNS */ #endif /* NO_DNS_SRV */ #ifdef VMS #define NO_DNS_SRV #endif /* VMS */ #ifdef STRATUS #define NO_DNS_SRV #endif /* STRATUS */ #ifdef datageneral #define NO_DNS_SRV #endif /* datageneral */ #ifdef ultrix #define NO_DNS_SRV #endif /* ultrix */ #ifdef NEXT #define NO_DNS_SRV #endif /* NEXT */ #endif /* NO_DNS_SRV */ #ifndef CK_DNS_SRV /* Use DNS SRV records to determine */ #ifndef NO_DNS_SRV /* host and ports */ #define CK_DNS_SRV #endif /* NO_DNS_SRV */ #endif /* CK_DNS_SRV */ #ifndef NOLISTEN /* select() is required to support */ #ifndef SELECT /* incoming connections. */ #ifndef VMS #ifndef OS2 #define NOLISTEN #endif /* OS2 */ #endif /* VMS */ #endif /* SELECT */ #endif /* NOLISTEN */ /* BSD sockets library header files */ #ifdef VMS /* Because bzero() and bcopy() are not portable among VMS versions, or compilers, or TCP/IP products, etc. */ #ifndef bzero #define bzero(s,n) memset(s,0,n) #endif /* bzero */ #ifndef bcopy #define bcopy(h,a,l) memcpy(a,h,l) #endif /* bcopy */ #endif /* VMS */ #ifdef HPUX6 /* These are missing in HP-UX 6.xx */ #ifndef bzero #define bzero(s,n) memset(s,0,n) #endif /* bzero */ #ifndef bcopy #define bcopy(h,a,l) memcpy(a,h,l) #endif /* bcopy */ #endif /* HPUX6 */ #ifdef UNIX /* UNIX section */ #ifdef SVR4 /* These suggested by Rob Healey, rhealey@kas.helios.mn.org, to avoid bugs in Berkeley compatibility library on Sys V R4 systems, but untested by me (fdc). Remove this bit if it gives you trouble. (Later corrected by Marc Boucher because bzero/bcopy are not argument-compatible with memset/memcpy|memmove.) */ #ifndef bzero #define bzero(s,n) memset(s,0,n) #endif #ifdef SOLARIS #ifdef SUNX25 #undef bzero /* WOULD YOU BELIEVE... That the Solaris X.25 /opt/SUNWcomm/lib/libsockx25 library references bzero, even though the use of bzero is forbidden in Solaris? Look for the function definition in ckcnet.c. */ _PROTOTYP( void bzero, (char *, int) ); #endif /* SUNX25 */ #ifndef bcopy #define bcopy(h,a,l) memcpy(a,h,l) #endif #else #ifndef bcopy #define bcopy(h,a,l) memmove(a,h,l) #endif #endif /* SOLARIS */ #else /* !SVR4 */ #ifdef PTX /* Sequent DYNIX PTX 1.3 */ #ifndef bzero #define bzero(s,n) memset(s,0,n) #endif #ifndef bcopy #define bcopy(h,a,l) memcpy(a,h,l) #endif #endif /* PTX */ #endif /* SVR4 */ #ifdef INTERLAN /* Racal-Interlan TCP/IP */ #include #include #include #include #include #include /* Why twice ? ? ? */ #else /* Not Interlan */ #ifdef BEBOX #include #else /* Not BEBOX */ /* Normal BSD TCP/IP library */ #ifdef COMMENT #ifndef HPUX #include #endif /* HPUX */ #endif /* COMMENT */ #ifdef SCO234 #include #include #endif /* SCO234 */ #include #ifdef WOLLONGONG #include #else #include #ifndef SV68R3V6 /* (maybe this should be SVR3 in general) */ #include /* Added June 2001 */ #endif /* SV68R3V6 */ #endif /* WOLLONGONG */ #endif /* BEBOX */ #endif /* INTERLAN */ #ifndef EXCELAN #include #ifndef INTERLAN #ifdef WOLLONGONG #define minor /* Do not include */ #include #else #ifndef OXOS #ifndef HPUX #ifndef BEBOX #include #endif /* BEBOX */ #endif /* HPUX */ #else /* OXOS */ /* In too many releases of X/OS, declares inet_addr() as * ``struct in_addr''. This is definitively wrong, and could cause * core dumps. Instead of including that bad file, inet_addr() is * correctly declared here. Of course, all the declarations done there * has been copied here. */ unsigned long inet_addr(); char *inet_ntoa(); struct in_addr inet_makeaddr(); unsigned long inet_network(); #endif /* OXOS */ #endif /* WOLLONGONG */ #endif /* INTERLAN */ #endif /* EXCELAN */ #ifdef EXCELAN /* Excelan TCP/IP */ #ifndef bzero #define bzero(s,n) memset(s,0,n) #endif /* bzero */ #ifndef bcopy #define bcopy(h,a,l) memcpy(a,h,l) #endif /* bcopy */ #include #endif /* EXCELAN */ #ifdef I386IX /* Interactive Sys V R3 network. */ /* #define TELOPTS */ /* This might need defining. */ #define ORG_NLONG ENAMETOOLONG /* Resolve conflicting symbols */ #undef ENAMETOOLONG /* in and */ #define ORG_NEMPTY ENOTEMPTY #undef ENOTEMPTY #include #undef ENAMETOOLONG #define ENAMETOOLONG ORG_NLONG #undef ENOTEMPTY #define ENOTEMPTY ORG_NEMPTY #include /* for inet_addr() */ #endif /* I386IX */ /* Data type of the inet_addr() function... We define INADDRX if it is of type struct inaddr. If it is undefined, unsigned long is assumed. Look at to find out. The following known cases are handled here. Other systems that need it can be added here, or else -DINADDRX can be included in the CFLAGS on the cc command line. */ #ifndef NOINADDRX #ifdef DU2 /* DEC Ultrix 2.0 */ #define INADDRX #endif /* DU2 */ #endif /* NOINADDRX */ #else /* Not UNIX */ #ifdef VMS /* (Open)VMS section */ #ifdef MULTINET /* TGV MultiNet */ /* In C-Kermit 7.0 Beta.08 we started getting scads of compile time warnings in Multinet builds: "blah" is implicitly declared as a function, where blah is socket_read/write/close, ntohs, htons, getpeername, accept, select, etc. I have no idea why -- these routines are declared in the header files below, and the includes haven't changed. The executable still seems to work OK. Messing with the order of the following includes is disastrous. */ #ifdef MULTINET_NO_PROTOTYPES #undef MULTINET_NO_PROTOTYPES #endif /* MULTINET_NO_PROTOTYPES */ #ifdef __cplusplus #undef __cplusplus #endif /* __cplusplus */ #include "multinet_root:[multinet.include]errno.h" #include "multinet_root:[multinet.include.sys]types.h" #include "multinet_root:[multinet.include.sys]socket.h" #include "multinet_root:[multinet.include]netdb.h" #include "multinet_root:[multinet.include.netinet]in.h" #include "multinet_root:[multinet.include.arpa]inet.h" #include "multinet_root:[multinet.include.sys]ioctl.h" #include "multinet_root:[multinet.include.vms]ucx$inetdef.h" #include "multinet_root:[multinet.include.sys]time.h" /*AGN 08-Jun-2023 Multinet supplies inet_aton()*/ #define NO_DCL_INET_ATON #ifdef COMMENT /* No longer needed because now bzero/bcopy are macros defined as memset/memmove in all VMS builds. */ /* We should be able to pick these up from but it's not portable between VAXC and DECC. And even with DECC 5.x we have a difference between VAX and Alpha. We get warnings here on the VAX with DECC 5.6-003 but they are not fatal. */ #ifndef __DECC_VER #ifndef bzero _PROTOTYP( void bzero, (char *, int) ); #endif /* bzero */ #ifndef bcopy _PROTOTYP( void bcopy, (char *, char *, int) ); #endif /* bcopy */ #endif /* __DECC_VER */ #endif /* COMMENT */ #ifdef __DECC /* If compiling under DEC C the socket calls must not be prefixed with DECC$. This is done by using the compiler switch /Prefix=Ansi_C89. However, this causes some calls that should be prefixed to not be (which I think is a bug in the compiler - I've been told these calls are present in ANSI compilers). At any rate, such calls are fixed here by explicitly prefixing them. */ #ifdef COMMENT /* But this causes errors with VMS 6.2 / DEC C 5.3-006 / MultiNet 4.0A on a VAX (but not on an Alpha). So now what happens if we skip doing this? */ #define close decc$close #define alarm decc$alarm #endif /* COMMENT */ #endif /* __DECC */ #else /* Not MULTINET */ #ifdef WINTCP /* WIN/TCP = PathWay for VMS */ #ifdef OLD_TWG #include "twg$tcp:[netdist.include.sys]errno.h" #include "twg$tcp:[netdist.include.sys]types2.h" /* avoid some duplicates */ #else #include "twg$tcp:[netdist.include]socket_aliases.h" #include #include "twg$tcp:[netdist.include.sys]types.h" #endif /* OLD_TWG */ #include "twg$tcp:[netdist.include.sys]socket.h" #include "twg$tcp:[netdist.include]netdb.h" #include "twg$tcp:[netdist.include.sys]domain.h" #include "twg$tcp:[netdist.include.sys]protosw.h" #include "twg$tcp:[netdist.include.netinet]in.h" #include "twg$tcp:[netdist.include.arpa]inet.h" #include "twg$tcp:[netdist.include.sys]ioctl.h" #else /* Not WINTCP */ #ifdef DEC_TCPIP #ifdef UCX50 #ifndef IF_DOT_H #define IF_DOT_H #endif /* IF_DOT_H */ #endif /* UCX50 */ #ifdef IF_DOT_H #include /* Needed to put up u_int typedef */ #else #ifdef NEEDUINT typedef unsigned int u_int; #endif /* NEEDUINT */ #endif /* IF_DOT_H */ #include #ifdef VMS #include /* (SMS 2007/02/15) */ #endif /* VMS */ #include #include #include "ckvioc.h" #define socket_errno errno #ifdef COMMENT /* No longer needed because now bzero/bcopy are macros defined as memset/memmove in all VMS builds. */ /* Translation: In , which exists only for DECC >= 5.2, bzero() and bcopy() are declared only for OpenVMS >= 7.0. This still might need adjustment for DECC 5.0 and higher. */ #ifdef __DECC_VER #ifdef VMSV70 /* Note: you can't use "#if (__VMS_VER>=70000000)" because that is not portable and kills non-VMS builds. */ #include #else #ifndef bzero #define bzero(s,n) memset(s,0,n) #endif #ifndef bcopy #define bcopy(h,a,l) memmove(a,h,l) #endif #endif /* VMSV70 */ #else #ifndef bzero #define bzero(s,n) memset(s,0,n) #endif #ifndef bcopy #define bcopy(h,a,l) memmove(a,h,l) #endif #endif /* __DECC_VER */ #endif /* COMMENT */ #define socket_read read #define socket_write write #define socket_ioctl ioctl #define socket_close close #ifdef __DECC int ioctl (int d, int request, void *argp); #else int ioctl (int d, int request, char *argp); #endif /* DECC */ /* UCX supports select(), but does not provide the needed symbol and structure definitions in any header file, so ... */ #include #ifndef NBBY /*- * Copyright (c) 1982, 1986, 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)types.h 8.1 (Berkeley) 6/2/93 */ #define NBBY 8 /* number of bits in a byte */ /* * Select uses bit masks of file descriptors in longs. These macros * manipulate such bit fields (the filesystem macros use chars). * FD_SETSIZE may be defined by the user, but the default here should * be enough for most uses. */ #ifndef FD_SETSIZE #define FD_SETSIZE 256 #endif typedef long fd_mask; #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */ #ifndef howmany #define howmany(x, y) (((x)+((y)-1))/(y)) #endif typedef struct fd_set { fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; } fd_set; #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) #define FD_COPY(f, t) bcopy(f, t, sizeof(*(f))) #define FD_ZERO(p) bzero(p, sizeof(*(p))) #endif /* !NBBY */ #else /* Not DEC_TCPIP */ #ifdef CMU_TCPIP #include #include #include #include #include #include #include "ckvioc.h" #define socket_errno errno /* * Routines supplied in LIBCMU.OLB */ #define socket_ioctl ioctl #define socket_read cmu_read #define socket_write cmu_write #define socket_close cmu_close #endif /* CMU_TCPIP */ #endif /* DEC_TCPIP */ #endif /* WINTCP */ #endif /* MULTINET */ #else /* Not VMS */ #ifdef OS2 #include "ckonet.h" #ifndef NT #include #endif #endif /* OS2 */ #ifdef STRATUS /* Stratus VOS using OS TCP/IP products S235, S236, S237 */ #include /* This gets used some places when TCPSOCKET is defined. */ /* OS TCP provides bzero(), but not bcopy()... go figure. */ #define bcopy(s,d,z) memcpy(d,s,z) #endif /* STRATUS */ #ifdef OSK #ifndef OSKXXC #include #include #include #else #include #include #include #endif /* OSKXXC */ #ifndef bzero #define bzero(s,n) memset(s,0,n) #endif #ifndef bcopy #define bcopy(h,a,l) memcpy(a,h,l) #endif typedef char * caddr_t; /* core address type */ #endif /* OSK */ #endif /* VMS */ #endif /* UNIX */ #endif /* TCPSOCKET */ #ifndef NOINADDRX /* 301 - Needed for Solaris 10 and 11 */ #ifdef SOLARIS #define NOINADDRX #ifdef INADDR_NONE #undef INADDR_NONE #endif /* INADDR_NONE */ #endif /* SOLARIS */ #endif /* NOINADDRX */ #ifdef NOINADDRX #ifdef INADDRX #undef INADDRX #endif /* INADDRX */ #endif /* NOINADDRX */ #ifdef TCPSOCKET #ifndef NOHADDRLIST #ifndef HADDRLIST #ifdef SUNOS41 #define HADDRLIST #endif /* SUNOS41 */ #ifdef SOLARIS #define HADDRLIST #endif /* SOLARIS */ #ifdef LINUX #define HADDRLIST #endif /* LINUX */ #ifdef AIXRS #define HADDRLIST #endif /* AIXRS */ #ifdef HPUX #define HADDRLIST #endif /* HPUX */ #ifdef IRIX #define HADDRLIST #endif /* IRIX */ #ifdef I386IX #define HADDRLIST #endif /* I386IX */ #endif /* HADDRLIST */ /* A system that defines h_addr as h_addr_list[0] should be HADDRLIST */ #ifndef HADDRLIST #ifdef h_addr #define HADDRLIST #endif /* h_addr */ #endif /* HADDRLIST */ #endif /* NOHADDRLIST */ #endif /* TCPSOCKET */ #ifdef TNCODE /* If we're compiling telnet code... */ #ifndef IKS_OPTION #ifndef STRATUS #ifndef NOIKSD #define IKS_OPTION #endif /* NOIKSD */ #endif /* STRATUS */ #endif /* IKS_OPTION */ #include "ckctel.h" #else extern int sstelnet; #ifdef IKSD #undef IKSD #endif /* IKSD */ #ifndef NOIKSD #define NOIKSD #endif /* NOIKSD */ #ifdef IKS_OPTION #undef IKS_OPTION #endif /* IKS_OPTION */ #endif /* TNCODE */ #ifndef NOTCPOPTS /* Automatically define NOTCPOPTS for configurations where they can't be used at runtime or cause too much trouble at compile time. */ #ifdef CMU_TCPIP /* CMU/Tek */ #define NOTCPOPTS #endif /* CMU_TCPIP */ #ifdef MULTINET /* Multinet on Alpha */ #ifdef __alpha #define NOTCPOPTS #endif /* __alpha */ #endif /* MULTINET */ #endif /* NOTCPOPTS */ #ifdef NOTCPOPTS #ifdef TCP_NODELAY #undef TCP_NODELAY #endif /* TCP_NODELAY */ #ifdef SO_LINGER #undef SO_LINGER #endif /* SO_LINGER */ #ifdef SO_KEEPALIVE #undef SO_KEEPALIVE #endif /* SO_KEEPALIVE */ #ifdef SO_SNDBUF #undef SO_SNDBUF #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF #undef SO_RCVBUF #endif /* SO_RCVBUF */ #endif /* NOTCPOPTS */ /* This function is declared even when TCPSOCKET is not available */ _PROTOTYP( char * ckgetpeer, (VOID)); #ifdef TCPSOCKET #ifdef SOL_SOCKET #ifdef TCP_NODELAY _PROTOTYP( int no_delay, (int, int) ); #endif /* TCP_NODELAY */ #ifdef SO_KEEPALIVE _PROTOTYP( int keepalive, (int, int) ) ; #endif /* SO_KEEPALIVE */ #ifdef SO_LINGER _PROTOTYP( int ck_linger, (int, int, int) ) ; #endif /* SO_LINGER */ #ifdef SO_SNDBUF _PROTOTYP( int sendbuf,(int, int) ) ; #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF _PROTOTYP( int recvbuf, (int, int) ) ; #endif /* SO_RCVBUF */ #ifdef SO_DONTROUTE _PROTOTYP(int dontroute, (int, int)); #endif /* SO_DONTROUTE */ #endif /* SOL_SOCKET */ _PROTOTYP( int getlocalipaddr, (VOID)); _PROTOTYP( int getlocalipaddrs, (char *,int,int)); _PROTOTYP( char * ckgetfqhostname,(char *)); _PROTOTYP( struct hostent * ck_copyhostent,(struct hostent *)); _PROTOTYP( char * ckname2addr, (char *)); _PROTOTYP( char * ckaddr2name, (char *)); /* AIX */ #ifdef AIXRS #ifndef TCP_NODELAY #define TCP_NODELAY 0x1 #endif /* TCP_NODELAY */ #ifndef TCP_MAXSEG #define TCP_MAXSEG 0x2 #endif /* TCP_MAXSEG */ #ifndef TCP_KEEPALIVE #define TCP_KEEPALIVE 0x8 #endif /* TCP_KEEPALIVE */ #endif /* AIXRS */ #endif /* TCPSOCKET */ #ifdef RLOGCODE #ifndef CK_TTGWSIZ SORRY_RLOGIN_REQUIRES_TTGWSIZ_see_ckcplm.doc #endif /* CK_TTGWSIZ */ #endif /* RLOGCODE */ #ifdef CK_NAWS #ifndef CK_TTGWSIZ SORRY_CK_NAWS_REQUIRES_TTGWSIZ_see_ckcplm.doc #endif /* CK_TTGWSIZ */ #endif /* CK_NAWS */ #ifndef PF_INET #ifdef AF_INET #define PF_INET AF_INET #endif /* AF_INET */ #endif /* PF_INET */ #ifndef IPPORT_ECHO #define IPPORT_ECHO 7 #endif /* IPPORT_ECHO */ #ifdef CK_KERBEROS #ifdef RLOGCODE _PROTOTYP(int ck_krb_rlogin,(CHAR *, int, CHAR *, CHAR *, CHAR *, struct sockaddr_in *, struct sockaddr_in *, int, int)); #endif /* RLOGCODE */ #endif /* CK_KERBEROS */ _PROTOTYP( VOID ini_kerb, ( void ) ); /* Kerberos initialization routine */ _PROTOTYP( int doauth, (int) ); /* AUTHENTICATE action routine */ #ifdef CK_DNS_SRV _PROTOTYP(int locate_srv_dns,(char *host, char *service, char *protocol, struct sockaddr **addr_pp, int *naddrs)); #endif /* CK_DNS_SRV */ #ifndef NOHTTP _PROTOTYP(int http_open, (char *, char *, int, char *, int, char *)); _PROTOTYP(int http_reopen, (VOID)); _PROTOTYP(int http_close, (VOID)); _PROTOTYP(int http_get, (char *,char **,char *,char *,char,char *,char *, int)); _PROTOTYP(int http_head, (char *,char **,char *,char *,char,char *,char *, int)); _PROTOTYP(int http_put, (char *,char **,char *,char *,char *,char,char *, char *, char *, int)); _PROTOTYP(int http_delete, (char *,char **,char *,char *,char,char *)); _PROTOTYP(int http_connect, (int, char *,char **,char *,char *,char,char *)); _PROTOTYP(int http_post, (char *,char **,char *,char *,char *,char,char *, char *,char *, int)); _PROTOTYP(int http_index, (char *,char **,char *,char *,char,char *,char *, int)); _PROTOTYP(int http_inc, (int)); _PROTOTYP(int http_isconnected, (void)); extern char * tcp_http_proxy; /* Name[:port] of http proxy server */ extern int tcp_http_proxy_errno; /* Return value from server */ extern char * tcp_http_proxy_user; /* Name of user for authentication */ extern char * tcp_http_proxy_pwd; /* Password of user */ #endif /* NOHTTP */ #ifdef TCPSOCKET /* Type needed as 5th argument (length) to get/setsockopt() */ #ifdef TRU64 /* They say it themselves - this does not conform to standards */ #define socklen_t int #else #ifdef HPUX #define socklen_t int #endif /* HPUX */ #endif /* TRU64 */ #ifndef SOCKOPT_T #ifdef CK_64BIT #ifndef NT #define SOCKOPT_T socklen_t #endif /* NT */ #endif /* CK_64BIT */ #endif /* SOCKOPT_T */ #ifndef SOCKOPT_T #define SOCKOPT_T int #ifdef MACOSX10 #undef SOCKOPT_T #define SOCKOPT_T unsigned int #else #ifdef AIX42 #undef SOCKOPT_T #define SOCKOPT_T unsigned long #else #ifdef PTX #undef SOCKOPT_T #define SOCKOPT_T size_t #else #ifdef NT #undef SOCKOPT_T #define SOCKOPT_T int #else /* NT */ #ifdef UNIXWARE #undef SOCKOPT_T #define SOCKOPT_T size_t #else /* UNIXWARE */ #ifdef VMS #ifdef DEC_TCPIP #ifdef __DECC_VER #undef SOCKOPT_T #define SOCKOPT_T size_t #endif /* __DECC_VER */ #endif /* DEC_TCPIP */ #endif /* VMS */ #endif /* UNIXWARE */ #endif /* NT */ #endif /* PTX */ #endif /* AIX42 */ #endif /* MACOSX10 */ #endif /* SOCKOPT_T */ /* Ditto for getsockname() */ #ifndef GSOCKNAME_T #ifdef CK_64BIT #ifndef NT #define GSOCKNAME_T socklen_t #endif /* NT */ #endif /* CK_64BIT */ #endif /* GSOCKNAME_T */ #ifndef GSOCKNAME_T #define GSOCKNAME_T int #ifdef MACOSX10 #undef GSOCKNAME_T #define GSOCKNAME_T unsigned int #else #ifdef PTX #undef GSOCKNAME_T #define GSOCKNAME_T size_t #else #ifdef AIX42 /* size_t in 4.2++, int in 4.1-- */ #undef GSOCKNAME_T #define GSOCKNAME_T size_t #else #ifdef UNIXWARE #undef GSOCKNAME_T #define GSOCKNAME_T size_t #else #ifdef VMS #ifdef DEC_TCPIP #ifdef __DECC_VER #undef GSOCKNAME_T #define GSOCKNAME_T size_t #endif /* __DECC_VER */ #endif /* DEC_TCPIP */ #endif /* VMS */ #endif /* UNIXWARE */ #endif /* AIX41 */ #endif /* PTX */ #endif /* MACOSX10 */ #endif /* GSOCKNAME_T */ #endif /* TCPSOCKET */ #ifdef MACOSX10 #ifdef bcopy #undef bcopy #endif #ifdef bzero #undef bzero #endif #endif /* MACOSX10 */ #endif /* CKCNET_H */ ckcsig.h000664 045065 024037 00000014015 14767401753 012616 0ustar00fdckermit000000 000000 /* C K C S I G . H */ /* Definitions and prototypes for signal handling */ /* Author: Jeffrey E Altman (jaltman@secure-endpoints.com), Secure Endpoints Inc., New York City. Copyright (C) 1985, 2013 Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ #ifdef OS2 #ifndef NT #ifndef __HEV__ /* INCL_SEMAPHORE may also define HEV */ #define __HEV__ typedef ULONG HEV; /* hev */ typedef HEV *PHEV; #endif /* __HEV__ */ #endif /* NT */ struct _threadinfo { int inuse; int child; int sibling; #ifdef NT HANDLE id; HANDLE handle; HANDLE parent; HANDLE CompletionSem ; HANDLE DieSem ; #else /* NT */ TID id; TID parent; HEV CompletionSem; HEV DieSem; #endif /* NT */ }; #endif /* OS2 */ #ifdef CK_ANSIC typedef SIGTYP (*ck_sigfunc)(void *); typedef SIGTYP (*ck_sighand)(int); #else typedef SIGTYP (*ck_sigfunc)(); typedef SIGTYP (*ck_sighand)(); #endif /* CK_ANSIC */ /* Macros for POSIX vs old-style signal handling. */ #ifdef CK_POSIX_SIG typedef sigjmp_buf ckjmpbuf; #else #ifdef NT #define NOCRYPT #include #ifdef NTASM typedef struct { CONTEXT context; DWORD retcode; } ckjmpbuf; #else /* NTASM */ typedef jmp_buf ckjmpbuf; #endif /* NTASM */ #else typedef jmp_buf ckjmpbuf; #endif #endif /* CK_POSIX_SIG */ /* Suppose you want to pass the address of a jmp_buf bar to a function foo. Since jmp_buf is normally defined (typedef'd) as an array, you would do it like this: foo(bar), where foo = foo(jmp_buf bar). But suppose a jmp_buf is (say) a struct rather than an array. Then you must do foo(&bar) where foo is foo(jmp_buf * bar). This is controlled here in the traditional fashion, by ifdefs. By default, we assume that jmp_buf is an array. Define the symbol JBNOTARRAY if jmp_buf is not an array. */ #ifndef JBNOTARRAY #ifdef NT #define JBNOTARRAY #endif /* NT */ #endif /* JBNOTARRAY */ #ifdef JBNOTARRAY typedef ckjmpbuf * ckjptr; #define ckjaddr(x) & x #define ckjdref(x) * x #ifdef CK_POSIX_SIG #define cksetjmp(x) sigsetjmp(x,1) #define cklongjmp(x,y) siglongjmp(x,y) #else #ifdef NT #ifdef COMMENT __inline int #else static __inline int /* duplicate definition issue */ #endif /* COMMENT */ ck_ih(void) { extern int TlsIndex; #ifdef NTSIG struct _threadinfo * threadinfo; threadinfo = (struct _threadinfo *) TlsGetValue(TlsIndex); if (threadinfo) { if (WaitAndResetSem(threadinfo->DieSem,0)) { ckThreadDie(threadinfo); return 1; /* This should never execute */ } } #ifdef COMMENT else debug( F100, "ck_ih() threadinfo is NULL","",0); #endif /* COMMENT */ #endif /* NTSIG */ return 0; } #ifdef NTSIG #define cksetjmp(x) setjmp(x) #define cklongjmp(x,y) longjmp(x,y) #else /* NTSIG */ #ifdef NTASM __inline DWORD cksetjmp( ckjptr jmp ) { extern int isinterrupted; jmp->retcode = 0; memset( &jmp->context, 0, sizeof(CONTEXT) ); jmp->context.ContextFlags = CONTEXT_FULL ; if ( !GetThreadContext( GetCurrentThread(), &jmp->context ) ) debug( F101, "cksetjmp GetThreadContext failed","",GetLastError()); debug(F101,"cksetjmp returns","",jmp->retcode); isinterrupted = 0; return (jmp->retcode); } __inline void cklongjmp( ckjptr jmp, int retval ) { extern HANDLE tidCommand; extern int mdmtyp ; extern CK_TTYFD_T ttyfd; extern DWORD CommandID; extern int isinterrupted; connoi(); isinterrupted = 1; jmp->retcode = ( retval ? retval : 1 ); debug(F101,"about to SetThreadContext for thread","", CommandID); debug(F101,"from Thread","",GetCurrentThreadId()); if ( mdmtyp >= 0 ) { PurgeComm( (HANDLE) ttyfd, PURGE_TXABORT | PURGE_RXABORT ); } if (SetThreadContext( tidCommand, &jmp->context )) debug(F100,"cklongjmp SetThreadContext success","",0); else debug(F101,"cklongjmp SetThreadContext failed","",GetLastError()); msleep(50); cmini(1); /* Reset command parser */ putkey(13); /* Stuff a carriage return */ /* PostEventAvailSem(); */ } #else /* NTASM */ void crash( void ) ; #define cksetjmp(x) setjmp(x) __inline void cklongjmp( ckjptr jmp, int retval ) { extern HANDLE tidCommand; extern int mdmtyp; extern CK_TTYFD_T ttyfd; extern DWORD CommandID; CONTEXT context; if ( mdmtyp >= 0 ) { PurgeComm( (HANDLE) ttyfd, PURGE_TXABORT | PURGE_RXABORT ) ; } memset( &context, 0, sizeof(CONTEXT) ); context.ContextFlags = CONTEXT_FULL; if ( !GetThreadContext( tidCommand, &context ) ) debug( F101, "cklongjmp GetThreadContext failed","",GetLastError()); /* Invalidate the instruction pointer */ context.Eip = (unsigned long) crash; debug(F101,"about to SetThreadContext for thread","", CommandID); debug(F101,"from Thread","",GetCurrentThreadId()); if (SetThreadContext( tidCommand, &context )) debug(F100,"cklongjmp SetThreadContext success","",0); else debug(F101,"cklongjmp SetThreadContext failed","",GetLastError()); } #endif /* NTASM */ #endif /* NTSIG */ #else /* NT */ #define cksetjmp(x) setjmp(x) #define cklongjmp(x,y) longjmp(x,y) #endif /* NT */ #endif /* CK_POSIX_SIG */ #else /* jmp_buf is an array */ typedef ckjmpbuf ckjptr; #define ckjaddr(x) x #define ckjdref(x) x #ifdef CK_POSIX_SIG #define cksetjmp(x) sigsetjmp(x,1) #define cklongjmp(x,y) siglongjmp(x,y) #else #define cksetjmp(x) setjmp(x) #define cklongjmp(x,y) longjmp(x,y) #endif /* CK_POSIX_SIG */ #endif /* JBNOTARRAY */ _PROTOTYP( int cc_execute, (ckjptr, ck_sigfunc, ck_sigfunc) ); _PROTOTYP( int alrm_execute, (ckjptr, int /* timo */, ck_sighand /* handler */, ck_sigfunc, ck_sigfunc) ); _PROTOTYP( int cc_alrm_execute, (ckjptr, int /* timo */, ck_sighand /* handler */, ck_sigfunc, ck_sigfunc) ); /* End of ckusig.h */ ckcssl.h000664 045065 024037 00000013222 14767401760 012632 0ustar00fdckermit000000 000000 #ifdef CK_SSL #ifndef CK_ANSIC #define NOPROTO #endif /* CK_ANSIC */ #include "bio.h" #include "buffer.h" #include "x509.h" #include "pem.h" #include "ssl.h" extern BIO *bio_err; extern SSL *ssl_con; extern SSL_CTX *ssl_ctx; extern int ssl_debug_flag; extern int ssl_only_flag; extern int ssl_active_flag; extern int ssl_verify_flag; extern int ssl_secure_flag; extern int ssl_verbose_flag; extern int ssl_disabled_flag; extern int ssl_cert_required; extern int ssl_certsok_flag; extern int ssl_dummy_flag; extern char *ssl_log_file; extern char *ssl_rsa_cert_file; extern char *ssl_rsa_key_file; extern char *ssl_dsa_cert_file; extern char *ssl_dh_key_file; extern char *ssl_cipher_list; extern SSL_CTX *tls_ctx; extern SSL *tls_con; extern int tls_only_flag; extern int tls_active_flag; extern int tls_secure_flag; _PROTOTYP(int ssl_do_init,(int)); _PROTOTYP(int ssl_display_connect_details,(SSL *,int)); _PROTOTYP(int ssl_server_verify_callback,(int, X509_STORE_CTX *)); _PROTOTYP(int ssl_client_verify_callback,(int, X509_STORE_CTX *)); #ifdef OS2 #define SSL_get_error ck_SSL_get_error #define SSL_read ck_SSL_read #define SSL_peek ck_SSL_peek #define SSL_connect ck_SSL_connect #define SSL_set_fd ck_SSL_set_fd #define SSL_free ck_SSL_free #define SSL_shutdown ck_SSL_shutdown #define SSL_write ck_SSL_write #define SSL_pending ck_SSL_pending #define SSL_load_error_strings ck_SSL_load_error_strings #define SSL_get_peer_certificate ck_SSL_get_peer_certificate #define SSL_CIPHER_get_name ck_SSL_CIPHER_get_name #define SSL_get_current_cipher ck_SSL_get_current_cipher #define SSL_get_shared_ciphers ck_SSL_get_shared_ciphers #define SSL_get_ciphers ck_SSL_get_ciphers #define SSL_get_cipher_list ck_SSL_get_cipher_list #define SSL_CTX_set_default_verify_paths ck_SSL_CTX_set_default_verify_paths #define SSL_use_RSAPrivateKey_file ck_SSL_use_RSAPrivateKey_file #define SSL_use_DSAPrivateKey_file ck_SSL_use_DSAPrivateKey_file #define SSL_use_PrivateKey_file ck_SSL_use_PrivateKey_file #define SSL_use_certificate_file ck_SSL_use_certificate_file #define SSL_CTX_use_PrivateKey_file ck_SSL_CTX_use_PrivateKey_file #define SSL_CTX_use_certificate_file ck_SSL_CTX_use_certificate_file #define SSL_set_verify ck_SSL_set_verify #define SSL_new ck_SSL_new #define SSL_CTX_ctrl ck_SSL_CTX_ctrl #define SSL_CTX_new ck_SSL_CTX_new #define SSL_CTX_free ck_SSL_CTX_free #define SSL_CTX_set_default_passwd_cb ck_SSL_CTX_set_default_passwd_cb #define SSLv23_method ck_SSLv23_method #ifndef OPENSSL_NO_SSL3 #define SSLv3_method ck_SSLv3_method #endif /* OPENSSL_NO_SSL3 */ #define TLSv1_method ck_TLSv1_method #define SSLv23_client_method ck_SSLv23_client_method #ifndef OPENSSL_NO_SSL3 #define SSLv3_client_method ck_SSLv3_client_method #endif /* OPENSSL_NO_SSL3 */ #define TLSv1_client_method ck_TLSv1_client_method #define SSLv23_server_method ck_SSLv23_server_method #ifndef OPENSSL_NO_SSL3 #define SSLv3_server_method ck_SSLv3_server_method #endif /* OPENSSL_NO_SSL3 */ #define TLSv1_server_method ck_TLSv1_server_method #define SSL_library_init ck_SSL_library_init #define SSL_state_string ck_SSL_state_string #define SSL_state_string_long ck_SSL_state_string_long #define SSL_accept ck_SSL_accept #define SSL_set_cipher_list ck_SSL_set_cipher_list #define ERR_print_errors ck_ERR_print_errors #define ERR_print_errors_fp ck_ERR_print_errors_fp #define ERR_error_string ck_ERR_error_string #define ERR_get_error ck_ERR_get_error #define BIO_printf ck_BIO_printf #define BIO_ctrl ck_BIO_ctrl #define BIO_new ck_BIO_new #define BIO_s_file ck_BIO_s_file #define BIO_s_mem ck_BIO_s_mem #define BIO_s_null ck_BIO_s_null #define BIO_read ck_BIO_read #define BIO_new_file ck_BIO_new_file #define BIO_free ck_BIO_free #define X509_get_issuer_name ck_X509_get_issuer_name #define X509_verify_cert_error_string ck_X509_verify_cert_error_string #define X509_NAME_oneline ck_X509_NAME_oneline #define X509_get_subject_name ck_X509_get_subject_name #define X509_STORE_CTX_get_current_cert ck_X509_STORE_CTX_get_current_cert #define X509_get_default_cert_dir ck_X509_get_default_cert_dir #define X509_free ck_X509_free #define RSA_free ck_RSA_free #define RSA_generate_key ck_RSA_generate_key #define DH_new ck_DH_new #define DH_free ck_DH_free #define DH_generate_key ck_DH_generate_key #define DH_generate_parameters ck_DH_generate_parameters #define DSA_free ck_DSA_free #define DSA_generate_key ck_DSA_generate_key #define DSA_generate_parameters ck_DSA_generate_parameters #define PEM_read_bio_DHparams ck_PEM_read_bio_DHparams #define BN_bin2bn ck_BN_bin2bn #endif /* OS2 */ #endif /* CK_SSL */ ckcsym.h000664 045065 024037 00000000425 14767401764 012646 0ustar00fdckermit000000 000000 /* This file is for use with compilers that don't have the capability to * #define symbols on the C compiler command line. This file must * be #include'd before all other ck*.h files so that the symbols #define'd * here can be used for any subsequent conditional code. */ ckctel.c000664 045065 024037 00001111504 14767403057 012614 0ustar00fdckermit000000 000000 char *cktelv = "Telnet support, 10.0.283, 16 Apr 2023"; #define CKCTEL_C int sstelnet = 0; /* Do server-side Telnet negotiation */ /* C K C T E L -- Telnet support */ /* Authors: Telnet protocol by Frank da Cruz and Jeffrey Altman. Telnet Forward X by Jeffrey Altman Telnet START_TLS support by Jeffrey Altman Telnet AUTH and ENCRYPT support by Jeffrey Altman Telnet COMPORT support by Jeffrey Altman Telnet NEW-ENVIRONMENT support by Jeffrey Altman Telnet NAWS support by Frank da Cruz and Jeffrey Altman Telnet TERMTYPE support by Jeffrey Altman Telnet KERMIT support by Jeffrey Altman Other contributions as indicated in the code. Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Latest update: 16 April 2023 (ANSI function declarations) */ /* NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku) C-Kermit source files, must be compatible with C preprocessors that support only #ifdef, #else, #endif, #define, and #undef. Please do not use #if, logical operators, or other preprocessor features in this module. Also, don't use any ANSI C constructs except within #ifdef CK_ANSIC..#endif. */ #ifndef NONET #ifndef NOTCPIP #include "ckcsym.h" #include "ckcdeb.h" #ifdef TIMEH #include /* fdc 2012-12-17 */ #else #ifdef SYSTIMH #include #endif /* SYSTIMH */ #endif /* TIMEH */ #ifdef TNCODE #include "ckcker.h" #define TELCMDS /* to define name array */ #define TELOPTS /* to define name array */ #define SLC_NAMES /* to define name array */ #define ENCRYPT_NAMES #define AUTH_NAMES #define TELOPT_STATES #define TELOPT_MODES #define TNC_NAMES #include "ckcnet.h" #include "ckctel.h" #ifdef CK_AUTHENTICATION #include "ckuath.h" #endif /* CK_AUTHENTICATION */ #ifdef CK_SSL #include "ck_ssl.h" #endif /* CK_SSL */ #ifndef NOTERM #ifdef OS2 /* For terminal type name string */ #include "ckuusr.h" #ifndef NT #define INCL_DOSSEMAPHORES #include #undef COMMENT #else #ifndef __WATCOMC__ #define isascii __isascii #endif /* __WATCOMC__ */ #endif /* NT */ #include "ckocon.h" extern int tt_type, max_tt; extern struct tt_info_rec tt_info[]; #ifdef SSHBUILTIN #include "ckossh.h" #endif /* SSHBUILTIN */ #endif /* OS2 */ #endif /* NOTERM */ #ifdef OS2 #include #ifdef NT #include #else /* NT */ #include #endif /* NT */ #include #include "ckcsig.h" #include "ckosyn.h" #endif /* OS2 */ #ifdef NT #include /* for getpid() */ #endif /* NT */ #ifdef CK_NAWS /* Negotiate About Window Size */ #ifdef RLOGCODE _PROTOTYP( int rlog_naws, (void) ); #endif /* RLOGCODE */ #endif /* CK_NAWS */ int tn_init = 0; /* Telnet protocol initialized flag */ int tn_begun = 0; /* Telnet protocol started flag */ static int tn_first = 1; /* First time init flag */ extern int tn_exit; /* Exit on disconnect */ extern int nettype; extern int inserver; /* Running as IKSD */ char *tn_term = NULL; /* Terminal type override */ #ifdef CK_SNDLOC char *tn_loc = NULL; /* Location override */ #endif /* CK_SNDLOC */ int tn_nlm = TNL_CRLF; /* Telnet CR -> CR LF mode */ int tn_b_nlm = TNL_CR; /* Telnet Binary CR RAW mode */ int tn_b_meu = 0; /* Telnet Binary ME means U too */ int tn_b_ume = 0; /* Telnet Binary U means ME too */ int tn_wait_flg = 1; /* Telnet Wait for Negotiations */ int tn_infinite = 0; /* Telnet Bug Infinite-Loop-Check */ int tn_rem_echo = 1; /* We will echo if WILL ECHO */ int tn_b_xfer = 0; /* Telnet Binary for Xfers? */ int tn_sb_bug = 1; /* Telnet BUG - SB w/o WILL or DO */ int tn_auth_krb5_des_bug = 1; /* Telnet BUG - AUTH KRB5 DES */ /* truncates long keys */ int tn_no_encrypt_xfer = 0; /* Turn off Telnet Encrypt? */ int tn_delay_sb = 1; /* Delay SBs until safe */ int tn_auth_how = TN_AUTH_HOW_ANY; int tn_auth_enc = TN_AUTH_ENC_ANY; int tn_deb = 0; /* Telnet Debug mode */ int tn_sfu = 0; /* Microsoft SFU compatibility */ #ifdef CK_FORWARD_X char * tn_fwdx_xauthority = NULL; /* Xauthority File */ int fwdx_no_encrypt = 0; /* Forward-X requires encryption */ #endif /* CK_FORWARD_X */ #ifdef OS2 int ttnum = -1; /* Last Telnet Terminal Type sent */ int ttnumend = 0; /* Has end of list been found */ #endif /* OS2 */ char tn_msg[TN_MSG_LEN]; /* Telnet data can be rather long */ char hexbuf[TN_MSG_LEN]; char tn_msg_out[TN_MSG_LEN]; #ifdef CK_FORWARD_X CHAR fwdx_msg_out[TN_MSG_LEN]; #endif /* CK_FORWARD_X */ /* In order to prevent an infinite telnet negotiation loop we maintain a count of the number of times the same telnet negotiation message is sent. When this count hits MAXTNCNT, we do not send any more of the message. The count is stored in the tncnts[][] array. The tncnts[][] array is indexed by negotiation option (SUPPRESS GO AHEAD, TERMINAL TYPE, NAWS, etc. - see the tnopts[] array) and the four negotiation message types (WILL, WONT, DO, DONT). All telnet negotiations are kept track of in this way. The count for a message is zeroed when the "opposite" message is sent. WILL is the opposite of WONT, and DO is the opposite of DONT. For example sending "WILL SGA" increments tncnts[TELOPT_SGA][0] and zeroes tncnts[TELOPT_SGA][1]. The code that does this is in tn_sopt(). rogersh@fsj.co.jp, 18/3/1995 8/16/1998 - with the recent rewrite of the telnet state machine I don't think this code is necessary anymore. However, it can't do any harm so I am leaving it in. - Jeff 12/28/1998 - all references to tncnts[] must be done with TELOPT_INDEX(opt) because the Telnet option list is no longer contiguous. We also must allocate NTELOPTS + 1 because the TELOPT_INDEX() macro returns NTELOPTS for an invalid option number. */ #define MAXTNCNT 4 /* Permits 4 intermediate telnet firewalls/gateways */ char tncnts[NTELOPTS+1][4]; /* Counts */ char tnopps[4] = { 1,0,3,2 }; /* Opposites */ #ifdef CK_ENVIRONMENT #ifdef CK_FORWARD_X #define TSBUFSIZ 2056 #else /* CK_FORWARD_X */ #define TSBUFSIZ 1024 #endif /* CK_FORWARD_X */ char tn_env_acct[64]; char tn_env_disp[64]; char tn_env_job[64]; char tn_env_prnt[64]; char tn_env_sys[64]; char * tn_env_uservar[8][2]; int tn_env_flg = 1; #else /* CK_ENVIRONMENT */ #define TSBUFSIZ 41 int tn_env_flg = 0; #endif /* CK_ENVIRONMENT */ #ifdef COMMENT /* SIGWINCH handler moved to ckuusx.c */ #ifndef NOSIGWINCH #ifdef CK_NAWS /* Window size business */ #ifdef UNIX #include #endif /* UNIX */ #endif /* CK_NAWS */ #endif /* NOSIGWINCH */ #endif /* COMMENT */ #include "ckuusr.h" #include "ckucmd.h" #include "ckcfnp.h" /* Prototypes (must be last) */ #ifdef CK_ANSIC static int tn_outst( int ); /* fdc - 30 November 2022 */ #endif /* CK_ANSIC */ CHAR sb[TSBUFSIZ]; /* Buffer - incoming subnegotiations */ CHAR sb_out[TSBUFSIZ]; /* Buffer - outgoing subnegotiations */ int tn_duplex = 1; /* Local echo */ extern char uidbuf[]; /* User ID buffer */ extern int quiet, ttnet, ttnproto, debses, what, duplex, oldplex, local; extern int seslog, sessft, whyclosed; #ifdef OS2 #ifndef NOTERM extern int tt_rows[], tt_cols[]; extern int tt_status[VNUM]; extern int scrninitialized[]; #endif /* NOTERM */ #else /* OS2 */ extern int tt_rows, tt_cols; /* Everybody has this */ #endif /* OS2 */ extern int cmd_cols, cmd_rows; extern char namecopy[]; extern char myipaddr[]; /* Global copy of my IP address */ /* A copy of this function also appears in ck_crp.c for use by Kermit 95s * telnet cryptography DLL (k95crypt.dll) */ char * #ifdef CK_ANSIC tel_unk(int opt) /* "UNKNOWN-%u" string. */ #else tel_unk(opt) int opt; #endif /* CK_ANSIC */ { /* 2024-03-27 SMS. Added (decimal) value to "UNKNOWN" messages. */ static char val_str[ 20]; sprintf(val_str, "UNKNOWN-%u", opt); return(val_str); } #ifndef TELOPT_MACRO int #ifdef CK_ANSIC telopt_index(int opt) #else telopt_index(opt) int opt; #endif /* CK_ANSIC */ { if (opt >= 0 && opt <= TELOPT_STDERR) return(opt); else if (opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT) return(opt-88); else if (opt == TELOPT_IBM_SAK) return(opt-147); else return(NTELOPTS); } int #ifdef CK_ANSIC telopt_ok(int opt) #else telopt_ok(opt) int opt; #endif /* CK_ANSIC */ { return((opt >= TELOPT_BINARY && opt <= TELOPT_STDERR) || (opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT) || (opt == TELOPT_IBM_SAK)); } char * #ifdef CK_ANSIC telopt(int opt) #else telopt(opt) int opt; #endif /* CK_ANSIC */ { if (telopt_ok(opt)) return(telopts[telopt_index(opt)]); else return(tel_unk(opt)); } int #ifdef CK_ANSIC telopt_mode_ok(int mode) #else telopt_mode_ok(mode) int mode; #endif /* CK_ANSIC */ { return (((unsigned int)mode) <= TN_NG_MU); } char * /* Type matches ckctel.h:telopt_modes[]. */ #ifdef CK_ANSIC telopt_mode(int mode) #else telopt_mode(mode) int mode; #endif /* CK_ANSIC */ { if (telopt_mode_ok(mode)) return(telopt_modes[mode-TN_NG_RF]); else return(tel_unk(mode)); } #endif /* TELOPT_MACRO */ static int #ifdef CK_ANSIC tn_outst( int notquiet ) #else tn_outst(notquiet) int notquiet; #endif /* CK_ANSIC */ { int outstanding = 0; int x = 0; #ifdef CK_ENCRYPTION int e = 0; int d = 0; #endif /* CK_ENCRYPTION */ if (tn_wait_flg) { for (x = TELOPT_FIRST; x <= TELOPT_LAST; x++) { if (TELOPT_OK(x)) { if (TELOPT_UNANSWERED_WILL(x)) { if ( notquiet ) printf("?Telnet waiting for response to WILL %s\r\n", TELOPT(x)); debug(F111,"tn_outst","unanswered WILL",x); outstanding = 1; if ( !notquiet ) break; } if (TELOPT_UNANSWERED_DO(x)) { if ( notquiet ) printf("?Telnet waiting for response to DO %s\r\n", TELOPT(x)); debug(F111,"tn_outst","unanswered DO",x); outstanding = 1; if ( !notquiet ) break; } if (TELOPT_UNANSWERED_WONT(x)) { if ( notquiet ) printf("?Telnet waiting for response to WONT %s\r\n", TELOPT(x)); debug(F111,"tn_outst","unanswered WONT",x); outstanding = 1; if ( !notquiet ) break; } if (TELOPT_UNANSWERED_DONT(x)) { if ( notquiet ) printf("?Telnet waiting for response to DONT %s\r\n", TELOPT(x)); debug(F111,"tn_outst","unanswered DONT",x); outstanding = 1; if ( !notquiet ) break; } if (TELOPT_UNANSWERED_SB(x)) { if ( notquiet ) printf("?Telnet waiting for response to SB %s\r\n", TELOPT(x)); debug(F111,"tn_outst","unanswered SB",x); outstanding = 1; if ( !notquiet ) break; } } } #ifdef CK_AUTHENTICATION if (ck_tn_auth_in_progress()) { if (TELOPT_ME(TELOPT_AUTHENTICATION)) { if (notquiet) printf("?Telnet waiting for WILL %s subnegotiation\r\n", TELOPT(TELOPT_AUTHENTICATION)); debug(F111, "tn_outst", "ME authentication in progress", TELOPT_AUTHENTICATION ); outstanding = 1; } else if (TELOPT_U(TELOPT_AUTHENTICATION)) { if (notquiet) printf("?Telnet waiting for DO %s subnegotiation\r\n", TELOPT(TELOPT_AUTHENTICATION)); debug(F111, "tn_outst", "U authentication in progress", TELOPT_AUTHENTICATION ); outstanding = 1; } } #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION if (!outstanding) { e = ck_tn_encrypting(); d = ck_tn_decrypting(); if (TELOPT_ME(TELOPT_ENCRYPTION)) { if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && e || !TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && !e ) { if ( notquiet ) printf("?Telnet waiting for WILL %s subnegotiation\r\n", TELOPT(TELOPT_ENCRYPTION)); debug(F111, "tn_outst", "encryption mode switch", TELOPT_ENCRYPTION ); outstanding = 1; } } if (TELOPT_U(TELOPT_ENCRYPTION)) { if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && d || !TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && !d ) { if ( notquiet ) printf("?Telnet waiting for DO %s subnegotiation\r\n", TELOPT(TELOPT_ENCRYPTION)); debug(F111, "tn_outst", "decryption mode switch", TELOPT_ENCRYPTION ); outstanding = 1; } } } #endif /* CK_ENCRYPTION */ } /* if (tn_wait_flg) */ #ifdef IKS_OPTION /* Even if we are not waiting for Telnet options we must wait for */ /* Kermit Telnet Subnegotiations if we have sent a request to the */ /* other guy. Otherwise we will get out of sync. */ if (!outstanding) { if (TELOPT_U(TELOPT_KERMIT) && (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start || TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop || !TELOPT_SB(TELOPT_KERMIT).kermit.sop) ) { if ( notquiet ) printf("?Telnet waiting for SB %s negotiation\r\n", TELOPT(TELOPT_KERMIT)); debug(F111,"tn_outst","U kermit in progress",TELOPT_KERMIT); outstanding = 1; } } #endif /* IKS_OPTION */ #ifdef TN_COMPORT if (!outstanding) { if (TELOPT_ME(TELOPT_COMPORT)) { if (TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb) { if (notquiet) printf("?Telnet waiting for SB %s negotiation\r\n", TELOPT(TELOPT_COMPORT)); debug(F111,"tn_outst","ComPort SB in progress",TELOPT_COMPORT); outstanding = 1; } if (TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms) { if (notquiet) printf("?Telnet waiting for SB %s MODEM_STATUS negotiation\r\n", TELOPT(TELOPT_COMPORT)); debug(F111,"tn_outst","ComPort SB MS in progress",TELOPT_COMPORT); outstanding = 1; } } } #endif /* TN_COMPORT */ return(outstanding); } int istncomport() { #ifdef TN_COMPORT if (!local) return(0); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (TELOPT_ME(TELOPT_COMPORT)) return(1); else #endif /* TN_COMPORT */ return(0); } /* tn_wait() -- Wait for response to Telnet negotiation. */ /* Wait for up to seconds for the response to arrive. Place all non-telnet data into Telnet Wait Buffer. If response does arrive return 1, else return 0. */ #ifndef TN_WAIT_BUF_SZ #define TN_WAIT_BUF_SZ 4096 #endif /* TN_WAIT_BUF_SZ */ static char tn_wait_buf[TN_WAIT_BUF_SZ]; static int tn_wait_idx = 0; #ifndef TN_TIMEOUT #define TN_TIMEOUT 120 #endif /* TN_TIMEOUT */ static int tn_wait_tmo = TN_TIMEOUT; #ifdef CKSPINNER VOID prtwait(state) int state; { switch (state % 4) { case 0: printf("/"); break; case 1: printf("-"); break; case 2: printf("\\"); break; case 3: printf("|"); break; } } #endif /* CKSPINNER */ static int nflag = 0; int #ifdef CK_ANSIC tn_wait(char * where) #else tn_wait(where) char * where; #endif /* CK_ANSIC */ /* tn_wait */ { extern int ckxech, local; int ch = 0, count = 0; #ifndef NOHINTS int nohintgiven = 1; extern int hints; #endif /* NOHINTS */ int outstanding; #ifdef TN_COMPORT int savcarr; extern int ttcarr; #endif /* TN_COMPORT */ /* if (!IS_TELNET()) return(1); */ rtimer(); debug(F110,"tn_wait waiting for",where,0); tn_wait_tmo = TN_TIMEOUT; debug(F111,"tn_wait","timeout",tn_wait_tmo); outstanding = tn_outst(0); debug(F111,"tn_wait","outstanding",outstanding); debug(F111,"tn_wait","tn_wait_flg",tn_wait_flg); /* The following is meant to be !(||). We only want to return */ /* immediately if both the tn_wait_flg && tn_outst() are false */ if (!(outstanding || tn_wait_flg)) /* If no need to wait */ return(1); /* Don't. */ if (tn_deb || debses) tn_debug(""); #ifdef CKSPINNER if (!sstelnet && !quiet) prtwait(0); #endif /* CKSPINNER */ /* Wait up to TN_TIMEOUT sec for responses to outstanding telnet negs */ do { #ifdef NTSIG ck_ih(); #endif /* NTSIG */ ch = ttinc(1); if (ch == -1) { /* Timed out */ if (!sstelnet && !quiet) { /* Let user know... */ #ifdef CKSPINNER printf("\b"); prtwait(gtimer()); #else if (nflag == 0) { printf(" Negotiations."); nflag++; } if (nflag > 0) { printf("."); nflag++; fflush(stdout); } #endif /* CKSPINNER */ } } else if (ch < -1) { printf("\r\n?Connection closed by peer.\r\n"); if (tn_deb || debses) tn_debug(""); return(-1); } else switch (ch) { case IAC: #ifdef CKSPINNER if (!sstelnet && !quiet) printf("\b"); #endif /* CKSPINNER */ ch = tn_doop((CHAR)(ch & 0xff),inserver?ckxech:duplex,ttinc); #ifdef CKSPINNER if (!sstelnet && !quiet) { prtwait(gtimer()); } #endif /* CKSPINNER */ debug(F101,"tn_wait tn_doop","",ch); switch (ch) { case 1: duplex = 1; /* Turn on echoing */ if (inserver) ckxech = 1; break; case 2: duplex = 0; /* Turn off echoing */ if (inserver) ckxech = 0; break; case 3: tn_wait_buf[tn_wait_idx++] = IAC; break; case 4: /* IKS event */ case 6: /* Logout */ break; case -1: if (!quiet) printf("?Telnet Option negotiation error.\n"); if (tn_deb || debses) tn_debug(""); return(-1); case -2: printf("?Connection closed by peer.\n"); if (tn_deb || debses) tn_debug(""); ttclos(0); return(-2); default: if (ch < 0) { if (tn_deb || debses) tn_debug(""); return(ch); } } /* switch */ break; default: #ifdef CKSPINNER if (!sstelnet && !quiet) { printf("\b"); prtwait(gtimer()); } #endif /* CKSPINNER */ tn_wait_buf[tn_wait_idx++] = (CHAR)(ch & 0xff); } /* switch */ outstanding = tn_outst(0); if ( outstanding && ch != IAC ) { int timer = gtimer(); if ( timer > tn_wait_tmo ) { if (!sstelnet) { printf( "\r\n?Telnet Protocol Timeout - connection closed\r\n"); if (tn_deb || debses) tn_debug( ""); tn_outst(1); } /* if we do not close the connection, then we will block */ /* the next time we hit a wait. and if we don't we will */ /* do the wrong thing if the host sends 0xFF and does */ /* not intend it to be an IAC. */ ttclos(0); whyclosed = WC_TELOPT; return(-1); } #ifndef NOHINTS else if ( hints && timer > 30 && nohintgiven && !inserver ) { #ifdef CKSPINNER printf("\b"); #else /* CKSPINNER */ printf("\r\n"); #endif /* CKSPINNER */ printf("*************************\r\n"); printf("The Telnet %s is not sending required responses.\r\n\r\n", sstelnet?"client":"server"); tn_outst(1); printf("\nYou can continue to wait or you can cancel with Ctrl-C.\r\n"); printf("In case the Telnet server never responds as required,\r\n"); printf("you can try connecting to this host with TELNET /NOWAIT.\r\n"); printf("Use SET HINTS OFF to suppress further hints.\r\n"); printf("*************************\r\n"); nohintgiven = 0; } #endif /* NOHINTS */ } #ifdef TN_COMPORT /* Must disable carrier detect check if we are using Telnet Comport */ savcarr = ttcarr; ttscarr(CAR_OFF); count = ttchk(); ttscarr(savcarr); #else /* TN_COMPORT */ count = ttchk(); #endif /* TN_COMPORT */ } while ((tn_wait_idx < TN_WAIT_BUF_SZ) && (outstanding && count >= 0)); if (tn_wait_idx == TN_WAIT_BUF_SZ) { if (tn_deb || debses) tn_debug(""); return(0); } if (!sstelnet && !quiet) { #ifdef CKSPINNER printf("\b \b"); #else if (nflag > 0) { printf(" (OK)\n"); nflag = -1; } #endif /* CKSPINNER */ } if (tn_deb || debses) tn_debug(""); return(0); } /* Push data from the Telnet Wait Buffer into the I/O Queue */ /* Return 1 on success */ int tn_push() { #ifdef NETLEBUF extern int tt_push_inited; #endif /* NETLEBUF */ /* if (!IS_TELNET()) return(1); */ if (tn_wait_idx) { ckhexdump((CHAR *)"tn_push",tn_wait_buf,tn_wait_idx); #ifdef NETLEBUF if (!tt_push_inited) /* Local handling */ le_init(); le_puts((CHAR *)tn_wait_buf,tn_wait_idx); #else /* External handling... */ #ifdef OS2 /* K95 has its own way */ le_puts((CHAR *)tn_wait_buf,tn_wait_idx); #else #ifdef TTLEBUF /* UNIX, etc */ le_puts((CHAR *)tn_wait_buf,tn_wait_idx); #else /* If you see this message in AOS/VS, OS-9, VOS, etc, you need to copy the #ifdef TTLEBUF..#endif code from ckutio.c to the corresponding places in your ck?tio.c module. */ printf("tn_push called but not implemented - data lost.\n"); #endif /* TTLEBUF */ #endif /* OS2 */ #endif /* NETLEBUF */ tn_wait_idx = 0; } tn_wait_tmo = TN_TIMEOUT; /* Reset wait timer stats */ return(1); } /* T N _ S O P T */ /* Sends a telnet option, avoids loops. Returns 1 if command was sent, 0 if not, -1 on error. */ int #ifdef CK_ANSIC tn_sopt( int cmd, int opt ) /* TELNET SEND OPTION */ #else tn_sopt(cmd,opt) int cmd, opt; #endif /* CK_ANSIC */ { CHAR buf[5]; char msg[128]; int rc; if (ttnet != NET_TCPB) return(-1); /* Must be TCP/IP */ if (ttnproto != NP_TELNET) return(-1); /* Must be telnet protocol */ if (!TELCMD_OK(cmd)) return(-1); if (TELOPT_OK(opt)) { if (cmd == DO && TELOPT_UNANSWERED_DO(opt)) return(0); if (cmd == WILL && TELOPT_UNANSWERED_WILL(opt)) return(0); if (cmd == DONT && TELOPT_UNANSWERED_DONT(opt)) return(0); if (cmd == WONT && TELOPT_UNANSWERED_WONT(opt)) return(0); } #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if (cmd == DO && opt == TELOPT_AUTHENTICATION) buf[0] = 0; if (tn_infinite && TELOPT_OK(opt)) { /* See comment above about */ int index = TELOPT_INDEX(opt); /* preventing infinite loops */ int m = cmd - WILL; if (tncnts[index][m] > MAXTNCNT) { #ifdef DEBUG if (tn_deb || debses || deblog) { ckmakmsg(msg,sizeof(msg), "TELNET negotiation loop ", TELCMD(cmd), " ", TELOPT(opt)); debug(F101,msg,"",opt); if (tn_deb || debses) tn_debug(msg); } #endif /* DEBUG */ return(0); } tncnts[index][m]++; tncnts[index][tnopps[m]] = 0; } buf[0] = (CHAR) IAC; buf[1] = (CHAR) (cmd & 0xff); buf[2] = (CHAR) (opt & 0xff); buf[3] = (CHAR) 0; #ifdef DEBUG if ((tn_deb || debses || deblog) && cmd != SB) ckmakmsg(msg,sizeof(msg),"TELNET SENT ",TELCMD(cmd)," ", TELOPT(opt)); #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif debug(F101,msg,"",opt); if ((tn_deb || debses) && cmd != SB) tn_debug(msg); rc = (ttol(buf,3) < 3); #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (TELOPT_OK(opt)) { if (cmd == DONT && TELOPT_UNANSWERED_DO(opt)) TELOPT_UNANSWERED_DO(opt) = 0; if (cmd == WONT && TELOPT_UNANSWERED_WILL(opt)) TELOPT_UNANSWERED_WILL(opt) = 0; if (cmd == DO && TELOPT_UNANSWERED_DONT(opt)) TELOPT_UNANSWERED_DONT(opt) = 0; if (cmd == WILL && TELOPT_UNANSWERED_WONT(opt)) TELOPT_UNANSWERED_WONT(opt) = 0; } return(1); } /* Send a telnet sub-option */ /* Returns 1 if command was sent, 0 if not, -1 on error */ int #ifdef CK_ANSIC tn_ssbopt( int opt, int sub, CHAR * data, int len ) #else tn_ssbopt(opt,sub,data,len) int opt, sub; CHAR * data; int len; #endif /* CK_ANSIC */ { CHAR buf[256]; int rc; if (ttnet != NET_TCPB) return(0); /* Must be TCP/IP */ if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */ if (!TELOPT_OK(opt)) return(-1); if (len < 0 || len > 250) { debug(F111,"Unable to Send TELNET SB - data too long","len",len); return(-1); /* Data too long */ } #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { if (ttchk() < 0) return(-1); else return(1); } #endif /* CK_SSL */ if (!data) len = 0; buf[0] = (CHAR) IAC; buf[1] = (CHAR) (SB & 0xff); buf[2] = (CHAR) (opt & 0xff); buf[3] = (CHAR) (sub & 0xff); if (data && len > 0) { memcpy(&buf[4],data,len); } buf[4+len] = (CHAR) IAC; buf[5+len] = (CHAR) SE; #ifdef DEBUG if (tn_deb || debses || deblog) { if (opt == TELOPT_START_TLS && sub == 1) ckmakmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ", TELOPT(opt)," FOLLOWS IAC SE",NULL); else if (opt == TELOPT_TTYPE && sub == 1) ckmakmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ", TELOPT(opt), " SEND IAC SE",NULL); else if (opt == TELOPT_TTYPE && sub == 0) ckmakxmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ",TELOPT(opt)," IS ", (char *)data," IAC SE",NULL,NULL,NULL,NULL,NULL,NULL,NULL); else if (opt == TELOPT_NEWENVIRON) { int i, quote; ckmakmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ", TELOPT(TELOPT_NEWENVIRON)," ", sub == TELQUAL_SEND ? "SEND" : sub == TELQUAL_IS ? "IS" : sub == TELQUAL_INFO ?"INFO" : tel_unk(sub) ); for (i = 0, quote = 0; i < len; i++) { if (quote) { sprintf(hexbuf,"%02x",data[i]); /* safe but ugly */ ckstrncat(tn_msg_out,hexbuf,TN_MSG_LEN); quote = 0; } else { switch (data[i]) { case TEL_ENV_USERVAR: ckstrncat(tn_msg_out," USERVAR ",TN_MSG_LEN); break; case TEL_ENV_VAR: ckstrncat(tn_msg_out," VAR ",TN_MSG_LEN); break; case TEL_ENV_VALUE: ckstrncat(tn_msg_out," VALUE ",TN_MSG_LEN); break; case TEL_ENV_ESC: ckstrncat(tn_msg_out," ESC ",TN_MSG_LEN); quote = 1; break; case IAC: ckstrncat(tn_msg_out," IAC ",TN_MSG_LEN); break; default: sprintf(hexbuf,"%c",data[i]); /* safe but ugly */ ckstrncat(tn_msg_out,hexbuf,TN_MSG_LEN); } } } ckstrncat(tn_msg_out," IAC SE",TN_MSG_LEN); } else { sprintf(hexbuf,"%02x",sub); /* safe but ugly */ ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(opt), " ", hexbuf, " IAC SE", NULL,NULL,NULL,NULL,NULL,NULL,NULL ); } } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif /* OS2 */ #ifdef DEBUG debug(F101,tn_msg_out,"",opt); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol(buf,6+len) < 6+len); #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); return(1); } /* tn_flui() -- Processes all waiting data for Telnet commands. All non-Telnet data is to be stored into the Telnet Wait Buffer. Returns 1 on success. */ int tn_flui() { extern int ckxech; int x = 0; /* if (!IS_TELNET()) return(0); */ /* Wait up to 5 sec for responses to outstanding telnet negotiations */ while (x >= 0 && ttchk() > 0 && tn_wait_idx < TN_WAIT_BUF_SZ) { x = ttinc(1); switch (x) { case IAC: x = tn_doop((CHAR)(x & 0xff),inserver?ckxech:duplex,ttinc); debug(F101,"tn_flui tn_doop","",x); switch (x) { case 1: /* Turn on echoing */ duplex = 1; if (inserver) ckxech = 1; break; case 2: /* Turn off echoing */ duplex = 0; if (inserver) ckxech = 0; break; case 3: tn_wait_buf[tn_wait_idx++] = IAC; break; case 4: /* IKS event */ case 6: /* Logout */ break; } break; default: if (x >= 0) tn_wait_buf[tn_wait_idx++] = x; } } return(1); } unsigned char * tn_get_display() { char * disp = NULL; static char tmploc[256]; /* Must compute the DISPLAY string we are going to send to the host */ /* If one is not assigned, do not send a string unless the user has */ /* explicitedly requested we try to send one via X-Display Location */ /* But do not send a string at all if FORWARD_X is in use. */ /* Note that in Kermit 95 this is also used for X11 forwarding */ /* over SSH */ /* if (!IS_TELNET()) return(0); */ debug(F110,"tn_get_display() myipaddr",myipaddr,0); #ifdef CK_ENVIRONMENT debug(F110,"tn_get_display() tn_env_disp",tn_env_disp,0); if (tn_env_disp[0]) { int colon = ckindex(":",tn_env_disp,0,0,1); if ( !colon ) { ckmakmsg(tmploc,256,myipaddr,":",tn_env_disp,NULL); disp = tmploc; } else if ( ckindex("localhost:",tn_env_disp,0,0,0) || ckindex("unix:",tn_env_disp,0,0,0) || ckindex("127.0.0.1:",tn_env_disp,0,0,0) || !ckstrcmp("0:",tn_env_disp,2,1) || tn_env_disp[0] == ':' ) { ckmakmsg(tmploc,256,myipaddr,":",&tn_env_disp[colon],NULL); disp = tmploc; } else disp = tn_env_disp; } else #endif /* CK_ENVIRONMENT */ if ((TELOPT_ME(TELOPT_XDISPLOC) || TELOPT_U(TELOPT_FORWARD_X)) #if OS2 #ifdef SSHBUILTIN || (IS_SSH() && ssh_get_iparam(SSH_IPARAM_XFW)) #endif /* SSHBUILTIN */ #endif /* OS2 */ ) { ckmakmsg(tmploc,256,myipaddr,":0.0",NULL,NULL); disp = tmploc; } debug(F110,"tn_get_display() returns",disp,0); return((CHAR *)disp); } #ifdef CK_FORWARD_X static Xauth fake_xauth = {0,0,NULL,0,NULL,0,NULL,0,NULL}; static Xauth *real_xauth=NULL; /* * Author: Jim Fulton, MIT X Consortium * * fwdx_parse_displayname - * display a display string up into its component parts */ #ifdef UNIX #define UNIX_CONNECTION "unix" #define UNIX_CONNECTION_LENGTH 4 #endif #endif /* CK_FORWARD_X */ #ifdef CK_FWDX_PARSE_DISPN /* * private utility routines */ static int #ifdef CK_ANSIC XmuGetHostname (char *buf, int maxlen) #else XmuGetHostname (buf, maxlen) char *buf; int maxlen; #endif /* CK_ANSIC */ { int len; #ifdef NEED_UTSNAME /* * same host name crock as in server and xinit. */ struct utsname name; uname (&name); len = strlen (name.nodename); if (len >= maxlen) len = maxlen - 1; strncpy (buf, name.nodename, len); buf[len] = '\0'; #else buf[0] = '\0'; (void) gethostname (buf, maxlen); buf [maxlen - 1] = '\0'; len = strlen(buf); #endif /* hpux */ return len; } static char * #ifdef CK_ANSIC copystring (char *src, int len) #else copystring (src, len) char *src; int len; #endif /* CK_ANSIC */ { char *cp; if (!src && len != 0) return NULL; cp = malloc (len + 1); if (cp) { if (src) strncpy (cp, src, len); cp[len] = '\0'; } return cp; } static char * #ifdef CK_ANSIC get_local_hostname (char *buf, int maxlen) #else get_local_hostname (buf, maxlen) char *buf; int maxlen; #endif { buf[0] = '\0'; (void) XmuGetHostname (buf, maxlen); return (buf[0] ? buf : NULL); } #ifndef UNIX static char * copyhostname () { char buf[256]; return (get_local_hostname (buf, sizeof buf) ? copystring (buf, strlen (buf)) : NULL); } #endif /* * Parse X11 display name. This is used by both Telnet X11 forwarding, * and on Kermit 95, X11 forwarding over SSH. */ int #ifdef CK_ANSIC fwdx_parse_displayname (char *displayname, int *familyp, char **hostp, int *dpynump, int *scrnump, char **restp) #else fwdx_parse_displayname (displayname, familyp, hostp, dpynump, scrnump, restp) char *displayname; int *familyp; /* return */ char **hostp; /* return */ int *dpynump, *scrnump; /* return */ char **restp; /* return */ #endif /* CK_ANSIC */ { char *ptr; /* work variables */ int len; /* work variable */ int family = -1; /* value to be returned */ char *host = NULL; /* must free if set and error return */ int dpynum = -1; /* value to be returned */ int scrnum = 0; /* value to be returned */ char *rest = NULL; /* must free if set and error return */ int dnet = 0; /* if 1 then using DECnet */ /* check the name */ if (!displayname || !displayname[0]) return 0; /* must have at least :number */ ptr = (char *)strchr(displayname, ':'); if (!ptr || !ptr[1]) return 0; if (ptr[1] == ':') { if (ptr[2] == '\0') return 0; dnet = 1; } /* * get the host string; if none is given, use the most effiecient path */ len = (ptr - displayname); /* length of host name */ if (len == 0) { /* choose most efficient path */ #ifdef UNIX host = copystring (UNIX_CONNECTION, UNIX_CONNECTION_LENGTH); family = FamilyLocal; #else if (dnet) { host = copystring ("0", 1); family = FamilyDECnet; } else { host = copyhostname (); family = FamilyInternet; } #endif } else { host = copystring (displayname, len); if (dnet) { family = dnet; } else { #ifdef UNIX if (host && strcmp (host, UNIX_CONNECTION) == 0) family = FamilyLocal; else #endif family = FamilyInternet; } } if (!host) return 0; /* * get the display number; we know that there is something after the * colon (or colons) from above. note that host is now set and must * be freed if there is an error. */ if (dnet) ptr++; /* skip the extra DECnet colon */ ptr++; /* move to start of display num */ { register char *cp; for (cp = ptr; *cp && isascii(*cp) && isdigit(*cp); cp++) ; len = (cp - ptr); /* check present and valid follow */ if (len == 0 || (*cp && *cp != '.')) { free (host); return 0; } dpynum = atoi (ptr); /* it will handle num. as well */ ptr = cp; } /* * now get screen number if given; ptr may point to nul at this point */ if (ptr[0] == '.') { register char *cp; ptr++; for (cp = ptr; *cp && isascii(*cp) && isdigit(*cp); cp++) ; len = (cp - ptr); if (len == 0 || (*cp && *cp != '.')) { /* all prop name */ free (host); return 0; } scrnum = atoi (ptr); /* it will handle num. as well */ ptr = cp; } /* * and finally, get any additional stuff that might be following the * the screen number; ptr must point to a period if there is anything */ if (ptr[0] == '.') { ptr++; len = strlen (ptr); if (len > 0) { rest = copystring (ptr, len); if (!rest) { free (host); return 1; } } } /* * and we are done! */ if ( familyp ) *familyp = family; if ( hostp ) *hostp = host; else free(host); if ( dpynump ) *dpynump = dpynum; if ( scrnump ) *scrnump = scrnum; if ( restp ) *restp = rest; else free(rest); return 1; } #endif /* CK_FWDX_PARSE_DISPN */ #ifdef CK_FORWARD_X int #ifdef CK_ANSIC fwdx_tn_sb( unsigned char * sb, int n ) #else fwdx_tn_sb( sb, n ) unsigned char * sb; int n; #endif /* CK_ANSIC */ { unsigned short hchannel, nchannel; unsigned char * p; int i; int rc = -1; /* check to ensure we have negotiated Forward X */ if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) || !sstelnet && !TELOPT_U(TELOPT_FORWARD_X) ) { debug(F100,"fwdx_tn_sb() not negotiated","",0); return(0); } #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ switch (sb[0]) { case FWDX_SCREEN: if (sstelnet && n == 4) rc = fwdx_create_listen_socket(sb[1]); break; case FWDX_OPEN: if ( !sstelnet && n >= 5 ) { p = (unsigned char *) &nchannel; i = 1; /* IAC quoting has been stripped in tn_sb() */ p[0] = sb[i++]; p[1] = sb[i++]; hchannel = ntohs(nchannel); rc = fwdx_open_client_channel(hchannel); if ( rc < 0 ) { /* Failed; Send CLOSE channel */ fwdx_send_close(hchannel); rc = 0; /* Do not consider this to be a telnet error */ } #ifdef NT if ( !TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started ) { ckThreadBegin( &fwdx_thread,32655, 0, FALSE, 0 ) ; TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 1; } #endif /* NT */ } break; case FWDX_CLOSE: p = (unsigned char *) &nchannel; i = 1; /* IAC quoting has been stripped in tn_sb() */ p[0] = sb[i++]; p[1] = sb[i++]; hchannel = ntohs(nchannel); fwdx_close_channel(hchannel); rc = 0; /* no errors when closing */ break; case FWDX_DATA: p = (unsigned char *) &nchannel; i = 1; /* IAC quoting has been stripped in tn_sb() */ p[0] = sb[i++]; p[1] = sb[i++]; hchannel = ntohs(nchannel); rc = fwdx_send_xauth_to_xserver(hchannel,(CHAR *)&sb[3],n-5); if ( rc >= 0 && n-5-rc > 0) { rc = fwdx_write_data_to_channel(hchannel,(char *)&sb[3+rc],n-5-rc); if ( rc < 0 ) { /* Failed; Send CLOSE channel */ rc = fwdx_send_close(hchannel); } } break; case FWDX_OPTIONS: if ( sstelnet ) { #ifndef FWDX_SERVER rc = 0; #else rc = fwdx_server_accept_options((char*)&sb[2],n-3); #endif } else { rc = fwdx_client_reply_options((char *)&sb[2],n-3); if ( rc >= 0 ) { rc = tn_sndfwdx(); } } break; case FWDX_OPT_DATA: switch ( sb[1] ) { default: rc = 0; /* we don't recognize, not an error */ } break; case FWDX_XOFF: case FWDX_XON: if ( !sstelnet ) { p = (unsigned char *) &nchannel; i = 1; /* IAC quoting has been stripped in tn_sb() */ p[0] = sb[i++]; p[1] = sb[i++]; hchannel = ntohs(nchannel); TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[hchannel].suspend = (sb[0] == FWDX_XOFF); rc = 0; } break; } return(rc < 0 ? -1 : 0); } int #ifdef CK_ANSIC fwdx_send_xauth_to_xserver(int channel, unsigned char * data, int len) #else fwdx_send_xauth_to_xserver(channel, data, len) int channel; unsigned char * data; int len; #endif /* CK_ANSIC */ { int name_len, data_len, i; for (i = 0; i < MAXFWDX ; i++) { if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel) break; } if ( i == MAXFWDX ) goto auth_err; if (!TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth) return(0); if (len < 12) goto auth_err; /* Parse the lengths of variable-length fields. */ if (data[0] == 0x42) { /* byte order MSB first. */ /* Xauth packets appear to always have this format */ if ( data[1] != 0x00 || data[2] != 0x00 || data[3] != 0x0B || data[4] != 0x00 || data[5] != 0x00 ) goto auth_err; name_len = (data[6] << 8) + data[7]; data_len = (data[8] << 8) + data[9]; } else if (data[0] == 0x6c) { /* Byte order LSB first. */ /* Xauth packets appear to always have this format */ if ( data[1] != 0x00 || data[2] != 0x0B || data[3] != 0x00 || data[4] != 0x00 || data[5] != 0x00 ) goto auth_err; name_len = data[6] + (data[7] << 8); data_len = data[8] + (data[9] << 8); } else { /* bad byte order byte */ goto auth_err; } /* Check if the whole packet is in buffer. */ if (len < 12 + ((name_len + 3) & ~3) + ((data_len + 3) & ~3)) goto auth_err; /* If the Telnet Server allows a real Xauth message to be sent */ /* Then let the message be processed by the Xserver. */ if (name_len + data_len > 0) { TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0; return(0); } else /* If an empty Xauth message was received. We are going to */ /* send our own Xauth message using the real Xauth data. And */ /* then send any other data in the buffer. */ { int dpynum, scrnum, family; char *display, *host = NULL, *rest = NULL; /* parse the local DISPLAY env var */ display = getenv("DISPLAY"); if ( !display ) display = "127.0.0.1:0.0"; if (fwdx_parse_displayname(display, &family, &host, &dpynum, &scrnum, &rest)) { char * disp_no = ckitoa(dpynum); /* should be unsigned */ if (family == FamilyLocal) { /* call with address = "" */ char address[300] = "localhost"; gethostname(address, sizeof(address) - 1); real_xauth = XauGetAuthByAddr(family, strlen(address), address, strlen(disp_no), disp_no, 0, NULL); } else if (family == FamilyInternet) { /* call with address = 4 bytes numeric ip addr (MSB) */ struct hostent *hi; if ((hi = gethostbyname(host))) real_xauth = XauGetAuthByAddr(family, 4, hi->h_addr, strlen(disp_no), disp_no, 0, NULL); } } if (host) free(host); if (rest) free(rest); if (!real_xauth) { TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0; return(0); } if (!strncmp(real_xauth->name, "MIT-MAGIC-COOKIE-1", real_xauth->name_length)) { char msg[64]; name_len = real_xauth->name_length; data_len = 16; if ( data[0] == 0x42 ) { msg[0] = 0x42; /* MSB order */ msg[1] = msg[2] = 0; msg[3] = 0x0B; msg[4] = msg[5] = 0; msg[6] = (name_len >> 8); msg[7] = (name_len & 0xFF); msg[8] = (data_len >> 8); msg[9] = (data_len & 0xFF); } else { msg[0] = 0x6c; /* LSB order */ msg[1] = 0; msg[2] = 0x0B; msg[3] = msg[4] = msg[5] = 0; msg[6] = (name_len & 0xFF); msg[7] = (name_len >> 8); msg[8] = (data_len & 0xFF); msg[9] = (data_len >> 8); } msg[10] = msg[11] = 0; memcpy(&msg[12],real_xauth->name,18); msg[30] = msg[31] = 0; memcpy(&msg[32],real_xauth->data,16); if (fwdx_write_data_to_channel(channel,(char *)msg,48) < 0) { TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0; return(-1); } else { TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0; return(12); } } else { TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0; return(0); /* we do not know how to handle this type yet */ } } auth_err: debug(F100,"fwdx_send_xauth_to_xserver error","",0); return(-1); } #ifdef COMMENT int #ifdef CK_ANSIC fwdx_authorize_channel(int channel, unsigned char * data, int len) #else fwdx_authorize_channel(channel, data, len) int channel; unsigned char * data; int len; #endif /* CK_ANSIC */ { /* XXX maybe we should have some retry handling if not the whole first * authorization packet arrives complete */ if ( !TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].authorized ) { int name_len, data_len; if (len < 12) goto auth_err; /* Parse the lengths of variable-length fields. */ if (data[0] == 0x42) { /* byte order MSB first. */ /* Xauth packets appear to always have this format */ if ( data[1] != 0x00 || data[2] != 0x00 || data[3] != 0x0B || data[4] != 0x00 || data[5] != 0x00 ) goto auth_err; name_len = (data[6] << 8) + data[7]; data_len = (data[8] << 8) + data[9]; } else if (data[0] == 0x6c) { /* Byte order LSB first. */ /* Xauth packets appear to always have this format */ if ( data[1] != 0x00 || data[2] != 0x0B || data[3] != 0x00 || data[4] != 0x00 || data[5] != 0x00 ) goto auth_err; name_len = data[6] + (data[7] << 8); data_len = data[8] + (data[9] << 8); } else { /* bad byte order byte */ goto auth_err; } /* Check if authentication protocol matches. */ if (name_len != fake_xauth.name_length || memcmp(data + 12, fake_xauth.name, name_len) != 0) { /* connection uses different authentication protocol */ goto auth_err; } /* Check if authentication data matches our fake data. */ if (data_len != fake_xauth.data_length || memcmp(data + 12 + ((name_len + 3) & ~3), fake_xauth.data, fake_xauth.data_length) != 0) { /* auth data does not match fake data */ goto auth_err; } /* substitute the fake data with real data if we have any */ if (real_xauth && real_xauth->data) memcpy(data + 12 + ((name_len + 3) & ~3), real_xauth->data, data_len); TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].authorized = 1; } return(0); auth_err: return(-1); } #endif /* COMMENT */ int #ifdef CK_ANSIC fwdx_send_close(int channel) #else fwdx_send_close(channel) int channel; #endif /* CK_ANSIC */ { unsigned short nchannel; int i,rc; CHAR * p; #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ nchannel = htons(channel); p = (unsigned char *) &nchannel; i = 0; sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_FORWARD_X; /* Forward X */ sb_out[i++] = FWDX_CLOSE; /* Open */ sb_out[i++] = p[0]; /* First Byte of Channel */ if ( p[0] == IAC ) sb_out[i++] = IAC; sb_out[i++] = p[1]; /* Second Byte of Channel */ if ( p[1] == IAC ) sb_out[i++] = IAC; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg((char *)fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ", TELOPT(TELOPT_FORWARD_X), " CLOSE CHANNEL=",ckitoa(channel)," IAC SE", NULL,NULL,NULL,NULL,NULL,NULL,NULL ); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,(char *)fwdx_msg_out,"",0); if (tn_deb || debses) tn_debug((char *)fwdx_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); return(0); } int #ifdef CK_ANSIC fwdx_send_open(int channel) #else /* CK_ANSIC */ fwdx_send_open(channel) int channel; #endif /* CK_ANSIC */ { unsigned short nchannel; int i, rc; CHAR * p; #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ nchannel = htons(channel); p = (unsigned char *) &nchannel; i = 0; sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_FORWARD_X; /* Forward X */ sb_out[i++] = FWDX_OPEN; /* Open */ sb_out[i++] = p[0]; /* First Byte of Channel */ if ( p[0] == IAC ) sb_out[i++] = IAC; sb_out[i++] = p[1]; /* Second Byte of Channel */ if ( p[1] == IAC ) sb_out[i++] = IAC; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg((char *)fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ", TELOPT(TELOPT_FORWARD_X), " OPEN CHANNEL=",ckitoa(channel)," IAC SE", NULL,NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,(char *)fwdx_msg_out,"",0); if (tn_deb || debses) tn_debug((char *)fwdx_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); return(0); } int #ifdef CK_ANSIC fwdx_client_reply_options(char *opts, int n) #else fwdx_client_reply_options(opts, n) char *opts; int n; #endif /* CK_ANSIC */ { int i,j,rc; #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ i = 0; sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_FORWARD_X; /* Forward X */ sb_out[i++] = FWDX_OPTIONS; /* Options */ /* Look for the options we recognize and will support for this session */ /* and reply with their bytes set */ for (j=0; j= 2045 && (i < len-1) ) { sb_priv[j++] = (CHAR) IAC; /* End of Subnegotiation */ sb_priv[j++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg( (char *)fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ", TELOPT(TELOPT_FORWARD_X), " DATA CHANNEL=",ckitoa(channel)," ", NULL,NULL,NULL,NULL,NULL,NULL,NULL ); tn_hex((CHAR *)fwdx_msg_out, TN_MSG_LEN,&sb_priv[j_sav],j-(j_sav+2)); ckstrncat((char *)fwdx_msg_out," IAC SE",TN_MSG_LEN); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,(char *)fwdx_msg_out,"",0); if (tn_deb || debses) tn_debug((char *)fwdx_msg_out); #endif /* DEBUG */ rc = (ttol(sb_priv,j) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) { debug(F110,"fwdx_send_data_from_channel()","ttol() failed",0); return(-1); } j = 0; sb_priv[j++] = (CHAR) IAC; /* I Am a Command */ sb_priv[j++] = (CHAR) SB; /* Subnegotiation */ sb_priv[j++] = TELOPT_FORWARD_X; /* Forward X */ sb_priv[j++] = FWDX_DATA; /* Data */ sb_priv[j++] = p[0]; /* First Byte of Channel */ if ( p[0] == IAC ) sb_priv[j++] = IAC; sb_priv[j++] = p[1]; /* Second Byte of Channel */ if ( p[1] == IAC ) sb_priv[j++] = IAC; } } sb_priv[j++] = (CHAR) IAC; /* End of Subnegotiation */ sb_priv[j++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg( (char *)fwdx_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_FORWARD_X), " DATA ",ckctox(p[0],1)," ",ckctox(p[1],1)," ", NULL,NULL,NULL,NULL,NULL); tn_hex((CHAR *)fwdx_msg_out,TN_MSG_LEN,&sb_priv[6],j-8); ckstrncat((char *)fwdx_msg_out," IAC SE",TN_MSG_LEN); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,(char *)fwdx_msg_out,"",0); if (tn_deb || debses) tn_debug((char *)fwdx_msg_out); #endif /* DEBUG */ rc = (ttol(sb_priv,j) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if ( rc ) { debug(F110,"fwdx_send_data_from_channel()","ttol() failed",0); return(-1); } return(0); } #ifdef COMMENT static unsigned char * #ifdef CK_ANSIC fwdx_add_quoted_twobyte(unsigned char *p, unsigned short twobyte) #else fwdx_add_quoted_twobyte(p, twobyte) unsigned char *p; unsigned short twobyte; #endif /* CK_ANSIC */ /* adds the IAC quoted (MSB) representation of 'channel' at buffer pointer 'p', * returning pointer to new buffer position. NO OVERFLOW CHECK! */ { *p++ = (unsigned char)((twobyte >> 8) & 0xFF); if (*(p - 1) == 0xFF) *p++ = 0xFF; *p++ = (unsigned char)(twobyte & 0xFF); if (*(p - 1) == 0xFF) *p++ = 0xFF; return p; } #endif /* COMMENT */ int #ifdef CK_ANSIC fwdx_create_fake_xauth(char *name, int name_len, int data_len) #else fwdx_create_fake_xauth(name, name_len, data_len) char *name; int name_len; int data_len; #endif /* CK_ANSIC */ { char stackdata[256]; unsigned int c, n; if (!name_len || !data_len) return 1; fake_xauth.name = malloc(name_len); fake_xauth.data = malloc(data_len); if (!fake_xauth.name || !fake_xauth.data) return 2; fake_xauth.name_length = name_len; memcpy(fake_xauth.name, name, name_len); fake_xauth.data_length = data_len; /* try to make a random unsigned int to feed srand() */ c = time(NULL); c *= getpid(); for (n = 0; n < sizeof(stackdata); n++) c += stackdata[n]; srand((unsigned int)c); for (c = 0; c < data_len; c++) fake_xauth.data[c] = (unsigned char)rand(); return 0; } #ifdef COMMENT /* No longer used */ int fwdx_send_xauth(void) { int c, err, dpynum, family, sb_len, rc; char *display, *host = NULL; unsigned char *sb_priv, *p; /* parse the local DISPLAY env var */ if (!(display = tn_get_display())) return (-1); if (fwdx_parse_displayname(display, &family, &host, &dpynum, NULL, NULL)) { char * disp_no = ckitoa(dpynum); if (family == FamilyLocal) { /* call with address = "" */ char address[300] = "localhost"; gethostname(address, sizeof(address) - 1); real_xauth = XauGetAuthByAddr(family, strlen(address), address, strlen(disp_no), disp_no, 0, NULL ); } else if (family == FamilyInternet) { /* call with address = 4 bytes numeric ip addr (MSB) */ struct hostent *hi; if ((hi = gethostbyname(host))) real_xauth = XauGetAuthByAddr(family, 4, hi->h_addr, strlen(disp_no), disp_no, 0, NULL ); } } if (host) { free(host); host = NULL; } if (real_xauth) err = fwdx_create_fake_xauth(real_xauth->name, real_xauth->name_length, real_xauth->data_length ); else err = fwdx_create_fake_xauth("MIT-MAGIC-COOKIE-1", strlen("MIT-MAGIC-COOKIE-1"), 16); if (err) return(-1); /* allocate memory for the SB block, alloc for worst case */ /* the following sprintf() calls are safe due to length checking */ /* buffer is twice as big as the input just in case every byte was IAC */ sb_len = 5 + 2 + 2 + fake_xauth.name_length + fake_xauth.data_length + 2; if (!(sb_priv = malloc(2 * sb_len))) return(-1); p = sb_priv; sprintf(p, "%c%c%c%c%c", IAC, SB, TELOPT_FORWARD_X, FWDX_OPT_DATA, FWDX_OPT_XAUTH); p += 5; p = fwdx_add_quoted_twobyte(p, fake_xauth.name_length); p = fwdx_add_quoted_twobyte(p, fake_xauth.data_length); for (c = 0; c < fake_xauth.name_length; c++) { *p++ = fake_xauth.name[c]; if ((unsigned char)fake_xauth.name[c] == 0xFF) *p++ = 0xFF; } for (c = 0; c < fake_xauth.data_length; c++) { *p++ = fake_xauth.data[c]; if ((unsigned char)fake_xauth.data[c] == 0xFF) *p++ = 0xFF; } sprintf(p, "%c%c", IAC, SE); p += 2; #ifdef DEBUG if (deblog || tn_deb || debses) { sprintf((char *)fwdx_msg_out,"TELNET SENT SB %s OPTION_DATA XAUTH ", TELOPT(TELOPT_FORWARD_X)); tn_hex((char *)fwdx_msg_out,TN_MSG_LEN,&sb_priv[5],(p-sb_priv)-7); ckstrncat((char *)fwdx_msg_out," IAC SE",TN_MSG_LEN); } #endif /* DEBUG */ /* Add Telnet Debug info here */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,(char *)fwdx_msg_out,"",0); if (tn_deb || debses) tn_debug((char *)fwdx_msg_out); #endif /* DEBUG */ rc = ( ttol(sb_priv,p-sb_priv) < 0 ); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) { debug(F110,"fwdx_send_xauth()","ttol() failed",0); return(-1); } free(sb_priv); return(0); } #endif /* COMMENT */ #ifdef FWDX_SERVER /* Only if we ever become a server - not yet ported to Kermit */ /* And even so most of this code does not belong in this module */ int fwdx_write_xauthfile(void) { int dpynum, scrnum, family; char myhost[300], *host, *rest = NULL; FILE *file; struct sockaddr_in saddr; struct hostent *hi; if (!fwdx_display && !fwdx_xauthfile) return 1; if (!parse_displayname(fwdx_display, &family, &host, &dpynum, &scrnum, &rest)) return 2; if (rest) free(rest); if (host) free(host); if (family != FamilyInternet) return 3; /* every thing but FamilyInternet is unexpected */ /* X connections to localhost:1 is actually treated as local unix sockets, * see the 'xauth' man page. */ xauth.family = FamilyLocal; if (gethostname(myhost, sizeof(myhost) - 1)) return 5; xauth.address_length = strlen(myhost); if (!(xauth.address = malloc(xauth.address_length))) return 5; memcpy(xauth.address, myhost, xauth.address_length); /* the display number is written as a string, not numeric */ if (!(xauth.number = malloc(6))) return 6; snprintf(xauth.number, 5, "%u", dpynum); xauth.number_length = strlen(xauth.number); if (!(file = fopen(fwdx_xauthfile, "wb"))) return 7; if (!XauWriteAuth(file, &xauth)) return 8; fclose(file); setenv("XAUTHORITY", fwdx_xauthfile, 1); return 0; } int fwdx_setup_xauth(unsigned char *sp, int len) /* called with 'len' xauth bytes, starting at 'sp' * the data format is: */ { int xauthfd; if (!fwdx_options[FWDX_OPT_XAUTH]) return 1; if (len < 4) return 2; /* setup the xauth struct */ xauth.name_length = (sp[0] << 8) + sp[1]; xauth.data_length = (sp[2] << 8) + sp[3]; if (len != 4 + xauth.name_length + xauth.data_length) return 3; xauth.name = malloc(xauth.name_length); xauth.data = malloc(xauth.data_length); if (!xauth.name || !xauth.data) return 4; memcpy(xauth.name, sp + 4, xauth.name_length); memcpy(xauth.data, sp + 4 + xauth.name_length, xauth.data_length); /* Setup to always have a local .Xauthority. */ fwdx_xauthfile = malloc(CKMAXPATH+1); snprintf(fwdx_xauthfile, CKMAXPATH, "/tmp/XauthXXXXXX"); if ((xauthfd = mkstemp(fwdx_xauthfile)) != -1) /* we change file ownership later, when we know who is to be owner! */ close(xauthfd); else { free(fwdx_xauthfile); fwdx_xauthfile = NULL; return 5; } /* Must have the subshell's new DISPLAY env var to write xauth to xauthfile */ if (fwdx_display) if (fwdx_write_xauthfile()) return 6; return 0; } void fwdx_set_xauthfile_owner(int uid) { struct passwd *pwd; if (!fwdx_xauthfile || !(pwd = getpwuid(uid))) return; chown(fwdx_xauthfile, pwd->pw_uid, pwd->pw_gid); } int fwdx_server_accept_options(unsigned char *sp, int len) /* called with 'len' option bytes, starting at 'sp' */ { int c; for (c = 0; c < len-2; c++) { if (c == 0) { if (sp[c] & FWDX_OPT_XAUTH) flag = 1; } } return(0); } #endif /* FWDX_SERVER */ #endif /* CK_FORWARD_X */ #ifdef IKS_OPTION /* iks_wait() -- Wait for an IKS subnegotiation response. sb - is either KERMIT_REQ_START or KERMIT_REQ_STOP depending on the desired state of the peer's Kermit server. flushok - specifies whether it is ok to throw away non-Telnet data if so, then we call ttflui() instead of tn_flui(). Returns: 1 if the desired state is achieved or if it is unknown. 0 if the desired state is not achieved. */ int #ifdef CK_ANSIC iks_wait(int sb, int flushok) #else /* CK_ANSIC */ iks_wait(sb,flushok) int sb; int flushok; #endif /* CK_ANSIC */ { int tn_wait_save = tn_wait_flg; int x; /* Problem noted with the Synchronet Telnet server, e.g. at b4bbs.sampsa.com: TELNET SENT DO KERMIT TELNET SENT WILL KERMIT TELNET RCVD WILL KERMIT <-- KERMIT option negotiated TELNET SENT SB KERMIT SOP 01 IAC SE <-- This is required TELNET RCVD DONT KERMIT <-- Required SB KERMIT SOP response not received. Session hangs waiting for required response. User SETs TELNET WAIT OFF as a workaround, but session still hangs on next CONNECT command because tn_wait_flg is set here and never restored. If user SETs TELNET WAIT OFF, it is precisely to avoid such situations, so it should be respected. Fixed by testing tn_wait_flg in the following line. -fdc, 2013-04-09. printf("*** TN_WAIT_FLG=*** TELOPT_U(TELOPT_KERMIT)=0%d\n",tn_wait_flg); printf("*** TELOPT_U(TELOPT_KERMIT)=%d\n",TELOPT_U(TELOPT_KERMIT)); */ if (tn_wait_flg && TELOPT_U(TELOPT_KERMIT)) { switch (sb) { case KERMIT_REQ_START: debug(F111, "iks_wait KERMIT_REQ_START", "u_start", TELOPT_SB(TELOPT_KERMIT).kermit.u_start ); tn_siks(KERMIT_REQ_START); /* SB KERMIT SOP x */ tn_wait_flg = 1; /* MUST wait for response: RFC2840 */ do { if (flushok) tn_wait_idx = 0; x = tn_wait("iks_wait() me_iks_req_start"); } while (x == 0 && flushok && tn_wait_idx == TN_WAIT_BUF_SZ && /* The idea here is that if, while waiting for a response to SB KERMIT SOP, we get a DONT KERMIT, as happens in at least one real-life situation, we break out of the wait loop. It's not exactly according to spec but it makes sense. This should work because tn_wait() calls tn_doop(), which calls tn_xdoop(), which will unset TELOPT_ME(TELOPT_KERMIT) if DONT KERMIT arrives. -fdc, 2013-04-10. */ TELOPT_ME(TELOPT_KERMIT) ); tn_wait_flg = tn_wait_save; if (flushok) tn_wait_idx = 0; if (tn_wait_idx == TN_WAIT_BUF_SZ) { /* * We are attempting to start a kermit server on the peer * the most likely reason is because we want to perform a * file transfer. But there is a huge amount of non telnet * negotiation data coming in and so we have not been able * to find the response. So we will lie and assume that * response is 'yes'. The worse that will happen is that * a RESP_STOP is received after we enter protocol mode. * And the protocol operation will be canceled. */ tn_push(); return(1); } else { tn_push(); return(TELOPT_SB(TELOPT_KERMIT).kermit.u_start); } case KERMIT_REQ_STOP: debug(F111, "iks_wait KERMIT_REQ_STOP", "u_start", TELOPT_SB(TELOPT_KERMIT).kermit.u_start ); tn_siks(KERMIT_REQ_STOP); tn_wait_flg = 1; /* Kermit Option MUST wait */ do { if (flushok) tn_wait_idx = 0; x = tn_wait("iks_wait() me_iks_req_stop"); } while (x == 0 && flushok && tn_wait_idx == TN_WAIT_BUF_SZ); tn_wait_flg = tn_wait_save; if (flushok) tn_wait_idx = 0; if (tn_wait_idx == TN_WAIT_BUF_SZ) { /* * We are attempting to stop a kermit server on the peer * the most likely reason being that we want to enter * CONNECT mode. But there is a huge amount of non telnet * negotiation data coming in and so we have not been able * to find the response. So we will lie and assume that * the answer is 'yes' and allow the CONNECT command to * succeed. The worst that happens is that CONNECT mode * swallows the incoming data displaying it to the user * and then it resumes Kermit client mode. */ tn_push(); return(1); } else { tn_push(); return(!TELOPT_SB(TELOPT_KERMIT).kermit.u_start); } } tn_push(); } return(1); } int #ifdef CK_ANSIC iks_tn_sb(CHAR * sb, int n) #else iks_tn_sb(sb, n) CHAR * sb; int n; #endif /* CK_ANSIC */ { extern int server; extern CHAR sstate; #ifdef NOICP extern int autodl; int inautodl = 0, cmdadl = 1; #else #ifdef CK_AUTODL extern int autodl, inautodl, cmdadl; #endif /* CK_AUTODL */ #endif /* NOICP */ switch (sb[0]) { case KERMIT_START: /* START */ TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 1; return(4); case KERMIT_STOP: /* STOP */ TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0; return(4); case KERMIT_REQ_START: /* REQ-START */ #ifndef NOXFER if (inserver) { #ifdef CK_AUTODL cmdadl = 1; /* Turn on packet detection */ #endif /* CK_AUTODL */ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1; tn_siks(KERMIT_RESP_START); } else if (TELOPT_SB(TELOPT_KERMIT).kermit.me_start) { tn_siks(KERMIT_RESP_START); } else { #ifndef IKSDONLY #ifdef CK_AUTODL #ifdef OS2 if (local && (IsConnectMode() && autodl) || (!IsConnectMode() && (inautodl || sstate == 'x' || sstate == 'v')) ) tn_siks(KERMIT_RESP_START); /* START */ else #else /* OS2 */ if ((local && what == W_CONNECT && autodl) || (local && what != W_CONNECT && (inautodl || sstate == 'x' || sstate == 'v') )) tn_siks(KERMIT_RESP_START); /* START */ else #endif /* OS2 */ #endif /* CK_AUTODL */ #endif /* IKSDONLY */ tn_siks(KERMIT_RESP_STOP); } #else /* NOXFER */ tn_siks(KERMIT_RESP_STOP); #endif /* NOXFER */ return(4); case KERMIT_REQ_STOP: /* REQ-STOP */ /* The protocol requires that the request be responded to */ /* either by changing states or by reporting the current */ /* state. */ /* We need to provide the user some way of dictating what */ /* the policies should be. For instance, if we are in */ /* CONNECT mode with autodownload ON and we get a REQ-STOP*/ /* what should the proper response be? */ #ifndef NOXFER if (inserver #ifdef CK_AUTODL || !local && cmdadl #endif /* CK_AUTODL */ ) { #ifdef CK_AUTODL cmdadl = 0; /* Turn off packet detection */ #endif /* CK_AUTODL */ tn_siks(KERMIT_RESP_STOP); } else if (server) { extern int en_fin; if (en_fin) { /* If the server is allowed to stop */ tn_siks(KERMIT_RESP_STOP); } else { /* We are not allowed to stop */ tn_siks(KERMIT_RESP_START); } } #ifndef IKSDONLY #ifdef CK_AUTODL #ifdef OS2 else if (local && (IsConnectMode() && autodl) || (!IsConnectMode() && inautodl) ) { /* If we are a pseudo-server and the other side requests */ /* that we stop, tell then that we have even though we */ /* have not. Otherwise, the other side might refuse to */ /* enter SERVER mode. */ tn_siks(KERMIT_RESP_STOP); /* STOP */ } #else /* OS2 */ else if ((local && what == W_CONNECT && autodl) || (local && what != W_CONNECT && inautodl) ) { /* If we are a pseudo-server and the other side requests */ /* that we stop, tell then that we have even though we */ /* have not. Otherwise, the other side might refuse to */ /* enter SERVER mode. */ tn_siks(KERMIT_RESP_STOP); /* STOP */ } #endif /* OS2 */ #endif /* CK_AUTODL */ #endif /* IKSDONLY */ else #endif /* NOXFER */ { /* If we are not currently in any mode that accepts */ /* Kermit packets then of course report that we are */ /* not being a Kermit server. */ tn_siks(KERMIT_RESP_STOP); /* STOP */ } return(4); case KERMIT_SOP: { /* SOP */ #ifndef NOXFER extern CHAR stchr; /* Incoming SOP character */ stchr = sb[1]; #endif /* NOXFER */ TELOPT_SB(TELOPT_KERMIT).kermit.sop = 1; return(4); } case KERMIT_RESP_START: /* START */ TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 1; if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start) { TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0; } else if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop) { /* If we have issued a request to stop a Kermit Server */ /* and the response is Start, then we must report this */ /* to the caller. */ TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0; } return(4); case KERMIT_RESP_STOP: /* STOP */ TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0; if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start) { TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0; /* If we have issued a request to start a Kermit Server */ /* and the response is Stop, then we must report this */ /* to the caller. */ } else if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop) { TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0; } return(4); default: return(0); } /* switch (sb[0]) */ } #endif /* IKS_OPTION */ /* Initialize telnet settings - set default values for ME and U modes */ int tn_set_modes() { int opt,cmd; #ifdef CK_FORWARD_X int x; #endif /* CK_FORWARD_X */ #ifdef CK_ENVIRONMENT { int i; for (i = 0; i < 8; i++) { tn_env_uservar[i][0] = NULL; tn_env_uservar[i][1] = NULL; } } #endif /* CK_ENVIRONMENT */ /* initialize all options to refuse in both directions */ for (opt = 0; opt < NTELOPTS; opt++) { TELOPT_ME(opt) = 0; TELOPT_U(opt) = 0; TELOPT_UNANSWERED_WILL(opt) = 0; TELOPT_UNANSWERED_DO(opt) = 0; TELOPT_UNANSWERED_WONT(opt) = 0; TELOPT_UNANSWERED_DONT(opt) = 0; TELOPT_UNANSWERED_SB(opt) = 0; TELOPT_ME_MODE(opt) = TN_NG_RF; TELOPT_U_MODE(opt) = TN_NG_RF; TELOPT_DEF_S_ME_MODE(opt) = TN_NG_RF; TELOPT_DEF_S_U_MODE(opt) = TN_NG_RF; TELOPT_DEF_C_ME_MODE(opt) = TN_NG_RF; TELOPT_DEF_C_U_MODE(opt) = TN_NG_RF; for (cmd = 0; cmd < 4; cmd ++) tncnts[TELOPT_INDEX(opt)][cmd] = 0; } #ifdef IKS_OPTION TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0; TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0; TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0; TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0; TELOPT_SB(TELOPT_KERMIT).kermit.sop = 0; #endif /* IKS_OPTION */ #ifdef CK_ENCRYPTION TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0; #endif /* CK_ENCRYPTION */ #ifdef CK_NAWS TELOPT_SB(TELOPT_NAWS).naws.x = 0; TELOPT_SB(TELOPT_NAWS).naws.y = 0; #endif /* CK_NAWS */ #ifdef CK_SSL TELOPT_SB(TELOPT_START_TLS).start_tls.u_follows = 0; TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 0; TELOPT_SB(TELOPT_START_TLS).start_tls.auth_request = 0; #endif /* CK_SSL */ /* Now set the ones we want to accept to the proper values */ TELOPT_DEF_S_ME_MODE(TELOPT_SGA) = TN_NG_RQ; TELOPT_DEF_S_U_MODE(TELOPT_SGA) = TN_NG_RQ; TELOPT_DEF_C_ME_MODE(TELOPT_SGA) = TN_NG_AC; TELOPT_DEF_C_U_MODE(TELOPT_SGA) = TN_NG_AC; TELOPT_DEF_S_ME_MODE(TELOPT_BINARY) = TN_NG_AC; TELOPT_DEF_S_U_MODE(TELOPT_BINARY) = TN_NG_AC; TELOPT_DEF_C_ME_MODE(TELOPT_BINARY) = TN_NG_AC; TELOPT_DEF_C_U_MODE(TELOPT_BINARY) = TN_NG_AC; TELOPT_DEF_S_ME_MODE(TELOPT_LOGOUT) = TN_NG_AC; TELOPT_DEF_S_U_MODE(TELOPT_LOGOUT) = TN_NG_AC; TELOPT_DEF_C_ME_MODE(TELOPT_LOGOUT) = TN_NG_AC; TELOPT_DEF_C_U_MODE(TELOPT_LOGOUT) = TN_NG_AC; #ifdef IKS_OPTION TELOPT_DEF_S_ME_MODE(TELOPT_KERMIT) = TN_NG_RQ; TELOPT_DEF_S_U_MODE(TELOPT_KERMIT) = TN_NG_RQ; TELOPT_DEF_C_ME_MODE(TELOPT_KERMIT) = TN_NG_RQ; TELOPT_DEF_C_U_MODE(TELOPT_KERMIT) = TN_NG_RQ; #endif /* IKS_OPTION */ #ifdef CK_ENCRYPTION TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ; TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ; TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ; TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ; #endif /* CK_ENCRYPTION */ TELOPT_DEF_S_ME_MODE(TELOPT_ECHO) = TN_NG_RQ; #ifdef IKSD if ( !inserver ) #endif /* IKSD */ TELOPT_DEF_S_U_MODE(TELOPT_TTYPE) = TN_NG_RQ; #ifdef CK_ENVIRONMENT TELOPT_DEF_S_U_MODE(TELOPT_NEWENVIRON) = TN_NG_RQ; #endif /* CK_ENVIRONMENT */ #ifdef CK_AUTHENTICATION TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ; #endif /* CK_AUTHENTICATION */ #ifdef CK_SSL if (ck_ssleay_is_installed()) { TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RQ; TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_AC; } #endif /* CK_SSL */ #ifdef CK_NAWS TELOPT_DEF_S_U_MODE(TELOPT_NAWS) = TN_NG_RQ; #endif /* CK_NAWS */ TELOPT_DEF_C_U_MODE(TELOPT_ECHO) = TN_NG_AC; TELOPT_DEF_C_ME_MODE(TELOPT_TTYPE) = TN_NG_RQ; #ifdef CK_ENVIRONMENT TELOPT_DEF_C_ME_MODE(TELOPT_NEWENVIRON) = TN_NG_RQ; #endif /* CK_ENVIRONMENT */ #ifdef CK_AUTHENTICATION TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ; #endif /* CK_AUTHENTICATION */ #ifdef CK_NAWS TELOPT_DEF_C_ME_MODE(TELOPT_NAWS) = TN_NG_RQ; #endif /* CK_NAWS */ #ifdef CK_SNDLOC TELOPT_DEF_C_ME_MODE(TELOPT_SNDLOC) = TN_NG_RQ; #endif /* CK_SNDLOC */ #ifdef CK_FORWARD_X TELOPT_DEF_C_U_MODE(TELOPT_FORWARD_X) = TN_NG_AC; TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1; for (x = 0; x < MAXFWDX; x++) { TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1; TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1; TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0; TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0; } #endif /* CK_FORWARD_X */ #ifdef TN_COMPORT TELOPT_DEF_C_ME_MODE(TELOPT_COMPORT) = TN_NG_RQ; #endif /* TN_COMPORT */ /* Set the initial values for currently known mode */ for (opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) { if (TELOPT_OK(opt)) { TELOPT_ME_MODE(opt) = sstelnet ? TELOPT_DEF_S_ME_MODE(opt) : TELOPT_DEF_C_ME_MODE(opt); TELOPT_U_MODE(opt) = sstelnet ? TELOPT_DEF_S_U_MODE(opt) : TELOPT_DEF_C_U_MODE(opt); } } return(1); } /* Send Delayed Subnegotiations */ VOID tn_sdsb() { /* if (!IS_TELNET()) return; */ if (TELOPT_SB(TELOPT_TTYPE).term.need_to_send) { tn_sttyp(); TELOPT_SB(TELOPT_TTYPE).term.need_to_send = 0; } #ifdef CK_ENVIRONMENT if (TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send && TELOPT_SB(TELOPT_NEWENVIRON).env.str) { tn_snenv((CHAR *)TELOPT_SB(TELOPT_NEWENVIRON).env.str, TELOPT_SB(TELOPT_NEWENVIRON).env.len); free(TELOPT_SB(TELOPT_NEWENVIRON).env.str); TELOPT_SB(TELOPT_NEWENVIRON).env.str=NULL; TELOPT_SB(TELOPT_NEWENVIRON).env.len=0; TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send = 0; } #ifdef CK_XDISPLOC if (TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send) { tn_sxdisploc(); TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send = 0; } #endif /* CK_XDISPLOC */ #endif /* CK_ENVIRONMENT */ #ifdef CK_NAWS if (TELOPT_SB(TELOPT_NAWS).naws.need_to_send) { tn_snaws(); TELOPT_SB(TELOPT_NAWS).naws.need_to_send = 0; } #endif /* CK_NAWS */ #ifdef CK_SNDLOC if (TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send) { tn_sndloc(); TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send = 0; } #endif /* CK_SNDLOC */ #ifdef CK_FORWARD_X if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send) { if ( sstelnet ) fwdx_send_options(); TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send = 0; } #endif /* CK_FORWARD_X */ #ifdef TN_COMPORT if (TELOPT_SB(TELOPT_COMPORT).comport.need_to_send) { tn_sndcomport(); TELOPT_SB(TELOPT_COMPORT).comport.need_to_send = 0; } #endif /* TN_COMPORT */ } int tn_reset() { int x,opt,cmd; /* if (!IS_TELNET()) return(1); */ tn_wait_idx = 0; /* Clear the tn_push() buffer */ tn_wait_tmo = TN_TIMEOUT; /* Reset wait timer stats */ nflag = 0; /* Reset the TELNET OPTIONS counts */ for (opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) { if (TELOPT_OK(opt)) { TELOPT_ME(opt) = 0; TELOPT_U(opt) = 0; TELOPT_UNANSWERED_WILL(opt) = 0; TELOPT_UNANSWERED_DO(opt) = 0; TELOPT_UNANSWERED_WONT(opt) = 0; TELOPT_UNANSWERED_DONT(opt) = 0; TELOPT_UNANSWERED_SB(opt) = 0; TELOPT_ME_MODE(opt) = sstelnet ? TELOPT_DEF_S_ME_MODE(opt) : TELOPT_DEF_C_ME_MODE(opt); TELOPT_U_MODE(opt) = sstelnet ? TELOPT_DEF_S_U_MODE(opt) : TELOPT_DEF_C_U_MODE(opt); #ifdef DEBUG if (deblog) { switch (TELOPT_ME_MODE(opt)) { case TN_NG_RF: debug(F110,"tn_ini ME REFUSE ",TELOPT(opt),0); break; case TN_NG_AC: debug(F110,"tn_ini ME ACCEPT ",TELOPT(opt),0); break; case TN_NG_RQ: debug(F110,"tn_ini ME REQUEST",TELOPT(opt),0); break; case TN_NG_MU: debug(F110,"tn_ini ME REQUIRE",TELOPT(opt),0); break; } switch (TELOPT_U_MODE(opt)) { case TN_NG_RF: debug(F110,"tn_ini U REFUSE ",TELOPT(opt),0); break; case TN_NG_AC: debug(F110,"tn_ini U ACCEPT ",TELOPT(opt),0); break; case TN_NG_RQ: debug(F110,"tn_ini U REQUEST",TELOPT(opt),0); break; case TN_NG_MU: debug(F110,"tn_ini U REQUIRE",TELOPT(opt),0); break; } } #endif /* DEBUG */ for (cmd = 0; cmd < 4; cmd ++) tncnts[TELOPT_INDEX(opt)][cmd] = 0; } } #ifdef CK_ENVIRONMENT if (!tn_env_flg) { TELOPT_ME_MODE(TELOPT_NEWENVIRON) = TN_NG_RF; TELOPT_U_MODE(TELOPT_NEWENVIRON) = TN_NG_RF; } #endif /* CK_ENVIRONMENT */ #ifdef CK_SNDLOC if (!tn_loc) TELOPT_DEF_C_ME_MODE(TELOPT_SNDLOC) = TN_NG_RF; #endif /* CK_SNDLOC */ #ifdef IKS_OPTION TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0; TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0; TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0; TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0; TELOPT_SB(TELOPT_KERMIT).kermit.sop = 0; #endif /* IKS_OPTION */ #ifdef CK_ENCRYPTION TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0; TELOPT_SB(TELOPT_ENCRYPTION).encrypt.need_to_send = 0; #endif /* CK_ENCRYPTION */ #ifdef CK_NAWS TELOPT_SB(TELOPT_NAWS).naws.need_to_send = 0; TELOPT_SB(TELOPT_NAWS).naws.x = 0; TELOPT_SB(TELOPT_NAWS).naws.y = 0; #endif /* CK_NAWS */ TELOPT_SB(TELOPT_TTYPE).term.need_to_send = 0; TELOPT_SB(TELOPT_TTYPE).term.type[0] = '\0'; #ifdef CK_ENVIRONMENT TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send = 0; if (tn_first) TELOPT_SB(TELOPT_NEWENVIRON).env.str=NULL; else if (TELOPT_SB(TELOPT_NEWENVIRON).env.str) { free(TELOPT_SB(TELOPT_NEWENVIRON).env.str); TELOPT_SB(TELOPT_NEWENVIRON).env.str=NULL; } TELOPT_SB(TELOPT_NEWENVIRON).env.len=0; #ifdef CK_XDISPLOC TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send = 0; #endif /* CK_XDISPLOC */ #endif /* CK_ENVIRONMENT */ #ifdef CK_SNDLOC TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send = 0; #endif /* CK_SNDLOC */ #ifdef CK_FORWARD_X TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send = 0; TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1; for (x = 0; x < MAXFWDX; x++) { TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1; TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1; TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0; TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0; } /* Reset Xauth data */ if ( real_xauth ) { XauDisposeAuth(real_xauth); real_xauth = NULL; } if ( fake_xauth.name ) free(fake_xauth.name); if ( fake_xauth.data ) free(fake_xauth.data); if ( fake_xauth.address ) free(fake_xauth.address); if ( fake_xauth.number ) free(fake_xauth.number); memset(&fake_xauth,0,sizeof(fake_xauth)); #ifdef NT TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0; #endif /* NT */ #endif /* CK_FORWARD_X */ #ifdef CK_SSL if (tls_only_flag || ssl_only_flag) { TELOPT_ME_MODE(TELOPT_START_TLS) = TN_NG_RF; TELOPT_U_MODE(TELOPT_START_TLS) = TN_NG_RF; } TELOPT_SB(TELOPT_START_TLS).start_tls.u_follows = 0; TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 0; TELOPT_SB(TELOPT_START_TLS).start_tls.auth_request = 0; #endif /* CK_SSL */ #ifdef CK_ENCRYPTION if (!ck_crypt_is_installed() #ifdef CK_SSL || tls_only_flag || ssl_only_flag #endif /* CK_SSL */ ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_ENCRYPTION */ #ifdef TN_COMPORT TELOPT_SB(TELOPT_COMPORT).comport.need_to_send = 0; TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms = 0; tnc_init(); #endif /* TN_COMPORT */ tn_first = 0; /* No longer the first time init */ #ifdef OS2 ttnum = -1; /* Reset TermType negotiation */ ttnumend = 0; #endif /* OS2 */ return(0); } int tn_start() { int wait, x, opt; /* if (!IS_TELNET()) return(0); */ if (tn_init && tn_begun) return(0); tn_begun = 1; debug(F111,"tn_start","sstelnet",sstelnet); wait = 0; if (tn_duplex) { oldplex = duplex; /* save old duplex value */ duplex = 1; /* and set to half duplex for telnet */ } #ifdef CK_SSL if (!TELOPT_ME(TELOPT_START_TLS) && TELOPT_ME_MODE(TELOPT_START_TLS) >= TN_NG_RQ) { if (tn_sopt(WILL, TELOPT_START_TLS) < 0) return(-1); TELOPT_UNANSWERED_WILL(TELOPT_START_TLS) = 1; wait = 1; } if (!TELOPT_U(TELOPT_START_TLS) && TELOPT_U_MODE(TELOPT_START_TLS) >= TN_NG_RQ) { if (tn_sopt(DO, TELOPT_START_TLS) < 0) return(-1); TELOPT_UNANSWERED_DO(TELOPT_START_TLS) = 1; wait = 1; } #endif /* CK_SSL */ #ifdef CK_AUTHENTICATION debug(F110,"tn_ini() CK_AUTHENTICATION","",0); if (tn_init) /* tn_ini() might be called recursively */ return(0); if (!TELOPT_ME(TELOPT_AUTHENTICATION) && TELOPT_ME_MODE(TELOPT_AUTHENTICATION) >= TN_NG_RQ) { if (tn_sopt(WILL, TELOPT_AUTHENTICATION) < 0) return(-1); TELOPT_UNANSWERED_WILL(TELOPT_AUTHENTICATION) = 1; wait = 1; } if (!TELOPT_U(TELOPT_AUTHENTICATION) && TELOPT_U_MODE(TELOPT_AUTHENTICATION) >= TN_NG_RQ) { if (tn_sopt(DO, TELOPT_AUTHENTICATION) < 0) return(-1); TELOPT_UNANSWERED_DO(TELOPT_AUTHENTICATION) = 1; wait = 1; } #ifdef CK_ENCRYPTION if (TELOPT_U_MODE(TELOPT_AUTHENTICATION) == TN_NG_RF && TELOPT_ME_MODE(TELOPT_AUTHENTICATION) == TN_NG_RF) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_ENCRYPTION */ #endif /* CK_AUTHENTICATION */ #ifdef CK_NAWS #ifndef NOLOCAL debug(F110,"tn_ini() CK_NAWS !NOLOCAL","",0); if (!sstelnet) { /* Console terminal screen rows and columns */ #ifdef OS2 debug(F101, "tn_ini tt_rows 1", "", VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) ); debug(F101,"tn_ini tt_cols 1","",VscrnGetWidth(VTERM)); /* Not known yet */ if (VscrnGetWidth(VTERM) < 0 || VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) < 0) { ttgwsiz(); /* Try to find out */ } debug(F101, "tn_ini tt_rows 2", "", VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) ); debug(F101,"tn_ini tt_cols 2","",VscrnGetWidth(VTERM)); /* Now do we know? */ if (VscrnGetWidth(VTERM) > 0 && VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) > 0) { if (!TELOPT_ME(TELOPT_NAWS) && TELOPT_ME_MODE(TELOPT_NAWS) >= TN_NG_RQ) { if (tn_sopt(WILL, TELOPT_NAWS) < 0) return(-1); TELOPT_UNANSWERED_WILL(TELOPT_NAWS) = 1; wait = 1; } } #else /* OS2 */ debug(F101,"tn_ini tt_rows 1","",tt_rows); debug(F101,"tn_ini tt_cols 1","",tt_cols); if (tt_rows < 0 || tt_cols < 0) { /* Not known yet */ ttgwsiz(); /* Try to find out */ } debug(F101,"tn_ini tt_rows 2","",tt_rows); debug(F101,"tn_ini tt_cols 2","",tt_cols); if (tt_rows > 0 && tt_cols > 0) { /* Now do we know? */ if (!TELOPT_ME(TELOPT_NAWS) && TELOPT_ME_MODE(TELOPT_NAWS) >= TN_NG_RQ) { if (tn_sopt(WILL, TELOPT_NAWS) < 0) return(-1); TELOPT_UNANSWERED_WILL(TELOPT_NAWS) = 1; wait = 1; } } #endif /* OS2 */ } else #endif /* NOLOCAL */ { if (!TELOPT_U(TELOPT_NAWS) && TELOPT_U_MODE(TELOPT_NAWS) >= TN_NG_RQ) { if (tn_sopt(DO, TELOPT_NAWS) < 0) return(-1); TELOPT_UNANSWERED_DO(TELOPT_NAWS) = 1; wait = 1; } } #endif /* CK_NAWS */ if (!TELOPT_ME(TELOPT_SGA) && TELOPT_ME_MODE(TELOPT_SGA) >= TN_NG_RQ) { if (tn_sopt(WILL, TELOPT_SGA) < 0) return(-1); TELOPT_UNANSWERED_WILL(TELOPT_SGA) = 1; wait = 1; } if (!TELOPT_U(TELOPT_SGA) && TELOPT_U_MODE(TELOPT_SGA) >= TN_NG_RQ) { if (tn_sopt(DO, TELOPT_SGA) < 0) return(-1); TELOPT_UNANSWERED_DO(TELOPT_SGA) = 1; wait = 1; } if (!tn_duplex) { if (!TELOPT_U(TELOPT_ECHO) && TELOPT_U_MODE(TELOPT_ECHO) >= TN_NG_RQ) { if (tn_sopt(DO, TELOPT_ECHO) < 0) return(-1); TELOPT_UNANSWERED_DO(TELOPT_ECHO) = 1; wait = 1; } } if (!TELOPT_ME(TELOPT_ECHO) && TELOPT_ME_MODE(TELOPT_ECHO) >= TN_NG_RQ) { if (tn_sopt(WILL, TELOPT_ECHO) < 0) return(-1); TELOPT_UNANSWERED_WILL(TELOPT_ECHO) = 1; wait = 1; } debug(F100,"tn_ini about to send WILL TTYPE if requested","",0); /* Talking to TELNET port, so send WILL TERMINAL TYPE and DO SGA. Also send WILL NAWS if we know our screen dimensions. */ if (!TELOPT_ME(TELOPT_TTYPE) && TELOPT_ME_MODE(TELOPT_TTYPE) >= TN_NG_RQ) { if ((x = tn_sopt(WILL,TELOPT_TTYPE)) < 0) { debug(F101,"tn_ini tn_sopt WILL TTYPE failed","",x); return(-1); } TELOPT_UNANSWERED_WILL(TELOPT_TTYPE) = 1; wait = 1; debug(F100,"tn_ini sent WILL TTYPE ok","",0); } if (!TELOPT_U(TELOPT_TTYPE) && TELOPT_U_MODE(TELOPT_TTYPE) >= TN_NG_RQ) { if ((x = tn_sopt(DO,TELOPT_TTYPE)) < 0) { debug(F101,"tn_ini tn_sopt DO TTYPE failed","",x); return(-1); } TELOPT_UNANSWERED_DO(TELOPT_TTYPE) = 1; wait = 1; debug(F100,"tn_ini sent DO TTYPE ok","",0); } if (!TELOPT_ME(TELOPT_BINARY) && TELOPT_ME_MODE(TELOPT_BINARY) >= TN_NG_RQ) { if (tn_sopt(WILL, TELOPT_BINARY) < 0) return(-1); TELOPT_UNANSWERED_WILL(TELOPT_BINARY) = 1; wait = 1; } if (!TELOPT_U(TELOPT_BINARY) && TELOPT_U_MODE(TELOPT_BINARY) >= TN_NG_RQ) { if (tn_sopt(DO, TELOPT_BINARY) < 0) return(-1); TELOPT_UNANSWERED_DO(TELOPT_BINARY) = 1; wait = 1; } #ifdef CK_SNDLOC if (tn_loc) { if (!TELOPT_ME(TELOPT_SNDLOC) && TELOPT_ME_MODE(TELOPT_SNDLOC) >= TN_NG_RQ) { if (tn_sopt(WILL, TELOPT_SNDLOC) < 0) return(-1); TELOPT_UNANSWERED_WILL(TELOPT_SNDLOC) = 1; wait = 1; } } #endif /* CK_SNDLOC */ #ifdef CK_ENVIRONMENT #ifdef CK_FORWARD_X if (!TELOPT_U(TELOPT_FORWARD_X) && TELOPT_U_MODE(TELOPT_FORWARD_X) >= TN_NG_RQ) { if (tn_sopt(WILL, TELOPT_FORWARD_X) < 0) return(-1); TELOPT_UNANSWERED_WILL(TELOPT_FORWARD_X) = 1; wait = 1; } #endif /* FORWARD_X */ #ifdef CK_XDISPLOC if (!TELOPT_ME(TELOPT_XDISPLOC) && TELOPT_ME_MODE(TELOPT_XDISPLOC) >= TN_NG_RQ) { if (tn_sopt(WILL, TELOPT_XDISPLOC) < 0) return(-1); TELOPT_UNANSWERED_WILL(TELOPT_XDISPLOC) = 1; wait = 1; } #endif /* CK_XDISPLOC */ /* Will send terminal environment. */ if (!TELOPT_ME(TELOPT_NEWENVIRON) && TELOPT_ME_MODE(TELOPT_NEWENVIRON) >= TN_NG_RQ) { if (tn_sopt(WILL, TELOPT_NEWENVIRON) < 0) return(-1); TELOPT_UNANSWERED_WILL(TELOPT_NEWENVIRON) = 1; wait = 1; } if (!TELOPT_U(TELOPT_NEWENVIRON) && TELOPT_U_MODE(TELOPT_NEWENVIRON) >= TN_NG_RQ) { if (tn_sopt(DO, TELOPT_NEWENVIRON) < 0) return(-1); TELOPT_UNANSWERED_DO(TELOPT_NEWENVIRON) = 1; wait = 1; } #endif /* CK_ENVIRONMENT */ /* Take care of any other telnet options that require handling. */ for (opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) { switch (opt) { case TELOPT_AUTHENTICATION: case TELOPT_ENCRYPTION: case TELOPT_TTYPE: case TELOPT_NAWS: case TELOPT_BINARY: case TELOPT_NEWENVIRON: case TELOPT_SNDLOC: case TELOPT_XDISPLOC: case TELOPT_SGA: case TELOPT_ECHO: case TELOPT_KERMIT: case TELOPT_START_TLS: case TELOPT_FORWARD_X: break; break; default: if (TELOPT_OK(opt)) { if (!TELOPT_ME(opt) && TELOPT_ME_MODE(opt) >= TN_NG_RQ) { if (tn_sopt(WILL, opt) < 0) return(-1); TELOPT_UNANSWERED_WILL(opt) = 1; wait = 1; } if (!TELOPT_U(opt) && TELOPT_U_MODE(opt) >= TN_NG_RQ) { if (tn_sopt(DO, opt) < 0) return(-1); TELOPT_UNANSWERED_DO(opt) = 1; wait = 1; } } } } if (wait) { if (tn_wait("pre-encrypt") < 0) { tn_push(); return(-1); } wait = 0; } #ifdef CK_ENCRYPTION if (tn_init) /* tn_ini() may be called recursively */ return(0); if (!TELOPT_ME(TELOPT_ENCRYPTION) && TELOPT_ME_MODE(TELOPT_ENCRYPTION) >= TN_NG_RQ) { if (tn_sopt(WILL, TELOPT_ENCRYPTION) < 0) return(-1); TELOPT_UNANSWERED_WILL(TELOPT_ENCRYPTION) = 1; wait = 1; } if (!TELOPT_U(TELOPT_ENCRYPTION) && TELOPT_U_MODE(TELOPT_ENCRYPTION) >= TN_NG_RQ) { if (tn_sopt(DO, TELOPT_ENCRYPTION) < 0) return(-1); TELOPT_UNANSWERED_DO(TELOPT_ENCRYPTION) = 1; wait = 1; } /* If we are going to encrypt, we want to do it before we send any more */ /* data, especially the terminal type and environment variables. */ if (wait) { if (tn_wait("post-encrypt") < 0) { tn_push(); return(-1); } wait = 0; } #endif /* CK_ENCRYPTION */ tn_sdsb(); if (tn_init) /* tn_ini() may be called recursively */ return(0); #ifdef IKS_OPTION /* Kermit Server negotiation must go last */ /* Send U before ME */ if (!TELOPT_U(TELOPT_KERMIT) && TELOPT_U_MODE(TELOPT_KERMIT) >= TN_NG_RQ) { if (tn_sopt(DO, TELOPT_KERMIT) < 0) return(-1); TELOPT_UNANSWERED_DO(TELOPT_KERMIT) = 1; wait = 1; } if (!TELOPT_ME(TELOPT_KERMIT) && TELOPT_ME_MODE(TELOPT_KERMIT) >= TN_NG_RQ) { if (tn_sopt(WILL, TELOPT_KERMIT) < 0) return(-1); TELOPT_UNANSWERED_WILL(TELOPT_KERMIT) = 1; wait = 1; } #endif /* IKS_OPTION */ if (wait) { if (tn_wait("end of telnet negotiations") < 0) { tn_push(); return(-1); } wait = 0; } tn_sdsb(); /* Send delayed subnegotiations */ tn_push(); return(0); } /* Start a telnet connection. */ /* Returns -1 on error, 0 if nothing happens, 1 if init msgs sent ok */ int tn_ini() { int x; debug(F101,"tn_ini ttnproto","",ttnproto); debug(F101,"tn_ini tn_init","",tn_init); if (ttnet != NET_TCPB) /* Make sure connection is TCP/IP */ return(0); /* if (!IS_TELNET()) return(0); */ if (tn_init) /* Have we done this already? */ return(0); /* Don't do it again. */ tn_reset(); /* Reset telnet parameters */ tn_begun = 0; /* Reset; will be set by tn_start() */ switch ( ttnproto ) { case NP_RLOGIN: case NP_K4LOGIN: case NP_EK4LOGIN: case NP_K5LOGIN: case NP_EK5LOGIN: case NP_K5U2U: tn_init = 1; debug(F100,"tn_ini telnet negotiations ignored","tn_init",tn_init); return(0); #ifdef COMMENT /* Jeff's code from 30 Dec 2005 - doesn't work with SSL POP server */ case NP_NONE: case NP_SSL: case NP_TLS: ttnproto = NP_TELNET; /* pretend it's telnet anyway, */ oldplex = duplex; /* save old duplex value */ duplex = 1; /* and set to half duplex for telnet */ if (inserver) debug(F100,"tn_ini skipping telnet negotiations","",0); else tn_wait("tn_ini - waiting to see if telnet negotiations were sent"); tn_push(); return(0); case NP_SSL_RAW: case NP_TLS_RAW: case NP_TCPRAW: /* Raw socket requested. */ debug(F100,"tn_ini telnet negotiations ignored","tn_init",tn_init); return(0); #else /* My code from 4 Dec 2005 - works with SSL POP server */ case NP_NONE: case NP_SSL: case NP_TLS: /* If not talking to a telnet port, */ case NP_SSL_RAW: /* SSL and TLS with Telnet */ case NP_TLS_RAW: /* negotiations disabled. */ ttnproto = NP_TELNET; /* pretend it's telnet anyway, */ oldplex = duplex; /* save old duplex value */ duplex = 1; /* and set to half duplex for telnet */ if (inserver) debug(F100,"tn_ini skipping telnet negotiations","",0); else tn_wait("tn_ini - waiting to see if telnet negotiations were sent"); tn_push(); return(0); case NP_TCPRAW: /* Raw socket requested. */ debug(F100,"tn_ini telnet negotiations ignored","tn_init",tn_init); return(0); #endif /* COMMENT */ case NP_KERMIT: /* switching to Telnet protocol */ case NP_SSL_TELNET: case NP_TLS_TELNET: debug(F101,"tn_ini switching from XXX to Telnet","",ttnproto); ttnproto = NP_TELNET; /* fall through */ default: /* We are already using a variation on Telnet protocol */ ; } x = tn_start(); tn_init = 1; /* Remember successful completion. */ /* Don't send anything else! */ debug(F101,"tn_ini duplex","",duplex); debug(F101,"tn_ini done, tn_init","",tn_init); return(x); } int #ifdef CK_ANSIC tn_hex(CHAR * buf, int buflen, CHAR * data, int datalen) #else /* CK_ANSIC */ tn_hex(buf, buflen, data, datalen) CHAR * buf; int buflen; CHAR * data; int datalen; #endif /* CK_ANSIC */ { int i = 0, j = 0, k = 0; CHAR tmp[16]; /* in case value is treated as negative */ #ifdef COMMENT int was_hex = 1; for (k=0; k < datalen; k++) { if (data[k] < 32 || data[k] >= 127) { sprintf(tmp,"%s%02X ",was_hex?"":"\" ",data[k]); was_hex = 1; } else { sprintf(tmp,"%s%c",was_hex?"\"":"",data[k]); was_hex = 0; } ckstrncat((char *)buf,tmp,buflen); } if (!was_hex) ckstrncat((char *)buf,"\" ",buflen); #else /* COMMENT */ if (datalen <= 0 || data == NULL || buf == NULL || buflen <= 0) return(0); for (i = 0; i < datalen; i++) { ckstrncat((char *)buf,"\r\n ",buflen); for (j = 0 ; (j < 16); j++) { if ((i + j) < datalen) sprintf((char *)tmp, "%s%02x ", (j == 8 ? "| " : ""), (unsigned int) data[i + j] ); else sprintf((char *)tmp, "%s ", (j == 8 ? "| " : "") ); ckstrncat((char *)buf,(char *)tmp,buflen); } ckstrncat((char *)buf," ",buflen); for (k = 0; (k < 16) && ((i + k) < datalen); k++) { sprintf((char *)tmp, "%s%c", (k == 8 ? " " : ""), isprint((char)(data[i+k])) ? data[i+k] : '.' ); ckstrncat((char *)buf,(char *)tmp,buflen); } i += j - 1; } /* end for */ ckstrncat((char *)buf,"\r\n ",buflen); #endif /* COMMENT */ return(strlen((char *)buf)); } VOID #ifdef CK_ANSIC tn_debug( char *s ) #else tn_debug(s) char *s; #endif /* CK_ANSIC */ { #ifdef NOLOCAL return; #else /* NOLOCAL */ #ifdef OS2 void cwrite(unsigned short); char *p = s; _PROTOTYP (void os2bold, (void)); extern int tt_type_mode; #endif /* OS2 */ if (!(tn_deb || debses)) return; debug(F111,"tn_debug",s,what); #ifdef OS2 if (1) { extern unsigned char colorcmd; colorcmd ^= 0x8 ; printf("%s\r\n",s); colorcmd ^= 0x8 ; } if (!scrninitialized[VTERM]) { USHORT x,y; checkscreenmode(); GetCurPos(&y, &x); SaveCmdMode(x+1,y+1); scrninit(); RestoreCmdMode(); } if ( ISVTNT(tt_type_mode) && ttnum != -1 && !debses ) return; RequestVscrnMutex( VTERM, SEM_INDEFINITE_WAIT ) ; os2bold(); /* Toggle boldness */ while (*p) cwrite((CHAR) *p++); /* Go boldly ... */ os2bold(); /* Toggle boldness back */ if (debses) { debses = 0; cwrite((CHAR) '\015'); cwrite((CHAR) '\012'); debses = 1; } else { cwrite((CHAR) '\015'); cwrite((CHAR) '\012'); } ReleaseVscrnMutex(VTERM) ; #else if (what != W_CONNECT && what != W_DIALING && what != W_COMMAND && what != W_NOTHING) return; /* CONNECT/command must be active */ conoll(s); #endif /* OS2 */ #endif /* NOLOCAL */ } /* Process in-band Telnet negotiation characters from the remote host. Call with the telnet IAC character and the current duplex setting (0 = remote echo, 1 = local echo), and a pointer to a function to call to read more characters. Returns: 6 if DO LOGOUT was received and accepted 5 if the Kermit start of packet character has changed 4 if state of remote Internet Kermit Service has changed 3 if a quoted IAC was received 2 if local echo must be changed to remote 1 if remote echo must be changed to local 0 if nothing happens or no action necessary -1 on failure (= internal or i/o error) */ #ifdef IKS_OPTION int #ifdef CK_ANSIC tn_siks( int cmd ) /* TELNET SEND IKS SUB */ #else tn_siks(cmd) int cmd; #endif /* CK_ANSIC */ { CHAR buf[8]; #ifndef NOXFER extern CHAR mystch; /* Outgoing Start of Packet Char */ #else CHAR mystch = '\1'; #endif /* NOXFER */ int rc; if (ttnet != NET_TCPB) return(0); /* Must be TCP/IP */ if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */ if (cmd < KERMIT_START || cmd > KERMIT_RESP_STOP) /* Illegal subcommand */ return(-1); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if (cmd == KERMIT_START || cmd == KERMIT_RESP_START) { TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1; } else if (cmd == KERMIT_STOP || cmd == KERMIT_RESP_STOP) { TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0; } else if (cmd == KERMIT_REQ_STOP) TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 1; else if (cmd == KERMIT_REQ_START) TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 1; if (cmd == KERMIT_SOP) { buf[0] = (CHAR) IAC; buf[1] = (CHAR) SB; buf[2] = (CHAR) TELOPT_KERMIT; buf[3] = (CHAR) (cmd & 0xff); buf[4] = (CHAR) mystch; buf[5] = (CHAR) IAC; buf[6] = (CHAR) SE; buf[7] = (CHAR) 0; #ifdef DEBUG if (tn_deb || debses || deblog) ckmakmsg( tn_msg_out,TN_MSG_LEN,"TELNET SENT SB KERMIT SOP ", ckctox(mystch,1)," IAC SE",NULL); #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F101,tn_msg_out,"",cmd); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = ( ttol(buf,7) < 7 ); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); } else { buf[0] = (CHAR) IAC; buf[1] = (CHAR) SB; buf[2] = (CHAR) TELOPT_KERMIT; buf[3] = (CHAR) (cmd & 0xff); buf[4] = (CHAR) IAC; buf[5] = (CHAR) SE; buf[6] = (CHAR) 0; #ifdef DEBUG if (tn_deb || debses || deblog) { char * s = 0; switch (cmd) { case KERMIT_START: s = "START"; break; case KERMIT_STOP: s = "STOP"; break; case KERMIT_REQ_START: s = "REQ-START"; break; case KERMIT_REQ_STOP: s = "REQ-STOP"; break; case KERMIT_RESP_START: s = "RESP-START"; break; case KERMIT_RESP_STOP: s = "RESP-STOP"; break; } ckmakmsg( tn_msg_out,TN_MSG_LEN, "TELNET SENT SB kermit ",s," IAC SE",NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F101,tn_msg_out,"",cmd); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = ( ttol(buf,6) < 6 ); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); } return(1); } #endif /* IKS_OPTION */ /* tn_sb() performs Telnet Subnegotiation Parsing and Debugging */ /* returns <= 0 on error, 1 on success */ /* the length returned includes the IAC SE bytes */ int #ifdef CK_ANSIC /* TELNET SB */ tn_sb( int opt, int * len, int (*fn)(int) ) #else tn_sb( opt, len, fn ) int opt; int * len; int (*fn)(); #endif /* CK_ANSIC */ /* tn_sb */ { int y, n, flag; /* if (!IS_TELNET()) return(1); */ debug(F100,"Entering tn_sb()","",0); *len = 0; /* Initialize Len to 0 */ n = flag = 0; /* Flag for when done reading SB */ while (n < TSBUFSIZ) { /* Loop looking for IAC SE */ if ((y = (*fn)(0)) < 0) /* Read a byte */ return(y); y &= 0xff; /* Make sure it's just 8 bits. */ sb[n++] = (char) y; /* Deposit in buffer. */ if (seslog && sessft == XYFT_D) { /* Take care of session log */ logchar((char) y); } if (y == IAC) { /* If this is an IAC */ if (flag) { /* If previous char was IAC */ n--; /* it's quoted, keep one IAC */ flag = 0; /* and turn off the flag. */ } else flag = 1; /* Otherwise set the flag. */ } else if (flag) { /* Something else following IAC */ if (y == SE) /* If not SE, it's a protocol error */ break; else if (y == DONT) { /* Used DONT instead of SE */ debug(F100, "TELNET Subnegotiation error - used DONT instead of SE!", "" ,0 ); if (tn_deb || debses) tn_debug( "TELNET Subnegotiation error - used DONT instead of SE!"); flag = 3; break; } else { /* Other protocol error */ flag = 0; break; } } #ifdef CK_FORWARD_X if ( opt == TELOPT_FORWARD_X && sb[0] == FWDX_DATA && n >= (TSBUFSIZ-4) && !flag ) { /* do not let the buffer over flow */ /* write the data to the channel and continue processing */ /* the incoming data until IAC SE is reached. */ sb[n++] = IAC; sb[n++] = SE; #ifdef DEBUG if ( deblog || tn_deb || debses ) { ckmakmsg( tn_msg,TN_MSG_LEN, "TELNET RCVD SB ",TELOPT(opt), " DATA(buffer-full) ",NULL); tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&sb[1],n-3); if (flag == 2) ckstrncat(tn_msg," SE",TN_MSG_LEN); else if (flag == 3) ckstrncat(tn_msg," IAC DONT",TN_MSG_LEN); else ckstrncat(tn_msg," IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #endif /* DEBUG */ if ( fwdx_tn_sb(sb,n) < 0 ) { debug(F100,"fxdx_tn_sb() failed","",0); /* We can't return though because that would leave */ /* data to be forwarded in the queue to the be sent */ /* to the terminal emulator. */ } /* reset leave the msg type and channel number in place */ n = 3; } #endif /* CK_FORWARD_X */ } debug(F111,"tn_sb end of while loop","flag",flag); if (!flag) { /* Make sure we got a valid SB */ debug(F111, "TELNET Subnegotiation prematurely broken","opt",opt); if (tn_deb || debses) { ckmakmsg( tn_msg, TN_MSG_LEN, "TELNET ", TELOPT(opt), " Subnegotiation prematurely broken",NULL ); tn_debug(tn_msg); } /* Was -1 but that would be an I/O error, so absorb it and go on. */ return(0); } #ifdef DEBUG if (deblog || tn_deb || debses) { int i; char * s[16]; for (i = 0; i < 16; i++) s[i] = ""; if (opt == TELOPT_NAWS) { i = 0; } else { i = 1; s[0] = "UNKNOWN"; switch (sb[0]) { case 0: if (opt == TELOPT_FORWARD_X) s[0] = "SCREEN"; else if (opt == TELOPT_KERMIT) s[0] = "START"; else if (opt == TELOPT_LFLOW) s[0] = "OFF"; else if (opt == TELOPT_COMPORT) s[0] = "SIGNATURE"; else s[0] = "IS"; if (opt == TELOPT_ENCRYPTION) { i++; if (sb[1] < ENCTYPE_CNT) { s[1] = enctype_names[sb[1]]; i++; switch(sb[2]) { case 1: s[2] = "FB64_IV"; break; case 2: s[2] = "FB64_IV_OK"; break; case 3: s[2] = "FB64_IV_BAD"; break; case 4: s[2] = "FB64_CHALLENGE"; break; case 5: s[2] = "FB64_RESPONSE"; break; } } else { s[1] = "UNKNOWN"; } } if (opt == TELOPT_AUTHENTICATION) { i += 2; s[1] = AUTHTYPE_NAME(sb[1]); s[2] = AUTHMODE_NAME(sb[2]); if (sb[1]) { i++; switch (sb[3]) { case 0: switch (sb[1]) { case AUTHTYPE_NTLM: s[3] = "NTLM_AUTH"; break; default: s[3] = "AUTH"; } break; case 1: switch (sb[1]) { case AUTHTYPE_SSL: s[3] = "START"; break; case AUTHTYPE_NTLM: s[3] = "NTLM_CHALLENGE"; break; default: s[3] = "REJECT"; } break; case 2: switch (sb[1]) { case AUTHTYPE_NTLM: s[3] = "NTLM_RESPONSE"; break; default: s[3] = "ACCEPT"; } break; case 3: switch (sb[1]) { case AUTHTYPE_NTLM: s[3] = "NTLM_ACCEPT"; break; case 1: /* KERBEROS_v4 */ case 5: /* SRP */ s[3] = "CHALLENGE"; break; case 2: /* KERBEROS_v5 */ s[3] = "RESPONSE"; break; case AUTHTYPE_SSL: s[3] = "REJECT"; break; } break; case 4: switch (sb[1]) { case AUTHTYPE_NTLM: s[3] = "NTLM_REJECT"; break; case 1: /* KERBEROS_V4 */ case 5: /* SRP */ s[3] = "RESPONSE"; break; case 2: /* KERBEROS_V5 */ s[3] = "FORWARD"; break; } break; case 5: switch (sb[1]) { case 5: /* SRP */ s[3] = "FORWARD"; break; case 2: /* KERBEROS_V5 */ s[3] = "FORWARD_ACCEPT"; break; } break; case 6: switch (sb[1]) { case 5: /* SRP */ s[3] = "FORWARD_ACCEPT"; break; case 2: /* KERBEROS_V5 */ s[3] = "FORWARD_REJECT"; break; } break; case 7: switch (sb[1]) { case 5: /* SRP */ s[3] = "FORWARD_REJECT"; break; case 2: /* KERBEROS_V5 */ s[3] = "TLS_VERIFY"; break; } break; case 8: switch (sb[1]) { case 5: /* SRP */ s[3] = "EXP"; break; } break; case 9: switch (sb[1]) { case 5: /* SRP */ s[3] = "PARAMS"; break; } break; } } } break; case 1: switch (opt) { case TELOPT_FORWARD_X: s[0] = "OPEN"; break; case TELOPT_LFLOW: s[0] = "ON"; break; case TELOPT_KERMIT: s[0] = "STOP"; break; case TELOPT_COMPORT: s[0] = "SET-BAUDRATE"; break; case TELOPT_AUTHENTICATION: s[0] = "SEND"; hexbuf[0] = '\0'; for (; i < n-2; i += 2) { if ( AUTHTYPE_NAME_OK(sb[i]) && AUTHMODE_NAME_OK(sb[i])) ckmakmsg( tn_msg, TN_MSG_LEN, AUTHTYPE_NAME(sb[i])," ", AUTHMODE_NAME(sb[i+1])," " ); else ckmakxmsg(tn_msg, TN_MSG_LEN, AUTHTYPE_NAME(sb[i]), "=", ckitoa(sb[i]), " ", AUTHMODE_NAME(sb[i+1]), "=", ckitoa(sb[i+1]), " ", NULL,NULL,NULL,NULL ); ckstrncat(hexbuf,tn_msg,sizeof(hexbuf)); } s[1] = hexbuf; break; case TELOPT_ENCRYPTION: s[0] = "SUPPORT"; while (i < n-2) { s[i] = enctype_names[sb[i]]; i++; } break; case TELOPT_START_TLS: s[0] = "FOLLOWS"; break; default: s[0] = "SEND"; } break; case 2: switch (opt) { case TELOPT_FORWARD_X: s[0] = "CLOSE"; break; case TELOPT_LFLOW: s[0] = "RESTART-ANY"; break; case TELOPT_KERMIT: s[0] = "REQ-START"; break; case TELOPT_COMPORT: s[0] = "SET-DATASIZE"; break; case TELOPT_NEWENVIRON: s[0] = "INFO"; break; case TELOPT_AUTHENTICATION: s[0] = "REPLY"; i=4; s[1] = AUTHTYPE_NAME(sb[1]); s[2] = AUTHMODE_NAME(sb[2]); switch (sb[3]) { case 0: switch (sb[1]) { case AUTHTYPE_NTLM: s[3] = "NTLM_AUTH"; break; default: s[3] = "AUTH"; } break; case 1: switch (sb[1]) { case AUTHTYPE_NTLM: s[3] = "NTLM_CHALLENGE"; break; default: s[3] = "REJECT"; } break; case 2: switch (sb[1]) { case AUTHTYPE_NTLM: s[3] = "NTLM_RESPONSE"; break; default: s[3] = "ACCEPT"; } break; case 3: switch (sb[1]) { case AUTHTYPE_NTLM: s[3] = "NTLM_ACCEPT"; break; case AUTHTYPE_KERBEROS_V4: case AUTHTYPE_SRP: s[3] = "CHALLENGE"; break; case AUTHTYPE_KERBEROS_V5: s[3] = "RESPONSE"; break; } break; case 4: switch (sb[1]) { case AUTHTYPE_NTLM: s[3] = "NTLM_REJECT"; break; case AUTHTYPE_KERBEROS_V4: case AUTHTYPE_SRP: s[3] = "RESPONSE"; break; case AUTHTYPE_KERBEROS_V5: s[3] = "FORWARD"; break; } break; case 5: switch (sb[1]) { case AUTHTYPE_SRP: s[3] = "FORWARD"; break; case AUTHTYPE_KERBEROS_V5: s[3] = "FORWARD_ACCEPT"; break; } break; case 6: switch (sb[1]) { case AUTHTYPE_SRP: s[3] = "FORWARD_ACCEPT"; break; case AUTHTYPE_KERBEROS_V5: s[3] = "FORWARD_REJECT"; break; } break; case 7: switch (sb[1]) { case AUTHTYPE_SRP: s[3] = "FORWARD_REJECT"; break; case AUTHTYPE_KERBEROS_V5: s[3] = "TLS_VERIFY"; break; } break; case 8: switch (sb[1]) { case AUTHTYPE_SRP: s[3] = "EXP"; break; } break; case 9: switch (sb[1]) { case AUTHTYPE_SRP: s[3] = "PARAMS"; break; } break; } break; case TELOPT_ENCRYPTION: s[0] = "REPLY"; s[1] = enctype_names[sb[1]]; i++; switch (sb[2]) { case 1: i++; s[2] = "FB64_IV"; break; case 2: i++; s[2] = "FB64_IV_OK"; break; case 3: i++; s[2] = "FB64_IV_BAD"; break; case 4: i++; s[2] = "FB64_CHALLENGE"; break; case 5: i++; s[2] = "FB64_RESPONSE"; break; } break; } break; case 3: switch (opt) { case TELOPT_FORWARD_X: s[0] = "DATA"; break; case TELOPT_LFLOW: s[0] = "RESTART-XON"; break; case TELOPT_KERMIT: s[0] = "REQ-STOP"; break; case TELOPT_COMPORT: s[0] = "SET-PARITY"; break; case TELOPT_AUTHENTICATION: s[0] = "NAME"; break; case TELOPT_ENCRYPTION: s[0] = "START"; break; } break; case 4: switch (opt) { case TELOPT_FORWARD_X: s[0] = "OPTIONS"; break; case TELOPT_KERMIT: s[0] = "SOP"; break; case TELOPT_COMPORT: s[0] = "SET-STOPSIZE"; break; case TELOPT_ENCRYPTION: s[0] = "END"; break; } break; case 5: switch (opt) { case TELOPT_FORWARD_X: s[0] = "OPTION_DATA"; break; case TELOPT_ENCRYPTION: s[0] = "REQUEST-START"; break; case TELOPT_COMPORT: s[0] = "SET-CONTROL"; break; } break; case 6: switch (opt) { case TELOPT_FORWARD_X: s[0] = "XOFF"; break; case TELOPT_ENCRYPTION: s[0] = "REQUEST-END"; break; case TELOPT_COMPORT: s[0] = "NOTIFY-LINESTATE"; break; } break; case 7: switch (opt) { case TELOPT_FORWARD_X: s[0] = "XON"; break; case TELOPT_ENCRYPTION: s[0] = "ENC-KEYID"; break; case TELOPT_COMPORT: s[0] = "NOTIFY-MODEMSTATE"; break; } break; case 8: switch (opt) { case TELOPT_KERMIT: s[0] = "RESP-START"; break; case TELOPT_ENCRYPTION: s[0] = "DEC-KEYID"; break; case TELOPT_COMPORT: s[0] = "FLOWCONTROL-SUSPEND"; break; } break; case 9: switch (opt) { case TELOPT_KERMIT: s[0] = "RESP-STOP"; break; case TELOPT_COMPORT: s[0] = "FLOWCONTROL-RESUME"; break; } break; case 10: switch (opt) { case TELOPT_COMPORT: s[0] = "SET-LINESTATE-MASK"; break; } break; case 11: switch (opt) { case TELOPT_COMPORT: s[0] = "SET-MODEMSTATE-MASK"; break; } break; case 12: switch (opt) { case TELOPT_COMPORT: s[0] = "PURGE-DATA"; break; } break; case 100: switch (opt) { case TELOPT_COMPORT: s[0] = "S_SIGNATURE"; break; } break; case 101: switch (opt) { case TELOPT_COMPORT: s[0] = "S_SET-BAUDRATE"; break; } break; case 102: switch (opt) { case TELOPT_COMPORT: s[0] = "S_SET-DATASIZE"; break; } break; case 103: switch (opt) { case TELOPT_COMPORT: s[0] = "S_SET-PARITY"; break; } break; case 104: switch (opt) { case TELOPT_COMPORT: s[0] = "S_SET-STOPSIZE"; break; } break; case 105: switch (opt) { case TELOPT_COMPORT: s[0] = "S_SET-CONTROL"; break; } break; case 106: switch (opt) { case TELOPT_COMPORT: s[0] = "S_NOTIFY-LINESTATE"; break; } break; case 107: switch (opt) { case TELOPT_COMPORT: s[0] = "S_NOTIFY-MODEMSTATE"; break; } break; case 108: switch (opt) { case TELOPT_COMPORT: s[0] = "S_FLOWCONTROL-SUSPEND"; break; } break; case 109: switch (opt) { case TELOPT_COMPORT: s[0] = "S_FLOWCONTROL-RESUME"; break; } break; case 110: switch (opt) { case TELOPT_COMPORT: s[0] = "S_SET-LINESTATE-MASK"; break; } break; case 111: switch (opt) { case TELOPT_COMPORT: s[0] = "S_SET-MODEMSTATE-MASK"; break; } break; case 112: switch (opt) { case TELOPT_COMPORT: s[0] = "S_PURGE-DATA"; break; } break; } } #ifdef M_XENIX { int len, param, param_len; ckmakmsg( tn_msg, TN_MSG_LEN, "TELNET RCVD SB ", TELOPT(opt)," ",NULL); len = strlen(tn_msg); for (param = 0; param <= 15; param++) { param_len = strlen(s[param]); if (param_len > 0) { strcpy(&tn_msg[len], s[param]); len += param_len; tn_msg[len++] = ' '; } } tn_msg[len] = '\0'; } #else /* M_XENIX */ ckmakxmsg(tn_msg,TN_MSG_LEN,"TELNET RCVD SB ",TELOPT(opt)," ", NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); { int i; for (i = 0; i < 16; i++) { if (s[i][0]) { ckstrncat(tn_msg,s[i],TN_MSG_LEN); ckstrncat(tn_msg," ",TN_MSG_LEN); } } } #endif /* M_XENIX */ tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&sb[i],n-2-i); if (flag == 2) ckstrncat(tn_msg," SE",TN_MSG_LEN); else if (flag == 3) ckstrncat(tn_msg," IAC DONT",TN_MSG_LEN); else ckstrncat(tn_msg," IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } debug(F111,"tn_sb","len",n); #endif /* DEBUG */ *len = n; /* return length */ return(1); /* success */ } static char rows_buf[16] = { 0, 0 }; /* LINES Environment variable */ static char cols_buf[16] = { 0, 0 }; /* COLUMNS Enviornment variable */ #ifndef OS2 static char term_buf[64] = { 0, 0 }; /* TERM Environment variable */ #endif /* OS2 */ #ifdef CK_CURSES #ifndef VMS #ifndef COHERENT _PROTOTYP(int tgetent,(char *, char *)); #endif /* COHERENT */ #else #ifdef __DECC _PROTOTYP(int tgetent,(char *, char *)); #endif /* __DECC */ #endif /* VMS */ extern char * trmbuf; /* Real curses */ #endif /* CK_CURSES */ #ifdef CK_ENCRYPTION static int tn_no_encrypt() { /* Prevent Encryption from being negotiated */ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; /* Cancel any negotiation that might have started */ ck_tn_enc_stop(); if (TELOPT_ME(TELOPT_ENCRYPTION) || TELOPT_UNANSWERED_WILL(TELOPT_ENCRYPTION)) { TELOPT_ME(TELOPT_ENCRYPTION) = 0; if (tn_sopt(WONT,TELOPT_ENCRYPTION) < 0) return(-1); TELOPT_UNANSWERED_WONT(TELOPT_ENCRYPTION) = 1; } if (TELOPT_U(TELOPT_ENCRYPTION) || TELOPT_UNANSWERED_DO(TELOPT_ENCRYPTION)) { TELOPT_U(TELOPT_ENCRYPTION) = 0; if (tn_sopt(DONT,TELOPT_ENCRYPTION) < 0) return(-1); TELOPT_UNANSWERED_DONT(TELOPT_ENCRYPTION) = 1; } return(0); } #endif /* CK_ENCRYPTION */ /* The following note came from the old SGA negotiation code. This should */ /* no longer be necessary with the New Telnet negotiation state machine. */ /* Note: The following is proper behavior, and required for talking to the Apertus interface to the NOTIS library system, e.g. at Iowa State U: scholar.iastate.edu. Without this reply, the server hangs forever. This code should not be loop-inducing, since C-Kermit never sends WILL SGA as an initial bid, so if DO SGA comes, it is never an ACK. */ /* Return values: -1 = Telnet Option negotiation error -2 = Connection closed by peer -3 = Connection closed by us 0 = Success 1 = Echoing on 2 = Echoing off 3 = Quoted IAC 4 = IKS Event 5 = (unassigned) 6 = Logout */ static int #ifdef CK_ANSIC /* TELNET DO OPTION */ tn_xdoop(CHAR z, int echo, int (*fn)(int)) #else tn_xdoop(z, echo, fn) CHAR z; int echo; int (*fn)(); #endif /* CK_ANSIC */ /* tn_xdoop */ { int c, x, y, n; #ifdef IKS_OPTION extern int server; #ifdef NOICP extern int autodl; int inautodl = 0, cmdadl = 1; #else #ifdef CK_AUTODL extern int autodl, inautodl, cmdadl; #endif /* CK_AUTODL */ #endif /* NOICP */ #endif /* IKS_OPTION */ /* if (!IS_TELNET()) return(7); */ /* Have IAC, read command character. */ while ((c = (*fn)(0)) == -1); /* Read command character */ if (c < 0) return(c); c &= 0xFF; /* Strip high bits */ if (!TELCMD_OK(c)) { #ifdef DEBUG if (tn_deb || debses || deblog) { ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET RCVD UNKNOWN (", ckitoa(c),")",NULL); debug(F101,tn_msg,"",c); if (tn_deb || debses) tn_debug(tn_msg); } #endif /* DEBUG */ return(0); } if (ttnproto == NP_NONE) { debug(F100,"tn_doop discovered a Telnet command", "ttnproto = NP_TELNET",0); ttnproto = NP_TELNET; } if (seslog && sessft == XYFT_D) { /* Copy to session log, if any. */ logchar((char)z); logchar((char)c); } if (c == (CHAR) IAC) /* Quoted IAC */ return(3); if (c < SB) { /* Other command with no arguments. */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET RCVD ",TELCMD(c),NULL,NULL); debug(F101,tn_msg,"",c); if (tn_deb || debses) tn_debug(tn_msg); } #endif /* DEBUG */ switch (c) { /* What we would like to do here */ case TN_GA: /* Is substitute ASCII characters */ break; /* for the Telnet Command so that */ case TN_EL: /* the command may be processed by */ break; /* either the internal emulator or */ case TN_EC: /* by the superior process or shell */ break; case TN_AYT: #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol((CHAR *)"[Yes]\015\012",7); #ifdef OS2 ReleaseTelnetMutex(); #endif break; case TN_AO: #ifdef BETADEBUG bleep(BP_NOTE); #endif /* BETADEBUG */ break; case TN_IP: break; case BREAK: break; case TN_DM: break; case TN_NOP: break; case SE: break; case TN_EOR: break; case TN_ABORT: break; case TN_SUSP: break; case TN_EOF: break; case TN_SAK: break; } return(0); } /* SB, WILL, WONT, DO, or DONT need more bytes... */ if ((x = (*fn)(0)) < 0) /* Get the option. */ return(x); x &= 0xff; /* Trim to 8 bits. */ if (seslog && sessft == XYFT_D) { /* Session log */ logchar((char) x); } #ifdef DEBUG if ((deblog || tn_deb || debses) && c != SB) { ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET RCVD ",TELCMD(c)," ",TELOPT(x)); debug(F101,tn_msg,"",x); if (tn_deb || debses) tn_debug(tn_msg); } #endif /* DEBUG */ /* Now handle the command */ switch (c) { case WILL: #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) return(0); #endif /* CK_SSL */ #ifdef CK_FORWARD_X if (x == TELOPT_FORWARD_X) { if (!fwdx_server_avail() || !(fwdx_no_encrypt || #ifdef CK_SSL (ssl_active_flag || tls_active_flag) #else /* CK_SSL */ 0 #endif /* CK_SSL */ || #ifdef CK_ENCRYPTION (ck_tn_encrypting() && ck_tn_decrypting()) #else /* CK_ENCRYPTION */ 0 #endif /* CK_ENCRYPTION */ )) { TELOPT_U_MODE(TELOPT_FORWARD_X) = TN_NG_RF; TELOPT_ME_MODE(TELOPT_FORWARD_X) = TN_NG_RF; } } #endif /* CK_FORWARD_X */ if (!TELOPT_OK(x) || TELOPT_U_MODE(x) == TN_NG_RF) { if (tn_sopt(DONT,x) < 0) return(-1); if (TELOPT_UNANSWERED_DO(x)) TELOPT_UNANSWERED_DO(x) = 0; } else if (!TELOPT_U(x)) { if (!TELOPT_UNANSWERED_DO(x)) { if (tn_sopt(DO,x) < 0) return -1; } if (TELOPT_UNANSWERED_DO(x)) TELOPT_UNANSWERED_DO(x) = 0; TELOPT_U(x) = 1; switch (x) { #ifdef CK_SSL case TELOPT_START_TLS: /* If my proposal is accepted, at this point the Telnet protocol is turned off and a TLS negotiation takes place. Start by sending SB START_TLS FOLLOWS to signal we are ready. Wait for the peer to send the same and then start the TLS negotiation. If the TLS negotiation succeeds we call tn_ini() again to reset the telnet state machine and restart the negotiation process over the now secure link. If the TLS negotiation fails, we call ttclos() to terminate the connection. Only the server should receive a WILL START_TLS */ tn_ssbopt(TELOPT_START_TLS,1,NULL,0); TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 1; break; #endif /* CK_SSL */ #ifdef CK_AUTHENTICATION case TELOPT_AUTHENTICATION: { /* We now have to perform a SB SEND to identify the */ /* supported authentication types to the other side. */ extern int authentication_version; #ifdef CK_SSL /* if we have an outstanding DO START_TLS then we must * wait for the response before we determine what to do */ if (TELOPT_UNANSWERED_DO(TELOPT_START_TLS)) { TELOPT_SB(TELOPT_START_TLS).start_tls.auth_request = 1; break; } #endif /* CK_SSL */ authentication_version = AUTHTYPE_AUTO; ck_tn_auth_request(); break; } #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION case TELOPT_ENCRYPTION: if (!(TELOPT_ME(TELOPT_AUTHENTICATION) || TELOPT_U(TELOPT_AUTHENTICATION)) ) { if (tn_sopt(DONT,x) < 0) return(-1); TELOPT_U(x) = 0; } else { if (ck_tn_auth_in_progress()) { TELOPT_SB(TELOPT_ENCRYPTION).encrypt.need_to_send = 1; } else { /* Perform subnegotiation */ ck_encrypt_send_support(); } if (!(TELOPT_ME(x) || TELOPT_UNANSWERED_WILL(x)) && TELOPT_ME_MODE(x) != TN_NG_RF) { if (tn_sopt(WILL, x) < 0) return(-1); TELOPT_UNANSWERED_WILL(x) = 1; } } break; #endif /* CK_ENCRYPTION */ #ifdef IKS_OPTION case TELOPT_KERMIT: if (!TELOPT_ME(x)) { /* Tell the other side what Start of Packet Character */ tn_siks(KERMIT_SOP); /* SOP */ if (!TELOPT_UNANSWERED_WILL(x) && TELOPT_ME_MODE(x) != TN_NG_RF) { if (tn_sopt(WILL, x) < 0) return(-1); TELOPT_UNANSWERED_WILL(x) = 1; } } break; #endif /* IKS_OPTION */ case TELOPT_BINARY: if (!TELOPT_ME(x)) { if (!TELOPT_UNANSWERED_WILL(x) && TELOPT_ME_MODE(x) >= TN_NG_RQ) { if (tn_sopt(WILL, x) < 0) return(-1); TELOPT_UNANSWERED_WILL(x) = 1; } } break; case TELOPT_ECHO: if (echo) { if (TELOPT_UNANSWERED_DO(x)) TELOPT_UNANSWERED_DO(x) = 0; return(2); } break; case TELOPT_TTYPE: /* SB TTYPE SEND */ tn_ssbopt(TELOPT_TTYPE,TELQUAL_SEND,NULL,0); TELOPT_UNANSWERED_SB(TELOPT_TTYPE)=1; break; #ifdef CK_ENVIRONMENT case TELOPT_NEWENVIRON: /* SB NEW-ENVIRON SEND */ { CHAR requestbuf[6]; /* Was CHAR but Clang hollers */ char * request = (char *)requestbuf; sprintf(request,"%cUSER",TEL_ENV_VAR); /* safe */ tn_ssbopt(TELOPT_NEWENVIRON,TELQUAL_SEND,(CHAR *)requestbuf, strlen((char *)request)); /* SMS 2022-06-03 */ TELOPT_UNANSWERED_SB(TELOPT_NEWENVIRON)=1; } break; #endif /* CK_ENVIRONMENT */ } /* switch */ } else { if (TELOPT_UNANSWERED_DO(x)) TELOPT_UNANSWERED_DO(x) = 0; } break; case WONT: #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) return(0); #endif /* CK_SSL */ if (TELOPT_U(x) || TELOPT_UNANSWERED_DO(x)) { /* David Borman says we should not respond DONT when * the WONT is a response to a DO that we sent. * Nor should we send one if the state is already WONT * such as when we do not recognize the option since * options are initialized in the WONT/DONT state. */ if (!(TELOPT_UNANSWERED_DO(x) || TELOPT_UNANSWERED_DONT(x))) if (tn_sopt(DONT,x) < 0) return(-1); if (TELOPT_UNANSWERED_DONT(x)) TELOPT_UNANSWERED_DONT(x) = 0; if (TELOPT_UNANSWERED_DO(x)) TELOPT_UNANSWERED_DO(x) = 0; if (TELOPT_U(x)) { TELOPT_U(x) = 0; } switch(x) { #ifdef CK_SSL case TELOPT_START_TLS: if (sstelnet) { if (TELOPT_U_MODE(x) == TN_NG_MU) { printf("Telnet Start-TLS refused.\n"); ttclos(0); whyclosed = WC_TELOPT; return(-3); } if (TELOPT_SB(x).start_tls.auth_request) { extern int authentication_version; TELOPT_SB(x).start_tls.auth_request = 0; authentication_version = AUTHTYPE_AUTO; ck_tn_auth_request(); } } break; #endif /* CK_SSL */ #ifdef CK_AUTHENTICATION case TELOPT_AUTHENTICATION: if (sstelnet && TELOPT_U_MODE(x) == TN_NG_MU) { printf("Telnet authentication refused.\n"); ttclos(0); whyclosed = WC_TELOPT; return(-3); } else if (TELOPT_U_MODE(x) == TN_NG_RQ) { TELOPT_U_MODE(x) = TN_NG_AC; } if (ck_tn_auth_in_progress()) printf("Telnet authentication refused.\n"); #ifdef CK_ENCRYPTION if (sstelnet) { if (tn_no_encrypt()<0) return(-1); } #endif /* CK_ENCRYPTION */ break; #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION case TELOPT_ENCRYPTION: ck_tn_enc_stop(); break; #endif /* CK_ENCRYPTION */ #ifdef IKS_OPTION case TELOPT_KERMIT: TELOPT_SB(x).kermit.u_start = 0; TELOPT_SB(x).kermit.me_req_start = 0; TELOPT_SB(x).kermit.me_req_stop = 0; break; #endif /* IKS_OPTION */ case TELOPT_NAWS: { /* The client does not support NAWS. */ /* Assume a height of 24 and a width of 80 */ if (sstelnet #ifdef IKSD || inserver #endif /* IKSD */ ) { int w = 80, h = 24; #ifndef NOLOCAL if (tcp_incoming) { #ifdef OS2 tt_cols[VTERM] = w; tt_rows[VTERM] = h; VscrnSetWidth(VTERM, w); VscrnSetHeight(VTERM, h+(tt_status[VTERM]?1:0)); #else /* OS2 */ tt_cols = w; tt_rows = h; #endif /* OS2 */ } else { #ifdef OS2 tt_cols[VCMD] = w; tt_rows[VCMD] = h; VscrnSetWidth(VCMD, w); VscrnSetHeight(VCMD, h); #endif /* OS2 */ cmd_cols = w; cmd_rows = h; } #else /* NOLOCAL */ cmd_cols = w; cmd_rows = h; #endif /* NOLOCAL */ /* Add LINES and COLUMNS to the environment */ ckmakmsg((char *)rows_buf,16,"LINES=",ckitoa(h), NULL,NULL); ckmakmsg((char *)cols_buf,16,"COLUMNS=",ckitoa(w), NULL,NULL); #ifdef OS2ORUNIX #ifndef NOPUTENV putenv(rows_buf); putenv(cols_buf); #endif /* NOPUTENV */ #endif /* OS2ORUNIX */ } break; } case TELOPT_ECHO: if (!echo) { if (TELOPT_UNANSWERED_DO(x)) TELOPT_UNANSWERED_DO(x) = 0; return(1); } break; } } else { if (TELOPT_UNANSWERED_DONT(x)) TELOPT_UNANSWERED_DONT(x) = 0; if (TELOPT_UNANSWERED_DO(x)) TELOPT_UNANSWERED_DO(x) = 0; } if (TELOPT_U_MODE(x) == TN_NG_MU) { ckmakmsg( tn_msg,TN_MSG_LEN, "Peer refuses TELNET DO ",TELOPT(x), " negotiations - terminating connection",NULL ); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); printf("%s\n",tn_msg); ttclos(0); whyclosed = WC_TELOPT; return(-3); } #ifdef COMMENT if (x == TELOPT_ECHO && !echo) /* Special handling for echo */ return(1); /* because we allow 'duplex' */ #endif /* COMMENT */ break; case DO: #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) return(0); #endif /* CK_SSL */ if (!TELOPT_OK(x) || TELOPT_ME_MODE(x) == TN_NG_RF) { if (tn_sopt(WONT,x) < 0) return(-1); if (TELOPT_UNANSWERED_WILL(x)) TELOPT_UNANSWERED_WILL(x) = 0; } else if (!TELOPT_ME(x)) { if (!TELOPT_UNANSWERED_WILL(x)) { if (tn_sopt(WILL,x) < 0) return(-1); } if (TELOPT_UNANSWERED_WILL(x)) TELOPT_UNANSWERED_WILL(x) = 0; TELOPT_ME(x) = 1; switch (x) { #ifdef CK_SSL case TELOPT_START_TLS: /* If my proposal is accepted at this point the Telnet protocol is turned off and a TLS negotiation takes place. Start by sending SB START_TLS FOLLOWS to signal we are ready. Wait for the peer to send the same and then start the TLS negotiation. If the TLS negotiation succeeds we call tn_ini() again to reset the telnet state machine and restart the negotiation process over the now secure link. If the TLS negotiation fails, we call ttclos() to terminate the connection. Then we set the U_MODE and ME_MODE for TELOPT_START_TLS to REFUSE and then call ttopen() to create a new connection to the same host but this time do not attempt TLS security. Only the client should receive DO START_TLS. */ tn_ssbopt(TELOPT_START_TLS,1,NULL,0); TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 1; break; #endif /* CK_SSL */ #ifdef CK_AUTHENTICATION case TELOPT_AUTHENTICATION: { /* We don't know what authentication we are using yet */ /* but it is not NULL until a failure is detected so */ /* use AUTO in the meantime. */ extern int authentication_version; authentication_version = AUTHTYPE_AUTO; break; } #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION case TELOPT_ENCRYPTION: if (!(TELOPT_ME(TELOPT_AUTHENTICATION) || TELOPT_U(TELOPT_AUTHENTICATION)) ) { if (tn_sopt(WONT,x) < 0) return(-1); TELOPT_ME(x) = 0; } else { if (!(TELOPT_U(x) || TELOPT_UNANSWERED_DO(x)) && TELOPT_U_MODE(x) != TN_NG_RF) { if (tn_sopt(DO, x) < 0) return(-1); TELOPT_UNANSWERED_DO(x) = 1; } } break; #endif /* CK_ENCRYPTION */ #ifdef IKS_OPTION case TELOPT_KERMIT: /* If currently processing Kermit server packets, must tell the other side */ debug(F111,"tn_doop","what",what); debug(F111,"tn_doop","server",server); #ifdef CK_AUTODL debug(F111,"tn_doop","autodl",autodl); debug(F111,"tn_doop","inautodl",inautodl); debug(F111,"tn_doop","cmdadl",cmdadl); #endif /* CK_AUTODL */ if (server #ifdef CK_AUTODL || (local && ((what == W_CONNECT && autodl) || (what != W_CONNECT && inautodl))) || (!local && cmdadl) #endif /* CK_AUTODL */ ) { tn_siks(KERMIT_START); /* START */ } if (!TELOPT_U(x)) { /* Tell the other side what Start of Packet Character */ tn_siks(KERMIT_SOP); /* SOP */ if (!TELOPT_UNANSWERED_DO(x) && TELOPT_U_MODE(x) != TN_NG_RF) { if (tn_sopt(DO, x) < 0) return(-1); TELOPT_UNANSWERED_DO(x) = 1; } } break; #endif /* IKS_OPTION */ case TELOPT_BINARY: if (!TELOPT_U(x)) { if (!TELOPT_UNANSWERED_DO(x) && TELOPT_U_MODE(x) >= TN_NG_RQ) { if (tn_sopt(DO, x) < 0) return(-1); TELOPT_UNANSWERED_DO(x) = 1; } } break; case TELOPT_NAWS: #ifdef CK_NAWS if ( !tn_delay_sb || !tn_outst(0) || tn_init ) { if (tn_snaws() < 0) return(-1); } else { TELOPT_SB(TELOPT_NAWS).naws.need_to_send = 1; } #endif /* CK_NAWS */ break; case TELOPT_LOGOUT: ttclos(0); /* And then hangup */ whyclosed = WC_TELOPT; return(6); #ifdef CK_SNDLOC case TELOPT_SNDLOC: if ( !tn_delay_sb || !tn_outst(0) || tn_init ) { if (tn_sndloc() < 0) return(-1); } else { TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send = 1; } break; #endif /* CK_SNDLOC */ #ifdef CK_FORWARD_X case TELOPT_FORWARD_X: if ( !tn_delay_sb || !tn_outst(0) || tn_init ) { if (fwdx_send_options() < 0) { if (tn_sopt(DONT,x) < 0) return(-1); TELOPT_UNANSWERED_DONT(x) = 1; } } else { TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send = 1; } break; #endif /* CK_FORWARD_X */ #ifdef TN_COMPORT case TELOPT_COMPORT: { extern int reliable; if (!tn_delay_sb || !tn_outst(0) || tn_init) { if (tn_sndcomport() < 0) return(-1); } else { TELOPT_SB(TELOPT_COMPORT).comport.need_to_send = 1; } /* Telnet -> Serial -> ??? is not a reliable connection. */ reliable = SET_OFF; break; } #endif /* TN_COMPORT */ } /* switch */ } else { if (TELOPT_UNANSWERED_WILL(x)) TELOPT_UNANSWERED_WILL(x) = 0; } break; case DONT: #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) return(0); #endif /* CK_SSL */ if (TELOPT_ME(x) || TELOPT_UNANSWERED_WILL(x)) { /* David Borman says we should not respond WONT when * the DONT is a response to a WILL that we sent. * Nor should we send one if the state is already WONT * such as when we do not recognize the option since * options are initialized in the WONT/DONT state. */ if (!(TELOPT_UNANSWERED_WILL(x) || TELOPT_UNANSWERED_WONT(x))) if (tn_sopt(WONT,x) < 0) return(-1); if (TELOPT_UNANSWERED_WILL(x)) TELOPT_UNANSWERED_WILL(x) = 0; if (TELOPT_UNANSWERED_WONT(x)) TELOPT_UNANSWERED_WONT(x) = 0; if (TELOPT_ME(x)) TELOPT_ME(x) = 0; switch (x) { #ifdef CK_SSL case TELOPT_START_TLS: if (!sstelnet && TELOPT_ME_MODE(x) == TN_NG_MU) { printf("Telnet Start-TLS refused.\n"); ttclos(0); whyclosed = WC_TELOPT; return(-3); } break; #endif /* CK_SSL */ #ifdef CK_AUTHENTICATION case TELOPT_AUTHENTICATION: if (!sstelnet && TELOPT_ME_MODE(x) == TN_NG_MU) { #ifdef CK_SSL if (tls_active_flag) { TELOPT_ME_MODE(x) = TN_NG_AC; break; } else #endif /* CK_SSL */ { printf("Telnet authentication refused.\n"); ttclos(0); whyclosed = WC_TELOPT; return(-3); } } else if (TELOPT_ME_MODE(x) == TN_NG_RQ) { TELOPT_ME_MODE(x) = TN_NG_AC; } if (ck_tn_auth_in_progress()) printf("Telnet authentication refused.\n"); #ifdef CK_ENCRYPTION if (!sstelnet) { if (tn_no_encrypt()<0) return(-1); } #endif /* CK_ENCRYPTION */ break; #endif /* CK_AUTHENTICATION */ case TELOPT_ENCRYPTION: #ifdef CK_ENCRYPTION ck_tn_enc_stop(); #endif /* CK_ENCRYPTION */ break; case TELOPT_KERMIT: #ifdef IKS_OPTION TELOPT_SB(x).kermit.me_start = 0; /* Begin section added 2013-04-12 */ /* The idea here is to nullify any outstanding Telnet Kermit subnegotiations. The first three should do the trick, but they don't. Setting TELOPT_U(TELOPT_KERMIT) to 0, however, does. TELOPT_ME(TELOPT_KERMIT) = 0; TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0; TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0; */ TELOPT_U(TELOPT_KERMIT) = 0; /* End section added 2013-04-12 */ #endif /* IKS_OPTION */ break; default: break; } /* switch */ } else { if (TELOPT_UNANSWERED_WILL(x)) TELOPT_UNANSWERED_WILL(x) = 0; if (TELOPT_UNANSWERED_WONT(x)) TELOPT_UNANSWERED_WONT(x) = 0; } if (TELOPT_ME_MODE(x) == TN_NG_MU) { ckmakmsg( tn_msg,TN_MSG_LEN, "Peer refuses TELNET WILL ",TELOPT(x), " negotiations - terminating connection", NULL ); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); printf("%s\n",tn_msg); ttclos(0); whyclosed = WC_TELOPT; return(-3); } break; case SB: if ((y = tn_sb(x,&n,fn)) <= 0) return(y); #ifdef CK_SSL /* Do not process subnegotiations other than START_TLS after we */ /* have agreed to begin the TLS negotiation sequence. */ if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows && x != TELOPT_START_TLS) break; #endif /* CK_SSL */ if (!TELOPT_OK(x)) { ckhexdump("unknown telnet subnegotiation",sb,n); break; } else if ( !(TELOPT_ME(x) || TELOPT_U(x)) ) { ckhexdump("telnet option not negotiated",sb,n); if (!tn_sb_bug) break; if (TELOPT_UNANSWERED_WILL(x)) { TELOPT_UNANSWERED_WILL(x) = 0; TELOPT_U(x) = 1; ckmakmsg(tn_msg,TN_MSG_LEN, "TELNET DO ",TELOPT(x), "(implied by receipt of SB - protocol error ignored)", NULL ); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } if (TELOPT_UNANSWERED_DO(x)) { TELOPT_UNANSWERED_DO(x) = 0; TELOPT_ME(x) = 1; ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET WILL ",TELOPT(x), " (implied by receipt of SB - protocol error ignored)", NULL); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } } TELOPT_UNANSWERED_SB(x)=0; switch (x) { #ifdef CK_FORWARD_X case TELOPT_FORWARD_X: return(fwdx_tn_sb(sb, n)); #endif /* CK_FORWARD_X */ #ifdef CK_SSL case TELOPT_START_TLS: { /* the other side is saying SB START_TLS FOLLOWS the incoming channel is now ready for starting the TLS negotiation. */ int def_tls_u_mode, def_tls_me_mode; int def_enc_u_mode, def_enc_me_mode; int rc = 0; if (sb[0] != 1) { break; } TELOPT_SB(TELOPT_START_TLS).start_tls.u_follows = 1; /* Preserve the default modes and make sure we will */ /* refuse START_TLS when we retry. */ if (sstelnet) { def_tls_u_mode = TELOPT_DEF_S_U_MODE(TELOPT_START_TLS); def_tls_me_mode = TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS); TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF; TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS)= TN_NG_RF; #ifdef CK_ENCRYPTION def_enc_u_mode = TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION); def_enc_me_mode = TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION); TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION)= TN_NG_RF; #endif /* CK_ENCRYPTION */ } else { def_tls_u_mode = TELOPT_DEF_C_U_MODE(TELOPT_START_TLS); def_tls_me_mode = TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS); TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF; TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS)= TN_NG_RF; #ifdef CK_ENCRYPTION def_enc_u_mode = TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION); def_enc_me_mode = TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION); TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION)= TN_NG_RF; #endif /* CK_ENCRYPTION */ } /* Negotiate TLS */ ttnproto = NP_TLS; tn_init = 0; tn_begun = 0; if (ck_tn_tls_negotiate()<0) { /* we failed. disconnect and if we are the client */ /* then reconnect and try without START_TLS. */ extern char * line; int x = -1; extern int mdmtyp; if (sstelnet) { printf("TLS failed: Disconnecting.\n"); TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = def_tls_u_mode; TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = def_tls_me_mode; #ifdef CK_ENCRYPTION TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = def_enc_u_mode; TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = def_enc_me_mode; #endif /* CK_ENCRYPTION */ ttclos(0); whyclosed = WC_TELOPT; ttnproto = NP_TELNET; rc = -3; } else { #ifndef NOLOCAL extern int tls_norestore; #endif /* NOLOCAL */ printf("TLS failed: Disconnecting...\n"); #ifdef CK_ENCRYPTION TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = def_enc_u_mode; TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = def_enc_me_mode; #endif /* CK_ENCRYPTION */ /* if START_TLS is not REQUIRED, then retry without it */ if ( def_tls_me_mode != TN_NG_MU ) { extern char ttname[]; #ifndef NOLOCAL tls_norestore = 1; #endif /* NOLOCAL */ ttclos(0); whyclosed = WC_TELOPT; #ifndef NOLOCAL tls_norestore = 0; #endif /* NOLOCAL */ ttnproto = NP_TELNET; printf("Reconnecting without TLS.\n"); sleep(2); if (ttopen(ttname,&x,mdmtyp,0)<0) rc = -3; } else { TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = def_tls_u_mode; TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = def_tls_me_mode; ttclos(0); whyclosed = WC_TELOPT; ttnproto = NP_TELNET; rc = -3; } } } else { #ifdef CK_AUTHENTICATION /* we succeeded. restart telnet negotiations from */ /* the beginning. However, if we have received a */ /* client certificate and we are a server, then do */ /* not offer TELOPT_AUTH. */ if ( ck_tn_auth_valid() == AUTH_VALID ) { TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_AC; TELOPT_DEF_S_ME_MODE(TELOPT_AUTHENTICATION)= TN_NG_AC; } #endif /* CK_AUTHENTICATION */ ttnproto = NP_TELNET; if (tn_ini() < 0) if (ttchk() < 0) rc = -1; } /* Restore the default modes */ if (sstelnet) { TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = def_tls_u_mode; TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = def_tls_me_mode; #ifdef CK_ENCRYPTION TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = def_enc_u_mode; TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = def_enc_me_mode; #endif /* CK_ENCRYPTION */ } else { TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = def_tls_u_mode; TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = def_tls_me_mode; #ifdef CK_ENCRYPTION TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = def_enc_u_mode; TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = def_enc_me_mode; #endif /* CK_ENCRYPTION */ } return(rc); } #endif /* CK_SSL */ #ifdef CK_AUTHENTICATION case TELOPT_AUTHENTICATION: if (ck_tn_sb_auth((char *)sb,n) < 0) { if (sstelnet && TELOPT_U_MODE(x) == TN_NG_MU) { ttclos(0); whyclosed = WC_TELOPT; return(-3); } else if (!sstelnet && TELOPT_ME_MODE(x) == TN_NG_MU) { ttclos(0); whyclosed = WC_TELOPT; return(-3); } else { if (TELOPT_ME_MODE(x) == TN_NG_RQ) TELOPT_ME_MODE(x) = TN_NG_AC; if (TELOPT_U_MODE(x) == TN_NG_RQ) TELOPT_U_MODE(x) = TN_NG_AC; } if (TELOPT_ME(x)) { TELOPT_ME(x) = 0; if (tn_sopt(WONT,x) < 0) return(-1); } if (TELOPT_U(x)) { TELOPT_U(x) = 0; if (tn_sopt(DONT,x) < 0) return(-1); } #ifdef CK_ENCRYPTION if (tn_no_encrypt()<0) return(-1); #endif /* CK_ENCRYPTION */ } else { #ifdef CK_ENCRYPTION if (!ck_tn_auth_in_progress()) { /* we are finished */ if (ck_tn_authenticated() == AUTHTYPE_SSL) { /* TLS was successful. Disable ENCRYPTION */ TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.need_to_send) { ck_encrypt_send_support(); TELOPT_SB(TELOPT_ENCRYPTION).encrypt.need_to_send = 0; } } #endif /* CK_ENCRYPTION */ } break; #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION case TELOPT_ENCRYPTION: if (ck_tn_sb_encrypt((char *)sb, n) < 0) { if (TELOPT_U_MODE(x) == TN_NG_MU || TELOPT_ME_MODE(x) == TN_NG_MU) { ttclos(0); whyclosed = WC_TELOPT; return(-3); } else { if (TELOPT_ME_MODE(x) == TN_NG_RQ) TELOPT_ME_MODE(x) = TN_NG_AC; if (TELOPT_U_MODE(x) == TN_NG_RQ) TELOPT_U_MODE(x) = TN_NG_AC; } if (TELOPT_ME(x)) { TELOPT_ME(x) = 0; if (tn_sopt(WONT,x) < 0) return(-1); } if (TELOPT_U(x)) { TELOPT_U(x) = 0; if (tn_sopt(DONT,x) < 0) return(-1); } } break; #endif /* CK_ENCRYPTION */ #ifdef IKS_OPTION case TELOPT_KERMIT: return(iks_tn_sb(sb, n-2)); #endif /* IKS_OPTION */ #ifdef TN_COMPORT case TELOPT_COMPORT: return(tnc_tn_sb(sb, n-2)); #endif /* TN_COMPORT */ case TELOPT_TTYPE: switch (sb[0]) { case TELQUAL_SEND: /* SEND terminal type? */ if ( !tn_delay_sb || !tn_outst(0) || tn_init ) { if (tn_sttyp() < 0) /* Yes, so send it. */ return(-1); } else { TELOPT_SB(TELOPT_TTYPE).term.need_to_send = 1; } break; case TELQUAL_IS: { /* IS terminal type? */ /* IS terminal type -- remote gave us its current type */ int i = 0; #ifndef OS2 CHAR oldterm[64], *p; #endif /* OS2 */ /* Isolate the specified terminal type string */ while (sb[i++] != IAC) { if (i == 40 || /* max len of term string - RFC */ sb[i] == IAC) { sb[i] = '\0'; break; } } #ifdef OS2 #ifndef NOTERM strupr(&(sb[1])); /* Upper case it */ for (i = 0; i <= max_tt; i++) { /* find it in our list */ if (!strcmp(&(sb[1]),tt_info[i].x_name) && i != TT_VTNT) /* can't support VTNT as server */ { /* Set terminal type to the one chosen */ if (i != tt_type) settermtype(i,0); break; } } if (i > max_tt && strcmp(&(sb[1]),TELOPT_SB(TELOPT_TTYPE).term.type)) { /* Couldn't find the specified term type */ sb[40] = '\0'; strcpy(TELOPT_SB(TELOPT_TTYPE).term.type,&(sb[1])); /* SB TTYPE SEND */ tn_ssbopt(TELOPT_TTYPE,TELQUAL_SEND,NULL,0); TELOPT_UNANSWERED_SB(TELOPT_TTYPE)=1; } #endif /* NOTERM */ #else /* OS2 */ p = (CHAR *) getenv("TERM"); if (p) ckstrncpy((char *)oldterm,(char *)p,63); else oldterm[0] = '\0'; cklower((char *)&(sb[1])); /* Lower case new term */ ckmakmsg(term_buf,64,"TERM=",(char *)&(sb[1]),NULL,NULL); #ifdef OS2ORUNIX #ifndef NOPUTENV putenv(term_buf); #endif /* NOPUTENV */ #endif /* OS2ORUNIX */ #ifdef CK_CURSES #ifndef MYCURSES #ifndef COHERENT if (trmbuf) { if (tgetent(trmbuf,(char *)&sb[1]) < 1) { /* Unsupported terminal. If new and old terminal */ /* types do not match, ask for another type. */ if (strcmp((char *)oldterm,(char *)&sb[1])) { /* SB TTYPE SEND */ tn_ssbopt(TELOPT_TTYPE,TELQUAL_SEND,NULL,0); TELOPT_UNANSWERED_SB(TELOPT_TTYPE)=1; } } } #endif /* COHERENT */ #endif /* MYCURSES */ #endif /* CK_CURSES */ #endif /* OS2 */ } } break; #ifdef CK_ENVIRONMENT #ifdef CK_XDISPLOC case TELOPT_XDISPLOC: /* Send X-Display Location */ if (sb[0] == TELQUAL_SEND) {/* SEND X-Display Loc? */ if ( !tn_delay_sb || !tn_outst(0) || tn_init ) { if (tn_sxdisploc() < 0) /* Yes, so send it. */ return(-1); } else { TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send = 1; } } /* IS -- X Display Location (not supported) */ else if (sb[0] == TELQUAL_IS) { int i = 0; /* Isolate the specified X-display string */ while (sb[i++] != IAC) { if (i >= TSBUFSIZ) return (-1); if (sb[i] == IAC) { sb[i] = '\0'; break; } } debug(F110,"TELNET SB XDISPLOC IS",&sb[1],0); } break; #endif /* CK_XDISPLOC */ #endif /* CK_ENVIRONMENT */ case TELOPT_NAWS: if (sstelnet #ifdef IKSD || inserver #endif /* IKSD */ ) { int w = 0, h = 0; int i = 0; /* At this point sb[] should contain width and height */ if (sb[i] == IAC) i++; w = (sb[i++] << 8); /* save upper height */ if (sb[i] == IAC) i++; w += sb[i++]; /* save the width */ if (sb[i] == IAC) i++; h = (sb[i++] << 8); /* save upper height */ if (sb[i] == IAC) i++; h += sb[i++]; debug(F111,"tn_doop NAWS SB","width",w); debug(F111,"tn_doop NAWS SB","height",h); if (w == 0) w = 80; if (h == 0) h = 24; #ifndef NOLOCAL if (tcp_incoming || inserver) { #ifdef OS2 tt_cols[VTERM] = w; tt_rows[VTERM] = h; VscrnSetWidth(VTERM, w); VscrnSetHeight(VTERM, h+(tt_status[VTERM]?1:0)); #ifdef IKSD if (inserver) { cmd_cols = tt_cols[VCMD] = w; cmd_rows = tt_rows[VCMD] = h; VscrnSetWidth(VCMD, w); VscrnSetHeight(VCMD, h); } #endif /* IKSD */ #else /* OS2 */ tt_cols = w; tt_rows = h; #endif /* OS2 */ } else { #ifdef OS2 tt_cols[VCMD] = w; tt_rows[VCMD] = h; VscrnSetWidth(VCMD, w); VscrnSetHeight(VCMD, h); #endif /* OS2 */ cmd_cols = w; cmd_rows = h; } #else /* NOLOCAL */ cmd_cols = w; cmd_rows = h; #endif /* NOLOCAL */ /* Add LINES and COLUMNS to the environment */ ckmakmsg((char *)rows_buf,16,"LINES=",ckitoa(h),NULL,NULL); ckmakmsg((char *)cols_buf,16,"COLUMNS=",ckitoa(w),NULL,NULL); #ifdef OS2ORUNIX #ifndef NOPUTENV putenv(rows_buf); putenv(cols_buf); #endif /* NOPUTENV */ #endif /* OS2ORUNIX */ } break; #ifdef CK_ENVIRONMENT case TELOPT_NEWENVIRON: switch (sb[0]) { case TELQUAL_IS: /* IS */ case TELQUAL_INFO: /* INFO */ if (sb[0] == TELQUAL_IS) debug(F101,"tn_doop NEW-ENV SB IS","",n-3); else debug(F101,"tn_doop NEW-ENV SB INFO","",n-3); if (sstelnet || inserver) { /* Yes, receive it. */ if (tn_rnenv((CHAR *)&sb[1],n-3) < 0) return(-1); } break; case TELQUAL_SEND: /* SEND */ if ( sstelnet || inserver ) /* ignore if server */ break; /* We need to take the sb[] and build a structure */ /* containing all of the variables and types that */ /* we are supposed to keep track of and send to */ /* the host, then call tn_snenv(). */ /* Or we can punt ... */ if ( !tn_delay_sb || !tn_outst(0) || tn_init ) { if (tn_snenv((CHAR *)&sb[1],n-3) < 0) /* Yes, send it. */ return(-1); } else { #ifndef VMS CHAR * xxx; xxx = (CHAR *) malloc(n-1); #else unsigned char * xxx; xxx = (unsigned char *) malloc(n-1); #endif /* VMS */ /* Postpone sending until end of tn_ini() */ TELOPT_SB(TELOPT_NEWENVIRON).env.str = xxx; if (TELOPT_SB(TELOPT_NEWENVIRON).env.str) { memcpy((char *)TELOPT_SB(TELOPT_NEWENVIRON).env.str, (char *)&sb[1],n-3); TELOPT_SB(TELOPT_NEWENVIRON).env.str[n-3] = IAC; TELOPT_SB(TELOPT_NEWENVIRON).env.str[n-2] = '\0'; TELOPT_SB(TELOPT_NEWENVIRON).env.len = n-3; TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send = 1; } } break; } break; #endif /* CK_ENVIRONMENT */ #ifdef CK_SNDLOC case TELOPT_SNDLOC: { if ( deblog ) { sb[n-2] = '\0'; debug(F110,"TELNET Send-Location",sb,0); } break; } #endif /* CK_SNDLOC */ } /* switch */ break; } return(0); } int #ifdef CK_ANSIC /* TELNET DO OPTION */ tn_doop(CHAR z, int echo, int (*fn)(int)) #else tn_doop(z, echo, fn) CHAR z; int echo; int (*fn)(); #endif /* CK_ANSIC */ /* tn_doop */ { int x=0, y=0; debug(F101,"tn_doop char","",z); debug(F101,"tn_doop ttnproto","",ttnproto); if (!IS_TELNET()) return(3); #ifdef CK_SSL debug(F101,"tn_doop ssl_raw_flag","",ssl_raw_flag); if (ssl_raw_flag || tls_raw_flag) return(7); #endif /* CK_SSL */ debug(F100,"tn_doop ttnproto proceeding...","",0); if (z != (CHAR) IAC) { debug(F101,"tn_doop bad call","",z); return(-1); } if (ttnet != NET_TCPB) /* Check network type */ return(0); if (ttnproto != NP_TELNET && ttnproto != NP_NONE) /* Check protocol */ return(0); x = tn_xdoop(z,echo,fn); if (x >= 0 && !tn_begun) { y = tn_start(); } return(y < 0 ? y : x); } #ifdef CK_ENVIRONMENT /* Telnet receive new environment */ /* Returns -1 on error, 0 if nothing happens, 1 on success */ /* In order for this code to work, sb[len] == IAC */ /* We currently only support the USER environment variable */ int #ifdef CK_ANSIC tn_rnenv(CHAR * sb, int len) #else tn_rnenv(sb, len) CHAR * sb; int len; #endif /* CK_ANSIC */ /* tn_rnenv */ { /* Receive new environment */ char varname[17]; char value[65]; int i,j,k; /* Worker. */ int type = 0; /* 0 for NONE, 1 for VAR, 2 for USERVAR, */ /* 3 for VALUE in progress */ if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (sb == NULL) return(-1); if (len == 0) return(1); /* Pairs of [VAR=0, VALUE=1, ESC=2, USERVAR=3] "unterminated" follow here until done... */ for (i = 0, j = 0, k = 0, type = 0, varname[0]= '\0'; i <= len; i++) { switch (sb[i]) { case TEL_ENV_VAR: /* VAR */ case TEL_ENV_USERVAR: /* USERVAR */ case IAC: /* End of the list */ switch (type) { case 0: /* Nothing in progress */ /* If we get IAC only, then that means there were */ /* no environment variables to send. we are done */ if (j == 0 && sb[i] == IAC) return(1); case 1: /* VAR in progress */ case 2: /* USERVAR in progress */ case 3: /* VALUE in progress */ value[k] = '\0'; varname[j] = '\0'; debug(F111,"tn_rnenv varname",varname,type); debug(F111,"tn_rnenv value",value,type); if (!strcmp(varname,"USER")) { #ifdef CK_AUTHENTICATION if (ck_tn_auth_valid() != AUTH_VALID) { extern char szUserNameRequested[]; debug(F100,"tn_rnenv != AUTH_VALID","",0); ckstrncpy(szUserNameRequested,value,UIDBUFLEN); ckstrncpy(uidbuf,value,UIDBUFLEN); #ifdef CK_SSL if (ssl_active_flag) { if ( tls_is_user_valid(ssl_con, uidbuf) ) { extern char szUserNameAuthenticated[]; ckstrncpy(szUserNameAuthenticated,uidbuf, UIDBUFLEN); auth_finished(AUTH_VALID); } } else if (tls_active_flag) { if ( tls_is_user_valid(tls_con, uidbuf) ) { extern char szUserNameAuthenticated[]; ckstrncpy(szUserNameAuthenticated,uidbuf, UIDBUFLEN); auth_finished(AUTH_VALID); } } #endif /* CK_SSL */ } else { /* AUTH_VALID */ int x = 0; debug(F110,"tn_rnenv AUTH_VALID uidbuf",uidbuf,0); #ifdef OS2 x = ckstrcmp(value,uidbuf,-1,0); /* case insensitive */ #ifdef NT /* NTLM authentication returns names of the form */ /* DOMAIN\user. We need to check to see of the */ /* USER VAR contains a domain name or not. If */ /* not, then we do not want to change state if */ /* the uidbuf matches the USER VAR when the */ /* DOMAIN is ignored. */ if ( x && ck_tn_authenticated() == AUTHTYPE_NTLM ) { char * s1=NULL, * s2=NULL; int len1, len2, i; len1 = strlen(value); for ( i=len1-1 ; i>=0 ; i--) { if ( value[i] == '\\' ) { s1 = &value[i+1]; /* DOMAIN found */ break; } } if ( s1 == NULL ) { len2 = strlen(uidbuf); for ( i=len2-1 ; i>=0 ; i--) { if ( uidbuf[i] == '\\' ) { s2 = &uidbuf[i+1]; /* DOMAIN found */ break; } } if ( s2 ) x = ckstrcmp(value,s2,-1,0); } } #endif /* NT */ #else /* OS2 */ x = ckstrcmp(value,uidbuf,-1,1); /* case sensitive */ #endif /* OS2 */ if ( x ) { extern char szUserNameRequested[]; ckstrncpy(uidbuf,value,UIDBUFLEN); ckstrncpy(szUserNameRequested,value,UIDBUFLEN); auth_finished(AUTH_USER); #ifdef CK_SSL if (ssl_active_flag || tls_active_flag) { if ( tls_is_user_valid(ssl_con, uidbuf) ) auth_finished(AUTH_VALID); } #endif /* CK_SSL */ } } #else /* CK_AUTHENTICATION */ ckstrncpy(uidbuf,value,UIDBUFLEN); #endif /* CK_AUTHENTICATION */ } break; } varname[0] = '\0'; value[0] = '\0'; j = 0; k = 0; type = (sb[i] == TEL_ENV_USERVAR ? 2 : /* USERVAR */ sb[i] == TEL_ENV_VAR ? 1 : /* VAR */ 0 ); break; case TEL_ENV_VALUE: /* VALUE */ if ( type == 1 || type == 2 ) type = 3; break; case TEL_ENV_ESC: /* ESC */ /* Take next character literally */ if ( ++i >= len ) break; /* otherwise, fallthrough so byte will be added to string. */ default: switch (type) { case 1: /* VAR in progress */ case 2: /* USERVAR in progress */ if ( j < 16 ) varname[j++] = sb[i]; break; case 3: if ( k < 64 ) value[k++] = sb[i]; break; } } } return(0); } /* These are for Microsoft SFU version 2 Telnet Server */ #define SFUTLNTVER "SFUTLNTVER" #define SFUTLNTMODE "SFUTLNTMODE" #define SFUTLNTVER_VALUE "2" #define SFUTLNTMODE_VALUE "console" /* The other value is "stream" */ /* Telnet send new environment */ /* Returns -1 on error, 0 if nothing happens, 1 on success */ /* In order for this code to work, sb[len] == IAC */ int #ifdef CK_ANSIC tn_snenv(CHAR * sb, int len) #else tn_snenv(sb, len) CHAR * sb; int len; #endif /* CK_ANSIC */ /* tn_snenv */ { /* Send new environment */ char varname[16]; char * reply = 0; int i,j,n; /* Worker. */ int type = 0; /* 0 for NONE, 1 for VAR, 2 for USERVAR in progress */ extern int ck_lcname; char localuidbuf[UIDBUFLEN]; /* (Initialized just below) */ char * uu = uidbuf; char * disp = NULL; localuidbuf[0] = '\0'; if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!sb) return(-1); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ #ifdef CK_FORWARD_X if (TELOPT_U(TELOPT_FORWARD_X)) { disp = NULL; } else #endif /* CK_FORWARD_X */ disp = (char *)tn_get_display(); if (ck_lcname) { ckstrncpy(localuidbuf,uidbuf,UIDBUFLEN); cklower(localuidbuf); uu = localuidbuf; } ckhexdump((CHAR *)"tn_snenv sb[]",sb,len); debug(F110,"tn_snenv uidbuf",uidbuf,0); debug(F110,"tn_snenv localuidbuf",localuidbuf,0); debug(F110,"tn_snenv tn_env_sys",tn_env_sys,0); debug(F110,"tn_snenv tn_env_disp",tn_env_disp,0); debug(F110,"tn_snenv disp",disp,0); /* First determine the size of the buffer we will need */ for (i = 0, j = 0, n = 0, type = 0, varname[0]= '\0'; i <= len; i++) { switch (sb[i]) { case TEL_ENV_VAR: /* VAR */ case TEL_ENV_USERVAR: /* USERVAR */ case IAC: /* End of the list */ switch (type) { case 0: /* Nothing in progress */ /* If we get IAC only, then that means send all */ /* VAR and USERVAR. */ if (!(j == 0 && sb[i] == IAC)) break; case 1: /* VAR in progress */ varname[j] = '\0' ; if (!varname[0]) { /* Send All */ if (uu[0]) n += strlen(uu) + 4 + 2; if (tn_env_job[0]) n += strlen(tn_env_job) + 3 + 2; if (tn_env_acct[0]) n += strlen(tn_env_acct) + 4 + 2; if (tn_env_prnt[0]) n += strlen(tn_env_prnt) + 7 + 2; if (tn_env_sys[0]) n += strlen(tn_env_sys) + 10 + 2; if (disp) n += strlen(disp) + 7 + 2; } else if (!strcmp(varname,"USER") && uu[0]) n += strlen(uu) + 4 + 2; else if (!strcmp(varname,"JOB") && tn_env_job[0]) n += strlen(tn_env_job) + 3 + 2; else if (!strcmp(varname,"ACCT") && tn_env_acct[0]) n += strlen(tn_env_acct) + 4 + 2; else if (!strcmp(varname,"PRINTER") && tn_env_prnt[0]) n += strlen(tn_env_prnt) + 7 + 2; else if (!strcmp(varname,"SYSTEMTYPE") && tn_env_sys[0]) n += strlen(tn_env_sys) + 10 + 2; else if (!strcmp(varname,"DISPLAY") && disp) n += strlen(disp) + 7 + 2; /* If we get IAC only, then that means send all */ /* VAR and USERVAR. */ if (!(j == 0 && sb[i] == IAC)) break; case 2: /* USERVAR in progress */ varname[j] = '\0' ; if (!varname[0]) { /* Send All */ int x; for ( x=0 ; x<8 ; x++ ) { if ( tn_env_uservar[x][0] && tn_env_uservar[x][1] ) n += strlen(tn_env_uservar[x][0]) + strlen(tn_env_uservar[x][1]) + 2; } if ( tn_sfu ) { /* For compatibility with Microsoft Telnet Server */ n += strlen(SFUTLNTVER) + strlen(SFUTLNTVER_VALUE) + 2; n += strlen(SFUTLNTMODE) + strlen(SFUTLNTMODE_VALUE) + 2; } #ifdef CK_SNDLOC if ( tn_loc && tn_loc[0] ) n += strlen("LOCATION") + strlen(tn_loc) + 2; #endif /* CK_SNDLOC */ } else if (tn_sfu && !strcmp(varname,SFUTLNTVER)) n += strlen(SFUTLNTVER) + strlen(SFUTLNTVER_VALUE) + 2; else if (tn_sfu && !strcmp(varname,SFUTLNTMODE)) n += strlen(SFUTLNTMODE) + strlen(SFUTLNTMODE_VALUE) + 2; #ifdef CK_SNDLOC else if ( tn_loc && tn_loc[0] && !strcmp(varname,"LOCATION")) n += strlen("LOCATION") + strlen(tn_loc) + 2; #endif /* CK_SNDLOC */ else { int x; for ( x=0 ; x<8 ; x++ ) { if ( tn_env_uservar[x][0] && tn_env_uservar[x][1] && !strcmp(varname,tn_env_uservar[x][0])) n += strlen(tn_env_uservar[x][0]) + strlen(tn_env_uservar[x][1]) + 2; } } break; } varname[0] = '\0'; j = 0; type = (sb[i] == TEL_ENV_USERVAR ? 2 : /* USERVAR */ sb[i] == TEL_ENV_VAR ? 1 : /* VAR */ 0 ); break; case TEL_ENV_VALUE: /* VALUE */ /* Protocol Error */ debug(F100, "TELNET Subnegotiation error - VALUE in SEND", "",0); if (tn_deb || debses) tn_debug("TELNET Subnegotiation error - VALUE in SEND"); return(0); case TEL_ENV_ESC: /* ESC */ if (++i >= len) break; default: if (j < 16 ) varname[j++] = sb[i]; } } reply = malloc(n + 16); /* Leave room for IAC stuff */ if (!reply) { debug(F100, "TELNET Subnegotiation error - malloc failed", "",0); if (tn_deb || debses) tn_debug("TELNET Subnegotiation error - malloc failed"); /* Send a return packet with no variables so that the host */ /* may continue with additional negotiations */ if (tn_ssbopt(TELOPT_NEWENVIRON,TELQUAL_IS,(CHAR *)"",0) < 0) return(-1); return(0); } /* Now construct the real reply */ n = 0; /* Start at beginning of buffer */ /* Pairs of [VAR=0, VALUE=1, ESC=2, USERVAR=3] "unterminated" follow here until done... */ for (i = 0, j = 0, type = 0, varname[0]= '\0'; i <= len; i++) { switch (sb[i]) { case TEL_ENV_VAR: /* VAR */ case TEL_ENV_USERVAR: /* USERVAR */ case IAC: /* End of the list */ switch (type) { case 0: /* Nothing in progress */ /* If we get IAC only, then that means send all */ /* VAR and USERVAR. */ if (!(j == 0 && sb[i] == IAC)) break; case 1: /* VAR in progress */ varname[j] = '\0'; if (!varname[0]) { /* Send All */ if (uu[0]) { reply[n] = TEL_ENV_VAR; /* VAR */ strcpy(&reply[n+1],"USER"); reply[n+5] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+6],uu); n += strlen(uu) + 4 + 2; } if (tn_env_job[0]) { reply[n] = TEL_ENV_VAR; /* VAR */ strcpy(&reply[n+1],"JOB"); reply[n+4] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+5],tn_env_job); n += strlen(tn_env_job) + 3 + 2; } if (tn_env_acct[0]) { reply[n] = TEL_ENV_VAR; /* VAR */ strcpy(&reply[n+1],"ACCT"); reply[n+5] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+6],tn_env_acct); n += strlen(tn_env_acct) + 4 + 2; } if (tn_env_prnt[0]) { reply[n] = TEL_ENV_VAR; /* VAR */ strcpy(&reply[n+1],"PRINTER"); reply[n+8] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+9],tn_env_prnt); n += strlen(tn_env_prnt) + 7 + 2; } if (tn_env_sys[0]) { reply[n] = TEL_ENV_VAR; /* VAR */ strcpy(&reply[n+1],"SYSTEMTYPE"); reply[n+11] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+12],tn_env_sys); n += strlen(tn_env_sys) + 10 + 2; } if (disp) { reply[n] = TEL_ENV_VAR; /* VAR */ strcpy(&reply[n+1],"DISPLAY"); reply[n+8] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+9],disp); n += strlen(disp) + 7 + 2; } } else if (!strcmp(varname,"USER") && uu[0]) { reply[n] = TEL_ENV_VAR; /* VAR */ strcpy(&reply[n+1],"USER"); reply[n+5] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+6],uu); n += strlen(uu) + 4 + 2; } else if (!strcmp(varname,"JOB") && tn_env_job[0]) { reply[n] = TEL_ENV_VAR; /* VAR */ strcpy(&reply[n+1],"JOB"); reply[n+4] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+5],tn_env_job); n += strlen(tn_env_job) + 3 + 2; } else if (!strcmp(varname,"ACCT") && tn_env_acct[0]) { reply[n] = TEL_ENV_VAR; /* VAR */ strcpy(&reply[n+1],"ACCT"); reply[n+5] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+6],tn_env_acct); n += strlen(tn_env_acct) + 4 + 2; } else if (!strcmp(varname,"PRINTER") && tn_env_prnt[0]) { reply[n] = TEL_ENV_VAR; /* VAR */ strcpy(&reply[n+1],"PRINTER"); reply[n+8] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+9],tn_env_prnt); n += strlen(tn_env_prnt) + 7 + 2; } else if (!strcmp(varname,"SYSTEMTYPE") && tn_env_sys[0]) { reply[n] = TEL_ENV_VAR; /* VAR */ strcpy(&reply[n+1],"SYSTEMTYPE"); reply[n+11] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+12],tn_env_sys); n += strlen(tn_env_sys) + 10 + 2; } else if (!strcmp(varname,"DISPLAY") && disp) { reply[n] = TEL_ENV_VAR; /* VAR */ strcpy(&reply[n+1],"DISPLAY"); reply[n+8] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+9],disp); n += strlen(disp) + 7 + 2; } /* If we get IAC only, then that means send all */ /* VAR and USERVAR. */ if (!(j == 0 && sb[i] == IAC)) break; case 2: /* USERVAR in progress */ varname[j] = '\0'; if (!varname[0]) { /* Send All */ int x,y; for ( x=0 ; x<8 ; x++ ) { if ( tn_env_uservar[x][0] && tn_env_uservar[x][1] ) { reply[n] = TEL_ENV_USERVAR; /* VAR */ y = strlen(tn_env_uservar[x][0]); strcpy(&reply[n+1],tn_env_uservar[x][0]); reply[n+y+1] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+y+2],tn_env_uservar[x][1]); n += y+strlen(tn_env_uservar[x][1])+2; } } if ( tn_sfu ) { /* Compatibility with Microsoft Telnet Server */ reply[n] = TEL_ENV_USERVAR; /* VAR */ strcpy(&reply[n+1],SFUTLNTVER); reply[n+11] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+12],SFUTLNTVER_VALUE); n += strlen(SFUTLNTVER)+strlen(SFUTLNTVER_VALUE)+2; reply[n] = TEL_ENV_USERVAR; /* VAR */ strcpy(&reply[n+1],SFUTLNTMODE); reply[n+12] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+13],SFUTLNTMODE_VALUE); n += strlen(SFUTLNTMODE)+strlen(SFUTLNTMODE_VALUE)+2; } if (tn_loc && tn_loc[0]) { reply[n] = TEL_ENV_USERVAR; /* VAR */ strcpy(&reply[n+1],"LOCATION"); reply[n+9] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+10],tn_loc); n += strlen("LOCATION") + strlen(tn_loc) + 2; } } else if (tn_sfu && !strcmp(varname,SFUTLNTVER)) { reply[n] = TEL_ENV_USERVAR; /* VAR */ strcpy(&reply[n+1],SFUTLNTVER); reply[n+11] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+12],SFUTLNTVER_VALUE); n += strlen(SFUTLNTVER) + strlen(SFUTLNTVER_VALUE) + 2; } else if (tn_sfu && !strcmp(varname,SFUTLNTMODE)) { reply[n] = TEL_ENV_USERVAR; /* VAR */ strcpy(&reply[n+1],SFUTLNTMODE); reply[n+12] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+13],SFUTLNTMODE_VALUE); n += strlen(SFUTLNTMODE) + strlen(SFUTLNTMODE_VALUE) + 2; } #ifdef CK_SNDLOC else if (tn_loc && tn_loc[0] && !strcmp(varname,"LOCATION")){ reply[n] = TEL_ENV_USERVAR; /* VAR */ strcpy(&reply[n+1],"LOCATION"); reply[n+9] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+10],tn_loc); n += strlen("LOCATION") + strlen(tn_loc) + 2; } #endif /* CK_SNDLOC */ else { int x,y; for ( x=0 ; x<8 ; x++ ) { if ( tn_env_uservar[x][0] && tn_env_uservar[x][1] && !strcmp(varname,tn_env_uservar[x][0])) { reply[n] = TEL_ENV_USERVAR; /* VAR */ y = strlen(tn_env_uservar[x][0]); strcpy(&reply[n+1],tn_env_uservar[x][0]); reply[n+y+1] = TEL_ENV_VALUE; /* VALUE */ strcpy(&reply[n+y+2],tn_env_uservar[x][1]); n += y+strlen(tn_env_uservar[x][1])+2; } } } break; } varname[0] = '\0'; j = 0; type = (sb[i] == TEL_ENV_USERVAR ? 2 : /* USERVAR */ sb[i] == TEL_ENV_VAR ? 1 : /* VAR */ 0 ); break; case TEL_ENV_VALUE: /* VALUE */ /* Protocol Error */ debug(F100, "TELNET Subnegotiation error - VALUE in SEND", "",0); if (tn_deb || debses) tn_debug("TELNET Subnegotiation error - VALUE in SEND"); return(0); /* Was -1 but that would be taken as */ /* an I/O error, so absorb it and go on. */ case TEL_ENV_ESC: /* ESC */ /* Not sure what this for. Quote next character? */ break; default: varname[j++] = sb[i]; } } if (tn_ssbopt(TELOPT_NEWENVIRON,TELQUAL_IS,(CHAR *)reply,n) < 0) { free(reply); return(-1); } free(reply); return(1); } #endif /* CK_ENVIRONMENT */ /* Telnet send terminal type */ /* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */ int tn_sttyp() { /* Send telnet terminal type. */ char *ttn; /* Name of terminal type. */ #ifdef OS2 static int alias = -1; /* which alias are we using ? */ int settype = 0; #endif /* OS2 */ int i, rc; /* Worker. */ int tntermflg = 0; if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_TTYPE)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ ttn = NULL; #ifndef NOTERM #ifdef OS2 if (!tn_term) { if (ttnum == -1) { ttnum = tt_type; settype = 0; alias = -1; } else if (ttnumend) { ttnumend = 0; settype = 0; } else { if (tt_info[tt_type].x_aliases[++alias] == NULL) { if (--tt_type < 0) tt_type = max_tt; if (ttnum == tt_type) ttnumend = 1; settype = 1; alias = -1; } } if (tt_type >= 0 && tt_type <= max_tt) { if (alias == -1) ttn = tt_info[tt_type].x_name; else ttn = tt_info[tt_type].x_aliases[alias]; } else ttn = NULL; } else settype = 0; #endif /* OS2 */ #endif /* NOTERM */ if (tn_term) { /* Terminal type override? */ debug(F110,"tn_sttyp",tn_term,0); if (*tn_term) { ttn = tn_term; tntermflg = 1; } } else debug(F100,"tn_sttyp no term override","",0); #ifndef datageneral if (!ttn) { /* If no override, */ ttn = getenv("TERM"); /* get it from the environment. */ } #endif /* datageneral */ if ((ttn == ((char *)0)) || ((int)strlen(ttn) >= TSBUFSIZ)) ttn = "UNKNOWN"; sb_out[0] = (CHAR) IAC; /* I Am a Command */ sb_out[1] = (CHAR) SB; /* Subnegotiation */ sb_out[2] = TELOPT_TTYPE; /* Terminal Type */ sb_out[3] = (CHAR) 0; /* Is... */ for (i = 4; *ttn; ttn++,i++) { /* Copy and uppercase it */ #ifdef VMS if (!tntermflg && *ttn == '-' && (!strcmp(ttn,"-80") || !strcmp(ttn,"-132"))) break; else #endif /* VMS */ sb_out[i] = (char) ((!tntermflg && islower(*ttn)) ? toupper(*ttn) : *ttn); } ttn = (char *)sb_out; /* Point back to beginning */ #ifdef DEBUG if (deblog || tn_deb || debses) { sb_out[i] = '\0'; /* For debugging */ ckmakxmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ", TELOPT(TELOPT_TTYPE)," IS ",(char *)sb_out+4," IAC SE", NULL,NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); #ifndef NOTERM #ifdef OS2 if (settype) settermtype(tt_type,0); else { ipadl25(); VscrnIsDirty(VTERM); } #endif /* OS2 */ #endif /* NOTERM */ return(1); } #ifdef CK_ENVIRONMENT #ifdef CK_XDISPLOC /* Telnet send xdisplay location */ /* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */ int tn_sxdisploc() { /* Send telnet X display location. */ char * disp=NULL; int i,rc; if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_XDISPLOC)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ #ifdef CK_FORWARD_X if (TELOPT_U(TELOPT_FORWARD_X)) { disp = NULL; } else #endif /* CK_FORWARD_X */ disp = (char *)tn_get_display(); debug(F110,"tn_sxdisploc",disp,0); if (!disp) { /* Can't do both, send WONT */ if (tn_sopt(WONT,TELOPT_XDISPLOC) < 0) return(-1); TELOPT_UNANSWERED_WONT(TELOPT_XDISPLOC) = 1; return(0); } sb_out[0] = (CHAR) IAC; /* I Am a Command */ sb_out[1] = (CHAR) SB; /* Subnegotiation */ sb_out[2] = TELOPT_XDISPLOC; /* X-Display Location */ sb_out[3] = (CHAR) 0; /* Is... */ for (i = 4; *disp; disp++,i++) { /* Copy and uppercase it */ sb_out[i] = (char) *disp; } #ifdef DEBUG if (deblog || tn_deb || debses) { sb_out[i] = '\0'; /* For debugging */ ckmakxmsg( tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_XDISPLOC), " IS ",(char *)sb_out+4," IAC SE", NULL,NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); return(1); } #endif /* CK_XDISPLOC */ #endif /* CK_ENVIRONMENT */ #ifdef CK_FORWARD_X int tn_sndfwdx() { /* Send Fwd X Screen number to host */ unsigned char screen = 0; char * disp; int i,rc; /* if (!IS_TELNET()) return(0); */ if (!TELOPT_U(TELOPT_FORWARD_X)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ /* * The format of the DISPLAY variable is [:][.] * where is an optional DNS name or ip address with a default of * the localhost; the screen defaults to 0 */ disp = (char *)tn_get_display(); if (disp) { int colon,dot; colon = ckindex(":",disp,0,0,1); dot = ckindex(".",&disp[colon],0,0,1); if ( dot ) { screen = atoi(&disp[colon+dot]); } } else { screen = 0; } i = 0; sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_FORWARD_X; /* Forward X */ sb_out[i++] = FWDX_SCREEN; /* Screen */ sb_out[i++] = screen; if ( screen == IAC ) sb_out[i++] = IAC; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg( tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_FORWARD_X), " SCREEN ",ckctox(screen,1)," IAC SE", NULL,NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); return(0); } #endif /* CK_FORWARD_X */ #ifdef CK_SNDLOC int tn_sndloc() { /* Send location. */ int i,rc; /* Worker. */ char *ttloc; /* if (!IS_TELNET()) return(0); */ if (!TELOPT_ME(TELOPT_SNDLOC)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ ttloc = (tn_loc ? tn_loc : ""); /* In case we are being called even */ /* though there is no location. */ sb_out[0] = (CHAR) IAC; /* I Am a Command */ sb_out[1] = (CHAR) SB; /* Subnegotiation */ sb_out[2] = TELOPT_SNDLOC; /* Location */ for (i = 3; *ttloc && i < TSBUFSIZ; ttloc++,i++) /* Copy it */ sb_out[i] = (char) *ttloc; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_SNDLOC)," ",(char *)sb_out+3, " IAC SE", NULL,NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); sb_out[i-2] = '\0'; /* For debugging */ return(0); } #endif /* CK_SNDLOC */ #ifdef CK_NAWS /* NAWS = Negotiate About Window Size */ int tn_snaws() { /* Send terminal width and height, RFC 1073 */ #ifndef NOLOCAL CHAR sb_out[24]; /* multiple threads */ int i = 0,rc; #ifdef OS2 int x = VscrnGetWidth(VTERM), y = VscrnGetHeight(VTERM) - (tt_status[VTERM] ? 1 : 0); #else /* OS2 */ int x = tt_cols, y = tt_rows; #endif /* OS2 */ if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_NAWS)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if (x < 0) x = 0; if (y < 0) y = 0; if (x == TELOPT_SB(TELOPT_NAWS).naws.x && /* Only send if changed */ y == TELOPT_SB(TELOPT_NAWS).naws.y ) return(0); TELOPT_SB(TELOPT_NAWS).naws.x = x; /* Remember the size */ TELOPT_SB(TELOPT_NAWS).naws.y = y; sb_out[i++] = (CHAR) IAC; /* Send the subnegotiation */ sb_out[i++] = (CHAR) SB; sb_out[i++] = TELOPT_NAWS; sb_out[i++] = (CHAR) (x >> 8) & 0xff; if ((CHAR) sb_out[i-1] == (CHAR) IAC) /* IAC in data must be doubled */ sb_out[i++] = (CHAR) IAC; sb_out[i++] = (CHAR) (x & 0xff); if ((CHAR) sb_out[i-1] == (CHAR) IAC) sb_out[i++] = (CHAR) IAC; sb_out[i++] = (CHAR) (y >> 8) & 0xff; if ((CHAR) sb_out[i-1] == (CHAR) IAC) sb_out[i++] = (CHAR) IAC; sb_out[i++] = (CHAR) (y & 0xff); if ((CHAR) sb_out[i-1] == (CHAR) IAC) sb_out[i++] = (CHAR) IAC; sb_out[i++] = (CHAR) IAC; sb_out[i++] = (CHAR) SE; #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB NAWS ", ckitoa(x)," ",ckitoa(y)," IAC SE", NULL,NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); #endif /* NOLOCAL */ return (0); } #endif /* CK_NAWS */ #ifdef TN_COMPORT static char * tnc_signature = NULL; static int tnc_ls_mask = 0; static int tnc_ls = 0; static int tnc_ms_mask = 255; static int tnc_ms = 0; static int tnc_oflow = 0; static int tnc_iflow = 0; static int tnc_bps = 0; static int tnc_datasize = 0; static int tnc_parity = 0; static int tnc_stopbit = 0; static int tnc_break = 0; static int tnc_dtr = 0; static int tnc_rts = 0; static int tnc_suspend_xmit = 0; static int tnc_bps_index = -1; int #ifdef CK_ANSIC tnc_init(void) #else /* CK_ANSIC */ tnc_init() #endif /* CK_ANSIC */ /* tnc_init */ { debug(F100,"tnc_init","",0); /* if (!IS_TELNET()) return(0); */ if (tnc_signature) { free(tnc_signature); tnc_signature = NULL; } tnc_ls_mask = 0; tnc_ls = 0; tnc_ms_mask = 255; tnc_ms = 0; tnc_oflow = 0; tnc_iflow = 0; tnc_bps = 0; tnc_datasize = 0; tnc_parity = 0; tnc_stopbit = 0; tnc_break = 0; tnc_dtr = 0; tnc_rts = 0; tnc_suspend_xmit = 0; tnc_bps_index = -1; return(0); } int #ifdef CK_ANSIC tn_sndcomport(void) #else /* CK_ANSIC */ tn_sndcomport() #endif /* CK_ANSIC */ /* tn_sndcomport */ { int baud, datasize, parity, stopsize, oflow, iflow; CONST char * signature; /* if (!IS_TELNET()) return(0); */ debug(F100,"tnc_sndcomport","",0); signature = tnc_get_signature(); baud = tnc_get_baud(); datasize = tnc_get_datasize(); parity = tnc_get_parity(); stopsize = tnc_get_stopsize(); oflow = tnc_get_oflow(); iflow = tnc_get_iflow(); tnc_set_ls_mask(255); tnc_set_ms_mask(255); return(0); } int #ifdef CK_ANSIC tnc_wait(CHAR * msg, int ms) #else /* CK_ANSIC */ tnc_wait(msg, ms) CHAR * msg; int ms; #endif /* CK_ANSIC */ /* tnc_wait */ { int rc, tn_wait_save = tn_wait_flg; /* if (!IS_TELNET()) return(0); */ debug(F111,"tnc_wait","begin",ms); if ( ms ) TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms = 1; else TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 1; tn_wait_flg = 1; rc = tn_wait((char *)msg); tn_push(); debug(F110,"tnc_wait","end",0); tn_wait_flg = tn_wait_save; return(rc); } /* Returns -1 on error, 0 on success */ /* In order for this code to work, sb[len] == IAC */ int #ifdef CK_ANSIC tnc_tn_sb(CHAR * sb, int len) #else tnc_tn_sb(sb, len) CHAR * sb; int len; #endif /* CK_ANSIC */ /* tnc_tn_sb */ { if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); if (!sb) return(-1); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ debug(F111,"tnc_tn_sb","sb[0]",sb[0]); debug(F111,"tnc_tn_sb","len",len); switch (sb[0]) { case TNC_C2S_SIGNATURE: case TNC_S2C_SIGNATURE: debug(F111,"tnc_tn_sb","signature",len); if (len == 1) { tnc_send_signature("Kermit Telnet Com Port Option"); } else { TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; if (tnc_signature) free(tnc_signature); tnc_signature = malloc(len); if (tnc_signature) { memcpy(tnc_signature,&sb[1],len-1); tnc_signature[len-1] = '\0'; } } break; case TNC_C2S_SET_BAUDRATE: case TNC_S2C_SET_BAUDRATE: { long baudrate; char * br = (char *)&baudrate; TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; if (len == 2) { /* Actual behavior of the Access Server... */ debug(F111,"tnc_tn_sb","baudrate index",sb[1]); tnc_bps_index = 1; switch (sb[1]) { case TNC_BPS_300: tnc_bps = 300; break; case TNC_BPS_600: tnc_bps = 600; break; case TNC_BPS_1200: tnc_bps = 1200; break; case TNC_BPS_2400: tnc_bps = 2400; break; case TNC_BPS_4800: tnc_bps = 4800; break; case TNC_BPS_9600: tnc_bps = 9600; break; case TNC_BPS_14400: tnc_bps = 14400; break; case TNC_BPS_19200: tnc_bps = 19200; break; case TNC_BPS_28800: tnc_bps = 28800; break; case TNC_BPS_38400: tnc_bps = 38400; break; case TNC_BPS_57600: tnc_bps = 57600; break; case TNC_BPS_115200: tnc_bps = 115200; break; case TNC_BPS_230400: tnc_bps = 230400; break; case TNC_BPS_460800: tnc_bps = 460800; break; default: tnc_bps = -1; } } else if (len == 5) { /* This section attempts to follow RFC 2217 */ tnc_bps_index = 0; br[0] = sb[1]; br[1] = sb[2]; br[2] = sb[3]; br[3] = sb[4]; #ifdef datageneral /* AOS/VS doesn't have ntohl() but MV's are big-endian */ tnc_bps = baudrate; #else tnc_bps = ntohl(baudrate); #endif /* datageneral */ debug(F111,"tnc_tn_sb","baudrate rfc",tnc_bps); } else { debug(F111,"tnc_tn_sb","baudrate invalid len",len); return(-1); } break; } case TNC_C2S_SET_DATASIZE: case TNC_S2C_SET_DATASIZE: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; if (len < 2) return(-1); tnc_datasize = sb[1]; debug(F111,"tnc_tn_sb","datasize",sb[1]); break; case TNC_C2S_SET_PARITY: case TNC_S2C_SET_PARITY: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; if (len < 2) return(-1); tnc_parity = sb[1]; debug(F111,"tnc_tn_sb","parity",sb[1]); break; case TNC_C2S_SET_STOPSIZE: case TNC_S2C_SET_STOPSIZE: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; if (len < 2) return(-1); tnc_stopbit = sb[1]; debug(F111,"tnc_tn_sb","stopsize",sb[1]); break; case TNC_C2S_SET_CONTROL: case TNC_S2C_SET_CONTROL: if (len < 2) { TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; return(-1); } #ifdef COMMENT /* This line should be removed when testing is complete. */ TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; #endif /* COMMENT */ switch ( sb[1] ) { case TNC_CTL_OFLOW_REQUEST: /* determine local outbound flow control and send to peer */ /* Cisco IOS returns 0 (TNC_CTL_OFLOW_REQUEST) when attempting */ /* to set the inbound flow control if it is not supported */ /* separately from outbound flow control. So must reset */ /* wait for sb flag. */ debug(F110,"tnc_tn_sb","oflow request",0); TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; break; case TNC_CTL_OFLOW_NONE: case TNC_CTL_OFLOW_XON_XOFF: case TNC_CTL_OFLOW_RTS_CTS: case TNC_CTL_OFLOW_DCD: case TNC_CTL_OFLOW_DSR: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; tnc_oflow = sb[1]; debug(F111,"tnc_tn_sb","oflow",sb[1]); break; case TNC_CTL_BREAK_REQUEST: /* determine local break state and send to peer */ debug(F110,"tnc_tn_sb","break request",0); break; case TNC_CTL_BREAK_ON: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; tnc_break = 1; debug(F110,"tnc_tn_sb","break on",0); break; case TNC_CTL_BREAK_OFF: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; tnc_break = 0; debug(F110,"tnc_tn_sb","break off",0); break; case TNC_CTL_DTR_REQUEST: /* determine local dtr state and send to peer */ debug(F110,"tnc_tn_sb","dtr request",0); break; case TNC_CTL_DTR_ON: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; tnc_dtr = 1; debug(F110,"tnc_tn_sb","dtr on",0); break; case TNC_CTL_DTR_OFF: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; tnc_dtr = 0; debug(F110,"tnc_tn_sb","dtr off",0); break; case TNC_CTL_RTS_REQUEST: /* determine local rts state and send to peer */ debug(F110,"tnc_tn_sb","rts request",0); break; case TNC_CTL_RTS_ON: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; tnc_rts = 1; debug(F110,"tnc_tn_sb","rts on",0); break; case TNC_CTL_RTS_OFF: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; tnc_rts = 0; debug(F110,"tnc_tn_sb","rts off",0); break; case TNC_CTL_IFLOW_REQUEST: /* determine local inbound flow control and send to peer */ debug(F110,"tnc_tn_sb","iflow request",0); break; case TNC_CTL_IFLOW_NONE: case TNC_CTL_IFLOW_XON_XOFF: case TNC_CTL_IFLOW_RTS_CTS: case TNC_CTL_IFLOW_DTR: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; tnc_iflow = sb[1]; debug(F111,"tnc_tn_sb","iflow",sb[1]); break; default: return(-1); } break; case TNC_C2S_NOTIFY_LINESTATE: case TNC_S2C_SEND_LS: if (len < 2) return(-1); tnc_ls = sb[1]; debug(F111,"tnc_tn_sb","linestate",sb[1]); if (tn_deb || debses) { if (tnc_ls & TNC_MS_DATA_READY ) tn_debug(" ComPort Linestate Data Ready"); if (tnc_ls & TNC_MS_OVERRUN_ERROR ) tn_debug(" ComPort Linestate Overrun Error"); if (tnc_ls & TNC_MS_PARITY_ERROR ) tn_debug(" ComPort Linestate Parity Error"); if (tnc_ls & TNC_MS_FRAME_ERROR ) tn_debug(" ComPort Linestate Framing Error"); if (tnc_ls & TNC_MS_BREAK_ERROR ) tn_debug(" ComPort Linestate Break Detect Error"); if (tnc_ls & TNC_MS_HR_EMPTY ) tn_debug(" ComPort Linestate Holding Register Empty"); if (tnc_ls & TNC_MS_SR_EMPTY ) tn_debug(" ComPort Linestate Shift Register Empty"); if (tnc_ls & TNC_MS_TIMEOUT_ERROR ) tn_debug(" ComPort Linestate Timeout Error"); } break; case TNC_C2S_NOTIFY_MODEMSTATE: case TNC_S2C_SEND_MS: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms = 0; if (len < 2) return(-1); tnc_ms = sb[1]; debug(F111,"tnc_tn_sb","modemstate",sb[1]); if (tn_deb || debses) { if (tnc_ms & TNC_MS_CTS_DELTA ) tn_debug(" ComPort Modemstate CTS State Change"); if (tnc_ms & TNC_MS_DSR_DELTA ) tn_debug(" ComPort Modemstate DSR State Change"); if (tnc_ms & TNC_MS_EDGE_RING ) tn_debug(" ComPort Modemstate Trailing Edge Ring Detector On"); else tn_debug(" ComPort Modemstate Trailing Edge Ring Detector Off"); if (tnc_ms & TNC_MS_RLSD_DELTA ) tn_debug(" ComPort Modemstate RLSD State Change"); if (tnc_ms & TNC_MS_CTS_SIG ) tn_debug(" ComPort Modemstate CTS Signal On"); else tn_debug(" ComPort Modemstate CTS Signal Off"); if (tnc_ms & TNC_MS_DSR_SIG ) tn_debug(" ComPort Modemstate DSR Signal On"); else tn_debug(" ComPort Modemstate DSR Signal Off"); if (tnc_ms & TNC_MS_RI_SIG ) tn_debug(" ComPort Modemstate Ring Indicator On"); else tn_debug(" ComPort Modemstate Ring Indicator Off"); if (tnc_ms & TNC_MS_RLSD_SIG ) tn_debug(" ComPort Modemstate RLSD Signal On"); else tn_debug(" ComPort Modemstate RLSD Signal Off"); } break; case TNC_C2S_FLOW_SUSPEND: case TNC_S2C_FLOW_SUSPEND: debug(F110,"tnc_tn_sb","flow suspend",0); tnc_suspend_xmit = 1; break; case TNC_C2S_FLOW_RESUME: case TNC_S2C_FLOW_RESUME: debug(F110,"tnc_tn_sb","flow resume",0); tnc_suspend_xmit = 0; break; case TNC_C2S_SET_LS_MASK: case TNC_S2C_SET_LS_MASK: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; if (len < 2) return(-1); debug(F111,"tnc_tn_sb","linestate mask",sb[1]); tnc_ls_mask = sb[1]; break; case TNC_C2S_SET_MS_MASK: case TNC_S2C_SET_MS_MASK: TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; if (len < 2) return(-1); debug(F111,"tnc_tn_sb","modemstate mask",sb[1]); tnc_ls_mask = sb[1]; break; case TNC_C2S_PURGE: case TNC_S2C_PURGE: if (len < 2) return(-1); debug(F111,"tnc_tn_sb","purge",sb[1]); switch ( sb[1] ) { case TNC_PURGE_RECEIVE: case TNC_PURGE_TRANSMIT: case TNC_PURGE_BOTH: /* purge local buffers */ break; default: return(-1); } break; default: return(-1); } return(0); } CONST char * #ifdef CK_ANSIC tnc_get_signature(void) #else /* CK_ANSIC */ tnc_get_signature() #endif /* CK_ANSIC */ /* tnc_get_signature */ { /* send IAC SB COM-PORT SIGNATURE IAC SE */ /* wait for response */ int i = 0, rc; if (ttnet != NET_TCPB) return(NULL); if (ttnproto != NP_TELNET) return(NULL); if (!TELOPT_ME(TELOPT_COMPORT)) return(NULL); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(NULL); } #endif /* CK_SSL */ if ( tnc_signature ) return(tnc_signature); sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SIGNATURE; /* Signature */ sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SIGNATURE IAC SE", NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(NULL); if (tnc_wait((CHAR *)"comport signature request",0) < 0) { tn_push(); return(NULL); } debug(F110,"tnc_get_signature",tnc_signature,0); return(tnc_signature); } int #ifdef CK_ANSIC tnc_send_signature(char * signature) #else /* CK_ANSIC */ tnc_send_signature(signature) char * signature; #endif /* CK_ANSIC */ /* tnc_send_signature */ { /* send IAC SB COM-PORT SIGNATURE IAC SE */ int i = 0, j = 0, rc; debug(F110,"tnc_send_signature",signature,0); if (!signature || !signature[0]) return(0); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SIGNATURE; /* Signature */ for (; signature[j]; i++,j++) sb_out[i] = signature[j]; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SIGNATURE ", signature, " IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); return(0); } int #ifdef CK_ANSIC tnc_set_baud( long baud ) #else /* CK_ANSIC */ tnc_set_baud(baud) long baud; #endif /* CK_ANSIC */ /* tnc_set_baud */ { /* send IAC SB COM-PORT SET-BAUD IAC SE */ /* wait for response */ /* 0 is used to request the current baud rate and */ /* may not be sent by this func */ /* return new host value */ /* * the above comes from the RFC. But that is not what I am seeing * instead I appear to be seeing to following: * * Value Baud * 1 ? * 2 ? * 3 300 * 4 600 * 5 1200 * 6 2400 * 7 4800 ? * 8 9600 * 9 ? * 10 19200 ? * 11 ? * 12 38400 * 13 57600 ? * 14 115200 * 15 230400 ? * 16 460800 ? */ int i = 0, rc; #ifdef datageneral /* AOS/VS doesn't have htonl() but MV's are big-endian */ long net_baud = baud; #else long net_baud = htonl(baud); #endif /* datageneral */ CHAR b; debug(F111,"tnc_set_baud","begin",baud); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if (baud <= 0) return(0); if ( net_baud != 0 && net_baud == tnc_bps) return(tnc_bps); sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_BAUDRATE; /* Set Baud Rate */ if (tnc_bps_index) { /* IOS Access Server */ if (baud <= 300) b = TNC_BPS_300; else if (baud <= 600) b = TNC_BPS_600; else if (baud <= 1200) b = TNC_BPS_1200; else if (baud <= 2400) b = TNC_BPS_2400; else if (baud <= 4800) b = TNC_BPS_4800; else if (baud <= 9600) b = TNC_BPS_9600; else if (baud <= 14400) b = TNC_BPS_14400; else if (baud <= 19200) b = TNC_BPS_19200; else if (baud <= 28800) b = TNC_BPS_28800; else if (baud <= 38400) b = TNC_BPS_38400; else if (baud <= 57600) b = TNC_BPS_57600; else if (baud <= 115200) b = TNC_BPS_115200; else if (baud <= 230400) b = TNC_BPS_230400; else b = TNC_BPS_460800; sb_out[i++] = b; } else { /* RFC 2217 */ sb_out[i++] = ((char *)&net_baud)[0]; sb_out[i++] = ((char *)&net_baud)[1]; sb_out[i++] = ((char *)&net_baud)[2]; sb_out[i++] = ((char *)&net_baud)[3]; } sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-BAUD-RATE ", ckltoa(baud)," IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport set baud rate",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_set_baud","end",tnc_bps); return(tnc_bps); } int #ifdef CK_ANSIC tnc_get_baud(void) #else /* CK_ANSIC */ tnc_get_baud() #endif /* CK_ANSIC */ /* tnc_get_baud */ { /* send IAC SB COM-PORT SET-BAUD IAC SE */ /* wait for response */ int i = 0, rc; debug(F110,"tnc_get_baud","begin",0); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_BAUDRATE; /* Set Baud Rate */ if (tnc_bps_index > 0) { /* Access Server */ sb_out[i++] = 0; } else { /* RFC 2217 */ sb_out[i++] = 0; sb_out[i++] = 0; sb_out[i++] = 0; sb_out[i++] = 0; } sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-BAUD-RATE ", ckltoa(0)," IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport get baud rate",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_get_baud","end",tnc_bps); return(tnc_bps); } int #ifdef CK_ANSIC tnc_set_datasize(int datasize) #else /* CK_ANSIC */ tnc_set_datasize(datasize) int datasize; #endif /* CK_ANSIC */ /* tnc_set_datasize */ { /* IAC SB COM-PORT SET_DATASIZE IAC SE */ /* Valid s are 5 through 8 */ /* Wait for response */ /* return new host value */ int i = 0, rc; debug(F111,"tnc_set_datasize","begin",datasize); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if ( !(datasize >= 5 && datasize <= 8) ) return(0); if ( datasize != 0 && datasize == tnc_datasize ) return(tnc_datasize); sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_DATASIZE; /* Set DataSize */ sb_out[i++] = (unsigned char)(datasize & 0xFF); sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-DATASIZE ", ckitoa(datasize)," IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport set datasize",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_set_datasize","end",tnc_datasize); return(tnc_datasize); } int #ifdef CK_ANSIC tnc_get_datasize(void) #else /* CK_ANSIC */ tnc_get_datasize() #endif /* CK_ANSIC */ /* tnc_get_datasize */ { /* IAC SB COM-PORT SET_DATASIZE IAC SE */ /* Wait for response */ int i = 0, rc; debug(F110,"tnc_get_datasize","begin",0); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_DATASIZE; /* Set DataSize */ sb_out[i++] = 0; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-DATASIZE ", ckltoa(0)," IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport get datasize",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_get_datasize","end",tnc_datasize); return(tnc_datasize); } int #ifdef CK_ANSIC tnc_set_parity(int parity) #else /* CK_ANSIC */ tnc_set_parity(parity) int parity; #endif /* CK_ANSIC */ /* tnc_set_parity */ { /* IAC SB COM-PORT SET_PARITY IAC SE */ /* Value Parity * 1 None * 2 Odd * 3 Even * 4 Mark * 5 Space */ /* Wait for response. Return new host value. */ int i = 0, rc; debug(F110,"tnc_set_parity","begin",parity); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if ( !(parity >= 1 && parity <= 5) ) return(0); if ( parity != 0 && parity == tnc_parity ) return(tnc_parity); sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_PARITY; /* Set Parity */ sb_out[i++] = (unsigned char)(parity & 0xFF); sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-PARITY ", ckitoa(parity)," IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport set parity",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_set_parity","end",tnc_parity); return(tnc_parity); } int #ifdef CK_ANSIC tnc_get_parity(void) #else /* CK_ANSIC */ tnc_get_parity() #endif /* CK_ANSIC */ /* tnc_get_parity */ { /* IAC SB COM-PORT SET_PARITY IAC SE */ /* wait for response */ int i = 0, rc; debug(F110,"tnc_get_parity","begin",0); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_PARITY; /* Set Parity */ sb_out[i++] = 0; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-PARITY ", ckitoa(0)," IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport get parity",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_get_parity","end",tnc_parity); return(tnc_parity); } int #ifdef CK_ANSIC tnc_set_stopsize(int stopsize) #else /* CK_ANSIC */ tnc_set_stopsize(stopsize) int stopsize; #endif /* CK_ANSIC */ /* tnc_set_stopsize */ { /* IAC SB COM-PORT SET_STOPSIZE IAC SE */ /* Value Stop Bit Size * 1 1 * 2 2 * 3 1.5 */ /* Wait for response. Return new host value. */ int i = 0, rc; debug(F111,"tnc_set_stopsize","begin",stopsize); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if (!(stopsize >= 1 && stopsize <= 3) ) return(0); if ( stopsize != 0 && stopsize == tnc_stopbit ) return(tnc_stopbit); sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_STOPSIZE; /* Set Stop Bits */ sb_out[i++] = (unsigned char)(stopsize & 0xFF); sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-STOPSIZE ", ckitoa(stopsize)," IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport set stopsize",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_set_stopsize","end",tnc_stopbit); return(tnc_stopbit); } int #ifdef CK_ANSIC tnc_get_stopsize(void) #else /* CK_ANSIC */ tnc_get_stopsize() #endif /* CK_ANSIC */ /* tnc_get_stopsize */ { /* IAC SB COM-PORT SET_STOPSIZE IAC SE */ /* Wait for response */ int i = 0, rc; debug(F110,"tnc_get_stopsize","begin",0); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_STOPSIZE; /* Set Stop Bits */ sb_out[i++] = 0; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-STOPSIZE ", ckitoa(0)," IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport set stopsize",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_get_stopsize","end",tnc_stopbit); return(tnc_stopbit); } int #ifdef CK_ANSIC tnc_set_oflow(int control) #else /* CK_ANSIC */ tnc_set_oflow(control) int control; #endif /* CK_ANSIC */ /* tnc_set_oflow */ { /* IAC SB COM_PORT SET_CONTROL IAC SE */ /* Value Flow Control * 1 No Flow Control * 2 Xon/Xoff * 3 Rts/Cts * 17 DCD * 19 DSR */ /* wait for response, return new host value. */ int i = 0, rc; debug(F111,"tnc_set_oflow","begin",control); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if (control != 1 && control != 2 && control != 3 && control != 17 && control != 19) return(0); if ( control != 0 && control == tnc_oflow ) return(tnc_oflow); sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */ sb_out[i++] = (unsigned char)(control & 0xFF); sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-CONTROL ", ckitoa(control)," IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport set outbound flow control",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_set_oflow","end",tnc_oflow); return(tnc_oflow); } int #ifdef CK_ANSIC tnc_get_oflow(void) #else /* CK_ANSIC */ tnc_get_oflow() #endif /* CK_ANSIC */ /* tnc_get_oflow */ { /* IAC SB COM_PORT SET_CONTROL IAC SE */ /* wait for response */ int i = 0, rc; debug(F110,"tnc_get_oflow","begin",0); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */ sb_out[i++] = TNC_CTL_OFLOW_REQUEST; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-CONTROL ", ckitoa(TNC_CTL_OFLOW_REQUEST), " IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport get outbound flow control",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_get_oflow","end",tnc_oflow); return(tnc_oflow); } int #ifdef CK_ANSIC tnc_set_iflow(int control) #else /* CK_ANSIC */ tnc_set_iflow(control) int control; #endif /* CK_ANSIC */ /* tnc_set_iflow */ { /* IAC SB COM_PORT SET_CONTROL IAC SE */ /* Value Flow Control * 14 No Flow Control * 15 Xon/Xoff * 16 Rts/Cts * 18 DTR */ /* wait for response, return new host value. */ int i = 0, rc; debug(F111,"tnc_set_iflow","begin",control); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if (control != 14 && control != 15 && control != 16 && control != 18) return(0); if ( control != 0 && control == tnc_iflow ) return(tnc_iflow); sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */ sb_out[i++] = (unsigned char)(control & 0xFF); sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-CONTROL ", ckitoa(control)," IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport set inbound flow control",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_set_iflow","end",tnc_iflow); return(tnc_iflow); } int #ifdef CK_ANSIC tnc_get_iflow(void) #else /* CK_ANSIC */ tnc_get_iflow() #endif /* CK_ANSIC */ /* tnc_get_iflow */ { /* IAC SB COM_PORT SET_CONTROL IAC SE */ /* wait for response */ int i = 0, rc; debug(F110,"tnc_get_iflow","begin",0); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */ sb_out[i++] = TNC_CTL_IFLOW_REQUEST; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-CONTROL ", ckitoa(TNC_CTL_IFLOW_REQUEST), " IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport get inbound flow control",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_get_iflow","end",tnc_iflow); return(tnc_iflow); } int #ifdef CK_ANSIC tnc_set_break_state(int onoff) #else /* CK_ANSIC */ tnc_set_break_state(onoff) int onoff; #endif /* CK_ANSIC */ /* tnc_set_break_state */ { /* IAC SB COM_PORT SET_CONTROL IAC SE */ /* Value Break State * 5 On * 6 Off */ /* wait for response, return new host value. */ int i = 0, rc; debug(F111,"tnc_set_break_state","begin",onoff); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if ( onoff != 0 && onoff == tnc_break ) return(tnc_break); sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */ sb_out[i++] = onoff ? TNC_CTL_BREAK_ON : TNC_CTL_BREAK_OFF; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-CONTROL ", onoff ? "BREAK-ON" : "BREAK-OFF", " IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport set break state",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_set_break_state","end",tnc_break); return(tnc_break); } int #ifdef CK_ANSIC tnc_get_break_state(void) #else /* CK_ANSIC */ tnc_get_break_state() #endif /* CK_ANSIC */ /* tnc_get_break_state */ { /* IAC SB COM_PORT SET_CONTROL IAC SE */ /* wait for response */ int i = 0, rc; debug(F110,"tnc_get_break_state","begin",0); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */ sb_out[i++] = TNC_CTL_BREAK_REQUEST; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-CONTROL ", "BREAK-REQUEST", " IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport get break state",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_get_break_state","end",tnc_break); return(tnc_break); } int #ifdef CK_ANSIC tnc_set_dtr_state(int onoff) #else /* CK_ANSIC */ tnc_set_dtr_state(onoff) int onoff; #endif /* CK_ANSIC */ /* tnc_set_dtr_state */ { /* IAC SB COM_PORT SET_CONTROL IAC SE */ /* Value Dtr State * 8 On * 9 Off */ /* wait for response, return new host value. */ int i = 0, rc; debug(F111,"tnc_set_dtr_state","begin",onoff); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if ( onoff != 0 && onoff == tnc_dtr ) return(tnc_dtr); sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */ sb_out[i++] = onoff ? TNC_CTL_DTR_ON : TNC_CTL_DTR_OFF; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-CONTROL ", onoff ? "DTR-ON" : "DTR-OFF", " IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport set dtr state",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_set_dtr_state","end",tnc_dtr); return(tnc_dtr); } int #ifdef CK_ANSIC tnc_get_dtr_state(void) #else /* CK_ANSIC */ tnc_get_dtr_state() #endif /* CK_ANSIC */ /* tnc_get_dtr_state */ { /* IAC SB COM_PORT SET_CONTROL IAC SE */ /* wait for response */ int i = 0, rc; debug(F110,"tnc_get_dtr_state","begin",0); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */ sb_out[i++] = TNC_CTL_DTR_REQUEST; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-CONTROL ", "DTR-REQUEST", " IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport get dtr state",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_get_dtr_state","end",tnc_dtr); return(tnc_dtr); } int #ifdef CK_ANSIC tnc_set_rts_state(int onoff) #else /* CK_ANSIC */ tnc_set_rts_state(onoff) int onoff; #endif /* CK_ANSIC */ /* tnc_set_rts_state */ { /* IAC SB COM_PORT SET_CONTROL IAC SE */ /* Value Rts State * 5 On * 6 Off */ /* wait for response, return new host value. */ int i = 0, rc; debug(F111,"tnc_set_rts_state","begin",onoff); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if ( onoff != 0 && onoff == tnc_rts ) return(tnc_rts); sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */ sb_out[i++] = onoff ? TNC_CTL_RTS_ON : TNC_CTL_RTS_OFF; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-CONTROL ", onoff ? "RTS-ON" : "RTS-OFF", " IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport set rts state",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_set_rts_state","end",tnc_rts); return(tnc_rts); } int #ifdef CK_ANSIC tnc_get_rts_state(void) #else /* CK_ANSIC */ tnc_get_rts_state() #endif /* CK_ANSIC */ /* tnc_get_rts_state */ { /* IAC SB COM_PORT SET_CONTROL IAC SE */ /* wait for response */ int i = 0, rc; debug(F110,"tnc_get_rts_state","begin",0); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_CONTROL; /* Set Control */ sb_out[i++] = TNC_CTL_RTS_REQUEST; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-CONTROL ", "RTS-REQUEST", " IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); if (tnc_wait((CHAR *)"comport get rts state",0) < 0) { tn_push(); return(-1); } debug(F111,"tnc_get_rts_state","end",tnc_rts); return(tnc_rts); } int #ifdef CK_ANSIC tnc_set_ls_mask(int mask) #else /* CK_ANSIC */ tnc_set_ls_mask(mask) int mask; #endif /* CK_ANSIC */ /* tnc_set_ls_mask */ { /* IAC SB COM_PORT SET_LINESTATE_MASK IAC SE */ /* Bit Meaning * 0 Data Ready * 1 Overrun Error * 2 Parity Error * 3 Framing Error * 4 Break Detect Error * 5 Transfer Holding Register Empty * 6 Transfer Shift Register Empty * 7 Timeout Error */ int i = 0, rc; debug(F111,"tnc_set_ls_mask","begin",mask); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if ( mask != 0 && mask == tnc_ls_mask ) return(tnc_ls_mask); sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_LS_MASK; sb_out[i++] = (unsigned char)(mask & 0xFF); if (sb_out[i-1] == IAC ) sb_out[i++] = IAC; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-LINESTATE-MASK ", ckitoa(mask & 0xFF), " IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); tnc_ls_mask = mask; debug(F111,"tnc_set_ls_mask","end",tnc_ls_mask); return(0); } int #ifdef CK_ANSIC tnc_get_ls_mask(void) #else /* CK_ANSIC */ tnc_get_ls_mask() #endif /* CK_ANSIC */ /* tnc_get_ls_mask */ { debug(F101,"tnc_get_ls_mask","",tnc_ls_mask); return(tnc_ls_mask); } int #ifdef CK_ANSIC tnc_get_ls(void) #else /* CK_ANSIC */ tnc_get_ls() #endif /* CK_ANSIC */ /* tnc_get_ls */ { int ls = tnc_ls; debug(F101,"tnc_get_ls","",tnc_ls); return(ls); } int #ifdef CK_ANSIC tnc_set_ms_mask(int mask) #else /* CK_ANSIC */ tnc_set_ms_mask(mask) int mask; #endif /* CK_ANSIC */ /* tnc_set_ms_mask */ { /* IAC SB COM_PORT SET_MODEMSTATE_MASK IAC SE */ /* Bit Meaning * 0 Delta Clear To Send * 1 Delta Data Set Ready * 2 Trailing Edge Ring Detector * 3 Delta Receive Line Signal (Carrier) Detect * 4 Clear To Send Signal State * 5 Data-Set-Ready Signal State * 6 Ring Indicator * 7 Receive Line Signal (Carrier) Detect */ int i = 0, rc; debug(F111,"tnc_set_ms_mask","begin",mask); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if ( mask != 0 && mask == tnc_ms_mask ) return(tnc_ms_mask); sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_SET_MS_MASK; sb_out[i++] = (unsigned char)(mask & 0xFF); if (sb_out[i-1] == IAC ) sb_out[i++] = IAC; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " SET-MODEMSTATE-MASK ", ckitoa(mask & 0xFF), " IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); tnc_ms_mask = mask; debug(F111,"tnc_set_ms_mask","end",tnc_ms_mask); return(0); } int #ifdef CK_ANSIC tnc_get_ms_mask(void) #else /* CK_ANSIC */ tnc_get_ms_mask() #endif /* CK_ANSIC */ /* tnc_get_ms_mask */ { debug(F101,"tnc_get_gs_mask","",tnc_ms_mask); return(tnc_ms_mask); } int #ifdef CK_ANSIC tnc_get_ms(void) #else /* CK_ANSIC */ tnc_get_ms() #endif /* CK_ANSIC */ /* tnc_get_ms */ { int ms = tnc_ms; debug(F101,"tnc_get_ms","",tnc_ms); return(ms); } int #ifdef CK_ANSIC tnc_send_purge_data(int mode) #else /* CK_ANSIC */ tnc_send_purge_data(mode) int mode; #endif /* CK_ANSIC */ /* tnc_send_purge_data */ { /* IAC SB COM_PORT PURGE_DATA IAC SE */ /* Value Meaning * 1 Purge access server receive data buffer * 2 Purge access server transmit data buffer * 3 Purge access server receive and transmit data buffers */ /* No response */ int i = 0, rc; debug(F111,"tnc_send_purge_data","begin",mode); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if ( !(mode >= 1 && mode <= 3) ) return(0); sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_PURGE; sb_out[i++] = (unsigned char)(mode & 0xFF); sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " PURGE-DATA ", ckitoa(mode & 0xFF), " IAC SE", NULL, NULL,NULL,NULL,NULL,NULL,NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); debug(F110,"tnc_send_purge_data","end",0); return(0); } int #ifdef CK_ANSIC tnc_flow_suspended(void) #else /* CK_ANSIC */ tnc_flow_suspended() #endif /* CK_ANSIC */ /* tnc_flow_suspended */ { debug(F111,"tnc_flow_suspended","",tnc_suspend_xmit); return(tnc_suspend_xmit); } int #ifdef CK_ANSIC tnc_suspend_flow(void) #else /* CK_ANSIC */ tnc_suspend_flow() #endif /* CK_ANSIC */ /* tnc_suspend_flow */ { /* IAC SB COM_PORT FLOWCONTROL_SUSPEND IAC SE */ int i = 0, rc; debug(F110,"tnc_suspend_flow","begin",0); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_FLOW_SUSPEND; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " FLOWCONTROL-SUSPEND IAC SE", NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); debug(F110,"tnc_suspend_flow","end",0); return(0); } int #ifdef CK_ANSIC tnc_resume_flow(void) #else /* CK_ANSIC */ tnc_resume_flow() #endif /* CK_ANSIC */ /* tnc_resume_flow */ { /* IAC SB COM_PORT FLOWCONTROL_RESUME IAC SE */ int i = 0, rc; debug(F110,"tnc_resume_flow","begin",0); if (ttnet != NET_TCPB) return(0); if (ttnproto != NP_TELNET) return(0); if (!TELOPT_ME(TELOPT_COMPORT)) return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ sb_out[i++] = (CHAR) IAC; /* I Am a Command */ sb_out[i++] = (CHAR) SB; /* Subnegotiation */ sb_out[i++] = TELOPT_COMPORT; /* ComPort */ sb_out[i++] = TNC_C2S_FLOW_RESUME; sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ #ifdef DEBUG if (deblog || tn_deb || debses) { ckmakmsg(tn_msg_out,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_COMPORT), " FLOWCONTROL-RESUME IAC SE", NULL); } #endif /* DEBUG */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif #ifdef DEBUG debug(F100,tn_msg_out,"",0); if (tn_deb || debses) tn_debug(tn_msg_out); #endif /* DEBUG */ rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ #ifdef OS2 ReleaseTelnetMutex(); #endif if (rc) return(-1); debug(F110,"tnc_resume_flow","end",0); return(0); } int #ifdef CK_ANSIC tnsetflow(int nflow) #else tnsetflow(nflow) int nflow; #endif /* CK_ANSIC */ /* tnsetflow */ { int rc = -1; debug(F111,"tnsetflow","begin",nflow); if (ttnet != NET_TCPB || ttnproto != NP_TELNET) return(-1); if (TELOPT_ME(TELOPT_COMPORT)) { switch(nflow) { case FLO_XONX: rc = tnc_set_oflow( TNC_CTL_OFLOW_XON_XOFF ); if (rc >= 0) rc = tnc_set_iflow( TNC_CTL_IFLOW_XON_XOFF ); break; case FLO_RTSC: rc = tnc_set_oflow( TNC_CTL_OFLOW_RTS_CTS ); if (rc >= 0) rc = tnc_set_iflow( TNC_CTL_IFLOW_RTS_CTS ); break; case FLO_KEEP: /* leave things exactly as they are */ rc = 0; break; case FLO_NONE: case FLO_DIAL: /* dialing hack */ case FLO_DIAX: /* cancel dialing hack */ rc = tnc_set_oflow( TNC_CTL_OFLOW_NONE ); if (rc >= 0) rc = tnc_set_iflow( TNC_CTL_IFLOW_NONE ); break; case FLO_DTRC: case FLO_ETXA: case FLO_STRG: case FLO_DTRT: default: /* not supported */ rc = -1; break; } } debug(F111,"tnsetflow","end",rc); return(rc >= 0 ? 0 : -1); } int #ifdef CK_ANSIC tnsettings(int par, int stop) #else tnsettings(par, stop) int par, stop; #endif /* CK_ANSIC */ /* tnsettings */ { int rc = -1; int datasize = 0; extern int hwparity; debug(F111,"tnsettings begin","par",par); debug(F111,"tnsettings begin","stop",stop); if (ttnet != NET_TCPB || ttnproto != NP_TELNET) return(-1); datasize = par ? TNC_DS_7 : TNC_DS_8; if (!par) par = hwparity; if (TELOPT_ME(TELOPT_COMPORT)) { switch (par) { case 'e': rc = tnc_set_parity(TNC_PAR_EVEN); if (rc >= 0) rc = tnc_set_datasize(datasize); break; case 'o': rc = tnc_set_parity(TNC_PAR_ODD); if (rc >= 0) rc = tnc_set_datasize(datasize); break; case 'm': rc = tnc_set_parity(TNC_PAR_MARK); if (rc >= 0) rc = tnc_set_datasize(datasize); break; case 's': rc = tnc_set_parity(TNC_PAR_SPACE); if (rc >= 0) rc = tnc_set_datasize(datasize); break; case 0: case 'n': rc = tnc_set_parity(TNC_PAR_NONE); if (rc >= 0) rc = tnc_set_datasize(datasize); break; default: /* no change */ rc = 0; } switch(stop) { case 2: if (rc >= 0) rc = tnc_set_stopsize(TNC_SB_2); break; case 1: if (rc >= 0) rc = tnc_set_stopsize(TNC_SB_1); break; default: /* no change */ if (rc >= 0) rc = 0; } } debug(F111,"tnsettings","end",rc); return((rc >= 0) ? 0 : -1); } /* T N G M D M -- Telnet Get modem signals */ /* 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. Returns: -3 Not implemented -2 if the line does not have modem control -1 on error. >= 0 on success, with a bit mask containing the modem signals that are on. */ int #ifdef CK_ANSIC tngmdm(void) #else tngmdm() #endif /* CK_ANSIC */ /* tngmdm */ { debug(F110,"tngmdm","begin",0); if (ttnet != NET_TCPB || ttnproto != NP_TELNET) return(-1); if (TELOPT_ME(TELOPT_COMPORT)) { int modemstate = tnc_get_ms(); int modem = 0; if (modemstate & TNC_MS_CTS_SIG) modem |= BM_CTS; if (modemstate & TNC_MS_DSR_SIG) modem |= BM_DSR; if (modemstate & TNC_MS_RI_SIG) modem |= BM_RNG; if (modemstate & TNC_MS_RLSD_SIG) modem |= BM_DCD; debug(F111,"tngmdm","end",modem); return(modem); } else { debug(F111,"tngmdm","end",-2); return(-2); } } int #ifdef CK_ANSIC tnsndb(long wait) #else tnsndb(wait) long wait; #endif /* CK_ANSIC */ /* tnsndb */ { int rc = -1; debug(F111,"tnsndb","begin",wait); if (ttnet != NET_TCPB || ttnproto != NP_TELNET) return(-1); if (TELOPT_ME(TELOPT_COMPORT)) { rc = tnc_set_break_state(1); if (rc >= 0) { msleep(wait); rc = tnc_set_break_state(0); } } debug(F111,"tnsndb","end",rc); return((rc >= 0) ? 0 : -1); } #endif /* TN_COMPORT */ #endif /* TNCODE */ #endif /* NOTCPIP */ #endif /* NONET */ ckctel.h000664 045065 024037 00000132133 14767403102 012610 0ustar00fdckermit000000 000000 /* ckctel.h -- Symbol and macro definitions for C-Kermit telnet support */ /* Authors: Jeffrey E Altman , Secure Endpoints Inc., New York City Frank da Cruz Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 2009, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Notes: . This file should be used in place of "arpa/telnet.h" . Only one source file should include #defines for TELCMDS, TELOPTS, TELOPT_STATES, SLC_NAMES, and AUTH_NAMES. */ #ifndef CKCTEL_H #define CKCTEL_H #ifdef TNCODE /* Definitions for the TELNET protocol. can't rely on library header files for any of them. */ #ifdef COMMENT /* In some compilers these are prone to sign extension */ #ifndef IAC /* First the telnet commands */ #define IAC 255 #endif /* IAC */ #ifndef DONT #define DONT 254 #endif /* DONT */ #ifndef DO #define DO 253 #endif /* DO */ #ifndef WONT #define WONT 252 #endif /* WONT */ #ifndef WILL #define WILL 251 #endif /* WILL */ #ifndef SB #define SB 250 #endif /* SB */ #ifndef TN_GA #define TN_GA 249 #endif /* TN_GA */ #ifndef TN_EL #define TN_EL 248 #endif /* TN_EL */ #ifndef TN_EC #define TN_EC 247 #endif /* TN_EC */ #ifndef TN_AYT #define TN_AYT 246 #endif /* TN_AYT */ #ifndef TN_AO #define TN_AO 245 #endif /* TN_AO */ #ifndef TN_IP #define TN_IP 244 #endif /* TN_IP */ #ifndef BREAK #define BREAK 243 #endif /* BREAK */ #ifndef TN_DM #define TN_DM 242 #endif /* TN_DM */ #ifndef TN_NOP #define TN_NOP 241 #endif /* TN_NOP */ #ifndef SE #define SE 240 #endif /* SE */ #ifndef TN_EOR #define TN_EOR 239 #endif /* TN_EOR */ #ifndef TN_ABORT #define TN_ABORT 238 #endif /* TN_ABORT */ #ifndef TN_SUSP #define TN_SUSP 237 #endif /* TN_SUSP */ #ifndef TN_EOF #define TN_EOF 236 #endif /* TN_EOF */ #ifndef LAST_TN_CMD #define LAST_TN_CMD 236 #define TN_SAK 200 /* IBM Secure Attention Key */ #endif /* LAST_TN_CMD */ #define SYNCH 242 /* for telfunc calls */ #else /* Hex notation seems to suppress the sugn extension effect */ #ifndef IAC /* First the telnet commands */ #define IAC 0xff #endif /* IAC */ #ifndef DONT #define DONT 0xfe /* 254 */ #endif /* DONT */ #ifndef DO #define DO 0xfd /* 253 */ #endif /* DO */ #ifndef WONT #define WONT 0xfc /* 252 */ #endif /* WONT */ #ifndef WILL #define WILL 0xfb /* 251 */ #endif /* WILL */ #ifndef SB #define SB 0xfa /* 250 */ #endif /* SB */ #ifndef TN_GA #define TN_GA 0xf9 /* 249 */ #endif /* TN_GA */ #ifndef TN_EL #define TN_EL 0xf8 /* 248 */ #endif /* TN_EL */ #ifndef TN_EC #define TN_EC 0xf7 /* 247 */ #endif /* TN_EC */ #ifndef TN_AYT #define TN_AYT 0xf6 /* 246 */ #endif /* TN_AYT */ #ifndef TN_AO #define TN_AO 0xf5 /* 245 */ #endif /* TN_AO */ #ifndef TN_IP #define TN_IP 0xf4 /* 244 */ #endif /* TN_IP */ #ifndef BREAK #define BREAK 0xf3 /* 243 */ #endif /* BREAK */ #ifndef TN_DM #define TN_DM 0xf2 /* 242 */ #endif /* TN_DM */ #ifndef TN_NOP #define TN_NOP 0xf1 /* 241 */ #endif /* TN_NOP */ #ifndef SE #define SE 0xf0 /* 240 */ #endif /* SE */ #ifndef TN_EOR #define TN_EOR 0xef /* 239 */ #endif /* TN_EOR */ #ifndef TN_ABORT #define TN_ABORT 0xee /* 238 */ #endif /* TN_ABORT */ #ifndef TN_SUSP #define TN_SUSP 0xed /* 237 */ #endif /* TN_SUSP */ #ifndef TN_EOF #define TN_EOF 0xec /* 236 */ #endif /* TN_EOF */ #ifndef LAST_TN_CMD #define LAST_TN_CMD 0xec /* 236 */ #define TN_SAK 0xc8 /* 200 - IBM Secure Attention Key */ #endif /* LAST_TN_CMD */ #define SYNCH 0xf2 /* 242 - for telfunc calls */ #endif /* COMMENT */ _PROTOTYP(char * tel_unk, (int)); /* "UNKNOWN-%u" string. */ #ifdef TELCMDS char *telcmds[] = { "EOF", "SUSP", "ABORT", "EOR", "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0 }; #else /* TELCMDS */ extern char *telcmds[]; #endif /* TELCMDS */ #define TELCMD_FIRST TN_EOF #define TELCMD_LAST IAC #define TELCMD_OK(x) ((unsigned int)(x) <= TELCMD_LAST && \ (unsigned int)(x) >= TELCMD_FIRST || \ (unsigned int)(x) == TN_SAK) #define TELCMD(x) (TELCMD_OK(x)? ((x) == TN_SAK?"SAK": \ telcmds[(x)-TELCMD_FIRST]):tel_unk(x)) /* Then the options */ /* NB: the following platforms have TELOPT_AUTHENTICATION defined as */ /* 45 instead of 37. */ #ifdef TELOPT_AUTHENTICATION #ifdef __osf__ #undef TELOPT_AUTHENTICATION #endif /* __osf__ */ #ifndef IRIX #undef TELOPT_AUTHENTICATION #endif /* IRIX */ #ifndef ultrix #undef TELOPT_AUTHENTICATION #endif /* ultrix */ #endif /* TELOPT_AUTHENTICATION */ /* telnet options */ #ifndef TELOPT_BINARY #define TELOPT_BINARY 0 /* 8-bit data path (RFC 856)*/ #endif #ifndef TELOPT_ECHO #define TELOPT_ECHO 1 /* echo (RFC 857)*/ #endif #ifndef TELOPT_RCP #define TELOPT_RCP 2 /* prepare to reconnect (NIC 50005)*/ #endif #ifndef TELOPT_SGA #define TELOPT_SGA 3 /* suppress go ahead (RFC 858) */ #endif #ifndef TELOPT_NAMS #define TELOPT_NAMS 4 /* approximate message size (ETHERNET) */ #endif #ifndef TELOPT_STATUS #define TELOPT_STATUS 5 /* give status (RFC 859) */ #endif #ifndef TELOPT_TM #define TELOPT_TM 6 /* timing mark (RFC 860) */ #endif #ifndef TELOPT_RCTE #define TELOPT_RCTE 7 /* remote controlled transmission and echo */ #endif /* (RFC 726) */ #ifndef TELOPT_NAOL #define TELOPT_NAOL 8 /* negotiate about output line width */ #endif /* (NIC 50005) */ #ifndef TELOPT_NAOP #define TELOPT_NAOP 9 /* negotiate about output page size */ #endif /* (NIC 50005) */ #ifndef TELOPT_NAOCRD #define TELOPT_NAOCRD 10 /* negotiate about CR disposition (RFC 652) */ #endif /* [Historic] */ #ifndef TELOPT_NAOHTS #define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ #endif /* (RFC 653) [Historic] */ #ifndef TELOPT_NAOHTD #define TELOPT_NAOHTD 12 /* negotiate about horiz tab disposition */ #endif /* (RFC 654) [Historic] */ #ifndef TELOPT_NAOFFD #define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ #endif /* (RFC 655) [Historic] */ #ifndef TELOPT_NAOVTS #define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ #endif /* (RFC 656) [Historic] */ #ifndef TELOPT_NAOVTD #define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ #endif /* (RFC 657) [Historic] */ #ifndef TELOPT_NAOLFD #define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ #endif /* (RFC 658) [Historic] */ #ifndef TELOPT_XASCII #define TELOPT_XASCII 17 /* extended ascii character set */ #endif /* (RFC 698) */ #ifndef TELOPT_LOGOUT #define TELOPT_LOGOUT 18 /* force logout (RFC 727) */ #endif #ifndef TELOPT_BM #define TELOPT_BM 19 /* byte macro (RFC 735) */ #endif #ifndef TELOPT_DET #define TELOPT_DET 20 /* data entry terminal (RFC 1043, 732) */ #endif #ifndef TELOPT_SUPDUP #define TELOPT_SUPDUP 21 /* supdup protocol (RFC 736, 734) */ #endif #ifndef TELOPT_SUPDUPOUTPUT #define TELOPT_SUPDUPOUTPUT 22 /* supdup output (RFC 749) */ #endif #ifndef TELOPT_SNDLOC #define TELOPT_SNDLOC 23 /* send location (RFC 779) */ #endif #ifndef TELOPT_TTYPE #define TELOPT_TTYPE 24 /* terminal type (RFC 1091) */ #endif #ifndef TELOPT_EOR #define TELOPT_EOR 25 /* end of record (RFC 885) */ #endif #ifndef TELOPT_TUID #define TELOPT_TUID 26 /* TACACS user identification (RFC 927) */ #endif #ifndef TELOPT_OUTMRK #define TELOPT_OUTMRK 27 /* output marking (RFC 933) */ #endif #ifndef TELOPT_TTYLOC #define TELOPT_TTYLOC 28 /* terminal location number (RFC 946) */ #endif #ifndef TELOPT_3270REGIME #define TELOPT_3270REGIME 29 /* 3270 regime (RFC 1041) */ #endif #ifndef TELOPT_X3PAD #define TELOPT_X3PAD 30 /* X.3 PAD (RFC 1053) */ #endif #ifndef TELOPT_NAWS #define TELOPT_NAWS 31 /* window size (RFC 1073) */ #endif #ifndef TELOPT_TSPEED #define TELOPT_TSPEED 32 /* terminal speed (RFC 1079) */ #endif #ifndef TELOPT_LFLOW #define TELOPT_LFLOW 33 /* remote flow control (RFC 1372) */ #endif #ifndef TELOPT_LINEMODE #define TELOPT_LINEMODE 34 /* Linemode option (RFC 1184) */ #endif #ifndef TELOPT_XDISPLOC #define TELOPT_XDISPLOC 35 /* X Display Location (RFC 1096) */ #endif #ifndef TELOPT_OLD_ENVIRON #define TELOPT_OLD_ENVIRON 36 /* Old - Environment variables (RFC 1408) */ #endif #ifndef TELOPT_AUTHENTICATION #define TELOPT_AUTHENTICATION 37/* Authenticate (RFC 2941) */ #endif #ifndef TELOPT_ENCRYPTION #define TELOPT_ENCRYPTION 38 /* Encryption option (RFC 2946) */ #endif #ifndef TELOPT_NEWENVIRON #define TELOPT_NEWENVIRON 39 /* New - Environment variables (RFC 1572) */ #endif #ifndef TELOPT_3270E #define TELOPT_3270E 40 /* 3270 Extended (RFC 1647) */ #endif #ifndef TELOPT_XAUTH #define TELOPT_XAUTH 41 /* ??? (Earhart) */ #endif #ifndef TELOPT_CHARSET #define TELOPT_CHARSET 42 /* Character-set (RFC 2066) */ #endif #ifndef TELOPT_RSP #define TELOPT_RSP 43 /* Remote Serial Port (Barnes) */ #endif #ifndef TELOPT_COMPORT #define TELOPT_COMPORT 44 /* Com Port Control (RFC 2217) */ #endif #ifndef TELOPT_SLE #define TELOPT_SLE 45 /* Suppress Local Echo (Atmar) - [rejected] */ #endif #ifndef TELOPT_START_TLS #define TELOPT_START_TLS 46 /* Telnet over Transport Layer Security */ #endif /* (Boe) */ #ifndef TELOPT_KERMIT #define TELOPT_KERMIT 47 /* Kermit (RFC 2840) */ #endif #ifndef TELOPT_SEND_URL #define TELOPT_SEND_URL 48 /* Send URL */ #endif #ifndef TELOPT_FORWARD_X #define TELOPT_FORWARD_X 49 /* X Windows Forwarding (Altman) */ #endif /* TELOPT_FORWARD_X */ #ifndef TELOPT_STDERR #define TELOPT_STDERR 50 /* Redirected Stderr (Altman) */ #endif /* TELOPT_STDERR */ #ifndef TELOPT_PRAGMA_LOGON #define TELOPT_PRAGMA_LOGON 138 /* Encrypted Logon option (PragmaSys) */ #endif #ifndef TELOPT_SSPI_LOGON #define TELOPT_SSPI_LOGON 139 /* MS SSPI Logon option (PragmaSys) */ #endif #ifndef TELOPT_PRAGMA_HEARTBEAT /* Server Send Heartbeat option (PragmaSys) */ #define TELOPT_PRAGMA_HEARTBEAT 140 #endif #define TELOPT_IBM_SAK 200 /* IBM Secure Attention Key */ /* IBM Secure Attention Key (SAK) Option In addition to terminal negotiation, the telnet command allows negotiation for the Secure Attention Key (SAK) option. This option, when supported, provides the local user with a secure communication path to the remote host for tasks such as changing user IDs or passwords. If the remote host supports the SAK function, a trusted shell is opened on the remote host when the telnet send sak subcommand is issued. The SAK function can also be assigned to a single key available in telnet input mode, using the set sak subcommand. TN_SAK Sends the TELNET SAK (Secure Attention Key) sequence, which causes the remote system to invoke the trusted shell. If the SAK is not supported, then an error message is displayed that reads: Remote side does not support SAK. */ #ifndef TELOPT_EXOPL #define TELOPT_EXOPL 255 /* Extended-options-list (RFC 861) */ #endif #ifdef NTELOPTS #undef NTELOPTS #endif /* NTELOPTS */ /* The Telnet Option space is no longer being allocated by ICANN as a */ /* continuous list. In other words it is becoming sparse. But we do */ /* not want to have to allocate memory for a long list of strings and */ /* structs which will never be used. Therefore, the NTELOPTS define */ /* can no longer be equal to TELOPT_LAST+1. In fact, the notion of */ /* TELOPT_FIRST and TELOPT_LAST no longer make sense. */ #define NTELOPTS 55 #define TELOPT_FIRST TELOPT_BINARY #define TELOPT_LAST TELOPT_IBM_SAK /* The following macros speed us up at runtime but are too complex for some preprocessors / compilers; if your compiler bombs on ckctel.c with "Instruction table overflow" or somesuch, rebuild with -DNOTOMACROS. */ #ifndef NOTOMACROS #ifndef TELOPT_MACRO #define TELOPT_MACRO #endif /* TELOPT_MACRO */ #endif /* NOTOMACROS */ #ifdef TELOPT_MACRO #define TELOPT_INDEX(x) (((x)>=0 && (x)<= TELOPT_STDERR)?(x):\ ((x)>=TELOPT_PRAGMA_LOGON && (x)<=TELOPT_PRAGMA_HEARTBEAT)?(x)-87: \ ((x) == TELOPT_IBM_SAK)?(x)-146: NTELOPTS) #define TELOPT_OK(x) (((x) >= TELOPT_BINARY && (x) <= TELOPT_STDERR) ||\ ((x) >= TELOPT_PRAGMA_LOGON && (x) <= TELOPT_PRAGMA_HEARTBEAT) ||\ ((x) == TELOPT_IBM_SAK)) #define TELOPT(x) (TELOPT_OK(x)?telopts[TELOPT_INDEX(x)]:tel_unk(x)) #else /* TELOPT_MACRO */ _PROTOTYP(int telopt_index,(int)); _PROTOTYP(int telopt_ok,(int)); _PROTOTYP(char * telopt, (int)); /* Type match telopts[], below. */ #define TELOPT_INDEX(x) telopt_index(x) #define TELOPT_OK(x) telopt_ok(x) #define TELOPT(x) telopt(x) #endif /* TELOPT_MACRO */ #ifdef TELOPTS char *telopts[NTELOPTS+2] = { /* 0 */ "BINARY", "ECHO", "RCP", "SUPPRESS-GO-AHEAD", /* 4 */ "NAME", "STATUS", "TIMING-MARK", "RCTE", /* 8 */ "NAOL", "NAOP", "NAOCRD", "NAOHTS", /* 12 */ "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD", /* 16 */ "NAOLFD", "EXTEND-ASCII", "LOGOUT", "BYTE-MACRO", /* 20 */ "DATA-ENTRY-TERMINAL", "SUPDUP", "SUPDUP-OUTPUT", "SEND-LOCATION", /* 24 */ "TERMINAL-TYPE", "END-OF-RECORD", "TACACS-UID", "OUTPUT-MARKING", /* 28 */ "TTYLOC", "3270-REGIME", "X.3-PAD", "NAWS", /* 32 */ "TSPEED", "LFLOW", "LINEMODE", "XDISPLOC", /* 36 */ "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPTION", "NEW-ENVIRONMENT", /* 40 */ "TN3270E","xauth","CHARSET", "remote-serial-port", /* 44 */ "COM-PORT-CONTROL","suppress-local-echo","START-TLS","KERMIT", /* 48 */ "send-url","FORWARD-X","stderr", /* 138 */ "pragma-logon", "sspi-logon", "pragma-heartbeat", /* 200 */ "ibm-sak", "unknown", 0 }; #else /*TELOPTS */ extern char * telopts[]; #endif /* TELOPTS */ /* TELNET Newline Mode */ #define TNL_CR 0 /* CR sends bare carriage return */ #define TNL_CRNUL 1 /* CR and NUL */ #define TNL_CRLF 2 /* CR and LF */ #define TNL_LF 3 /* LF instead of CR */ /* TELNET Negotiation Mode */ #define TN_NG_RF 0 /* Negotiation REFUSED */ #define TN_NG_AC 1 /* Negotiation ACCEPTED */ #define TN_NG_RQ 2 /* Negotiation REQUESTED */ #define TN_NG_MU 3 /* Negotiation REQUIRED (must) */ /* Systems where we know we can define TELNET NAWS automatically. */ #ifndef CK_NAWS /* In other words, if both */ #ifdef CK_TTGWSIZ /* TNCODE and TTGWSIZ are defined */ #define CK_NAWS /* then we can do NAWS. */ #endif /* CK_TTGWSIZ */ #endif /* CK_NAWS */ #ifdef CK_FORWARD_X #ifndef MAXFWDX #define MAXFWDX 64 /* Num of X windows to be fwd'd */ #endif /* MAXFWDX */ #endif /* CK_FORWARD_X */ /* Telnet State structures and definitions */ struct _telopt_state { unsigned char def_server_me_mode; /* Default Negotiation Mode */ unsigned char def_server_u_mode; /* Default Negotiation Mode */ unsigned char def_client_me_mode; /* Default Negotiation Mode */ unsigned char def_client_u_mode; /* Default Negotiation Mode */ unsigned char me_mode; /* Telnet Negotiation Mode */ unsigned char u_mode; /* Telnet Negotiation Mode */ unsigned char me; /* Am I ? */ unsigned char u; /* Are you? */ unsigned char unanswered_will; /* Sent Will, Waiting for DO/DONT */ unsigned char unanswered_do; /* Send DO, Waiting for WILL/WONT */ unsigned char unanswered_wont; /* Sent WONT, Waiting for DONT */ unsigned char unanswered_dont; /* Sent DONT, Waiting for WONT */ unsigned char unanswered_sb; /* Sent SB, Waiting for SB (server) */ union { #ifdef IKS_OPTION struct _telopt_kermit { /* Kermit Option States */ unsigned char me_start; /* I have a Server active */ unsigned char me_req_start; /* Sent Req-Start, Waiting for response */ unsigned char me_req_stop; /* Sent Req-Stop, Waiting for response */ unsigned char u_start; /* You have a Server active */ unsigned char sop; /* Have we received the SOP char? */ } kermit; #endif /* IKS_OPTION */ #ifdef CK_ENCRYPTION struct _telopt_encrypt { /* Encryption Option States */ unsigned char need_to_send; unsigned char stop; /* Is encryption stopped? */ } encrypt; #endif /* CK_ENCRYPTION */ #ifdef CK_NAWS struct _telopt_naws { /* NAWS Option Information */ unsigned char need_to_send; int x; /* Last Width */ int y; /* Last Height */ } naws; #endif /* CK_NAWS */ #ifdef CK_SSL struct _telopt_start_tls { /* Start TLS Option */ unsigned char u_follows; /* u ready for TLS negotiation */ unsigned char me_follows; /* me ready for TLS negotiation */ unsigned char auth_request; /* Rcvd WILL AUTH before WONT START_TLS */ } start_tls; #endif /* CK_SSL */ struct _telopt_term { /* Terminal Type */ unsigned char need_to_send; unsigned char type[41]; /* Last terminal type */ } term; #ifdef CK_ENVIRONMENT struct _telopt_new_env { unsigned char need_to_send; unsigned char * str; int len; } env; #ifdef CK_XDISPLOC struct _telopt_xdisp { unsigned char need_to_send; } xdisp; #endif /* CK_XDISPLOC */ #endif /* CK_ENVIRONMENT */ #ifdef CK_SNDLOC struct _telopt_sndloc { unsigned char need_to_send; } sndloc; #endif /* CK_SNDLOC */ #ifdef CK_FORWARD_X struct _telopt_fwd_x { unsigned char need_to_send; int listen_socket; struct _channel { int fd; int id; unsigned char need_to_send_xauth; unsigned char suspend; } channel[MAXFWDX]; #ifdef NT int thread_started; #endif /* NT */ } forward_x; #endif /* CK_FORWARD_X */ #ifdef TN_COMPORT struct _telopt_comport { unsigned char need_to_send; unsigned char wait_for_sb; unsigned char wait_for_ms; } comport; #endif /* TN_COMPORT */ /* additional options such as New Environment or Send Location */ } sb; }; typedef struct _telopt_state telopt_state, *p_telopt_state; /* telopt_states[] is the array of structs which the state of each telnet */ /* option is stored. We allocate one more than we need in case we are */ /* sent telnet options that we do not recognize. If by some chance the */ /* TELOPT_OK() check is skipped, TELOPT_INDEX() will force the option to */ /* use the extra cell. */ #ifdef TELOPT_STATES telopt_state telopt_states[NTELOPTS+1]; #else /* TELOPT_STATES */ extern telopt_state telopt_states[]; #endif /* TELOPT_STATES */ #define TELOPT_ME(x) (telopt_states[TELOPT_INDEX(x)].me) #define TELOPT_U(x) (telopt_states[TELOPT_INDEX(x)].u) #define TELOPT_ME_MODE(x) \ (telopt_states[TELOPT_INDEX(x)].me_mode) #define TELOPT_U_MODE(x) \ (telopt_states[TELOPT_INDEX(x)].u_mode) #define TELOPT_UNANSWERED_WILL(x) \ (telopt_states[TELOPT_INDEX(x)].unanswered_will) #define TELOPT_UNANSWERED_DO(x) \ (telopt_states[TELOPT_INDEX(x)].unanswered_do) #define TELOPT_UNANSWERED_WONT(x) \ (telopt_states[TELOPT_INDEX(x)].unanswered_wont) #define TELOPT_UNANSWERED_DONT(x) \ (telopt_states[TELOPT_INDEX(x)].unanswered_dont) #define TELOPT_UNANSWERED_SB(x) \ (telopt_states[TELOPT_INDEX(x)].unanswered_sb) #define TELOPT_SB(x) \ (telopt_states[TELOPT_INDEX(x)].sb) #define TELOPT_DEF_S_ME_MODE(x) \ (telopt_states[TELOPT_INDEX(x)].def_server_me_mode) #define TELOPT_DEF_S_U_MODE(x) \ (telopt_states[TELOPT_INDEX(x)].def_server_u_mode) #define TELOPT_DEF_C_ME_MODE(x) \ (telopt_states[TELOPT_INDEX(x)].def_client_me_mode) #define TELOPT_DEF_C_U_MODE(x) \ (telopt_states[TELOPT_INDEX(x)].def_client_u_mode) #ifdef TELOPT_MODES char * telopt_modes[4] = { "REFUSED", "ACCEPTED", "REQUESTED", "REQUIRED" }; #else /* TELOPT_MODES */ extern char * telopt_modes[]; #endif /* TELOPT_MODES */ #ifdef TELOPT_MACRO #define TELOPT_MODE_OK(x) ((unsigned int)(x) <= TN_NG_MU) #define TELOPT_MODE(x) (TELOPT_MODE_OK(x)?telopt_modes[(x)-TN_NG_RF]:tel_unk(x)) #else /* TELOPT_MACRO */ _PROTOTYP(int telopt_mode_ok,(int)); _PROTOTYP(char * telopt_mode,(int)); /* Type match telopt_modes[], above. */ #define TELOPT_MODE_OK(x) telopt_mode_ok(x) #define TELOPT_MODE(x) telopt_mode(x) #endif /* TELOPT_MACRO */ /* Sub-option qualifiers */ #define TELQUAL_IS 0 /* option is... */ #define TELQUAL_SEND 1 /* send option */ #define TELQUAL_INFO 2 /* ENVIRON: informational version of IS */ #define TELQUAL_REPLY 2 /* AUTHENTICATION: client version of IS */ #define TELQUAL_NAME 3 /* AUTHENTICATION: client version of IS */ #define TEL_ENV_VAR 0 #define TEL_ENV_VALUE 1 #define TEL_ENV_ESC 2 #define TEL_ENV_USERVAR 3 #define LFLOW_OFF 0 /* Disable remote flow control */ #define LFLOW_ON 1 /* Enable remote flow control */ #define LFLOW_RESTART_ANY 2 /* Restart output on any char */ #define LFLOW_RESTART_XON 3 /* Restart output only on XON */ /* * LINEMODE suboptions */ #define LM_MODE 1 #define LM_FORWARDMASK 2 #define LM_SLC 3 #define MODE_EDIT 0x01 #define MODE_TRAPSIG 0x02 #define MODE_ACK 0x04 #define MODE_SOFT_TAB 0x08 #define MODE_LIT_ECHO 0x10 #define MODE_MASK 0x1f /* Not part of protocol, but needed to simplify things... */ #define MODE_FLOW 0x0100 #define MODE_ECHO 0x0200 #define MODE_INBIN 0x0400 #define MODE_OUTBIN 0x0800 #define MODE_FORCE 0x1000 #define SLC_SYNCH 1 #define SLC_BRK 2 #define SLC_IP 3 #define SLC_AO 4 #define SLC_AYT 5 #define SLC_EOR 6 #define SLC_ABORT 7 #define SLC_EOF 8 #define SLC_SUSP 9 #define SLC_EC 10 #define SLC_EL 11 #define SLC_EW 12 #define SLC_RP 13 #define SLC_LNEXT 14 #define SLC_XON 15 #define SLC_XOFF 16 #define SLC_FORW1 17 #define SLC_FORW2 18 #define SLC_MCL 19 #define SLC_MCR 20 #define SLC_MCWL 21 #define SLC_MCWR 22 #define SLC_MCBOL 23 #define SLC_MCEOL 24 #define SLC_INSRT 25 #define SLC_OVER 26 #define SLC_ECR 27 #define SLC_EWR 28 #define SLC_EBOL 29 #define SLC_EEOL 30 #define NSLC 30 /* * For backwards compatability, we define SLC_NAMES to be the * list of names if SLC_NAMES is not defined. */ #define SLC_NAMELIST "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ "LNEXT", "XON", "XOFF", "FORW1", "FORW2", \ "MCL", "MCR", "MCWL", "MCWR", "MCBOL", "MCEOL", \ "INSRT", "OVER", "ECR", "EWR", "EBOL", "EEOL", 0 #ifdef SLC_NAMES char *slc_names[] = { SLC_NAMELIST }; #else extern char *slc_names[]; #define SLC_NAMES SLC_NAMELIST #endif #define SLC_NAME_OK(x) ((unsigned int)(x) <= NSLC) #define SLC_NAME(x) (SLC_NAME_OK(x)?slc_names[x]:tel_unk(x)) #define SLC_NOSUPPORT 0 #define SLC_CANTCHANGE 1 #define SLC_VARIABLE 2 #define SLC_DEFAULT 3 #define SLC_LEVELBITS 0x03 #define SLC_FUNC 0 #define SLC_FLAGS 1 #define SLC_VALUE 2 #define SLC_ACK 0x80 #define SLC_FLUSHIN 0x40 #define SLC_FLUSHOUT 0x20 #define OLD_ENV_VAR 1 #define OLD_ENV_VALUE 0 #define NEW_ENV_VAR 0 #define NEW_ENV_VALUE 1 #define ENV_ESC 2 #define ENV_USERVAR 3 #define FWDX_SCREEN 0 #define FWDX_OPEN 1 #define FWDX_CLOSE 2 #define FWDX_DATA 3 #define FWDX_OPTIONS 4 #define FWDX_OPT_DATA 5 #define FWDX_XOFF 6 #define FWDX_XON 7 #define FWDX_OPT_NONE 0 #define FWDX_OPT_XAUTH 1 /* * AUTHENTICATION suboptions */ /* * Who is authenticating who ... */ #define AUTH_CLIENT_TO_SERVER 0 /* Client authenticating server */ #define AUTH_SERVER_TO_CLIENT 1 /* Server authenticating client */ #define AUTH_WHO_MASK 1 /* * amount of authentication done */ #define AUTH_HOW_ONE_WAY 0 #define AUTH_HOW_MUTUAL 2 #define AUTH_HOW_MASK 2 /* * should we be encrypting? */ #define AUTH_ENCRYPT_OFF 0 #define AUTH_ENCRYPT_USING_TELOPT 4 #define AUTH_ENCRYPT_AFTER_EXCHANGE 16 #define AUTH_ENCRYPT_START_TLS 20 #define AUTH_ENCRYPT_MASK 20 /* * will we be forwarding? * if we want to activate the use of this flag then * #define USE_INI_CRED_FWD */ #define INI_CRED_FWD_OFF 0 #define INI_CRED_FWD_ON 8 #define INI_CRED_FWD_MASK 8 #define USE_INI_CRED_FWD #define AUTHTYPE_NULL 0 #define AUTHTYPE_KERBEROS_V4 1 #define AUTHTYPE_KERBEROS_V5 2 #define AUTHTYPE_SPX 3 #define AUTHTYPE_MINK 4 #define AUTHTYPE_SRP 5 #define AUTHTYPE_RSA 6 #define AUTHTYPE_SSL 7 #define AUTHTYPE_LOKI 10 #define AUTHTYPE_SSA 11 #define AUTHTYPE_KEA_SJ 12 #define AUTHTYPE_KEA_INTEG 13 #define AUTHTYPE_DSS 14 #define AUTHTYPE_NTLM 15 #define AUTHTYPE_GSSAPI_KRB5 16 /* Not allocated by IANA */ #ifdef AUTHTYPE_CNT #undef AUTHTYPE_CNT #endif /* AUTHTYPE_CNT */ #define AUTHTYPE_CNT 17 /* * AUTHTYPEs Last updated 21 March 1999 * from http://www.isi.edu/in-notes/iana/assignments/telnet-options */ #define AUTHTYPE_AUTO 99 #ifdef AUTH_NAMES char *authtype_names[] = { "NULL", /* RFC 2941 */ "KERBEROS_V4", /* RFC 2941 / 1411 */ "KERBEROS_V5", /* RFC 2941 */ "SPX", /* RFC 2941 (not Internet Standard) */ "MINK", /* RFC 2941 (not Internet Standard) */ "SRP", /* RFC 2944 */ "RSA", /* RFC 2941 (not Internet Standard) */ "SSL", /* RFC 2941 (not Internet Standard) */ "IANA_8", /* not assigned by IANA */ "IANA_9", /* not assigned by IANA */ "LOKI", /* RFC 2941 (not Internet Standard) */ "SSA", /* Schoch */ "KEA_SJ", /* RFC 2951 */ "KEA_SJ_INTEG", /* RFC 2951 */ "DSS", /* RFC 2943 */ "NTLM", /* Kahn */ "GSSAPI-KRB5", /* experimental - altman */ 0 }; char * authmode_names[] = { "CLIENT_TO_SERVER|ONE_WAY", "SERVER_TO_CLIENT|ONE_WAY", "CLIENT_TO_SERVER|MUTUAL", "SERVER_TO_CLIENT|MUTUAL", "CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_USING_TELOPT", "SERVER_TO_CLIENT|ONE_WAY|ENCRYPT_USING_TELOPT", "CLIENT_TO_SERVER|MUTUAL|ENCRYPT_USING_TELOPT", "SERVER_TO_CLIENT|MUTUAL|ENCRYPT_USING_TELOPT", "CLIENT_TO_SERVER|ONE_WAY|CRED_FWD", "SERVER_TO_CLIENT|ONE_WAY|CRED_FWD", "CLIENT_TO_SERVER|MUTUAL|CRED_FWD", "SERVER_TO_CLIENT|MUTUAL|CRED_FWD", "CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_USING_TELOPT|CRED_FWD", "SERVER_TO_CLIENT|ONE_WAY|ENCRYPT_USING_TELOPT|CRED_FWD", "CLIENT_TO_SERVER|MUTUAL|ENCRYPT_USING_TELOPT|CRED_FWD", "SERVER_TO_CLIENT|MUTUAL|ENCRYPT_USING_TELOPT|CRED_FWD", "CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_AFTER_EXCHANGE", "SERVER_TO_CLIENT|ONE_WAY|ENCRYPT_AFTER_EXCHANGE", "CLIENT_TO_SERVER|MUTUAL|ENCRYPT_AFTER_EXCHANGE", "SERVER_TO_CLIENT|MUTUAL|ENCRYPT_AFTER_EXCHANGE", "CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_START_TLS", "SERVER_TO_CLIENT|ONE_WAY|ENCRYPT_START_TLS", "CLIENT_TO_SERVER|MUTUAL|ENCRYPT_START_TLS", "SERVER_TO_CLIENT|MUTUAL|ENCRYPT_START_TLS", "CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_AFTER_EXCHANGE|CRED_FWD", "SERVER_TO_CLIENT|ONE_WAY|ENCRYPT_AFTER_EXCHANGE|CRED_FWD", "CLIENT_TO_SERVER|MUTUAL|ENCRYPT_AFTER_EXCHANGE|CRED_FWD", "SERVER_TO_CLIENT|MUTUAL|ENCRYPT_AFTER_EXCHANGE|CRED_FWD", "CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_START_TLS|CRED_FWD", "SERVER_TO_CLIENT|ONE_WAY|ENCRYPT_START_TLS|CRED_FWD", "CLIENT_TO_SERVER|MUTUAL|ENCRYPT_START_TLS|CRED_FWD", "SERVER_TO_CLIENT|MUTUAL|ENCRYPT_START_TLS|CRED_FWD", 0 }; #else extern char *authtype_names[]; extern char *authmode_names[]; #endif #define AUTHMODE_CNT 32 #define AUTHTYPE_NAME_OK(x) ((unsigned int)(x) < AUTHTYPE_CNT) #define AUTHTYPE_NAME(x) (AUTHTYPE_NAME_OK(x)?authtype_names[x]:tel_unk(x)) #define AUTHMODE_NAME_OK(x) ((unsigned int)(x) < AUTHMODE_CNT) #define AUTHMODE_NAME(x) (AUTHMODE_NAME_OK(x)?authmode_names[x]:tel_unk(x)) /* Kerberos Authentication Message Identifiers */ #define KRB_AUTH 0 /* Authentication data follows */ #define KRB_REJECT 1 /* Rejected (reason might follow) */ #define KRB_ACCEPT 2 /* Accepted */ #define KRB4_CHALLENGE 3 #define KRB4_RESPONSE 4 #define KRB5_RESPONSE 3 /* Response for mutual auth. */ #define KRB5_FORWARD 4 /* Forwarded credentials follow */ #define KRB5_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */ #define KRB5_FORWARD_REJECT 6 /* Forwarded credentials rejected */ #define KRB5_TLS_VERIFY 7 /* TLS Finished Msg verifier */ /* GSSAPI-KRB5 Authentication Message Identifiers */ #define GSS_AUTH_DATA 0 /* Authentication data follows */ #define GSS_REJECT 1 /* Rejected (reason might follow) */ #define GSS_ACCEPT 2 /* Accepted (username might follow) */ #define GSS_CONTINUE 3 /* Secure Remote Password Authentication Message Identifiers */ #define SRP_AUTH 0 /* Authentication data follows */ #define SRP_REJECT 1 /* Rejected (reason might follow) */ #define SRP_ACCEPT 2 /* Accepted */ #define SRP_CHALLENGE 3 #define SRP_RESPONSE 4 #define SRP_EXP 8 /* */ #define SRP_PARAMS 9 /* */ /* Telnet Auth using KEA and SKIPJACK */ #define KEA_CERTA_RA 1 #define KEA_CERTB_RB_IVB_NONCEB 2 #define KEA_IVA_RESPONSEB_NONCEA 3 #define KEA_RESPONSEA 4 /* Tim Hudson's SSL Authentication Message Identifiers */ #define SSL_START 1 #define SSL_ACCEPT 2 #define SSL_REJECT 3 /* Microsoft NTLM Authentication Message Identifiers */ #define NTLM_AUTH 0 #define NTLM_CHALLENGE 1 #define NTLM_RESPONSE 2 #define NTLM_ACCEPT 3 #define NTLM_REJECT 4 /* Generic Constants */ #define AUTH_SUCCESS 0 #define AUTH_FAILURE 255 /* * ENCRYPTion suboptions */ #define ENCRYPT_IS 0 /* I pick encryption type ... */ #define ENCRYPT_SUPPORT 1 /* I support encryption types ... */ #define ENCRYPT_REPLY 2 /* Initial setup response */ #define ENCRYPT_START 3 /* Am starting to send encrypted */ #define ENCRYPT_END 4 /* Am ending encrypted */ #define ENCRYPT_REQSTART 5 /* Request you start encrypting */ #define ENCRYPT_REQEND 6 /* Request you send encrypting */ #define ENCRYPT_ENC_KEYID 7 #define ENCRYPT_DEC_KEYID 8 #define ENCRYPT_CNT 9 #define ENCTYPE_ANY 0 #define ENCTYPE_DES_CFB64 1 #define ENCTYPE_DES_OFB64 2 #define ENCTYPE_DES3_CFB64 3 #define ENCTYPE_DES3_OFB64 4 #define ENCTYPE_CAST5_40_CFB64 8 #define ENCTYPE_CAST5_40_OFB64 9 #define ENCTYPE_CAST128_CFB64 10 #define ENCTYPE_CAST128_OFB64 11 #ifdef ENCTYPE_CNT #undef ENCTYPE_CNT #endif #define ENCTYPE_CNT 12 #ifdef ENCRYPT_NAMES char *encrypt_names[] = { "IS", "SUPPORT", "REPLY", "START", "END", "REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID", 0 }; char *enctype_names[] = { "ANY", "DES_CFB64", /* RFC 2952 */ "DES_OFB64", /* RFC 2953 */ "DES3_CFB64", /* RFC 2947 */ "DES3_OFB64", /* RFC 2948 */ "UNKNOWN-5", "UNKNOWN-6", "UNKNOWN-7", "CAST5_40_CFB64", /* RFC 2950 */ "CAST5_40_OFB64", /* RFC 2949 */ "CAST128_CFB64", /* RFC 2950*/ "CAST128_OFB64", /* RFC 2949 */ 0 }; #else extern char *encrypt_names[]; extern char *enctype_names[]; #endif #define ENCRYPT_NAME_OK(x) ((unsigned int)(x) < ENCRYPT_CNT) #define ENCRYPT_NAME(x) (ENCRYPT_NAME_OK(x)?encrypt_names[x]:tel_unk(x)) #define ENCTYPE_NAME_OK(x) ((unsigned int)(x) < ENCTYPE_CNT) #define ENCTYPE_NAME(x) (ENCTYPE_NAME_OK(x)?enctype_names[x]:tel_unk(x)) /* For setting the state of validUser */ #define AUTH_REJECT 0 /* Rejected */ #define AUTH_UNKNOWN 1 /* We don't know who he is, but he's okay */ #define AUTH_OTHER 2 /* We know him, but not his name */ #define AUTH_USER 3 /* We know he name */ #define AUTH_VALID 4 /* We know him, and he needs no password */ /* Kermit Option Subnegotiations */ #define KERMIT_START 0 #define KERMIT_STOP 1 #define KERMIT_REQ_START 2 #define KERMIT_REQ_STOP 3 #define KERMIT_SOP 4 #define KERMIT_RESP_START 8 #define KERMIT_RESP_STOP 9 /* For SET TELNET AUTH HOW */ #define TN_AUTH_HOW_ANY 0 #define TN_AUTH_HOW_ONE_WAY 1 #define TN_AUTH_HOW_MUTUAL 2 /* For SET TELNET AUTH ENCRYPT */ #define TN_AUTH_ENC_ANY 0 #define TN_AUTH_ENC_NONE 1 #define TN_AUTH_ENC_TELOPT 2 #define TN_AUTH_ENC_EXCH 3 /* not used in Kermit */ #define TN_AUTH_ENC_TLS 4 /* Telnet protocol functions defined in C-Kermit */ _PROTOTYP( int tn_ini, (void) ); /* Telnet protocol support */ _PROTOTYP( int tn_reset, (void)); _PROTOTYP( int tn_set_modes, (void)); _PROTOTYP( int tn_sopt, (int, int) ); _PROTOTYP( int tn_doop, (CHAR, int, int (*)(int) ) ); _PROTOTYP( int tn_sttyp, (void) ); _PROTOTYP( int tn_snenv, (CHAR *, int) ) ; _PROTOTYP( int tn_rnenv, (CHAR *, int) ) ; _PROTOTYP( int tn_wait, (char *) ) ; _PROTOTYP( int tn_push, (void) ) ; _PROTOTYP( int tnsndbrk, (void) ); _PROTOTYP( VOID tn_debug, (char *)); _PROTOTYP( int tn_hex, (CHAR *, int, CHAR *, int)); _PROTOTYP( unsigned char * tn_get_display, (void)); #ifdef IKS_OPTION _PROTOTYP( int tn_siks, (int) ); _PROTOTYP( int iks_wait, (int, int) ); #endif /* IKS_OPTION */ #ifdef CK_NAWS _PROTOTYP( int tn_snaws, (void) ); #endif /* CK_NAWS */ #ifdef CK_XDISPLOC _PROTOTYP( int tn_sxdisploc, (void) ); #endif /* CK_XDISPLOC */ #ifdef CK_SNDLOC _PROTOTYP( int tn_sndloc, (void) ); #endif /* CK_SNDLOC */ /* * The fwdx_parse_displayname function is required if: * CK_FORWARD_X is defined (Telnet X11 forwarding) * SSHBUILTIN is defined (SSH X11 forwarding) * Kermit 95 for Windows supports both, but Kermit 95 for OS/2 only supports * X11 forwarding over SSH. */ #ifdef CK_FORWARD_X #define CK_FWDX_PARSE_DISPN #else /* CK_FORWARD_X */ #ifdef SSHBUILTIN #ifndef CK_FWDX_PARSE_DISPN #define CK_FWDX_PARSE_DISPN #endif /* CK_FWDX_PARSE_DISPN */ #endif /* SSHBUILTIN */ #endif /* CK_FORWARD_X */ #ifdef CK_FORWARD_X /* From Xauth.h */ typedef struct xauth { unsigned short family; unsigned short address_length; char *address; unsigned short number_length; char *number; unsigned short name_length; char *name; unsigned short data_length; char *data; } Xauth; #include #include "ckuusr.h" #include "ckcfnp.h" #endif /* CK_FORWARD_X */ #ifdef CK_FWDX_PARSE_DISPN /* from X.h */ #define FamilyInternet 0 #define FamilyDECnet 1 #define FamilyChaos 2 # define FamilyLocal (256) /* not part of X standard (i.e. X.h) */ # define FamilyWild (65535) # define FamilyNetname (254) /* not part of X standard */ # define FamilyKrb5Principal (253) /* Kerberos 5 principal name */ # define FamilyLocalHost (252) /* for local non-net authentication */ #endif /* CK_FWDX_PARSE_DISPN */ #ifdef CK_FORWARD_X char *XauFileName(); Xauth *XauReadAuth( FILE* /* auth_file */ ); int XauWriteAuth( FILE* /* auth_file */, Xauth* /* auth */ ); Xauth *XauGetAuthByName( const char* /* display_name */ ); Xauth *XauGetAuthByAddr( unsigned int /* family */, unsigned int /* address_length */, const char* /* address */, unsigned int /* number_length */, const char* /* number */, unsigned int /* name_length */, const char* /* name */ ); void XauDisposeAuth( Xauth* /* auth */ ); _PROTOTYP( int fwdx_create_listen_socket,(int)); _PROTOTYP( int fwdx_open_client_channel,(int)); _PROTOTYP( int fwdx_open_server_channel,(VOID)); _PROTOTYP( int fwdx_close_channel,(int)); _PROTOTYP( int fwdx_write_data_to_channel,(int, char *,int)); _PROTOTYP( int fwdx_send_data_from_channel,(int, char *,int)); _PROTOTYP( int fwdx_close_all,(VOID)); _PROTOTYP( int fwdx_tn_sb,(unsigned char *, int)); _PROTOTYP( int tn_sndfwdx, (void)); _PROTOTYP( int fwdx_send_close,(int)); _PROTOTYP( int fwdx_send_open,(int)); _PROTOTYP( int fwdx_client_reply_options,(char *, int)); _PROTOTYP( int fwdx_send_options,(VOID)); _PROTOTYP( VOID fwdx_check_sockets,(fd_set *)); _PROTOTYP( int fwdx_init_fd_set,(fd_set *)); _PROTOTYP( int fwdx_authorize_channel, (int, unsigned char *, int)); _PROTOTYP( int fwdx_create_fake_xauth, (char *, int, int)); _PROTOTYP( int fwdx_send_xauth_to_xserver, (int, unsigned char *, int len)); _PROTOTYP( int fwdx_server_avail, (VOID)); #ifdef NT _PROTOTYP( VOID fwdx_thread,(VOID *)); #endif /* NT */ #endif /* CK_FORWARD_X */ #ifdef CK_FWDX_PARSE_DISPN /* This function is used for SSH X11 forwarding which works * whether or not Telnet X11 forwarding is supported. */ _PROTOTYP( int fwdx_parse_displayname, (char *, int *, char **, int *, int *, char **)); #endif /* FWDX_PARSE_DISPN */ #ifdef TN_COMPORT #define TNC_C2S_SIGNATURE 0 #define TNC_C2S_SET_BAUDRATE 1 #define TNC_C2S_SET_DATASIZE 2 #define TNC_C2S_SET_PARITY 3 #define TNC_C2S_SET_STOPSIZE 4 #define TNC_C2S_SET_CONTROL 5 #define TNC_C2S_NOTIFY_LINESTATE 6 #define TNC_C2S_NOTIFY_MODEMSTATE 7 #define TNC_C2S_FLOW_SUSPEND 8 #define TNC_C2S_FLOW_RESUME 9 #define TNC_C2S_SET_LS_MASK 10 #define TNC_C2S_SET_MS_MASK 11 #define TNC_C2S_PURGE 12 #define TNC_S2C_SIGNATURE 100 #define TNC_S2C_SET_BAUDRATE 101 #define TNC_S2C_SET_DATASIZE 102 #define TNC_S2C_SET_PARITY 103 #define TNC_S2C_SET_STOPSIZE 104 #define TNC_S2C_SET_CONTROL 105 #define TNC_S2C_SEND_LS 106 #define TNC_S2C_SEND_MS 107 #define TNC_S2C_FLOW_SUSPEND 108 #define TNC_S2C_FLOW_RESUME 109 #define TNC_S2C_SET_LS_MASK 110 #define TNC_S2C_SET_MS_MASK 111 #define TNC_S2C_PURGE 112 /* The COMPORT values are not defined in RFC 2217 */ #define TNC_BPS_REQUEST 0 #define TNC_BPS_300 3 #define TNC_BPS_600 4 #define TNC_BPS_1200 5 #define TNC_BPS_2400 6 #define TNC_BPS_4800 7 #define TNC_BPS_9600 8 #define TNC_BPS_14400 9 #define TNC_BPS_19200 10 #define TNC_BPS_28800 11 #define TNC_BPS_38400 12 #define TNC_BPS_57600 13 #define TNC_BPS_115200 14 #define TNC_BPS_230400 15 #define TNC_BPS_460800 16 #define TNC_DS_REQUEST 0 #define TNC_DS_5 5 #define TNC_DS_6 6 #define TNC_DS_7 7 #define TNC_DS_8 8 #define TNC_PAR_REQUEST 0 #define TNC_PAR_NONE 1 #define TNC_PAR_ODD 2 #define TNC_PAR_EVEN 3 #define TNC_PAR_MARK 4 #define TNC_PAR_SPACE 5 #define TNC_SB_REQUEST 0 #define TNC_SB_1 1 #define TNC_SB_1_5 3 #define TNC_SB_2 2 #define TNC_CTL_OFLOW_REQUEST 0 #define TNC_CTL_OFLOW_NONE 1 #define TNC_CTL_OFLOW_XON_XOFF 2 #define TNC_CTL_OFLOW_RTS_CTS 3 #define TNC_CTL_OFLOW_DCD 17 #define TNC_CTL_OFLOW_DSR 19 #define TNC_CTL_BREAK_REQUEST 4 #define TNC_CTL_BREAK_ON 5 #define TNC_CTL_BREAK_OFF 6 #define TNC_CTL_DTR_REQUEST 7 #define TNC_CTL_DTR_ON 8 #define TNC_CTL_DTR_OFF 9 #define TNC_CTL_RTS_REQUEST 10 #define TNC_CTL_RTS_ON 11 #define TNC_CTL_RTS_OFF 12 #define TNC_CTL_IFLOW_REQUEST 13 #define TNC_CTL_IFLOW_NONE 14 #define TNC_CTL_IFLOW_XON_XOFF 15 #define TNC_CTL_IFLOW_RTS_CTS 16 #define TNC_CTL_IFLOW_DTR 18 #define TNC_MS_DATA_READY 1 #define TNC_MS_OVERRUN_ERROR 2 #define TNC_MS_PARITY_ERROR 4 #define TNC_MS_FRAME_ERROR 8 #define TNC_MS_BREAK_ERROR 16 #define TNC_MS_HR_EMPTY 32 #define TNC_MS_SR_EMPTY 64 #define TNC_MS_TIMEOUT_ERROR 128 #define TNC_MS_CTS_DELTA 1 #define TNC_MS_DSR_DELTA 2 #define TNC_MS_EDGE_RING 4 #define TNC_MS_RLSD_DELTA 8 #define TNC_MS_CTS_SIG 16 #define TNC_MS_DSR_SIG 32 #define TNC_MS_RI_SIG 64 #define TNC_MS_RLSD_SIG 128 #define TNC_PURGE_RECEIVE 1 #define TNC_PURGE_TRANSMIT 2 #define TNC_PURGE_BOTH 3 #ifdef TNC_NAMES char *tnc_names[] = { "SIGNATURE", "SET-BAUDRATE", "SET-DATARATE", "SET-PARITY", "SET-STOPSIZE", "SET-CONTROL", "NOTIFY-LINESTATE", "NOTIFY-MODEMSTATE", "FLOWCONTROL-SUSPEND", "FLOWCONTROL-RESUME", "SET-LINESTATE-MASK", "SET-MODEMSTATE-MASK", "PURGE-DATA", 0 }; #else extern char *tnc_names[]; #endif #define TNC_NAME_OK(x) ((x) >= 0 && (x) <= 12 || (x) >= 100 && (x) <= 112) #define TNC_NAME(x) \ (TNC_NAME_OK(x)?tnc_names[(x)>=100?(x)-100:(x)]:tel_unk(x)) _PROTOTYP(int tnc_init,(void)); _PROTOTYP(int tnc_wait,(CHAR *, int)); _PROTOTYP(int tnc_tn_sb,(CHAR *,int)); _PROTOTYP(CONST char * tnc_get_signature, (void)); _PROTOTYP(int tnc_send_signature, (char *)); _PROTOTYP(int tnc_set_baud,(long)); _PROTOTYP(int tnc_get_baud,(void)); _PROTOTYP(int tnc_set_datasize,(int)); _PROTOTYP(int tnc_get_datasize,(void)); _PROTOTYP(int tnc_set_parity,(int)); _PROTOTYP(int tnc_get_parity,(void)); _PROTOTYP(int tnc_set_stopsize,(int)); _PROTOTYP(int tnc_get_stopsize,(void)); _PROTOTYP(int tnc_set_oflow,(int)); _PROTOTYP(int tnc_get_oflow,(void)); _PROTOTYP(int tnc_set_iflow,(int)); _PROTOTYP(int tnc_get_iflow,(void)); _PROTOTYP(int tnc_set_break_state,(int)); _PROTOTYP(int tnc_get_break_state,(void)); _PROTOTYP(int tnc_set_dtr_state,(int)); _PROTOTYP(int tnc_get_dtr_state,(void)); _PROTOTYP(int tnc_set_rts_state,(int)); _PROTOTYP(int tnc_get_rts_state,(void)); _PROTOTYP(int tnc_set_ls_mask,(int)); _PROTOTYP(int tnc_get_ls_mask,(void)); _PROTOTYP(int tnc_get_ls,(void)); _PROTOTYP(int tnc_set_ms_mask,(int)); _PROTOTYP(int tnc_get_ms_mask,(void)); _PROTOTYP(int tnc_get_ms,(void)); _PROTOTYP(int tnc_send_purge_data,(int)); _PROTOTYP(int tnc_flow_suspended,(void)); _PROTOTYP(int tnc_suspend_flow,(void)); _PROTOTYP(int tnc_resume_flow,(void)); /* The following methods are to be called by ck?tio.c routines */ _PROTOTYP(int tnsetflow,(int)); _PROTOTYP(int tnsettings,(int,int)); _PROTOTYP(int tngmdm,(void)); _PROTOTYP(int tnsndb,(long)); _PROTOTYP(int istncomport,(void)); _PROTOTYP(int tn_sndcomport,(void)); #endif /* TN_COMPORT */ #ifndef CKCTEL_C /* These are declared in ckctel.c */ extern int tn_init; /* Telnet protocol initialized flag */ extern char *tn_term; /* Terminal type override */ extern int sstelnet; /* Server side telnet? */ extern int tn_deb; /* Telnet option debugging flag */ extern int tn_auth_krb5_des_bug; /* Telnet BUG */ #endif /* CKCTEL_C */ #define TN_MSG_LEN 12292 #endif /* TNCODE */ #endif /* CKCTEL_H */ ckcuni.c000664 045065 024037 00002746575 14767401776 012660 0ustar00fdckermit000000 000000 char * ckcuni = "Unicode support 10.0.116, 23 Sep 2022"; #ifdef OS2 #define KERMITFONT #endif /* OS2 */ /* C K C U N I . C -- Unicode/Terminal character-set translations */ /* Copyright (C) 1999, 2022, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Authors: Frank da Cruz The Kermit Project, New York City. Jeffrey E Altman Secure Endpoints Inc., New York City Functions u_blah() translate from blah to Unicode (incoming material). Functions tx_blah() translate from Unicode to blah (keystrokes). Function pointers are kept in parallel arrays indexed by TX_blah values defined in ckcuni.h. NOTE: tx_decspec and tx_dectech are undefined since these character sets are never typed, only displayed. The blah_u() routines accept an unsigned character value in character-set blah, and return the Unicode translation, or 0xfffd if the character is not defined in Unicode. The 8th bit of the argument should be ignored, a`la ISO 4873 and 2022. The tx_blah() routines accept a unicode value and return the value of the corresponding character in character-set blah, or else -1 if the character does not exist in blah. In this case, the full 8-bit value is returned, since ISO 2022 only works in the host-to-terminal direction. NOTE: KERMITFONT should be defined only if we are using the new (still hypothetical) Kermit font that has all the VT/Heath/Wyse/TVI graphic characters in it. IMPORTANT: all Kermitfont code points need updating to the values in the final proposal to the UTC. LATER NOTE: The needed characters were approved for Unicode 3.1, and therefore nothing special should be required to use them, except that it will take some time for them to show up in commercial fonts. TO DO: A lot of the functions can be tightened up -- use ranges when possible, sort switch statements in order of frequency, etc. */ #include "ckcsym.h" /* Includes... */ #include "ckcdeb.h" #include "ckcker.h" #include "ckucmd.h" #include "ckcxla.h" #include "ckuxla.h" #include "ckuusr.h" #include "ckcnet.h" /* struct sockaddr */ #include "ckcfnp.h" /* Prototypes (must be last) */ #ifdef UNICODE #ifdef OS2 /* This material is needed for the integration of TextPS into Kermit 95. When printing a file we use the SET FILE CHARACTER-SET value as the input character-set and then convert it to the special Latin1 set called CourierLatin1 using the Unicode translation functions. */ struct _pair { int tx; int fc; } TXFC[] = { TX_ASCII, FC_USASCII, TX_BRITISH, FC_UKASCII, TX_CN_FRENCH, FC_FCASCII, TX_CP437, FC_CP437, TX_CP850, FC_CP850, TX_CP852, FC_CP852, TX_CP857, -2, TX_CP862, FC_CP862, TX_CP864, -2, TX_CP866, FC_CP866, TX_CP869, -2, TX_CUBAN, -2, TX_CZECH, -2, TX_DANISH, -2, TX_DECMCS, FC_DECMCS, TX_DECSPEC, -2, /* while defined, not in fcs tables */ TX_DECTECH, -2, /* while defined, not in fcs tables */ TX_DGI, FC_DGMCS, TX_DUTCH, FC_DUASCII, TX_FINNISH, FC_FIASCII, TX_FRENCH, FC_FRASCII, TX_GERMAN, FC_GEASCII, TX_HE7, FC_HE7, TX_HPR8, FC_HPR8, TX_HUNGARIAN, FC_HUASCII, TX_ITALIAN, FC_ITASCII, TX_J201R, -2, TX_J201K, -2, TX_KOI7, FC_KOI7, TX_KOI8, FC_KOI8, TX_KOI8R, FC_KOI8R, TX_KOI8U, FC_KOI8U, TX_8859_1, FC_1LATIN, TX_8859_2, FC_2LATIN, TX_8859_3, -2, TX_8859_4, -2, TX_8859_5, FC_CYRILL, TX_8859_6, -2, TX_8859_7, -2, TX_8859_8, FC_HEBREW, TX_8859_9, -2, TX_8859_10, -2, TX_8859_15, -2, TX_MACL1, FC_APPQD, TX_NEXT, FC_NEXT, TX_NORWEGIAN, FC_NOASCII, TX_PORTUGUESE, FC_POASCII, TX_SPANISH, FC_SPASCII, TX_SWEDISH, FC_SWASCII, TX_SWISS, FC_CHASCII, TX_ICELANDIC, -2, TX_JIS7, -2, TX_SHJIS, FC_SHJIS, TX_JEUC, FC_JEUC, TX_JDEC, FC_JDEC, TX_ELOT927, FC_ELOT, TX_DGPCGRPH, -2, TX_DGLDGRPH, -2, TX_DGWPGRPH, -2, TX_HPLINE, -2, TX_HPMATH, -2, TX_QNXGRPH, -2, TX_SNIBRACK, -2, TX_SNIEURO, -2, TX_SNIFACET, -2, TX_SNIIBM, -2, TX_SNIBLANK, -2, TX_CP1252, -2, TX_CP1250, FC_CP1250, TX_CP1251, FC_CP1251, TX_CP1253, -2, TX_CP1254, -2, TX_CP1257, -2, TX_CP856, -2, TX_CP855, FC_CP855, TX_CP819, FC_1LATIN, TX_CP912, FC_2LATIN, TX_CP913, -2, TX_CP914, -2, TX_CP915, FC_CYRILL, TX_CP1089, -2, TX_CP813, FC_GREEK, TX_CP916, FC_HEBREW, TX_CP920, -2, TX_CP1051, -2, TX_CP858, FC_CP858, TX_8859_15, FC_9LATIN, TX_CP923, FC_CP923, TX_ELOT928, -2, TX_CP10000, -2, TX_CP37, -2, TX_CP1255, -2, TX_CP1256, -2, TX_CP1258, -2, TX_MAZOVIA, FC_MAZOVIA, TX_APL1, -2, TX_APL2, -2, TX_APL3, -2, TX_APL4, -2, TX_APL5, -2, TX_TRANSP, FC_TRANSP }; int nTXFC = sizeof(TXFC) / sizeof(struct _pair); int #ifdef CK_ANSIC fc2tx(int fc) #else fc2tx(int c) int fc; #endif /* CK_ANSIC */ { int i; for (i = 0; i < nTXFC ; i++) if (TXFC[i].fc == fc && TXFC[i].tx >= 0) return(TXFC[i].tx); return(TX_ASCII); } int #ifdef CK_ANSIC tx2fc(int tx) #else tx2fc(int x) int tx; #endif /* CK_ANSIC */ { int i; for (i = 0; i < nTXFC ; i++) if (TXFC[i].tx == tx && TXFC[i].fc >= 0) return(TXFC[i].fc); return(FC_USASCII); } /* SET TERMINAL REMOTE CHARACTER-SET keyword table */ struct keytab txrtab[] = { "apl2-ibm", TX_APL4, 0, "apl-2741", TX_APL5, 0, "apl-dyadic", TX_APL2, 0, "apl-iso", TX_APL1, 0, "apl-plus-2000", TX_APL3, 0, /* = APL-2000 */ "arabic-iso", TX_8859_6, 0, "ascii", TX_ASCII, 0, "british", TX_BRITISH, 0, "canadian-french", TX_CN_FRENCH, 0, "bulgaria-pc", TX_CP856, 0, #ifdef COMMENT "cp037", TX_CP37, 0, /* U.S. EBCDIC */ #endif /* COMMENT */ "cp10000", TX_CP10000, 0, /* Apple Quickdraw */ "cp1051", TX_CP1051, 0, /* Same as HP Roman 8 */ "cp1089", TX_CP1089, 0, /* Same as ISO 8859-6 */ "cp1250", TX_CP1250, 0, /* Latin-2 Windows */ "cp1251", TX_CP1251, 0, /* Cyrillic Windows */ "cp1252", TX_CP1252, 0, /* Latin-1 Windows */ "cp1253", TX_CP1253, 0, /* Greek Windows */ "cp1254", TX_CP1254, 0, /* Turkey Windows */ "cp1255", TX_CP1255, 0, /* Hebrew Windows */ "cp1256", TX_CP1256, 0, /* Arabic Windows */ "cp1257", TX_CP1257, 0, /* Latin-4 Windows */ "cp1258", TX_CP1258, 0, /* Viet Nam Windows */ "cp437", TX_CP437, 0, "cp813", TX_CP813, 0, /* Same as ISO 8859-7 */ "cp819", TX_CP819, 0, /* Same as ISO 8859-1 */ "cp850", TX_CP850, 0, "cp852", TX_CP852, 0, "cp855", TX_CP855, 0, /* Cyrillic */ "cp856", TX_CP856, CM_INV, /* Bulgaria */ "cp857", TX_CP857, 0, /* Latin-5 */ "cp858", TX_CP858, 0, /* Euro modified cp850 */ "cp862-hebrew", TX_CP862, 0, /* Hebrew */ "cp864", TX_CP864, 0, /* Arabic */ "cp866", TX_CP866, 0, /* Cyrillic */ "cp869", TX_CP869, 0, /* Greek */ "cp912", TX_CP912, 0, /* Same as ISO 8859-2 */ "cp913", TX_CP913, 0, /* Same as ISO 8859-3 */ "cp914", TX_CP914, 0, /* Same as ISO 8859-4 */ "cp915", TX_CP915, 0, /* Same as ISO 8859-5 */ "cp916", TX_CP916, 0, /* Same as ISO 8859-8 */ "cp920", TX_CP920, 0, /* Same as ISO 8859-9 */ "cp923", TX_CP923, 0, /* Same as ISO 8859-15 */ #ifdef COMMENT /* Not implemented yet */ "cuban", TX_CUBAN, 0, #endif /* COMMENT */ "cyrillic-iso", TX_8859_5, 0, #ifdef COMMENT /* Not implemented yet */ "czech", TX_CZECH, 0, #endif /* COMMENT */ "danish", TX_DANISH, 0, "dec-m", TX_DECMCS, CM_ABR|CM_INV, "dec-mcs", TX_DECMCS, CM_INV, "dec-multinational",TX_DECMCS, 0, #ifdef COMMENT /* Not implemented yet */ "dec-kanji", TX_JDEC, 0, #endif /* COMMENT */ "dec-special", TX_DECSPEC, 0, "dec-technical", TX_DECTECH, 0, "dg-international", TX_DGI, 0, "dg-linedrawing", TX_DGLDGRPH, 0, "dg-specialgraphcs",TX_DGPCGRPH, 0, "dg-wordprocessing",TX_DGWPGRPH, 0, "dutch", TX_DUTCH, 0, "elot927-greek", TX_ELOT927, 0, "elot928-greek", TX_ELOT928, 0, "finnish", TX_FINNISH, 0, "french", TX_FRENCH, 0, "german", TX_GERMAN, 0, "greek-iso", TX_8859_7, 0, "hebrew-7", TX_HE7, 0, "hebrew-iso", TX_8859_8, 0, "hp-line-drawing", TX_HPLINE, 0, "hp-math/technical",TX_HPMATH, 0, "hp-roman8", TX_HPR8, 0, "hungarian", TX_HUNGARIAN, 0, "italian", TX_ITALIAN, 0, "japanese-roman", TX_J201R, 0, #ifdef COMMENT /* Not implemented yet */ "japanese-euc", TX_JEUC, 0, "jis7-kanji", TX_JIS7, 0, #endif /* COMMENT */ "katakana", TX_J201K, 0, "ko", TX_KOI8, CM_ABR|CM_INV, "koi", TX_KOI8, CM_ABR|CM_INV, "koi8", TX_KOI8, 0, "koi8-cyrillic", TX_KOI8, CM_INV, "koi8r", TX_KOI8R, 0, "koi8u", TX_KOI8U, 0, "l", TX_8859_1, CM_ABR|CM_INV, "la", TX_8859_1, CM_ABR|CM_INV, "lat", TX_8859_1, CM_ABR|CM_INV, "lati", TX_8859_1, CM_ABR|CM_INV, "latin", TX_8859_1, CM_ABR|CM_INV, "latin1-iso", TX_8859_1, 0, "latin2-iso", TX_8859_2, 0, "latin3-iso", TX_8859_3, 0, "latin4-iso", TX_8859_4, 0, "latin5-iso", TX_8859_9, 0, "latin6-iso", TX_8859_10, 0, "latin9-iso", TX_8859_15, 0, "macintosh-latin", TX_MACL1, 0, "mazovia-pc", TX_MAZOVIA, 0, "next-multinational",TX_NEXT, 0, "norwegian", TX_NORWEGIAN, 0, "portuguese", TX_PORTUGUESE, 0, "qnx-console", TX_QNXGRPH, 0, #ifdef COMMENT /* Not implemented yet */ "shift-jis", TX_SHJIS, 0, #endif /* COMMENT */ "short-koi", TX_KOI7, 0, "sni-blanks", TX_SNIBLANK, 0, "sni-brackets", TX_SNIBRACK, 0, "sni-euro", TX_SNIEURO, 0, "sni-facet", TX_SNIFACET, 0, "sni-ibm", TX_SNIIBM, 0, "spanish", TX_SPANISH, 0, "swedish", TX_SWEDISH, 0, "swiss", TX_SWISS, 0, "transparent", TX_TRANSP, 0, #ifdef COMMENT "utf7", TX_UTF7, 0, #endif /* COMMENT */ "utf-8", TX_UTF8, CM_INV, "utf8", TX_UTF8, 0, "", 0, 0 }; int ntxrtab = sizeof(txrtab)/sizeof(struct keytab) - 1; #endif /* OS2 */ #ifdef KANJI /* All Kanji/Unicode translations are based on the Unicode 3.0 Shift-JIS mapping. Other character sets, like EUC-JP, JIS-7, etc, are transformed algorithmically to/from Shift-JIS before/after conversion to/from Unicode. This is because Kanji/Unicode mapping tables add about 120K to the program, and we don't want to do this for each Kanji character set. */ static USHORT /* Shift-JIS to Unicode */ sju_8140[] = { /* 0x8140 thru 0x9ffc */ 0x3000, 0x3001, 0x3002, 0xff0c, 0xff0e, 0x30fb, 0xff1a, 0xff1b, 0xff1f, 0xff01, 0x309b, 0x309c, 0x00b4, 0xff40, 0x00a8, 0xff3e, 0xffe3, 0xff3f, 0x30fd, 0x30fe, 0x309d, 0x309e, 0x3003, 0x4edd, 0x3005, 0x3006, 0x3007, 0x30fc, 0x2015, 0x2010, 0xff0f, 0x005c, 0x301c, 0x2016, 0xff5c, 0x2026, 0x2025, 0x2018, 0x2019, 0x201c, 0x201d, 0xff08, 0xff09, 0x3014, 0x3015, 0xff3b, 0xff3d, 0xff5b, 0xff5d, 0x3008, 0x3009, 0x300a, 0x300b, 0x300c, 0x300d, 0x300e, 0x300f, 0x3010, 0x3011, 0xff0b, 0x2212, 0x00b1, 0x00d7, 0xfffd, 0x00f7, 0xff1d, 0x2260, 0xff1c, 0xff1e, 0x2266, 0x2267, 0x221e, 0x2234, 0x2642, 0x2640, 0x00b0, 0x2032, 0x2033, 0x2103, 0xffe5, 0xff04, 0x00a2, 0x00a3, 0xff05, 0xff03, 0xff06, 0xff0a, 0xff20, 0x00a7, 0x2606, 0x2605, 0x25cb, 0x25cf, 0x25ce, 0x25c7, 0x25c6, 0x25a1, 0x25a0, 0x25b3, 0x25b2, 0x25bd, 0x25bc, 0x203b, 0x3012, 0x2192, 0x2190, 0x2191, 0x2193, 0x3013, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2208, 0x220b, 0x2286, 0x2287, 0x2282, 0x2283, 0x222a, 0x2229, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2227, 0x2228, 0x00ac, 0x21d2, 0x21d4, 0x2200, 0x2203, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2220, 0x22a5, 0x2312, 0x2202, 0x2207, 0x2261, 0x2252, 0x226a, 0x226b, 0x221a, 0x223d, 0x221d, 0x2235, 0x222b, 0x222c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x212b, 0x2030, 0x266f, 0x266d, 0x266a, 0x2020, 0x2021, 0x00b6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x25ef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xff10, 0xff11, 0xff12, 0xff13, 0xff14, 0xff15, 0xff16, 0xff17, 0xff18, 0xff19, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xff21, 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, 0xff28, 0xff29, 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, 0xff30, 0xff31, 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, 0xff38, 0xff39, 0xff3a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, 0xff58, 0xff59, 0xff5a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x3041, 0x3042, 0x3043, 0x3044, 0x3045, 0x3046, 0x3047, 0x3048, 0x3049, 0x304a, 0x304b, 0x304c, 0x304d, 0x304e, 0x304f, 0x3050, 0x3051, 0x3052, 0x3053, 0x3054, 0x3055, 0x3056, 0x3057, 0x3058, 0x3059, 0x305a, 0x305b, 0x305c, 0x305d, 0x305e, 0x305f, 0x3060, 0x3061, 0x3062, 0x3063, 0x3064, 0x3065, 0x3066, 0x3067, 0x3068, 0x3069, 0x306a, 0x306b, 0x306c, 0x306d, 0x306e, 0x306f, 0x3070, 0x3071, 0x3072, 0x3073, 0x3074, 0x3075, 0x3076, 0x3077, 0x3078, 0x3079, 0x307a, 0x307b, 0x307c, 0x307d, 0x307e, 0x307f, 0x3080, 0x3081, 0x3082, 0x3083, 0x3084, 0x3085, 0x3086, 0x3087, 0x3088, 0x3089, 0x308a, 0x308b, 0x308c, 0x308d, 0x308e, 0x308f, 0x3090, 0x3091, 0x3092, 0x3093, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x30a1, 0x30a2, 0x30a3, 0x30a4, 0x30a5, 0x30a6, 0x30a7, 0x30a8, 0x30a9, 0x30aa, 0x30ab, 0x30ac, 0x30ad, 0x30ae, 0x30af, 0x30b0, 0x30b1, 0x30b2, 0x30b3, 0x30b4, 0x30b5, 0x30b6, 0x30b7, 0x30b8, 0x30b9, 0x30ba, 0x30bb, 0x30bc, 0x30bd, 0x30be, 0x30bf, 0x30c0, 0x30c1, 0x30c2, 0x30c3, 0x30c4, 0x30c5, 0x30c6, 0x30c7, 0x30c8, 0x30c9, 0x30ca, 0x30cb, 0x30cc, 0x30cd, 0x30ce, 0x30cf, 0x30d0, 0x30d1, 0x30d2, 0x30d3, 0x30d4, 0x30d5, 0x30d6, 0x30d7, 0x30d8, 0x30d9, 0x30da, 0x30db, 0x30dc, 0x30dd, 0x30de, 0x30df, 0xfffd, 0x30e0, 0x30e1, 0x30e2, 0x30e3, 0x30e4, 0x30e5, 0x30e6, 0x30e7, 0x30e8, 0x30e9, 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ee, 0x30ef, 0x30f0, 0x30f1, 0x30f2, 0x30f3, 0x30f4, 0x30f5, 0x30f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, 0x03a0, 0x03a1, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0401, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0451, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0xfffd, 0x043e, 0x043f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2500, 0x2502, 0x250c, 0x2510, 0x2518, 0x2514, 0x251c, 0x252c, 0x2524, 0x2534, 0x253c, 0x2501, 0x2503, 0x250f, 0x2513, 0x251b, 0x2517, 0x2523, 0x2533, 0x252b, 0x253b, 0x254b, 0x2520, 0x252f, 0x2528, 0x2537, 0x253f, 0x251d, 0x2530, 0x2525, 0x2538, 0x2542, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x4e9c, 0x5516, 0x5a03, 0x963f, 0x54c0, 0x611b, 0x6328, 0x59f6, 0x9022, 0x8475, 0x831c, 0x7a50, 0x60aa, 0x63e1, 0x6e25, 0x65ed, 0x8466, 0x82a6, 0x9bf5, 0x6893, 0x5727, 0x65a1, 0x6271, 0x5b9b, 0x59d0, 0x867b, 0x98f4, 0x7d62, 0x7dbe, 0x9b8e, 0x6216, 0x7c9f, 0x88b7, 0x5b89, 0x5eb5, 0x6309, 0x6697, 0x6848, 0x95c7, 0x978d, 0x674f, 0x4ee5, 0x4f0a, 0x4f4d, 0x4f9d, 0x5049, 0x56f2, 0x5937, 0x59d4, 0x5a01, 0x5c09, 0x60df, 0x610f, 0x6170, 0x6613, 0x6905, 0x70ba, 0x754f, 0x7570, 0x79fb, 0x7dad, 0x7def, 0x80c3, 0x840e, 0x8863, 0x8b02, 0x9055, 0x907a, 0x533b, 0x4e95, 0x4ea5, 0x57df, 0x80b2, 0x90c1, 0x78ef, 0x4e00, 0x58f1, 0x6ea2, 0x9038, 0x7a32, 0x8328, 0x828b, 0x9c2f, 0x5141, 0x5370, 0x54bd, 0x54e1, 0x56e0, 0x59fb, 0x5f15, 0x98f2, 0x6deb, 0x80e4, 0x852d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9662, 0x9670, 0x96a0, 0x97fb, 0x540b, 0x53f3, 0x5b87, 0x70cf, 0x7fbd, 0x8fc2, 0x96e8, 0x536f, 0x9d5c, 0x7aba, 0x4e11, 0x7893, 0x81fc, 0x6e26, 0x5618, 0x5504, 0x6b1d, 0x851a, 0x9c3b, 0x59e5, 0x53a9, 0x6d66, 0x74dc, 0x958f, 0x5642, 0x4e91, 0x904b, 0x96f2, 0x834f, 0x990c, 0x53e1, 0x55b6, 0x5b30, 0x5f71, 0x6620, 0x66f3, 0x6804, 0x6c38, 0x6cf3, 0x6d29, 0x745b, 0x76c8, 0x7a4e, 0x9834, 0x82f1, 0x885b, 0x8a60, 0x92ed, 0x6db2, 0x75ab, 0x76ca, 0x99c5, 0x60a6, 0x8b01, 0x8d8a, 0x95b2, 0x698e, 0x53ad, 0x5186, 0xfffd, 0x5712, 0x5830, 0x5944, 0x5bb4, 0x5ef6, 0x6028, 0x63a9, 0x63f4, 0x6cbf, 0x6f14, 0x708e, 0x7114, 0x7159, 0x71d5, 0x733f, 0x7e01, 0x8276, 0x82d1, 0x8597, 0x9060, 0x925b, 0x9d1b, 0x5869, 0x65bc, 0x6c5a, 0x7525, 0x51f9, 0x592e, 0x5965, 0x5f80, 0x5fdc, 0x62bc, 0x65fa, 0x6a2a, 0x6b27, 0x6bb4, 0x738b, 0x7fc1, 0x8956, 0x9d2c, 0x9d0e, 0x9ec4, 0x5ca1, 0x6c96, 0x837b, 0x5104, 0x5c4b, 0x61b6, 0x81c6, 0x6876, 0x7261, 0x4e59, 0x4ffa, 0x5378, 0x6069, 0x6e29, 0x7a4f, 0x97f3, 0x4e0b, 0x5316, 0x4eee, 0x4f55, 0x4f3d, 0x4fa1, 0x4f73, 0x52a0, 0x53ef, 0x5609, 0x590f, 0x5ac1, 0x5bb6, 0x5be1, 0x79d1, 0x6687, 0x679c, 0x67b6, 0x6b4c, 0x6cb3, 0x706b, 0x73c2, 0x798d, 0x79be, 0x7a3c, 0x7b87, 0x82b1, 0x82db, 0x8304, 0x8377, 0x83ef, 0x83d3, 0x8766, 0x8ab2, 0x5629, 0x8ca8, 0x8fe6, 0x904e, 0x971e, 0x868a, 0x4fc4, 0x5ce8, 0x6211, 0x7259, 0x753b, 0x81e5, 0x82bd, 0x86fe, 0x8cc0, 0x96c5, 0x9913, 0x99d5, 0x4ecb, 0x4f1a, 0x89e3, 0x56de, 0x584a, 0x58ca, 0x5efb, 0x5feb, 0x602a, 0x6094, 0x6062, 0x61d0, 0x6212, 0x62d0, 0x6539, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b41, 0x6666, 0x68b0, 0x6d77, 0x7070, 0x754c, 0x7686, 0x7d75, 0x82a5, 0x87f9, 0x958b, 0x968e, 0x8c9d, 0x51f1, 0x52be, 0x5916, 0x54b3, 0x5bb3, 0x5d16, 0x6168, 0x6982, 0x6daf, 0x788d, 0x84cb, 0x8857, 0x8a72, 0x93a7, 0x9ab8, 0x6d6c, 0x99a8, 0x86d9, 0x57a3, 0x67ff, 0x86ce, 0x920e, 0x5283, 0x5687, 0x5404, 0x5ed3, 0x62e1, 0x64b9, 0x683c, 0x6838, 0x6bbb, 0x7372, 0x78ba, 0x7a6b, 0x899a, 0x89d2, 0x8d6b, 0x8f03, 0x90ed, 0x95a3, 0x9694, 0x9769, 0x5b66, 0x5cb3, 0x697d, 0x984d, 0x984e, 0x639b, 0x7b20, 0x6a2b, 0xfffd, 0x6a7f, 0x68b6, 0x9c0d, 0x6f5f, 0x5272, 0x559d, 0x6070, 0x62ec, 0x6d3b, 0x6e07, 0x6ed1, 0x845b, 0x8910, 0x8f44, 0x4e14, 0x9c39, 0x53f6, 0x691b, 0x6a3a, 0x9784, 0x682a, 0x515c, 0x7ac3, 0x84b2, 0x91dc, 0x938c, 0x565b, 0x9d28, 0x6822, 0x8305, 0x8431, 0x7ca5, 0x5208, 0x82c5, 0x74e6, 0x4e7e, 0x4f83, 0x51a0, 0x5bd2, 0x520a, 0x52d8, 0x52e7, 0x5dfb, 0x559a, 0x582a, 0x59e6, 0x5b8c, 0x5b98, 0x5bdb, 0x5e72, 0x5e79, 0x60a3, 0x611f, 0x6163, 0x61be, 0x63db, 0x6562, 0x67d1, 0x6853, 0x68fa, 0x6b3e, 0x6b53, 0x6c57, 0x6f22, 0x6f97, 0x6f45, 0x74b0, 0x7518, 0x76e3, 0x770b, 0x7aff, 0x7ba1, 0x7c21, 0x7de9, 0x7f36, 0x7ff0, 0x809d, 0x8266, 0x839e, 0x89b3, 0x8acc, 0x8cab, 0x9084, 0x9451, 0x9593, 0x9591, 0x95a2, 0x9665, 0x97d3, 0x9928, 0x8218, 0x4e38, 0x542b, 0x5cb8, 0x5dcc, 0x73a9, 0x764c, 0x773c, 0x5ca9, 0x7feb, 0x8d0b, 0x96c1, 0x9811, 0x9854, 0x9858, 0x4f01, 0x4f0e, 0x5371, 0x559c, 0x5668, 0x57fa, 0x5947, 0x5b09, 0x5bc4, 0x5c90, 0x5e0c, 0x5e7e, 0x5fcc, 0x63ee, 0x673a, 0x65d7, 0x65e2, 0x671f, 0x68cb, 0x68c4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x6a5f, 0x5e30, 0x6bc5, 0x6c17, 0x6c7d, 0x757f, 0x7948, 0x5b63, 0x7a00, 0x7d00, 0x5fbd, 0x898f, 0x8a18, 0x8cb4, 0x8d77, 0x8ecc, 0x8f1d, 0x98e2, 0x9a0e, 0x9b3c, 0x4e80, 0x507d, 0x5100, 0x5993, 0x5b9c, 0x622f, 0x6280, 0x64ec, 0x6b3a, 0x72a0, 0x7591, 0x7947, 0x7fa9, 0x87fb, 0x8abc, 0x8b70, 0x63ac, 0x83ca, 0x97a0, 0x5409, 0x5403, 0x55ab, 0x6854, 0x6a58, 0x8a70, 0x7827, 0x6775, 0x9ecd, 0x5374, 0x5ba2, 0x811a, 0x8650, 0x9006, 0x4e18, 0x4e45, 0x4ec7, 0x4f11, 0x53ca, 0x5438, 0x5bae, 0x5f13, 0x6025, 0x6551, 0xfffd, 0x673d, 0x6c42, 0x6c72, 0x6ce3, 0x7078, 0x7403, 0x7a76, 0x7aae, 0x7b08, 0x7d1a, 0x7cfe, 0x7d66, 0x65e7, 0x725b, 0x53bb, 0x5c45, 0x5de8, 0x62d2, 0x62e0, 0x6319, 0x6e20, 0x865a, 0x8a31, 0x8ddd, 0x92f8, 0x6f01, 0x79a6, 0x9b5a, 0x4ea8, 0x4eab, 0x4eac, 0x4f9b, 0x4fa0, 0x50d1, 0x5147, 0x7af6, 0x5171, 0x51f6, 0x5354, 0x5321, 0x537f, 0x53eb, 0x55ac, 0x5883, 0x5ce1, 0x5f37, 0x5f4a, 0x602f, 0x6050, 0x606d, 0x631f, 0x6559, 0x6a4b, 0x6cc1, 0x72c2, 0x72ed, 0x77ef, 0x80f8, 0x8105, 0x8208, 0x854e, 0x90f7, 0x93e1, 0x97ff, 0x9957, 0x9a5a, 0x4ef0, 0x51dd, 0x5c2d, 0x6681, 0x696d, 0x5c40, 0x66f2, 0x6975, 0x7389, 0x6850, 0x7c81, 0x50c5, 0x52e4, 0x5747, 0x5dfe, 0x9326, 0x65a4, 0x6b23, 0x6b3d, 0x7434, 0x7981, 0x79bd, 0x7b4b, 0x7dca, 0x82b9, 0x83cc, 0x887f, 0x895f, 0x8b39, 0x8fd1, 0x91d1, 0x541f, 0x9280, 0x4e5d, 0x5036, 0x53e5, 0x533a, 0x72d7, 0x7396, 0x77e9, 0x82e6, 0x8eaf, 0x99c6, 0x99c8, 0x99d2, 0x5177, 0x611a, 0x865e, 0x55b0, 0x7a7a, 0x5076, 0x5bd3, 0x9047, 0x9685, 0x4e32, 0x6adb, 0x91e7, 0x5c51, 0x5c48, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x6398, 0x7a9f, 0x6c93, 0x9774, 0x8f61, 0x7aaa, 0x718a, 0x9688, 0x7c82, 0x6817, 0x7e70, 0x6851, 0x936c, 0x52f2, 0x541b, 0x85ab, 0x8a13, 0x7fa4, 0x8ecd, 0x90e1, 0x5366, 0x8888, 0x7941, 0x4fc2, 0x50be, 0x5211, 0x5144, 0x5553, 0x572d, 0x73ea, 0x578b, 0x5951, 0x5f62, 0x5f84, 0x6075, 0x6176, 0x6167, 0x61a9, 0x63b2, 0x643a, 0x656c, 0x666f, 0x6842, 0x6e13, 0x7566, 0x7a3d, 0x7cfb, 0x7d4c, 0x7d99, 0x7e4b, 0x7f6b, 0x830e, 0x834a, 0x86cd, 0x8a08, 0x8a63, 0x8b66, 0x8efd, 0x981a, 0x9d8f, 0x82b8, 0x8fce, 0x9be8, 0xfffd, 0x5287, 0x621f, 0x6483, 0x6fc0, 0x9699, 0x6841, 0x5091, 0x6b20, 0x6c7a, 0x6f54, 0x7a74, 0x7d50, 0x8840, 0x8a23, 0x6708, 0x4ef6, 0x5039, 0x5026, 0x5065, 0x517c, 0x5238, 0x5263, 0x55a7, 0x570f, 0x5805, 0x5acc, 0x5efa, 0x61b2, 0x61f8, 0x62f3, 0x6372, 0x691c, 0x6a29, 0x727d, 0x72ac, 0x732e, 0x7814, 0x786f, 0x7d79, 0x770c, 0x80a9, 0x898b, 0x8b19, 0x8ce2, 0x8ed2, 0x9063, 0x9375, 0x967a, 0x9855, 0x9a13, 0x9e78, 0x5143, 0x539f, 0x53b3, 0x5e7b, 0x5f26, 0x6e1b, 0x6e90, 0x7384, 0x73fe, 0x7d43, 0x8237, 0x8a00, 0x8afa, 0x9650, 0x4e4e, 0x500b, 0x53e4, 0x547c, 0x56fa, 0x59d1, 0x5b64, 0x5df1, 0x5eab, 0x5f27, 0x6238, 0x6545, 0x67af, 0x6e56, 0x72d0, 0x7cca, 0x88b4, 0x80a1, 0x80e1, 0x83f0, 0x864e, 0x8a87, 0x8de8, 0x9237, 0x96c7, 0x9867, 0x9f13, 0x4e94, 0x4e92, 0x4f0d, 0x5348, 0x5449, 0x543e, 0x5a2f, 0x5f8c, 0x5fa1, 0x609f, 0x68a7, 0x6a8e, 0x745a, 0x7881, 0x8a9e, 0x8aa4, 0x8b77, 0x9190, 0x4e5e, 0x9bc9, 0x4ea4, 0x4f7c, 0x4faf, 0x5019, 0x5016, 0x5149, 0x516c, 0x529f, 0x52b9, 0x52fe, 0x539a, 0x53e3, 0x5411, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x540e, 0x5589, 0x5751, 0x57a2, 0x597d, 0x5b54, 0x5b5d, 0x5b8f, 0x5de5, 0x5de7, 0x5df7, 0x5e78, 0x5e83, 0x5e9a, 0x5eb7, 0x5f18, 0x6052, 0x614c, 0x6297, 0x62d8, 0x63a7, 0x653b, 0x6602, 0x6643, 0x66f4, 0x676d, 0x6821, 0x6897, 0x69cb, 0x6c5f, 0x6d2a, 0x6d69, 0x6e2f, 0x6e9d, 0x7532, 0x7687, 0x786c, 0x7a3f, 0x7ce0, 0x7d05, 0x7d18, 0x7d5e, 0x7db1, 0x8015, 0x8003, 0x80af, 0x80b1, 0x8154, 0x818f, 0x822a, 0x8352, 0x884c, 0x8861, 0x8b1b, 0x8ca2, 0x8cfc, 0x90ca, 0x9175, 0x9271, 0x783f, 0x92fc, 0x95a4, 0x964d, 0xfffd, 0x9805, 0x9999, 0x9ad8, 0x9d3b, 0x525b, 0x52ab, 0x53f7, 0x5408, 0x58d5, 0x62f7, 0x6fe0, 0x8c6a, 0x8f5f, 0x9eb9, 0x514b, 0x523b, 0x544a, 0x56fd, 0x7a40, 0x9177, 0x9d60, 0x9ed2, 0x7344, 0x6f09, 0x8170, 0x7511, 0x5ffd, 0x60da, 0x9aa8, 0x72db, 0x8fbc, 0x6b64, 0x9803, 0x4eca, 0x56f0, 0x5764, 0x58be, 0x5a5a, 0x6068, 0x61c7, 0x660f, 0x6606, 0x6839, 0x68b1, 0x6df7, 0x75d5, 0x7d3a, 0x826e, 0x9b42, 0x4e9b, 0x4f50, 0x53c9, 0x5506, 0x5d6f, 0x5de6, 0x5dee, 0x67fb, 0x6c99, 0x7473, 0x7802, 0x8a50, 0x9396, 0x88df, 0x5750, 0x5ea7, 0x632b, 0x50b5, 0x50ac, 0x518d, 0x6700, 0x54c9, 0x585e, 0x59bb, 0x5bb0, 0x5f69, 0x624d, 0x63a1, 0x683d, 0x6b73, 0x6e08, 0x707d, 0x91c7, 0x7280, 0x7815, 0x7826, 0x796d, 0x658e, 0x7d30, 0x83dc, 0x88c1, 0x8f09, 0x969b, 0x5264, 0x5728, 0x6750, 0x7f6a, 0x8ca1, 0x51b4, 0x5742, 0x962a, 0x583a, 0x698a, 0x80b4, 0x54b2, 0x5d0e, 0x57fc, 0x7895, 0x9dfa, 0x4f5c, 0x524a, 0x548b, 0x643e, 0x6628, 0x6714, 0x67f5, 0x7a84, 0x7b56, 0x7d22, 0x932f, 0x685c, 0x9bad, 0x7b39, 0x5319, 0x518a, 0x5237, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x5bdf, 0x62f6, 0x64ae, 0x64e6, 0x672d, 0x6bba, 0x85a9, 0x96d1, 0x7690, 0x9bd6, 0x634c, 0x9306, 0x9bab, 0x76bf, 0x6652, 0x4e09, 0x5098, 0x53c2, 0x5c71, 0x60e8, 0x6492, 0x6563, 0x685f, 0x71e6, 0x73ca, 0x7523, 0x7b97, 0x7e82, 0x8695, 0x8b83, 0x8cdb, 0x9178, 0x9910, 0x65ac, 0x66ab, 0x6b8b, 0x4ed5, 0x4ed4, 0x4f3a, 0x4f7f, 0x523a, 0x53f8, 0x53f2, 0x55e3, 0x56db, 0x58eb, 0x59cb, 0x59c9, 0x59ff, 0x5b50, 0x5c4d, 0x5e02, 0x5e2b, 0x5fd7, 0x601d, 0x6307, 0x652f, 0x5b5c, 0x65af, 0x65bd, 0x65e8, 0x679d, 0x6b62, 0xfffd, 0x6b7b, 0x6c0f, 0x7345, 0x7949, 0x79c1, 0x7cf8, 0x7d19, 0x7d2b, 0x80a2, 0x8102, 0x81f3, 0x8996, 0x8a5e, 0x8a69, 0x8a66, 0x8a8c, 0x8aee, 0x8cc7, 0x8cdc, 0x96cc, 0x98fc, 0x6b6f, 0x4e8b, 0x4f3c, 0x4f8d, 0x5150, 0x5b57, 0x5bfa, 0x6148, 0x6301, 0x6642, 0x6b21, 0x6ecb, 0x6cbb, 0x723e, 0x74bd, 0x75d4, 0x78c1, 0x793a, 0x800c, 0x8033, 0x81ea, 0x8494, 0x8f9e, 0x6c50, 0x9e7f, 0x5f0f, 0x8b58, 0x9d2b, 0x7afa, 0x8ef8, 0x5b8d, 0x96eb, 0x4e03, 0x53f1, 0x57f7, 0x5931, 0x5ac9, 0x5ba4, 0x6089, 0x6e7f, 0x6f06, 0x75be, 0x8cea, 0x5b9f, 0x8500, 0x7be0, 0x5072, 0x67f4, 0x829d, 0x5c61, 0x854a, 0x7e1e, 0x820e, 0x5199, 0x5c04, 0x6368, 0x8d66, 0x659c, 0x716e, 0x793e, 0x7d17, 0x8005, 0x8b1d, 0x8eca, 0x906e, 0x86c7, 0x90aa, 0x501f, 0x52fa, 0x5c3a, 0x6753, 0x707c, 0x7235, 0x914c, 0x91c8, 0x932b, 0x82e5, 0x5bc2, 0x5f31, 0x60f9, 0x4e3b, 0x53d6, 0x5b88, 0x624b, 0x6731, 0x6b8a, 0x72e9, 0x73e0, 0x7a2e, 0x816b, 0x8da3, 0x9152, 0x9996, 0x5112, 0x53d7, 0x546a, 0x5bff, 0x6388, 0x6a39, 0x7dac, 0x9700, 0x56da, 0x53ce, 0x5468, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x5b97, 0x5c31, 0x5dde, 0x4fee, 0x6101, 0x62fe, 0x6d32, 0x79c0, 0x79cb, 0x7d42, 0x7e4d, 0x7fd2, 0x81ed, 0x821f, 0x8490, 0x8846, 0x8972, 0x8b90, 0x8e74, 0x8f2f, 0x9031, 0x914b, 0x916c, 0x96c6, 0x919c, 0x4ec0, 0x4f4f, 0x5145, 0x5341, 0x5f93, 0x620e, 0x67d4, 0x6c41, 0x6e0b, 0x7363, 0x7e26, 0x91cd, 0x9283, 0x53d4, 0x5919, 0x5bbf, 0x6dd1, 0x795d, 0x7e2e, 0x7c9b, 0x587e, 0x719f, 0x51fa, 0x8853, 0x8ff0, 0x4fca, 0x5cfb, 0x6625, 0x77ac, 0x7ae3, 0x821c, 0x99ff, 0x51c6, 0x5faa, 0x65ec, 0x696f, 0x6b89, 0x6df3, 0xfffd, 0x6e96, 0x6f64, 0x76fe, 0x7d14, 0x5de1, 0x9075, 0x9187, 0x9806, 0x51e6, 0x521d, 0x6240, 0x6691, 0x66d9, 0x6e1a, 0x5eb6, 0x7dd2, 0x7f72, 0x66f8, 0x85af, 0x85f7, 0x8af8, 0x52a9, 0x53d9, 0x5973, 0x5e8f, 0x5f90, 0x6055, 0x92e4, 0x9664, 0x50b7, 0x511f, 0x52dd, 0x5320, 0x5347, 0x53ec, 0x54e8, 0x5546, 0x5531, 0x5617, 0x5968, 0x59be, 0x5a3c, 0x5bb5, 0x5c06, 0x5c0f, 0x5c11, 0x5c1a, 0x5e84, 0x5e8a, 0x5ee0, 0x5f70, 0x627f, 0x6284, 0x62db, 0x638c, 0x6377, 0x6607, 0x660c, 0x662d, 0x6676, 0x677e, 0x68a2, 0x6a1f, 0x6a35, 0x6cbc, 0x6d88, 0x6e09, 0x6e58, 0x713c, 0x7126, 0x7167, 0x75c7, 0x7701, 0x785d, 0x7901, 0x7965, 0x79f0, 0x7ae0, 0x7b11, 0x7ca7, 0x7d39, 0x8096, 0x83d6, 0x848b, 0x8549, 0x885d, 0x88f3, 0x8a1f, 0x8a3c, 0x8a54, 0x8a73, 0x8c61, 0x8cde, 0x91a4, 0x9266, 0x937e, 0x9418, 0x969c, 0x9798, 0x4e0a, 0x4e08, 0x4e1e, 0x4e57, 0x5197, 0x5270, 0x57ce, 0x5834, 0x58cc, 0x5b22, 0x5e38, 0x60c5, 0x64fe, 0x6761, 0x6756, 0x6d44, 0x72b6, 0x7573, 0x7a63, 0x84b8, 0x8b72, 0x91b8, 0x9320, 0x5631, 0x57f4, 0x98fe, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x62ed, 0x690d, 0x6b96, 0x71ed, 0x7e54, 0x8077, 0x8272, 0x89e6, 0x98df, 0x8755, 0x8fb1, 0x5c3b, 0x4f38, 0x4fe1, 0x4fb5, 0x5507, 0x5a20, 0x5bdd, 0x5be9, 0x5fc3, 0x614e, 0x632f, 0x65b0, 0x664b, 0x68ee, 0x699b, 0x6d78, 0x6df1, 0x7533, 0x75b9, 0x771f, 0x795e, 0x79e6, 0x7d33, 0x81e3, 0x82af, 0x85aa, 0x89aa, 0x8a3a, 0x8eab, 0x8f9b, 0x9032, 0x91dd, 0x9707, 0x4eba, 0x4ec1, 0x5203, 0x5875, 0x58ec, 0x5c0b, 0x751a, 0x5c3d, 0x814e, 0x8a0a, 0x8fc5, 0x9663, 0x976d, 0x7b25, 0x8acf, 0x9808, 0x9162, 0x56f3, 0x53a8, 0xfffd, 0x9017, 0x5439, 0x5782, 0x5e25, 0x63a8, 0x6c34, 0x708a, 0x7761, 0x7c8b, 0x7fe0, 0x8870, 0x9042, 0x9154, 0x9310, 0x9318, 0x968f, 0x745e, 0x9ac4, 0x5d07, 0x5d69, 0x6570, 0x67a2, 0x8da8, 0x96db, 0x636e, 0x6749, 0x6919, 0x83c5, 0x9817, 0x96c0, 0x88fe, 0x6f84, 0x647a, 0x5bf8, 0x4e16, 0x702c, 0x755d, 0x662f, 0x51c4, 0x5236, 0x52e2, 0x59d3, 0x5f81, 0x6027, 0x6210, 0x653f, 0x6574, 0x661f, 0x6674, 0x68f2, 0x6816, 0x6b63, 0x6e05, 0x7272, 0x751f, 0x76db, 0x7cbe, 0x8056, 0x58f0, 0x88fd, 0x897f, 0x8aa0, 0x8a93, 0x8acb, 0x901d, 0x9192, 0x9752, 0x9759, 0x6589, 0x7a0e, 0x8106, 0x96bb, 0x5e2d, 0x60dc, 0x621a, 0x65a5, 0x6614, 0x6790, 0x77f3, 0x7a4d, 0x7c4d, 0x7e3e, 0x810a, 0x8cac, 0x8d64, 0x8de1, 0x8e5f, 0x78a9, 0x5207, 0x62d9, 0x63a5, 0x6442, 0x6298, 0x8a2d, 0x7a83, 0x7bc0, 0x8aac, 0x96ea, 0x7d76, 0x820c, 0x8749, 0x4ed9, 0x5148, 0x5343, 0x5360, 0x5ba3, 0x5c02, 0x5c16, 0x5ddd, 0x6226, 0x6247, 0x64b0, 0x6813, 0x6834, 0x6cc9, 0x6d45, 0x6d17, 0x67d3, 0x6f5c, 0x714e, 0x717d, 0x65cb, 0x7a7f, 0x7bad, 0x7dda, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x7e4a, 0x7fa8, 0x817a, 0x821b, 0x8239, 0x85a6, 0x8a6e, 0x8cce, 0x8df5, 0x9078, 0x9077, 0x92ad, 0x9291, 0x9583, 0x9bae, 0x524d, 0x5584, 0x6f38, 0x7136, 0x5168, 0x7985, 0x7e55, 0x81b3, 0x7cce, 0x564c, 0x5851, 0x5ca8, 0x63aa, 0x66fe, 0x66fd, 0x695a, 0x72d9, 0x758f, 0x758e, 0x790e, 0x7956, 0x79df, 0x7c97, 0x7d20, 0x7d44, 0x8607, 0x8a34, 0x963b, 0x9061, 0x9f20, 0x50e7, 0x5275, 0x53cc, 0x53e2, 0x5009, 0x55aa, 0x58ee, 0x594f, 0x723d, 0x5b8b, 0x5c64, 0x531d, 0x60e3, 0x60f3, 0x635c, 0x6383, 0x633f, 0x63bb, 0xfffd, 0x64cd, 0x65e9, 0x66f9, 0x5de3, 0x69cd, 0x69fd, 0x6f15, 0x71e5, 0x4e89, 0x75e9, 0x76f8, 0x7a93, 0x7cdf, 0x7dcf, 0x7d9c, 0x8061, 0x8349, 0x8358, 0x846c, 0x84bc, 0x85fb, 0x88c5, 0x8d70, 0x9001, 0x906d, 0x9397, 0x971c, 0x9a12, 0x50cf, 0x5897, 0x618e, 0x81d3, 0x8535, 0x8d08, 0x9020, 0x4fc3, 0x5074, 0x5247, 0x5373, 0x606f, 0x6349, 0x675f, 0x6e2c, 0x8db3, 0x901f, 0x4fd7, 0x5c5e, 0x8cca, 0x65cf, 0x7d9a, 0x5352, 0x8896, 0x5176, 0x63c3, 0x5b58, 0x5b6b, 0x5c0a, 0x640d, 0x6751, 0x905c, 0x4ed6, 0x591a, 0x592a, 0x6c70, 0x8a51, 0x553e, 0x5815, 0x59a5, 0x60f0, 0x6253, 0x67c1, 0x8235, 0x6955, 0x9640, 0x99c4, 0x9a28, 0x4f53, 0x5806, 0x5bfe, 0x8010, 0x5cb1, 0x5e2f, 0x5f85, 0x6020, 0x614b, 0x6234, 0x66ff, 0x6cf0, 0x6ede, 0x80ce, 0x817f, 0x82d4, 0x888b, 0x8cb8, 0x9000, 0x902e, 0x968a, 0x9edb, 0x9bdb, 0x4ee3, 0x53f0, 0x5927, 0x7b2c, 0x918d, 0x984c, 0x9df9, 0x6edd, 0x7027, 0x5353, 0x5544, 0x5b85, 0x6258, 0x629e, 0x62d3, 0x6ca2, 0x6fef, 0x7422, 0x8a17, 0x9438, 0x6fc1, 0x8afe, 0x8338, 0x51e7, 0x86f8, 0x53ea, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x53e9, 0x4f46, 0x9054, 0x8fb0, 0x596a, 0x8131, 0x5dfd, 0x7aea, 0x8fbf, 0x68da, 0x8c37, 0x72f8, 0x9c48, 0x6a3d, 0x8ab0, 0x4e39, 0x5358, 0x5606, 0x5766, 0x62c5, 0x63a2, 0x65e6, 0x6b4e, 0x6de1, 0x6e5b, 0x70ad, 0x77ed, 0x7aef, 0x7baa, 0x7dbb, 0x803d, 0x80c6, 0x86cb, 0x8a95, 0x935b, 0x56e3, 0x58c7, 0x5f3e, 0x65ad, 0x6696, 0x6a80, 0x6bb5, 0x7537, 0x8ac7, 0x5024, 0x77e5, 0x5730, 0x5f1b, 0x6065, 0x667a, 0x6c60, 0x75f4, 0x7a1a, 0x7f6e, 0x81f4, 0x8718, 0x9045, 0x99b3, 0x7bc9, 0x755c, 0x7af9, 0x7b51, 0x84c4, 0xfffd, 0x9010, 0x79e9, 0x7a92, 0x8336, 0x5ae1, 0x7740, 0x4e2d, 0x4ef2, 0x5b99, 0x5fe0, 0x62bd, 0x663c, 0x67f1, 0x6ce8, 0x866b, 0x8877, 0x8a3b, 0x914e, 0x92f3, 0x99d0, 0x6a17, 0x7026, 0x732a, 0x82e7, 0x8457, 0x8caf, 0x4e01, 0x5146, 0x51cb, 0x558b, 0x5bf5, 0x5e16, 0x5e33, 0x5e81, 0x5f14, 0x5f35, 0x5f6b, 0x5fb4, 0x61f2, 0x6311, 0x66a2, 0x671d, 0x6f6e, 0x7252, 0x753a, 0x773a, 0x8074, 0x8139, 0x8178, 0x8776, 0x8abf, 0x8adc, 0x8d85, 0x8df3, 0x929a, 0x9577, 0x9802, 0x9ce5, 0x52c5, 0x6357, 0x76f4, 0x6715, 0x6c88, 0x73cd, 0x8cc3, 0x93ae, 0x9673, 0x6d25, 0x589c, 0x690e, 0x69cc, 0x8ffd, 0x939a, 0x75db, 0x901a, 0x585a, 0x6802, 0x63b4, 0x69fb, 0x4f43, 0x6f2c, 0x67d8, 0x8fbb, 0x8526, 0x7db4, 0x9354, 0x693f, 0x6f70, 0x576a, 0x58f7, 0x5b2c, 0x7d2c, 0x722a, 0x540a, 0x91e3, 0x9db4, 0x4ead, 0x4f4e, 0x505c, 0x5075, 0x5243, 0x8c9e, 0x5448, 0x5824, 0x5b9a, 0x5e1d, 0x5e95, 0x5ead, 0x5ef7, 0x5f1f, 0x608c, 0x62b5, 0x633a, 0x63d0, 0x68af, 0x6c40, 0x7887, 0x798e, 0x7a0b, 0x7de0, 0x8247, 0x8a02, 0x8ae6, 0x8e44, 0x9013, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90b8, 0x912d, 0x91d8, 0x9f0e, 0x6ce5, 0x6458, 0x64e2, 0x6575, 0x6ef4, 0x7684, 0x7b1b, 0x9069, 0x93d1, 0x6eba, 0x54f2, 0x5fb9, 0x64a4, 0x8f4d, 0x8fed, 0x9244, 0x5178, 0x586b, 0x5929, 0x5c55, 0x5e97, 0x6dfb, 0x7e8f, 0x751c, 0x8cbc, 0x8ee2, 0x985b, 0x70b9, 0x4f1d, 0x6bbf, 0x6fb1, 0x7530, 0x96fb, 0x514e, 0x5410, 0x5835, 0x5857, 0x59ac, 0x5c60, 0x5f92, 0x6597, 0x675c, 0x6e21, 0x767b, 0x83df, 0x8ced, 0x9014, 0x90fd, 0x934d, 0x7825, 0x783a, 0x52aa, 0x5ea6, 0x571f, 0x5974, 0x6012, 0x5012, 0x515a, 0x51ac, 0xfffd, 0x51cd, 0x5200, 0x5510, 0x5854, 0x5858, 0x5957, 0x5b95, 0x5cf6, 0x5d8b, 0x60bc, 0x6295, 0x642d, 0x6771, 0x6843, 0x68bc, 0x68df, 0x76d7, 0x6dd8, 0x6e6f, 0x6d9b, 0x706f, 0x71c8, 0x5f53, 0x75d8, 0x7977, 0x7b49, 0x7b54, 0x7b52, 0x7cd6, 0x7d71, 0x5230, 0x8463, 0x8569, 0x85e4, 0x8a0e, 0x8b04, 0x8c46, 0x8e0f, 0x9003, 0x900f, 0x9419, 0x9676, 0x982d, 0x9a30, 0x95d8, 0x50cd, 0x52d5, 0x540c, 0x5802, 0x5c0e, 0x61a7, 0x649e, 0x6d1e, 0x77b3, 0x7ae5, 0x80f4, 0x8404, 0x9053, 0x9285, 0x5ce0, 0x9d07, 0x533f, 0x5f97, 0x5fb3, 0x6d9c, 0x7279, 0x7763, 0x79bf, 0x7be4, 0x6bd2, 0x72ec, 0x8aad, 0x6803, 0x6a61, 0x51f8, 0x7a81, 0x6934, 0x5c4a, 0x9cf6, 0x82eb, 0x5bc5, 0x9149, 0x701e, 0x5678, 0x5c6f, 0x60c7, 0x6566, 0x6c8c, 0x8c5a, 0x9041, 0x9813, 0x5451, 0x66c7, 0x920d, 0x5948, 0x90a3, 0x5185, 0x4e4d, 0x51ea, 0x8599, 0x8b0e, 0x7058, 0x637a, 0x934b, 0x6962, 0x99b4, 0x7e04, 0x7577, 0x5357, 0x6960, 0x8edf, 0x96e3, 0x6c5d, 0x4e8c, 0x5c3c, 0x5f10, 0x8fe9, 0x5302, 0x8cd1, 0x8089, 0x8679, 0x5eff, 0x65e5, 0x4e73, 0x5165, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x5982, 0x5c3f, 0x97ee, 0x4efb, 0x598a, 0x5fcd, 0x8a8d, 0x6fe1, 0x79b0, 0x7962, 0x5be7, 0x8471, 0x732b, 0x71b1, 0x5e74, 0x5ff5, 0x637b, 0x649a, 0x71c3, 0x7c98, 0x4e43, 0x5efc, 0x4e4b, 0x57dc, 0x56a2, 0x60a9, 0x6fc3, 0x7d0d, 0x80fd, 0x8133, 0x81bf, 0x8fb2, 0x8997, 0x86a4, 0x5df4, 0x628a, 0x64ad, 0x8987, 0x6777, 0x6ce2, 0x6d3e, 0x7436, 0x7834, 0x5a46, 0x7f75, 0x82ad, 0x99ac, 0x4ff3, 0x5ec3, 0x62dd, 0x6392, 0x6557, 0x676f, 0x76c3, 0x724c, 0x80cc, 0x80ba, 0x8f29, 0x914d, 0x500d, 0x57f9, 0x5a92, 0x6885, 0xfffd, 0x6973, 0x7164, 0x72fd, 0x8cb7, 0x58f2, 0x8ce0, 0x966a, 0x9019, 0x877f, 0x79e4, 0x77e7, 0x8429, 0x4f2f, 0x5265, 0x535a, 0x62cd, 0x67cf, 0x6cca, 0x767d, 0x7b94, 0x7c95, 0x8236, 0x8584, 0x8feb, 0x66dd, 0x6f20, 0x7206, 0x7e1b, 0x83ab, 0x99c1, 0x9ea6, 0x51fd, 0x7bb1, 0x7872, 0x7bb8, 0x8087, 0x7b48, 0x6ae8, 0x5e61, 0x808c, 0x7551, 0x7560, 0x516b, 0x9262, 0x6e8c, 0x767a, 0x9197, 0x9aea, 0x4f10, 0x7f70, 0x629c, 0x7b4f, 0x95a5, 0x9ce9, 0x567a, 0x5859, 0x86e4, 0x96bc, 0x4f34, 0x5224, 0x534a, 0x53cd, 0x53db, 0x5e06, 0x642c, 0x6591, 0x677f, 0x6c3e, 0x6c4e, 0x7248, 0x72af, 0x73ed, 0x7554, 0x7e41, 0x822c, 0x85e9, 0x8ca9, 0x7bc4, 0x91c6, 0x7169, 0x9812, 0x98ef, 0x633d, 0x6669, 0x756a, 0x76e4, 0x78d0, 0x8543, 0x86ee, 0x532a, 0x5351, 0x5426, 0x5983, 0x5e87, 0x5f7c, 0x60b2, 0x6249, 0x6279, 0x62ab, 0x6590, 0x6bd4, 0x6ccc, 0x75b2, 0x76ae, 0x7891, 0x79d8, 0x7dcb, 0x7f77, 0x80a5, 0x88ab, 0x8ab9, 0x8cbb, 0x907f, 0x975e, 0x98db, 0x6a0b, 0x7c38, 0x5099, 0x5c3e, 0x5fae, 0x6787, 0x6bd8, 0x7435, 0x7709, 0x7f8e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f3b, 0x67ca, 0x7a17, 0x5339, 0x758b, 0x9aed, 0x5f66, 0x819d, 0x83f1, 0x8098, 0x5f3c, 0x5fc5, 0x7562, 0x7b46, 0x903c, 0x6867, 0x59eb, 0x5a9b, 0x7d10, 0x767e, 0x8b2c, 0x4ff5, 0x5f6a, 0x6a19, 0x6c37, 0x6f02, 0x74e2, 0x7968, 0x8868, 0x8a55, 0x8c79, 0x5edf, 0x63cf, 0x75c5, 0x79d2, 0x82d7, 0x9328, 0x92f2, 0x849c, 0x86ed, 0x9c2d, 0x54c1, 0x5f6c, 0x658c, 0x6d5c, 0x7015, 0x8ca7, 0x8cd3, 0x983b, 0x654f, 0x74f6, 0x4e0d, 0x4ed8, 0x57e0, 0x592b, 0x5a66, 0x5bcc, 0x51a8, 0x5e03, 0x5e9c, 0x6016, 0x6276, 0x6577, 0xfffd, 0x65a7, 0x666e, 0x6d6e, 0x7236, 0x7b26, 0x8150, 0x819a, 0x8299, 0x8b5c, 0x8ca0, 0x8ce6, 0x8d74, 0x961c, 0x9644, 0x4fae, 0x64ab, 0x6b66, 0x821e, 0x8461, 0x856a, 0x90e8, 0x5c01, 0x6953, 0x98a8, 0x847a, 0x8557, 0x4f0f, 0x526f, 0x5fa9, 0x5e45, 0x670d, 0x798f, 0x8179, 0x8907, 0x8986, 0x6df5, 0x5f17, 0x6255, 0x6cb8, 0x4ecf, 0x7269, 0x9b92, 0x5206, 0x543b, 0x5674, 0x58b3, 0x61a4, 0x626e, 0x711a, 0x596e, 0x7c89, 0x7cde, 0x7d1b, 0x96f0, 0x6587, 0x805e, 0x4e19, 0x4f75, 0x5175, 0x5840, 0x5e63, 0x5e73, 0x5f0a, 0x67c4, 0x4e26, 0x853d, 0x9589, 0x965b, 0x7c73, 0x9801, 0x50fb, 0x58c1, 0x7656, 0x78a7, 0x5225, 0x77a5, 0x8511, 0x7b86, 0x504f, 0x5909, 0x7247, 0x7bc7, 0x7de8, 0x8fba, 0x8fd4, 0x904d, 0x4fbf, 0x52c9, 0x5a29, 0x5f01, 0x97ad, 0x4fdd, 0x8217, 0x92ea, 0x5703, 0x6355, 0x6b69, 0x752b, 0x88dc, 0x8f14, 0x7a42, 0x52df, 0x5893, 0x6155, 0x620a, 0x66ae, 0x6bcd, 0x7c3f, 0x83e9, 0x5023, 0x4ff8, 0x5305, 0x5446, 0x5831, 0x5949, 0x5b9d, 0x5cf0, 0x5cef, 0x5d29, 0x5e96, 0x62b1, 0x6367, 0x653e, 0x65b9, 0x670b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x6cd5, 0x6ce1, 0x70f9, 0x7832, 0x7e2b, 0x80de, 0x82b3, 0x840c, 0x84ec, 0x8702, 0x8912, 0x8a2a, 0x8c4a, 0x90a6, 0x92d2, 0x98fd, 0x9cf3, 0x9d6c, 0x4e4f, 0x4ea1, 0x508d, 0x5256, 0x574a, 0x59a8, 0x5e3d, 0x5fd8, 0x5fd9, 0x623f, 0x66b4, 0x671b, 0x67d0, 0x68d2, 0x5192, 0x7d21, 0x80aa, 0x81a8, 0x8b00, 0x8c8c, 0x8cbf, 0x927e, 0x9632, 0x5420, 0x982c, 0x5317, 0x50d5, 0x535c, 0x58a8, 0x64b2, 0x6734, 0x7267, 0x7766, 0x7a46, 0x91e6, 0x52c3, 0x6ca1, 0x6b86, 0x5800, 0x5e4c, 0x5954, 0x672c, 0x7ffb, 0x51e1, 0x76c6, 0xfffd, 0x6469, 0x78e8, 0x9b54, 0x9ebb, 0x57cb, 0x59b9, 0x6627, 0x679a, 0x6bce, 0x54e9, 0x69d9, 0x5e55, 0x819c, 0x6795, 0x9baa, 0x67fe, 0x9c52, 0x685d, 0x4ea6, 0x4fe3, 0x53c8, 0x62b9, 0x672b, 0x6cab, 0x8fc4, 0x4fad, 0x7e6d, 0x9ebf, 0x4e07, 0x6162, 0x6e80, 0x6f2b, 0x8513, 0x5473, 0x672a, 0x9b45, 0x5df3, 0x7b95, 0x5cac, 0x5bc6, 0x871c, 0x6e4a, 0x84d1, 0x7a14, 0x8108, 0x5999, 0x7c8d, 0x6c11, 0x7720, 0x52d9, 0x5922, 0x7121, 0x725f, 0x77db, 0x9727, 0x9d61, 0x690b, 0x5a7f, 0x5a18, 0x51a5, 0x540d, 0x547d, 0x660e, 0x76df, 0x8ff7, 0x9298, 0x9cf4, 0x59ea, 0x725d, 0x6ec5, 0x514d, 0x68c9, 0x7dbf, 0x7dec, 0x9762, 0x9eba, 0x6478, 0x6a21, 0x8302, 0x5984, 0x5b5f, 0x6bdb, 0x731b, 0x76f2, 0x7db2, 0x8017, 0x8499, 0x5132, 0x6728, 0x9ed9, 0x76ee, 0x6762, 0x52ff, 0x9905, 0x5c24, 0x623b, 0x7c7e, 0x8cb0, 0x554f, 0x60b6, 0x7d0b, 0x9580, 0x5301, 0x4e5f, 0x51b6, 0x591c, 0x723a, 0x8036, 0x91ce, 0x5f25, 0x77e2, 0x5384, 0x5f79, 0x7d04, 0x85ac, 0x8a33, 0x8e8d, 0x9756, 0x67f3, 0x85ae, 0x9453, 0x6109, 0x6108, 0x6cb9, 0x7652, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8aed, 0x8f38, 0x552f, 0x4f51, 0x512a, 0x52c7, 0x53cb, 0x5ba5, 0x5e7d, 0x60a0, 0x6182, 0x63d6, 0x6709, 0x67da, 0x6e67, 0x6d8c, 0x7336, 0x7337, 0x7531, 0x7950, 0x88d5, 0x8a98, 0x904a, 0x9091, 0x90f5, 0x96c4, 0x878d, 0x5915, 0x4e88, 0x4f59, 0x4e0e, 0x8a89, 0x8f3f, 0x9810, 0x50ad, 0x5e7c, 0x5996, 0x5bb9, 0x5eb8, 0x63da, 0x63fa, 0x64c1, 0x66dc, 0x694a, 0x69d8, 0x6d0b, 0x6eb6, 0x7194, 0x7528, 0x7aaf, 0x7f8a, 0x8000, 0x8449, 0x84c9, 0x8981, 0x8b21, 0x8e0a, 0x9065, 0x967d, 0x990a, 0x617e, 0x6291, 0x6b32, 0xfffd, 0x6c83, 0x6d74, 0x7fcc, 0x7ffc, 0x6dc0, 0x7f85, 0x87ba, 0x88f8, 0x6765, 0x83b1, 0x983c, 0x96f7, 0x6d1b, 0x7d61, 0x843d, 0x916a, 0x4e71, 0x5375, 0x5d50, 0x6b04, 0x6feb, 0x85cd, 0x862d, 0x89a7, 0x5229, 0x540f, 0x5c65, 0x674e, 0x68a8, 0x7406, 0x7483, 0x75e2, 0x88cf, 0x88e1, 0x91cc, 0x96e2, 0x9678, 0x5f8b, 0x7387, 0x7acb, 0x844e, 0x63a0, 0x7565, 0x5289, 0x6d41, 0x6e9c, 0x7409, 0x7559, 0x786b, 0x7c92, 0x9686, 0x7adc, 0x9f8d, 0x4fb6, 0x616e, 0x65c5, 0x865c, 0x4e86, 0x4eae, 0x50da, 0x4e21, 0x51cc, 0x5bee, 0x6599, 0x6881, 0x6dbc, 0x731f, 0x7642, 0x77ad, 0x7a1c, 0x7ce7, 0x826f, 0x8ad2, 0x907c, 0x91cf, 0x9675, 0x9818, 0x529b, 0x7dd1, 0x502b, 0x5398, 0x6797, 0x6dcb, 0x71d0, 0x7433, 0x81e8, 0x8f2a, 0x96a3, 0x9c57, 0x9e9f, 0x7460, 0x5841, 0x6d99, 0x7d2f, 0x985e, 0x4ee4, 0x4f36, 0x4f8b, 0x51b7, 0x52b1, 0x5dba, 0x601c, 0x73b2, 0x793c, 0x82d3, 0x9234, 0x96b7, 0x96f6, 0x970a, 0x9e97, 0x9f62, 0x66a6, 0x6b74, 0x5217, 0x52a3, 0x70c8, 0x88c2, 0x5ec9, 0x604b, 0x6190, 0x6f23, 0x7149, 0x7c3e, 0x7df4, 0x806f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x84ee, 0x9023, 0x932c, 0x5442, 0x9b6f, 0x6ad3, 0x7089, 0x8cc2, 0x8def, 0x9732, 0x52b4, 0x5a41, 0x5eca, 0x5f04, 0x6717, 0x697c, 0x6994, 0x6d6a, 0x6f0f, 0x7262, 0x72fc, 0x7bed, 0x8001, 0x807e, 0x874b, 0x90ce, 0x516d, 0x9e93, 0x7984, 0x808b, 0x9332, 0x8ad6, 0x502d, 0x548c, 0x8a71, 0x6b6a, 0x8cc4, 0x8107, 0x60d1, 0x67a0, 0x9df2, 0x4e99, 0x4e98, 0x9c10, 0x8a6b, 0x85c1, 0x8568, 0x6900, 0x6e7e, 0x7897, 0x8155, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x5f0c, 0x4e10, 0x4e15, 0x4e2a, 0x4e31, 0x4e36, 0x4e3c, 0x4e3f, 0x4e42, 0x4e56, 0x4e58, 0x4e82, 0x4e85, 0x8c6b, 0x4e8a, 0x8212, 0x5f0d, 0x4e8e, 0x4e9e, 0x4e9f, 0x4ea0, 0x4ea2, 0x4eb0, 0x4eb3, 0x4eb6, 0x4ece, 0x4ecd, 0x4ec4, 0x4ec6, 0x4ec2, 0x4ed7, 0x4ede, 0x4eed, 0x4edf, 0x4ef7, 0x4f09, 0x4f5a, 0x4f30, 0x4f5b, 0x4f5d, 0x4f57, 0x4f47, 0x4f76, 0x4f88, 0x4f8f, 0x4f98, 0x4f7b, 0x4f69, 0x4f70, 0x4f91, 0x4f6f, 0x4f86, 0x4f96, 0x5118, 0x4fd4, 0x4fdf, 0x4fce, 0x4fd8, 0x4fdb, 0x4fd1, 0x4fda, 0x4fd0, 0x4fe4, 0x4fe5, 0x501a, 0x5028, 0x5014, 0x502a, 0x5025, 0x5005, 0x4f1c, 0x4ff6, 0x5021, 0x5029, 0x502c, 0x4ffe, 0x4fef, 0x5011, 0x5006, 0x5043, 0x5047, 0x6703, 0x5055, 0x5050, 0x5048, 0x505a, 0x5056, 0x506c, 0x5078, 0x5080, 0x509a, 0x5085, 0x50b4, 0x50b2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x50c9, 0x50ca, 0x50b3, 0x50c2, 0x50d6, 0x50de, 0x50e5, 0x50ed, 0x50e3, 0x50ee, 0x50f9, 0x50f5, 0x5109, 0x5101, 0x5102, 0x5116, 0x5115, 0x5114, 0x511a, 0x5121, 0x513a, 0x5137, 0x513c, 0x513b, 0x513f, 0x5140, 0x5152, 0x514c, 0x5154, 0x5162, 0x7af8, 0x5169, 0x516a, 0x516e, 0x5180, 0x5182, 0x56d8, 0x518c, 0x5189, 0x518f, 0x5191, 0x5193, 0x5195, 0x5196, 0x51a4, 0x51a6, 0x51a2, 0x51a9, 0x51aa, 0x51ab, 0x51b3, 0x51b1, 0x51b2, 0x51b0, 0x51b5, 0x51bd, 0x51c5, 0x51c9, 0x51db, 0x51e0, 0x8655, 0x51e9, 0x51ed, 0xfffd, 0x51f0, 0x51f5, 0x51fe, 0x5204, 0x520b, 0x5214, 0x520e, 0x5227, 0x522a, 0x522e, 0x5233, 0x5239, 0x524f, 0x5244, 0x524b, 0x524c, 0x525e, 0x5254, 0x526a, 0x5274, 0x5269, 0x5273, 0x527f, 0x527d, 0x528d, 0x5294, 0x5292, 0x5271, 0x5288, 0x5291, 0x8fa8, 0x8fa7, 0x52ac, 0x52ad, 0x52bc, 0x52b5, 0x52c1, 0x52cd, 0x52d7, 0x52de, 0x52e3, 0x52e6, 0x98ed, 0x52e0, 0x52f3, 0x52f5, 0x52f8, 0x52f9, 0x5306, 0x5308, 0x7538, 0x530d, 0x5310, 0x530f, 0x5315, 0x531a, 0x5323, 0x532f, 0x5331, 0x5333, 0x5338, 0x5340, 0x5346, 0x5345, 0x4e17, 0x5349, 0x534d, 0x51d6, 0x535e, 0x5369, 0x536e, 0x5918, 0x537b, 0x5377, 0x5382, 0x5396, 0x53a0, 0x53a6, 0x53a5, 0x53ae, 0x53b0, 0x53b6, 0x53c3, 0x7c12, 0x96d9, 0x53df, 0x66fc, 0x71ee, 0x53ee, 0x53e8, 0x53ed, 0x53fa, 0x5401, 0x543d, 0x5440, 0x542c, 0x542d, 0x543c, 0x542e, 0x5436, 0x5429, 0x541d, 0x544e, 0x548f, 0x5475, 0x548e, 0x545f, 0x5471, 0x5477, 0x5470, 0x5492, 0x547b, 0x5480, 0x5476, 0x5484, 0x5490, 0x5486, 0x54c7, 0x54a2, 0x54b8, 0x54a5, 0x54ac, 0x54c4, 0x54c8, 0x54a8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x54ab, 0x54c2, 0x54a4, 0x54be, 0x54bc, 0x54d8, 0x54e5, 0x54e6, 0x550f, 0x5514, 0x54fd, 0x54ee, 0x54ed, 0x54fa, 0x54e2, 0x5539, 0x5540, 0x5563, 0x554c, 0x552e, 0x555c, 0x5545, 0x5556, 0x5557, 0x5538, 0x5533, 0x555d, 0x5599, 0x5580, 0x54af, 0x558a, 0x559f, 0x557b, 0x557e, 0x5598, 0x559e, 0x55ae, 0x557c, 0x5583, 0x55a9, 0x5587, 0x55a8, 0x55da, 0x55c5, 0x55df, 0x55c4, 0x55dc, 0x55e4, 0x55d4, 0x5614, 0x55f7, 0x5616, 0x55fe, 0x55fd, 0x561b, 0x55f9, 0x564e, 0x5650, 0x71df, 0x5634, 0x5636, 0x5632, 0x5638, 0xfffd, 0x566b, 0x5664, 0x562f, 0x566c, 0x566a, 0x5686, 0x5680, 0x568a, 0x56a0, 0x5694, 0x568f, 0x56a5, 0x56ae, 0x56b6, 0x56b4, 0x56c2, 0x56bc, 0x56c1, 0x56c3, 0x56c0, 0x56c8, 0x56ce, 0x56d1, 0x56d3, 0x56d7, 0x56ee, 0x56f9, 0x5700, 0x56ff, 0x5704, 0x5709, 0x5708, 0x570b, 0x570d, 0x5713, 0x5718, 0x5716, 0x55c7, 0x571c, 0x5726, 0x5737, 0x5738, 0x574e, 0x573b, 0x5740, 0x574f, 0x5769, 0x57c0, 0x5788, 0x5761, 0x577f, 0x5789, 0x5793, 0x57a0, 0x57b3, 0x57a4, 0x57aa, 0x57b0, 0x57c3, 0x57c6, 0x57d4, 0x57d2, 0x57d3, 0x580a, 0x57d6, 0x57e3, 0x580b, 0x5819, 0x581d, 0x5872, 0x5821, 0x5862, 0x584b, 0x5870, 0x6bc0, 0x5852, 0x583d, 0x5879, 0x5885, 0x58b9, 0x589f, 0x58ab, 0x58ba, 0x58de, 0x58bb, 0x58b8, 0x58ae, 0x58c5, 0x58d3, 0x58d1, 0x58d7, 0x58d9, 0x58d8, 0x58e5, 0x58dc, 0x58e4, 0x58df, 0x58ef, 0x58fa, 0x58f9, 0x58fb, 0x58fc, 0x58fd, 0x5902, 0x590a, 0x5910, 0x591b, 0x68a6, 0x5925, 0x592c, 0x592d, 0x5932, 0x5938, 0x593e, 0x7ad2, 0x5955, 0x5950, 0x594e, 0x595a, 0x5958, 0x5962, 0x5960, 0x5967, 0x596c, 0x5969, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x5978, 0x5981, 0x599d, 0x4f5e, 0x4fab, 0x59a3, 0x59b2, 0x59c6, 0x59e8, 0x59dc, 0x598d, 0x59d9, 0x59da, 0x5a25, 0x5a1f, 0x5a11, 0x5a1c, 0x5a09, 0x5a1a, 0x5a40, 0x5a6c, 0x5a49, 0x5a35, 0x5a36, 0x5a62, 0x5a6a, 0x5a9a, 0x5abc, 0x5abe, 0x5acb, 0x5ac2, 0x5abd, 0x5ae3, 0x5ad7, 0x5ae6, 0x5ae9, 0x5ad6, 0x5afa, 0x5afb, 0x5b0c, 0x5b0b, 0x5b16, 0x5b32, 0x5ad0, 0x5b2a, 0x5b36, 0x5b3e, 0x5b43, 0x5b45, 0x5b40, 0x5b51, 0x5b55, 0x5b5a, 0x5b5b, 0x5b65, 0x5b69, 0x5b70, 0x5b73, 0x5b75, 0x5b78, 0x6588, 0x5b7a, 0x5b80, 0xfffd, 0x5b83, 0x5ba6, 0x5bb8, 0x5bc3, 0x5bc7, 0x5bc9, 0x5bd4, 0x5bd0, 0x5be4, 0x5be6, 0x5be2, 0x5bde, 0x5be5, 0x5beb, 0x5bf0, 0x5bf6, 0x5bf3, 0x5c05, 0x5c07, 0x5c08, 0x5c0d, 0x5c13, 0x5c20, 0x5c22, 0x5c28, 0x5c38, 0x5c39, 0x5c41, 0x5c46, 0x5c4e, 0x5c53, 0x5c50, 0x5c4f, 0x5b71, 0x5c6c, 0x5c6e, 0x4e62, 0x5c76, 0x5c79, 0x5c8c, 0x5c91, 0x5c94, 0x599b, 0x5cab, 0x5cbb, 0x5cb6, 0x5cbc, 0x5cb7, 0x5cc5, 0x5cbe, 0x5cc7, 0x5cd9, 0x5ce9, 0x5cfd, 0x5cfa, 0x5ced, 0x5d8c, 0x5cea, 0x5d0b, 0x5d15, 0x5d17, 0x5d5c, 0x5d1f, 0x5d1b, 0x5d11, 0x5d14, 0x5d22, 0x5d1a, 0x5d19, 0x5d18, 0x5d4c, 0x5d52, 0x5d4e, 0x5d4b, 0x5d6c, 0x5d73, 0x5d76, 0x5d87, 0x5d84, 0x5d82, 0x5da2, 0x5d9d, 0x5dac, 0x5dae, 0x5dbd, 0x5d90, 0x5db7, 0x5dbc, 0x5dc9, 0x5dcd, 0x5dd3, 0x5dd2, 0x5dd6, 0x5ddb, 0x5deb, 0x5df2, 0x5df5, 0x5e0b, 0x5e1a, 0x5e19, 0x5e11, 0x5e1b, 0x5e36, 0x5e37, 0x5e44, 0x5e43, 0x5e40, 0x5e4e, 0x5e57, 0x5e54, 0x5e5f, 0x5e62, 0x5e64, 0x5e47, 0x5e75, 0x5e76, 0x5e7a, 0x9ebc, 0x5e7f, 0x5ea0, 0x5ec1, 0x5ec2, 0x5ec8, 0x5ed0, 0x5ecf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x5ed6, 0x5ee3, 0x5edd, 0x5eda, 0x5edb, 0x5ee2, 0x5ee1, 0x5ee8, 0x5ee9, 0x5eec, 0x5ef1, 0x5ef3, 0x5ef0, 0x5ef4, 0x5ef8, 0x5efe, 0x5f03, 0x5f09, 0x5f5d, 0x5f5c, 0x5f0b, 0x5f11, 0x5f16, 0x5f29, 0x5f2d, 0x5f38, 0x5f41, 0x5f48, 0x5f4c, 0x5f4e, 0x5f2f, 0x5f51, 0x5f56, 0x5f57, 0x5f59, 0x5f61, 0x5f6d, 0x5f73, 0x5f77, 0x5f83, 0x5f82, 0x5f7f, 0x5f8a, 0x5f88, 0x5f91, 0x5f87, 0x5f9e, 0x5f99, 0x5f98, 0x5fa0, 0x5fa8, 0x5fad, 0x5fbc, 0x5fd6, 0x5ffb, 0x5fe4, 0x5ff8, 0x5ff1, 0x5fdd, 0x60b3, 0x5fff, 0x6021, 0x6060, 0xfffd, 0x6019, 0x6010, 0x6029, 0x600e, 0x6031, 0x601b, 0x6015, 0x602b, 0x6026, 0x600f, 0x603a, 0x605a, 0x6041, 0x606a, 0x6077, 0x605f, 0x604a, 0x6046, 0x604d, 0x6063, 0x6043, 0x6064, 0x6042, 0x606c, 0x606b, 0x6059, 0x6081, 0x608d, 0x60e7, 0x6083, 0x609a, 0x6084, 0x609b, 0x6096, 0x6097, 0x6092, 0x60a7, 0x608b, 0x60e1, 0x60b8, 0x60e0, 0x60d3, 0x60b4, 0x5ff0, 0x60bd, 0x60c6, 0x60b5, 0x60d8, 0x614d, 0x6115, 0x6106, 0x60f6, 0x60f7, 0x6100, 0x60f4, 0x60fa, 0x6103, 0x6121, 0x60fb, 0x60f1, 0x610d, 0x610e, 0x6147, 0x613e, 0x6128, 0x6127, 0x614a, 0x613f, 0x613c, 0x612c, 0x6134, 0x613d, 0x6142, 0x6144, 0x6173, 0x6177, 0x6158, 0x6159, 0x615a, 0x616b, 0x6174, 0x616f, 0x6165, 0x6171, 0x615f, 0x615d, 0x6153, 0x6175, 0x6199, 0x6196, 0x6187, 0x61ac, 0x6194, 0x619a, 0x618a, 0x6191, 0x61ab, 0x61ae, 0x61cc, 0x61ca, 0x61c9, 0x61f7, 0x61c8, 0x61c3, 0x61c6, 0x61ba, 0x61cb, 0x7f79, 0x61cd, 0x61e6, 0x61e3, 0x61f6, 0x61fa, 0x61f4, 0x61ff, 0x61fd, 0x61fc, 0x61fe, 0x6200, 0x6208, 0x6209, 0x620d, 0x620c, 0x6214, 0x621b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x621e, 0x6221, 0x622a, 0x622e, 0x6230, 0x6232, 0x6233, 0x6241, 0x624e, 0x625e, 0x6263, 0x625b, 0x6260, 0x6268, 0x627c, 0x6282, 0x6289, 0x627e, 0x6292, 0x6293, 0x6296, 0x62d4, 0x6283, 0x6294, 0x62d7, 0x62d1, 0x62bb, 0x62cf, 0x62ff, 0x62c6, 0x64d4, 0x62c8, 0x62dc, 0x62cc, 0x62ca, 0x62c2, 0x62c7, 0x629b, 0x62c9, 0x630c, 0x62ee, 0x62f1, 0x6327, 0x6302, 0x6308, 0x62ef, 0x62f5, 0x6350, 0x633e, 0x634d, 0x641c, 0x634f, 0x6396, 0x638e, 0x6380, 0x63ab, 0x6376, 0x63a3, 0x638f, 0x6389, 0x639f, 0x63b5, 0x636b, 0xfffd, 0x6369, 0x63be, 0x63e9, 0x63c0, 0x63c6, 0x63e3, 0x63c9, 0x63d2, 0x63f6, 0x63c4, 0x6416, 0x6434, 0x6406, 0x6413, 0x6426, 0x6436, 0x651d, 0x6417, 0x6428, 0x640f, 0x6467, 0x646f, 0x6476, 0x644e, 0x652a, 0x6495, 0x6493, 0x64a5, 0x64a9, 0x6488, 0x64bc, 0x64da, 0x64d2, 0x64c5, 0x64c7, 0x64bb, 0x64d8, 0x64c2, 0x64f1, 0x64e7, 0x8209, 0x64e0, 0x64e1, 0x62ac, 0x64e3, 0x64ef, 0x652c, 0x64f6, 0x64f4, 0x64f2, 0x64fa, 0x6500, 0x64fd, 0x6518, 0x651c, 0x6505, 0x6524, 0x6523, 0x652b, 0x6534, 0x6535, 0x6537, 0x6536, 0x6538, 0x754b, 0x6548, 0x6556, 0x6555, 0x654d, 0x6558, 0x655e, 0x655d, 0x6572, 0x6578, 0x6582, 0x6583, 0x8b8a, 0x659b, 0x659f, 0x65ab, 0x65b7, 0x65c3, 0x65c6, 0x65c1, 0x65c4, 0x65cc, 0x65d2, 0x65db, 0x65d9, 0x65e0, 0x65e1, 0x65f1, 0x6772, 0x660a, 0x6603, 0x65fb, 0x6773, 0x6635, 0x6636, 0x6634, 0x661c, 0x664f, 0x6644, 0x6649, 0x6641, 0x665e, 0x665d, 0x6664, 0x6667, 0x6668, 0x665f, 0x6662, 0x6670, 0x6683, 0x6688, 0x668e, 0x6689, 0x6684, 0x6698, 0x669d, 0x66c1, 0x66b9, 0x66c9, 0x66be, 0x66bc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x66c4, 0x66b8, 0x66d6, 0x66da, 0x66e0, 0x663f, 0x66e6, 0x66e9, 0x66f0, 0x66f5, 0x66f7, 0x670f, 0x6716, 0x671e, 0x6726, 0x6727, 0x9738, 0x672e, 0x673f, 0x6736, 0x6741, 0x6738, 0x6737, 0x6746, 0x675e, 0x6760, 0x6759, 0x6763, 0x6764, 0x6789, 0x6770, 0x67a9, 0x677c, 0x676a, 0x678c, 0x678b, 0x67a6, 0x67a1, 0x6785, 0x67b7, 0x67ef, 0x67b4, 0x67ec, 0x67b3, 0x67e9, 0x67b8, 0x67e4, 0x67de, 0x67dd, 0x67e2, 0x67ee, 0x67b9, 0x67ce, 0x67c6, 0x67e7, 0x6a9c, 0x681e, 0x6846, 0x6829, 0x6840, 0x684d, 0x6832, 0x684e, 0xfffd, 0x68b3, 0x682b, 0x6859, 0x6863, 0x6877, 0x687f, 0x689f, 0x688f, 0x68ad, 0x6894, 0x689d, 0x689b, 0x6883, 0x6aae, 0x68b9, 0x6874, 0x68b5, 0x68a0, 0x68ba, 0x690f, 0x688d, 0x687e, 0x6901, 0x68ca, 0x6908, 0x68d8, 0x6922, 0x6926, 0x68e1, 0x690c, 0x68cd, 0x68d4, 0x68e7, 0x68d5, 0x6936, 0x6912, 0x6904, 0x68d7, 0x68e3, 0x6925, 0x68f9, 0x68e0, 0x68ef, 0x6928, 0x692a, 0x691a, 0x6923, 0x6921, 0x68c6, 0x6979, 0x6977, 0x695c, 0x6978, 0x696b, 0x6954, 0x697e, 0x696e, 0x6939, 0x6974, 0x693d, 0x6959, 0x6930, 0x6961, 0x695e, 0x695d, 0x6981, 0x696a, 0x69b2, 0x69ae, 0x69d0, 0x69bf, 0x69c1, 0x69d3, 0x69be, 0x69ce, 0x5be8, 0x69ca, 0x69dd, 0x69bb, 0x69c3, 0x69a7, 0x6a2e, 0x6991, 0x69a0, 0x699c, 0x6995, 0x69b4, 0x69de, 0x69e8, 0x6a02, 0x6a1b, 0x69ff, 0x6b0a, 0x69f9, 0x69f2, 0x69e7, 0x6a05, 0x69b1, 0x6a1e, 0x69ed, 0x6a14, 0x69eb, 0x6a0a, 0x6a12, 0x6ac1, 0x6a23, 0x6a13, 0x6a44, 0x6a0c, 0x6a72, 0x6a36, 0x6a78, 0x6a47, 0x6a62, 0x6a59, 0x6a66, 0x6a48, 0x6a38, 0x6a22, 0x6a90, 0x6a8d, 0x6aa0, 0x6a84, 0x6aa2, 0x6aa3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x6a97, 0x8617, 0x6abb, 0x6ac3, 0x6ac2, 0x6ab8, 0x6ab3, 0x6aac, 0x6ade, 0x6ad1, 0x6adf, 0x6aaa, 0x6ada, 0x6aea, 0x6afb, 0x6b05, 0x8616, 0x6afa, 0x6b12, 0x6b16, 0x9b31, 0x6b1f, 0x6b38, 0x6b37, 0x76dc, 0x6b39, 0x98ee, 0x6b47, 0x6b43, 0x6b49, 0x6b50, 0x6b59, 0x6b54, 0x6b5b, 0x6b5f, 0x6b61, 0x6b78, 0x6b79, 0x6b7f, 0x6b80, 0x6b84, 0x6b83, 0x6b8d, 0x6b98, 0x6b95, 0x6b9e, 0x6ba4, 0x6baa, 0x6bab, 0x6baf, 0x6bb2, 0x6bb1, 0x6bb3, 0x6bb7, 0x6bbc, 0x6bc6, 0x6bcb, 0x6bd3, 0x6bdf, 0x6bec, 0x6beb, 0x6bf3, 0x6bef, 0xfffd, 0x9ebe, 0x6c08, 0x6c13, 0x6c14, 0x6c1b, 0x6c24, 0x6c23, 0x6c5e, 0x6c55, 0x6c62, 0x6c6a, 0x6c82, 0x6c8d, 0x6c9a, 0x6c81, 0x6c9b, 0x6c7e, 0x6c68, 0x6c73, 0x6c92, 0x6c90, 0x6cc4, 0x6cf1, 0x6cd3, 0x6cbd, 0x6cd7, 0x6cc5, 0x6cdd, 0x6cae, 0x6cb1, 0x6cbe, 0x6cba, 0x6cdb, 0x6cef, 0x6cd9, 0x6cea, 0x6d1f, 0x884d, 0x6d36, 0x6d2b, 0x6d3d, 0x6d38, 0x6d19, 0x6d35, 0x6d33, 0x6d12, 0x6d0c, 0x6d63, 0x6d93, 0x6d64, 0x6d5a, 0x6d79, 0x6d59, 0x6d8e, 0x6d95, 0x6fe4, 0x6d85, 0x6df9, 0x6e15, 0x6e0a, 0x6db5, 0x6dc7, 0x6de6, 0x6db8, 0x6dc6, 0x6dec, 0x6dde, 0x6dcc, 0x6de8, 0x6dd2, 0x6dc5, 0x6dfa, 0x6dd9, 0x6de4, 0x6dd5, 0x6dea, 0x6dee, 0x6e2d, 0x6e6e, 0x6e2e, 0x6e19, 0x6e72, 0x6e5f, 0x6e3e, 0x6e23, 0x6e6b, 0x6e2b, 0x6e76, 0x6e4d, 0x6e1f, 0x6e43, 0x6e3a, 0x6e4e, 0x6e24, 0x6eff, 0x6e1d, 0x6e38, 0x6e82, 0x6eaa, 0x6e98, 0x6ec9, 0x6eb7, 0x6ed3, 0x6ebd, 0x6eaf, 0x6ec4, 0x6eb2, 0x6ed4, 0x6ed5, 0x6e8f, 0x6ea5, 0x6ec2, 0x6e9f, 0x6f41, 0x6f11, 0x704c, 0x6eec, 0x6ef8, 0x6efe, 0x6f3f, 0x6ef2, 0x6f31, 0x6eef, 0x6f32, 0x6ecc }; static USHORT /* Shift-JIS to Unicode */ sju_e040[] = { /* 0xe040 thru 0xeaa4 */ 0x6f3e, 0x6f13, 0x6ef7, 0x6f86, 0x6f7a, 0x6f78, 0x6f81, 0x6f80, 0x6f6f, 0x6f5b, 0x6ff3, 0x6f6d, 0x6f82, 0x6f7c, 0x6f58, 0x6f8e, 0x6f91, 0x6fc2, 0x6f66, 0x6fb3, 0x6fa3, 0x6fa1, 0x6fa4, 0x6fb9, 0x6fc6, 0x6faa, 0x6fdf, 0x6fd5, 0x6fec, 0x6fd4, 0x6fd8, 0x6ff1, 0x6fee, 0x6fdb, 0x7009, 0x700b, 0x6ffa, 0x7011, 0x7001, 0x700f, 0x6ffe, 0x701b, 0x701a, 0x6f74, 0x701d, 0x7018, 0x701f, 0x7030, 0x703e, 0x7032, 0x7051, 0x7063, 0x7099, 0x7092, 0x70af, 0x70f1, 0x70ac, 0x70b8, 0x70b3, 0x70ae, 0x70df, 0x70cb, 0x70dd, 0xfffd, 0x70d9, 0x7109, 0x70fd, 0x711c, 0x7119, 0x7165, 0x7155, 0x7188, 0x7166, 0x7162, 0x714c, 0x7156, 0x716c, 0x718f, 0x71fb, 0x7184, 0x7195, 0x71a8, 0x71ac, 0x71d7, 0x71b9, 0x71be, 0x71d2, 0x71c9, 0x71d4, 0x71ce, 0x71e0, 0x71ec, 0x71e7, 0x71f5, 0x71fc, 0x71f9, 0x71ff, 0x720d, 0x7210, 0x721b, 0x7228, 0x722d, 0x722c, 0x7230, 0x7232, 0x723b, 0x723c, 0x723f, 0x7240, 0x7246, 0x724b, 0x7258, 0x7274, 0x727e, 0x7282, 0x7281, 0x7287, 0x7292, 0x7296, 0x72a2, 0x72a7, 0x72b9, 0x72b2, 0x72c3, 0x72c6, 0x72c4, 0x72ce, 0x72d2, 0x72e2, 0x72e0, 0x72e1, 0x72f9, 0x72f7, 0x500f, 0x7317, 0x730a, 0x731c, 0x7316, 0x731d, 0x7334, 0x732f, 0x7329, 0x7325, 0x733e, 0x734e, 0x734f, 0x9ed8, 0x7357, 0x736a, 0x7368, 0x7370, 0x7378, 0x7375, 0x737b, 0x737a, 0x73c8, 0x73b3, 0x73ce, 0x73bb, 0x73c0, 0x73e5, 0x73ee, 0x73de, 0x74a2, 0x7405, 0x746f, 0x7425, 0x73f8, 0x7432, 0x743a, 0x7455, 0x743f, 0x745f, 0x7459, 0x7441, 0x745c, 0x7469, 0x7470, 0x7463, 0x746a, 0x7476, 0x747e, 0x748b, 0x749e, 0x74a7, 0x74ca, 0x74cf, 0x74d4, 0x73f1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x74e0, 0x74e3, 0x74e7, 0x74e9, 0x74ee, 0x74f2, 0x74f0, 0x74f1, 0x74f8, 0x74f7, 0x7504, 0x7503, 0x7505, 0x750c, 0x750e, 0x750d, 0x7515, 0x7513, 0x751e, 0x7526, 0x752c, 0x753c, 0x7544, 0x754d, 0x754a, 0x7549, 0x755b, 0x7546, 0x755a, 0x7569, 0x7564, 0x7567, 0x756b, 0x756d, 0x7578, 0x7576, 0x7586, 0x7587, 0x7574, 0x758a, 0x7589, 0x7582, 0x7594, 0x759a, 0x759d, 0x75a5, 0x75a3, 0x75c2, 0x75b3, 0x75c3, 0x75b5, 0x75bd, 0x75b8, 0x75bc, 0x75b1, 0x75cd, 0x75ca, 0x75d2, 0x75d9, 0x75e3, 0x75de, 0x75fe, 0x75ff, 0xfffd, 0x75fc, 0x7601, 0x75f0, 0x75fa, 0x75f2, 0x75f3, 0x760b, 0x760d, 0x7609, 0x761f, 0x7627, 0x7620, 0x7621, 0x7622, 0x7624, 0x7634, 0x7630, 0x763b, 0x7647, 0x7648, 0x7646, 0x765c, 0x7658, 0x7661, 0x7662, 0x7668, 0x7669, 0x766a, 0x7667, 0x766c, 0x7670, 0x7672, 0x7676, 0x7678, 0x767c, 0x7680, 0x7683, 0x7688, 0x768b, 0x768e, 0x7696, 0x7693, 0x7699, 0x769a, 0x76b0, 0x76b4, 0x76b8, 0x76b9, 0x76ba, 0x76c2, 0x76cd, 0x76d6, 0x76d2, 0x76de, 0x76e1, 0x76e5, 0x76e7, 0x76ea, 0x862f, 0x76fb, 0x7708, 0x7707, 0x7704, 0x7729, 0x7724, 0x771e, 0x7725, 0x7726, 0x771b, 0x7737, 0x7738, 0x7747, 0x775a, 0x7768, 0x776b, 0x775b, 0x7765, 0x777f, 0x777e, 0x7779, 0x778e, 0x778b, 0x7791, 0x77a0, 0x779e, 0x77b0, 0x77b6, 0x77b9, 0x77bf, 0x77bc, 0x77bd, 0x77bb, 0x77c7, 0x77cd, 0x77d7, 0x77da, 0x77dc, 0x77e3, 0x77ee, 0x77fc, 0x780c, 0x7812, 0x7926, 0x7820, 0x792a, 0x7845, 0x788e, 0x7874, 0x7886, 0x787c, 0x789a, 0x788c, 0x78a3, 0x78b5, 0x78aa, 0x78af, 0x78d1, 0x78c6, 0x78cb, 0x78d4, 0x78be, 0x78bc, 0x78c5, 0x78ca, 0x78ec, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x78e7, 0x78da, 0x78fd, 0x78f4, 0x7907, 0x7912, 0x7911, 0x7919, 0x792c, 0x792b, 0x7940, 0x7960, 0x7957, 0x795f, 0x795a, 0x7955, 0x7953, 0x797a, 0x797f, 0x798a, 0x799d, 0x79a7, 0x9f4b, 0x79aa, 0x79ae, 0x79b3, 0x79b9, 0x79ba, 0x79c9, 0x79d5, 0x79e7, 0x79ec, 0x79e1, 0x79e3, 0x7a08, 0x7a0d, 0x7a18, 0x7a19, 0x7a20, 0x7a1f, 0x7980, 0x7a31, 0x7a3b, 0x7a3e, 0x7a37, 0x7a43, 0x7a57, 0x7a49, 0x7a61, 0x7a62, 0x7a69, 0x9f9d, 0x7a70, 0x7a79, 0x7a7d, 0x7a88, 0x7a97, 0x7a95, 0x7a98, 0x7a96, 0x7aa9, 0x7ac8, 0x7ab0, 0xfffd, 0x7ab6, 0x7ac5, 0x7ac4, 0x7abf, 0x9083, 0x7ac7, 0x7aca, 0x7acd, 0x7acf, 0x7ad5, 0x7ad3, 0x7ad9, 0x7ada, 0x7add, 0x7ae1, 0x7ae2, 0x7ae6, 0x7aed, 0x7af0, 0x7b02, 0x7b0f, 0x7b0a, 0x7b06, 0x7b33, 0x7b18, 0x7b19, 0x7b1e, 0x7b35, 0x7b28, 0x7b36, 0x7b50, 0x7b7a, 0x7b04, 0x7b4d, 0x7b0b, 0x7b4c, 0x7b45, 0x7b75, 0x7b65, 0x7b74, 0x7b67, 0x7b70, 0x7b71, 0x7b6c, 0x7b6e, 0x7b9d, 0x7b98, 0x7b9f, 0x7b8d, 0x7b9c, 0x7b9a, 0x7b8b, 0x7b92, 0x7b8f, 0x7b5d, 0x7b99, 0x7bcb, 0x7bc1, 0x7bcc, 0x7bcf, 0x7bb4, 0x7bc6, 0x7bdd, 0x7be9, 0x7c11, 0x7c14, 0x7be6, 0x7be5, 0x7c60, 0x7c00, 0x7c07, 0x7c13, 0x7bf3, 0x7bf7, 0x7c17, 0x7c0d, 0x7bf6, 0x7c23, 0x7c27, 0x7c2a, 0x7c1f, 0x7c37, 0x7c2b, 0x7c3d, 0x7c4c, 0x7c43, 0x7c54, 0x7c4f, 0x7c40, 0x7c50, 0x7c58, 0x7c5f, 0x7c64, 0x7c56, 0x7c65, 0x7c6c, 0x7c75, 0x7c83, 0x7c90, 0x7ca4, 0x7cad, 0x7ca2, 0x7cab, 0x7ca1, 0x7ca8, 0x7cb3, 0x7cb2, 0x7cb1, 0x7cae, 0x7cb9, 0x7cbd, 0x7cc0, 0x7cc5, 0x7cc2, 0x7cd8, 0x7cd2, 0x7cdc, 0x7ce2, 0x9b3b, 0x7cef, 0x7cf2, 0x7cf4, 0x7cf6, 0x7cfa, 0x7d06, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x7d02, 0x7d1c, 0x7d15, 0x7d0a, 0x7d45, 0x7d4b, 0x7d2e, 0x7d32, 0x7d3f, 0x7d35, 0x7d46, 0x7d73, 0x7d56, 0x7d4e, 0x7d72, 0x7d68, 0x7d6e, 0x7d4f, 0x7d63, 0x7d93, 0x7d89, 0x7d5b, 0x7d8f, 0x7d7d, 0x7d9b, 0x7dba, 0x7dae, 0x7da3, 0x7db5, 0x7dc7, 0x7dbd, 0x7dab, 0x7e3d, 0x7da2, 0x7daf, 0x7ddc, 0x7db8, 0x7d9f, 0x7db0, 0x7dd8, 0x7ddd, 0x7de4, 0x7dde, 0x7dfb, 0x7df2, 0x7de1, 0x7e05, 0x7e0a, 0x7e23, 0x7e21, 0x7e12, 0x7e31, 0x7e1f, 0x7e09, 0x7e0b, 0x7e22, 0x7e46, 0x7e66, 0x7e3b, 0x7e35, 0x7e39, 0x7e43, 0x7e37, 0xfffd, 0x7e32, 0x7e3a, 0x7e67, 0x7e5d, 0x7e56, 0x7e5e, 0x7e59, 0x7e5a, 0x7e79, 0x7e6a, 0x7e69, 0x7e7c, 0x7e7b, 0x7e83, 0x7dd5, 0x7e7d, 0x8fae, 0x7e7f, 0x7e88, 0x7e89, 0x7e8c, 0x7e92, 0x7e90, 0x7e93, 0x7e94, 0x7e96, 0x7e8e, 0x7e9b, 0x7e9c, 0x7f38, 0x7f3a, 0x7f45, 0x7f4c, 0x7f4d, 0x7f4e, 0x7f50, 0x7f51, 0x7f55, 0x7f54, 0x7f58, 0x7f5f, 0x7f60, 0x7f68, 0x7f69, 0x7f67, 0x7f78, 0x7f82, 0x7f86, 0x7f83, 0x7f88, 0x7f87, 0x7f8c, 0x7f94, 0x7f9e, 0x7f9d, 0x7f9a, 0x7fa3, 0x7faf, 0x7fb2, 0x7fb9, 0x7fae, 0x7fb6, 0x7fb8, 0x8b71, 0x7fc5, 0x7fc6, 0x7fca, 0x7fd5, 0x7fd4, 0x7fe1, 0x7fe6, 0x7fe9, 0x7ff3, 0x7ff9, 0x98dc, 0x8006, 0x8004, 0x800b, 0x8012, 0x8018, 0x8019, 0x801c, 0x8021, 0x8028, 0x803f, 0x803b, 0x804a, 0x8046, 0x8052, 0x8058, 0x805a, 0x805f, 0x8062, 0x8068, 0x8073, 0x8072, 0x8070, 0x8076, 0x8079, 0x807d, 0x807f, 0x8084, 0x8086, 0x8085, 0x809b, 0x8093, 0x809a, 0x80ad, 0x5190, 0x80ac, 0x80db, 0x80e5, 0x80d9, 0x80dd, 0x80c4, 0x80da, 0x80d6, 0x8109, 0x80ef, 0x80f1, 0x811b, 0x8129, 0x8123, 0x812f, 0x814b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x968b, 0x8146, 0x813e, 0x8153, 0x8151, 0x80fc, 0x8171, 0x816e, 0x8165, 0x8166, 0x8174, 0x8183, 0x8188, 0x818a, 0x8180, 0x8182, 0x81a0, 0x8195, 0x81a4, 0x81a3, 0x815f, 0x8193, 0x81a9, 0x81b0, 0x81b5, 0x81be, 0x81b8, 0x81bd, 0x81c0, 0x81c2, 0x81ba, 0x81c9, 0x81cd, 0x81d1, 0x81d9, 0x81d8, 0x81c8, 0x81da, 0x81df, 0x81e0, 0x81e7, 0x81fa, 0x81fb, 0x81fe, 0x8201, 0x8202, 0x8205, 0x8207, 0x820a, 0x820d, 0x8210, 0x8216, 0x8229, 0x822b, 0x8238, 0x8233, 0x8240, 0x8259, 0x8258, 0x825d, 0x825a, 0x825f, 0x8264, 0xfffd, 0x8262, 0x8268, 0x826a, 0x826b, 0x822e, 0x8271, 0x8277, 0x8278, 0x827e, 0x828d, 0x8292, 0x82ab, 0x829f, 0x82bb, 0x82ac, 0x82e1, 0x82e3, 0x82df, 0x82d2, 0x82f4, 0x82f3, 0x82fa, 0x8393, 0x8303, 0x82fb, 0x82f9, 0x82de, 0x8306, 0x82dc, 0x8309, 0x82d9, 0x8335, 0x8334, 0x8316, 0x8332, 0x8331, 0x8340, 0x8339, 0x8350, 0x8345, 0x832f, 0x832b, 0x8317, 0x8318, 0x8385, 0x839a, 0x83aa, 0x839f, 0x83a2, 0x8396, 0x8323, 0x838e, 0x8387, 0x838a, 0x837c, 0x83b5, 0x8373, 0x8375, 0x83a0, 0x8389, 0x83a8, 0x83f4, 0x8413, 0x83eb, 0x83ce, 0x83fd, 0x8403, 0x83d8, 0x840b, 0x83c1, 0x83f7, 0x8407, 0x83e0, 0x83f2, 0x840d, 0x8422, 0x8420, 0x83bd, 0x8438, 0x8506, 0x83fb, 0x846d, 0x842a, 0x843c, 0x855a, 0x8484, 0x8477, 0x846b, 0x84ad, 0x846e, 0x8482, 0x8469, 0x8446, 0x842c, 0x846f, 0x8479, 0x8435, 0x84ca, 0x8462, 0x84b9, 0x84bf, 0x849f, 0x84d9, 0x84cd, 0x84bb, 0x84da, 0x84d0, 0x84c1, 0x84c6, 0x84d6, 0x84a1, 0x8521, 0x84ff, 0x84f4, 0x8517, 0x8518, 0x852c, 0x851f, 0x8515, 0x8514, 0x84fc, 0x8540, 0x8563, 0x8558, 0x8548, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8541, 0x8602, 0x854b, 0x8555, 0x8580, 0x85a4, 0x8588, 0x8591, 0x858a, 0x85a8, 0x856d, 0x8594, 0x859b, 0x85ea, 0x8587, 0x859c, 0x8577, 0x857e, 0x8590, 0x85c9, 0x85ba, 0x85cf, 0x85b9, 0x85d0, 0x85d5, 0x85dd, 0x85e5, 0x85dc, 0x85f9, 0x860a, 0x8613, 0x860b, 0x85fe, 0x85fa, 0x8606, 0x8622, 0x861a, 0x8630, 0x863f, 0x864d, 0x4e55, 0x8654, 0x865f, 0x8667, 0x8671, 0x8693, 0x86a3, 0x86a9, 0x86aa, 0x868b, 0x868c, 0x86b6, 0x86af, 0x86c4, 0x86c6, 0x86b0, 0x86c9, 0x8823, 0x86ab, 0x86d4, 0x86de, 0x86e9, 0x86ec, 0xfffd, 0x86df, 0x86db, 0x86ef, 0x8712, 0x8706, 0x8708, 0x8700, 0x8703, 0x86fb, 0x8711, 0x8709, 0x870d, 0x86f9, 0x870a, 0x8734, 0x873f, 0x8737, 0x873b, 0x8725, 0x8729, 0x871a, 0x8760, 0x875f, 0x8778, 0x874c, 0x874e, 0x8774, 0x8757, 0x8768, 0x876e, 0x8759, 0x8753, 0x8763, 0x876a, 0x8805, 0x87a2, 0x879f, 0x8782, 0x87af, 0x87cb, 0x87bd, 0x87c0, 0x87d0, 0x96d6, 0x87ab, 0x87c4, 0x87b3, 0x87c7, 0x87c6, 0x87bb, 0x87ef, 0x87f2, 0x87e0, 0x880f, 0x880d, 0x87fe, 0x87f6, 0x87f7, 0x880e, 0x87d2, 0x8811, 0x8816, 0x8815, 0x8822, 0x8821, 0x8831, 0x8836, 0x8839, 0x8827, 0x883b, 0x8844, 0x8842, 0x8852, 0x8859, 0x885e, 0x8862, 0x886b, 0x8881, 0x887e, 0x889e, 0x8875, 0x887d, 0x88b5, 0x8872, 0x8882, 0x8897, 0x8892, 0x88ae, 0x8899, 0x88a2, 0x888d, 0x88a4, 0x88b0, 0x88bf, 0x88b1, 0x88c3, 0x88c4, 0x88d4, 0x88d8, 0x88d9, 0x88dd, 0x88f9, 0x8902, 0x88fc, 0x88f4, 0x88e8, 0x88f2, 0x8904, 0x890c, 0x890a, 0x8913, 0x8943, 0x891e, 0x8925, 0x892a, 0x892b, 0x8941, 0x8944, 0x893b, 0x8936, 0x8938, 0x894c, 0x891d, 0x8960, 0x895e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8966, 0x8964, 0x896d, 0x896a, 0x896f, 0x8974, 0x8977, 0x897e, 0x8983, 0x8988, 0x898a, 0x8993, 0x8998, 0x89a1, 0x89a9, 0x89a6, 0x89ac, 0x89af, 0x89b2, 0x89ba, 0x89bd, 0x89bf, 0x89c0, 0x89da, 0x89dc, 0x89dd, 0x89e7, 0x89f4, 0x89f8, 0x8a03, 0x8a16, 0x8a10, 0x8a0c, 0x8a1b, 0x8a1d, 0x8a25, 0x8a36, 0x8a41, 0x8a5b, 0x8a52, 0x8a46, 0x8a48, 0x8a7c, 0x8a6d, 0x8a6c, 0x8a62, 0x8a85, 0x8a82, 0x8a84, 0x8aa8, 0x8aa1, 0x8a91, 0x8aa5, 0x8aa6, 0x8a9a, 0x8aa3, 0x8ac4, 0x8acd, 0x8ac2, 0x8ada, 0x8aeb, 0x8af3, 0x8ae7, 0xfffd, 0x8ae4, 0x8af1, 0x8b14, 0x8ae0, 0x8ae2, 0x8af7, 0x8ade, 0x8adb, 0x8b0c, 0x8b07, 0x8b1a, 0x8ae1, 0x8b16, 0x8b10, 0x8b17, 0x8b20, 0x8b33, 0x97ab, 0x8b26, 0x8b2b, 0x8b3e, 0x8b28, 0x8b41, 0x8b4c, 0x8b4f, 0x8b4e, 0x8b49, 0x8b56, 0x8b5b, 0x8b5a, 0x8b6b, 0x8b5f, 0x8b6c, 0x8b6f, 0x8b74, 0x8b7d, 0x8b80, 0x8b8c, 0x8b8e, 0x8b92, 0x8b93, 0x8b96, 0x8b99, 0x8b9a, 0x8c3a, 0x8c41, 0x8c3f, 0x8c48, 0x8c4c, 0x8c4e, 0x8c50, 0x8c55, 0x8c62, 0x8c6c, 0x8c78, 0x8c7a, 0x8c82, 0x8c89, 0x8c85, 0x8c8a, 0x8c8d, 0x8c8e, 0x8c94, 0x8c7c, 0x8c98, 0x621d, 0x8cad, 0x8caa, 0x8cbd, 0x8cb2, 0x8cb3, 0x8cae, 0x8cb6, 0x8cc8, 0x8cc1, 0x8ce4, 0x8ce3, 0x8cda, 0x8cfd, 0x8cfa, 0x8cfb, 0x8d04, 0x8d05, 0x8d0a, 0x8d07, 0x8d0f, 0x8d0d, 0x8d10, 0x9f4e, 0x8d13, 0x8ccd, 0x8d14, 0x8d16, 0x8d67, 0x8d6d, 0x8d71, 0x8d73, 0x8d81, 0x8d99, 0x8dc2, 0x8dbe, 0x8dba, 0x8dcf, 0x8dda, 0x8dd6, 0x8dcc, 0x8ddb, 0x8dcb, 0x8dea, 0x8deb, 0x8ddf, 0x8de3, 0x8dfc, 0x8e08, 0x8e09, 0x8dff, 0x8e1d, 0x8e1e, 0x8e10, 0x8e1f, 0x8e42, 0x8e35, 0x8e30, 0x8e34, 0x8e4a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e47, 0x8e49, 0x8e4c, 0x8e50, 0x8e48, 0x8e59, 0x8e64, 0x8e60, 0x8e2a, 0x8e63, 0x8e55, 0x8e76, 0x8e72, 0x8e7c, 0x8e81, 0x8e87, 0x8e85, 0x8e84, 0x8e8b, 0x8e8a, 0x8e93, 0x8e91, 0x8e94, 0x8e99, 0x8eaa, 0x8ea1, 0x8eac, 0x8eb0, 0x8ec6, 0x8eb1, 0x8ebe, 0x8ec5, 0x8ec8, 0x8ecb, 0x8edb, 0x8ee3, 0x8efc, 0x8efb, 0x8eeb, 0x8efe, 0x8f0a, 0x8f05, 0x8f15, 0x8f12, 0x8f19, 0x8f13, 0x8f1c, 0x8f1f, 0x8f1b, 0x8f0c, 0x8f26, 0x8f33, 0x8f3b, 0x8f39, 0x8f45, 0x8f42, 0x8f3e, 0x8f4c, 0x8f49, 0x8f46, 0x8f4e, 0x8f57, 0x8f5c, 0xfffd, 0x8f62, 0x8f63, 0x8f64, 0x8f9c, 0x8f9f, 0x8fa3, 0x8fad, 0x8faf, 0x8fb7, 0x8fda, 0x8fe5, 0x8fe2, 0x8fea, 0x8fef, 0x9087, 0x8ff4, 0x9005, 0x8ff9, 0x8ffa, 0x9011, 0x9015, 0x9021, 0x900d, 0x901e, 0x9016, 0x900b, 0x9027, 0x9036, 0x9035, 0x9039, 0x8ff8, 0x904f, 0x9050, 0x9051, 0x9052, 0x900e, 0x9049, 0x903e, 0x9056, 0x9058, 0x905e, 0x9068, 0x906f, 0x9076, 0x96a8, 0x9072, 0x9082, 0x907d, 0x9081, 0x9080, 0x908a, 0x9089, 0x908f, 0x90a8, 0x90af, 0x90b1, 0x90b5, 0x90e2, 0x90e4, 0x6248, 0x90db, 0x9102, 0x9112, 0x9119, 0x9132, 0x9130, 0x914a, 0x9156, 0x9158, 0x9163, 0x9165, 0x9169, 0x9173, 0x9172, 0x918b, 0x9189, 0x9182, 0x91a2, 0x91ab, 0x91af, 0x91aa, 0x91b5, 0x91b4, 0x91ba, 0x91c0, 0x91c1, 0x91c9, 0x91cb, 0x91d0, 0x91d6, 0x91df, 0x91e1, 0x91db, 0x91fc, 0x91f5, 0x91f6, 0x921e, 0x91ff, 0x9214, 0x922c, 0x9215, 0x9211, 0x925e, 0x9257, 0x9245, 0x9249, 0x9264, 0x9248, 0x9295, 0x923f, 0x924b, 0x9250, 0x929c, 0x9296, 0x9293, 0x929b, 0x925a, 0x92cf, 0x92b9, 0x92b7, 0x92e9, 0x930f, 0x92fa, 0x9344, 0x932e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9319, 0x9322, 0x931a, 0x9323, 0x933a, 0x9335, 0x933b, 0x935c, 0x9360, 0x937c, 0x936e, 0x9356, 0x93b0, 0x93ac, 0x93ad, 0x9394, 0x93b9, 0x93d6, 0x93d7, 0x93e8, 0x93e5, 0x93d8, 0x93c3, 0x93dd, 0x93d0, 0x93c8, 0x93e4, 0x941a, 0x9414, 0x9413, 0x9403, 0x9407, 0x9410, 0x9436, 0x942b, 0x9435, 0x9421, 0x943a, 0x9441, 0x9452, 0x9444, 0x945b, 0x9460, 0x9462, 0x945e, 0x946a, 0x9229, 0x9470, 0x9475, 0x9477, 0x947d, 0x945a, 0x947c, 0x947e, 0x9481, 0x947f, 0x9582, 0x9587, 0x958a, 0x9594, 0x9596, 0x9598, 0x9599, 0xfffd, 0x95a0, 0x95a8, 0x95a7, 0x95ad, 0x95bc, 0x95bb, 0x95b9, 0x95be, 0x95ca, 0x6ff6, 0x95c3, 0x95cd, 0x95cc, 0x95d5, 0x95d4, 0x95d6, 0x95dc, 0x95e1, 0x95e5, 0x95e2, 0x9621, 0x9628, 0x962e, 0x962f, 0x9642, 0x964c, 0x964f, 0x964b, 0x9677, 0x965c, 0x965e, 0x965d, 0x965f, 0x9666, 0x9672, 0x966c, 0x968d, 0x9698, 0x9695, 0x9697, 0x96aa, 0x96a7, 0x96b1, 0x96b2, 0x96b0, 0x96b4, 0x96b6, 0x96b8, 0x96b9, 0x96ce, 0x96cb, 0x96c9, 0x96cd, 0x894d, 0x96dc, 0x970d, 0x96d5, 0x96f9, 0x9704, 0x9706, 0x9708, 0x9713, 0x970e, 0x9711, 0x970f, 0x9716, 0x9719, 0x9724, 0x972a, 0x9730, 0x9739, 0x973d, 0x973e, 0x9744, 0x9746, 0x9748, 0x9742, 0x9749, 0x975c, 0x9760, 0x9764, 0x9766, 0x9768, 0x52d2, 0x976b, 0x9771, 0x9779, 0x9785, 0x977c, 0x9781, 0x977a, 0x9786, 0x978b, 0x978f, 0x9790, 0x979c, 0x97a8, 0x97a6, 0x97a3, 0x97b3, 0x97b4, 0x97c3, 0x97c6, 0x97c8, 0x97cb, 0x97dc, 0x97ed, 0x9f4f, 0x97f2, 0x7adf, 0x97f6, 0x97f5, 0x980f, 0x980c, 0x9838, 0x9824, 0x9821, 0x9837, 0x983d, 0x9846, 0x984f, 0x984b, 0x986b, 0x986f, 0x9870, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9871, 0x9874, 0x9873, 0x98aa, 0x98af, 0x98b1, 0x98b6, 0x98c4, 0x98c3, 0x98c6, 0x98e9, 0x98eb, 0x9903, 0x9909, 0x9912, 0x9914, 0x9918, 0x9921, 0x991d, 0x991e, 0x9924, 0x9920, 0x992c, 0x992e, 0x993d, 0x993e, 0x9942, 0x9949, 0x9945, 0x9950, 0x994b, 0x9951, 0x9952, 0x994c, 0x9955, 0x9997, 0x9998, 0x99a5, 0x99ad, 0x99ae, 0x99bc, 0x99df, 0x99db, 0x99dd, 0x99d8, 0x99d1, 0x99ed, 0x99ee, 0x99f1, 0x99f2, 0x99fb, 0x99f8, 0x9a01, 0x9a0f, 0x9a05, 0x99e2, 0x9a19, 0x9a2b, 0x9a37, 0x9a45, 0x9a42, 0x9a40, 0x9a43, 0xfffd, 0x9a3e, 0x9a55, 0x9a4d, 0x9a5b, 0x9a57, 0x9a5f, 0x9a62, 0x9a65, 0x9a64, 0x9a69, 0x9a6b, 0x9a6a, 0x9aad, 0x9ab0, 0x9abc, 0x9ac0, 0x9acf, 0x9ad1, 0x9ad3, 0x9ad4, 0x9ade, 0x9adf, 0x9ae2, 0x9ae3, 0x9ae6, 0x9aef, 0x9aeb, 0x9aee, 0x9af4, 0x9af1, 0x9af7, 0x9afb, 0x9b06, 0x9b18, 0x9b1a, 0x9b1f, 0x9b22, 0x9b23, 0x9b25, 0x9b27, 0x9b28, 0x9b29, 0x9b2a, 0x9b2e, 0x9b2f, 0x9b32, 0x9b44, 0x9b43, 0x9b4f, 0x9b4d, 0x9b4e, 0x9b51, 0x9b58, 0x9b74, 0x9b93, 0x9b83, 0x9b91, 0x9b96, 0x9b97, 0x9b9f, 0x9ba0, 0x9ba8, 0x9bb4, 0x9bc0, 0x9bca, 0x9bb9, 0x9bc6, 0x9bcf, 0x9bd1, 0x9bd2, 0x9be3, 0x9be2, 0x9be4, 0x9bd4, 0x9be1, 0x9c3a, 0x9bf2, 0x9bf1, 0x9bf0, 0x9c15, 0x9c14, 0x9c09, 0x9c13, 0x9c0c, 0x9c06, 0x9c08, 0x9c12, 0x9c0a, 0x9c04, 0x9c2e, 0x9c1b, 0x9c25, 0x9c24, 0x9c21, 0x9c30, 0x9c47, 0x9c32, 0x9c46, 0x9c3e, 0x9c5a, 0x9c60, 0x9c67, 0x9c76, 0x9c78, 0x9ce7, 0x9cec, 0x9cf0, 0x9d09, 0x9d08, 0x9ceb, 0x9d03, 0x9d06, 0x9d2a, 0x9d26, 0x9daf, 0x9d23, 0x9d1f, 0x9d44, 0x9d15, 0x9d12, 0x9d41, 0x9d3f, 0x9d3e, 0x9d46, 0x9d48, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d5d, 0x9d5e, 0x9d64, 0x9d51, 0x9d50, 0x9d59, 0x9d72, 0x9d89, 0x9d87, 0x9dab, 0x9d6f, 0x9d7a, 0x9d9a, 0x9da4, 0x9da9, 0x9db2, 0x9dc4, 0x9dc1, 0x9dbb, 0x9db8, 0x9dba, 0x9dc6, 0x9dcf, 0x9dc2, 0x9dd9, 0x9dd3, 0x9df8, 0x9de6, 0x9ded, 0x9def, 0x9dfd, 0x9e1a, 0x9e1b, 0x9e1e, 0x9e75, 0x9e79, 0x9e7d, 0x9e81, 0x9e88, 0x9e8b, 0x9e8c, 0x9e92, 0x9e95, 0x9e91, 0x9e9d, 0x9ea5, 0x9ea9, 0x9eb8, 0x9eaa, 0x9ead, 0x9761, 0x9ecc, 0x9ece, 0x9ecf, 0x9ed0, 0x9ed4, 0x9edc, 0x9ede, 0x9edd, 0x9ee0, 0x9ee5, 0x9ee8, 0x9eef, 0xfffd, 0x9ef4, 0x9ef6, 0x9ef7, 0x9ef9, 0x9efb, 0x9efc, 0x9efd, 0x9f07, 0x9f08, 0x76b7, 0x9f15, 0x9f21, 0x9f2c, 0x9f3e, 0x9f4a, 0x9f52, 0x9f54, 0x9f63, 0x9f5f, 0x9f60, 0x9f61, 0x9f66, 0x9f67, 0x9f6c, 0x9f6a, 0x9f77, 0x9f72, 0x9f76, 0x9f95, 0x9f9c, 0x9fa0, 0x582f, 0x69c7, 0x9059, 0x7464, 0x51dc, 0x7199 }; /* Unicode-to-Kanji tables... */ static USHORT /* Unicode to Shift-JIS */ usj_0391[] = { /* 0x0391 thru 0x039c */ 0x839f, 0x83a0, 0x83a1, 0x83a2, 0x83a3, 0x83a4, 0x83a5, 0x83a6, 0x83a7, 0x83a8, 0x83a9, 0x83aa, 0x83ab, 0x83ac, 0x83ad, 0x83ae, 0x83af, 0xfffd, 0x83b0, 0x83b1, 0x83b2, 0x83b3, 0x83b4, 0x83b5, 0x83b6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x83bf, 0x83c0, 0x83c1, 0x83c2, 0x83c3, 0x83c4, 0x83c5, 0x83c6, 0x83c7, 0x83c8, 0x83c9, 0x83ca, 0x83cb, 0x83cc, 0x83cd, 0x83ce, 0x83cf, 0xfffd, 0x83d0, 0x83d1, 0x83d2, 0x83d3, 0x83d4, 0x83d5, 0x83d6 }; static USHORT /* Unicode to Shift-JIS */ usj_0401[] = { /* 0x0401 thru 0x0451 */ 0x8446, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8440, 0x8441, 0x8442, 0x8443, 0x8444, 0x8445, 0x8447, 0x8448, 0x8449, 0x844a, 0x844b, 0x844c, 0x844d, 0x844e, 0x844f, 0x8450, 0x8451, 0x8452, 0x8453, 0x8454, 0x8455, 0x8456, 0x8457, 0x8458, 0x8459, 0x845a, 0x845b, 0x845c, 0x845d, 0x845e, 0x845f, 0x8460, 0x8470, 0x8471, 0x8472, 0x8473, 0x8474, 0x8475, 0x8477, 0x8478, 0x8479, 0x847a, 0x847b, 0x847c, 0x847d, 0x847e, 0x8480, 0x8481, 0x8482, 0x8483, 0x8484, 0x8485, 0x8486, 0x8487, 0x8488, 0x8489, 0x848a, 0x848b, 0x848c, 0x848d, 0x848e, 0x848f, 0x8490, 0x8491, 0xfffd, 0x8476 }; static USHORT /* Unicode to Shift-JIS */ usj_3000[] = { /* 0x3000 thru 0x30ff */ 0x8140, 0x8141, 0x8142, 0x8156, 0xfffd, 0x8158, 0x8159, 0x815a, 0x8171, 0x8172, 0x8173, 0x8174, 0x8175, 0x8176, 0x8177, 0x8178, 0x8179, 0x817a, 0x81a7, 0x81ac, 0x816b, 0x816c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8160, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x829f, 0x82a0, 0x82a1, 0x82a2, 0x82a3, 0x82a4, 0x82a5, 0x82a6, 0x82a7, 0x82a8, 0x82a9, 0x82aa, 0x82ab, 0x82ac, 0x82ad, 0x82ae, 0x82af, 0x82b0, 0x82b1, 0x82b2, 0x82b3, 0x82b4, 0x82b5, 0x82b6, 0x82b7, 0x82b8, 0x82b9, 0x82ba, 0x82bb, 0x82bc, 0x82bd, 0x82be, 0x82bf, 0x82c0, 0x82c1, 0x82c2, 0x82c3, 0x82c4, 0x82c5, 0x82c6, 0x82c7, 0x82c8, 0x82c9, 0x82ca, 0x82cb, 0x82cc, 0x82cd, 0x82ce, 0x82cf, 0x82d0, 0x82d1, 0x82d2, 0x82d3, 0x82d4, 0x82d5, 0x82d6, 0x82d7, 0x82d8, 0x82d9, 0x82da, 0x82db, 0x82dc, 0x82dd, 0x82de, 0x82df, 0x82e0, 0x82e1, 0x82e2, 0x82e3, 0x82e4, 0x82e5, 0x82e6, 0x82e7, 0x82e8, 0x82e9, 0x82ea, 0x82eb, 0x82ec, 0x82ed, 0x82ee, 0x82ef, 0x82f0, 0x82f1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x814a, 0x814b, 0x8154, 0x8155, 0xfffd, 0xfffd, 0x8340, 0x8341, 0x8342, 0x8343, 0x8344, 0x8345, 0x8346, 0x8347, 0x8348, 0x8349, 0x834a, 0x834b, 0x834c, 0x834d, 0x834e, 0x834f, 0x8350, 0x8351, 0x8352, 0x8353, 0x8354, 0x8355, 0x8356, 0x8357, 0x8358, 0x8359, 0x835a, 0x835b, 0x835c, 0x835d, 0x835e, 0x835f, 0x8360, 0x8361, 0x8362, 0x8363, 0x8364, 0x8365, 0x8366, 0x8367, 0x8368, 0x8369, 0x836a, 0x836b, 0x836c, 0x836d, 0x836e, 0x836f, 0x8370, 0x8371, 0x8372, 0x8373, 0x8374, 0x8375, 0x8376, 0x8377, 0x8378, 0x8379, 0x837a, 0x837b, 0x837c, 0x837d, 0x837e, 0x8380, 0x8381, 0x8382, 0x8383, 0x8384, 0x8385, 0x8386, 0x8387, 0x8388, 0x8389, 0x838a, 0x838b, 0x838c, 0x838d, 0x838e, 0x838f, 0x8390, 0x8391, 0x8392, 0x8393, 0x8394, 0x8395, 0x8396, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8145, 0x815b, 0x8152, 0x8153, 0xfffd }; static USHORT /* Unicode to Shift-JIS */ usj_ff00[] = { /* 0xff00 thru 0x0ff9f */ 0xfffd, 0x8149, 0xfffd, 0x8194, 0x8190, 0x8193, 0x8195, 0xfffd, 0x8169, 0x816a, 0x8196, 0x817b, 0x8143, 0xfffd, 0x8144, 0x815e, 0x824f, 0x8250, 0x8251, 0x8252, 0x8253, 0x8254, 0x8255, 0x8256, 0x8257, 0x8258, 0x8146, 0x8147, 0x8183, 0x8181, 0x8184, 0x8148, 0x8197, 0x8260, 0x8261, 0x8262, 0x8263, 0x8264, 0x8265, 0x8266, 0x8267, 0x8268, 0x8269, 0x826a, 0x826b, 0x826c, 0x826d, 0x826e, 0x826f, 0x8270, 0x8271, 0x8272, 0x8273, 0x8274, 0x8275, 0x8276, 0x8277, 0x8278, 0x8279, 0x816d, 0xfffd, 0x816e, 0x814f, 0x8151, 0x814d, 0x8281, 0x8282, 0x8283, 0x8284, 0x8285, 0x8286, 0x8287, 0x8288, 0x8289, 0x828a, 0x828b, 0x828c, 0x828d, 0x828e, 0x828f, 0x8290, 0x8291, 0x8292, 0x8293, 0x8294, 0x8295, 0x8296, 0x8297, 0x8298, 0x8299, 0x829a, 0x816f, 0x8162, 0x8170, 0xfffd, 0xfffd, 0xfffd, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df }; /* Now one humongous table for Kanji */ static USHORT /* Unicode to Shift-JIS */ usj_4e00[] = { /* 0x4e00 thru 0x9fa0 */ 0x88ea, 0x929a, 0xfffd, 0x8eb5, 0xfffd, 0xfffd, 0xfffd, 0x969c, 0x8fe4, 0x8e4f, 0x8fe3, 0x89ba, 0xfffd, 0x9573, 0x975e, 0xfffd, 0x98a0, 0x894e, 0xfffd, 0xfffd, 0x8a8e, 0x98a1, 0x90a2, 0x99c0, 0x8b75, 0x95b8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fe5, 0xfffd, 0xfffd, 0x97bc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95c0, 0xfffd, 0xfffd, 0xfffd, 0x98a2, 0xfffd, 0xfffd, 0x9286, 0xfffd, 0xfffd, 0xfffd, 0x98a3, 0x8bf8, 0xfffd, 0xfffd, 0xfffd, 0x98a4, 0xfffd, 0x8adb, 0x924f, 0xfffd, 0x8ee5, 0x98a5, 0xfffd, 0xfffd, 0x98a6, 0xfffd, 0xfffd, 0x98a7, 0x9454, 0xfffd, 0x8b76, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9456, 0xfffd, 0x93e1, 0x8cc1, 0x9652, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe568, 0x98a8, 0x8fe6, 0x98a9, 0x89b3, 0xfffd, 0xfffd, 0xfffd, 0x8be3, 0x8cee, 0x96e7, 0xfffd, 0xfffd, 0x9ba4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9790, 0xfffd, 0x93fb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8aa3, 0xfffd, 0x8b54, 0xfffd, 0x98aa, 0xfffd, 0xfffd, 0x98ab, 0x97b9, 0xfffd, 0x975c, 0x9188, 0x98ad, 0x8e96, 0x93f1, 0xfffd, 0x98b0, 0xfffd, 0xfffd, 0x895d, 0x8cdd, 0xfffd, 0x8cdc, 0x88e4, 0xfffd, 0xfffd, 0x986a, 0x9869, 0xfffd, 0x8db1, 0x889f, 0xfffd, 0x98b1, 0x98b2, 0x98b3, 0x9653, 0x98b4, 0xfffd, 0x8cf0, 0x88e5, 0x9692, 0xfffd, 0x8b9c, 0xfffd, 0xfffd, 0x8b9d, 0x8b9e, 0x92e0, 0x97ba, 0xfffd, 0x98b5, 0xfffd, 0xfffd, 0x98b6, 0xfffd, 0xfffd, 0x98b7, 0xfffd, 0xfffd, 0xfffd, 0x906c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f59, 0x906d, 0x98bc, 0xfffd, 0x98ba, 0xfffd, 0x98bb, 0x8b77, 0xfffd, 0xfffd, 0x8da1, 0x89ee, 0xfffd, 0x98b9, 0x98b8, 0x95a7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e65, 0x8e64, 0x91bc, 0x98bd, 0x9574, 0x90e5, 0xfffd, 0xfffd, 0xfffd, 0x8157, 0x98be, 0x98c0, 0xfffd, 0xfffd, 0xfffd, 0x91e3, 0x97df, 0x88c8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98bf, 0x89bc, 0xfffd, 0x8bc2, 0xfffd, 0x9287, 0xfffd, 0xfffd, 0xfffd, 0x8c8f, 0x98c1, 0xfffd, 0xfffd, 0xfffd, 0x9443, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ae9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98c2, 0x88c9, 0xfffd, 0xfffd, 0x8cde, 0x8aea, 0x959a, 0x94b0, 0x8b78, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89ef, 0xfffd, 0x98e5, 0x9360, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x948c, 0x98c4, 0xfffd, 0xfffd, 0xfffd, 0x94ba, 0xfffd, 0x97e0, 0xfffd, 0x904c, 0xfffd, 0x8e66, 0xfffd, 0x8e97, 0x89be, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92cf, 0xfffd, 0xfffd, 0x9241, 0x98c8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88ca, 0x92e1, 0x8f5a, 0x8db2, 0x9743, 0xfffd, 0x91cc, 0xfffd, 0x89bd, 0xfffd, 0x98c7, 0xfffd, 0x975d, 0x98c3, 0x98c5, 0x8dec, 0x98c6, 0x9b43, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98ce, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98d1, 0x98cf, 0xfffd, 0xfffd, 0x89c0, 0xfffd, 0x95b9, 0x98c9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98cd, 0x8cf1, 0xfffd, 0xfffd, 0x8e67, 0xfffd, 0xfffd, 0xfffd, 0x8aa4, 0xfffd, 0xfffd, 0x98d2, 0xfffd, 0x98ca, 0xfffd, 0xfffd, 0x97e1, 0xfffd, 0x8e98, 0xfffd, 0x98cb, 0xfffd, 0x98d0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98d3, 0xfffd, 0x98cc, 0xfffd, 0xfffd, 0x8b9f, 0xfffd, 0x88cb, 0xfffd, 0xfffd, 0x8ba0, 0x89bf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b44, 0xfffd, 0x9699, 0x958e, 0x8cf2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x904e, 0x97b5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95d6, 0xfffd, 0xfffd, 0x8c57, 0x91a3, 0x89e2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f72, 0xfffd, 0xfffd, 0xfffd, 0x98d7, 0xfffd, 0x98dc, 0x98da, 0xfffd, 0xfffd, 0x98d5, 0xfffd, 0xfffd, 0x91ad, 0x98d8, 0xfffd, 0x98db, 0x98d9, 0xfffd, 0x95db, 0xfffd, 0x98d6, 0xfffd, 0x904d, 0xfffd, 0x9693, 0x98dd, 0x98de, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f43, 0x98eb, 0xfffd, 0xfffd, 0xfffd, 0x946f, 0xfffd, 0x9555, 0x98e6, 0xfffd, 0x95ee, 0xfffd, 0x89b4, 0xfffd, 0xfffd, 0xfffd, 0x98ea, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98e4, 0x98ed, 0xfffd, 0xfffd, 0x9171, 0xfffd, 0x8cc2, 0xfffd, 0x947b, 0xfffd, 0xe0c5, 0xfffd, 0x98ec, 0x937c, 0xfffd, 0x98e1, 0xfffd, 0x8cf4, 0xfffd, 0xfffd, 0x8cf3, 0x98df, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ed8, 0xfffd, 0x98e7, 0xfffd, 0x95ed, 0x926c, 0x98e3, 0x8c91, 0xfffd, 0x98e0, 0x98e8, 0x98e2, 0x97cf, 0x98e9, 0x9860, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8be4, 0xfffd, 0xfffd, 0x8c90, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98ee, 0xfffd, 0xfffd, 0xfffd, 0x98ef, 0x98f3, 0x88cc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95ce, 0x98f2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98f1, 0x98f5, 0xfffd, 0xfffd, 0xfffd, 0x98f4, 0xfffd, 0x92e2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c92, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ec3, 0xfffd, 0x91a4, 0x92e3, 0x8bf4, 0xfffd, 0x98f7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b55, 0xfffd, 0xfffd, 0x98f8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98fa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9654, 0xfffd, 0xfffd, 0xfffd, 0x8c86, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e50, 0x94f5, 0x98f9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8dc3, 0x9762, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x98fc, 0x9942, 0x98fb, 0x8dc2, 0xfffd, 0x8f9d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c58, 0xfffd, 0xfffd, 0xfffd, 0x9943, 0xfffd, 0xfffd, 0x8bcd, 0xfffd, 0xfffd, 0xfffd, 0x9940, 0x9941, 0xfffd, 0xfffd, 0x93ad, 0xfffd, 0x919c, 0xfffd, 0x8ba1, 0xfffd, 0xfffd, 0xfffd, 0x966c, 0x9944, 0xfffd, 0xfffd, 0xfffd, 0x97bb, 0xfffd, 0xfffd, 0xfffd, 0x9945, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9948, 0xfffd, 0x9946, 0xfffd, 0x916d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9947, 0x9949, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x994b, 0xfffd, 0xfffd, 0xfffd, 0x994a, 0xfffd, 0x95c6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b56, 0x994d, 0x994e, 0xfffd, 0x89ad, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x994c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ef2, 0xfffd, 0x9951, 0x9950, 0x994f, 0xfffd, 0x98d4, 0xfffd, 0x9952, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f9e, 0xfffd, 0x9953, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9744, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96d7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9955, 0xfffd, 0xfffd, 0x9954, 0x9957, 0x9956, 0xfffd, 0xfffd, 0x9958, 0x9959, 0x88f2, 0xfffd, 0x8cb3, 0x8c5a, 0x8f5b, 0x929b, 0x8ba2, 0x90e6, 0x8cf5, 0xfffd, 0x8d8e, 0x995b, 0x96c6, 0x9365, 0xfffd, 0x8e99, 0xfffd, 0x995a, 0xfffd, 0x995c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x937d, 0xfffd, 0x8a95, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x995d, 0xfffd, 0xfffd, 0x93fc, 0xfffd, 0xfffd, 0x9153, 0x995f, 0x9960, 0x94aa, 0x8cf6, 0x985a, 0x9961, 0xfffd, 0xfffd, 0x8ba4, 0xfffd, 0xfffd, 0xfffd, 0x95ba, 0x91b4, 0x8bef, 0x9354, 0xfffd, 0xfffd, 0xfffd, 0x8c93, 0xfffd, 0xfffd, 0xfffd, 0x9962, 0xfffd, 0x9963, 0xfffd, 0xfffd, 0x93e0, 0x897e, 0xfffd, 0xfffd, 0x9966, 0x8dfb, 0xfffd, 0x9965, 0x8dc4, 0xfffd, 0x9967, 0xe3ec, 0x9968, 0x9660, 0x9969, 0xfffd, 0x996a, 0x996b, 0x8fe7, 0xfffd, 0x8eca, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8aa5, 0xfffd, 0x996e, 0xfffd, 0x996c, 0x96bb, 0x996d, 0xfffd, 0x9579, 0x996f, 0x9970, 0x9971, 0x937e, 0xfffd, 0xfffd, 0xfffd, 0x9975, 0x9973, 0x9974, 0x9972, 0x8de1, 0x9976, 0x96e8, 0x97e2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9977, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90a6, 0x9978, 0x8f79, 0xfffd, 0xfffd, 0x9979, 0xfffd, 0x929c, 0x97bd, 0x9380, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99c3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x997a, 0xeaa3, 0x8bc3, 0xfffd, 0xfffd, 0x997b, 0x967d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f88, 0x91fa, 0xfffd, 0x997d, 0x93e2, 0xfffd, 0xfffd, 0x997e, 0xfffd, 0xfffd, 0x9980, 0x8a4d, 0xfffd, 0xfffd, 0xfffd, 0x9981, 0x8ba5, 0xfffd, 0x93ca, 0x899a, 0x8f6f, 0xfffd, 0xfffd, 0x949f, 0x9982, 0xfffd, 0x9381, 0xfffd, 0xfffd, 0x906e, 0x9983, 0xfffd, 0x95aa, 0x90d8, 0x8aa0, 0xfffd, 0x8aa7, 0x9984, 0xfffd, 0xfffd, 0x9986, 0xfffd, 0xfffd, 0x8c59, 0xfffd, 0xfffd, 0x9985, 0xfffd, 0xfffd, 0x97f1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f89, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94bb, 0x95ca, 0xfffd, 0x9987, 0xfffd, 0x9798, 0x9988, 0xfffd, 0xfffd, 0xfffd, 0x9989, 0xfffd, 0x939e, 0xfffd, 0xfffd, 0x998a, 0xfffd, 0xfffd, 0x90a7, 0x8dfc, 0x8c94, 0x998b, 0x8e68, 0x8d8f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92e4, 0x998d, 0xfffd, 0xfffd, 0x91a5, 0xfffd, 0xfffd, 0x8ded, 0x998e, 0x998f, 0x914f, 0xfffd, 0x998c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9991, 0xfffd, 0x9655, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d84, 0xfffd, 0xfffd, 0x9990, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c95, 0x8ddc, 0x948d, 0xfffd, 0xfffd, 0xfffd, 0x9994, 0x9992, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x959b, 0x8fe8, 0x999b, 0x8a84, 0x9995, 0x9993, 0x916e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9997, 0xfffd, 0x9996, 0xfffd, 0xfffd, 0xfffd, 0x8a63, 0xfffd, 0xfffd, 0xfffd, 0x8c80, 0x999c, 0x97ab, 0xfffd, 0xfffd, 0xfffd, 0x9998, 0xfffd, 0xfffd, 0xfffd, 0x999d, 0x999a, 0xfffd, 0x9999, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97cd, 0xfffd, 0xfffd, 0xfffd, 0x8cf7, 0x89c1, 0xfffd, 0xfffd, 0x97f2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f95, 0x9377, 0x8d85, 0x99a0, 0x99a1, 0xfffd, 0xfffd, 0xfffd, 0x97e3, 0xfffd, 0xfffd, 0x984a, 0x99a3, 0xfffd, 0xfffd, 0xfffd, 0x8cf8, 0xfffd, 0xfffd, 0x99a2, 0xfffd, 0x8a4e, 0xfffd, 0xfffd, 0x99a4, 0xfffd, 0x9675, 0xfffd, 0x92ba, 0xfffd, 0x9745, 0xfffd, 0x95d7, 0xfffd, 0xfffd, 0xfffd, 0x99a5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8d3, 0xfffd, 0xfffd, 0x93ae, 0xfffd, 0x99a6, 0x8aa8, 0x96b1, 0xfffd, 0xfffd, 0xfffd, 0x8f9f, 0x99a7, 0x95e5, 0x99ab, 0xfffd, 0x90a8, 0x99a8, 0x8bce, 0xfffd, 0x99a9, 0x8aa9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c4d, 0x99ac, 0xfffd, 0x99ad, 0xfffd, 0xfffd, 0x99ae, 0x99af, 0x8ed9, 0xfffd, 0xfffd, 0xfffd, 0x8cf9, 0x96dc, 0xfffd, 0x96e6, 0x93f5, 0xfffd, 0xfffd, 0x95ef, 0x99b0, 0xfffd, 0x99b1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99b3, 0xfffd, 0x99b5, 0x99b4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99b6, 0x89bb, 0x966b, 0xfffd, 0x8dfa, 0x99b7, 0xfffd, 0xfffd, 0x9178, 0xfffd, 0xfffd, 0x8fa0, 0x8ba7, 0xfffd, 0x99b8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94d9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99b9, 0xfffd, 0x99ba, 0xfffd, 0x99bb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99bc, 0x9543, 0x8be6, 0x88e3, 0xfffd, 0xfffd, 0xfffd, 0x93bd, 0x99bd, 0x8f5c, 0xfffd, 0x90e7, 0xfffd, 0x99bf, 0x99be, 0x8fa1, 0x8cdf, 0x99c1, 0x94bc, 0xfffd, 0xfffd, 0x99c2, 0xfffd, 0xfffd, 0xfffd, 0x94da, 0x91b2, 0x91ec, 0x8ba6, 0xfffd, 0xfffd, 0x93ec, 0x9250, 0xfffd, 0x948e, 0xfffd, 0x966d, 0xfffd, 0x99c4, 0xfffd, 0x90e8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c54, 0xfffd, 0xfffd, 0x99c5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99c6, 0x894b, 0x88f3, 0x8aeb, 0xfffd, 0x91a6, 0x8b70, 0x9791, 0xfffd, 0x99c9, 0x89b5, 0xfffd, 0xfffd, 0x99c8, 0xfffd, 0xfffd, 0xfffd, 0x8ba8, 0xfffd, 0xfffd, 0x99ca, 0xfffd, 0x96ef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99cb, 0xfffd, 0x97d0, 0xfffd, 0x8cfa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cb4, 0x99cc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99ce, 0x99cd, 0xfffd, 0x907e, 0x8958, 0xfffd, 0xfffd, 0xfffd, 0x897d, 0x99cf, 0xfffd, 0x99d0, 0xfffd, 0xfffd, 0x8cb5, 0xfffd, 0xfffd, 0x99d1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b8e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e51, 0x99d2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9694, 0x8db3, 0x8b79, 0x9746, 0x916f, 0x94bd, 0x8efb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f66, 0xfffd, 0x8ee6, 0x8ef3, 0xfffd, 0x8f96, 0xfffd, 0x94be, 0xfffd, 0xfffd, 0xfffd, 0x99d5, 0xfffd, 0x8962, 0x9170, 0x8cfb, 0x8cc3, 0x8be5, 0xfffd, 0xfffd, 0x99d9, 0x9240, 0x91fc, 0x8ba9, 0x8fa2, 0x99da, 0x99d8, 0x89c2, 0x91e4, 0x8eb6, 0x8e6a, 0x8945, 0xfffd, 0xfffd, 0x8a90, 0x8d86, 0x8e69, 0xfffd, 0x99db, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99dc, 0xfffd, 0x8b68, 0x8a65, 0xfffd, 0xfffd, 0xfffd, 0x8d87, 0x8b67, 0x92dd, 0x8944, 0x93af, 0x96bc, 0x8d40, 0x9799, 0x9366, 0x8cfc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c4e, 0xfffd, 0x99e5, 0xfffd, 0x8be1, 0x9669, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94db, 0xfffd, 0xfffd, 0x99e4, 0xfffd, 0x8adc, 0x99df, 0x99e0, 0x99e2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99e3, 0xfffd, 0x8b7a, 0x9081, 0xfffd, 0x95ab, 0x99e1, 0x99dd, 0x8ce1, 0xfffd, 0x99de, 0xfffd, 0x9843, 0xfffd, 0xfffd, 0xfffd, 0x95f0, 0xfffd, 0x92e6, 0x8ce0, 0x8d90, 0xfffd, 0xfffd, 0xfffd, 0x99e6, 0xfffd, 0xfffd, 0x93db, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99ea, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8efc, 0xfffd, 0x8ef4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99ed, 0x99eb, 0xfffd, 0x96a1, 0xfffd, 0x99e8, 0x99f1, 0x99ec, 0xfffd, 0xfffd, 0xfffd, 0x99ef, 0x8cc4, 0x96bd, 0xfffd, 0xfffd, 0x99f0, 0xfffd, 0xfffd, 0xfffd, 0x99f2, 0xfffd, 0x99f4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8dee, 0x9861, 0xfffd, 0x99e9, 0x99e7, 0x99f3, 0xfffd, 0x99ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99f6, 0xfffd, 0x9a42, 0x99f8, 0xfffd, 0xfffd, 0x99fc, 0xfffd, 0xfffd, 0x9a40, 0x99f9, 0xfffd, 0xfffd, 0x9a5d, 0xfffd, 0xfffd, 0x8de7, 0x8a50, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x99f7, 0xfffd, 0xfffd, 0xfffd, 0x9a44, 0x88f4, 0x9a43, 0xfffd, 0x88a3, 0x9569, 0x9a41, 0xfffd, 0x99fa, 0xfffd, 0xfffd, 0x99f5, 0x99fb, 0x8dc6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a45, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88f5, 0x9a4e, 0xfffd, 0xfffd, 0x9a46, 0x9a47, 0xfffd, 0x8fa3, 0x9689, 0xfffd, 0xfffd, 0xfffd, 0x9a4c, 0x9a4b, 0xfffd, 0xfffd, 0xfffd, 0x934e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a4d, 0xfffd, 0xfffd, 0x9a4a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8953, 0xfffd, 0x8db4, 0x904f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a48, 0x9382, 0xfffd, 0xfffd, 0xfffd, 0x9a49, 0xfffd, 0x88a0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a53, 0x9742, 0xfffd, 0x8fa5, 0xfffd, 0x9a59, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a58, 0x9a4f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91c1, 0xfffd, 0x9a50, 0xfffd, 0xfffd, 0xfffd, 0x91ed, 0x9a55, 0x8fa4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a52, 0xfffd, 0xfffd, 0x96e2, 0xfffd, 0xfffd, 0xfffd, 0x8c5b, 0xfffd, 0xfffd, 0x9a56, 0x9a57, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a54, 0x9a5a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a51, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a60, 0x9a65, 0xfffd, 0x9a61, 0xfffd, 0x9a5c, 0xfffd, 0xfffd, 0x9a66, 0x9150, 0xfffd, 0xfffd, 0x9a68, 0xfffd, 0x8d41, 0x9a5e, 0x929d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a62, 0x9a5b, 0x8aab, 0xfffd, 0x8aec, 0x8a85, 0x9a63, 0x9a5f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c96, 0x9a69, 0x9a67, 0x9172, 0x8b69, 0x8baa, 0xfffd, 0x9a64, 0xfffd, 0x8bf2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8963, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a6d, 0x9a6b, 0xfffd, 0x9aa5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a70, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a6a, 0xfffd, 0x9a6e, 0xfffd, 0xfffd, 0x9a6c, 0xfffd, 0xfffd, 0xfffd, 0x8e6b, 0x9a6f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a72, 0xfffd, 0x9a77, 0xfffd, 0xfffd, 0xfffd, 0x9a75, 0x9a74, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9251, 0xfffd, 0xfffd, 0x89c3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a71, 0xfffd, 0x9a73, 0x8fa6, 0x8952, 0xfffd, 0xfffd, 0x9a76, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89dc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a82, 0xfffd, 0x8ffa, 0x9a7d, 0xfffd, 0x9a7b, 0xfffd, 0x9a7c, 0xfffd, 0x9a7e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x895c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9158, 0xfffd, 0x9a78, 0xfffd, 0x9a79, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a9a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a81, 0xfffd, 0xfffd, 0xfffd, 0x8aed, 0xfffd, 0x9a84, 0x9a80, 0x9a83, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95ac, 0xfffd, 0xfffd, 0xfffd, 0x93d3, 0xfffd, 0x94b6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a86, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a85, 0x8a64, 0xfffd, 0xfffd, 0x9a87, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a8a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a89, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a88, 0xfffd, 0x9458, 0xfffd, 0xfffd, 0x9a8b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a8c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a8e, 0xfffd, 0x9a8d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a90, 0xfffd, 0xfffd, 0xfffd, 0x9a93, 0x9a91, 0x9a8f, 0x9a92, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a94, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a95, 0xfffd, 0xfffd, 0x9a96, 0xfffd, 0x9a97, 0xfffd, 0xfffd, 0xfffd, 0x9a98, 0x9964, 0xfffd, 0x8efa, 0x8e6c, 0xfffd, 0xfffd, 0x89f1, 0xfffd, 0x88f6, 0xfffd, 0xfffd, 0x9263, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a99, 0xfffd, 0x8da2, 0xfffd, 0x88cd, 0x907d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a9a, 0x8cc5, 0xfffd, 0xfffd, 0x8d91, 0xfffd, 0x9a9c, 0x9a9b, 0xfffd, 0xfffd, 0x95de, 0x9a9d, 0xfffd, 0xfffd, 0xfffd, 0x9a9f, 0x9a9e, 0xfffd, 0x9aa0, 0xfffd, 0x9aa1, 0xfffd, 0x8c97, 0xfffd, 0xfffd, 0x8980, 0x9aa2, 0xfffd, 0xfffd, 0x9aa4, 0xfffd, 0x9aa3, 0xfffd, 0xfffd, 0xfffd, 0x9aa6, 0xfffd, 0xfffd, 0x9379, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9aa7, 0x88b3, 0x8ddd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c5c, 0xfffd, 0xfffd, 0x926e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9aa8, 0x9aa9, 0xfffd, 0xfffd, 0x9aab, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9aac, 0xfffd, 0x8de2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8bcf, 0xfffd, 0xfffd, 0x9656, 0xfffd, 0xfffd, 0xfffd, 0x9aaa, 0x9aad, 0x8dbf, 0x8d42, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ab1, 0xfffd, 0xfffd, 0x8da3, 0xfffd, 0x9252, 0xfffd, 0xfffd, 0x9aae, 0x92d8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ab2, 0xfffd, 0xfffd, 0x9082, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ab0, 0x9ab3, 0xfffd, 0x8c5e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ab4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ab5, 0xfffd, 0x8d43, 0x8a5f, 0x9ab7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ab8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ab9, 0xfffd, 0xfffd, 0x9ab6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9aaf, 0xfffd, 0xfffd, 0x9aba, 0xfffd, 0xfffd, 0x9abb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9684, 0xfffd, 0xfffd, 0x8fe9, 0xfffd, 0xfffd, 0xfffd, 0x9abd, 0x9abe, 0x9abc, 0xfffd, 0x9ac0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9457, 0xfffd, 0xfffd, 0x88e6, 0x9575, 0xfffd, 0xfffd, 0x9ac1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ffb, 0xfffd, 0xfffd, 0x8eb7, 0xfffd, 0x947c, 0x8aee, 0xfffd, 0x8de9, 0xfffd, 0xfffd, 0xfffd, 0x9678, 0xfffd, 0x93b0, 0xfffd, 0xfffd, 0x8c98, 0x91cd, 0xfffd, 0xfffd, 0xfffd, 0x9abf, 0x9ac2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91c2, 0xfffd, 0xfffd, 0xfffd, 0x9ac3, 0xfffd, 0xfffd, 0xfffd, 0x9ac4, 0xfffd, 0xfffd, 0xfffd, 0x9ac6, 0xfffd, 0xfffd, 0x92e7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8aac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea9f, 0x8981, 0x95f1, 0xfffd, 0xfffd, 0x8fea, 0x9367, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8de4, 0xfffd, 0xfffd, 0x9acc, 0xfffd, 0xfffd, 0x95bb, 0x97db, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89f2, 0x9ac8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9159, 0x9acb, 0xfffd, 0x9383, 0xfffd, 0xfffd, 0x9368, 0x9384, 0x94b7, 0x92cb, 0xfffd, 0xfffd, 0xfffd, 0x8dc7, 0xfffd, 0xfffd, 0xfffd, 0x9ac7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8996, 0xfffd, 0x9355, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ac9, 0xfffd, 0x9ac5, 0xfffd, 0xfffd, 0x906f, 0xfffd, 0xfffd, 0xfffd, 0x9acd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f6d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8bab, 0xfffd, 0x9ace, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95e6, 0xfffd, 0xfffd, 0xfffd, 0x919d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92c4, 0xfffd, 0xfffd, 0x9ad0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x966e, 0xfffd, 0xfffd, 0x9ad1, 0xfffd, 0xfffd, 0x9ad6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95ad, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ad5, 0x9acf, 0x9ad2, 0x9ad4, 0xfffd, 0xfffd, 0x8da4, 0xfffd, 0xfffd, 0x95c7, 0xfffd, 0xfffd, 0xfffd, 0x9ad7, 0xfffd, 0x9264, 0xfffd, 0xfffd, 0x89f3, 0xfffd, 0x8feb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ad9, 0xfffd, 0x9ad8, 0xfffd, 0x8d88, 0xfffd, 0x9ada, 0x9adc, 0x9adb, 0xfffd, 0xfffd, 0x9ade, 0xfffd, 0x9ad3, 0x9ae0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9adf, 0x9add, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e6d, 0x9070, 0xfffd, 0x9173, 0x9ae1, 0x90ba, 0x88eb, 0x9484, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92d9, 0xfffd, 0x9ae3, 0x9ae2, 0x9ae4, 0x9ae5, 0x9ae6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ae7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95cf, 0x9ae8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89c4, 0x9ae9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x975b, 0x8a4f, 0xfffd, 0x99c7, 0x8f67, 0x91bd, 0x9aea, 0x96e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96b2, 0xfffd, 0xfffd, 0x9aec, 0xfffd, 0x91e5, 0xfffd, 0x9356, 0x91be, 0x9576, 0x9aed, 0x9aee, 0x899b, 0xfffd, 0xfffd, 0x8eb8, 0x9aef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88ce, 0x9af0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9af1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8982, 0xfffd, 0xfffd, 0x8aef, 0x93de, 0x95f2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9af5, 0x9174, 0x9af4, 0x8c5f, 0xfffd, 0xfffd, 0x967a, 0x9af3, 0xfffd, 0x9385, 0x9af7, 0xfffd, 0x9af6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9af9, 0xfffd, 0x9af8, 0xfffd, 0xfffd, 0x899c, 0xfffd, 0x9afa, 0x8fa7, 0x9afc, 0x9244, 0xfffd, 0x9afb, 0xfffd, 0x95b1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f97, 0x937a, 0xfffd, 0xfffd, 0xfffd, 0x9b40, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d44, 0xfffd, 0xfffd, 0xfffd, 0x9b41, 0x9440, 0x94dc, 0x96cf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9444, 0xfffd, 0xfffd, 0x9b4a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b57, 0xfffd, 0xfffd, 0x9764, 0xfffd, 0xfffd, 0x96ad, 0xfffd, 0x9baa, 0xfffd, 0x9b42, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b45, 0xfffd, 0x91c3, 0xfffd, 0xfffd, 0x9657, 0xfffd, 0xfffd, 0xfffd, 0x9369, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b46, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9685, 0xfffd, 0x8dc8, 0xfffd, 0xfffd, 0x8fa8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b47, 0xfffd, 0xfffd, 0x8e6f, 0xfffd, 0x8e6e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88b7, 0x8cc6, 0xfffd, 0x90a9, 0x88cf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b4b, 0x9b4c, 0xfffd, 0x9b49, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8957, 0x8aad, 0xfffd, 0x9b48, 0xfffd, 0x96c3, 0x9550, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88a6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88f7, 0xfffd, 0xfffd, 0xfffd, 0x8e70, 0xfffd, 0x88d0, 0xfffd, 0x88a1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b51, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b4f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96ba, 0xfffd, 0x9b52, 0xfffd, 0x9b50, 0xfffd, 0xfffd, 0x9b4e, 0x9050, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b4d, 0xfffd, 0xfffd, 0xfffd, 0x95d8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ce2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b56, 0x9b57, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fa9, 0xfffd, 0xfffd, 0xfffd, 0x9b53, 0x984b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x946b, 0xfffd, 0xfffd, 0x9b55, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8da5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b58, 0xfffd, 0xfffd, 0xfffd, 0x9577, 0xfffd, 0xfffd, 0xfffd, 0x9b59, 0xfffd, 0x9b54, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96b9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x947d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b5a, 0x9551, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b5b, 0x9b5f, 0x9b5c, 0xfffd, 0xfffd, 0x89c5, 0x9b5e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8eb9, 0xfffd, 0x9b5d, 0x8c99, 0xfffd, 0xfffd, 0xfffd, 0x9b6b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b64, 0x9b61, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9284, 0xfffd, 0x9b60, 0xfffd, 0xfffd, 0x9b62, 0xfffd, 0xfffd, 0x9b63, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b65, 0x9b66, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8af0, 0xfffd, 0x9b68, 0x9b67, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b69, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fec, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b6c, 0xfffd, 0x92da, 0xfffd, 0xfffd, 0xfffd, 0x8964, 0xfffd, 0x9b6a, 0xfffd, 0xfffd, 0xfffd, 0x9b6d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b6e, 0xfffd, 0x9b71, 0xfffd, 0xfffd, 0x9b6f, 0xfffd, 0x9b70, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e71, 0x9b72, 0xfffd, 0xfffd, 0x8d45, 0x9b73, 0xfffd, 0x8e9a, 0x91b6, 0xfffd, 0x9b74, 0x9b75, 0x8e79, 0x8d46, 0xfffd, 0x96d0, 0xfffd, 0xfffd, 0xfffd, 0x8b47, 0x8cc7, 0x9b76, 0x8a77, 0xfffd, 0xfffd, 0x9b77, 0xfffd, 0x91b7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b78, 0x9ba1, 0xfffd, 0x9b79, 0xfffd, 0x9b7a, 0xfffd, 0xfffd, 0x9b7b, 0xfffd, 0x9b7d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b7e, 0xfffd, 0xfffd, 0x9b80, 0xfffd, 0x91ee, 0xfffd, 0x8946, 0x8ee7, 0x88c0, 0xfffd, 0x9176, 0x8aae, 0x8eb3, 0xfffd, 0x8d47, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9386, 0xfffd, 0x8f40, 0x8aaf, 0x9288, 0x92e8, 0x88b6, 0x8b58, 0x95f3, 0xfffd, 0x8ec0, 0xfffd, 0xfffd, 0x8b71, 0x90e9, 0x8eba, 0x9747, 0x9b81, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b7b, 0xfffd, 0x8dc9, 0xfffd, 0xfffd, 0x8a51, 0x8983, 0x8faa, 0x89c6, 0xfffd, 0x9b82, 0x9765, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f68, 0xfffd, 0xfffd, 0x8ee2, 0x9b83, 0x8af1, 0x93d0, 0x96a7, 0x9b84, 0xfffd, 0x9b85, 0xfffd, 0xfffd, 0x9578, 0xfffd, 0xfffd, 0xfffd, 0x9b87, 0xfffd, 0x8aa6, 0x8bf5, 0x9b86, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ab0, 0xfffd, 0x9051, 0x9b8b, 0x8e40, 0xfffd, 0x89c7, 0x9b8a, 0xfffd, 0x9b88, 0x9b8c, 0x9b89, 0x944a, 0x9ecb, 0x9052, 0xfffd, 0x9b8d, 0xfffd, 0xfffd, 0x97be, 0xfffd, 0x9b8e, 0xfffd, 0xfffd, 0x9b90, 0xfffd, 0x929e, 0x9b8f, 0xfffd, 0x90a1, 0xfffd, 0x8e9b, 0xfffd, 0xfffd, 0xfffd, 0x91ce, 0x8ef5, 0xfffd, 0x9595, 0x90ea, 0xfffd, 0x8ecb, 0x9b91, 0x8fab, 0x9b92, 0x9b93, 0x88d1, 0x91b8, 0x9071, 0xfffd, 0x9b94, 0x93b1, 0x8fac, 0xfffd, 0x8fad, 0xfffd, 0x9b95, 0xfffd, 0xfffd, 0x90eb, 0xfffd, 0xfffd, 0xfffd, 0x8fae, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b96, 0xfffd, 0x9b97, 0xfffd, 0x96de, 0xfffd, 0xfffd, 0xfffd, 0x9b98, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8bc4, 0xfffd, 0xfffd, 0xfffd, 0x8f41, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9b99, 0x9b9a, 0x8eda, 0x904b, 0x93f2, 0x9073, 0x94f6, 0x9441, 0x8bc7, 0x9b9b, 0xfffd, 0xfffd, 0xfffd, 0x8b8f, 0x9b9c, 0xfffd, 0x8bfc, 0xfffd, 0x93cd, 0x89ae, 0xfffd, 0x8e72, 0x9b9d, 0x9ba0, 0x9b9f, 0x8bfb, 0xfffd, 0x9b9e, 0xfffd, 0x9357, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91ae, 0xfffd, 0x936a, 0x8ec6, 0xfffd, 0xfffd, 0x9177, 0x979a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ba2, 0xfffd, 0x9ba3, 0x93d4, 0xfffd, 0x8e52, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ba5, 0xfffd, 0xfffd, 0x9ba6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ba7, 0xfffd, 0xfffd, 0xfffd, 0x8af2, 0x9ba8, 0xfffd, 0xfffd, 0x9ba9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89aa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x915a, 0x8ae2, 0xfffd, 0x9bab, 0x96a6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91d0, 0xfffd, 0x8a78, 0xfffd, 0xfffd, 0x9bad, 0x9baf, 0x8add, 0xfffd, 0xfffd, 0x9bac, 0x9bae, 0xfffd, 0x9bb1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bb0, 0xfffd, 0x9bb2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bb3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93bb, 0x8bac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89e3, 0x9bb4, 0x9bb9, 0xfffd, 0xfffd, 0x9bb7, 0xfffd, 0x95f5, 0x95f4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9387, 0xfffd, 0xfffd, 0xfffd, 0x9bb6, 0x8f73, 0xfffd, 0x9bb5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9092, 0xfffd, 0xfffd, 0xfffd, 0x9bba, 0xfffd, 0xfffd, 0x8de8, 0xfffd, 0xfffd, 0x9bc0, 0xfffd, 0xfffd, 0x9bc1, 0x9bbb, 0x8a52, 0x9bbc, 0x9bc5, 0x9bc4, 0x9bc3, 0x9bbf, 0xfffd, 0xfffd, 0xfffd, 0x9bbe, 0xfffd, 0xfffd, 0x9bc2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bc9, 0x9bc6, 0xfffd, 0x9bc8, 0xfffd, 0x9792, 0xfffd, 0x9bc7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bbd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9093, 0xfffd, 0xfffd, 0x9bca, 0xfffd, 0xfffd, 0x8db5, 0xfffd, 0xfffd, 0xfffd, 0x9bcb, 0xfffd, 0xfffd, 0x9bcc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bcf, 0xfffd, 0x9bce, 0xfffd, 0xfffd, 0x9bcd, 0xfffd, 0xfffd, 0xfffd, 0x9388, 0x9bb8, 0xfffd, 0xfffd, 0xfffd, 0x9bd5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bd1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bd0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bd2, 0xfffd, 0x9bd3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bd6, 0xfffd, 0xfffd, 0x97e4, 0xfffd, 0x9bd7, 0x9bd4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bd8, 0xfffd, 0xfffd, 0x8ade, 0x9bd9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bdb, 0x9bda, 0xfffd, 0xfffd, 0x9bdc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bdd, 0xfffd, 0x90ec, 0x8f42, 0xfffd, 0xfffd, 0x8f84, 0xfffd, 0x9183, 0xfffd, 0x8d48, 0x8db6, 0x8d49, 0x8b90, 0xfffd, 0xfffd, 0x9bde, 0xfffd, 0xfffd, 0x8db7, 0xfffd, 0xfffd, 0x8cc8, 0x9bdf, 0x96a4, 0x9462, 0x9be0, 0xfffd, 0x8d4a, 0xfffd, 0xfffd, 0xfffd, 0x8aaa, 0xfffd, 0x9246, 0x8bd0, 0xfffd, 0xfffd, 0xfffd, 0x8e73, 0x957a, 0xfffd, 0xfffd, 0x94bf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9be1, 0x8af3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9be4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x929f, 0xfffd, 0xfffd, 0x9be3, 0x9be2, 0x9be5, 0xfffd, 0x92e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9083, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e74, 0xfffd, 0x90c8, 0xfffd, 0x91d1, 0x8b41, 0xfffd, 0xfffd, 0x92a0, 0xfffd, 0xfffd, 0x9be6, 0x9be7, 0x8fed, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9658, 0xfffd, 0xfffd, 0x9bea, 0xfffd, 0xfffd, 0x9be9, 0x9be8, 0x959d, 0xfffd, 0x9bf1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9679, 0xfffd, 0x9beb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bed, 0x968b, 0xfffd, 0x9bec, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bee, 0xfffd, 0x94a6, 0x9bef, 0x95bc, 0x9bf0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ab1, 0x95bd, 0x944e, 0x9bf2, 0x9bf3, 0xfffd, 0x8d4b, 0x8ab2, 0x9bf4, 0x8cb6, 0x9763, 0x9748, 0x8af4, 0x9bf6, 0xfffd, 0x92a1, 0xfffd, 0x8d4c, 0x8faf, 0xfffd, 0xfffd, 0x94dd, 0xfffd, 0xfffd, 0x8fb0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f98, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92ea, 0x95f7, 0x9358, 0xfffd, 0xfffd, 0x8d4d, 0xfffd, 0x957b, 0xfffd, 0xfffd, 0xfffd, 0x9bf7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9378, 0x8dc0, 0xfffd, 0xfffd, 0xfffd, 0x8cc9, 0xfffd, 0x92eb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88c1, 0x8f8e, 0x8d4e, 0x9766, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bf8, 0x9bf9, 0x9470, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bfa, 0x97f5, 0x984c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9bfc, 0x9bfb, 0xfffd, 0xfffd, 0x8a66, 0xfffd, 0xfffd, 0x9c40, 0xfffd, 0xfffd, 0xfffd, 0x9c43, 0x9c44, 0xfffd, 0x9c42, 0xfffd, 0x955f, 0x8fb1, 0x9c46, 0x9c45, 0x9c41, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c47, 0x9c48, 0xfffd, 0xfffd, 0x9c49, 0xfffd, 0xfffd, 0xfffd, 0x9c4c, 0x9c4a, 0xfffd, 0x9c4b, 0x9c4d, 0xfffd, 0x8984, 0x92ec, 0x9c4e, 0xfffd, 0x8c9a, 0x89f4, 0x9455, 0xfffd, 0x9c4f, 0x93f9, 0xfffd, 0x95d9, 0xfffd, 0x9c50, 0x984d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c51, 0x95be, 0x9c54, 0x989f, 0x98af, 0xfffd, 0x8eae, 0x93f3, 0x9c55, 0xfffd, 0x8b7c, 0x92a2, 0x88f8, 0x9c56, 0x95a4, 0x8d4f, 0xfffd, 0xfffd, 0x926f, 0xfffd, 0xfffd, 0xfffd, 0x92ed, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96ed, 0x8cb7, 0x8cca, 0xfffd, 0x9c57, 0xfffd, 0xfffd, 0xfffd, 0x9c58, 0xfffd, 0x9c5e, 0xfffd, 0x8ee3, 0xfffd, 0xfffd, 0xfffd, 0x92a3, 0xfffd, 0x8bad, 0x9c59, 0xfffd, 0xfffd, 0xfffd, 0x954a, 0xfffd, 0x9265, 0xfffd, 0xfffd, 0x9c5a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c5b, 0xfffd, 0x8bae, 0xfffd, 0x9c5c, 0xfffd, 0x9c5d, 0xfffd, 0xfffd, 0x9c5f, 0xfffd, 0x9396, 0xfffd, 0xfffd, 0x9c60, 0x9c61, 0xfffd, 0x9c62, 0xfffd, 0xfffd, 0x9c53, 0x9c52, 0xfffd, 0xfffd, 0xfffd, 0x9c63, 0x8c60, 0xfffd, 0xfffd, 0xfffd, 0x9546, 0xfffd, 0xfffd, 0x8dca, 0x9556, 0x92a4, 0x956a, 0x9c64, 0xfffd, 0xfffd, 0x8fb2, 0x8965, 0xfffd, 0x9c65, 0xfffd, 0xfffd, 0xfffd, 0x9c66, 0xfffd, 0x96f0, 0xfffd, 0xfffd, 0x94de, 0xfffd, 0xfffd, 0x9c69, 0x899d, 0x90aa, 0x9c68, 0x9c67, 0x8c61, 0x91d2, 0xfffd, 0x9c6d, 0x9c6b, 0xfffd, 0x9c6a, 0x97a5, 0x8ce3, 0xfffd, 0xfffd, 0xfffd, 0x8f99, 0x9c6c, 0x936b, 0x8f5d, 0xfffd, 0xfffd, 0xfffd, 0x93be, 0x9c70, 0x9c6f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c6e, 0xfffd, 0x9c71, 0x8ce4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c72, 0x959c, 0x8f7a, 0xfffd, 0xfffd, 0x9c73, 0x94f7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93bf, 0x92a5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x934f, 0xfffd, 0xfffd, 0x9c74, 0x8b4a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9053, 0xfffd, 0x954b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8af5, 0x9445, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c75, 0x8e75, 0x9659, 0x965a, 0xfffd, 0xfffd, 0x899e, 0x9c7a, 0xfffd, 0xfffd, 0x9289, 0xfffd, 0xfffd, 0xfffd, 0x9c77, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89f5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cab, 0x9c79, 0xfffd, 0xfffd, 0xfffd, 0x944f, 0xfffd, 0xfffd, 0x9c78, 0xfffd, 0xfffd, 0x9c76, 0xfffd, 0x8d9a, 0xfffd, 0x9c7c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c83, 0x9c89, 0x9c81, 0xfffd, 0x937b, 0xfffd, 0xfffd, 0x9c86, 0x957c, 0xfffd, 0xfffd, 0x9c80, 0xfffd, 0x9c85, 0x97e5, 0x8e76, 0xfffd, 0xfffd, 0x91d3, 0x9c7d, 0xfffd, 0xfffd, 0xfffd, 0x8b7d, 0x9c88, 0x90ab, 0x8985, 0x9c82, 0x89f6, 0x9c87, 0xfffd, 0xfffd, 0xfffd, 0x8baf, 0xfffd, 0x9c84, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c8a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c8c, 0x9c96, 0x9c94, 0xfffd, 0xfffd, 0x9c91, 0xfffd, 0xfffd, 0xfffd, 0x9c90, 0x97f6, 0xfffd, 0x9c92, 0xfffd, 0xfffd, 0x8bb0, 0xfffd, 0x8d50, 0xfffd, 0xfffd, 0x8f9a, 0xfffd, 0xfffd, 0xfffd, 0x9c99, 0x9c8b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c8f, 0x9c7e, 0xfffd, 0x89f8, 0x9c93, 0x9c95, 0x9270, 0xfffd, 0xfffd, 0x8da6, 0x89b6, 0x9c8d, 0x9c98, 0x9c97, 0x8bb1, 0xfffd, 0x91a7, 0x8a86, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c62, 0xfffd, 0x9c8e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9c9a, 0xfffd, 0x9c9d, 0x9c9f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ebb, 0xfffd, 0x9ca5, 0x92ee, 0x9c9b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ca3, 0xfffd, 0x89f7, 0xfffd, 0x9ca1, 0x9ca2, 0xfffd, 0xfffd, 0x9c9e, 0x9ca0, 0xfffd, 0xfffd, 0xfffd, 0x8ce5, 0x9749, 0xfffd, 0xfffd, 0x8ab3, 0xfffd, 0xfffd, 0x8978, 0x9ca4, 0xfffd, 0x9459, 0x88ab, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94df, 0x9c7b, 0x9caa, 0x9cae, 0x96e3, 0xfffd, 0x9ca7, 0xfffd, 0xfffd, 0xfffd, 0x9389, 0x9cac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fee, 0x9cad, 0x93d5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9866, 0xfffd, 0x9ca9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9caf, 0xfffd, 0x8d9b, 0xfffd, 0x90c9, 0xfffd, 0xfffd, 0x88d2, 0x9ca8, 0x9ca6, 0xfffd, 0x9179, 0xfffd, 0xfffd, 0xfffd, 0x9c9c, 0x8e53, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91c4, 0x9cbb, 0xfffd, 0x917a, 0x9cb6, 0xfffd, 0x9cb3, 0x9cb4, 0xfffd, 0x8ee4, 0x9cb7, 0x9cba, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cb5, 0x8f44, 0xfffd, 0x9cb8, 0xfffd, 0xfffd, 0x9cb2, 0xfffd, 0x96fa, 0x96f9, 0xfffd, 0xfffd, 0xfffd, 0x9cbc, 0x9cbd, 0x88d3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cb1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8bf0, 0x88a4, 0xfffd, 0xfffd, 0xfffd, 0x8ab4, 0xfffd, 0x9cb9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cc1, 0x9cc0, 0xfffd, 0xfffd, 0xfffd, 0x9cc5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cc6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cc4, 0x9cc7, 0x9cbf, 0x9cc3, 0xfffd, 0xfffd, 0x9cc8, 0xfffd, 0x9cc9, 0xfffd, 0xfffd, 0x9cbe, 0x8e9c, 0xfffd, 0x9cc2, 0x91d4, 0x8d51, 0x9cb0, 0x9054, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cd6, 0xfffd, 0x95e7, 0xfffd, 0xfffd, 0x9ccc, 0x9ccd, 0x9cce, 0xfffd, 0xfffd, 0x9cd5, 0xfffd, 0x9cd4, 0xfffd, 0xfffd, 0x969d, 0x8ab5, 0xfffd, 0x9cd2, 0xfffd, 0x8c64, 0x8a53, 0xfffd, 0xfffd, 0x9ccf, 0xfffd, 0xfffd, 0x97b6, 0x9cd1, 0x88d4, 0x9cd3, 0xfffd, 0x9cca, 0x9cd0, 0x9cd7, 0x8c63, 0x9ccb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x977c, 0xfffd, 0xfffd, 0xfffd, 0x974a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cda, 0xfffd, 0xfffd, 0x9cde, 0xfffd, 0xfffd, 0xfffd, 0x919e, 0xfffd, 0x97f7, 0x9cdf, 0xfffd, 0xfffd, 0x9cdc, 0xfffd, 0x9cd9, 0xfffd, 0xfffd, 0x9cd8, 0x9cdd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95ae, 0xfffd, 0xfffd, 0x93b2, 0xfffd, 0x8c65, 0xfffd, 0x9ce0, 0x9cdb, 0xfffd, 0x9ce1, 0xfffd, 0xfffd, 0xfffd, 0x8c9b, 0xfffd, 0xfffd, 0xfffd, 0x89af, 0xfffd, 0xfffd, 0xfffd, 0x9ce9, 0xfffd, 0xfffd, 0xfffd, 0x8ab6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ce7, 0xfffd, 0xfffd, 0x9ce8, 0x8da7, 0x9ce6, 0x9ce4, 0x9ce3, 0x9cea, 0x9ce2, 0x9cec, 0xfffd, 0xfffd, 0x89f9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cee, 0xfffd, 0xfffd, 0x9ced, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92a6, 0xfffd, 0x9cf1, 0xfffd, 0x9cef, 0x9ce5, 0x8c9c, 0xfffd, 0x9cf0, 0xfffd, 0x9cf4, 0x9cf3, 0x9cf5, 0x9cf2, 0x9cf6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9cf7, 0x9cf8, 0x95e8, 0xfffd, 0x9cfa, 0x9cf9, 0x8f5e, 0xfffd, 0x90ac, 0x89e4, 0x89fa, 0xfffd, 0x9cfb, 0xfffd, 0x88bd, 0xfffd, 0xfffd, 0xfffd, 0x90ca, 0x9cfc, 0xfffd, 0xe6c1, 0x9d40, 0x8c81, 0xfffd, 0x9d41, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90ed, 0xfffd, 0xfffd, 0xfffd, 0x9d42, 0xfffd, 0xfffd, 0xfffd, 0x9d43, 0x8b59, 0x9d44, 0xfffd, 0x9d45, 0x9d46, 0x91d5, 0xfffd, 0xfffd, 0xfffd, 0x8ccb, 0xfffd, 0xfffd, 0x96df, 0xfffd, 0xfffd, 0xfffd, 0x965b, 0x8f8a, 0x9d47, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90ee, 0xe7bb, 0x94e0, 0xfffd, 0x8ee8, 0xfffd, 0x8dcb, 0x9d48, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91c5, 0xfffd, 0x95a5, 0xfffd, 0xfffd, 0x91ef, 0xfffd, 0xfffd, 0x9d4b, 0xfffd, 0xfffd, 0x9d49, 0xfffd, 0x9d4c, 0xfffd, 0xfffd, 0x9d4a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d4d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95af, 0xfffd, 0xfffd, 0x88b5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x957d, 0xfffd, 0xfffd, 0x94e1, 0xfffd, 0xfffd, 0x9d4e, 0xfffd, 0x9d51, 0x8fb3, 0x8b5a, 0xfffd, 0x9d4f, 0x9d56, 0x8fb4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d50, 0x9463, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x977d, 0x9d52, 0x9d53, 0x9d57, 0x938a, 0x9d54, 0x8d52, 0x90dc, 0xfffd, 0xfffd, 0x9d65, 0x94b2, 0xfffd, 0x91f0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94e2, 0x9dab, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95f8, 0xfffd, 0xfffd, 0xfffd, 0x92ef, 0xfffd, 0xfffd, 0xfffd, 0x9695, 0xfffd, 0x9d5a, 0x899f, 0x928a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d63, 0xfffd, 0xfffd, 0x9253, 0x9d5d, 0x9d64, 0x9d5f, 0x9d66, 0x9d62, 0xfffd, 0x9d61, 0x948f, 0xfffd, 0x9d5b, 0x89fb, 0x9d59, 0x8b91, 0x91f1, 0x9d55, 0xfffd, 0xfffd, 0x9d58, 0x8d53, 0x90d9, 0xfffd, 0x8fb5, 0x9d60, 0x9471, 0xfffd, 0xfffd, 0x8b92, 0x8a67, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a87, 0x9040, 0x9d68, 0x9d6d, 0xfffd, 0x9d69, 0xfffd, 0x8c9d, 0xfffd, 0x9d6e, 0x8e41, 0x8d89, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f45, 0x9d5c, 0xfffd, 0x8e9d, 0x9d6b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e77, 0x9d6c, 0x88c2, 0xfffd, 0xfffd, 0x9d67, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92a7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b93, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8bb2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d6a, 0x88a5, 0xfffd, 0xfffd, 0x8dc1, 0xfffd, 0xfffd, 0xfffd, 0x9055, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92f0, 0xfffd, 0xfffd, 0x94d2, 0x9d70, 0x917d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91a8, 0xfffd, 0xfffd, 0x8e4a, 0x9d71, 0xfffd, 0x9d73, 0x9d6f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95df, 0xfffd, 0x92bb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x917b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95f9, 0x8ecc, 0x9d80, 0xfffd, 0x9d7e, 0xfffd, 0xfffd, 0x9098, 0xfffd, 0xfffd, 0xfffd, 0x8c9e, 0xfffd, 0xfffd, 0xfffd, 0x9d78, 0x8fb7, 0xfffd, 0xfffd, 0x93e6, 0x9450, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d76, 0xfffd, 0xfffd, 0x917c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ef6, 0x9d7b, 0xfffd, 0xfffd, 0x8fb6, 0xfffd, 0x9d75, 0x9d7a, 0xfffd, 0xfffd, 0x9472, 0xfffd, 0xfffd, 0xfffd, 0x9d74, 0xfffd, 0x8c40, 0xfffd, 0xfffd, 0x8a7c, 0xfffd, 0xfffd, 0xfffd, 0x9d7c, 0x97a9, 0x8dcc, 0x9254, 0x9d79, 0xfffd, 0x90da, 0xfffd, 0x8d54, 0x9084, 0x8986, 0x915b, 0x9d77, 0x8b64, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c66, 0xfffd, 0x92cd, 0x9d7d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x917e, 0xfffd, 0xfffd, 0x9d81, 0xfffd, 0x9d83, 0xfffd, 0xfffd, 0x91b5, 0x9d89, 0xfffd, 0x9d84, 0xfffd, 0xfffd, 0x9d86, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9560, 0x92f1, 0xfffd, 0x9d87, 0xfffd, 0xfffd, 0xfffd, 0x974b, 0xfffd, 0xfffd, 0xfffd, 0x9767, 0x8ab7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88ac, 0xfffd, 0x9d85, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d82, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8af6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8987, 0xfffd, 0x9d88, 0xfffd, 0xfffd, 0xfffd, 0x9768, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d8c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91b9, 0xfffd, 0x9d93, 0xfffd, 0xfffd, 0xfffd, 0x9d8d, 0xfffd, 0xfffd, 0x9d8a, 0x9d91, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d72, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d8e, 0xfffd, 0x9d92, 0xfffd, 0xfffd, 0xfffd, 0x94c0, 0x938b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d8b, 0xfffd, 0x9d8f, 0xfffd, 0xfffd, 0xfffd, 0x8c67, 0xfffd, 0xfffd, 0xfffd, 0x8def, 0xfffd, 0xfffd, 0xfffd, 0x90db, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d97, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9345, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d94, 0xfffd, 0x9680, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d95, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d96, 0xfffd, 0x96cc, 0xfffd, 0x90a0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c82, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d9d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e54, 0x9d9a, 0xfffd, 0x9d99, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9451, 0xfffd, 0xfffd, 0xfffd, 0x93b3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9350, 0x9d9b, 0xfffd, 0xfffd, 0xfffd, 0x9d9c, 0xfffd, 0x958f, 0xfffd, 0x9464, 0x8e42, 0xfffd, 0x90ef, 0xfffd, 0x966f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a68, 0xfffd, 0x9da3, 0x9d9e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9769, 0x9da5, 0xfffd, 0xfffd, 0x9da1, 0xfffd, 0x9da2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9180, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9da0, 0xfffd, 0x9d5e, 0xfffd, 0xfffd, 0xfffd, 0x9da4, 0xfffd, 0x9d9f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9da9, 0x9daa, 0x9346, 0x9dac, 0xfffd, 0xfffd, 0x8e43, 0x9da7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b5b, 0xfffd, 0xfffd, 0x9dad, 0xfffd, 0x9da6, 0x9db1, 0xfffd, 0x9db0, 0xfffd, 0x9daf, 0xfffd, 0xfffd, 0xfffd, 0x9db2, 0xfffd, 0xfffd, 0x9db4, 0x8fef, 0xfffd, 0x9db3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9db7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9db5, 0xfffd, 0xfffd, 0xfffd, 0x9db6, 0x9d90, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9db9, 0x9db8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9d98, 0x9dba, 0x9dae, 0xfffd, 0xfffd, 0x8e78, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9dbb, 0x9dbc, 0x9dbe, 0x9dbd, 0x9dbf, 0x89fc, 0xfffd, 0x8d55, 0xfffd, 0xfffd, 0x95fa, 0x90ad, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ccc, 0xfffd, 0xfffd, 0x9dc1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9dc4, 0xfffd, 0x9571, 0xfffd, 0x8b7e, 0xfffd, 0xfffd, 0xfffd, 0x9dc3, 0x9dc2, 0x9473, 0x9dc5, 0x8bb3, 0xfffd, 0xfffd, 0xfffd, 0x9dc7, 0x9dc6, 0xfffd, 0xfffd, 0xfffd, 0x8ab8, 0x8e55, 0xfffd, 0xfffd, 0x93d6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c68, 0xfffd, 0xfffd, 0xfffd, 0x9094, 0xfffd, 0x9dc8, 0xfffd, 0x90ae, 0x9347, 0xfffd, 0x957e, 0x9dc9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9dca, 0x9dcb, 0xfffd, 0xfffd, 0xfffd, 0x95b6, 0x9b7c, 0x90c4, 0xfffd, 0xfffd, 0x956b, 0xfffd, 0x8dd6, 0xfffd, 0x94e3, 0x94c1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x936c, 0xfffd, 0x97bf, 0xfffd, 0x9dcd, 0x8ece, 0xfffd, 0xfffd, 0x9dce, 0xfffd, 0x88b4, 0xfffd, 0xfffd, 0x8bd2, 0x90cb, 0xfffd, 0x9580, 0xfffd, 0xfffd, 0xfffd, 0x9dcf, 0x8e61, 0x9266, 0xfffd, 0x8e7a, 0x9056, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9dd0, 0xfffd, 0x95fb, 0xfffd, 0xfffd, 0x8997, 0x8e7b, 0xfffd, 0xfffd, 0xfffd, 0x9dd3, 0xfffd, 0x9dd1, 0x9dd4, 0x97b7, 0x9dd2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90f9, 0x9dd5, 0xfffd, 0xfffd, 0x91b0, 0xfffd, 0xfffd, 0x9dd6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8af8, 0xfffd, 0x9dd8, 0xfffd, 0x9dd7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9dd9, 0x9dda, 0x8af9, 0xfffd, 0xfffd, 0x93fa, 0x9255, 0x8b8c, 0x8e7c, 0x9181, 0xfffd, 0xfffd, 0x8f7b, 0x88ae, 0xfffd, 0xfffd, 0xfffd, 0x9ddb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89a0, 0x9ddf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d56, 0x9dde, 0xfffd, 0xfffd, 0x8da9, 0x8fb8, 0xfffd, 0xfffd, 0x9ddd, 0xfffd, 0x8fb9, 0xfffd, 0x96be, 0x8da8, 0xfffd, 0xfffd, 0xfffd, 0x88d5, 0x90cc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9de4, 0xfffd, 0xfffd, 0x90af, 0x8966, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f74, 0xfffd, 0x9686, 0x8df0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fba, 0xfffd, 0x90a5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9de3, 0x9de1, 0x9de2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x928b, 0xfffd, 0xfffd, 0x9e45, 0xfffd, 0x9de8, 0x8e9e, 0x8d57, 0x9de6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9de7, 0xfffd, 0x9057, 0xfffd, 0xfffd, 0xfffd, 0x9de5, 0xfffd, 0xfffd, 0x8e4e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9dea, 0x9de9, 0x9dee, 0xfffd, 0xfffd, 0x9def, 0xfffd, 0x9deb, 0xfffd, 0x8a41, 0x9dec, 0x9ded, 0x94d3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9581, 0x8c69, 0x9df0, 0xfffd, 0xfffd, 0xfffd, 0x90b0, 0xfffd, 0x8fbb, 0xfffd, 0xfffd, 0xfffd, 0x9271, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8bc5, 0xfffd, 0x9df1, 0x9df5, 0xfffd, 0xfffd, 0x89c9, 0x9df2, 0x9df4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9df3, 0xfffd, 0xfffd, 0x8f8b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9267, 0x88c3, 0x9df6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9df7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92a8, 0xfffd, 0xfffd, 0xfffd, 0x97ef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e62, 0xfffd, 0xfffd, 0x95e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x965c, 0xfffd, 0xfffd, 0xfffd, 0x9e41, 0x9df9, 0xfffd, 0xfffd, 0x9dfc, 0xfffd, 0x9dfb, 0xfffd, 0xfffd, 0x9df8, 0xfffd, 0xfffd, 0x9e40, 0xfffd, 0xfffd, 0x93dc, 0xfffd, 0x9dfa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e42, 0xfffd, 0xfffd, 0x8f8c, 0x9e43, 0xfffd, 0x976a, 0x9498, 0xfffd, 0xfffd, 0x9e44, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e46, 0xfffd, 0xfffd, 0x9e47, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e48, 0xfffd, 0x8bc8, 0x8967, 0x8d58, 0x9e49, 0xfffd, 0x9e4a, 0x8f91, 0x9182, 0xfffd, 0xfffd, 0x99d6, 0x915d, 0x915c, 0x91d6, 0x8dc5, 0xfffd, 0xfffd, 0x98f0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c8e, 0x974c, 0xfffd, 0x95fc, 0xfffd, 0x959e, 0xfffd, 0x9e4b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8df1, 0x92bd, 0x9e4c, 0x984e, 0xfffd, 0xfffd, 0xfffd, 0x965d, 0xfffd, 0x92a9, 0x9e4d, 0x8afa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e4e, 0x9e4f, 0x96d8, 0xfffd, 0x96a2, 0x9696, 0x967b, 0x8e44, 0x9e51, 0xfffd, 0xfffd, 0x8ee9, 0xfffd, 0xfffd, 0x9670, 0xfffd, 0x9e53, 0x9e56, 0x9e55, 0xfffd, 0x8af7, 0xfffd, 0xfffd, 0x8b80, 0xfffd, 0x9e52, 0xfffd, 0x9e54, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e57, 0xfffd, 0xfffd, 0x9099, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x979b, 0x88c7, 0x8dde, 0x91ba, 0xfffd, 0x8edb, 0xfffd, 0xfffd, 0x8ff1, 0xfffd, 0xfffd, 0x9e5a, 0xfffd, 0xfffd, 0x936d, 0xfffd, 0x9e58, 0x91a9, 0x9e59, 0x8ff0, 0x96db, 0x9e5b, 0x9e5c, 0x9788, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e61, 0xfffd, 0xfffd, 0x8d59, 0xfffd, 0x9474, 0x9e5e, 0x938c, 0x9ddc, 0x9de0, 0xfffd, 0x8b6e, 0xfffd, 0x9466, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e60, 0xfffd, 0x8fbc, 0x94c2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e66, 0xfffd, 0x94f8, 0xfffd, 0x9e5d, 0xfffd, 0x9e63, 0x9e62, 0xfffd, 0xfffd, 0xfffd, 0x90cd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x968d, 0xfffd, 0x97d1, 0xfffd, 0xfffd, 0x9687, 0xfffd, 0x89ca, 0x8e7d, 0xfffd, 0xfffd, 0x9867, 0x9e65, 0x9095, 0xfffd, 0xfffd, 0xfffd, 0x9e64, 0xfffd, 0xfffd, 0x9e5f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ccd, 0xfffd, 0xfffd, 0xfffd, 0x9e6b, 0x9e69, 0xfffd, 0x89cb, 0x9e67, 0x9e6d, 0x9e73, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91c6, 0xfffd, 0xfffd, 0x95bf, 0xfffd, 0x9e75, 0xfffd, 0xfffd, 0xfffd, 0x9541, 0xfffd, 0xfffd, 0xfffd, 0x9e74, 0x9490, 0x965e, 0x8ab9, 0xfffd, 0x90f5, 0x8f5f, 0xfffd, 0xfffd, 0xfffd, 0x92d1, 0xfffd, 0x974d, 0xfffd, 0xfffd, 0x9e70, 0x9e6f, 0xfffd, 0xfffd, 0xfffd, 0x9e71, 0xfffd, 0x9e6e, 0xfffd, 0xfffd, 0x9e76, 0xfffd, 0x9e6c, 0xfffd, 0xfffd, 0x9e6a, 0xfffd, 0x9e72, 0x9e68, 0xfffd, 0x928c, 0xfffd, 0x96f6, 0x8ec4, 0x8df2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8db8, 0xfffd, 0xfffd, 0x968f, 0x8a60, 0xfffd, 0xfffd, 0x92cc, 0x93c8, 0x8968, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90f0, 0xfffd, 0xfffd, 0x90b2, 0x8c49, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e78, 0xfffd, 0xfffd, 0x8d5a, 0x8a9c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e7a, 0x8a94, 0x9e81, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e7d, 0xfffd, 0x90f1, 0xfffd, 0xfffd, 0xfffd, 0x8a6a, 0x8daa, 0xfffd, 0xfffd, 0x8a69, 0x8dcd, 0xfffd, 0xfffd, 0x9e7b, 0x8c85, 0x8c6a, 0x938d, 0xfffd, 0xfffd, 0x9e79, 0xfffd, 0x88c4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e7c, 0x9e7e, 0xfffd, 0x8bcb, 0x8c4b, 0xfffd, 0x8aba, 0x8b6a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e82, 0xfffd, 0xfffd, 0x8df7, 0x9691, 0xfffd, 0x8e56, 0xfffd, 0xfffd, 0xfffd, 0x9e83, 0xfffd, 0xfffd, 0xfffd, 0x954f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e8f, 0xfffd, 0x89b1, 0x9e84, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e95, 0x9e85, 0xfffd, 0x97c0, 0xfffd, 0x9e8c, 0xfffd, 0x947e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e94, 0xfffd, 0x9e87, 0xfffd, 0xfffd, 0xfffd, 0x88b2, 0x9e89, 0xfffd, 0xfffd, 0x8d5b, 0xfffd, 0xfffd, 0xfffd, 0x9e8b, 0xfffd, 0x9e8a, 0xfffd, 0x9e86, 0x9e91, 0xfffd, 0x8fbd, 0xfffd, 0xfffd, 0xfffd, 0x9aeb, 0x8ce6, 0x979c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e88, 0xfffd, 0x92f2, 0x8a42, 0x8dab, 0xfffd, 0x9e80, 0xfffd, 0x9e90, 0x8a81, 0xfffd, 0xfffd, 0x9e8e, 0x9e92, 0xfffd, 0x938e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8afc, 0xfffd, 0x9eb0, 0xfffd, 0xfffd, 0x96c7, 0x9e97, 0x8afb, 0xfffd, 0x9e9e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x965f, 0xfffd, 0x9e9f, 0x9ea1, 0xfffd, 0x9ea5, 0x9e99, 0xfffd, 0x9249, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x938f, 0x9ea9, 0x9e9c, 0xfffd, 0x9ea6, 0xfffd, 0xfffd, 0xfffd, 0x9ea0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9058, 0x9eaa, 0xfffd, 0xfffd, 0x90b1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ea8, 0x8abb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x986f, 0x9e96, 0xfffd, 0xfffd, 0x9ea4, 0x88d6, 0xfffd, 0xfffd, 0x9e98, 0xfffd, 0xfffd, 0x96b8, 0x9e9d, 0x9041, 0x92c5, 0x9e93, 0xfffd, 0xfffd, 0x9ea3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x909a, 0x9ead, 0x8a91, 0x8c9f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9eaf, 0x9e9a, 0x9eae, 0xfffd, 0x9ea7, 0x9e9b, 0xfffd, 0x9eab, 0xfffd, 0x9eac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ebd, 0xfffd, 0xfffd, 0xfffd, 0x93cc, 0xfffd, 0x9ea2, 0xfffd, 0xfffd, 0x9eb9, 0xfffd, 0xfffd, 0xfffd, 0x9ebb, 0xfffd, 0x92d6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x976b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9596, 0x9eb6, 0x91c8, 0xfffd, 0xfffd, 0xfffd, 0x9ebc, 0x915e, 0xfffd, 0x9eb3, 0x9ec0, 0x9ebf, 0xfffd, 0x93ed, 0x9ebe, 0x93e8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ec2, 0x9eb5, 0xfffd, 0x8bc6, 0x9eb8, 0x8f7c, 0xfffd, 0xfffd, 0xfffd, 0x9480, 0x9eba, 0x8bc9, 0xfffd, 0x9eb2, 0x9eb4, 0x9eb1, 0xfffd, 0xfffd, 0x984f, 0x8a79, 0x9eb7, 0xfffd, 0xfffd, 0x9ec1, 0x8a54, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8de5, 0xfffd, 0xfffd, 0xfffd, 0x897c, 0xfffd, 0xfffd, 0x9ed2, 0xfffd, 0xfffd, 0x9850, 0x9ed5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9059, 0x9ed4, 0xfffd, 0xfffd, 0xfffd, 0x9ed3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ed0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ec4, 0xfffd, 0xfffd, 0x9ee1, 0x9ec3, 0xfffd, 0x9ed6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ece, 0xfffd, 0xfffd, 0x9ec9, 0x9ec6, 0xfffd, 0x9ec7, 0xfffd, 0x9ecf, 0xfffd, 0xfffd, 0xfffd, 0xeaa0, 0xfffd, 0xfffd, 0x9ecc, 0x8d5c, 0x92c6, 0x9184, 0x9eca, 0xfffd, 0x9ec5, 0xfffd, 0xfffd, 0x9ec8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x976c, 0x968a, 0xfffd, 0xfffd, 0xfffd, 0x9ecd, 0x9ed7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9edf, 0x9ed8, 0xfffd, 0xfffd, 0x9ee5, 0xfffd, 0x9ee3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ede, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9edd, 0xfffd, 0x92ce, 0xfffd, 0x9185, 0xfffd, 0x9edb, 0xfffd, 0xfffd, 0x9ed9, 0xfffd, 0xfffd, 0x9ee0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ee6, 0x94f3, 0x9eec, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ee7, 0x9eea, 0x9ee4, 0xfffd, 0xfffd, 0x9294, 0xfffd, 0x9557, 0xfffd, 0x9eda, 0xfffd, 0xfffd, 0x9ee2, 0x8fbe, 0xfffd, 0x96cd, 0x9ef6, 0x9ee9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ca0, 0x89a1, 0x8a7e, 0xfffd, 0xfffd, 0x9ed1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fbf, 0x9eee, 0xfffd, 0x9ef5, 0x8ef7, 0x8a92, 0xfffd, 0xfffd, 0x924d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9eeb, 0xfffd, 0xfffd, 0x9ef0, 0x9ef4, 0xfffd, 0xfffd, 0x8bb4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b6b, 0x9ef2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b40, 0xfffd, 0x93c9, 0x9ef1, 0xfffd, 0xfffd, 0xfffd, 0x9ef3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9eed, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9eef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a80, 0x9268, 0xfffd, 0xfffd, 0xfffd, 0x9efa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ef8, 0x8ce7, 0xfffd, 0x9ef7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f40, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e77, 0xfffd, 0xfffd, 0xfffd, 0x9ef9, 0xfffd, 0x9efb, 0x9efc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f4b, 0xfffd, 0x9f47, 0xfffd, 0x9e8d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f46, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f45, 0xfffd, 0xfffd, 0x9f42, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ee8, 0x9f44, 0x9f43, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f49, 0xfffd, 0x9845, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f4c, 0x8bf9, 0xfffd, 0xfffd, 0x9f48, 0x9f4a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94a5, 0xfffd, 0x9f4d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f51, 0x9f4e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9793, 0x9f4f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9edc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f52, 0xfffd, 0xfffd, 0xfffd, 0x9f53, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8954, 0xfffd, 0x9f55, 0x8c87, 0x8e9f, 0xfffd, 0x8bd3, 0xfffd, 0xfffd, 0xfffd, 0x89a2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x977e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f57, 0x9f56, 0x9f59, 0x8b5c, 0xfffd, 0xfffd, 0x8bd4, 0x8abc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f5c, 0xfffd, 0xfffd, 0xfffd, 0x9f5b, 0xfffd, 0x9f5d, 0xfffd, 0xfffd, 0x89cc, 0xfffd, 0x9256, 0xfffd, 0x9f5e, 0xfffd, 0xfffd, 0x8abd, 0x9f60, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f5f, 0xfffd, 0x9f61, 0xfffd, 0xfffd, 0xfffd, 0x9f62, 0xfffd, 0x9f63, 0x8e7e, 0x90b3, 0x8d9f, 0xfffd, 0x9590, 0xfffd, 0xfffd, 0x95e0, 0x9863, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e95, 0xfffd, 0xfffd, 0xfffd, 0x8dce, 0x97f0, 0xfffd, 0xfffd, 0xfffd, 0x9f64, 0x9f65, 0xfffd, 0x8e80, 0xfffd, 0xfffd, 0xfffd, 0x9f66, 0x9f67, 0xfffd, 0xfffd, 0x9f69, 0x9f68, 0xfffd, 0x9677, 0xfffd, 0xfffd, 0x8f7d, 0x8eea, 0x8e63, 0xfffd, 0x9f6a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f6c, 0x9042, 0xfffd, 0x9f6b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f6d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f6e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f6f, 0x9f70, 0xfffd, 0xfffd, 0xfffd, 0x9f71, 0xfffd, 0x9f73, 0x9f72, 0x9f74, 0x89a3, 0x9269, 0xfffd, 0x9f75, 0xfffd, 0xfffd, 0x8e45, 0x8a6b, 0x9f76, 0xfffd, 0xfffd, 0x9361, 0x9aca, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b42, 0x9f77, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f78, 0xfffd, 0x95ea, 0x9688, 0xfffd, 0xfffd, 0xfffd, 0x93c5, 0x9f79, 0x94e4, 0xfffd, 0xfffd, 0xfffd, 0x94f9, 0xfffd, 0xfffd, 0x96d1, 0xfffd, 0xfffd, 0xfffd, 0x9f7a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f7c, 0x9f7b, 0xfffd, 0xfffd, 0x9f7e, 0xfffd, 0xfffd, 0xfffd, 0x9f7d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f81, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e81, 0xfffd, 0x96af, 0xfffd, 0x9f82, 0x9f83, 0xfffd, 0xfffd, 0x8b43, 0xfffd, 0xfffd, 0xfffd, 0x9f84, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f86, 0x9f85, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9085, 0xfffd, 0xfffd, 0x9558, 0x8969, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94c3, 0xfffd, 0x92f3, 0x8f60, 0x8b81, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94c4, 0xfffd, 0x8eac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f88, 0xfffd, 0x8abe, 0xfffd, 0xfffd, 0x8998, 0xfffd, 0xfffd, 0x93f0, 0x9f87, 0x8d5d, 0x9272, 0xfffd, 0x9f89, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f91, 0xfffd, 0x9f8a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91bf, 0xfffd, 0x8b82, 0x9f92, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c88, 0xfffd, 0xfffd, 0x8b44, 0x9f90, 0xfffd, 0xfffd, 0x9f8e, 0x9f8b, 0x9780, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92be, 0xfffd, 0xfffd, 0xfffd, 0x93d7, 0x9f8c, 0xfffd, 0xfffd, 0x9f94, 0xfffd, 0x9f93, 0x8c42, 0xfffd, 0xfffd, 0x89ab, 0xfffd, 0xfffd, 0x8db9, 0x9f8d, 0x9f8f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9676, 0x91f2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9697, 0xfffd, 0xfffd, 0x9f9c, 0xfffd, 0xfffd, 0x9f9d, 0xfffd, 0x89cd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95a6, 0x96fb, 0x9f9f, 0x8ea1, 0x8fc0, 0x9f98, 0x9f9e, 0x8988, 0xfffd, 0x8bb5, 0xfffd, 0xfffd, 0x9f95, 0x9f9a, 0xfffd, 0xfffd, 0xfffd, 0x90f2, 0x9491, 0xfffd, 0x94e5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9f97, 0xfffd, 0x9640, 0xfffd, 0x9f99, 0xfffd, 0x9fa2, 0xfffd, 0x9fa0, 0xfffd, 0x9f9b, 0xfffd, 0xfffd, 0xfffd, 0x9641, 0x9467, 0x8b83, 0xfffd, 0x9344, 0xfffd, 0xfffd, 0x928d, 0xfffd, 0x9fa3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fa1, 0x91d7, 0x9f96, 0xfffd, 0x896a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x976d, 0x9fae, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fad, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90f4, 0xfffd, 0x9faa, 0xfffd, 0x978c, 0xfffd, 0xfffd, 0x93b4, 0x9fa4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92c3, 0xfffd, 0xfffd, 0xfffd, 0x896b, 0x8d5e, 0x9fa7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f46, 0x9fac, 0xfffd, 0x9fab, 0x9fa6, 0xfffd, 0x9fa9, 0xfffd, 0xfffd, 0x8a88, 0xfffd, 0x9fa8, 0x9468, 0xfffd, 0xfffd, 0x97ac, 0xfffd, 0xfffd, 0x8ff2, 0x90f3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fb4, 0x9fb2, 0xfffd, 0x956c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9faf, 0x9fb1, 0xfffd, 0x8959, 0xfffd, 0xfffd, 0x8d5f, 0x9851, 0xfffd, 0x8a5c, 0xfffd, 0x9582, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9781, 0xfffd, 0xfffd, 0x8a43, 0x905a, 0x9fb3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fb8, 0xfffd, 0xfffd, 0x8fc1, 0xfffd, 0xfffd, 0xfffd, 0x974f, 0xfffd, 0x9fb5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fb0, 0xfffd, 0x9fb6, 0xfffd, 0xfffd, 0xfffd, 0x97dc, 0xfffd, 0x9393, 0x93c0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a55, 0xfffd, 0xfffd, 0x8974, 0xfffd, 0xfffd, 0x9fbc, 0xfffd, 0xfffd, 0x9fbf, 0xfffd, 0xfffd, 0xfffd, 0x97c1, 0xfffd, 0xfffd, 0xfffd, 0x9784, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fc6, 0x9fc0, 0x9fbd, 0xfffd, 0xfffd, 0xfffd, 0x97d2, 0x9fc3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f69, 0x9fc5, 0xfffd, 0xfffd, 0x9fca, 0xfffd, 0xfffd, 0x9391, 0x9fc8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fc2, 0xfffd, 0xfffd, 0x9257, 0xfffd, 0xfffd, 0x9fc9, 0xfffd, 0x9fbe, 0xfffd, 0x9fc4, 0xfffd, 0x9fcb, 0x88fa, 0x9fc1, 0xfffd, 0x9fcc, 0xfffd, 0xfffd, 0x905b, 0xfffd, 0x8f7e, 0xfffd, 0x95a3, 0xfffd, 0x8dac, 0xfffd, 0x9fb9, 0x9fc7, 0x9359, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90b4, 0xfffd, 0x8a89, 0x8dcf, 0x8fc2, 0x9fbb, 0x8f61, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c6b, 0xfffd, 0x9fba, 0xfffd, 0xfffd, 0xfffd, 0x9fd0, 0x8f8d, 0x8cb8, 0xfffd, 0x9fdf, 0xfffd, 0x9fd9, 0x8b94, 0x936e, 0xfffd, 0x9fd4, 0x9fdd, 0x88ad, 0x8951, 0xfffd, 0xfffd, 0x89b7, 0xfffd, 0x9fd6, 0x91aa, 0x9fcd, 0x9fcf, 0x8d60, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fe0, 0xfffd, 0x9fdb, 0xfffd, 0xfffd, 0xfffd, 0x9fd3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fda, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96a9, 0xfffd, 0xfffd, 0x9fd8, 0x9fdc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cce, 0xfffd, 0x8fc3, 0xfffd, 0xfffd, 0x9258, 0xfffd, 0xfffd, 0xfffd, 0x9fd2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x974e, 0xfffd, 0xfffd, 0xfffd, 0x9fd5, 0xfffd, 0xfffd, 0x9fce, 0x9392, 0xfffd, 0xfffd, 0x9fd1, 0xfffd, 0xfffd, 0xfffd, 0x9fd7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9870, 0x8ebc, 0x969e, 0xfffd, 0x9fe1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94ac, 0xfffd, 0xfffd, 0x9fed, 0x8cb9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f80, 0xfffd, 0x9fe3, 0xfffd, 0xfffd, 0xfffd, 0x97ad, 0x8d61, 0xfffd, 0x9ff0, 0xfffd, 0xfffd, 0x88ec, 0xfffd, 0xfffd, 0x9fee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fe2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fe8, 0xfffd, 0xfffd, 0x9fea, 0xfffd, 0xfffd, 0xfffd, 0x976e, 0x9fe5, 0xfffd, 0xfffd, 0x934d, 0xfffd, 0xfffd, 0x9fe7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9fef, 0xfffd, 0x9fe9, 0x96c5, 0xfffd, 0xfffd, 0xfffd, 0x9fe4, 0xfffd, 0x8ea0, 0x9ffc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a8a, 0xfffd, 0x9fe6, 0x9feb, 0x9fec, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91ea, 0x91d8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ff4, 0xfffd, 0xfffd, 0x9ffa, 0xfffd, 0xfffd, 0x9ff8, 0xfffd, 0x9348, 0xfffd, 0xfffd, 0xe042, 0x9ff5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ff6, 0x9fde, 0xfffd, 0x8b99, 0x9559, 0xfffd, 0xfffd, 0xfffd, 0x8ebd, 0xfffd, 0xfffd, 0x8d97, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9852, 0xfffd, 0x9ff2, 0xfffd, 0xe041, 0x8989, 0x9186, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9499, 0xfffd, 0x8abf, 0x97f8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x969f, 0x92d0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ff9, 0x9ffb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9151, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe040, 0x9ff7, 0xfffd, 0x9ff1, 0xfffd, 0xfffd, 0xfffd, 0x8ac1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c89, 0xfffd, 0xfffd, 0xfffd, 0xe04e, 0xfffd, 0xfffd, 0xe049, 0x90f6, 0xfffd, 0xfffd, 0x8a83, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f81, 0xfffd, 0xe052, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe04b, 0x92aa, 0xe048, 0x92d7, 0xfffd, 0xfffd, 0xfffd, 0xe06b, 0xfffd, 0xfffd, 0xfffd, 0xe045, 0xfffd, 0xe044, 0xfffd, 0xe04d, 0xfffd, 0xfffd, 0xfffd, 0xe047, 0xe046, 0xe04c, 0xfffd, 0x909f, 0xfffd, 0xe043, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe04f, 0xfffd, 0xfffd, 0xe050, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ac0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe055, 0xfffd, 0xe054, 0xe056, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe059, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9362, 0xfffd, 0xe053, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe057, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c83, 0x91f7, 0xe051, 0x945a, 0xfffd, 0xfffd, 0xe058, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe05d, 0xe05b, 0xfffd, 0xfffd, 0xe05e, 0xfffd, 0xfffd, 0xe061, 0xfffd, 0xfffd, 0xfffd, 0xe05a, 0x8d8a, 0x9447, 0xfffd, 0xfffd, 0x9fb7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9794, 0xe05c, 0xfffd, 0xe060, 0x91f3, 0xfffd, 0xe05f, 0xfffd, 0xe04a, 0xfffd, 0xfffd, 0xe889, 0xfffd, 0xfffd, 0xfffd, 0xe064, 0xfffd, 0xfffd, 0xfffd, 0xe068, 0xfffd, 0xfffd, 0xe066, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe062, 0xfffd, 0xe063, 0xfffd, 0xfffd, 0xfffd, 0xe067, 0xfffd, 0xe065, 0xfffd, 0xfffd, 0xfffd, 0x956d, 0xfffd, 0xfffd, 0xe06d, 0xfffd, 0xe06a, 0xe069, 0xfffd, 0xe06c, 0x93d2, 0xe06e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9295, 0x91eb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90a3, 0xfffd, 0xfffd, 0xfffd, 0xe06f, 0xfffd, 0xe071, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe070, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9ff3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe072, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93e5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe073, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89ce, 0xfffd, 0xfffd, 0xfffd, 0x9394, 0x8a44, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b84, 0xfffd, 0xfffd, 0xfffd, 0x8edc, 0x8dd0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9846, 0x9086, 0xfffd, 0xfffd, 0xfffd, 0x898a, 0xfffd, 0xfffd, 0xfffd, 0xe075, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe074, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe078, 0x9259, 0xe07b, 0xe076, 0xfffd, 0xfffd, 0xfffd, 0xe07a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe079, 0x935f, 0x88d7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97f3, 0xfffd, 0xfffd, 0xe07d, 0xfffd, 0xfffd, 0xfffd, 0x8947, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe080, 0xfffd, 0xfffd, 0xfffd, 0xe07e, 0xfffd, 0xe07c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe077, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9642, 0xfffd, 0xfffd, 0xfffd, 0xe082, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe081, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x898b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe084, 0x95b0, 0xfffd, 0xe083, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96b3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fc5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9152, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fc4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97f9, 0xfffd, 0xfffd, 0xe08a, 0xfffd, 0x90f7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe086, 0xe08b, 0xfffd, 0xfffd, 0x898c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe089, 0xfffd, 0x9481, 0xe085, 0xe088, 0x8fc6, 0xfffd, 0x94cf, 0xfffd, 0xfffd, 0xe08c, 0xfffd, 0x8ecf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90f8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe08f, 0xfffd, 0xfffd, 0xfffd, 0xe087, 0xfffd, 0x8c46, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe08d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x976f, 0xe090, 0xfffd, 0xfffd, 0xfffd, 0xeaa4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f6e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe091, 0xfffd, 0xfffd, 0xfffd, 0xe092, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x944d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe094, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe095, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9452, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9395, 0xe097, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe099, 0xfffd, 0x97d3, 0xfffd, 0xe096, 0xfffd, 0xe098, 0x898d, 0xfffd, 0xe093, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9a7a, 0xe09a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9187, 0x8e57, 0xe09c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe09b, 0x9043, 0x99d7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe09d, 0xfffd, 0xfffd, 0xfffd, 0xe09f, 0xfffd, 0xe08e, 0xe09e, 0xfffd, 0xfffd, 0xe0a0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x949a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0a1, 0xfffd, 0xfffd, 0xe0a2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0a3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0a4, 0xfffd, 0x92dc, 0xfffd, 0xe0a6, 0xe0a5, 0xfffd, 0xfffd, 0xe0a7, 0xfffd, 0xe0a8, 0xfffd, 0xfffd, 0x8edd, 0x9583, 0xfffd, 0xfffd, 0xfffd, 0x96ea, 0xe0a9, 0xe0aa, 0x9175, 0x8ea2, 0xe0ab, 0xe0ac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0ad, 0x95d0, 0x94c5, 0xfffd, 0xfffd, 0xe0ae, 0x9476, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92ab, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0af, 0x89e5, 0xfffd, 0x8b8d, 0xfffd, 0x96c4, 0xfffd, 0x96b4, 0xfffd, 0x89b2, 0x9853, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9671, 0xfffd, 0x95a8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90b5, 0xfffd, 0xe0b0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93c1, 0xfffd, 0xfffd, 0xfffd, 0x8ca1, 0xe0b1, 0xfffd, 0x8dd2, 0xe0b3, 0xe0b2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0b4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0b5, 0xfffd, 0xfffd, 0xfffd, 0xe0b6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b5d, 0xfffd, 0xe0b7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0b8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ca2, 0xfffd, 0xfffd, 0x94c6, 0xfffd, 0xfffd, 0xe0ba, 0xfffd, 0xfffd, 0xfffd, 0x8ff3, 0xfffd, 0xfffd, 0xe0b9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8bb6, 0xe0bb, 0xe0bd, 0xfffd, 0xe0bc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0be, 0xfffd, 0x8ccf, 0xfffd, 0xe0bf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8be7, 0xfffd, 0x915f, 0xfffd, 0x8d9d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0c1, 0xe0c2, 0xe0c0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8eeb, 0xfffd, 0xfffd, 0x93c6, 0x8bb7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0c4, 0x924b, 0xe0c3, 0xfffd, 0xfffd, 0x9854, 0x9482, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0c7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0c9, 0xe0c6, 0xfffd, 0xfffd, 0xfffd, 0x96d2, 0xe0c8, 0xe0ca, 0xfffd, 0x97c2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0ce, 0xfffd, 0xfffd, 0xfffd, 0xe0cd, 0x9296, 0x944c, 0xfffd, 0xfffd, 0x8ca3, 0xe0cc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0cb, 0xfffd, 0x9750, 0x9751, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0cf, 0x898e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d96, 0x8e82, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0d0, 0xe0d1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0d3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f62, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0d5, 0xfffd, 0xe0d4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0d6, 0xfffd, 0x8a6c, 0xfffd, 0xfffd, 0xe0d8, 0xfffd, 0xfffd, 0xe0d7, 0xfffd, 0xe0da, 0xe0d9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cba, 0xfffd, 0xfffd, 0x97a6, 0xfffd, 0x8bca, 0xfffd, 0x89a4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8be8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8adf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97e6, 0xe0dc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0de, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0df, 0xfffd, 0x89cf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0db, 0xfffd, 0x8e58, 0xfffd, 0xfffd, 0x92bf, 0xe0dd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0e2, 0xfffd, 0x8eec, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0e0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c5d, 0xfffd, 0xfffd, 0x94c7, 0xe0e1, 0xfffd, 0xfffd, 0xe0fc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0e7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cbb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b85, 0xfffd, 0xe0e4, 0x979d, 0xfffd, 0xfffd, 0x97ae, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91f4, 0xfffd, 0xfffd, 0xe0e6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0e8, 0x97d4, 0x8bd5, 0x94fa, 0x9469, 0xfffd, 0xfffd, 0xfffd, 0xe0e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0eb, 0xfffd, 0xe0ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0ea, 0xfffd, 0xfffd, 0xfffd, 0xe0ed, 0x8ce8, 0x896c, 0xe0ef, 0xfffd, 0x9090, 0xe0ec, 0x97da, 0xfffd, 0xfffd, 0xe0f2, 0xeaa2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0f0, 0xe0f3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0e5, 0xe0f1, 0xfffd, 0xfffd, 0x8dba, 0xfffd, 0xfffd, 0xe0f4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0f5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x979e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0f7, 0xfffd, 0xfffd, 0xfffd, 0xe0e3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0f8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ac2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ea3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0f9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0fa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe0fb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x895a, 0xfffd, 0xfffd, 0xfffd, 0xe140, 0xfffd, 0x955a, 0xe141, 0xfffd, 0xfffd, 0x8aa2, 0xe142, 0xfffd, 0xe143, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe144, 0xfffd, 0xe146, 0xe147, 0xe145, 0xfffd, 0xfffd, 0xfffd, 0x9572, 0xe149, 0xe148, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe14b, 0xe14a, 0xe14c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe14d, 0xe14f, 0xe14e, 0xfffd, 0xfffd, 0x8d99, 0xfffd, 0xe151, 0xfffd, 0xe150, 0xfffd, 0xfffd, 0x8ac3, 0xfffd, 0x9072, 0xfffd, 0x935b, 0xfffd, 0xe152, 0x90b6, 0xfffd, 0xfffd, 0xfffd, 0x8e59, 0xfffd, 0x8999, 0xe153, 0xfffd, 0x9770, 0xfffd, 0xfffd, 0x95e1, 0xe154, 0xfffd, 0xfffd, 0xfffd, 0x9363, 0x9752, 0x8d62, 0x905c, 0xfffd, 0xfffd, 0xfffd, 0x926a, 0x99b2, 0xfffd, 0x92ac, 0x89e6, 0xe155, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe156, 0xfffd, 0xe15b, 0xfffd, 0xfffd, 0xe159, 0xe158, 0x9dc0, 0x8a45, 0xe157, 0xfffd, 0x88d8, 0xfffd, 0x94a8, 0xfffd, 0xfffd, 0x94c8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97af, 0xe15c, 0xe15a, 0x927b, 0x90a4, 0xfffd, 0xfffd, 0x94a9, 0xfffd, 0x954c, 0xfffd, 0xe15e, 0x97aa, 0x8c6c, 0xe15f, 0xfffd, 0xe15d, 0x94d4, 0xe160, 0xfffd, 0xe161, 0xfffd, 0xfffd, 0x88d9, 0xfffd, 0xfffd, 0x8ff4, 0xe166, 0xfffd, 0xe163, 0x93eb, 0xe162, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b45, 0xfffd, 0xfffd, 0xe169, 0xfffd, 0xfffd, 0xfffd, 0xe164, 0xe165, 0xfffd, 0xe168, 0xe167, 0x9544, 0xfffd, 0xfffd, 0x9161, 0x9160, 0xfffd, 0x8b5e, 0xfffd, 0xfffd, 0xe16a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe16b, 0xfffd, 0xfffd, 0xe16c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe16e, 0xfffd, 0xe16d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8975, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe176, 0x94e6, 0xe170, 0xfffd, 0xe172, 0xfffd, 0xfffd, 0xe174, 0x905d, 0xfffd, 0xfffd, 0xe175, 0xe173, 0x8ebe, 0xfffd, 0xfffd, 0xfffd, 0xe16f, 0xe171, 0xfffd, 0x9561, 0xfffd, 0x8fc7, 0xfffd, 0xfffd, 0xe178, 0xfffd, 0xfffd, 0xe177, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe179, 0xfffd, 0x8ea4, 0x8dad, 0xfffd, 0xfffd, 0x9397, 0xe17a, 0xfffd, 0x92c9, 0xfffd, 0xfffd, 0xe17c, 0xfffd, 0xfffd, 0xfffd, 0x979f, 0xe17b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9189, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe182, 0xfffd, 0xe184, 0xe185, 0x9273, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe183, 0xfffd, 0xe180, 0xfffd, 0xe17d, 0xe17e, 0xfffd, 0xe181, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe188, 0xfffd, 0xe186, 0xfffd, 0xe187, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe189, 0xe18b, 0xe18c, 0xe18d, 0xfffd, 0xe18e, 0xfffd, 0xfffd, 0xe18a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe190, 0xfffd, 0xfffd, 0xfffd, 0xe18f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe191, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97c3, 0xfffd, 0xfffd, 0xfffd, 0xe194, 0xe192, 0xe193, 0xfffd, 0xfffd, 0xfffd, 0x8ae0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96fc, 0xfffd, 0xfffd, 0xfffd, 0x95c8, 0xfffd, 0xe196, 0xfffd, 0xfffd, 0xfffd, 0xe195, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe197, 0xe198, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe19c, 0xe199, 0xe19a, 0xe19b, 0xfffd, 0xe19d, 0xfffd, 0xfffd, 0xfffd, 0xe19e, 0xfffd, 0xe19f, 0xfffd, 0xfffd, 0xfffd, 0xe1a0, 0xfffd, 0xe1a1, 0xfffd, 0x94ad, 0x936f, 0xe1a2, 0x9492, 0x9553, 0xfffd, 0xe1a3, 0xfffd, 0xfffd, 0xe1a4, 0x9349, 0xfffd, 0x8a46, 0x8d63, 0xe1a5, 0xfffd, 0xfffd, 0xe1a6, 0xfffd, 0xfffd, 0xe1a7, 0xfffd, 0x8e48, 0xfffd, 0xfffd, 0xe1a9, 0xfffd, 0xfffd, 0xe1a8, 0xfffd, 0xfffd, 0xe1aa, 0xe1ab, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94e7, 0xfffd, 0xe1ac, 0xfffd, 0xfffd, 0xfffd, 0xe1ad, 0xfffd, 0xfffd, 0xea89, 0xe1ae, 0xe1af, 0xe1b0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e4d, 0xfffd, 0xfffd, 0xe1b1, 0x9475, 0xfffd, 0xfffd, 0x967e, 0xfffd, 0x896d, 0xfffd, 0x8976, 0xfffd, 0xfffd, 0xe1b2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1b4, 0xfffd, 0xfffd, 0xfffd, 0xe1b3, 0x9390, 0xfffd, 0xfffd, 0xfffd, 0x90b7, 0x9f58, 0xfffd, 0xe1b5, 0x96bf, 0xfffd, 0xe1b6, 0xfffd, 0x8ac4, 0x94d5, 0xe1b7, 0xfffd, 0xe1b8, 0xfffd, 0xfffd, 0xe1b9, 0xfffd, 0xfffd, 0xfffd, 0x96da, 0xfffd, 0xfffd, 0xfffd, 0x96d3, 0xfffd, 0x92bc, 0xfffd, 0xfffd, 0xfffd, 0x918a, 0xfffd, 0xfffd, 0xe1bb, 0xfffd, 0xfffd, 0x8f82, 0xfffd, 0xfffd, 0x8fc8, 0xfffd, 0xfffd, 0xe1be, 0xfffd, 0xfffd, 0xe1bd, 0xe1bc, 0x94fb, 0xfffd, 0x8ac5, 0x8ca7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1c4, 0xfffd, 0xfffd, 0xe1c1, 0x905e, 0x96b0, 0xfffd, 0xfffd, 0xfffd, 0xe1c0, 0xe1c2, 0xe1c3, 0xfffd, 0xfffd, 0xe1bf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1c5, 0xe1c6, 0xfffd, 0x92ad, 0xfffd, 0x8ae1, 0xfffd, 0xfffd, 0xfffd, 0x9285, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1c7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1c8, 0xe1cb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9087, 0xfffd, 0x93c2, 0xfffd, 0xe1cc, 0x9672, 0xfffd, 0xe1c9, 0xfffd, 0xfffd, 0xe1ca, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1cf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1ce, 0xe1cd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1d1, 0xfffd, 0xfffd, 0xe1d0, 0xfffd, 0xfffd, 0xe1d2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1d4, 0xfffd, 0xe1d3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95cb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f75, 0x97c4, 0xfffd, 0xfffd, 0xe1d5, 0xfffd, 0xfffd, 0x93b5, 0xfffd, 0xfffd, 0xe1d6, 0xfffd, 0xfffd, 0xe1d7, 0xfffd, 0xe1db, 0xe1d9, 0xe1da, 0xfffd, 0xe1d8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1dc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1dd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1de, 0xfffd, 0xfffd, 0xe1df, 0x96b5, 0xe1e0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96ee, 0xe1e1, 0xfffd, 0x926d, 0xfffd, 0x948a, 0xfffd, 0x8be9, 0xfffd, 0xfffd, 0xfffd, 0x925a, 0xe1e2, 0x8bb8, 0xfffd, 0xfffd, 0xfffd, 0x90ce, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1e3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8dbb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1e4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1e5, 0xfffd, 0x8ca4, 0x8dd3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1e7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9375, 0x8dd4, 0x8b6d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9643, 0xfffd, 0x946a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9376, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d7b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fc9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97b0, 0x8d64, 0xfffd, 0xfffd, 0x8ca5, 0xfffd, 0xfffd, 0x94a1, 0xfffd, 0xe1eb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1ed, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ce9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1ec, 0x92f4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1ef, 0x8a56, 0xe1ea, 0xfffd, 0xfffd, 0x94e8, 0xfffd, 0x894f, 0xfffd, 0x8dea, 0xfffd, 0x9871, 0xfffd, 0xfffd, 0xe1ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1f0, 0xfffd, 0xfffd, 0xfffd, 0x95c9, 0xfffd, 0x90d7, 0xe1f2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1f3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1f1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a6d, 0xfffd, 0xe1f9, 0xfffd, 0xe1f8, 0xfffd, 0xfffd, 0x8ea5, 0xfffd, 0xfffd, 0xfffd, 0xe1fa, 0xe1f5, 0xfffd, 0xfffd, 0xfffd, 0xe1fb, 0xe1f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94d6, 0xe1f4, 0xfffd, 0xfffd, 0xe1f7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe241, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe240, 0x9681, 0xfffd, 0xfffd, 0xfffd, 0xe1fc, 0xfffd, 0xfffd, 0x88e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe243, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe242, 0xfffd, 0xfffd, 0xfffd, 0x8fca, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe244, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9162, 0xfffd, 0xfffd, 0xe246, 0xe245, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe247, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe1e6, 0xfffd, 0xfffd, 0xfffd, 0xe1e8, 0xe249, 0xe248, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ea6, 0xfffd, 0x97e7, 0xfffd, 0x8ed0, 0xfffd, 0xe24a, 0x8c56, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b5f, 0x8b46, 0x8e83, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9753, 0xfffd, 0xfffd, 0xe250, 0xfffd, 0xe24f, 0x9163, 0xe24c, 0xfffd, 0xfffd, 0xe24e, 0xfffd, 0xfffd, 0x8f6a, 0x905f, 0xe24d, 0xe24b, 0xfffd, 0x9449, 0xfffd, 0xfffd, 0x8fcb, 0xfffd, 0xfffd, 0x955b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8dd5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9398, 0xfffd, 0xfffd, 0xe251, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe252, 0xe268, 0x8bd6, 0xfffd, 0xfffd, 0x985c, 0x9154, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe253, 0xfffd, 0xfffd, 0x89d0, 0x92f5, 0x959f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe254, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b9a, 0xe255, 0xfffd, 0xfffd, 0xe257, 0xfffd, 0xfffd, 0xfffd, 0xe258, 0xfffd, 0x9448, 0xfffd, 0xfffd, 0xe259, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe25a, 0xe25b, 0xfffd, 0xfffd, 0x8bd7, 0x89d1, 0x93c3, 0x8f47, 0x8e84, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe25c, 0xfffd, 0x8f48, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89c8, 0x9562, 0xfffd, 0xfffd, 0xe25d, 0xfffd, 0xfffd, 0x94e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9164, 0xfffd, 0xe260, 0xfffd, 0xe261, 0x9489, 0xfffd, 0x9060, 0xe25e, 0xfffd, 0x9281, 0xfffd, 0xfffd, 0xe25f, 0xfffd, 0xfffd, 0xfffd, 0x8fcc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88da, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b48, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe262, 0xfffd, 0xfffd, 0x92f6, 0xfffd, 0xe263, 0x90c5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96ab, 0xfffd, 0xfffd, 0x9542, 0xe264, 0xe265, 0x9274, 0xfffd, 0x97c5, 0xfffd, 0xfffd, 0xe267, 0xe266, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8eed, 0xfffd, 0xfffd, 0xe269, 0x88ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe26c, 0xfffd, 0xfffd, 0xfffd, 0xe26a, 0x89d2, 0x8c6d, 0xe26b, 0x8d65, 0x8d92, 0xfffd, 0x95e4, 0xe26d, 0xfffd, 0xfffd, 0x9673, 0xfffd, 0xfffd, 0xe26f, 0xfffd, 0xfffd, 0xfffd, 0x90cf, 0x896e, 0x89b8, 0x88aa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe26e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe270, 0xe271, 0x8ff5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe272, 0xfffd, 0x8a6e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe274, 0xfffd, 0xfffd, 0xfffd, 0x8c8a, 0xfffd, 0x8b86, 0xfffd, 0xfffd, 0xe275, 0x8bf3, 0xfffd, 0xfffd, 0xe276, 0xfffd, 0x90fa, 0xfffd, 0x93cb, 0xfffd, 0x90de, 0x8df3, 0xfffd, 0xfffd, 0xfffd, 0xe277, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9282, 0x918b, 0xfffd, 0xe279, 0xe27b, 0xe278, 0xe27a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c41, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe27c, 0x8c45, 0xfffd, 0xfffd, 0xfffd, 0x8b87, 0x9771, 0xe27e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe280, 0xfffd, 0xfffd, 0xfffd, 0x894d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe283, 0xfffd, 0xfffd, 0xfffd, 0x8a96, 0xe282, 0xe281, 0xfffd, 0xe285, 0xe27d, 0xfffd, 0xe286, 0x97a7, 0xfffd, 0xe287, 0xfffd, 0xe288, 0xfffd, 0xfffd, 0x9af2, 0xe28a, 0xfffd, 0xe289, 0xfffd, 0xfffd, 0xfffd, 0xe28b, 0xe28c, 0xfffd, 0x97b3, 0xe28d, 0xfffd, 0xe8ed, 0x8fcd, 0xe28e, 0xe28f, 0x8f76, 0xfffd, 0x93b6, 0xe290, 0xfffd, 0xfffd, 0xfffd, 0x9247, 0xfffd, 0xfffd, 0xe291, 0xfffd, 0x925b, 0xe292, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ba3, 0xfffd, 0x995e, 0x927c, 0x8eb1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ac6, 0xfffd, 0xfffd, 0xe293, 0xfffd, 0xe2a0, 0xfffd, 0xe296, 0xfffd, 0x8b88, 0xfffd, 0xe295, 0xe2a2, 0xfffd, 0xfffd, 0xfffd, 0xe294, 0xfffd, 0x8fce, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe298, 0xe299, 0xfffd, 0x934a, 0xfffd, 0xfffd, 0xe29a, 0xfffd, 0x8a7d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9079, 0x9584, 0xfffd, 0xe29c, 0xfffd, 0xfffd, 0xfffd, 0x91e6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe297, 0xfffd, 0xe29b, 0xe29d, 0xfffd, 0xfffd, 0x8df9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2a4, 0x954d, 0xfffd, 0x94a4, 0x9399, 0xfffd, 0x8bd8, 0xe2a3, 0xe2a1, 0xfffd, 0x94b3, 0xe29e, 0x927d, 0x939b, 0xfffd, 0x939a, 0xfffd, 0x8df4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2b6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2a6, 0xfffd, 0xe2a8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2ab, 0xfffd, 0xe2ac, 0xfffd, 0xe2a9, 0xe2aa, 0xfffd, 0xfffd, 0xe2a7, 0xe2a5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe29f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95cd, 0x89d3, 0xfffd, 0xfffd, 0xfffd, 0xe2b3, 0xfffd, 0xe2b0, 0xfffd, 0xe2b5, 0xfffd, 0xfffd, 0xe2b4, 0xfffd, 0x9493, 0x96a5, 0xfffd, 0x8e5a, 0xe2ae, 0xe2b7, 0xe2b2, 0xfffd, 0xe2b1, 0xe2ad, 0xfffd, 0xe2af, 0xfffd, 0x8ac7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x925c, 0xfffd, 0xfffd, 0x90fb, 0xfffd, 0xfffd, 0xfffd, 0x94a0, 0xfffd, 0xfffd, 0xe2bc, 0xfffd, 0xfffd, 0xfffd, 0x94a2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90df, 0xe2b9, 0xfffd, 0xfffd, 0x94cd, 0xfffd, 0xe2bd, 0x95d1, 0xfffd, 0x927a, 0xfffd, 0xe2b8, 0xe2ba, 0xfffd, 0xfffd, 0xe2bb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2be, 0xfffd, 0xfffd, 0x8ec2, 0xfffd, 0xfffd, 0xfffd, 0x93c4, 0xe2c3, 0xe2c2, 0xfffd, 0xfffd, 0xe2bf, 0xfffd, 0xfffd, 0xfffd, 0x9855, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2c8, 0xfffd, 0xfffd, 0xe2cc, 0xe2c9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2c5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2c6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2cb, 0xfffd, 0xfffd, 0xfffd, 0xe2c0, 0x99d3, 0xe2c7, 0xe2c1, 0xfffd, 0xfffd, 0xe2ca, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2d0, 0xfffd, 0x8ac8, 0xfffd, 0xe2cd, 0xfffd, 0xfffd, 0xfffd, 0xe2ce, 0xfffd, 0xfffd, 0xe2cf, 0xe2d2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2d1, 0x94f4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2d3, 0x97fa, 0x95eb, 0xe2d8, 0xfffd, 0xfffd, 0xe2d5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2d4, 0x90d0, 0xfffd, 0xe2d7, 0xe2d9, 0xfffd, 0xfffd, 0xfffd, 0xe2d6, 0xfffd, 0xe2dd, 0xfffd, 0xe2da, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2db, 0xe2c4, 0xfffd, 0xfffd, 0xfffd, 0xe2dc, 0xe2de, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2df, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95c4, 0xfffd, 0xe2e0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96e0, 0xfffd, 0xfffd, 0x8bcc, 0x8c48, 0xe2e1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95b2, 0xfffd, 0x9088, 0xfffd, 0x96ae, 0xfffd, 0xfffd, 0xe2e2, 0xfffd, 0x97b1, 0xfffd, 0xfffd, 0x9494, 0xfffd, 0x9165, 0x9453, 0xfffd, 0xfffd, 0x8f6c, 0xfffd, 0xfffd, 0xfffd, 0x88be, 0xfffd, 0xe2e7, 0xe2e5, 0xfffd, 0xe2e3, 0x8a9f, 0xfffd, 0x8fcf, 0xe2e8, 0xfffd, 0xfffd, 0xe2e6, 0xfffd, 0xe2e4, 0xe2ec, 0xfffd, 0xfffd, 0xe2eb, 0xe2ea, 0xe2e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2ed, 0xfffd, 0xfffd, 0xfffd, 0xe2ee, 0x90b8, 0xfffd, 0xe2ef, 0xfffd, 0xe2f1, 0xfffd, 0xfffd, 0xe2f0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cd0, 0xfffd, 0xfffd, 0xfffd, 0x9157, 0xfffd, 0xfffd, 0xfffd, 0xe2f3, 0xfffd, 0xfffd, 0xfffd, 0x939c, 0xfffd, 0xe2f2, 0xfffd, 0xfffd, 0xfffd, 0xe2f4, 0xfffd, 0x95b3, 0x918c, 0x8d66, 0xfffd, 0xe2f5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97c6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2f7, 0xfffd, 0xfffd, 0xe2f8, 0xfffd, 0xe2f9, 0xfffd, 0xe2fa, 0xfffd, 0x8e85, 0xfffd, 0xe2fb, 0x8c6e, 0xfffd, 0xfffd, 0x8b8a, 0xfffd, 0x8b49, 0xfffd, 0xe340, 0xfffd, 0x96f1, 0x8d67, 0xe2fc, 0xfffd, 0xfffd, 0xfffd, 0xe343, 0x96e4, 0xfffd, 0x945b, 0xfffd, 0xfffd, 0x9552, 0xfffd, 0xfffd, 0xfffd, 0x8f83, 0xe342, 0xfffd, 0x8ed1, 0x8d68, 0x8e86, 0x8b89, 0x95b4, 0xe341, 0xfffd, 0xfffd, 0xfffd, 0x9166, 0x9661, 0x8df5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e87, 0x92db, 0xfffd, 0xe346, 0x97dd, 0x8dd7, 0xfffd, 0xe347, 0x9061, 0xfffd, 0xe349, 0xfffd, 0xfffd, 0xfffd, 0x8fd0, 0x8dae, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe348, 0xfffd, 0xfffd, 0x8f49, 0x8cbc, 0x9167, 0xe344, 0xe34a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe345, 0x8c6f, 0xfffd, 0xe34d, 0xe351, 0x8c8b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe34c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe355, 0xfffd, 0xfffd, 0x8d69, 0xfffd, 0xfffd, 0x978d, 0x88ba, 0xe352, 0xfffd, 0xfffd, 0x8b8b, 0xfffd, 0xe34f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe350, 0xfffd, 0xfffd, 0x939d, 0xe34e, 0xe34b, 0xfffd, 0x8a47, 0x90e2, 0xfffd, 0xfffd, 0x8ca6, 0xfffd, 0xfffd, 0xfffd, 0xe357, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe354, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe356, 0xfffd, 0xfffd, 0xfffd, 0xe353, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c70, 0x91b1, 0xe358, 0x918e, 0xfffd, 0xfffd, 0xe365, 0xfffd, 0xfffd, 0xe361, 0xe35b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe35f, 0x8ef8, 0x88db, 0xe35a, 0xe362, 0xe366, 0x8d6a, 0x96d4, 0xfffd, 0x92d4, 0xe35c, 0xfffd, 0xfffd, 0xe364, 0xfffd, 0xe359, 0x925d, 0xfffd, 0xe35e, 0x88bb, 0x96c8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe35d, 0xfffd, 0xfffd, 0x8bd9, 0x94ea, 0xfffd, 0xfffd, 0xfffd, 0x918d, 0xfffd, 0x97ce, 0x8f8f, 0xfffd, 0xfffd, 0xe38e, 0xfffd, 0xfffd, 0xe367, 0xfffd, 0x90fc, 0xfffd, 0xe363, 0xe368, 0xe36a, 0xfffd, 0x92f7, 0xe36d, 0xfffd, 0xfffd, 0xe369, 0xfffd, 0xfffd, 0xfffd, 0x95d2, 0x8ac9, 0xfffd, 0xfffd, 0x96c9, 0xfffd, 0xfffd, 0x88dc, 0xfffd, 0xfffd, 0xe36c, 0xfffd, 0x97fb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe36b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x898f, 0xfffd, 0xfffd, 0x93ea, 0xe36e, 0xfffd, 0xfffd, 0xfffd, 0xe375, 0xe36f, 0xe376, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe372, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x949b, 0xfffd, 0xfffd, 0x8ec8, 0xe374, 0xfffd, 0xe371, 0xe377, 0xe370, 0xfffd, 0xfffd, 0x8f63, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9644, 0xfffd, 0xfffd, 0x8f6b, 0xfffd, 0xfffd, 0xe373, 0xe380, 0xfffd, 0xfffd, 0xe37b, 0xfffd, 0xe37e, 0xfffd, 0xe37c, 0xe381, 0xe37a, 0xfffd, 0xe360, 0x90d1, 0xfffd, 0xfffd, 0x94c9, 0xfffd, 0xe37d, 0xfffd, 0xfffd, 0xe378, 0xfffd, 0xfffd, 0xfffd, 0x9140, 0x8c71, 0xfffd, 0x8f4a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9044, 0x9155, 0xe384, 0xfffd, 0xfffd, 0xe386, 0xe387, 0xfffd, 0xfffd, 0xe383, 0xe385, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe379, 0xe382, 0xfffd, 0xe38a, 0xe389, 0xfffd, 0xfffd, 0x969a, 0xfffd, 0xfffd, 0x8c4a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe388, 0xfffd, 0xe38c, 0xe38b, 0xe38f, 0xfffd, 0xe391, 0xfffd, 0xfffd, 0x8e5b, 0xe38d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe392, 0xe393, 0xfffd, 0xfffd, 0xe394, 0xfffd, 0xe39a, 0x935a, 0xe396, 0xfffd, 0xe395, 0xe397, 0xe398, 0xfffd, 0xe399, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe39b, 0xe39c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8aca, 0xfffd, 0xe39d, 0xfffd, 0xe39e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe39f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3a0, 0xe3a1, 0xe3a2, 0xfffd, 0xe3a3, 0xe3a4, 0xfffd, 0xfffd, 0xe3a6, 0xe3a5, 0xfffd, 0xfffd, 0xe3a7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3a8, 0xe3a9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3ac, 0xe3aa, 0xe3ab, 0x8ddf, 0x8c72, 0xfffd, 0xfffd, 0x9275, 0xfffd, 0x94b1, 0xfffd, 0x8f90, 0xfffd, 0xfffd, 0x946c, 0xfffd, 0x94eb, 0xe3ad, 0x9ceb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3ae, 0xe3b0, 0xfffd, 0x9785, 0xe3af, 0xe3b2, 0xe3b1, 0xfffd, 0x9772, 0xfffd, 0xe3b3, 0xfffd, 0x94fc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3b4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3b7, 0xfffd, 0xfffd, 0xe3b6, 0xe3b5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3b8, 0x8c51, 0xfffd, 0xfffd, 0xfffd, 0x9141, 0x8b60, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3bc, 0xe3b9, 0xfffd, 0xfffd, 0xe3ba, 0xfffd, 0xfffd, 0xfffd, 0xe3bd, 0xfffd, 0xe3be, 0xe3bb, 0xfffd, 0xfffd, 0xfffd, 0x8948, 0xfffd, 0xfffd, 0xfffd, 0x89a5, 0xfffd, 0xfffd, 0xfffd, 0xe3c0, 0xe3c1, 0xfffd, 0xfffd, 0xfffd, 0xe3c2, 0xfffd, 0x9782, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f4b, 0xfffd, 0xe3c4, 0xe3c3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9089, 0xe3c5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3c6, 0xfffd, 0xfffd, 0xe3c7, 0xfffd, 0x8ae3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8acb, 0xfffd, 0xfffd, 0xe3c8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3c9, 0xfffd, 0x967c, 0x9783, 0xfffd, 0xfffd, 0xfffd, 0x9773, 0x9856, 0xfffd, 0x8d6c, 0xe3cc, 0x8ed2, 0xe3cb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3cd, 0x8ea7, 0xfffd, 0xfffd, 0xfffd, 0x91cf, 0xfffd, 0xe3ce, 0xfffd, 0xfffd, 0x8d6b, 0xfffd, 0x96d5, 0xe3cf, 0xe3d0, 0xfffd, 0xfffd, 0xe3d1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3d2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3d3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ea8, 0xfffd, 0xfffd, 0x96eb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3d5, 0xfffd, 0x925e, 0xfffd, 0xe3d4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3d7, 0xfffd, 0xfffd, 0xfffd, 0xe3d6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3d8, 0xfffd, 0xfffd, 0xfffd, 0x90b9, 0xfffd, 0xe3d9, 0xfffd, 0xe3da, 0xfffd, 0xfffd, 0xfffd, 0x95b7, 0xe3db, 0xfffd, 0x918f, 0xe3dc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3dd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97fc, 0xe3e0, 0xfffd, 0xe3df, 0xe3de, 0x92ae, 0xfffd, 0xe3e1, 0x9045, 0xfffd, 0xe3e2, 0xfffd, 0xfffd, 0xfffd, 0xe3e3, 0x9857, 0xe3e4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3e5, 0xe3e7, 0xe3e6, 0x94a3, 0xfffd, 0x93f7, 0xfffd, 0x985d, 0x94a7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3e9, 0xfffd, 0xfffd, 0x8fd1, 0xfffd, 0x9549, 0xfffd, 0xe3ea, 0xe3e8, 0xfffd, 0x8acc, 0xfffd, 0xfffd, 0xfffd, 0x8cd2, 0x8e88, 0xfffd, 0xfffd, 0x94ec, 0xfffd, 0xfffd, 0xfffd, 0x8ca8, 0x9662, 0xfffd, 0xe3ed, 0xe3eb, 0xfffd, 0x8d6d, 0xfffd, 0x8d6e, 0x88e7, 0xfffd, 0x8de6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9478, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88dd, 0xe3f2, 0xfffd, 0x925f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9477, 0xfffd, 0x91d9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3f4, 0xfffd, 0xfffd, 0xe3f0, 0xe3f3, 0xe3ee, 0xfffd, 0xe3f1, 0x9645, 0xfffd, 0xfffd, 0x8cd3, 0xfffd, 0xfffd, 0x88fb, 0xe3ef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3f6, 0xfffd, 0xe3f7, 0xfffd, 0xfffd, 0x93b7, 0xfffd, 0xfffd, 0xfffd, 0x8bb9, 0xfffd, 0xfffd, 0xfffd, 0xe445, 0x945c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e89, 0xfffd, 0xfffd, 0x8bba, 0x90c6, 0x9865, 0x96ac, 0xe3f5, 0x90d2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b72, 0xe3f8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3fa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3f9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3fb, 0xfffd, 0x9245, 0xfffd, 0x945d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92af, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe442, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe441, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe3fc, 0xfffd, 0xfffd, 0x9074, 0xfffd, 0x9585, 0xe444, 0xfffd, 0xe443, 0x8d6f, 0x9872, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe454, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe448, 0xe449, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8eee, 0xfffd, 0xfffd, 0xe447, 0xfffd, 0x8d98, 0xe446, 0xfffd, 0xfffd, 0xe44a, 0xfffd, 0xfffd, 0xfffd, 0x92b0, 0x95a0, 0x9142, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91da, 0xe44e, 0xfffd, 0xe44f, 0xe44b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe44c, 0xfffd, 0xe44d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d70, 0xfffd, 0xfffd, 0xfffd, 0xe455, 0xfffd, 0xe451, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9586, 0xfffd, 0x968c, 0x9547, 0xfffd, 0xfffd, 0xe450, 0xfffd, 0xfffd, 0xe453, 0xe452, 0xfffd, 0xfffd, 0xfffd, 0x9663, 0xe456, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe457, 0xfffd, 0xfffd, 0x9156, 0xfffd, 0xe458, 0xfffd, 0xfffd, 0xe45a, 0xfffd, 0xe45e, 0xfffd, 0xfffd, 0xe45b, 0xe459, 0x945e, 0xe45c, 0xfffd, 0xe45d, 0xfffd, 0xfffd, 0xfffd, 0x89b0, 0xfffd, 0xe464, 0xe45f, 0xfffd, 0xfffd, 0xfffd, 0xe460, 0xfffd, 0xfffd, 0xfffd, 0xe461, 0xfffd, 0x919f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe463, 0xe462, 0xe465, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe466, 0xe467, 0xfffd, 0xfffd, 0x9062, 0xfffd, 0x89e7, 0xfffd, 0xe468, 0x97d5, 0xfffd, 0x8ea9, 0xfffd, 0xfffd, 0x8f4c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e8a, 0x9276, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe469, 0xe46a, 0x8950, 0xfffd, 0xe46b, 0xfffd, 0xfffd, 0xe46c, 0xe46d, 0xfffd, 0xfffd, 0xe46e, 0xfffd, 0xe46f, 0x8bbb, 0x9da8, 0xe470, 0xfffd, 0x90e3, 0xe471, 0x8ec9, 0xfffd, 0xe472, 0xfffd, 0x98ae, 0xfffd, 0xfffd, 0xfffd, 0xe473, 0x95dc, 0x8ada, 0xfffd, 0xfffd, 0x9143, 0x8f77, 0xfffd, 0x9591, 0x8f4d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe474, 0x8d71, 0xe475, 0x94ca, 0xfffd, 0xe484, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe477, 0xfffd, 0x91c7, 0x9495, 0x8cbd, 0xe476, 0x9144, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe478, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92f8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe47a, 0xe479, 0xe47c, 0xfffd, 0xfffd, 0xe47b, 0xfffd, 0xe47d, 0xfffd, 0xfffd, 0xe480, 0xfffd, 0xe47e, 0xfffd, 0x8acd, 0xfffd, 0xe481, 0xfffd, 0xe482, 0xe483, 0xfffd, 0xfffd, 0x8daf, 0x97c7, 0xfffd, 0xe485, 0x9046, 0xfffd, 0xfffd, 0xfffd, 0x8990, 0xe486, 0xe487, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe488, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88f0, 0xfffd, 0xe489, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe48a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9587, 0xfffd, 0xfffd, 0xfffd, 0x8ec5, 0xfffd, 0xe48c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a48, 0x88b0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe48b, 0xe48e, 0x946d, 0xfffd, 0x9063, 0xfffd, 0x89d4, 0xfffd, 0x9646, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c7c, 0x8bda, 0xfffd, 0xe48d, 0xfffd, 0x89e8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8aa1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8991, 0xe492, 0x97e8, 0x91db, 0xfffd, 0xfffd, 0x9563, 0xfffd, 0xe49e, 0xfffd, 0x89d5, 0xe49c, 0xfffd, 0xe49a, 0xe491, 0xfffd, 0xe48f, 0xfffd, 0xe490, 0xfffd, 0x8ee1, 0x8bea, 0x9297, 0xfffd, 0xfffd, 0xfffd, 0x93cf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8970, 0xfffd, 0xe494, 0xe493, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe499, 0xe495, 0xe498, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96ce, 0xe497, 0x89d6, 0x8a9d, 0xe49b, 0xfffd, 0xfffd, 0xe49d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c73, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4a1, 0xe4aa, 0xe4ab, 0xfffd, 0xfffd, 0xfffd, 0x88a9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4b2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88ef, 0xfffd, 0xfffd, 0xe4a9, 0xfffd, 0xfffd, 0xfffd, 0xe4a8, 0xfffd, 0xe4a3, 0xe4a2, 0xfffd, 0xe4a0, 0xe49f, 0x9283, 0xfffd, 0x91f9, 0xe4a5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4a4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4a7, 0xfffd, 0xfffd, 0xfffd, 0x9190, 0x8c74, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8960, 0xe4a6, 0xfffd, 0x8d72, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9191, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4b8, 0xfffd, 0xe4b9, 0xfffd, 0x89d7, 0xfffd, 0xfffd, 0xfffd, 0x89ac, 0xe4b6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4ac, 0xfffd, 0xe4b4, 0xfffd, 0xe4bb, 0xe4b5, 0xfffd, 0xfffd, 0xfffd, 0xe4b3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe496, 0xfffd, 0xfffd, 0xe4b1, 0xfffd, 0xfffd, 0xfffd, 0xe4ad, 0xfffd, 0xfffd, 0xfffd, 0x8ace, 0xe4af, 0xe4ba, 0xfffd, 0xe4b0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4bc, 0xfffd, 0xe4ae, 0x949c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9789, 0xfffd, 0xfffd, 0xfffd, 0xe4b7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4cd, 0xfffd, 0xfffd, 0xfffd, 0xe4c5, 0xfffd, 0xfffd, 0xfffd, 0x909b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b65, 0xfffd, 0x8bdb, 0xfffd, 0xe4c0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89d9, 0xfffd, 0xfffd, 0x8fd2, 0xfffd, 0xe4c3, 0xfffd, 0xfffd, 0xfffd, 0x8dd8, 0xfffd, 0xfffd, 0x9370, 0xe4c8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95ec, 0xfffd, 0xe4bf, 0xfffd, 0xfffd, 0xfffd, 0x89d8, 0x8cd4, 0x9548, 0xe4c9, 0xfffd, 0xe4bd, 0xfffd, 0xfffd, 0xe4c6, 0xfffd, 0xfffd, 0xfffd, 0xe4d0, 0xfffd, 0xe4c1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4c2, 0x93b8, 0xfffd, 0xfffd, 0xe4c7, 0xfffd, 0xfffd, 0xfffd, 0xe4c4, 0x9647, 0xe4ca, 0x88de, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4be, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4cc, 0xfffd, 0xe4cb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x948b, 0xe4d2, 0xfffd, 0xe4dd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a9e, 0xfffd, 0xfffd, 0xfffd, 0xe4e0, 0xfffd, 0xfffd, 0xe4ce, 0xfffd, 0xfffd, 0xfffd, 0xe4d3, 0x978e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4dc, 0xfffd, 0xfffd, 0x9774, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97a8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9298, 0xfffd, 0xfffd, 0xfffd, 0x8a8b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9592, 0xe4e2, 0x939f, 0xfffd, 0xfffd, 0x88af, 0xfffd, 0xfffd, 0xe4db, 0xfffd, 0xe4d7, 0x9192, 0xe4d1, 0xe4d9, 0xe4de, 0xfffd, 0x944b, 0xfffd, 0xfffd, 0xfffd, 0x88a8, 0xfffd, 0xe4d6, 0xfffd, 0xe4df, 0x9598, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4da, 0xfffd, 0xe4d5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fd3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f4e, 0xfffd, 0xfffd, 0xfffd, 0x8eaa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96d6, 0xfffd, 0xfffd, 0x9566, 0xfffd, 0xfffd, 0xe4e5, 0xfffd, 0xe4ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4d8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a97, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ff6, 0xe4e3, 0xfffd, 0xe4e8, 0x9193, 0xfffd, 0xfffd, 0xe4e4, 0xfffd, 0xe4eb, 0xfffd, 0xfffd, 0x927e, 0xfffd, 0xe4ec, 0xfffd, 0xfffd, 0x9775, 0xe4e1, 0x8a57, 0xfffd, 0xe4e7, 0xfffd, 0xfffd, 0xe4ea, 0x96aa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4ed, 0xfffd, 0xfffd, 0xe4e6, 0xe4e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9648, 0xfffd, 0x9840, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4f1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4f8, 0xfffd, 0xfffd, 0xe4f0, 0x8ec1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4cf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95cc, 0xfffd, 0x96a0, 0xe4f7, 0xe4f6, 0xfffd, 0xe4f2, 0xe4f3, 0xfffd, 0x8955, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4f5, 0xfffd, 0xe4ef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92d3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4f4, 0x88fc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91a0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95c1, 0xfffd, 0xfffd, 0xe4f9, 0xe540, 0xfffd, 0x94d7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4fc, 0x8fd4, 0x8ec7, 0xe542, 0xfffd, 0xfffd, 0x8bbc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe543, 0xfffd, 0x9599, 0xe4fb, 0xfffd, 0xe4d4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe4fa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x986e, 0x93a0, 0x9593, 0xfffd, 0xfffd, 0xe54a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe550, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe551, 0xfffd, 0xe544, 0xfffd, 0xfffd, 0xfffd, 0x9496, 0xfffd, 0xfffd, 0xe54e, 0xe546, 0xfffd, 0xe548, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe552, 0xe547, 0xfffd, 0xfffd, 0xe54b, 0xfffd, 0xfffd, 0x8992, 0xfffd, 0x93e3, 0xfffd, 0xe54c, 0xe54f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe545, 0xfffd, 0x9145, 0xfffd, 0xe549, 0x8e46, 0x9064, 0x8c4f, 0x96f2, 0xfffd, 0x96f7, 0x8f92, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe556, 0xe554, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x986d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe553, 0xfffd, 0xfffd, 0xfffd, 0x9795, 0xfffd, 0xe555, 0xe557, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe558, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe55b, 0xe559, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93a1, 0xe55a, 0xfffd, 0xfffd, 0xfffd, 0x94cb, 0xe54d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f93, 0xfffd, 0xe55c, 0xe561, 0x9194, 0xfffd, 0xfffd, 0xe560, 0xfffd, 0xfffd, 0xfffd, 0xe541, 0xfffd, 0xfffd, 0xfffd, 0xe562, 0x9168, 0xfffd, 0xfffd, 0xe55d, 0xe55f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe55e, 0xfffd, 0xfffd, 0x9f50, 0x9f41, 0xfffd, 0xfffd, 0xe564, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe563, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9796, 0xfffd, 0xe1ba, 0xe565, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe566, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe567, 0x8cd5, 0xfffd, 0x8b73, 0xfffd, 0xfffd, 0xfffd, 0xe569, 0x997c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b95, 0xfffd, 0x97b8, 0xfffd, 0x8bf1, 0xe56a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe56b, 0xfffd, 0xfffd, 0xfffd, 0x928e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe56c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93f8, 0xfffd, 0x88b8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89e1, 0xe571, 0xe572, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe56d, 0xfffd, 0x8e5c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe56e, 0x9461, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe56f, 0xe570, 0xe57a, 0xfffd, 0xfffd, 0xfffd, 0xe574, 0xe577, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe573, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe575, 0xfffd, 0xe576, 0x8ed6, 0xfffd, 0xe578, 0xfffd, 0x9260, 0xfffd, 0x8c75, 0x8a61, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe57b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a5e, 0xfffd, 0xe581, 0xfffd, 0xfffd, 0xe57c, 0xe580, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94b8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe57d, 0xfffd, 0xfffd, 0xe57e, 0x9567, 0x94d8, 0xe582, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91fb, 0xe58c, 0xfffd, 0xe588, 0xfffd, 0xfffd, 0x89e9, 0xfffd, 0xe586, 0xfffd, 0x9649, 0xe587, 0xfffd, 0xfffd, 0xe584, 0xfffd, 0xe585, 0xe58a, 0xe58d, 0xfffd, 0xfffd, 0xe58b, 0xfffd, 0xfffd, 0xfffd, 0xe589, 0xe583, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9277, 0xfffd, 0xe594, 0xfffd, 0x96a8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe592, 0xfffd, 0xfffd, 0xfffd, 0xe593, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe58e, 0xfffd, 0xfffd, 0xe590, 0xfffd, 0xfffd, 0xfffd, 0xe591, 0xfffd, 0xfffd, 0xfffd, 0xe58f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90e4, 0xfffd, 0x9858, 0xe598, 0xfffd, 0xe599, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe59f, 0xfffd, 0x9049, 0xfffd, 0xe59b, 0xfffd, 0xe59e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe596, 0xe595, 0xfffd, 0xfffd, 0xe5a0, 0xfffd, 0xfffd, 0x89da, 0xfffd, 0xe59c, 0xfffd, 0xe5a1, 0xfffd, 0xfffd, 0xfffd, 0xe59d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe59a, 0xfffd, 0x92b1, 0xfffd, 0xe597, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9488, 0xfffd, 0xfffd, 0xe5a5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x975a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5a4, 0xfffd, 0xfffd, 0xe5a3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5ac, 0xfffd, 0xfffd, 0xfffd, 0xe5a6, 0xfffd, 0xfffd, 0xfffd, 0xe5ae, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9786, 0xe5b1, 0xfffd, 0xe5a8, 0xfffd, 0xfffd, 0xe5a9, 0xfffd, 0xfffd, 0xfffd, 0xe5ad, 0xfffd, 0xe5b0, 0xe5af, 0xfffd, 0xfffd, 0xfffd, 0xe5a7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5aa, 0xfffd, 0xe5bb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5b4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5b2, 0xfffd, 0xfffd, 0xe5b3, 0xfffd, 0xfffd, 0xfffd, 0xe5b8, 0xe5b9, 0xfffd, 0x8a49, 0xfffd, 0x8b61, 0xfffd, 0xfffd, 0xe5b7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5a2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5b6, 0xe5ba, 0xe5b5, 0xfffd, 0xe5bc, 0xfffd, 0xfffd, 0xfffd, 0xe5be, 0xe5bd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5c0, 0xe5bf, 0xe579, 0xfffd, 0xfffd, 0xfffd, 0xe5c4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5c1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5c2, 0xfffd, 0xfffd, 0xe5c3, 0xfffd, 0xe5c5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c8c, 0xfffd, 0xe5c7, 0xfffd, 0xe5c6, 0xfffd, 0x8f4f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d73, 0x9fa5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5c8, 0x8f70, 0xfffd, 0xfffd, 0xfffd, 0x8a58, 0xfffd, 0xe5c9, 0xfffd, 0x8971, 0xfffd, 0x8fd5, 0xe5ca, 0xfffd, 0xfffd, 0x8d74, 0xe5cb, 0x88df, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x955c, 0xfffd, 0xfffd, 0xe5cc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x908a, 0xfffd, 0xe5d3, 0xfffd, 0xfffd, 0xe5d0, 0xfffd, 0x928f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5d1, 0xe5ce, 0x8bdc, 0xfffd, 0xe5cd, 0xe5d4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c55, 0xfffd, 0xfffd, 0x91dc, 0xfffd, 0xe5da, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5d6, 0xfffd, 0xfffd, 0xfffd, 0x91b3, 0xe5d5, 0xfffd, 0xe5d8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5cf, 0xfffd, 0xfffd, 0xfffd, 0xe5d9, 0xfffd, 0xe5db, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94ed, 0xfffd, 0xfffd, 0xe5d7, 0xfffd, 0xe5dc, 0xe5de, 0xfffd, 0xfffd, 0x8cd1, 0xe5d2, 0xfffd, 0x88bf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5dd, 0xfffd, 0x8dd9, 0x97f4, 0xe5df, 0xe5e0, 0x9195, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97a0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5e1, 0x9754, 0xfffd, 0xfffd, 0xe5e2, 0xe5e3, 0xfffd, 0xfffd, 0x95e2, 0xe5e4, 0xfffd, 0x8dbe, 0xfffd, 0x97a1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5ea, 0x8fd6, 0xe5e8, 0xfffd, 0xfffd, 0xfffd, 0x9787, 0xe5e5, 0xfffd, 0xfffd, 0xe5e7, 0x90bb, 0x909e, 0xfffd, 0xfffd, 0xfffd, 0xe5e6, 0xfffd, 0xe5eb, 0xfffd, 0xfffd, 0x95a1, 0xfffd, 0xfffd, 0xe5ed, 0xfffd, 0xe5ec, 0xfffd, 0xfffd, 0xfffd, 0x8a8c, 0xfffd, 0x964a, 0xe5ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5fa, 0xe5f0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5f1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5f2, 0xe5f3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5f7, 0xfffd, 0xe5f8, 0xfffd, 0xfffd, 0xe5f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5f4, 0xfffd, 0xe5ef, 0xe5f5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5f9, 0xe8b5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89a6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe5fc, 0x8bdd, 0xe5fb, 0xfffd, 0xfffd, 0xfffd, 0xe641, 0xfffd, 0xe640, 0xfffd, 0xfffd, 0xfffd, 0xe643, 0xfffd, 0xfffd, 0xe642, 0xfffd, 0xe644, 0xfffd, 0xfffd, 0x8f50, 0xfffd, 0xe645, 0xfffd, 0xfffd, 0xe646, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe647, 0x90bc, 0xfffd, 0x9776, 0xfffd, 0xe648, 0xfffd, 0xfffd, 0x95a2, 0x9465, 0xe649, 0xfffd, 0xe64a, 0x8ca9, 0xfffd, 0xfffd, 0xfffd, 0x8b4b, 0xfffd, 0xfffd, 0xfffd, 0xe64b, 0xfffd, 0xfffd, 0x8e8b, 0x9460, 0xe64c, 0xfffd, 0x8a6f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe64d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe64f, 0x9797, 0xfffd, 0xe64e, 0x9065, 0xfffd, 0xe650, 0xfffd, 0xfffd, 0xe651, 0xfffd, 0xfffd, 0xe652, 0x8acf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe653, 0xfffd, 0xfffd, 0xe654, 0xfffd, 0xe655, 0xe656, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a70, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe657, 0xfffd, 0xe658, 0xe659, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89f0, 0xfffd, 0xfffd, 0x9047, 0xe65a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe65b, 0xfffd, 0xfffd, 0xfffd, 0xe65c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cbe, 0xfffd, 0x92f9, 0xe65d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c76, 0xfffd, 0x9075, 0xfffd, 0xe660, 0xfffd, 0x93a2, 0xfffd, 0xe65f, 0xfffd, 0xfffd, 0x8c50, 0xfffd, 0xfffd, 0xe65e, 0x91f5, 0x8b4c, 0xfffd, 0xfffd, 0xe661, 0xfffd, 0xe662, 0xfffd, 0x8fd7, 0xfffd, 0xfffd, 0xfffd, 0x8c8d, 0xfffd, 0xe663, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x964b, 0xfffd, 0xfffd, 0x90dd, 0xfffd, 0xfffd, 0xfffd, 0x8b96, 0xfffd, 0x96f3, 0x9169, 0xfffd, 0xe664, 0xfffd, 0xfffd, 0xfffd, 0x9066, 0x9290, 0x8fd8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe665, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe668, 0xfffd, 0xe669, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8dbc, 0x91c0, 0xe667, 0xfffd, 0x8fd9, 0x955d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe666, 0xfffd, 0xfffd, 0x8e8c, 0xfffd, 0x8972, 0xfffd, 0xe66d, 0x8c77, 0xfffd, 0xfffd, 0x8e8e, 0xfffd, 0xfffd, 0x8e8d, 0xfffd, 0x986c, 0xe66c, 0xe66b, 0x9146, 0xfffd, 0x8b6c, 0x9862, 0x8a59, 0x8fda, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe66a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe66f, 0xfffd, 0xe670, 0xe66e, 0xfffd, 0x8cd6, 0xfffd, 0x975f, 0xfffd, 0xfffd, 0x8e8f, 0x9446, 0xfffd, 0xfffd, 0xfffd, 0xe673, 0xfffd, 0x90be, 0xfffd, 0x9261, 0xfffd, 0xfffd, 0x9755, 0xfffd, 0xe676, 0xfffd, 0xfffd, 0xfffd, 0x8cea, 0xfffd, 0x90bd, 0xe672, 0xfffd, 0xe677, 0x8ceb, 0xe674, 0xe675, 0xfffd, 0xe671, 0xfffd, 0xfffd, 0xfffd, 0x90e0, 0x93c7, 0xfffd, 0xfffd, 0x924e, 0xfffd, 0x89db, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94ee, 0xfffd, 0xfffd, 0x8b62, 0xfffd, 0xfffd, 0x92b2, 0xfffd, 0xfffd, 0xe67a, 0xfffd, 0xe678, 0xfffd, 0xfffd, 0x926b, 0xfffd, 0xfffd, 0xfffd, 0x90bf, 0x8ad0, 0xe679, 0xfffd, 0x907a, 0xfffd, 0xfffd, 0x97c8, 0xfffd, 0xfffd, 0xfffd, 0x985f, 0xfffd, 0xfffd, 0xfffd, 0xe67b, 0xe687, 0x92b3, 0xfffd, 0xe686, 0xfffd, 0xe683, 0xe68b, 0xe684, 0xfffd, 0xe680, 0xfffd, 0x92fa, 0xe67e, 0xfffd, 0xfffd, 0xfffd, 0xe67c, 0xfffd, 0x9740, 0x8e90, 0xfffd, 0xfffd, 0xe681, 0xfffd, 0xe67d, 0xfffd, 0xfffd, 0xfffd, 0xe685, 0x8f94, 0xfffd, 0x8cbf, 0xfffd, 0xfffd, 0xfffd, 0x91f8, 0xfffd, 0x9664, 0x8979, 0x88e0, 0xfffd, 0x93a3, 0xfffd, 0xfffd, 0xe689, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe688, 0xfffd, 0x93e4, 0xfffd, 0xe68d, 0xfffd, 0xfffd, 0xfffd, 0xe682, 0xfffd, 0xe68c, 0xe68e, 0xfffd, 0x8caa, 0xe68a, 0x8d75, 0xfffd, 0x8ed3, 0xfffd, 0xfffd, 0xe68f, 0x9777, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe692, 0xfffd, 0xe695, 0xfffd, 0xfffd, 0xe693, 0x9554, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe690, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8bde, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe694, 0xfffd, 0xfffd, 0xe696, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe69a, 0xfffd, 0xfffd, 0xe697, 0xfffd, 0xe699, 0xe698, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe69b, 0xfffd, 0x8eaf, 0xfffd, 0xe69d, 0xe69c, 0x9588, 0xfffd, 0xfffd, 0xe69f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c78, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe69e, 0xe6a0, 0xfffd, 0xfffd, 0xe6a1, 0x8b63, 0xe3bf, 0x8ff7, 0xfffd, 0xe6a2, 0xfffd, 0xfffd, 0x8cec, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6a3, 0xfffd, 0xfffd, 0xe6a4, 0xfffd, 0xfffd, 0x8e5d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9dcc, 0xfffd, 0xe6a5, 0xfffd, 0xe6a6, 0xfffd, 0x8f51, 0xfffd, 0xe6a7, 0xe6a8, 0xfffd, 0xfffd, 0xe6a9, 0xfffd, 0xfffd, 0xe6aa, 0xe6ab, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x924a, 0xfffd, 0xfffd, 0xe6ac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6ae, 0xfffd, 0xe6ad, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93a4, 0xfffd, 0xe6af, 0xfffd, 0x964c, 0xfffd, 0xe6b0, 0xfffd, 0xe6b1, 0xfffd, 0xe6b2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6b3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93d8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fdb, 0xe6b4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d8b, 0x98ac, 0xe6b5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6b6, 0x955e, 0xe6b7, 0xfffd, 0xe6bf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6b8, 0xfffd, 0xfffd, 0xe6ba, 0xfffd, 0xfffd, 0xfffd, 0xe6b9, 0xe6bb, 0xfffd, 0x9665, 0xe6bc, 0xe6bd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6be, 0xfffd, 0xfffd, 0xfffd, 0xe6c0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a4c, 0x92e5, 0xfffd, 0x9589, 0x8de0, 0x8d76, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x956e, 0x89dd, 0x94cc, 0xe6c3, 0x8ad1, 0x90d3, 0xe6c2, 0xe6c7, 0x9299, 0x96e1, 0xfffd, 0xe6c5, 0xe6c6, 0x8b4d, 0xfffd, 0xe6c8, 0x9483, 0x91dd, 0xfffd, 0xfffd, 0x94ef, 0x935c, 0xe6c4, 0xfffd, 0x9666, 0x89ea, 0xe6ca, 0x9847, 0x92c0, 0x9864, 0xfffd, 0xfffd, 0x8e91, 0xe6c9, 0xfffd, 0x91af, 0xfffd, 0xfffd, 0xe6da, 0x9147, 0xfffd, 0xfffd, 0x93f6, 0xfffd, 0x956f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6cd, 0x8e5e, 0x8e92, 0xfffd, 0x8fdc, 0xfffd, 0x9485, 0xfffd, 0x8cab, 0xe6cc, 0xe6cb, 0xfffd, 0x958a, 0xfffd, 0xfffd, 0xfffd, 0x8ebf, 0xfffd, 0xfffd, 0x9371, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6cf, 0xe6d0, 0x8d77, 0xe6ce, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6d1, 0xe6d2, 0xfffd, 0xe6d4, 0x91a1, 0xfffd, 0xe6d3, 0x8ae4, 0xfffd, 0xe6d6, 0xfffd, 0xe6d5, 0xe6d7, 0xfffd, 0xfffd, 0xe6d9, 0xe6db, 0xfffd, 0xe6dc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90d4, 0xfffd, 0x8ecd, 0xe6dd, 0xfffd, 0xfffd, 0xfffd, 0x8a71, 0xfffd, 0xe6de, 0xfffd, 0xfffd, 0x9196, 0xe6df, 0xfffd, 0xe6e0, 0x958b, 0xfffd, 0xfffd, 0x8b4e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6e1, 0xfffd, 0xfffd, 0xfffd, 0x92b4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x897a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6e2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8eef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9096, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91ab, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6e5, 0xfffd, 0xfffd, 0xfffd, 0xe6e4, 0xfffd, 0xfffd, 0xfffd, 0xe6e3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6eb, 0xe6e9, 0xfffd, 0xfffd, 0xe6e6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6e8, 0xfffd, 0xfffd, 0xfffd, 0xe6e7, 0xe6ea, 0xfffd, 0x8b97, 0xfffd, 0xe6ee, 0xfffd, 0x90d5, 0xfffd, 0xe6ef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cd7, 0xfffd, 0xe6ec, 0xe6ed, 0xfffd, 0xfffd, 0xfffd, 0x9848, 0xfffd, 0xfffd, 0xfffd, 0x92b5, 0xfffd, 0x9148, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6f0, 0xfffd, 0xfffd, 0xe6f3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6f1, 0xe6f2, 0x9778, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93a5, 0xe6f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6f4, 0xe6f5, 0xe6f7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe748, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6fa, 0xfffd, 0xfffd, 0xfffd, 0xe6fb, 0xe6f9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe6f8, 0xfffd, 0x92fb, 0xfffd, 0xfffd, 0xe740, 0xe744, 0xe741, 0xe6fc, 0xfffd, 0xe742, 0xfffd, 0xfffd, 0xfffd, 0xe743, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe74a, 0xfffd, 0xfffd, 0xfffd, 0xe745, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90d6, 0xe747, 0xfffd, 0xfffd, 0xe749, 0xe746, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe74c, 0xfffd, 0x8f52, 0xfffd, 0xe74b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe74d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe74e, 0xfffd, 0xfffd, 0xe751, 0xe750, 0xfffd, 0xe74f, 0xfffd, 0xfffd, 0xe753, 0xe752, 0xfffd, 0x96f4, 0xfffd, 0xfffd, 0xfffd, 0xe755, 0xfffd, 0xe754, 0xe756, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe757, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe759, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe758, 0x9067, 0xe75a, 0xfffd, 0xfffd, 0x8beb, 0xe75b, 0xe75d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe75e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe75f, 0xe75c, 0xfffd, 0xe760, 0xfffd, 0x8ed4, 0xe761, 0x8b4f, 0x8c52, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cac, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe762, 0xfffd, 0xfffd, 0xfffd, 0x93ee, 0xfffd, 0xfffd, 0x935d, 0xe763, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe766, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8eb2, 0xfffd, 0xfffd, 0xe765, 0xe764, 0x8c79, 0xe767, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a72, 0xfffd, 0xe769, 0xfffd, 0xfffd, 0xfffd, 0x8dda, 0xe768, 0xfffd, 0xe771, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe76b, 0xe76d, 0x95e3, 0xe76a, 0xfffd, 0xfffd, 0xfffd, 0xe76c, 0xfffd, 0xe770, 0xe76e, 0x8b50, 0xfffd, 0xe76f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe772, 0xfffd, 0xfffd, 0x9479, 0x97d6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f53, 0xfffd, 0xfffd, 0xfffd, 0xe773, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9741, 0xe775, 0xfffd, 0xe774, 0xfffd, 0xfffd, 0xe778, 0x9760, 0xfffd, 0xfffd, 0xe777, 0xfffd, 0x8a8d, 0xe776, 0xe77b, 0xfffd, 0xfffd, 0xe77a, 0xfffd, 0xfffd, 0xe779, 0x9351, 0xe77c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe77d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe77e, 0xfffd, 0xfffd, 0x8d8c, 0xfffd, 0x8c44, 0xe780, 0xe781, 0xe782, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9068, 0xe783, 0xfffd, 0x8eab, 0xe784, 0xfffd, 0xfffd, 0xfffd, 0xe785, 0xfffd, 0xfffd, 0xfffd, 0x999f, 0x999e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe786, 0xe390, 0xe787, 0x9243, 0x904a, 0x945f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe788, 0xfffd, 0xfffd, 0x95d3, 0x92d2, 0x8d9e, 0xfffd, 0xfffd, 0x9248, 0xfffd, 0xfffd, 0x8949, 0xfffd, 0x9698, 0x9076, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c7d, 0xfffd, 0xfffd, 0x8bdf, 0xfffd, 0xfffd, 0x95d4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe789, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe78b, 0xfffd, 0xfffd, 0xe78a, 0x89de, 0xfffd, 0xfffd, 0x93f4, 0xe78c, 0x9497, 0xfffd, 0x9352, 0xfffd, 0xe78d, 0x8f71, 0xfffd, 0xfffd, 0xfffd, 0xe78f, 0xfffd, 0xfffd, 0x96c0, 0xe79e, 0xe791, 0xe792, 0xfffd, 0xfffd, 0x92c7, 0xfffd, 0xfffd, 0x91de, 0x9197, 0xfffd, 0x93a6, 0xfffd, 0xe790, 0x8b74, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe799, 0xfffd, 0xe796, 0xe7a3, 0x93a7, 0x9280, 0xe793, 0xfffd, 0x92fc, 0x9372, 0xe794, 0xe798, 0x9080, 0xfffd, 0x9487, 0x92ca, 0xfffd, 0xfffd, 0x90c0, 0xe797, 0x91ac, 0x91a2, 0xe795, 0x88a7, 0x9841, 0xfffd, 0xfffd, 0xfffd, 0xe79a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91df, 0xfffd, 0xfffd, 0x8f54, 0x9069, 0xfffd, 0xfffd, 0xe79c, 0xe79b, 0xfffd, 0x88ed, 0xe79d, 0xfffd, 0xfffd, 0x954e, 0xfffd, 0xe7a5, 0xfffd, 0xfffd, 0x93d9, 0x908b, 0xfffd, 0xfffd, 0x9278, 0xfffd, 0x8bf6, 0xfffd, 0xe7a4, 0x9756, 0x895e, 0xfffd, 0x95d5, 0x89df, 0xe79f, 0xe7a0, 0xe7a1, 0xe7a2, 0x93b9, 0x9242, 0x88e1, 0xe7a6, 0xfffd, 0xe7a7, 0xeaa1, 0xfffd, 0xfffd, 0x91bb, 0xfffd, 0xe7a8, 0xfffd, 0x8993, 0x916b, 0xfffd, 0x8cad, 0xfffd, 0x9779, 0xfffd, 0xfffd, 0xe7a9, 0x934b, 0xfffd, 0xfffd, 0xfffd, 0x9198, 0x8ed5, 0xe7aa, 0xfffd, 0xfffd, 0xe7ad, 0xfffd, 0xfffd, 0x8f85, 0xe7ab, 0x914a, 0x9149, 0xfffd, 0x88e2, 0xfffd, 0x97c9, 0xe7af, 0xfffd, 0x94f0, 0xe7b1, 0xe7b0, 0xe7ae, 0xe284, 0x8ad2, 0xfffd, 0xfffd, 0xe78e, 0xfffd, 0xe7b3, 0xe7b2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7b4, 0xfffd, 0x9757, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93df, 0xfffd, 0xfffd, 0x964d, 0xfffd, 0xe7b5, 0xfffd, 0x8ed7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7b6, 0xfffd, 0xe7b7, 0xfffd, 0xfffd, 0xfffd, 0xe7b8, 0xfffd, 0xfffd, 0x9340, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88e8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d78, 0xfffd, 0xfffd, 0xfffd, 0x9859, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7bc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c53, 0xe7b9, 0xfffd, 0xe7ba, 0xfffd, 0xfffd, 0xfffd, 0x9594, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a73, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9758, 0xfffd, 0x8bbd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9373, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7bd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7be, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7bf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9341, 0xfffd, 0xfffd, 0xe7c1, 0xfffd, 0xe7c0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93d1, 0xe7c2, 0x8f55, 0x8ede, 0x947a, 0x9291, 0xfffd, 0xfffd, 0xfffd, 0x8ef0, 0xfffd, 0x908c, 0xfffd, 0xe7c3, 0xfffd, 0xe7c4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x907c, 0xe7c5, 0xfffd, 0xe7c6, 0xfffd, 0xfffd, 0xfffd, 0xe7c7, 0x978f, 0xfffd, 0x8f56, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7c9, 0xe7c8, 0xfffd, 0x8d79, 0xfffd, 0x8d93, 0x8e5f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7cc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f86, 0xfffd, 0xe7cb, 0xfffd, 0xe7ca, 0xfffd, 0x91e7, 0xfffd, 0xfffd, 0x8ced, 0xfffd, 0x90c1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94ae, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f58, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7cd, 0xfffd, 0x8fdd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7d0, 0xe7ce, 0xfffd, 0xfffd, 0xfffd, 0xe7cf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7d2, 0xe7d1, 0xfffd, 0xfffd, 0x8ff8, 0xfffd, 0xe7d3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7d4, 0xe7d5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94ce, 0x8dd1, 0x8edf, 0xe7d6, 0xfffd, 0xe7d7, 0x97a2, 0x8f64, 0x96ec, 0x97ca, 0xe7d8, 0x8be0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7d9, 0xfffd, 0x9342, 0xfffd, 0xfffd, 0xe7dc, 0x8a98, 0x906a, 0xfffd, 0xe7da, 0xfffd, 0xe7db, 0xfffd, 0x92de, 0xfffd, 0xfffd, 0x9674, 0x8bfa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7de, 0xe7df, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7dd, 0xfffd, 0xfffd, 0xe7e1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93dd, 0x8a62, 0xfffd, 0xfffd, 0xe7e5, 0xfffd, 0xfffd, 0xe7e2, 0xe7e4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7e0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe86e, 0xfffd, 0xfffd, 0xe7e3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97e9, 0xfffd, 0xfffd, 0x8cd8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7ed, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9353, 0xe7e8, 0xfffd, 0xfffd, 0xe7eb, 0xe7e9, 0xfffd, 0xe7ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7ef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7e7, 0xfffd, 0xfffd, 0xe7f4, 0x8994, 0xfffd, 0xfffd, 0xe7e6, 0xfffd, 0xfffd, 0xfffd, 0x94ab, 0xfffd, 0xe7ea, 0xfffd, 0x8fde, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d7a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9667, 0xfffd, 0x8be2, 0xfffd, 0xfffd, 0x8f65, 0xfffd, 0x93ba, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x914c, 0xfffd, 0xe7f2, 0xfffd, 0xe7ec, 0xe7f1, 0xfffd, 0x96c1, 0xfffd, 0x92b6, 0xe7f3, 0xe7f0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x914b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7f7, 0xfffd, 0xe7f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7f5, 0xfffd, 0xfffd, 0x964e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8f9b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7f8, 0x95dd, 0xfffd, 0xfffd, 0x8973, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9565, 0x9292, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b98, 0xfffd, 0xe7fa, 0xfffd, 0x8d7c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e4b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7f9, 0x908d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x908e, 0xe840, 0xe842, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ff9, 0xfffd, 0xe841, 0xe843, 0xfffd, 0xfffd, 0x8bd1, 0xfffd, 0x9564, 0xfffd, 0xfffd, 0x8ee0, 0x9842, 0xfffd, 0xe7fc, 0x8df6, 0xfffd, 0xfffd, 0x985e, 0xfffd, 0xfffd, 0xe845, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe844, 0xe846, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe7fb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93e7, 0xfffd, 0x9374, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92d5, 0xfffd, 0xe84b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9262, 0xe847, 0xfffd, 0xfffd, 0xfffd, 0xe848, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c4c, 0xfffd, 0xe84a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cae, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe849, 0xfffd, 0x8fdf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a99, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe84f, 0xfffd, 0x8dbd, 0x9199, 0xfffd, 0xfffd, 0x92c8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a5a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe84d, 0xe84e, 0x92c1, 0xfffd, 0xe84c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe850, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe856, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe859, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe858, 0x934c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe851, 0xe852, 0xe855, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe857, 0xfffd, 0xfffd, 0xfffd, 0x8bbe, 0xfffd, 0xfffd, 0xe85a, 0xe854, 0xfffd, 0xfffd, 0xe853, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe85e, 0xfffd, 0xfffd, 0xfffd, 0xe85f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe860, 0xfffd, 0xfffd, 0xe85d, 0xe85c, 0xfffd, 0xfffd, 0xfffd, 0x8fe0, 0x93a8, 0xe85b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe864, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe862, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe863, 0xe861, 0xfffd, 0x91f6, 0xfffd, 0xe865, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe866, 0xfffd, 0xfffd, 0xe868, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ad3, 0xe867, 0x96f8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe873, 0xe869, 0xfffd, 0xfffd, 0xe86c, 0xfffd, 0xe86a, 0xfffd, 0xe86b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe86d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe86f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe870, 0xfffd, 0xe871, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe874, 0xe872, 0xe875, 0xe877, 0xfffd, 0xe876, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92b7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x96e5, 0xfffd, 0xe878, 0x914d, 0xfffd, 0xfffd, 0xfffd, 0xe879, 0xfffd, 0x95c2, 0xe87a, 0x8a4a, 0xfffd, 0xfffd, 0xfffd, 0x895b, 0xfffd, 0x8ad5, 0xfffd, 0x8ad4, 0xe87b, 0xfffd, 0xe87c, 0xfffd, 0xe87d, 0xe87e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe880, 0xfffd, 0x8ad6, 0x8a74, 0x8d7d, 0x94b4, 0xfffd, 0xe882, 0xe881, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe883, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x897b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe886, 0xfffd, 0xe885, 0xe884, 0xfffd, 0xe887, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe88a, 0xfffd, 0xfffd, 0xfffd, 0x88c5, 0xfffd, 0xfffd, 0xe888, 0xfffd, 0xe88c, 0xe88b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe88e, 0xe88d, 0xe88f, 0xfffd, 0x93ac, 0xfffd, 0xfffd, 0xfffd, 0xe890, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe891, 0xe893, 0xfffd, 0xfffd, 0xe892, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x958c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe894, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe895, 0xfffd, 0x8de3, 0xfffd, 0xfffd, 0xfffd, 0xe896, 0xe897, 0xfffd, 0xfffd, 0x9668, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x916a, 0xfffd, 0xfffd, 0xfffd, 0x88a2, 0x91c9, 0xfffd, 0xe898, 0xfffd, 0x958d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe89b, 0xe899, 0x8d7e, 0xfffd, 0xe89a, 0x8cc0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95c3, 0xe89d, 0xe89f, 0xe89e, 0xe8a0, 0xfffd, 0xfffd, 0x8940, 0x9077, 0x8f9c, 0x8ad7, 0xe8a1, 0xfffd, 0xfffd, 0xfffd, 0x9486, 0xfffd, 0xe8a3, 0xfffd, 0xfffd, 0xfffd, 0x8941, 0xfffd, 0xe8a2, 0x92c2, 0xfffd, 0x97cb, 0x93a9, 0xe89c, 0x97a4, 0xfffd, 0x8caf, 0xfffd, 0xfffd, 0x977a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8bf7, 0x97b2, 0xfffd, 0x8c47, 0xfffd, 0x91e0, 0xe440, 0xfffd, 0xe8a4, 0x8a4b, 0x908f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a75, 0xe8a6, 0xfffd, 0xe8a7, 0xe8a5, 0x8c84, 0xfffd, 0x8ddb, 0x8fe1, 0xfffd, 0xfffd, 0xfffd, 0x8942, 0xfffd, 0xfffd, 0x97d7, 0xfffd, 0xfffd, 0xfffd, 0xe8a9, 0xe7ac, 0xfffd, 0xe8a8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8ac, 0xe8aa, 0xe8ab, 0xfffd, 0xe8ad, 0xfffd, 0xe8ae, 0x97ea, 0xe8af, 0xe8b0, 0xfffd, 0x90c7, 0x94b9, 0xfffd, 0xfffd, 0xfffd, 0x909d, 0x8ae5, 0xfffd, 0xfffd, 0x9759, 0x89eb, 0x8f57, 0x8cd9, 0xfffd, 0xe8b3, 0xfffd, 0xe8b2, 0x8e93, 0xe8b4, 0xe8b1, 0xfffd, 0xfffd, 0x8e47, 0xfffd, 0xfffd, 0xfffd, 0xe8b8, 0xe5ab, 0xfffd, 0xfffd, 0x99d4, 0xfffd, 0x9097, 0xe8b6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97a3, 0x93ef, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x894a, 0xfffd, 0x90e1, 0x8eb4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x95b5, 0xfffd, 0x895f, 0xfffd, 0xfffd, 0xfffd, 0x97eb, 0x978b, 0xfffd, 0xe8b9, 0xfffd, 0x9364, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ef9, 0xfffd, 0xfffd, 0xfffd, 0xe8ba, 0xfffd, 0xe8bb, 0x906b, 0xe8bc, 0xfffd, 0x97ec, 0xfffd, 0xfffd, 0xe8b7, 0xe8be, 0xe8c0, 0xfffd, 0xe8bf, 0xfffd, 0xe8bd, 0xfffd, 0xfffd, 0xe8c1, 0xfffd, 0xfffd, 0xe8c2, 0xfffd, 0xfffd, 0x919a, 0xfffd, 0x89e0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8c3, 0xfffd, 0xfffd, 0x96b6, 0xfffd, 0xfffd, 0xe8c4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8c5, 0xfffd, 0x9849, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9e50, 0xe8c6, 0xfffd, 0xfffd, 0xfffd, 0xe8c7, 0xe8c8, 0xfffd, 0xfffd, 0xfffd, 0xe8cc, 0xfffd, 0xe8c9, 0xfffd, 0xe8ca, 0xfffd, 0xe8cb, 0xe8cd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x90c2, 0xfffd, 0xfffd, 0xfffd, 0x96f5, 0xfffd, 0xfffd, 0x90c3, 0xfffd, 0xfffd, 0xe8ce, 0xfffd, 0x94f1, 0xfffd, 0xe8cf, 0xea72, 0x96ca, 0xfffd, 0xe8d0, 0xfffd, 0xe8d1, 0xfffd, 0xe8d2, 0x8a76, 0xfffd, 0xe8d4, 0xfffd, 0x9078, 0xfffd, 0xfffd, 0xfffd, 0xe8d5, 0xfffd, 0xfffd, 0x8c43, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8d6, 0xe8da, 0xfffd, 0xe8d8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8d9, 0xfffd, 0xfffd, 0x8a93, 0xe8d7, 0xe8db, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8dc, 0xfffd, 0x88c6, 0xfffd, 0xe8dd, 0xe8de, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8fe2, 0xfffd, 0xfffd, 0xfffd, 0xe8df, 0xfffd, 0xfffd, 0xfffd, 0x8b66, 0xfffd, 0xfffd, 0xe8e2, 0xfffd, 0xfffd, 0xe8e1, 0xfffd, 0xe8e0, 0xfffd, 0xfffd, 0xe691, 0xfffd, 0x95da, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8e3, 0xe8e4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8e5, 0xfffd, 0xfffd, 0xe8e6, 0xfffd, 0xe8e7, 0xfffd, 0xfffd, 0xe8e8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ad8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8ea, 0x9442, 0xfffd, 0xfffd, 0xfffd, 0xe8ec, 0x89b9, 0xfffd, 0xe8ef, 0xe8ee, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8943, 0xfffd, 0xfffd, 0xfffd, 0x8bbf, 0xfffd, 0x95c5, 0x92b8, 0x8da0, 0xfffd, 0x8d80, 0x8f87, 0xfffd, 0x907b, 0xfffd, 0xfffd, 0xfffd, 0xe8f1, 0xfffd, 0xfffd, 0xe8f0, 0x9761, 0x8ae6, 0x94d0, 0x93da, 0xfffd, 0xfffd, 0xfffd, 0x909c, 0x97cc, 0xfffd, 0x8c7a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8f4, 0xfffd, 0xfffd, 0xe8f3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x966a, 0x93aa, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x896f, 0xfffd, 0xfffd, 0xe8f5, 0xe8f2, 0xfffd, 0xfffd, 0x9570, 0x978a, 0xe8f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8f7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe8f9, 0x91e8, 0x8a7a, 0x8a7b, 0xe8f8, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ae7, 0x8cb0, 0xfffd, 0xfffd, 0x8ae8, 0xfffd, 0xfffd, 0x935e, 0xfffd, 0xfffd, 0x97de, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cda, 0xfffd, 0xfffd, 0xfffd, 0xe8fa, 0xfffd, 0xfffd, 0xfffd, 0xe8fb, 0xe8fc, 0xe940, 0xfffd, 0xe942, 0xe941, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9597, 0xfffd, 0xe943, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe944, 0xfffd, 0xe945, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe946, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe948, 0xe947, 0xfffd, 0xe949, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x94f2, 0xe3ca, 0xfffd, 0xfffd, 0x9048, 0xfffd, 0xfffd, 0x8b51, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe94a, 0xfffd, 0xe94b, 0xfffd, 0x99aa, 0x9f5a, 0x94d1, 0xfffd, 0xfffd, 0x88f9, 0xfffd, 0x88b9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8e94, 0x964f, 0x8ffc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe94c, 0xfffd, 0x96dd, 0xfffd, 0xfffd, 0xfffd, 0xe94d, 0x977b, 0xfffd, 0x8961, 0xfffd, 0xfffd, 0xfffd, 0x8e60, 0xfffd, 0xe94e, 0x89ec, 0xe94f, 0xfffd, 0xfffd, 0xfffd, 0xe950, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe952, 0xe953, 0xfffd, 0xe955, 0xe951, 0xfffd, 0xfffd, 0xe954, 0xfffd, 0xfffd, 0xfffd, 0x8ad9, 0xfffd, 0xfffd, 0xfffd, 0xe956, 0xfffd, 0xe957, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe958, 0xe959, 0xfffd, 0xfffd, 0xfffd, 0xe95a, 0xfffd, 0xfffd, 0xe95c, 0xfffd, 0xfffd, 0xfffd, 0xe95b, 0xfffd, 0xe95e, 0xe961, 0xfffd, 0xfffd, 0xfffd, 0xe95d, 0xe95f, 0xe960, 0xfffd, 0xfffd, 0xe962, 0xfffd, 0x8bc0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8ef1, 0xe963, 0xe964, 0x8d81, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe965, 0xfffd, 0xfffd, 0x8a5d, 0xfffd, 0xfffd, 0xfffd, 0x946e, 0xe966, 0xe967, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9279, 0x93e9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe968, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x949d, 0xfffd, 0xfffd, 0x91ca, 0x8977, 0x8bec, 0xfffd, 0x8bed, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9293, 0xe96d, 0x8bee, 0xfffd, 0xfffd, 0x89ed, 0xfffd, 0xfffd, 0xe96c, 0xfffd, 0xfffd, 0xe96a, 0xfffd, 0xe96b, 0xfffd, 0xe969, 0xfffd, 0xfffd, 0xe977, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe96e, 0xe96f, 0xfffd, 0xfffd, 0xe970, 0xe971, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe973, 0xfffd, 0xfffd, 0xe972, 0xfffd, 0xfffd, 0xfffd, 0x8f78, 0xfffd, 0xe974, 0xfffd, 0xfffd, 0xfffd, 0xe976, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8b52, 0xe975, 0xfffd, 0xfffd, 0x919b, 0x8cb1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe978, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91cb, 0xfffd, 0xfffd, 0xe979, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x93ab, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe97a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe980, 0xfffd, 0xe97d, 0xfffd, 0xe97c, 0xe97e, 0xfffd, 0xe97b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe982, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe981, 0xfffd, 0xe984, 0xfffd, 0xfffd, 0x8bc1, 0xe983, 0xfffd, 0xfffd, 0xfffd, 0xe985, 0xfffd, 0xfffd, 0xe986, 0xfffd, 0xe988, 0xe987, 0xfffd, 0xfffd, 0xfffd, 0xe989, 0xe98b, 0xe98a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d9c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe98c, 0xfffd, 0xfffd, 0xe98d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a5b, 0xfffd, 0xfffd, 0xfffd, 0xe98e, 0xfffd, 0xfffd, 0xfffd, 0xe98f, 0xfffd, 0xfffd, 0xfffd, 0x9091, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe990, 0xfffd, 0xe991, 0xfffd, 0xe992, 0xe993, 0xfffd, 0xfffd, 0xfffd, 0x8d82, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe994, 0xe995, 0xfffd, 0xfffd, 0xe996, 0xe997, 0xfffd, 0xfffd, 0xe998, 0xfffd, 0xfffd, 0xfffd, 0x94af, 0xe99a, 0xfffd, 0x9545, 0xe99b, 0xe999, 0xfffd, 0xe99d, 0xfffd, 0xfffd, 0xe99c, 0xfffd, 0xfffd, 0xe99e, 0xfffd, 0xfffd, 0xfffd, 0xe99f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9a0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9a1, 0xfffd, 0xe9a2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9a3, 0xfffd, 0xfffd, 0xe9a4, 0xe9a5, 0xfffd, 0xe9a6, 0xfffd, 0xe9a7, 0xe9a8, 0xe9a9, 0xe9aa, 0xfffd, 0xfffd, 0xfffd, 0xe9ab, 0xe9ac, 0xfffd, 0x9f54, 0xe9ad, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe2f6, 0x8b53, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a40, 0x8db0, 0xe9af, 0xe9ae, 0x96a3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9b1, 0xe9b2, 0xe9b0, 0xfffd, 0xe9b3, 0xfffd, 0xfffd, 0x9682, 0xfffd, 0xfffd, 0xfffd, 0xe9b4, 0xfffd, 0x8b9b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9844, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9b5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9b7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x88bc, 0xfffd, 0xfffd, 0xe9b8, 0x95a9, 0xe9b6, 0xfffd, 0xfffd, 0xe9b9, 0xe9ba, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9bb, 0xe9bc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9bd, 0xfffd, 0x968e, 0x8e4c, 0xfffd, 0x8df8, 0x914e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9be, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9c1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9bf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9c2, 0xfffd, 0xfffd, 0x8cef, 0xe9c0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9c3, 0xfffd, 0xe9c4, 0xe9c5, 0xfffd, 0xe9c9, 0xfffd, 0x8e49, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x91e2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9ca, 0xe9c7, 0xe9c6, 0xe9c8, 0xfffd, 0xfffd, 0xfffd, 0x8c7e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9ce, 0xe9cd, 0xe9cc, 0xfffd, 0xfffd, 0x88b1, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9d8, 0xfffd, 0xe9d4, 0xfffd, 0xe9d5, 0xe9d1, 0xe9d7, 0xfffd, 0xe9d3, 0x8a82, 0xfffd, 0xfffd, 0x986b, 0xfffd, 0xe9d6, 0xe9d2, 0xe9d0, 0xe9cf, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9da, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9dd, 0xfffd, 0xfffd, 0xe9dc, 0xe9db, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9568, 0xe9d9, 0x88f1, 0xe9de, 0xfffd, 0xe9e0, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8a8f, 0xe9cb, 0x8956, 0xfffd, 0xfffd, 0xe9e2, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9e1, 0xe9df, 0x924c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9690, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97d8, 0xfffd, 0xfffd, 0xe9e3, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9e4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9e5, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9e6, 0xfffd, 0xe9e7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x92b9, 0xfffd, 0xe9e8, 0xfffd, 0x94b5, 0xfffd, 0xe9ed, 0xe9e9, 0xfffd, 0xfffd, 0xfffd, 0xe9ea, 0xfffd, 0xfffd, 0x9650, 0x96c2, 0xfffd, 0x93ce, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xe9ee, 0xfffd, 0xfffd, 0xe9ef, 0x93bc, 0xe9ec, 0xe9eb, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89a8, 0xfffd, 0xfffd, 0xfffd, 0xe9f7, 0xfffd, 0xfffd, 0xe9f6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8995, 0xfffd, 0xfffd, 0xfffd, 0xe9f4, 0xfffd, 0xfffd, 0xfffd, 0xe9f3, 0xfffd, 0xfffd, 0xe9f1, 0xfffd, 0x8a9b, 0xfffd, 0xe9f0, 0x8eb0, 0x89a7, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8d83, 0xfffd, 0xfffd, 0xe9fa, 0xe9f9, 0xfffd, 0xe9f8, 0xfffd, 0xfffd, 0xe9f5, 0xfffd, 0xe9fb, 0xfffd, 0xe9fc, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea44, 0xea43, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea45, 0xfffd, 0xfffd, 0x894c, 0xea40, 0xea41, 0xfffd, 0x8d94, 0x96b7, 0xfffd, 0xfffd, 0xea42, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9651, 0xfffd, 0xfffd, 0xea4a, 0xfffd, 0xfffd, 0xea46, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea4b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea48, 0xfffd, 0xea47, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8c7b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea4c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea4d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea4e, 0xfffd, 0xea49, 0xfffd, 0xfffd, 0xfffd, 0xe9f2, 0xfffd, 0xfffd, 0xea4f, 0xfffd, 0x92df, 0xfffd, 0xfffd, 0xfffd, 0xea53, 0xfffd, 0xea54, 0xea52, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea51, 0xea57, 0xfffd, 0xea50, 0xfffd, 0xea55, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea56, 0xfffd, 0xfffd, 0xfffd, 0xea59, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea58, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea5b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea5c, 0xfffd, 0xea5d, 0xfffd, 0xfffd, 0x9868, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea5a, 0x91e9, 0x8deb, 0xfffd, 0xfffd, 0xea5e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea5f, 0xea60, 0xfffd, 0xfffd, 0xea61, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea62, 0xfffd, 0xfffd, 0x8cb2, 0xea63, 0xfffd, 0xfffd, 0xfffd, 0xea64, 0xfffd, 0x8ead, 0xfffd, 0xea65, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea66, 0xfffd, 0xfffd, 0xea67, 0xea68, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea6b, 0xea69, 0x985b, 0xfffd, 0xea6a, 0xfffd, 0x97ed, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea6c, 0xfffd, 0x97d9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea6d, 0x949e, 0xfffd, 0xfffd, 0xea6e, 0xea70, 0xfffd, 0xfffd, 0xea71, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea6f, 0x8d8d, 0x96cb, 0x9683, 0x9bf5, 0xfffd, 0x9f80, 0x969b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x89a9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea73, 0x8b6f, 0xea74, 0xea75, 0xea76, 0xfffd, 0x8d95, 0xfffd, 0xea77, 0xfffd, 0xfffd, 0xfffd, 0xe0d2, 0x96d9, 0xfffd, 0x91e1, 0xea78, 0xea7a, 0xea79, 0xfffd, 0xea7b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea7c, 0xfffd, 0xfffd, 0xea7d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea7e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea80, 0xfffd, 0xea81, 0xea82, 0xfffd, 0xea83, 0xfffd, 0xea84, 0xea85, 0xea86, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea87, 0xea88, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9343, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x8cdb, 0xfffd, 0xea8a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x916c, 0xea8b, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea8c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x9540, 0xfffd, 0xfffd, 0xea8d, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea8e, 0xe256, 0xfffd, 0xfffd, 0xe6d8, 0xe8eb, 0xfffd, 0xfffd, 0xea8f, 0xfffd, 0xea90, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea92, 0xea93, 0xea94, 0x97ee, 0xea91, 0xfffd, 0xfffd, 0xea95, 0xea96, 0xfffd, 0xfffd, 0xea98, 0xfffd, 0xea97, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea9a, 0xfffd, 0xfffd, 0xfffd, 0xea9b, 0xea99, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x97b4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea9c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xea9d, 0xe273, 0xfffd, 0xfffd, 0xea9e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; #endif /* KANJI */ /* Blah-to-Unicode translation tables */ struct x_to_unicode u_transparent = { 256, X2U_CXG, 0, 0, "Transparent", "transparent", 0, "", 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; /* 7-bit character sets: ISO 646, DEC NRCs, Short KOI, and Hebrew-7 */ struct x_to_unicode u_ascii = { 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "US ASCII", "ascii", 6, "B", 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e }; struct x_to_unicode u_british = { 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "British ISO 646", "british", 1, "A", 0x0021, 0x0022, 0x00a3, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e }; struct x_to_unicode u_dutch = { 94, 33, X2U_DEC|X2U_STD, AL_ROMAN, "Dutch NRC", "dutch", 0, "4", 0x0021, 0x0022, 0x00a3, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x00be, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00ff, 0x00bd, 0x007c, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00a8, 0x00a4, 0x00bc, 0x0027 }; struct x_to_unicode u_finnish = { 94, 33, X2U_DEC|X2U_STD, AL_ROMAN, "Finnish NRC", "finnish", 0, "5C", 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00c4, 0x00d6, 0x00c5, 0x00dc, 0x005f, 0x00e9, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00e4, 0x00f6, 0x00e5, 0x00fc }; struct x_to_unicode u_french = { 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "French ISO 646", "french", 0, "fR", 0x0021, 0x0022, 0x00a3, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x00e0, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00b0, 0x00e7, 0x00a7, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00e9, 0x00f9, 0x00e8, 0x00a8 }; struct x_to_unicode u_fr_canadian = { 94,33,X2U_DEC|X2U_STD,AL_ROMAN,"French Canadian NRC","canadian-french",0,"9Q", 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x00e0, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00e2, 0x00e7, 0x00ea, 0x00ee, 0x005f, 0x00f4, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00e9, 0x00f9, 0x00e8, 0x00fb }; struct x_to_unicode u_german = { 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "German ISO 646", "german", 21, "K", 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x00a7, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00c4, 0x00d6, 0x00dc, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00e4, 0x00f6, 0x00fc, 0x00df }; struct x_to_unicode u_hungarian = { 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "Hungarian ISO 646","hungarian",86,"i", 0x0021, 0x0022, 0x0023, 0x00a4, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x00c1, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00c9, 0x00d6, 0x00dc, 0x005e, 0x005f, 0x00e1, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00e9, 0x00f6, 0x00fc, 0x0022, 0x02dd }; struct x_to_unicode u_italian = { 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "Italian ISO 646", "italian", 15, "Y", 0x0021, 0x0022, 0x00a3, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x00a7, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00b0, 0x00e7, 0x00e9, 0x005e, 0x005f, 0x00f9, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00e0, 0x00f2, 0x00e8, 0x00ec }; struct x_to_unicode u_icelandic = { 94, 33, X2U_DEC|X2U_STD, AL_ROMAN, "Icelandic NRC", "icelandic", 0, NULL, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x00de, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00f0, 0x00d8, 0x00c6, 0x00d6, 0x005f, 0x00fe, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00f0, 0x007c, 0x00e6, 0x00f6 }; struct x_to_unicode u_jis0201r = { 94, 33, X2U_ISO|X2U_STD,AL_ROMAN,"Japanese Roman","japanese-roman",14,"J", 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x00a5, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x203e }; struct x_to_unicode u_jis0201k = { 94, 33, X2U_ISO|X2U_STD,AL_KANA,"Japanese Katakana", "katakana", 13, "I", 0xff61, 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67, 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f, 0xff70, 0xff71, 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77, 0xff78, 0xff79, 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f, 0xff80, 0xff81, 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87, 0xff88, 0xff89, 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f, 0xff90, 0xff91, 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97, 0xff98, 0xff99, 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd }; struct x_to_unicode u_norwegian = { /* Same as Danish */ 94,33,X2U_ISO|X2U_STD,AL_ROMAN,"Norwegian ISO 646", "norwegian", 60, "`E6", 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00c6, 0x00d8, 0x00c5, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00e6, 0x00f8, 0x00e5, 0x007e }; struct x_to_unicode u_danish = { /* Same as Norwegian */ 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "Danish ISO 646", "danish", 60, "`E6", 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00c6, 0x00d8, 0x00c5, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00e6, 0x00f8, 0x00e5, 0x007e }; struct x_to_unicode u_portuguese = { 94,33,X2U_ISO|X2U_STD,AL_ROMAN,"Portuguese ISO 646","portuguese",16,"L%6", 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00c6, 0x00d8, 0x00c5, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00e6, 0x00f8, 0x00e5, 0x007e }; struct x_to_unicode u_spanish = { 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "Spanish ISO 646", "spanish", 17, "Z", 0x0021, 0x0022, 0x00a3, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x00a7, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00a1, 0x00d1, 0x00bf, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00b0, 0x00f1, 0x00e7, 0x007e }; struct x_to_unicode u_swedish = { 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "Swedish ISO 646", "swedish", 11, "HG", 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x00c9, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00c4, 0x00d6, 0x00c5, 0x00dc, 0x005f, 0x00e9, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00e4, 0x00f6, 0x00e5, 0x00fc }; struct x_to_unicode u_swiss = { 94, 33, X2U_DEC|X2U_STD, AL_ROMAN, "Swiss NRC", "swiss", 0, "=", 0x0021, 0x0022, 0x00f9, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x00e0, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x00e9, 0x00e7, 0x00ea, 0x00ee, 0x00e8, 0x00f4, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x00e4, 0x00f6, 0x00fc, 0x00fb }; struct x_to_unicode u_koi7 = { 94, 33, X2U_STD, AL_CYRIL, "Short KOI", "short-koi", 0, NULL, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427 }; struct x_to_unicode u_elot927 = { 94, 33, X2U_STD, AL_GREEK, "ELOT 927", "elot927-greek", 0, NULL, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, 0x03a0, 0x03a1, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x0020, 0x0020, 0x007b, 0x007c, 0x007d, 0x007e }; struct x_to_unicode u_hebrew7 = { 94, 33, X2U_STD, AL_HEBREW, "Hebrew-7", "hebrew-7", 0, NULL, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea, 0x007b, 0x007c, 0x007d, 0x007e }; struct x_to_unicode u_apl1 = { 94, 33, X2U_ISO|X2U_STD, AL_ROMAN, "APL ISO", "apl-iso", 68, "e", 0x00a8, 0x0029, 0x003c, 0x2264, 0x003d, 0x003e, 0x005d, 0x2228, 0x2227, 0x2260, 0x00f7, 0x002c, 0x002b, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x0028, 0x005b, 0x003b, 0x00d7, 0x003a, 0x005c, 0x00af, 0x237a, 0x22a5, 0x22c2, 0x230a, 0x220a, 0x005f, 0x2207, 0x2206, 0x2373, 0x2218, 0x0027, 0x25af, 0x007c, 0x22a4, 0x25cb, 0x22c6, 0x003f, 0x2374, 0x2308, 0x223c, 0x2193, 0x222a, 0x2375, 0x2283, 0x2191, 0x2282, 0x2190, 0x22a2, 0x2192, 0x2265, 0x002d, 0x22c4, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x007b, 0x22a3, 0x007d, 0x0024 }; /* ISO 8859 Latin Alphabets */ struct x_to_unicode u_8859_1 = { 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-1", "latin1", 100, "A", 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF }; struct x_to_unicode u_8859_2 = { 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-2", "latin2", 101, "B", 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 }; struct x_to_unicode u_8859_3 = { 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-3", "latin3", 109, "C", 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0xfffd, 0x0124, 0x00A7, 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0xfffd, 0x017B, 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0xfffd, 0x017C, 0x00C0, 0x00C1, 0x00C2, 0xfffd, 0x00C4, 0x010A, 0x0108, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0xfffd, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0xfffd, 0x00E4, 0x010B, 0x0109, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0xfffd, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9 }; struct x_to_unicode u_8859_4 = { 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-4", "latin4", 110, "D", 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7, 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF, 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7, 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B, 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A, 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF, 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B, 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9 }; struct x_to_unicode u_8859_5 = { 96,32,X2U_ISO|X2U_STD,AL_CYRIL,"ISO Latin/Cyrillic","cyrillic-iso",144,"L", 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F }; struct x_to_unicode u_8859_6 = { 96, 32, X2U_ISO|X2U_STD,AL_ARABIC,"ISO Latin/Arabic","arabic-iso",127,"G", 0x00A0, 0xfffd, 0xfffd, 0xfffd, 0x00A4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x060C, 0x00AD, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x061B, 0xfffd, 0xfffd, 0xfffd, 0x061F, 0xfffd, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x0651, 0x0652, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd }; struct x_to_unicode u_8859_7 = { 96, 32, X2U_ISO|X2U_STD,AL_GREEK,"ISO Latin/Greek", "greek-iso", 126, "F", 0x00A0, 0x2018, 0x2019, 0x00A3, 0xFFFD, 0xFFFD, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0xFFFD, 0x2015, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7, 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03A1, 0xfffd, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xfffd }; struct x_to_unicode u_8859_8 = { 96, 32, X2U_ISO|X2U_STD,AL_HEBREW,"ISO Latin/Hebrew","hebrew-iso",121,"H", 0x00A0, 0xfffd, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x203E, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2017, 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd }; struct x_to_unicode u_8859_9 = { 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-5", "latin5", 148, "M", 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF }; struct x_to_unicode u_8859_10 = { 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-6", "latin6", 157, "V", 0x00a0, 0x0104, 0x0112, 0x0122, 0x012a, 0x0128, 0x0136, 0x013b, 0x0143, 0x0156, 0x0160, 0x0166, 0x017d, 0x00ad, 0x0138, 0x014a, 0x0111, 0x0105, 0x0113, 0x0123, 0x012b, 0x0129, 0x0137, 0x013c, 0x0144, 0x0157, 0x0161, 0x0167, 0x017e, 0x00bd, 0x00be, 0x014b, 0x0100, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x012e, 0x010c, 0x00c9, 0x0118, 0x00cb, 0x0116, 0x00cd, 0x00ce, 0x00cf, 0x0110, 0x0145, 0x014c, 0x00de, 0x00d4, 0x00d5, 0x00d6, 0x0168, 0x00d8, 0x0172, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x016a, 0x0101, 0x00e1, 0x00e2, 0x00d3, 0x00e4, 0x00e5, 0x00e6, 0x012f, 0x010d, 0x00e9, 0x0119, 0x00eb, 0x0117, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x014d, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x0169, 0x00f8, 0x0173, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x016b }; /* Latin-9 (ISO 8859-15) is the same as Latin-1 with the following changes: * A4 is Euro Symbol 20AC * A6 is Capital S Caron 0160 * A8 is Small s caron 0161 * B4 is Capital Z caron 017D * B8 is Small z caron 017E * BC is Capital OE ligature 0152 * BD is Small oe ligature 0153 * BE is Capital Y diaeresis 0178 */ struct x_to_unicode u_8859_15 = { 96, 32, X2U_ISO|X2U_STD, AL_ROMAN, "ISO Latin-9", "latin9", 0, NULL, 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7, 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7, 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF }; /* Dyadic Systems Dyalog/X APL, corresponds to APLTERMI.TTF. */ /* Unicode mappings according to ISO-IEC / JTC 1 / SC 22 N 3067, 1999-12-28. */ struct x_to_unicode u_apl2 = { /* Dyadic Systems APL + box drawings */ 96, 32, X2U_STD, AL_ROMAN, "Dyadic Systems APL", "apl-dyadic", 0, NULL, 0x00a0, 0x00d7, 0x2502, 0x2524, 0x00a2, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x2518, 0x250c, 0x2206, 0x00f7, 0x2260, 0x22c4, 0x2375, 0x2374, 0x237a, 0x220a, 0x2261, 0x2265, 0x2264, 0x22a5, 0x22a4, 0x2190, 0x2218, 0x235d, 0x233f, 0x2340, 0x234e, 0x2355, 0x234b, 0x2352, 0x2372, 0x2371, 0x2368, 0x235f, 0x25af, 0x235e, 0x2339, 0x236b, 0x236a, 0x2262, 0x230a, 0x2308, 0x2349, 0x2229, 0x222a, 0x236c, 0x00a3, 0x233d, 0x2296, 0x22a2, 0x22a3, 0x2337, 0x00af, 0x2373, 0x00a8, 0x25cb, 0x2192, 0x2228, 0x2282, 0x2283, 0x2359, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x2207, 0x2191, 0x2193 }; struct x_to_unicode u_apl3 = { /* APL-Plus = APL-2000 */ 128, 0, X2U_CXG, AL_ROMAN, "APL-2000", "apl-2000", 0, NULL, 0x20ac, 0x22a3, 0x22a4, 0x22a5, 0x2190, 0x2192, 0x2191, 0x2193, 0x2264, 0x2265, 0x2372, 0x2371, 0x25af, 0x235e, 0x2339, 0x2359, 0x236b, 0x2206, 0x2207, 0x234b, 0x2352, 0x2355, 0x234e, 0x2308, 0x230a, 0x2340, 0x233f, 0x2282, 0x2283, 0x2229, 0x222a, 0x2228, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x22a2, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x235d, 0x22c4, 0x00ab, 0x2260, 0x2261, 0x236a, 0x00af, 0x2218, 0x25cb, 0x233d, 0x2349, 0x2296, 0x235f, 0x00b6, 0x00b7, 0x237a, 0x220a, 0x2377, 0x00bb, 0x2373, 0x2374, 0x2375, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x236c, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x2337, 0x00df, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x2364, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x2205, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x2368, 0x00ff }; struct x_to_unicode u_apl4 = { /* IBM APL2 */ 128, 0, X2U_CXG, AL_ROMAN, "IBM APL2", "apl2-ibm", 0, NULL, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x25af, 0x235e, 0x2339, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x22a4, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x22a5, 0x2190, 0x2336, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2308, 0x00ac, 0x2192, 0x222a, 0x00a1, 0x2355, 0x234e, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x235f, 0x2206, 0x2207, 0x2192, 0x2563, 0x2551, 0x2557, 0x255d, 0x2190, 0x230a, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x2191, 0x2193, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2261, 0x2378, 0x2377, 0x2235, 0x2337, 0x2342, 0x233b, 0x22a2, 0x22a3, 0x22c4, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580, 0x237a, 0x00df, 0x2282, 0x2283, 0x235d, 0x2372, 0x2374, 0x2371, 0x233d, 0x2296, 0x25cb, 0x2228, 0x2373, 0x2349, 0x00c5, 0x2229, 0x233f, 0x2340, 0x2265, 0x2264, 0x2260, 0x00d7, 0x00f7, 0x2359, 0x2218, 0x2375, 0x236b, 0x234b, 0x2352, 0x00af, 0x00a8, 0x00a0 }; struct x_to_unicode u_apl5 = { /* APL-2741 */ 128, 0, X2U_CXG, AL_ROMAN, "APL-2741", "apl-2741", 0, NULL, 0x20ac, 0x22a3, 0x22a4, 0x22a5, 0x2190, 0x2192, 0x2191, 0x2193, 0x2264, 0x2265, 0x2372, 0x2371, 0x25af, 0x235e, 0x2339, 0x2359, 0x236b, 0x2206, 0x2207, 0x234b, 0x2352, 0x2355, 0x234e, 0x2308, 0x230a, 0x2340, 0x233f, 0x2282, 0x2283, 0x2229, 0x222a, 0x2228, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x22a2, 0x2378, 0x2261, 0x2336, 0x00a8, 0x235d, 0x22c4, 0x236c, 0x2260, 0x2261, 0x236a, 0x00af, 0x2218, 0x25cb, 0x233d, 0x2349, 0x2296, 0x235f, 0x00b6, 0x00b7, 0x237a, 0x220a, 0x2377, 0x2262, 0x2373, 0x2374, 0x2375, 0x00bf, 0x2514, 0x2534, 0x252c, 0x251c, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x2342, 0x233b, 0x2510, 0x00cd, 0x2500, 0x253c, 0x236c, 0x00d1, 0x2350, 0x2357, 0x2347, 0x2348, 0x00d6, 0x00d7, 0x00d8, 0x2518, 0x250c, 0x2502, 0x00dc, 0x2524, 0x2337, 0x00df, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x2364, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x2205, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x2235, 0x2368, 0x2365 }; /* 8-bit GOST standard sets */ struct x_to_unicode u_koi8 = { 96, 32, X2U_STD, AL_CYRIL, "KOI-8", "koi8", 0, NULL, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0xfffd }; /* Other KOI-8 based sets */ struct x_to_unicode u_koi8r = { /* (Russia) Table from RFC1489 */ 128, 0, X2U_CP, AL_CYRIL, "KOI8-R", "koi8r", 0, NULL, 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, 0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556, 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E, 0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565, 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x00A9, 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A }; struct x_to_unicode u_koi8u = { /* (Ukraine) From RFC2319 */ 128, 0, X2U_CP, AL_CYRIL, "KOI8-U", "koi8u", 0, NULL, 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, 0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457, 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E, 0x255F, 0x2560, 0x2561, 0x0401, 0x0404, 0x2563, 0x0406, 0x0407, 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x0490, 0x256C, 0x00A9, 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A }; /* PC Code Pages */ struct x_to_unicode u_cp437 = { 128, 0, X2U_CP, AL_ROMAN,"PC Code Page 437","cp437", 0, NULL, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, /* 0x25ae */ 0x25a0, 0x00a0 }; struct x_to_unicode u_mazovia = { 128, 0, X2U_CP, AL_ROMAN,"Polish Mazovia PC Code Page","mazovia", 0, NULL, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x0105, 0x00e7, /* 80 */ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x0107, 0x00c4, 0x0104, /* 88 */ 0x0118, 0x0119, 0x0142, 0x00f4, 0x00f6, 0x0106, 0x00fb, 0x00f9, /* 90 */ 0x015a, 0x00d6, 0x00dc, 0x00a2, 0x0141, 0x00a5, 0x015b, 0x0192, /* 98 */ 0x0179, 0x017b, 0x00f3, 0x00d3, 0x0144, 0x0143, 0x017a, 0x017c, /* a0 */ 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, /* a8 */ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, /* b0 */ 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, /* b8 */ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, /* c0 */ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, /* c8 */ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, /* d0 */ 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, /* d8 */ 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, /* e0 */ 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, /* e8 */ 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, /* f0 */ 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 /* f8 */ }; struct x_to_unicode u_cp850 = { 128, 0, X2U_CP, AL_ROMAN,"PC Code Page 850","cp850", 0, NULL, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x00d7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x00ae, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x00c0, 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, 0x00a2, 0x00a5, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x00e3, 0x00c3, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, 0x00f0, 0x00d0, 0x00ca, 0x00cb, 0x00c8, 0x0131, 0x00cd, 0x00ce, 0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580, 0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0x00fe, 0x00de, 0x00da, 0x00db, 0x00d9, 0x00fd, 0x00dd, 0x00af, 0x00b4, 0x00ad, 0x00b1, 0x2017, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8, 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0 }; struct x_to_unicode u_cp852 = { 128, 0, X2U_CP, AL_ROMAN,"PC Code Page 852","cp852", 0, NULL, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x016f, 0x0107, 0x00e7, 0x0142, 0x00eb, 0x0150, 0x0151, 0x00ee, 0x0179, 0x00c4, 0x0106, 0x00c9, 0x0139, 0x013a, 0x00f4, 0x00f6, 0x013d, 0x013e, 0x015a, 0x015b, 0x00d6, 0x00dc, 0x0164, 0x0165, 0x0141, 0x00d7, 0x010d, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x0104, 0x0105, 0x017d, 0x017e, 0x0118, 0x0119, 0x00ac, 0x017a, 0x010c, 0x015f, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x011a, 0x015e, 0x2563, 0x2551, 0x2557, 0x255d, 0x017b, 0x017c, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x0102, 0x0103, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, 0x0111, 0x0110, 0x010e, 0x00cb, 0x010f, 0x0147, 0x00cd, 0x00ce, 0x011b, 0x2518, 0x250c, 0x2588, 0x2584, 0x0162, 0x016e, 0x2580, 0x00d3, 0x00df, 0x00d4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00da, 0x0155, 0x0170, 0x00fd, 0x00dd, 0x0163, 0x00b4, 0x00ad, 0x02dd, 0x02db, 0x02c7, 0x02d8, 0x00a7, 0x00f7, 0x00b8, 0x00b0, 0x00a8, 0x02d9, 0x0171, 0x0158, 0x0159, 0x25a0, 0x00a0 }; struct x_to_unicode u_cp855 = { /* CP855 Cyrillic to Unicode */ 128, 0, X2U_CP, AL_CYRIL,"PC Code Page 855","cp855", 0, NULL, 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, 0x0459, 0x0409, 0x045a, 0x040a, 0x045b, 0x040b, 0x045c, 0x040c, 0x045e, 0x040e, 0x045f, 0x040f, 0x044e, 0x042e, 0x044a, 0x042a, 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255d, 0x0439, 0x0419, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x043a, 0x041a, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, 0x043b, 0x041b, 0x043c, 0x041c, 0x043d, 0x041d, 0x043e, 0x041e, 0x043f, 0x2518, 0x250c, 0x2588, 0x2584, 0x041f, 0x044f, 0x2580, 0x042f, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044c, 0x042c, 0x2116, 0x002d, 0x044b, 0x042b, 0x0437, 0x0417, 0x0448, 0x0428, 0x044d, 0x042d, 0x0449, 0x0429, 0x0447, 0x0427, 0x00a7, 0x25a0, 0x0020 }; struct x_to_unicode u_cp856 = { /* CP856 (Bulgaria) to Unicode */ 128, 0, X2U_CP, AL_CYRIL,"PC Code Page 856","cp856", 0, NULL, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x2563, 0x2551, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2510, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2116, 0x00a7, 0x2557, 0x255d, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; struct x_to_unicode u_cp857 = { 128, 0, X2U_CP, AL_ROMAN,"PC Code Page 857","cp857", 0, NULL, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, /* 0x80 */ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x0131, 0x00c4, 0x00c5, /* 0x88 */ 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, /* 0x90 */ 0x0130, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x015e, 0x015f, /* 0x98 */ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x011e, 0x011f, /* 0xa0 */ 0x00bf, 0x00ae, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, /* 0xa8 */ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x00c0, /* 0xb0 */ 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, 0x00a2, 0x00a5, 0x2510, /* 0xb8 */ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x00e3, 0x00c3, /* 0xc0 */ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, /* 0xc8 */ 0x00ba, 0x00aa, 0x00ca, 0x00cb, 0x00c8, 0x20ac, 0x00cd, 0x00ce, /* 0xd0 */ 0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580, /* 0xd8 */ 0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0xfffd, /* 0xe0 */ 0x00d7, 0x00da, 0x00db, 0x00d9, 0x00ec, 0x00ff, 0x00af, 0x00b4, /* 0xe8 */ 0x00ad, 0x00b1, 0xfffd, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8, /* 0xf0 */ 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0 /* 0xf8 */ }; struct x_to_unicode u_cp858 = { 128, 0, X2U_CP, AL_ROMAN,"PC Code Page 858","cp858", 0, NULL, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x00d7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x00ae, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x00c0, 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, 0x00a2, 0x00a5, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x00e3, 0x00c3, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, 0x00f0, 0x00d0, 0x00ca, 0x00cb, 0x00c8, 0x20ac, 0x00cd, 0x00ce, 0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580, 0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0x00fe, 0x00de, 0x00da, 0x00db, 0x00d9, 0x00fd, 0x00dd, 0x00af, 0x00b4, 0x00ad, 0x00b1, 0x2017, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8, 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0 }; struct x_to_unicode u_cp862 = { 128, 0, X2U_CP, AL_HEBREW,"PC Code Page 862","cp862", 0, NULL, 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; struct x_to_unicode u_cp864 = { 128, 0, X2U_CP, AL_ARABIC,"PC Code Page 864","cp864", 0, NULL, 0x00b0, 0x00b7, 0x2219, 0x221a, 0x2592, 0x2500, 0x2502, 0x253c, 0x2524, 0x252c, 0x251c, 0x2534, 0x2510, 0x250c, 0x2514, 0x2518, 0x03b2, 0x221e, 0x03c6, 0x00b1, 0x00bd, 0x00bc, 0x2248, 0x00ab, 0x00bb, 0xfef7, 0xfef8, 0xfffd, 0xfffd, 0xfefb, 0xfefc, 0xfffd, 0x00a0, 0x00ad, 0xfe82, 0x00a3, 0x00a4, 0xfe84, 0xfffd, 0xfffd, 0xfe8e, 0xfe8f, 0xfe95, 0xfe99, 0x060c, 0xfe9d, 0xfea1, 0xfea5, 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xfed1, 0x061b, 0xfeb1, 0xfeb5, 0xfeb9, 0x061f, 0x00a2, 0xfe80, 0xfe81, 0xfe83, 0xfe85, 0xfeca, 0xfe8b, 0xfe8d, 0xfe91, 0xfe93, 0xfe97, 0xfe9b, 0xfe9f, 0xfea3, 0xfea7, 0xfea9, 0xfeab, 0xfead, 0xfeaf, 0xfeb3, 0xfeb7, 0xfebb, 0xfebf, 0xfec1, 0xfec5, 0xfecb, 0xfecf, 0x00a6, 0x00ac, 0x00f7, 0x00d7, 0xfec9, 0x0640, 0xfed3, 0xfed7, 0xfedb, 0xfedf, 0xfee3, 0xfee7, 0xfeeb, 0xfeed, 0xfeef, 0xfef3, 0xfebd, 0xfecc, 0xfece, 0xfecd, 0xfee1, 0xfe7d, 0x0651, 0xfee5, 0xfee9, 0xfeec, 0xfef0, 0xfef2, 0xfed0, 0xfed5, 0xfef5, 0xfef6, 0xfedd, 0xfed9, 0xfef1, 0x25a0, 0xfffd }; struct x_to_unicode u_cp866 = { 128, 0, X2U_CP, AL_CYRIL,"PC Code Page 866","cp866", 0, NULL, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040e, 0x045e, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x2116, 0x00a4, 0x25a0, 0x00a0 }; struct x_to_unicode u_cp869 = { 128, 0, X2U_CP, AL_GREEK,"PC Code Page 869","cp869", 0, NULL, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x0386, 0xfffd, 0x00b7, 0x00ac, 0x00a6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, 0x038a, 0x03aa, 0x038c, 0xfffd, 0xfffd, 0x038e, 0x03ab, 0x00a9, 0x038f, 0x00b2, 0x00b3, 0x03ac, 0x00a3, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc, 0x03cd, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00bd, 0x0398, 0x0399, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039a, 0x039b, 0x039c, 0x039d, 0x2563, 0x2551, 0x2557, 0x255d, 0x039e, 0x039f, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x03a0, 0x03a1, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03b1, 0x03b2, 0x03b3, 0x2518, 0x250c, 0x2588, 0x2584, 0x03b4, 0x03b5, 0x2580, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x0384, 0x00ad, 0x00b1, 0x03c5, 0x03c6, 0x03c7, 0x00a7, 0x03c8, 0x0385, 0x00b0, 0x00a8, 0x03c9, 0x03cb, 0x03b0, 0x03ce, 0x25a0, 0x00a0 }; /* Windows code pages */ struct x_to_unicode u_cp1250 = { /* Windows Latin-2 */ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1250","cp1250", 0, NULL, 0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, /* 80 */ 0x005e, 0x2031, 0x0160, 0x003c, 0x015a, 0x0164, 0x017d, 0x0179, /* 88 */ 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2012, 0x2014, /* 90 */ 0xfffd, 0x2122, 0x0161, 0x003e, 0x015b, 0x0165, 0x017e, 0x017a, /* 98 */ 0x00A0, 0x02c7, 0x02d8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, /* A0 */ 0x00A8, 0x00a9, 0x015E, 0x00ab, 0x00ac, 0x002D, 0x00ae, 0x017B, /* A8 */ 0x00B0, 0x00b1, 0x02DB, 0x0142, 0x00B4, 0x00b5, 0x00b6, 0x00b7, /* B0 */ 0x00B8, 0x0105, 0x015F, 0x00bb, 0x013d, 0x02DD, 0x013E, 0x017C, /* B8 */ 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, /* C0 */ 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 }; struct x_to_unicode u_cp1251 = { /* Windows Cyrillic */ 128, 0, X2U_CP, AL_CYRIL,"Windows Code Page 1251","cp1251", 0, NULL, 0x0402, 0x0403, 0x201a, 0x0453, 0x201e, 0x2026, 0x2020, 0x2021, /* 80 */ 0x20ac, 0x2031, 0x0409, 0x003c, 0x040a, 0x040c, 0x040b, 0x040f, /* 88 */ 0x0452, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2012, 0x2014, /* 90 */ 0x007e, 0x2122, 0x0459, 0x003e, 0x045a, 0x045c, 0x045b, 0x045f, /* 98 */ 0x00A0, 0x040e, 0x045e, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, /* a0 */ 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, /* a8 */ 0x00b0, 0x00b1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, /* b0 */ 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, /* b8 */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, /* c0 */ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, /* c8 */ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, /* d0 */ 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, /* d8 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, /* e0 */ 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, /* e8 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, /* f0 */ 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f /* f8 */ }; struct x_to_unicode u_cp1252 = { /* Windows Latin-1 */ /* The following code points added September 1998: 0x80: Euro 0x8E: Latin Capital Letter Z with Caron 0x9E: Latin Small Letter Z with Caron Announced by Murray Sargent to Unicode consortium, email, 3 September 1998. The code page was changed in June 1998. The change is reflected in Windows 98 and "recent service packs" for Window 95 and Windows NT 4.0. */ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1252","cp1252", 0, NULL, 0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x005e, 0x2031, 0x0160, 0x003c, 0x0152, 0xfffd, 0x017D, 0xfffd, 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2012, 0x2014, 0x007e, 0x2122, 0x0161, 0x003e, 0x0153, 0xfffd, 0x017E, 0x0178, 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF }; struct x_to_unicode u_cp1253 = { /* Windows Greece */ 128, 0, X2U_CP, AL_GREEK,"Windows Code Page 1253","cp1253", 0, NULL, 0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, /* 80 */ 0xfffd, 0x2031, 0xfffd, 0x003c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* 88 */ 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2012, 0x2014, /* 90 */ 0xfffd, 0x2122, 0xfffd, 0x003e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* 98 */ 0x00A0, 0x00b7, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, /* a0 */ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, /* a8 */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B7, 0x00B5, 0x00B6, 0x00B7, /* b0 */ 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, /* b8 */ 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, /* c0 */ 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, /* c8 */ 0x03a0, 0x03a1, 0xfffd, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, /* d0 */ 0x03a8, 0x03a9, 0x03aA, 0x03aB, 0x03aC, 0x03aD, 0x03aE, 0x03aF, /* d8 */ 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, /* e0 */ 0x03b8, 0x03b9, 0x03bA, 0x03bB, 0x03bC, 0x03bD, 0x03bE, 0x03bF, /* e8 */ 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, /* f0 */ 0x03c8, 0x03c9, 0x03cA, 0x03cB, 0x03cC, 0x03cD, 0x03cE, 0xfffd /* f8 */ }; struct x_to_unicode u_cp1254 = { /* Windows Turkey */ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1254","cp1254", 0, NULL, 0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, /* 80 */ 0x005e, 0x2031, 0x0160, 0x003c, 0x0152, 0xfffd, 0xfffd, 0xfffd, /* 88 */ 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2012, 0x2014, /* 90 */ 0x007e, 0x2122, 0x0161, 0x003e, 0x0153, 0xfffd, 0xfffd, 0x0178, /* 98 */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x011e, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015e, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x011f, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015f, 0x00FF }; struct x_to_unicode u_cp1255 = { /* Windows Hebrew */ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1255 (Hebrew)","cp1255", 0, NULL, 0x20AC, 0xFFFD, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x02c6, 0x2030, 0xfffd, 0x2039, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x02dc, 0x2122, 0xfffd, 0x203a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x20aa, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00d7, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00f7, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7, 0x05b8, 0x05b9, 0xfffd, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf, 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05f0, 0x05f1, 0x05f2, 0x05f3, 0x05f4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea, 0xfffd, 0xfffd, 0x200e, 0x200f, 0xfffd }; struct x_to_unicode u_cp1256 = { /* Windows Arabic */ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1256 (Arabic)","cp1256", 0, NULL, 0x20ac, 0x067e, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x02c6, 0x2030, 0xfffd, 0x2039, 0x0152, 0x0686, 0x0698, 0xfffd, /* 88 */ 0x06af, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, /* 90 */ 0xfffd, 0x2122, 0xfffd, 0x003a, 0x0153, 0x200c, 0x200d, 0xfffd, /* 98 */ 0x00A0, 0x060c, 0x00A2, 0x00A3, 0x00A4, 0x00a5, 0x00A6, 0x00A7, /* a0 */ 0x00a8, 0x00A9, 0xfffd, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00af, /* a8 */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00b4, 0x00B5, 0x00B6, 0x00B7, /* b0 */ 0x00b8, 0x00B9, 0x061b, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061f, /* b8 */ 0xfffd, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, /* c0 */ 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f, /* c8 */ 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, /* d0 */ 0x0637, 0x0638, 0x0639, 0x063a, 0x0640, 0x0641, 0x0642, 0x0643, /* d8 */ 0x00e0, 0x0644, 0x00e2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00e7, /* e0 */ 0x00e8, 0x00E9, 0x00ea, 0x00eb, 0x0649, 0x064a, 0x00ee, 0x00ef, /* e8 */ 0x064b, 0x064c, 0x064d, 0x064e, 0x00f4, 0x064f, 0x0650, 0x00F7, /* f0 */ 0x0651, 0x00f9, 0x0652, 0x00fb, 0x00fc, 0x200e, 0x200f, 0xfffd /* f8 */ }; struct x_to_unicode u_cp1257 = { /* Windows Latin-4 */ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1257","cp1257", 0, NULL, 0x20ac, 0xfffd, 0x201a, 0xfffd, 0x201e, 0x2026, 0x2020, 0x2021, /* 80 */ 0xfffd, 0x2031, 0xfffd, 0x003c, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* 88 */ 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2012, 0x2014, /* 90 */ 0xfffd, 0x2122, 0xfffd, 0x003e, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* 98 */ 0x00A0, 0xfffd, 0x00A2, 0x00A3, 0x00A4, 0xfffd, 0x00A6, 0x00A7, /* a0 */ 0x00d8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00c6, /* a8 */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0xfffd, 0x00B5, 0x00B6, 0x00B7, /* b0 */ 0x00f8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00e6, /* b8 */ 0x0104, 0x012e, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, /* c0 */ 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012a, 0x00b7, /* c8 */ 0x0160, 0x0143, 0x0145, 0x00d3, 0x014c, 0x00D5, 0x00D6, 0x00D7, /* d0 */ 0x0172, 0x0141, 0x015A, 0x016a, 0x00DC, 0x017b, 0x017d, 0x00DF, /* d8 */ 0x0105, 0x012f, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, /* e0 */ 0x010D, 0x00E9, 0x017a, 0x0117, 0x0123, 0x0137, 0x012b, 0x013c, /* e8 */ 0x0161, 0x0144, 0x0146, 0x00f3, 0x014d, 0x00F5, 0x00F6, 0x00F7, /* f0 */ 0x0173, 0x0142, 0x015b, 0x016b, 0x00fc, 0x017c, 0x017e, 0xfffd /* f8 */ }; struct x_to_unicode u_cp1258 = { /* Windows Viet Nam */ 128, 0, X2U_CP, AL_ROMAN,"Windows Code Page 1258 (Viet Nam)","cp1258", 0, NULL, 0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, /* 80 */ 0x02c6, 0x2030, 0xfffd, 0x2039, 0x0152, 0xfffd, 0xfffd, 0xfffd, /* 88 */ 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, /* 90 */ 0x02dc, 0x2122, 0xfffd, 0x203a, 0x0153, 0xfffd, 0xfffd, 0x0178, /* 98 */ 0x00A0, 0x00a1, 0x00A2, 0x00A3, 0x00A4, 0x00a5, 0x00A6, 0x00A7, /* a0 */ 0x00a8, 0x00A9, 0x00aa, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00af, /* a8 */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00b4, 0x00B5, 0x00B6, 0x00B7, /* b0 */ 0x00b8, 0x00B9, 0x00ba, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00bf, /* b8 */ 0x00c0, 0x00c1, 0x00c2, 0x0102, 0x00C4, 0x00C5, 0x00c6, 0x00c7, /* c0 */ 0x00c8, 0x00C9, 0x00ca, 0x00cb, 0x0300, 0x00cd, 0x00ce, 0x00cf, /* c8 */ 0x0110, 0x00d1, 0x0309, 0x00d3, 0x00d4, 0x01a0, 0x00D6, 0x00D7, /* d0 */ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00DC, 0x01af, 0x0303, 0x00DF, /* d8 */ 0x00e0, 0x00e1, 0x00e2, 0x0103, 0x00E4, 0x00E5, 0x00e6, 0x00d7, /* e0 */ 0x00e8, 0x00E9, 0x00ea, 0x00eb, 0x0301, 0x00ed, 0x00ee, 0x00ef, /* e8 */ 0x0111, 0x00f1, 0x0323, 0x00f3, 0x00f4, 0x01a1, 0x00F6, 0x00F7, /* f0 */ 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x01b0, 0x20ab, 0x00ff /* f8 */ }; struct x_to_unicode u_cp37 = { /* EBCDIC U.S. */ 256, 0, X2U_CP, AL_ROMAN,"Code Page 037 EBCDIC (U.S.)","cp037", 0, NULL, 0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F, 0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087, 0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007, 0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004, 0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A, 0x0020, 0x00A0, 0x00E2, 0x00E4, 0x00E0, 0x00E1, 0x00E3, 0x00E5, 0x00E7, 0x00F1, 0x00A2, 0x002E, 0x003C, 0x0028, 0x002B, 0x007C, 0x0026, 0x00E9, 0x00EA, 0x00EB, 0x00E8, 0x00ED, 0x00EE, 0x00EF, 0x00EC, 0x00DF, 0x0021, 0x0024, 0x002A, 0x0029, 0x003B, 0x00AC, 0x002D, 0x002F, 0x00C2, 0x00C4, 0x00C0, 0x00C1, 0x00C3, 0x00C5, 0x00C7, 0x00D1, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F, 0x00F8, 0x00C9, 0x00CA, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022, 0x00D8, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x00AB, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1, 0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x00AA, 0x00BA, 0x00E6, 0x00B8, 0x00C6, 0x00A4, 0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x00A1, 0x00BF, 0x00D0, 0x00DD, 0x00DE, 0x00AE, 0x005E, 0x00A3, 0x00A5, 0x00B7, 0x00A9, 0x00A7, 0x00B6, 0x00BC, 0x00BD, 0x00BE, 0x005B, 0x005D, 0x00AF, 0x00A8, 0x00B4, 0x00D7, 0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x00AD, 0x00F4, 0x00F6, 0x00F2, 0x00F3, 0x00F5, 0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x00B9, 0x00FB, 0x00FC, 0x00F9, 0x00FA, 0x00FF, 0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x00B2, 0x00D4, 0x00D6, 0x00D2, 0x00D3, 0x00D5, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x00B3, 0x00DB, 0x00DC, 0x00D9, 0x00DA, 0x009F }; /* Other proprietary 8-bit sets */ struct x_to_unicode u_decmcs = { 96, 32, X2U_DEC|X2U_STD, AL_ROMAN, "DEC Multinational", "dec-mcs", 0, "%5", 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0xfffd, 0x00A5, 0xfffd, 0x00A7, 0x00A4, 0x00A9, 0x00AA, 0x00AB, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0xfffd, 0x00B5, 0x00B6, 0x00B7, 0xfffd, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0xfffd, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0xfffd, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0152, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0xfffd, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0xfffd, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0153, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0xfffd, 0x00FF }; struct x_to_unicode u_hproman8 = { 96, 32, X2U_STD, AL_ROMAN, "Hewlett Packard Roman 8", "hp-roman8", 0, NULL, 0x00a0, 0x00c0, 0x00c2, 0x00c8, 0x00ca, 0x00cb, 0x00ce, 0x00cf, 0x00b4, 0x00a6, 0x00a9, 0x00a8, 0x00ac, 0x00d9, 0x00db, 0x20a4, 0x00af, 0x00dd, 0x00fd, 0x00b0, 0x00c7, 0x00e7, 0x00d1, 0x00f1, 0x00a1, 0x00bf, 0x00a4, 0x00a3, 0x00a5, 0x00a7, 0x0192, 0x00a2, 0x00e2, 0x00ea, 0x00f4, 0x00fb, 0x00e1, 0x00e9, 0x00f3, 0x00fa, 0x00e0, 0x00e8, 0x00f2, 0x00f9, 0x00e4, 0x00eb, 0x00f6, 0x00fc, 0x00c5, 0x00ee, 0x00d8, 0x00c6, 0x00e5, 0x00ed, 0x00f8, 0x00e6, 0x00c4, 0x00ec, 0x00d6, 0x00dc, 0x00c9, 0x00ef, 0x00df, 0x00d4, 0x00c1, 0x00c3, 0x00e3, 0x00d0, 0x00f0, 0x00cd, 0x00cc, 0x00d3, 0x00d2, 0x00d5, 0x00f5, 0x0160, 0x0161, 0x00da, 0x00b8, 0x00ff, 0x00de, 0x00fe, 0x00b7, 0x00b5, 0x00b6, 0x00be, 0x2015, 0x00bc, 0x00bd, 0x00aa, 0x00ba, 0x00ab, 0x2588, 0x00bb, 0x00b1, 0xfffd }; struct x_to_unicode u_dgi = { 96,32,X2U_STD,AL_ROMAN,"Data General International","dg-international",0,NULL, 0x00a0, 0x00ac, 0x00bd, 0x00b5, 0x00b2, 0x00b3, 0x00a4, 0x00a2, 0x00a3, 0x00aa, 0x00ba, 0x00a1, 0x00bf, 0x00a9, 0x00ae, 0x2021, 0x00bb, 0x00ab, 0x00b6, 0x2122, 0x0192, 0x00a5, 0x00b1, 0x2264, 0x2265, 0x00b7, 0x00b8, 0x00a7, 0x00b0, 0x00a8, 0x00b4, 0x2191, 0x00c1, 0x00c0, 0x00c2, 0x00c4, 0x00c3, 0x00c5, 0x00c6, 0x00c7, 0x00c9, 0x00c8, 0x00ca, 0x00cb, 0x00cd, 0x00cc, 0x00ce, 0x00cf, 0x00d1, 0x00d3, 0x00d2, 0x00d4, 0x00d6, 0x00d5, 0x00d8, 0x0276, 0x00da, 0x00d9, 0x00db, 0x00dc, 0xfffd, 0x0178, 0xfffd, 0xfffd, 0x00e1, 0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e6, 0x00e7, 0x00e9, 0x00e8, 0x00ea, 0x00eb, 0x00ed, 0x00ec, 0x00ee, 0x00ef, 0x00f1, 0x00f3, 0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00f8, 0x0153, 0x00fa, 0x00f9, 0x00fb, 0x00fc, 0x00df, 0x00ff, 0xfffd, 0x2588 }; struct x_to_unicode u_nextstep = { 128, 0, 0, AL_ROMAN,"NeXTSTEP Multinational","next-multinational",0,NULL, 0x00a0, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00b5, 0x00d7, 0x00f7, 0x00a9, 0x00a1, 0x00a2, 0x00a3, 0x2044, 0x00a5, 0x0192, 0x00a7, 0x00a4, 0x2019, 0x201c, 0x00ab, 0x2039, 0x203a, 0xfb01, 0xfb02, 0x00ae, 0x2013, 0x2020, 0x2021, 0x00b7, 0x00a6, 0x00b6, 0x2022, 0x201a, 0x201e, 0x201d, 0x00bb, 0x2026, 0x2030, 0x00ac, 0x00bf, 0x00b9, 0x02cb, 0x00b4, 0x02c6, 0x02dc, 0x00af, 0x02d8, 0x02d9, 0x00a8, 0x00b2, 0x02da, 0x00b8, 0x00b3, 0x02dd, 0x02db, 0x02c7, 0x2014, 0x00b1, 0x00bc, 0x00bd, 0x00be, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00c6, 0x00ed, 0x00aa, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x0141, 0x00d8, 0x0152, 0x00ba, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00e6, 0x00f9, 0x00fa, 0x00fb, 0x0131, 0x00fc, 0x00fd, 0x0142, 0x00f8, 0x0153, 0x00df, 0x00fe, 0x00ff, 0xfffd, 0xfffd }; struct x_to_unicode u_maclatin = { 128, 0, 0, AL_ROMAN,"Macintosh Latin","maclatin", 0, NULL, 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, 0x00DD, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8, 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x2126, 0x00E6, 0x00F8, 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, 0x00FF, 0x0178, 0x2044, 0x00A4, 0x00D0, 0x00F0, 0x00DE, 0x00FE, 0x00FD, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7 }; struct x_to_unicode u_quickdraw = { 128, 0, 0, AL_ROMAN,"QuickDraw","quickdraw", 0, NULL, 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8, 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8, 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, 0x00FF, 0x0178, 0x2044, 0x00A4, 0x2039, 0x203A, 0xFB01, 0xFB02, 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7 }; /* DEC special graphics / technical sets for VT emulation */ #ifdef KERMITFONT struct x_to_unicode u_dectech = { 94, 33, X2U_DEC|X2U_STD,AL_ROMAN,"DEC Technical", "dec-technical", 0, ">", 0xE400, 0x250c, 0x2500, 0x2320, 0x2321, 0x2502, 0xE204, 0xE203, 0xE209, 0xE208, 0xE202, 0xE201, 0xE207, 0xE206, 0xE200, 0xE205, 0xE20D, 0xE20C, 0x2572, 0x2571, 0xE20E, 0xE20F, 0x232a, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2264, 0x2260, 0x2265, 0x222b, 0x2234, 0x221d, 0x221e, 0x00f7, 0x2206, 0x2207, 0x03a6, 0x0393, 0x223c, 0x2243, 0x0398, 0x00d7, 0x039b, 0x21d4, 0x21d2, 0x2261, 0x220f, 0x03a8, 0xE401, 0x03a3, 0xFFFD, 0xfffd, 0x221a, 0x03a9, 0x039e, 0x03d2, 0x2282, 0x2283, 0x2229, 0x222a, 0x2227, 0x2228, 0x00ac, 0x03b1, 0x03b2, 0x03c7, 0x03b4, 0x03b5, 0x03c6, 0x03b3, 0x03b7, 0x03b9, 0x03b8, 0x03ba, 0x03bb, 0xFFFD, 0x03bd, 0x2202, 0x03c0, 0x03c8, 0x03c1, 0x03c3, 0x03c4, 0xFFFD, 0x0192, 0x03c9, 0x03be, 0x03c5, 0x03b6, 0x2190, 0x2191, 0x2192, 0x2193 }; #else struct x_to_unicode u_dectech = { 94, 33, X2U_DEC|X2U_STD,AL_ROMAN,"DEC Technical", "dec-technical", 0, ">", 0x221a, 0x250c, 0x2500, 0x2320, 0x2321, 0x2502, 0x2308, /* 21-27 */ 0x230a, 0x2309, 0x230b, 0x256d, 0x2570, 0x256e, 0x256f, 0x2525, /* 28-2f */ 0x251d, 0x2211, 0x2211, 0x2572, 0x2571, 0x231d, 0x231f, 0x232a, /* 30-37 */ 0x005b, 0x2022, 0x005d, 0x00b1, 0x2264, 0x2260, 0x2265, 0x222b, /* 38-3f */ 0x2234, 0x221d, 0x221e, 0x00f7, 0x25b3, 0x25bd, 0x03a6, 0x0393, /* 40-47 */ 0x223c, 0x2243, 0x0398, 0x00d7, 0x039b, 0x21d4, 0x21d2, 0x2261, /* 48-4f */ 0x220f, 0x03a8, 0x2218, 0x2211, 0x00a7, 0x00b6, 0x221a, 0x03a9, /* 50-57 */ 0x039e, 0x03d2, 0x2282, 0x2283, 0x2229, 0x222a, 0x2227, 0x2228, /* 58-5f */ 0x00ac, 0x03b1, 0x03b2, 0x03c7, 0x03b4, 0x03b5, 0x03c6, 0x03b3, /* 60-67 */ 0x03b7, 0x03b9, 0x03b8, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x2202, /* 68-6f */ 0x03c0, 0x03c8, 0x03c1, 0x03c3, 0x03c4, 0x0020, 0x0192, 0x03c9, /* 70-77 */ 0x03be, 0x03c5, 0x03b6, 0x2190, 0x2191, 0x2192, 0x2193 /* 78-7e */ }; #endif /* KERMITFONT */ #ifdef KERMITFONT struct x_to_unicode u_decspec = { 94,33,X2U_DEC|X2U_STD,AL_ROMAN,"DEC Special Graphics","dec-special",0,"0", 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x2666, 0x2591, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23BA, 0x23BB, 0x2500, 0x23BC, 0x23BD, 0x251c, 0x2524, 0x2534, 0x252c, 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00B7 }; #else struct x_to_unicode u_decspec = { 94,33,X2U_DEC|X2U_STD,AL_ROMAN,"DEC Special Graphics","dec-special",0,"0", 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x2666, 0x2591, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x2594, 0x2500, 0x2500, 0x2500, 0x2500, 0x251c, 0x2524, 0x2534, 0x252c, 0x2502, 0x2264, 0x2265, 0x03a0, 0x2260, 0x00a3, 0x00B7 }; #endif /* KERMITFONT */ /* Hazeltine 1500/1520 graphic set. Includes several approximations: . (0,9) should be heavy black right arrow. Unicode has one of these at U+27A1 but... . (3,9) should be heavy black down arrow; Unicode doesn't have one. So we use the white versions of the heavy arrows instead. . (1,9) the letters "Pe" in one cell, doesn't exist in Unicode. Substitution is just "P". */ struct x_to_unicode u_hz1500 = { 94,33,X2U_STD,AL_ROMAN,"Hazeltime Graphics","hz1500-graphics",0,"0", /* 0 1 2 3 4 5 6 7 */ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, /* 0 */ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, /* 1 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, /* 2 */ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, /* 3 */ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, /* 4 */ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, /* 5 */ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, /* 6 */ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, /* 7 */ 0x2500, 0x2502, 0x253c, 0x2534, 0x252c, 0x2514, 0x250c, 0x00b1, /* 8 */ 0x21e8, 0x0050, 0x00f7, 0x21e9, 0x2510, 0x2518, 0x251c, 0x2524, /* 9 */ 0x0070, 0x0071, 0x0072, 0x250c, 0x0074, 0x0075, 0x0076, 0x0077, /* a */ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e /* b */ }; #ifdef KERMITFONT struct x_to_unicode u_heath19g = { 94,33,X2U_STD,AL_ROMAN,"Heath-19 Special Graphics","h19-special",0,NULL, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x25cf, 0xe30b, 0x2502, 0x2500, 0x253c, 0x2510, 0x2518, 0x2514, 0x250c, 0x00b1, 0x2192, 0x2592, 0x00f7, 0x2193, 0xe321, 0xe320, 0xe322, 0xe328, 0x2580, 0xe325, 0xe30a, 0x252c, 0x2524, 0x2534, 0x251c, 0x2573, 0x2571, 0x2572, 0xe311, 0xe319, 0xe300, 0xe309, 0x00b6 }; #else struct x_to_unicode u_heath19g = { 94,33,X2U_STD,AL_ROMAN,"Heath-19 Special Graphics","h19-special",0,NULL, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x25cf, 0x25e5, 0x2502, 0x2500, 0x253c, 0x2510, 0x2518, 0x2514, 0x250c, 0x00b1, 0x2192, 0x2592, 0x00f7, 0x2193, 0x2590, 0x258c, 0x258c, 0x2590, 0x2580, 0x2590, 0x25e4, 0x252c, 0x2524, 0x2534, 0x251c, 0x2573, 0x2571, 0x2572, 0x2500, 0x2500, 0x2502, 0x2502, 0x00b6 }; #endif /* KERMITFONT */ /* DG Graphic sets - "KERMITFONT" these later... */ /* Missing, backwards question mark eighth note "DT" control pic horizontal scan lines */ struct x_to_unicode u_dgspec = { /* Needs to be checked */ 94, 33, X2U_STD,AL_ROMAN,"DG Special Graphics","dg-specialgraphics",0,NULL, 0xfffd, 0xfffd, 0x2424, 0x2594, 0x2594, 0x2581, 0x2581, 0x25a1, 0x263a, 0x263b, 0x2665, 0x2663, 0x2660, 0x25cf, 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266c, 0x263c, 0x2195, 0x2583, 0x21a8, 0x231e, 0x2194, 0x2207, 0x00ff, 0x20a7, 0x00aa, 0x00ba, 0x231c, 0x231d, 0x2591, 0x2591, 0x2593, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x0393, 0x03c0, 0x03a3, 0x03a6, 0x0398, 0x03d5, 0x03b5, 0x03a0, 0x039e, 0x00b7, 0x03b7, 0x25a0, 0x0178, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd }; /* Missing: arrow-to-line, various orientations */ struct x_to_unicode u_dgline = { 94, 33, X2U_STD,AL_ROMAN,"DG Line Drawing","dg-linedrawing",0,NULL, 0x250c, 0x2510, 0x2514, 0x2518, 0x252c, 0x2524, 0x251c, 0x2534, 0x253c, 0x2502, 0x2500, 0x219f, 0x21e5, 0x21e4, 0x21a1, 0x2506, 0x250f, 0x2513, 0x2517, 0x251b, 0x2533, 0x252b, 0x2523, 0x253b, 0x254b, 0x2503, 0x2501, 0x2504, 0x00f7, 0x00a2, 0x2122, 0x00ae, 0x00a9, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd }; struct x_to_unicode u_dgword = { 94, 33, X2U_STD,AL_ROMAN,"DG Word Processing","dg-wordprocessing",0,NULL, 0x2308, 0x230a, 0x2309, 0x230b, 0x0192, 0x223c, 0x2202, 0xfffd, 0xfffd, 0x2320, 0x2321, 0x221a, 0xfffd, 0x221e, 0x221d, 0x2070, 0x00b9, 0x00b2, 0x00b3, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x2260, 0xfffd, 0x21ef, 0xfffd, 0x21e5, 0x00b7, 0x203c, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03a9, 0x0394, 0x00b6, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x22a6, 0x25c6, 0x25b6, 0x25b7, 0x25c0, 0x25b2, 0x25bc, 0x2327, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x25e3, 0x25e2, 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0xfffd, 0x2191, 0x2192, 0x2190, 0x2193 }; /* HP Graphic sets - "KERMITFONT" these later... */ /* Many are missing from Unicode, Single-to-triple-line box-drawing characters. Double/double cross & some others. */ struct x_to_unicode u_hpline = { /* Needs to be checked */ 94, 33, X2U_STD,AL_ROMAN,"HP Line Drawing Graphics", "hp-line-drawing",0,NULL, 0x2520, 0x2528, 0x252f, 0x2537, 0x255f, 0x2562, 0x2564, 0x2567, 0x2551, 0x2542, 0x253f, 0x2550, 0x230a, 0x2502, 0x253c, 0x254b, 0x2523, 0x252b, 0x2533, 0x253b, 0x251c, 0x2524, 0x252c, 0x2534, 0x2550, 0x2503, 0x2501, 0x256b, 0x2308, 0x256a, 0x256c, 0x255e, 0x2517, 0x2549, 0x2588, 0x258c, 0x258e, 0x2514, 0x2518, 0x2510, 0x2555, 0x252c, 0x2556, 0x2556, 0x2547, 0x2548, 0x2555, 0x230b, 0x250f, 0x250c, 0x251b, 0x2510, 0x2524, 0x254a, 0x2513, 0x2584, 0x2309, 0x2582, 0x2561, 0x2504, 0x2559, 0x2576, 0x2565, 0x255e, 0x2517, 0x2549, 0x2588, 0x258c, 0x258e, 0x2514, 0x2518, 0x2510, 0x2555, 0x252c, 0x2556, 0x2556, 0x2547, 0x2548, 0x2555, 0x230b, 0x250f, 0x250c, 0x251b, 0x2510, 0x2524, 0x254a, 0x2513, 0x2584, 0x2309, 0x2582, 0x2561, 0x2504, 0x2559, 0x2576 }; struct x_to_unicode u_hpmath = { 94, 33, X2U_STD,AL_ROMAN,"HP Math/Technical","hp-math/technical",0,NULL, 0x221a, 0x2223, 0x00a7, 0x2207, 0x00b1, 0x03b1, 0x2320, 0x00f7, 0x2243, 0x03a0, 0x0393, 0x03c8, 0x2261, 0x03a6, 0x039e, 0x2070, 0x00b9, 0x00b2, 0x00b3, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x03a9, 0x039b, 0x221e, 0x2321, 0x2020, 0x03a3, 0x00b6, 0x03b1, 0x03b2, 0x03c8, 0x03d5, 0x03b5, 0x2202, 0x03bb, 0x03b7, 0x03b9, 0x0398, 0x03ba, 0x03c9, 0x03bc, 0x03bd, 0x03c1, 0x03c0, 0x03b3, 0x03b8, 0x03c3, 0x03c4, 0x03be, 0x0394, 0x03b4, 0x00d7, 0x03c5, 0x03b6, 0x2191, 0x2192, 0x03d2, 0x2190, 0x2193, 0x00b6, 0x03b1, 0x03b2, 0x03c8, 0x03d5, 0x03b5, 0x2202, 0x03bb, 0x03b7, 0x03b9, 0x0398, 0x03ba, 0x03c9, 0x03bc, 0x03bd, 0x03c1, 0x03c0, 0x03b3, 0x03b8, 0x03c3, 0x03c4, 0x03be, 0x0394, 0x03b4, 0x00d7, 0x03c5, 0x03b6, 0x2191, 0x2192, 0x03d2, 0x2190 }; struct x_to_unicode u_tvig = { 15,65,0,0,"Televideo Special Graphics","tvi-special",0,NULL, 0x2570, 0x256D, 0x256E, 0x256F, 0x2514, 0x250C, 0x2510, 0x2518, 0x253C, 0x2502, 0x2500, 0x2524, 0x251C, 0x252C, 0x2534 }; struct x_to_unicode u_wyse_gn = { #ifdef COMMENT 16,16,0,0,"Wyse Normal-Mode Graphics","wy-graphics-normal",0,NULL, 0x252C, 0x2514, 0x250C, 0x2510, 0x251C, 0x2518, 0x2502, 0x2588, 0x253C, 0x2524, 0x2500, 0x2592, 0x2550, 0x2534, 0x2551, 0x2591 #else 80,48,0,0,"Wyse Normal-Mode Graphics","wy-graphics-normal",0,NULL, 0x252C, 0x2514, 0x250C, 0x2510, 0x251C, 0x2518, 0x2502, 0x2588, 0x253C, 0x2524, 0x2500, 0x2592, 0x2550, 0x2534, 0x2551, 0x2591, 0x252C, 0x2514, 0x250C, 0x2510, 0x251C, 0x2518, 0x2502, 0x2588, 0x253C, 0x2524, 0x2500, 0x2592, 0x2550, 0x2534, 0x2551, 0x2591, 0x252C, 0x2514, 0x250C, 0x2510, 0x251C, 0x2518, 0x2502, 0x2588, 0x253C, 0x2524, 0x2500, 0x2592, 0x2550, 0x2534, 0x2551, 0x2591, 0x252C, 0x2514, 0x250C, 0x2510, 0x251C, 0x2518, 0x2502, 0x2588, 0x253C, 0x2524, 0x2500, 0x2592, 0x2550, 0x2534, 0x2551, 0x2591, 0x252C, 0x2514, 0x250C, 0x2510, 0x251C, 0x2518, 0x2502, 0x2588, 0x253C, 0x2524, 0x2500, 0x2592, 0x2550, 0x2534, 0x2551, 0x2591 #endif /* COMMENT */ }; struct x_to_unicode u_wyse_g1 = { 79,48,0,0,"Wyse Graphics 1","wy-graphics-1",0,NULL, 0x2070, 0x00B9, 0x00B2, 0x00B3, 0x2074, 0x2075, 0x2075, 0x2077, 0x2078, 0x2079, 0xFFFD, 0xFFFD, 0x25BA, 0x25C4, 0x25B2, 0x25BC, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x2518, 0x2510, 0x250C, 0x2514, 0x253C, 0x258C, 0x2590, 0x2500, 0x2584, 0x2580, 0x251C, 0x2524, 0x2534, 0x252C, 0x2502, 0xFFFD, 0x256E, 0x256F, 0x2570, 0x256D, 0x258C }; struct x_to_unicode u_wyse_g2 = { 41,64,0,0,"Wyse Graphics 2","wy-graphics-2",0,NULL, 0x250C, 0xFFFD, 0xFFFD, 0xFFFD, 0x2510, 0xFFFD, 0xFFFD, 0xFFFD, 0x2514, 0xFFFD, 0xFFFD, 0xFFFD, 0x2518, 0xFFFD, 0xFFFD, 0xFFFD, 0x252C, 0xFFFD, 0xFFFD, 0xFFFD, 0x2524, 0xFFFD, 0xFFFD, 0xFFFD, 0x251C, 0xFFFD, 0xFFFD, 0xFFFD, 0x2534, 0xFFFD, 0xFFFD, 0xFFFD, 0x2500, 0xFFFD, 0xFFFD, 0xFFFD, 0x2502, 0xFFFD, 0xFFFD, 0xFFFD, 0x253C }; #ifdef KERMITFONT struct x_to_unicode u_wyse_g3 = { 31,65,0,0,"Wyse Graphics 3","wy-graphics-3",0,NULL, 0x2570, 0x256D, 0x256E, 0x256F, 0x2514, 0x250C, 0x2510, 0x2518, 0x253C, 0x2502, 0x2500, 0x2524, 0x251C, 0x252C, 0x2534, 0x23BA, 0x23BD, 0x2666, 0xE328, 0xE321, 0xE320, 0xE322, 0x2590, 0x2584, 0x258C, 0x2580, 0xE323, 0xE326, 0xE327, 0xE329, 0x258C }; #else struct x_to_unicode u_wyse_g3 = { 31,65,0,0,"Wyse Graphics 3","wy-graphics-3",0,NULL, 0x2570, 0x256D, 0x256E, 0x256F, 0x2514, 0x250C, 0x2510, 0x2518, 0x253C, 0x2502, 0x2500, 0x2524, 0x251C, 0x252C, 0x2534, 0x2500, 0x2500, 0x2666, 0x2590, 0x2590, 0x258c, 0x258c, 0x2590, 0x2584, 0x258C, 0x2580, 0x2588, 0x2588, 0x2588, 0x2588, 0x258C }; #endif /* KERMITFONT */ /* QNX Console -- This is exactly the same as CP437 except for the code point at 0xEE (epsilon vs element-of), which I think was just a mistake in reading glyphs by the QNX people, but who knows. Also the glyph at 0xED might be a fi (as it is in CP437, and as I have it here) or it might be a null-set symbol. */ struct x_to_unicode u_qnxgrph = { 128,0,0,0,"QNX Console","qnx-console",0,NULL, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, /* 128 */ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, /* 136 */ 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, /* 144 */ 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, /* 152 */ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, /* 160 */ 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, /* 168 */ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, /* 176 */ 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, /* 184 */ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, /* 192 */ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, /* 200 */ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, /* 208 */ 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, /* 216 */ 0x221d, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, /* 224 */ 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x2208, 0x2229, /* 232 */ 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, /* 240 */ 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25ae, 0x00a0 /* 248 */ }; struct x_to_unicode u_snibrack = { 94, 33, 0, 0,"Siemens Nixdorf 97801 Brackets","sni-brackets",0,"w", 0x2590, 0x258c, 0x2584, 0x2580, 0x2590, 0x258c, 0x2584, /* a0-7 */ 0x2580, 0x2329, 0x2327, 0x25af, 0x00b7, 0x25b9, 0x25c1, 0x003c, /* a8-f */ 0x253b, 0x2533, 0x2523, 0x252b, 0x2329, 0x232a, 0x2304, 0x2303, /* b0-7 */ 0x25e4, 0x25e5, 0x25e3, 0x25e2, 0x253f, 0x231b, 0x25cf, 0x25cb, /* b8-f */ 0x2502, 0x2500, 0x250c, 0x2510, 0x2514, 0x2518, 0x251c, 0x2524, /* c0-7 */ 0x252c, 0x2534, 0x253c, 0x2192, 0x2190, 0x2191, 0x2193, 0x2575, /* c8-f */ 0x2577, 0x25d4, 0x256d, 0x256e, 0x2570, 0x256f, 0x251c, 0x2524, /* d0-7 */ 0x252c, 0x2534, 0x253c, 0x253c, 0x2592, 0x2591, 0x2592, 0x2593, /* d8-f */ 0x2503, 0x2501, 0x250f, 0x2513, 0x2517, 0x251b, 0x2523, 0x252b, /* e0-7 */ 0x2533, 0x253b, 0x254b, 0x279e, 0x2190, 0x2191, 0x2193, 0x2579, /* e8-f */ 0x257b, 0x2261, 0x2554, 0x2557, 0x255a, 0x255d, 0x2523, 0x252b, /* f0-7 */ 0x2533, 0x253b, 0x254b, 0x254b, 0x0393, 0x03c3, 0x03c4 /* f8-f */ }; struct x_to_unicode u_sniblanks = { 94, 33, 0, 0,"Siemens Nixdorf 97801 Blanks","sni-blanks",0,"y", 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* a0-7 */ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* a8-f */ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* b0-7 */ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* b8-f */ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* c0-7 */ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* c8-f */ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* d0-7 */ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* d8-f */ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* e0-7 */ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* e8-f */ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, /* f0-7 */ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 /* f8-f */ }; struct x_to_unicode u_snifacet = { 94, 33, 0, 0,"Siemens Nixdorf 97801 Facet","sni-facet",0,"c", 0x0020, 0x2581, 0x2582, 0x2583, 0x2584, 0x2585, 0x2587, /* a1-a7 */ 0x005f, 0x2581, 0x2582, 0x2583, 0x2584, 0x2585, 0x2586, 0x2587, /* a8-af */ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* b0-b7 */ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* b8-bf */ 0x2503, 0x2501, 0x250f, 0x2513, 0x2517, 0x251b, 0x2523, 0x252b, /* c0-c7 */ 0x2533, 0x253b, 0x254b, 0x258f, 0x2595, 0xfffd, 0xfffd, 0xfffd, /* c8-cf */ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* d0-d7 */ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2591, 0x2591, 0x2588, /* d8-df */ 0x2503, 0x2501, 0x250f, 0x2513, 0x2517, 0x251b, 0x2523, 0x252b, /* e0-e7 */ 0x2533, 0x253b, 0x254b, 0xfffd, 0xfffd, 0x2593, 0x2593, 0x0020, /* e8-ef */ 0x2585, 0x2586, 0x2587, 0x2588, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* f0-f7 */ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2594, 0x2594, 0xfffd /* f8-fe */ }; struct x_to_unicode u_sniibm = { 94, 33, 0, 0,"Siemens Nixdorf 97801 IBM","sni-ibm",0,"v", 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x25cf, 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c, 0x25ba, 0x25c4, 0x2195, 0x203c, 0x00b6, 0x25c1, 0x2582, 0x21a8, 0x2191, 0x2193, 0x2192, 0x2190, 0x2319, 0x2194, 0x25b4, 0x25be, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* Hex */ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, /* bytes */ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2070, 0x00b9, 0x00b2, 0x00b3, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207b, 0x207a, 0xfffd, 0xfffd, 0x2320, 0x2321, 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208b, 0x208a, 0x221e, 0x03b1, 0x03a6 }; struct x_to_unicode u_snieuro = { 94, 33, 0, 0,"Siemens Nixdorf 97801 Euro","sni-euro",0,"u", 0x00e0, 0x00e1, 0x00e2, 0x00e4, 0x00e5, 0x0105, 0x00e3, 0x0103, 0x00e6, 0x00e7, 0x010d, 0x0107, 0x00f0, 0x0111, 0x010f, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x011b, 0x0119, 0x011f, 0x0131, 0x00ee, 0x00ec, 0x01d0, 0x00ef, 0x0133, 0x013a, 0x0142, 0x013e, 0x0148, 0x0144, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f6, 0x00f5, 0x00f8, 0x0151, 0x0153, 0x00fe, 0x0159, 0x0155, 0x0161, 0x015b, 0x015f, 0x00df, 0x0163, 0x0165, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x016f, 0x0171, 0x00fd, 0x00ff, 0x017e, 0x017a, 0x017c, 0x00c9, 0x00c5, 0x00c6, 0x00d0, 0x0130, 0x0132, 0x0167, 0x00d8, 0x0152, 0x00de, 0x00c4, 0x00d6, 0x00dc, 0x00a7, 0x0024, 0x00a3, 0x00ae, 0x00a9, 0x03a9, 0x00b5, 0x00b0, 0x00c7, 0x20a7, 0x03c0, 0x02d8, 0x00b4, 0x02dd, 0x00d1, 0x2514, 0x2518, 0x007e, 0x02c7 }; struct x_to_unicode u_smiley = { 32,0,X2U_CXG,0,"PC C0 Graphics","smiley-faces",0,NULL, 0x00a0, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25d8, 0x25ef, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266c, 0x263c, 0x25ba, 0x25c4, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8, 0x2191, 0x2193, 0x2192, 0x2190, 0x2319, 0x2194, 0x25b2, 0x25bc }; struct x_to_unicode u_c0pics = { 128,0,X2U_CXG,0,"C0/C1 Display Controls","display-controls",0,NULL, 0x2400, 0x2401, 0x2402, 0x2403, 0x2404, 0x2405, 0x2406, 0x2407, 0x2408, 0x2409, 0x240a, 0x240b, 0x240c, 0x240d, 0x240e, 0x240f, 0x2410, 0x2411, 0x2412, 0x2413, 0x2414, 0x2415, 0x2416, 0x2417, 0x2418, 0x2419, 0x241a, 0x241b, 0x241c, 0x241d, 0x241e, 0x241f, 0x2420, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x2421 }; #ifdef KERMITFONT struct x_to_unicode u_c1pics = { 32,0,X2U_CXG,0,"C1 Display Controls","c1-display-controls",0,NULL, 0xe080, 0xe081, 0xe082, 0xe083, 0xe084, 0xe085, 0xe086, 0xe087, 0xe088, 0xe089, 0xe08a, 0xe08b, 0xe08c, 0xe08d, 0xe08e, 0xe08f, 0xe090, 0xe091, 0xe092, 0xe093, 0xe094, 0xe095, 0xe096, 0xe097, 0xe098, 0xe099, 0xe09a, 0xe09b, 0xe09c, 0xe09d, 0xe09e, 0xe09f }; #else struct x_to_unicode u_c1pics = { 32,0,X2U_CXG,0,"C1 Display Controls","c1-display-controls",0,NULL, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd }; #endif /* KERMITFONT */ /* Blah-to-Unicode functions */ USHORT #ifdef CK_ANSIC ascii_u(CHAR c) #else ascii_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); /* NOTE: Strict ANSI compilers complain about "<" and similar comparisons between unsigned and signed quantities, as found in all the routines of the "blah_u()" class -- casts must be added to squelch the warnings. */ if (c < u_ascii.offset) return(c); else if (c >= u_ascii.offset + u_ascii.size) return(c); else return(u_ascii.map[c - u_ascii.offset]); } USHORT #ifdef CK_ANSIC british_u(CHAR c) #else british_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_british.offset) return(c); else if (c >= u_british.offset + u_british.size) return(c); else return(u_british.map[c - u_british.offset]); } USHORT #ifdef CK_ANSIC dutch_u(CHAR c) #else dutch_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_dutch.offset) return(c); else if (c >= u_dutch.offset + u_dutch.size) return(c); else return(u_dutch.map[c - u_dutch.offset]); } USHORT #ifdef CK_ANSIC finnish_u(CHAR c) #else finnish_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_finnish.offset) return(c); else if (c >= u_finnish.offset + u_finnish.size) return(c); else return(u_finnish.map[c - u_finnish.offset]); } USHORT #ifdef CK_ANSIC french_u(CHAR c) #else french_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_french.offset) return(c); else if (c >= u_french.offset + u_french.size) return(c); else return(u_french.map[c - u_french.offset]); } USHORT #ifdef CK_ANSIC fr_canadian_u(CHAR c) #else fr_canadian_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_fr_canadian.offset) return(c); else if (c >= u_fr_canadian.offset + u_fr_canadian.size) return(c); else return(u_fr_canadian.map[c - u_fr_canadian.offset]); } USHORT #ifdef CK_ANSIC german_u(CHAR c) #else german_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_german.offset) return(c); else if (c >= u_german.offset + u_german.size) return(c); else return(u_german.map[c - u_german.offset]); } USHORT #ifdef CK_ANSIC hungarian_u(CHAR c) #else hungarian_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_hungarian.offset) return(c); else if (c >= u_hungarian.offset + u_hungarian.size) return(c); else return(u_hungarian.map[c - u_hungarian.offset]); } USHORT #ifdef CK_ANSIC italian_u(CHAR c) #else italian_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_italian.offset) return(c); else if (c >= u_italian.offset + u_italian.size) return(c); else return(u_italian.map[c - u_italian.offset]); } USHORT #ifdef CK_ANSIC icelandic_u(CHAR c) #else icelandic_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_icelandic.offset) return(c); else if (c >= u_icelandic.offset + u_icelandic.size) return(c); else return(u_icelandic.map[c - u_icelandic.offset]); } USHORT #ifdef CK_ANSIC jis0201r_u(CHAR c) #else jis0201r_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_jis0201r.offset) return(c); else if (c >= u_jis0201r.offset + u_jis0201r.size) return(c); else return(u_jis0201r.map[c - u_jis0201r.offset]); } USHORT #ifdef CK_ANSIC jis0201k_u(CHAR c) #else jis0201k_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_jis0201k.offset) return(c); else if (c >= u_jis0201k.offset + u_jis0201k.size) return(c); else return(u_jis0201k.map[c - u_jis0201k.offset]); } USHORT #ifdef CK_ANSIC norwegian_u(CHAR c) #else norwegian_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_norwegian.offset) return(c); else if (c >= u_norwegian.offset + u_norwegian.size) return(c); else return(u_norwegian.map[c - u_norwegian.offset]); } USHORT #ifdef CK_ANSIC danish_u(CHAR c) #else danish_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_danish.offset) return(c); else if (c >= u_danish.offset + u_danish.size) return(c); else return(u_danish.map[c - u_danish.offset]); } USHORT #ifdef CK_ANSIC portuguese_u(CHAR c) #else portuguese_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_portuguese.offset) return(c); else if (c >= u_portuguese.offset + u_portuguese.size) return(c); else return(u_portuguese.map[c - u_portuguese.offset]); } USHORT #ifdef CK_ANSIC spanish_u(CHAR c) #else spanish_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_spanish.offset) return(c); else if (c >= u_spanish.offset + u_spanish.size) return(c); else return(u_spanish.map[c - u_spanish.offset]); } USHORT #ifdef CK_ANSIC swedish_u(CHAR c) #else swedish_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_swedish.offset) return(c); else if (c >= u_swedish.offset + u_swedish.size) return(c); else return(u_swedish.map[c - u_swedish.offset]); } USHORT #ifdef CK_ANSIC swiss_u(CHAR c) #else swiss_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_swiss.offset) return(c); else if (c >= u_swiss.offset + u_swiss.size) return(c); else return(u_swiss.map[c - u_swiss.offset]); } USHORT #ifdef CK_ANSIC apl1_u(CHAR c) #else apl1_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_apl1.offset) return(c); else if (c >= u_apl1.offset + u_apl1.size) return(c); else return(u_apl1.map[c - u_apl1.offset]); } USHORT #ifdef CK_ANSIC ident_u(CHAR c) #else /* CK_ANSIC */ ident_u(c) CHAR c; #endif /* CK_ANSIC */ { return((USHORT)c); } USHORT #ifdef CK_ANSIC iso_8859_1_u(CHAR c) #else iso_8859_1_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_8859_1.offset) return(c); else if (c >= u_8859_1.offset + u_8859_1.size) return(c); else return(u_8859_1.map[c - u_8859_1.offset]); } USHORT #ifdef CK_ANSIC iso_8859_2_u(CHAR c) #else iso_8859_2_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_8859_2.offset) return(c); else if (c >= u_8859_2.offset + u_8859_2.size) return(c); else return(u_8859_2.map[c - u_8859_2.offset]); } USHORT #ifdef CK_ANSIC iso_8859_3_u(CHAR c) #else iso_8859_3_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_8859_3.offset) return(c); else if (c >= u_8859_3.offset + u_8859_3.size) return(c); else return(u_8859_3.map[c - u_8859_3.offset]); } USHORT #ifdef CK_ANSIC iso_8859_4_u(CHAR c) #else iso_8859_4_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_8859_4.offset) return(c); else if (c >= u_8859_4.offset + u_8859_4.size) return(c); else return(u_8859_4.map[c - u_8859_4.offset]); } USHORT #ifdef CK_ANSIC iso_8859_5_u(CHAR c) #else iso_8859_5_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_8859_5.offset) return(c); else if (c >= u_8859_5.offset + u_8859_5.size) return(c); else return(u_8859_5.map[c - u_8859_5.offset]); } USHORT #ifdef CK_ANSIC koi8_u(CHAR c) #else koi8_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_koi8.offset) return(c); else if (c >= u_koi8.offset + u_koi8.size) return(c); else return(u_koi8.map[c - u_koi8.offset]); } USHORT #ifdef CK_ANSIC koi8r_u(CHAR c) /* KOI8-R to Unicode */ #else koi8r_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_koi8r.offset) return(c); else if (c >= u_koi8r.offset + u_koi8r.size) return(c); else return(u_koi8r.map[c - u_koi8r.offset]); } USHORT #ifdef CK_ANSIC koi8u_u(CHAR c) #else koi8u_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_koi8u.offset) return(c); else if (c >= u_koi8u.offset + u_koi8u.size) return(c); else return(u_koi8u.map[c - u_koi8u.offset]); } USHORT #ifdef CK_ANSIC iso_8859_6_u(CHAR c) #else iso_8859_6_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_8859_6.offset) return(c); else if (c >= u_8859_6.offset + u_8859_6.size) return(c); else return(u_8859_6.map[c - u_8859_6.offset]); } USHORT #ifdef CK_ANSIC iso_8859_7_u(CHAR c) #else iso_8859_7_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_8859_7.offset) return(c); else if (c >= u_8859_7.offset + u_8859_7.size) return(c); else return(u_8859_7.map[c - u_8859_7.offset]); } USHORT #ifdef CK_ANSIC iso_8859_8_u(CHAR c) #else iso_8859_8_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_8859_8.offset) return(c); else if (c >= u_8859_8.offset + u_8859_8.size) return(c); else return(u_8859_8.map[c - u_8859_8.offset]); } USHORT #ifdef CK_ANSIC hebrew7_u(CHAR c) #else hebrew7_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_hebrew7.offset) return(c); else if (c >= u_hebrew7.offset + u_hebrew7.size) return(c); else return(u_hebrew7.map[c - u_hebrew7.offset]); } USHORT #ifdef CK_ANSIC elot927_u(CHAR c) #else elot927_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_elot927.offset) return(c); else if (c >= u_elot927.offset + u_elot927.size) return(c); else return(u_elot927.map[c - u_elot927.offset]); } USHORT #ifdef CK_ANSIC iso_8859_9_u(CHAR c) #else iso_8859_9_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_8859_9.offset) return(c); else if (c >= u_8859_9.offset + u_8859_9.size) return(c); else return(u_8859_9.map[c - u_8859_9.offset]); } USHORT #ifdef CK_ANSIC iso_8859_10_u(CHAR c) #else iso_8859_10_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_8859_10.offset) return(c); else if (c >= u_8859_10.offset + u_8859_10.size) return(c); else return(u_8859_10.map[c - u_8859_10.offset]); } USHORT #ifdef CK_ANSIC iso_8859_15_u(CHAR c) #else iso_8859_15_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_8859_15.offset) return(c); else if (c >= u_8859_15.offset + u_8859_15.size) return(c); else return(u_8859_15.map[c - u_8859_15.offset]); } USHORT #ifdef CK_ANSIC apl2_u(CHAR c) #else apl2_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_apl2.offset) return(c); else if (c >= u_apl2.offset + u_apl2.size) return(c); else return(u_apl2.map[c - u_apl2.offset]); } USHORT #ifdef CK_ANSIC apl3_u(CHAR c) #else apl3_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_apl3.offset) return(c); else if (c >= u_apl3.offset + u_apl3.size) return(c); else return(u_apl3.map[c - u_apl3.offset]); } USHORT #ifdef CK_ANSIC apl4_u(CHAR c) #else apl4_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_apl4.offset) return(c); else if (c >= u_apl4.offset + u_apl4.size) return(c); else return(u_apl4.map[c - u_apl4.offset]); } USHORT #ifdef CK_ANSIC apl5_u(CHAR c) #else apl5_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_apl5.offset) return(c); else if (c >= u_apl5.offset + u_apl5.size) return(c); else return(u_apl5.map[c - u_apl5.offset]); } USHORT #ifdef CK_ANSIC koi7_u(CHAR c) #else koi7_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c & 0x80) return(UNK); if (c < u_koi7.offset) return(c); else if (c >= u_koi7.offset + u_koi7.size) return(c); else return(u_koi7.map[c - u_koi7.offset]); } USHORT #ifdef CK_ANSIC decmcs_u(CHAR c) #else decmcs_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); c &= 0x7f; if (c < u_decmcs.offset) return(c); else if (c >= u_decmcs.offset + u_decmcs.size) return(c); else return(u_decmcs.map[c - u_decmcs.offset]); } USHORT #ifdef CK_ANSIC nextstep_u(CHAR c) #else nextstep_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_nextstep.map[(c & 0x7f) - u_nextstep.offset]); } USHORT #ifdef CK_ANSIC dgi_u(CHAR c) #else dgi_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); return(u_dgi.map[(c & 0x7f) - u_dgi.offset]); } USHORT #ifdef CK_ANSIC hproman8_u(CHAR c) #else hproman8_u(c) CHAR c; #endif /* CK_ANSIC */ { if (c >= 0x80 && c < 0xa0) return(c); return(u_hproman8.map[(c & 0x7f) - u_hproman8.offset]); } USHORT #ifdef CK_ANSIC cp37_u(CHAR c) #else cp37_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp37.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp437_u(CHAR c) #else cp437_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp437.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC mazovia_u(CHAR c) /* Mazovia = CP437 with substitutions */ #else mazovia_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_mazovia.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp850_u(CHAR c) #else cp850_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp850.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp858_u(CHAR c) #else cp858_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp858.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp1250_u(CHAR c) #else cp1250_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp1250.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp1251_u(CHAR c) #else cp1251_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp1251.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp1252_u(CHAR c) #else cp1252_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp1252.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp1253_u(CHAR c) #else cp1253_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp1253.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp1254_u(CHAR c) #else cp1254_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp1254.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp1255_u(CHAR c) #else cp1255_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp1255.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp1256_u(CHAR c) #else cp1256_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp1256.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp1257_u(CHAR c) #else cp1257_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp1257.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp1258_u(CHAR c) #else cp1258_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp1258.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp852_u(CHAR c) #else cp852_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp852.map[c & 0x7f]); } USHORT /* Cyrillic */ #ifdef CK_ANSIC cp855_u(CHAR c) #else cp855_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp855.map[c & 0x7f]); } USHORT /* Bulgaria */ #ifdef CK_ANSIC cp856_u(CHAR c) #else cp856_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp856.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp857_u(CHAR c) #else cp857_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp857.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp862_u(CHAR c) #else cp862_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp862.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp864_u(CHAR c) #else cp864_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp864.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp866_u(CHAR c) #else cp866_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp866.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC cp869_u(CHAR c) #else cp869_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_cp869.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC maclatin_u(CHAR c) #else maclatin_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_maclatin.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC quickdraw_u(CHAR c) #else quickdraw_u(c) CHAR c; #endif /* CK_ANSIC */ { return(u_quickdraw.map[c & 0x7f]); } USHORT #ifdef CK_ANSIC decspec_u(CHAR c) #else decspec_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_decspec.offset) return(c); else if (c >= u_decspec.offset + u_decspec.size) return(c); else return (u_decspec.map[c - u_decspec.offset]); } USHORT #ifdef CK_ANSIC dectech_u(CHAR c) #else dectech_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_dectech.offset) return(c); else if (c >= u_dectech.offset + u_dectech.size) return(c); else return(u_dectech.map[c - u_dectech.offset]); } USHORT #ifdef CK_ANSIC dgspec_u(CHAR c) #else dgspec_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_dgspec.offset) return(c); else if (c >= u_dgspec.offset + u_dgspec.size) return(c); else return(u_dgspec.map[c - u_dgspec.offset]); } USHORT #ifdef CK_ANSIC dgline_u(CHAR c) #else dgline_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_dgline.offset) return(c); else if (c >= u_dgline.offset + u_dgline.size) return(c); else return(u_dgline.map[c - u_dgline.offset]); } USHORT #ifdef CK_ANSIC dgword_u(CHAR c) #else dgword_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_dgword.offset) return(c); else if (c >= u_dgword.offset + u_dgword.size) return(c); else return(u_dgword.map[c - u_dgword.offset]); } USHORT #ifdef CK_ANSIC hpline_u(CHAR c) #else hpline_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_hpline.offset) return(c); else if (c >= u_hpline.offset + u_hpline.size) return(c); else return(u_hpline.map[c - u_hpline.offset]); } USHORT #ifdef CK_ANSIC hpmath_u(CHAR c) #else hpmath_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_hpmath.offset) return(c); else if (c >= u_hpmath.offset + u_hpmath.size) return(c); else return(u_hpmath.map[c - u_hpmath.offset]); } USHORT #ifdef CK_ANSIC qnxgrph_u(CHAR c) #else qnxgrph_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_qnxgrph.offset) return(c); else if (c >= u_qnxgrph.offset + u_qnxgrph.size) return(c); else return(u_qnxgrph.map[c - u_qnxgrph.offset]); } USHORT #ifdef CK_ANSIC hz1500_u(CHAR c) #else hz1500_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_hz1500.offset) return(c); else if (c >= u_hz1500.offset + u_hz1500.size) return(c); else return(u_hz1500.map[c - u_hz1500.offset]); } USHORT #ifdef CK_ANSIC sniblanks_u(CHAR c) #else sniblanks_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_sniblanks.offset) return(c); else if (c >= u_sniblanks.offset + u_sniblanks.size) return(c); else return(u_sniblanks.map[c - u_sniblanks.offset]); } USHORT #ifdef CK_ANSIC snibrack_u(CHAR c) #else snibrack_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_snibrack.offset) return(c); else if (c >= u_snibrack.offset + u_snibrack.size) return(c); else return(u_snibrack.map[c - u_snibrack.offset]); } USHORT #ifdef CK_ANSIC snifacet_u(CHAR c) #else snifacet_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_snifacet.offset) return(c); else if (c >= u_snifacet.offset + u_snifacet.size) return(c); else return(u_snifacet.map[c - u_snifacet.offset]); } USHORT #ifdef CK_ANSIC sniibm_u(CHAR c) #else sniibm_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_sniibm.offset) return(c); else if (c >= u_sniibm.offset + u_sniibm.size) return(c); else return(u_sniibm.map[c - u_sniibm.offset]); } USHORT #ifdef CK_ANSIC snieuro_u(CHAR c) #else snieuro_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_snieuro.offset) return(c); else if (c >= u_snieuro.offset + u_snieuro.size) return(c); else return(u_snieuro.map[c - u_snieuro.offset]); } USHORT #ifdef CK_ANSIC heath19g_u(CHAR c) #else heath19g_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_heath19g.offset) return(c); else if (c >= u_heath19g.offset + u_heath19g.size) return(c); else return(u_heath19g.map[c - u_heath19g.offset]); } USHORT #ifdef CK_ANSIC tvig_u(CHAR c) #else tvig_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_tvig.offset) return(c); else if (c >= u_tvig.offset + u_tvig.size) return(c); else return(u_tvig.map[c - u_tvig.offset]); } USHORT #ifdef CK_ANSIC wyse_gn_u(CHAR c) #else wyse_gn_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_wyse_gn.offset) return(c); else if (c >= u_wyse_gn.offset + u_wyse_gn.size) return(c); else return(u_wyse_gn.map[c - u_wyse_gn.offset]); } USHORT #ifdef CK_ANSIC wyse_g1_u(CHAR c) #else wyse_g1_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_wyse_g1.offset) return(c); else if (c >= u_wyse_g1.offset + u_wyse_g1.size) return(c); else return(u_wyse_g1.map[c - u_wyse_g1.offset]); } USHORT #ifdef CK_ANSIC wyse_g2_u(CHAR c) #else wyse_g2_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_wyse_g2.offset) return(c); else if (c >= u_wyse_g2.offset + u_wyse_g2.size) return(c); else return(u_wyse_g2.map[c - u_wyse_g2.offset]); } USHORT #ifdef CK_ANSIC wyse_g3_u(CHAR c) #else wyse_g3_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_wyse_g3.offset) return(c); else if (c >= u_wyse_g3.offset + u_wyse_g3.size) return(c); else return(u_wyse_g3.map[c - u_wyse_g3.offset]); } USHORT #ifdef CK_ANSIC smiley_u(CHAR c) #else smiley_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_smiley.offset) return(c); else if (c >= u_smiley.offset + u_smiley.size) return(c); else return(u_smiley.map[c - u_smiley.offset]); } USHORT #ifdef CK_ANSIC c0pics_u(CHAR c) #else c0pics_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_c0pics.offset) return(c); else if (c >= u_c0pics.offset + u_c0pics.size) return(c); else return(u_c0pics.map[c - u_c0pics.offset]); } USHORT #ifdef CK_ANSIC c1pics_u(CHAR c) #else c1pics_u(c) CHAR c; #endif /* CK_ANSIC */ { c &= 0x7f; if (c < u_c1pics.offset) return(c); else if (c >= u_c1pics.offset + u_c1pics.size) return(c); else return(u_c1pics.map[c - u_c1pics.offset]); } #ifdef KANJI /* Kanji/Unicode functions */ static long /* Statistics counters */ bad = 0, /* REMOVE THESE LATER... */ kanji = 0, kana = 0, greek = 0, cyrillic = 0, special = 0, roman = 0; USHORT #ifdef CK_ANSIC sj_to_un(USHORT sj) /* Shift-JIS to Unicode */ #else sj_to_un(sj) USHORT sj; #endif /* CK_ANSIC */ { /* Kanji blocks */ if (sj >= 0x8140) { /* All possible Kanjis */ kanji++; /* Optimistically count a Kanji */ if (sj <= 0x9ffc) { /* 7869-element table */ return(sju_8140[sj - 0x8140]); } else if (sj >= 0xe040 && sj <= 0xeaa4) { /* 2660-element table */ return(sju_e040[sj - 0xe040]); } else if (sj >= 0xf040) { /* User-defined areas */ if (sj <= 0xf0fc) { /* ten 189-char chunks */ return(0xe000 + (sj - 0xf040)); } else if (sj >= 0xf140 && sj <= 0xf1fc) { return(0xe0bc + (sj - 0xf140)); } else if (sj >= 0xf240 && sj <= 0xf2fc) { return(0xe178 + (sj - 0xf240)); } else if (sj >= 0xf340 && sj <= 0xf3fc) { return(0xe234 + (sj - 0xf340)); } else if (sj >= 0xf440 && sj <= 0xf4fc) { return(0xe2f0 + (sj - 0xf440)); } else if (sj >= 0xf540 && sj <= 0xf5fc) { return(0xe3ac + (sj - 0xf540)); } else if (sj >= 0xf640 && sj <= 0xf6fc) { return(0xe468 + (sj - 0xf640)); } else if (sj >= 0xf740 && sj <= 0xf7fc) { return(0xe524 + (sj - 0xf740)); } else if (sj >= 0xf840 && sj <= 0xf8fc) { return(0xe5e0 + (sj - 0xf840)); } else if (sj >= 0xf940 && sj <= 0xf9fc) { return(0xe69c + (sj - 0xf940)); } } kanji--; /* None of the above, uncount */ } /* C0 / Halfwidth-Roman / C1 block (0x00-0x9f, no holes) */ else if (sj < 0x00a0) { roman++; /* Count a Roman */ if (sj == 0x5c) { /* Yen sign */ return(0x00a5); } else if (sj == 0x7e) { /* Overline (macron) */ return(0x203e); } else { /* Control or Halfwidth Roman */ return(sj); } } /* Halfwidth Katakana block (0xa0-0xdf, no holes) */ else if (sj >= 0xa1 && sj <= 0xdf) { kana++; return(sj + 0xfec0); } /* Catch-all must be final */ bad++; return(0xfffd); } USHORT #ifdef CK_ANSIC un_to_sj(USHORT un) /* Unicode to Shift-JIS */ #else un_to_sj(un) USHORT un; #endif /* CK_ANSIC */ { if (un < 0x00a0) { switch (un) { case 0x005c: roman++; return(0x815f); /* Backslash */ case 0x007e: bad++; return(0xfffd); /* No tilde in Shift-JIS */ default: /* ASCII or C0/C1 control */ roman++; return(un); } } if (un >= 0x00a0 && un < 0x0391) { /* Latin-1 symbols */ roman++; switch(un) { case 0x00A2: return(0x8191); case 0x00A3: return(0x8192); case 0x00A5: return(0x005C); /* Yen */ case 0x00A7: return(0x8198); case 0x00A8: return(0x814E); case 0x00AC: return(0x81CA); case 0x00B0: return(0x818B); case 0x00B1: return(0x817D); case 0x00B4: return(0x814C); case 0x00B6: return(0x81F7); case 0x00D7: return(0x817E); case 0x00F7: return(0x8180); default: roman--; bad++; return(0xfffd); } } if (un >= 0x0391 && un < 0x0401) { /* Greek */ greek++; if (un <= 0x039c) return(usj_0391[un-0x0391]); greek--; bad++; return(0xfffd); } if (un >= 0x0401 && un < 0x2010) { /* Cyrillic */ cyrillic++; if (un <= 0x0451) return(usj_0401[un-0x0401]); cyrillic--; bad++; return(0xfffd); } if (un >= 0x2010 && un < 0x2500) { /* General punctuation */ special++; switch(un) { case 0x2010: return(0x815D); case 0x2015: return(0x815C); case 0x2016: return(0x8161); case 0x2018: return(0x8165); case 0x2019: return(0x8166); case 0x201C: return(0x8167); case 0x201D: return(0x8168); case 0x2020: return(0x81F5); case 0x2021: return(0x81F6); case 0x2025: return(0x8164); case 0x2026: return(0x8163); case 0x2030: return(0x81F1); case 0x2032: return(0x818C); case 0x2033: return(0x818D); case 0x203B: return(0x81A6); case 0x203E: return(0x007E); case 0x2103: return(0x818E); /* Letterlike symbols */ case 0x212B: return(0x81F0); case 0x2190: return(0x81A9); /* Arrows */ case 0x2191: return(0x81AA); case 0x2192: return(0x81A8); case 0x2193: return(0x81AB); case 0x21D2: return(0x81CB); case 0x21D4: return(0x81CC); case 0x2200: return(0x81CD); /* Math */ case 0x2202: return(0x81DD); case 0x2203: return(0x81CE); case 0x2207: return(0x81DE); case 0x2208: return(0x81B8); case 0x220B: return(0x81B9); case 0x2212: return(0x817C); case 0x221A: return(0x81E3); case 0x221D: return(0x81E5); case 0x221E: return(0x8187); case 0x2220: return(0x81DA); case 0x2227: return(0x81C8); case 0x2228: return(0x81C9); case 0x2229: return(0x81BF); case 0x222A: return(0x81BE); case 0x222B: return(0x81E7); case 0x222C: return(0x81E8); case 0x2234: return(0x8188); case 0x2235: return(0x81E6); case 0x223D: return(0x81E4); case 0x2252: return(0x81E0); case 0x2260: return(0x8182); case 0x2261: return(0x81DF); case 0x2266: return(0x8185); case 0x2267: return(0x8186); case 0x226A: return(0x81E1); case 0x226B: return(0x81E2); case 0x2282: return(0x81BC); case 0x2283: return(0x81BD); case 0x2286: return(0x81BA); case 0x2287: return(0x81BB); case 0x22A5: return(0x81DB); case 0x2312: return(0x81DC); /* Arc */ default: special--; bad++; return(0xfffd); } } if (un >= 0x2500 && un < 0x3000) { /* Box drawing */ special++; switch(un) { case 0x2500: return(0x849F); case 0x2501: return(0x84AA); case 0x2502: return(0x84A0); case 0x2503: return(0x84AB); case 0x250C: return(0x84A1); case 0x250F: return(0x84AC); case 0x2510: return(0x84A2); case 0x2513: return(0x84AD); case 0x2514: return(0x84A4); case 0x2517: return(0x84AF); case 0x2518: return(0x84A3); case 0x251B: return(0x84AE); case 0x251C: return(0x84A5); case 0x251D: return(0x84BA); case 0x2520: return(0x84B5); case 0x2523: return(0x84B0); case 0x2524: return(0x84A7); case 0x2525: return(0x84BC); case 0x2528: return(0x84B7); case 0x252B: return(0x84B2); case 0x252C: return(0x84A6); case 0x252F: return(0x84B6); case 0x2530: return(0x84BB); case 0x2533: return(0x84B1); case 0x2534: return(0x84A8); case 0x2537: return(0x84B8); case 0x2538: return(0x84BD); case 0x253B: return(0x84B3); case 0x253C: return(0x84A9); case 0x253F: return(0x84B9); case 0x2542: return(0x84BE); case 0x254B: return(0x84B4); case 0x25A0: return(0x81A1); /* Geometric shapes */ case 0x25A1: return(0x81A0); case 0x25B2: return(0x81A3); case 0x25B3: return(0x81A2); case 0x25BC: return(0x81A5); case 0x25BD: return(0x81A4); case 0x25C6: return(0x819F); case 0x25C7: return(0x819E); case 0x25CB: return(0x819B); case 0x25CE: return(0x819D); case 0x25CF: return(0x819C); case 0x25EF: return(0x81FC); case 0x2605: return(0x819A); /* Misc symbols */ case 0x2606: return(0x8199); case 0x2640: return(0x818A); case 0x2642: return(0x8189); case 0x266A: return(0x81F4); case 0x266D: return(0x81F3); case 0x266F: return(0x81F2); default: special--; bad++; return(0xfffd); } } if (un >= 0x3000 && un < 0x4e00) { /* CJK symbols & punc */ kanji++; if (un <= 0x30ff) return(usj_3000[un-0x3000]); kanji--; bad++; return(0xfffd); } if (un >= 0xff00 && un < 0xffff) { /* Half/full-width Roman & Katakana */ if (un <= 0xff9f) { if (un > 0xff60) kana++; return(usj_ff00[un-0xff00]); } bad++; return(0xfffd); } if (un >= 0x4e00 && un < 0xe000) { /* Kanji */ kanji++; if (un <= 0x9fa0) return(usj_4e00[un-0x4e00]); kanji--; bad++; return(0xfffd); } if (un >= 0xe000 && un < 0xff00) { /* User-defined (Gaiji) */ kanji++; if (un <= 0xe0bb) { /* ten 189-char chunks */ return(0xf040 + (un - 0xe000)); } else if (un >= 0xe0bc && un <= 0xe177) { return(0xf140 + (un - 0xe0bc)); } else if (un >= 0xe178 && un <= 0xe233) { return(0xf240 + (un - 0xe178)); } else if (un >= 0xe234 && un <= 0xe2ef) { return(0xf340 + (un - 0xe234)); } else if (un >= 0xe2f0 && un <= 0xe3ab) { return(0xf440 + (un - 0xe2f0)); } else if (un >= 0xe3ac && un <= 0xe467) { return(0xf540 + (un - 0xe3ac)); } else if (un >= 0xe468 && un <= 0xe523) { return(0xf640 + (un - 0xe468)); } else if (un >= 0xe524 && un <= 0xe5df) { return(0xf740 + (un - 0xe524)); } else if (un >= 0xe5e0 && un <= 0xe69b) { return(0xf840 + (un - 0xe5e0)); } else if (un >= 0xe69c && un <= 0xe757) { return(0xf940 + (un - 0xe69c)); } bad++; return(0xfffd); } /* NOTREACHED */ /* Some compilers (correctly) warn of "statement not reached" here. */ /* But others give up the ghost with "no return value". The former */ /* is the lesser of two evils. */ bad++; return(0xfffd); } #endif /* KANJI */ /* Unicode-to-blah functions, tx_blah(). */ static int #ifdef CK_ANSIC tx_punc(USHORT c) #else tx_punc(c) USHORT c; #endif /* CK_ANSIC */ { if (c >= 0x2000 && c <= 0x200a) /* Various-width spaces */ return((CHAR)(0x20)); else if (c >= 0x2010 && c <= 0x2015) /* Various-width dashes */ return((CHAR)'-'); else if (c >= 0x2018 && c <= 0x201b) /* Assorted single quotes */ return((CHAR)0x27); else if (c >= 0x201c && c <= 0x201f) /* Assorted double quotes */ return((CHAR)0x22); else if ((c >= 0x2022 && c <= 0x2024) || c == 0x2043) /* Bullets */ return((CHAR)0xb7); switch (c) { case 0x2039: /* Less-than sign */ return((CHAR)0x3c); case 0x203a: /* Greater-than sign */ return((CHAR)0x3e); case 0x2044: /* Solidus -> Slash */ return((CHAR)0x2f); default: return(-1); } } int /* For Latin-1 */ #ifdef CK_ANSIC tx_ident(USHORT c) #else tx_ident(c) USHORT c; #endif /* CK_ANSIC */ { if (c == 0x203e) /* Overline -> Macron */ return((CHAR)0xaf); else if (c < 0x100) /* Latin-1 range */ return((CHAR)(c & 0xff)); else /* Or maybe from punctuation block */ return(tx_punc(c)); } int #ifdef CK_ANSIC tx_usascii(USHORT c) #else tx_usascii(c) USHORT c; /* US ASCII */ #endif /* CK_ANSIC */ { if (c < 0x80) return((CHAR)(c & 0xff)); else if (c >= 0x2000 && c <= 0x200a) /* Various-width spaces */ return((CHAR)(0x20)); else if (c >= 0x2010 && c <= 0x2015) /* Various-width dashes */ return((CHAR)'-'); else if (c >= 0x2018 && c <= 0x201b) /* Assorted single quotes */ return((CHAR)0x27); else if (c >= 0x201c && c <= 0x201f) /* Assorted double quotes */ return((CHAR)0x22); else if ((c >= 0x2022 && c <= 0x2024) || c == 0x2043) /* Bullets */ return((CHAR)0xb7); switch (c) { case 0x2039: /* Less-than sign */ return((CHAR)0x3c); case 0x203a: /* Greater-than sign */ return((CHAR)0x3e); case 0x2044: /* Solidus -> Slash */ return((CHAR)0x2f); } /* Here we might also (a) map accented Roman letters to unaccented ones; (b) map Greek/Cyrillic A (etc) to Roman, and so on. */ return((c & 0xff80) ? -1 : (CHAR)(c & 0x7f)); } int #ifdef CK_ANSIC tx_british(USHORT c) #else tx_british(c) USHORT c; /* British */ #endif /* CK_ANSIC */ { if (c & 0xff00) return(-1); else if (c == (USHORT) 0x00a3) /* Pound sign */ return(0x2b); else return(tx_usascii(c)); } int #ifdef CK_ANSIC tx_apl1(USHORT c) #else tx_apl1(c) USHORT c; /* Apl1 */ #endif /* CK_ANSIC */ { if (c >= 0x0041 && c <= 0x005a) /* Letters */ return(c + 0x20); switch (c) { /* Others */ case 0x0024: return((CHAR)0x7e); case 0x0027: return((CHAR)0x4b); case 0x0028: return((CHAR)0x3a); case 0x0029: return((CHAR)0x22); case 0x002b: return((CHAR)0x2d); case 0x002c: return((CHAR)0x2c); case 0x002d: return((CHAR)0x5f); case 0x002e: return((CHAR)0x2e); case 0x002f: return((CHAR)0x2f); case 0x0030: return((CHAR)0x30); case 0x0031: return((CHAR)0x31); case 0x0032: return((CHAR)0x32); case 0x0033: return((CHAR)0x33); case 0x0034: return((CHAR)0x34); case 0x0035: return((CHAR)0x35); case 0x0036: return((CHAR)0x36); case 0x0037: return((CHAR)0x37); case 0x0038: return((CHAR)0x38); case 0x0039: return((CHAR)0x39); case 0x003a: return((CHAR)0x3e); case 0x003b: return((CHAR)0x3c); case 0x003c: return((CHAR)0x23); case 0x003d: return((CHAR)0x25); case 0x003e: return((CHAR)0x26); case 0x003f: return((CHAR)0x51); case 0x005b: return((CHAR)0x3b); case 0x005c: return((CHAR)0x3f); case 0x005d: return((CHAR)0x27); case 0x005f: return((CHAR)0x46); case 0x007b: return((CHAR)0x7b); case 0x007c: return((CHAR)0x4d); case 0x007d: return((CHAR)0x7d); case 0x00a8: return((CHAR)0x21); case 0x00af: return((CHAR)0x40); case 0x00d7: return((CHAR)0x3d); case 0x00f7: return((CHAR)0x2b); case 0x2190: return((CHAR)0x5b); case 0x2191: return((CHAR)0x59); case 0x2192: return((CHAR)0x5d); case 0x2193: return((CHAR)0x55); case 0x2206: return((CHAR)0x48); case 0x2207: return((CHAR)0x47); case 0x220a: return((CHAR)0x45); case 0x2218: return((CHAR)0x4a); case 0x2227: return((CHAR)0x29); case 0x2228: return((CHAR)0x28); case 0x222a: return((CHAR)0x56); case 0x223c: return((CHAR)0x54); case 0x2260: return((CHAR)0x2a); case 0x2264: return((CHAR)0x24); case 0x2265: return((CHAR)0x5e); case 0x2282: return((CHAR)0x5a); case 0x2283: return((CHAR)0x58); case 0x22a2: return((CHAR)0x5c); case 0x22a3: return((CHAR)0x7c); case 0x22a4: return((CHAR)0x4e); case 0x22a5: return((CHAR)0x42); case 0x22c2: return((CHAR)0x43); case 0x22c4: return((CHAR)0x60); case 0x22c6: return((CHAR)0x50); case 0x2308: return((CHAR)0x53); case 0x230a: return((CHAR)0x44); case 0x2373: return((CHAR)0x49); case 0x2374: return((CHAR)0x52); case 0x2375: return((CHAR)0x57); case 0x237a: return((CHAR)0x41); case 0x25af: return((CHAR)0x4c); case 0x25cb: return((CHAR)0x4f); default: return(tx_usascii(c)); } } int /* Canadian French */ #ifdef CK_ANSIC tx_fr_canadian(USHORT c) #else tx_fr_canadian(c) USHORT c; #endif /* CK_ANSIC */ { if (c & 0xff00) /* Out of range */ return(-1); switch(c) { case 0xe0: return(0x40); /* a grave */ case 0xe2: return(0x5b); /* a circumflex */ case 0xe7: return(0x5c); /* c cedilla */ case 0xe8: return(0x7d); /* e grave */ case 0xe9: return(0x7b); /* e acute */ case 0xea: return(0x5d); /* e circumflex */ case 0xee: return(0x5e); /* i circumflex */ case 0xf4: return(0x60); /* o circumflex */ case 0xf9: return(0x7c); /* u grave */ case 0xfb: return(0x6e); /* u circumflex */ default: return(tx_usascii(c)); } } int /* Danish/Norwegian */ #ifdef CK_ANSIC tx_danish(USHORT c) #else tx_danish(c) USHORT c; #endif /* CK_ANSIC */ { if (c & 0xff00) /* Out of range */ return(-1); switch(c) { case 0xc6: return(0x5b); /* AE */ case 0xd8: return(0x5c); /* O stroke */ case 0xe6: return(0x7b); /* ae */ case 0xf8: return(0x7c); /* o stroke */ case 0xe5: return(0x7d); /* a ring */ case 0xaf: return(0x7e); /* macron */ default: return(tx_usascii(c)); } } int /* Dutch */ #ifdef CK_ANSIC tx_dutch(USHORT c) #else tx_dutch(c) USHORT c; #endif /* CK_ANSIC */ { if (c & 0xfe00) /* Out of range */ return(-1); switch(c) { case 0x007c: return(0x5d); /* vertical bar */ case 0x00a3: return(0x23); /* pound sign */ case 0x00ab: return(0x7b); /* diaeresis */ case 0x00b4: return(0x7e); /* acute accent */ case 0x00bc: return(0x7d); /* 1/4 */ case 0x00be: return(0x40); /* 3/4 */ case 0x00bd: return(0x5c); /* 1/2 */ case 0x00ff: return(0x5b); /* y diaeresis (ij) */ case 0x0192: return(0x7c); /* Florin */ default: return((c & 0x80) ? -1 : (CHAR)(c & 0x7f)); } } int /* Finnish */ #ifdef CK_ANSIC tx_finnish(USHORT c) #else tx_finnish(c) USHORT c; #endif /* CK_ANSIC */ { if (c & 0xff00) /* Out of range */ return(-1); switch(c) { case 0xc4: return(0x5b); /* A diaeresis */ case 0xd6: return(0x5c); /* O diaeresis */ case 0xc5: return(0x5d); /* A ring */ case 0xdc: return(0x5e); /* U diaeresis */ case 0xe9: return(0x60); /* e acute */ case 0xe4: return(0x7b); /* a diaeresis */ case 0xf6: return(0x7c); /* o diaeresis */ case 0xe5: return(0x7d); /* a ring */ case 0xfc: return(0x7e); /* u diaeresis */ default: return(tx_usascii(c)); } } int /* French */ #ifdef CK_ANSIC tx_french(USHORT c) #else tx_french(c) USHORT c; #endif /* CK_ANSIC */ { if (c & 0xff00) /* Out of range */ return(-1); switch(c) { case 0xa3: return(0x23); /* pound sign */ case 0xa7: return(0x5d); /* section sign */ case 0xa8: return(0x7e); /* diaeresis */ case 0xb0: return(0x5b); /* ring */ case 0xb5: return(0x60); /* micron sign (mu) */ case 0xe0: return(0x40); /* a grave */ case 0xe7: return(0x5c); /* c cedilla */ case 0xe8: return(0x7d); /* e grave */ case 0xe9: return(0x7b); /* e acute */ case 0xf9: return(0x7c); /* u grave */ default: return(tx_usascii(c)); } } int /* German */ #ifdef CK_ANSIC tx_german(USHORT c) #else tx_german(c) USHORT c; #endif /* CK_ANSIC */ { if (c & 0xff00) /* Out of range */ return(-1); switch(c) { case 0xa7: return(0x40); /* section sign */ case 0xc4: return(0x5b); /* A umlaut */ case 0xd6: return(0x5c); /* O umlaut */ case 0xdc: return(0x5d); /* U umlaut */ case 0xdf: return(0x7e); /* ess-zet */ case 0xe4: return(0x7b); /* a umlaut */ case 0xf6: return(0x7c); /* o umlaut */ case 0xfc: return(0x7d); /* u umlaut*/ default: return(tx_usascii(c)); } } int /* Hebrew-7 */ #ifdef CK_ANSIC tx_hebrew7(USHORT c) #else tx_hebrew7(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x60) /* ASCII */ return((CHAR)(c & 0x7f)); else if (c >= 123 && c < 128) /* ASCII */ return((CHAR)(c & 0x7f)); else if (c >= 0x05d0 && c <= 0x05ea) /* Hebrew 27 contiguous characters */ return((CHAR)((int)c - 0x5d0 + 96)); else return(-1); } int /* Greek ELOT 927 */ #ifdef CK_ANSIC tx_elot927(USHORT c) #else tx_elot927(c) USHORT c; #endif /* CK_ANSIC */ { if (c <= 0x80) { /* ASCII */ if (islower(c)) c = toupper(c); /* Send all letters in uppercase */ return((CHAR)(c & 0x7f)); } /* Greek -- map all Greek characters to unaccented uppercase */ if (c >= 0x0391 && c <= 0x03a1) /* Alpha thru Rho - uppercase */ return((CHAR)((int)c - 0x0391 + 97)); else if (c >= 0x03a3 && c <= 0x03a9) /* Sigma thru Omega - uppercase */ return((CHAR)((int)c - 0x0391 + 96)); else if (c >= 0x03b1 && c <= 0x03c1) /* Alpha thru Rho - lowercase */ return((CHAR)((int)c - 0x0391 + 97)); else if (c >= 0x03c3 && c <= 0x03c9) /* Sigma thru Omega - uppercase */ return((CHAR)((int)c - 0x0391 + 96)); switch (c) { case 0x03c2: return((CHAR)114); /* Terminal sigma */ case 0x0386: return((CHAR)97); /* Alpha Tonos */ case 0x03ac: return((CHAR)97); /* alpha Tonos */ case 0x0388: return((CHAR)101); /* Epsilon Tonos */ case 0x03ad: return((CHAR)101); /* epsilon Tonos */ case 0x0389: return((CHAR)103); /* Eta Tonos */ case 0x03ae: return((CHAR)103); /* eta Tonos */ case 0x038a: return((CHAR)105); /* Iota Tonos */ case 0x03af: return((CHAR)105); /* iota Tonos */ case 0x03ca: return((CHAR)105); /* iota Dialytika */ case 0x038c: return((CHAR)111); /* Omicron Tonos */ case 0x03cc: return((CHAR)111); /* omicron Tonos */ case 0x038e: return((CHAR)116); /* Upsilon Tonos */ case 0x03d3: return((CHAR)116); /* Upsilon Tonos */ case 0x03cd: return((CHAR)116); /* upsilon Tonos */ case 0x03cb: return((CHAR)116); /* upsilon Dialytika */ case 0x03b0: return((CHAR)116); /* upsilon Dialytika+Tonos */ case 0x038f: return((CHAR)120); /* Omega Tonos */ case 0x03ce: return((CHAR)120); /* omega Tonos */ case 0x0390: return((CHAR)105); /* iota Dialytika+Tonos */ case 0x03aa: return((CHAR)105); /* Iota Dialytika */ case 0x03ab: return((CHAR)116); /* Upsilon Dialytika */ case 0x03d4: return((CHAR)116); /* Upsilon Dialytika */ case 0x03d0: return((CHAR)98); /* Alternative beta */ case 0x03d1: return((CHAR)104); /* Open theta */ case 0x03d5: return((CHAR)117); /* Open phi */ case 0x03d6: return((CHAR)112); /* Alternative Pi */ default: return(-1); } } int /* Hungarian */ #ifdef CK_ANSIC tx_hungarian(USHORT c) #else tx_hungarian(c) USHORT c; #endif /* CK_ANSIC */ { if (c == 0x02dd || c == 0x2033) return(0x7e); /* double acute accent */ else if (c & 0xff00) /* Out of range */ return(-1); switch(c) { case 0xc1: return(0x40); /* A acute */ case 0xc9: return(0x5b); /* E acute */ case 0xd6: return(0x5c); /* O umlaut */ case 0xdc: return(0x5d); /* U umlaut */ case 0xe9: return(0x7b); /* e acute */ case 0xf6: return(0x7c); /* o umlaut */ case 0xfa: return(0x60); /* u acute */ case 0xfc: return(0x7d); /* u umlaut */ default: return(tx_usascii(c)); } } int /* Icelandic */ #ifdef CK_ANSIC tx_icelandic(USHORT c) #else tx_icelandic(c) USHORT c; #endif /* CK_ANSIC */ { if (c & 0xff00) /* Out of range */ return(-1); switch(c) { case 0xde: return(0x40); /* Thorn */ case 0xd0: return(0x5b); /* Eth */ case 0xc6: return(0x5d); /* AE */ case 0xd6: return(0x5e); /* O umlaut */ case 0xfe: return(0x60); /* thorn */ case 0xf0: return(0x7b); /* eth */ case 0xe6: return(0x7d); /* ae */ case 0xf6: return(0x7e); /* o umlaut */ default: return(tx_usascii(c)); } } int /* Italian */ #ifdef CK_ANSIC tx_italian(USHORT c) #else tx_italian(c) USHORT c; #endif /* CK_ANSIC */ { if (c & 0xff00) /* Out of range */ return(-1); switch(c) { case 0xa3: return(0x23); /* pound sign */ case 0xa7: return(0x40); /* section sign */ case 0xb0: return(0x5b); /* ring */ case 0xe7: return(0x5c); /* c cedilla */ case 0xe9: return(0x5d); /* e acute */ case 0xf9: return(0x60); /* u grave */ case 0xe0: return(0x7b); /* a grave */ case 0xf2: return(0x7c); /* o grave */ case 0xe8: return(0x7d); /* e grave */ case 0xec: return(0x7e); /* i grave */ default: return(tx_usascii(c)); } } int /* JIS 0201 Roman */ #ifdef CK_ANSIC tx_jis0201r(USHORT c) #else tx_jis0201r(c) USHORT c; #endif /* CK_ANSIC */ { if (c & 0xff80) /* 7 bits */ return(-1); switch (c) { /* Like ASCII with */ case 0x00a5: return(92); /* two exceptions */ case 0x00af: return(126); case 0x203e: return(126); default: return(tx_usascii(c)); } } int /* JIS 0201 Katakana */ #ifdef CK_ANSIC tx_jis0201k(USHORT c) #else tx_jis0201k(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xff61 || c > 0xff9f) return(-1); /* Out of range */ else return((int)c - 0xfec0); /* 0xff61 - a0 = 0xfec0 */ } int /* Short KOI */ #ifdef CK_ANSIC tx_koi7(USHORT c) #else tx_koi7(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x50) return((CHAR)(c & 0x7f)); else if (c > 0x7f) return(-1); /* Out of range */ switch(c) { case 0x0410: return((CHAR)97); case 0x0411: return((CHAR)98); case 0x0412: return((CHAR)119); case 0x0413: return((CHAR)103); case 0x0414: return((CHAR)100); case 0x0415: return((CHAR)101); case 0x0416: return((CHAR)118); case 0x0417: return((CHAR)122); case 0x0418: return((CHAR)105); case 0x0419: return((CHAR)106); case 0x041a: return((CHAR)107); case 0x041b: return((CHAR)108); case 0x041c: return((CHAR)109); case 0x041d: return((CHAR)110); case 0x041e: return((CHAR)111); case 0x041f: return((CHAR)112); case 0x0420: return((CHAR)114); case 0x0421: return((CHAR)115); case 0x0422: return((CHAR)116); case 0x0423: return((CHAR)117); case 0x0424: return((CHAR)102); case 0x0425: return((CHAR)104); case 0x0426: return((CHAR)99); case 0x0427: return((CHAR)126); case 0x0428: return((CHAR)123); case 0x0429: return((CHAR)125); case 0x042b: return((CHAR)121); case 0x042c: return((CHAR)120); case 0x042d: return((CHAR)124); case 0x042e: return((CHAR)96); case 0x042f: return((CHAR)113); default: return(-1); } } int /* Portuguese */ #ifdef CK_ANSIC tx_portuguese(USHORT c) #else tx_portuguese(c) USHORT c; #endif /* CK_ANSIC */ { if (c & 0xff00) /* Out of range */ return(-1); switch(c) { case 0xe0: return(0xa7); /* section sign */ case 0xb0: return(0xc3); /* A tilde */ case 0xe7: return(0xc7); /* C cedilla */ case 0xa7: return(0xd5); /* O tilde */ case 0xe9: return(0xe3); /* a tilde */ case 0xf9: return(0xe7); /* c cedilla */ case 0xe8: return(0xf5); /* o tilde */ case 0xa8: return(0xb0); /* ring */ default: return(tx_usascii(c)); } } int /* Spanish */ #ifdef CK_ANSIC tx_spanish(USHORT c) #else tx_spanish(c) USHORT c; #endif /* CK_ANSIC */ { if (c & 0xff00) /* Out of range */ return(-1); switch(c) { case 0xa3: return(0x23); /* pound sign */ case 0xa7: return(0x40); /* section */ case 0xa1: return(0x5b); /* inverted exclamation */ case 0xd1: return(0x5c); /* N tilde */ case 0xbf: return(0x5d); /* inverted question mark */ case 0xb0: return(0x7b); /* ring */ case 0xf1: return(0x7c); /* n tilde */ case 0xe7: return(0x7d); /* c cedilla */ default: return(tx_usascii(c)); } } int /* Swedish */ #ifdef CK_ANSIC tx_swedish(USHORT c) #else tx_swedish(c) USHORT c; #endif /* CK_ANSIC */ { if (c & 0xff00) /* Out of range */ return(-1); switch(c) { case 0xc9: return(0x40); /* E acute */ case 0xc4: return(0x5b); /* A umlaut*/ case 0xd6: return(0x5c); /* O umlaut */ case 0xc5: return(0x5d); /* A ring */ case 0xdc: return(0x5e); /* U umlaut */ case 0xe9: return(0x60); /* e acute */ case 0xe4: return(0x7b); /* a umlaut */ case 0xf6: return(0x7c); /* o umlaut */ case 0xe5: return(0x7d); /* a ring */ case 0xfc: return(0x7e); /* u umlaut */ default: return(tx_usascii(c)); } } int /* Swiss NRC */ #ifdef CK_ANSIC tx_swiss(USHORT c) #else tx_swiss(c) USHORT c; #endif /* CK_ANSIC */ { if (c & 0xff00) /* Out of range */ return(-1); switch(c) { case 0xf9: return(0x23); /* u grave */ case 0xe0: return(0x40); /* a grave */ case 0xe9: return(0x5b); /* e acute */ case 0xe7: return(0x5c); /* c cedilla */ case 0xea: return(0x5d); /* e circumflex */ case 0xee: return(0x5e); /* i circumflex */ case 0xe8: return(0x5f); /* e grave */ case 0xf4: return(0x60); /* o circumflex */ case 0xe4: return(0x7b); /* a umlaut */ case 0xf6: return(0x7c); /* o umlaut */ case 0xfc: return(0x7d); /* u umlaut */ case 0xfb: return(0x7e); /* u circumflex */ default: return(tx_usascii(c)); } } int /* Dyadic APL */ #ifdef CK_ANSIC tx_apl2(USHORT c) #else tx_apl2(c) USHORT c; #endif /* CK_ANSIC */ { if (c >= 0x0041 && c <= 0x005a) /* Letters */ return(c - 0xa2); switch (c) { case 0x00a0: return((CHAR)0xa0); case 0x00a2: return((CHAR)0xa4); case 0x00a3: return((CHAR)0xd4); case 0x00a8: return((CHAR)0xdc); case 0x00af: return((CHAR)0xda); case 0x00d7: return((CHAR)0xa1); case 0x00f7: return((CHAR)0xaf); case 0x2190: return((CHAR)0xbb); case 0x2191: return((CHAR)0xfe); case 0x2192: return((CHAR)0xde); case 0x2193: return((CHAR)0xff); case 0x2206: return((CHAR)0xae); case 0x2207: return((CHAR)0xfd); case 0x220a: return((CHAR)0xb5); case 0x2218: return((CHAR)0xbc); case 0x2228: return((CHAR)0xdf); case 0x2229: return((CHAR)0xd1); case 0x222a: return((CHAR)0xd2); case 0x2260: return((CHAR)0xb0); case 0x2261: return((CHAR)0xb6); case 0x2262: return((CHAR)0xcd); case 0x2264: return((CHAR)0xb8); case 0x2265: return((CHAR)0xb7); case 0x2282: return((CHAR)0xe0); case 0x2283: return((CHAR)0xe1); case 0x2296: return((CHAR)0xd6); case 0x22a2: return((CHAR)0xd7); case 0x22a3: return((CHAR)0xd8); case 0x22a4: return((CHAR)0xba); case 0x22a5: return((CHAR)0xb9); case 0x22c4: return((CHAR)0xb1); case 0x2308: return((CHAR)0xcf); case 0x230a: return((CHAR)0xce); case 0x2337: return((CHAR)0xd9); case 0x2339: return((CHAR)0xca); case 0x233d: return((CHAR)0xd5); case 0x233f: return((CHAR)0xbe); case 0x2340: return((CHAR)0xbf); case 0x2349: return((CHAR)0xd0); case 0x234b: return((CHAR)0xc2); case 0x234e: return((CHAR)0xc0); case 0x2352: return((CHAR)0xc3); case 0x2355: return((CHAR)0xc1); case 0x2359: return((CHAR)0xe2); case 0x235d: return((CHAR)0xbd); case 0x235e: return((CHAR)0xc9); case 0x235f: return((CHAR)0xc7); case 0x2368: return((CHAR)0xc6); case 0x236a: return((CHAR)0xcc); case 0x236b: return((CHAR)0xcb); case 0x236c: return((CHAR)0xd3); case 0x2371: return((CHAR)0xc5); case 0x2372: return((CHAR)0xc4); case 0x2373: return((CHAR)0xdb); case 0x2374: return((CHAR)0xb3); case 0x2375: return((CHAR)0xb2); case 0x237a: return((CHAR)0xb4); case 0x2500: return((CHAR)0xaa); case 0x2502: return((CHAR)0xa2); case 0x250c: return((CHAR)0xad); case 0x2510: return((CHAR)0xa5); case 0x2514: return((CHAR)0xa6); case 0x2518: return((CHAR)0xac); case 0x251c: return((CHAR)0xa9); case 0x2524: return((CHAR)0xa3); case 0x252c: return((CHAR)0xa8); case 0x2534: return((CHAR)0xa7); case 0x253c: return((CHAR)0xab); case 0x25af: return((CHAR)0xc8); case 0x25cb: return((CHAR)0xdd); default: if (c < 0xa0) return((CHAR)(c & 0xff)); return(tx_punc(c)); } } int /* APL-Plus */ #ifdef CK_ANSIC tx_apl3(USHORT c) #else tx_apl3(c) USHORT c; #endif /* CK_ANSIC */ { switch (c) { case 0x00a0: return((CHAR)0xa0); case 0x00a1: return((CHAR)0xa1); case 0x00a2: return((CHAR)0xa2); case 0x00a3: return((CHAR)0xa3); case 0x00a5: return((CHAR)0xa5); case 0x00a6: return((CHAR)0xa6); case 0x00a7: return((CHAR)0xa7); case 0x00a8: return((CHAR)0xa8); case 0x00ab: return((CHAR)0xab); case 0x00af: return((CHAR)0xaf); case 0x00b6: return((CHAR)0xb6); case 0x00b7: return((CHAR)0xb7); case 0x00bb: return((CHAR)0xbb); case 0x00bf: return((CHAR)0xbf); case 0x00c0: return((CHAR)0xc0); case 0x00c1: return((CHAR)0xc1); case 0x00c2: return((CHAR)0xc2); case 0x00c3: return((CHAR)0xc3); case 0x00c4: return((CHAR)0xc4); case 0x00c5: return((CHAR)0xc5); case 0x00c6: return((CHAR)0xc6); case 0x00c7: return((CHAR)0xc7); case 0x00c8: return((CHAR)0xc8); case 0x00c9: return((CHAR)0xc9); case 0x00ca: return((CHAR)0xca); case 0x00cb: return((CHAR)0xcb); case 0x00cc: return((CHAR)0xcc); case 0x00cd: return((CHAR)0xcd); case 0x00ce: return((CHAR)0xce); case 0x00cf: return((CHAR)0xcf); case 0x00d1: return((CHAR)0xd1); case 0x00d2: return((CHAR)0xd2); case 0x00d3: return((CHAR)0xd3); case 0x00d4: return((CHAR)0xd4); case 0x00d5: return((CHAR)0xd5); case 0x00d6: return((CHAR)0xd6); case 0x00d7: return((CHAR)0xd7); case 0x00d8: return((CHAR)0xd8); case 0x00d9: return((CHAR)0xd9); case 0x00da: return((CHAR)0xda); case 0x00db: return((CHAR)0xdb); case 0x00dc: return((CHAR)0xdc); case 0x00dd: return((CHAR)0xdd); case 0x00df: return((CHAR)0xdf); case 0x00e0: return((CHAR)0xe0); case 0x00e1: return((CHAR)0xe1); case 0x00e2: return((CHAR)0xe2); case 0x00e3: return((CHAR)0xe3); case 0x00e4: return((CHAR)0xe4); case 0x00e5: return((CHAR)0xe5); case 0x00e6: return((CHAR)0xe6); case 0x00e7: return((CHAR)0xe7); case 0x00e8: return((CHAR)0xe8); case 0x00e9: return((CHAR)0xe9); case 0x00ea: return((CHAR)0xea); case 0x00eb: return((CHAR)0xeb); case 0x00ec: return((CHAR)0xec); case 0x00ed: return((CHAR)0xed); case 0x00ee: return((CHAR)0xee); case 0x00ef: return((CHAR)0xef); case 0x00f1: return((CHAR)0xf1); case 0x00f2: return((CHAR)0xf2); case 0x00f3: return((CHAR)0xf3); case 0x00f4: return((CHAR)0xf4); case 0x00f5: return((CHAR)0xf5); case 0x00f6: return((CHAR)0xf6); case 0x00f7: return((CHAR)0xf7); case 0x00f9: return((CHAR)0xf9); case 0x00fa: return((CHAR)0xfa); case 0x00fb: return((CHAR)0xfb); case 0x00fc: return((CHAR)0xfc); case 0x00fd: return((CHAR)0xfd); case 0x00ff: return((CHAR)0xff); case 0x20ac: return((CHAR)0x80); case 0x2190: return((CHAR)0x84); case 0x2191: return((CHAR)0x86); case 0x2192: return((CHAR)0x85); case 0x2193: return((CHAR)0x87); case 0x2205: return((CHAR)0xf8); case 0x2206: return((CHAR)0x91); case 0x2207: return((CHAR)0x92); case 0x220a: return((CHAR)0xb9); case 0x2218: return((CHAR)0xb0); case 0x2228: return((CHAR)0x9f); case 0x2229: return((CHAR)0x9d); case 0x222a: return((CHAR)0x9e); case 0x2260: return((CHAR)0xac); case 0x2261: return((CHAR)0xad); case 0x2264: return((CHAR)0x88); case 0x2265: return((CHAR)0x89); case 0x2282: return((CHAR)0x9b); case 0x2283: return((CHAR)0x9c); case 0x2296: return((CHAR)0xb4); case 0x22a2: return((CHAR)0xa4); case 0x22a3: return((CHAR)0x81); case 0x22a4: return((CHAR)0x82); case 0x22a5: return((CHAR)0x83); case 0x22c4: return((CHAR)0xaa); case 0x2308: return((CHAR)0x97); case 0x230a: return((CHAR)0x98); case 0x2337: return((CHAR)0xde); case 0x2339: return((CHAR)0x8e); case 0x233d: return((CHAR)0xb2); case 0x233f: return((CHAR)0x9a); case 0x2340: return((CHAR)0x99); case 0x2349: return((CHAR)0xb3); case 0x234b: return((CHAR)0x93); case 0x234e: return((CHAR)0x96); case 0x2352: return((CHAR)0x94); case 0x2355: return((CHAR)0x95); case 0x2359: return((CHAR)0x8f); case 0x235d: return((CHAR)0xa9); case 0x235e: return((CHAR)0x8d); case 0x235f: return((CHAR)0xb5); case 0x2364: return((CHAR)0xf0); case 0x2368: return((CHAR)0xfe); case 0x236a: return((CHAR)0xae); case 0x236b: return((CHAR)0x90); case 0x236c: return((CHAR)0xd0); case 0x2371: return((CHAR)0x8b); case 0x2372: return((CHAR)0x8a); case 0x2373: return((CHAR)0xbc); case 0x2374: return((CHAR)0xbd); case 0x2375: return((CHAR)0xbe); case 0x2377: return((CHAR)0xba); case 0x237a: return((CHAR)0xb8); case 0x25af: return((CHAR)0x8c); case 0x25cb: return((CHAR)0xb1); default: return(tx_punc(c)); } } int /* IBM APL2 */ #ifdef CK_ANSIC tx_apl4(USHORT c) #else tx_apl4(c) USHORT c; #endif /* CK_ANSIC */ { switch (c) { case 0x00a0: return((CHAR)0xff); case 0x00a1: return((CHAR)0xad); case 0x00a3: return((CHAR)0x9c); case 0x00a6: return((CHAR)0xdd); case 0x00a8: return((CHAR)0xfe); case 0x00aa: return((CHAR)0xa6); case 0x00ac: return((CHAR)0xaa); case 0x00af: return((CHAR)0xfd); case 0x00ba: return((CHAR)0xa7); case 0x00bf: return((CHAR)0xa8); case 0x00c4: return((CHAR)0x8e); case 0x00c5: return((CHAR)0xee); /* and 0x8f */ case 0x00c7: return((CHAR)0x80); case 0x00cc: return((CHAR)0xde); case 0x00d1: return((CHAR)0xa5); case 0x00d6: return((CHAR)0x99); case 0x00d7: return((CHAR)0xf5); case 0x00dc: return((CHAR)0x9a); case 0x00df: return((CHAR)0xe1); case 0x00e0: return((CHAR)0x85); case 0x00e1: return((CHAR)0xa0); case 0x00e2: return((CHAR)0x83); case 0x00e4: return((CHAR)0x84); case 0x00e5: return((CHAR)0x86); case 0x00e7: return((CHAR)0x87); case 0x00e8: return((CHAR)0x8a); case 0x00e9: return((CHAR)0x82); case 0x00ea: return((CHAR)0x88); case 0x00eb: return((CHAR)0x89); case 0x00ec: return((CHAR)0x8d); case 0x00ed: return((CHAR)0xa1); case 0x00ee: return((CHAR)0x8c); case 0x00ef: return((CHAR)0x8b); case 0x00f1: return((CHAR)0xa4); case 0x00f2: return((CHAR)0x95); case 0x00f3: return((CHAR)0xa2); case 0x00f4: return((CHAR)0x93); case 0x00f6: return((CHAR)0x94); case 0x00f7: return((CHAR)0xf6); case 0x00f8: return((CHAR)0x9b); case 0x00f9: return((CHAR)0x97); case 0x00fa: return((CHAR)0xa3); case 0x00fb: return((CHAR)0x96); case 0x00fc: return((CHAR)0x81); case 0x2190: return((CHAR)0x9e); case 0x2191: return((CHAR)0xc6); case 0x2192: return((CHAR)0xab); case 0x2193: return((CHAR)0xc7); case 0x2206: return((CHAR)0xb6); case 0x2207: return((CHAR)0xb7); case 0x2218: return((CHAR)0xf8); case 0x2228: return((CHAR)0xeb); case 0x2229: return((CHAR)0xef); case 0x222a: return((CHAR)0xac); case 0x2235: return((CHAR)0xd2); case 0x2260: return((CHAR)0xf4); case 0x2261: return((CHAR)0xcf); case 0x2264: return((CHAR)0xf3); case 0x2265: return((CHAR)0xf2); case 0x2282: return((CHAR)0xe2); case 0x2283: return((CHAR)0xe3); case 0x2296: return((CHAR)0xe9); case 0x22a2: return((CHAR)0xd6); case 0x22a3: return((CHAR)0xd7); case 0x22a4: return((CHAR)0x98); case 0x22a5: return((CHAR)0x9d); case 0x22c4: return((CHAR)0xd8); case 0x2308: return((CHAR)0xa9); case 0x230a: return((CHAR)0xbe); case 0x2336: return((CHAR)0x9f); case 0x2337: return((CHAR)0xd3); case 0x2339: return((CHAR)0x92); case 0x233b: return((CHAR)0xd5); case 0x233d: return((CHAR)0xe8); case 0x233f: return((CHAR)0xf0); case 0x2340: return((CHAR)0xf1); case 0x2342: return((CHAR)0xd4); case 0x2349: return((CHAR)0xed); case 0x234b: return((CHAR)0xfb); case 0x234e: return((CHAR)0xaf); case 0x2352: return((CHAR)0xfc); case 0x2355: return((CHAR)0xae); case 0x2359: return((CHAR)0xf7); case 0x235d: return((CHAR)0xe4); case 0x235e: return((CHAR)0x91); case 0x235f: return((CHAR)0xb5); case 0x236b: return((CHAR)0xfa); case 0x2371: return((CHAR)0xe7); case 0x2372: return((CHAR)0xe5); case 0x2373: return((CHAR)0xec); case 0x2374: return((CHAR)0xe6); case 0x2375: return((CHAR)0xf9); case 0x2377: return((CHAR)0xd1); case 0x2378: return((CHAR)0xd0); case 0x237a: return((CHAR)0xe0); case 0x2500: return((CHAR)0xc4); case 0x2502: return((CHAR)0xb3); case 0x250c: return((CHAR)0xda); case 0x2510: return((CHAR)0xbf); case 0x2514: return((CHAR)0xc0); case 0x2518: return((CHAR)0xd9); case 0x251c: return((CHAR)0xc3); case 0x2524: return((CHAR)0xb4); case 0x252c: return((CHAR)0xc2); case 0x2534: return((CHAR)0xc1); case 0x253c: return((CHAR)0xc5); case 0x2550: return((CHAR)0xcd); case 0x2551: return((CHAR)0xba); case 0x2554: return((CHAR)0xc9); case 0x2557: return((CHAR)0xbb); case 0x255a: return((CHAR)0xc8); case 0x255d: return((CHAR)0xbc); case 0x2560: return((CHAR)0xcc); case 0x2563: return((CHAR)0xb9); case 0x2566: return((CHAR)0xcb); case 0x2569: return((CHAR)0xca); case 0x256c: return((CHAR)0xce); case 0x2580: return((CHAR)0xdf); case 0x2584: return((CHAR)0xdc); case 0x2588: return((CHAR)0xdb); case 0x2591: return((CHAR)0xb0); case 0x2592: return((CHAR)0xb1); case 0x2593: return((CHAR)0xb2); case 0x25af: return((CHAR)0x90); case 0x25cb: return((CHAR)0xea); default: return(tx_punc(c)); } } int /* APL-2741 */ #ifdef CK_ANSIC tx_apl5(USHORT c) #else tx_apl5(c) USHORT c; #endif /* CK_ANSIC */ { switch (c) { case 0x00a0: return((CHAR)0xa0); case 0x00a1: return((CHAR)0xa1); case 0x00a2: return((CHAR)0xa2); case 0x00a3: return((CHAR)0xa3); case 0x00a8: return((CHAR)0xa8); case 0x00af: return((CHAR)0xaf); case 0x00b6: return((CHAR)0xb6); case 0x00b7: return((CHAR)0xb7); case 0x00bf: return((CHAR)0xbf); case 0x00c4: return((CHAR)0xc4); case 0x00c5: return((CHAR)0xc5); case 0x00c6: return((CHAR)0xc6); case 0x00c7: return((CHAR)0xc7); case 0x00c8: return((CHAR)0xc8); case 0x00c9: return((CHAR)0xc9); case 0x00cd: return((CHAR)0xcd); case 0x00d1: return((CHAR)0xd1); case 0x00d6: return((CHAR)0xd6); case 0x00d7: return((CHAR)0xd7); case 0x00d8: return((CHAR)0xd8); case 0x00dc: return((CHAR)0xdc); case 0x00df: return((CHAR)0xdf); case 0x00e0: return((CHAR)0xe0); case 0x00e1: return((CHAR)0xe1); case 0x00e2: return((CHAR)0xe2); case 0x00e3: return((CHAR)0xe3); case 0x00e4: return((CHAR)0xe4); case 0x00e5: return((CHAR)0xe5); case 0x00e6: return((CHAR)0xe6); case 0x00e7: return((CHAR)0xe7); case 0x00e8: return((CHAR)0xe8); case 0x00e9: return((CHAR)0xe9); case 0x00ea: return((CHAR)0xea); case 0x00eb: return((CHAR)0xeb); case 0x00ec: return((CHAR)0xec); case 0x00ed: return((CHAR)0xed); case 0x00ee: return((CHAR)0xee); case 0x00ef: return((CHAR)0xef); case 0x00f1: return((CHAR)0xf1); case 0x00f2: return((CHAR)0xf2); case 0x00f3: return((CHAR)0xf3); case 0x00f4: return((CHAR)0xf4); case 0x00f5: return((CHAR)0xf5); case 0x00f6: return((CHAR)0xf6); case 0x00f7: return((CHAR)0xf7); case 0x00f9: return((CHAR)0xf9); case 0x00fa: return((CHAR)0xfa); case 0x00fb: return((CHAR)0xfb); case 0x00fc: return((CHAR)0xfc); case 0x20ac: return((CHAR)0x80); case 0x2190: return((CHAR)0x84); case 0x2191: return((CHAR)0x86); case 0x2192: return((CHAR)0x85); case 0x2193: return((CHAR)0x87); case 0x2205: return((CHAR)0xf8); case 0x2206: return((CHAR)0x91); case 0x2207: return((CHAR)0x92); case 0x220a: return((CHAR)0xb9); case 0x2218: return((CHAR)0xb0); case 0x2228: return((CHAR)0x9f); case 0x2229: return((CHAR)0x9d); case 0x222a: return((CHAR)0x9e); case 0x2235: return((CHAR)0xfd); case 0x2260: return((CHAR)0xac); case 0x2261: return((CHAR)0xa6); case 0x2262: return((CHAR)0xbb); case 0x2264: return((CHAR)0x88); case 0x2265: return((CHAR)0x89); case 0x2282: return((CHAR)0x9b); case 0x2283: return((CHAR)0x9c); case 0x2296: return((CHAR)0xb4); case 0x22a2: return((CHAR)0xa4); case 0x22a3: return((CHAR)0x81); case 0x22a4: return((CHAR)0x82); case 0x22a5: return((CHAR)0x83); case 0x22c4: return((CHAR)0xaa); case 0x2308: return((CHAR)0x97); case 0x230a: return((CHAR)0x98); case 0x2336: return((CHAR)0xa7); case 0x2337: return((CHAR)0xde); case 0x2339: return((CHAR)0x8e); case 0x233b: return((CHAR)0xcb); case 0x233d: return((CHAR)0xb2); case 0x233f: return((CHAR)0x9a); case 0x2340: return((CHAR)0x99); case 0x2342: return((CHAR)0xca); case 0x2347: return((CHAR)0xd4); case 0x2348: return((CHAR)0xd5); case 0x2349: return((CHAR)0xb3); case 0x234b: return((CHAR)0x93); case 0x234e: return((CHAR)0x96); case 0x2350: return((CHAR)0xd2); case 0x2352: return((CHAR)0x94); case 0x2355: return((CHAR)0x95); case 0x2357: return((CHAR)0xd3); case 0x2359: return((CHAR)0x8f); case 0x235d: return((CHAR)0xa9); case 0x235e: return((CHAR)0x8d); case 0x235f: return((CHAR)0xb5); case 0x2364: return((CHAR)0xf0); case 0x2365: return((CHAR)0xff); case 0x2368: return((CHAR)0xfe); case 0x236a: return((CHAR)0xae); case 0x236b: return((CHAR)0x90); case 0x236c: return((CHAR)0xab); case 0x2371: return((CHAR)0x8b); case 0x2372: return((CHAR)0x8a); case 0x2373: return((CHAR)0xbc); case 0x2374: return((CHAR)0xbd); case 0x2375: return((CHAR)0xbe); case 0x2377: return((CHAR)0xba); case 0x2378: return((CHAR)0xa5); case 0x237a: return((CHAR)0xb8); case 0x2500: return((CHAR)0xce); case 0x2502: return((CHAR)0xdb); case 0x250c: return((CHAR)0xda); case 0x2510: return((CHAR)0xcc); case 0x2514: return((CHAR)0xc0); case 0x2518: return((CHAR)0xd9); case 0x251c: return((CHAR)0xc3); case 0x2524: return((CHAR)0xdd); case 0x252c: return((CHAR)0xc2); case 0x2534: return((CHAR)0xc1); case 0x253c: return((CHAR)0xcf); case 0x25af: return((CHAR)0x8c); case 0x25cb: return((CHAR)0xb1); default: return(tx_punc(c)); } } /* For Latin-1, use tx_ident() */ int /* Latin-2 */ #ifdef CK_ANSIC tx_8859_2(USHORT c) #else tx_8859_2(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) return((CHAR)(c & 0xff)); switch(c) { case 0x00A0: return((CHAR)160); case 0x00A4: return((CHAR)164); case 0x00A7: return((CHAR)167); case 0x00A8: return((CHAR)168); case 0x00AD: return((CHAR)173); case 0x00B0: return((CHAR)176); case 0x00B4: return((CHAR)180); case 0x00B8: return((CHAR)184); case 0x00C1: return((CHAR)193); case 0x00C2: return((CHAR)194); case 0x00C4: return((CHAR)196); case 0x00C7: return((CHAR)199); case 0x00C9: return((CHAR)201); case 0x00CB: return((CHAR)203); case 0x00CD: return((CHAR)205); case 0x00CE: return((CHAR)206); case 0x00D3: return((CHAR)211); case 0x00D4: return((CHAR)212); case 0x00D6: return((CHAR)214); case 0x00D7: return((CHAR)215); case 0x00DA: return((CHAR)218); case 0x00DC: return((CHAR)220); case 0x00DD: return((CHAR)221); case 0x00DF: return((CHAR)223); case 0x00E1: return((CHAR)225); case 0x00E2: return((CHAR)226); case 0x00E4: return((CHAR)228); case 0x00E7: return((CHAR)231); case 0x00E9: return((CHAR)233); case 0x00EB: return((CHAR)235); case 0x00ED: return((CHAR)237); case 0x00EE: return((CHAR)238); case 0x00F3: return((CHAR)243); case 0x00F4: return((CHAR)244); case 0x00F6: return((CHAR)246); case 0x00F7: return((CHAR)247); case 0x00FA: return((CHAR)250); case 0x00FC: return((CHAR)252); case 0x00FD: return((CHAR)253); case 0x0102: return((CHAR)195); case 0x0103: return((CHAR)227); case 0x0104: return((CHAR)161); case 0x0105: return((CHAR)177); case 0x0106: return((CHAR)198); case 0x0107: return((CHAR)230); case 0x010C: return((CHAR)200); case 0x010D: return((CHAR)232); case 0x010E: return((CHAR)207); case 0x010F: return((CHAR)239); case 0x0110: return((CHAR)208); case 0x0111: return((CHAR)240); case 0x0118: return((CHAR)202); case 0x0119: return((CHAR)234); case 0x011A: return((CHAR)204); case 0x011B: return((CHAR)236); case 0x0139: return((CHAR)197); case 0x013A: return((CHAR)229); case 0x013D: return((CHAR)165); case 0x013E: return((CHAR)181); case 0x0141: return((CHAR)163); case 0x0142: return((CHAR)179); case 0x0143: return((CHAR)209); case 0x0144: return((CHAR)241); case 0x0147: return((CHAR)210); case 0x0148: return((CHAR)242); case 0x0150: return((CHAR)213); case 0x0151: return((CHAR)245); case 0x0154: return((CHAR)192); case 0x0155: return((CHAR)224); case 0x0158: return((CHAR)216); case 0x0159: return((CHAR)248); case 0x015A: return((CHAR)166); case 0x015B: return((CHAR)182); case 0x015E: return((CHAR)170); case 0x015F: return((CHAR)186); case 0x0160: return((CHAR)169); case 0x0161: return((CHAR)185); case 0x0162: return((CHAR)222); case 0x0163: return((CHAR)254); case 0x0164: return((CHAR)171); case 0x0165: return((CHAR)187); case 0x016E: return((CHAR)217); case 0x016F: return((CHAR)249); case 0x0170: return((CHAR)219); case 0x0171: return((CHAR)251); case 0x0179: return((CHAR)172); case 0x017A: return((CHAR)188); case 0x017B: return((CHAR)175); case 0x017C: return((CHAR)191); case 0x017D: return((CHAR)174); case 0x017E: return((CHAR)190); case 0x02C7: return((CHAR)183); case 0x02D8: return((CHAR)162); case 0x02D9: return((CHAR)255); case 0x02DB: return((CHAR)178); case 0x02DD: return((CHAR)189); default: return(tx_punc(c)); } } int /* Latin-3 */ #ifdef CK_ANSIC tx_8859_3(USHORT c) #else tx_8859_3(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) return((CHAR)(c & 0xff)); switch(c) { case 0x00A0: return((CHAR)160); case 0x00A3: return((CHAR)163); case 0x00A4: return((CHAR)164); case 0x00A7: return((CHAR)167); case 0x00A8: return((CHAR)168); case 0x00AD: return((CHAR)173); case 0x00B0: return((CHAR)176); case 0x00B2: return((CHAR)178); case 0x00B3: return((CHAR)179); case 0x00B4: return((CHAR)180); case 0x00B5: return((CHAR)181); case 0x00B7: return((CHAR)183); case 0x00B8: return((CHAR)184); case 0x00BD: return((CHAR)189); case 0x00C0: return((CHAR)192); case 0x00C1: return((CHAR)193); case 0x00C2: return((CHAR)194); case 0x00C4: return((CHAR)196); case 0x00C7: return((CHAR)199); case 0x00C8: return((CHAR)200); case 0x00C9: return((CHAR)201); case 0x00CA: return((CHAR)202); case 0x00CB: return((CHAR)203); case 0x00CC: return((CHAR)204); case 0x00CD: return((CHAR)205); case 0x00CE: return((CHAR)206); case 0x00CF: return((CHAR)207); case 0x00D1: return((CHAR)209); case 0x00D2: return((CHAR)210); case 0x00D3: return((CHAR)211); case 0x00D4: return((CHAR)212); case 0x00D6: return((CHAR)214); case 0x00D7: return((CHAR)215); case 0x00D9: return((CHAR)217); case 0x00DA: return((CHAR)218); case 0x00DB: return((CHAR)219); case 0x00DC: return((CHAR)220); case 0x00DF: return((CHAR)223); case 0x00E0: return((CHAR)224); case 0x00E1: return((CHAR)225); case 0x00E2: return((CHAR)226); case 0x00E4: return((CHAR)228); case 0x00E7: return((CHAR)231); case 0x00E8: return((CHAR)232); case 0x00E9: return((CHAR)233); case 0x00EA: return((CHAR)234); case 0x00EB: return((CHAR)235); case 0x00EC: return((CHAR)236); case 0x00ED: return((CHAR)237); case 0x00EE: return((CHAR)238); case 0x00EF: return((CHAR)239); case 0x00F1: return((CHAR)241); case 0x00F2: return((CHAR)242); case 0x00F3: return((CHAR)243); case 0x00F4: return((CHAR)244); case 0x00F6: return((CHAR)246); case 0x00F7: return((CHAR)247); case 0x00F9: return((CHAR)249); case 0x00FA: return((CHAR)250); case 0x00FB: return((CHAR)251); case 0x00FC: return((CHAR)252); case 0x0108: return((CHAR)198); case 0x0109: return((CHAR)230); case 0x010A: return((CHAR)197); case 0x010B: return((CHAR)229); case 0x011C: return((CHAR)216); case 0x011D: return((CHAR)248); case 0x011E: return((CHAR)171); case 0x011F: return((CHAR)187); case 0x0120: return((CHAR)213); case 0x0121: return((CHAR)245); case 0x0124: return((CHAR)166); case 0x0125: return((CHAR)182); case 0x0126: return((CHAR)161); case 0x0127: return((CHAR)177); case 0x0130: return((CHAR)169); case 0x0131: return((CHAR)185); case 0x0134: return((CHAR)172); case 0x0135: return((CHAR)188); case 0x015C: return((CHAR)222); case 0x015D: return((CHAR)254); case 0x015E: return((CHAR)170); case 0x015F: return((CHAR)186); case 0x016C: return((CHAR)221); case 0x016D: return((CHAR)253); case 0x017B: return((CHAR)175); case 0x017C: return((CHAR)191); case 0x02D8: return((CHAR)162); case 0x02D9: return((CHAR)255); default: return(tx_punc(c)); } } int /* Latin-4 */ #ifdef CK_ANSIC tx_8859_4(USHORT c) #else tx_8859_4(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) return((CHAR)(c & 0xff)); switch(c) { case 0x00A0: return((CHAR)160); case 0x00A4: return((CHAR)164); case 0x00A7: return((CHAR)167); case 0x00A8: return((CHAR)168); case 0x00AD: return((CHAR)173); case 0x00AF: return((CHAR)175); case 0x00B0: return((CHAR)176); case 0x00B4: return((CHAR)180); case 0x00B8: return((CHAR)184); case 0x00C1: return((CHAR)193); case 0x00C2: return((CHAR)194); case 0x00C3: return((CHAR)195); case 0x00C4: return((CHAR)196); case 0x00C5: return((CHAR)197); case 0x00C6: return((CHAR)198); case 0x00C9: return((CHAR)201); case 0x00CB: return((CHAR)203); case 0x00CD: return((CHAR)205); case 0x00CE: return((CHAR)206); case 0x00D4: return((CHAR)212); case 0x00D5: return((CHAR)213); case 0x00D6: return((CHAR)214); case 0x00D7: return((CHAR)215); case 0x00D8: return((CHAR)216); case 0x00DA: return((CHAR)218); case 0x00DB: return((CHAR)219); case 0x00DC: return((CHAR)220); case 0x00DF: return((CHAR)223); case 0x00E1: return((CHAR)225); case 0x00E2: return((CHAR)226); case 0x00E3: return((CHAR)227); case 0x00E4: return((CHAR)228); case 0x00E5: return((CHAR)229); case 0x00E6: return((CHAR)230); case 0x00E9: return((CHAR)233); case 0x00EB: return((CHAR)235); case 0x00ED: return((CHAR)237); case 0x00EE: return((CHAR)238); case 0x00F4: return((CHAR)244); case 0x00F5: return((CHAR)245); case 0x00F6: return((CHAR)246); case 0x00F7: return((CHAR)247); case 0x00F8: return((CHAR)248); case 0x00FA: return((CHAR)250); case 0x00FB: return((CHAR)251); case 0x00FC: return((CHAR)252); case 0x0100: return((CHAR)192); case 0x0101: return((CHAR)224); case 0x0104: return((CHAR)161); case 0x0105: return((CHAR)177); case 0x010C: return((CHAR)200); case 0x010D: return((CHAR)232); case 0x0110: return((CHAR)208); case 0x0111: return((CHAR)240); case 0x0112: return((CHAR)170); case 0x0113: return((CHAR)186); case 0x0116: return((CHAR)204); case 0x0117: return((CHAR)236); case 0x0118: return((CHAR)202); case 0x0119: return((CHAR)234); case 0x0122: return((CHAR)171); case 0x0123: return((CHAR)187); case 0x0128: return((CHAR)165); case 0x0129: return((CHAR)181); case 0x012A: return((CHAR)207); case 0x012B: return((CHAR)239); case 0x012E: return((CHAR)199); case 0x012F: return((CHAR)231); case 0x0136: return((CHAR)211); case 0x0137: return((CHAR)243); case 0x0138: return((CHAR)162); case 0x013B: return((CHAR)166); case 0x013C: return((CHAR)182); case 0x0145: return((CHAR)209); case 0x0146: return((CHAR)241); case 0x014A: return((CHAR)189); case 0x014B: return((CHAR)191); case 0x014C: return((CHAR)210); case 0x014D: return((CHAR)242); case 0x0156: return((CHAR)163); case 0x0157: return((CHAR)179); case 0x0160: return((CHAR)169); case 0x0161: return((CHAR)185); case 0x0166: return((CHAR)172); case 0x0167: return((CHAR)188); case 0x0168: return((CHAR)221); case 0x0169: return((CHAR)253); case 0x016A: return((CHAR)222); case 0x016B: return((CHAR)254); case 0x0172: return((CHAR)217); case 0x0173: return((CHAR)249); case 0x017D: return((CHAR)174); case 0x017E: return((CHAR)190); case 0x02C7: return((CHAR)183); case 0x02D9: return((CHAR)255); case 0x02DB: return((CHAR)178); default: return(tx_punc(c)); } } int /* ISO 8859-5 (Latin/Cyrillic) */ #ifdef CK_ANSIC tx_8859_5(USHORT c) #else tx_8859_5(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) /* (8859-5 is not Latin-5!) */ return((CHAR)(c & 0xff)); switch(c) { case 0x00A0: return((CHAR)160); case 0x00A7: return((CHAR)253); case 0x00AD: return((CHAR)173); case 0x0401: return((CHAR)161); case 0x0402: return((CHAR)162); case 0x0403: return((CHAR)163); case 0x0404: return((CHAR)164); case 0x0405: return((CHAR)165); case 0x0406: return((CHAR)166); case 0x0407: return((CHAR)167); case 0x0408: return((CHAR)168); case 0x0409: return((CHAR)169); case 0x040A: return((CHAR)170); case 0x040B: return((CHAR)171); case 0x040C: return((CHAR)172); case 0x040E: return((CHAR)174); case 0x040F: return((CHAR)175); case 0x0410: return((CHAR)176); case 0x0411: return((CHAR)177); case 0x0412: return((CHAR)178); case 0x0413: return((CHAR)179); case 0x0414: return((CHAR)180); case 0x0415: return((CHAR)181); case 0x0416: return((CHAR)182); case 0x0417: return((CHAR)183); case 0x0418: return((CHAR)184); case 0x0419: return((CHAR)185); case 0x041A: return((CHAR)186); case 0x041B: return((CHAR)187); case 0x041C: return((CHAR)188); case 0x041D: return((CHAR)189); case 0x041E: return((CHAR)190); case 0x041F: return((CHAR)191); case 0x0420: return((CHAR)192); case 0x0421: return((CHAR)193); case 0x0422: return((CHAR)194); case 0x0423: return((CHAR)195); case 0x0424: return((CHAR)196); case 0x0425: return((CHAR)197); case 0x0426: return((CHAR)198); case 0x0427: return((CHAR)199); case 0x0428: return((CHAR)200); case 0x0429: return((CHAR)201); case 0x042A: return((CHAR)202); case 0x042B: return((CHAR)203); case 0x042C: return((CHAR)204); case 0x042D: return((CHAR)205); case 0x042E: return((CHAR)206); case 0x042F: return((CHAR)207); case 0x0430: return((CHAR)208); case 0x0431: return((CHAR)209); case 0x0432: return((CHAR)210); case 0x0433: return((CHAR)211); case 0x0434: return((CHAR)212); case 0x0435: return((CHAR)213); case 0x0436: return((CHAR)214); case 0x0437: return((CHAR)215); case 0x0438: return((CHAR)216); case 0x0439: return((CHAR)217); case 0x043A: return((CHAR)218); case 0x043B: return((CHAR)219); case 0x043C: return((CHAR)220); case 0x043D: return((CHAR)221); case 0x043E: return((CHAR)222); case 0x043F: return((CHAR)223); case 0x0440: return((CHAR)224); case 0x0441: return((CHAR)225); case 0x0442: return((CHAR)226); case 0x0443: return((CHAR)227); case 0x0444: return((CHAR)228); case 0x0445: return((CHAR)229); case 0x0446: return((CHAR)230); case 0x0447: return((CHAR)231); case 0x0448: return((CHAR)232); case 0x0449: return((CHAR)233); case 0x044A: return((CHAR)234); case 0x044B: return((CHAR)235); case 0x044C: return((CHAR)236); case 0x044D: return((CHAR)237); case 0x044E: return((CHAR)238); case 0x044F: return((CHAR)239); case 0x0451: return((CHAR)241); case 0x0452: return((CHAR)242); case 0x0453: return((CHAR)243); case 0x0454: return((CHAR)244); case 0x0455: return((CHAR)245); case 0x0456: return((CHAR)246); case 0x0457: return((CHAR)247); case 0x0458: return((CHAR)248); case 0x0459: return((CHAR)249); case 0x045A: return((CHAR)250); case 0x045B: return((CHAR)251); case 0x045C: return((CHAR)252); case 0x045E: return((CHAR)254); case 0x045F: return((CHAR)255); case 0x2116: return((CHAR)240); default: return(tx_punc(c)); } } int /* ISO 8859-6 (Latin/Arabic) */ #ifdef CK_ANSIC tx_8859_6(USHORT c) #else tx_8859_6(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) /* (8859-6 != Latin-6) */ return((CHAR)(c & 0xff)); switch(c) { case 0x00A0: return((CHAR)160); case 0x00A4: return((CHAR)164); case 0x00AD: return((CHAR)173); case 0x060C: return((CHAR)172); case 0x061B: return((CHAR)187); case 0x061F: return((CHAR)191); case 0x0621: return((CHAR)193); case 0x0622: return((CHAR)194); case 0x0623: return((CHAR)195); case 0x0624: return((CHAR)196); case 0x0625: return((CHAR)197); case 0x0626: return((CHAR)198); case 0x0627: return((CHAR)199); case 0x0628: return((CHAR)200); case 0x0629: return((CHAR)201); case 0x062A: return((CHAR)202); case 0x062B: return((CHAR)203); case 0x062C: return((CHAR)204); case 0x062D: return((CHAR)205); case 0x062E: return((CHAR)206); case 0x062F: return((CHAR)207); case 0x0630: return((CHAR)208); case 0x0631: return((CHAR)209); case 0x0632: return((CHAR)210); case 0x0633: return((CHAR)211); case 0x0634: return((CHAR)212); case 0x0635: return((CHAR)213); case 0x0636: return((CHAR)214); case 0x0637: return((CHAR)215); case 0x0638: return((CHAR)216); case 0x0639: return((CHAR)217); case 0x063A: return((CHAR)218); case 0x0640: return((CHAR)224); case 0x0641: return((CHAR)225); case 0x0642: return((CHAR)226); case 0x0643: return((CHAR)227); case 0x0644: return((CHAR)228); case 0x0645: return((CHAR)229); case 0x0646: return((CHAR)230); case 0x0647: return((CHAR)231); case 0x0648: return((CHAR)232); case 0x0649: return((CHAR)233); case 0x064A: return((CHAR)234); case 0x064B: return((CHAR)235); case 0x064C: return((CHAR)236); case 0x064D: return((CHAR)237); case 0x064E: return((CHAR)238); case 0x064F: return((CHAR)239); case 0x0650: return((CHAR)240); case 0x0651: return((CHAR)241); case 0x0652: return((CHAR)242); default: return(tx_punc(c)); } } int /* ISO 8859-7 (Latin/Greek) */ #ifdef CK_ANSIC tx_8859_7(USHORT c) #else tx_8859_7(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) return((CHAR)(c & 0xff)); switch(c) { case 0x00a0: return((CHAR)160); case 0x00a3: return((CHAR)163); case 0x00a6: return((CHAR)166); case 0x00a7: return((CHAR)167); case 0x00a8: return((CHAR)168); case 0x00a9: return((CHAR)169); case 0x00ab: return((CHAR)171); case 0x00ac: return((CHAR)172); case 0x00ad: return((CHAR)173); case 0x00b0: return((CHAR)176); case 0x00b1: return((CHAR)177); case 0x00b2: return((CHAR)178); case 0x00b3: return((CHAR)179); case 0x00b7: return((CHAR)183); case 0x00bb: return((CHAR)187); case 0x00bd: return((CHAR)189); case 0x02bc: return((CHAR)162); case 0x02bd: return((CHAR)161); case 0x0384: return((CHAR)180); case 0x0385: return((CHAR)181); case 0x0386: return((CHAR)182); case 0x0388: return((CHAR)184); case 0x0389: return((CHAR)185); case 0x038a: return((CHAR)186); case 0x038c: return((CHAR)188); case 0x038e: return((CHAR)190); case 0x038f: return((CHAR)191); case 0x0390: return((CHAR)192); case 0x0391: return((CHAR)193); case 0x0392: return((CHAR)194); case 0x0393: return((CHAR)195); case 0x0394: return((CHAR)196); case 0x0395: return((CHAR)197); case 0x0396: return((CHAR)198); case 0x0397: return((CHAR)199); case 0x0398: return((CHAR)200); case 0x0399: return((CHAR)201); case 0x039a: return((CHAR)202); case 0x039b: return((CHAR)203); case 0x039c: return((CHAR)204); case 0x039d: return((CHAR)205); case 0x039e: return((CHAR)206); case 0x039f: return((CHAR)207); case 0x03a0: return((CHAR)208); case 0x03a1: return((CHAR)209); case 0x03a3: return((CHAR)211); case 0x03a4: return((CHAR)212); case 0x03a5: return((CHAR)213); case 0x03a6: return((CHAR)214); case 0x03a7: return((CHAR)215); case 0x03a8: return((CHAR)216); case 0x03a9: return((CHAR)217); case 0x03aa: return((CHAR)218); case 0x03ab: return((CHAR)219); case 0x03ac: return((CHAR)220); case 0x03ad: return((CHAR)221); case 0x03ae: return((CHAR)222); case 0x03af: return((CHAR)223); case 0x03b0: return((CHAR)224); case 0x03b1: return((CHAR)225); case 0x03b2: return((CHAR)226); case 0x03b3: return((CHAR)227); case 0x03b4: return((CHAR)228); case 0x03b5: return((CHAR)229); case 0x03b6: return((CHAR)230); case 0x03b7: return((CHAR)231); case 0x03b8: return((CHAR)232); case 0x03b9: return((CHAR)233); case 0x03ba: return((CHAR)234); case 0x03bb: return((CHAR)235); case 0x03bc: return((CHAR)236); case 0x03bd: return((CHAR)237); case 0x03be: return((CHAR)238); case 0x03bf: return((CHAR)239); case 0x03c0: return((CHAR)240); case 0x03c1: return((CHAR)241); case 0x03c2: return((CHAR)242); case 0x03c3: return((CHAR)243); case 0x03c4: return((CHAR)244); case 0x03c5: return((CHAR)245); case 0x03c6: return((CHAR)246); case 0x03c7: return((CHAR)247); case 0x03c8: return((CHAR)248); case 0x03c9: return((CHAR)249); case 0x03ca: return((CHAR)250); case 0x03cb: return((CHAR)251); case 0x03cc: return((CHAR)252); case 0x03cd: return((CHAR)253); case 0x03ce: return((CHAR)254); case 0x2015: return((CHAR)175); case 0x2018: return((CHAR)161); case 0x2019: return((CHAR)162); default: return(tx_punc(c)); } } int /* ISO 8859-8 (Latin/Hebrew) */ #ifdef CK_ANSIC tx_8859_8(USHORT c) #else tx_8859_8(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) return((CHAR)(c & 0xff)); switch(c) { case 0x00a0: return((CHAR)160); case 0x00a2: return((CHAR)162); case 0x00a3: return((CHAR)163); case 0x00a4: return((CHAR)164); case 0x00a5: return((CHAR)165); case 0x00a6: return((CHAR)166); case 0x00a7: return((CHAR)167); case 0x00a8: return((CHAR)168); case 0x00a9: return((CHAR)169); case 0x00d7: return((CHAR)170); case 0x00ab: return((CHAR)171); case 0x00ac: return((CHAR)172); case 0x00ad: return((CHAR)173); case 0x00ae: return((CHAR)174); case 0x203e: return((CHAR)175); case 0x00b0: return((CHAR)176); case 0x00b1: return((CHAR)177); case 0x00b2: return((CHAR)178); case 0x00b3: return((CHAR)179); case 0x00b4: return((CHAR)180); case 0x00b5: return((CHAR)181); case 0x00b6: return((CHAR)182); case 0x00b7: return((CHAR)183); case 0x00b8: return((CHAR)184); case 0x00b9: return((CHAR)185); case 0x00f7: return((CHAR)186); case 0x00bb: return((CHAR)187); case 0x00bc: return((CHAR)188); case 0x00bd: return((CHAR)189); case 0x00be: return((CHAR)190); case 0x2017: return((CHAR)223); case 0x05d0: return((CHAR)224); case 0x05d1: return((CHAR)225); case 0x05d2: return((CHAR)226); case 0x05d3: return((CHAR)227); case 0x05d4: return((CHAR)228); case 0x05d5: return((CHAR)229); case 0x05d6: return((CHAR)230); case 0x05d7: return((CHAR)231); case 0x05d8: return((CHAR)232); case 0x05d9: return((CHAR)233); case 0x05da: return((CHAR)234); case 0x05db: return((CHAR)235); case 0x05dc: return((CHAR)236); case 0x05dd: return((CHAR)237); case 0x05de: return((CHAR)238); case 0x05df: return((CHAR)239); case 0x05e0: return((CHAR)240); case 0x05e1: return((CHAR)241); case 0x05e2: return((CHAR)242); case 0x05e3: return((CHAR)243); case 0x05e4: return((CHAR)244); case 0x05e5: return((CHAR)245); case 0x05e6: return((CHAR)246); case 0x05e7: return((CHAR)247); case 0x05e8: return((CHAR)248); case 0x05e9: return((CHAR)249); case 0x05ea: return((CHAR)250); default: return(tx_punc(c)); } } int /* ISO 8859-9 (Latin-4) */ #ifdef CK_ANSIC tx_8859_9(USHORT c) #else tx_8859_9(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) return((CHAR)(c & 0xff)); switch(c) { case 0x011E: return((CHAR)208); /* Differs from Latin-1 in */ case 0x011F: return((CHAR)240); /* only six places */ case 0x0130: return((CHAR)221); case 0x0131: return((CHAR)253); case 0x015E: return((CHAR)222); case 0x015F: return((CHAR)254); default: return(tx_ident(c)); } } int /* Latin-6 */ #ifdef CK_ANSIC tx_8859_10(USHORT c) #else tx_8859_10(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) return((CHAR)(c & 0xff)); switch(c) { case 0x00a0: return((CHAR)160); case 0x00ad: return((CHAR)173); case 0x00bd: return((CHAR)189); case 0x00be: return((CHAR)190); case 0x00c1: return((CHAR)193); case 0x00c2: return((CHAR)194); case 0x00c3: return((CHAR)195); case 0x00c4: return((CHAR)196); case 0x00c5: return((CHAR)197); case 0x00c6: return((CHAR)198); case 0x00c9: return((CHAR)201); case 0x00cb: return((CHAR)203); case 0x00cd: return((CHAR)205); case 0x00ce: return((CHAR)206); case 0x00cf: return((CHAR)207); case 0x00d3: return((CHAR)211); case 0x00d4: return((CHAR)212); case 0x00d5: return((CHAR)213); case 0x00d6: return((CHAR)214); case 0x00d8: return((CHAR)216); case 0x00da: return((CHAR)218); case 0x00db: return((CHAR)219); case 0x00dc: return((CHAR)220); case 0x00dd: return((CHAR)221); case 0x00de: return((CHAR)222); case 0x00e1: return((CHAR)225); case 0x00e2: return((CHAR)226); case 0x00e3: return((CHAR)227); case 0x00e4: return((CHAR)228); case 0x00e5: return((CHAR)229); case 0x00e6: return((CHAR)230); case 0x00e9: return((CHAR)233); case 0x00eb: return((CHAR)235); case 0x00ed: return((CHAR)237); case 0x00ee: return((CHAR)238); case 0x00ef: return((CHAR)239); case 0x00f0: return((CHAR)240); case 0x00f1: return((CHAR)241); case 0x00f3: return((CHAR)243); case 0x00f4: return((CHAR)244); case 0x00f5: return((CHAR)245); case 0x00f6: return((CHAR)246); case 0x00f8: return((CHAR)248); case 0x00fa: return((CHAR)250); case 0x00fb: return((CHAR)251); case 0x00fc: return((CHAR)252); case 0x00fd: return((CHAR)253); case 0x00fe: return((CHAR)254); case 0x0100: return((CHAR)192); case 0x0101: return((CHAR)224); case 0x0104: return((CHAR)161); case 0x0105: return((CHAR)177); case 0x010c: return((CHAR)200); case 0x010d: return((CHAR)232); case 0x0110: return((CHAR)208); case 0x0111: return((CHAR)176); case 0x0112: return((CHAR)162); case 0x0113: return((CHAR)178); case 0x0116: return((CHAR)204); case 0x0117: return((CHAR)236); case 0x0118: return((CHAR)202); case 0x0119: return((CHAR)234); case 0x0122: return((CHAR)163); case 0x0123: return((CHAR)179); case 0x0128: return((CHAR)165); case 0x0129: return((CHAR)181); case 0x012a: return((CHAR)164); case 0x012b: return((CHAR)180); case 0x012e: return((CHAR)199); case 0x012f: return((CHAR)231); case 0x0136: return((CHAR)166); case 0x0137: return((CHAR)182); case 0x0138: return((CHAR)174); case 0x013b: return((CHAR)167); case 0x013c: return((CHAR)183); case 0x0143: return((CHAR)168); case 0x0144: return((CHAR)184); case 0x0145: return((CHAR)209); case 0x014a: return((CHAR)175); case 0x014b: return((CHAR)191); case 0x014c: return((CHAR)210); case 0x014d: return((CHAR)242); case 0x0156: return((CHAR)169); case 0x0157: return((CHAR)185); case 0x0160: return((CHAR)170); case 0x0161: return((CHAR)186); case 0x0166: return((CHAR)171); case 0x0167: return((CHAR)187); case 0x0168: return((CHAR)215); case 0x0169: return((CHAR)247); case 0x016a: return((CHAR)223); case 0x016b: return((CHAR)255); case 0x0172: return((CHAR)217); case 0x0173: return((CHAR)249); case 0x017d: return((CHAR)172); case 0x017e: return((CHAR)188); default: return(tx_ident(c)); } } int /* ISO 8859-15 Latin-9 */ #ifdef CK_ANSIC tx_8859_15(USHORT c) #else tx_8859_15(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) return((CHAR)(c & 0xff)); switch(c) { case 0x20AC: return((CHAR)0xA4); /* Differs from Latin-1 in */ case 0x0160: return((CHAR)0xAC); /* only eight places */ case 0x0161: return((CHAR)0xA8); case 0x017D: return((CHAR)0xB4); case 0x017E: return((CHAR)0xB8); case 0x0152: return((CHAR)0xBC); case 0x0153: return((CHAR)0xBD); case 0x0178: return((CHAR)0xBE); default: return(tx_ident(c)); } } int /* Old KOI-8 (ECMA 113 First Ed.) */ #ifdef CK_ANSIC tx_koi8(USHORT c) #else tx_koi8(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) return((CHAR)(c & 0xff)); switch(c) { case 0x0410: return((CHAR)(225 & 0xff)); case 0x0411: return((CHAR)(226 & 0xff)); case 0x0412: return((CHAR)(247 & 0xff)); case 0x0413: return((CHAR)(231 & 0xff)); case 0x0414: return((CHAR)(228 & 0xff)); case 0x0415: return((CHAR)(229 & 0xff)); case 0x0416: return((CHAR)(246 & 0xff)); case 0x0417: return((CHAR)(250 & 0xff)); case 0x0418: return((CHAR)(233 & 0xff)); case 0x0419: return((CHAR)(234 & 0xff)); case 0x041a: return((CHAR)(235 & 0xff)); case 0x041b: return((CHAR)(236 & 0xff)); case 0x041c: return((CHAR)(237 & 0xff)); case 0x041d: return((CHAR)(238 & 0xff)); case 0x041e: return((CHAR)(239 & 0xff)); case 0x041f: return((CHAR)(240 & 0xff)); case 0x0420: return((CHAR)(242 & 0xff)); case 0x0421: return((CHAR)(243 & 0xff)); case 0x0422: return((CHAR)(244 & 0xff)); case 0x0423: return((CHAR)(245 & 0xff)); case 0x0424: return((CHAR)(230 & 0xff)); case 0x0425: return((CHAR)(232 & 0xff)); case 0x0426: return((CHAR)(227 & 0xff)); case 0x0427: return((CHAR)(254 & 0xff)); case 0x0428: return((CHAR)(251 & 0xff)); case 0x0429: return((CHAR)(253 & 0xff)); case 0x042b: return((CHAR)(249 & 0xff)); case 0x042c: return((CHAR)(248 & 0xff)); case 0x042d: return((CHAR)(252 & 0xff)); case 0x042e: return((CHAR)(224 & 0xff)); case 0x042f: return((CHAR)(241 & 0xff)); case 0x0430: return((CHAR)(193 & 0xff)); case 0x0431: return((CHAR)(194 & 0xff)); case 0x0432: return((CHAR)(215 & 0xff)); case 0x0433: return((CHAR)(199 & 0xff)); case 0x0434: return((CHAR)(196 & 0xff)); case 0x0435: return((CHAR)(197 & 0xff)); case 0x0436: return((CHAR)(214 & 0xff)); case 0x0437: return((CHAR)(218 & 0xff)); case 0x0438: return((CHAR)(201 & 0xff)); case 0x0439: return((CHAR)(202 & 0xff)); case 0x043a: return((CHAR)(203 & 0xff)); case 0x043b: return((CHAR)(204 & 0xff)); case 0x043c: return((CHAR)(205 & 0xff)); case 0x043d: return((CHAR)(206 & 0xff)); case 0x043e: return((CHAR)(207 & 0xff)); case 0x043f: return((CHAR)(208 & 0xff)); case 0x0440: return((CHAR)(210 & 0xff)); case 0x0441: return((CHAR)(211 & 0xff)); case 0x0442: return((CHAR)(212 & 0xff)); case 0x0443: return((CHAR)(213 & 0xff)); case 0x0444: return((CHAR)(198 & 0xff)); case 0x0445: return((CHAR)(200 & 0xff)); case 0x0446: return((CHAR)(195 & 0xff)); case 0x0447: return((CHAR)(222 & 0xff)); case 0x0448: return((CHAR)(219 & 0xff)); case 0x0449: return((CHAR)(221 & 0xff)); case 0x044a: return((CHAR)(223 & 0xff)); case 0x044b: return((CHAR)(217 & 0xff)); case 0x044c: return((CHAR)(216 & 0xff)); case 0x044d: return((CHAR)(220 & 0xff)); case 0x044e: return((CHAR)(192 & 0xff)); case 0x044f: return((CHAR)(209 & 0xff)); default: return(tx_ident(c)); } } int /* UCS-2 to KOI8-R (Russia) */ #ifdef CK_ANSIC tx_koi8r(USHORT c) #else tx_koi8r(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x00A0) return((CHAR)(c & 0xff)); switch(c) { case 0x00A0: return((CHAR)(154 & 0xff)); case 0x00A9: return((CHAR)(191 & 0xff)); case 0x00B0: return((CHAR)(156 & 0xff)); case 0x00B2: return((CHAR)(157 & 0xff)); case 0x00B7: return((CHAR)(158 & 0xff)); case 0x00F7: return((CHAR)(159 & 0xff)); case 0x0401: return((CHAR)(179 & 0xff)); case 0x0410: return((CHAR)(225 & 0xff)); case 0x0411: return((CHAR)(226 & 0xff)); case 0x0412: return((CHAR)(247 & 0xff)); case 0x0413: return((CHAR)(231 & 0xff)); case 0x0414: return((CHAR)(228 & 0xff)); case 0x0415: return((CHAR)(229 & 0xff)); case 0x0416: return((CHAR)(246 & 0xff)); case 0x0417: return((CHAR)(250 & 0xff)); case 0x0418: return((CHAR)(233 & 0xff)); case 0x0419: return((CHAR)(234 & 0xff)); case 0x041A: return((CHAR)(235 & 0xff)); case 0x041B: return((CHAR)(236 & 0xff)); case 0x041C: return((CHAR)(237 & 0xff)); case 0x041D: return((CHAR)(238 & 0xff)); case 0x041E: return((CHAR)(239 & 0xff)); case 0x041F: return((CHAR)(240 & 0xff)); case 0x0420: return((CHAR)(242 & 0xff)); case 0x0421: return((CHAR)(243 & 0xff)); case 0x0422: return((CHAR)(244 & 0xff)); case 0x0423: return((CHAR)(245 & 0xff)); case 0x0424: return((CHAR)(230 & 0xff)); case 0x0425: return((CHAR)(232 & 0xff)); case 0x0426: return((CHAR)(227 & 0xff)); case 0x0427: return((CHAR)(254 & 0xff)); case 0x0428: return((CHAR)(251 & 0xff)); case 0x0429: return((CHAR)(253 & 0xff)); case 0x042A: return((CHAR)(255 & 0xff)); case 0x042B: return((CHAR)(249 & 0xff)); case 0x042C: return((CHAR)(248 & 0xff)); case 0x042D: return((CHAR)(252 & 0xff)); case 0x042E: return((CHAR)(224 & 0xff)); case 0x042F: return((CHAR)(241 & 0xff)); case 0x0430: return((CHAR)(193 & 0xff)); case 0x0431: return((CHAR)(194 & 0xff)); case 0x0432: return((CHAR)(215 & 0xff)); case 0x0433: return((CHAR)(199 & 0xff)); case 0x0434: return((CHAR)(196 & 0xff)); case 0x0435: return((CHAR)(197 & 0xff)); case 0x0436: return((CHAR)(214 & 0xff)); case 0x0437: return((CHAR)(218 & 0xff)); case 0x0438: return((CHAR)(201 & 0xff)); case 0x0439: return((CHAR)(202 & 0xff)); case 0x043A: return((CHAR)(203 & 0xff)); case 0x043B: return((CHAR)(204 & 0xff)); case 0x043C: return((CHAR)(205 & 0xff)); case 0x043D: return((CHAR)(206 & 0xff)); case 0x043E: return((CHAR)(207 & 0xff)); case 0x043F: return((CHAR)(208 & 0xff)); case 0x0440: return((CHAR)(210 & 0xff)); case 0x0441: return((CHAR)(211 & 0xff)); case 0x0442: return((CHAR)(212 & 0xff)); case 0x0443: return((CHAR)(213 & 0xff)); case 0x0444: return((CHAR)(198 & 0xff)); case 0x0445: return((CHAR)(200 & 0xff)); case 0x0446: return((CHAR)(195 & 0xff)); case 0x0447: return((CHAR)(222 & 0xff)); case 0x0448: return((CHAR)(219 & 0xff)); case 0x0449: return((CHAR)(221 & 0xff)); case 0x044A: return((CHAR)(223 & 0xff)); case 0x044B: return((CHAR)(217 & 0xff)); case 0x044C: return((CHAR)(216 & 0xff)); case 0x044D: return((CHAR)(220 & 0xff)); case 0x044E: return((CHAR)(192 & 0xff)); case 0x044F: return((CHAR)(209 & 0xff)); case 0x0451: return((CHAR)(163 & 0xff)); case 0x2219: return((CHAR)(149 & 0xff)); case 0x221A: return((CHAR)(150 & 0xff)); case 0x2248: return((CHAR)(151 & 0xff)); case 0x2264: return((CHAR)(152 & 0xff)); case 0x2265: return((CHAR)(153 & 0xff)); case 0x2320: return((CHAR)(147 & 0xff)); case 0x2321: return((CHAR)(155 & 0xff)); case 0x2500: return((CHAR)(128 & 0xff)); case 0x2502: return((CHAR)(129 & 0xff)); case 0x250C: return((CHAR)(130 & 0xff)); case 0x2510: return((CHAR)(131 & 0xff)); case 0x2514: return((CHAR)(132 & 0xff)); case 0x2518: return((CHAR)(133 & 0xff)); case 0x251C: return((CHAR)(134 & 0xff)); case 0x2524: return((CHAR)(135 & 0xff)); case 0x252C: return((CHAR)(136 & 0xff)); case 0x2534: return((CHAR)(137 & 0xff)); case 0x253C: return((CHAR)(138 & 0xff)); case 0x2550: return((CHAR)(160 & 0xff)); case 0x2551: return((CHAR)(161 & 0xff)); case 0x2552: return((CHAR)(162 & 0xff)); case 0x2553: return((CHAR)(164 & 0xff)); case 0x2554: return((CHAR)(165 & 0xff)); case 0x2555: return((CHAR)(166 & 0xff)); case 0x2556: return((CHAR)(167 & 0xff)); case 0x2557: return((CHAR)(168 & 0xff)); case 0x2558: return((CHAR)(169 & 0xff)); case 0x2559: return((CHAR)(170 & 0xff)); case 0x255A: return((CHAR)(171 & 0xff)); case 0x255B: return((CHAR)(172 & 0xff)); case 0x255C: return((CHAR)(173 & 0xff)); case 0x255D: return((CHAR)(174 & 0xff)); case 0x255E: return((CHAR)(175 & 0xff)); case 0x255F: return((CHAR)(176 & 0xff)); case 0x2560: return((CHAR)(177 & 0xff)); case 0x2561: return((CHAR)(178 & 0xff)); case 0x2562: return((CHAR)(180 & 0xff)); case 0x2563: return((CHAR)(181 & 0xff)); case 0x2564: return((CHAR)(182 & 0xff)); case 0x2565: return((CHAR)(183 & 0xff)); case 0x2566: return((CHAR)(184 & 0xff)); case 0x2567: return((CHAR)(185 & 0xff)); case 0x2568: return((CHAR)(186 & 0xff)); case 0x2569: return((CHAR)(187 & 0xff)); case 0x256A: return((CHAR)(188 & 0xff)); case 0x256B: return((CHAR)(189 & 0xff)); case 0x256C: return((CHAR)(190 & 0xff)); case 0x2580: return((CHAR)(139 & 0xff)); case 0x2584: return((CHAR)(140 & 0xff)); case 0x2588: return((CHAR)(141 & 0xff)); case 0x258C: return((CHAR)(142 & 0xff)); case 0x2590: return((CHAR)(143 & 0xff)); case 0x2591: return((CHAR)(144 & 0xff)); case 0x2592: return((CHAR)(145 & 0xff)); case 0x2593: return((CHAR)(146 & 0xff)); case 0x25A0: return((CHAR)(148 & 0xff)); default: return(tx_ident(c)); } } int /* KOI8-U (Ukraine) */ #ifdef CK_ANSIC tx_koi8u(USHORT c) #else tx_koi8u(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) return((CHAR)(c & 0xff)); switch(c) { case 0x00A0: return((CHAR)(154 & 0xff)); case 0x00A9: return((CHAR)(191 & 0xff)); case 0x00B0: return((CHAR)(156 & 0xff)); case 0x00B2: return((CHAR)(157 & 0xff)); case 0x00B7: return((CHAR)(158 & 0xff)); case 0x00F7: return((CHAR)(159 & 0xff)); case 0x0401: return((CHAR)(179 & 0xff)); case 0x0404: return((CHAR)(180 & 0xff)); case 0x0406: return((CHAR)(182 & 0xff)); case 0x0407: return((CHAR)(183 & 0xff)); case 0x0410: return((CHAR)(225 & 0xff)); case 0x0411: return((CHAR)(226 & 0xff)); case 0x0412: return((CHAR)(247 & 0xff)); case 0x0413: return((CHAR)(231 & 0xff)); case 0x0414: return((CHAR)(228 & 0xff)); case 0x0415: return((CHAR)(229 & 0xff)); case 0x0416: return((CHAR)(246 & 0xff)); case 0x0417: return((CHAR)(250 & 0xff)); case 0x0418: return((CHAR)(233 & 0xff)); case 0x0419: return((CHAR)(234 & 0xff)); case 0x041A: return((CHAR)(235 & 0xff)); case 0x041B: return((CHAR)(236 & 0xff)); case 0x041C: return((CHAR)(237 & 0xff)); case 0x041D: return((CHAR)(238 & 0xff)); case 0x041E: return((CHAR)(239 & 0xff)); case 0x041F: return((CHAR)(240 & 0xff)); case 0x0420: return((CHAR)(242 & 0xff)); case 0x0421: return((CHAR)(243 & 0xff)); case 0x0422: return((CHAR)(244 & 0xff)); case 0x0423: return((CHAR)(245 & 0xff)); case 0x0424: return((CHAR)(230 & 0xff)); case 0x0425: return((CHAR)(232 & 0xff)); case 0x0426: return((CHAR)(227 & 0xff)); case 0x0427: return((CHAR)(254 & 0xff)); case 0x0428: return((CHAR)(251 & 0xff)); case 0x0429: return((CHAR)(253 & 0xff)); case 0x042A: return((CHAR)(255 & 0xff)); case 0x042B: return((CHAR)(249 & 0xff)); case 0x042C: return((CHAR)(248 & 0xff)); case 0x042D: return((CHAR)(252 & 0xff)); case 0x042E: return((CHAR)(224 & 0xff)); case 0x042F: return((CHAR)(241 & 0xff)); case 0x0430: return((CHAR)(193 & 0xff)); case 0x0431: return((CHAR)(194 & 0xff)); case 0x0432: return((CHAR)(215 & 0xff)); case 0x0433: return((CHAR)(199 & 0xff)); case 0x0434: return((CHAR)(196 & 0xff)); case 0x0435: return((CHAR)(197 & 0xff)); case 0x0436: return((CHAR)(214 & 0xff)); case 0x0437: return((CHAR)(218 & 0xff)); case 0x0438: return((CHAR)(201 & 0xff)); case 0x0439: return((CHAR)(202 & 0xff)); case 0x043A: return((CHAR)(203 & 0xff)); case 0x043B: return((CHAR)(204 & 0xff)); case 0x043C: return((CHAR)(205 & 0xff)); case 0x043D: return((CHAR)(206 & 0xff)); case 0x043E: return((CHAR)(207 & 0xff)); case 0x043F: return((CHAR)(208 & 0xff)); case 0x0440: return((CHAR)(210 & 0xff)); case 0x0441: return((CHAR)(211 & 0xff)); case 0x0442: return((CHAR)(212 & 0xff)); case 0x0443: return((CHAR)(213 & 0xff)); case 0x0444: return((CHAR)(198 & 0xff)); case 0x0445: return((CHAR)(200 & 0xff)); case 0x0446: return((CHAR)(195 & 0xff)); case 0x0447: return((CHAR)(222 & 0xff)); case 0x0448: return((CHAR)(219 & 0xff)); case 0x0449: return((CHAR)(221 & 0xff)); case 0x044A: return((CHAR)(223 & 0xff)); case 0x044B: return((CHAR)(217 & 0xff)); case 0x044C: return((CHAR)(216 & 0xff)); case 0x044D: return((CHAR)(220 & 0xff)); case 0x044E: return((CHAR)(192 & 0xff)); case 0x044F: return((CHAR)(209 & 0xff)); case 0x0451: return((CHAR)(163 & 0xff)); case 0x0454: return((CHAR)(164 & 0xff)); case 0x0456: return((CHAR)(166 & 0xff)); case 0x0457: return((CHAR)(167 & 0xff)); case 0x0490: return((CHAR)(189 & 0xff)); case 0x0491: return((CHAR)(173 & 0xff)); case 0x2219: return((CHAR)(149 & 0xff)); case 0x221A: return((CHAR)(150 & 0xff)); case 0x2248: return((CHAR)(151 & 0xff)); case 0x2264: return((CHAR)(152 & 0xff)); case 0x2265: return((CHAR)(153 & 0xff)); case 0x2320: return((CHAR)(147 & 0xff)); case 0x2321: return((CHAR)(155 & 0xff)); case 0x2500: return((CHAR)(128 & 0xff)); case 0x2502: return((CHAR)(129 & 0xff)); case 0x250C: return((CHAR)(130 & 0xff)); case 0x2510: return((CHAR)(131 & 0xff)); case 0x2514: return((CHAR)(132 & 0xff)); case 0x2518: return((CHAR)(133 & 0xff)); case 0x251C: return((CHAR)(134 & 0xff)); case 0x2524: return((CHAR)(135 & 0xff)); case 0x252C: return((CHAR)(136 & 0xff)); case 0x2534: return((CHAR)(137 & 0xff)); case 0x253C: return((CHAR)(138 & 0xff)); case 0x2550: return((CHAR)(160 & 0xff)); case 0x2551: return((CHAR)(161 & 0xff)); case 0x2552: return((CHAR)(162 & 0xff)); case 0x2554: return((CHAR)(165 & 0xff)); case 0x2557: return((CHAR)(168 & 0xff)); case 0x2558: return((CHAR)(169 & 0xff)); case 0x2559: return((CHAR)(170 & 0xff)); case 0x255A: return((CHAR)(171 & 0xff)); case 0x255B: return((CHAR)(172 & 0xff)); case 0x255D: return((CHAR)(174 & 0xff)); case 0x255E: return((CHAR)(175 & 0xff)); case 0x255F: return((CHAR)(176 & 0xff)); case 0x2560: return((CHAR)(177 & 0xff)); case 0x2561: return((CHAR)(178 & 0xff)); case 0x2563: return((CHAR)(181 & 0xff)); case 0x2566: return((CHAR)(184 & 0xff)); case 0x2567: return((CHAR)(185 & 0xff)); case 0x2568: return((CHAR)(186 & 0xff)); case 0x2569: return((CHAR)(187 & 0xff)); case 0x256A: return((CHAR)(188 & 0xff)); case 0x256C: return((CHAR)(190 & 0xff)); case 0x2580: return((CHAR)(139 & 0xff)); case 0x2584: return((CHAR)(140 & 0xff)); case 0x2588: return((CHAR)(141 & 0xff)); case 0x258C: return((CHAR)(142 & 0xff)); case 0x2590: return((CHAR)(143 & 0xff)); case 0x2591: return((CHAR)(144 & 0xff)); case 0x2592: return((CHAR)(145 & 0xff)); case 0x2593: return((CHAR)(146 & 0xff)); case 0x25A0: return((CHAR)(148 & 0xff)); default: return(tx_ident(c)); } } int /* DEC MCS */ #ifdef CK_ANSIC tx_decmcs(USHORT c) #else tx_decmcs(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) return((CHAR)(c & 0xff)); switch(c) { case 0x00a6: case 0x00a8: case 0x00ac: case 0x00ae: case 0x00af: case 0x00b4: case 0x00b8: case 0x00be: case 0x00d0: case 0x00de: case 0x00f0: case 0x00fe: case 0x00ff: return(-1); /* These are all undefined in DECMCS */ case 0x00a4: /* Currency sign */ return((CHAR)0xa8); case 0x0152: /* OE */ return((CHAR)0xd7); case 0x0153: /* oe */ return((CHAR)0xf7); default: return(tx_ident(c)); } } int /* NeXTSTEP */ #ifdef CK_ANSIC tx_nextstep(USHORT c) #else tx_nextstep(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00a0: return((CHAR)(128 & 0xff)); case 0x00a1: return((CHAR)(161 & 0xff)); case 0x00a2: return((CHAR)(162 & 0xff)); case 0x00a3: return((CHAR)(163 & 0xff)); case 0x00a4: return((CHAR)(168 & 0xff)); case 0x00a5: return((CHAR)(165 & 0xff)); case 0x00a6: return((CHAR)(181 & 0xff)); case 0x00a7: return((CHAR)(167 & 0xff)); case 0x00a8: return((CHAR)(200 & 0xff)); case 0x00a9: return((CHAR)(160 & 0xff)); case 0x00aa: return((CHAR)(227 & 0xff)); case 0x00ab: return((CHAR)(171 & 0xff)); case 0x00ac: return((CHAR)(190 & 0xff)); case 0x00ae: return((CHAR)(176 & 0xff)); case 0x00af: return((CHAR)(197 & 0xff)); case 0x00b1: return((CHAR)(209 & 0xff)); case 0x00b2: return((CHAR)(201 & 0xff)); case 0x00b3: return((CHAR)(204 & 0xff)); case 0x00b4: return((CHAR)(194 & 0xff)); case 0x00b5: return((CHAR)(157 & 0xff)); case 0x00b6: return((CHAR)(182 & 0xff)); case 0x00b7: return((CHAR)(180 & 0xff)); case 0x00b8: return((CHAR)(203 & 0xff)); case 0x00b9: return((CHAR)(192 & 0xff)); case 0x00ba: return((CHAR)(235 & 0xff)); case 0x00bb: return((CHAR)(187 & 0xff)); case 0x00bc: return((CHAR)(210 & 0xff)); case 0x00bd: return((CHAR)(211 & 0xff)); case 0x00be: return((CHAR)(212 & 0xff)); case 0x00bf: return((CHAR)(191 & 0xff)); case 0x00c0: return((CHAR)(129 & 0xff)); case 0x00c1: return((CHAR)(130 & 0xff)); case 0x00c2: return((CHAR)(131 & 0xff)); case 0x00c3: return((CHAR)(132 & 0xff)); case 0x00c4: return((CHAR)(133 & 0xff)); case 0x00c5: return((CHAR)(134 & 0xff)); case 0x00c6: return((CHAR)(225 & 0xff)); case 0x00c7: return((CHAR)(135 & 0xff)); case 0x00c8: return((CHAR)(136 & 0xff)); case 0x00c9: return((CHAR)(137 & 0xff)); case 0x00ca: return((CHAR)(138 & 0xff)); case 0x00cb: return((CHAR)(139 & 0xff)); case 0x00cc: return((CHAR)(140 & 0xff)); case 0x00cd: return((CHAR)(141 & 0xff)); case 0x00ce: return((CHAR)(142 & 0xff)); case 0x00cf: return((CHAR)(143 & 0xff)); case 0x00d0: return((CHAR)(144 & 0xff)); case 0x00d1: return((CHAR)(145 & 0xff)); case 0x00d2: return((CHAR)(146 & 0xff)); case 0x00d3: return((CHAR)(147 & 0xff)); case 0x00d4: return((CHAR)(148 & 0xff)); case 0x00d5: return((CHAR)(149 & 0xff)); case 0x00d6: return((CHAR)(150 & 0xff)); case 0x00d7: return((CHAR)(158 & 0xff)); case 0x00d8: return((CHAR)(233 & 0xff)); case 0x00d9: return((CHAR)(151 & 0xff)); case 0x00da: return((CHAR)(152 & 0xff)); case 0x00db: return((CHAR)(153 & 0xff)); case 0x00dc: return((CHAR)(154 & 0xff)); case 0x00dd: return((CHAR)(155 & 0xff)); case 0x00de: return((CHAR)(156 & 0xff)); case 0x00df: return((CHAR)(251 & 0xff)); case 0x00e0: return((CHAR)(213 & 0xff)); case 0x00e1: return((CHAR)(214 & 0xff)); case 0x00e2: return((CHAR)(215 & 0xff)); case 0x00e3: return((CHAR)(216 & 0xff)); case 0x00e4: return((CHAR)(217 & 0xff)); case 0x00e5: return((CHAR)(218 & 0xff)); case 0x00e6: return((CHAR)(241 & 0xff)); case 0x00e7: return((CHAR)(219 & 0xff)); case 0x00e8: return((CHAR)(220 & 0xff)); case 0x00e9: return((CHAR)(221 & 0xff)); case 0x00ea: return((CHAR)(222 & 0xff)); case 0x00eb: return((CHAR)(223 & 0xff)); case 0x00ec: return((CHAR)(224 & 0xff)); case 0x00ed: return((CHAR)(226 & 0xff)); case 0x00ee: return((CHAR)(228 & 0xff)); case 0x00ef: return((CHAR)(229 & 0xff)); case 0x00f0: return((CHAR)(230 & 0xff)); case 0x00f1: return((CHAR)(231 & 0xff)); case 0x00f2: return((CHAR)(236 & 0xff)); case 0x00f3: return((CHAR)(237 & 0xff)); case 0x00f4: return((CHAR)(238 & 0xff)); case 0x00f5: return((CHAR)(239 & 0xff)); case 0x00f6: return((CHAR)(240 & 0xff)); case 0x00f7: return((CHAR)(159 & 0xff)); case 0x00f8: return((CHAR)(249 & 0xff)); case 0x00f9: return((CHAR)(242 & 0xff)); case 0x00fa: return((CHAR)(243 & 0xff)); case 0x00fb: return((CHAR)(244 & 0xff)); case 0x00fc: return((CHAR)(246 & 0xff)); case 0x00fd: return((CHAR)(247 & 0xff)); case 0x00fe: return((CHAR)(252 & 0xff)); case 0x00ff: return((CHAR)(253 & 0xff)); case 0x0131: return((CHAR)(245 & 0xff)); case 0x0141: return((CHAR)(232 & 0xff)); case 0x0142: return((CHAR)(248 & 0xff)); case 0x0152: return((CHAR)(234 & 0xff)); case 0x0153: return((CHAR)(250 & 0xff)); case 0x0192: return((CHAR)(166 & 0xff)); case 0x02c6: return((CHAR)(195 & 0xff)); case 0x02c7: return((CHAR)(207 & 0xff)); case 0x02cb: return((CHAR)(193 & 0xff)); case 0x02d8: return((CHAR)(198 & 0xff)); case 0x02d9: return((CHAR)(199 & 0xff)); case 0x02da: return((CHAR)(202 & 0xff)); case 0x02db: return((CHAR)(206 & 0xff)); case 0x02dc: return((CHAR)(196 & 0xff)); case 0x02dd: return((CHAR)(205 & 0xff)); case 0x2013: return((CHAR)(177 & 0xff)); case 0x2014: return((CHAR)(208 & 0xff)); case 0x2019: return((CHAR)(169 & 0xff)); case 0x201a: return((CHAR)(184 & 0xff)); case 0x201c: return((CHAR)(170 & 0xff)); case 0x201d: return((CHAR)(186 & 0xff)); case 0x201e: return((CHAR)(185 & 0xff)); case 0x2020: return((CHAR)(178 & 0xff)); case 0x2021: return((CHAR)(179 & 0xff)); case 0x2022: return((CHAR)(183 & 0xff)); case 0x2026: return((CHAR)(188 & 0xff)); case 0x2030: return((CHAR)(189 & 0xff)); case 0x2039: return((CHAR)(172 & 0xff)); case 0x203a: return((CHAR)(173 & 0xff)); case 0x2044: return((CHAR)(164 & 0xff)); case 0xfb01: return((CHAR)(174 & 0xff)); case 0xfb02: return((CHAR)(175 & 0xff)); default: return(tx_punc(c)); } } int /* DG International */ #ifdef CK_ANSIC tx_dgi(USHORT c) #else tx_dgi(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) return((CHAR)(c & 0xff)); switch(c) { case 0x00a0: return((CHAR)(160 & 0xff)); case 0x00a1: return((CHAR)(171 & 0xff)); case 0x00a2: return((CHAR)(167 & 0xff)); case 0x00a3: return((CHAR)(168 & 0xff)); case 0x00a4: return((CHAR)(166 & 0xff)); case 0x00a5: return((CHAR)(181 & 0xff)); case 0x00a7: return((CHAR)(187 & 0xff)); case 0x00a8: return((CHAR)(189 & 0xff)); case 0x00a9: return((CHAR)(173 & 0xff)); case 0x00aa: return((CHAR)(169 & 0xff)); case 0x00ab: return((CHAR)(177 & 0xff)); case 0x00ac: return((CHAR)(161 & 0xff)); case 0x00ae: return((CHAR)(174 & 0xff)); case 0x00b0: return((CHAR)(188 & 0xff)); case 0x00b1: return((CHAR)(182 & 0xff)); case 0x00b2: return((CHAR)(164 & 0xff)); case 0x00b3: return((CHAR)(165 & 0xff)); case 0x00b4: return((CHAR)(190 & 0xff)); case 0x00b5: return((CHAR)(163 & 0xff)); case 0x00b6: return((CHAR)(178 & 0xff)); case 0x00b7: return((CHAR)(185 & 0xff)); case 0x00b8: return((CHAR)(186 & 0xff)); case 0x00ba: return((CHAR)(170 & 0xff)); case 0x00bb: return((CHAR)(176 & 0xff)); case 0x00bd: return((CHAR)(162 & 0xff)); case 0x00bf: return((CHAR)(172 & 0xff)); case 0x00c0: return((CHAR)(193 & 0xff)); case 0x00c1: return((CHAR)(192 & 0xff)); case 0x00c2: return((CHAR)(194 & 0xff)); case 0x00c3: return((CHAR)(196 & 0xff)); case 0x00c4: return((CHAR)(195 & 0xff)); case 0x00c5: return((CHAR)(197 & 0xff)); case 0x00c6: return((CHAR)(198 & 0xff)); case 0x00c7: return((CHAR)(199 & 0xff)); case 0x00c8: return((CHAR)(201 & 0xff)); case 0x00c9: return((CHAR)(200 & 0xff)); case 0x00ca: return((CHAR)(202 & 0xff)); case 0x00cb: return((CHAR)(203 & 0xff)); case 0x00cc: return((CHAR)(205 & 0xff)); case 0x00cd: return((CHAR)(204 & 0xff)); case 0x00ce: return((CHAR)(206 & 0xff)); case 0x00cf: return((CHAR)(207 & 0xff)); case 0x00d1: return((CHAR)(208 & 0xff)); case 0x00d2: return((CHAR)(210 & 0xff)); case 0x00d3: return((CHAR)(209 & 0xff)); case 0x00d4: return((CHAR)(211 & 0xff)); case 0x00d5: return((CHAR)(213 & 0xff)); case 0x00d6: return((CHAR)(212 & 0xff)); case 0x00d8: return((CHAR)(214 & 0xff)); case 0x00d9: return((CHAR)(217 & 0xff)); case 0x00da: return((CHAR)(216 & 0xff)); case 0x00db: return((CHAR)(218 & 0xff)); case 0x00dc: return((CHAR)(219 & 0xff)); case 0x00df: return((CHAR)(252 & 0xff)); case 0x00e0: return((CHAR)(225 & 0xff)); case 0x00e1: return((CHAR)(224 & 0xff)); case 0x00e2: return((CHAR)(226 & 0xff)); case 0x00e3: return((CHAR)(228 & 0xff)); case 0x00e4: return((CHAR)(227 & 0xff)); case 0x00e5: return((CHAR)(229 & 0xff)); case 0x00e6: return((CHAR)(230 & 0xff)); case 0x00e7: return((CHAR)(231 & 0xff)); case 0x00e8: return((CHAR)(233 & 0xff)); case 0x00e9: return((CHAR)(232 & 0xff)); case 0x00ea: return((CHAR)(234 & 0xff)); case 0x00eb: return((CHAR)(235 & 0xff)); case 0x00ec: return((CHAR)(237 & 0xff)); case 0x00ed: return((CHAR)(236 & 0xff)); case 0x00ee: return((CHAR)(238 & 0xff)); case 0x00ef: return((CHAR)(239 & 0xff)); case 0x00f1: return((CHAR)(240 & 0xff)); case 0x00f2: return((CHAR)(242 & 0xff)); case 0x00f3: return((CHAR)(241 & 0xff)); case 0x00f4: return((CHAR)(243 & 0xff)); case 0x00f5: return((CHAR)(245 & 0xff)); case 0x00f6: return((CHAR)(244 & 0xff)); case 0x00f8: return((CHAR)(246 & 0xff)); case 0x00f9: return((CHAR)(249 & 0xff)); case 0x00fa: return((CHAR)(248 & 0xff)); case 0x00fb: return((CHAR)(250 & 0xff)); case 0x00fc: return((CHAR)(251 & 0xff)); case 0x00ff: return((CHAR)(253 & 0xff)); case 0x0153: return((CHAR)(247 & 0xff)); case 0x0178: return((CHAR)(221 & 0xff)); case 0x0192: return((CHAR)(180 & 0xff)); case 0x0276: return((CHAR)(215 & 0xff)); case 0x2021: return((CHAR)(175 & 0xff)); case 0x2122: return((CHAR)(179 & 0xff)); case 0x2191: return((CHAR)(191 & 0xff)); case 0x2264: return((CHAR)(183 & 0xff)); case 0x2265: return((CHAR)(184 & 0xff)); case 0x2588: return((CHAR)(255 & 0xff)); default: return(tx_punc(c)); } } int /* Macintosh Latin */ #ifdef CK_ANSIC tx_maclatin(USHORT c) #else tx_maclatin(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00a0: return((CHAR)(202 & 0xff)); case 0x00a1: return((CHAR)(193 & 0xff)); case 0x00a2: return((CHAR)(162 & 0xff)); case 0x00a3: return((CHAR)(163 & 0xff)); case 0x00a4: return((CHAR)(219 & 0xff)); case 0x00a5: return((CHAR)(180 & 0xff)); case 0x00a7: return((CHAR)(164 & 0xff)); case 0x00a8: return((CHAR)(172 & 0xff)); case 0x00a9: return((CHAR)(169 & 0xff)); case 0x00aa: return((CHAR)(187 & 0xff)); case 0x00ab: return((CHAR)(199 & 0xff)); case 0x00ac: return((CHAR)(194 & 0xff)); case 0x00ae: return((CHAR)(168 & 0xff)); case 0x00af: return((CHAR)(248 & 0xff)); case 0x00b0: return((CHAR)(161 & 0xff)); case 0x00b1: return((CHAR)(177 & 0xff)); case 0x00b4: return((CHAR)(171 & 0xff)); case 0x00b5: return((CHAR)(181 & 0xff)); case 0x00b6: return((CHAR)(166 & 0xff)); case 0x00b7: return((CHAR)(225 & 0xff)); case 0x00b8: return((CHAR)(252 & 0xff)); case 0x00ba: return((CHAR)(188 & 0xff)); case 0x00bb: return((CHAR)(200 & 0xff)); case 0x00bf: return((CHAR)(192 & 0xff)); case 0x00c0: return((CHAR)(203 & 0xff)); case 0x00c1: return((CHAR)(231 & 0xff)); case 0x00c2: return((CHAR)(229 & 0xff)); case 0x00c3: return((CHAR)(204 & 0xff)); case 0x00c4: return((CHAR)(128 & 0xff)); case 0x00c5: return((CHAR)(129 & 0xff)); case 0x00c6: return((CHAR)(174 & 0xff)); case 0x00c7: return((CHAR)(130 & 0xff)); case 0x00c8: return((CHAR)(233 & 0xff)); case 0x00c9: return((CHAR)(131 & 0xff)); case 0x00ca: return((CHAR)(230 & 0xff)); case 0x00cb: return((CHAR)(232 & 0xff)); case 0x00cc: return((CHAR)(237 & 0xff)); case 0x00cd: return((CHAR)(234 & 0xff)); case 0x00ce: return((CHAR)(235 & 0xff)); case 0x00cf: return((CHAR)(236 & 0xff)); case 0x00d0: return((CHAR)(220 & 0xff)); case 0x00d1: return((CHAR)(132 & 0xff)); case 0x00d2: return((CHAR)(241 & 0xff)); case 0x00d3: return((CHAR)(238 & 0xff)); case 0x00d4: return((CHAR)(239 & 0xff)); case 0x00d5: return((CHAR)(205 & 0xff)); case 0x00d6: return((CHAR)(133 & 0xff)); case 0x00d8: return((CHAR)(175 & 0xff)); case 0x00d9: return((CHAR)(244 & 0xff)); case 0x00da: return((CHAR)(242 & 0xff)); case 0x00db: return((CHAR)(243 & 0xff)); case 0x00dc: return((CHAR)(134 & 0xff)); case 0x00dd: return((CHAR)(160 & 0xff)); case 0x00de: return((CHAR)(222 & 0xff)); case 0x00df: return((CHAR)(167 & 0xff)); case 0x00e0: return((CHAR)(136 & 0xff)); case 0x00e1: return((CHAR)(135 & 0xff)); case 0x00e2: return((CHAR)(137 & 0xff)); case 0x00e3: return((CHAR)(139 & 0xff)); case 0x00e4: return((CHAR)(138 & 0xff)); case 0x00e5: return((CHAR)(140 & 0xff)); case 0x00e6: return((CHAR)(190 & 0xff)); case 0x00e7: return((CHAR)(141 & 0xff)); case 0x00e8: return((CHAR)(143 & 0xff)); case 0x00e9: return((CHAR)(142 & 0xff)); case 0x00ea: return((CHAR)(144 & 0xff)); case 0x00eb: return((CHAR)(145 & 0xff)); case 0x00ec: return((CHAR)(147 & 0xff)); case 0x00ed: return((CHAR)(146 & 0xff)); case 0x00ee: return((CHAR)(148 & 0xff)); case 0x00ef: return((CHAR)(149 & 0xff)); case 0x00f0: return((CHAR)(221 & 0xff)); case 0x00f1: return((CHAR)(150 & 0xff)); case 0x00f2: return((CHAR)(152 & 0xff)); case 0x00f3: return((CHAR)(151 & 0xff)); case 0x00f4: return((CHAR)(153 & 0xff)); case 0x00f5: return((CHAR)(155 & 0xff)); case 0x00f6: return((CHAR)(154 & 0xff)); case 0x00f7: return((CHAR)(214 & 0xff)); case 0x00f8: return((CHAR)(191 & 0xff)); case 0x00f9: return((CHAR)(157 & 0xff)); case 0x00fa: return((CHAR)(156 & 0xff)); case 0x00fb: return((CHAR)(158 & 0xff)); case 0x00fc: return((CHAR)(159 & 0xff)); case 0x00fd: return((CHAR)(224 & 0xff)); case 0x00fe: return((CHAR)(223 & 0xff)); case 0x00ff: return((CHAR)(216 & 0xff)); case 0x0131: return((CHAR)(245 & 0xff)); case 0x0152: return((CHAR)(206 & 0xff)); case 0x0153: return((CHAR)(207 & 0xff)); case 0x0178: return((CHAR)(217 & 0xff)); case 0x0192: return((CHAR)(196 & 0xff)); case 0x02c6: return((CHAR)(246 & 0xff)); case 0x02c7: return((CHAR)(255 & 0xff)); case 0x02d8: return((CHAR)(249 & 0xff)); case 0x02d9: return((CHAR)(250 & 0xff)); case 0x02da: return((CHAR)(251 & 0xff)); case 0x02db: return((CHAR)(254 & 0xff)); case 0x02dc: return((CHAR)(247 & 0xff)); case 0x02dd: return((CHAR)(253 & 0xff)); case 0x03c0: return((CHAR)(185 & 0xff)); case 0x2013: return((CHAR)(208 & 0xff)); case 0x2014: return((CHAR)(209 & 0xff)); case 0x2018: return((CHAR)(212 & 0xff)); case 0x2019: return((CHAR)(213 & 0xff)); case 0x201a: return((CHAR)(226 & 0xff)); case 0x201c: return((CHAR)(210 & 0xff)); case 0x201d: return((CHAR)(211 & 0xff)); case 0x201e: return((CHAR)(227 & 0xff)); case 0x2022: return((CHAR)(165 & 0xff)); case 0x2026: return((CHAR)(201 & 0xff)); case 0x2030: return((CHAR)(228 & 0xff)); case 0x2044: return((CHAR)(218 & 0xff)); case 0x2122: return((CHAR)(170 & 0xff)); case 0x2126: return((CHAR)(189 & 0xff)); case 0x2202: return((CHAR)(182 & 0xff)); case 0x2206: return((CHAR)(198 & 0xff)); case 0x220f: return((CHAR)(184 & 0xff)); case 0x2211: return((CHAR)(183 & 0xff)); case 0x221a: return((CHAR)(195 & 0xff)); case 0x221e: return((CHAR)(176 & 0xff)); case 0x222b: return((CHAR)(186 & 0xff)); case 0x2248: return((CHAR)(197 & 0xff)); case 0x2260: return((CHAR)(173 & 0xff)); case 0x2264: return((CHAR)(178 & 0xff)); case 0x2265: return((CHAR)(179 & 0xff)); case 0x25ca: return((CHAR)(215 & 0xff)); case 0xf8ff: return((CHAR)(240 & 0xff)); default: return(tx_punc(c)); } } int /* Apple QuickDraw / CP10000 */ #ifdef CK_ANSIC tx_quickdraw(USHORT c) #else tx_quickdraw(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00a0: return((CHAR)(202 & 0xff)); case 0x00a1: return((CHAR)(193 & 0xff)); case 0x00a2: return((CHAR)(162 & 0xff)); case 0x00a3: return((CHAR)(163 & 0xff)); case 0x00a4: return((CHAR)(219 & 0xff)); case 0x00a5: return((CHAR)(180 & 0xff)); case 0x00a7: return((CHAR)(164 & 0xff)); case 0x00a8: return((CHAR)(172 & 0xff)); case 0x00a9: return((CHAR)(169 & 0xff)); case 0x00aa: return((CHAR)(187 & 0xff)); case 0x00ab: return((CHAR)(199 & 0xff)); case 0x00ac: return((CHAR)(194 & 0xff)); case 0x00ae: return((CHAR)(168 & 0xff)); case 0x00af: return((CHAR)(248 & 0xff)); case 0x00b0: return((CHAR)(161 & 0xff)); case 0x00b1: return((CHAR)(177 & 0xff)); case 0x00b4: return((CHAR)(171 & 0xff)); case 0x00b5: return((CHAR)(181 & 0xff)); case 0x00b6: return((CHAR)(166 & 0xff)); case 0x00b7: return((CHAR)(225 & 0xff)); case 0x00b8: return((CHAR)(252 & 0xff)); case 0x00ba: return((CHAR)(188 & 0xff)); case 0x00bb: return((CHAR)(200 & 0xff)); case 0x00bf: return((CHAR)(192 & 0xff)); case 0x00c0: return((CHAR)(203 & 0xff)); case 0x00c1: return((CHAR)(231 & 0xff)); case 0x00c2: return((CHAR)(229 & 0xff)); case 0x00c3: return((CHAR)(204 & 0xff)); case 0x00c4: return((CHAR)(128 & 0xff)); case 0x00c5: return((CHAR)(129 & 0xff)); case 0x00c6: return((CHAR)(174 & 0xff)); case 0x00c7: return((CHAR)(130 & 0xff)); case 0x00c8: return((CHAR)(233 & 0xff)); case 0x00c9: return((CHAR)(131 & 0xff)); case 0x00ca: return((CHAR)(230 & 0xff)); case 0x00cb: return((CHAR)(232 & 0xff)); case 0x00cc: return((CHAR)(237 & 0xff)); case 0x00cd: return((CHAR)(234 & 0xff)); case 0x00ce: return((CHAR)(235 & 0xff)); case 0x00cf: return((CHAR)(236 & 0xff)); case 0x2039: return((CHAR)(220 & 0xff)); case 0x00d1: return((CHAR)(132 & 0xff)); case 0x00d2: return((CHAR)(241 & 0xff)); case 0x00d3: return((CHAR)(238 & 0xff)); case 0x00d4: return((CHAR)(239 & 0xff)); case 0x00d5: return((CHAR)(205 & 0xff)); case 0x00d6: return((CHAR)(133 & 0xff)); case 0x00d8: return((CHAR)(175 & 0xff)); case 0x00d9: return((CHAR)(244 & 0xff)); case 0x00da: return((CHAR)(242 & 0xff)); case 0x00db: return((CHAR)(243 & 0xff)); case 0x00dc: return((CHAR)(134 & 0xff)); case 0x2020: return((CHAR)(160 & 0xff)); case 0xfb01: return((CHAR)(222 & 0xff)); case 0x00df: return((CHAR)(167 & 0xff)); case 0x00e0: return((CHAR)(136 & 0xff)); case 0x00e1: return((CHAR)(135 & 0xff)); case 0x00e2: return((CHAR)(137 & 0xff)); case 0x00e3: return((CHAR)(139 & 0xff)); case 0x00e4: return((CHAR)(138 & 0xff)); case 0x00e5: return((CHAR)(140 & 0xff)); case 0x00e6: return((CHAR)(190 & 0xff)); case 0x00e7: return((CHAR)(141 & 0xff)); case 0x00e8: return((CHAR)(143 & 0xff)); case 0x00e9: return((CHAR)(142 & 0xff)); case 0x00ea: return((CHAR)(144 & 0xff)); case 0x00eb: return((CHAR)(145 & 0xff)); case 0x00ec: return((CHAR)(147 & 0xff)); case 0x00ed: return((CHAR)(146 & 0xff)); case 0x00ee: return((CHAR)(148 & 0xff)); case 0x00ef: return((CHAR)(149 & 0xff)); case 0x203a: return((CHAR)(221 & 0xff)); case 0x00f1: return((CHAR)(150 & 0xff)); case 0x00f2: return((CHAR)(152 & 0xff)); case 0x00f3: return((CHAR)(151 & 0xff)); case 0x00f4: return((CHAR)(153 & 0xff)); case 0x00f5: return((CHAR)(155 & 0xff)); case 0x00f6: return((CHAR)(154 & 0xff)); case 0x00f7: return((CHAR)(214 & 0xff)); case 0x00f8: return((CHAR)(191 & 0xff)); case 0x00f9: return((CHAR)(157 & 0xff)); case 0x00fa: return((CHAR)(156 & 0xff)); case 0x00fb: return((CHAR)(158 & 0xff)); case 0x00fc: return((CHAR)(159 & 0xff)); case 0x2021: return((CHAR)(224 & 0xff)); case 0xfb02: return((CHAR)(223 & 0xff)); case 0x00ff: return((CHAR)(216 & 0xff)); case 0x0131: return((CHAR)(245 & 0xff)); case 0x0152: return((CHAR)(206 & 0xff)); case 0x0153: return((CHAR)(207 & 0xff)); case 0x0178: return((CHAR)(217 & 0xff)); case 0x0192: return((CHAR)(196 & 0xff)); case 0x02c6: return((CHAR)(246 & 0xff)); case 0x02c7: return((CHAR)(255 & 0xff)); case 0x02d8: return((CHAR)(249 & 0xff)); case 0x02d9: return((CHAR)(250 & 0xff)); case 0x02da: return((CHAR)(251 & 0xff)); case 0x02db: return((CHAR)(254 & 0xff)); case 0x02dc: return((CHAR)(247 & 0xff)); case 0x02dd: return((CHAR)(253 & 0xff)); case 0x03c0: return((CHAR)(185 & 0xff)); case 0x2013: return((CHAR)(208 & 0xff)); case 0x2014: return((CHAR)(209 & 0xff)); case 0x2018: return((CHAR)(212 & 0xff)); case 0x2019: return((CHAR)(213 & 0xff)); case 0x201a: return((CHAR)(226 & 0xff)); case 0x201c: return((CHAR)(210 & 0xff)); case 0x201d: return((CHAR)(211 & 0xff)); case 0x201e: return((CHAR)(227 & 0xff)); case 0x2022: return((CHAR)(165 & 0xff)); case 0x2026: return((CHAR)(201 & 0xff)); case 0x2030: return((CHAR)(228 & 0xff)); case 0x2044: return((CHAR)(218 & 0xff)); case 0x2122: return((CHAR)(170 & 0xff)); case 0x03a9: return((CHAR)(189 & 0xff)); case 0x2202: return((CHAR)(182 & 0xff)); case 0x2206: return((CHAR)(198 & 0xff)); case 0x220f: return((CHAR)(184 & 0xff)); case 0x2211: return((CHAR)(183 & 0xff)); case 0x221a: return((CHAR)(195 & 0xff)); case 0x221e: return((CHAR)(176 & 0xff)); case 0x222b: return((CHAR)(186 & 0xff)); case 0x2248: return((CHAR)(197 & 0xff)); case 0x2260: return((CHAR)(173 & 0xff)); case 0x2264: return((CHAR)(178 & 0xff)); case 0x2265: return((CHAR)(179 & 0xff)); case 0x25ca: return((CHAR)(215 & 0xff)); case 0xf8ff: return((CHAR)(240 & 0xff)); default: return(tx_punc(c)); } } int /* HP Roman-8 */ #ifdef CK_ANSIC tx_hproman8(USHORT c) #else tx_hproman8(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xa0) return((CHAR)(c & 0xff)); switch(c) { case 0x00a0: return((CHAR)(160 & 0xff)); case 0x00a1: return((CHAR)(171 & 0xff)); case 0x00a2: return((CHAR)(167 & 0xff)); case 0x00a3: return((CHAR)(168 & 0xff)); case 0x00a4: return((CHAR)(166 & 0xff)); case 0x00a5: return((CHAR)(181 & 0xff)); case 0x00a7: return((CHAR)(187 & 0xff)); case 0x00a8: return((CHAR)(189 & 0xff)); case 0x00a9: return((CHAR)(173 & 0xff)); case 0x00aa: return((CHAR)(169 & 0xff)); case 0x00ab: return((CHAR)(177 & 0xff)); case 0x00ac: return((CHAR)(161 & 0xff)); case 0x00ae: return((CHAR)(174 & 0xff)); case 0x00b0: return((CHAR)(188 & 0xff)); case 0x00b1: return((CHAR)(182 & 0xff)); case 0x00b2: return((CHAR)(164 & 0xff)); case 0x00b3: return((CHAR)(165 & 0xff)); case 0x00b4: return((CHAR)(190 & 0xff)); case 0x00b5: return((CHAR)(163 & 0xff)); case 0x00b6: return((CHAR)(178 & 0xff)); case 0x00b7: return((CHAR)(185 & 0xff)); case 0x00b8: return((CHAR)(186 & 0xff)); case 0x00ba: return((CHAR)(170 & 0xff)); case 0x00bb: return((CHAR)(176 & 0xff)); case 0x00bd: return((CHAR)(162 & 0xff)); case 0x00bf: return((CHAR)(172 & 0xff)); case 0x00c0: return((CHAR)(193 & 0xff)); case 0x00c1: return((CHAR)(192 & 0xff)); case 0x00c2: return((CHAR)(194 & 0xff)); case 0x00c3: return((CHAR)(196 & 0xff)); case 0x00c4: return((CHAR)(195 & 0xff)); case 0x00c5: return((CHAR)(197 & 0xff)); case 0x00c6: return((CHAR)(198 & 0xff)); case 0x00c7: return((CHAR)(199 & 0xff)); case 0x00c8: return((CHAR)(201 & 0xff)); case 0x00c9: return((CHAR)(200 & 0xff)); case 0x00ca: return((CHAR)(202 & 0xff)); case 0x00cb: return((CHAR)(203 & 0xff)); case 0x00cc: return((CHAR)(205 & 0xff)); case 0x00cd: return((CHAR)(204 & 0xff)); case 0x00ce: return((CHAR)(206 & 0xff)); case 0x00cf: return((CHAR)(207 & 0xff)); case 0x00d1: return((CHAR)(208 & 0xff)); case 0x00d2: return((CHAR)(210 & 0xff)); case 0x00d3: return((CHAR)(209 & 0xff)); case 0x00d4: return((CHAR)(211 & 0xff)); case 0x00d5: return((CHAR)(213 & 0xff)); case 0x00d6: return((CHAR)(212 & 0xff)); case 0x00d8: return((CHAR)(214 & 0xff)); case 0x00d9: return((CHAR)(217 & 0xff)); case 0x00da: return((CHAR)(216 & 0xff)); case 0x00db: return((CHAR)(218 & 0xff)); case 0x00dc: return((CHAR)(219 & 0xff)); case 0x00df: return((CHAR)(252 & 0xff)); case 0x00e0: return((CHAR)(225 & 0xff)); case 0x00e1: return((CHAR)(224 & 0xff)); case 0x00e2: return((CHAR)(226 & 0xff)); case 0x00e3: return((CHAR)(228 & 0xff)); case 0x00e4: return((CHAR)(227 & 0xff)); case 0x00e5: return((CHAR)(229 & 0xff)); case 0x00e6: return((CHAR)(230 & 0xff)); case 0x00e7: return((CHAR)(231 & 0xff)); case 0x00e8: return((CHAR)(233 & 0xff)); case 0x00e9: return((CHAR)(232 & 0xff)); case 0x00ea: return((CHAR)(234 & 0xff)); case 0x00eb: return((CHAR)(235 & 0xff)); case 0x00ec: return((CHAR)(237 & 0xff)); case 0x00ed: return((CHAR)(236 & 0xff)); case 0x00ee: return((CHAR)(238 & 0xff)); case 0x00ef: return((CHAR)(239 & 0xff)); case 0x00f1: return((CHAR)(240 & 0xff)); case 0x00f2: return((CHAR)(242 & 0xff)); case 0x00f3: return((CHAR)(241 & 0xff)); case 0x00f4: return((CHAR)(243 & 0xff)); case 0x00f5: return((CHAR)(245 & 0xff)); case 0x00f6: return((CHAR)(244 & 0xff)); case 0x00f8: return((CHAR)(246 & 0xff)); case 0x00f9: return((CHAR)(249 & 0xff)); case 0x00fa: return((CHAR)(248 & 0xff)); case 0x00fb: return((CHAR)(250 & 0xff)); case 0x00fc: return((CHAR)(251 & 0xff)); case 0x00ff: return((CHAR)(253 & 0xff)); case 0x0153: return((CHAR)(247 & 0xff)); case 0x0178: return((CHAR)(221 & 0xff)); case 0x0192: return((CHAR)(180 & 0xff)); case 0x0276: return((CHAR)(215 & 0xff)); case 0x2021: return((CHAR)(175 & 0xff)); case 0x2122: return((CHAR)(179 & 0xff)); case 0x2191: return((CHAR)(191 & 0xff)); case 0x2264: return((CHAR)(183 & 0xff)); case 0x2265: return((CHAR)(184 & 0xff)); case 0x2588: return((CHAR)(255 & 0xff)); default: return(tx_punc(c)); } } int /* PC Code Page 437 */ #ifdef CK_ANSIC tx_cp437(USHORT c) #else tx_cp437(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00a0: return((CHAR)(255 & 0xff)); case 0x00a1: return((CHAR)(173 & 0xff)); case 0x00a2: return((CHAR)(155 & 0xff)); case 0x00a3: return((CHAR)(156 & 0xff)); case 0x00a4: return((CHAR)(15 & 0xff)); case 0x00a5: return((CHAR)(157 & 0xff)); case 0x00a6: return((CHAR)(124 & 0xff)); case 0x00a7: return((CHAR)(21 & 0xff)); case 0x00a8: return((CHAR)(34 & 0xff)); case 0x00a9: return((CHAR)(67 & 0xff)); case 0x00aa: return((CHAR)(166 & 0xff)); case 0x00ab: return((CHAR)(174 & 0xff)); case 0x00ac: return((CHAR)(170 & 0xff)); case 0x00ad: return((CHAR)(45 & 0xff)); case 0x00ae: return((CHAR)(84 & 0xff)); case 0x00af: return((CHAR)(22 & 0xff)); case 0x00b0: return((CHAR)(248 & 0xff)); case 0x00b1: return((CHAR)(241 & 0xff)); case 0x00b2: return((CHAR)(253 & 0xff)); case 0x00b3: return((CHAR)(51 & 0xff)); case 0x00b4: return((CHAR)(39 & 0xff)); case 0x00b5: return((CHAR)(230 & 0xff)); case 0x00b6: return((CHAR)(20 & 0xff)); case 0x00b7: return((CHAR)(250 & 0xff)); case 0x00b8: return((CHAR)(44 & 0xff)); case 0x00b9: return((CHAR)(49 & 0xff)); case 0x00ba: return((CHAR)(167 & 0xff)); case 0x00bb: return((CHAR)(175 & 0xff)); case 0x00bc: return((CHAR)(172 & 0xff)); case 0x00bd: return((CHAR)(171 & 0xff)); case 0x00be: return((CHAR)(19 & 0xff)); case 0x00bf: return((CHAR)(168 & 0xff)); case 0x00c0: return((CHAR)(65 & 0xff)); case 0x00c1: return((CHAR)(65 & 0xff)); case 0x00c2: return((CHAR)(65 & 0xff)); case 0x00c3: return((CHAR)(65 & 0xff)); case 0x00c4: return((CHAR)(142 & 0xff)); case 0x00c5: return((CHAR)(143 & 0xff)); case 0x00c6: return((CHAR)(146 & 0xff)); case 0x00c7: return((CHAR)(128 & 0xff)); case 0x00c8: return((CHAR)(69 & 0xff)); case 0x00c9: return((CHAR)(144 & 0xff)); case 0x00ca: return((CHAR)(69 & 0xff)); case 0x00cb: return((CHAR)(69 & 0xff)); case 0x00cc: return((CHAR)(73 & 0xff)); case 0x00cd: return((CHAR)(73 & 0xff)); case 0x00ce: return((CHAR)(73 & 0xff)); case 0x00cf: return((CHAR)(73 & 0xff)); case 0x00d0: return((CHAR)(19 & 0xff)); case 0x00d1: return((CHAR)(165 & 0xff)); case 0x00d2: return((CHAR)(79 & 0xff)); case 0x00d3: return((CHAR)(79 & 0xff)); case 0x00d4: return((CHAR)(79 & 0xff)); case 0x00d5: return((CHAR)(79 & 0xff)); case 0x00d6: return((CHAR)(153 & 0xff)); case 0x00d7: return((CHAR)(120 & 0xff)); case 0x00d8: return((CHAR)(79 & 0xff)); case 0x00d9: return((CHAR)(85 & 0xff)); case 0x00da: return((CHAR)(85 & 0xff)); case 0x00db: return((CHAR)(85 & 0xff)); case 0x00dc: return((CHAR)(154 & 0xff)); case 0x00dd: return((CHAR)(89 & 0xff)); case 0x00de: return((CHAR)(19 & 0xff)); case 0x00df: return((CHAR)(225 & 0xff)); case 0x00e0: return((CHAR)(133 & 0xff)); case 0x00e1: return((CHAR)(160 & 0xff)); case 0x00e2: return((CHAR)(131 & 0xff)); case 0x00e3: return((CHAR)(97 & 0xff)); /* a-tilde -> a (not 101 = e) */ case 0x00e4: return((CHAR)(132 & 0xff)); case 0x00e5: return((CHAR)(134 & 0xff)); case 0x00e6: return((CHAR)(145 & 0xff)); case 0x00e7: return((CHAR)(135 & 0xff)); case 0x00e8: return((CHAR)(138 & 0xff)); case 0x00e9: return((CHAR)(130 & 0xff)); case 0x00ea: return((CHAR)(136 & 0xff)); case 0x00eb: return((CHAR)(137 & 0xff)); case 0x00ec: return((CHAR)(141 & 0xff)); case 0x00ed: return((CHAR)(161 & 0xff)); case 0x00ee: return((CHAR)(140 & 0xff)); case 0x00ef: return((CHAR)(139 & 0xff)); case 0x00f0: return((CHAR)(19 & 0xff)); case 0x00f1: return((CHAR)(164 & 0xff)); case 0x00f2: return((CHAR)(149 & 0xff)); case 0x00f3: return((CHAR)(162 & 0xff)); case 0x00f4: return((CHAR)(147 & 0xff)); case 0x00f5: return((CHAR)(111 & 0xff)); case 0x00f6: return((CHAR)(148 & 0xff)); case 0x00f7: return((CHAR)(246 & 0xff)); case 0x00f8: return((CHAR)(111 & 0xff)); case 0x00f9: return((CHAR)(151 & 0xff)); case 0x00fa: return((CHAR)(163 & 0xff)); case 0x00fb: return((CHAR)(150 & 0xff)); case 0x00fc: return((CHAR)(129 & 0xff)); case 0x00fd: return((CHAR)(121 & 0xff)); case 0x00fe: return((CHAR)(19 & 0xff)); case 0x00ff: return((CHAR)(152 & 0xff)); case 0x0192: return((CHAR)(159 & 0xff)); case 0x0393: return((CHAR)(226 & 0xff)); case 0x0398: return((CHAR)(233 & 0xff)); case 0x03a3: return((CHAR)(228 & 0xff)); case 0x03a6: return((CHAR)(232 & 0xff)); case 0x03a9: return((CHAR)(234 & 0xff)); case 0x03b1: return((CHAR)(224 & 0xff)); case 0x03b4: return((CHAR)(235 & 0xff)); case 0x03b5: return((CHAR)(238 & 0xff)); case 0x03c0: return((CHAR)(227 & 0xff)); case 0x03c3: return((CHAR)(229 & 0xff)); case 0x03c4: return((CHAR)(231 & 0xff)); case 0x03c6: return((CHAR)(237 & 0xff)); case 0x207f: return((CHAR)(252 & 0xff)); case 0x20a7: return((CHAR)(158 & 0xff)); case 0x2219: return((CHAR)(249 & 0xff)); case 0x221a: return((CHAR)(251 & 0xff)); case 0x221e: return((CHAR)(236 & 0xff)); case 0x2229: return((CHAR)(239 & 0xff)); case 0x2248: return((CHAR)(247 & 0xff)); case 0x2261: return((CHAR)(240 & 0xff)); case 0x2264: return((CHAR)(243 & 0xff)); case 0x2265: return((CHAR)(242 & 0xff)); case 0x2310: return((CHAR)(169 & 0xff)); case 0x2320: return((CHAR)(244 & 0xff)); case 0x2321: return((CHAR)(245 & 0xff)); case 0x2500: return((CHAR)(196 & 0xff)); case 0x2502: return((CHAR)(179 & 0xff)); case 0x250c: return((CHAR)(218 & 0xff)); case 0x2510: return((CHAR)(191 & 0xff)); case 0x2514: return((CHAR)(192 & 0xff)); case 0x2518: return((CHAR)(217 & 0xff)); case 0x251c: return((CHAR)(195 & 0xff)); case 0x2524: return((CHAR)(180 & 0xff)); case 0x252c: return((CHAR)(194 & 0xff)); case 0x2534: return((CHAR)(193 & 0xff)); case 0x253c: return((CHAR)(197 & 0xff)); case 0x2550: return((CHAR)(205 & 0xff)); case 0x2551: return((CHAR)(186 & 0xff)); case 0x2552: return((CHAR)(213 & 0xff)); case 0x2553: return((CHAR)(214 & 0xff)); case 0x2554: return((CHAR)(201 & 0xff)); case 0x2555: return((CHAR)(184 & 0xff)); case 0x2556: return((CHAR)(183 & 0xff)); case 0x2557: return((CHAR)(187 & 0xff)); case 0x2558: return((CHAR)(212 & 0xff)); case 0x2559: return((CHAR)(211 & 0xff)); case 0x255a: return((CHAR)(200 & 0xff)); case 0x255b: return((CHAR)(190 & 0xff)); case 0x255c: return((CHAR)(189 & 0xff)); case 0x255d: return((CHAR)(188 & 0xff)); case 0x255e: return((CHAR)(198 & 0xff)); case 0x255f: return((CHAR)(199 & 0xff)); case 0x2560: return((CHAR)(204 & 0xff)); case 0x2561: return((CHAR)(181 & 0xff)); case 0x2562: return((CHAR)(182 & 0xff)); case 0x2563: return((CHAR)(185 & 0xff)); case 0x2564: return((CHAR)(209 & 0xff)); case 0x2565: return((CHAR)(210 & 0xff)); case 0x2566: return((CHAR)(203 & 0xff)); case 0x2567: return((CHAR)(207 & 0xff)); case 0x2568: return((CHAR)(208 & 0xff)); case 0x2569: return((CHAR)(202 & 0xff)); case 0x256a: return((CHAR)(216 & 0xff)); case 0x256b: return((CHAR)(215 & 0xff)); case 0x256c: return((CHAR)(206 & 0xff)); case 0x2580: return((CHAR)(223 & 0xff)); case 0x2584: return((CHAR)(220 & 0xff)); case 0x2588: return((CHAR)(219 & 0xff)); case 0x258c: return((CHAR)(221 & 0xff)); case 0x2590: return((CHAR)(222 & 0xff)); case 0x2591: return((CHAR)(176 & 0xff)); case 0x2592: return((CHAR)(177 & 0xff)); case 0x2593: return((CHAR)(178 & 0xff)); case 0x25a0: return((CHAR)(254 & 0xff)); /* Black square */ default: return(tx_cpsub(c)); /* For box characters etc */ } } int /* Mazovia */ #ifdef CK_ANSIC tx_mazovia(USHORT c) #else tx_mazovia(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00d3: return((CHAR)0xa3 & 0xff); /* O acute */ case 0x00f3: return((CHAR)0xa2 & 0xff); /* O acute */ case 0x0104: return((CHAR)0x8f & 0xff); /* A Ogonek */ case 0x0105: return((CHAR)0x86 & 0xff); /* a Ogonek */ case 0x0106: return((CHAR)0x95 & 0xff); /* C acute */ case 0x0107: return((CHAR)0x8d & 0xff); /* c acute */ case 0x0118: return((CHAR)0x90 & 0xff); /* E Ogonek */ case 0x0119: return((CHAR)0x91 & 0xff); /* E Ogonek */ case 0x0141: return((CHAR)0x9c & 0xff); /* L stroke */ case 0x0142: return((CHAR)0x92 & 0xff); /* L stroke */ case 0x0143: return((CHAR)0xa5 & 0xff); /* N acute */ case 0x0144: return((CHAR)0xa4 & 0xff); /* N acute */ case 0x015a: return((CHAR)0x98 & 0xff); /* S acute */ case 0x015b: return((CHAR)0x9e & 0xff); /* S acute */ case 0x0179: return((CHAR)0xa0 & 0xff); /* Z acute */ case 0x017a: return((CHAR)0xa6 & 0xff); /* Z acute */ case 0x017b: return((CHAR)0xa1 & 0xff); /* Z dot above */ case 0x017c: return((CHAR)0xa7 & 0xff); /* Z dot above */ default: return(tx_cp437(c)); } } int /* PC Code Page 850 */ #ifdef CK_ANSIC tx_cp850(USHORT c) #else tx_cp850(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00a0: return((CHAR)(255 & 0xff)); case 0x00a1: return((CHAR)(173 & 0xff)); case 0x00a2: return((CHAR)(189 & 0xff)); case 0x00a3: return((CHAR)(156 & 0xff)); case 0x00a4: return((CHAR)(207 & 0xff)); case 0x00a5: return((CHAR)(190 & 0xff)); case 0x00a6: return((CHAR)(221 & 0xff)); case 0x00a7: return((CHAR)(245 & 0xff)); case 0x00a8: return((CHAR)(249 & 0xff)); case 0x00a9: return((CHAR)(184 & 0xff)); case 0x00aa: return((CHAR)(166 & 0xff)); case 0x00ab: return((CHAR)(174 & 0xff)); case 0x00ac: return((CHAR)(170 & 0xff)); case 0x00ad: return((CHAR)(240 & 0xff)); case 0x00ae: return((CHAR)(169 & 0xff)); case 0x00af: return((CHAR)(238 & 0xff)); case 0x00b0: return((CHAR)(248 & 0xff)); case 0x00b1: return((CHAR)(241 & 0xff)); case 0x00b2: return((CHAR)(253 & 0xff)); case 0x00b3: return((CHAR)(252 & 0xff)); case 0x00b4: return((CHAR)(239 & 0xff)); case 0x00b5: return((CHAR)(230 & 0xff)); case 0x00b6: return((CHAR)(244 & 0xff)); case 0x00b7: return((CHAR)(250 & 0xff)); case 0x00b8: return((CHAR)(247 & 0xff)); case 0x00b9: return((CHAR)(251 & 0xff)); case 0x00ba: return((CHAR)(167 & 0xff)); case 0x00bb: return((CHAR)(175 & 0xff)); case 0x00bc: return((CHAR)(172 & 0xff)); case 0x00bd: return((CHAR)(171 & 0xff)); case 0x00be: return((CHAR)(243 & 0xff)); case 0x00bf: return((CHAR)(168 & 0xff)); case 0x00c0: return((CHAR)(183 & 0xff)); case 0x00c1: return((CHAR)(181 & 0xff)); case 0x00c2: return((CHAR)(182 & 0xff)); case 0x00c3: return((CHAR)(199 & 0xff)); case 0x00c4: return((CHAR)(142 & 0xff)); case 0x00c5: return((CHAR)(143 & 0xff)); case 0x00c6: return((CHAR)(146 & 0xff)); case 0x00c7: return((CHAR)(128 & 0xff)); case 0x00c8: return((CHAR)(212 & 0xff)); case 0x00c9: return((CHAR)(144 & 0xff)); case 0x00ca: return((CHAR)(210 & 0xff)); case 0x00cb: return((CHAR)(211 & 0xff)); case 0x00cc: return((CHAR)(222 & 0xff)); case 0x00cd: return((CHAR)(214 & 0xff)); case 0x00ce: return((CHAR)(215 & 0xff)); case 0x00cf: return((CHAR)(216 & 0xff)); case 0x00d0: return((CHAR)(209 & 0xff)); case 0x00d1: return((CHAR)(165 & 0xff)); case 0x00d2: return((CHAR)(227 & 0xff)); case 0x00d3: return((CHAR)(224 & 0xff)); case 0x00d4: return((CHAR)(226 & 0xff)); case 0x00d5: return((CHAR)(229 & 0xff)); case 0x00d6: return((CHAR)(153 & 0xff)); case 0x00d7: return((CHAR)(158 & 0xff)); case 0x00d8: return((CHAR)(157 & 0xff)); case 0x00d9: return((CHAR)(235 & 0xff)); case 0x00da: return((CHAR)(233 & 0xff)); case 0x00db: return((CHAR)(234 & 0xff)); case 0x00dc: return((CHAR)(154 & 0xff)); case 0x00dd: return((CHAR)(237 & 0xff)); case 0x00de: return((CHAR)(232 & 0xff)); case 0x00df: return((CHAR)(225 & 0xff)); case 0x00e0: return((CHAR)(133 & 0xff)); case 0x00e1: return((CHAR)(160 & 0xff)); case 0x00e2: return((CHAR)(131 & 0xff)); case 0x00e3: return((CHAR)(198 & 0xff)); case 0x00e4: return((CHAR)(132 & 0xff)); case 0x00e5: return((CHAR)(134 & 0xff)); case 0x00e6: return((CHAR)(145 & 0xff)); case 0x00e7: return((CHAR)(135 & 0xff)); case 0x00e8: return((CHAR)(138 & 0xff)); case 0x00e9: return((CHAR)(130 & 0xff)); case 0x00ea: return((CHAR)(136 & 0xff)); case 0x00eb: return((CHAR)(137 & 0xff)); case 0x00ec: return((CHAR)(141 & 0xff)); case 0x00ed: return((CHAR)(161 & 0xff)); case 0x00ee: return((CHAR)(140 & 0xff)); case 0x00ef: return((CHAR)(139 & 0xff)); case 0x00f0: return((CHAR)(208 & 0xff)); case 0x00f1: return((CHAR)(164 & 0xff)); case 0x00f2: return((CHAR)(149 & 0xff)); case 0x00f3: return((CHAR)(162 & 0xff)); case 0x00f4: return((CHAR)(147 & 0xff)); case 0x00f5: return((CHAR)(228 & 0xff)); case 0x00f6: return((CHAR)(148 & 0xff)); case 0x00f7: return((CHAR)(246 & 0xff)); case 0x00f8: return((CHAR)(155 & 0xff)); case 0x00f9: return((CHAR)(151 & 0xff)); case 0x00fa: return((CHAR)(163 & 0xff)); case 0x00fb: return((CHAR)(150 & 0xff)); case 0x00fc: return((CHAR)(129 & 0xff)); case 0x00fd: return((CHAR)(236 & 0xff)); case 0x00fe: return((CHAR)(231 & 0xff)); case 0x00ff: return((CHAR)(152 & 0xff)); case 0x0131: return((CHAR)(213 & 0xff)); case 0x0192: return((CHAR)(159 & 0xff)); case 0x2017: return((CHAR)(242 & 0xff)); case 0x2500: return((CHAR)(196 & 0xff)); case 0x2502: return((CHAR)(179 & 0xff)); case 0x250c: return((CHAR)(218 & 0xff)); case 0x2510: return((CHAR)(191 & 0xff)); case 0x2514: return((CHAR)(192 & 0xff)); case 0x2518: return((CHAR)(217 & 0xff)); case 0x251c: return((CHAR)(195 & 0xff)); case 0x2524: return((CHAR)(180 & 0xff)); case 0x252c: return((CHAR)(194 & 0xff)); case 0x2534: return((CHAR)(193 & 0xff)); case 0x253c: return((CHAR)(197 & 0xff)); case 0x2550: return((CHAR)(205 & 0xff)); case 0x2551: return((CHAR)(186 & 0xff)); case 0x2554: return((CHAR)(201 & 0xff)); case 0x2557: return((CHAR)(187 & 0xff)); case 0x255a: return((CHAR)(200 & 0xff)); case 0x255d: return((CHAR)(188 & 0xff)); case 0x2560: return((CHAR)(204 & 0xff)); case 0x2563: return((CHAR)(185 & 0xff)); case 0x2566: return((CHAR)(203 & 0xff)); case 0x2569: return((CHAR)(202 & 0xff)); case 0x256c: return((CHAR)(206 & 0xff)); case 0x2580: return((CHAR)(223 & 0xff)); case 0x2584: return((CHAR)(220 & 0xff)); case 0x2588: return((CHAR)(219 & 0xff)); case 0x2591: return((CHAR)(176 & 0xff)); case 0x2592: return((CHAR)(177 & 0xff)); case 0x2593: return((CHAR)(178 & 0xff)); case 0x25a0: return((CHAR)(254 & 0xff)); default: return(tx_cpsub(c)); /* For box characters etc */ } } int /* PC Code Page 858 */ #ifdef CK_ANSIC tx_cp858(USHORT c) #else tx_cp858(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00a0: return((CHAR)(255 & 0xff)); case 0x00a1: return((CHAR)(173 & 0xff)); case 0x00a2: return((CHAR)(189 & 0xff)); case 0x00a3: return((CHAR)(156 & 0xff)); case 0x00a4: return((CHAR)(207 & 0xff)); case 0x00a5: return((CHAR)(190 & 0xff)); case 0x00a6: return((CHAR)(221 & 0xff)); case 0x00a7: return((CHAR)(245 & 0xff)); case 0x00a8: return((CHAR)(249 & 0xff)); case 0x00a9: return((CHAR)(184 & 0xff)); case 0x00aa: return((CHAR)(166 & 0xff)); case 0x00ab: return((CHAR)(174 & 0xff)); case 0x00ac: return((CHAR)(170 & 0xff)); case 0x00ad: return((CHAR)(240 & 0xff)); case 0x00ae: return((CHAR)(169 & 0xff)); case 0x00af: return((CHAR)(238 & 0xff)); case 0x00b0: return((CHAR)(248 & 0xff)); case 0x00b1: return((CHAR)(241 & 0xff)); case 0x00b2: return((CHAR)(253 & 0xff)); case 0x00b3: return((CHAR)(252 & 0xff)); case 0x00b4: return((CHAR)(239 & 0xff)); case 0x00b5: return((CHAR)(230 & 0xff)); case 0x00b6: return((CHAR)(244 & 0xff)); case 0x00b7: return((CHAR)(250 & 0xff)); case 0x00b8: return((CHAR)(247 & 0xff)); case 0x00b9: return((CHAR)(251 & 0xff)); case 0x00ba: return((CHAR)(167 & 0xff)); case 0x00bb: return((CHAR)(175 & 0xff)); case 0x00bc: return((CHAR)(172 & 0xff)); case 0x00bd: return((CHAR)(171 & 0xff)); case 0x00be: return((CHAR)(243 & 0xff)); case 0x00bf: return((CHAR)(168 & 0xff)); case 0x00c0: return((CHAR)(183 & 0xff)); case 0x00c1: return((CHAR)(181 & 0xff)); case 0x00c2: return((CHAR)(182 & 0xff)); case 0x00c3: return((CHAR)(199 & 0xff)); case 0x00c4: return((CHAR)(142 & 0xff)); case 0x00c5: return((CHAR)(143 & 0xff)); case 0x00c6: return((CHAR)(146 & 0xff)); case 0x00c7: return((CHAR)(128 & 0xff)); case 0x00c8: return((CHAR)(212 & 0xff)); case 0x00c9: return((CHAR)(144 & 0xff)); case 0x00ca: return((CHAR)(210 & 0xff)); case 0x00cb: return((CHAR)(211 & 0xff)); case 0x00cc: return((CHAR)(222 & 0xff)); case 0x00cd: return((CHAR)(214 & 0xff)); case 0x00ce: return((CHAR)(215 & 0xff)); case 0x00cf: return((CHAR)(216 & 0xff)); case 0x00d0: return((CHAR)(209 & 0xff)); case 0x00d1: return((CHAR)(165 & 0xff)); case 0x00d2: return((CHAR)(227 & 0xff)); case 0x00d3: return((CHAR)(224 & 0xff)); case 0x00d4: return((CHAR)(226 & 0xff)); case 0x00d5: return((CHAR)(229 & 0xff)); case 0x00d6: return((CHAR)(153 & 0xff)); case 0x00d7: return((CHAR)(158 & 0xff)); case 0x00d8: return((CHAR)(157 & 0xff)); case 0x00d9: return((CHAR)(235 & 0xff)); case 0x00da: return((CHAR)(233 & 0xff)); case 0x00db: return((CHAR)(234 & 0xff)); case 0x00dc: return((CHAR)(154 & 0xff)); case 0x00dd: return((CHAR)(237 & 0xff)); case 0x00de: return((CHAR)(232 & 0xff)); case 0x00df: return((CHAR)(225 & 0xff)); case 0x00e0: return((CHAR)(133 & 0xff)); case 0x00e1: return((CHAR)(160 & 0xff)); case 0x00e2: return((CHAR)(131 & 0xff)); case 0x00e3: return((CHAR)(198 & 0xff)); case 0x00e4: return((CHAR)(132 & 0xff)); case 0x00e5: return((CHAR)(134 & 0xff)); case 0x00e6: return((CHAR)(145 & 0xff)); case 0x00e7: return((CHAR)(135 & 0xff)); case 0x00e8: return((CHAR)(138 & 0xff)); case 0x00e9: return((CHAR)(130 & 0xff)); case 0x00ea: return((CHAR)(136 & 0xff)); case 0x00eb: return((CHAR)(137 & 0xff)); case 0x00ec: return((CHAR)(141 & 0xff)); case 0x00ed: return((CHAR)(161 & 0xff)); case 0x00ee: return((CHAR)(140 & 0xff)); case 0x00ef: return((CHAR)(139 & 0xff)); case 0x00f0: return((CHAR)(208 & 0xff)); case 0x00f1: return((CHAR)(164 & 0xff)); case 0x00f2: return((CHAR)(149 & 0xff)); case 0x00f3: return((CHAR)(162 & 0xff)); case 0x00f4: return((CHAR)(147 & 0xff)); case 0x00f5: return((CHAR)(228 & 0xff)); case 0x00f6: return((CHAR)(148 & 0xff)); case 0x00f7: return((CHAR)(246 & 0xff)); case 0x00f8: return((CHAR)(155 & 0xff)); case 0x00f9: return((CHAR)(151 & 0xff)); case 0x00fa: return((CHAR)(163 & 0xff)); case 0x00fb: return((CHAR)(150 & 0xff)); case 0x00fc: return((CHAR)(129 & 0xff)); case 0x00fd: return((CHAR)(236 & 0xff)); case 0x00fe: return((CHAR)(231 & 0xff)); case 0x00ff: return((CHAR)(152 & 0xff)); case 0x20ac: return((CHAR)(213 & 0xff)); case 0x0192: return((CHAR)(159 & 0xff)); case 0x2017: return((CHAR)(242 & 0xff)); case 0x2500: return((CHAR)(196 & 0xff)); case 0x2502: return((CHAR)(179 & 0xff)); case 0x250c: return((CHAR)(218 & 0xff)); case 0x2510: return((CHAR)(191 & 0xff)); case 0x2514: return((CHAR)(192 & 0xff)); case 0x2518: return((CHAR)(217 & 0xff)); case 0x251c: return((CHAR)(195 & 0xff)); case 0x2524: return((CHAR)(180 & 0xff)); case 0x252c: return((CHAR)(194 & 0xff)); case 0x2534: return((CHAR)(193 & 0xff)); case 0x253c: return((CHAR)(197 & 0xff)); case 0x2550: return((CHAR)(205 & 0xff)); case 0x2551: return((CHAR)(186 & 0xff)); case 0x2554: return((CHAR)(201 & 0xff)); case 0x2557: return((CHAR)(187 & 0xff)); case 0x255a: return((CHAR)(200 & 0xff)); case 0x255d: return((CHAR)(188 & 0xff)); case 0x2560: return((CHAR)(204 & 0xff)); case 0x2563: return((CHAR)(185 & 0xff)); case 0x2566: return((CHAR)(203 & 0xff)); case 0x2569: return((CHAR)(202 & 0xff)); case 0x256c: return((CHAR)(206 & 0xff)); case 0x2580: return((CHAR)(223 & 0xff)); case 0x2584: return((CHAR)(220 & 0xff)); case 0x2588: return((CHAR)(219 & 0xff)); case 0x2591: return((CHAR)(176 & 0xff)); case 0x2592: return((CHAR)(177 & 0xff)); case 0x2593: return((CHAR)(178 & 0xff)); case 0x25a0: return((CHAR)(254 & 0xff)); default: return(tx_cpsub(c)); /* For box characters etc */ } } int /* Windows Code Page 1250 (Latin-2) */ #ifdef CK_ANSIC tx_cp1250(USHORT c) #else tx_cp1250(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80 || (c > 0xbf && c <= 0xff)) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x002D: return((CHAR)(0xad & 0xff)); case 0x00A0: return((CHAR)(0xa0 & 0xff)); case 0x00A4: return((CHAR)(0xa4 & 0xff)); case 0x00A6: return((CHAR)(0xa6 & 0xff)); case 0x00A7: return((CHAR)(0xa7 & 0xff)); case 0x00A8: return((CHAR)(0xa8 & 0xff)); case 0x00A9: return((CHAR)(0xa9 & 0xff)); case 0x00AB: return((CHAR)(0xab & 0xff)); case 0x00AC: return((CHAR)(0xac & 0xff)); case 0x00AE: return((CHAR)(0xae & 0xff)); case 0x00B0: return((CHAR)(0xb0 & 0xff)); case 0x00B1: return((CHAR)(0xb1 & 0xff)); case 0x00B4: return((CHAR)(0xb4 & 0xff)); case 0x00B5: return((CHAR)(0xb5 & 0xff)); case 0x00B6: return((CHAR)(0xb6 & 0xff)); case 0x00B7: return((CHAR)(0xb7 & 0xff)); case 0x00B8: return((CHAR)(0xb8 & 0xff)); case 0x00BB: return((CHAR)(0xbb & 0xff)); case 0x0104: return((CHAR)(0xa5 & 0xff)); case 0x0105: return((CHAR)(0xb9 & 0xff)); case 0x013D: return((CHAR)(0xbc & 0xff)); case 0x013E: return((CHAR)(0xbe & 0xff)); case 0x0141: return((CHAR)(0xa3 & 0xff)); case 0x0142: return((CHAR)(0xb3 & 0xff)); case 0x015A: return((CHAR)(0x8c & 0xff)); /* S acute */ case 0x015E: return((CHAR)(0xaa & 0xff)); case 0x015F: return((CHAR)(0xba & 0xff)); case 0x015b: return((CHAR)(0x9c & 0xff)); /* s acute */ case 0x0164: return((CHAR)(0x8d & 0xff)); /* T caron */ case 0x0165: return((CHAR)(0x9d & 0xff)); /* t caron */ case 0x0173: return((CHAR)(0x9e & 0xff)); /* z caron */ case 0x0179: return((CHAR)(0x8f & 0xff)); /* Z acute */ case 0x017A: return((CHAR)(0x9f & 0xff)); /* z acute */ case 0x017B: return((CHAR)(0xaf & 0xff)); case 0x017C: return((CHAR)(0xbf & 0xff)); case 0x017D: return((CHAR)(0x8e & 0xff)); /* Z caron */ case 0x02C7: return((CHAR)(0xa1 & 0xff)); case 0x02D8: return((CHAR)(0xa2 & 0xff)); case 0x02DB: return((CHAR)(0xb2 & 0xff)); case 0x02DD: return((CHAR)(0xbd & 0xff)); case 0x2010: case 0x2011: /* Hyphens */ return((CHAR)(0x2d & 0xff)); case 0x2012: case 0x2013: /* en-dashes */ return((CHAR)(0x96 & 0xff)); case 0x2014: case 0x2015: /* em-dashes */ return((CHAR)(0x97 & 0xff)); case 0x2018: /* Various quotation marks... */ return((CHAR)(0x91 & 0xff)); case 0x2019: return((CHAR)(0x92 & 0xff)); case 0x201c: return((CHAR)(0x93 & 0xff)); case 0x201d: return((CHAR)(0x94 & 0xff)); case 0x201e: return((CHAR)(0x84 & 0xff)); case 0x2020: /* Dagger */ return((CHAR)(0x86 & 0xff)); case 0x2021: /* Double Dagger */ return((CHAR)(0x87 & 0xff)); case 0x2022: /* Bullet */ return((CHAR)(0x95 & 0xff)); case 0x2026: /* Ellipsis */ return((CHAR)(0x85 & 0xff)); case 0x2030: /* Per mil */ return((CHAR)(0x89 & 0xff)); case 0x20AC: /* Euro */ return((CHAR)(0x80 & 0xff)); case 0x2122: /* Trade Mark */ return((CHAR)(0x99 & 0xff)); default: return(0x003f); } } int /* Windows Code Page 1251 (Cyrillic) */ #ifdef CK_ANSIC tx_cp1251(USHORT c) #else tx_cp1251(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); /* This is simply the inverse of u_cp1251.map */ switch (c) { case 0x003c: return((CHAR)(0x8b & 0xff)); case 0x003e: return((CHAR)(0x9b & 0xff)); case 0x007e: return((CHAR)(0x98 & 0xff)); case 0x00A0: return((CHAR)(0xa0 & 0xff)); case 0x00A4: return((CHAR)(0xa4 & 0xff)); case 0x00A6: return((CHAR)(0xa6 & 0xff)); case 0x00A7: return((CHAR)(0xa7 & 0xff)); case 0x00A9: return((CHAR)(0xa9 & 0xff)); case 0x00AB: return((CHAR)(0xab & 0xff)); case 0x00AC: return((CHAR)(0xac & 0xff)); case 0x00AD: return((CHAR)(0xad & 0xff)); case 0x00AE: return((CHAR)(0xae & 0xff)); case 0x00b0: return((CHAR)(0xb0 & 0xff)); case 0x00b1: return((CHAR)(0xb1 & 0xff)); case 0x00B5: return((CHAR)(0xb5 & 0xff)); case 0x00B6: return((CHAR)(0xb6 & 0xff)); case 0x00B7: return((CHAR)(0xb7 & 0xff)); case 0x00BB: return((CHAR)(0xbb & 0xff)); case 0x0401: return((CHAR)(0xa8 & 0xff)); case 0x0402: return((CHAR)(0x80 & 0xff)); case 0x0403: return((CHAR)(0x81 & 0xff)); case 0x0404: return((CHAR)(0xaa & 0xff)); case 0x0405: return((CHAR)(0xbd & 0xff)); case 0x0406: return((CHAR)(0xb2 & 0xff)); case 0x0407: return((CHAR)(0xaf & 0xff)); case 0x0408: return((CHAR)(0xa3 & 0xff)); case 0x0409: return((CHAR)(0x8a & 0xff)); case 0x040a: return((CHAR)(0x8c & 0xff)); case 0x040b: return((CHAR)(0x8e & 0xff)); case 0x040c: return((CHAR)(0x8d & 0xff)); case 0x040e: return((CHAR)(0xa1 & 0xff)); case 0x040f: return((CHAR)(0x8f & 0xff)); case 0x0410: return((CHAR)(0xc0 & 0xff)); case 0x0411: return((CHAR)(0xc1 & 0xff)); case 0x0412: return((CHAR)(0xc2 & 0xff)); case 0x0413: return((CHAR)(0xc3 & 0xff)); case 0x0414: return((CHAR)(0xc4 & 0xff)); case 0x0415: return((CHAR)(0xc5 & 0xff)); case 0x0416: return((CHAR)(0xc6 & 0xff)); case 0x0417: return((CHAR)(0xc7 & 0xff)); case 0x0418: return((CHAR)(0xc8 & 0xff)); case 0x0419: return((CHAR)(0xc9 & 0xff)); case 0x041a: return((CHAR)(0xca & 0xff)); case 0x041b: return((CHAR)(0xcb & 0xff)); case 0x041c: return((CHAR)(0xcc & 0xff)); case 0x041d: return((CHAR)(0xcd & 0xff)); case 0x041e: return((CHAR)(0xce & 0xff)); case 0x041f: return((CHAR)(0xcf & 0xff)); case 0x0420: return((CHAR)(0xd0 & 0xff)); case 0x0421: return((CHAR)(0xd1 & 0xff)); case 0x0422: return((CHAR)(0xd2 & 0xff)); case 0x0423: return((CHAR)(0xd3 & 0xff)); case 0x0424: return((CHAR)(0xd4 & 0xff)); case 0x0425: return((CHAR)(0xd5 & 0xff)); case 0x0426: return((CHAR)(0xd6 & 0xff)); case 0x0427: return((CHAR)(0xd7 & 0xff)); case 0x0428: return((CHAR)(0xd8 & 0xff)); case 0x0429: return((CHAR)(0xd9 & 0xff)); case 0x042a: return((CHAR)(0xda & 0xff)); case 0x042b: return((CHAR)(0xdb & 0xff)); case 0x042c: return((CHAR)(0xdc & 0xff)); case 0x042d: return((CHAR)(0xdd & 0xff)); case 0x042e: return((CHAR)(0xde & 0xff)); case 0x042f: return((CHAR)(0xdf & 0xff)); case 0x0430: return((CHAR)(0xe0 & 0xff)); case 0x0431: return((CHAR)(0xe1 & 0xff)); case 0x0432: return((CHAR)(0xe2 & 0xff)); case 0x0433: return((CHAR)(0xe3 & 0xff)); case 0x0434: return((CHAR)(0xe4 & 0xff)); case 0x0435: return((CHAR)(0xe5 & 0xff)); case 0x0436: return((CHAR)(0xe6 & 0xff)); case 0x0437: return((CHAR)(0xe7 & 0xff)); case 0x0438: return((CHAR)(0xe8 & 0xff)); case 0x0439: return((CHAR)(0xe9 & 0xff)); case 0x043a: return((CHAR)(0xea & 0xff)); case 0x043b: return((CHAR)(0xeb & 0xff)); case 0x043c: return((CHAR)(0xec & 0xff)); case 0x043d: return((CHAR)(0xed & 0xff)); case 0x043e: return((CHAR)(0xee & 0xff)); case 0x043f: return((CHAR)(0xef & 0xff)); case 0x0440: return((CHAR)(0xf0 & 0xff)); case 0x0441: return((CHAR)(0xf1 & 0xff)); case 0x0442: return((CHAR)(0xf2 & 0xff)); case 0x0443: return((CHAR)(0xf3 & 0xff)); case 0x0444: return((CHAR)(0xf4 & 0xff)); case 0x0445: return((CHAR)(0xf5 & 0xff)); case 0x0446: return((CHAR)(0xf6 & 0xff)); case 0x0447: return((CHAR)(0xf7 & 0xff)); case 0x0448: return((CHAR)(0xf8 & 0xff)); case 0x0449: return((CHAR)(0xf9 & 0xff)); case 0x044a: return((CHAR)(0xfa & 0xff)); case 0x044b: return((CHAR)(0xfb & 0xff)); case 0x044c: return((CHAR)(0xfc & 0xff)); case 0x044d: return((CHAR)(0xfd & 0xff)); case 0x044e: return((CHAR)(0xfe & 0xff)); case 0x044f: return((CHAR)(0xff & 0xff)); case 0x0451: return((CHAR)(0xb8 & 0xff)); case 0x0452: return((CHAR)(0x90 & 0xff)); case 0x0453: return((CHAR)(0x83 & 0xff)); case 0x0454: return((CHAR)(0xba & 0xff)); case 0x0455: return((CHAR)(0xbe & 0xff)); case 0x0456: return((CHAR)(0xb3 & 0xff)); case 0x0457: return((CHAR)(0xbf & 0xff)); case 0x0458: return((CHAR)(0xbc & 0xff)); case 0x0459: return((CHAR)(0x9a & 0xff)); case 0x045a: return((CHAR)(0x9c & 0xff)); case 0x045b: return((CHAR)(0x9e & 0xff)); case 0x045c: return((CHAR)(0x9d & 0xff)); case 0x045e: return((CHAR)(0xa2 & 0xff)); case 0x045f: return((CHAR)(0x9f & 0xff)); case 0x0490: return((CHAR)(0xa5 & 0xff)); case 0x0491: return((CHAR)(0xb4 & 0xff)); case 0x2012: return((CHAR)(0x96 & 0xff)); case 0x2014: return((CHAR)(0x97 & 0xff)); case 0x2018: return((CHAR)(0x91 & 0xff)); case 0x2019: return((CHAR)(0x92 & 0xff)); case 0x201a: return((CHAR)(0x82 & 0xff)); case 0x201c: return((CHAR)(0x93 & 0xff)); case 0x201d: return((CHAR)(0x94 & 0xff)); case 0x201e: return((CHAR)(0x84 & 0xff)); case 0x2020: return((CHAR)(0x86 & 0xff)); case 0x2021: return((CHAR)(0x87 & 0xff)); case 0x2022: return((CHAR)(0x95 & 0xff)); case 0x2026: return((CHAR)(0x85 & 0xff)); case 0x2031: return((CHAR)(0x89 & 0xff)); case 0x20AC: /* Euro */ return((CHAR)(0x88 & 0xff)); case 0x2116: return((CHAR)(0xb9 & 0xff)); case 0x2122: return((CHAR)(0x99 & 0xff)); default: return(0x003f); } } int /* Unicode to Windows Code Page 1252 (Latin-1) */ #ifdef CK_ANSIC tx_cp1252(USHORT c) #else tx_cp1252(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80 || (c > 0x9f && c <= 0xff)) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x0152: /* OE */ return((CHAR)(0x8c & 0xff)); case 0x0153: /* oe */ return((CHAR)(0x9c & 0xff)); case 0x0160: /* S caron */ return((CHAR)(0x8a & 0xff)); case 0x0161: /* s caron */ return((CHAR)(0x9a & 0xff)); case 0x0178: /* Y diaeresis */ return((CHAR)(0x9f & 0xff)); case 0x017D: /* Z caron */ return((CHAR)(0x8e & 0xff)); case 0x017E: /* z caron */ return((CHAR)(0x9e & 0xff)); case 0x0192: /* Florin */ return((CHAR)(0x83 & 0xff)); case 0x2010: case 0x2011: /* Hyphens */ return((CHAR)(0x2d & 0xff)); case 0x2012: case 0x2013: /* en-dashes */ return((CHAR)(0x96 & 0xff)); case 0x2014: case 0x2015: /* em-dashes */ return((CHAR)(0x97 & 0xff)); case 0x2018: /* Various quotation marks... */ return((CHAR)(0x91 & 0xff)); case 0x2019: return((CHAR)(0x92 & 0xff)); case 0x201c: return((CHAR)(0x93 & 0xff)); case 0x201d: return((CHAR)(0x94 & 0xff)); case 0x201e: return((CHAR)(0x84 & 0xff)); case 0x2020: /* Dagger */ return((CHAR)(0x86 & 0xff)); case 0x2021: /* Double Dagger */ return((CHAR)(0x87 & 0xff)); case 0x2022: /* Bullet */ return((CHAR)(0x95 & 0xff)); case 0x2026: /* Ellipsis */ return((CHAR)(0x85 & 0xff)); case 0x2030: /* Per mil */ return((CHAR)(0x89 & 0xff)); case 0x20AC: /* Euro */ return((CHAR)(0x80 & 0xff)); case 0x2122: /* Trade Mark */ return((CHAR)(0x99 & 0xff)); default: return(0x003f); } } int /* PC Code Page 852 */ #ifdef CK_ANSIC tx_cp852(USHORT c) #else tx_cp852(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00a0: return((CHAR)(255 & 0xff)); case 0x00a4: return((CHAR)(207 & 0xff)); case 0x00a7: return((CHAR)(245 & 0xff)); case 0x00a8: return((CHAR)(249 & 0xff)); case 0x00ab: return((CHAR)(174 & 0xff)); case 0x00ac: return((CHAR)(170 & 0xff)); case 0x00ad: return((CHAR)(240 & 0xff)); case 0x00b0: return((CHAR)(248 & 0xff)); case 0x00b4: return((CHAR)(239 & 0xff)); case 0x00b8: return((CHAR)(247 & 0xff)); case 0x00bb: return((CHAR)(175 & 0xff)); case 0x00c1: return((CHAR)(181 & 0xff)); case 0x00c2: return((CHAR)(182 & 0xff)); case 0x00c4: return((CHAR)(142 & 0xff)); case 0x00c7: return((CHAR)(128 & 0xff)); case 0x00c9: return((CHAR)(144 & 0xff)); case 0x00cb: return((CHAR)(211 & 0xff)); case 0x00cd: return((CHAR)(214 & 0xff)); case 0x00ce: return((CHAR)(215 & 0xff)); case 0x00d3: return((CHAR)(224 & 0xff)); case 0x00d4: return((CHAR)(226 & 0xff)); case 0x00d6: return((CHAR)(153 & 0xff)); case 0x00d7: return((CHAR)(158 & 0xff)); case 0x00da: return((CHAR)(233 & 0xff)); case 0x00dc: return((CHAR)(154 & 0xff)); case 0x00dd: return((CHAR)(237 & 0xff)); case 0x00df: return((CHAR)(225 & 0xff)); case 0x00e1: return((CHAR)(160 & 0xff)); case 0x00e2: return((CHAR)(131 & 0xff)); case 0x00e4: return((CHAR)(132 & 0xff)); case 0x00e7: return((CHAR)(135 & 0xff)); case 0x00e9: return((CHAR)(130 & 0xff)); case 0x00eb: return((CHAR)(137 & 0xff)); case 0x00ed: return((CHAR)(161 & 0xff)); case 0x00ee: return((CHAR)(140 & 0xff)); case 0x00f3: return((CHAR)(162 & 0xff)); case 0x00f4: return((CHAR)(147 & 0xff)); case 0x00f6: return((CHAR)(148 & 0xff)); case 0x00f7: return((CHAR)(246 & 0xff)); case 0x00fa: return((CHAR)(163 & 0xff)); case 0x00fc: return((CHAR)(129 & 0xff)); case 0x00fd: return((CHAR)(236 & 0xff)); case 0x0102: return((CHAR)(198 & 0xff)); case 0x0103: return((CHAR)(199 & 0xff)); case 0x0104: return((CHAR)(164 & 0xff)); case 0x0105: return((CHAR)(165 & 0xff)); case 0x0106: return((CHAR)(143 & 0xff)); case 0x0107: return((CHAR)(134 & 0xff)); case 0x010c: return((CHAR)(172 & 0xff)); case 0x010d: return((CHAR)(159 & 0xff)); case 0x010e: return((CHAR)(210 & 0xff)); case 0x010f: return((CHAR)(212 & 0xff)); case 0x0110: return((CHAR)(209 & 0xff)); case 0x0111: return((CHAR)(208 & 0xff)); case 0x0118: return((CHAR)(168 & 0xff)); case 0x0119: return((CHAR)(169 & 0xff)); case 0x011a: return((CHAR)(183 & 0xff)); case 0x011b: return((CHAR)(216 & 0xff)); case 0x0139: return((CHAR)(145 & 0xff)); case 0x013a: return((CHAR)(146 & 0xff)); case 0x013d: return((CHAR)(149 & 0xff)); case 0x013e: return((CHAR)(150 & 0xff)); case 0x0141: return((CHAR)(157 & 0xff)); case 0x0142: return((CHAR)(136 & 0xff)); case 0x0143: return((CHAR)(227 & 0xff)); case 0x0144: return((CHAR)(228 & 0xff)); case 0x0147: return((CHAR)(213 & 0xff)); case 0x0148: return((CHAR)(229 & 0xff)); case 0x0150: return((CHAR)(138 & 0xff)); case 0x0151: return((CHAR)(139 & 0xff)); case 0x0154: return((CHAR)(232 & 0xff)); case 0x0155: return((CHAR)(234 & 0xff)); case 0x0158: return((CHAR)(252 & 0xff)); case 0x0159: return((CHAR)(253 & 0xff)); case 0x015a: return((CHAR)(151 & 0xff)); case 0x015b: return((CHAR)(152 & 0xff)); case 0x015e: return((CHAR)(184 & 0xff)); case 0x015f: return((CHAR)(173 & 0xff)); case 0x0160: return((CHAR)(230 & 0xff)); case 0x0161: return((CHAR)(231 & 0xff)); case 0x0162: return((CHAR)(221 & 0xff)); case 0x0163: return((CHAR)(238 & 0xff)); case 0x0164: return((CHAR)(155 & 0xff)); case 0x0165: return((CHAR)(156 & 0xff)); case 0x016e: return((CHAR)(222 & 0xff)); case 0x016f: return((CHAR)(133 & 0xff)); case 0x0170: return((CHAR)(235 & 0xff)); case 0x0171: return((CHAR)(251 & 0xff)); case 0x0179: return((CHAR)(141 & 0xff)); case 0x017a: return((CHAR)(171 & 0xff)); case 0x017b: return((CHAR)(189 & 0xff)); case 0x017c: return((CHAR)(190 & 0xff)); case 0x017d: return((CHAR)(166 & 0xff)); case 0x017e: return((CHAR)(167 & 0xff)); case 0x02c7: return((CHAR)(243 & 0xff)); case 0x02d8: return((CHAR)(244 & 0xff)); case 0x02d9: return((CHAR)(250 & 0xff)); case 0x02db: return((CHAR)(242 & 0xff)); case 0x02dd: return((CHAR)(241 & 0xff)); case 0x2500: return((CHAR)(196 & 0xff)); case 0x2502: return((CHAR)(179 & 0xff)); case 0x250c: return((CHAR)(218 & 0xff)); case 0x2510: return((CHAR)(191 & 0xff)); case 0x2514: return((CHAR)(192 & 0xff)); case 0x2518: return((CHAR)(217 & 0xff)); case 0x251c: return((CHAR)(195 & 0xff)); case 0x2524: return((CHAR)(180 & 0xff)); case 0x252c: return((CHAR)(194 & 0xff)); case 0x2534: return((CHAR)(193 & 0xff)); case 0x253c: return((CHAR)(197 & 0xff)); case 0x2550: return((CHAR)(205 & 0xff)); case 0x2551: return((CHAR)(186 & 0xff)); case 0x2554: return((CHAR)(201 & 0xff)); case 0x2557: return((CHAR)(187 & 0xff)); case 0x255a: return((CHAR)(200 & 0xff)); case 0x255d: return((CHAR)(188 & 0xff)); case 0x2560: return((CHAR)(204 & 0xff)); case 0x2563: return((CHAR)(185 & 0xff)); case 0x2566: return((CHAR)(203 & 0xff)); case 0x2569: return((CHAR)(202 & 0xff)); case 0x256c: return((CHAR)(206 & 0xff)); case 0x2580: return((CHAR)(223 & 0xff)); case 0x2584: return((CHAR)(220 & 0xff)); case 0x2588: return((CHAR)(219 & 0xff)); case 0x2591: return((CHAR)(176 & 0xff)); case 0x2592: return((CHAR)(177 & 0xff)); case 0x2593: return((CHAR)(178 & 0xff)); case 0x25a0: return((CHAR)(254 & 0xff)); default: return(tx_cpsub(c)); /* For box characters etc */ } } int /* Windows Code Page 1253 (Greek) */ #ifdef CK_ANSIC tx_cp1253(USHORT c) #else tx_cp1253(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x003c: return((CHAR)(0x8b & 0xff)); case 0x003e: return((CHAR)(0x9b & 0xff)); case 0x00A0: return((CHAR)(0xa0 & 0xff)); case 0x00A3: return((CHAR)(0xa3 & 0xff)); case 0x00A4: return((CHAR)(0xa4 & 0xff)); case 0x00A5: return((CHAR)(0xa5 & 0xff)); case 0x00A6: return((CHAR)(0xa6 & 0xff)); case 0x00A7: return((CHAR)(0xa7 & 0xff)); case 0x00A8: return((CHAR)(0xa8 & 0xff)); case 0x00A9: return((CHAR)(0xa9 & 0xff)); case 0x00AA: return((CHAR)(0xaa & 0xff)); case 0x00AB: return((CHAR)(0xab & 0xff)); case 0x00AC: return((CHAR)(0xac & 0xff)); case 0x00AD: return((CHAR)(0xad & 0xff)); case 0x00AE: return((CHAR)(0xae & 0xff)); case 0x00AF: return((CHAR)(0xaf & 0xff)); case 0x00B0: return((CHAR)(0xb0 & 0xff)); case 0x00B1: return((CHAR)(0xb1 & 0xff)); case 0x00B2: return((CHAR)(0xb2 & 0xff)); case 0x00B3: return((CHAR)(0xb3 & 0xff)); case 0x00B5: return((CHAR)(0xb5 & 0xff)); case 0x00B6: return((CHAR)(0xb6 & 0xff)); case 0x00b7: return((CHAR)(0xa1 & 0xff)); case 0x00BB: return((CHAR)(0xbb & 0xff)); case 0x00BD: return((CHAR)(0xbd & 0xff)); case 0x0192: return((CHAR)(0x83 & 0xff)); case 0x0386: return((CHAR)(0xa2 & 0xff)); case 0x0388: return((CHAR)(0xb8 & 0xff)); case 0x0389: return((CHAR)(0xb9 & 0xff)); case 0x038A: return((CHAR)(0xba & 0xff)); case 0x038C: return((CHAR)(0xbc & 0xff)); case 0x038E: return((CHAR)(0xbe & 0xff)); case 0x038F: return((CHAR)(0xbf & 0xff)); case 0x0390: return((CHAR)(0xc0 & 0xff)); case 0x0391: return((CHAR)(0xc1 & 0xff)); case 0x0392: return((CHAR)(0xc2 & 0xff)); case 0x0393: return((CHAR)(0xc3 & 0xff)); case 0x0394: return((CHAR)(0xc4 & 0xff)); case 0x0395: return((CHAR)(0xc5 & 0xff)); case 0x0396: return((CHAR)(0xc6 & 0xff)); case 0x0397: return((CHAR)(0xc7 & 0xff)); case 0x0398: return((CHAR)(0xc8 & 0xff)); case 0x0399: return((CHAR)(0xc9 & 0xff)); case 0x039A: return((CHAR)(0xca & 0xff)); case 0x039B: return((CHAR)(0xcb & 0xff)); case 0x039C: return((CHAR)(0xcc & 0xff)); case 0x039D: return((CHAR)(0xcd & 0xff)); case 0x039E: return((CHAR)(0xce & 0xff)); case 0x039F: return((CHAR)(0xcf & 0xff)); case 0x03a0: return((CHAR)(0xd0 & 0xff)); case 0x03a1: return((CHAR)(0xd1 & 0xff)); case 0x03a3: return((CHAR)(0xd3 & 0xff)); case 0x03a4: return((CHAR)(0xd4 & 0xff)); case 0x03a5: return((CHAR)(0xd5 & 0xff)); case 0x03a6: return((CHAR)(0xd6 & 0xff)); case 0x03a7: return((CHAR)(0xd7 & 0xff)); case 0x03a8: return((CHAR)(0xd8 & 0xff)); case 0x03a9: return((CHAR)(0xd9 & 0xff)); case 0x03aA: return((CHAR)(0xda & 0xff)); case 0x03aB: return((CHAR)(0xdb & 0xff)); case 0x03aC: return((CHAR)(0xdc & 0xff)); case 0x03aD: return((CHAR)(0xdd & 0xff)); case 0x03aE: return((CHAR)(0xde & 0xff)); case 0x03aF: return((CHAR)(0xdf & 0xff)); case 0x03b0: return((CHAR)(0xe0 & 0xff)); case 0x03b1: return((CHAR)(0xe1 & 0xff)); case 0x03b2: return((CHAR)(0xe2 & 0xff)); case 0x03b3: return((CHAR)(0xe3 & 0xff)); case 0x03b4: return((CHAR)(0xe4 & 0xff)); case 0x03b5: return((CHAR)(0xe5 & 0xff)); case 0x03b6: return((CHAR)(0xe6 & 0xff)); case 0x03b7: return((CHAR)(0xe7 & 0xff)); case 0x03b8: return((CHAR)(0xe8 & 0xff)); case 0x03b9: return((CHAR)(0xe9 & 0xff)); case 0x03bA: return((CHAR)(0xea & 0xff)); case 0x03bB: return((CHAR)(0xeb & 0xff)); case 0x03bC: return((CHAR)(0xec & 0xff)); case 0x03bD: return((CHAR)(0xed & 0xff)); case 0x03bE: return((CHAR)(0xee & 0xff)); case 0x03bF: return((CHAR)(0xef & 0xff)); case 0x03c0: return((CHAR)(0xf0 & 0xff)); case 0x03c1: return((CHAR)(0xf1 & 0xff)); case 0x03c2: return((CHAR)(0xf2 & 0xff)); case 0x03c3: return((CHAR)(0xf3 & 0xff)); case 0x03c4: return((CHAR)(0xf4 & 0xff)); case 0x03c5: return((CHAR)(0xf5 & 0xff)); case 0x03c6: return((CHAR)(0xf6 & 0xff)); case 0x03c7: return((CHAR)(0xf7 & 0xff)); case 0x03c8: return((CHAR)(0xf8 & 0xff)); case 0x03c9: return((CHAR)(0xf9 & 0xff)); case 0x03cA: return((CHAR)(0xfa & 0xff)); case 0x03cB: return((CHAR)(0xfb & 0xff)); case 0x03cC: return((CHAR)(0xfc & 0xff)); case 0x03cD: return((CHAR)(0xfd & 0xff)); case 0x03cE: return((CHAR)(0xfe & 0xff)); case 0x2012: return((CHAR)(0x96 & 0xff)); case 0x2014: return((CHAR)(0x97 & 0xff)); case 0x2018: return((CHAR)(0x91 & 0xff)); case 0x2019: return((CHAR)(0x92 & 0xff)); case 0x201a: return((CHAR)(0x82 & 0xff)); case 0x201c: return((CHAR)(0x93 & 0xff)); case 0x201d: return((CHAR)(0x94 & 0xff)); case 0x201e: return((CHAR)(0x84 & 0xff)); case 0x2020: return((CHAR)(0x86 & 0xff)); case 0x2021: return((CHAR)(0x87 & 0xff)); case 0x2022: return((CHAR)(0x95 & 0xff)); case 0x2026: return((CHAR)(0x85 & 0xff)); case 0x2031: return((CHAR)(0x89 & 0xff)); case 0x20AC: /* Euro */ return((CHAR)(0x80 & 0xff)); case 0x2122: return((CHAR)(0x99 & 0xff)); default: return(0x003f); } } int /* Windows Code Page 1254 (Turkish) */ #ifdef CK_ANSIC tx_cp1254(USHORT c) #else tx_cp1254(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) return((CHAR)(c & 0xff)); switch (c) { case 0x011e: return((CHAR)(0xd0 & 0xff)); /* G breve */ case 0x0130: return((CHAR)(0xdd & 0xff)); /* I with dot */ case 0x015e: return((CHAR)(0xde & 0xff)); /* S cedilla */ case 0x011f: return((CHAR)(0xf0 & 0xff)); /* g breve */ case 0x0131: return((CHAR)(0xfd & 0xff)); /* i dotless */ case 0x015f: return((CHAR)(0xfe & 0xff)); /* s cedilla */ default: return(tx_cp1252(c)); /* The rest is like Windows Latin-1 */ } } int #ifdef CK_ANSIC tx_cp1255(USHORT c) #else tx_cp1255(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x080) return((CHAR)(c & 0xff)); switch (c) { case 0x20AC: return((CHAR)(0x80 & 0xff)); /* EURO SIGN */ case 0x201A: return((CHAR)(0x82 & 0xff)); /* SINGLE LOW-9 QUOTATION MARK */ case 0x0192: return((CHAR)(0x83 & 0xff)); /* LATIN SMALL LETTER F WITH HOOK */ case 0x201E: return((CHAR)(0x84 & 0xff)); /* DOUBLE LOW-9 QUOTATION MARK */ case 0x2026: return((CHAR)(0x85 & 0xff)); /* HORIZONTAL ELLIPSIS */ case 0x2020: return((CHAR)(0x86 & 0xff)); /* DAGGER */ case 0x2021: return((CHAR)(0x87 & 0xff)); /* DOUBLE DAGGER */ case 0x02C6: return((CHAR)(0x88 & 0xff)); /* MODIFIER LETTER CIRCUMFLEX ACCENT */ case 0x2030: return((CHAR)(0x89 & 0xff)); /* PER MILLE SIGN */ case 0x2039: return((CHAR)(0x8B & 0xff)); /* SINGLE LEFT-POINTING ANGLE QUOTE */ case 0x2018: return((CHAR)(0x91 & 0xff)); /* LEFT SINGLE QUOTATION MARK */ case 0x2019: return((CHAR)(0x92 & 0xff)); /* RIGHT SINGLE QUOTATION MARK */ case 0x201C: return((CHAR)(0x93 & 0xff)); /* LEFT DOUBLE QUOTATION MARK */ case 0x201D: return((CHAR)(0x94 & 0xff)); /* RIGHT DOUBLE QUOTATION MARK */ case 0x2022: return((CHAR)(0x95 & 0xff)); /* BULLET */ case 0x2013: return((CHAR)(0x96 & 0xff)); /* EN DASH */ case 0x2014: return((CHAR)(0x97 & 0xff)); /* EM DASH */ case 0x02DC: return((CHAR)(0x98 & 0xff)); /* SMALL TILDE */ case 0x2122: return((CHAR)(0x99 & 0xff)); /* TRADE MARK SIGN */ case 0x203A: return((CHAR)(0x9B & 0xff)); /* SINGLE RIGHT-POINTING ANGLE QUOTE */ case 0x00A0: return((CHAR)(0xA0 & 0xff)); /* NO-BREAK SPACE */ case 0x00A1: return((CHAR)(0xA1 & 0xff)); /* INVERTED EXCLAMATION MARK */ case 0x00A2: return((CHAR)(0xA2 & 0xff)); /* CENT SIGN */ case 0x00A3: return((CHAR)(0xA3 & 0xff)); /* POUND SIGN */ case 0x20AA: return((CHAR)(0xA4 & 0xff)); /* NEW SHEQEL SIGN */ case 0x00A5: return((CHAR)(0xA5 & 0xff)); /* YEN SIGN */ case 0x00A6: return((CHAR)(0xA6 & 0xff)); /* BROKEN BAR */ case 0x00A7: return((CHAR)(0xA7 & 0xff)); /* SECTION SIGN */ case 0x00A8: return((CHAR)(0xA8 & 0xff)); /* DIAERESIS */ case 0x00A9: return((CHAR)(0xA9 & 0xff)); /* COPYRIGHT SIGN */ case 0x00D7: return((CHAR)(0xAA & 0xff)); /* MULTIPLICATION SIGN */ case 0x00AB: return((CHAR)(0xAB & 0xff)); /* LEFT-POINTING DOUBLE ANGLE QUOTE */ case 0x00AC: return((CHAR)(0xAC & 0xff)); /* NOT SIGN */ case 0x00AD: return((CHAR)(0xAD & 0xff)); /* SOFT HYPHEN */ case 0x00AE: return((CHAR)(0xAE & 0xff)); /* REGISTERED SIGN */ case 0x00AF: return((CHAR)(0xAF & 0xff)); /* MACRON */ case 0x00B0: return((CHAR)(0xB0 & 0xff)); /* DEGREE SIGN */ case 0x00B1: return((CHAR)(0xB1 & 0xff)); /* PLUS-MINUS SIGN */ case 0x00B2: return((CHAR)(0xB2 & 0xff)); /* SUPERSCRIPT TWO */ case 0x00B3: return((CHAR)(0xB3 & 0xff)); /* SUPERSCRIPT THREE */ case 0x00B4: return((CHAR)(0xB4 & 0xff)); /* ACUTE ACCENT */ case 0x00B5: return((CHAR)(0xB5 & 0xff)); /* MICRO SIGN */ case 0x00B6: return((CHAR)(0xB6 & 0xff)); /* PILCROW SIGN */ case 0x00B7: return((CHAR)(0xB7 & 0xff)); /* MIDDLE DOT */ case 0x00B8: return((CHAR)(0xB8 & 0xff)); /* CEDILLA */ case 0x00B9: return((CHAR)(0xB9 & 0xff)); /* SUPERSCRIPT ONE */ case 0x00F7: return((CHAR)(0xBA & 0xff)); /* DIVISION SIGN */ case 0x00BB: return((CHAR)(0xBB & 0xff)); /* RIGHT-POINTING DOUBLE ANGLE QUOTE */ case 0x00BC: return((CHAR)(0xBC & 0xff)); /* VULGAR FRACTION ONE QUARTER */ case 0x00BD: return((CHAR)(0xBD & 0xff)); /* VULGAR FRACTION ONE HALF */ case 0x00BE: return((CHAR)(0xBE & 0xff)); /* VULGAR FRACTION THREE QUARTERS */ case 0x00BF: return((CHAR)(0xBF & 0xff)); /* INVERTED QUESTION MARK */ case 0x05B0: return((CHAR)(0xC0 & 0xff)); /* HEBREW POINT SHEVA */ case 0x05B1: return((CHAR)(0xC1 & 0xff)); /* HEBREW POINT HATAF SEGOL */ case 0x05B2: return((CHAR)(0xC2 & 0xff)); /* HEBREW POINT HATAF PATAH */ case 0x05B3: return((CHAR)(0xC3 & 0xff)); /* HEBREW POINT HATAF QAMATS */ case 0x05B4: return((CHAR)(0xC4 & 0xff)); /* HEBREW POINT HIRIQ */ case 0x05B5: return((CHAR)(0xC5 & 0xff)); /* HEBREW POINT TSERE */ case 0x05B6: return((CHAR)(0xC6 & 0xff)); /* HEBREW POINT SEGOL */ case 0x05B7: return((CHAR)(0xC7 & 0xff)); /* HEBREW POINT PATAH */ case 0x05B8: return((CHAR)(0xC8 & 0xff)); /* HEBREW POINT QAMATS */ case 0x05B9: return((CHAR)(0xC9 & 0xff)); /* HEBREW POINT HOLAM */ case 0x05BB: return((CHAR)(0xCB & 0xff)); /* HEBREW POINT QUBUTS */ case 0x05BC: return((CHAR)(0xCC & 0xff)); /* HEBREW POINT DAGESH OR MAPIQ */ case 0x05BD: return((CHAR)(0xCD & 0xff)); /* HEBREW POINT METEG */ case 0x05BE: return((CHAR)(0xCE & 0xff)); /* HEBREW PUNCTUATION MAQAF */ case 0x05BF: return((CHAR)(0xCF & 0xff)); /* HEBREW POINT RAFE */ case 0x05C0: return((CHAR)(0xD0 & 0xff)); /* HEBREW PUNCTUATION PASEQ */ case 0x05C1: return((CHAR)(0xD1 & 0xff)); /* HEBREW POINT SHIN DOT */ case 0x05C2: return((CHAR)(0xD2 & 0xff)); /* HEBREW POINT SIN DOT */ case 0x05C3: return((CHAR)(0xD3 & 0xff)); /* HEBREW PUNCTUATION SOF PASUQ */ case 0x05F0: return((CHAR)(0xD4 & 0xff)); /* HEBREW LIG. YIDDISH DOUBLE VAV */ case 0x05F1: return((CHAR)(0xD5 & 0xff)); /* HEBREW LIGATURE YIDDISH VAV YOD */ case 0x05F2: return((CHAR)(0xD6 & 0xff)); /* HEBREW LIG. YIDDISH DOUBLE YOD */ case 0x05F3: return((CHAR)(0xD7 & 0xff)); /* HEBREW PUNCTUATION GERESH */ case 0x05F4: return((CHAR)(0xD8 & 0xff)); /* HEBREW PUNCTUATION GERSHAYIM */ case 0x05D0: return((CHAR)(0xE0 & 0xff)); /* HEBREW LETTER ALEF */ case 0x05D1: return((CHAR)(0xE1 & 0xff)); /* HEBREW LETTER BET */ case 0x05D2: return((CHAR)(0xE2 & 0xff)); /* HEBREW LETTER GIMEL */ case 0x05D3: return((CHAR)(0xE3 & 0xff)); /* HEBREW LETTER DALET */ case 0x05D4: return((CHAR)(0xE4 & 0xff)); /* HEBREW LETTER HE */ case 0x05D5: return((CHAR)(0xE5 & 0xff)); /* HEBREW LETTER VAV */ case 0x05D6: return((CHAR)(0xE6 & 0xff)); /* HEBREW LETTER ZAYIN */ case 0x05D7: return((CHAR)(0xE7 & 0xff)); /* HEBREW LETTER HET */ case 0x05D8: return((CHAR)(0xE8 & 0xff)); /* HEBREW LETTER TET */ case 0x05D9: return((CHAR)(0xE9 & 0xff)); /* HEBREW LETTER YOD */ case 0x05DA: return((CHAR)(0xEA & 0xff)); /* HEBREW LETTER FINAL KAF */ case 0x05DB: return((CHAR)(0xEB & 0xff)); /* HEBREW LETTER KAF */ case 0x05DC: return((CHAR)(0xEC & 0xff)); /* HEBREW LETTER LAMED */ case 0x05DD: return((CHAR)(0xED & 0xff)); /* HEBREW LETTER FINAL MEM */ case 0x05DE: return((CHAR)(0xEE & 0xff)); /* HEBREW LETTER MEM */ case 0x05DF: return((CHAR)(0xEF & 0xff)); /* HEBREW LETTER FINAL NUN */ case 0x05E0: return((CHAR)(0xF0 & 0xff)); /* HEBREW LETTER NUN */ case 0x05E1: return((CHAR)(0xF1 & 0xff)); /* HEBREW LETTER SAMEKH */ case 0x05E2: return((CHAR)(0xF2 & 0xff)); /* HEBREW LETTER AYIN */ case 0x05E3: return((CHAR)(0xF3 & 0xff)); /* HEBREW LETTER FINAL PE */ case 0x05E4: return((CHAR)(0xF4 & 0xff)); /* HEBREW LETTER PE */ case 0x05E5: return((CHAR)(0xF5 & 0xff)); /* HEBREW LETTER FINAL TSADI */ case 0x05E6: return((CHAR)(0xF6 & 0xff)); /* HEBREW LETTER TSADI */ case 0x05E7: return((CHAR)(0xF7 & 0xff)); /* HEBREW LETTER QOF */ case 0x05E8: return((CHAR)(0xF8 & 0xff)); /* HEBREW LETTER RESH */ case 0x05E9: return((CHAR)(0xF9 & 0xff)); /* HEBREW LETTER SHIN */ case 0x05EA: return((CHAR)(0xFA & 0xff)); /* HEBREW LETTER TAV */ case 0x200E: return((CHAR)(0xFD & 0xff)); /* LEFT-TO-RIGHT MARK */ case 0x200F: return((CHAR)(0xFE & 0xff)); /* RIGHT-TO-LEFT MARK */ default: return(0x003f); } } int /* Windows Arabic */ #ifdef CK_ANSIC tx_cp1256(USHORT c) #else tx_cp1256(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) return((CHAR)(c & 0xff)); switch (c) { case 0x20AC: return((CHAR)(0x80 & 0xff)); /* EURO SIGN */ case 0x067E: return((CHAR)(0x81 & 0xff)); /* ARABIC LETTER PEH */ case 0x201A: return((CHAR)(0x82 & 0xff)); /* SINGLE LOW-9 QUOTATION MARK */ case 0x0192: return((CHAR)(0x83 & 0xff)); /* LATIN SMALL LETTER F WITH HOOK */ case 0x201E: return((CHAR)(0x84 & 0xff)); /* DOUBLE LOW-9 QUOTATION MARK */ case 0x2026: return((CHAR)(0x85 & 0xff)); /* HORIZONTAL ELLIPSIS */ case 0x2020: return((CHAR)(0x86 & 0xff)); /* DAGGER */ case 0x2021: return((CHAR)(0x87 & 0xff)); /* DOUBLE DAGGER */ case 0x02C6: return((CHAR)(0x88 & 0xff)); /* MODIFIER LETTER CIRCUMFLEX ACCENT */ case 0x2030: return((CHAR)(0x89 & 0xff)); /* PER MILLE SIGN */ case 0x2039: return((CHAR)(0x8B & 0xff)); /* SINGLE LEFT-POINTING ANGLE QUOTE */ case 0x0152: return((CHAR)(0x8C & 0xff)); /* LATIN CAPITAL LIGATURE OE */ case 0x0686: return((CHAR)(0x8D & 0xff)); /* ARABIC LETTER TCHEH */ case 0x0698: return((CHAR)(0x8E & 0xff)); /* ARABIC LETTER JEH */ case 0x06AF: return((CHAR)(0x90 & 0xff)); /* ARABIC LETTER GAF */ case 0x2018: return((CHAR)(0x91 & 0xff)); /* LEFT SINGLE QUOTATION MARK */ case 0x2019: return((CHAR)(0x92 & 0xff)); /* RIGHT SINGLE QUOTATION MARK */ case 0x201C: return((CHAR)(0x93 & 0xff)); /* LEFT DOUBLE QUOTATION MARK */ case 0x201D: return((CHAR)(0x94 & 0xff)); /* RIGHT DOUBLE QUOTATION MARK */ case 0x2022: return((CHAR)(0x95 & 0xff)); /* BULLET */ case 0x2013: return((CHAR)(0x96 & 0xff)); /* EN DASH */ case 0x2014: return((CHAR)(0x97 & 0xff)); /* EM DASH */ case 0x2122: return((CHAR)(0x99 & 0xff)); /* TRADE MARK SIGN */ case 0x203A: return((CHAR)(0x9B & 0xff)); /* SINGLE RIGHT-POINTING ANGLE QUOTE */ case 0x0153: return((CHAR)(0x9C & 0xff)); /* LATIN SMALL LIGATURE OE */ case 0x200C: return((CHAR)(0x9D & 0xff)); /* ZERO WIDTH NON-JOINER */ case 0x200D: return((CHAR)(0x9E & 0xff)); /* ZERO WIDTH JOINER */ case 0x00A0: return((CHAR)(0xA0 & 0xff)); /* NO-BREAK SPACE */ case 0x060C: return((CHAR)(0xA1 & 0xff)); /* ARABIC COMMA */ case 0x00A2: return((CHAR)(0xA2 & 0xff)); /* CENT SIGN */ case 0x00A3: return((CHAR)(0xA3 & 0xff)); /* POUND SIGN */ case 0x00A4: return((CHAR)(0xA4 & 0xff)); /* CURRENCY SIGN */ case 0x00A5: return((CHAR)(0xA5 & 0xff)); /* YEN SIGN */ case 0x00A6: return((CHAR)(0xA6 & 0xff)); /* BROKEN BAR */ case 0x00A7: return((CHAR)(0xA7 & 0xff)); /* SECTION SIGN */ case 0x00A8: return((CHAR)(0xA8 & 0xff)); /* DIAERESIS */ case 0x00A9: return((CHAR)(0xA9 & 0xff)); /* COPYRIGHT SIGN */ case 0x00AB: return((CHAR)(0xAB & 0xff)); /* LEFT-POINTING DOUBLE ANGLE QUOTE */ case 0x00AC: return((CHAR)(0xAC & 0xff)); /* NOT SIGN */ case 0x00AD: return((CHAR)(0xAD & 0xff)); /* SOFT HYPHEN */ case 0x00AE: return((CHAR)(0xAE & 0xff)); /* REGISTERED SIGN */ case 0x00AF: return((CHAR)(0xAF & 0xff)); /* MACRON */ case 0x00B0: return((CHAR)(0xB0 & 0xff)); /* DEGREE SIGN */ case 0x00B1: return((CHAR)(0xB1 & 0xff)); /* PLUS-MINUS SIGN */ case 0x00B2: return((CHAR)(0xB2 & 0xff)); /* SUPERSCRIPT TWO */ case 0x00B3: return((CHAR)(0xB3 & 0xff)); /* SUPERSCRIPT THREE */ case 0x00B4: return((CHAR)(0xB4 & 0xff)); /* ACUTE ACCENT */ case 0x00B5: return((CHAR)(0xB5 & 0xff)); /* MICRO SIGN */ case 0x00B6: return((CHAR)(0xB6 & 0xff)); /* PILCROW SIGN */ case 0x00B7: return((CHAR)(0xB7 & 0xff)); /* MIDDLE DOT */ case 0x00B8: return((CHAR)(0xB8 & 0xff)); /* CEDILLA */ case 0x00B9: return((CHAR)(0xB9 & 0xff)); /* SUPERSCRIPT ONE */ case 0x061B: return((CHAR)(0xBA & 0xff)); /* ARABIC SEMICOLON */ case 0x00BB: return((CHAR)(0xBB & 0xff)); /* RIGHT-POINTING DOUBLE ANGLE QUOTE */ case 0x00BC: return((CHAR)(0xBC & 0xff)); /* VULGAR FRACTION ONE QUARTER */ case 0x00BD: return((CHAR)(0xBD & 0xff)); /* VULGAR FRACTION ONE HALF */ case 0x00BE: return((CHAR)(0xBE & 0xff)); /* VULGAR FRACTION THREE QUARTERS */ case 0x061F: return((CHAR)(0xBF & 0xff)); /* ARABIC QUESTION MARK */ case 0x0621: return((CHAR)(0xC1 & 0xff)); /* ARABIC LETTER HAMZA */ case 0x0622: return((CHAR)(0xC2 & 0xff)); /* ARABIC LTR. ALEF WITH MADDA ABOVE */ case 0x0623: return((CHAR)(0xC3 & 0xff)); /* ARABIC LTR. ALEF WITH HAMZA ABOVE */ case 0x0624: return((CHAR)(0xC4 & 0xff)); /* ARABIC LTR. WAW WITH HAMZA ABOVE */ case 0x0625: return((CHAR)(0xC5 & 0xff)); /* ARABIC LTR. ALEF WITH HAMZA BELOW */ case 0x0626: return((CHAR)(0xC6 & 0xff)); /* ARABIC LTR. YEH WITH HAMZA ABOVE */ case 0x0627: return((CHAR)(0xC7 & 0xff)); /* ARABIC LTR. ALEF */ case 0x0628: return((CHAR)(0xC8 & 0xff)); /* ARABIC LTR. BEH */ case 0x0629: return((CHAR)(0xC9 & 0xff)); /* ARABIC LETTER TEH MARBUTA */ case 0x062A: return((CHAR)(0xCA & 0xff)); /* ARABIC LETTER TEH */ case 0x062B: return((CHAR)(0xCB & 0xff)); /* ARABIC LETTER THEH */ case 0x062C: return((CHAR)(0xCC & 0xff)); /* ARABIC LETTER JEEM */ case 0x062D: return((CHAR)(0xCD & 0xff)); /* ARABIC LETTER HAH */ case 0x062E: return((CHAR)(0xCE & 0xff)); /* ARABIC LETTER KHAH */ case 0x062F: return((CHAR)(0xCF & 0xff)); /* ARABIC LETTER DAL */ case 0x0630: return((CHAR)(0xD0 & 0xff)); /* ARABIC LETTER THAL */ case 0x0631: return((CHAR)(0xD1 & 0xff)); /* ARABIC LETTER REH */ case 0x0632: return((CHAR)(0xD2 & 0xff)); /* ARABIC LETTER ZAIN */ case 0x0633: return((CHAR)(0xD3 & 0xff)); /* ARABIC LETTER SEEN */ case 0x0634: return((CHAR)(0xD4 & 0xff)); /* ARABIC LETTER SHEEN */ case 0x0635: return((CHAR)(0xD5 & 0xff)); /* ARABIC LETTER SAD */ case 0x0636: return((CHAR)(0xD6 & 0xff)); /* ARABIC LETTER DAD */ case 0x00D7: return((CHAR)(0xD7 & 0xff)); /* MULTIPLICATION SIGN */ case 0x0637: return((CHAR)(0xD8 & 0xff)); /* ARABIC LETTER TAH */ case 0x0638: return((CHAR)(0xD9 & 0xff)); /* ARABIC LETTER ZAH */ case 0x0639: return((CHAR)(0xDA & 0xff)); /* ARABIC LETTER AIN */ case 0x063A: return((CHAR)(0xDB & 0xff)); /* ARABIC LETTER GHAIN */ case 0x0640: return((CHAR)(0xDC & 0xff)); /* ARABIC TATWEEL */ case 0x0641: return((CHAR)(0xDD & 0xff)); /* ARABIC LETTER FEH */ case 0x0642: return((CHAR)(0xDE & 0xff)); /* ARABIC LETTER QAF */ case 0x0643: return((CHAR)(0xDF & 0xff)); /* ARABIC LETTER KAF */ case 0x00E0: return((CHAR)(0xE0 & 0xff)); /* LATIN SMALL LETTER A WITH GRAVE */ case 0x0644: return((CHAR)(0xE1 & 0xff)); /* ARABIC LETTER LAM */ case 0x00E2: return((CHAR)(0xE2 & 0xff)); /* SMALL LETTER A WITH CIRCUMFLEX */ case 0x0645: return((CHAR)(0xE3 & 0xff)); /* ARABIC LETTER MEEM */ case 0x0646: return((CHAR)(0xE4 & 0xff)); /* ARABIC LETTER NOON */ case 0x0647: return((CHAR)(0xE5 & 0xff)); /* ARABIC LETTER HEH */ case 0x0648: return((CHAR)(0xE6 & 0xff)); /* ARABIC LETTER WAW */ case 0x00E7: return((CHAR)(0xE7 & 0xff)); /* LATIN SMALL LETTER C WITH CEDILLA */ case 0x00E8: return((CHAR)(0xE8 & 0xff)); /* LATIN SMALL LETTER E WITH GRAVE */ case 0x00E9: return((CHAR)(0xE9 & 0xff)); /* LATIN SMALL LETTER E WITH ACUTE */ case 0x00EA: return((CHAR)(0xEA & 0xff)); /* SMALL LETTER E WITH CIRCUMFLEX */ case 0x00EB: return((CHAR)(0xEB & 0xff)); /* SMALL LETTER E WITH DIAERESIS */ case 0x0649: return((CHAR)(0xEC & 0xff)); /* ARABIC LETTER ALEF MAKSURA */ case 0x064A: return((CHAR)(0xED & 0xff)); /* ARABIC LETTER YEH */ case 0x00EE: return((CHAR)(0xEE & 0xff)); /* SMALL LETTER I WITH CIRCUMFLEX */ case 0x00EF: return((CHAR)(0xEF & 0xff)); /* SMALL LETTER I WITH DIAERESIS */ case 0x064B: return((CHAR)(0xF0 & 0xff)); /* ARABIC FATHATAN */ case 0x064C: return((CHAR)(0xF1 & 0xff)); /* ARABIC DAMMATAN */ case 0x064D: return((CHAR)(0xF2 & 0xff)); /* ARABIC KASRATAN */ case 0x064E: return((CHAR)(0xF3 & 0xff)); /* ARABIC FATHA */ case 0x00F4: return((CHAR)(0xF4 & 0xff)); /* SMALL LETTER O WITH CIRCUMFLEX */ case 0x064F: return((CHAR)(0xF5 & 0xff)); /* ARABIC DAMMA */ case 0x0650: return((CHAR)(0xF6 & 0xff)); /* ARABIC KASRA */ case 0x00F7: return((CHAR)(0xF7 & 0xff)); /* DIVISION SIGN */ case 0x0651: return((CHAR)(0xF8 & 0xff)); /* ARABIC SHADDA */ case 0x00F9: return((CHAR)(0xF9 & 0xff)); /* LATIN SMALL LETTER U WITH GRAVE */ case 0x0652: return((CHAR)(0xFA & 0xff)); /* ARABIC SUKUN */ case 0x00FB: return((CHAR)(0xFB & 0xff)); /* SMALL LETTER U WITH CIRCUMFLEX */ case 0x00FC: return((CHAR)(0xFC & 0xff)); /* SMALL LETTER U WITH DIAERESIS */ case 0x200E: return((CHAR)(0xFD & 0xff)); /* LEFT-TO-RIGHT MARK */ case 0x200F: return((CHAR)(0xFE & 0xff)); /* RIGHT-TO-LEFT MARK */ default: return(0x003f); } } int /* Windows Code Page 1257 (Latin-4) */ #ifdef CK_ANSIC tx_cp1257(USHORT c) #else tx_cp1257(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) return((CHAR)(c & 0xff)); switch (c) { case 0x003c: return((CHAR)(0x8b & 0xff)); case 0x003e: return((CHAR)(0x9b & 0xff)); case 0x00A0: return((CHAR)(0xa0 & 0xff)); case 0x00A2: return((CHAR)(0xa2 & 0xff)); case 0x00A3: return((CHAR)(0xa3 & 0xff)); case 0x00A4: return((CHAR)(0xa4 & 0xff)); case 0x00A6: return((CHAR)(0xa6 & 0xff)); case 0x00A7: return((CHAR)(0xa7 & 0xff)); case 0x00A9: return((CHAR)(0xa9 & 0xff)); case 0x00AB: return((CHAR)(0xab & 0xff)); case 0x00AC: return((CHAR)(0xac & 0xff)); case 0x00AD: return((CHAR)(0xad & 0xff)); case 0x00AE: return((CHAR)(0xae & 0xff)); case 0x00B0: return((CHAR)(0xb0 & 0xff)); case 0x00B1: return((CHAR)(0xb1 & 0xff)); case 0x00B2: return((CHAR)(0xb2 & 0xff)); case 0x00B3: return((CHAR)(0xb3 & 0xff)); case 0x00B5: return((CHAR)(0xb5 & 0xff)); case 0x00B6: return((CHAR)(0xb6 & 0xff)); case 0x00B7: return((CHAR)(0xb7 & 0xff)); case 0x00B9: return((CHAR)(0xb9 & 0xff)); case 0x00BB: return((CHAR)(0xbb & 0xff)); case 0x00BC: return((CHAR)(0xbc & 0xff)); case 0x00BD: return((CHAR)(0xbd & 0xff)); case 0x00BE: return((CHAR)(0xbe & 0xff)); case 0x00C4: return((CHAR)(0xc4 & 0xff)); case 0x00C5: return((CHAR)(0xc5 & 0xff)); case 0x00c6: return((CHAR)(0xaf & 0xff)); case 0x00C9: return((CHAR)(0xc9 & 0xff)); case 0x00d3: return((CHAR)(0xd3 & 0xff)); case 0x00D5: return((CHAR)(0xd5 & 0xff)); case 0x00D6: return((CHAR)(0xd6 & 0xff)); case 0x00D7: return((CHAR)(0xd7 & 0xff)); case 0x00d8: return((CHAR)(0xa8 & 0xff)); case 0x00DC: return((CHAR)(0xdc & 0xff)); case 0x00DF: return((CHAR)(0xdf & 0xff)); case 0x00E4: return((CHAR)(0xe4 & 0xff)); case 0x00E5: return((CHAR)(0xe5 & 0xff)); case 0x00e6: return((CHAR)(0xbf & 0xff)); case 0x00E9: return((CHAR)(0xe9 & 0xff)); case 0x00f3: return((CHAR)(0xf3 & 0xff)); case 0x00F5: return((CHAR)(0xf5 & 0xff)); case 0x00F6: return((CHAR)(0xf6 & 0xff)); case 0x00F7: return((CHAR)(0xf7 & 0xff)); case 0x00f8: return((CHAR)(0xb8 & 0xff)); case 0x00fc: return((CHAR)(0xfc & 0xff)); case 0x0100: return((CHAR)(0xc2 & 0xff)); case 0x0101: return((CHAR)(0xe2 & 0xff)); case 0x0104: return((CHAR)(0xc0 & 0xff)); case 0x0105: return((CHAR)(0xe0 & 0xff)); case 0x0106: return((CHAR)(0xc3 & 0xff)); case 0x0107: return((CHAR)(0xe3 & 0xff)); case 0x010C: return((CHAR)(0xc8 & 0xff)); case 0x010D: return((CHAR)(0xe8 & 0xff)); case 0x0112: return((CHAR)(0xc7 & 0xff)); case 0x0113: return((CHAR)(0xe7 & 0xff)); case 0x0116: return((CHAR)(0xcb & 0xff)); case 0x0117: return((CHAR)(0xeb & 0xff)); case 0x0118: return((CHAR)(0xc6 & 0xff)); case 0x0119: return((CHAR)(0xe6 & 0xff)); case 0x0122: return((CHAR)(0xcc & 0xff)); case 0x0123: return((CHAR)(0xec & 0xff)); case 0x012a: return((CHAR)(0xce & 0xff)); case 0x012b: return((CHAR)(0xee & 0xff)); case 0x012e: return((CHAR)(0xc1 & 0xff)); case 0x012f: return((CHAR)(0xe1 & 0xff)); case 0x0136: return((CHAR)(0xcd & 0xff)); case 0x0137: return((CHAR)(0xed & 0xff)); case 0x013c: return((CHAR)(0xef & 0xff)); case 0x0141: return((CHAR)(0xd9 & 0xff)); case 0x0142: return((CHAR)(0xf9 & 0xff)); case 0x0143: return((CHAR)(0xd1 & 0xff)); case 0x0144: return((CHAR)(0xf1 & 0xff)); case 0x0145: return((CHAR)(0xd2 & 0xff)); case 0x0146: return((CHAR)(0xf2 & 0xff)); case 0x014c: return((CHAR)(0xd4 & 0xff)); case 0x014d: return((CHAR)(0xf4 & 0xff)); case 0x0156: return((CHAR)(0xaa & 0xff)); case 0x0157: return((CHAR)(0xba & 0xff)); case 0x015A: return((CHAR)(0xda & 0xff)); case 0x015b: return((CHAR)(0xfa & 0xff)); case 0x0160: return((CHAR)(0xd0 & 0xff)); case 0x0161: return((CHAR)(0xf0 & 0xff)); case 0x016a: return((CHAR)(0xdb & 0xff)); case 0x016b: return((CHAR)(0xfb & 0xff)); case 0x0172: return((CHAR)(0xd8 & 0xff)); case 0x0173: return((CHAR)(0xf8 & 0xff)); case 0x0179: return((CHAR)(0xca & 0xff)); case 0x017a: return((CHAR)(0xea & 0xff)); case 0x017b: return((CHAR)(0xdd & 0xff)); case 0x017c: return((CHAR)(0xfd & 0xff)); case 0x017d: return((CHAR)(0xde & 0xff)); case 0x017e: return((CHAR)(0xfe & 0xff)); case 0x2012: return((CHAR)(0x96 & 0xff)); case 0x2014: return((CHAR)(0x97 & 0xff)); case 0x2018: return((CHAR)(0x91 & 0xff)); case 0x2019: return((CHAR)(0x92 & 0xff)); case 0x201a: return((CHAR)(0x82 & 0xff)); case 0x201c: return((CHAR)(0x93 & 0xff)); case 0x201d: return((CHAR)(0x94 & 0xff)); case 0x201e: return((CHAR)(0x84 & 0xff)); case 0x2020: return((CHAR)(0x86 & 0xff)); case 0x2021: return((CHAR)(0x87 & 0xff)); case 0x2022: return((CHAR)(0x95 & 0xff)); case 0x2026: return((CHAR)(0x85 & 0xff)); case 0x2031: return((CHAR)(0x89 & 0xff)); case 0x20AC: /* Euro */ return((CHAR)(0x80 & 0xff)); case 0x2122: return((CHAR)(0x99 & 0xff)); default: return(0x003f); } } int /* Windows Code Page 1258 (Viet Nam) */ #ifdef CK_ANSIC tx_cp1258(USHORT c) #else tx_cp1258(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x20AC: return((CHAR)(0x80 & 0xff)); /* EURO SIGN */ case 0x201A: return((CHAR)(0x82 & 0xff)); /* SINGLE LOW-9 QUOTATION MARK */ case 0x0192: return((CHAR)(0x83 & 0xff)); /* LATIN SMALL LETTER F WITH HOOK */ case 0x201E: return((CHAR)(0x84 & 0xff)); /* DOUBLE LOW-9 QUOTATION MARK */ case 0x2026: return((CHAR)(0x85 & 0xff)); /* HORIZONTAL ELLIPSIS */ case 0x2020: return((CHAR)(0x86 & 0xff)); /* DAGGER */ case 0x2021: return((CHAR)(0x87 & 0xff)); /* DOUBLE DAGGER */ case 0x02C6: return((CHAR)(0x88 & 0xff)); /* MODIFIER LETTER CIRCUMFLEX ACCENT */ case 0x2030: return((CHAR)(0x89 & 0xff)); /* PER MILLE SIGN */ case 0x2039: return((CHAR)(0x8B & 0xff)); /* SINGLE LEFT ANGLE QUOTATION MARK */ case 0x0152: return((CHAR)(0x8C & 0xff)); /* LATIN CAPITAL LIGATURE OE */ case 0x2018: return((CHAR)(0x91 & 0xff)); /* LEFT SINGLE QUOTATION MARK */ case 0x2019: return((CHAR)(0x92 & 0xff)); /* RIGHT SINGLE QUOTATION MARK */ case 0x201C: return((CHAR)(0x93 & 0xff)); /* LEFT DOUBLE QUOTATION MARK */ case 0x201D: return((CHAR)(0x94 & 0xff)); /* RIGHT DOUBLE QUOTATION MARK */ case 0x2022: return((CHAR)(0x95 & 0xff)); /* BULLET */ case 0x2013: return((CHAR)(0x96 & 0xff)); /* EN DASH */ case 0x2014: return((CHAR)(0x97 & 0xff)); /* EM DASH */ case 0x02DC: return((CHAR)(0x98 & 0xff)); /* SMALL TILDE */ case 0x2122: return((CHAR)(0x99 & 0xff)); /* TRADE MARK SIGN */ case 0x203A: /* SINGLE RIGHT-POINTING ANGLE QUOTATION MAR K*/ return((CHAR)(0x9B & 0xff)); case 0x0153: return((CHAR)(0x9C & 0xff)); /* LATIN SMALL LIGATURE OE */ case 0x0178: /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ return((CHAR)(0x9F & 0xff)); case 0x00A0: return((CHAR)(0xA0 & 0xff)); /* NO-BREAK SPACE */ case 0x00A1: return((CHAR)(0xA1 & 0xff)); /* INVERTED EXCLAMATION MARK */ case 0x00A2: return((CHAR)(0xA2 & 0xff)); /* CENT SIGN */ case 0x00A3: return((CHAR)(0xA3 & 0xff)); /* POUND SIGN */ case 0x00A4: return((CHAR)(0xA4 & 0xff)); /* CURRENCY SIGN */ case 0x00A5: return((CHAR)(0xA5 & 0xff)); /* YEN SIGN */ case 0x00A6: return((CHAR)(0xA6 & 0xff)); /* BROKEN BAR */ case 0x00A7: return((CHAR)(0xA7 & 0xff)); /* SECTION SIGN */ case 0x00A8: return((CHAR)(0xA8 & 0xff)); /* DIAERESIS */ case 0x00A9: return((CHAR)(0xA9 & 0xff)); /* COPYRIGHT SIGN */ case 0x00AA: return((CHAR)(0xAA & 0xff)); /* FEMININE ORDINAL INDICATOR */ case 0x00AB: /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */ return((CHAR)(0xAB & 0xff)); case 0x00AC: return((CHAR)(0xAC & 0xff)); /* NOT SIGN */ case 0x00AD: return((CHAR)(0xAD & 0xff)); /* SOFT HYPHEN */ case 0x00AE: return((CHAR)(0xAE & 0xff)); /* REGISTERED SIGN */ case 0x00AF: return((CHAR)(0xAF & 0xff)); /* MACRON */ case 0x00B0: return((CHAR)(0xB0 & 0xff)); /* DEGREE SIGN */ case 0x00B1: return((CHAR)(0xB1 & 0xff)); /* PLUS-MINUS SIGN */ case 0x00B2: return((CHAR)(0xB2 & 0xff)); /* SUPERSCRIPT TWO */ case 0x00B3: return((CHAR)(0xB3 & 0xff)); /* SUPERSCRIPT THREE */ case 0x00B4: return((CHAR)(0xB4 & 0xff)); /* ACUTE ACCENT */ case 0x00B5: return((CHAR)(0xB5 & 0xff)); /* MICRO SIGN */ case 0x00B6: return((CHAR)(0xB6 & 0xff)); /* PILCROW SIGN */ case 0x00B7: return((CHAR)(0xB7 & 0xff)); /* MIDDLE DOT */ case 0x00B8: return((CHAR)(0xB8 & 0xff)); /* CEDILLA */ case 0x00B9: return((CHAR)(0xB9 & 0xff)); /* SUPERSCRIPT ONE */ case 0x00BA: return((CHAR)(0xBA & 0xff)); /* MASCULINE ORDINAL INDICATOR */ case 0x00BB: /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MAR K*/ return((CHAR)(0xBB & 0xff)); case 0x00BC: return((CHAR)(0xBC & 0xff)); /* VULGAR FRACTION ONE QUARTER */ case 0x00BD: return((CHAR)(0xBD & 0xff)); /* VULGAR FRACTION ONE HALF */ case 0x00BE: return((CHAR)(0xBE & 0xff)); /* VULGAR FRACTION THREE QUARTERS */ case 0x00BF: return((CHAR)(0xBF & 0xff)); /* INVERTED QUESTION MARK */ case 0x00C0: return((CHAR)(0xC0 & 0xff)); /* LATIN CAPITAL LETTER A WITH GRAVE */ case 0x00C1: return((CHAR)(0xC1 & 0xff)); /* LATIN CAPITAL LETTER A WITH ACUTE */ case 0x00C2: return((CHAR)(0xC2 & 0xff)); /* A CIRCUMFLEX */ case 0x0102: return((CHAR)(0xC3 & 0xff)); /* LATIN CAPITAL LETTER A WITH BREVE */ case 0x00C4: return((CHAR)(0xC4 & 0xff)); /* A DIAERESIS */ case 0x00C5: return((CHAR)(0xC5 & 0xff)); /* A RING */ case 0x00C6: return((CHAR)(0xC6 & 0xff)); /* LATIN CAPITAL LETTER AE */ case 0x00C7: return((CHAR)(0xC7 & 0xff)); /* C CEDILLA */ case 0x00C8: return((CHAR)(0xC8 & 0xff)); /* E GRAVE */ case 0x00C9: return((CHAR)(0xC9 & 0xff)); /* LATIN CAPITAL LETTER E WITH ACUTE */ case 0x00CA: return((CHAR)(0xCA & 0xff)); /* E WITH CIRCUMFLEX */ case 0x00CB: return((CHAR)(0xCB & 0xff)); /* E WITH DIAERESIS */ case 0x0300: return((CHAR)(0xCC & 0xff)); /* COMBINING GRAVE ACCENT */ case 0x00CD: return((CHAR)(0xCD & 0xff)); /* I WITH ACUTE */ case 0x00CE: return((CHAR)(0xCE & 0xff)); /* I WITH CIRCUMFLEX */ case 0x00CF: return((CHAR)(0xCF & 0xff)); /* I WITH DIAERESIS */ case 0x0110: return((CHAR)(0xD0 & 0xff)); /* D WITH STROKE */ case 0x00D1: return((CHAR)(0xD1 & 0xff)); /* LATIN CAPITAL LETTER N WITH TILDE */ case 0x0309: return((CHAR)(0xD2 & 0xff)); /* COMBINING HOOK ABOVE */ case 0x00D3: return((CHAR)(0xD3 & 0xff)); /* LATIN CAPITAL LETTER O WITH ACUTE */ case 0x00D4: return((CHAR)(0xD4 & 0xff)); /* O WITH CIRCUMFLEX */ case 0x01A0: return((CHAR)(0xD5 & 0xff)); /* LATIN CAPITAL LETTER O WITH HORN */ case 0x00D6: return((CHAR)(0xD6 & 0xff)); /* O WITH DIAERESIS */ case 0x00D7: return((CHAR)(0xD7 & 0xff)); /* MULTIPLICATION SIGN */ case 0x00D8: return((CHAR)(0xD8 & 0xff)); /* O WITH STROKE */ case 0x00D9: return((CHAR)(0xD9 & 0xff)); /* LATIN CAPITAL LETTER U WITH GRAVE */ case 0x00DA: return((CHAR)(0xDA & 0xff)); /* LATIN CAPITAL LETTER U WITH ACUTE */ case 0x00DB: return((CHAR)(0xDB & 0xff)); /* U WITH CIRCUMFLEX */ case 0x00DC: return((CHAR)(0xDC & 0xff)); /* U WITH DIAERESIS */ case 0x01AF: return((CHAR)(0xDD & 0xff)); /* LATIN CAPITAL LETTER U WITH HORN */ case 0x0303: return((CHAR)(0xDE & 0xff)); /* COMBINING TILDE */ case 0x00DF: return((CHAR)(0xDF & 0xff)); /* LATIN SMALL LETTER SHARP S */ case 0x00E0: return((CHAR)(0xE0 & 0xff)); /* LATIN SMALL LETTER A WITH GRAVE */ case 0x00E1: return((CHAR)(0xE1 & 0xff)); /* LATIN SMALL LETTER A WITH ACUTE */ case 0x00E2: return((CHAR)(0xE2 & 0xff)); /* SMALL A WITH CIRCUMFLEX */ case 0x0103: return((CHAR)(0xE3 & 0xff)); /* LATIN SMALL LETTER A WITH BREVE */ case 0x00E4: return((CHAR)(0xE4 & 0xff)); /* SMALL A WITH DIAERESIS */ case 0x00E5: return((CHAR)(0xE5 & 0xff)); /* SMALL A WITH RING ABOVE */ case 0x00E6: return((CHAR)(0xE6 & 0xff)); /* LATIN SMALL LETTER AE */ case 0x00E7: return((CHAR)(0xE7 & 0xff)); /* LATIN SMALL LETTER C WITH CEDILLA */ case 0x00E8: return((CHAR)(0xE8 & 0xff)); /* LATIN SMALL LETTER E WITH GRAVE */ case 0x00E9: return((CHAR)(0xE9 & 0xff)); /* LATIN SMALL LETTER E WITH ACUTE */ case 0x00EA: return((CHAR)(0xEA & 0xff)); /* SMALL E WITH CIRCUMFLEX */ case 0x00EB: return((CHAR)(0xEB & 0xff)); /* SMALL E WITH DIAERESIS */ case 0x0301: return((CHAR)(0xEC & 0xff)); /* COMBINING ACUTE ACCENT */ case 0x00ED: return((CHAR)(0xED & 0xff)); /* LATIN SMALL LETTER I WITH ACUTE */ case 0x00EE: return((CHAR)(0xEE & 0xff)); /* SMALL I WITH CIRCUMFLEX */ case 0x00EF: return((CHAR)(0xEF & 0xff)); /* SMALL I WITH DIAERESIS */ case 0x0111: return((CHAR)(0xF0 & 0xff)); /* LATIN SMALL LETTER D WITH STROKE */ case 0x00F1: return((CHAR)(0xF1 & 0xff)); /* LATIN SMALL LETTER N WITH TILDE */ case 0x0323: return((CHAR)(0xF2 & 0xff)); /* COMBINING DOT BELOW */ case 0x00F3: return((CHAR)(0xF3 & 0xff)); /* LATIN SMALL LETTER O WITH ACUTE */ case 0x00F4: return((CHAR)(0xF4 & 0xff)); /* SMALL O WITH CIRCUMFLEX */ case 0x01A1: return((CHAR)(0xF5 & 0xff)); /* LATIN SMALL LETTER O WITH HORN */ case 0x00F6: return((CHAR)(0xF6 & 0xff)); /* SMALL O WITH DIAERESIS */ case 0x00F7: return((CHAR)(0xF7 & 0xff)); /* DIVISION SIGN */ case 0x00F8: return((CHAR)(0xF8 & 0xff)); /* LATIN SMALL LETTER O WITH STROKE */ case 0x00F9: return((CHAR)(0xF9 & 0xff)); /* LATIN SMALL LETTER U WITH GRAVE */ case 0x00FA: return((CHAR)(0xFA & 0xff)); /* LATIN SMALL LETTER U WITH ACUTE */ case 0x00FB: return((CHAR)(0xFB & 0xff)); /* SMALL U WITH CIRCUMFLEX */ case 0x00FC: return((CHAR)(0xFC & 0xff)); /* SMALL U WITH DIAERESIS */ case 0x01B0: return((CHAR)(0xFD & 0xff)); /* LATIN SMALL LETTER U WITH HORN */ case 0x20AB: return((CHAR)(0xFE & 0xff)); /* DONG SIGN */ case 0x00FF: return((CHAR)(0xFF & 0xff)); /* SMALL Y WITH DIAERESIS */ default: return(0x003f); } } int /* Code Page 037 - EBCDIC (U.S.) */ #ifdef CK_ANSIC tx_cp37(USHORT c) #else tx_cp37(c) USHORT c; #endif /* CK_ANSIC */ { switch (c) { case 0x0000: return((CHAR)(0x00 & 0xff)); /* NULL */ case 0x0001: return((CHAR)(0x01 & 0xff)); /* START OF HEADING */ case 0x0002: return((CHAR)(0x02 & 0xff)); /* START OF TEXT */ case 0x0003: return((CHAR)(0x03 & 0xff)); /* END OF TEXT */ case 0x009C: return((CHAR)(0x04 & 0xff)); /* CONTROL */ case 0x0009: return((CHAR)(0x05 & 0xff)); /* HORIZONTAL TABULATION */ case 0x0086: return((CHAR)(0x06 & 0xff)); /* CONTROL */ case 0x007F: return((CHAR)(0x07 & 0xff)); /* DELETE */ case 0x0097: return((CHAR)(0x08 & 0xff)); /* CONTROL */ case 0x008D: return((CHAR)(0x09 & 0xff)); /* CONTROL */ case 0x008E: return((CHAR)(0x0A & 0xff)); /* CONTROL */ case 0x000B: return((CHAR)(0x0B & 0xff)); /* VERTICAL TABULATION */ case 0x000C: return((CHAR)(0x0C & 0xff)); /* FORM FEED */ case 0x000D: return((CHAR)(0x0D & 0xff)); /* CARRIAGE RETURN */ case 0x000E: return((CHAR)(0x0E & 0xff)); /* SHIFT OUT */ case 0x000F: return((CHAR)(0x0F & 0xff)); /* SHIFT IN */ case 0x0010: return((CHAR)(0x10 & 0xff)); /* DATA LINK ESCAPE */ case 0x0011: return((CHAR)(0x11 & 0xff)); /* DEVICE CONTROL ONE */ case 0x0012: return((CHAR)(0x12 & 0xff)); /* DEVICE CONTROL TWO */ case 0x0013: return((CHAR)(0x13 & 0xff)); /* DEVICE CONTROL THREE */ case 0x009D: return((CHAR)(0x14 & 0xff)); /* CONTROL */ case 0x0085: return((CHAR)(0x15 & 0xff)); /* CONTROL */ case 0x0008: return((CHAR)(0x16 & 0xff)); /* BACKSPACE */ case 0x0087: return((CHAR)(0x17 & 0xff)); /* CONTROL */ case 0x0018: return((CHAR)(0x18 & 0xff)); /* CANCEL */ case 0x0019: return((CHAR)(0x19 & 0xff)); /* END OF MEDIUM */ case 0x0092: return((CHAR)(0x1A & 0xff)); /* CONTROL */ case 0x008F: return((CHAR)(0x1B & 0xff)); /* CONTROL */ case 0x001C: return((CHAR)(0x1C & 0xff)); /* FILE SEPARATOR */ case 0x001D: return((CHAR)(0x1D & 0xff)); /* GROUP SEPARATOR */ case 0x001E: return((CHAR)(0x1E & 0xff)); /* RECORD SEPARATOR */ case 0x001F: return((CHAR)(0x1F & 0xff)); /* UNIT SEPARATOR */ case 0x0080: return((CHAR)(0x20 & 0xff)); /* CONTROL */ case 0x0081: return((CHAR)(0x21 & 0xff)); /* CONTROL */ case 0x0082: return((CHAR)(0x22 & 0xff)); /* CONTROL */ case 0x0083: return((CHAR)(0x23 & 0xff)); /* CONTROL */ case 0x0084: return((CHAR)(0x24 & 0xff)); /* CONTROL */ case 0x000A: return((CHAR)(0x25 & 0xff)); /* LINE FEED */ case 0x0017: return((CHAR)(0x26 & 0xff)); /* END OF TRANSMISSION BLOCK */ case 0x001B: return((CHAR)(0x27 & 0xff)); /* ESCAPE */ case 0x0088: return((CHAR)(0x28 & 0xff)); /* CONTROL */ case 0x0089: return((CHAR)(0x29 & 0xff)); /* CONTROL */ case 0x008A: return((CHAR)(0x2A & 0xff)); /* CONTROL */ case 0x008B: return((CHAR)(0x2B & 0xff)); /* CONTROL */ case 0x008C: return((CHAR)(0x2C & 0xff)); /* CONTROL */ case 0x0005: return((CHAR)(0x2D & 0xff)); /* ENQUIRY */ case 0x0006: return((CHAR)(0x2E & 0xff)); /* ACKNOWLEDGE */ case 0x0007: return((CHAR)(0x2F & 0xff)); /* BELL */ case 0x0090: return((CHAR)(0x30 & 0xff)); /* CONTROL */ case 0x0091: return((CHAR)(0x31 & 0xff)); /* CONTROL */ case 0x0016: return((CHAR)(0x32 & 0xff)); /* SYNCHRONOUS IDLE */ case 0x0093: return((CHAR)(0x33 & 0xff)); /* CONTROL */ case 0x0094: return((CHAR)(0x34 & 0xff)); /* CONTROL */ case 0x0095: return((CHAR)(0x35 & 0xff)); /* CONTROL */ case 0x0096: return((CHAR)(0x36 & 0xff)); /* CONTROL */ case 0x0004: return((CHAR)(0x37 & 0xff)); /* END OF TRANSMISSION */ case 0x0098: return((CHAR)(0x38 & 0xff)); /* CONTROL */ case 0x0099: return((CHAR)(0x39 & 0xff)); /* CONTROL */ case 0x009A: return((CHAR)(0x3A & 0xff)); /* CONTROL */ case 0x009B: return((CHAR)(0x3B & 0xff)); /* CONTROL */ case 0x0014: return((CHAR)(0x3C & 0xff)); /* DEVICE CONTROL FOUR */ case 0x0015: return((CHAR)(0x3D & 0xff)); /* NEGATIVE ACKNOWLEDGE */ case 0x009E: return((CHAR)(0x3E & 0xff)); /* CONTROL */ case 0x001A: return((CHAR)(0x3F & 0xff)); /* SUBSTITUTE */ case 0x0020: return((CHAR)(0x40 & 0xff)); /* SPACE */ case 0x00A0: return((CHAR)(0x41 & 0xff)); /* NO-BREAK SPACE */ case 0x00E2: return((CHAR)(0x42 & 0xff)); /* SMALL LETTER A WITH CIRCUMFLEX */ case 0x00E4: return((CHAR)(0x43 & 0xff)); /* SMALL LETTER A WITH DIAERESIS */ case 0x00E0: return((CHAR)(0x44 & 0xff)); /* LATIN SMALL LETTER A WITH GRAVE */ case 0x00E1: return((CHAR)(0x45 & 0xff)); /* LATIN SMALL LETTER A WITH ACUTE */ case 0x00E3: return((CHAR)(0x46 & 0xff)); /* LATIN SMALL LETTER A WITH TILDE */ case 0x00E5: return((CHAR)(0x47 & 0xff)); /* SMALL LETTER A WITH RING ABOVE */ case 0x00E7: return((CHAR)(0x48 & 0xff)); /* LATIN SMALL LETTER C WITH CEDILLA */ case 0x00F1: return((CHAR)(0x49 & 0xff)); /* LATIN SMALL LETTER N WITH TILDE */ case 0x00A2: return((CHAR)(0x4A & 0xff)); /* CENT SIGN */ case 0x002E: return((CHAR)(0x4B & 0xff)); /* FULL STOP */ case 0x003C: return((CHAR)(0x4C & 0xff)); /* LESS-THAN SIGN */ case 0x0028: return((CHAR)(0x4D & 0xff)); /* LEFT PARENTHESIS */ case 0x002B: return((CHAR)(0x4E & 0xff)); /* PLUS SIGN */ case 0x007C: return((CHAR)(0x4F & 0xff)); /* VERTICAL LINE */ case 0x0026: return((CHAR)(0x50 & 0xff)); /* AMPERSAND */ case 0x00E9: return((CHAR)(0x51 & 0xff)); /* SMALL LETTER E WITH ACUTE */ case 0x00EA: return((CHAR)(0x52 & 0xff)); /* SMALL LETTER E WITH CIRCUMFLEX */ case 0x00EB: return((CHAR)(0x53 & 0xff)); /* SMALL LETTER E WITH DIAERESIS */ case 0x00E8: return((CHAR)(0x54 & 0xff)); /* LATIN SMALL LETTER E WITH GRAVE */ case 0x00ED: return((CHAR)(0x55 & 0xff)); /* LATIN SMALL LETTER I WITH ACUTE */ case 0x00EE: return((CHAR)(0x56 & 0xff)); /* SMALL LETTER I WITH CIRCUMFLEX */ case 0x00EF: return((CHAR)(0x57 & 0xff)); /* SMALL LETTER I WITH DIAERESIS */ case 0x00EC: return((CHAR)(0x58 & 0xff)); /* LATIN SMALL LETTER I WITH GRAVE */ case 0x00DF: return((CHAR)(0x59 & 0xff)); /* SMALL LETTER SHARP S (GERMAN) */ case 0x0021: return((CHAR)(0x5A & 0xff)); /* EXCLAMATION MARK */ case 0x0024: return((CHAR)(0x5B & 0xff)); /* DOLLAR SIGN */ case 0x002A: return((CHAR)(0x5C & 0xff)); /* ASTERISK */ case 0x0029: return((CHAR)(0x5D & 0xff)); /* RIGHT PARENTHESIS */ case 0x003B: return((CHAR)(0x5E & 0xff)); /* SEMICOLON */ case 0x00AC: return((CHAR)(0x5F & 0xff)); /* NOT SIGN */ case 0x002D: return((CHAR)(0x60 & 0xff)); /* HYPHEN-MINUS */ case 0x002F: return((CHAR)(0x61 & 0xff)); /* SOLIDUS */ case 0x00C2: return((CHAR)(0x62 & 0xff)); /* CAPITAL LETTER A WITH CIRCUMFLEX */ case 0x00C4: return((CHAR)(0x63 & 0xff)); /* CAPITAL LETTER A WITH DIAERESIS */ case 0x00C0: return((CHAR)(0x64 & 0xff)); /* LATIN CAPITAL LETTER A WITH GRAVE */ case 0x00C1: return((CHAR)(0x65 & 0xff)); /* LATIN CAPITAL LETTER A WITH ACUTE */ case 0x00C3: return((CHAR)(0x66 & 0xff)); /* LATIN CAPITAL LETTER A WITH TILDE */ case 0x00C5: return((CHAR)(0x67 & 0xff)); /* CAPITAL LETTER A WITH RING ABOVE */ case 0x00C7: return((CHAR)(0x68 & 0xff)); /* CAPITAL LETTER C WITH CEDILLA */ case 0x00D1: return((CHAR)(0x69 & 0xff)); /* LATIN CAPITAL LETTER N WITH TILDE */ case 0x00A6: return((CHAR)(0x6A & 0xff)); /* BROKEN BAR */ case 0x002C: return((CHAR)(0x6B & 0xff)); /* COMMA */ case 0x0025: return((CHAR)(0x6C & 0xff)); /* PERCENT SIGN */ case 0x005F: return((CHAR)(0x6D & 0xff)); /* LOW LINE */ case 0x003E: return((CHAR)(0x6E & 0xff)); /* GREATER-THAN SIGN */ case 0x003F: return((CHAR)(0x6F & 0xff)); /* QUESTION MARK */ case 0x00F8: return((CHAR)(0x70 & 0xff)); /* LATIN SMALL LETTER O WITH STROKE */ case 0x00C9: return((CHAR)(0x71 & 0xff)); /* LATIN CAPITAL LETTER E WITH ACUTE */ case 0x00CA: /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ return((CHAR)(0x72 & 0xff)); case 0x00CB: /* LATIN CAPITAL LETTER E WITH DIAERESIS */ return((CHAR)(0x73 & 0xff)); case 0x00C8: return((CHAR)(0x74 & 0xff)); /* LATIN CAPITAL LETTER E WITH GRAVE */ case 0x00CD: return((CHAR)(0x75 & 0xff)); /* LATIN CAPITAL LETTER I WITH ACUTE */ case 0x00CE: /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ return((CHAR)(0x76 & 0xff)); case 0x00CF: /* LATIN CAPITAL LETTER I WITH DIAERESIS */ return((CHAR)(0x77 & 0xff)); case 0x00CC: return((CHAR)(0x78 & 0xff)); /* LATIN CAPITAL LETTER I WITH GRAVE */ case 0x0060: return((CHAR)(0x79 & 0xff)); /* GRAVE ACCENT */ case 0x003A: return((CHAR)(0x7A & 0xff)); /* COLON */ case 0x0023: return((CHAR)(0x7B & 0xff)); /* NUMBER SIGN */ case 0x0040: return((CHAR)(0x7C & 0xff)); /* COMMERCIAL AT */ case 0x0027: return((CHAR)(0x7D & 0xff)); /* APOSTROPHE */ case 0x003D: return((CHAR)(0x7E & 0xff)); /* EQUALS SIGN */ case 0x0022: return((CHAR)(0x7F & 0xff)); /* QUOTATION MARK */ case 0x00D8: /* LATIN CAPITAL LETTER O WITH STROKE */ return((CHAR)(0x80 & 0xff)); case 0x0061: return((CHAR)(0x81 & 0xff)); /* LATIN SMALL LETTER A */ case 0x0062: return((CHAR)(0x82 & 0xff)); /* LATIN SMALL LETTER B */ case 0x0063: return((CHAR)(0x83 & 0xff)); /* LATIN SMALL LETTER C */ case 0x0064: return((CHAR)(0x84 & 0xff)); /* LATIN SMALL LETTER D */ case 0x0065: return((CHAR)(0x85 & 0xff)); /* LATIN SMALL LETTER E */ case 0x0066: return((CHAR)(0x86 & 0xff)); /* LATIN SMALL LETTER F */ case 0x0067: return((CHAR)(0x87 & 0xff)); /* LATIN SMALL LETTER G */ case 0x0068: return((CHAR)(0x88 & 0xff)); /* LATIN SMALL LETTER H */ case 0x0069: return((CHAR)(0x89 & 0xff)); /* LATIN SMALL LETTER I */ case 0x00AB: /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */ return((CHAR)(0x8A & 0xff)); case 0x00BB: /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MAR K*/ return((CHAR)(0x8B & 0xff)); case 0x00F0: /* LATIN SMALL LETTER ETH (ICELANDIC) */ return((CHAR)(0x8C & 0xff)); case 0x00FD: return((CHAR)(0x8D & 0xff)); /* LATIN SMALL LETTER Y WITH ACUTE */ case 0x00FE: /* LATIN SMALL LETTER THORN (ICELANDIC) */ return((CHAR)(0x8E & 0xff)); case 0x00B1: return((CHAR)(0x8F & 0xff)); /* PLUS-MINUS SIGN */ case 0x00B0: return((CHAR)(0x90 & 0xff)); /* DEGREE SIGN */ case 0x006A: return((CHAR)(0x91 & 0xff)); /* LATIN SMALL LETTER J */ case 0x006B: return((CHAR)(0x92 & 0xff)); /* LATIN SMALL LETTER K */ case 0x006C: return((CHAR)(0x93 & 0xff)); /* LATIN SMALL LETTER L */ case 0x006D: return((CHAR)(0x94 & 0xff)); /* LATIN SMALL LETTER M */ case 0x006E: return((CHAR)(0x95 & 0xff)); /* LATIN SMALL LETTER N */ case 0x006F: return((CHAR)(0x96 & 0xff)); /* LATIN SMALL LETTER O */ case 0x0070: return((CHAR)(0x97 & 0xff)); /* LATIN SMALL LETTER P */ case 0x0071: return((CHAR)(0x98 & 0xff)); /* LATIN SMALL LETTER Q */ case 0x0072: return((CHAR)(0x99 & 0xff)); /* LATIN SMALL LETTER R */ case 0x00AA: return((CHAR)(0x9A & 0xff)); /* FEMININE ORDINAL INDICATOR */ case 0x00BA: return((CHAR)(0x9B & 0xff)); /* MASCULINE ORDINAL INDICATOR */ case 0x00E6: return((CHAR)(0x9C & 0xff)); /* LATIN SMALL LIGATURE AE */ case 0x00B8: return((CHAR)(0x9D & 0xff)); /* CEDILLA */ case 0x00C6: return((CHAR)(0x9E & 0xff)); /* LATIN CAPITAL LIGATURE AE */ case 0x00A4: return((CHAR)(0x9F & 0xff)); /* CURRENCY SIGN */ case 0x00B5: return((CHAR)(0xA0 & 0xff)); /* MICRO SIGN */ case 0x007E: return((CHAR)(0xA1 & 0xff)); /* TILDE */ case 0x0073: return((CHAR)(0xA2 & 0xff)); /* LATIN SMALL LETTER S */ case 0x0074: return((CHAR)(0xA3 & 0xff)); /* LATIN SMALL LETTER T */ case 0x0075: return((CHAR)(0xA4 & 0xff)); /* LATIN SMALL LETTER U */ case 0x0076: return((CHAR)(0xA5 & 0xff)); /* LATIN SMALL LETTER V */ case 0x0077: return((CHAR)(0xA6 & 0xff)); /* LATIN SMALL LETTER W */ case 0x0078: return((CHAR)(0xA7 & 0xff)); /* LATIN SMALL LETTER X */ case 0x0079: return((CHAR)(0xA8 & 0xff)); /* LATIN SMALL LETTER Y */ case 0x007A: return((CHAR)(0xA9 & 0xff)); /* LATIN SMALL LETTER Z */ case 0x00A1: return((CHAR)(0xAA & 0xff)); /* INVERTED EXCLAMATION MARK */ case 0x00BF: return((CHAR)(0xAB & 0xff)); /* INVERTED QUESTION MARK */ case 0x00D0: /* LATIN CAPITAL LETTER ETH (ICELANDIC) */ return((CHAR)(0xAC & 0xff)); case 0x00DD: return((CHAR)(0xAD & 0xff)); /* LATIN CAPITAL LETTER Y WITH ACUTE */ case 0x00DE: /* LATIN CAPITAL LETTER THORN (ICELANDIC) */ return((CHAR)(0xAE & 0xff)); case 0x00AE: return((CHAR)(0xAF & 0xff)); /* REGISTERED SIGN */ case 0x005E: return((CHAR)(0xB0 & 0xff)); /* CIRCUMFLEX ACCENT */ case 0x00A3: return((CHAR)(0xB1 & 0xff)); /* POUND SIGN */ case 0x00A5: return((CHAR)(0xB2 & 0xff)); /* YEN SIGN */ case 0x00B7: return((CHAR)(0xB3 & 0xff)); /* MIDDLE DOT */ case 0x00A9: return((CHAR)(0xB4 & 0xff)); /* COPYRIGHT SIGN */ case 0x00A7: return((CHAR)(0xB5 & 0xff)); /* SECTION SIGN */ case 0x00B6: return((CHAR)(0xB6 & 0xff)); /* PILCROW SIGN */ case 0x00BC: return((CHAR)(0xB7 & 0xff)); /* VULGAR FRACTION ONE QUARTER */ case 0x00BD: return((CHAR)(0xB8 & 0xff)); /* VULGAR FRACTION ONE HALF */ case 0x00BE: return((CHAR)(0xB9 & 0xff)); /* VULGAR FRACTION THREE QUARTERS */ case 0x005B: return((CHAR)(0xBA & 0xff)); /* LEFT SQUARE BRACKET */ case 0x005D: return((CHAR)(0xBB & 0xff)); /* RIGHT SQUARE BRACKET */ case 0x00AF: return((CHAR)(0xBC & 0xff)); /* MACRON */ case 0x00A8: return((CHAR)(0xBD & 0xff)); /* DIAERESIS */ case 0x00B4: return((CHAR)(0xBE & 0xff)); /* ACUTE ACCENT */ case 0x00D7: return((CHAR)(0xBF & 0xff)); /* MULTIPLICATION SIGN */ case 0x007B: return((CHAR)(0xC0 & 0xff)); /* LEFT CURLY BRACKET */ case 0x0041: return((CHAR)(0xC1 & 0xff)); /* LATIN CAPITAL LETTER A */ case 0x0042: return((CHAR)(0xC2 & 0xff)); /* LATIN CAPITAL LETTER B */ case 0x0043: return((CHAR)(0xC3 & 0xff)); /* LATIN CAPITAL LETTER C */ case 0x0044: return((CHAR)(0xC4 & 0xff)); /* LATIN CAPITAL LETTER D */ case 0x0045: return((CHAR)(0xC5 & 0xff)); /* LATIN CAPITAL LETTER E */ case 0x0046: return((CHAR)(0xC6 & 0xff)); /* LATIN CAPITAL LETTER F */ case 0x0047: return((CHAR)(0xC7 & 0xff)); /* LATIN CAPITAL LETTER G */ case 0x0048: return((CHAR)(0xC8 & 0xff)); /* LATIN CAPITAL LETTER H */ case 0x0049: return((CHAR)(0xC9 & 0xff)); /* LATIN CAPITAL LETTER I */ case 0x00AD: return((CHAR)(0xCA & 0xff)); /* SOFT HYPHEN */ case 0x00F4: return((CHAR)(0xCB & 0xff)); /* SMALL LETTER O WITH CIRCUMFLEX */ case 0x00F6: return((CHAR)(0xCC & 0xff)); /* SMALL LETTER O WITH DIAERESIS */ case 0x00F2: return((CHAR)(0xCD & 0xff)); /* LATIN SMALL LETTER O WITH GRAVE */ case 0x00F3: return((CHAR)(0xCE & 0xff)); /* LATIN SMALL LETTER O WITH ACUTE */ case 0x00F5: return((CHAR)(0xCF & 0xff)); /* LATIN SMALL LETTER O WITH TILDE */ case 0x007D: return((CHAR)(0xD0 & 0xff)); /* RIGHT CURLY BRACKET */ case 0x004A: return((CHAR)(0xD1 & 0xff)); /* LATIN CAPITAL LETTER J */ case 0x004B: return((CHAR)(0xD2 & 0xff)); /* LATIN CAPITAL LETTER K */ case 0x004C: return((CHAR)(0xD3 & 0xff)); /* LATIN CAPITAL LETTER L */ case 0x004D: return((CHAR)(0xD4 & 0xff)); /* LATIN CAPITAL LETTER M */ case 0x004E: return((CHAR)(0xD5 & 0xff)); /* LATIN CAPITAL LETTER N */ case 0x004F: return((CHAR)(0xD6 & 0xff)); /* LATIN CAPITAL LETTER O */ case 0x0050: return((CHAR)(0xD7 & 0xff)); /* LATIN CAPITAL LETTER P */ case 0x0051: return((CHAR)(0xD8 & 0xff)); /* LATIN CAPITAL LETTER Q */ case 0x0052: return((CHAR)(0xD9 & 0xff)); /* LATIN CAPITAL LETTER R */ case 0x00B9: return((CHAR)(0xDA & 0xff)); /* SUPERSCRIPT ONE */ case 0x00FB: return((CHAR)(0xDB & 0xff)); /* SMALL LETTER U WITH CIRCUMFLEX */ case 0x00FC: return((CHAR)(0xDC & 0xff)); /* SMALL LETTER U WITH DIAERESIS */ case 0x00F9: return((CHAR)(0xDD & 0xff)); /* SMALL LETTER U WITH GRAVE */ case 0x00FA: return((CHAR)(0xDE & 0xff)); /* SMALL LETTER U WITH ACUTE */ case 0x00FF: return((CHAR)(0xDF & 0xff)); /* SMALL LETTER Y WITH DIAERESIS */ case 0x005C: return((CHAR)(0xE0 & 0xff)); /* REVERSE SOLIDUS */ case 0x00F7: return((CHAR)(0xE1 & 0xff)); /* DIVISION SIGN */ case 0x0053: return((CHAR)(0xE2 & 0xff)); /* LATIN CAPITAL LETTER S */ case 0x0054: return((CHAR)(0xE3 & 0xff)); /* LATIN CAPITAL LETTER T */ case 0x0055: return((CHAR)(0xE4 & 0xff)); /* LATIN CAPITAL LETTER U */ case 0x0056: return((CHAR)(0xE5 & 0xff)); /* LATIN CAPITAL LETTER V */ case 0x0057: return((CHAR)(0xE6 & 0xff)); /* LATIN CAPITAL LETTER W */ case 0x0058: return((CHAR)(0xE7 & 0xff)); /* LATIN CAPITAL LETTER X */ case 0x0059: return((CHAR)(0xE8 & 0xff)); /* LATIN CAPITAL LETTER Y */ case 0x005A: return((CHAR)(0xE9 & 0xff)); /* LATIN CAPITAL LETTER Z */ case 0x00B2: return((CHAR)(0xEA & 0xff)); /* SUPERSCRIPT TWO */ case 0x00D4: return((CHAR)(0xEB & 0xff)); /* CAPITAL LETTER O WITH CIRCUMFLEX */ case 0x00D6: return((CHAR)(0xEC & 0xff)); /* CAPITAL LETTER O WITH DIAERESIS */ case 0x00D2: return((CHAR)(0xED & 0xff)); /* CAPITAL LETTER O WITH GRAVE */ case 0x00D3: return((CHAR)(0xEE & 0xff)); /* CAPITAL LETTER O WITH ACUTE */ case 0x00D5: return((CHAR)(0xEF & 0xff)); /* CAPITAL LETTER O WITH TILDE */ case 0x0030: return((CHAR)(0xF0 & 0xff)); /* DIGIT ZERO */ case 0x0031: return((CHAR)(0xF1 & 0xff)); /* DIGIT ONE */ case 0x0032: return((CHAR)(0xF2 & 0xff)); /* DIGIT TWO */ case 0x0033: return((CHAR)(0xF3 & 0xff)); /* DIGIT THREE */ case 0x0034: return((CHAR)(0xF4 & 0xff)); /* DIGIT FOUR */ case 0x0035: return((CHAR)(0xF5 & 0xff)); /* DIGIT FIVE */ case 0x0036: return((CHAR)(0xF6 & 0xff)); /* DIGIT SIX */ case 0x0037: return((CHAR)(0xF7 & 0xff)); /* DIGIT SEVEN */ case 0x0038: return((CHAR)(0xF8 & 0xff)); /* DIGIT EIGHT */ case 0x0039: return((CHAR)(0xF9 & 0xff)); /* DIGIT NINE */ case 0x00B3: return((CHAR)(0xFA & 0xff)); /* SUPERSCRIPT THREE */ case 0x00DB: return((CHAR)(0xFB & 0xff)); /* CAPITAL LETTER U WITH CIRCUMFLEX */ case 0x00DC: return((CHAR)(0xFC & 0xff)); /* CAPITAL LETTER U WITH DIAERESIS */ case 0x00D9: return((CHAR)(0xFD & 0xff)); /* LATIN CAPITAL LETTER U WITH GRAVE */ case 0x00DA: return((CHAR)(0xFE & 0xff)); /* LATIN CAPITAL LETTER U WITH ACUTE */ case 0x009F: return((CHAR)(0xFF & 0xff)); /* CONTROL */ default: return(0x003f); } } int /* PC Code Page 855 */ #ifdef CK_ANSIC tx_cp855(USHORT c) #else tx_cp855(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00a4: return((CHAR)(207 & 0xff)); case 0x00a7: return((CHAR)(253 & 0xff)); case 0x00ab: return((CHAR)(174 & 0xff)); case 0x00bb: return((CHAR)(175 & 0xff)); case 0x0401: return((CHAR)(133 & 0xff)); case 0x0402: return((CHAR)(129 & 0xff)); case 0x0403: return((CHAR)(131 & 0xff)); case 0x0404: return((CHAR)(135 & 0xff)); case 0x0405: return((CHAR)(137 & 0xff)); case 0x0406: return((CHAR)(139 & 0xff)); case 0x0407: return((CHAR)(141 & 0xff)); case 0x0408: return((CHAR)(143 & 0xff)); case 0x0409: return((CHAR)(145 & 0xff)); case 0x040a: return((CHAR)(147 & 0xff)); case 0x040b: return((CHAR)(149 & 0xff)); case 0x040c: return((CHAR)(151 & 0xff)); case 0x040e: return((CHAR)(153 & 0xff)); case 0x040f: return((CHAR)(155 & 0xff)); case 0x0410: return((CHAR)(161 & 0xff)); case 0x0411: return((CHAR)(163 & 0xff)); case 0x0412: return((CHAR)(236 & 0xff)); case 0x0413: return((CHAR)(173 & 0xff)); case 0x0414: return((CHAR)(167 & 0xff)); case 0x0415: return((CHAR)(169 & 0xff)); case 0x0416: return((CHAR)(234 & 0xff)); case 0x0417: return((CHAR)(244 & 0xff)); case 0x0418: return((CHAR)(184 & 0xff)); case 0x0419: return((CHAR)(190 & 0xff)); case 0x041a: return((CHAR)(199 & 0xff)); case 0x041b: return((CHAR)(209 & 0xff)); case 0x041c: return((CHAR)(211 & 0xff)); case 0x041d: return((CHAR)(213 & 0xff)); case 0x041e: return((CHAR)(215 & 0xff)); case 0x041f: return((CHAR)(221 & 0xff)); case 0x0420: return((CHAR)(226 & 0xff)); case 0x0421: return((CHAR)(228 & 0xff)); case 0x0422: return((CHAR)(230 & 0xff)); case 0x0423: return((CHAR)(232 & 0xff)); case 0x0424: return((CHAR)(171 & 0xff)); case 0x0425: return((CHAR)(182 & 0xff)); case 0x0426: return((CHAR)(165 & 0xff)); case 0x0427: return((CHAR)(252 & 0xff)); case 0x0428: return((CHAR)(246 & 0xff)); case 0x0429: return((CHAR)(250 & 0xff)); case 0x042a: return((CHAR)(159 & 0xff)); case 0x042b: return((CHAR)(242 & 0xff)); case 0x042c: return((CHAR)(238 & 0xff)); case 0x042d: return((CHAR)(248 & 0xff)); case 0x042e: return((CHAR)(157 & 0xff)); case 0x042f: return((CHAR)(224 & 0xff)); case 0x0430: return((CHAR)(160 & 0xff)); case 0x0431: return((CHAR)(162 & 0xff)); case 0x0432: return((CHAR)(235 & 0xff)); case 0x0433: return((CHAR)(172 & 0xff)); case 0x0434: return((CHAR)(166 & 0xff)); case 0x0435: return((CHAR)(168 & 0xff)); case 0x0436: return((CHAR)(233 & 0xff)); case 0x0437: return((CHAR)(243 & 0xff)); case 0x0438: return((CHAR)(183 & 0xff)); case 0x0439: return((CHAR)(189 & 0xff)); case 0x043a: return((CHAR)(198 & 0xff)); case 0x043b: return((CHAR)(208 & 0xff)); case 0x043c: return((CHAR)(210 & 0xff)); case 0x043d: return((CHAR)(212 & 0xff)); case 0x043e: return((CHAR)(214 & 0xff)); case 0x043f: return((CHAR)(216 & 0xff)); case 0x0440: return((CHAR)(225 & 0xff)); case 0x0441: return((CHAR)(227 & 0xff)); case 0x0442: return((CHAR)(229 & 0xff)); case 0x0443: return((CHAR)(231 & 0xff)); case 0x0444: return((CHAR)(170 & 0xff)); case 0x0445: return((CHAR)(181 & 0xff)); case 0x0446: return((CHAR)(164 & 0xff)); case 0x0447: return((CHAR)(251 & 0xff)); case 0x0448: return((CHAR)(245 & 0xff)); case 0x0449: return((CHAR)(249 & 0xff)); case 0x044a: return((CHAR)(158 & 0xff)); case 0x044b: return((CHAR)(241 & 0xff)); case 0x044c: return((CHAR)(237 & 0xff)); case 0x044d: return((CHAR)(247 & 0xff)); case 0x044e: return((CHAR)(156 & 0xff)); case 0x044f: return((CHAR)(222 & 0xff)); case 0x0451: return((CHAR)(132 & 0xff)); case 0x0452: return((CHAR)(128 & 0xff)); case 0x0453: return((CHAR)(130 & 0xff)); case 0x0454: return((CHAR)(134 & 0xff)); case 0x0455: return((CHAR)(136 & 0xff)); case 0x0456: return((CHAR)(138 & 0xff)); case 0x0457: return((CHAR)(140 & 0xff)); case 0x0458: return((CHAR)(142 & 0xff)); case 0x0459: return((CHAR)(144 & 0xff)); case 0x045a: return((CHAR)(146 & 0xff)); case 0x045b: return((CHAR)(148 & 0xff)); case 0x045c: return((CHAR)(150 & 0xff)); case 0x045e: return((CHAR)(152 & 0xff)); case 0x045f: return((CHAR)(154 & 0xff)); case 0x2116: return((CHAR)(239 & 0xff)); case 0x2500: return((CHAR)(196 & 0xff)); case 0x2502: return((CHAR)(179 & 0xff)); case 0x250c: return((CHAR)(218 & 0xff)); case 0x2510: return((CHAR)(191 & 0xff)); case 0x2514: return((CHAR)(192 & 0xff)); case 0x2518: return((CHAR)(217 & 0xff)); case 0x251c: return((CHAR)(195 & 0xff)); case 0x2524: return((CHAR)(180 & 0xff)); case 0x252c: return((CHAR)(194 & 0xff)); case 0x2534: return((CHAR)(193 & 0xff)); case 0x253c: return((CHAR)(197 & 0xff)); case 0x2550: return((CHAR)(205 & 0xff)); case 0x2551: return((CHAR)(186 & 0xff)); case 0x2554: return((CHAR)(201 & 0xff)); case 0x2557: return((CHAR)(187 & 0xff)); case 0x255a: return((CHAR)(200 & 0xff)); case 0x255d: return((CHAR)(188 & 0xff)); case 0x2560: return((CHAR)(204 & 0xff)); case 0x2563: return((CHAR)(185 & 0xff)); case 0x2566: return((CHAR)(203 & 0xff)); case 0x2569: return((CHAR)(202 & 0xff)); case 0x256c: return((CHAR)(206 & 0xff)); case 0x2580: return((CHAR)(223 & 0xff)); case 0x2584: return((CHAR)(220 & 0xff)); case 0x2588: return((CHAR)(219 & 0xff)); case 0x2591: return((CHAR)(176 & 0xff)); case 0x2592: return((CHAR)(177 & 0xff)); case 0x2593: return((CHAR)(178 & 0xff)); case 0x25a0: return((CHAR)(254 & 0xff)); default: return(tx_cpsub(c)); /* For box characters etc */ } } int /* PC Code Page 856 */ #ifdef CK_ANSIC tx_cp856(USHORT c) #else tx_cp856(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00a0: return((CHAR)(0xff & 0xff)); case 0x00a7: return((CHAR)(0xd6 & 0xff)); case 0x00b0: return((CHAR)(0xf8 & 0xff)); case 0x00b1: return((CHAR)(0xf1 & 0xff)); case 0x00b2: return((CHAR)(0xfd & 0xff)); case 0x00b5: return((CHAR)(0xe6 & 0xff)); case 0x00b7: return((CHAR)(0xfa & 0xff)); case 0x00df: return((CHAR)(0xe1 & 0xff)); case 0x00f7: return((CHAR)(0xf6 & 0xff)); case 0x0393: return((CHAR)(0xe2 & 0xff)); case 0x0398: return((CHAR)(0xe9 & 0xff)); case 0x03a3: return((CHAR)(0xe4 & 0xff)); case 0x03a6: return((CHAR)(0xe8 & 0xff)); case 0x03a9: return((CHAR)(0xea & 0xff)); case 0x03b1: return((CHAR)(0xe0 & 0xff)); case 0x03b4: return((CHAR)(0xeb & 0xff)); case 0x03b5: return((CHAR)(0xee & 0xff)); case 0x03c0: return((CHAR)(0xe3 & 0xff)); case 0x03c3: return((CHAR)(0xe5 & 0xff)); case 0x03c4: return((CHAR)(0xe7 & 0xff)); case 0x03c6: return((CHAR)(0xed & 0xff)); case 0x0410: return((CHAR)(0x80 & 0xff)); case 0x0411: return((CHAR)(0x81 & 0xff)); case 0x0412: return((CHAR)(0x82 & 0xff)); case 0x0413: return((CHAR)(0x83 & 0xff)); case 0x0414: return((CHAR)(0x84 & 0xff)); case 0x0415: return((CHAR)(0x85 & 0xff)); case 0x0416: return((CHAR)(0x86 & 0xff)); case 0x0417: return((CHAR)(0x87 & 0xff)); case 0x0418: return((CHAR)(0x88 & 0xff)); case 0x0419: return((CHAR)(0x89 & 0xff)); case 0x041a: return((CHAR)(0x8a & 0xff)); case 0x041b: return((CHAR)(0x8b & 0xff)); case 0x041c: return((CHAR)(0x8c & 0xff)); case 0x041d: return((CHAR)(0x8d & 0xff)); case 0x041e: return((CHAR)(0x8e & 0xff)); case 0x041f: return((CHAR)(0x8f & 0xff)); case 0x0420: return((CHAR)(0x90 & 0xff)); case 0x0421: return((CHAR)(0x91 & 0xff)); case 0x0422: return((CHAR)(0x92 & 0xff)); case 0x0423: return((CHAR)(0x93 & 0xff)); case 0x0424: return((CHAR)(0x94 & 0xff)); case 0x0425: return((CHAR)(0x95 & 0xff)); case 0x0426: return((CHAR)(0x96 & 0xff)); case 0x0427: return((CHAR)(0x97 & 0xff)); case 0x0428: return((CHAR)(0x98 & 0xff)); case 0x0429: return((CHAR)(0x99 & 0xff)); case 0x042a: return((CHAR)(0x9a & 0xff)); case 0x042b: return((CHAR)(0x9b & 0xff)); case 0x042c: return((CHAR)(0x9c & 0xff)); case 0x042d: return((CHAR)(0x9d & 0xff)); case 0x042e: return((CHAR)(0x9e & 0xff)); case 0x042f: return((CHAR)(0x9f & 0xff)); case 0x0430: return((CHAR)(0xa0 & 0xff)); case 0x0431: return((CHAR)(0xa1 & 0xff)); case 0x0432: return((CHAR)(0xa2 & 0xff)); case 0x0433: return((CHAR)(0xa3 & 0xff)); case 0x0434: return((CHAR)(0xa4 & 0xff)); case 0x0435: return((CHAR)(0xa5 & 0xff)); case 0x0436: return((CHAR)(0xa6 & 0xff)); case 0x0437: return((CHAR)(0xa7 & 0xff)); case 0x0438: return((CHAR)(0xa8 & 0xff)); case 0x0439: return((CHAR)(0xa9 & 0xff)); case 0x043a: return((CHAR)(0xaa & 0xff)); case 0x043b: return((CHAR)(0xab & 0xff)); case 0x043c: return((CHAR)(0xac & 0xff)); case 0x043d: return((CHAR)(0xad & 0xff)); case 0x043e: return((CHAR)(0xae & 0xff)); case 0x043f: return((CHAR)(0xaf & 0xff)); case 0x0440: return((CHAR)(0xb0 & 0xff)); case 0x0441: return((CHAR)(0xb1 & 0xff)); case 0x0442: return((CHAR)(0xb2 & 0xff)); case 0x0443: return((CHAR)(0xb3 & 0xff)); case 0x0444: return((CHAR)(0xb4 & 0xff)); case 0x0445: return((CHAR)(0xb5 & 0xff)); case 0x0446: return((CHAR)(0xb6 & 0xff)); case 0x0447: return((CHAR)(0xb7 & 0xff)); case 0x0448: return((CHAR)(0xb8 & 0xff)); case 0x0449: return((CHAR)(0xb9 & 0xff)); case 0x044a: return((CHAR)(0xba & 0xff)); case 0x044b: return((CHAR)(0xbb & 0xff)); case 0x044c: return((CHAR)(0xbc & 0xff)); case 0x044d: return((CHAR)(0xbd & 0xff)); case 0x044e: return((CHAR)(0xbe & 0xff)); case 0x044f: return((CHAR)(0xbf & 0xff)); case 0x207f: return((CHAR)(0xfc & 0xff)); case 0x2116: return((CHAR)(0xd5 & 0xff)); case 0x2219: return((CHAR)(0xf9 & 0xff)); case 0x221a: return((CHAR)(0xfb & 0xff)); case 0x221e: return((CHAR)(0xec & 0xff)); case 0x2229: return((CHAR)(0xef & 0xff)); case 0x2248: return((CHAR)(0xf7 & 0xff)); case 0x2261: return((CHAR)(0xf0 & 0xff)); case 0x2264: return((CHAR)(0xf3 & 0xff)); case 0x2265: return((CHAR)(0xf2 & 0xff)); case 0x2320: return((CHAR)(0xf4 & 0xff)); case 0x2321: return((CHAR)(0xf5 & 0xff)); case 0x2500: return((CHAR)(0xc4 & 0xff)); case 0x2502: return((CHAR)(0xd3 & 0xff)); case 0x250c: return((CHAR)(0xda & 0xff)); case 0x2510: return((CHAR)(0xcf & 0xff)); case 0x2514: return((CHAR)(0xc0 & 0xff)); case 0x2518: return((CHAR)(0xd9 & 0xff)); case 0x251c: return((CHAR)(0xc3 & 0xff)); case 0x2524: return((CHAR)(0xd4 & 0xff)); case 0x252c: return((CHAR)(0xc2 & 0xff)); case 0x2534: return((CHAR)(0xc1 & 0xff)); case 0x253c: return((CHAR)(0xc5 & 0xff)); case 0x2550: return((CHAR)(0xcd & 0xff)); case 0x2551: return((CHAR)(0xc7 & 0xff)); case 0x2554: return((CHAR)(0xc9 & 0xff)); case 0x2557: return((CHAR)(0xd7 & 0xff)); case 0x255a: return((CHAR)(0xc8 & 0xff)); case 0x255d: return((CHAR)(0xd8 & 0xff)); case 0x2560: return((CHAR)(0xcc & 0xff)); case 0x2563: return((CHAR)(0xc6 & 0xff)); case 0x2566: return((CHAR)(0xcb & 0xff)); case 0x2569: return((CHAR)(0xca & 0xff)); case 0x256c: return((CHAR)(0xce & 0xff)); case 0x2580: return((CHAR)(0xdf & 0xff)); case 0x2584: return((CHAR)(0xdc & 0xff)); case 0x2588: return((CHAR)(0xdb & 0xff)); case 0x258c: return((CHAR)(0xdd & 0xff)); case 0x2590: return((CHAR)(0xde & 0xff)); case 0x2591: return((CHAR)(0xd0 & 0xff)); case 0x2592: return((CHAR)(0xd1 & 0xff)); case 0x2593: return((CHAR)(0xd2 & 0xff)); case 0x25a0: return((CHAR)(0xfe & 0xff)); default: return(tx_cpsub(c)); /* For box characters etc */ } } int /* PC Code Page 857 */ #ifdef CK_ANSIC tx_cp857(USHORT c) #else tx_cp857(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00c7: return((CHAR)(128 & 0xff)); case 0x00fc: return((CHAR)(129 & 0xff)); case 0x00e9: return((CHAR)(130 & 0xff)); case 0x00e2: return((CHAR)(131 & 0xff)); case 0x00e4: return((CHAR)(132 & 0xff)); case 0x00e0: return((CHAR)(133 & 0xff)); case 0x00e5: return((CHAR)(134 & 0xff)); case 0x00e7: return((CHAR)(135 & 0xff)); case 0x00ea: return((CHAR)(136 & 0xff)); case 0x00eb: return((CHAR)(137 & 0xff)); case 0x00e8: return((CHAR)(138 & 0xff)); case 0x00ef: return((CHAR)(139 & 0xff)); case 0x00ee: return((CHAR)(140 & 0xff)); case 0x0131: return((CHAR)(141 & 0xff)); case 0x00c4: return((CHAR)(142 & 0xff)); case 0x00c5: return((CHAR)(143 & 0xff)); case 0x00c9: return((CHAR)(144 & 0xff)); case 0x00e6: return((CHAR)(145 & 0xff)); case 0x00c6: return((CHAR)(146 & 0xff)); case 0x00f4: return((CHAR)(147 & 0xff)); case 0x00f6: return((CHAR)(148 & 0xff)); case 0x00f2: return((CHAR)(149 & 0xff)); case 0x00fb: return((CHAR)(150 & 0xff)); case 0x00f9: return((CHAR)(151 & 0xff)); case 0x0130: return((CHAR)(152 & 0xff)); case 0x00d6: return((CHAR)(153 & 0xff)); case 0x00dc: return((CHAR)(154 & 0xff)); case 0x00f8: return((CHAR)(155 & 0xff)); case 0x00a3: return((CHAR)(156 & 0xff)); case 0x00d8: return((CHAR)(157 & 0xff)); case 0x015e: return((CHAR)(158 & 0xff)); case 0x015f: return((CHAR)(159 & 0xff)); case 0x00e1: return((CHAR)(160 & 0xff)); case 0x00ed: return((CHAR)(161 & 0xff)); case 0x00f3: return((CHAR)(162 & 0xff)); case 0x00fa: return((CHAR)(163 & 0xff)); case 0x00f1: return((CHAR)(164 & 0xff)); case 0x00d1: return((CHAR)(165 & 0xff)); case 0x011e: return((CHAR)(166 & 0xff)); case 0x011f: return((CHAR)(167 & 0xff)); case 0x00bf: return((CHAR)(168 & 0xff)); case 0x00ae: return((CHAR)(169 & 0xff)); case 0x00ac: return((CHAR)(170 & 0xff)); case 0x00bd: return((CHAR)(171 & 0xff)); case 0x00bc: return((CHAR)(172 & 0xff)); case 0x00a1: return((CHAR)(173 & 0xff)); case 0x00ab: return((CHAR)(174 & 0xff)); case 0x00bb: return((CHAR)(175 & 0xff)); case 0x20ac: return((CHAR)(213 & 0xff)); /* Euro */ case 0x2591: return((CHAR)(176 & 0xff)); case 0x2592: return((CHAR)(177 & 0xff)); case 0x2593: return((CHAR)(178 & 0xff)); case 0x2502: return((CHAR)(179 & 0xff)); case 0x2524: return((CHAR)(180 & 0xff)); case 0x00c1: return((CHAR)(181 & 0xff)); case 0x00c2: return((CHAR)(182 & 0xff)); case 0x00c0: return((CHAR)(183 & 0xff)); case 0x00a9: return((CHAR)(184 & 0xff)); case 0x2563: return((CHAR)(185 & 0xff)); case 0x2551: return((CHAR)(186 & 0xff)); case 0x2557: return((CHAR)(187 & 0xff)); case 0x255d: return((CHAR)(188 & 0xff)); case 0x00a2: return((CHAR)(189 & 0xff)); case 0x00a5: return((CHAR)(190 & 0xff)); case 0x2510: return((CHAR)(191 & 0xff)); case 0x2514: return((CHAR)(192 & 0xff)); case 0x2534: return((CHAR)(193 & 0xff)); case 0x252c: return((CHAR)(194 & 0xff)); case 0x251c: return((CHAR)(195 & 0xff)); case 0x2500: return((CHAR)(196 & 0xff)); case 0x253c: return((CHAR)(197 & 0xff)); case 0x00e3: return((CHAR)(198 & 0xff)); case 0x00c3: return((CHAR)(199 & 0xff)); case 0x255a: return((CHAR)(200 & 0xff)); case 0x2554: return((CHAR)(201 & 0xff)); case 0x2569: return((CHAR)(202 & 0xff)); case 0x2566: return((CHAR)(203 & 0xff)); case 0x2560: return((CHAR)(204 & 0xff)); case 0x2550: return((CHAR)(205 & 0xff)); case 0x256c: return((CHAR)(206 & 0xff)); case 0x00a4: return((CHAR)(207 & 0xff)); case 0x00ba: return((CHAR)(208 & 0xff)); case 0x00aa: return((CHAR)(209 & 0xff)); case 0x00ca: return((CHAR)(210 & 0xff)); case 0x00cb: return((CHAR)(211 & 0xff)); case 0x00c8: return((CHAR)(212 & 0xff)); case 0x00cd: return((CHAR)(214 & 0xff)); case 0x00ce: return((CHAR)(215 & 0xff)); case 0x00cf: return((CHAR)(216 & 0xff)); case 0x2518: return((CHAR)(217 & 0xff)); case 0x250c: return((CHAR)(218 & 0xff)); case 0x2588: return((CHAR)(219 & 0xff)); case 0x2584: return((CHAR)(220 & 0xff)); case 0x00a6: return((CHAR)(221 & 0xff)); case 0x00cc: return((CHAR)(222 & 0xff)); case 0x2580: return((CHAR)(223 & 0xff)); case 0x00d3: return((CHAR)(224 & 0xff)); case 0x00df: return((CHAR)(225 & 0xff)); case 0x00d4: return((CHAR)(226 & 0xff)); case 0x00d2: return((CHAR)(227 & 0xff)); case 0x00f5: return((CHAR)(228 & 0xff)); case 0x00d5: return((CHAR)(229 & 0xff)); case 0x00b5: return((CHAR)(230 & 0xff)); case 0x00d7: return((CHAR)(232 & 0xff)); case 0x00da: return((CHAR)(233 & 0xff)); case 0x00db: return((CHAR)(234 & 0xff)); case 0x00d9: return((CHAR)(235 & 0xff)); case 0x00ec: return((CHAR)(236 & 0xff)); case 0x00ff: return((CHAR)(237 & 0xff)); case 0x00af: return((CHAR)(238 & 0xff)); case 0x00b4: return((CHAR)(239 & 0xff)); case 0x00ad: return((CHAR)(240 & 0xff)); case 0x00b1: return((CHAR)(241 & 0xff)); case 0x00be: return((CHAR)(243 & 0xff)); case 0x00b6: return((CHAR)(244 & 0xff)); case 0x00a7: return((CHAR)(245 & 0xff)); case 0x00f7: return((CHAR)(246 & 0xff)); case 0x00b8: return((CHAR)(247 & 0xff)); case 0x00b0: return((CHAR)(248 & 0xff)); case 0x00a8: return((CHAR)(249 & 0xff)); case 0x00b7: return((CHAR)(250 & 0xff)); case 0x00b9: return((CHAR)(251 & 0xff)); case 0x00b3: return((CHAR)(252 & 0xff)); case 0x00b2: return((CHAR)(253 & 0xff)); case 0x25a0: return((CHAR)(254 & 0xff)); case 0x00a0: return((CHAR)(255 & 0xff)); default: return(tx_cpsub(c)); /* For box characters etc */ } } int /* PC Code Page 862 */ #ifdef CK_ANSIC tx_cp862(USHORT c) #else tx_cp862(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x05d0: return((CHAR)(128 & 0xff)); case 0x05d1: return((CHAR)(129 & 0xff)); case 0x05d2: return((CHAR)(130 & 0xff)); case 0x05d3: return((CHAR)(131 & 0xff)); case 0x05d4: return((CHAR)(132 & 0xff)); case 0x05d5: return((CHAR)(133 & 0xff)); case 0x05d6: return((CHAR)(134 & 0xff)); case 0x05d7: return((CHAR)(135 & 0xff)); case 0x05d8: return((CHAR)(136 & 0xff)); case 0x05d9: return((CHAR)(137 & 0xff)); case 0x05da: return((CHAR)(138 & 0xff)); case 0x05db: return((CHAR)(139 & 0xff)); case 0x05dc: return((CHAR)(140 & 0xff)); case 0x05dd: return((CHAR)(141 & 0xff)); case 0x05de: return((CHAR)(142 & 0xff)); case 0x05df: return((CHAR)(143 & 0xff)); case 0x05e0: return((CHAR)(144 & 0xff)); case 0x05e1: return((CHAR)(145 & 0xff)); case 0x05e2: return((CHAR)(146 & 0xff)); case 0x05e3: return((CHAR)(147 & 0xff)); case 0x05e4: return((CHAR)(148 & 0xff)); case 0x05e5: return((CHAR)(149 & 0xff)); case 0x05e6: return((CHAR)(150 & 0xff)); case 0x05e7: return((CHAR)(151 & 0xff)); case 0x05e8: return((CHAR)(152 & 0xff)); case 0x05e9: return((CHAR)(153 & 0xff)); case 0x05ea: return((CHAR)(154 & 0xff)); case 0x00a2: return((CHAR)(155 & 0xff)); case 0x00a3: return((CHAR)(156 & 0xff)); case 0x00a5: return((CHAR)(157 & 0xff)); case 0x20a7: return((CHAR)(158 & 0xff)); case 0x0192: return((CHAR)(159 & 0xff)); case 0x00e1: return((CHAR)(160 & 0xff)); case 0x00ed: return((CHAR)(161 & 0xff)); case 0x00f3: return((CHAR)(162 & 0xff)); case 0x00fa: return((CHAR)(163 & 0xff)); case 0x00f1: return((CHAR)(164 & 0xff)); case 0x00d1: return((CHAR)(165 & 0xff)); case 0x00aa: return((CHAR)(166 & 0xff)); case 0x00ba: return((CHAR)(167 & 0xff)); case 0x00bf: return((CHAR)(168 & 0xff)); case 0x2310: return((CHAR)(169 & 0xff)); case 0x00ac: return((CHAR)(170 & 0xff)); case 0x00bd: return((CHAR)(171 & 0xff)); case 0x00bc: return((CHAR)(172 & 0xff)); case 0x00a1: return((CHAR)(173 & 0xff)); case 0x00ab: return((CHAR)(174 & 0xff)); case 0x00bb: return((CHAR)(175 & 0xff)); case 0x2591: return((CHAR)(176 & 0xff)); case 0x2592: return((CHAR)(177 & 0xff)); case 0x2593: return((CHAR)(178 & 0xff)); case 0x2502: return((CHAR)(179 & 0xff)); case 0x2524: return((CHAR)(180 & 0xff)); case 0x2561: return((CHAR)(181 & 0xff)); case 0x2562: return((CHAR)(182 & 0xff)); case 0x2556: return((CHAR)(183 & 0xff)); case 0x2555: return((CHAR)(184 & 0xff)); case 0x2563: return((CHAR)(185 & 0xff)); case 0x2551: return((CHAR)(186 & 0xff)); case 0x2557: return((CHAR)(187 & 0xff)); case 0x255d: return((CHAR)(188 & 0xff)); case 0x255c: return((CHAR)(189 & 0xff)); case 0x255b: return((CHAR)(190 & 0xff)); case 0x2510: return((CHAR)(191 & 0xff)); case 0x2514: return((CHAR)(192 & 0xff)); case 0x2534: return((CHAR)(193 & 0xff)); case 0x252c: return((CHAR)(194 & 0xff)); case 0x251c: return((CHAR)(195 & 0xff)); case 0x2500: return((CHAR)(196 & 0xff)); case 0x253c: return((CHAR)(197 & 0xff)); case 0x255e: return((CHAR)(198 & 0xff)); case 0x255f: return((CHAR)(199 & 0xff)); case 0x255a: return((CHAR)(200 & 0xff)); case 0x2554: return((CHAR)(201 & 0xff)); case 0x2569: return((CHAR)(202 & 0xff)); case 0x2566: return((CHAR)(203 & 0xff)); case 0x2560: return((CHAR)(204 & 0xff)); case 0x2550: return((CHAR)(205 & 0xff)); case 0x256c: return((CHAR)(206 & 0xff)); case 0x2567: return((CHAR)(207 & 0xff)); case 0x2568: return((CHAR)(208 & 0xff)); case 0x2564: return((CHAR)(209 & 0xff)); case 0x2565: return((CHAR)(210 & 0xff)); case 0x2559: return((CHAR)(211 & 0xff)); case 0x2558: return((CHAR)(212 & 0xff)); case 0x2552: return((CHAR)(213 & 0xff)); case 0x2553: return((CHAR)(214 & 0xff)); case 0x256b: return((CHAR)(215 & 0xff)); case 0x256a: return((CHAR)(216 & 0xff)); case 0x2518: return((CHAR)(217 & 0xff)); case 0x250c: return((CHAR)(218 & 0xff)); case 0x2588: return((CHAR)(219 & 0xff)); case 0x2584: return((CHAR)(220 & 0xff)); case 0x258c: return((CHAR)(221 & 0xff)); case 0x2590: return((CHAR)(222 & 0xff)); case 0x2580: return((CHAR)(223 & 0xff)); case 0x03b1: return((CHAR)(224 & 0xff)); case 0x00df: return((CHAR)(225 & 0xff)); case 0x0393: return((CHAR)(226 & 0xff)); case 0x03c0: return((CHAR)(227 & 0xff)); case 0x03a3: return((CHAR)(228 & 0xff)); case 0x03c3: return((CHAR)(229 & 0xff)); case 0x00b5: return((CHAR)(230 & 0xff)); case 0x03c4: return((CHAR)(231 & 0xff)); case 0x03a6: return((CHAR)(232 & 0xff)); case 0x0398: return((CHAR)(233 & 0xff)); case 0x03a9: return((CHAR)(234 & 0xff)); case 0x03b4: return((CHAR)(235 & 0xff)); case 0x221e: return((CHAR)(236 & 0xff)); case 0x03c6: return((CHAR)(237 & 0xff)); case 0x03b5: return((CHAR)(238 & 0xff)); case 0x2229: return((CHAR)(239 & 0xff)); case 0x2261: return((CHAR)(240 & 0xff)); case 0x00b1: return((CHAR)(241 & 0xff)); case 0x2265: return((CHAR)(242 & 0xff)); case 0x2264: return((CHAR)(243 & 0xff)); case 0x2320: return((CHAR)(244 & 0xff)); case 0x2321: return((CHAR)(245 & 0xff)); case 0x00f7: return((CHAR)(246 & 0xff)); case 0x2248: return((CHAR)(247 & 0xff)); case 0x00b0: return((CHAR)(248 & 0xff)); case 0x2219: return((CHAR)(249 & 0xff)); case 0x00b7: return((CHAR)(250 & 0xff)); case 0x221a: return((CHAR)(251 & 0xff)); case 0x207f: return((CHAR)(252 & 0xff)); case 0x00b2: return((CHAR)(253 & 0xff)); case 0x25a0: return((CHAR)(254 & 0xff)); case 0x00a0: return((CHAR)(255 & 0xff)); default: return(tx_cpsub(c)); /* For box characters etc */ } } int /* PC Code Page 864 */ #ifdef CK_ANSIC tx_cp864(USHORT c) #else tx_cp864(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00b0: return((CHAR)0x80 & 0xff); case 0x00b7: return((CHAR)0x81 & 0xff); case 0x2219: return((CHAR)0x82 & 0xff); case 0x221a: return((CHAR)0x83 & 0xff); case 0x2592: return((CHAR)0x84 & 0xff); case 0x2500: return((CHAR)0x85 & 0xff); case 0x2502: return((CHAR)0x86 & 0xff); case 0x253c: return((CHAR)0x87 & 0xff); case 0x2524: return((CHAR)0x88 & 0xff); case 0x252c: return((CHAR)0x89 & 0xff); case 0x251c: return((CHAR)0x8a & 0xff); case 0x2534: return((CHAR)0x8b & 0xff); case 0x2510: return((CHAR)0x8c & 0xff); case 0x250c: return((CHAR)0x8d & 0xff); case 0x2514: return((CHAR)0x8e & 0xff); case 0x2518: return((CHAR)0x8f & 0xff); case 0x03b2: return((CHAR)0x90 & 0xff); case 0x221e: return((CHAR)0x91 & 0xff); case 0x03c6: return((CHAR)0x92 & 0xff); case 0x00b1: return((CHAR)0x93 & 0xff); case 0x00bd: return((CHAR)0x94 & 0xff); case 0x00bc: return((CHAR)0x95 & 0xff); case 0x2248: return((CHAR)0x96 & 0xff); case 0x00ab: return((CHAR)0x97 & 0xff); case 0x00bb: return((CHAR)0x98 & 0xff); case 0xfef7: return((CHAR)0x99 & 0xff); case 0xfef8: return((CHAR)0x9a & 0xff); case 0xfefb: return((CHAR)0x9d & 0xff); case 0xfefc: return((CHAR)0x9e & 0xff); case 0x00a0: return((CHAR)0xa0 & 0xff); case 0x00ad: return((CHAR)0xa1 & 0xff); case 0xfe82: return((CHAR)0xa2 & 0xff); case 0x00a3: return((CHAR)0xa3 & 0xff); case 0x00a4: return((CHAR)0xa4 & 0xff); case 0xfe84: return((CHAR)0xa5 & 0xff); case 0xfe8e: return((CHAR)0xa8 & 0xff); case 0xfe8f: return((CHAR)0xa9 & 0xff); case 0xfe95: return((CHAR)0xaa & 0xff); case 0xfe99: return((CHAR)0xab & 0xff); case 0x060c: return((CHAR)0xac & 0xff); case 0xfe9d: return((CHAR)0xad & 0xff); case 0xfea1: return((CHAR)0xae & 0xff); case 0xfea5: return((CHAR)0xaf & 0xff); case 0x0660: return((CHAR)0xb0 & 0xff); case 0x0661: return((CHAR)0xb1 & 0xff); case 0x0662: return((CHAR)0xb2 & 0xff); case 0x0663: return((CHAR)0xb3 & 0xff); case 0x0664: return((CHAR)0xb4 & 0xff); case 0x0665: return((CHAR)0xb5 & 0xff); case 0x0666: return((CHAR)0xb6 & 0xff); case 0x0667: return((CHAR)0xb7 & 0xff); case 0x0668: return((CHAR)0xb8 & 0xff); case 0x0669: return((CHAR)0xb9 & 0xff); case 0xfed1: return((CHAR)0xba & 0xff); case 0x061b: return((CHAR)0xbb & 0xff); case 0xfeb1: return((CHAR)0xbc & 0xff); case 0xfeb5: return((CHAR)0xbd & 0xff); case 0xfeb9: return((CHAR)0xbe & 0xff); case 0x061f: return((CHAR)0xbf & 0xff); case 0x00a2: return((CHAR)0xc0 & 0xff); case 0xfe80: return((CHAR)0xc1 & 0xff); case 0xfe81: return((CHAR)0xc2 & 0xff); case 0xfe83: return((CHAR)0xc3 & 0xff); case 0xfe85: return((CHAR)0xc4 & 0xff); case 0xfeca: return((CHAR)0xc5 & 0xff); case 0xfe8b: return((CHAR)0xc6 & 0xff); case 0xfe8d: return((CHAR)0xc7 & 0xff); case 0xfe91: return((CHAR)0xc8 & 0xff); case 0xfe93: return((CHAR)0xc9 & 0xff); case 0xfe97: return((CHAR)0xca & 0xff); case 0xfe9b: return((CHAR)0xcb & 0xff); case 0xfe9f: return((CHAR)0xcc & 0xff); case 0xfea3: return((CHAR)0xcd & 0xff); case 0xfea7: return((CHAR)0xce & 0xff); case 0xfea9: return((CHAR)0xcf & 0xff); case 0xfeab: return((CHAR)0xd0 & 0xff); case 0xfead: return((CHAR)0xd1 & 0xff); case 0xfeaf: return((CHAR)0xd2 & 0xff); case 0xfeb3: return((CHAR)0xd3 & 0xff); case 0xfeb7: return((CHAR)0xd4 & 0xff); case 0xfebb: return((CHAR)0xd5 & 0xff); case 0xfebf: return((CHAR)0xd6 & 0xff); case 0xfec1: return((CHAR)0xd7 & 0xff); case 0xfec5: return((CHAR)0xd8 & 0xff); case 0xfecb: return((CHAR)0xd9 & 0xff); case 0xfecf: return((CHAR)0xda & 0xff); case 0x00a6: return((CHAR)0xdb & 0xff); case 0x00ac: return((CHAR)0xdc & 0xff); case 0x00f7: return((CHAR)0xdd & 0xff); case 0x00d7: return((CHAR)0xde & 0xff); case 0xfec9: return((CHAR)0xdf & 0xff); case 0x0640: return((CHAR)0xe0 & 0xff); case 0xfed3: return((CHAR)0xe1 & 0xff); case 0xfed7: return((CHAR)0xe2 & 0xff); case 0xfedb: return((CHAR)0xe3 & 0xff); case 0xfedf: return((CHAR)0xe4 & 0xff); case 0xfee3: return((CHAR)0xe5 & 0xff); case 0xfee7: return((CHAR)0xe6 & 0xff); case 0xfeeb: return((CHAR)0xe7 & 0xff); case 0xfeed: return((CHAR)0xe8 & 0xff); case 0xfeef: return((CHAR)0xe9 & 0xff); case 0xfef3: return((CHAR)0xea & 0xff); case 0xfebd: return((CHAR)0xeb & 0xff); case 0xfecc: return((CHAR)0xec & 0xff); case 0xfece: return((CHAR)0xed & 0xff); case 0xfecd: return((CHAR)0xee & 0xff); case 0xfee1: return((CHAR)0xef & 0xff); case 0xfe7d: return((CHAR)0xf0 & 0xff); case 0x0651: return((CHAR)0xf1 & 0xff); case 0xfee5: return((CHAR)0xf2 & 0xff); case 0xfee9: return((CHAR)0xf3 & 0xff); case 0xfeec: return((CHAR)0xf4 & 0xff); case 0xfef0: return((CHAR)0xf5 & 0xff); case 0xfef2: return((CHAR)0xf6 & 0xff); case 0xfed0: return((CHAR)0xf7 & 0xff); case 0xfed5: return((CHAR)0xf8 & 0xff); case 0xfef5: return((CHAR)0xf9 & 0xff); case 0xfef6: return((CHAR)0xfa & 0xff); case 0xfedd: return((CHAR)0xfb & 0xff); case 0xfed9: return((CHAR)0xfc & 0xff); case 0xfef1: return((CHAR)0xfd & 0xff); case 0x25a0: return((CHAR)0xfe & 0xff); default: return(tx_cpsub(c)); /* For box characters etc */ } } int /* PC Code Page 866 */ #ifdef CK_ANSIC tx_cp866(USHORT c) #else tx_cp866(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00a0: return((CHAR)(255 & 0xff)); case 0x00a4: return((CHAR)(253 & 0xff)); case 0x00b0: return((CHAR)(248 & 0xff)); case 0x00b7: return((CHAR)(250 & 0xff)); case 0x0401: return((CHAR)(240 & 0xff)); case 0x0404: return((CHAR)(242 & 0xff)); case 0x0407: return((CHAR)(244 & 0xff)); case 0x040e: return((CHAR)(246 & 0xff)); case 0x0410: return((CHAR)(128 & 0xff)); case 0x0411: return((CHAR)(129 & 0xff)); case 0x0412: return((CHAR)(130 & 0xff)); case 0x0413: return((CHAR)(131 & 0xff)); case 0x0414: return((CHAR)(132 & 0xff)); case 0x0415: return((CHAR)(133 & 0xff)); case 0x0416: return((CHAR)(134 & 0xff)); case 0x0417: return((CHAR)(135 & 0xff)); case 0x0418: return((CHAR)(136 & 0xff)); case 0x0419: return((CHAR)(137 & 0xff)); case 0x041a: return((CHAR)(138 & 0xff)); case 0x041b: return((CHAR)(139 & 0xff)); case 0x041c: return((CHAR)(140 & 0xff)); case 0x041d: return((CHAR)(141 & 0xff)); case 0x041e: return((CHAR)(142 & 0xff)); case 0x041f: return((CHAR)(143 & 0xff)); case 0x0420: return((CHAR)(144 & 0xff)); case 0x0421: return((CHAR)(145 & 0xff)); case 0x0422: return((CHAR)(146 & 0xff)); case 0x0423: return((CHAR)(147 & 0xff)); case 0x0424: return((CHAR)(148 & 0xff)); case 0x0425: return((CHAR)(149 & 0xff)); case 0x0426: return((CHAR)(150 & 0xff)); case 0x0427: return((CHAR)(151 & 0xff)); case 0x0428: return((CHAR)(152 & 0xff)); case 0x0429: return((CHAR)(153 & 0xff)); case 0x042a: return((CHAR)(154 & 0xff)); case 0x042b: return((CHAR)(155 & 0xff)); case 0x042c: return((CHAR)(156 & 0xff)); case 0x042d: return((CHAR)(157 & 0xff)); case 0x042e: return((CHAR)(158 & 0xff)); case 0x042f: return((CHAR)(159 & 0xff)); case 0x0430: return((CHAR)(160 & 0xff)); case 0x0431: return((CHAR)(161 & 0xff)); case 0x0432: return((CHAR)(162 & 0xff)); case 0x0433: return((CHAR)(163 & 0xff)); case 0x0434: return((CHAR)(164 & 0xff)); case 0x0435: return((CHAR)(165 & 0xff)); case 0x0436: return((CHAR)(166 & 0xff)); case 0x0437: return((CHAR)(167 & 0xff)); case 0x0438: return((CHAR)(168 & 0xff)); case 0x0439: return((CHAR)(169 & 0xff)); case 0x043a: return((CHAR)(170 & 0xff)); case 0x043b: return((CHAR)(171 & 0xff)); case 0x043c: return((CHAR)(172 & 0xff)); case 0x043d: return((CHAR)(173 & 0xff)); case 0x043e: return((CHAR)(174 & 0xff)); case 0x043f: return((CHAR)(175 & 0xff)); case 0x0440: return((CHAR)(224 & 0xff)); case 0x0441: return((CHAR)(225 & 0xff)); case 0x0442: return((CHAR)(226 & 0xff)); case 0x0443: return((CHAR)(227 & 0xff)); case 0x0444: return((CHAR)(228 & 0xff)); case 0x0445: return((CHAR)(229 & 0xff)); case 0x0446: return((CHAR)(230 & 0xff)); case 0x0447: return((CHAR)(231 & 0xff)); case 0x0448: return((CHAR)(232 & 0xff)); case 0x0449: return((CHAR)(233 & 0xff)); case 0x044a: return((CHAR)(234 & 0xff)); case 0x044b: return((CHAR)(235 & 0xff)); case 0x044c: return((CHAR)(236 & 0xff)); case 0x044d: return((CHAR)(237 & 0xff)); case 0x044e: return((CHAR)(238 & 0xff)); case 0x044f: return((CHAR)(239 & 0xff)); case 0x0451: return((CHAR)(241 & 0xff)); case 0x0454: return((CHAR)(243 & 0xff)); case 0x0457: return((CHAR)(245 & 0xff)); case 0x045e: return((CHAR)(247 & 0xff)); case 0x2116: return((CHAR)(252 & 0xff)); case 0x2219: return((CHAR)(249 & 0xff)); case 0x221a: return((CHAR)(251 & 0xff)); case 0x2500: return((CHAR)(196 & 0xff)); case 0x2502: return((CHAR)(179 & 0xff)); case 0x250c: return((CHAR)(218 & 0xff)); case 0x2510: return((CHAR)(191 & 0xff)); case 0x2514: return((CHAR)(192 & 0xff)); case 0x2518: return((CHAR)(217 & 0xff)); case 0x251c: return((CHAR)(195 & 0xff)); case 0x2524: return((CHAR)(180 & 0xff)); case 0x252c: return((CHAR)(194 & 0xff)); case 0x2534: return((CHAR)(193 & 0xff)); case 0x253c: return((CHAR)(197 & 0xff)); case 0x2550: return((CHAR)(205 & 0xff)); case 0x2551: return((CHAR)(186 & 0xff)); case 0x2552: return((CHAR)(213 & 0xff)); case 0x2553: return((CHAR)(214 & 0xff)); case 0x2554: return((CHAR)(201 & 0xff)); case 0x2555: return((CHAR)(184 & 0xff)); case 0x2556: return((CHAR)(183 & 0xff)); case 0x2557: return((CHAR)(187 & 0xff)); case 0x2558: return((CHAR)(212 & 0xff)); case 0x2559: return((CHAR)(211 & 0xff)); case 0x255a: return((CHAR)(200 & 0xff)); case 0x255b: return((CHAR)(190 & 0xff)); case 0x255c: return((CHAR)(189 & 0xff)); case 0x255d: return((CHAR)(188 & 0xff)); case 0x255e: return((CHAR)(198 & 0xff)); case 0x255f: return((CHAR)(199 & 0xff)); case 0x2560: return((CHAR)(204 & 0xff)); case 0x2561: return((CHAR)(181 & 0xff)); case 0x2562: return((CHAR)(182 & 0xff)); case 0x2563: return((CHAR)(185 & 0xff)); case 0x2564: return((CHAR)(209 & 0xff)); case 0x2565: return((CHAR)(210 & 0xff)); case 0x2566: return((CHAR)(203 & 0xff)); case 0x2567: return((CHAR)(207 & 0xff)); case 0x2568: return((CHAR)(208 & 0xff)); case 0x2569: return((CHAR)(202 & 0xff)); case 0x256a: return((CHAR)(216 & 0xff)); case 0x256b: return((CHAR)(215 & 0xff)); case 0x256c: return((CHAR)(206 & 0xff)); case 0x2580: return((CHAR)(223 & 0xff)); case 0x2584: return((CHAR)(220 & 0xff)); case 0x2588: return((CHAR)(219 & 0xff)); case 0x258c: return((CHAR)(221 & 0xff)); case 0x2590: return((CHAR)(222 & 0xff)); case 0x2591: return((CHAR)(176 & 0xff)); case 0x2592: return((CHAR)(177 & 0xff)); case 0x2593: return((CHAR)(178 & 0xff)); case 0x25a0: return((CHAR)(254 & 0xff)); default: return(tx_cpsub(c)); /* For box characters etc */ } } int /* PC Code Page 869 */ #ifdef CK_ANSIC tx_cp869(USHORT c) #else tx_cp869(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x80) /* Has C1 graphics */ return((CHAR)(c & 0xff)); switch (c) { case 0x00a0: return((CHAR)(255 & 0xff)); case 0x00a3: return((CHAR)(156 & 0xff)); case 0x00a6: return((CHAR)(138 & 0xff)); case 0x00a7: return((CHAR)(245 & 0xff)); case 0x00a8: return((CHAR)(249 & 0xff)); case 0x00a9: return((CHAR)(151 & 0xff)); case 0x00ab: return((CHAR)(174 & 0xff)); case 0x00ac: return((CHAR)(137 & 0xff)); case 0x00ad: return((CHAR)(240 & 0xff)); case 0x00b0: return((CHAR)(248 & 0xff)); case 0x00b1: return((CHAR)(241 & 0xff)); case 0x00b2: return((CHAR)(153 & 0xff)); case 0x00b3: return((CHAR)(154 & 0xff)); case 0x00b7: return((CHAR)(136 & 0xff)); case 0x00bb: return((CHAR)(175 & 0xff)); case 0x00bd: return((CHAR)(171 & 0xff)); case 0x0384: return((CHAR)(239 & 0xff)); case 0x0385: return((CHAR)(247 & 0xff)); case 0x0386: return((CHAR)(134 & 0xff)); case 0x0388: return((CHAR)(141 & 0xff)); case 0x0389: return((CHAR)(143 & 0xff)); case 0x038a: return((CHAR)(144 & 0xff)); case 0x038c: return((CHAR)(146 & 0xff)); case 0x038e: return((CHAR)(149 & 0xff)); case 0x038f: return((CHAR)(152 & 0xff)); case 0x0390: return((CHAR)(161 & 0xff)); case 0x0391: return((CHAR)(164 & 0xff)); case 0x0392: return((CHAR)(165 & 0xff)); case 0x0393: return((CHAR)(166 & 0xff)); case 0x0394: return((CHAR)(167 & 0xff)); case 0x0395: return((CHAR)(168 & 0xff)); case 0x0396: return((CHAR)(169 & 0xff)); case 0x0397: return((CHAR)(170 & 0xff)); case 0x0398: return((CHAR)(172 & 0xff)); case 0x0399: return((CHAR)(173 & 0xff)); case 0x039a: return((CHAR)(181 & 0xff)); case 0x039b: return((CHAR)(182 & 0xff)); case 0x039c: return((CHAR)(183 & 0xff)); case 0x039d: return((CHAR)(184 & 0xff)); case 0x039e: return((CHAR)(189 & 0xff)); case 0x039f: return((CHAR)(190 & 0xff)); case 0x03a0: return((CHAR)(198 & 0xff)); case 0x03a1: return((CHAR)(199 & 0xff)); case 0x03a3: return((CHAR)(207 & 0xff)); case 0x03a4: return((CHAR)(208 & 0xff)); case 0x03a5: return((CHAR)(209 & 0xff)); case 0x03a6: return((CHAR)(210 & 0xff)); case 0x03a7: return((CHAR)(211 & 0xff)); case 0x03a8: return((CHAR)(212 & 0xff)); case 0x03a9: return((CHAR)(213 & 0xff)); case 0x03aa: return((CHAR)(145 & 0xff)); case 0x03ab: return((CHAR)(150 & 0xff)); case 0x03ac: return((CHAR)(155 & 0xff)); case 0x03ad: return((CHAR)(157 & 0xff)); case 0x03ae: return((CHAR)(158 & 0xff)); case 0x03af: return((CHAR)(159 & 0xff)); case 0x03b0: return((CHAR)(252 & 0xff)); case 0x03b1: return((CHAR)(214 & 0xff)); case 0x03b2: return((CHAR)(215 & 0xff)); case 0x03b3: return((CHAR)(216 & 0xff)); case 0x03b4: return((CHAR)(221 & 0xff)); case 0x03b5: return((CHAR)(222 & 0xff)); case 0x03b6: return((CHAR)(224 & 0xff)); case 0x03b7: return((CHAR)(225 & 0xff)); case 0x03b8: return((CHAR)(226 & 0xff)); case 0x03b9: return((CHAR)(227 & 0xff)); case 0x03ba: return((CHAR)(228 & 0xff)); case 0x03bb: return((CHAR)(229 & 0xff)); case 0x03bc: return((CHAR)(230 & 0xff)); case 0x03bd: return((CHAR)(231 & 0xff)); case 0x03be: return((CHAR)(232 & 0xff)); case 0x03bf: return((CHAR)(233 & 0xff)); case 0x03c0: return((CHAR)(234 & 0xff)); case 0x03c1: return((CHAR)(235 & 0xff)); case 0x03c2: return((CHAR)(237 & 0xff)); case 0x03c3: return((CHAR)(236 & 0xff)); case 0x03c4: return((CHAR)(238 & 0xff)); case 0x03c5: return((CHAR)(242 & 0xff)); case 0x03c6: return((CHAR)(243 & 0xff)); case 0x03c7: return((CHAR)(244 & 0xff)); case 0x03c8: return((CHAR)(246 & 0xff)); case 0x03c9: return((CHAR)(250 & 0xff)); case 0x03ca: return((CHAR)(160 & 0xff)); case 0x03cb: return((CHAR)(251 & 0xff)); case 0x03cc: return((CHAR)(162 & 0xff)); case 0x03cd: return((CHAR)(163 & 0xff)); case 0x03ce: return((CHAR)(253 & 0xff)); case 0x2015: return((CHAR)(142 & 0xff)); case 0x2018: return((CHAR)(139 & 0xff)); case 0x2019: return((CHAR)(140 & 0xff)); case 0x2500: return((CHAR)(196 & 0xff)); case 0x2502: return((CHAR)(179 & 0xff)); case 0x250c: return((CHAR)(218 & 0xff)); case 0x2510: return((CHAR)(191 & 0xff)); case 0x2514: return((CHAR)(192 & 0xff)); case 0x2518: return((CHAR)(217 & 0xff)); case 0x251c: return((CHAR)(195 & 0xff)); case 0x2524: return((CHAR)(180 & 0xff)); case 0x252c: return((CHAR)(194 & 0xff)); case 0x2534: return((CHAR)(193 & 0xff)); case 0x253c: return((CHAR)(197 & 0xff)); case 0x2550: return((CHAR)(205 & 0xff)); case 0x2551: return((CHAR)(186 & 0xff)); case 0x2554: return((CHAR)(201 & 0xff)); case 0x2557: return((CHAR)(187 & 0xff)); case 0x255a: return((CHAR)(200 & 0xff)); case 0x255d: return((CHAR)(188 & 0xff)); case 0x2560: return((CHAR)(204 & 0xff)); case 0x2563: return((CHAR)(185 & 0xff)); case 0x2566: return((CHAR)(203 & 0xff)); case 0x2569: return((CHAR)(202 & 0xff)); case 0x256c: return((CHAR)(206 & 0xff)); case 0x2580: return((CHAR)(223 & 0xff)); case 0x2584: return((CHAR)(220 & 0xff)); case 0x2588: return((CHAR)(219 & 0xff)); case 0x2591: return((CHAR)(176 & 0xff)); case 0x2592: return((CHAR)(177 & 0xff)); case 0x2593: return((CHAR)(178 & 0xff)); case 0x25a0: return((CHAR)(254 & 0xff)); default: return(tx_cpsub(c)); /* For box characters etc */ } } int /* PC Code Page C0 graphics */ #ifdef CK_ANSIC tx_smiley(USHORT c) #else tx_smiley(c) USHORT c; #endif /* CK_ANSIC */ { if (c > 0x1f) return(-1); switch (c) { case 0x00a0: return((CHAR)0 & 0x7f); case 0x00a7: return((CHAR)21 & 0x7f); case 0x00b6: return((CHAR)20 & 0x7f); case 0x2022: return((CHAR)7 & 0x7f); case 0x203c: return((CHAR)19 & 0x7f); case 0x2190: return((CHAR)27 & 0x7f); case 0x2191: return((CHAR)24 & 0x7f); case 0x2192: return((CHAR)26 & 0x7f); case 0x2193: return((CHAR)25 & 0x7f); case 0x2194: return((CHAR)29 & 0x7f); case 0x2195: return((CHAR)18 & 0x7f); case 0x21a8: return((CHAR)23 & 0x7f); case 0x2319: return((CHAR)28 & 0x7f); case 0x25ac: return((CHAR)22 & 0x7f); case 0x25b2: return((CHAR)30 & 0x7f); case 0x25ba: return((CHAR)16 & 0x7f); case 0x25bc: return((CHAR)31 & 0x7f); case 0x25c4: return((CHAR)17 & 0x7f); case 0x25d8: return((CHAR)8 & 0x7f); case 0x25d9: return((CHAR)10 & 0x7f); case 0x25ef: return((CHAR)9 & 0x7f); case 0x263a: return((CHAR)1 & 0x7f); case 0x263b: return((CHAR)2 & 0x7f); case 0x263c: return((CHAR)15 & 0x7f); case 0x2640: return((CHAR)12 & 0x7f); case 0x2642: return((CHAR)11 & 0x7f); case 0x2660: return((CHAR)6 & 0x7f); case 0x2663: return((CHAR)5 & 0x7f); case 0x2665: return((CHAR)3 & 0x7f); case 0x2666: return((CHAR)4 & 0x7f); case 0x266a: return((CHAR)13 & 0x7f); case 0x266c: return((CHAR)14 & 0x7f); default: return(-1); } } USHORT /* Horizontal Scan Lines Unicode substitutions */ #ifdef CK_ANSIC tx_hslsub(USHORT c) #else tx_hslsub(c) USHORT c; #endif /* CK_ANSIC */ { if (c >= 0x23BA && c <= 0x23BD ) switch (c) { case 0x23BA: return(0x2500); /* H line - Scan 1 */ case 0x23BB: return(0x2500); /* H line - Scan 3 */ case 0x23BC: return(0x2500); /* H line - Scan 7 */ case 0x23BD: return(0x2500); /* H line - Scan 9 */ } return(c); } USHORT /* Kermit font 0xE??? Unicode substitutions */ #ifdef CK_ANSIC tx_usub(USHORT c) #else tx_usub(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0xE000 || c > 0xEFFF) return(c); switch (c) { case 0xE200: return(0x2524); /* Extensible Left Brace Middle */ case 0xE201: return(0x2570); /* Extensible Left Parenthesis bot */ case 0xE202: return(0x256d); /* Extensible left parenthesis top */ case 0xE203: return(0x2514); /* Extensible left SB bot */ case 0xE204: return(0x250c); /* Extensible left SB top */ case 0xE205: return(0x251c); /* Extensible right brace middle */ case 0xE206: return(0x256f); /* Extensible right parenthesis bot */ case 0xE207: return(0x256e); /* Extensible right parenthesis top */ case 0xE208: return(0x2518); /* Extensible right SB bot */ case 0xE209: return(0x2510); /* Extensible right SB top */ case 0xE20C: return(0x03a3); /* Summation symbol bot */ case 0xE20D: return(0x03a3); /* Summation symbol top */ case 0xE20E: return(0x2510); /* Right ceiling corner */ case 0xE20F: return(0x2518); /* Right floor corner */ case 0xE300: return(0x2502); /* V box line, extensible, left */ case 0xE309: return(0x2502); /* V box line, extensible, right */ case 0xE30A: return(0x258c); /* Diagonal fill, dark, UL */ case 0xE30B: return(0x2590); /* Diagonal fill, dark, UR */ case 0xE320: return(0x2583); /* Quadrant LL */ case 0xE321: return(0x2490); /* Quadrant LR */ case 0xE322: return(0x258c); /* Quadrant UL */ case 0xE323: return(0x2588); /* Quadrant UL and LL and LR */ case 0xE324: return(0x2588); /* Quadrant UL and LR */ case 0xE325: return(0x2588); /* Quadrant UL and LR */ case 0xE326: return(0x2588); /* Quadrant UL and UR and LL */ case 0xE327: return(0x2588); /* Quadrant UL and UR and LR */ case 0xE328: return(0x2590); /* Quadrant UR */ case 0xE329: return(0x2588); /* Quadrant UR and LL and LR */ case 0xE400: return(0x221a); /* Radical symbol, small */ case 0xE401: return(0x00bf); /* Reverse question mark */ default: return((unsigned)0xfffd); } } int /* Unicode to CP437 substitutions */ #ifdef CK_ANSIC tx_cpsub(USHORT c) #else tx_cpsub(c) USHORT c; #endif /* CK_ANSIC */ { int x; if (c < 0x0080) /* ASCII */ return((CHAR)(c & 0xff)); if (c >= 0x0080 && c <= 0x0100) { switch (c) { /* Latin-1 */ case 0x00A2: return(0x9b); /* Cent sign */ case 0x00A3: return(156); /* Pound sign */ case 0x00AC: return(170); /* Not symbol */ case 0x00B0: return(248); /* Degree symbol */ case 0x00B1: return(241); /* Plus or minus symbol */ case 0x00B2: return(253); /* Superscript 2 */ case 0x00B3: return(51); /* Superscript 3 */ case 0x00B6: return(14); /* Pilcrow symbol */ case 0x00B7: return(250); /* Center dot, small */ case 0x00B9: return(49); /* Superscript 1 */ case 0x00D0: return(68); /* Eth -> D */ case 0x00D7: return(120); /* Multiplication symbol */ case 0x00DE: return(84); /* Thorn -> T */ case 0x00F0: return(100); /* eth -> eth */ case 0x00F7: return(246); /* Division symbol */ case 0x00FE: return(116); /* thorn -> t */ default: return(0x13); } } else if (c >= 0x0100 && c <= 0x02ff) { /* Latin-2 etc */ switch (c) { case 0x0103: return(97); /* a breve */ case 0x0105: return(97); /* a ogonek */ case 0x0107: /* c acute */ case 0x010d: return(99); /* c caron */ case 0x010f: /* d caron */ case 0x0111: return(100); /* d with stroke */ case 0x0119: /* e ogonek */ case 0x011b: return(101); /* e caron */ case 0x011f: return(103); /* g breve */ case 0x0130: return(73); /* Capital I with Dot */ case 0x0131: return(105); /* Dotless i */ case 0x0132: return(89); /* IJ => Y */ case 0x0133: return(152); /* ij -> y diaeresis */ case 0x013a: /* l acute */ case 0x013e: /* l caron */ case 0x0142: return(108); /* l with stroke */ case 0x0144: /* n acute */ case 0x0148: return(110); /* n caron */ case 0x0151: return(111); /* o double acute */ case 0x0152: return(79); /* OE */ case 0x0153: return(111); /* oe */ case 0x0155: /* r acute */ case 0x0159: return(114); /* r caron */ case 0x015b: /* s acute */ case 0x015f: /* s ogonek */ case 0x0161: return(115); /* s caron */ case 0x0163: /* t ogonek */ case 0x0165: /* t caron */ case 0x0167: return(116); /* t with stroke */ case 0x016f: /* u ring */ case 0x0171: return(117); /* u double acute */ case 0x017a: /* z acute */ case 0x017c: /* z dot above */ case 0x017e: return(122); /* z caron */ case 0x0192: return(159); /* Function-of symbol, Script f */ case 0x01d0: return(105); /* i caron */ case 0x02c7: /* caron -> UNK */ case 0x02d8: return(0x13); /* breve -> UNK */ case 0x02dd: return(34); /* Double acute -> Doublequote */ default: return(0x13); } } else if (c >= 0x0300 && c <= 0x03ff) { /* Greek */ switch (c) { case 0x0393: return(226); /* Uppercase Greek Gamma */ case 0x0398: return(233); /* Uppercase Greek Theta */ case 0x039B: return(235); /* Uppercase Greek Lambda */ case 0x03A0: return(227); /* Uppercase Greek Pi */ case 0x03A3: return(228); /* Uppercase Greek Sigma */ case 0x03A4: return(0xEA); /* Omega */ case 0x03A6: return(232); /* Uppercase Greek Phi */ case 0x03A9: return(234); /* Uppercase Greek Omega */ case 0x03B1: return(0xE0); /* alpha */ case 0x03B2: return(0xE1); /* beta */ case 0x03B3: return(226); /* Lowercase Greek gamma */ case 0x03B4: return(0xEB); /* delta */ case 0x03B5: return(238); /* Lowercase Greek epsilon */ case 0x03B7: return(238); /* Lowercase Greek eta */ case 0x03B8: return(233); /* Lowercase Greek theta */ case 0x03B9: return(105); /* Lowercase Greek iota */ case 0x03BA: return(107); /* Lowercase Greek kappa */ case 0x03BB: return(235); /* Lowercase Greek lambda */ case 0x03BC: return(230); /* Lowercase Greek mu */ case 0x03C0: return(227); /* Lowercase Greek pi */ case 0x03C3: return(229); /* Lowercase Greek sigma */ case 0x03C4: return(231); /* Lowercase Greek tau */ case 0x03C6: return(237); /* Lowercase Greek phi */ case 0x03C7: return(120); /* Lowercase Greek chi */ case 0x03C9: return(234); /* Lowercase Greek omega */ default: return(0x13); } } else if (c >= 0x2000 && c <= 0x20ff) { /* Sub+Superscripts & Currency */ switch (c) { case 0x203C: return(0x13); /* !! */ case 0x2070: return(48); /* Superscript 0 */ case 0x2074: return(52); /* Superscript 4 */ case 0x2075: return(53); /* Superscript 5 */ case 0x2076: return(54); /* Superscript 6 */ case 0x2077: return(55); /* Superscript 7 */ case 0x2078: return(56); /* Superscript 8 */ case 0x2079: return(57); /* Superscript 9 */ case 0x207a: return(43); /* Superscript + */ case 0x207b: return(45); /* Superscript - */ case 0x207F: return(252); /* Superscript n */ case 0x2080: return(48); /* Subscript 0 */ case 0x2081: return(49); /* Subscript 1 */ case 0x2082: return(50); /* Subscript 2 */ case 0x2083: return(51); /* Subscript 3 */ case 0x2084: return(52); /* Subscript 4 */ case 0x2085: return(53); /* Subscript 5 */ case 0x2086: return(54); /* Subscript 6 */ case 0x2087: return(55); /* Subscript 7 */ case 0x2088: return(56); /* Subscript 8 */ case 0x2089: return(57); /* Subscript 9 */ case 0x208a: return(43); /* Subscript + */ case 0x208b: return(45); /* Subscript - */ case 0x20a7: return(0x93); /* Peseta */ default: x = tx_punc(c); /* Various spaces, dashes, etc */ return((x < 0) ? 0x13 : x); } } else if (c >= 0x2100 && c <= 0x21ff) { /* Arrows */ switch (c) { case 0x2190: return(27); /* Arrow, left-pointing */ case 0x2191: return(24); /* Arrow, up-pointing */ case 0x2192: return(26); /* Arrow, right-pointing */ case 0x2193: return(25); /* Arrow, down-pointing */ case 0x2194: return(0x1d); /* Arrow, left-right */ case 0x2195: return(0x12); /* Arrow, up-down */ case 0x219F: return(0x18); /* Arrow, up, doublehead */ case 0x21A1: return(0x19); /* Arrow, down, doublehead */ case 0x21A8: return(0x17); /* Arrow, up-down with base */ case 0x21D2: return(26); /* Implies symbol */ case 0x21D4: return(29); /* If and only if symbol */ case 0x21E4: return(0x1B); /* Arrow, left, to bar */ case 0x21E5: return(0x1A); /* Arrow, right, to bar */ case 0x21E8: return(0x10); /* Outline white right arrow */ case 0x21E9: return(0x0f); /* Outline white down arrow */ default: return(0x13); } } else if (c >= 0x2200 && c <= 0x22ff) { /* Math */ switch (c) { case 0x2202: return(235); /* Partial differential symbol */ case 0x2207: return(31); /* Nabla, Laplace operator */ case 0x2208: return(0x33); /* (because of QNX misunderstanding) */ case 0x221A: return(251); /* Radical symbol */ case 0x221D: return(236); /* Proportional-to */ case 0x221E: return(236); /* Infinity symbol */ case 0x2227: return(30); /* Logical AND */ case 0x2228: return(31); /* Logical OR */ case 0x2229: return(239); /* Intersection symbol */ case 0x222A: return(85); /* Union symbol */ case 0x222B: return(244); /* Integral symbol */ case 0x2234: return(254); /* Therefore symbol */ case 0x223C: return(126); /* Centered tilde operator */ case 0x2243: return(247); /* Asymptotically equals */ case 0x2248: return(247); /* Almost equal to symbol */ case 0x2260: return(88); /* Not equal symbol */ case 0x2261: return(240); /* Identity symbol */ case 0x2264: return(243); /* Less than or equal symbol */ case 0x2265: return(242); /* Greater than or equal symbol */ case 0x2282: return(40); /* Subset symbol */ case 0x2283: return(41); /* Superset symbol */ case 0x22A6: return(0xC3); /* Assertion symbol */ default: return(0x13); } } else if (c >= 0x23BA && c <= 0x23BD ) { switch (c) { case 0x23BA: return(0x2500); /* H line - Scan 1 */ case 0x23BB: return(0x2500); /* H line - Scan 3 */ case 0x23BC: return(0x2500); /* H line - Scan 7 */ case 0x23BD: return(0x2500); /* H line - Scan 9 */ } } else if (c >= 0x2300 && c <= 0x24ff) { /* Tech */ switch (c) { case 0x2308: return(0xDA); /* Left ceiling */ case 0x2309: return(0xBF); /* Right ceiling */ case 0x230A: return(0xC0); /* Left floor */ case 0x230B: return(0xD9); /* Right floor */ case 0x2319: return(0x1C); /* Turned Not sign */ case 0x2320: return(244); /* Integral symbol top */ case 0x2321: return(245); /* Integral symbol bot */ case 0x2329: return(60); /* BRA, large left angle bracket */ case 0x232A: return(62); /* KET, large right angle bracket */ case 0x2409: return(26); /* "HT" becomes right arrow */ case 0x240A: return(25); /* "LF" becomes down arrow */ case 0x240B: return(23); /* "VT" becomes up-down arrow */ case 0x240C: return(24); /* "FF" becomes up arrow */ case 0x240D: return(27); /* "CR" becomes left arrow */ case 0x2424: return(31); /* "NL" becomes down triangle */ default: return(0x13); } } else if (c >= 0x2500 && c <= 0x2552) { /* Box drawing */ switch (c) { case 0x2500: return(196); /* Center box bar horizontal */ case 0x2501: return(0xCD); /* Bold -> Double */ case 0x2502: return(179); /* Center box bar vertical */ case 0x2503: return(0xBA); /* Bold */ case 0x2504: return(45); /* Dashed line */ case 0x2506: return(124); /* Broken vertical bar */ case 0x250C: return(218); /* UL box corner */ case 0x250F: return(0xC9); /* Bold */ case 0x2510: return(191); /* UR Box Corner */ case 0x2513: return(0xBB); /* Bold */ case 0x2514: return(192); /* LL box corner */ case 0x2517: return(0xC8); /* Bold */ case 0x2518: return(217); /* LR box corner */ case 0x251B: return(0xBC); /* Bold */ case 0x251C: return(195); /* Left middle box side */ case 0x2520: return(0xC3); case 0x2523: return(0xCC); /* Bold */ case 0x2524: return(180); /* Right middle box side */ case 0x2528: return(180); case 0x252B: return(0xB9); /* Bold */ case 0x252C: return(194); /* Middle box top */ case 0x252F: return(194); case 0x2533: return(0xCB); /* Bold */ case 0x2534: return(193); /* Middle box bot */ case 0x2537: return(193); case 0x253B: return(0xCA); /* Bold */ case 0x253C: return(197); /* Box intersection */ case 0x253F: return(197); case 0x2542: return(197); case 0x2547: return(197); case 0x2548: return(197); case 0x2549: return(197); case 0x254A: return(197); case 0x254B: return(0xCE); /* Bold */ case 0x2550: return(205); /* Center box bar horizontal double */ case 0x2551: return(186); /* Center box bar vertical double */ case 0x2552: return(213); /* UL box corner single to double */ default: return(0x13); } } else if (c >= 0x2553 && c <= 0x2579) { /* More box drawing */ switch (c) { case 0x2553: return(214); /* UL box corner double to single */ case 0x2554: return(201); /* UL box corner double */ case 0x2555: return(184); /* UR box corner double to single */ case 0x2556: return(183); /* UR box corner single to double */ case 0x2557: return(187); /* UR box corner double */ case 0x2558: return(212); /* LL box corner single to double */ case 0x2559: return(211); /* LL box corner double to single */ case 0x255A: return(200); /* LL box corner double */ case 0x255B: return(190); /* LR box corner double to single */ case 0x255C: return(189); /* LR box corner single to double */ case 0x255D: return(188); /* LR box corner double */ case 0x255E: return(198); /* Left mid box side single to doubl */ case 0x255F: return(199); /* Left mid box side double to singl */ case 0x2560: return(204); /* Left middle box side double */ case 0x2561: return(181); /* Right box side double to single */ case 0x2562: return(182); /* Right box side single to double */ case 0x2563: return(185); /* Right middle box side double */ case 0x2564: return(209); /* Middle box top double to single */ case 0x2565: return(210); /* Middle box top single to double */ case 0x2566: return(203); /* Middle box top double */ case 0x2567: return(207); /* Middle box bot single to double */ case 0x2568: return(208); /* Middle box bot double to single */ case 0x2569: return(202); /* Middle box bot double */ case 0x256A: return(216); /* Box intersection double to single */ case 0x256B: return(215); /* Box intersection single to double */ case 0x256C: return(206); /* Box intersection double */ case 0x256D: return(218); /* UL arc */ case 0x256E: return(191); /* UR arc */ case 0x256F: return(217); /* LR arc */ case 0x2570: return(192); /* LL arc */ case 0x2571: return(179); /* Diagonal line LL to UR */ case 0x2572: return(196); /* Diagonal line UL to LR */ case 0x2573: return(88); /* Diagonal lines crossed */ case 0x2575: return(0xb3); /* High vertical line */ case 0x2576: return(45); /* Short horizontal line */ case 0x2577: return(0xb3); /* Low vertical line */ case 0x2579: return(0xb3); /* High vertical line bold */ default: return(0x13); } } else if (c >= 0x257a && c <= 0x25ff) { /* Still more box drawing */ switch (c) { case 0x257b: return(0xb3); /* Low vertical line bold */ case 0x2580: return(223); /* Quadrant UL and UR (top half) */ case 0x2581: return(0xc4); /* Scan line 9 */ case 0x2582: return(0xDC); /* Black blob lower half */ case 0x2584: return(220); /* Quadrant LL and LR (lower half) */ case 0x2588: return(219); /* Fill character dark */ case 0x258C: return(221); /* Quadrant UL and LL (left half) */ case 0x258E: return(0xDD); case 0x2590: return(222); /* Quadrant UR and LR (right half) */ case 0x2591: return(176); /* Fill character light */ case 0x2592: return(177); /* Fill character medium */ case 0x2593: return(178); /* Fill character heavy */ case 0x2594: return(0xc4); /* Scan line 1 */ case 0x25A0: return(254); /* Solid square, center */ case 0x25A6: return(177); /* Blotch */ case 0x25AC: /* Black rectangle */ case 0x25AF: return(0x16); /* White rectangle */ case 0x25B2: /* Triangle, up-pointing */ case 0x25B4: return(0x1e); /* Triangle, up-pointing */ case 0x25B6: /* Triangle, right-pointing, dark */ case 0x25B7: /* Triangle, right-pointing, light */ case 0x25B9: /* Triangle, right-pointing, light */ case 0x25BA: return(0x10); /* Triangle, right-pointing, narrow */ case 0x25BC: /* Triangle, down-pointing */ case 0x25BE: return(0x1f); /* Triangle, down-pointing */ case 0x25C0: /* Triangle, left-pointing, dark */ case 0x25C1: /* Triangle, left-pointing, dark */ case 0x25C4: return(0x11); /* Triangle, left-pointing, narrow */ case 0x25C6: return(4); /* Diamond, center, solid */ case 0x25CB: return(0x09); /* Circle */ case 0x25CF: return(249); /* Center dot, large */ case 0x25d8: return(0x08); /* Inverse bullet */ case 0x25d9: return(0x0a); /* Inverse white circle */ case 0x25E2: return(0xD9); /* Lower right triangle */ case 0x25E3: return(0xC0); /* Lower left triangle */ case 0x25E4: return(0xDA); /* Upper left triangle */ case 0x25E5: return(0xBf); /* Upper right triangle */ default: return(0x13); } } else if (c >= 0x2600) { /* All the rest */ switch (c) { case 0x263a: return(0x01); /* Smiley */ case 0x263b: return(0x02); /* Inverse Smiley */ case 0x263c: return(0x0f); /* White Sun with Rays */ case 0x2640: return(0x0c); /* Male sign */ case 0x2642: return(0x0b); /* Female sign */ case 0x2660: return(0x06); /* Spade */ case 0x2663: return(0x05); /* Club */ case 0x2665: return(0x03); /* Heart */ case 0x2666: return(0x04); /* Diamond, center, solid */ case 0x266a: return(0x0d); /* Quarter note */ case 0x266b: /* Beamed quarter notes */ case 0x266c: return(0x0e); /* Beamed 8th notes */ case 0x279e: return(0x1a); /* Bold right arrow */ case 0x27a1: return(0x1a); /* Heavy black right arrow. */ case 0xE200: return(180); /* Extensible left brace middle */ case 0xE201: return(192); /* Extensible Left parenthesis bot */ case 0xE202: return(218); /* Extensible left parenthesis top */ case 0xE203: return(192); /* Extensible left SB bot */ case 0xE204: return(218); /* Extensible left SB top */ case 0xE205: return(195); /* Extensible right brace middle */ case 0xE206: return(217); /* Extensible right parenthesis bot */ case 0xE207: return(191); /* Extensible right parenthesis top */ case 0xE208: return(217); /* Extensible right SB bot */ case 0xE209: return(191); /* Extensible right SB top */ case 0xE20C: return(228); /* Summation symbol bot */ case 0xE20D: return(228); /* Summation symbol top */ case 0xE20E: return(191); /* Right ceiling corner */ case 0xE20F: return(217); /* Right floor corner */ case 0xE300: return(179); /* V box line, extensible, left */ case 0xE309: return(179); /* V box line, extensible, right */ case 0xE30A: return(221); /* Diagonal fill, dark, UL */ case 0xE30B: return(222); /* Diagonal fill, dark, UR */ case 0xE320: return(221); /* Quadrant LL */ case 0xE321: return(222); /* Quadrant LR */ case 0xE322: return(221); /* Quadrant UL */ case 0xE323: return(219); /* Quadrant UL and LL and LR */ case 0xE324: return(219); /* Quadrant UL and LR */ case 0xE325: return(219); /* Quadrant UL and LR */ case 0xE326: return(219); /* Quadrant UL and UR and LL */ case 0xE327: return(219); /* Quadrant UL and UR and LR */ case 0xE328: return(222); /* Quadrant UR */ case 0xE329: return(219); /* Quadrant UR and LL and LR */ case 0xE400: return(251); /* Radical symbol, small */ case 0xE401: return(168); /* Reverse question mark */ case 0xFFFD: return(0x13); /* !! for unknown */ default: return(0x13); } } return(0x13); } #ifdef OS2 /* Lucida Console is a Unicode font, but it is very sparsely populated. Since it is the only monospace Unicode font most people have, we have to make reasonable substitutions or else 3/4 of the glyphs will show up as blobs on the screen. */ USHORT /* Unicode to Lucida Console */ #ifdef CK_ANSIC tx_lucidasub(USHORT c) #else tx_lucidasub(c) USHORT c; #endif /* CK_ANSIC */ { if (c < 0x0180) /* Latin-1 and Extended A */ return(c); /* For efficiency we try to arrange the sections by frequency of use. */ if (c >= 0x23BA && c <= 0x23BD) { switch(c) { case 0x23BA: /* H line - Scan 1 */ case 0x23BB: /* H line - Scan 3 */ case 0x23BC: /* H line - Scan 7 */ case 0x23BD: /* H line - Scan 9 */ return(0x2500); } } if (c >= 0x2500 && c <= 0x257f) { /* Box drawing */ if (c >= 0x2550 && c <= 0x256c) return(c); switch (c) { /* Themselves */ case 0x2500: case 0x2502: case 0x250c: case 0x2510: case 0x2514: case 0x2518: case 0x251c: case 0x2524: case 0x252c: case 0x2534: case 0x253c: return(c); /* Horizontal lines */ case 0x2501: /* Bold */ return(0x2550); /* Use double */ case 0x2504: case 0x2505: case 0x2508: case 0x2509: case 0x254c: case 0x254d: case 0x257c: case 0x257e: return(0x2500); /* Vertical lines */ case 0x2503: /* Bold */ return(0x2551); /* Use double */ case 0x2506: case 0x2507: case 0x250a: case 0x250b: /* Other */ case 0x254e: case 0x254f: case 0x257d: case 0x257f: case 0x2575: case 0x2577: case 0x2579: case 0x257b: return(0x2502); /* Upper left box corner */ case 0x250f: /* Bold */ return(0x2554); /* Use double */ case 0x250d: case 0x250e: /* Other */ return(0x250c); /* Upper right box corner */ case 0x2513: /* Bold */ return(0x2557); case 0x2511: case 0x2512: /* Other */ return(0x2510); /* Lower left box corner */ case 0x2517: /* Bold */ return(0x255a); case 0x2515: case 0x2516: /* Other */ return(0x2514); /* Lower right box corner */ case 0x251b: /* Bold */ return(0x255d); case 0x2519: case 0x251a: /* Other */ return(0x2518); /* Vertical and right */ case 0x2523: /* Bold */ return(0x2560); case 0x251d: case 0x251e: case 0x251f: case 0x2520: case 0x2521: case 0x2522: return(0x251c); /* Vertical and left */ case 0x252b: /* Bold */ return(0x2563); case 0x2525: case 0x2526: case 0x2527: case 0x2528: case 0x2529: case 0x252a: return(0x2524); /* Horizontal and down */ case 0x2533: /* Bold */ return(0x2566); case 0x252d: case 0x252e: case 0x252f: case 0x2530: case 0x2531: case 0x2532: return(0x252c); /* Horizontal and up */ case 0x253b: /* Bold */ return(0x2569); case 0x2535: case 0x2536: case 0x2537: case 0x2538: case 0x2539: case 0x253a: return(0x2534); /* Horizontal and Vertical */ case 0x254b: /* Bold */ return(0x256c); case 0x253d: case 0x253e: case 0x253f: case 0x2540: case 0x2541: case 0x2542: case 0x2543: case 0x2544: case 0x2545: case 0x2546: case 0x2547: case 0x2548: case 0x2549: case 0x254a: return(0x253c); /* Curved corners */ case 0x256d: /* UL */ return(0x250c); case 0x256e: /* UR */ return(0x2510); case 0x256f: /* LL */ return(0x2518); case 0x2570: /* LR */ return(0x2514); case 0x2571: /* Diagonal */ return(0x002f); case 0x2572: /* Other diagonal */ return(0x005c); case 0x2573: /* Diagonal cross */ return(0x00d7); /* Partial horizontal lines */ case 0x2574: case 0x2576: case 0x2578: case 0x257a: return(0x002d); default: return(0xfffd); } } if (c >= 0x2190 && c <= 0x21ff) { /* Arrows */ if (c >= 0x2190 && c <= 0x2195 || c == 0x21a8) return(c); switch (c) { /* Left-arrow forms */ case 0x219e: case 0x21a2: case 0x21a4: case 0x21a9: case 0x21bc: case 0x21d0: case 0x21da: case 0x21dc: case 0x21e0: case 0x21e4: case 0x21e6: case 0x21c7: return(0x2190); /* Right-arrow forms */ case 0x21a0: case 0x21a3: case 0x21a6: case 0x21aa: case 0x21c0: case 0x21c1: case 0x21c9: case 0x21d2: case 0x21db: case 0x21dd: case 0x21e2: case 0x21e5: case 0x21e8: return(0x2192); /* Up-arrow forms */ case 0x219f: case 0x21a5: case 0x21be: case 0x21bf: case 0x21c8: case 0x21d1: case 0x21de: case 0x21e1: case 0x21e7: case 0x21ea: return(0x2191); /* Down-arrow forms */ case 0x21a1: case 0x21a7: case 0x21af: case 0x21c2: case 0x21ce: case 0x21ca: case 0x21d3: case 0x21df: case 0x21e3: case 0x21e9: return(0x2193); /* Up-down-arrow forms */ case 0x21c5: case 0x21d5: return(0x2195); default: return(0xfffd); } } if (c >= 0x2580 && c <= 0x259f) { /* Block elements */ switch (c) { case 0x2580: case 0x2584: case 0x2588: case 0x258c: case 0x2590: case 0x2591: case 0x2592: case 0x2593: return(c); case 0x2581: case 0x2582: case 0x2583: case 0x2585: case 0x2586: case 0x2587: return(0x2584); case 0x2589: case 0x258a: case 0x258b: case 0x258d: case 0x258e: case 0x258f: return(0x258c); case 0x2595: return(0x2502); default: return(0xfffd); } } if (c >= 0x2200 && c <= 0x22ff) { /* Mathematical operators */ switch (c) { case 0x2202: case 0x2206: case 0x220f: case 0x2211: case 0x2212: case 0x2219: case 0x2220: case 0x221e: case 0x221f: case 0x2229: case 0x222b: case 0x2248: case 0x2260: case 0x2261: case 0x2264: case 0x2265: return(c); default: return(0xfffd); } } if (c >= 0x2300 && c <= 0x237f) { /* Miscellaneous Technical */ if (c == 0x2302 || c == 0x2310 || c == 0x2320 || c == 0x2321) return(c); switch (c) { case 0x2329: /* BRA */ return(0x003c); case 0x232a: /* KET */ return(0x003e); default: return(0xfffd); } } if (c >= 0x25a0 && c <= 0x25ff) { /* Geometric shapes */ switch (c) { /* Themselves */ case 0x25a0: case 0x25ac: case 0x25b2: case 0x25ba: case 0x25bc: case 0x25c4: case 0x25ca: case 0x25cb: case 0x25d8: case 0x25d9: return(c); /* Squares */ case 0x25a1: case 0x25a2: case 0x25a3: case 0x25a4: case 0x25a5: case 0x25a6: case 0x25a7: case 0x25a8: case 0x25a9: case 0x25aa: case 0x25ab: case 0x25e7: case 0x25e8: case 0x25e9: case 0x25ea: case 0x25eb: return(0x25a0); case 0x25ad: case 0x25ae: case 0x25af: /* Rectangles */ case 0x25b0: case 0x25b1: return(0x25ac); case 0x25b3: case 0x25b4: case 0x25b5: /* Upright triangles */ case 0x25ec: case 0x25ed: case 0x25ee: return(0x25b2); case 0x25b6: case 0x25b7: case 0x25b8: case 0x25b9: case 0x25bb: return(0x25ba); /* Right-pointing triangles */ case 0x25bd: case 0x25be: case 0x25bf: /* Down-pointing triangles */ return(0x25bc); case 0x25c0: case 0x25c1: case 0x25c2: case 0x25c3: case 0x25c5: return(0x25c4); /* Left-pointing triangles */ case 0x25c6: case 0x25c7: case 0x25c8: /* Diamonds */ return(0x2666); /* Circles */ case 0x25c9: case 0x25cc: case 0x25cd: case 0x25ce: case 0x25cf: case 0x25d0: case 0x25d1: case 0x25d2: case 0x25d3: case 0x25d4: case 0x25d5: case 0x25e6: case 0x25ef: return(0x25cb); /* Curves and corner triangles */ case 0x25dc: case 0x25e4: /* UL */ return(0x250c); case 0x25dd: case 0x25e5: /* UR */ return(0x2510); case 0x25df: case 0x25e3: /* LL */ return(0x2514); case 0x25de: case 0x25e2: /* LR */ return(0x2518); default: return(0xfffd); } } if (c >= 0x2600 && c <= 0x26ff) { /* Misc symbols */ switch (c) { /* Themselves */ case 0x263a: case 0x263b: case 0x263c: case 0x2640: case 0x2642: case 0x2660: case 0x2663: case 0x2665: case 0x2666: case 0x266a: case 0x266b: return(c); default: return(0xfffd); } } if (c >= 0x2794 && c <= 0x27be) /* Right-arrow Dingbats */ return(0x2192); if (c >= 0x2070 && c <= 0x209f) { /* Super & subscripts */ if (c == 0x207f) /* n */ return(c); else if (c == 0x2070) /* 0 */ return(0x0030); else if (c >= 0x2074 && c <= 0x2079) return(c - 0x2040); else if (c >= 0x2080 && c <= 0x2089) return(c - 0x2050); switch (c) { case 0x207a: case 0x208a: return(0x002b); case 0x207b: case 0x208b: return(0x002d); case 0x207c: case 0x208c: return(0x003d); case 0x207d: case 0x208d: return(0x0028); case 0x207e: case 0x208e: return(0x0029); default: return(0xfffd); } } if (c >= 0x0180 && c <= 0x024f) { /* Latin Extended B, Part I */ if (c == 0x0192 || c >= 0x01fa && c <= 0x01ff) return(c); /* Latin Extended B */ switch (c) { case 0x0180: case 0x0183: case 0x0184: case 0x0185: return(0x0062); /* Lowercase b variants */ case 0x0181: case 0x0182: return(0x0042); /* Uppercase B variants */ case 0x0186: case 0x0187: return(0x0043); /* Uppercase C variants */ case 0x0189: /* D with stroke */ return(0x00D0); /* Looks just like Eth */ case 0x018a: /* D with hook */ return(0x0044); case 0x018e: case 0x0190: /* E-like letters */ return(0x0045); case 0x018f: /* e-like letters */ return(0x0065); case 0x0191: /* F-like */ return(0x0046); case 0x0193: /* G-like */ return(0x0047); case 0x0194: /* Latin Capital Gamma */ return(0x0393); /* Use Greek */ case 0x0195: /* Gothic hv */ return(0x0068); /* Use h */ case 0x0196: /* Latin Capital Iota */ return(0x0399); /* Use Greek */ case 0x0197: /* I with bar */ return(0x0069); case 0x0198: /* K with hook */ return(0x004B); case 0x0199: /* k with hook */ return(0x006B); case 0x019A: /* l with bar */ return(0x006C); case 0x019B: /* lambda with bar */ return(0x03bb); /* Use Greek */ case 0x019C: /* Upside down m */ return(0x006d); case 0x019D: /* N with left hook */ return(0x004e); case 0x019E: /* n with long right leg */ return(0x006e); case 0x019F: case 0x01a0: case 0x01a2: /* O-like letters */ return(0x004f); case 0x01a1: case 0x01a3: /* o-like */ return(0x006f); case 0x01A4: /* P with hook */ return(0x0050); case 0x01A5: /* p with hook */ return(0x0070); case 0x01A6: /* Old Norse YR */ return(0x0052); case 0x01A7: /* Backwards S */ return(0x0053); case 0x01A8: case 0x01AA: /* s-like letters */ return(0x0073); case 0x01A9: /* Esh */ return(0x03a3); /* Looks just like Sigma */ case 0x01AB: case 0x01AD: /* t-like */ return(0x0074); case 0x01AC: case 0x01AE: /* T-like */ return(0x0054); case 0x01AF: case 0x01B1: /* U-like */ return(0x0055); case 0x01B0: /* u-like */ return(0x0075); case 0x01B2: /* V-like */ return(0x0056); case 0x01B3: /* Y-like */ return(0x0059); case 0x01B4: /* y-like */ return(0x0079); case 0x01B5: /* Z-like */ return(0x005a); case 0x01B6: /* z-like */ return(0x007a); case 0x01B7: /* Yogh */ return(0x0033); /* Use "3" */ case 0x01BF: /* Wynn */ return(0x0077); /* Use "w" */ case 0x01CD: /* A caron */ return(0x0041); case 0x01CE: /* a caron */ return(0x0061); case 0x01CF: /* I caron */ return(0x0049); case 0x01D0: /* i caron */ return(0x0069); case 0x01D1: /* O caron */ return(0x004f); case 0x01D2: /* o caron */ return(0x006f); case 0x01D3: /* U caron */ return(0x0055); case 0x01D4: /* u caron */ return(0x0075); /* U diaeresis + other things */ case 0x01D5: case 0x01D7: case 0x01D9: case 0x01DB: return(0x00dc); /* u diaeresis + other things */ case 0x01D6: case 0x01Da: case 0x01Dc: return(0x00fc); /* Fill in more here if anybody asks */ default: return(0xfffd); } } if (c >= 0x1e00 && c <= 0x1eff) { /* Latin Extended Additional */ if (c >= 0x1e80 && c <= 0x1e85) return(c); else return(0xfffd); } if (c >= 0x0400 && c <= 0x04ff) { /* Cyrillic */ if (c >= 0x0400 && c <= 0x045f || c == 0x0490 || c == 0x0491) return(c); else return(0xfffd); } if (c >= 0x0370 && c <= 0x03ff) { /* Greek */ if (c == 0x037e || c >= 0x0384 && c <= 0x03ce) return(c); switch (c) { case 0x0374: case 0x0375: return(0x0027); case 0x037a: return(0x002c); /* Fill in more here if needed */ default: return(0xfffd); } } if (c >= 0x1f00 && c <= 0x1fff) { /* Greek Extended */ /* Fill in if asked */ return(0xfffd); } if (c >= 0x20a0 && c <= 0x20cf) { /* Currency symbols */ if (c == 0x20a3 || c == 0x20a4 || c == 0x20a7 || c == 0x20ac) return(c); else return(0xfffd); } if (c >= 0x2100 && c <= 0x214f) { /* Letterlike symbols */ if (c == 0x2116 || c == 0x2122 || c == 0x2126) return(c); else return(0xfffd); } if (c >= 0x2150 && c <= 0x218f) { /* Number forms */ if (c >= 0x215b && c <= 0x215e) /* Roman numerals etc */ return(c); else return(0xfffd); } if (c >= 0x02b0 && c <= 0x02ff) { /* Spacing modifier letters */ if (c == 0x02c6 || c == 0x02c7 || c == 0x02c9 || c >= 0x02d8 && c <= 0x02dd) return(c); switch (c) { case 0x02b0: case 0x02b1: return(0x0068); case 0x02b2: return(0x006a); case 0x02b3: case 0x02b4: case 0x02b5: return(0x0072); case 0x02b7: return(0x0077); case 0x02b8: return(0x0079); case 0x02b9: return(0x00b4); case 0x02ba: return(0x0022); case 0x02bb: case 0x02bc: case 0x02bd: case 0x02be: case 0x02bf: return(0x0027); case 0x02c2: return(0x003c); case 0x02c3: return(0x003e); case 0x02da: return(0x00b0); case 0x02dc: return(0x007e); default: return(0xfffd); } } if (c >= 0x2000 && c <= 0x206f) { /* General Punctuation */ if (c >= 0x2013 && c <= 0x2015 || c >= 0x2017 && c <= 0x201a || c >= 0x201c && c <= 0x201e || c >= 0x2020 && c <= 0x2022 || c == 0x2026 || c == 0x2030 || c >= 0x2039 && c <= 0x203a || c == 0x203c || c == 0x203e || c == 0x2044) return(c); else if (c == 0x2016) return(0x2551); else if (c == 0x2017) return(0x2550); else if (c == 0x2044) return(0x002f); else return(0xfffd); } if (c == 0xfb01 || c == 0xfb02) /* Alphabetic Presentation Forms */ return(c); return(0xfffd); /* Catch-all */ } #endif /* OS2 */ /* Table of Blah-to-Unicode information structures. KEEP THIS IN SYNC WITH THE TX_blah DEFINITIONS in ckcuni.h. */ struct x_to_unicode * txrinfo[MAXTXSETS+1] = { &u_ascii, /* 0 US ISO 646 (ASCII) */ &u_british, /* 1 UK ISO 646 */ &u_fr_canadian, /* 2 Canadian French NRC */ NULL, /* 3 Cuba */ NULL, /* 4 Czecho */ &u_danish, /* 5 Danish/Norwegian ISO 646 */ &u_dutch, /* 6 Dutch NRC */ &u_finnish, /* 7 Finnish NRC */ &u_french, /* 8 French ISO 646 */ &u_german, /* 9 German ISO 646 */ &u_hebrew7, /* 10 Hebrew-7 (DEC) */ &u_hungarian, /* 11 Hungarian ISO 646 */ &u_icelandic, /* 12 Icelandic NRC */ &u_italian, /* 13 Italian ISO 646 */ &u_jis0201r, /* 14 Japanese Roman ISO 646 */ &u_jis0201k, /* 15 Japanese Katakana */ &u_koi7, /* 16 Short KOI */ &u_danish, /* 17 Norwegian/Danish ISO 646 */ &u_portuguese, /* 18 Portuguese ISO 646 */ &u_spanish, /* 19 spanish ISO 646 */ &u_swedish, /* 20 Swedish ISO 646 */ NULL, /* 21 Swedish ISO 646 for names */ &u_swiss, /* 22 Swiss NRC */ &u_8859_1, /* 23 ISO 8859-1 */ &u_8859_2, /* 24 ISO 8859-2 */ &u_8859_3, /* 25 ISO 8859-3 */ &u_8859_4, /* 26 ISO 8859-4 */ &u_8859_5, /* 27 ISO 8859-5 */ /* Cyrillic */ &u_8859_6, /* 28 ISO 8859-6 */ /* Arabic */ &u_8859_7, /* 29 ISO 8859-7 */ /* Greek */ &u_8859_8, /* 30 ISO 8859-8 */ /* Hebrew */ &u_8859_9, /* 31 ISO 8859-9 */ &u_8859_10, /* 32 ISO 8859-10 */ &u_koi8, /* 33 KOI-8 */ NULL, /* 34 JIS-7 */ NULL, /* 35 Shift JIS */ NULL, /* 36 Japanese EUC (JAE) */ NULL, /* 37 Japanese DEC Kanji */ &u_decmcs, /* 38 DEC MCS */ &u_nextstep, /* 39 NeXT */ &u_dgi, /* 40 DGI */ &u_maclatin, /* 41 Macintosh Latin */ &u_hproman8, /* 42 HP Roman 8 */ &u_cp437, /* 43 CP437 - Original */ &u_cp850, /* 44 CP850 - W Europe */ &u_cp852, /* 45 CP852 - E Europe */ &u_cp857, /* 46 CP857 - Turkish */ &u_cp862, /* 47 CP862 - Hebrew */ &u_cp864, /* 48 CP864 - Arabic */ &u_cp866, /* 49 CP866 - Cyrillic */ &u_cp869, /* 50 CP869 - Greek */ &u_decspec, /* 51 DEC Special Graphics */ &u_dectech, /* 52 DEC Technical */ &u_c0pics, /* 53 C0 Pictures */ &u_c1pics, /* 54 C1 Pictures */ &u_smiley, /* 55 IBM C0 Graphics */ &u_heath19g, /* 56 Heath 19 Graphics */ &u_tvig, /* 57 TVI Graphics */ &u_wyse_gn, /* 58 Wyse 60 Graphics Normal */ &u_wyse_g1, /* 59 Wyse 60 Graphics 1 */ &u_wyse_g2, /* 60 Wyse 60 Graphics 2 */ &u_wyse_g3, /* 61 Wyse 60 Graphics 3 */ &u_elot927, /* 62 Greek ELOT 927 */ &u_dgspec, /* 63 DG Special graphics */ &u_dgline, /* 64 DG Line drawing */ &u_dgword, /* 65 DG Word processing */ &u_hpline, /* 66 HP Line drawing */ &u_hpmath, /* 67 HP Math/Technical */ &u_qnxgrph, /* 68 QNX Graphics */ &u_snibrack, /* 69 SNI Brackets */ &u_snieuro, /* 70 SNI Euro */ &u_snifacet, /* 71 SNI Facet */ &u_sniibm, /* 72 SNI IBM */ &u_sniblanks, /* 73 SNI Blanks */ &u_cp1252, /* 74 Windows Latin-1 */ &u_cp1250, /* 75 Windows Latin-2 */ &u_cp1251, /* 76 Windows Cyrillic */ &u_cp1253, /* 77 Windows Greek */ &u_cp1254, /* 78 Windows Turkish */ &u_cp1257, /* 79 Windows Latin-4 */ &u_cp856, /* 80 Cyrillic PC Code Page 856 */ &u_cp855, /* 81 Cyrillic PC Code Page 855 */ &u_8859_1, /* 82 CP819 - Same as 8859-1 */ &u_8859_2, /* 83 CP912 - Same as 8859-2 */ &u_8859_3, /* 84 CP913 - Same as 8859-3 */ &u_8859_4, /* 85 CP914 - Same as 8859-4 */ &u_8859_5, /* 86 CP915 - Same as 8859-5 */ &u_8859_6, /* 87 CP1089 - Same as 8859-6 */ &u_8859_7, /* 88 CP813 - Same as 8859-7 */ &u_8859_8, /* 89 CP916 - Same as 8859-8 */ &u_8859_9, /* 90 CP920 - Same as 8859-9 */ &u_hproman8, /* 91 CP1051 - Same as HP Roman 8 */ &u_cp858, /* 92 CP858 - W Europe w/Euro */ &u_8859_15, /* 93 ISO 8859-15 Latin-15 */ &u_8859_15, /* 94 CP923 - Same as 8859-15 */ &u_8859_7, /* 95 ELOT928 - Same as 8859-7 */ &u_quickdraw, /* 96 CP10000 - Apple Quickdraw */ &u_cp37, /* 97 CP37 - U.S. EBCDIC */ &u_cp1255, /* 98 CP1255 - Windows Hebrew */ &u_cp1256, /* 99 CP1256 - Windows Arabic */ &u_cp1258, /* 100 CP1258 - Windows Viet Nam */ &u_mazovia, /* 101 Mazovia Polish code page */ &u_transparent, /* 102 Transparent */ &u_hz1500, /* 103 Hazeltine 1500/1520 graphics */ &u_koi8r, /* 104 KOI8-R */ &u_koi8u, /* 105 KOI8-U */ &u_apl1, /* 106 APL 1 (ISO) */ &u_apl2, /* 107 APL 2 (Dyadic) */ &u_apl3, /* 108 APL 3 (Plus) */ &u_apl4, /* 108 APL 4 (IBM) */ &u_apl5 /* 110 APL 5 (2741) */ }; /* Table of Blah-to-Unicode translation functions. KEEP THIS IN SYNC WITH THE TX_blah DEFINITITIONS in ckcuni.h. */ USHORT #ifdef CK_ANSIC (*xl_u[MAXTXSETS+1])(CHAR) #else (*xl_u[MAXTXSETS+1])() #endif /* CK_ANSIC */ = { ascii_u, /* 0 US ISO 646 (ASCII) */ british_u, /* 1 UK ISO 646 */ fr_canadian_u, /* 2 Canadian French NRC */ NULL, /* 3 Cuba */ NULL, /* 4 Czecho */ danish_u, /* 5 Danish/Norwegian ISO 646 */ dutch_u, /* 6 Dutch NRC */ finnish_u, /* 7 Finnish NRC */ french_u, /* 8 French ISO 646 */ german_u, /* 9 German ISO 646 */ hebrew7_u, /* 10 Hebrew-7 (DEC) */ hungarian_u, /* 11 Hungarian ISO 646 */ icelandic_u, /* 12 Icelandic */ italian_u, /* 13 Italian ISO 646 */ jis0201r_u, /* 14 Japanese Roman ISO 646 */ jis0201k_u, /* 15 Japanese Katakana */ koi7_u, /* 16 Short KOI */ danish_u, /* 17 Norwegian/Danish ISO 646 */ portuguese_u, /* 18 Portuguese ISO 646 */ spanish_u, /* 19 spanish ISO 646 */ swedish_u, /* 20 Swedish ISO 646 */ NULL, /* 21 Swedish ISO 646 for names */ swiss_u, /* 22 Swiss NRC */ iso_8859_1_u, /* 23 ISO 8859-1 */ iso_8859_2_u, /* 24 ISO 8859-2 */ iso_8859_3_u, /* 25 ISO 8859-3 */ iso_8859_4_u, /* 26 ISO 8859-4 */ iso_8859_5_u, /* 27 ISO 8859-5 */ /* Cyrillic */ iso_8859_6_u, /* 28 ISO 8859-6 */ /* Arabic */ iso_8859_7_u, /* 29 ISO 8859-7 */ /* Greek */ iso_8859_8_u, /* 30 ISO 8859-8 */ /* Hebrew */ iso_8859_9_u, /* 31 ISO 8859-9 */ /* Latin-5 */ iso_8859_10_u, /* 32 ISO 8859-10 */ koi8_u, /* 33 KOI-8 */ NULL, /* 34 JIS-7 */ NULL, /* 35 Shift JIS */ NULL, /* 36 Japanese EUC (JAE) */ NULL, /* 37 Japanese DEC Kanji */ decmcs_u, /* 38 DEC MCS */ nextstep_u, /* 39 NeXT */ dgi_u, /* 40 DGI */ maclatin_u, /* 41 Macintosh Latin */ hproman8_u, /* 42 HP Roman 8 */ cp437_u, /* 43 CP437 - Original */ cp850_u, /* 44 CP850 - W Europe */ cp852_u, /* 45 CP852 - E Europe */ cp857_u, /* 46 CP857 - Turkish */ cp862_u, /* 47 CP862 - Hebrew */ cp864_u, /* 48 CP864 - Arabic */ cp866_u, /* 49 CP866 - Cyrillic */ cp869_u, /* 50 CP869 - Greek */ decspec_u, /* 51 DEC Special Graphics */ dectech_u, /* 52 DEC Technical */ c0pics_u, /* 53 C0 Pictures */ c1pics_u, /* 54 C1 Pictures */ smiley_u, /* 55 IBM C0 Graphics */ heath19g_u, /* 56 Heath 19 graphics */ tvig_u, /* 57 TVI graphics */ wyse_gn_u, /* 58 Wyse 60 normal-mode graphics */ wyse_g1_u, /* 59 Wyse 60 graphics 1 */ wyse_g2_u, /* 60 Wyse 60 graphics 2 */ wyse_g3_u, /* 61 Wyse 60 graphics 3 */ elot927_u, /* 62 Greek ELOT 927 */ dgspec_u, /* 63 DG Special graphics */ dgline_u, /* 64 DG Line drawing */ dgword_u, /* 65 DG Word processing */ hpline_u, /* 66 HP Line drawing */ hpmath_u, /* 67 HP Math/Technical */ qnxgrph_u, /* 68 QNX Graphics */ snibrack_u, /* 69 SNI Brackets */ snieuro_u, /* 70 SNI Euro */ snifacet_u, /* 71 SNI Facet */ sniibm_u, /* 72 SNI IBM */ sniblanks_u, /* 73 SNI Blanks */ cp1252_u, /* 74 Windows Latin-1 */ cp1250_u, /* 75 Windows Latin-2 */ cp1251_u, /* 76 Windows Cyrillic */ cp1253_u, /* 77 Windows Greek */ cp1254_u, /* 78 Windows Turkish */ cp1257_u, /* 79 Windows Latin-4 */ cp856_u, /* 80 Cyrillic PC Code Page 856 */ cp855_u, /* 81 Cyrillic PC Code Page 856 */ iso_8859_1_u, /* 82 CP819 - Same as 8859-1 */ iso_8859_2_u, /* 83 CP912 - Same as 8859-2 */ iso_8859_3_u, /* 84 CP913 - Same as 8859-3 */ iso_8859_4_u, /* 85 CP914 - Same as 8859-4 */ iso_8859_5_u, /* 86 CP915 - Same as 8859-5 */ iso_8859_6_u, /* 87 CP1089 - Same as 8859-6 */ iso_8859_7_u, /* 88 CP813 - Same as 8859-7 */ iso_8859_8_u, /* 89 CP916 - Same as 8859-8 */ iso_8859_9_u, /* 90 CP920 - Same as 8859-9 */ hproman8_u, /* 91 CP1051 -Same as HP Roman 8 */ cp858_u, /* 92 CP858 - W Europe w/Euro */ iso_8859_15_u, /* 93 ISO 8859-15 Latin 15 */ iso_8859_15_u, /* 94 CP923 - Same as 8859-15 */ iso_8859_7_u, /* 95 ELOT928 - Same as 8859-7 */ quickdraw_u, /* 96 CP10000 - Apple Quickdraw */ cp37_u, /* 97 CP37 - U.S. EBCDIC */ cp1255_u, /* 98 CP1255 - Windows Hebrew */ cp1256_u, /* 99 CP1256 - Windows Arabic */ cp1258_u, /* 100 CP1258 - Windows Viet Nam */ mazovia_u, /* 101 Mazovia PC code page */ ident_u, /* 102 Transparent - no translation */ hz1500_u, /* 103 Hazeltine 1500/1520 graphics */ koi8r_u, /* 104 KOI8-R */ koi8u_u, /* 105 KOI8-U */ apl1_u, /* 106 APL 1 (ISO) */ apl2_u, /* 107 APL 2 (AIX) */ apl3_u, /* 108 APL 3 (Plus) */ apl4_u, /* 109 APL 4 (IBM) */ apl5_u /* 110 APL 5 (2741) */ }; /* Table of Unicode-to-Blah translation functions. KEEP THIS IN SYNC WITH THE TX_blah DEFINITITIONS in ckcuni.h, and also with the tables above. */ int #ifdef CK_ANSIC (*xl_tx[MAXTXSETS+1])(USHORT) #else (*xl_tx[MAXTXSETS+1])() #endif /* CK_ANSIC */ = { tx_usascii, /* 0 US ISO 646 (ASCII) */ tx_british, /* 1 UK ISO 646 */ tx_fr_canadian, /* 2 Canadian French NRC */ NULL, /* 3 Cuba */ NULL, /* 4 Czecho */ tx_danish, /* 5 Danish/Norwegian ISO 646 */ tx_dutch, /* 6 Dutch NRC */ tx_finnish, /* 7 Finnish NRC */ tx_french, /* 8 French ISO 646 */ tx_german, /* 9 German ISO 646 */ tx_hebrew7, /* 10 Hebrew-7 (DEC) */ tx_hungarian, /* 11 Hungarian ISO 646 */ tx_icelandic, /* 12 Icelandic */ tx_italian, /* 13 Italian ISO 646 */ tx_jis0201r, /* 14 Japanese Roman ISO 646 */ tx_jis0201k, /* 15 Japanese Katakana */ tx_koi7, /* 16 Short KOI */ tx_danish, /* 17 Norwegian/Danish ISO 646 */ tx_portuguese, /* 18 Portuguese ISO 646 */ tx_spanish, /* 19 spanish ISO 646 */ tx_swedish, /* 20 Swedish ISO 646 */ NULL, /* 21 Swedish ISO 646 for names */ tx_swiss, /* 22 Swiss NRC */ tx_ident, /* 23 ISO 8859-1 */ tx_8859_2, /* 24 ISO 8859-2 */ tx_8859_3, /* 25 ISO 8859-3 */ tx_8859_4, /* 26 ISO 8859-4 */ tx_8859_5, /* 27 ISO 8859-5 */ /* Cyrillic */ tx_8859_6, /* 28 ISO 8859-6 */ /* Arabic */ tx_8859_7, /* 29 ISO 8859-7 */ /* Greek */ tx_8859_8, /* 30 ISO 8859-8 */ /* Hebrew */ tx_8859_9, /* 31 ISO 8859-9 */ /* Latin-5 */ tx_8859_10, /* 32 ISO 8859-10 */ /* Latin-6 */ tx_koi8, /* 33 KOI-8 */ NULL, /* 34 JIS-7 */ NULL, /* 35 Shift JIS */ NULL, /* 36 Japanese EUC (JAE) */ NULL, /* 37 Japanese DEC Kanji */ tx_decmcs, /* 38 DEC MCS */ tx_nextstep, /* 39 NeXT */ tx_dgi, /* 40 DGI */ tx_maclatin, /* 41 Macintosh Latin */ tx_hproman8, /* 42 HP Roman 8 */ tx_cp437, /* 43 CP437 - Original */ tx_cp850, /* 44 CP850 - W Europe */ tx_cp852, /* 45 CP852 - E Europe */ tx_cp857, /* 46 CP857 - Turkish */ tx_cp862, /* 47 CP862 - Hebrew */ tx_cp866, /* 48 CP864 - Arabic */ tx_cp866, /* 49 CP866 - Cyrillic */ tx_cp869, /* 50 CP869 - Greek */ NULL, /* Display only */ /* 51 DEC Special Graphics */ NULL, /* Display only */ /* 52 DEC Technical */ NULL, /* Display only */ /* 53 C0 Pictures */ NULL, /* Display only */ /* 54 C1 Pictures */ NULL, /* Display only */ /* 55 IBM C0 Graphics */ NULL, /* Display only */ /* 56 Heath 19 graphics */ NULL, /* Display only */ /* 57 TVI graphics */ NULL, /* Display only */ /* 58 Wyse 60 normal-mode graphics */ NULL, /* Display only */ /* 59 Wyse 60 graphics 1 */ NULL, /* Display only */ /* 60 Wyse 60 graphics 2 */ NULL, /* Display only */ /* 61 Wyse 60 graphics 3 */ tx_elot927, /* 62 Greek ELOT 927 */ NULL, /* Display only */ /* 63 DG special graphics */ NULL, /* Display only */ /* 64 DG line-drawing */ NULL, /* Display only */ /* 65 DG word-processing */ NULL, /* Display only */ /* 66 HP line-drawing */ NULL, /* Display only */ /* 67 HP math/techical */ NULL, /* Display only */ /* 68 QNX Graphics */ NULL, /* Display only */ /* 69 SNI Brackets */ NULL, /* Display only */ /* 70 SNI Euro */ NULL, /* Display only */ /* 71 SNI Facet */ NULL, /* Display only */ /* 72 SNI IBM */ NULL, /* Display only */ /* 73 SNI Blanks */ tx_cp1252, /* 74 Windows Latin-1 */ tx_cp1250, /* 75 Windows Latin-2 */ tx_cp1251, /* 76 Windows Cyrillic */ tx_cp1253, /* 77 Windows Greek */ tx_cp1254, /* 78 Windows Turkish */ tx_cp1257, /* 79 Windows Latin-4 */ tx_cp856, /* 80 Cyrillic PC Code Page 856 */ tx_cp855, /* 81 Cyrillic PC Code Page 855 */ tx_ident, /* 82 CP819 - Same as 8859-1 */ tx_8859_2, /* 83 CP912 - Same as 8859-2 */ tx_8859_3, /* 84 CP913 - Same as 8859-3 */ tx_8859_4, /* 85 CP914 - Same as 8859-4 */ tx_8859_5, /* 86 CP915 - Same as 8859-5 */ tx_8859_6, /* 87 CP1089 - Same as 8859-6 */ tx_8859_7, /* 88 CP813 - Same as 8859-7 */ tx_8859_8, /* 89 CP916 - Same as 8859-8 */ tx_8859_9, /* 90 CP920 - Same as 8859-9 */ tx_hproman8, /* 91 CP1051 -Same as HP Roman 8 */ tx_cp858, /* 92 CP858 - W Europe w/Euro */ tx_8859_15, /* 93 ISO 8859-15 Latin 15 */ tx_8859_15, /* 94 CP923 - Same as Latin 15 */ tx_8859_7, /* 95 ELOT928 - Same as 8859-7 */ tx_quickdraw, /* 96 CP10000 - Apple Quickdraw */ tx_cp37, /* 97 CP37 - U.S. EBCDIC */ tx_cp1255, /* 98 CP1255 - Windows Hebrew */ tx_cp1256, /* 99 CP1256 - Windows Arabic */ tx_cp1258, /* 100 CP1258 - Windows Viet Nam */ tx_mazovia, /* 101 Mazovia PC code page */ tx_ident, /* 102 Transparent - no translation */ NULL, /* Display only */ /* 103 Hazeltine 1500/1520 graphics */ tx_koi8r, /* 104 KOI8-R */ tx_koi8u, /* 105 KOI8-U */ tx_apl1, /* 106 APL 1 (ISO) */ tx_apl2, /* 107 APL 2 (AIX) */ tx_apl3, /* 108 APL 3 (Plus) */ tx_apl4, /* 108 APL 4 (IBM) */ tx_apl5 /* 110 APL 5 (2741) */ }; /* Table of FCS-to-Unicode translation functions. KEEP THIS IN SYNC WITH THE FC_blah DEFINITITIONS in ckuxla.h. */ USHORT #ifdef CK_ANSIC (*xl_fcu[MAXFCSETS+1])(CHAR) #else (*xl_fcu[MAXFCSETS+1])() #endif /* CK_ANSIC */ = { ascii_u, /* 0 US ISO 646 (ASCII) */ british_u, /* 1 UK ISO 646 */ dutch_u, /* 2 Dutch NRC */ finnish_u, /* 3 Finnish NRC */ french_u, /* 4 French ISO 646 */ fr_canadian_u, /* 5 Canadian French NRC */ german_u, /* 6 German ISO 646 */ hungarian_u, /* 7 Hungarian ISO 646 */ italian_u, /* 8 Italian ISO 646 */ danish_u, /* 9 Danish/Norwegian ISO 646 */ portuguese_u, /* 10 Portuguese ISO 646 */ spanish_u, /* 11 spanish ISO 646 */ swedish_u, /* 12 Swedish ISO 646 */ swiss_u, /* 13 Swiss NRC */ iso_8859_1_u, /* 14 ISO 8859-1 Latin-1 */ iso_8859_2_u, /* 15 ISO 8859-2 Latin-2 */ decmcs_u, /* 16 DEC MCS */ nextstep_u, /* 17 NeXT */ cp437_u, /* 18 CP437 - Original */ cp850_u, /* 19 CP850 - W Europe */ cp852_u, /* 20 CP852 - E Europe */ quickdraw_u, /* 21 CP10000 - Apple Quickdraw */ dgi_u, /* 22 DGI */ hproman8_u, /* 23 HP Roman 8 */ iso_8859_5_u, /* 24 ISO 8859-5 Cyrillic */ cp866_u, /* 25 CP866 - Cyrillic */ koi7_u, /* 26 Short KOI */ koi8_u, /* 27 KOI-8 */ NULL, /* 28 JIS-7 */ NULL, /* 29 Shift-JIS */ NULL, /* 30 Japanese EUC */ NULL, /* 31 DEC Kanji */ hebrew7_u, /* 32 Hebrew-7 (DEC) */ iso_8859_8_u, /* 33 ISO 8859-8 Hebrew */ cp862_u, /* 34 CP862 Hebrew */ elot927_u, /* 35 Greek ELOT 927 */ iso_8859_7_u, /* 36 ISO 8859-7 Greek */ cp869_u, /* 37 CP869 Greek */ iso_8859_15_u, /* 38 ISO 8859-15 Latin-9 */ cp858_u, /* 39 CP858 - W Europe w/Euro */ cp855_u, /* 40 Cyrillic PC Code Page 856 */ cp1251_u, /* 41 Windows Cyrillic */ cp856_u, /* 42 Bulgarian PC Code Page 856 */ cp1250_u, /* 43 Windows Latin-2 */ mazovia_u, /* 44 Mazovia PC code page */ NULL, /* 45 UCS-2 */ NULL, /* 46 UTF-8 */ koi8r_u, /* 47 KOI8-R */ koi8u_u, /* 48 KOI8-U */ cp1252_u /* 49 CP1252 */ }; /* Table of Unicode-to-FCS translation functions. KEEP THIS IN SYNC WITH THE FC_blah DEFINITITIONS in ckuxla.h. */ int #ifdef CK_ANSIC (*xl_ufc[MAXFCSETS+1])(USHORT) #else (*xl_ufc[MAXFCSETS+1])() #endif /* CK_ANSIC */ = { tx_usascii, /* 0 US ISO 646 (ASCII) */ tx_british, /* 1 UK ISO 646 */ tx_dutch, /* 2 Dutch NRC */ tx_finnish, /* 3 Finnish NRC */ tx_french, /* 4 French ISO 646 */ tx_fr_canadian, /* 5 Canadian French NRC */ tx_german, /* 6 German ISO 646 */ tx_hungarian, /* 7 Hungarian ISO 646 */ tx_italian, /* 8 Italian ISO 646 */ tx_danish, /* 9 Danish/Norwegian ISO 646 */ tx_portuguese, /* 10 Portuguese ISO 646 */ tx_spanish, /* 11 spanish ISO 646 */ tx_swedish, /* 12 Swedish ISO 646 */ tx_swiss, /* 13 Swiss NRC */ tx_ident, /* 14 ISO 8859-1 Latin-1 */ tx_8859_2, /* 15 ISO 8859-2 Latin-2 */ tx_decmcs, /* 16 DEC MCS */ tx_nextstep, /* 17 NeXT */ tx_cp437, /* 18 CP437 - Original */ tx_cp850, /* 19 CP850 - W Europe */ tx_cp852, /* 20 CP852 - E Europe */ tx_quickdraw, /* 21 CP10000 - Apple Quickdraw */ tx_dgi, /* 22 DGI */ tx_hproman8, /* 23 HP Roman 8 */ tx_8859_5, /* 24 ISO 8859-5 Cyrillic */ tx_cp866, /* 25 CP866 - Cyrillic */ tx_koi7, /* 26 Short KOI */ tx_koi8, /* 27 KOI-8 */ NULL, /* 28 JIS-7 */ NULL, /* 29 Shift-JIS */ NULL, /* 30 Japanese EUC */ NULL, /* 31 DEC Kanji */ tx_hebrew7, /* 32 Hebrew-7 (DEC) */ tx_8859_8, /* 33 ISO 8859-8 Hebrew */ tx_cp862, /* 34 CP862 Hebrew */ tx_elot927, /* 35 Greek ELOT 927 */ tx_8859_7, /* 36 ISO 8859-7 Greek */ tx_cp869, /* 37 CP869 Greek */ tx_8859_15, /* 38 ISO 8859-15 Latin-9 */ tx_cp858, /* 39 CP858 - W Europe w/Euro */ tx_cp855, /* 40 Cyrillic PC Code Page 856 */ tx_cp1251, /* 41 Windows Cyrillic */ tx_cp856, /* 42 Bulgarian PC Code Page 856 */ tx_cp1250, /* 43 Windows Latin-2 */ tx_mazovia, /* 44 Mazovia PC code page */ NULL, /* 45 UCS-2 */ NULL, /* 46 UTF-8 */ tx_koi8r, /* 47 KOI8-R */ tx_koi8u, /* 48 KOI8-U */ tx_cp1252 /* 49 CP1252 */ }; /* Table of TCS-to-Unicode translation functions. KEEP THIS IN SYNC WITH THE TC_blah DEFINITIONS in ckuxla.h. */ USHORT #ifdef CK_ANSIC (*xl_tcu[MAXTCSETS+1])(CHAR) #else (*xl_tcu[MAXTCSETS+1])() #endif /* CK_ANSIC */ = { NULL, /* 0 = Transparent */ ascii_u, /* 1 = ASCII */ iso_8859_1_u, /* 2 ISO 8859-1 Latin-1 */ iso_8859_2_u, /* 3 ISO 8859-2 Latin-2 */ iso_8859_5_u, /* 4 ISO 8859-5 Cyrillic */ NULL, /* 5 Japanese EUC */ iso_8859_8_u, /* 6 ISO 8859-8 Hebrew */ iso_8859_7_u, /* 7 ISO 8859-7 Greek */ iso_8859_15_u, /* 8 ISO 8859-15 Latin-9 */ NULL, /* 9 UCS-2 */ NULL /* 10 UTF-8 */ }; /* Table of Unicode-to-TCS translation functions. KEEP THIS IN SYNC WITH THE TC_blah DEFINITIONS in ckuxla.h. */ int #ifdef CK_ANSIC (*xl_utc[MAXTCSETS+1])(USHORT) #else (*xl_utc[MAXTCSETS+1])() #endif /* CK_ANSIC */ = { NULL, /* 0 = Transparent */ tx_usascii, /* 1 = ASCII */ tx_ident, /* 2 ISO 8859-1 Latin-1 */ tx_8859_2, /* 3 ISO 8859-2 Latin-2 */ tx_8859_5, /* 4 ISO 8859-5 Cyrillic */ NULL, /* 5 Japanese EUC */ tx_8859_8, /* 6 ISO 8859-8 Hebrew */ tx_8859_7, /* 7 ISO 8859-7 Greek */ tx_8859_15, /* 8 ISO 8859-15 Latin-9 */ NULL, /* 9 UCS-2 */ NULL /* 10 UTF-8 */ }; #ifdef COMMENT /* The UTF8 conversions are based on the ConvertUTF functions written by Mark E. Davis, copyright 1994 Taligent, Inc. Tables for use in calculating UTF8 conversions. These contain support for ISO-10646 which supports a 31-bit char size. NOTE: 0xnnnUL is NOT portable! */ ULONG offsetsFromUTF8[7] = { #ifdef CK_ANSIC 0x00000000UL, /* Ignored */ 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL #else 0x00000000L, /* Ignored */ 0x00000000L, 0x00003080L, 0x000E2080L, 0x03C82080L, (unsigned) 0xFA082080L, (unsigned) 0x82082080L #endif /* CK_ANSIC */ }; CHAR bytesInUTF8[256] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6 }; #endif /* COMMENT */ CHAR firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC}; /* utf8_to_ucs2() takes one UTF-8 byte at a time. It returns a pointer the UCS-2 character if and only if the entire UTF-8 string has been received. Return values: 0: Complete UTF-8 sequence received; ucs2 points to valid ucs2 character. >0: UTF-8 sequence incomplete, ignore ucs2 value. <0: UTF-8 error, 0xfffd should be inserted BEFORE the ucs2 value. NOTE: A negative value is returned only when two return values are indicated, e.g. when a UTF-8 sequence is interrupted by an ASCII char. In this case the incomplete UTF-8 sequence must be replaced by 0xfffd, and then the ASCII character is kept as-is. In other error cases, ucs2 is set to 0xfffd and the return value is 0. */ #define UTFBUFSIZ 16 int #ifdef CK_ANSIC utf8_to_ucs2(CHAR ch, USHORT ** ucs2) #else utf8_to_ucs2(ch, ucs2) CHAR ch; USHORT ** ucs2; #endif /* CK_ANSIC */ { static USHORT ucs2return = 0; #ifdef COMMENT /* Unicode Consortium sample code works only with well-formed UTF8 */ int i = 0; static int len = 0; static CHAR utf8[UTFBUFSIZ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; ULONG ucs4 = 0; utf8[len++] = ch; /* Add char to string to process */ if (len < bytesInUTF8[utf8[0]]) /* Need more bytes */ return(bytesInUTF8[utf8[0]] - len); switch (len) { /* Have complete sequence... */ case 6: ucs4 += utf8[i++]; ucs4 <<= 6; /* (fall-thru is intentional) */ case 5: ucs4 += utf8[i++]; ucs4 <<= 6; case 4: ucs4 += utf8[i++]; ucs4 <<= 6; case 3: ucs4 += utf8[i++]; ucs4 <<= 6; case 2: ucs4 += utf8[i++]; ucs4 <<= 6; case 1: ucs4 += utf8[i++]; } ucs4 -= offsetsFromUTF8[len]; ucs2return = (USHORT)(ucs4 & 0xFFFF); #ifdef DEBUG /* This shows that our return value is in the prevailing byte order: */ /* e.g. LE on PC, BE on Sparc. */ if (deblog) { char buf[16]; union ck_short xx; xx.x_short = ucs2return; sprintf(buf,"%04X",ucs2return); debug(F111,"utf8_to_ucs2 short",buf,ucs2return); debug(F101,"utf8_to_ucs2 char[0]","",xx.x_char[0]); debug(F101,"utf8_to_ucs2 char[1]","",xx.x_char[1]); } #endif /* DEBUG */ *ucs2 = &ucs2return; len = 0; return(0); #else /* Robuster code adapted from Thomas Dickey, Xfree86, recommended by Markus Kuhn. */ static int utfcount = 0; /* Position in UTF sequence */ int utferror = 0; /* Flag for malformed UTF */ unsigned c = ch; /* Input byte */ int haveucs2 = 0; if (ch < 0x80) { /* ASCII char... */ if (utfcount > 0) /* Not legal in UTF-8 sequence */ utferror = 1; /* so flag */ haveucs2 = 1; ucs2return = ch; /* but also return it */ utfcount = 0; /* reset UTF-8 count */ } else if (ch < 0xc0) { /* 0x80 <= c < 0xc0... */ if (utfcount < 1) { /* Not valid in first position... */ utferror = 1; } else { /* Maybe valid */ if (ucs2return > 0x03ff) { /* Value would be > 0xffff */ utferror = 1; /* so not valid */ } else { /* OK... */ ucs2return <<= 6; /* Shift result */ ucs2return |= (ch & 0x3f); /* and OR in this byte */ } if (--utfcount == 0) haveucs2 = 1; } } else { /* c >= 0xc0... */ if (utfcount > 0) utferror = 1; if (c < 0xe0) { utfcount = 1; ucs2return = (c & 0x1f); haveucs2 = 1; } else if (c < 0xf0) { utfcount = 2; ucs2return = (c & 0x0f); haveucs2 = 1; } else if (c < 0xf8) { utfcount = 3; ucs2return = (c & 0x07); haveucs2 = 1; } else if (c < 0xfc) { utfcount = 4; ucs2return = (c & 0x03); haveucs2 = 1; } else if (c < 0xfe) { utfcount = 5; ucs2return = (c & 0x01); haveucs2 = 1; } else { utferror = 1; utfcount = 0; } } if (haveucs2 == 0 && utferror != 0) { haveucs2 = 1; ucs2return = 0xfffd; utferror = 0; } if (haveucs2) { *ucs2 = &ucs2return; if (utferror) utfcount = 0 - utfcount; return(utfcount); } else { if (utfcount == 0) utfcount++; return(utfcount); } #endif /* COMMENT */ } /* ucs2_to_utf8() takes one ucs2 character and returns the length and and a pointer to an array containing the equivalent utf8 string. This code can easily be altered to support UCS4 simply by changing the input from USHORT to ULONG. Returns: >0: Number of bytes in the utf8 string. 0: (or less) Error. */ int #ifdef CK_ANSIC ucs2_to_utf8(USHORT ucs2, CHAR ** utf8) #else ucs2_to_utf8(ucs2, utf8) USHORT ucs2; CHAR ** utf8; #endif /* CK_ANSIC */ { static CHAR utf8return[8]={0,0,0,0,0,0,0,0}; register CONST ULONG byteMask = 0xBF; register CONST ULONG byteMark = 0x80; int utf8len = 0; int i = 0; if (ucs2 < 0x80) { utf8len = 1; debug(F101,"ucs2_to_utf8 X1","",utf8len); } else if (ucs2 < 0x800) { utf8len = 2; debug(F101,"ucs2_to_utf8 X2","",utf8len); } else #ifdef DO_UCS4 /* This is always true for UCS-2 but would be needed for UCS-4*/ /* When ucs2 is USHORT this gives compiler warnings. */ if (ucs2 <= 0xffff) #endif /* DO_UCS4 */ { utf8len = 3; debug(F101,"ucs2_to_utf8 X3","",utf8len); } #ifdef DO_UCS4 /* The following would be for UCS-4 */ else if (ucs2 < 0x200000) { utf8len = 4; } else if (ucs2 < 0x4000000) { utf8len = 5; } else if (ucs2 <= #ifdef CK_ANSIC 0x7FFFFFFFUL /* (doesn't really need the "U") */ #else 0x7FFFFFFFL #endif /* CK_ANSIC */ ) { /* 31 bits = max for UCS4 */ utf8len = 6; } else { utf8len = 2; ucs2 = 0xFFFD; /* Replacement for invalid char */ } #endif /* DO_UCS4 */ i = utf8len; /* index into utf8return */ utf8return[i--] = 0; /* Null terminate the string */ switch (utf8len) { /* code falls through cases! */ case 6: utf8return[i--] = (ucs2 | byteMark) & byteMask; ucs2 >>= 6; case 5: utf8return[i--] = (ucs2 | byteMark) & byteMask; ucs2 >>= 6; case 4: utf8return[i--] = (ucs2 | byteMark) & byteMask; ucs2 >>= 6; case 3: utf8return[i--] = (ucs2 | byteMark) & byteMask; ucs2 >>= 6; case 2: utf8return[i--] = (ucs2 | byteMark) & byteMask; ucs2 >>= 6; case 1: utf8return[i--] = ucs2 | firstByteMark[utf8len]; } debug(F111,"ucs2_to_utf8",utf8return,utf8len); *utf8 = utf8return; return(utf8len); } /* UTF-8 functions... */ #ifdef CK_ANSIC extern int (*xuf)(USHORT); /* Translation function UCS to FCS */ extern USHORT (*xfu)(CHAR); /* Translation function FCS to UCS */ #else extern int (*xuf)(); extern USHORT (*xfu)(); #endif /* CK_ANSIC */ /* u _ t o _ b -- UTF-8 to Byte */ /* Converts from UTF-8 to the current terminal or file character set. Call with: c: a single byte, which is part of a UTF-8 stream. Returns: -9: Error, with second char to follow (call u_to_b2() to get it). -2: UCS line/paragraph end (LS or PS). -1: UTF-8 stream is incomplete and more input is required. >=0: Byte value of result, possibly the "error" byte (e.g. '?'). Requires: Global (*xuf)() to point to a function that translates from UCS-2 to the appropriate term/file character set. */ static int savedbyte = 0; int /* Call if u_to_b() returns -9 */ u_to_b2() { return((unsigned)(savedbyte & 0xff)); } int /* UTF-8 to byte */ #ifdef CK_ANSIC u_to_b(CHAR c) #else u_to_b(c) CHAR c; #endif /* CK_ANSIC */ { int x; USHORT * ucs2, uc; if (!xuf) /* If no conversion function */ return(c); /* don't convert (shouldn't happen). */ x = utf8_to_ucs2(c,&ucs2); /* Send for conversion to UCS-2 */ if (x > 0) /* Not done yet... */ return(-1); uc = (x < 0) ? 0xfffd : *ucs2; /* Done, check result */ if (uc == 0x2028 || uc == 0x2029) /* LS or PS */ return(-2); return((unsigned)(((*xuf)(uc)) & 0xff)); /* Convert UCS-2 to byte */ } /* b _ t o _ u -- Byte to UTF-8 */ /* Converts a byte from the current terminal or file character set to UTF-8. Call with: c........ The byte to be converted. buf...... Pointer to buffer in which to place the result. buflen... Length of the result buffer. setsize.. The size of the source character set (128 or 256). Requires: Global (*xfu)() to point to the function to convert the byte to UCS-2. Returns: -1 if the xfu is NULL; otherwise: >0 indicating the length (in bytes) of the UTF-8 string. If the translation fails, the Unicode "Replacement Character" is returned (0xFFFD translated to UTF-8 == 0xFFBD). */ int /* Byte to UTF-8 */ #ifdef CK_ANSIC b_to_u(CHAR c, CHAR * buf, int buflen, int setsize) #else b_to_u(c, buf, buflen, setsize) CHAR c, * buf; int buflen, setsize; #endif /* CK_ANSIC */ { CHAR * tmp = NULL; int i, count = 0; USHORT uc; if (!xfu) { debug(F100,"b_to_u no xfu","",0); return(-1); } uc = c; if (((setsize > 128) && (c & 0x80)) || setsize <= 128) { if (xfu) /* FCS-to-UCS function */ uc = (*xfu)(c); } count = ucs2_to_utf8(uc,&tmp); if (count < 0) { buf[0] = 0xef; /* == 0xFFFD in UTF-8 */ buf[1] = 0xbf; buf[2] = 0xbd; buf[3] = '\0'; return(2); } if (count >= buflen) { debug(F101,"WARNING: UTF8 buffer overflow","",count); count = buflen - 1; } for (i = 0; i < count; i++) /* Copy to result buffer */ buf[i] = tmp[i]; buf[i] = '\0'; return(count); } #ifndef OS2 int ck_isunicode( /* Tells whether the host we are */ #ifdef CK_ANSIC /* running on supports Unicode */ void /* display */ #endif /* CK_ANSIC */ ) { #ifdef NT extern int tt_unicode; #ifdef KUI return(tt_unicode); #else /* KUI */ if (tt_unicode && !isWin95()) return(1); else return(0); #endif /* KUI */ #else /* NT */ return(0); #endif /* NT */ } #endif /* OS2 */ #endif /* UNICODE */ ckcuni.h000664 045065 024037 00000025655 14767402002 012627 0ustar00fdckermit000000 000000 /* C K C U N I . H -- Unicode/Terminal character-set translations */ /* Copyright (C) 1999, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Authors: Frank da Cruz The Kermit Project, New York City. Jeffrey E Altman Secure Endpoints Inc., New York City Most recent update: Fri May 5 16:25:43 2023 */ /* Terminal character sets */ #ifndef CKOUNI_H #define CKOUNI_H #ifdef OS2 #ifndef CKOUNI #define CKOUNI /* Use UNICODE for OS/2 functions */ #endif /* CKOUNI */ #ifdef KUI #define X_CKOUNI_IN /* Use Unicode Input */ #define CKOUNI_OUT #endif /* KUI */ #endif /* OS2 */ /* Terminal Character Sets */ #define TX_ASCII 0 /* US ASCII */ #define TX_BRITISH 1 /* British ISO 646 */ #define TX_CN_FRENCH 2 /* Canadian French NRC */ #define TX_CUBAN 3 /* Cuba */ #define TX_CZECH 4 /* Czech Republic */ #define TX_DANISH 5 /* Denmark / Norway ISO 646 */ #define TX_DUTCH 6 /* Dutch NRC */ #define TX_FINNISH 7 /* Finnish NRC */ #define TX_FRENCH 8 /* French ISO 646 */ #define TX_GERMAN 9 /* German ISO 646 */ #define TX_HE7 10 /* Hebrew 7 (DEC) */ #define TX_HUNGARIAN 11 /* Hungarian ISO 646 */ #define TX_ICELANDIC 12 /* Icelandic NRC */ #define TX_ITALIAN 13 /* Italian ISO 646 */ #define TX_J201R 14 /* JIS 0201 Japanese Roman */ #define TX_J201K 15 /* JIS 0201 Katakana */ #define TX_KOI7 16 /* Short KOI */ #define TX_NORWEGIAN 17 /* Denmark / Norway ISO 646 */ #define TX_PORTUGUESE 18 /* Portuguese ISO 646 */ #define TX_SPANISH 19 /* Spanish ISO 646 */ #define TX_SWEDISH 20 /* Swedish ISO 646 */ #define TX_SWE_2 21 /* Swedish for names ISO 646 */ #define TX_SWISS 22 /* Swiss NRC */ #define TX_8859_1 23 /* Latin-1 */ #define TX_8859_2 24 /* Latin-2 */ #define TX_8859_3 25 /* Latin-3 */ #define TX_8859_4 26 /* Latin-4 */ #define TX_8859_5 27 /* Latin/Cyrillic */ #define TX_8859_6 28 /* Latin/Arabic */ #define TX_8859_7 29 /* Latin/Greek */ #define TX_8859_8 30 /* Latin/Hebrew */ #define TX_8859_9 31 /* Latin-5 */ #define TX_8859_10 32 /* Latin-6 */ #define TX_KOI8 33 /* GOST 19768-74 KOI-8 */ #define TX_JIS7 34 /* JIS-7 */ #define TX_SHJIS 35 /* Shift JIS */ #define TX_JEUC 36 /* Japanese EUC */ #define TX_JDEC 37 /* Japanese DEC Kanji */ #define TX_DECMCS 38 /* DEC MCS */ #define TX_NEXT 39 /* NeXT */ #define TX_DGI 40 /* Data General International */ #define TX_MACL1 41 /* Macintosh Latin-1 */ #define TX_HPR8 42 /* HP Roman 8 */ /* Code pages */ #define TX_CP437 43 /* Original */ #define TX_CP850 44 /* Multinational (Western Europe) */ #define TX_CP852 45 /* Eastern Europe */ #define TX_CP857 46 /* Turkey */ #define TX_CP862 47 /* Hebrew */ #define TX_CP864 48 /* Arabic */ #define TX_CP866 49 /* Cyrillic */ #define TX_CP869 50 /* Greek */ #define TX_DECSPEC 51 /* DEC Special Graphics */ #define TX_DECTECH 52 /* DEC Technical */ #define TX_C0PICT 53 /* C0 Display Controls */ #define TX_C1PICT 54 /* C1 Display Controls */ #define TX_IBMC0GRPH 55 /* IBM C0 Graphics (smileys) */ #define TX_H19GRAPH 56 /* Heath/Zenith 19 Graphics */ #define TX_TVIGRAPH 57 /* Televideo Graphics */ #define TX_WYSE60G_N 58 /* Wyse 60 Native Mode Graphics */ #define TX_WYSE60G_1 59 /* Wyse 60 Graphics 1 */ #define TX_WYSE60G_2 60 /* Wyse 60 Graphics 2 */ #define TX_WYSE60G_3 61 /* Wyse 60 Graphics 3 */ /* New ones that came too late for the nice grouping... */ #define TX_ELOT927 62 /* Greek ELOT 927 */ #define TX_DGPCGRPH 63 /* DG PC Graphics */ #define TX_DGLDGRPH 64 /* DG Line Drawing Graphics */ #define TX_DGWPGRPH 65 /* DG Word Processing (etc) Graphics */ #define TX_HPLINE 66 /* HP Line Drawing */ #define TX_HPMATH 67 /* HP Math/Technical */ #define TX_QNXGRPH 68 /* QNX Graphics */ /* Siemens Nixdorf character sets */ #define TX_SNIBRACK 69 /* SNI 97801 Brackets */ #define TX_SNIEURO 70 /* SNI 97801 Euro */ #define TX_SNIFACET 71 /* SNI 97801 Facet */ #define TX_SNIIBM 72 /* SNI 97801 "IBM" */ #define TX_SNIBLANK 73 /* SNI 97801 Blanks */ /* Windows Code pages */ #define TX_CP1252 74 /* Latin-1 Windows */ #define TX_CP1250 75 /* Latin-2 Windows */ #define TX_CP1251 76 /* Cyrillic Windows */ #define TX_CP1253 77 /* Greece Windows */ #define TX_CP1254 78 /* Turkey Windows */ #define TX_CP1257 79 /* Latin-4 Windows */ #define TX_CP856 80 /* Bulgaria CP856 (DATECS Ltd) */ #define TX_CP855 81 #define TX_CP819 82 /* Same as ISO 8859-1 */ #define TX_CP912 83 /* Same as ISO 8859-2 */ #define TX_CP913 84 /* Same as ISO 8859-3 */ #define TX_CP914 85 /* Same as ISO 8859-4 */ #define TX_CP915 86 /* Same as ISO 8859-5 */ #define TX_CP1089 87 /* Same as ISO 8859-6 */ #define TX_CP813 88 /* Same as ISO 8859-7 */ #define TX_CP916 89 /* Same as ISO 8859-8 */ #define TX_CP920 90 /* Same as ISO 8859-9 */ #define TX_CP1051 91 /* Same as HP Roman 8 */ #define TX_CP858 92 /* Multinational (W. Europe) w/Euro */ #define TX_8859_15 93 /* Latin-9 */ #define TX_CP923 94 /* Same as ISO 8859-15 */ #define TX_ELOT928 95 /* Same as ISO 8859-7 */ #define TX_CP10000 96 /* Same as original Apple Quickdraw */ #define TX_CP37 97 /* EBCDIC */ #define TX_CP1255 98 /* Israel Windows */ #define TX_CP1256 99 /* Arabic Windows */ #define TX_CP1258 100 /* Viet Nam Windows */ #define TX_MAZOVIA 101 #define TX_TRANSP 102 /* Transparent - no translation */ #define TX_HZ1500 103 /* Hazeltine 1500 graphics set */ #define TX_KOI8R 104 /* KOI8R - Russian */ #define TX_KOI8U 105 /* KOI8U - Ukrainian */ #define TX_APL1 106 /* APL ISO IR 68 */ #define TX_APL2 107 /* Dyadic Systems Inc APL */ #define TX_APL3 108 /* APL-Plus (APL-2000) */ #define TX_APL4 109 /* IBM APL/2 */ #define TX_APL5 110 /* APL-2741 */ #define MAXTXSETS 111 /* Number of terminal character sets */ /* The following are not implemented yet */ /* UTF-8 is supported as a special mode in Kermit 95 (see utf8 flag) */ #define TX_UTF7 128 #define TX_UTF8 129 #define TX_HEXBYTES 242 /* Hex bytes */ #define TX_DEBUG 243 /* Debugging but not hex bytes */ /* These are actually used */ #define TX_UNDEF 255 /* Unknown character-set */ /* Flag bit values */ #define X2U_STD 1 /* Has standard ISO 4873 layout */ #define X2U_ISO 2 /* ISO standard character set */ #define X2U_JIS 4 /* Japan Industrial Standard */ #define X2U_CP 8 /* PC Code Page */ #define X2U_DEC 16 /* DEC Private character set */ #define X2U_CXG 32 /* Control codes used for graphics */ struct x_to_unicode { int size; /* 94, 96, 128, or other */ int offset; /* 0, 32, 33, 128, 160, ... */ int flags; int family; /* Language family, writing system */ char * keywd; /* Keyword name */ char * name; /* Descriptive name */ int code; /* ISO reg number if Standard */ /* CP number if Code-page, etc. */ char * final; /* Esc seq final char(s) (ISO, DEC) */ unsigned short map[256]; /* Mapping table */ }; extern struct keytab txrtab[]; extern int ntxrtab; #ifndef NULL #define NULL (char *)0 #endif /* NULL */ #ifndef USHORT #define USHORT unsigned short #endif /* USHORT */ #ifndef ULONG #define ULONG unsigned long #endif /* ULONG */ #ifndef CHAR #define CHAR unsigned char #endif /* CHAR */ #ifdef CK_ANSIC extern USHORT (*xl_u[MAXTXSETS+1])(CHAR); /* Blah-to-Unicode functions */ extern int (*xl_tx[MAXTXSETS+1])(USHORT); /* Unicode-to-Blah functions */ #else extern USHORT (*xl_u[MAXTXSETS+1])(); extern int (*xl_tx[MAXTXSETS+1])(); #endif /* CK_ANSIC */ extern struct x_to_unicode * txrinfo[MAXTXSETS+1]; #ifndef NT _PROTOTYP(int ck_isunicode, (void)); #endif /* NT */ _PROTOTYP(int utf8_to_ucs2, (CHAR, USHORT **)); _PROTOTYP(int ucs2_to_utf8, (USHORT, CHAR **)); _PROTOTYP(int tx_cpsub, (USHORT)); _PROTOTYP(int u_to_b, (CHAR) ); _PROTOTYP(int u_to_b2, (void) ); _PROTOTYP(int b_to_u, (CHAR, CHAR *, int, int) ); #ifdef KANJI _PROTOTYP(USHORT sj_to_un, (USHORT) ); /* Shift-JIS to Unicode */ _PROTOTYP(USHORT un_to_sj, (USHORT) ); /* Unicode to Shift-JIS */ #endif /* KANJI */ #ifdef OS2 #ifdef NT #ifdef COMMENT _inline #else /* [jt] 2013/11/21 - duplicate definition issue */ static _inline #endif /* COMMENT */ #else #ifdef __WATCOMC__ inline #else _Inline #endif /* __WATCOMC__ */ #endif /* NT */ int ck_isunicode( #ifdef CK_ANSIC void #endif /* CK_ANSIC */ ) { extern int tt_unicode; #ifdef NT #ifdef KUI return(tt_unicode); #else /* KUI */ if (tt_unicode && !isWin95()) return(1); else return(0); #endif /* KUI */ #else /* NT */ return(0); #endif /* NT */ } #endif /* OS2 */ #endif /* CKOUNI_H */ ckcxla.h000664 045065 024037 00000025674 14767402013 012623 0ustar00fdckermit000000 000000 /* File CKCXLA.H System-independent character-set translation header file for C-Kermit. */ /* Author: Frank da Cruz , The Kermit Project - Columbia University, New York City. Copyright (C) 1985, 2009, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ /* NOTE: ISO 204 is Latin-1 + Euro. ISO 205 is Latin-4 + Euro. ISO 206 is Latin-7 + Euro. */ #ifndef CKCXLA_H /* Guard against multiple inclusion */ #define CKCXLA_H #ifndef KANJI /* Systems supporting Kanji */ #ifdef OS2 #define KANJI #endif /* OS2 */ #endif /* KANJI */ #ifdef NOKANJI /* Except if NOKANJI is defined. */ #ifdef KANJI #undef KANJI #endif /* KANJI */ #endif /* NOKANJI */ #ifndef NOUNICODE #ifndef UNICODE /* Unicode support */ #ifdef OS2ORUNIX /* Only for K95, UNIX, VMS,... */ #define UNICODE #else #ifdef VMS #define UNICODE #endif /* VMS */ #endif /* OS2ORUNIX */ #endif /* UNICODE */ #endif /* NOUNICODE */ #define XLA_NONE 0 /* Translation types - none */ #define XLA_BYTE 1 /* Byte-for-byte */ #define XLA_JAPAN 2 /* Japanese */ #define XLA_UNICODE 3 /* Unicode */ #ifndef UNIORKANJI /* Unicode OR Kanji */ #ifdef UNICODE /* i.e. some support for */ #define UNIORKANJI /* multibyte character sets */ #endif /* UNICODE */ #ifdef KANJI #define UNIORKANJI #endif /* KANJI */ #endif /* UNIORKANJI */ /* Disable all support for all classes of character sets if NOCSETS is defined. */ #ifdef NOCSETS #ifdef CKOUNI #undef CKOUNI #endif /* CKOUNI */ #ifdef KANJI #undef KANJI #endif /* KANJI */ #ifdef CYRILLIC #undef CYRILLIC #endif /* CYRILLIC */ #ifdef LATIN2 #undef LATIN2 #endif /* LATIN2 */ #ifdef HEBREW #undef HEBREW #endif /* HEBREW */ #ifdef UNICODE #undef UNICODE #endif /* UNICODE */ #ifndef NOUNICODE #define NOUNICODE #endif /* NOUNICODE */ #else /* Not NOCSETS - Rest of this file... */ #ifdef NOUNICODE /* Unicode */ #ifdef UNICODE #undef UNICODE #endif /* UNICODE */ #endif /* NOUNICODE */ #ifdef UNICODE #ifdef OS2 #ifndef CKOUNI #define CKOUNI /* Special Unicode features for K95 */ #endif /* CKOUNI */ #endif /* OS2 */ #endif /* UNICODE */ #ifndef OS2 #ifdef CKOUNI #undef CKOUNI #endif /* CKOUNI */ #endif /* OS2 */ #ifndef NOLATIN2 /* If they didn't say "no Latin-2" */ #ifndef LATIN2 /* Then if LATIN2 isn't already */ #define LATIN2 /* defined, define it. */ #endif /* LATIN2 */ #endif /* NOLATIN2 */ #ifdef NOCYRILLIC /* (spelling variant...) */ #ifndef NOCYRIL #define NOCYRIL #endif /* NOCYRIL */ #endif /* NOCYRILLIC */ #ifndef NOCYRIL /* If they didn't say "no Cyrillic" */ #ifndef CYRILLIC /* Then if CYRILLIC isn't already */ #define CYRILLIC /* defined, define it. */ #endif /* CYRILLIC */ #endif /* NOCYRIL */ #ifndef NOHEBREW /* If they didn't say "no Hebrew" */ #ifndef HEBREW /* Then if HEBREW isn't already */ #define HEBREW /* defined, define it. */ #endif /* HEBREW */ #endif /* NOHEBREW */ #ifndef NOGREEK /* If not no Greek */ #ifndef GREEK /* then if GREEK isn't already */ #define GREEK /* defined, define it. */ #endif /* GREEK */ #endif /* NOGREEK */ #ifndef NOKANJI /* If not no Kanji */ #ifndef KANJI /* then if KANJI isn't already */ #define KANJI /* defined, define it. */ #endif /* KANJI */ #endif /* NOKANJI */ /* File ckcxla.h -- Character-set-related definitions, system independent */ /* Codes for Kermit Transfer Syntax Level (obsolete) */ #define TS_L0 0 /* Level 0 (Transparent) */ #define TS_L1 1 /* Level 1 (one standard character set) */ #define TS_L2 2 /* Level 2 (multiple character sets in same file) */ #define UNK 63 /* Symbol to use for unknown character (63 = ?) */ /* Codes for the base alphabet of a given character set. These are assigned in roughly ISO 8859 order. (Each is assumed to include ASCII/Roman.) */ #define AL_UNIV 0 /* Universal (like ISO 10646) */ #define AL_ROMAN 1 /* Roman (Latin) alphabet */ #define AL_CYRIL 2 /* Cyrillic alphabet */ #define AL_ARABIC 3 /* Arabic */ #define AL_GREEK 4 /* Greek */ #define AL_HEBREW 5 /* Hebrew */ #define AL_KANA 6 /* Japanese Katakana */ #define AL_JAPAN 7 /* Japanese Katakana+Kanji ideograms */ #define AL_HAN 8 /* Chinese/Japanese/Korean ideograms */ #define AL_INDIA 9 /* Indian scripts (ISCII) */ #define AL_VIET 10 /* Vietnamese (VISCII) */ /* Add more here... */ #define AL_UNK 999 /* Unknown (transparent) */ /* Codes for languages */ /* NOTE: It would perhaps be better to use ISO 639-1988 2-letter "Codes for Representation of Names of Languages" here, shown in the comments below. */ #define L_ASCII 0 /* EN ASCII, English */ #define L_USASCII 0 /* EN ASCII, English */ #define L_DUTCH 1 /* NL Dutch */ #define L_FINNISH 2 /* FI Finnish */ #define L_FRENCH 3 /* FR French */ #define L_GERMAN 4 /* DE German */ #define L_HUNGARIAN 5 /* HU Hungarian */ #define L_ITALIAN 6 /* IT Italian */ #define L_NORWEGIAN 7 /* NO Norwegian */ #define L_PORTUGUESE 8 /* PT Portuguese */ #define L_SPANISH 9 /* ES Spanish */ #define L_SWEDISH 10 /* SV Swedish */ #define L_SWISS 11 /* RM Swiss (Rhaeto-Romance) */ #define L_DANISH 12 /* DA Danish */ #define L_ICELANDIC 13 /* IS Icelandic */ #define L_RUSSIAN 14 /* RU Russian */ #define L_JAPANESE 15 /* JA Japanese */ #define L_HEBREW 16 /* IW Hebrew */ #define L_GREEK 17 /* Greek */ #define MAXLANG 17 /* Number of languages */ /* File character-sets are defined in the system-specific ck?xla.h file, except for the following ones, which must be available to all versions: */ #define FC_TRANSP 254 /* Transparent */ #define FC_UNDEF 255 /* Undefined */ /* Designators for Kermit's transfer character sets. These are all standard sets, or based on them. Symbols must be unique in the first 8 characters, because some C preprocessors have this limit. */ /* LIST1 */ #define TC_TRANSP 0 /* Transparent, no character translation */ #define TC_USASCII 1 /* ISO 646 IRV / US 7-bit ASCII */ #define TC_1LATIN 2 /* ISO 8859-1, Latin Alphabet 1 */ #define TC_2LATIN 3 /* ISO 8859-2, Latin Alphabet 2 */ #define TC_CYRILL 4 /* ISO 8859-5, Latin/Cyrillic */ #define TC_JEUC 5 /* Japanese EUC = JIS 0201+0202+0208 */ #define TC_HEBREW 6 /* ISO 8859-8, Latin/Hebrew */ #define TC_GREEK 7 /* ISO 8859-7, Latin/Greek */ #define TC_9LATIN 8 /* ISO 8859-15 Latin Alphabet 9 (with Euro) */ #define TC_UCS2 9 /* ISO 10646 / Unicode UCS-2 */ #define TC_UTF8 10 /* ISO 10646 / Unicode UTF-8 */ #define MAXTCSETS 10 /* Highest Transfer Character Set Number */ #ifdef COMMENT /* Not used and probably won't be due to ISO-10646 / Unicode. */ #define TC_3LATIN 11 /* ISO 8859-3, Latin-3 */ #define TC_4LATIN 12 /* ISO 8859-4, Latin-4 */ #define TC_5LATIN 13 /* ISO 8859-9, Latin-5 */ #define TC_ARABIC 14 /* ISO-8859-6, Latin/Arabic */ #define TC_JIS208 15 /* Japanese JIS X 0208 multibyte set */ #define TC_CHINES 16 /* Chinese Standard GB 2312-80 */ #define TC_KOREAN 17 /* Korean KS C 5601-1987 */ #define TC_ISCII 18 /* Indian standard code for ii... */ #define TC_VSCII 19 /* Vietnam standard code for ii... */ /* etc... */ #endif /* COMMENT */ /* Structure for character-set information */ struct csinfo { char *name; /* Descriptive name of character set */ int size; /* Size (e.g. 128, 256, 16384) */ int code; /* Like TC_1LATIN, etc. */ char *designator; /* Designator, like I2/100 = Latin-1 */ int alphabet; /* Base alphabet */ char *keyword; /* Keyword for this character-set */ }; /* Structure for language information */ struct langinfo { int id; /* Language ID code (L_whatever) */ int fc; /* File character set to use */ int tc; /* Transfer character set to use */ char *description; /* Description of language */ }; /* Now take in the system-specific definitions */ #ifdef UNIX #include "ckuxla.h" #endif /* UNIX */ #ifdef OSK /* OS-9 */ #include "ckuxla.h" #endif /* OS-9 */ #ifdef VMS /* VAX/VMS */ #include "ckuxla.h" #endif /* VMS */ #ifdef GEMDOS /* Atari ST */ #include "ckuxla.h" #endif /* GEMDOS */ #ifdef MAC /* Macintosh */ #include "ckmxla.h" #endif /* MAC */ #ifdef OS2 /* OS/2 */ #include "ckuxla.h" /* Uses big UNIX version */ #endif /* OS2 */ #ifdef AMIGA /* Commodore Amiga */ #include "ckuxla.h" #endif /* AMIGA */ #ifdef datageneral /* Data General MV AOS/VS */ #include "ckuxla.h" #endif /* datageneral */ #ifdef STRATUS /* Stratus Computer, Inc. VOS */ #include "ckuxla.h" #endif /* STRATUS */ #ifdef UNICODE #include "ckcuni.h" /* Unicode */ #endif /* UNICODE */ #ifdef KANJI #define UNKSJIS 0x817f _PROTOTYP(USHORT eu_to_sj, (USHORT) ); /* EUC-JP to Shift-JIS */ _PROTOTYP(USHORT sj_to_eu, (USHORT) ); /* Shift-JIS to EUC-JP */ _PROTOTYP( int xkanjf, (void) ); _PROTOTYP( int xkanji, (int, int (*)(char)) ); _PROTOTYP( int xkanjz, (int (*)(char) ) ); _PROTOTYP( int zkanjf, (void) ); _PROTOTYP( int zkanji, (int (*)(void)) ); /* Kanji function prototypes */ _PROTOTYP( int zkanjz, (void) ); _PROTOTYP(VOID j7init, ( void ) ); /* Initialize JIS-7 parser */ _PROTOTYP(int getj7, ( void ) ); /* Get next JIS-7 character */ #endif /* KANJI */ #ifndef MAC #ifndef NOLOCAL _PROTOTYP( int cs_size, (int) ); _PROTOTYP( int cs_is_std, (int) ); _PROTOTYP( int cs_is_nrc, (int) ); _PROTOTYP( VOID setremcharset, (int, int) ); _PROTOTYP( VOID setlclcharset, (int) ); #endif /* NOLOCAL */ #endif /* MAC */ _PROTOTYP(VOID setxlatype, (int, int)); #endif /* NOCSETS */ #endif /* CKCXLA_H */ /* End of ckcxla.h */ ckcxxx.h000664 045065 024037 00000017613 14767402016 012663 0ustar00fdckermit000000 000000 /* Kermit 95 variable declarations for GUI -*-C-*- */ /* #include "ckcdeb.h" */ extern char *copyright[]; /* Copyright notice text */ /* File transfer protocol parameters */ extern int protocol; /* File transfer protocol */ extern struct ck_p ptab[]; /* Settings for each protocol */ /* struct ck_p is defined in ckcker.h and has 10 members -- packet length, window size, control-char prefixing options, filename collision options, pathname stripping options, which are kept on a per-protocol basis. These are, in general, duplicates of protocol-specific global variables. The relevant SET commands set the values in both places, depending on what the current protocol is. Whenever we switch protocols, we set the global variables to whatever is in this struct for that protocol. */ /* Packet retransmission limit */ extern int maxtry; /* SET RETRY value */ /* Packet lengths */ extern int urpsiz; /* SET RECEIVE PACKET-LENGTH value */ extern int rpsiz; /* Biggest non-long packet to receive */ extern int maxrps; /* (internal) Max incoming long packet size */ extern int spsizr; /* SET SEND PACKET-LENGTH value */ extern int spsizf; /* Flag that SET SEND PACKET given */ extern int maxsps; /* (internal) Maximum outbound l.p. size */ extern int spmax; /* Biggest packet we can send, negotiated */ /* Sliding Windows */ extern int wslots; /* (internal) Window size currently in use */ extern int wslotr; /* SET WINDOW value */ extern int wslotn; /* Window size negotiated */ /* Packet framing */ extern CHAR mystch; /* SET SEND START-OF-PACKET value */ extern CHAR stchr; /* SET RECEIVE START-OF-PACKET value */ extern CHAR seol; /* SET SEND END-OF-PACKET value */ extern CHAR eol; /* SET RECEIVE END-OF-PACKET value */ /* Control-character prefixing */ extern CHAR myctlq; /* SET SEND CONTROL-PREFIX value */ extern CHAR ctlq; /* SET RECEIVE CONTROL-PREFIX value */ extern int prefixing; /* SET PREFIXING value */ extern short ctlp[]; /* SET CONTROL PREFIX table */ /* Packet timeouts */ extern int timint; /* Timeout interval I actually use */ extern int pkttim; /* SET RECEIVE TIMEOUT value */ extern int rtimo; /* SET SEND TIMEOUT value */ extern int timef; /* Flag that SET SEND TIMEOUT given */ /* Padding */ extern int npad; /* SET SEND PADDING value */ extern int mypadn; /* SET RECEIVE PADDING value */ extern CHAR padch; /* SET SEND PAD-CHARACTER value */ extern CHAR mypadc; /* SET RECEIVE PAD-CHARACTER value */ /* Block check (1, 2, 3, B) */ extern int bctr; /* SET BLOCK-CHECK value */ extern int bctu; /* Block check type actually used */ extern int bctl; /* Block check length */ /* Eighth-bit prefixing */ extern int ebq; /* 8th bit prefix */ extern int ebqflg; /* 8th-bit quoting active flag */ extern int rqf; /* (internal) 8bq negotiation flag */ extern int rq; /* (internal) Received 8bq bid */ extern int sq; /* (internal) Sent 8bq bid */ /* Repeat-count compression */ extern int rpt; /* (internal) Current repeat count */ extern int rptq; /* Repeat prefix character */ extern int rptflg; /* Repeat processing active flag */ extern int rptena; /* Repeat processing enabled */ extern int rptmin; /* Repeat-count minimum */ extern CHAR myrptq; /* Repeat prefix I want to use */ /* Remote-mode file-transfer cancellation -- doesn't apply to K95 (?) */ extern int xfrcan; /* Transfer cancellation enabled */ extern int xfrchr; /* Transfer cancel character value */ extern int xfrnum; /* How many xfrchr needed to cancel */ /* Protocol capabilities -- K95 has all of them */ /* but their use must be negotiated with the other Kermit */ extern int lpcapr; /* Long packets requested */ extern int lpcapu; /* Long packets used */ extern int swcapr; /* Sliding windows requested */ extern int swcapu; /* Sliding windows used */ extern int atcapr; /* Attribute packets requested */ extern int atcapu; /* Attribute packets used */ extern int rscapr; /* RESEND capability requested */ extern int rscapu; /* RESEND capability used */ extern int lscapr; /* Locking Shift requested */ extern int lscapu; /* Locking Shift used */ /* Flags for whether to use particular attributes */ extern int atenci; /* Encoding in */ extern int atenco; /* Encoding out */ extern int atdati; /* Date in */ extern int atdato; /* Date out */ extern int atdisi; /* Disposition in/out */ extern int atdiso; extern int atleni; /* Length in/out (both kinds) */ extern int atleno; extern int atblki; /* Blocksize in/out */ extern int atblko; extern int attypi; /* File type in/out */ extern int attypo; extern int atsidi; /* System ID in/out */ extern int atsido; extern int atsysi; /* Sys-dependent parameters in/out */ extern int atsyso; /* File and/or file-transfer related variables */ extern int fcharset; /* SET FILE CHARACTER-SET value */ extern int tcharset; /* SET TRANSFER CHARACTER-SET value */ extern int language; /* SET LANGUAGE value (for file transfer) */ extern int fncact; /* SET FILE COLLISION value */ extern int fncnv; /* SET FILE NAMES value */ extern int fnspath; /* SET SEND PATHNAMES value */ extern int fnrpath; /* SET RECEIVE PATHNAMES value */ extern int binary; /* SET FILE TYPE value */ extern int fmask; /* SET FILE BYTESIZE mask */ /* Bytesize 7 => fmask 0x7f Bytesize 8 => fmask 0xff */ extern char * dldir; /* SET FILE DOWNLOAD-DIRECTORY value */ extern int keep; /* SET FILE INCOMPLETE value */ extern int unkcs; /* SET FILE UNKNOWN-CHAR value */ /* Protocol state info */ extern CHAR sstate; /* Starting state for automaton */ extern int sendmode; /* Type of SENDing (ckcker.h) */ extern int moving; /* MOVE = send, then delete */ extern long sendstart; /* PSEND/RESEND start position */ extern int server; /* Nonzero = in server mode */ extern int xflg; /* Receiving screen data from server */ extern int hcflg; /* Server is doing REMOTE HOST cmd */ extern int cxseen; /* Flag for cancelling a file */ extern int czseen; /* Flag for cancelling file group */ /* Client/Server items */ extern int srvdis; /* SET SERVER DISPLAY value */ extern int srvtim; /* SET SERVER TIMEOUT value */ extern int en_cwd; /* REMOTE CD/CWD ENABLED */ extern int en_cpy; /* REMOTE COPY ENABLED */ extern int en_del; /* REMOTE DELETE ENABLED */ extern int en_dir; /* REMOTE DIRECTORY ENABLED */ extern int en_fin; /* FINISH/BYE ENABLED */ extern int en_get; /* GET ENABLED */ extern int en_hos; /* REMOTE HOST disabled ENABLED */ extern int en_ren; /* REMOTE RENAME ENABLED */ extern int en_sen; /* SEND ENABLED */ extern int en_set; /* REMOTE SET ENABLED */ extern int en_spa; /* REMOTE SPACE ENABLED */ extern int en_typ; /* REMOTE TYPE ENABLED */ extern int en_who; /* REMOTE WHO ENABLED */ extern int en_bye; /* BYE ENABLED */ extern cku2tm.c000664 045065 024037 00000012361 14767402022 012543 0ustar00fdckermit000000 000000 /* * Steven Schultz - sms@moe.2bsd.com * * @(#)ctimed.c 1.0 (2.11BSD) 1996/6/25 * * ctimed - the daemon that supports the ctime() and getpw*() stubs * in 'libcstubs.a'. */ #include #include #include #include #include #include #include #include #include "ckcfnp.h" /* Prototypes (must be last) */ /* * These should probably be placed in an include file. If you add anything * here then you will also have to modify /usr/src/usr.lib/libstubs/stubs.c * (if for no other reason than to add the stub code). */ #define CTIME 1 #define ASCTIME 2 #define TZSET 3 #define LOCALTIME 4 #define GMTIME 5 #define OFFTIME 6 #define GETPWENT 7 #define GETPWNAM 8 #define GETPWUID 9 #define SETPASSENT 10 #define ENDPWENT 11 extern struct tm *offtime(); jmp_buf env; char *cp; char junk[256 + sizeof (struct passwd) + 4]; long off; time_t l; void timeout(), checkppid(); struct tm tmtmp, *tp; main() { register int i; register struct passwd *pw; struct itimerval it; u_char c, xxx; int len, tosslen; uid_t uid; signal(SIGPIPE, SIG_DFL); for (i = getdtablesize(); --i > 2; ) close(i); /* * Need a timer running while we disassociate from the control terminal * in case of a modem line which has lost carrier. */ timerclear(&it.it_interval); it.it_value.tv_sec = 5; it.it_value.tv_usec = 0; signal(SIGALRM, timeout); setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL); if (setjmp(env) == 0) { i = open("/dev/tty", 0); if (i >= 0) { ioctl(i, TIOCNOTTY, NULL); close(i); } } /* * Now start a timer with one minute refresh. In the signal service * routine, check the parent process id to see if this process has * been orphaned and if so exit. This is primarily aimed at removing * the 'ctimed' process left behind by 'sendmail's multi-fork startup * but may prove useful in preventing accumulation of 'ctimed' processes * in other circumstances as well. Normally this process is short * lived. */ it.it_interval.tv_sec = 60; it.it_interval.tv_usec = 0; it.it_value.tv_sec = 60; it.it_value.tv_usec = 0; signal(SIGALRM, checkppid); setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL); while (read(fileno(stdin), &c, 1) == 1) { switch (c) { case CTIME: l = 0L; getb(fileno(stdin), &l, sizeof l); cp = ctime(&l); write(fileno(stdout), cp, 26); break; case ASCTIME: getb(fileno(stdin), &tmtmp, sizeof tmtmp); cp = asctime(&tmtmp); write(fileno(stdout), cp, 26); break; case TZSET: (void) tzset(); break; case LOCALTIME: l = 0L; getb(fileno(stdin), &l, sizeof l); tp = localtime(&l); write(fileno(stdout), tp, sizeof (*tp)); strcpy(junk, tp->tm_zone); junk[24] = '\0'; write(fileno(stdout), junk, 24); break; case GMTIME: l = 0L; getb(fileno(stdin), &l, sizeof l); tp = gmtime(&l); write(fileno(stdout), tp, sizeof (*tp)); strcpy(junk, tp->tm_zone); junk[24] = '\0'; write(fileno(stdout), junk, 24); break; case OFFTIME: getb(fileno(stdin), &l, sizeof l); getb(fileno(stdin), &off, sizeof off); #ifdef __bsdi__ l += off; tp = localtime(&l); #else tp = offtime(&l, off); #endif write(fileno(stdout), tp, sizeof (*tp)); break; case GETPWENT: pw = getpwent(); do_pw(pw); break; case GETPWNAM: getb(fileno(stdin), &len, sizeof (int)); if (len > UT_NAMESIZE) { tosslen = len - UT_NAMESIZE; len = UT_NAMESIZE; } else tosslen = 0; getb(fileno(stdin), junk, len); for (;tosslen; tosslen--) getb(fileno(stdin), &xxx, 1); junk[len] = '\0'; pw = getpwnam(junk); do_pw(pw); break; case GETPWUID: getb(fileno(stdin), &uid, sizeof (uid_t)); pw = getpwuid(uid); do_pw(pw); break; case SETPASSENT: getb(fileno(stdin), &len, sizeof (int)); if (setpassent(len)) len = 1; else len = 0; write(fileno(stdout), &len, sizeof (int)); break; case ENDPWENT: endpwent(); break; default: abort("switch"); } } } getb(f, p, n) int f; register char *p; register int n; { register int i; while (n) { i = read(f, p, n); if (i <= 0) return; p += i; n -= i; } } void timeout() { longjmp(env, 1); } void checkppid() { if (getppid() == 1) exit(0); } do_pw(pw) struct passwd *pw; { int len; if (!pw) { len = 0; write(fileno(stdout), &len, sizeof (int)); return; } len = packpwtobuf(pw, junk); write(fileno(stdout), &len, sizeof (int)); write(fileno(stdout), pw, sizeof (*pw)); write(fileno(stdout), junk, len); return; } packpwtobuf(pw, buf) register struct passwd *pw; char *buf; { register char *cp = buf; register char *dp; dp = pw->pw_name; pw->pw_name = (char*) 0; while (*cp++ = *dp++) ; dp = pw->pw_passwd; pw->pw_passwd = (char*) (cp - buf); while (*cp++ = *dp++) ; dp = pw->pw_class; pw->pw_class = (char*) (cp - buf); while (*cp++ = *dp++) ; dp = pw->pw_gecos; pw->pw_gecos = (char*) (cp - buf); while (*cp++ = *dp++) ; dp = pw->pw_dir; pw->pw_dir = (char*) (cp - buf); while (*cp++ = *dp++) ; dp = pw->pw_shell; pw->pw_shell = (char*) (cp - buf); while (*cp++ = *dp++) ; return(cp - buf); } ckuat2.h000664 045065 024037 00000030161 14767403114 012535 0ustar00fdckermit000000 000000 /* C K U A T 2 . H -- Kerberos headers for C-Kermit Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Author: Kerberos IV and V intergration. Jeffrey E Altman (jaltman@secure-endpoints.com) Secure Endpoints Inc., New York City Last update: 23 June 2023, David Goodwin */ /* * Based on a concatenation of all necessary include files distributed with * the Kerberos 5 NT Alpha 2 Telnet package from MIT. */ #ifndef KRB5_TELNET_H #define KRB5_TELNET_H /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)encrypt.h 8.1 (Berkeley) 6/4/93 */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #ifdef CK_ENCRYPTION #ifndef __ENCRYPTION__ #define __ENCRYPTION__ #define DIR_DECRYPT 1 #define DIR_ENCRYPT 2 #ifndef CK_DES_C #ifndef NOBLOCKDEF typedef unsigned char Block[8]; #endif /* NOBLOCKDEF */ typedef unsigned char *BlockT; #ifndef KRB4 /* already defined in kerberosiv/des.h */ typedef struct des_ks_struct { Block _; } Schedule[16]; #else /* KRB4 */ #ifndef NOBLOCKDEF /* already defined in kerberosiv/des.h */ typedef struct des_ks_struct { Block _; } Schedule[16]; #endif /* NOBLOCKDEF */ #endif /* KRB4 */ #define VALIDKEY(key) (key[0]|key[1]|key[2]|key[3]|key[4]|key[5]|key[6]|key[7]) #define SAMEKEY(k1, k2) (!memcmp((void *)k1, (void *)k2, sizeof(Block))) #endif /* CK_DES_C */ typedef struct _session_key { short type; int length; unsigned char *data; } Session_Key; #ifdef __STDC__ typedef struct { char *name; int type; void (*output)(unsigned char *, int); int (*input)(int); void (*init)(int); int (*start)(int, int); int (*is)(unsigned char *, int); int (*reply)(unsigned char *, int); int (*session)(Session_Key *, int); int (*keyid)(int, unsigned char *, int *); void (*printsub)(unsigned char *, int, unsigned char *, int); } Encryptions; #if !defined(P) #define P(x) x #endif #else typedef struct { char *name; int type; void (*output)(); int (*input)(); void (*init)(); int (*start)(); int (*is)(); int (*reply)(); int (*session)(); int (*keyid)(); void (*printsub)(); } Encryptions; #if !defined(P) #define P(x) () #endif #endif int encrypt_parse(unsigned char *, int); #ifdef DEBUG int printsub(char, unsigned char *, size_t); #endif #define SK_GENERIC 0 /* Just a string of bits */ #define SK_DES 1 /* Matched Kerberos v5 ENCTYPE_DES */ void encrypt_init P((kstream,int)); Encryptions *findencryption P((int)); void encrypt_send_support P((void)); void encrypt_auto P((int)); void decrypt_auto P((int)); int encrypt_is P((unsigned char *, int)); int encrypt_reply P((unsigned char *, int)); void encrypt_start_input P((int)); int encrypt_session_key P((Session_Key *, int)); int encrypt_dont_support P((int)); void encrypt_end_input P((void)); void encrypt_start_output P((int)); void encrypt_end_output P((void)); void encrypt_send_request_start P((void)); void encrypt_send_request_end P((void)); void encrypt_send_end P((void)); void encrypt_wait P((void)); int encrypt_is_encrypting P((void)); void encrypt_send_support P((void)); int encrypt_send_keyid P((int, unsigned char *, int, int)); int encrypt_cmd P((int, char **)); void encrypt_display P((void)); #ifdef CK_KERBEROS void krbdes_encrypt P((unsigned char *, int)); int krbdes_decrypt P((int)); int krbdes_is P((unsigned char *, int)); int krbdes_reply P((unsigned char *, int)); void krbdes_init P((int)); int krbdes_start P((int, int)); void krbdes_session P((Session_Key *, int)); void krbdes_printsub P((unsigned char *, int, unsigned char *, int)); #endif /* CK_KERBEROS */ void cfb64_encrypt P((unsigned char *, int)); int cfb64_decrypt P((int)); void cfb64_init P((int)); int cfb64_start P((int, int)); int cfb64_is P((unsigned char *, int)); int cfb64_reply P((unsigned char *, int)); int cfb64_session P((Session_Key *, int)); int cfb64_keyid P((int, unsigned char *, int *)); void cfb64_printsub P((unsigned char *, int, unsigned char *, int)); void ofb64_encrypt P((unsigned char *, int)); int ofb64_decrypt P((int)); void ofb64_init P((int)); int ofb64_start P((int, int)); int ofb64_is P((unsigned char *, int)); int ofb64_reply P((unsigned char *, int)); int ofb64_session P((Session_Key *, int)); int ofb64_keyid P((int, unsigned char *, int *)); void ofb64_printsub P((unsigned char *, int, unsigned char *, int)); void des3_cfb64_encrypt P((unsigned char *, int)); int des3_cfb64_decrypt P((int)); void des3_cfb64_init P((int)); int des3_cfb64_start P((int, int)); int des3_cfb64_is P((unsigned char *, int)); int des3_cfb64_reply P((unsigned char *, int)); int des3_cfb64_session P((Session_Key *, int)); int des3_cfb64_keyid P((int, unsigned char *, int *)); void des3_cfb64_printsub P((unsigned char *, int, unsigned char *, int)); void des3_ofb64_encrypt P((unsigned char *, int)); int des3_ofb64_decrypt P((int)); void des3_ofb64_init P((int)); int des3_ofb64_start P((int, int)); int des3_ofb64_is P((unsigned char *, int)); int des3_ofb64_reply P((unsigned char *, int)); int des3_ofb64_session P((Session_Key *, int)); int des3_ofb64_keyid P((int, unsigned char *, int *)); void des3_ofb64_printsub P((unsigned char *, int, unsigned char *, int)); #ifdef CAST_ENCRYPTION void cast_cfb64_encrypt P((unsigned char *, int)); int cast_cfb64_decrypt P((int)); void cast_cfb64_init P((int)); int cast_cfb64_start P((int, int)); int cast_cfb64_is P((unsigned char *, int)); int cast_cfb64_reply P((unsigned char *, int)); int cast_cfb64_session P((Session_Key *, int)); int cast_cfb64_keyid P((int, unsigned char *, int *)); void cast_cfb64_printsub P((unsigned char *, int, unsigned char *, int)); void cast_ofb64_encrypt P((unsigned char *, int)); int cast_ofb64_decrypt P((int)); void cast_ofb64_init P((int)); int cast_ofb64_start P((int, int)); int cast_ofb64_is P((unsigned char *, int)); int cast_ofb64_reply P((unsigned char *, int)); int cast_ofb64_session P((Session_Key *, int)); int cast_ofb64_keyid P((int, unsigned char *, int *)); void cast_ofb64_printsub P((unsigned char *, int, unsigned char *, int)); void castexp_cfb64_encrypt P((unsigned char *, int)); int castexp_cfb64_decrypt P((int)); void castexp_cfb64_init P((int)); int castexp_cfb64_start P((int, int)); int castexp_cfb64_is P((unsigned char *, int)); int castexp_cfb64_reply P((unsigned char *, int)); int castexp_cfb64_session P((Session_Key *, int)); int castexp_cfb64_keyid P((int, unsigned char *, int *)); void castexp_cfb64_printsub P((unsigned char *, int, unsigned char *, int)); void castexp_ofb64_encrypt P((unsigned char *, int)); int castexp_ofb64_decrypt P((int)); void castexp_ofb64_init P((int)); int castexp_ofb64_start P((int, int)); int castexp_ofb64_is P((unsigned char *, int)); int castexp_ofb64_reply P((unsigned char *, int)); int castexp_ofb64_session P((Session_Key *, int)); int castexp_ofb64_keyid P((int, unsigned char *, int *)); void castexp_ofb64_printsub P((unsigned char *, int, unsigned char *, int)); #endif /* CAST_ENCRYPTION */ /* int des_string_to_key P((char *, Block)); */ #ifdef DEBUG extern int encrypt_debug_mode; #endif int decrypt_ks_hack(unsigned char *, int); #endif /* __ENCRYPTION__ */ #endif /* ENCRYPTION */ #ifdef CRYPT_DLL typedef struct { int version; /* Version 1 variables */ int (*p_ttol)(char *,int); int (*p_dodebug)(int,char *,char *,CK_OFF_T); int (*p_dohexdump)(char *,char *,int); void (*p_tn_debug)(char *); int (*p_scrnprint)(const char *); /* Version 2 variables */ void * p_k5_context; /* Version 3 variables */ void (*callbackp_install_dllfunc)(char *,void *); /* Version 5 variables */ unsigned long (*p_reqtelmutex)(unsigned long); unsigned long (*p_reltelmutex)(void); } crypt_dll_init_data; #endif /* CRYPT_DLL */ /* per Kerberos v5 protocol spec */ #ifndef ENCTYPE_NULL #define ENCTYPE_NULL 0x0000 #endif #ifndef ENCTYPE_DES_CBC_CRC #define ENCTYPE_DES_CBC_CRC 0x0001 /* DES cbc mode with CRC-32 */ #endif #ifndef ENCTYPE_DES_CBC_MD4 #define ENCTYPE_DES_CBC_MD4 0x0002 /* DES cbc mode with RSA-MD4 */ #endif #ifndef ENCTYPE_DES_CBC_MD5 #define ENCTYPE_DES_CBC_MD5 0x0003 /* DES cbc mode with RSA-MD5 */ #endif #ifndef ENCTYPE_DES_CBC_RAW #define ENCTYPE_DES_CBC_RAW 0x0004 /* DES cbc mode raw */ #endif /* XXX deprecated? */ #ifndef ENCTYPE_DES3_CBC_SHA #define ENCTYPE_DES3_CBC_SHA 0x0005 /* DES-3 cbc mode with NIST-SHA */ #endif #ifndef ENCTYPE_DES3_CBC_RAW #define ENCTYPE_DES3_CBC_RAW 0x0006 /* DES-3 cbc mode raw */ #endif #ifndef ENCTYPE_DES_HMAC_SHA1 #define ENCTYPE_DES_HMAC_SHA1 0x0008 #endif #ifndef ENCTYPE_DES3_CBC_SHA1 #define ENCTYPE_DES3_CBC_SHA1 0x0010 #endif #ifndef ENCTYPE_AES128_CTS_HMAC_SHA1_96 #define ENCTYPE_AES128_CTS_HMAC_SHA1_96 0x0011 #endif #ifndef ENCTYPE_AES256_CTS_HMAC_SHA1_96 #define ENCTYPE_AES256_CTS_HMAC_SHA1_96 0x0012 #endif #ifndef ENCTYPE_ARCFOUR_HMAC #define ENCTYPE_ARCFOUR_HMAC 0x0017 #endif #ifndef ENCTYPE_ARCFOUR_HMAC_EXP #define ENCTYPE_ARCFOUR_HMAC_EXP 0x0018 #endif #ifndef ENCTYPE_LOCAL_RC4_MD4 #define ENCTYPE_LOCAL_RC4_MD4 0xFFFFFF80 #endif #ifndef ENCTYPE_UNKNOWN #define ENCTYPE_UNKNOWN 0x01ff #endif /* local crud */ /* marc's DES-3 with 32-bit length */ #ifndef ENCTYPE_LOCAL_DES3_HMAC_SHA1 #define ENCTYPE_LOCAL_DES3_HMAC_SHA1 0x7007 #endif #endif /* KRB5_TELNET_H */ ckuath.c000664 045065 024037 00001445643 14767403124 012637 0ustar00fdckermit000000 000000 char *ckathv = "Authentication, 10.0.244, 04 May 2023"; /* C K U A T H . C -- Authentication for C-Kermit Copyright (C) 1999, 2032, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Author: Jeffrey E Altman (jaltman@secure-endpoints.com) Secure Endpoints Inc., New York City Latest update: Tue Dec 13 07:10:21 2022 (David Goodwin for K95) */ /* * Additional copyrights included with affected code. */ #ifdef HEIMDAL /* Turned off User to User support Turned off KDESTROY support Turned off KLIST support Turned off krb5_prompter() support Turned off ticket validation Turned off ticket renewal Turned off alternative cache support in k5_get_ccache() Remaining link problems: ckuath.o: In function `ck_krb5_initTGT': ckuath.o(.text+0x50c2): undefined reference to `krb5_string_to_deltat' ckuath.o(.text+0x516d): undefined reference to `krb5_string_to_deltat' ckuath.o(.text+0x51ef): undefined reference to `krb5_string_to_deltat' */ #endif /* HEIMDAL */ /* * Implements Kerberos 4/5, SRP, SSL, NTLM authentication and START_TLS */ #include "ckcsym.h" #include "ckcdeb.h" #ifdef CK_SECURITY #define CKUATH_C #include "ckcker.h" #include "ckuusr.h" #include "ckucmd.h" /* For struct keytab */ #include "ckcnet.h" #include "ckctel.h" char szUserNameRequested[UIDBUFLEN+1]; /* for incoming connections */ char szUserNameAuthenticated[UIDBUFLEN+1];/* for incoming connections */ char szHostName[UIDBUFLEN+1]; char szUserName[UIDBUFLEN+1]; static char szIP[16]; static int validUser = AUTH_REJECT; /* User starts out invalid */ int authentication_version = AUTHTYPE_NULL; int accept_complete = 0; #ifdef CK_AUTHENTICATION #ifdef CK_SSL #ifdef KRB5 #define TLS_VERIFY #endif /* KRB5 */ #endif /* CK_SSL */ #ifdef CK_DES #ifdef CK_SSL #ifndef LIBDES #define LIBDES #endif /* LIBDES */ #endif /* CK_SSL */ #endif /* CK_DES */ #ifdef CRYPT_DLL #ifndef LIBDES #define LIBDES #endif /* LIBDES */ #endif /* CRYPT_DLL */ #ifdef OS2 #ifdef NT #include #else /* NT */ #define INCL_DOSMODULEMGR #define INCL_DOSSEMAPHORES #include #undef COMMENT #endif /* NT */ #endif /* OS2 */ #ifdef NT #define KRB5_AUTOCONF__ #ifndef NONTLM #define NTLM #endif /* NONTLM */ #endif /* NT */ #ifdef CK_KERBEROS #define KINIT #ifndef HEIMDAL #define KLIST #define KDESTROY #endif /* HEIMDAL */ #define CHECKADDRS #else /* CK_KERBEROS */ #ifdef KRB4 #undef KRB4 #endif /* KRB4 */ #ifdef KRB5 #undef KRB5 #endif /* KRB5 */ #ifdef KRB524 #undef KRB524 #endif /* KRB524 */ #endif /* CK_KERBEROS */ #include #include #include #include #include #ifndef OS2 /* Not OS/2 or NT */ #include #endif /* OS2 */ #ifdef OS2 #include #ifdef NT /* Win32 gets errno.h */ #include #else /* NT */ /* OS2 gets errno.h only if we're not compiling with Watcom C as * the definitions in its errno.h conflict with those in os2.h */ #ifndef __WATCOMC__ #include #endif /* __WATCOMC__ */ #endif /* NT */ #endif /* OS2 */ #ifdef KRB5 #ifdef HEIMDAL #ifdef printf #define saveprintf printf #undef printf #endif /* printf */ #include "krb5.h" /* ifdefs -fdc 22 November 2022 */ #ifdef XX_COM_ERR_H #include "com_err.h" #else #ifdef K5_COM_ERR_H #include "krb5/com_err.h" #else #ifdef ET_COM_ERR_H #include "et/com_err.h" #endif /* ET_COM_ERR_H */ #endif /* K5_COM_ERR_H */ #endif /* COM_ERR_H */ #ifdef saveprintf #define printf saveprintf #endif /* saveprintf */ #else /* HEIMDAL */ #include "krb5.h" /* #include "com_err.h" */ /* already done just above */ #ifdef KRB5_GET_INIT_CREDS_OPT_TKT_LIFE #define KRB5_HAVE_GET_INIT_CREDS #else #define krb5_free_unparsed_name(con,val) krb5_xfree((char *)(val)) #endif /* KRB5_GET_INIT_CREDS_OPT_TKT_LIFE */ #ifndef KRB5_HAVE_GET_INIT_CREDS #define krb5_free_data_contents(c,v) krb5_xfree((char *)(v)->data) #endif #endif /* HEIMDAL */ #ifdef HAVE_PWD_H #include #endif /* HAVE_PWD_H */ #endif /* KRB5 */ #ifdef KRB4 #define des_cblock Block #define const_des_cblock const Block #define des_key_schedule Schedule #ifdef KRB524 #ifdef NT #define _WINDOWS #endif /* NT */ #include "kerberosIV/krb.h" #ifndef OS2 #ifdef KRB524_CONV #include "krb524.h" #endif /* KRB524_CONV */ _PROTOTYP(const char * krb_get_err_text_entry, (int)); #endif /* OS2 */ #else /* KRB524 */ #ifdef SOLARIS #ifndef sun /* for some reason the Makefile entries for the Solaris systems have -Usun */ #define sun #endif /* sun */ #endif /* SOLARIS */ #include "krb.h" #define krb_get_err_text_entry krb_get_err_text #endif /* KRB524 */ #else /* KRB4 */ #ifdef CK_SSL #define des_cblock Block #ifdef COMMENT #define const_des_cblock const Block #endif /* COMMENT */ #define des_key_schedule Schedule #endif /* CK_SSL */ #endif /* KRB4 */ #include "ckuath.h" #ifdef CK_KERBEROS #ifndef KRB5 #define NOBLOCKDEF #else /* KRB5 */ #ifdef KRB524 #define NOBLOCKDEF #endif /* KRB524 */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ #include "ckuat2.h" #ifdef CK_SSL #ifdef LIBDES #ifdef OPENSSL_097 #ifdef CK_DES #define OPENSSL_ENABLE_OLD_DES_SUPPORT #include #endif /* CK_DES */ #endif /* OPENSSL_097 */ #ifndef HEADER_DES_H #define HEADER_DES_H #endif /* HEADER_DES_H */ #endif /* LIBDES */ #include "ck_ssl.h" extern int ssl_finished_messages; #endif /* SSL */ #define PWD_SZ 128 #ifndef LIBDES #ifdef UNIX #define des_set_random_generator_seed(x) des_init_random_number_generator(x) #endif /* UNIX */ #else /* LIBDES */ #define des_fixup_key_parity des_set_odd_parity #endif /* LIBDES */ #ifdef OS2 #ifdef CK_ENCRYPTION #define MAP_DES #endif /* CK_ENCRYPTION */ #ifdef KRB4 #define MAP_KRB4 #endif /* KRB4 */ #ifdef SRPDLL #define MAP_SRP #endif /* SRPDLL */ #ifdef KRB5 #define MAP_KRB5 #endif /* KRB5 */ #ifdef CRYPT_DLL #define MAP_CRYPT #endif /* CRYPT_DLL */ #define MAP_NTLM #include "ckoath.h" #include "ckosyn.h" #endif /* OS2 */ #ifdef OS2 #ifndef NOLOCAL _PROTOTYP(void ipadl25, (void)); /* Default status-line maker */ #endif /* NOLOCAL */ #ifdef CK_AUTHENTICATION int ck_security_loaddll( void ); #endif /* CK_AUTHENTICATION */ #ifdef NT #ifdef NTLM int ntlm_auth_send(); /* ckoath.c */ int ck_ntlm_is_valid(int query_user); /* ckoath.c */ #endif /* NTLM */ #endif /* NT */ #endif /* OS2 */ /* * Globals */ int auth_type_user[AUTHTYPLSTSZ] = {AUTHTYPE_AUTO, AUTHTYPE_NULL}; int auth_how=0; int auth_crypt=0; int auth_fwd=0; /* These are state completion variables */ static int mutual_complete = 0; #ifdef KRB4 #ifdef OS2 static LEASH_CREDENTIALS cred; #else /* OS2 */ static CREDENTIALS cred; #endif /* OS2 */ static KTEXT_ST k4_auth; static char k4_name[ANAME_SZ]; static AUTH_DAT k4_adat = { 0 }; static MSG_DAT k4_msg_data; #ifdef CK_ENCRYPTION static Block k4_session_key = { 0 }; static Schedule k4_sched; static Block k4_challenge = { 0 }; #ifdef MIT_CURRENT static krb5_keyblock k4_krbkey; #endif /* MIT_CURRENT */ #endif /* ENCRYPTION */ #define KRB4_SERVICE_NAME "rcmd" _PROTOTYP(static int k4_auth_send,(VOID)); _PROTOTYP(static int k4_auth_reply,(unsigned char *, int)); _PROTOTYP(static int k4_auth_is,(unsigned char *, int)); #endif /* KRB4 */ #ifdef KRB5 static krb5_data k5_auth; static krb5_auth_context auth_context; static krb5_keyblock *k5_session_key = NULL; static krb5_ticket *k5_ticket = NULL; #ifndef KRB5_SERVICE_NAME #define KRB5_SERVICE_NAME "host" #ifdef MACOSX #define MIT_CURRENT 1 #define decode_krb5_ticket krb5_decode_ticket #define krb5_read_message ck_krb5_read_message #define krb5_write_message ck_krb5_write_message #endif /* MACOSX */ #endif _PROTOTYP(static int k5_auth_send,(int,int,int)); _PROTOTYP(static int k5_auth_reply,(int, unsigned char *, int)); _PROTOTYP(static int k5_auth_is,(int,unsigned char *, int)); _PROTOTYP(static int SendK5AuthSB,(int, void *, int)); #ifdef TLS_VERIFY static int krb5_tls_verified = 0; #endif /* TLS_VERIFY */ #endif /* KRB5 */ #ifdef GSSAPI_KRB5 #include #include #include static gss_ctx_id_t gcontext; #define GSS_BUFSIZ 4096 static gss_buffer_desc gss_send_tok, gss_recv_tok, *gss_token_ptr; static char gss_stbuf[GSS_BUFSIZ]; static gss_name_t gss_target_name; static struct gss_channel_bindings_struct gss_chan; _PROTOTYP(static int gssk5_auth_send,(int,int,int)); _PROTOTYP(static int gssk5_auth_reply,(int, unsigned char *, int)); _PROTOTYP(static int gssk5_auth_is,(int,unsigned char *, int)); _PROTOTYP(static int SendGSSK5AuthSB,(int, void *, int)); #endif /* GSSAPI_KRB5 */ #ifdef CK_SRP #ifdef PRE_SRP_1_7_3 _PROTOTYP(static int srp_reply,(int, unsigned char *, int)); _PROTOTYP(static int srp_is,(int, unsigned char *, int)); #else /* PRE_SRP_1_7_3 */ _PROTOTYP(static int new_srp_reply,(int, unsigned char *, int)); _PROTOTYP(static int new_srp_is,(int, unsigned char *, int)); #endif /* PRE_SRP_1_7_3 */ #endif /* SRP */ #ifdef CK_ENCRYPTION int encrypt_flag = 1; #endif #ifdef FORWARD int forward_flag = 0; /* forward tickets? */ int forwardable_flag = 1; /* get forwardable tickets to forward? */ int forwarded_tickets = 0; /* were tickets forwarded? */ #endif static unsigned char str_data[4096] = { IAC, SB, TELOPT_AUTHENTICATION, 0, AUTHTYPE_KERBEROS_V5, }; #define AUTHTMPBL 2048 static char strTmp[AUTHTMPBL+1]; static kstream g_kstream=NULL; #ifdef KRB5 krb5_context k5_context=NULL; static krb5_creds * ret_cred=NULL; static krb5_context telnet_context=NULL; static char * telnet_krb5_realm = NULL; static krb5_principal fwd_server = NULL; #endif /* KRB5 */ #ifdef CK_SRP #ifdef PRE_SRP_1_4_4 #ifndef PRE_SRP_1_4_5 #define PRE_SRP_1_4_5 #endif /* PRE_SRP_1_4_5 */ #endif /* PRE_SRP_1_4_5 */ #ifdef PRE_SRP_1_4_5 #ifndef PRE_SRP_1_7_3 #define PRE_SRP_1_7_3 #endif /* PRE_SRP_1_7_3 */ #endif /* PRE_SRP_1_4_5 */ #include #include #include static struct t_server * ts = NULL; static struct t_client * tc = NULL; #ifdef PRE_SRP_1_4_4 static struct t_pw * tpw = NULL; static struct t_conf * tconf = NULL; #endif /* PRE_SRP_1_4_4 */ #ifndef PRE_SRP_1_7_3 #ifndef STDC_HEADERS #define STDC_HEADERS 1 #endif /* STDC_HEADERS */ #include static SRP * s_srp = NULL; static cstr * s_key = NULL; static SRP * c_srp = NULL; static cstr * c_key = NULL; #endif /* PRE_SRP_1_7_3 */ static int srp_waitresp = 0; /* Flag to indicate readiness for response */ static char srp_passwd[PWD_SZ]; #endif /* CK_SRP */ #ifdef CK_KERBEROS #ifdef RLOGCODE #define OPTS_FORWARD_CREDS 0x00000020 #define OPTS_FORWARDABLE_CREDS 0x00000010 #define KCMD_KEYUSAGE 1026 #define RLOG_BUFSIZ 5120 static int rlog_encrypt = 0; char des_inbuf[2*RLOG_BUFSIZ]; /* needs to be > largest read size */ char des_outpkt[2*RLOG_BUFSIZ+4]; /* needs to be > largest write size */ #ifdef KRB5 krb5_data desinbuf,desoutbuf; static krb5_data encivec_i[2], encivec_o[2]; enum krb5_kcmd_proto { /* Old protocol: DES encryption only. No subkeys. No protection for cleartext length. No ivec supplied. OOB hacks used for rlogin. Checksum may be omitted at connection startup. */ KCMD_OLD_PROTOCOL = 1, /* New protocol: Any encryption scheme. Client-generated subkey required. Prepend cleartext-length to cleartext data (but don't include it in count). Starting ivec defined, chained. In-band signalling. Checksum required. */ KCMD_NEW_PROTOCOL, /* Hack: Get credentials, and use the old protocol iff the session key type is single-DES. */ KCMD_PROTOCOL_COMPAT_HACK, KCMD_UNKNOWN_PROTOCOL }; enum krb5_kcmd_proto krb5_rlog_ver = KCMD_PROTOCOL_COMPAT_HACK; #endif /* KRB5 */ #endif /* RLOGCODE */ static char storage[65536]; /* storage for the decryption */ static int nstored = 0; static char *store_ptr = storage; extern char * krb5_d_principal; /* Default principal */ extern char * krb5_d_instance; /* Default instance */ extern char * krb5_d_realm; /* Default realm */ extern char * krb5_d_cc; /* Default credentials cache */ extern char * krb5_d_srv; /* Default service name */ extern int krb5_d_lifetime; /* Default lifetime */ extern int krb5_d_forwardable; extern int krb5_d_proxiable; extern int krb5_d_renewable; extern int krb5_autoget; extern int krb5_checkaddrs; extern int krb5_d_getk4; extern int krb5_d_no_addresses; extern char * k5_keytab; extern int krb5_errno; extern char * krb5_errmsg; extern char * krb4_d_principal; /* Default principal */ extern char * krb4_d_realm; /* Default realm */ extern char * krb4_d_srv; /* Default service name */ extern int krb4_d_lifetime; /* Default lifetime */ extern int krb4_d_preauth; extern char * krb4_d_instance; extern int krb4_autoget; extern int krb4_checkaddrs; extern char * k4_keytab; extern int krb4_errno; extern char * krb4_errmsg; #endif /* CK_KERBEROS */ extern char tn_msg[], hexbuf[]; /* from ckcnet.c */ extern CHAR pwbuf[]; extern int pwflg, pwcrypt; extern int deblog, debses, tn_deb; extern int sstelnet, inserver; #ifdef CK_LOGIN extern int ckxanon; #endif /* CK_LOGIN */ extern int tn_auth_how; extern int tn_auth_enc; #ifdef CK_ENCRYPTION extern int cx_type; #endif /* CK_ENCRYPTION */ extern int quiet, ttyfd, ttnproto; int ck_gssapi_is_installed() { #ifdef KRB5 #ifdef OS2 return(hGSSAPI != NULL); #else /* OS2 */ return(1); #endif /* OS2 */ #else /* KRB5 */ return(0); #endif /* KRB5 */ } int ck_krb5_is_installed() { #ifdef KRB5 #ifdef OS2 return(hKRB5_32 != NULL); #else /* OS2 */ return(1); #endif /* OS2 */ #else /* KRB5 */ return(0); #endif /* KRB5 */ } int ck_krb5_is_installed_as_server() { #ifdef KRB5 #ifdef HEIMDAL krb5_error_code ret; krb5_keytab kt; krb5_kt_cursor cursor; ret = krb5_kt_default(k5_context, &kt); if ( ret ) { krb5_kt_close(k5_context, kt); return(0); } else { krb5_kt_end_seq_get(k5_context, kt, &cursor); krb5_kt_close(k5_context, kt); return(1); } #else /* HEIMDAL */ #ifndef COMMENT char ktname[CKMAXPATH]=""; if ( k5_keytab ) { ckstrncpy(ktname,k5_keytab,CKMAXPATH); } else { krb5_error_code code; if ( k5_context == NULL) if (krb5_init_context(&k5_context)) return(0); code = krb5_kt_default_name(k5_context,ktname,CKMAXPATH); debug(F101,"krb5_kt_default_name","",code); if ( code ) { /* We can't check the existence of the file since we can't */ /* determine the file name. So we return TRUE and let */ /* Krb5 be offered to the user even though it may fail later */ return(1); } } if ( !strncmp("FILE:",ktname,5) ) { if ( zchki(&ktname[5]) > 0 ) return(1); else return(0); } else { if (ktname[0]) return(1); else return(0); } #else /* COMMENT */ krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC; krb5_context krb5context = NULL; krb5_ccache krb5ccdef = NULL; krb5_creds krb5creds, *krb5credsp = NULL; int rc = 0; if ( !ck_krb5_is_installed() ) return(0); memset((char *)&krb5creds, 0, sizeof(krb5creds)); if ((krb5rc = krb5_init_context(&krb5context)) != 0) goto err; if ((krb5rc = krb5_sname_to_principal(krb5context, szHostName, krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME, KRB5_NT_SRV_HST, &krb5creds.server)) != 0) goto err; if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0) goto err; if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef, &krb5creds.client)) != 0) goto err; if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef, &krb5creds, &krb5credsp)) != 0) goto err; rc = 1; err: if (krb5creds.client) krb5_free_principal(krb5context, krb5creds.client); if (krb5creds.server) krb5_free_principal(krb5context, krb5creds.server); if (krb5context) krb5_free_context(krb5context); return(rc); #endif /* COMMENT */ #endif /* HEIMDAL */ #else /* KRB5 */ return(0); #endif /* KRB5 */ } int ck_krb4_is_installed() { #ifdef KRB4 #ifdef OS2 return(hKRB4_32 != NULL); #else /* OS2 */ return(1); #endif /* OS2 */ #else /* KRB4 */ return(0); #endif /* KRB4 */ } int ck_krb4_is_installed_as_server() { if ( !ck_krb4_is_installed() ) return(0); #ifdef KRB4 if ( !k4_keytab ) { #ifdef NT char name[CKMAXPATH]=""; DWORD len = CKMAXPATH; len = GetWindowsDirectory(name,len); if ( len > 0 ) ckstrncat(name,"/srvtab",CKMAXPATH); if ( name[0] ) makestr(&k4_keytab,name); #else /* NT */ makestr(&k4_keytab,"/etc/srvtab"); #endif /* NT */ } if ( !k4_keytab ) return(0); if ( zchki(k4_keytab) > 0 ) return(1); #ifdef KRB524 else if (ck_krb5_is_installed_as_server()) return(1); #endif /* KRB524 */ else return(0); /* 2022-12-01 SMS. Added return in case where ifndef KRB4. Smarter to * make the whole function ifdef KRB4, like its only invocation, below? */ #else /* def KRB4 */ return(0); #endif /* KRB4 */ } int ck_srp_is_installed_as_server() { #ifdef CK_SRP #ifdef SRPDLL if ( hSRP == NULL ) return(0); #endif /* SRPDLL */ #ifdef COMMENT /* This is the new API as of 1.7.4. However, all it does is allocate a data structure. It can never fail. */ { SRP * s_srp = SRP_new(SRP_RFC2945_server_method()); if ( s_srp ) { SRP_free(s_srp); s_srp = NULL; return(1); } return(0); } #else /* COMMENT */ { struct t_pw * tpw = NULL; struct t_conf * tconf = NULL; if((tconf = t_openconf(NULL)) == NULL) return(0); if((tpw = t_openpw(NULL)) == NULL) { t_closeconf(tconf); return(0); } t_closeconf(tconf); t_closepw(tpw); return(1); } #endif /* COMMENT */ #else /* SRP */ return(0); #endif /* SRP */ } int ck_srp_is_installed() { #ifdef CK_SRP #ifdef SRPDLL if ( hSRP == NULL ) return(0); #endif /* SRPDLL */ return(1); #else /* CK_SRP */ return(0); #endif /* CK_SRP */ } int ck_krypto_is_installed() { #ifdef CK_SRP #ifdef OS2 if ( hLIBKRYPTO == NULL ) return(0); #endif /* OS2 */ return(1); #else /* CK_SRP */ return(0); #endif /* CK_SRP */ } int ck_crypt_is_installed() { #ifdef CK_ENCRYPTION #ifdef CRYPT_DLL return(hCRYPT != NULL); #else /* CRYPT_DLL */ return(1); #endif /* CRYPT_DLL */ #else /* ENCRYPTION */ return(0); #endif /* ENCRYPTION */ } int ck_ntlm_is_installed() { #ifdef NT #ifndef NTLM return(0); #else return(hSSPI != NULL); #endif #else /* NT */ return(0); #endif /* NT */ } int ck_tn_auth_valid() { return(validUser); } /* C K _ K R B _ A U T H _ I N _ P R O G R E S S * * Is an authentication negotiation still in progress? * */ int #ifdef CK_ANSIC ck_tn_auth_in_progress(void) #else ck_tn_auth_in_progress() #endif { switch (authentication_version) { case AUTHTYPE_AUTO: return(1); case AUTHTYPE_NULL: return(0); #ifdef KRB4 case AUTHTYPE_KERBEROS_V4: if (!accept_complete) { debug(F100,"ck_auth_in_progress() Kerberos 4 !accept_complete", "",0); return(1); } else if ((auth_how & AUTH_HOW_MASK) && !mutual_complete) { debug(F100,"ck_auth_in_progress() Kerberos 4 !mutual_complete", "",0); return(1); } else return(0); #endif /* KRB4 */ #ifdef KRB5 case AUTHTYPE_KERBEROS_V5: if (!accept_complete) { debug(F100,"ck_auth_in_progress() Kerberos 5 !accept_complete", "",0); return(1); } else if ((auth_how & AUTH_HOW_MASK) && !mutual_complete) { debug(F100,"ck_auth_in_progress() Kerberos 5 !mutual_complete", "",0); return(1); } else return(0); #ifdef GSSAPI_K5 case AUTHTYPE_GSSAPI_KRB5: if (!accept_complete) { debug(F100, "ck_auth_in_progress() GSSAPI Kerberos 5 !accept_complete", "", 0 ); return(1); } else if ((auth_how & AUTH_HOW_MASK) && !mutual_complete) { debug(F100, "ck_auth_in_progress() GSSAPI Kerberos 5 !mutual_complete", "", 0 ); return(1); } else return(0); break; #endif /* GSSAPI_K5 */ #endif /* KRB5 */ #ifdef CK_SRP case AUTHTYPE_SRP: if (!accept_complete || srp_waitresp) return(1); else return(0); #endif /* CK_SRP */ #ifdef NTLM case AUTHTYPE_NTLM: if (!accept_complete) { debug(F100,"ck_auth_in_progress() NTLM !accept_complete", "",0); return(1); } else return(0); #endif /* NTLM */ case AUTHTYPE_SSL: if (!accept_complete) { debug(F100,"ck_auth_in_progress() SSL !accept_complete", "",0); return(1); } else return(0); default: return(0); } return(0); } /* C K _ K R B _ T N _ A U T H _ R E Q U E S T * * Builds a Telnet Authentication Send Negotiation providing the * list of supported authentication methods. To be used only * when accepting incoming connections as only the server (DO) side of the * Telnet negotiation is allowed to send an AUTH SEND. * * Returns: 0 on success and -1 on failure */ static unsigned char str_request[64] = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_SEND }; #ifdef GSSAPI_K5 static int ck_tn_auth_request_gsskrb5(int i) { if (ck_gssapi_is_installed() && ck_krb5_is_installed_as_server()) { if ( (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_EXCH) ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_AFTER_EXCHANGE; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_AFTER_EXCHANGE ", TN_MSG_LEN); i++; } } } #endif /* GSSAPI_K5 */ #ifdef KRB5 static int ck_tn_auth_request_krb5(int i) { if (ck_krb5_is_installed_as_server()) { #ifdef CK_SSL if ( ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) && ssl_finished_messages ) { #ifdef USE_INI_CRED_FWD if ( forward_flag && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT) ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_START_TLS; str_request[i] |= INI_CRED_FWD_ON; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_START_TLS|INI_CRED_FWD_ON ", TN_MSG_LEN); i++; } #endif /* USE_INI_CRED_FWD */ if ( (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT) ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_START_TLS; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_START_TLS ", TN_MSG_LEN); i++; } if ( tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_START_TLS; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "KERBEROS_V5 CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_START_TLS ", TN_MSG_LEN); i++; } } #ifdef CK_ENCRYPTION else { #endif /* CK_ENCRYPTION */ #endif /* CK_SSL */ #ifdef CK_ENCRYPTION #ifdef USE_INI_CRED_FWD if ( forward_flag && TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT) ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_USING_TELOPT; str_request[i] |= INI_CRED_FWD_ON; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_USING_TELOPT|INI_CRED_FWD_ON ", TN_MSG_LEN); i++; } #endif /* USE_INI_CRED_FWD */ if ( TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT) ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_USING_TELOPT; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL|ENCRYPT_USING_TELOPT ", TN_MSG_LEN); i++; } #ifdef CK_SSL } #endif /* CK_SSL */ #endif /* CK_ENCRYPTION */ if ( TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_NONE) #ifdef CK_SSL && !(ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) && tls_is_anon(0)) #endif /* CK_SSL */ ) { #ifdef CK_ENCRYPTION /* Can't perform mutual authentication without encryption */ if ( tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"KERBEROS_V5 CLIENT_TO_SERVER|MUTUAL ", TN_MSG_LEN); i++; } #endif /* CK_ENCRYPTION */ if ( tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY ) { str_request[i++] = AUTHTYPE_KERBEROS_V5; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"KERBEROS_V5 CLIENT_TO_SERVER|ONE_WAY ", TN_MSG_LEN); i++; } } } return(i); } #endif /* KRB5 */ #ifdef KRB4 static int ck_tn_auth_request_krb4(int i) { if (ck_krb4_is_installed_as_server()) { #ifdef CK_ENCRYPTION if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT) ) { str_request[i++] = AUTHTYPE_KERBEROS_V4; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_USING_TELOPT; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"KERBEROS_V4 CLIENT_TO_SERVER|MUTUAL|ENCRYPT ", TN_MSG_LEN); i++; } #endif /* CK_ENCRYPTION */ if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_NONE) ) { #ifdef CK_ENCRYPTION /* Can't perform mutual authentication without encryption */ if ( tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL ) { str_request[i++] = AUTHTYPE_KERBEROS_V4; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_MUTUAL; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"KERBEROS_V4 CLIENT_TO_SERVER|MUTUAL ", TN_MSG_LEN); i++; } #endif /* CK_ENCRYPTION */ if ( tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY ) { str_request[i++] = AUTHTYPE_KERBEROS_V4; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"KERBEROS_V4 CLIENT_TO_SERVER|ONE_WAY ", TN_MSG_LEN); i++; } } } return(i); } #endif /* KRB4 */ #ifdef CK_SRP static int ck_tn_auth_request_srp(int i) { if (ck_srp_is_installed_as_server()) { #ifndef PRE_SRP_1_4_5 /* Dont' do this yet. SRP when it uses the ENCRYPT_USING_TELOPT */ /* flag it must perform a checksum of the auth-type-pair but there */ /* is no mechansim to do that yet. */ #ifdef CK_SSL if ( ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) && ssl_finished_messages && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT)) { str_request[i++] = AUTHTYPE_SRP; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_START_TLS; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "SRP CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_START_TLS ", TN_MSG_LEN); i++; } #ifdef CK_ENCRYPTION else { #endif /* CK_ENCRYPTION */ #endif /* CK_SSL */ #ifdef CK_ENCRYPTION if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_RF && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_TELOPT) ) { str_request[i++] = AUTHTYPE_SRP; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_USING_TELOPT; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg, "SRP CLIENT_TO_SERVER|ONE_WAY|ENCRYPT_USING_TELOPT ", TN_MSG_LEN); i++; } #ifdef CK_SSL } #endif /* CK_SSL */ #endif /* CK_ENCRYPTION */ #endif /* PRE_SRP_1_4_5 */ if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_MUTUAL) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_NONE) #ifdef CK_SSL && !(ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) && tls_is_anon(0)) #endif /* CK_SSL */ ) { str_request[i++] = AUTHTYPE_SRP; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"SRP CLIENT_TO_SERVER|ONE_WAY ", TN_MSG_LEN); i++; } } return(i); } #endif /* CK_SRP */ #ifdef CK_SSL static int ck_tn_auth_request_ssl(int i) { if (ck_ssleay_is_installed() && !tls_active_flag && !ssl_active_flag && ssl_initialized ) { if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_NONE) ) { str_request[i++] = AUTHTYPE_SSL; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"SSL CLIENT_TO_SERVER|ONE_WAY ", TN_MSG_LEN); i++; } } return(i); } #endif /* CK_SSL */ #ifdef NTLM static int ck_tn_auth_request_ntlm(int i) { /* Microsoft's Telnet client won't perform authentication if */ /* NTLM is not first. */ if ( ck_ntlm_is_valid(1) ) { if (TELOPT_ME_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && TELOPT_U_MODE(TELOPT_ENCRYPTION) != TN_NG_MU && (tn_auth_how == TN_AUTH_HOW_ANY || tn_auth_how == TN_AUTH_HOW_ONE_WAY) && (tn_auth_enc == TN_AUTH_ENC_ANY || tn_auth_enc == TN_AUTH_ENC_NONE) ) { str_request[i++] = AUTHTYPE_NTLM; str_request[i] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY; str_request[i] |= AUTH_ENCRYPT_OFF; if ( deblog || tn_deb || debses ) ckstrncat(tn_msg,"NTLM CLIENT_TO_SERVER|ONE_WAY ", TN_MSG_LEN); i++; } } return(i); } #endif /* NTLM */ int #ifdef CK_ANSIC ck_tn_auth_request(void) #else ck_tn_auth_request() #endif { int i = 4, rc = -1; #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return(0); } #endif /* CK_SSL */ if ( deblog || tn_deb || debses ) strcpy(tn_msg,"TELNET SENT SB AUTHENTICATION SEND "); /* Create a list of acceptable Authentication types to send to */ /* the client and let it choose find one that we support */ /* For those authentication methods that support Encryption or */ /* Credentials Forwarding we must send all of the appropriate */ /* combinations based upon the state of */ /* TELOPT_x_MODE(TELOPT_ENCRYPTION) and forward_flag. */ if ( auth_type_user[0] == AUTHTYPE_AUTO ) { #ifdef GSSAPI_K5 i = ck_tn_auth_request_gsskrb5(i); #endif /* GSSAPI_K5 */ #ifdef KRB5 i = ck_tn_auth_request_krb5(i); #endif /* KRB5 */ #ifdef KRB4 i = ck_tn_auth_request_krb4(i); #endif /* KRB4 */ #ifdef CK_SRP i = ck_tn_auth_request_srp(i); #endif /* SRP */ #ifdef CK_SSL i = ck_tn_auth_request_ssl(i); #endif /* CK_SSL */ #ifdef NTLM i = ck_tn_auth_request_ntlm(i); #endif /* NTLM */ } else { int j; for ( j=0; jencrypt && encrypt_is_encrypting()) { debug(F111,"ck_tn_encrypting","encrypting", g_kstream->encrypt_type); return(g_kstream->encrypt_type); } #endif /* CK_ENCRYPTION */ debug(F110,"ck_tn_encrypting","not encrypting",0); return(0); } /* C K _ K R B _ D E C R Y P T I N G * Returns 1 if we are decrypting and 0 if we are not */ int #ifdef CK_ANSIC ck_tn_decrypting(VOID) #else ck_tn_decrypting() #endif /* CK_ANSIC */ { #ifdef CK_ENCRYPTION if ( g_kstream == NULL ) return(0); if ( g_kstream->decrypt && encrypt_is_decrypting()) { debug(F111,"ck_tn_decrypting","decrypting", g_kstream->decrypt_type); return(g_kstream->decrypt_type); } #endif /* CK_ENCRYPTION */ debug(F110,"ck_tn_decrypting","not decrypting",0); return(0); } /* C K _ K R B _ A U T H E N T I C A T E D * Returns the authentication type: AUTHTYPE_NULL, AUTHTYPE_KERBEROS4, * or AUTHTYPE_KERBEROS5, AUTHTYPE_SRP, ... (see ckctel.h) */ int #ifdef CK_ANSIC ck_tn_authenticated(VOID) #else ck_tn_authenticated() #endif { return(authentication_version); } /* C K _ K R B _ E N C R Y P T * encrypts n characters in s if we are encrypting */ VOID #ifdef CK_ANSIC ck_tn_encrypt( char * s, int n ) #else ck_tn_encrypt( s,n ) char * s; int n; #endif { #ifdef CK_ENCRYPTION struct kstream_data_block i; if (g_kstream->encrypt && encrypt_is_encrypting()) { #ifdef DEBUG ckhexdump("from plaintext", s, n); #endif i.ptr = s; i.length = n; g_kstream->encrypt(&i, NULL); #ifdef DEBUG ckhexdump("to cyphertext", s, n); #endif } else debug(F101,"ck_tn_encrypt not encrypting","",n); #endif /* ENCRYPTION */ } /* C K _ K R B _ D E C R Y P T * decrypts n characters in s if we are decrypting */ VOID #ifdef CK_ANSIC ck_tn_decrypt( char * s, int n ) #else ck_tn_decrypt( s,n ) char * s; int n; #endif { #ifdef CK_ENCRYPTION struct kstream_data_block i; if (g_kstream->decrypt && encrypt_is_decrypting()) { #ifdef DEBUG ckhexdump("from cyphertext", s, n); #endif i.ptr = s; i.length = n; g_kstream->decrypt(&i, NULL); #ifdef DEBUG ckhexdump("to plaintext", s, n); #endif } else debug(F101,"ck_tn_decrypt not decrypting","",n); #endif /* ENCRYPTION */ } #ifdef KRB5 /* S E N D K 5 A U T H S B * Send a Kerberos 5 Authentication Subnegotiation to host and * output appropriate Telnet Debug messages * * type - Sub Negotiation type * data - ptr to buffer containing data * len - len of buffer if not NUL terminated * * returns number of characters sent or error value */ static int #ifdef CK_ANSIC SendK5AuthSB(int type, void *data, int len) #else SendK5AuthSB(type,data,len) int type; void *data; int len; #endif { int rc; unsigned char *p = str_data + 3; unsigned char *cd = (unsigned char *)data; extern int sstelnet; #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { if (ttchk() < 0) return(0); else return(1); } #endif /* CK_SSL */ if ( type < 0 || type > 7 ) /* Check for invalid values */ return(0); if (!cd) { cd = (unsigned char *)""; len = 0; } if (len == -1) /* Use strlen() for len */ len = strlen((char *)cd); /* Construct Message */ *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS; *p++ = AUTHTYPE_KERBEROS_V5; *p = AUTH_CLIENT_TO_SERVER; *p |= auth_how; #ifdef CK_ENCRYPTION *p |= auth_crypt; #endif #ifdef USE_INI_CRED_FWD if (auth_fwd) *p |= INI_CRED_FWD_ON; #endif /* USE_INI_CRED_FWD */ p++; *p++ = type; while (len-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; /* Handle Telnet Debugging Messages */ if (deblog || tn_deb || debses) { int deblen=p-str_data-2; char *s=NULL; int mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) | auth_crypt #ifdef USE_INI_CRED_FWD | (auth_fwd?INI_CRED_FWD_ON:INI_CRED_FWD_OFF) #endif /* USE_INI_CRED_FWD */ ; switch (type) { case 0: s = "AUTH"; break; case 1: s = "REJECT"; break; case 2: s = "ACCEPT"; break; case 3: s = "RESPONSE"; break; case 4: s = "FORWARD"; break; case 5: s = "FORWARD_ACCEPT"; break; case 6: s = "FORWARD_REJECT"; break; case 7: s = "TLS_VERIFY"; break; } ckmakxmsg(tn_msg,TN_MSG_LEN, "TELNET SENT SB ", TELOPT(TELOPT_AUTHENTICATION)," ", str_data[3] == TELQUAL_IS ? "IS" : str_data[3] == TELQUAL_REPLY ? "REPLY" : "???"," ", AUTHTYPE_NAME(authentication_version)," ", AUTHMODE_NAME(mode)," ", s," ",NULL); tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } /* Send data */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif rc = ttol((CHAR *)str_data, p - str_data); #ifdef OS2 ReleaseTelnetMutex(); #endif debug(F111,"SendK5AuthSB","ttol()",rc); return(rc); } #endif /* KRB5 */ #ifdef KRB4 /* S E N D K 4 A U T H S B * Send a Kerberos 4 Authentication Subnegotiation to host and * output appropriate Telnet Debug messages * * type - Sub Negotiation type * data - ptr to buffer containing data * len - len of buffer if not NUL terminated * * returns number of characters sent or error value */ static int #ifdef CK_ANSIC SendK4AuthSB(int type, void *data, int len) #else SendK4AuthSB(type,data,len) int type; void *data; int len; #endif { int rc; unsigned char *p = str_data + 3; unsigned char *cd = (unsigned char *)data; extern int sstelnet; int mode = (auth_how & AUTH_HOW_MASK) | auth_crypt; if ( type < 0 || type > 4 ) /* Check for invalid values */ return(0); #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { if (ttchk() < 0) return(0); else return(1); } #endif /* CK_SSL */ if (!cd) { cd = (unsigned char *)""; len = 0; } if (len == -1) /* Use strlen() for len */ len = strlen((char *)cd); /* Construct Message */ *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS; *p++ = AUTHTYPE_KERBEROS_V4; *p = AUTH_CLIENT_TO_SERVER; *p |= mode; p++; *p++ = type; while (len-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; /* Handle Telnet Debugging Messages */ if (deblog || tn_deb || debses) { int deblen=p-str_data-2; char *s=NULL; switch (type) { case 0: s = "AUTH"; break; case 1: s = "REJECT"; break; case 2: s = "ACCEPT"; break; case 3: s = "CHALLENGE"; break; case 4: s = "RESPONSE"; break; } ckmakxmsg(tn_msg,TN_MSG_LEN,"TELNET SENT SB ", TELOPT(TELOPT_AUTHENTICATION)," ", str_data[3] == TELQUAL_IS ? "IS" : (str_data[3] == TELQUAL_REPLY ? "REPLY" : "???")," ", AUTHTYPE_NAME(authentication_version)," ", AUTHMODE_NAME(mode)," ", s," ",NULL); tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } /* Send data */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif rc = ttol((CHAR *)str_data, p - str_data); #ifdef OS2 ReleaseTelnetMutex(); #endif debug(F111,"SendK4AuthSB","ttol()",rc); return(rc); } #endif /* KRB4 */ #ifdef CK_SRP /* S E N D S R P A U T H S B * Send a SRP Authentication Subnegotiation to host and * output appropriate Telnet Debug messages * * type - Sub Negotiation type * data - ptr to buffer containing data * len - len of buffer if not NUL terminated * * returns number of characters sent or error value */ static int #ifdef CK_ANSIC SendSRPAuthSB(int type, void *data, int len) #else SendSRPAuthSB(type,data,len) int type; void *data; int len; #endif { int rc; unsigned char *p = str_data + 3; unsigned char *cd = (unsigned char *)data; extern int sstelnet; /* Check for invalid values */ if ( type != SRP_EXP && type != SRP_RESPONSE && type != SRP_REJECT && type != SRP_ACCEPT && type != SRP_CHALLENGE && type != SRP_PARAMS && type != SRP_AUTH) return(0); if (len == -1) /* Use strlen() for len */ len = strlen((char *)cd); /* Construct Message */ *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS; *p++ = AUTHTYPE_SRP; *p = AUTH_CLIENT_TO_SERVER; *p |= auth_how; #ifdef CK_ENCRYPTION *p |= auth_crypt; #endif p++; *p++ = type; while (len-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; /* Handle Telnet Debugging Messages */ if (deblog || tn_deb || debses) { int deblen=p-str_data-2; char *s=NULL; int mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) | auth_crypt; switch (type) { case 0: s = "AUTH"; break; case 1: s = "REJECT"; break; case 2: s = "ACCEPT"; break; case 3: s = "CHALLENGE"; break; case 4: s = "RESPONSE"; break; case 5: s = "FORWARD"; break; case 6: s = "FORWARD_ACCEPT"; break; case 7: s = "FORWARD_REJECT"; break; case 8: s = "EXP"; break; case 9: s = "PARAMS"; break; } ckmakxmsg(tn_msg,TN_MSG_LEN, "TELNET SENT SB ", TELOPT(TELOPT_AUTHENTICATION)," ", str_data[3] == TELQUAL_REPLY ? "REPLY" : str_data[3] == TELQUAL_IS ? "IS" : "???"," ", AUTHTYPE_NAME(authentication_version)," ", AUTHMODE_NAME(mode)," ", s," ",NULL); tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } /* Send data */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif rc = ttol((CHAR *)str_data, p - str_data); #ifdef OS2 ReleaseTelnetMutex(); #endif return(rc); } #endif /* CK_SRP */ #ifdef CK_ENCRYPTION /* * Function: Enable or disable the encryption process. * * Parameters: * enable - TRUE to enable, FALSE to disable. */ static VOID #ifdef CK_ANSIC auth_encrypt_enable(BOOL enable) #else auth_encrypt_enable(enable) BOOL enable; #endif { encrypt_flag = enable; } #endif /* * Function: Abort the authentication process * * Parameters: */ static VOID #ifdef CK_ANSIC auth_abort(char *errmsg, long r) #else auth_abort(errmsg,r) char *errmsg; long r; #endif { char buf[9]; extern int sstelnet; #ifdef CK_SSL if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { return; } #endif /* CK_SSL */ debug(F111,"auth_abort",errmsg,r); /* Construct Telnet Debugging messages */ if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION), " IS ",AUTHTYPE_NAME(AUTHTYPE_NULL)," ", AUTHTYPE_NAME(AUTHTYPE_NULL)," IAC SE", NULL,NULL,NULL,NULL,NULL ); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } /* Construct the Abort message to send to the host */ /* Basicly we change the authentication type to NULL */ sprintf(buf, "%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION, sstelnet ? TELQUAL_REPLY : TELQUAL_IS, AUTHTYPE_NULL, AUTHTYPE_NULL, IAC, SE); /* safe */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol((CHAR *)buf, 8); #ifdef OS2 ReleaseTelnetMutex(); #endif /* If there is an error message, and error number construct */ /* an explanation to display to the user */ if (errmsg != NULL) { ckstrncpy(strTmp, errmsg, AUTHTMPBL); } else strTmp[0] = '\0'; if (r != AUTH_SUCCESS) { ckstrncat(strTmp, "\r\n",AUTHTMPBL); #ifdef KRB4 if ( authentication_version == AUTHTYPE_KERBEROS_V4 ) { ckstrncat(strTmp, (char *)krb_get_err_text_entry(r), AUTHTMPBL); debug(F111,"auth_abort",(char *)krb_get_err_text_entry(r),r); } #endif #ifdef KRB5 if ( authentication_version == AUTHTYPE_KERBEROS_V5 ) { ckstrncat(strTmp, error_message(r),AUTHTMPBL); debug(F111,"auth_abort",error_message(r),r); } #endif } printf("Authentication failed: %s\r\n",strTmp); #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_LI && ckxlogging) { cksyslog(SYSLG_LI, 0, "Telnet authentication failure", (char *) szUserNameRequested, strTmp); } #endif /* CKSYSLOG */ authentication_version = AUTHTYPE_NULL; } /* * Function: Copy data to buffer, doubling IAC character if present. * */ int #ifdef CK_ANSIC copy_for_net(unsigned char *to, unsigned char *from, int c) #else copy_for_net(to,from,c) unsigned char *to; unsigned char *from; int c; #endif { int n; n = c; debug(F111,"copy_for_net","before",n); while (c-- > 0) { if ((*to++ = *from++) == IAC) { n++; *to++ = IAC; } } debug(F111,"copy_for_net","after",n); return n; } #ifdef CK_SSL /* S E N D S S L A U T H S B * Send a SSL Authentication Subnegotiation to host and * output appropriate Telnet Debug messages * * type - Sub Negotiation type * data - ptr to buffer containing data * len - len of buffer if not NUL terminated * * returns number of characters sent or error value */ int #ifdef CK_ANSIC SendSSLAuthSB(int type, void *data, int len) #else SendSSLAuthSB(type,data,len) int type; void *data; int len; #endif { int rc; unsigned char *p = str_data + 3; unsigned char *cd = (unsigned char *)data; extern int sstelnet; /* Check for invalid values */ if ( type != SSL_START && type != SSL_ACCEPT && type != SSL_REJECT) return(0); if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { if (ttchk() < 0) return(0); else return(1); } if (len == -1) /* Use strlen() for len */ len = strlen((char *)cd); /* Construct Message */ *p++ = sstelnet ? TELQUAL_REPLY : TELQUAL_IS; *p++ = AUTHTYPE_SSL; *p = AUTH_CLIENT_TO_SERVER; *p |= auth_how; #ifdef CK_ENCRYPTION *p |= auth_crypt; #endif p++; *p++ = type; while (len-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; /* Handle Telnet Debugging Messages */ if (deblog || tn_deb || debses) { int i; int deblen=p-str_data-2; char *s=NULL; int mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) | (auth_crypt?AUTH_ENCRYPT_USING_TELOPT:AUTH_ENCRYPT_OFF); switch (type) { case SSL_START: s = "START"; break; case SSL_ACCEPT: s = "ACCEPT"; break; case SSL_REJECT: s = "REJECT"; break; } ckmakxmsg(tn_msg,TN_MSG_LEN, "TELNET SENT SB ", TELOPT(TELOPT_AUTHENTICATION)," ", str_data[3] == TELQUAL_REPLY ? "REPLY" : str_data[3] == TELQUAL_IS ? "IS" : "???"," ", AUTHTYPE_NAME(authentication_version)," ", AUTHMODE_NAME(mode)," ", s," ",NULL); tn_hex((CHAR *)tn_msg,TN_MSG_LEN,&str_data[7],deblen-7); ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } /* Send data */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif rc = ttol((CHAR *)str_data, p - str_data); #ifdef OS2 ReleaseTelnetMutex(); #endif return(rc); } #endif /* CK_SSL */ int tn_how_ok(int how) { switch ( tn_auth_how ) { case TN_AUTH_HOW_ANY: return(1); case TN_AUTH_HOW_ONE_WAY: return((how & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY); case TN_AUTH_HOW_MUTUAL: return((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL); default: return(0); } } int tn_enc_ok(int enc) { switch ( tn_auth_enc ) { case TN_AUTH_ENC_ANY: if ((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS && (!ck_ssleay_is_installed() #ifdef CK_SSL || !ssl_finished_messages || !(tls_active_flag || ssl_active_flag) #endif /* CK_SSL */ )) { #ifdef CK_SSL if (!ssl_finished_messages) debug(F100,"tn_enc_ok !ssl_finished_messages","",0); #endif /* CK_SSL */ return(0); } return(1); case TN_AUTH_ENC_NONE: return((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_OFF); case TN_AUTH_ENC_TELOPT: return((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT); case TN_AUTH_ENC_EXCH: return((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_AFTER_EXCHANGE); case TN_AUTH_ENC_TLS: return(((enc & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) && ck_ssleay_is_installed() #ifdef CK_SSL && ssl_finished_messages && (tls_active_flag || ssl_active_flag) #endif /* CK_SSL */ ); default: return(0); } } static int atok(int at) { int i; if ( auth_type_user[0] == AUTHTYPE_AUTO ) return(1); if ( auth_type_user[0] == AUTHTYPE_NULL ) return(0); for ( i=0; i 512 ? 512 : end_sub; memcpy(send_list,parsedat,send_len); /* Search the list of acceptable Authentication types sent from */ /* the host and find one that we support */ /* For Kerberos authentications, try to determine if we have a */ /* valid TGT, if not skip over the authentication type because */ /* we wouldn't be able to successfully login anyway. Perhaps */ /* there is another supported authentication which we could use */ #ifdef NO_FTP_AUTH /* If the userid is "ftp" or "anonymous" refuse to perform AUTH */ /* for Kerberos or SRP. */ #endif /* NO_FTP_AUTH */ if ( auth_type_user[0] == AUTHTYPE_AUTO ) { for (i = 2; i+1 <= end_sub; i += 2) { #ifdef NTLM if (parsedat[i] == AUTHTYPE_NTLM && ck_ntlm_is_valid(1) && ntlm_auth_send() == 0) { if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef CK_ENCRYPTION /* NTLM does not support Telnet Encryption */ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #endif /* CK_ENCRYPTION */ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; authentication_version = AUTHTYPE_NTLM; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* NTLM */ #ifdef CK_SSL if ( parsedat[i] == AUTHTYPE_SSL && ssl_initialized && #ifdef SSLDLL ck_ssleay_is_installed() && #endif /* SSLDLL */ !tls_active_flag && !ssl_active_flag #ifndef USE_CERT_CB && tls_load_certs(ssl_ctx,ssl_con,0) #endif /* USE_CERT_CB */ ) { if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef CK_ENCRYPTION /* SSL does not support Telnet Encryption */ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #endif /* CK_ENCRYPTION */ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; authentication_version = AUTHTYPE_SSL; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* SSL */ #ifdef CK_SRP if ( parsedat[i] == AUTHTYPE_SRP #ifdef SRPDLL && hSRP #endif /* SRPDLL */ #ifdef NO_FTP_AUTH && strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) #endif /* NO_FTP_AUTH */ ) { if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef PRE_SRP_1_4_5 if (parsedat[i+1] & AUTH_ENCRYPT_MASK) /* Do not support ENCRYPT_USING_TELOPT yet. */ continue; #endif /* PRE_SRP_1_4_5 */ if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT) && (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF || TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #ifdef CK_ENCRYPTION if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; } #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if ( auth_crypt == AUTH_ENCRYPT_START_TLS && ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_SSL */ authentication_version = AUTHTYPE_SRP; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* SRP */ #ifdef GSSAPI_KRB5 if (parsedat[i] == AUTHTYPE_GSSAPI_KRB5 && (parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_AFTER_EXCHANGE && #ifdef OS2 hGSSAPI && #endif /* OS2 */ #ifdef NO_FTP_AUTH strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) && #endif /* NO_FTP_AUTH */ ck_gssapi_is_installed() && !gssk5_msg) { if ( !gssk5_auth_send(parsedat[i+1] & AUTH_HOW_MASK, parsedat[i+1] & AUTH_ENCRYPT_MASK, parsedat[i+1] & INI_CRED_FWD_MASK) ) { /* If we are auto-getting TGTs, try */ if ( !ck_krb5_is_tgt_valid() ) { printf("Kerberos 5: Ticket Getting Ticket not valid.\r\n"); } gssk5_msg = 1; } else if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #ifdef CK_ENCRYPTION if ( auth_crypt == AUTH_ENCRYPT_AFTER_EXCHANGE ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_ENCRYPTION */ auth_fwd = parsedat[i+1] & INI_CRED_FWD_MASK; authentication_version = AUTHTYPE_GSSAPI_KRB5; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* GSSAPI_KRB5 */ #ifdef KRB5 if (parsedat[i] == AUTHTYPE_KERBEROS_V5 && #ifdef OS2 hKRB5_32 && #endif /* OS2 */ #ifdef NO_FTP_AUTH strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) && #endif /* NO_FTP_AUTH */ ck_krb5_is_installed() && !krb5_msg) { /* Without encryption we can't perform mutual authentication */ if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !ck_crypt_is_installed()) continue; /* Skip over entries that request credential forwarding */ /* if we are not forwarding. */ if ((!forward_flag && (parsedat[i+1] & INI_CRED_FWD_MASK)) || (forward_flag && ((parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY))) continue; if ( !k5_auth_send(parsedat[i+1] & AUTH_HOW_MASK, parsedat[i+1] & AUTH_ENCRYPT_MASK, parsedat[i+1] & INI_CRED_FWD_MASK) ) { /* If we are auto-getting TGTs, try */ if ( !ck_krb5_is_tgt_valid() ) { printf("Kerberos 5: Ticket Getting Ticket not valid.\r\n"); } krb5_msg = 1; } else if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT) && (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF || TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF)) continue; if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) && (!ck_ssleay_is_installed() #ifdef CK_SSL || !(tls_active_flag || ssl_active_flag) #endif /* CK_SSL */ )) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #ifdef CK_ENCRYPTION if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; } #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if ( auth_crypt == AUTH_ENCRYPT_START_TLS && ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_SSL */ auth_fwd = parsedat[i+1] & INI_CRED_FWD_MASK; authentication_version = AUTHTYPE_KERBEROS_V5; auth_how = parsedat[i+1] & AUTH_HOW_MASK; if ( auth_how == AUTH_HOW_ONE_WAY ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } break; } } #endif /* KRB5 */ #ifdef KRB4 if (parsedat[i] == AUTHTYPE_KERBEROS_V4 && #ifdef OS2 hKRB4_32 && #endif /* OS2 */ #ifdef NO_FTP_AUTH strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) && #endif /* NO_FTP_AUTH */ ck_krb4_is_installed() && !krb4_msg) { int rc = 0; /* Without encryption we can't perform mutual authentication */ if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !ck_crypt_is_installed() ) continue; if ( !k4_auth_send() ) { /* If we are auto-getting TGTs, try */ if ( !ck_krb4_is_tgt_valid() ) { printf("Kerberos 4: Ticket Getting Ticket not valid.\r\n"); } krb4_msg = 1; } else if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef CK_ENCRYPTION if ((parsedat[i+1] & AUTH_ENCRYPT_MASK) && (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF || TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; } #endif /* CK_ENCRYPTION */ authentication_version = AUTHTYPE_KERBEROS_V4; auth_how = parsedat[i+1] & AUTH_HOW_MASK; if ( auth_how == AUTH_HOW_ONE_WAY ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } break; } } #endif /* KRB4 */ } } else { for (i = 2; i+1 <= end_sub; i += 2) { #ifdef CK_SSL if ( atok(AUTHTYPE_SSL) && parsedat[i] == AUTHTYPE_SSL && #ifdef SSLDLL ck_ssleay_is_installed() && #endif /* SSLDLL */ !tls_active_flag && !ssl_active_flag && ssl_initialized #ifndef USE_CERT_CB && tls_load_certs(ssl_ctx,ssl_con,0) #endif /* USE_CERT_CB */ ) { if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef CK_ENCRYPTION /* SSL does not support Telnet Encryption */ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #endif /* CK_ENCRYPTION */ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; authentication_version = AUTHTYPE_SSL; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* SSL */ #ifdef CK_SRP if ( atok(AUTHTYPE_SRP) && parsedat[i] == AUTHTYPE_SRP #ifdef SRPDLL && hSRP #endif /* SRPDLL */ #ifdef NO_FTP_AUTH && strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) #endif /* NO_FTP_AUTH */ ) { if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef PRE_SRP_1_4_5 if (parsedat[i+1] & AUTH_ENCRYPT_MASK) /* Do not support ENCRYPT_USING_TELOPT yet. */ continue; #endif /* PRE_SRP_1_4_5 */ if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT) && (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF || TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF)) continue; if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) && (!ck_ssleay_is_installed() #ifdef CK_SSL || !(tls_active_flag || ssl_active_flag) #endif /* CK_SSL */ )) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #ifdef CK_ENCRYPTION if ( auth_crypt == AUTH_ENCRYPT_USING_TELOPT ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; } #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if ( auth_crypt == AUTH_ENCRYPT_START_TLS && ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_SSL */ authentication_version = AUTHTYPE_SRP; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* SRP */ #ifdef GSSAPI_KRB5 if (atok(AUTHTYPE_GSSAPI_KRB5) && parsedat[i] == AUTHTYPE_GSSAPI_KRB5 && (parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_AFTER_EXCHANGE && #ifdef OS2 hGSSAPI && #endif /* OS2 */ #ifdef NO_FTP_AUTH strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) && #endif /* NO_FTP_AUTH */ ck_gssapi_is_installed() && !gssk5_msg) { if ( !gssk5_auth_send(parsedat[i+1] & AUTH_HOW_MASK, parsedat[i+1] & AUTH_ENCRYPT_MASK, parsedat[i+1] & INI_CRED_FWD_MASK) ) { /* If we are auto-getting TGTs, try */ if ( !ck_krb5_is_tgt_valid() ) { printf("Kerberos 5: Ticket Getting Ticket not valid.\r\n"); } gssk5_msg = 1; } else if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #ifdef CK_ENCRYPTION if ( auth_crypt == AUTH_ENCRYPT_AFTER_EXCHANGE ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_ENCRYPTION */ auth_fwd = parsedat[i+1] & INI_CRED_FWD_MASK; authentication_version = AUTHTYPE_GSSAPI_KRB5; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* GSSAPI_KRB5 */ #ifdef KRB5 if ( atok(AUTHTYPE_KERBEROS_V5) && parsedat[i] == AUTHTYPE_KERBEROS_V5 && #ifdef OS2 hKRB5_32 && #endif /* OS2 */ #ifdef NO_FTP_AUTH strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) && #endif /* NO_FTP_AUTH */ ck_krb5_is_installed() && !krb5_msg) { /* Without encryption we can't perform mutual authentication */ if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !ck_crypt_is_installed()) continue; /* Skip over entries that request credential forwarding */ /* if we are not forwarding. */ if ((!forward_flag && (parsedat[i+1] & INI_CRED_FWD_MASK)) || (forward_flag && ((parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY))) continue; if ( !k5_auth_send(parsedat[i+1] & AUTH_HOW_MASK, parsedat[i+1] & AUTH_ENCRYPT_MASK, parsedat[i+1] & INI_CRED_FWD_MASK) ) { /* If we are auto-getting TGTs, try */ if ( !ck_krb5_is_tgt_valid() ) { printf( "Kerberos 5: Ticket Getting Ticket not valid.\r\n"); } krb5_msg = 1; } else if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT) && (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF || TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF)) continue; if (((parsedat[i+1] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) && (!ck_ssleay_is_installed() #ifdef CK_SSL || !(tls_active_flag || ssl_active_flag) #endif /* CK_SSL */ )) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #ifdef CK_ENCRYPTION if (auth_crypt) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; } #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if ( auth_crypt == AUTH_ENCRYPT_START_TLS && ck_ssleay_is_installed() && (tls_active_flag || ssl_active_flag) ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_SSL */ authentication_version = AUTHTYPE_KERBEROS_V5; auth_how = parsedat[i+1] & AUTH_HOW_MASK; if ( auth_how == AUTH_HOW_ONE_WAY ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } break; } } #endif /* KRB5 */ #ifdef KRB4 if ( atok(AUTHTYPE_KERBEROS_V4) && parsedat[i] == AUTHTYPE_KERBEROS_V4 && #ifdef OS2 hKRB4_32 && #endif /* OS2 */ #ifdef NO_FTP_AUTH strcmp("ftp",szUserName) && strcmp("anonymous",szUserName) && #endif /* NO_FTP_AUTH */ ck_krb4_is_installed() && !krb4_msg) { int rc = 0; /* Without encryption we can't perform mutual authentication */ if ( (parsedat[i+1] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !ck_crypt_is_installed()) continue; if ( !k4_auth_send() ) { /* If we are auto-getting TGTs, try */ if ( !ck_krb4_is_tgt_valid() ) { printf("Kerberos 4: Ticket Getting Ticket not valid.\r\n"); } krb4_msg = 1; } else if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef CK_ENCRYPTION if ((parsedat[i+1] & AUTH_ENCRYPT_MASK) && (TELOPT_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_RF || TELOPT_U_MODE(TELOPT_ENCRYPTION) == TN_NG_RF)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; if (auth_crypt) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; } #endif /* CK_ENCRYPTION */ authentication_version = AUTHTYPE_KERBEROS_V4; auth_how = parsedat[i+1] & AUTH_HOW_MASK; if ( auth_how == AUTH_HOW_ONE_WAY ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } break; } } #endif /* KRB4 */ #ifdef NTLM if ( atok(AUTHTYPE_NTLM) && parsedat[i] == AUTHTYPE_NTLM && ck_ntlm_is_valid(1) && ntlm_auth_send() == 0) { if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER && tn_how_ok(parsedat[i+1]) && tn_enc_ok(parsedat[i+1])) { #ifdef CK_ENCRYPTION /* NTLM does not support Telnet Encryption */ if ((parsedat[i+1] & AUTH_ENCRYPT_MASK)) continue; auth_crypt = parsedat[i+1] & AUTH_ENCRYPT_MASK; #endif /* CK_ENCRYPTION */ TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; authentication_version = AUTHTYPE_NTLM; auth_how = parsedat[i+1] & AUTH_HOW_MASK; break; } } #endif /* NTLM */ } } if (auth_how == -1) { /* Did we find one? */ switch ( auth_type_user[0] ) { /* If not, abort the negotiation */ case AUTHTYPE_NULL: auth_abort("User refused to accept any authentication method",0); break; case AUTHTYPE_AUTO: auth_abort("No authentication method available", 0); break; default: { char msg[80]; ckmakmsg(msg,80,AUTHTYPE_NAME(auth_type_user[0]), " could not be negotiated",NULL,NULL ); auth_abort(msg, 0); } } auth_finished(AUTH_REJECT); return AUTH_FAILURE; } printf("Authenticating with %s\r\n", AUTHTYPE_NAME(authentication_version)); /* Send Telnet Auth Name message (if necessary) */ switch ( authentication_version ) { case AUTHTYPE_SRP: case AUTHTYPE_KERBEROS_V4: case AUTHTYPE_KERBEROS_V5: case AUTHTYPE_GSSAPI_KRB5: /* if we do not have a name to login with get one now. */ while ( szUserName[0] == '\0' ) { extern char * tn_pr_uid; int ok = uq_txt(NULL, tn_pr_uid && tn_pr_uid[0] ? tn_pr_uid : "Host Userid: ", 1, NULL, szUserName, 63, NULL,DEFAULT_UQ_TIMEOUT); if ( !ok ) return AUTH_FAILURE; } plen = strlen(szUserName); pname = (unsigned char *) szUserName; /* Construct Telnet Debugging Message */ if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION), " NAME ",(char *)pname," IAC SE",NULL, NULL,NULL,NULL,NULL,NULL,NULL ); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } /* Construct and send Authentication Name subnegotiation */ if ( plen < sizeof(buf) - 6 ) { sprintf((char *)buf, "%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME); memcpy(&buf[4], pname, plen); /* safe */ sprintf((char *)&buf[plen + 4], "%c%c", IAC, SE); /* safe */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol((CHAR *)buf, plen+6); #ifdef OS2 ReleaseTelnetMutex(); #endif } else { sprintf((char *)buf, "%c%c%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, IAC, SE); /* safe */ #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol((CHAR *)buf, 6); #ifdef OS2 ReleaseTelnetMutex(); #endif } } /* Construct Authentication Mode subnegotiation message (if necessary) */ switch ( authentication_version ) { case AUTHTYPE_SRP: case AUTHTYPE_KERBEROS_V4: case AUTHTYPE_KERBEROS_V5: case AUTHTYPE_GSSAPI_KRB5: case AUTHTYPE_NTLM: mode = AUTH_CLIENT_TO_SERVER | (auth_how & AUTH_HOW_MASK) | auth_crypt #ifdef USE_INI_CRED_FWD | (((authentication_version == AUTHTYPE_KERBEROS_V5) && auth_fwd)?INI_CRED_FWD_ON:INI_CRED_FWD_OFF) #endif /* USE_INI_CRED_FWD */ ; sprintf((char *)buf, "%c%c%c%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_IS, authentication_version, mode, KRB_AUTH); /* safe */ break; } /* Send initial authentication data */ switch ( authentication_version ) { #ifdef CK_SSL case AUTHTYPE_SSL: SendSSLAuthSB(SSL_START,NULL,0); break; #endif /* SSL */ #ifdef CK_SRP case AUTHTYPE_SRP: sprintf(&buf[7], "%c%c", IAC, SE); /* safe */ if (deblog || tn_deb || debses) { ckmakxmsg(tn_msg,TN_MSG_LEN, "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION), " IS ",AUTHTYPE_NAME(authentication_version), " AUTH ",AUTHMODE_NAME(mode)," IAC SE", NULL,NULL,NULL,NULL,NULL ); debug(F100,tn_msg,"",0); if (tn_deb || debses) tn_debug(tn_msg); } #ifdef OS2 RequestTelnetMutex( SEM_INDEFINITE_WAIT ); #endif ttol((CHAR *)buf, 9); #ifdef OS2 ReleaseTelnetMutex(); #endif break; #endif /* SRP */ #ifdef NTLM case AUTHTYPE_NTLM: { int length = 0; for ( i=0 ; i= 0; --i) { register int x; x = (unsigned int)k4_challenge[i] + 1; k4_challenge[i] = x; /* ignore overflow */ if (x < 256) /* if no overflow, all done */ break; } ckhexdump("auth_send k4_challenge+1",k4_challenge,8); #ifdef MIT_CURRENT data.data = k4_challenge; data.length = 8; encdata.ciphertext.data = k4_challenge; encdata.ciphertext.length = 8; encdata.enctype = ENCTYPE_UNKNOWN; if (code = krb5_c_encrypt(k5_context, &k4_krbkey, 0, 0, &data, &encdata)) { com_err("libtelnet", code, "while encrypting random key"); return(0); } #else /* MIT_CURRENT */ #ifdef NT des_ecb_encrypt(k4_challenge, k4_challenge, k4_sched, 1); #else /* NT */ des_ecb_encrypt(&k4_challenge, &k4_challenge, k4_sched, 1); #endif /* NT */ ckhexdump("auth_send des_ecb_encrypt(k4_session_key,k4_challenge,1)", k4_challenge,8); #endif /* MIT_CURRENT */ } #endif /* ENCRYPTION */ #endif /* REMOVE_FOR_EXPORT */ break; #endif /* KRB4 */ #ifdef GSSAPI_KRB5 case AUTHTYPE_GSSAPI_KRB5: for ( i=0 ; i 63 ? 63 : (end_sub-2); if ( len > 0 && (len + 1) < sizeof(szUserNameRequested)) { memcpy(szUserNameRequested,&parsedat[2],len); /* safe */ szUserNameRequested[len] = '\0'; } else szUserNameRequested[0] = '\0'; debug(F111,"auth_name szUserNameRequested",szUserNameRequested,len); return(AUTH_SUCCESS); } /* * Function: Parse the athorization sub-options and reply. * * Parameters: * parsedat - sub-option string to parse. * * end_sub - last charcter position in parsedat. */ int auth_parse(unsigned char *parsedat, int end_sub) { int rc = AUTH_FAILURE; switch (parsedat[1]) { case TELQUAL_SEND: rc = auth_send(parsedat, end_sub); break; case TELQUAL_REPLY: rc= auth_reply(parsedat, end_sub); break; case TELQUAL_IS: rc = auth_is(parsedat, end_sub); break; case TELQUAL_NAME: rc = auth_name(parsedat, end_sub); break; } debug(F111,"auth_parse","rc",rc); return(rc); } /* * Function: Initialization routine called kstream encryption system. * * Parameters: * data - user data. */ int #ifdef CK_ANSIC auth_init(kstream ks) #else auth_init(ks) kstream_ptr ks; #endif { #ifdef FORWARD forwarded_tickets = 0; /* were tickets forwarded? */ #endif /* FORWARD */ #ifdef CK_ENCRYPTION encrypt_init(ks,cx_type); #endif return 0; } /* * Function: Destroy routine called kstream encryption system. * * Parameters: * data - user data. */ VOID #ifdef CK_ANSIC auth_destroy(void) #else auth_destroy() #endif { } /* * Function: Callback to encrypt a block of characters * * Parameters: * out - return as pointer to converted buffer. * * in - the buffer to convert * * Returns: number of characters converted. */ int #ifdef CK_ANSIC auth_encrypt(struct kstream_data_block *out, struct kstream_data_block *in) #else auth_encrypt(out,in) struct kstream_data_block *out; struct kstream_data_block *in; #endif { out->ptr = in->ptr; out->length = in->length; return(out->length); } /* * Function: Callback to decrypt a block of characters * * Parameters: * out - return as pointer to converted buffer. * * in - the buffer to convert * * Returns: number of characters converted. */ int #ifdef CK_ANSIC auth_decrypt(struct kstream_data_block *out, struct kstream_data_block *in) #else auth_decrypt(out,in) struct kstream_data_block *out; struct kstream_data_block *in; #endif { out->ptr = in->ptr; out->length = in->length; return(out->length); } #ifdef KRB4 #ifdef NT void ck_krb4_debug(int x) { set_krb_debug(x); set_krb_ap_req_debug(x); } #endif /* NT */ int ck_krb4_autoget_TGT(char * realm) { extern struct krb_op_data krb_op; extern struct krb4_init_data krb4_init; char passwd[PWD_SZ]; char prompt[256]; char * saverealm=NULL; int rc = -1; extern char * k4prprompt; extern char * k4pwprompt; ini_kerb(); /* Place defaults in above structs */ passwd[0] = '\0'; if ( krb4_init.principal == NULL || krb4_init.principal[0] == '\0') { int ok = uq_txt(NULL, k4prprompt && k4prprompt[0] ? k4prprompt : "Kerberos 4 Principal: ", 2, NULL, passwd,PWD_SZ-1, NULL, DEFAULT_UQ_TIMEOUT); if ( ok && passwd[0] ) makestr(&krb4_init.principal,passwd); else return(0); } /* Save realm in init structure so it can be restored */ if ( realm ) { saverealm = krb4_init.realm; krb4_init.realm = realm; } if ( passwd[0] || !(pwbuf[0] && pwflg) ) { int ok; if ( k4pwprompt && k4pwprompt[0] && (strlen(k4pwprompt) + strlen(krb4_init.principal) + strlen(krb4_init.realm) - 4) < sizeof(prompt)) { sprintf(prompt,k4pwprompt,krb4_init.principal,krb4_init.realm); } else ckmakxmsg(prompt,sizeof(prompt), "Kerberos 4 Password for ",krb4_init.principal,"@", krb4_init.realm,": ", NULL,NULL,NULL,NULL,NULL,NULL,NULL); ok = uq_txt(NULL,prompt,2,NULL,passwd,PWD_SZ-1,NULL, DEFAULT_UQ_TIMEOUT); if ( !ok ) passwd[0] = '\0'; } else { ckstrncpy(passwd,pwbuf,sizeof(passwd)); #ifdef OS2 if ( pwcrypt ) ck_encrypt((char *)passwd); #endif /* OS2 */ } if ( passwd[0] ) { makestr(&krb4_init.password,passwd); rc = ck_krb4_initTGT(&krb_op, &krb4_init); free(krb4_init.password); krb4_init.password = NULL; } krb4_init.password = NULL; memset(passwd,0,PWD_SZ); /* restore realm to init structure if needed */ if ( saverealm ) krb4_init.realm = saverealm; return(rc == 0); } char * ck_krb4_realmofhost(char *host) { return (char *)krb_realmofhost(host); } /* * * K4_auth_send - gets authentication bits we need to send to KDC. * * Result is left in auth * * Returns: 0 on failure, 1 on success */ static int #ifdef CK_ANSIC k4_auth_send(void) #else k4_auth_send() #endif { int r=0; /* Return value */ char instance[INST_SZ+1]=""; char *realm=NULL; char tgt[4*REALM_SZ+1]; memset(instance, 0, sizeof(instance)); #ifdef COMMENT /* we only need to call krb_get_phost if the hostname */ /* is not fully qualified. But we have already done */ /* this in netopen() call. This will save a round of */ /* DNS queries. */ debug(F110,"k4_auth_send","krb_get_phost",0); if (realm = (char *)krb_get_phost(szHostName)) { ckstrncpy(instance, realm, INST_SZ); } #else /* COMMENT */ { char *p; ckstrncpy(instance, szHostName, INST_SZ); for ( p=instance; *p && *p != '.' ; p++ ); *p = '\0'; } #endif /* COMMENT */ debug(F110,"k4_auth_send","krb_get_realmofhost",0); realm = (char *)krb_realmofhost(szHostName); if (!realm) { strcpy(strTmp, "Can't find realm for host \""); ckstrncat(strTmp, szHostName,AUTHTMPBL); ckstrncat(strTmp, "\"",AUTHTMPBL); printf("?Kerberos 4 error: %s\r\n",strTmp); krb4_errno = r; makestr(&krb4_errmsg,strTmp); return(0); } ckmakmsg(tgt,sizeof(tgt),"krbtgt.",realm,"@",realm); r = ck_krb4_tkt_isvalid(tgt); if ( r <= 0 && krb4_autoget ) ck_krb4_autoget_TGT(realm); debug(F110,"k4_auth_send","krb_mk_req",0); r = krb_mk_req(&k4_auth, krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME, instance, realm, 0); if (r == 0) { debug(F110,"k4_auth_send","krb_get_cred",0); r = krb_get_cred(krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME, instance, realm, &cred); if (r) debug(F111,"k4_auth_send","krb_get_cred() failed",r); } else debug(F111,"k4_auth_send","krb_mk_req() failed",r); if (r) { strcpy(strTmp, "Can't get \""); ckstrncat(strTmp, krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME,AUTHTMPBL); if (instance[0] != 0) { ckstrncat(strTmp, ".",AUTHTMPBL); ckstrncat(strTmp, instance,AUTHTMPBL); } ckstrncat(strTmp, "@",AUTHTMPBL); ckstrncat(strTmp, realm,AUTHTMPBL); ckstrncat(strTmp, "\" ticket\r\n ",AUTHTMPBL); ckstrncat(strTmp, (char *)krb_get_err_text_entry(r),AUTHTMPBL); debug(F111,"k4_auth_send",(char *)krb_get_err_text_entry(r),r); printf("?Kerberos 4 error: %s\r\n",strTmp); krb4_errno = r; makestr(&krb4_errmsg,krb_get_err_text_entry(krb4_errno)); return(0); } #ifdef OS2 if ( !szUserName[0] || !stricmp(szUserName,cred.pname) ) { ckstrncpy(szUserName, cred.pname, UIDBUFLEN); } #endif /* OS2 */ krb4_errno = r; makestr(&krb4_errmsg,krb_get_err_text_entry(krb4_errno)); debug(F110,"k4_auth_send",krb4_errmsg,0); return(1); } /* * Function: K4 parse authentication reply command * * Parameters: * parsedat - the sub-command data. * * end_sub - index of the character in the 'parsedat' array which * is the last byte in a sub-negotiation * * Returns: Kerberos error code. */ static int #ifdef CK_ANSIC k4_auth_reply(unsigned char *parsedat, int end_sub) #else k4_auth_reply(parsedat,end_sub) unsigned char *parsedat; int end_sub; #endif { #ifdef CK_ENCRYPTION Session_Key skey; #ifdef MIT_CURRENT krb5_data kdata; krb5_enc_data encdata; krb5_error_code code; #endif /* MIT_CURRENT */ #endif time_t t; int x; int i; if (end_sub < 4 || parsedat[2] != AUTHTYPE_KERBEROS_V4) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } if (parsedat[4] == KRB_REJECT) { strTmp[0] = 0; for (i = 5; i <= end_sub; i++) { if (parsedat[i] == IAC) break; strTmp[i-5] = parsedat[i]; strTmp[i-4] = 0; } if (!strTmp[0]) strcpy(strTmp, "Authentication rejected by remote machine!"); printf("Kerberos V4 authentication failed!\r\n%s\r\n",strTmp); krb4_errno = -1; makestr(&krb4_errmsg,strTmp); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } if (parsedat[4] == KRB_ACCEPT) { int net_len; if ((parsedat[3] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY) { ckmakmsg(strTmp,sizeof(strTmp),"Kerberos V4 accepts you as ", szUserName,NULL,NULL); printf("%s\r\n",strTmp); accept_complete = 1; krb4_errno = 0; makestr(&krb4_errmsg,strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; } if ((parsedat[3] & AUTH_HOW_MASK) != AUTH_HOW_MUTUAL) { printf("Kerberos V4 authentication failed!\r\n"); ckstrncpy(strTmp, "Kerberos V4 accepted you, but didn't provide mutual authentication", sizeof(strTmp)); printf("%s\r\n",strTmp); krb4_errno = -1; makestr(&krb4_errmsg,strTmp); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #ifndef REMOVE_FOR_EXPORT #ifdef CK_ENCRYPTION SendK4AuthSB(KRB4_CHALLENGE,k4_session_key,sizeof(k4_session_key)); /* We have sent the decrypted session key to the host as a challenge */ /* now encrypt it to restore it to its original valid DES key value */ #ifdef MIT_CURRENT kdata.data = k4_session_key; kdata.length = 8; encdata.ciphertext.data = k4_session_key; encdata.ciphertext.length = 8; encdata.enctype = ENCTYPE_UNKNOWN; if (code = krb5_c_encrypt(k5_context, &k4_krbkey, 0, 0, &kdata, &encdata)) { com_err("k4_auth_reply", code, "while encrypting session_key"); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #else /* MIT_CURRENT */ #ifdef NT des_ecb_encrypt(k4_session_key, k4_session_key, k4_sched, 1); #else /* NT */ des_ecb_encrypt(&k4_session_key, &k4_session_key, k4_sched, 1); #endif /* NT */ ckhexdump( "k4_auth_reply des_ecb_encrypt(k4_session_key,k4_session_key,1)", k4_session_key, 8 ); #endif /* MIT_CURRENT */ #ifdef CK_SSL if (!(ssl_active_flag || tls_active_flag)) #endif /* CK_SSL */ { /* And then use it to configure the encryption state machine. */ skey.type = SK_DES; skey.length = 8; skey.data = k4_session_key; encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER); } #endif /* ENCRYPTION */ #endif /* REMOVE_FOR_EXPORT */ accept_complete = 1; ckmakmsg(strTmp,sizeof(strTmp), "Kerberos V4 accepts you as ",szUserName,NULL,NULL); printf("%s\r\n",strTmp); krb4_errno = 0; makestr(&krb4_errmsg,strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; } if (parsedat[4] == KRB4_RESPONSE) { if (end_sub < 12) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } ckhexdump("KRB4_RESPONSE &parsedat[5]",&parsedat[5],8); #ifdef CK_ENCRYPTION ckhexdump("KRB4_RESPONSE k4_challenge",k4_challenge,8); /* The datablock returned from the host should match the value */ /* we stored in k4_challenge. */ if (memcmp(&parsedat[5], k4_challenge, sizeof(k4_challenge)) != 0) { printf("Kerberos V4 authentication failed!\r\n%s\r\n", "Remote machine is being impersonated!"); krb4_errno = -1; makestr(&krb4_errmsg,"Remote machine is being impersonated!"); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #else /* ENCRYPTION */ makestr(&krb4_errmsg,"Kermit built without support for encryption."); return AUTH_FAILURE; #endif /* ENCRYPTION */ mutual_complete = 1; ckstrncpy(strTmp,"Remote machine has been mutually authenticated", sizeof(strTmp)); printf("%s\r\n",strTmp); krb4_errno = 0; makestr(&krb4_errmsg,strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; } auth_finished(AUTH_REJECT); return AUTH_FAILURE; } /* * Function: K4 parse authentication IS command * * Parameters: * parsedat - the sub-command data. * * end_sub - index of the character in the 'parsedat' array which * is the last byte in a sub-negotiation * * Returns: Kerberos error code. */ static int #ifdef CK_ANSIC k4_auth_is(unsigned char *parsedat, int end_sub) #else k4_auth_is(parsedat,end_sub) unsigned char *parsedat; int end_sub; #endif { #ifdef CK_ENCRYPTION Session_Key skey; #ifdef MIT_CURRENT Block datablock, tmpkey; krb5_data kdata; krb5_enc_data encdata; krb5_error_code code; #else /* MIT_CURRENT */ Block datablock; #endif /* MIT_CURRENT */ #endif /* ENCRYPTION */ char realm[REALM_SZ+1]; char instance[INST_SZ]; int r = 0; char * data = &parsedat[5]; int cnt = end_sub - 5; extern char myipaddr[]; struct hostent *host; struct in_addr inaddr; int i; if (end_sub < 4 || parsedat[2] != AUTHTYPE_KERBEROS_V4) { debug(F110,"k4_auth_is","Not kerberos v4",0); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } switch (parsedat[4]) { case KRB_AUTH: debug(F110,"k4_auth_is","KRB_AUTH",0); ckstrncpy(realm,ck_krb4_getrealm(),REALM_SZ+1); if (realm[0] == '\0') { SendK4AuthSB(KRB_REJECT, (void *)"No local V4 Realm.", -1); printf("\r\n? Kerberos 4 - No Local Realm\r\n"); debug(F110,"k4_auth_is","No local realm",0); krb4_errno = -1; makestr(&krb4_errmsg,"No local realm"); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } debug(F110,"k4_auth_is",realm,0); if ( cnt < sizeof(k4_auth.dat) ) { k4_auth.length = cnt; memcpy((void *)k4_auth.dat, (void *)data, k4_auth.length); } else k4_auth.length = 0; ckhexdump("k4_auth.dat",k4_auth.dat, k4_auth.length); /* Get Instance */ inaddr.s_addr = inet_addr(myipaddr); host = gethostbyaddr((unsigned char *)&inaddr,4,PF_INET); if ( host ) { #ifdef HADDRLIST host = ck_copyhostent(host); #endif /* HADDRLIST */ ckstrncpy(instance,host->h_name,INST_SZ); for ( i=0;i= 0; r--) { register int t; t = (unsigned int)k4_challenge[r] + 1; k4_challenge[r] = t; /* ignore overflow */ if (t < 256) /* if no overflow, all done */ break; } ckhexdump("auth_is k4_challenge+1",k4_challenge,8); #ifdef MIT_CURRENT kdata.data = k4_challenge; kdata.length = 8; encdata.ciphertext.data = k4_challenge; encdata.ciphertext.length = 8; encdata.enctype = ENCTYPE_UNKNOWN; if (code = krb5_c_encrypt(k5_context, &k4_krbkey, 0, 0, &kdata, &encdata)) { com_err("k4_auth_is", code, "while decrypting challenge"); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #else /* MIT_CURRENT */ #ifdef NT des_ecb_encrypt(k4_challenge, k4_challenge, k4_sched, 1); #else /* NT */ des_ecb_encrypt(&k4_challenge, &k4_challenge, k4_sched, 1); #endif /* NT */ ckhexdump("auth_is des_ecb_encrypt(k4_challenge_key,k4_challenge,1)", k4_challenge,8); #endif /* MIT_CURRENT */ SendK4AuthSB(KRB4_RESPONSE,(void *)k4_challenge,sizeof(k4_challenge)); #endif /* ENCRYPTION */ mutual_complete = 1; break; default: if (1) printf("Unknown Kerberos option %d\r\n", data[-1]); SendK4AuthSB(KRB_REJECT, 0, 0); return(AUTH_FAILURE); } krb4_errno = r; makestr(&krb4_errmsg,krb_get_err_text_entry(krb4_errno)); return(AUTH_SUCCESS); } #endif /* KRB4 */ #ifdef KRB5 int ck_krb5_autoget_TGT(char * realm) { extern struct krb_op_data krb_op; extern struct krb5_init_data krb5_init; char passwd[PWD_SZ]; char prompt[64]; char * saverealm=NULL; int rc = -1; extern char * k5prprompt; extern char * k5pwprompt; ini_kerb(); /* Place defaults in above structs */ passwd[0] = '\0'; if ( krb5_init.principal == NULL || krb5_init.principal[0] == '\0') { int ok = uq_txt(NULL,k5prprompt && k5prprompt[0] ? k5prprompt : "Kerberos 5 Principal: ",2,NULL,passwd,PWD_SZ-1,NULL, DEFAULT_UQ_TIMEOUT); if ( ok && passwd[0] ) makestr(&krb5_init.principal,passwd); else return(0); } /* Save realm in init structure so it can be restored */ if ( realm ) { saverealm = krb5_init.realm; krb5_init.realm = realm; } if ( passwd[0] || !(pwbuf[0] && pwflg) ) { int ok; if ( k5pwprompt && k5pwprompt[0] && (strlen(k5pwprompt) + strlen(krb5_init.principal) + strlen(krb5_init.realm) - 4) < sizeof(prompt)) { sprintf(prompt,k5pwprompt,krb5_init.principal,krb5_init.realm); } else ckmakxmsg(prompt,sizeof(prompt), k5pwprompt && k5pwprompt[0] ? k5pwprompt : "Kerberos 5 Password for ", krb5_init.principal,"@",krb5_init.realm,": ", NULL,NULL,NULL,NULL,NULL,NULL,NULL ); ok = uq_txt(NULL,prompt,2,NULL,passwd,PWD_SZ-1,NULL, DEFAULT_UQ_TIMEOUT); if ( !ok ) passwd[0] = '\0'; } else { ckstrncpy(passwd,(char *)pwbuf,sizeof(passwd)); #ifdef OS2 if ( pwcrypt ) ck_encrypt((char *)passwd); #endif /* OS2 */ } if ( passwd[0] ) { extern struct krb4_init_data krb4_init; char * savek4realm=NULL; makestr(&krb5_init.password,passwd); if ( krb5_d_getk4 ) { krb5_init.getk4 = 1; makestr(&krb4_init.principal,krb5_init.principal); makestr(&krb4_init.password,passwd); if ( realm ) { savek4realm = krb4_init.realm; krb4_init.realm = realm; } rc = ck_krb5_initTGT(&krb_op, &krb5_init,&krb4_init); if ( savek4realm ) krb4_init.realm = savek4realm; free(krb4_init.password); krb4_init.password = NULL; } else { rc = ck_krb5_initTGT(&krb_op, &krb5_init,NULL); } free(krb5_init.password); krb5_init.password = NULL; memset(passwd,0,PWD_SZ); } /* restore realm to init structure if needed */ if ( saverealm ) krb5_init.realm = saverealm; return(rc == 0); } static krb5_error_code #ifdef CK_ANSIC k5_get_ccache( krb5_context k5_context, krb5_ccache * p_ccache, char * cc_name ) #else /* CK_ANSIC */ k5_get_ccache(k5_context, p_ccache, cc_name) krb5_context k5_context; krb5_ccache * p_ccache; char * cc_name; #endif /* CK_ANSIC */ { krb5_error_code r=0; char cc_tmp[CKMAXPATH+1]; const char * def_name = NULL; #ifndef HEIMDAL if ( cc_name ) { if ( strncmp("FILE:",cc_name,5) && strncmp("MEMORY:",cc_name,7) && strncmp("API:",cc_name,4) && strncmp("STDIO:",cc_name,6) && strncmp("MSLSA:",cc_name,6)) #ifdef NT ckmakmsg(cc_tmp,CKMAXPATH,"API:",cc_name,NULL,NULL); #else /* NT */ ckmakmsg(cc_tmp,CKMAXPATH,"FILE:",cc_name,NULL,NULL); #endif /* NT */ else { ckstrncpy(cc_tmp,cc_name,CKMAXPATH); } r = krb5_cc_resolve (k5_context, cc_tmp, p_ccache); if (r != 0) { com_err("k5_get_ccache resolving ccache",r, cc_tmp); } else { /* Make sure GSSAPI sees the same cache we are using */ char buf[128]; ckmakmsg((char *)buf,128,"KRB5CCNAME=",cc_tmp,NULL,NULL); putenv(buf); } } else if ( krb5_d_cc ) { if ( strncmp("FILE:",krb5_d_cc,5) && strncmp("MEMORY:",krb5_d_cc,7) && strncmp("API:",krb5_d_cc,4) && strncmp("STDIO:",krb5_d_cc,6) && strncmp("MSLSA:", krb5_d_cc,6)) #ifdef NT ckmakmsg(cc_tmp,CKMAXPATH,"API:",krb5_d_cc,NULL,NULL); #else /* NT */ ckmakmsg(cc_tmp,CKMAXPATH,"FILE:",krb5_d_cc,NULL,NULL); #endif /* NT */ else { ckstrncpy(cc_tmp,krb5_d_cc,CKMAXPATH); } r = krb5_cc_resolve (k5_context, cc_tmp, p_ccache); if (r != 0) { com_err("k5_get_ccache resolving ccache",r, krb5_d_cc); } else { /* Make sure GSSAPI sees the same cache we are using */ char buf[128]; ckmakmsg((char *)buf,128,"KRB5CCNAME=",cc_tmp,NULL,NULL); putenv(buf); } } else #endif /* HEIMDAL */ { if ((r = krb5_cc_default(k5_context, p_ccache))) { com_err("k5_get_ccache",r,"while getting default ccache"); } } /* do not set krb5_errno/krb5_errmsg here since the value returned */ /* is being passed internally within the krb5 functions. */ return(r); } char * ck_krb5_realmofhost(char *host) { char ** realmlist=NULL; krb5_context private_context=NULL; static char * realm = NULL; if ( !host ) return NULL; if ( realm ) { free(realm); realm = NULL; } /* create private_context */ if (krb5_init_context(&private_context)) { debug(F110,"ck_krb5_realmofhost()","unable to init_context",0); return(NULL); } krb5_get_host_realm(private_context,host,&realmlist); if (realmlist && realmlist[0]) { makestr(&realm,realmlist[0]); krb5_free_host_realm(private_context,realmlist); realmlist = NULL; } if ( private_context ) { krb5_free_context(private_context); private_context = NULL; } if (ckstrchr(realm,'.') == NULL) { int n = 0; char * p = host; while ( (p = ckstrchr(p,'.')) != NULL ) { n++; p++; } if (n == 1) { makestr(&realm,host); ckupper(realm); } else { free(realm); realm = NULL; } } return(realm); } /* * * K5_auth_send - gets authentication bits we need to send to KDC. * * Code lifted from telnet sample code in the appl directory. * * Result is left in k5_auth * * Returns: 0 on failure, 1 on success * */ static int #ifdef CK_ANSIC k5_auth_send(int how, int encrypt, int forward) #else k5_auth_send(how,encrypt,forward) int how; int encrypt; int forward; #endif { krb5_error_code r=0; krb5_ccache ccache=NULL; #ifndef HEIMDAL krb5_creds creds; #endif /* HEIMDAL */ krb5_creds * new_creds=NULL; #ifdef CK_ENCRYPTION krb5_keyblock *newkey = 0; #endif /* CK_ENCRYPTION */ krb5_flags ap_opts, auth_flags; char type_check[32]; krb5_data checksum; int len=0; char * realm = NULL; char tgt[256]; realm = ck_krb5_realmofhost(szHostName); if (!realm) { ckstrncpy(strTmp, "Can't find realm for host \"",AUTHTMPBL); ckstrncat(strTmp, szHostName,AUTHTMPBL); ckstrncat(strTmp, "\"",AUTHTMPBL); printf("?Kerberos 5 error: %s\r\n",strTmp); krb5_errno = KRB5_ERR_HOST_REALM_UNKNOWN; makestr(&krb5_errmsg,strTmp); return(0); } ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm); debug(F110,"k5_auth_send TGT",tgt,0); if ( krb5_autoget && !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) || (ck_krb5_is_tgt_valid() > 0)) ) ck_krb5_autoget_TGT(realm); r = k5_get_ccache(k5_context,&ccache,NULL); if ( r ) { com_err(NULL, r, "while authorizing (0)."); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(0); } #ifndef HEIMDAL memset((char *)&creds, 0, sizeof(creds)); if (r = krb5_sname_to_principal(k5_context, szHostName, krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME, KRB5_NT_SRV_HST, &creds.server)) { com_err(NULL, r, "while authorizing (1)."); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(0); } if (forward_flag) { if (fwd_server) { krb5_free_principal(k5_context,fwd_server); fwd_server = NULL; } krb5_copy_principal(k5_context,creds.server,&fwd_server); } r = krb5_cc_get_principal(k5_context, ccache, &creds.client); if (r) { com_err(NULL, r, "while authorizing (2)."); krb5_free_cred_contents(k5_context, &creds); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(0); } if (szUserName[0] == '\0') { /* Get user name now */ len = krb5_princ_component(k5_context, creds.client, 0)->length; if ( len < sizeof(szUserName) ) { memcpy(szUserName, krb5_princ_component(k5_context, creds.client, 0)->data, len); /* safe */ } else len = 0; szUserName[len] = '\0'; } else { char * name = NULL; len = krb5_princ_component(k5_context, creds.client, 0)->length; if ( len == strlen(szUserName) ) { name = krb5_princ_component(k5_context, creds.client, 0)->data; #ifdef OS2 if ( !strnicmp(szUserName,name,len) ) memcpy(szUserName,name,len); /* safe */ #endif /* OS2 */ } } if ( tn_auth_krb5_des_bug ) { /* !ALLOW_KRB_3DES_ENCRYPT */ /* Not sure if this is necessary anymore. What impact does it have * on Win2000 TGTs that use DES_CBC_MD5 or RC4_HMAC? * * This prevents using 3DES Service Tickets. */ creds.keyblock.enctype=ENCTYPE_DES_CBC_CRC; } if (r = krb5_get_credentials(k5_context, 0, ccache, &creds, &new_creds)) { com_err(NULL, r, "while authorizing (3)."); krb5_free_cred_contents(k5_context, &creds); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(0); } #endif /* HEIMDAL */ if (auth_context) { krb5_auth_con_free(k5_context, auth_context); auth_context = 0; } if (r = krb5_auth_con_init(k5_context, &auth_context)) { com_err(NULL, r, "while initializing auth context"); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(0); } /* UPDATE for START_TLS. AUTH_ENCRYPT_START_TLS and inclusion of */ /* client and then server finished messages. */ type_check[0] = AUTHTYPE_KERBEROS_V5; type_check[1] = AUTH_CLIENT_TO_SERVER | (how ? AUTH_HOW_MUTUAL : AUTH_HOW_ONE_WAY) | (encrypt) | (forward ? INI_CRED_FWD_ON : INI_CRED_FWD_OFF); #ifdef CK_SSL if (encrypt == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); } #endif /* CK_SSL */ #ifndef HEIMDAL checksum.magic = KV5M_DATA; #endif /* HEIMDAL */ checksum.length = #ifdef CK_SSL (encrypt == AUTH_ENCRYPT_START_TLS) ? 26 : #endif /* CK_SSL */ 2; checksum.data = (char *)&type_check; ap_opts = 0; if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ap_opts |= AP_OPTS_MUTUAL_REQUIRED; #ifdef HEIMDAL #ifdef notdef r = krb5_auth_setkeytype(k5_context, auth_context, KEYTYPE_DES); if (r) com_err(NULL, r, "while setting auth keytype"); #endif r = krb5_auth_con_setaddrs_from_fd(k5_context,auth_context, &ttyfd); if (r) com_err(NULL, r, "while setting auth addrs"); r = krb5_mk_req(k5_context, &auth_context, ap_opts, krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME, szHostName, &checksum, ccache, &k5_auth); if (r) com_err(NULL, r, "while making request"); #else /* HEIMDAL */ auth_flags = KRB5_AUTH_CONTEXT_RET_TIME; #ifdef CK_ENCRYPTION ap_opts |= AP_OPTS_USE_SUBKEY; #endif /* CK_ENCRYPTION */ #ifdef TLS_VERIFY if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { auth_flags |= KRB5_AUTH_CONTEXT_DO_SEQUENCE; if (!krb5_d_no_addresses) r = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR); } #endif /* CK_SSL */ krb5_auth_con_setflags(k5_context, auth_context, auth_flags); r = krb5_mk_req_extended(k5_context, &auth_context, ap_opts, &checksum, new_creds, &k5_auth); #endif /* HEIMDAL */ #ifdef CK_ENCRYPTION if (!r) { r = krb5_auth_con_getlocalsubkey(k5_context, auth_context, &newkey); if (r) r = krb5_auth_con_getkey(k5_context, auth_context, &newkey); if (k5_session_key) { krb5_free_keyblock(k5_context, k5_session_key); k5_session_key = 0; } } if (newkey) { /* * keep the key in our private storage, but don't use it * yet---see kerberos5_reply() below */ #ifdef HEIMDAL if ((newkey->keytype == ETYPE_DES_CBC_CRC) || (newkey->keytype == ETYPE_DES_CBC_MD5) || (newkey->keytype == ETYPE_DES_CBC_MD4)) { debug(F111,"k5_auth_send()","newkey->keytype",newkey->keytype); krb5_copy_keyblock(k5_context, newkey, &k5_session_key); } #else /* HEIMDAL */ /* look for all possible DES keys first - just for compatibility */ /* other key types are much less likely to be available */ if ((newkey->enctype == ENCTYPE_DES_CBC_CRC) || (newkey->enctype == ENCTYPE_DES_CBC_MD5) || (newkey->enctype == ENCTYPE_DES_CBC_MD4)) { debug(F111,"k5_auth_send()","newkey->enctype",newkey->enctype); krb5_copy_keyblock(k5_context, newkey, &k5_session_key); } else if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC) || (new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5)) { /* use the session key in credentials instead */ debug(F111,"k5_auth_send()","new_creds->keyblock.enctype", new_creds->keyblock.enctype); krb5_copy_keyblock(k5_context, &new_creds->keyblock, &k5_session_key); } else if (newkey->enctype != 0) { debug(F111,"k5_auth_send()","newkey->enctype",newkey->enctype); krb5_copy_keyblock(k5_context, newkey, &k5_session_key); } else if (new_creds->keyblock.enctype != 0) { /* use the session key in credentials instead */ debug(F111,"k5_auth_send()","new_creds->keyblock.enctype", new_creds->keyblock.enctype); krb5_copy_keyblock(k5_context, &new_creds->keyblock, &k5_session_key); } else { debug(F110,"k5_auth_send()","NO KEY in newkey",0); } #endif /* HEIMDAL */ krb5_free_keyblock(k5_context, newkey); } #endif /* CK_ENCRYPTION */ #ifndef HEIMDAL krb5_free_cred_contents(k5_context, &creds); krb5_free_creds(k5_context, new_creds); #endif /* HEIMDAL */ krb5_cc_close(k5_context,ccache); if (r) { com_err(NULL, r, "while authorizing (4)."); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(0); } krb5_errno = 0; makestr(&krb5_errmsg,"OK"); return(1); } /* * K5_auth_reply -- checks the reply for mutual authentication. */ static int #ifdef CK_ANSIC k5_auth_reply(int how, unsigned char *data, int cnt) #else k5_auth_reply(how,data,cnt) int how; unsigned char *data; int cnt; #endif { #ifdef CK_ENCRYPTION Session_Key skey; #endif /* CK_ENCRYPTION */ data += 4; /* Point to status byte */ cnt -=5; switch (*data++) { case KRB_REJECT: if (cnt > 0) { char *s; int len; ckstrncpy(strTmp,"Kerberos V5 refuses authentication because\r\n", sizeof(strTmp)); len = strlen(strTmp); if ( len + cnt < sizeof(strTmp) ) { s = strTmp + strlen(strTmp); memcpy(s, data, cnt); /* safe */ s[cnt] = 0; } } else ckstrncpy(strTmp,"Kerberos V5 refuses authentication", sizeof(strTmp)); krb5_errno = -1; makestr(&krb5_errmsg,strTmp); printf("Kerberos authentication failed!\r\n%s\r\n",strTmp); auth_finished(AUTH_REJECT); return AUTH_FAILURE; case KRB_ACCEPT: if (!mutual_complete) { if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !mutual_complete) { ckstrncpy(strTmp, "Kerberos V5 accepted you, but didn't provide" " mutual authentication",sizeof(strTmp)); printf("Kerberos authentication failed!\r\n%s\r\n",strTmp); krb5_errno = -1; makestr(&krb5_errmsg,strTmp); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #ifdef CK_ENCRYPTION if (k5_session_key) { if ( tn_auth_krb5_des_bug ) { /* !ALLOW_KRB_3DES_ENCRYPT */ skey.type = SK_DES; skey.length = 8; #ifdef HEIMDAL skey.data = k5_session_key->keyvalue.data; #else /* HEIMDAL */ skey.data = k5_session_key->contents; #endif /* HEIMDAL */ } else { switch ( #ifdef HEIMDAL k5_session_key->keytype #else /* HEIMDAL */ k5_session_key->enctype #endif /* HEIMDAL */ ) { #ifdef HEIMDAL case ETYPE_DES_CBC_CRC: case ETYPE_DES_CBC_MD5: case ETYPE_DES_CBC_MD4: #else /* HEIMDAL */ case ENCTYPE_DES_CBC_CRC: case ENCTYPE_DES_CBC_MD5: case ENCTYPE_DES_CBC_MD4: #endif /* HEIMDAL */ skey.type = SK_DES; skey.length = 8; break; default: skey.type = SK_GENERIC; #ifdef HEIMDAL skey.length = k5_session_key->keyvalue.length; #else /* HEIMDAL */ skey.length = k5_session_key->length; #endif /* HEIMDAL */ encrypt_dont_support(ENCTYPE_DES_CFB64); encrypt_dont_support(ENCTYPE_DES_OFB64); } #ifdef HEIMDAL skey.data = k5_session_key->keyvalue.data; #else /* HEIMDAL */ skey.data = k5_session_key->contents; #endif /* HEIMDAL */ } encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER); } #endif /* CK_ENCRYPTION */ } if ( cnt > 0 ) { char *s; int len; ckstrncpy(strTmp,"Kerberos V5 accepts you as ",sizeof(strTmp)); len = strlen(strTmp); if ( len + cnt < sizeof(strTmp) ) { s = strTmp + strlen(strTmp); memcpy(s,data,cnt); s[cnt] = 0; } } accept_complete = 1; printf("%s\r\n",strTmp); #ifdef FORWARD if (forward_flag #ifdef COMMENT /* Marc Horowitz has successfully argued that it is indeed safe to send Forwarded credentials to an untrusted host. */ && (auth_how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL #endif /* COMMENT */ ) kerberos5_forward(); #endif /* FORWARD */ krb5_errno = 0; makestr(&krb5_errmsg,strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; case KRB5_RESPONSE: #ifdef TLS_VERIFY if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS && !krb5_tls_verified) { printf( "Man in the middle attack detected. Session terminated.\r\n"); #ifndef KRB_BETATEST netclos(); #endif /* KRB_BETATEST */ krb5_errno = -1; makestr(&krb5_errmsg,"TLS not verified"); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } if((ssl_active_flag || tls_active_flag) && (how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { printf("TLS session parameters verified by Kerberos 5\r\n"); } #endif /* TLS_VERIFY */ if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { /* the rest of the reply should contain a krb_ap_rep */ krb5_ap_rep_enc_part *reply; krb5_data inbuf; krb5_error_code r; inbuf.length = cnt; inbuf.data = (char *)data; if (r = krb5_rd_rep(k5_context, auth_context, &inbuf, &reply)) { com_err(NULL, r, "while authorizing. (5)"); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } krb5_free_ap_rep_enc_part(k5_context, reply); #ifdef CK_ENCRYPTION if (encrypt_flag && k5_session_key) { if ( tn_auth_krb5_des_bug ) { /* !ALLOW_KRB_3DES_ENCRYPT */ skey.type = SK_DES; skey.length = 8; #ifdef HEIMDAL skey.data = k5_session_key->keyvalue.data; #else /* HEIMDAL */ skey.data = k5_session_key->contents; #endif /* HEIMDAL */ } else { switch ( #ifdef HEIMDAL k5_session_key->keytype #else /* HEIMDAL */ k5_session_key->enctype #endif /* HEIMDAL */ ) { #ifdef HEIMDAL case ETYPE_DES_CBC_CRC: case ETYPE_DES_CBC_MD5: case ETYPE_DES_CBC_MD4: #else /* HEIMDAL */ case ENCTYPE_DES_CBC_CRC: case ENCTYPE_DES_CBC_MD5: case ENCTYPE_DES_CBC_MD4: #endif /* HEIMDAL */ skey.type = SK_DES; skey.length = 8; default: skey.type = SK_GENERIC; #ifdef HEIMDAL skey.length = k5_session_key->keyvalue.length; #else /* HEIMDAL */ skey.length = k5_session_key->length; #endif /* HEIMDAL */ } #ifdef HEIMDAL skey.data = k5_session_key->keyvalue.data; #else /* HEIMDAL */ skey.data = k5_session_key->contents; #endif /* HEIMDAL */ } encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER); } #endif /* ENCRYPTION */ mutual_complete = 1; } ckstrncpy(strTmp,"Remote machine has been mutually authenticated", sizeof(strTmp)); krb5_errno = 0; makestr(&krb5_errmsg,strTmp); printf("%s\r\n",strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; #ifdef FORWARD case KRB5_FORWARD_ACCEPT: forwarded_tickets = 1; ckstrncpy(strTmp,"Remote machine has accepted forwarded credentials", sizeof(strTmp)); krb5_errno = 0; makestr(&krb5_errmsg,strTmp); printf("%s\r\n",strTmp); return AUTH_SUCCESS; case KRB5_FORWARD_REJECT: forwarded_tickets = 0; if (cnt > 0) { char *s; int len; len = ckstrncpy(strTmp, "Kerberos V5 refuses forwarded credentials because ", sizeof(strTmp)); if ( len + cnt < sizeof(strTmp) ) { s = strTmp + strlen(strTmp); memcpy(s, data, cnt); s[cnt] = 0; } } else ckstrncpy(strTmp, "Kerberos V5 refuses forwarded credentials", sizeof(strTmp)); printf("%s\r\n",strTmp); krb5_errno = -1; makestr(&krb5_errmsg,strTmp); return AUTH_SUCCESS; #endif /* FORWARD */ #ifdef TLS_VERIFY case KRB5_TLS_VERIFY: if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { krb5_data reply, msg; char tls_verify[24]; krb5_replay_data repdata; krb5_error_code r; ssl_get_server_finished(&tls_verify[0],12); ssl_get_client_finished(&tls_verify[12],12); reply.data = (char *)data; reply.length = cnt; krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR); if (r = krb5_rd_safe(k5_context,auth_context,&reply,&msg,&repdata)) { com_err("", r, "decoding tls verifier"); krb5_errno = r; makestr(&krb5_errmsg,"TLS verify failure"); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } if ( msg.length == 24 && !memcmp(msg.data,tls_verify,24) ) krb5_tls_verified = 1; #ifdef HEIMDAL krb5_data_free(&msg); #else /* HEIMDAL */ krb5_free_data_contents(k5_context,&msg); #endif /* HEIMDAL */ if (krb5_tls_verified) return(AUTH_SUCCESS); } printf("Man in the middle attack detected. Session terminated.\r\n"); netclos(); krb5_errno = -1; makestr(&krb5_errmsg,"TLS verify failure"); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); #endif /* CK_SSL */ default: krb5_errno = -1; makestr(&krb5_errmsg,"Unknown reply type"); auth_finished(AUTH_REJECT); return AUTH_FAILURE; /* Unknown reply type */ } } #ifdef FORWARD /* Decode, decrypt and store the forwarded creds in the local ccache. */ /* Needed for KRB5_FORWARD */ static krb5_error_code rd_and_store_for_creds(context, auth_context, inbuf, client) krb5_context context; krb5_auth_context auth_context; krb5_data *inbuf; krb5_principal client; { krb5_creds ** creds=NULL; krb5_error_code retval; krb5_ccache ccache=NULL; #ifdef HEIMDAL /* Heimdal Telnetd creates the cache file at this point and sets the KRB5CCNAME environment variable. struct passwd *pwd; char ccname[1024]; pwd = getpwnam(szUserNameRequested); if (pwd == NULL) break; snprintf(ccname, sizeof(ccname)-1, "FILE:/tmp/krb5cc_%u",pwd->pw_uid); retval = krb5_cc_resolve(context,ccname,&ccache); chown(ccname + 5, pwd->pw_uid, -1); */ #endif /* HEIMDAL */ if (retval = k5_get_ccache(context,&ccache,NULL)) return(retval); #ifdef HEIMDAL if ((retval = krb5_cc_initialize(context, ccache, client))) return(retval); if ((retval = krb5_rd_cred2(context, auth_context, ccache, inbuf))) return(retval); #else /* HEIMDAL */ if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL))) return(retval); if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client))) goto cleanup; if ((retval = krb5_cc_store_cred(context, ccache, creds[0]))) goto cleanup; if ((retval = krb5_cc_close(context, ccache))) goto cleanup; cleanup: krb5_free_tgt_creds(context, creds); #endif /* HEIMDAL */ return retval; } #endif /* FORWARD */ /* * * K5_auth_is. * */ static int #ifdef CK_ANSIC k5_auth_is(int how, unsigned char *data, int cnt) #else k5_auth_is(how,data,cnt) int how; unsigned char *data; int cnt; #endif { int r = 0; krb5_principal server; krb5_keyblock *newkey = NULL; krb5_data outbuf; char errbuf[128]=""; char *getenv(); #ifndef HEIMDAL krb5_authenticator *authenticator; krb5_keytab keytabid = 0; #endif /* HEIMDAL */ krb5_data inbuf; #ifdef CK_ENCRYPTION Session_Key skey; #endif /* CK_ENCRYPTION */ char princ[256]=""; int len; data += 4; /* Point to status byte */ cnt -= 4; ckhexdump("k5_auth_is data",data,cnt); debug(F111,"k5_auth_is","how",how); if (cnt-- < 1) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } switch (*data++) { case KRB_AUTH: k5_auth.data = (char *)data; k5_auth.length = cnt; debug(F110,"k5_auth_is","KRB_AUTH",0); debug(F111,"k5_auth_is","auth_context",auth_context); if (!r && !auth_context) { r = krb5_auth_con_init(k5_context, &auth_context); debug(F111,"k5_auth_is","krb5_auth_con_init",r); } #ifdef HEIMDAL if (!r) r = krb5_auth_con_setaddrs_from_fd(k5_context, auth_context, &ttyfd); if (!r) r = krb5_sock_to_principal(k5_context, 0, "host", KRB5_NT_SRV_HST, &server); if (!r) #else /* HEIMDAL */ if (!r) { krb5_rcache rcache = NULL; r = krb5_auth_con_getrcache(k5_context, auth_context, &rcache); debug(F111,"k5_auth_is","krb5_auth_con_getrcache",r); if (!r && !rcache) { /* Do not resolve server's principal name, we will check */ /* for validity after the krb5_rd_req() call. */ r = krb5_sname_to_principal(k5_context, 0, 0, KRB5_NT_SRV_HST, &server); debug(F111,"k5_auth_is","krb5_sname_to_principal",r); if (!r) { r = krb5_get_server_rcache(k5_context, krb5_princ_component(k5_context, server, 0), &rcache); debug(F111,"k5_auth_is","krb5_get_server_rcache",r); krb5_free_principal(k5_context, server); } } if (!r) { r = krb5_auth_con_setrcache(k5_context, auth_context, rcache); debug(F111,"k5_auth_is","krb5_auth_con_setrcache",r); } } if (!r && k5_keytab) { r = krb5_kt_resolve(k5_context, k5_keytab, &keytabid); debug(F111,"k5_auth_is","krb5_kt_resolve",r); } #endif /* HEIMDAL */ if (!r) { r = krb5_rd_req(k5_context, &auth_context, &k5_auth, #ifdef HEIMDAL server, NULL, NULL, #else /* HEIMDAL */ NULL, keytabid, NULL, #endif /* HEIMDAL */ &k5_ticket); debug(F111,"k5_auth_is","krb5_rd_req",r); } if (r) { (void) ckstrncpy(errbuf, "krb5_rd_req failed: ",sizeof(errbuf)); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); goto errout; } #ifdef HEIMDAL krb5_free_principal(k5_context, server); { char type_check[26]; /* UPDATE for START_TLS. AUTH_ENCRYPT_START_TLS and inclusion of */ /* client and then server finished messages. */ type_check[0] = AUTHTYPE_KERBEROS_V5; type_check[1] = how; /* not broken into parts */ #ifdef CK_SSL if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); ckhexdump("k5_auth_is type_check",type_check,26); } #endif /* CK_SSL */ r = krb5_verify_authenticator_checksum(k5_context, auth_context, type_check, #ifdef CK_SSL ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) ? 26 : #endif /* CK_SSL */ 2); } #else /* HEIMDAL */ len = krb5_princ_component(k5_context,k5_ticket->server,0)->length; if (len < 256) { memcpy(princ, krb5_princ_component(k5_context,k5_ticket->server,0)->data, len); princ[len] = '\0'; } if ( strcmp((krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME), princ) ) { debug(F110,"k5_auth_is incorrect service name",princ,0); ckstrncpy(errbuf,"incorrect service name: ",sizeof(errbuf)); ckstrncat(errbuf,krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME, sizeof(errbuf)); ckstrncat(errbuf," != ",sizeof(errbuf)); ckstrncat(errbuf,princ,sizeof(errbuf)); goto errout; } r = krb5_auth_con_getauthenticator(k5_context, auth_context, &authenticator); debug(F111,"k5_auth_is","krb5_auth_con_getauthenticator",r); if (r) { (void) ckstrncpy(errbuf, "krb5_auth_con_getauthenticator failed: ", sizeof(errbuf) ); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); goto errout; } if (authenticator->checksum) { char type_check[26]; krb5_checksum *cksum = authenticator->checksum; krb5_keyblock *key; /* UPDATE for START_TLS. AUTH_ENCRYPT_START_TLS and inclusion of */ /* client and then server finished messages. */ type_check[0] = AUTHTYPE_KERBEROS_V5; type_check[1] = how; /* not broken into parts */ #ifdef CK_SSL if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); ckhexdump("k5_auth_is type_check",type_check,26); } #endif /* CK_SSL */ r = krb5_auth_con_getkey(k5_context, auth_context, &key); debug(F111,"k5_auth_is","krb5_auth_con_getkey",r); if (r) { (void) ckstrncpy(errbuf, "krb5_auth_con_getkey failed: ", sizeof(errbuf)); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); goto errout; } r = krb5_verify_checksum(k5_context, cksum->checksum_type, cksum, &type_check, ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) ? 26 : 2, key->contents, key->length ); debug(F111,"k5_auth_is","krb5_verify_checksum",r); if (r) { (void) ckstrncpy(errbuf, "checksum verification failed: ", sizeof(errbuf) ); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); goto errout; } krb5_free_keyblock(k5_context, key); } else { if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_USING_TELOPT) { (void) strcpy(errbuf, "authenticator is missing required checksum"); goto errout; } } krb5_free_authenticator(k5_context, authenticator); #endif /* HEIMDAL */ #ifdef TLS_VERIFY if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { krb5_data in, msg; char tls_verify[24]; krb5_replay_data repdata; ssl_get_server_finished(&tls_verify[0],12); ssl_get_client_finished(&tls_verify[12],12); in.data = tls_verify; in.length = 24; krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR); if (r = krb5_mk_safe(k5_context,auth_context,&in,&msg,&repdata)) { com_err("", r, "encoding tls verifier"); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); goto errout; } SendK5AuthSB(KRB5_TLS_VERIFY, msg.data, msg.length); #ifdef HEIMDAL krb5_data_free(&msg); #else krb5_free_data_contents(k5_context,&msg); #endif } #endif /* CK_SSL */ if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { /* do ap_rep stuff here */ if ((r = krb5_mk_rep(k5_context, #ifdef HEIMDAL /* Greg Troxel 29 Sep 2022 */ &auth_context, #else /* HEIMDAL */ auth_context, #endif /* HEIMDAL */ &outbuf))) { debug(F111,"k5_auth_is","krb5_mk_rep",r); (void) ckstrncpy(errbuf, "Make reply failed: ",sizeof(errbuf)); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); goto errout; } debug(F111,"k5_auth_is","krb5_mk_rep",r); SendK5AuthSB(KRB5_RESPONSE, outbuf.data, outbuf.length); mutual_complete = 1; } #ifdef HEIMDAL { char * name = NULL; if (krb5_unparse_name(k5_context, k5_ticket->client, &name)) { szUserNameAuthenticated[0] = '\0'; } else { ckstrncpy(szUserNameAuthenticated,name,UIDBUFLEN); free(name); } } #else /* HEIMDAL */ if ( krb5_aname_to_localname(k5_context, k5_ticket->enc_part2->client, UIDBUFLEN,szUserNameAuthenticated) ) szUserNameAuthenticated[0] = '\0'; #endif /* HEIMDAL */ SendK5AuthSB(KRB_ACCEPT, szUserNameAuthenticated, szUserNameAuthenticated[0] ? -1 : 0); accept_complete = 1; ckmakmsg(strTmp,sizeof(strTmp), "Kerberos5 identifies him as ``", szUserNameAuthenticated,"''",NULL); printf("%s\r\n",strTmp); if (szUserNameRequested[0] && krb5_kuserok(k5_context, #ifdef HEIMDAL k5_ticket->client, #else /* HEIMDAL */ k5_ticket->enc_part2->client, #endif /* HEIMDAL */ szUserNameRequested)) auth_finished(AUTH_VALID); else auth_finished(AUTH_USER); krb5_auth_con_getremotesubkey(k5_context, auth_context, &newkey); if (k5_session_key) { krb5_free_keyblock(k5_context, k5_session_key); k5_session_key = 0; } if (newkey) { krb5_copy_keyblock(k5_context, newkey, &k5_session_key); krb5_free_keyblock(k5_context, newkey); } else { krb5_copy_keyblock(k5_context, #ifdef HEIMDAL &k5_ticket->ticket.key, #else /* HEIMDAL */ k5_ticket->enc_part2->session, #endif /* HEIMDAL */ &k5_session_key); } #ifdef CK_ENCRYPTION #ifdef HEIMDAL skey.type = k5_session_key->keyvalue.length == 8 ? SK_DES : SK_GENERIC; skey.length = k5_session_key->keyvalue.length; skey.data = k5_session_key->keyvalue.data; #else /* HEIMDAL */ skey.type = k5_session_key->length == 8 ? SK_DES : SK_GENERIC; skey.length = k5_session_key->length; skey.data = k5_session_key->contents; #endif /* HEIMDAL */ encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT); #endif /* CK_ENCRYPTION */ debug(F100,"k5_auth_is AUTH_SUCCESS","",0); krb5_errno = r; if ( krb5_errno ) makestr(&krb5_errmsg,error_message(krb5_errno)); else makestr(&krb5_errmsg,strTmp); return AUTH_SUCCESS; #ifdef FORWARD case KRB5_FORWARD: if ( !forward_flag ) { SendK5AuthSB(KRB5_FORWARD_REJECT, "forwarded credentials are being refused.", -1); return(AUTH_SUCCESS); } inbuf.length = cnt; inbuf.data = (char *)data; if ( #ifndef HEIMDAL (!krb5_d_no_addresses && (r = krb5_auth_con_genaddrs(k5_context,auth_context,g_kstream->fd, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR))) || #endif /* HEIMDAL */ (r = rd_and_store_for_creds(k5_context, auth_context,&inbuf, #ifdef HEIMDAL k5_ticket->client #else /* HEIMDAL */ k5_ticket->enc_part2->client #endif /* HEIMDAL */ ))) { (void) ckstrncpy(errbuf, "Read forwarded creds failed: ", sizeof(errbuf)); (void) ckstrncat(errbuf, error_message(r),sizeof(errbuf)); SendK5AuthSB(KRB5_FORWARD_REJECT, errbuf, -1); printf("Could not read forwarded credentials\r\n"); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); } else { SendK5AuthSB(KRB5_FORWARD_ACCEPT, 0, 0); ckstrncpy(strTmp,"Forwarded credentials obtained",sizeof(strTmp)); printf("%s\r\n",strTmp); krb5_errno = 0; makestr(&krb5_errmsg,strTmp); } /* A failure to accept forwarded credentials is not an */ /* authentication failure. */ return AUTH_SUCCESS; #endif /* FORWARD */ default: printf("Unknown Kerberos option %d\r\n", data[-1]); SendK5AuthSB(KRB_REJECT, 0, 0); break; } auth_finished(AUTH_REJECT); return AUTH_FAILURE; errout: SendK5AuthSB(KRB_REJECT, errbuf, -1); krb5_errno = r; makestr(&krb5_errmsg,errbuf); printf("%s\r\n", errbuf); if (auth_context) { krb5_auth_con_free(k5_context, auth_context); auth_context = 0; } auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #ifdef FORWARD int #ifdef CK_ANSIC kerberos5_forward(void) #else kerberos5_forward() #endif { krb5_error_code r; krb5_ccache ccache=NULL; krb5_principal client = 0; krb5_principal server = 0; krb5_data forw_creds; #ifdef HEIMDAL krb5_creds creds; #endif /* HEIMDAL */ forw_creds.data = 0; r = k5_get_ccache(k5_context,&ccache,NULL); if ( r ) { com_err(NULL, r, "Kerberos V5: could not get default ccache"); krb5_errno = r; makestr(&krb5_errmsg,error_message(krb5_errno)); return(AUTH_FAILURE); } if ((r = krb5_cc_get_principal(k5_context, ccache, &client))) { com_err(NULL, r, "Kerberos V5: could not get default principal"); goto cleanup; } #ifdef HEIMDAL memset(&creds, 0, sizeof(creds)); creds.client = client; if (r = krb5_build_principal(k5_context, &creds.server, strlen(client->realm), client->realm, "krbtgt", client->realm, NULL)) { com_err(NULL, r, "Kerberos V5: could not get principal"); goto cleanup; } creds.times.endtime = 0; if (r = krb5_get_forwarded_creds(k5_context, auth_context, ccache, 0, szHostName, &creds, &forw_creds)) { com_err(NULL, r, "Kerberos V5: error getting forwarded creds"); goto cleanup; } #else /* HEIMDAL */ /* we should not need to make this call since we are storing the */ /* server's principal in fwd_server from our call to */ /* krb5_sname_to_principal() in k5_auth_send() */ if (fwd_server == NULL) { if ((r = krb5_sname_to_principal(k5_context, szHostName, krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME, KRB5_NT_SRV_HST, &server))) { com_err(NULL, r, "Kerberos V5: could not make server principal"); goto cleanup; } } if (!krb5_d_no_addresses && (r = krb5_auth_con_genaddrs(k5_context, auth_context, g_kstream->fd, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR))) { com_err(NULL, r, "Kerberos V5: could not gen local full address"); goto cleanup; } if (r = krb5_fwd_tgt_creds(k5_context, auth_context, 0, client, fwd_server ? fwd_server : server, ccache, forwardable_flag, &forw_creds)) { com_err(NULL, r, "Kerberos V5: error getting forwardable credentials"); goto cleanup; } #endif /* HEIMDAL */ /* Send forwarded credentials */ if (!SendK5AuthSB(KRB5_FORWARD, forw_creds.data, forw_creds.length)) { printf("Kerberos V5 forwarding error!\r\n%s\r\n", "Not enough room for authentication data"); } cleanup: if (client) krb5_free_principal(k5_context, client); if (server) krb5_free_principal(k5_context, server); #ifdef HEIMDAL krb5_data_free(&forw_creds); #else /* HEIMDAL */ krb5_free_data_contents(k5_context,&forw_creds); #endif /* HEIMDAL */ krb5_cc_close(k5_context, ccache); krb5_errno = r; makestr(&krb5_errmsg,krb5_errno?error_message(krb5_errno):"OK"); return(r?AUTH_FAILURE:AUTH_SUCCESS); } #endif /* FORWARD */ #else /* KRB5 */ int ck_krb5_autoget_TGT(char * dummy) { return(0); } #ifdef CK_KERBEROS int #ifdef CK_ANSIC ck_krb5_initTGT( struct krb_op_data * op, struct krb5_init_data * init, struct krb4_init_data * k4_init) #else ck_krb5_initTGT(op,init,k4_init) krb_op_data * op; struct krb5_init_data * init; struct krb4_init_data * k4_init; #endif /* CK_ANSIC*/ { return(-1); } int #ifdef CK_ANSIC ck_krb5_destroy(struct krb_op_data * op) #else ck_krb5_destroy(op) struct krb_op_data * op; #endif { return(-1); } int #ifdef CK_ANSIC ck_krb5_list_creds(struct krb_op_data * op, struct krb5_list_cred_data * lc) #else ck_krb5_list_creds(op,lc) struct krb_op_data * op; struct krb5_list_cred_data * lc; #endif { return(-1); } #else /* CK_KERBEROS */ int #ifdef CK_ANSIC ck_krb5_initTGT(void * op, void * init, void * k4_init ) #else ck_krb5_initTGT(op,init,k4_init) void * op; void * init; void * k4_init; #endif /* CK_ANSIC*/ { return(-1); } int #ifdef CK_ANSIC ck_krb5_destroy(void * op) #else ck_krb5_destroy(op) void * op; #endif { return(-1); } int #ifdef CK_ANSIC ck_krb5_list_creds(void * op, void * lc) #else ck_krb5_list_creds(op,lc) void * op; void * lc; #endif { return(-1); } #endif /* CK_KERBEROS */ #endif /* KRB5 */ #ifdef GSSAPI_KRB5 /* * * gssk5_auth_send - gets authentication bits we need to send to KDC. * * Result is left in k5_auth * * Returns: 0 on failure, 1 on success * */ static int #ifdef CK_ANSIC gssk5_auth_send(int how, int encrypt, int forward) #else gssk5_auth_send(how,encrypt,forward) int how; int encrypt; int forward; #endif { OM_uint32 maj_stat, min_stat; #ifdef KRB5 char * realm = NULL; char tgt[256]; #endif /* KRB5 */ gss_chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */ gss_chan.initiator_address.length = 4; gss_chan.initiator_address.value = &myctladdr.sin_addr.s_addr; gss_chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */ gss_chan.acceptor_address.length = 4; gss_chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr; gss_chan.application_data.length = 0; gss_chan.application_data.value = 0; #ifdef KRB5 realm = ck_krb5_realmofhost(ftp_host); if (realm) { ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm); debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0); if ( krb5_autoget && !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) || (ck_krb5_is_tgt_valid() > 0)) ) ck_krb5_autoget_TGT(realm); } #endif /* KRB5 */ /* Blob from gss-client */ /* host@hostname */ /* the V5 GSSAPI binding canonicalizes this for us... */ ckmakmsg(gss_stbuf,GSS_BUFSIZ, krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME, "@", szHostName, NULL ); fprintf(stderr, "Authenticating to <%s>...\n", gss_stbuf); gss_send_tok.value = gss_stbuf; gss_send_tok.length = strlen(gss_stbuf); maj_stat = gss_import_name(&min_stat, &gss_send_tok, gss_nt_service_name, &gss_target_name ); if (maj_stat != GSS_S_COMPLETE) { user_gss_error(maj_stat, min_stat, "parsing name"); secure_error("name parsed <%s>\n", gss_stbuf); return(0); } token_ptr = GSS_C_NO_BUFFER; gcontext = GSS_C_NO_CONTEXT; /* structure copy */ fprintf(stderr, "calling gss_init_sec_context\n"); maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &gcontext, gss_target_name, gss_mech_krb5, GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | ((forward && forward_flag) ? GSS_C_DELEG_FLAG : 0), 0, (krb5_d_no_addresses ? /* channel bindings */ GSS_C_NO_CHANNEL_BINDINGS : &gss_chan), gss_token_ptr, NULL, /* ignore mech type */ &gss_send_tok, NULL, /* ignore ret_flags */ NULL ); /* ignore time_rec */ if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) { user_gss_error(maj_stat, min_stat, "initializing context" ); gss_release_name(&min_stat, &gss_target_name); return(0); } return(1); } /* * gssk5_auth_reply -- checks the reply for mutual authentication. */ static int #ifdef CK_ANSIC gssk5_auth_reply(int how, unsigned char *data, int cnt) #else gssk5_auth_reply(how,data,cnt) int how; unsigned char *data; int cnt; #endif { data += 4; /* Point to status byte */ cnt -=5; switch (*data++) { case GSS_REJECT: if (cnt > 0) { char *s; int len; ckstrncpy(strTmp,"GSSAPI refuses authentication because\r\n", sizeof(strTmp)); len = strlen(strTmp); if ( len + cnt < sizeof(strTmp) ) { s = strTmp + strlen(strTmp); memcpy(s, data, cnt); /* safe */ s[cnt] = 0; } } else ckstrncpy(strTmp,"GSSAPI refuses authentication", sizeof(strTmp)); printf("GSSAPI authentication failed!\r\n%s\r\n",strTmp); auth_finished(AUTH_REJECT); return AUTH_FAILURE; case GSS_ACCEPT: if ( cnt > 0 ) { char *s; int len; ckstrncpy(strTmp,"GSSAPI accepts you as ",sizeof(strTmp)); len = strlen(strTmp); if ( len + cnt < sizeof(strTmp) ) { s = strTmp + strlen(strTmp); memcpy(s,data,cnt); s[cnt] = 0; } } accept_complete = 1; printf("%s\r\n",strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; case GSS_RESPONSE: gss_token_ptr = &gss_recv_tok; gss_recv_tok.value = data; gss_recv_tok.length = cnt; maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &gcontext, gss_target_name, gss_krb5_mech, GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | (forward_flag ? GSS_C_DELEG_FLAG : 0), 0, (krb5_d_no_addresses ? /* channel bindings */ GSS_C_NO_CHANNEL_BINDINGS : &gss_chan), gss_token_ptr, NULL, /* ignore mech type */ &gss_send_tok, NULL, /* ignore ret_flags */ NULL ); /* ignore time_rec */ if ( maj_stat == GSS_S_COMPLETE ) { } else if ( maj_stat == CSS_S_CONTINUE_NEEDED ) { } else { } ckstrncpy(strTmp,"Remote machine has been mutually authenticated", sizeof(strTmp)); printf("%s\r\n",strTmp); auth_finished(AUTH_USER); return AUTH_SUCCESS; default: auth_finished(AUTH_REJECT); return AUTH_FAILURE; /* Unknown reply type */ } } /* * * gssk5_auth_is. * */ static int #ifdef CK_ANSIC k5_auth_is(int how, unsigned char *data, int cnt) #else k5_auth_is(how,data,cnt) int how; unsigned char *data; int cnt; #endif { int replied = 0; gss_cred_id_t server_creds, deleg_creds; gss_name_t client; int ret_flags; gss_buffer_desc name_buf; gss_name_t server_name; OM_uint32 acquire_maj, acquire_min, accept_maj, accept_min, stat_maj, stat_min; gss_OID mechid; gss_buffer_desc tok, out_tok; char gbuf[GSS_BUFSIZ]; u_char gout_buf[GSS_BUFSIZ]; char localname[MAXHOSTNAMELEN]; char service_name[MAXHOSTNAMELEN+10]; char **service; struct hostent *hp; data += 4; /* Point to status byte */ cnt -= 4; ckhexdump("gssk5_auth_is data",data,cnt); debug(F111,"gssk5_auth_is","how",how); if (cnt-- < 1) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } switch (*data++) { case GSS_AUTH: gss_chan.initiator_addrtype = GSS_C_AF_INET; gss_chan.initiator_address.length = 4; gss_chan.initiator_address.value = &his_addr.sin_addr.s_addr; gss_chan.acceptor_addrtype = GSS_C_AF_INET; gss_chan.acceptor_address.length = 4; gss_chan.acceptor_address.value = &ctrl_addr.sin_addr.s_addr; gss_chan.application_data.length = 0; gss_chan.application_data.value = 0; tok.value = data; tok.length = cnt; if (gethostname(localname, MAXHOSTNAMELEN)) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } if (!(hp = gethostbyname(localname))) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #ifdef HADDRLIST hp = ck_copyhostent(hp); #endif /* HADDRLIST */ strncpy(localname, hp->h_name, sizeof(localname) - 1); localname[sizeof(localname) - 1] = '\0'; sprintf(service_name, "%s@%s", *service, localname); name_buf.value = service_name; name_buf.length = strlen(name_buf.value) + 1; stat_maj = gss_import_name(&stat_min, &name_buf, gss_nt_service_name, &server_name); if (stat_maj != GSS_S_COMPLETE) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } acquire_maj = gss_acquire_cred(&acquire_min, server_name, 0, GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &server_creds, NULL, NULL); (void) gss_release_name(&stat_min, &server_name); if (acquire_maj != GSS_S_COMPLETE) { reply_gss_error(535, accept_maj, accept_min, "accepting context"); syslog(LOG_ERR, "failed accepting context"); (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) (void) gss_release_cred(&stat_min, &deleg_creds); return 0; } gcontext = GSS_C_NO_CONTEXT; accept_maj = gss_accept_sec_context(&accept_min, &gcontext, /* context_handle */ /* verifier_cred_handle */ server_creds, &tok, /* input_token */ (krb5_d_no_addresses ? /* channel bindings */ GSS_C_NO_CHANNEL_BINDINGS : &gss_chan), &client, /* src_name */ &mechid, /* mech_type */ &out_tok, /* output_token */ &ret_flags, NULL, /* ignore time_rec */ /* forwarded credentials */ &deleg_creds ); if (accept_maj!=GSS_S_COMPLETE && accept_maj!=GSS_S_CONTINUE_NEEDED) { reply_gss_error(535, accept_maj, accept_min, "accepting context"); syslog(LOG_ERR, "failed accepting context"); (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) (void) gss_release_cred(&stat_min, &deleg_creds); return 0; } if (out_tok.length) { if (kerror = radix_encode(out_tok.value,gbuf,&out_tok.length, 0)) { secure_error("Couldn't encode ADAT reply (%s)", radix_error(kerror)); syslog(LOG_ERR, "couldn't encode ADAT reply"); (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) (void) gss_release_cred(&stat_min, &deleg_creds); return(0); } if (stat_maj == GSS_S_COMPLETE) { reply(235, "ADAT=%s", gbuf); replied = 1; } else { /* If the server accepts the security data, and requires additional data, it should respond with reply code 335. */ reply(335, "ADAT=%s", gbuf); } (void) gss_release_buffer(&stat_min, &out_tok); } if (stat_maj == GSS_S_COMPLETE) { /* GSSAPI authentication succeeded */ stat_maj = gss_display_name(&stat_min, client, &client_name, &mechid); if (stat_maj != GSS_S_COMPLETE) { /* "If the server rejects the security data (if a checksum fails, for instance), it should respond with reply code 535." */ reply_gss_error(535, stat_maj, stat_min, "extracting GSSAPI identity name"); syslog(LOG_ERR, "gssapi error extracting identity"); (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) (void) gss_release_cred(&stat_min, &deleg_creds); return 0; } auth_type = temp_auth_type; temp_auth_type = NULL; (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) { if (want_creds) ftpd_gss_convert_creds(client_name.value, deleg_creds); (void) gss_release_cred(&stat_min, &deleg_creds); } /* If the server accepts the security data, but does not require any additional data (i.e., the security data exchange has completed successfully), it must respond with reply code 235. */ if (!replied) { if (ret_flags & GSS_C_DELEG_FLAG && !have_creds) reply(235, "GSSAPI Authentication succeeded, but could not accept forwarded credentials" ); else reply(235, "GSSAPI Authentication succeeded"); } return(1); } else if (stat_maj == GSS_S_CONTINUE_NEEDED) { /* If the server accepts the security data, and requires additional data, it should respond with reply code 335. */ reply(335, "more data needed"); (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) (void) gss_release_cred(&stat_min, &deleg_creds); return(0); } else { /* "If the server rejects the security data (if a checksum fails, for instance), it should respond with reply code 535." */ reply_gss_error(535, stat_maj, stat_min, "GSSAPI failed processing ADAT"); syslog(LOG_ERR, "GSSAPI failed processing ADAT"); (void) gss_release_cred(&stat_min, &server_creds); if (ret_flags & GSS_C_DELEG_FLAG) (void) gss_release_cred(&stat_min, &deleg_creds); return(0); } debug(F100,"gssk5_auth_is AUTH_SUCCESS","",0); krb5_errno = r; if ( krb5_errno ) makestr(&krb5_errmsg,error_message(krb5_errno)); else makestr(&krb5_errmsg,strTmp); return AUTH_SUCCESS; default: printf("Unknown Kerberos option %d\r\n", data[-1]); SendGSSK5AuthSB(GSS_REJECT, 0, 0); break; } auth_finished(AUTH_REJECT); return AUTH_FAILURE; } #endif /* GSSAPI_KRB5 */ #ifdef CK_SRP /* * Copyright (c) 1997 Stanford University * * The use of this software for revenue-generating purposes may require a * license from the owners of the underlying intellectual property. * Specifically, the SRP-3 protocol may not be used for revenue-generating * purposes without a license. * * NOTE: Columbia University has a license. * * Within that constraint, permission to use, copy, modify, and distribute * this software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notices and this permission * notice appear in all copies of the software and related documentation. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ static void srp_encode_length(data, num) unsigned char * data; int num; { *data = (num >> 8) & 0xff; *++data = num & 0xff; } static int srp_decode_length(data) unsigned char * data; { return (((int) *data & 0xff) << 8) | (*(data + 1) & 0xff); } #ifdef PRE_SRP_1_7_3 static int #ifdef CK_ANSIC srp_reply(int how, unsigned char *data, int cnt) #else srp_reply(how,data,cnt) int how; unsigned char *data; int cnt; #endif { struct t_num n; struct t_num g; struct t_num s; struct t_num B; struct t_num * A; char type_check[26]; int pflag; #ifdef CK_ENCRYPTION Session_Key skey; #endif /* ENCRYPTION */ char * str=NULL; data += 4; /* Point to status byte */ cnt -= 4; if(cnt-- < 1) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } switch(*data++) { case SRP_REJECT: ckmakmsg(strTmp,sizeof(strTmp), "SRP refuses authentication for '",szUserName, "'\r\n",NULL); if (cnt > 0) { int len = strlen(strTmp); if ( len + cnt < sizeof(strTmp) ) { str = strTmp + strlen(strTmp); memcpy(str,data,cnt); str[cnt] = 0; } } printf("SRP authentication failed!\r\n%s\r\n",strTmp); if (tc != NULL) { t_clientclose(tc); tc = NULL; } auth_finished(AUTH_REJECT); return AUTH_FAILURE; case SRP_ACCEPT: if(cnt < RESPONSE_LEN || !srp_waitresp || tc == NULL ) { printf("SRP Protocol error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } srp_waitresp = 0; if(t_clientverify(tc, data) == 0) { printf("SRP accepts you as %s\r\n",szUserName); #ifdef CK_SSL if((ssl_active_flag || tls_active_flag) && (how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { printf("TLS session parameters verified by SRP\r\n"); } else #endif /* CK_SSL */ #ifdef CK_ENCRYPTION { skey.type = SK_GENERIC; skey.length = SESSION_KEY_LEN; skey.data = tc->session_key; encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER); } #endif /* ENCRYPTION */ t_clientclose(tc); tc = NULL; accept_complete = 1; auth_finished(AUTH_VALID); return AUTH_SUCCESS; } else { printf("SRP server authentication failed!\r\n"); t_clientclose(tc); tc = NULL; return(auth_resend(AUTHTYPE_SRP)); } break; case SRP_PARAMS: if(!szUserName) { printf("No username available\r\n"); return(auth_resend(AUTHTYPE_SRP)); } n.len = srp_decode_length(data); data += 2; cnt -= 2; if(n.len > cnt) { printf("n too long\r\n"); return(auth_resend(AUTHTYPE_SRP)); } n.data = data; data += n.len; cnt -= n.len; g.len = srp_decode_length(data); data += 2; cnt -= 2; if(g.len > cnt) { printf("g too long\r\n"); return(auth_resend(AUTHTYPE_SRP)); } g.data = data; data += g.len; cnt -= g.len; s.len = srp_decode_length(data); data += 2; cnt -= 2; if(s.len > cnt) { printf("salt too long\r\n"); return(auth_resend(AUTHTYPE_SRP)); } s.data = data; data += s.len; cnt -= s.len; /* If the parameters provided by the server cannot be * validated the following function will fail. */ tc = t_clientopen(szUserName, &n, &g, &s); if (tc == NULL) { printf("SRP parameter initialization error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } A = t_clientgenexp(tc); if(A == NULL) { printf("SRP protocol error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } SendSRPAuthSB(SRP_EXP, A->data, A->len); if ( pwbuf[0] && pwflg ) { printf("SRP using %d-bit modulus for '%s'\r\n", 8 * n.len, szUserName ); ckstrncpy(srp_passwd,pwbuf,sizeof(srp_passwd)); #ifdef OS2 if ( pwcrypt ) ck_encrypt((char *)srp_passwd); #endif /* OS2 */ } else { extern char * srppwprompt; char preface[128]; int ok; if (srppwprompt && srppwprompt[0] && (strlen(srppwprompt) + strlen(szUserName) - 2) < sizeof(preface)) { sprintf(preface,srppwprompt,szUserName); } else { ckmakxmsg( preface,sizeof(preface), "SRP using ",ckitoa(8*n.len),"-bit modulus for '", szUserName, "'", NULL, NULL, NULL, NULL, NULL, NULL, NULL); } ok = uq_txt( preface,"Password: ",2,NULL, srp_passwd,sizeof(srp_passwd)-1,NULL, DEFAULT_UQ_TIMEOUT); if ( !ok ) srp_passwd[0] = '\0'; } t_clientpasswd(tc, srp_passwd); memset(srp_passwd, 0, sizeof(srp_passwd)); return AUTH_SUCCESS; case SRP_CHALLENGE: if(tc == NULL) { printf("SRP protocol error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } #ifndef PRE_SRP_1_4_5 /* * The original SRP AUTH implementation did not protect against * tampering of the auth-type-pairs. Therefore, when the * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted * into the SRP hash computation. When AUTH_ENCRYPT_START_TLS * is set we also insert the SSL/TLS client and server finished * messages to ensure that there is no man in the middle attack * underway on the SSL/TLS connection. */ if ((how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF) { type_check[0] = AUTHTYPE_SRP; type_check[1] = how; #ifdef CK_SSL if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); t_clientaddexdata(tc,type_check,26); } else #endif /* CK_SSL */ t_clientaddexdata(tc,type_check,2); } #endif /* PRE_SRP_1_4_5 */ B.data = data; B.len = cnt; t_clientgetkey(tc, &B); SendSRPAuthSB(SRP_RESPONSE, t_clientresponse(tc), RESPONSE_LEN); srp_waitresp = 1; return AUTH_SUCCESS; default: return(auth_resend(AUTHTYPE_SRP)); } return AUTH_FAILURE; } static int #ifdef CK_ANSIC srp_is(int how, unsigned char *data, int cnt) #else srp_is(how,data,cnt) int how; unsigned char *data; int cnt; #endif { char * pbuf = NULL; char * ptr; #ifdef CK_ENCRYPTION Session_Key skey; #endif struct t_num A; struct t_pw * tpw = NULL; struct t_conf * tconf = NULL; struct passwd * pass; static struct t_num * B = NULL; /* Holder for B */ #ifdef CK_SSL char type_check[26]; #else char type_check[2]; #endif /* CK_SSL */ if ((cnt -= 4) < 1) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } data += 4; cnt -= 1; switch(*data++) { case SRP_AUTH: /* Send parameters back to client */ if(ts != NULL) { t_serverclose(ts); ts = NULL; } if(!szUserNameRequested[0]) { if (1) printf("No username available\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "No username supplied", -1); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } #ifdef IKSD #ifdef CK_LOGIN if (inserver && ckxanon && !strcmp(szUserNameRequested,"anonymous")) { SendSRPAuthSB(SRP_REJECT, (void *) "anonymous login cannot be performed with Secure Remote Password", -1); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } #endif /* CK_LOGIN */ #endif /* IKSD */ #ifndef PRE_SRP_1_4_4 if(tpw == NULL) { if((tpw = t_openpw(NULL)) == NULL) { if (1) printf("Unable to open password file\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "No password file", -1); return(AUTH_FAILURE); } } if(tconf == NULL) { if((tconf = t_openconf(NULL)) == NULL) { if (1) printf("Unable to open configuration file\r\n"); SendSRPAuthSB(SRP_REJECT, (void *)"No configuration file", -1); return(AUTH_FAILURE); } } ts = t_serveropenfromfiles(szUserNameRequested, tpw, tconf); t_closepw(tpw); tpw = NULL; t_closeconf(tconf); tconf = NULL; #else /* PRE_SRP_1_4_4 */ #ifdef COMMENT /* the code in this block should no longer be necessary on OS/2 or Windows because I have added functionality to libsrp.lib to find the srp files. 4/22/2000 */ /* On Windows and OS/2 there is no well defined place for the */ /* ETC directory. So we look for either an SRP_ETC or ETC */ /* environment variable in that order. If we find one we */ /* attempt to open the files manually. */ /* We will reuse the strTmp[] for the file names. */ ptr = getenv("SRP_ETC"); if ( !ptr ) ptr = getenv("ETC"); #ifdef NT if ( !ptr ) { DWORD len; len = AUTHTMPBL; len = GetWindowsDirectory(strTmp,len); if ( len > 0 && len < AUTHTMPBL) { if ( !isWin95() ) { if ( len == 1 ) ckstrncat(strTmp,"SYSTEM32/DRIVERS/ETC",sizeof(strTmp)); else ckstrncat(strTmp,"/SYSTEM32/DRIVERS/ETC",sizeof(strTmp)); } } ptr = strTmp; } #endif /* NT */ if ( ptr ) { int len = strlen(ptr); int i; if (ptr != strTmp) strcpy(strTmp,ptr); for ( i=0;in.len + ts->g.len + ts->s.len + 7); ptr = pbuf; srp_encode_length(ptr, ts->n.len); ptr += 2; memcpy(ptr, ts->n.data, ts->n.len); /* safe */ ptr += ts->n.len; srp_encode_length(ptr, ts->g.len); ptr += 2; memcpy(ptr, ts->g.data, ts->g.len); /* safe */ ptr += ts->g.len; srp_encode_length(ptr, ts->s.len); ptr += 2; memcpy(ptr, ts->s.data, ts->s.len); /* safe */ ptr += ts->s.len; SendSRPAuthSB(SRP_PARAMS, pbuf, ptr - pbuf); free(pbuf); pbuf = NULL; B = t_servergenexp(ts); ckstrncpy(szUserNameAuthenticated,szUserNameRequested,UIDBUFLEN); return AUTH_SUCCESS; case SRP_EXP: /* Client is sending A to us, compute challenge & expected response. */ if (ts == NULL || B == NULL) { printf("Protocol error: SRP_EXP unexpected\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Protocol error: unexpected EXP", -1 ); return(AUTH_FAILURE); } /* Wait until now to send B, since it contains the key to "u" */ SendSRPAuthSB(SRP_CHALLENGE, B->data, B->len); B = NULL; #ifndef PRE_SRP_1_4_5 /* * The original SRP AUTH implementation did not protect against * tampering of the auth-type-pairs. Therefore, when the * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted * into the SRP hash computation. When AUTH_ENCRYPT_START_TLS * is set we also insert the SSL/TLS client and server finished * messages to ensure that there is no man in the middle attack * underway on the SSL/TLS connection. */ if ( (how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF ) { type_check[0] = AUTHTYPE_SRP; type_check[1] = how; #ifdef CK_SSL if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); } #endif /* CK_SSL */ t_serveraddexdata(ts,type_check, #ifdef CK_SSL ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) ? 26 : #endif /* CK_SSL */ 2); } #endif /* PRE_SRP_1_4_5 */ A.data = data; A.len = cnt; ptr = t_servergetkey(ts, &A); if(ptr == NULL) { if (1) printf("Security alert: Trivial session key attempted\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Trivial session key detected", -1 ); return(AUTH_FAILURE); } srp_waitresp = 1; return AUTH_SUCCESS; case SRP_RESPONSE: /* Got the response; see if it's correct */ if (!srp_waitresp || ts == NULL ) { if (1) printf("Protocol error: SRP_RESPONSE unexpected\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Protocol error: unexpected RESPONSE", -1 ); return(AUTH_FAILURE); } srp_waitresp = 0; /* we got a response */ if (cnt < RESPONSE_LEN) { if (1) printf("Protocol error: malformed response\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Protocol error: malformed response", -1 ); return(AUTH_FAILURE); } if (t_serververify(ts, data) == 0) { SendSRPAuthSB(SRP_ACCEPT, t_serverresponse(ts), RESPONSE_LEN); accept_complete = 1; #ifdef CK_ENCRYPTION #ifdef CK_SSL if (!(ssl_active_flag || tls_active_flag)) #endif /* CK_SSL */ { ckhexdump("SRP_RESPONSE ts",ts,sizeof(ts)); ckhexdump("SRP_RESPONSE session_key", ts->session_key, SESSION_KEY_LEN ); skey.type = SK_GENERIC; skey.length = SESSION_KEY_LEN; skey.data = ts->session_key; encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT); } #endif /* CK_ENCRYPTION */ auth_finished(AUTH_VALID); } else { SendSRPAuthSB(SRP_REJECT, (void *) "Login incorrect", -1); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } return AUTH_SUCCESS; default: printf("Unknown SRP option %d\r\n", data[-1]); SendSRPAuthSB(SRP_REJECT, (void *) "Unknown option received", -1); return(AUTH_FAILURE); } } #else /* PRE_SRP_1_7_3 */ static int #ifdef CK_ANSIC new_srp_reply(int how, unsigned char *data, int cnt) #else new_srp_reply(how,data,cnt) int how; unsigned char *data; int cnt; #endif { data += 4; /* Point to status byte */ cnt -= 4; if(cnt-- < 1) { /* Matches with data++ */ auth_finished(AUTH_REJECT); return AUTH_FAILURE; } switch(*data++) { case SRP_PARAMS: { struct t_num n; struct t_num g; struct t_num s; cstr * A; if(!szUserName) { printf("No username available\r\n"); return(auth_resend(AUTHTYPE_SRP)); } n.len = srp_decode_length(data); data += 2; cnt -= 2; if(n.len > cnt) { printf("n too long\r\n"); return(auth_resend(AUTHTYPE_SRP)); } n.data = data; data += n.len; cnt -= n.len; g.len = srp_decode_length(data); data += 2; cnt -= 2; if(g.len > cnt) { printf("g too long\r\n"); return(auth_resend(AUTHTYPE_SRP)); } g.data = data; data += g.len; cnt -= g.len; s.len = srp_decode_length(data); data += 2; cnt -= 2; if(s.len != cnt) { printf("invalid salt\r\n"); return(auth_resend(AUTHTYPE_SRP)); } s.data = data; data += s.len; cnt -= s.len; /* If the parameters provided by the server cannot be * validated the following function will fail. */ c_srp = SRP_new(SRP_RFC2945_client_method()); if (c_srp == NULL || SRP_set_username(c_srp, szUserName) != SRP_SUCCESS || SRP_set_params(c_srp,n.data,n.len,g.data,g.len,s.data,s.len) != SRP_SUCCESS) { printf("SRP Parameter initialization error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } A = cstr_new(); if(SRP_gen_pub(c_srp, &A) != SRP_SUCCESS) { printf("SRP Error generating key exchange\r\n"); return(auth_resend(AUTHTYPE_SRP)); } SendSRPAuthSB(SRP_EXP, A->data, A->length); cstr_free(A); if ( pwbuf[0] && pwflg ) { printf("SRP using %d-bit modulus for '%s'\r\n", 8 * n.len, szUserName ); ckstrncpy(srp_passwd,pwbuf,sizeof(srp_passwd)); #ifdef OS2 if ( pwcrypt ) ck_encrypt((char *)srp_passwd); #endif /* OS2 */ } else { extern char * srppwprompt; char preface[128]; int ok; if (srppwprompt && srppwprompt[0] && (strlen(srppwprompt) + strlen(szUserName) - 2) < sizeof(preface)) { sprintf(preface,srppwprompt,szUserName); } else { ckmakxmsg( preface,sizeof(preface), "SRP using ",ckitoa(8*n.len),"-bit modulus for '", szUserName, "'", NULL, NULL, NULL, NULL, NULL, NULL, NULL); } ok = uq_txt(preface,"Password: ",2,NULL, srp_passwd,sizeof(srp_passwd)-1,NULL, DEFAULT_UQ_TIMEOUT); if ( !ok ) srp_passwd[0] = '\0'; } if(SRP_set_auth_password(c_srp, srp_passwd) != SRP_SUCCESS) { memset(srp_passwd, 0, sizeof(srp_passwd)); printf("SRP Error setting client password\r\n"); return(auth_resend(AUTHTYPE_SRP)); } memset(srp_passwd, 0, sizeof(srp_passwd)); return AUTH_SUCCESS; } case SRP_CHALLENGE: { char type_check[26]; cstr * resp = NULL; if(c_srp == NULL) { printf("SRP protocol error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } /* * The original SRP AUTH implementation did not protect against * tampering of the auth-type-pairs. Therefore, when the * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted * into the SRP hash computation. When AUTH_ENCRYPT_START_TLS * is set we also insert the SSL/TLS client and server finished * messages to ensure that there is no man in the middle attack * underway on the SSL/TLS connection. */ if ((how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF) { type_check[0] = AUTHTYPE_SRP; type_check[1] = how; #ifdef CK_SSL if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); SRP_add_ex_data(c_srp, type_check, 26); } else #endif /* CK_SSL */ SRP_add_ex_data(c_srp, type_check, 2); } if(SRP_compute_key(c_srp, &c_key, data, cnt) != SRP_SUCCESS) { printf("SRP ERROR: unable to compute client key\r\n"); return(auth_resend(AUTHTYPE_SRP)); } resp = cstr_new(); if(SRP_respond(c_srp, &resp) != SRP_SUCCESS) { printf("SRP ERROR: unable to compute client response\r\n"); return(auth_resend(AUTHTYPE_SRP)); } SendSRPAuthSB(SRP_RESPONSE, resp->data, resp->length); cstr_free(resp); srp_waitresp = 1; return AUTH_SUCCESS; } case SRP_ACCEPT: { #ifdef CK_ENCRYPTION Session_Key skey; #endif /* ENCRYPTION */ if(cnt < RESPONSE_LEN || !srp_waitresp || c_srp == NULL) { printf("SRP Protocol error\r\n"); return(auth_resend(AUTHTYPE_SRP)); } srp_waitresp = 0; if(SRP_verify(c_srp, data, cnt) == SRP_SUCCESS) { printf("SRP accepts you as %s\r\n",szUserName); #ifdef CK_SSL if((ssl_active_flag || tls_active_flag) && (how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { printf("TLS session parameters verified by SRP\r\n"); } else #endif /* CK_SSL */ #ifdef CK_ENCRYPTION { skey.type = SK_GENERIC; skey.length = c_key->length; skey.data = c_key->data; encrypt_session_key(&skey, AUTH_CLIENT_TO_SERVER); cstr_clear_free(c_key); c_key = NULL; } #endif /* CK_ENCRYPTION */ accept_complete = 1; auth_finished(AUTH_VALID); SRP_free(c_srp); c_srp = NULL; return AUTH_SUCCESS; } else { printf("[ Error: SRP server authentication failed ]\r\n"); return(auth_resend(AUTHTYPE_SRP)); } } case SRP_REJECT: { char * str=NULL; ckmakmsg(strTmp,sizeof(strTmp), "SRP refuses authentication for '",szUserName, "'\r\n",NULL); if (cnt > 0) { int len = strlen(strTmp); if ( len + cnt < sizeof(strTmp) ) { str = strTmp + strlen(strTmp); memcpy(str,data,cnt); str[cnt] = 0; } } printf("SRP authentication failed!\r\n%s\r\n",strTmp); auth_finished(AUTH_REJECT); return AUTH_FAILURE; } default: printf("Unknown SRP option %d\r\n", data[-1]); return(auth_resend(AUTHTYPE_SRP)); } /* NEVER REACHED */ } static int #ifdef CK_ANSIC new_srp_is(int how, unsigned char *data, int cnt) #else new_srp_is(how,data,cnt) int how; unsigned char *data; int cnt; #endif { char * pbuf = NULL; char * ptr; #ifdef CK_ENCRYPTION Session_Key skey; #endif static cstr * B = NULL; /* Holder for B */ struct t_passwd * pass; cstr * resp; char type_check[26]; if ((cnt -= 4) < 1) { auth_finished(AUTH_REJECT); return AUTH_FAILURE; } data += 4; cnt -= 1; switch(*data++) { case SRP_AUTH: /* Send parameters back to client */ if(s_srp != NULL) { SRP_free(s_srp); s_srp = NULL; } if (B != NULL) { cstr_free(B); B = NULL; } if(!szUserNameRequested[0]) { if (1) printf("No username available\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "No username supplied", -1); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } #ifdef IKSD #ifdef CK_LOGIN if (inserver && ckxanon && !strcmp(szUserNameRequested,"anonymous")) { SendSRPAuthSB(SRP_REJECT, (void *) "anonymous login cannot be performed with Secure Remote Password", -1); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } #endif /* CK_LOGIN */ #endif /* IKSD */ s_srp = SRP_new(SRP_RFC2945_server_method()); if(s_srp == NULL) { printf("Error initializing SRP server\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "SRP server init failed", -1 ); return(AUTH_FAILURE); } pass = gettpnam(szUserNameRequested); if(pass == NULL) { printf("User %s not found\r\n", szUserNameRequested); SendSRPAuthSB(SRP_REJECT, (void *) "Password not set", -1); return(AUTH_FAILURE); } if(SRP_set_username(s_srp, szUserNameRequested) != SRP_SUCCESS || SRP_set_params(s_srp, pass->tc.modulus.data, pass->tc.modulus.len, pass->tc.generator.data, pass->tc.generator.len, pass->tp.salt.data, pass->tp.salt.len) != SRP_SUCCESS || SRP_set_authenticator(s_srp, pass->tp.password.data, pass->tp.password.len) != SRP_SUCCESS) { printf("Error initializing SRP parameters\r\n"); SendSRPAuthSB(SRP_REJECT,(void *)"SRP parameter init failed", -1); return(AUTH_FAILURE); } pbuf = (char *)malloc(pass->tc.modulus.len + pass->tc.generator.len + pass->tp.salt.len + 7); ptr = pbuf; srp_encode_length(ptr, pass->tc.modulus.len); ptr += 2; memcpy(ptr, pass->tc.modulus.data, pass->tc.modulus.len); ptr += pass->tc.modulus.len; srp_encode_length(ptr, pass->tc.generator.len); ptr += 2; memcpy(ptr, pass->tc.generator.data, pass->tc.generator.len); ptr += pass->tc.generator.len; srp_encode_length(ptr, pass->tp.salt.len); ptr += 2; memcpy(ptr, pass->tp.salt.data, pass->tp.salt.len); ptr += pass->tp.salt.len; SendSRPAuthSB(SRP_PARAMS, pbuf, ptr - pbuf); free(pbuf); pbuf = NULL; if(SRP_gen_pub(s_srp, &B) != SRP_SUCCESS) { printf("Error generating SRP public value\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "SRP_gen_pub failed", -1); return(AUTH_FAILURE); } ckstrncpy(szUserNameAuthenticated,szUserNameRequested,UIDBUFLEN); return AUTH_SUCCESS; case SRP_EXP: /* Client is sending A to us, compute challenge and expected response. */ if (s_srp == NULL || B == NULL) { printf("Protocol error: SRP_EXP unexpected\r\n"); SendSRPAuthSB(SRP_REJECT, (void *)"Protocol error: unexpected EXP", -1); return(AUTH_FAILURE); } /* Wait until now to send B, since it contains the key to "u" */ SendSRPAuthSB(SRP_CHALLENGE, B->data, B->length); cstr_free(B); B = NULL; /* * The original SRP AUTH implementation did not protect against * tampering of the auth-type-pairs. Therefore, when the * AUTH_ENCRYPT_MASK bits are zero, no extra data is inserted * into the SRP hash computation. When AUTH_ENCRYPT_START_TLS * is set we also insert the SSL/TLS client and server finished * messages to ensure that there is no man in the middle attack * underway on the SSL/TLS connection. */ if ( (how & AUTH_ENCRYPT_MASK) != AUTH_ENCRYPT_OFF ) { type_check[0] = AUTHTYPE_SRP; type_check[1] = how; #ifdef CK_SSL if ((how & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_START_TLS) { ssl_get_client_finished(&type_check[2],12); ssl_get_server_finished(&type_check[14],12); SRP_add_ex_data(s_srp, type_check, 26); } else #endif /* CK_SSL */ SRP_add_ex_data(s_srp, type_check, 2); } if(SRP_compute_key(s_srp, &s_key, data, cnt) != SRP_SUCCESS) { printf("Security alert: Trivial session key attempted\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Trivial session key detected", -1); return(AUTH_FAILURE); } srp_waitresp = 1; return AUTH_SUCCESS; case SRP_RESPONSE: /* Got the response; see if it's correct */ if (!srp_waitresp || s_srp == NULL) { if (1) printf("Protocol error: SRP_RESPONSE unexpected\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Protocol error: unexpected RESPONSE", -1 ); return(AUTH_FAILURE); } srp_waitresp = 0; /* we got a response */ if (cnt < RESPONSE_LEN) { if (1) printf("Protocol error: malformed response\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Protocol error: malformed response", -1 ); return(AUTH_FAILURE); } if(SRP_verify(s_srp, data, cnt) == SRP_SUCCESS) { resp = cstr_new(); if(SRP_respond(s_srp, &resp) != SRP_SUCCESS) { printf("Error computing response\r\n"); SendSRPAuthSB(SRP_REJECT, (void *) "Error computing response", -1); return(AUTH_FAILURE); } SendSRPAuthSB(SRP_ACCEPT, resp->data, resp->length); accept_complete = 1; cstr_free(resp); #ifdef CK_ENCRYPTION #ifdef CK_SSL if (!(ssl_active_flag || tls_active_flag)) #endif /* CK_SSL */ { skey.type = SK_GENERIC; skey.length = s_key->length; skey.data = s_key->data; encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT); cstr_clear_free(s_key); s_key = NULL; } #endif /* CK_ENCRYPTION */ auth_finished(AUTH_VALID); } else { SendSRPAuthSB(SRP_REJECT, (void *) "Login incorrect", -1); auth_finished(AUTH_REJECT); return(AUTH_FAILURE); } return AUTH_SUCCESS; default: printf("Unknown SRP option %d\r\n", data[-1]); SendSRPAuthSB(SRP_REJECT, (void *) "Unknown option received", -1); return(AUTH_FAILURE); } } #endif /* PRE_SRP_1_7_3 */ #endif /* SRP */ #ifdef KRB5 #ifdef KINIT /* * clients/kinit/kinit.c * * Copyright 1990 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * * Initialize a credentials cache. */ #define KRB5_DEFAULT_OPTIONS 0 #define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ static krb5_data tgtname = { #ifndef HEIMDAL 0, #endif /* HEIMDAL */ KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME }; /* Internal prototypes */ _PROTOTYP(static krb5_error_code krb5_validate_tgt, (krb5_context, krb5_ccache,krb5_principal, krb5_data *)); _PROTOTYP(static krb5_error_code krb5_renew_tgt, (krb5_context, krb5_ccache, krb5_principal, krb5_data *)); _PROTOTYP(static krb5_error_code krb5_tgt_gen, (krb5_context, krb5_ccache, krb5_principal, krb5_data *, int opt)); #ifdef KRB5_HAVE_GET_INIT_CREDS static krb5_error_code KRB5_CALLCONV ck_krb5_prompter( krb5_context context, void *data, const char *name, const char *banner, int num_prompts, krb5_prompt prompts[]) { krb5_error_code errcode = 0; int i; #ifdef KUI struct txtbox * tb = NULL; #else /* KUI */ char * prompt = NULL; #endif /* KUI */ int len = 0, blen=0, nlen=0; debug(F110,"ck_krb5_prompter name",name,0); debug(F110,"ck_krb5_prompter banner",banner,0); debug(F101,"ck_krb5_prompter num_prompts","",num_prompts); if (name) nlen = strlen(name)+2; if (banner) blen = strlen(banner)+2; #ifdef KUI tb = (struct txtbox *) malloc(sizeof(struct txtbox) * num_prompts); if ( tb != NULL ) { int ok; memset(tb,0,sizeof(struct txtbox) * num_prompts); for ( i=0; i < num_prompts; i++ ) { tb[i].t_buf = prompts[i].reply->data; tb[i].t_len = prompts[i].reply->length; tb[i].t_lbl = prompts[i].prompt; tb[i].t_dflt = NULL; tb[i].t_echo = (prompts[i].hidden ? 2 : 1); } ok = uq_mtxt((char *)banner,NULL,num_prompts,tb); if ( ok ) { for ( i=0; i < num_prompts; i++ ) prompts[i].reply->length = strlen(prompts[i].reply->data); } else errcode = -2; } #else /* KUI */ for (i = 0; i < num_prompts; i++) { debug(F111,"ck_krb5_prompter prompt",prompts[i].prompt,i); if ( prompt && len < (nlen + blen + strlen(prompts[i].prompt)+2) ) { free(prompt); prompt = NULL; } if ( !prompt ) prompt = (char *)malloc(nlen + blen + strlen(prompts[i].prompt)+2); if ( !prompt ) { errcode = KRB5_RC_MALLOC; goto cleanup; } len = nlen + blen + strlen(prompts[i].prompt)+2; ckmakxmsg(prompt,len, (char *) (name?name:""), name?"\r\n":"", (char *) (banner?banner:""), banner?"\r\n":"", (char *)prompts[i].prompt, ": ",NULL,NULL,NULL,NULL,NULL,NULL); memset(prompts[i].reply->data, 0, prompts[i].reply->length); if (prompts[i].hidden) { readpass(prompt, prompts[i].reply->data, prompts[i].reply->length); } else { readtext(prompt, prompts[i].reply->data, prompts[i].reply->length); } prompts[i].reply->length = strlen(prompts[i].reply->data); } #endif /* KUI */ cleanup: #ifdef KUI if ( tb ) free(tb); #else /* KUI */ if ( prompt ) free(prompt); #endif /* KUI */ if (errcode) { for (i = 0; i < num_prompts; i++) { memset(prompts[i].reply->data, 0, prompts[i].reply->length); } } return errcode; } /* * I'm not really sure what to do with this. The NRL DLLs use a * different interface for the krb5_prompter callback. It has * one less parameter. This is going to be ugly. */ static krb5_error_code KRB5_CALLCONV ck_NRL_krb5_prompter( krb5_context context, const char *name, const char *banner, int num_prompts, krb5_prompt prompts[]) { return(ck_krb5_prompter(context,NULL,name,banner,num_prompts,prompts)); } #endif /* KRB5_HAVE_GET_INIT_CREDS */ #ifdef KRB524_CONV long try_convert524(krb5_context ctx, krb5_principal me, krb5_ccache cc) { char * progname = "convert524"; krb5_error_code code = 0; int icode = 0; krb5_principal kpcserver = 0; krb5_creds *v5creds = 0; krb5_creds increds; #ifdef OS2 LEASH_CREDENTIALS v4creds; #else /* OS2 */ CREDENTIALS v4creds; #endif /* OS2 */ memset((char *) &increds, 0, sizeof(increds)); /* From this point on, we can goto cleanup because increds is initialized. */ if ((code = krb5_build_principal(ctx, &kpcserver, krb5_princ_realm(ctx, me)->length, krb5_princ_realm(ctx, me)->data, "krbtgt", krb5_princ_realm(ctx, me)->data, NULL))) { com_err(progname, code, "while creating service principal name"); goto cleanup; } memset((char*) &increds, 0, sizeof(increds)); increds.client = me; increds.server = kpcserver; /* Prevent duplicate free calls. */ kpcserver = 0; increds.times.endtime = 0; increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; if ((code = krb5_get_credentials(ctx, 0, cc, &increds, &v5creds))) { com_err(progname, code, "getting V5 credentials"); goto cleanup; } if ((icode = krb524_convert_creds_kdc(ctx, v5creds, &v4creds))) { com_err(progname, icode, "converting to V4 credentials"); goto cleanup; } /* this is stolen from the v4 kinit */ /* initialize ticket cache */ if ((icode = krb_in_tkt(v4creds.pname, v4creds.pinst, v4creds.realm) != KSUCCESS)) { com_err(progname, icode, "trying to create the V4 ticket file"); goto cleanup; } /* stash ticket, session key, etc. for future use */ if ((icode = krb_save_credentials(v4creds.service, v4creds.instance, v4creds.realm, v4creds.session, v4creds.lifetime, v4creds.kvno, &(v4creds.ticket_st), v4creds.issue_date))) { com_err(progname, icode, "trying to save the V4 ticket"); goto cleanup; } cleanup: memset(&v4creds, 0, sizeof(v4creds)); if (v5creds) krb5_free_creds(ctx, v5creds); increds.client = 0; krb5_free_cred_contents(ctx, &increds); if (kpcserver) krb5_free_principal(ctx, kpcserver); return !(code || icode); } #endif /* KRB524_CONV */ #define NO_KEYTAB int #ifdef CK_ANSIC ck_krb5_initTGT( struct krb_op_data * op, struct krb5_init_data * init, struct krb4_init_data * k4_init) #else ck_krb5_initTGT(op,init,k4_init) krb_op_data * op; struct krb5_init_data * init; struct krb4_init_data * k4_init; #endif /* CK_ANSIC*/ { krb5_context kcontext; krb5_ccache ccache = NULL; krb5_deltat lifetime = KRB5_DEFAULT_LIFE; /* -l option */ krb5_timestamp starttime = 0; krb5_deltat rlife = 0; int options = KRB5_DEFAULT_OPTIONS; int option; int errflg = 0; krb5_error_code code; krb5_principal me=NULL; krb5_principal server=NULL; krb5_creds my_creds; krb5_timestamp now; #ifndef HEIMDAL krb5_address **addrs = (krb5_address **)0; #endif /* HEIMDAL */ int addr_count=0; int i,j; #ifndef NO_KEYTAB int use_keytab = 0; /* -k option */ krb5_keytab keytab = NULL; #endif /* NO_KEYTAB */ struct passwd *pw = 0; int pwsize; char *client_name=NULL, principal[256]="", realm[256]="", numstr[40]=""; char *password=NULL, passwd[80]=""; #ifdef KRB5_HAVE_GET_INIT_CREDS krb5_get_init_creds_opt opts; #endif char * name; int len; if ( !ck_krb5_is_installed() ) return(-1); #ifdef COMMENT printf("Kerberos V initialization\r\n"); #endif /* COMMENT */ code = krb5_init_context(&kcontext); if (code) { com_err("krb5_kinit",code,"while init_context"); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } debug(F110,"krb5_init","krb5_init_context",0); if ((code = krb5_timeofday(kcontext, &now))) { com_err("krb5_kinit",code,"while getting time of day"); goto exit_k5_init; } #ifdef KRB5_HAVE_GET_INIT_CREDS memset(&opts, 0, sizeof(opts)); krb5_get_init_creds_opt_init(&opts); debug(F110,"krb5_init","krb5_get_init_creds_opt_init",0); #endif if ( init->renewable ) { options |= KDC_OPT_RENEWABLE; ckmakmsg(numstr,sizeof(numstr),ckitoa(init->renewable),"m",NULL,NULL); #ifdef HEIMDAL code = -1; #else /* HEIMDAL */ code = krb5_string_to_deltat(numstr, &rlife); #endif /* HEIMDAL */ if (code != 0 || rlife == 0) { printf("Bad renewable time value %s\r\n", numstr); errflg++; } #ifdef KRB5_HAVE_GET_INIT_CREDS krb5_get_init_creds_opt_set_renew_life(&opts, rlife); #endif } if ( init->renew ) { /* renew the ticket */ options |= KDC_OPT_RENEW; } if ( init->validate ) { /* validate the ticket */ options |= KDC_OPT_VALIDATE; } if ( init->proxiable ) { options |= KDC_OPT_PROXIABLE; #ifdef KRB5_HAVE_GET_INIT_CREDS krb5_get_init_creds_opt_set_proxiable(&opts, 1); #endif } if ( init->forwardable ) { options |= KDC_OPT_FORWARDABLE; #ifdef KRB5_HAVE_GET_INIT_CREDS krb5_get_init_creds_opt_set_forwardable(&opts, 1); #endif } #ifndef NO_KEYTAB if ( ) { use_keytab = 1; } if ( ) { if (keytab == NULL && keytab_name != NULL) { code = krb5_kt_resolve(kcontext, keytab_name, &keytab); if (code != 0) { debug(F111,"krb5_init resolving keytab", keytab_name,code); errflg++; } } } #endif /* NO_KEYTAB */ if ( init->lifetime ) { ckmakmsg(numstr,sizeof(numstr),ckitoa(init->lifetime),"m",NULL,NULL); #ifdef HEIMDAL code = -1; #else /* HEIMDAL */ code = krb5_string_to_deltat(numstr, &lifetime); #endif /* HEIMDAL */ if (code != 0 || lifetime == 0) { printf("Bad lifetime value %s\r\n", numstr); errflg++; } #ifdef KRB5_HAVE_GET_INIT_CREDS krb5_get_init_creds_opt_set_tkt_life(&opts, lifetime); #endif } if ( init->postdate ) { /* Convert cmdate() to a time_t value */ struct tm * time_tm; struct tm * cmdate2tm(char *,int); time_tm = cmdate2tm(init->postdate,0); if ( time_tm ) starttime = (krb5_timestamp) mktime(time_tm); if (code != 0 || starttime == 0 || starttime == -1) { krb5_deltat ktmp; #ifdef HEIMDAL code = -1; #else /* HEIMDAL */ code = krb5_string_to_deltat(init->postdate, &ktmp); #endif /* HEIMDAL */ if (code == 0 && ktmp != 0) { starttime = now + ktmp; options |= KDC_OPT_POSTDATED; } else { printf("Bad postdate start time value %s\r\n", init->postdate); errflg++; } } else { options |= KDC_OPT_POSTDATED; } } debug(F110,"krb5_init searching for ccache",op->cache,0); code = k5_get_ccache(kcontext,&ccache,op->cache); if (code != 0) { com_err("krb5_kinit",code,"while getting default ccache"); goto exit_k5_init; } /* This is our realm unless it is changed */ ckstrncpy(realm,init->realm ? init->realm : krb5_d_realm, 256); #ifdef KRB5_BETATEST /* This code is going to take the realm and attempt to correct */ /* the case. */ { profile_t profile; code = krb5_get_profile(kcontext, &profile); if ( !code ) { const char *names[4]; char ** realms; int found = 0; names[0] = "realms"; names[1] = NULL; code = profile_get_subsection_names(profile,names,&realms); if ( code == 0 ) { int i=0; while ( realms[i] ) { if (ckstrcmp(realm,realms[i],-1,0) == 0) { strcpy(realm,realms[i]); found = 1; break; } i++; } } #ifdef CK_DNS_SRV if ( !found ) { char * dns_realm = NULL; /* We did not find the realm in the profile so let's try DNS */ locate_txt_rr("_kerberos",realm,&dns_realm); if ( dns_realm && ckstrcmp(realm,dns_realm,-1,0) == 0 && ckstrcmp(realm,dns_realm,-1,1) != 0 ) { ckstrncpy(realm,dns_realm,256); free(dns_realm); } } #endif /* CK_DNS_SRV */ } if (init->realm && ckstrcmp(realm,init->realm,-1,0) == 0 && ckstrcmp(realm,init->realm,-1,1) != 0) strcpy(init->realm,realm); if (ckstrcmp(realm,krb5_d_realm,-1,0) == 0 && ckstrcmp(realm,krb5_d_realm,-1,1) != 0) strcpy(krb5_d_realm,realm); } #endif /* KRB_BETATEST */ if (init->principal == NULL) { /* No principal name specified */ #ifndef NO_KEYTAB if (use_keytab) { /* Use the default host/service name */ code = krb5_sname_to_principal(kcontext, NULL, NULL, KRB5_NT_SRV_HST, &me); if (code == 0 && krb5_princ_realm(kcontext, me)->length < sizeof(realm)) { /* Save the realm */ memcpy(realm,krb5_princ_realm(kcontext, me)->data, krb5_princ_realm(kcontext, me)->length); /* safe */ realm[krb5_princ_realm(kcontext, me)->length]='\0'; } else { com_err("krb5_kinit", code, "when creating default server principal name"); goto exit_k5_init; } } else #endif /* NO_KEYTAB */ { int len; char * name; /* Get default principal from cache if one exists */ code = krb5_cc_get_principal(kcontext, ccache, &me); #ifdef HEIMDAL name = me->realm; len = strlen(name); #else /* HEIMDAL */ len = krb5_princ_realm(kcontext, me)->length; name = krb5_princ_realm(kcontext, me)->data; #endif /* HEIMDAL */ if (code == 0 && len < sizeof(realm)) { /* Save the realm */ memcpy(realm,name,len); /* safe */ realm[len]='\0'; } else { #ifdef HAVE_PWD_H /* Else search passwd file for client */ pw = getpwuid((int) getuid()); if (pw) { char princ_realm[256]; if ( (strlen(pw->pw_name) + strlen(realm) + 1) > 255 ) goto exit_k5_init; ckstrncpy(principal,pw->pw_name,256); ckstrncpy(princ_realm,pw->pw_name,256); ckstrncat(princ_realm,"@",256); ckstrncat(princ_realm,realm,256); if ((code = krb5_parse_name(kcontext,princ_realm,&me))) { krb5_errno = code; com_err("krb5_kinit",code,"when parsing name", princ_realm); goto exit_k5_init; } } else { printf( "Unable to identify user from password file\r\n"); goto exit_k5_init; } #else /* HAVE_PWD_H */ printf("Unable to identify user\r\n"); goto exit_k5_init; #endif /* HAVE_PWD_H */ } } #ifdef HEIMDAL len = me->name.name_string.len; name = *me->name.name_string.val; #else /* HEIMDAL */ len = krb5_princ_name(kcontext, me)->length; name = krb5_princ_name(kcontext, me)->data; #endif /* HEIMDAL */ if ( len < sizeof(principal) ) { memcpy(principal,name,len); /* safe */ principal[len]='\0'; } } /* Use specified name */ else { char princ_realm[256]; if ( (strlen(init->principal) + (init->instance ? strlen(init->instance)+1 : 0) + strlen(realm) + 2) > 255 ) goto exit_k5_init; ckstrncpy(principal,init->principal,256); ckstrncpy(princ_realm,init->principal,256); if (init->instance) { ckstrncat(princ_realm,"/",256); ckstrncat(princ_realm,init->instance,256); } if (realm[0]) { ckstrncat(princ_realm,"@",256); ckstrncat(princ_realm,realm,256); } if ((code = krb5_parse_name (kcontext, princ_realm, &me))) { com_err("krb5_kinit",code,"when parsing name",princ_realm); goto exit_k5_init; } } if ((code = krb5_unparse_name(kcontext, me, &client_name))) { com_err("krb5_kinit",code,"when unparsing name"); goto exit_k5_init; } debug(F110,"krb5_init client_name",client_name,0); memset((char *)&my_creds, 0, sizeof(my_creds)); my_creds.client = me; if (init->service == NULL) { if ((code = krb5_build_principal_ext(kcontext, &server, strlen(realm),realm, tgtname.length, tgtname.data, strlen(realm),realm, 0))) { com_err("krb5_kinit",code,"while building server name"); goto exit_k5_init; } } else { if (code = krb5_parse_name(kcontext, init->service, &server)) { com_err("krb5_kinit",code,"while parsing service name", init->service); goto exit_k5_init; } } my_creds.server = server; if (options & KDC_OPT_POSTDATED) { my_creds.times.starttime = starttime; my_creds.times.endtime = starttime + lifetime; } else { my_creds.times.starttime = 0; /* start timer when request gets to KDC */ my_creds.times.endtime = now + lifetime; } if (options & KDC_OPT_RENEWABLE) { my_creds.times.renew_till = now + rlife; } else my_creds.times.renew_till = 0; if (options & KDC_OPT_VALIDATE) { krb5_data outbuf; #ifdef KRB5_HAVE_GET_INIT_CREDS code = krb5_get_validated_creds(kcontext, &my_creds, me, ccache, init->service); if ( code == -1 ) #endif { #ifdef HEIMDAL printf("?validate not implemented\r\n"); code = -1; goto exit_k5_init; #else /* HEIMDAL */ code = krb5_validate_tgt(kcontext, ccache, server, &outbuf); #endif /* HEIMDAL */ } if (code) { com_err("krb5_kinit",code,"validating tgt"); goto exit_k5_init; } /* should be done... */ goto exit_k5_init; } if (options & KDC_OPT_RENEW) { krb5_data outbuf; #ifdef KRB5_HAVE_GET_INIT_CREDS code = krb5_get_renewed_creds(kcontext, &my_creds, me, ccache, init->service); if ( code == -1 ) #endif { #ifdef HEIMDAL printf("?renew not implemented\r\n"); code = -1; goto exit_k5_init; #else /* HEIMDAL */ code = krb5_renew_tgt(kcontext, ccache, server, &outbuf); #endif /* HEIMDAL */ } if (code) { com_err("krb5_kinit",code,"while renewing tgt"); goto exit_k5_init; } /* should be done... */ goto store_cred; } #ifndef HEIMDAL if ( init->addrs && !init->no_addresses ) { /* construct an array of krb5_address structs to pass to get_in_tkt */ /* include both the local ip addresses as well as any other that */ /* are specified. */ unsigned long ipaddr; for ( addr_count=0;addr_countaddrs[addr_count] == NULL ) break; if (addr_count > 0) { krb5_address ** local_addrs=NULL; krb5_os_localaddr(kcontext, &local_addrs); i = 0; while ( local_addrs[i] ) i++; addr_count += i; addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *)); if ( !addrs ) { krb5_free_addresses(kcontext, local_addrs); goto exit_k5_init; } memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1)); i = 0; while ( local_addrs[i] ) { addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); if (addrs[i] == NULL) { krb5_free_addresses(kcontext, local_addrs); goto exit_k5_init; } addrs[i]->magic = local_addrs[i]->magic; addrs[i]->addrtype = local_addrs[i]->addrtype; addrs[i]->length = local_addrs[i]->length; addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); if (!addrs[i]->contents) { krb5_free_addresses(kcontext, local_addrs); goto exit_k5_init; } memcpy(addrs[i]->contents,local_addrs[i]->contents, local_addrs[i]->length); /* safe */ i++; } krb5_free_addresses(kcontext, local_addrs); for ( j=0;imagic = KV5M_ADDRESS; addrs[i]->addrtype = AF_INET; addrs[i]->length = 4; addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); if (!addrs[i]->contents) goto exit_k5_init; ipaddr = inet_addr(init->addrs[j]); memcpy(addrs[i]->contents,&ipaddr,4); /* safe */ } #ifdef KRB5_HAVE_GET_INIT_CREDS krb5_get_init_creds_opt_set_address_list(&opts,addrs); #endif } } #endif /* !HEIMDAL */ #ifdef KRB5_HAVE_GET_INIT_CREDS if ( init->no_addresses ) krb5_get_init_creds_opt_set_address_list(&opts,NULL); #endif #ifndef NO_KEYTAB if (!use_keytab) #endif { if ( init->password ) { pwsize = strlen(init->password); if ( pwsize ) password = init->password; } else if (init->getk4 && k4_init) { /* When we are requesting that K4 tickets be automatically */ /* acquired when K5 tickets are acquired, we must get the */ /* password up front. */ char prmpt[256]; extern char * k5prprompt; extern char * k5pwprompt; int ok = 0; if ( k5pwprompt && k5pwprompt[0] && (strlen(k5pwprompt) + strlen(principal) + strlen(realm) - 4) < sizeof(prmpt)) { sprintf(prmpt,k5pwprompt,principal,realm); } else ckmakxmsg(prmpt,sizeof(prmpt), k5pwprompt && k5pwprompt[0] ? k5pwprompt : "Kerberos 5 Password for ", principal,"@",realm,": ", NULL,NULL,NULL,NULL,NULL,NULL,NULL ); ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,DEFAULT_UQ_TIMEOUT); if ( ok ) password = passwd; if ( k4_init->password == NULL ) makestr(&k4_init->password,passwd); } #ifdef KRB5_HAVE_GET_INIT_CREDS debug(F100,"krb5_init calling krb5_get_init_creds_password()","",0); #ifdef OS2 if ( is_NRL_KRB5() ) code = krb5_get_init_creds_password(kcontext, &my_creds, me, password, (void *)ck_NRL_krb5_prompter, NULL, starttime, init->service, &opts); else #endif /* OS2 */ code = krb5_get_init_creds_password(kcontext, &my_creds, me, password, ck_krb5_prompter, NULL, starttime, init->service, &opts); debug(F111,"krb5_init","krb5_get_init_creds_password()",code); if ( code == -1 ) { if (!password) { char prmpt[256]; int ok; ckmakmsg(prmpt,sizeof(prmpt),"Kerberos 5 Password for ", client_name,": ",NULL); ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL, DEFAULT_UQ_TIMEOUT); if ( ok ) password = passwd; else { code = -2; goto exit_k5_init; } } if ( !password ) password = ""; code = krb5_get_in_tkt_with_password(kcontext, options, #ifdef HEIMDAL NULL, #else /* HEIMDAL */ init->no_addresses ? NULL :addrs, #endif /* HEIMDAL */ NULL, NULL, password, NULL, &my_creds, NULL); if ( code ) debug(F111,"krb5_init","krb5_get_in_tkt_with_password()",code); } #else /* KRB5_HAVE_GET_INIT_CREDS */ if (!password) { char prmpt[256]; int ok; ckmakmsg(prmpt,sizeof(prmpt),"Kerberos 5 Password for ", client_name,": ",NULL); ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,DEFAULT_UQ_TIMEOUT); if ( ok ) password = passwd; else { code = -2; goto exit_k5_init; } } if ( !password ) password = ""; code = krb5_get_in_tkt_with_password(kcontext, options, #ifdef HEIMDAL NULL, #else /* HEIMDAL */ init->no_addresses ? NULL :addrs, #endif /* HEIMDAL */ NULL, NULL, password, NULL, &my_creds, NULL); if ( code ) debug(F111,"krb5_init","krb5_get_in_tkt_with_password()",code); #endif /* KRB5_HAVE_GET_INIT_CREDS */ if ( init->password && pwsize > 0 ) memset(init->password, 0, pwsize); memset(passwd,0,80); } #ifndef NO_KEYTAB else { #ifdef KRB5_HAVE_GET_INIT_CREDS code = krb5_get_init_creds_keytab(kcontext, &my_creds, me, keytab, starttime, init->service, &opts); #ifdef OS2 if ( code == -1) code = krb5_get_in_tkt_with_keytab(kcontext, options, init->no_addresses ? NULL :addrs, NULL, NULL, keytab, NULL, &my_creds, 0); #endif /* OS2 */ #else /* KRB5_HAVE_GET_INIT_CREDS */ code = krb5_get_in_tkt_with_keytab(kcontext, options, #ifdef HEIMDAL NULL, #else /* HEIMDAL */ init->no_addresses ? NULL :addrs, #endif /* HEIMDAL */ NULL, NULL, keytab, NULL, &my_creds, 0); #endif /* KRB5_HAVE_GET_INIT_CREDS */ } #endif if (code) { switch (code) { case KRB5KRB_AP_ERR_BAD_INTEGRITY: printf("Password incorrect\r\n"); goto exit_k5_init; case KRB5KRB_AP_ERR_V4_REPLY: if (init->getk4 && k4_init) { printf("Kerberos 5 Tickets not support by server. "); printf("A version 4 Ticket will be requested.\r\n"); } goto exit_k5_init; default: goto exit_k5_init; } } store_cred: debug(F100,"krb5_init calling krb5_cc_initialize()","",0); code = krb5_cc_initialize (kcontext, ccache, me); if ( code == KRB5_CC_BADNAME ) { /* This is a really ugly hack that should not have to be here. * krb5_cc_initialize should not fail with an error if the * cache already exists. The reason the problem is occuring * is that the krb5 library is no longer calling cc_destroy() * when cc_initialize() is called and the CCAPI implementation * on Windows has not yet been corrected to handle it. To * ensure that K95 will continue to work with both we will call * cc_destroy() if the cc_initialize() call fails with a BADNAME * error. If the cc_destroy() is successful, we will try again. */ debug(F100,"krb5_init calling krb5_cc_destroy()","",0); code = krb5_cc_destroy (kcontext, ccache); if ( !code ) { debug(F100,"krb5_init calling k5_get_ccache()","",0); code = k5_get_ccache(kcontext,&ccache,op->cache); debug(F100,"krb5_init calling krb5_cc_initialize()","",0); code = krb5_cc_initialize (kcontext, ccache, me); } else code = KRB5_CC_BADNAME; } if (code) { com_err("krb5_kinit",code,"when initializing cache",op->cache); goto exit_k5_init; } debug(F100,"krb5_init calling krb5_cc_store_cred()","",0); code = krb5_cc_store_cred(kcontext, ccache, &my_creds); if (code) { com_err("krb5_kinit",code,"while storing credentials"); goto exit_k5_init; } if ( init->getk4 && #ifdef KRB524_CONV !try_convert524(kcontext,me,ccache) && #endif /* KRB524_CONV */ k4_init ) { int k4rc = ck_krb4_initTGT(op,k4_init); if (k4rc < 0) code = -3; } exit_k5_init: debug(F100,"krb5_init exit_k5_init","",0); #ifndef HEIMDAL /* Free krb5_address structures if we created them */ if ( addrs ) { for ( i=0;icontents ) free(addrs[i]->contents); free(addrs[i]); } } } #endif /* HEIMDAL */ krb5_errno = code; makestr(&krb5_errmsg,krb5_errno ? error_message(krb5_errno) : "OK"); if (client_name) krb5_free_unparsed_name(kcontext, client_name); /* my_creds is pointing at server */ debug(F100,"krb5_init calling krb5_free_principal()","",0); krb5_free_principal(kcontext, server); debug(F100,"krb5_init calling krb5_cc_close()","",0); krb5_cc_close(kcontext,ccache); debug(F100,"krb5_init calling krb5_free_context()","",0); krb5_free_context(kcontext); if (code != -2) printf("Result from realm %s: %s\r\n",realm, code==-3?"Unable to retrieve Kerberos IV credentials": code?error_message(code):"OK"); return(code?-1:0); } #ifndef HEIMDAL #define VALIDATE 0 #define RENEW 1 /* stripped down version of krb5_mk_req */ static krb5_error_code #ifdef CK_ANSIC krb5_validate_tgt( krb5_context context, krb5_ccache ccache, krb5_principal server, /* tgtname */ krb5_data *outbuf ) #else krb5_validate_tgt(context, ccache, server, outbuf) krb5_context context; krb5_ccache ccache; krb5_principal server; /* tgtname */ krb5_data *outbuf; #endif { return krb5_tgt_gen(context, ccache, server, outbuf, VALIDATE); } /* stripped down version of krb5_mk_req */ static krb5_error_code #ifdef CK_ANSIC krb5_renew_tgt(krb5_context context, krb5_ccache ccache, krb5_principal server, /* tgtname */ krb5_data *outbuf) #else krb5_renew_tgt(context, ccache, server, outbuf) krb5_context context; krb5_ccache ccache; krb5_principal server; /* tgtname */ krb5_data *outbuf; #endif { return krb5_tgt_gen(context, ccache, server, outbuf, RENEW); } /* stripped down version of krb5_mk_req */ static krb5_error_code #ifdef CK_ANSIC krb5_tgt_gen(krb5_context context, krb5_ccache ccache, krb5_principal server, /* tgtname */ krb5_data *outbuf, int opt) #else krb5_tgt_gen(context, ccache, server, outbuf, opt) krb5_context context; krb5_ccache ccache; krb5_principal server; /* tgtname */ krb5_data *outbuf; int opt; #endif { krb5_error_code retval; krb5_creds * credsp; krb5_creds creds; /* obtain ticket & session key */ memset((char *)&creds, 0, sizeof(creds)); if ((retval = krb5_copy_principal(context, server, &creds.server))) goto cleanup; if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) goto cleanup_creds; if (opt == VALIDATE) { if ((retval = krb5_get_credentials_validate(context, 0, ccache, &creds, &credsp))) goto cleanup_creds; } else { if ((retval = krb5_get_credentials_renew(context, 0, ccache, &creds, &credsp))) goto cleanup_creds; } /* we don't actually need to do the mk_req, just get the creds. */ cleanup_creds: krb5_free_cred_contents(context, &creds); cleanup: return retval; } #endif /* HEIMDAL */ #endif /* KINIT */ #ifdef KDESTROY int #ifdef CK_ANSIC ck_krb5_destroy(struct krb_op_data * op) #else ck_krb5_destroy(op) struct krb_op_data * op; #endif { krb5_context kcontext; krb5_error_code retval; int c; krb5_ccache ccache = NULL; char *cache_name = NULL; int code; int errflg=0; int quiet = 0; if ( !ck_krb5_is_installed() ) return(-1); code = krb5_init_context(&kcontext); if (code) { debug(F101,"ck_krb5_destroy while initializing krb5","",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } code = k5_get_ccache(kcontext,&ccache,op->cache); if (code != 0) { debug(F101,"ck_krb5_destroy while getting ccache", "",code); krb5_free_context(kcontext); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } code = krb5_cc_destroy (kcontext, ccache); if (code != 0) { debug(F101,"ck_krb5_destroy while destroying cache","",code); if ( code == KRB5_FCC_NOFILE ) printf("No ticket cache to destroy.\r\n"); else printf("Ticket cache NOT destroyed!\r\n"); krb5_cc_close(kcontext,ccache); krb5_free_context(kcontext); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } printf("Tickets destroyed.\r\n"); /* Do not call krb5_cc_close() because cache has been destroyed */ krb5_free_context(kcontext); krb5_errno = 0; makestr(&krb5_errmsg,"OK"); return (0); } #else /* KDESTROY */ #ifdef KRB5 int #ifdef CK_ANSIC ck_krb5_destroy(struct krb_op_data * op) #else ck_krb5_destroy(op) struct krb_op_data * op; #endif { printf("?Not implemented.\r\n"); return(-1); } #endif /* KRB5 */ #endif /* KDESTROY */ #ifndef KLIST #ifdef KRB5 int #ifdef CK_ANSIC ck_krb5_list_creds(struct krb_op_data * op, struct krb5_list_cred_data * lc) #else ck_krb5_list_creds(op,lc) struct krb_op_data * op; struct krb5_list_cred_data * lc; #endif { printf("?Not implemented.\r\n"); return(-1); } #endif /* KRB5 */ #else /* KLIST */ static int show_flags = 0, show_time = 0, status_only = 0, show_keys = 0; static int show_etype = 0, show_addr = 0; static char *defname; static char *progname; static krb5_int32 now; static int timestamp_width; _PROTOTYP(static char * etype_string, (krb5_enctype )); _PROTOTYP(static void show_credential,(krb5_context,krb5_creds *)); _PROTOTYP(static int do_ccache, (krb5_context,char *)); _PROTOTYP(static int do_keytab, (krb5_context,char *)); _PROTOTYP(static void printtime, (time_t)); _PROTOTYP(static void fillit, (int, int)); #define DEFAULT 0 #define CCACHE 1 #define KEYTAB 2 int #ifdef CK_ANSIC ck_krb5_list_creds(struct krb_op_data * op, struct krb5_list_cred_data * lc) #else ck_krb5_list_creds(op,lc) struct krb_op_data * op; struct krb5_list_cred_data * lc; #endif { krb5_context kcontext; krb5_error_code retval; int code; char *name = op->cache; int mode; if ( !ck_krb5_is_installed() ) return(-1); code = krb5_init_context(&kcontext); if (code) { debug(F101,"ck_krb5_list_creds while initializing krb5","",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } name = op->cache; mode = DEFAULT; show_flags = 0; show_time = 0; status_only = 0; show_keys = 0; show_etype = 0; show_addr = 0; show_flags = lc->flags; show_etype = lc->encryption; show_addr = lc->addr; show_time = 1; show_keys = 1; mode = CCACHE; if ((code = krb5_timeofday(kcontext, &now))) { if (!status_only) debug(F101,"ck_krb5_list_creds while getting time of day.", "",code); krb5_free_context(kcontext); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } else { char tmp[BUFSIZ]; if (!krb5_timestamp_to_sfstring(now, tmp, 20, (char *) NULL) || !krb5_timestamp_to_sfstring(now, tmp, sizeof(tmp), (char *) NULL)) timestamp_width = (int) strlen(tmp); else timestamp_width = 15; } if (mode == DEFAULT || mode == CCACHE) retval = do_ccache(kcontext,name); else retval = do_keytab(kcontext,name); krb5_free_context(kcontext); return(retval); } static int #ifdef CK_ANSIC do_keytab(krb5_context kcontext, char * name) #else do_keytab(kcontext,name) krb5_context kcontext; char * name; #endif { krb5_keytab kt; krb5_keytab_entry entry; krb5_kt_cursor cursor; char buf[BUFSIZ]; /* hopefully large enough for any type */ char *pname; int code = 0; if (name == NULL) { if ((code = krb5_kt_default(kcontext, &kt))) { debug(F101,"ck_krb5_list_creds while getting default keytab", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } } else { if ((code = krb5_kt_resolve(kcontext, name, &kt))) { debug(F111,"ck_krb5_list_creds while resolving keytab", name,code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } } if ((code = krb5_kt_get_name(kcontext, kt, buf, BUFSIZ))) { debug(F101,"ck_krb5_list_creds while getting keytab name", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } printf("Keytab name: %s\r\n", buf); if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor))) { debug(F101,"ck_krb5_list_creds while starting keytab scan", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } if (show_time) { printf("KVNO Timestamp"); fillit(timestamp_width - sizeof("Timestamp") + 2, (int) ' '); printf("Principal\r\n"); printf("---- "); fillit(timestamp_width, (int) '-'); printf(" "); fillit(78 - timestamp_width - sizeof("KVNO"), (int) '-'); printf("\r\n"); } else { printf("KVNO Principal\r\n"); printf( "---- --------------------------------------------------------------------\ ------\r\n"); } while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0) { if ((code = krb5_unparse_name(kcontext, entry.principal, &pname))) { debug(F101,"ck_krb5_list_creds while unparsing principal name", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } printf("%4d ", entry.vno); if (show_time) { printtime(entry.timestamp); printf(" "); } printf("%s", pname); if (show_etype) printf(" (%s) " , #ifdef HEIMDAL etype_string(entry.key.keytype) #else /* HEIMDAL */ etype_string(entry.key.enctype) #endif /* HEIMDAL */ ); if (show_keys) { printf(" (0x"); { int i; for (i = 0; i < entry.key.length; i++) printf("%02x", #ifdef HEIMDAL entry.key.keyvalue[i] #else /* HEIMDAL */ entry.key.contents[i] #endif /* HEIMDAL */ ); } printf(")"); } printf("\r\n"); krb5_free_unparsed_name(kcontext,pname); } if (code && code != KRB5_KT_END) { debug(F101,"ck_krb5_list_creds while scanning keytab", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } if ((code = krb5_kt_end_seq_get(kcontext, kt, &cursor))) { debug(F101,"ck_krb5_list_creds while ending keytab scan", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } krb5_errno = 0; makestr(&krb5_errmsg,"OK"); return(0); } static int #ifdef CK_ANSIC do_ccache(krb5_context kcontext, char * cc_name) #else do_ccache(kcontext,name) krb5_context kcontext; char * cc_name; #endif { krb5_ccache cache = NULL; krb5_cc_cursor cur; krb5_creds creds; krb5_principal princ=NULL; krb5_flags flags=0; krb5_error_code code = 0; int exit_status = 0; if (status_only) /* exit_status is set back to 0 if a valid tgt is found */ exit_status = 1; code = k5_get_ccache(kcontext,&cache,cc_name); if (code != 0) { debug(F111,"do_ccache while getting ccache", error_message(code),code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); return(-1); } flags = 0; /* turns off OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { if (code == ENOENT) { debug(F111,"ck_krb5_list_creds (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } else { debug(F111, "ck_krb5_list_creds while setting cache flags (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } printf("No ticket File.\r\n"); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) { debug(F101,"ck_krb5_list_creds while retrieving principal name", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } if ((code = krb5_unparse_name(kcontext, princ, &defname))) { debug(F101,"ck_krb5_list_creds while unparsing principal name", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } if (!status_only) { printf("Ticket cache: %s:%s\r\nDefault principal: %s\r\n\r\n", krb5_cc_get_type(kcontext, cache), krb5_cc_get_name(kcontext, cache), defname); printf("Valid starting"); fillit(timestamp_width - sizeof("Valid starting") + 3, (int) ' '); printf("Expires"); fillit(timestamp_width - sizeof("Expires") + 3, (int) ' '); printf("Service principal\r\n"); } if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_list_creds while starting to retrieve tickets", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) { if (status_only) { if (exit_status && creds.server->length == 2 && strcmp(creds.server->realm.data, princ->realm.data) == 0 && strcmp((char *)creds.server->data[0].data, "krbtgt") == 0 && strcmp((char *)creds.server->data[1].data, princ->realm.data) == 0 && creds.times.endtime > now) exit_status = 0; } else { show_credential(kcontext, &creds); } krb5_free_cred_contents(kcontext, &creds); } printf("\r\n"); if (code == KRB5_CC_END || code == KRB5_CC_NOTFOUND) { if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_list_creds while finishing ticket retrieval", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { debug(F101,"ck_krb5_list_creds while closing ccache", "",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } krb5_errno = 0; makestr(&krb5_errmsg,"OK"); krb5_cc_close(kcontext,cache); return(0); } else { debug(F101,"ck_krb5_list_creds while retrieving a ticket","",code); krb5_errno = code; makestr(&krb5_errmsg,error_message(krb5_errno)); krb5_cc_close(kcontext,cache); return(-1); } krb5_errno = 0; makestr(&krb5_errmsg,"OK"); krb5_cc_close(kcontext,cache); return(0); } static char * #ifdef CK_ANSIC #ifdef HEIMDAL etype_string(krb5_keytype enctype) #else /* HEIMDAL */ etype_string(krb5_enctype enctype) #endif /* HEIMDAL */ #else #ifdef HEIMDAL etype_string(enctype) krb5_keytype enctype; #else /* HEIMDAL */ etype_string(enctype) krb5_enctype enctype; #endif /* HEIMDAL */ #endif { static char buf[12]; switch (enctype) { case ENCTYPE_NULL: return "NULL"; case ENCTYPE_DES_CBC_CRC: return "DES-CBC-CRC"; case ENCTYPE_DES_CBC_MD4: return "DES-CBC-MD4"; case ENCTYPE_DES_CBC_MD5: return "DES-CBC-MD5"; case ENCTYPE_DES_CBC_RAW: return "DES-CBC-RAW"; case ENCTYPE_DES3_CBC_SHA: return "DES3-CBC-SHA"; case ENCTYPE_DES3_CBC_RAW: return "DES3-CBC-RAW"; case ENCTYPE_DES_HMAC_SHA1: return "DES-HMAC-SHA1"; case ENCTYPE_DES3_CBC_SHA1: return "DES3-CBC-SHA1"; case ENCTYPE_AES128_CTS_HMAC_SHA1_96: return "AES128_CTS-HMAC-SHA1_96"; case ENCTYPE_AES256_CTS_HMAC_SHA1_96: return "AES256_CTS-HMAC-SHA1_96"; case ENCTYPE_ARCFOUR_HMAC: return "RC4-HMAC-NT"; case ENCTYPE_ARCFOUR_HMAC_EXP: return "RC4-HMAC-NT-EXP"; case ENCTYPE_UNKNOWN: return "UNKNOWN"; case ENCTYPE_LOCAL_DES3_HMAC_SHA1: return "LOCAL-DES3-HMAC-SHA1"; case ENCTYPE_LOCAL_RC4_MD4: return "LOCAL-RC4-MD4"; default: ckmakmsg(buf, sizeof(buf),"etype ", ckitoa(enctype),NULL,NULL); return buf; break; } } static char * #ifdef CK_ANSIC flags_string(register krb5_creds *cred) #else flags_string(cred) register krb5_creds *cred; #endif { static char buf[32]; int i = 0; if (cred->ticket_flags & TKT_FLG_FORWARDABLE) buf[i++] = 'F'; if (cred->ticket_flags & TKT_FLG_FORWARDED) buf[i++] = 'f'; if (cred->ticket_flags & TKT_FLG_PROXIABLE) buf[i++] = 'P'; if (cred->ticket_flags & TKT_FLG_PROXY) buf[i++] = 'p'; if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE) buf[i++] = 'D'; if (cred->ticket_flags & TKT_FLG_POSTDATED) buf[i++] = 'd'; if (cred->ticket_flags & TKT_FLG_INVALID) buf[i++] = 'i'; if (cred->ticket_flags & TKT_FLG_RENEWABLE) buf[i++] = 'R'; if (cred->ticket_flags & TKT_FLG_INITIAL) buf[i++] = 'I'; if (cred->ticket_flags & TKT_FLG_HW_AUTH) buf[i++] = 'H'; if (cred->ticket_flags & TKT_FLG_PRE_AUTH) buf[i++] = 'A'; buf[i] = '\0'; return(buf); } static char * #ifdef CK_ANSIC short_date(long *dp) #else short_date(dp) long *dp; #endif { register char *cp; #ifndef ctime extern char *ctime(); #endif /* ctime */ cp = ctime(dp) + 4; cp[15] = '\0'; return (cp); } static VOID #ifdef CK_ANSIC printtime(time_t tv) #else printtime(tv) time_t tv; #endif { char timestring[BUFSIZ]; char format[12]; char fill; fill = ' '; sprintf(format,"%%-%ds",timestamp_width); /* safe */ if (!krb5_timestamp_to_sfstring((krb5_timestamp) tv, timestring, timestamp_width+1, &fill)) { printf(format,timestring); } else { printf(format,short_date(&tv)); } } static void #ifdef CK_ANSIC one_addr(krb5_address *a) #else one_addr(a) krb5_address *a; #endif { struct hostent *h; extern tcp_rdns; if ((a->addrtype == ADDRTYPE_INET) && (a->length == 4)) { if (tcp_rdns != SET_OFF) { h = gethostbyaddr(a->contents, 4, AF_INET); if (h) { #ifdef HADDRLIST h = ck_copyhostent(h); #endif /* HADDRLIST */ printf("%s (%d.%d.%d.%d)", h->h_name, a->contents[0], a->contents[1], a->contents[2], a->contents[3]); } } if (tcp_rdns == SET_OFF || !h) { printf("%d.%d.%d.%d", a->contents[0], a->contents[1], a->contents[2], a->contents[3]); } } else { printf("unknown addr type %d", a->addrtype); } } static VOID #ifdef CK_ANSIC show_credential(krb5_context kcontext, register krb5_creds * cred) #else show_credential(kcontext, cred) krb5_context kcontext; register krb5_creds * cred; #endif { krb5_error_code retval=0; krb5_ticket *tkt=NULL; char *name=NULL, *sname=NULL, *flags=NULL; int extra_field = 0; retval = krb5_unparse_name(kcontext, cred->client, &name); if (retval) { debug(F101,"ck_krb5_list_creds while unparsing client name","",retval); krb5_errno = retval; makestr(&krb5_errmsg,error_message(krb5_errno)); return; } retval = krb5_unparse_name(kcontext, cred->server, &sname); if (retval) { debug(F101,"ck_krb5_list_creds while unparsing server name","",retval); free(name); krb5_errno = retval; makestr(&krb5_errmsg,error_message(krb5_errno)); return; } if (!cred->times.starttime) cred->times.starttime = cred->times.authtime; printtime(cred->times.starttime); printf(" "); if ( time(0) < cred->times.endtime ) printtime(cred->times.endtime); else printf("** expired ** "); printf(" %s\r\n", sname); if (strcmp(name, defname)) { printf(" for client %s", name); extra_field++; } if (cred->times.renew_till) { if (!extra_field) printf(" "); else printf(", "); printf("renew until "); printtime(cred->times.renew_till); extra_field += 2; } if (extra_field > 3) { printf("\r\n"); extra_field = 0; } if (show_flags) { flags = flags_string(cred); if (flags && *flags) { if (!extra_field) printf(" "); else printf(", "); printf("Flags: %s", flags); extra_field++; } } if (extra_field > 2) { printf("\r\n"); extra_field = 0; } if (show_etype) { retval = decode_krb5_ticket(&cred->ticket, &tkt); if (!extra_field) printf(" "); else printf(", "); #ifdef HEIMDAL printf("Etype (skey, tkt): %s, %s ", etype_string(cred->session.keytype), etype_string(tkt->enc_part.keytype)); #else /* HEIMDAL */ printf("Etype (skey, tkt): %s, %s ", etype_string(cred->keyblock.enctype), etype_string(tkt->enc_part.enctype)); #endif /* HEIMDAL */ krb5_free_ticket(kcontext, tkt); extra_field++; } /* if any additional info was printed, extra_field is non-zero */ if (extra_field) printf("\r\n"); if ( show_addr ) { if (!cred->addresses || !cred->addresses[0]) { printf("\tAddresses: (none)\r\n"); } else { int i; for (i=0; cred->addresses[i]; i++) { if (i) printf(" "); else printf(" Addresses: "); one_addr(cred->addresses[i]); printf("\r\n"); } } } krb5_free_unparsed_name(kcontext,name); krb5_free_unparsed_name(kcontext,sname); krb5_errno = 0; makestr(&krb5_errmsg,"OK"); } static VOID #ifdef CK_ANSIC fillit(int num, int c) #else fillit(num, c) int num; int c; #endif { int i; for (i=0; i= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'F') return c - 'A' + 10; if (c >= 'a' && c <= 'f') return c - 'a' + 10; return -1; } /* returns: NULL for ok, pointer to error string for bad input */ static char* #ifdef CK_ANSIC hex_scan_four_bytes(char *out, char *in) #else hex_scan_four_bytes(out, in) char *out; char *in; #endif { int i; int c; char c1; for (i=0; i<8; i++) { if(!in[i]) return "not enough input"; c = hex_scan_nybble(in[i]); if(c<0) return "invalid digit"; c1 = c; i++; if(!in[i]) return "not enough input"; c = hex_scan_nybble(in[i]); if(c<0) return "invalid digit"; *out++ = (c1 << 4) + c; } switch(in[i]) { case 0: case '\r': case '\n': return NULL; default: return "extra characters at end of input"; } } #endif /* COMMENT */ /* ck_krb4_initTGT() returns 0 on success */ int #ifdef CK_ANSIC ck_krb4_initTGT(struct krb_op_data * op, struct krb4_init_data * init) #else ck_krb4_initTGT(op,init) struct krb_op_data * op, struct krb4_init_data * init #endif { char aname[ANAME_SZ+1]; char inst[INST_SZ+1]; char realm[REALM_SZ+1]; char *password=NULL; char passwd[80]=""; char *username = NULL; char *usernameptr=NULL; int iflag, /* Instance */ rflag, /* Realm */ vflag, /* Verbose */ lflag, /* Lifetime */ pflag, /* Preauth */ lifetime=KRB_DEFAULT_LIFE, /* Life Time */ k_errno; register char *cp; register i; if ( !ck_krb4_is_installed() ) return(-1); *inst = *realm = '\0'; iflag = rflag = vflag = lflag = pflag = 0; vflag = init->verbose; pflag = init->preauth; if ( init->lifetime ) { lifetime = init->lifetime<5?1:init->lifetime/5; if ( lifetime > 255 ) lifetime = 255; } else lifetime = KRB_DEFAULT_LIFE; username = init->principal; if (username && username[0] && (k_errno = kname_parse(aname, inst, realm, username)) != AUTH_SUCCESS) { krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); printf("%s\r\n", krb_get_err_text_entry(k_errno)); iflag = rflag = 1; username = NULL; } if ( init->realm ) { ckstrncpy(realm,init->realm,REALM_SZ); } if ( init->instance ) { ckstrncpy(inst,init->instance, INST_SZ); } #ifdef COMMENT if ( vflag ) printf("Kerberos IV initialization\r\n"); #endif /* COMMENT */ if (!username || !username[0]) { debug(F100,"ck_krb4_initTGT no username specified","",0); printf("?Invalid principal specified.\r\n"); krb4_errno = -1; makestr(&krb4_errmsg,"No principal specified"); return(-1); } if (!*realm) { ckstrncpy(realm,ck_krb4_getrealm(),REALM_SZ); } if ( init->password ) password = init->password; else { char prmpt[80]; int ok; ckmakxmsg(prmpt,sizeof(prmpt), "Kerberos 4 Password for ",username,"@",realm,": ", NULL,NULL,NULL,NULL,NULL,NULL,NULL); ok = uq_txt(NULL,prmpt,2,NULL,passwd,80,NULL,DEFAULT_UQ_TIMEOUT); if ( ok ) password = passwd; } if (pflag) { k_errno = krb_get_pw_in_tkt_preauth( aname, inst, realm, "krbtgt", realm, lifetime, password); if (k_errno == -1) { /* preauth method not available */ k_errno = krb_get_pw_in_tkt(aname, inst, realm, "krbtgt", realm, lifetime, password); } } else { k_errno = krb_get_pw_in_tkt(aname, inst, realm, "krbtgt", realm, lifetime, password); } memset(passwd,0,sizeof(passwd)); if (k_errno) { printf("%s for principal %s%s%s@%s\r\n", krb_get_err_text_entry(k_errno), aname, inst[0]?".":"", inst, realm); krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(-1); } else if (vflag) { printf("Result from realm %s: ", realm); printf("%s\r\n", krb_get_err_text_entry(k_errno)); } krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(0); } #endif /* KINIT */ #ifdef KDESTROY int #ifdef CK_ANSIC ck_krb4_destroy(struct krb_op_data * op) #else ck_krb4_destroy(op) struct krb_op_data * op; #endif { int k_errno=0; if ( !ck_krb4_is_installed() ) return(-1); k_errno = dest_tkt(); krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); if (k_errno == 0) printf("Tickets destroyed.\r\n"); else if (k_errno == RET_TKFIL) printf("No tickets to destroy.\r\n"); else { printf("Tickets MAY NOT be destroyed.\r\n"); return(-1); } return(0); } #endif /* KDESTROY */ #ifdef KLIST _PROTOTYP(static int display_tktfile,(char *, int, int, int)); int #ifdef CK_ANSIC ck_krb4_list_creds(struct krb_op_data * op) #else ck_krb4_list_creds(op) struct krb_op_data * op; #endif { int long_form = 1; int tgt_test = 0; int do_srvtab = 0; int show_kvnos = 0; char *tkt_file = NULL; if ( !ck_krb4_is_installed() ) return(-1); if ( op->cache ) tkt_file = op->cache; if ( k4debug ) { show_kvnos = 1; } if (do_srvtab) return(display_srvtab(tkt_file)); else return(display_tktfile(tkt_file, tgt_test, long_form, show_kvnos)); } #ifndef KRB5 static int timestamp_width=0; static char * #ifdef CK_ANSIC short_date(long *dp) #else short_date(dp) long *dp; #endif { register char *cp; extern char *ctime(); cp = ctime(dp) + 4; cp[15] = '\0'; return (cp); } static VOID #ifdef CK_ANSIC printtime(time_t tv) #else printtime(tv) time_t tv; #endif { char timestring[BUFSIZ]; char format[12]; char fill; fill = ' '; sprintf(format,"%%-%ds",timestamp_width); /* safe */ printf(format,short_date(&tv)); } #endif /* KRB5 */ static int #ifdef CK_ANSIC display_tktfile(char *file, int tgt_test, int long_form, int show_kvnos) #else display_tktfile(file,tgt_test,long_form,show_kvnos) char *file; int tgt_test; int long_form; int show_kvnos; #endif { char pname[ANAME_SZ]; char pinst[INST_SZ]; char prealm[REALM_SZ]; char buf1[20], buf2[20]; int k_errno; #ifdef OS2 LEASH_CREDENTIALS creds; #else /* OS2 */ CREDENTIALS creds; #endif /* OS2 */ int header = 1; file = tkt_string(); if (long_form) { printf("Ticket cache: %s\r\n", file); } /* * Since krb_get_tf_realm will return a ticket_file error, * we will call tf_init and tf_close first to filter out * things like no ticket file. Otherwise, the error that * the user would see would be * klist: can't find realm of ticket file: No ticket file (tf_util) * instead of * klist: No ticket file (tf_util) */ /* Open ticket file */ if (k_errno = tf_init(file, R_TKT_FIL)) { if (!tgt_test) printf("%s\r\n", krb_get_err_text_entry (k_errno)); krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(-1); } /* Close ticket file */ (void) tf_close(); /* * We must find the realm of the ticket file here before calling * tf_init because since the realm of the ticket file is not * really stored in the principal section of the file, the * routine we use must itself call tf_init and tf_close. */ if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) { if (!tgt_test) printf("can't find realm of ticket file: %s\r\n", krb_get_err_text_entry (k_errno)); krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(-1); } /* Open ticket file */ if (k_errno = tf_init(file, R_TKT_FIL)) { if (!tgt_test) printf("%s\r\n", krb_get_err_text_entry (k_errno)); krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(-1); } /* Get principal name and instance */ if ((k_errno = tf_get_pname(pname)) || (k_errno = tf_get_pinst(pinst))) { (void) tf_close(); if (!tgt_test) printf("%s\r\n", krb_get_err_text_entry (k_errno)); krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(-1); } /* * You may think that this is the obvious place to get the * realm of the ticket file, but it can't be done here as the * routine to do this must open the ticket file. This is why * it was done before tf_init. */ if (!tgt_test && long_form) printf("Default principal: %s%s%s%s%s\r\n\r\n", pname, (pinst[0] ? "." : ""), pinst, (prealm[0] ? "@" : ""), prealm); while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) { if (!tgt_test && long_form && header) { printf("%-17s %-17s %s\r\n", "Valid starting", "Expires", "Service principal"); header = 0; } if (tgt_test) { creds.issue_date += ((unsigned char) creds.lifetime) * 5 * 60; if (!strcmp(creds.service, "krbtgt") && !strcmp(creds.instance, prealm)) { krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); (void) tf_close(); if (time(0) < creds.issue_date) { return(0); /* tgt hasn't expired */ } else { return(-1); /* has expired */ } } continue; /* not a tgt */ } if (long_form) { timestamp_width = 17; /* for k5 display function */ /* if available */ printtime(creds.issue_date); printf(" "); creds.issue_date += ((unsigned char) creds.lifetime) * 5 * 60; if ( time(0) < creds.issue_date ) printtime(creds.issue_date); else printf("*** expired *** "); printf(" "); } if (show_kvnos) printf("%s%s%s%s%s (%d)\r\n", creds.service, (creds.instance[0] ? "." : ""), creds.instance, (creds.realm[0] ? "@" : ""), creds.realm, creds.kvno); else printf("%s%s%s%s%s\r\n", creds.service, (creds.instance[0] ? "." : ""), creds.instance, (creds.realm[0] ? "@" : ""), creds.realm); #ifdef OS2 if ( creds.address[0] ) printf(" Address: %s\r\n",creds.address); #endif /* OS2 */ } (void) tf_close(); if (tgt_test) { return(-1); }/* no tgt found */ if (header && long_form && k_errno == EOF) { printf("No tickets in file.\r\n"); } krb4_errno = k_errno; makestr(&krb4_errmsg,krb_get_err_text_entry(k_errno)); return(0); } #ifdef COMMENT /* Just so we remember what the command line interface looked like */ usage() { printf( "Usage: [ -s | -t ] [ -file filename ] [ -srvtab ] [ -version ]\r\n"); return(-1); } #endif /* COMMENT */ /* adapted from getst() in librkb */ /* * ok_getst() takes a file descriptor, a string and a count. It reads * from the file until either it has read "count" characters, or until * it reads a null byte. When finished, what has been read exists in * the given string "s". If "count" characters were actually read, the * last is changed to a null, so the returned string is always null- * terminated. ok_getst() returns the number of characters read, including * the null terminator. * * If there is a read error, it returns -1 (like the read(2) system call) */ static int #ifdef CK_ANSIC ok_getst(int fd, register char *s, int n) #else ok_getst(fd, s, n) int fd; register char *s; int n; #endif { register int count = n; int err; while ((err = read(fd, s, 1)) > 0 && --count) if (*s++ == '\0') return (n - count); if (err < 0) return(-1); *s = '\0'; return (n - count); } int #ifdef CK_ANSIC display_srvtab(char *file) #else display_srvtab(file) char *file; #endif { int stab; char serv[SNAME_SZ]; char inst[INST_SZ]; char rlm[REALM_SZ]; unsigned char key[8]; unsigned char vno; int count; printf("Server key file: %s\r\n", file); #ifdef NT #ifndef O_RDONLY #define O_RDONLY _O_RDONLY #endif /* O_RDONLY */ #endif /* NT */ if ((stab = open(file, O_RDONLY, 0400)) < 0) { perror(file); return(-1); } printf("%-15s %-15s %-10s %s\r\n","Service","Instance","Realm", "Key Version"); printf("------------------------------------------------------\r\n"); /* argh. getst doesn't return error codes, it silently fails */ while (((count = ok_getst(stab, serv, SNAME_SZ)) > 0) && ((count = ok_getst(stab, inst, INST_SZ)) > 0) && ((count = ok_getst(stab, rlm, REALM_SZ)) > 0)) { if (((count = read(stab,(char *) &vno,1)) != 1) || ((count = read(stab,(char *) key,8)) != 8)) { if (count < 0) perror("reading from key file"); else printf("key file truncated\r\n"); return(-1); } printf("%-15s %-15s %-15s %d\r\n",serv,inst,rlm,vno); } if (count < 0) perror(file); (void) close(stab); return(0); } #endif /* KLIST */ #else /* KRB4 */ int ck_krb4_autoget_TGT(char * dummy) { return(-1); } #ifdef CK_KERBEROS int #ifdef CK_ANSIC ck_krb4_initTGT(struct krb_op_data * op, struct krb4_init_data * init) #else ck_krb4_initTGT(op,init) struct krb_op_data * op, struct krb4_init_data * init #endif { return(-1); } int #ifdef CK_ANSIC ck_krb4_destroy(struct krb_op_data * op) #else ck_krb4_destroy(op) struct krb_op_data * op; #endif { return(-1); } int #ifdef CK_ANSIC ck_krb4_list_creds(struct krb_op_data * op) #else ck_krb4_list_creds(op) struct krb_op_data * op; #endif { return(-1); } #else /* CK_KERBEROS */ int ck_krb4_initTGT(void * a, void *b) { return(-1); } int ck_krb4_destroy(void *a) { return(-1); } int ck_krb4_list_creds(void *a) { return(-1); } #endif /* CK_KERBEROS */ #endif /* KRB4 */ /* The following functions are used to implement the Kermit Script Language */ /* functions */ struct tkt_list_item { char * name; struct tkt_list_item * next; }; #ifdef KRB4 static struct tkt_list_item * k4_tkt_list = NULL; #endif int #ifdef CK_ANSIC ck_krb4_get_tkts(VOID) #else ck_krb4_get_tkts() #endif { #ifdef KRB4 char *file=NULL; char pname[ANAME_SZ]; char pinst[INST_SZ]; char prealm[REALM_SZ]; char buf1[20], buf2[20]; int k_errno; #ifdef OS2 LEASH_CREDENTIALS creds; #else /* OS2 */ CREDENTIALS creds; #endif /* OS2 */ int tkt_count=0; struct tkt_list_item ** list = &k4_tkt_list; while ( k4_tkt_list ) { struct tkt_list_item * next; next = k4_tkt_list->next; free(k4_tkt_list->name); free(k4_tkt_list); k4_tkt_list = next; } if ( !ck_krb4_is_installed() ) return(-1); file = tkt_string(); /* * Since krb_get_tf_realm will return a ticket_file error, * we will call tf_init and tf_close first to filter out * things like no ticket file. Otherwise, the error that * the user would see would be * klist: can't find realm of ticket file: No ticket file (tf_util) * instead of * klist: No ticket file (tf_util) */ /* Open ticket file */ if (k_errno = tf_init(file, R_TKT_FIL)) { return(-1); } /* Close ticket file */ (void) tf_close(); /* * We must find the realm of the ticket file here before calling * tf_init because since the realm of the ticket file is not * really stored in the principal section of the file, the * routine we use must itself call tf_init and tf_close. */ if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) { return(-1); } /* Open ticket file */ if (k_errno = tf_init(file, R_TKT_FIL)) { return(-1); } /* Get principal name and instance */ if ((k_errno = tf_get_pname(pname)) || (k_errno = tf_get_pinst(pinst))) { return(-1); } /* * You may think that this is the obvious place to get the * realm of the ticket file, but it can't be done here as the * routine to do this must open the ticket file. This is why * it was done before tf_init. */ while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) { char tkt_buf[256]; ckmakxmsg(tkt_buf,sizeof(tkt_buf), creds.service, (creds.instance[0] ? "." : ""), creds.instance, (creds.realm[0] ? "@" : ""), creds.realm, NULL,NULL,NULL,NULL,NULL,NULL,NULL); *list = (struct tkt_list_item *) malloc(sizeof(struct tkt_list_item)); (*list)->name = strdup(tkt_buf); (*list)->next = NULL; list = &((*list)->next); tkt_count++; } tf_close(); return(tkt_count); #else /* KRB4 */ return(0); #endif /* KRB4 */ } char * #ifdef CK_ANSIC ck_krb4_get_next_tkt(VOID) #else ck_krb4_get_next_tkt() #endif { #ifdef KRB4 static char * s=NULL; struct tkt_list_item * next=NULL; if ( s ) { free(s); s = NULL; } if ( k4_tkt_list == NULL ) return(NULL); next = k4_tkt_list->next; s = k4_tkt_list->name; free(k4_tkt_list); k4_tkt_list = next; return(s); #else /* KRB4 */ return(NULL); #endif /* KRB4 */ } int #ifdef CK_ANSIC ck_krb4_tkt_isvalid(char * tktname) #else ck_krb4_tkt_isvalid(tktname) char * tktname; #endif { #ifdef KRB4 char *file=NULL; char pname[ANAME_SZ]; char pinst[INST_SZ]; char prealm[REALM_SZ]; char buf1[20], buf2[20]; int k_errno; time_t issue_t, expire_t, now_t; #ifdef OS2 LEASH_CREDENTIALS creds; #else /* OS2 */ CREDENTIALS creds; #endif /* OS2 */ if ( !ck_krb4_is_installed() ) return(-1); debug(F110,"ck_krb4_tkt_isvalid","tkt_string",0); file = tkt_string(); /* * Since krb_get_tf_realm will return a ticket_file error, * we will call tf_init and tf_close first to filter out * things like no ticket file. Otherwise, the error that * the user would see would be * klist: can't find realm of ticket file: No ticket file (tf_util) * instead of * klist: No ticket file (tf_util) */ /* Open ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_init",0); if (k_errno = tf_init(file, R_TKT_FIL)) { return(-1); } /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); /* * We must find the realm of the ticket file here before calling * tf_init because since the realm of the ticket file is not * really stored in the principal section of the file, the * routine we use must itself call tf_init and tf_close. */ debug(F110,"ck_krb4_tkt_isvalid","krb_get_tf_realm",0); if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) { return(-1); } /* Open ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_init",0); if (k_errno = tf_init(file, R_TKT_FIL)) { return(-1); } /* Get principal name and instance */ debug(F110,"ck_krb4_tkt_isvalid","tf_get_name/tf_get_pinst",0); if ((k_errno = tf_get_pname(pname)) || (k_errno = tf_get_pinst(pinst))) { /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(-1); } /* * You may think that this is the obvious place to get the * realm of the ticket file, but it can't be done here as the * routine to do this must open the ticket file. This is why * it was done before tf_init. */ debug(F110,"ck_krb4_tkt_isvalid","tf_get_cred",0); while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) { char tkt_buf[256]; ckmakxmsg(tkt_buf,sizeof(tkt_buf), creds.service, (creds.instance[0] ? "." : ""), creds.instance, (creds.realm[0] ? "@" : ""), creds.realm, NULL,NULL,NULL,NULL,NULL,NULL,NULL); if ( !strcmp(tktname,tkt_buf) ) { /* we found the ticket we are looking for */ issue_t = creds.issue_date; expire_t = creds.issue_date + ((unsigned char) creds.lifetime) * 5 * 60; now_t = time(0); /* We add a 5 minutes fudge factor to compensate for potential */ /* clock skew errors between the KDC and K95's host OS */ if ( now_t >= (issue_t-300) && now_t < expire_t) { #ifdef OS2 #ifdef CHECKADDRS if ( krb4_checkaddrs ) { extern char myipaddr[20]; /* From ckcnet.c */ if ( !myipaddr[0] ) { int i; char buf[60]; for ( i=0;i<64;i++ ) { if ( getlocalipaddrs(buf,60,i) < 0 ) break; if ( !strcmp(buf,creds.address) ) { /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(1); /* They're the same */ } } /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(0); /* They're different */ } else if ( strcmp(myipaddr,creds.address) ) { /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(0); /* They're different */ } else { /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(1); /* They're the same */ } } else { /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(1); /* They're the same */ } #else /* CHECKADDRS */ /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(1); /* valid but no ip address check */ #endif /* CHECKADDRS */ #else /* OS2 */ /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(1); /* Valid but no ip address check */ #endif /* OS2 */ } else { /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(0); /* expired or otherwise invalid */ } } } /* Close ticket file */ debug(F110,"ck_krb4_tkt_isvalid","tf_close",0); (void) tf_close(); return(0); /* could not find the desired ticket */ #else /* KRB4 */ return(-1); #endif /* KRB4 */ } int #ifdef CK_ANSIC ck_krb4_is_tgt_valid(VOID) #else ck_krb4_is_tgt_valid() #endif { #ifdef KRB4 char tgt[256]; char * s; int rc = 0; s = krb4_d_realm ? krb4_d_realm : ck_krb4_getrealm(); ckmakmsg(tgt,sizeof(tgt),"krbtgt.",s,"@",s); rc = ck_krb4_tkt_isvalid(tgt); debug(F111,"ck_krb4_is_tgt_valid",tgt,rc); return(rc > 0); #else /* KRB4 */ return(0); #endif /* KRB4 */ } int #ifdef CK_ANSIC ck_krb4_tkt_time(char * tktname) #else ck_krb4_tkt_time(tktname) char * tktname; #endif { #ifdef KRB4 char *file=NULL; char pname[ANAME_SZ]; char pinst[INST_SZ]; char prealm[REALM_SZ]; char buf1[20], buf2[20]; int k_errno; #ifdef OS2 LEASH_CREDENTIALS creds; #else /* OS2 */ CREDENTIALS creds; #endif /* OS2 */ if ( !ck_krb4_is_installed() ) return(-1); file = tkt_string(); /* * Since krb_get_tf_realm will return a ticket_file error, * we will call tf_init and tf_close first to filter out * things like no ticket file. Otherwise, the error that * the user would see would be * klist: can't find realm of ticket file: No ticket file (tf_util) * instead of * klist: No ticket file (tf_util) */ /* Open ticket file */ if (k_errno = tf_init(file, R_TKT_FIL)) { return(-1); } /* Close ticket file */ (void) tf_close(); /* * We must find the realm of the ticket file here before calling * tf_init because since the realm of the ticket file is not * really stored in the principal section of the file, the * routine we use must itself call tf_init and tf_close. */ if ((k_errno = krb_get_tf_realm(file, prealm)) != AUTH_SUCCESS) { return(-1); } /* Open ticket file */ if (k_errno = tf_init(file, R_TKT_FIL)) { return(-1); } /* Get principal name and instance */ if ((k_errno = tf_get_pname(pname)) || (k_errno = tf_get_pinst(pinst))) { tf_close(); return(-1); } /* * You may think that this is the obvious place to get the * realm of the ticket file, but it can't be done here as the * routine to do this must open the ticket file. This is why * it was done before tf_init. */ while ((k_errno = tf_get_cred(&creds)) == AUTH_SUCCESS) { char tkt_buf[256]; ckmakxmsg(tkt_buf,sizeof(tkt_buf), creds.service, (creds.instance[0] ? "." : ""), creds.instance, (creds.realm[0] ? "@" : ""), creds.realm, NULL,NULL,NULL,NULL,NULL,NULL,NULL); if ( !strcmp(tktname,tkt_buf) ) { /* we found the ticket we are looking for */ int n = (creds.issue_date + (((unsigned char) creds.lifetime) * 5 * 60)) - time(0); tf_close(); return(n <= 0 ? 0 : n); } } tf_close(); return(0); /* could not find the desired ticket */ #else /* KRB4 */ return(-1); #endif /* KRB4 */ } char * #ifdef CK_ANSIC ck_krb4_getrealm(void) #else ck_krb4_getrealm() #endif { #ifdef KRB4 char *file=NULL; int k_errno; static char realm[256]=""; realm[0]='\0'; if ( !ck_krb4_is_installed() ) return(realm); /* Try to get realm from ticket file */ /* If failure get the local realm */ /* * Since krb_get_tf_realm will return a ticket_file error, * we will call tf_init and tf_close first to filter out * things like no ticket file. */ /* Open ticket file */ file = tkt_string(); if (file == NULL || !file[0]) return(realm); if ((k_errno = tf_init(file, R_TKT_FIL)) == KSUCCESS) { /* Close ticket file */ (void) tf_close(); k_errno = krb_get_tf_realm(file, realm); } if (k_errno != KSUCCESS) { k_errno = krb_get_lrealm(realm, 1); } return(realm); #else /* KRB4 */ return(""); #endif /* KRB4 */ } char * #ifdef CK_ANSIC ck_krb4_getprincipal(void) #else ck_krb4_getprincipal() #endif { #ifdef KRB4 char *file=NULL; int k_errno; static char principal[256]=""; char instance[256]=""; char realm[256]=""; principal[0]='\0'; if ( !ck_krb4_is_installed() ) return(principal); /* Try to get realm from ticket file */ /* If failure get the local realm */ /* * Since krb_get_tf_realm will return a ticket_file error, * we will call tf_init and tf_close first to filter out * things like no ticket file. */ /* Open ticket file */ file = tkt_string(); if (file == NULL || !file[0]) return(principal); if ((k_errno = tf_init(file, R_TKT_FIL)) == KSUCCESS) { /* Close ticket file */ (void) tf_close(); k_errno = krb_get_tf_fullname(file, principal, instance, realm); } return(principal); #else /* KRB4 */ return(""); #endif /* KRB4 */ } #ifdef KRB5 static struct tkt_list_item * k5_tkt_list = NULL; #endif int #ifdef CK_ANSIC ck_krb5_get_tkts(char * cc_name) #else ck_krb5_get_tkts(cc_name) char * cc_name; #endif { #ifdef KRB5 #ifndef HEIMDAL krb5_context kcontext; krb5_error_code retval; krb5_ccache cache = NULL; krb5_cc_cursor cur; krb5_creds creds; krb5_principal princ=NULL; krb5_flags flags=0; krb5_error_code code=0; int exit_status = 0; int tkt_count=0; struct tkt_list_item ** list = &k5_tkt_list; while ( k5_tkt_list ) { struct tkt_list_item * next; next = k5_tkt_list->next; free(k5_tkt_list->name); free(k5_tkt_list); k5_tkt_list = next; } if ( !ck_krb5_is_installed() ) return(-1); retval = krb5_init_context(&kcontext); if (retval) { debug(F101,"ck_krb5_get_tkts while initializing krb5","",retval); return(-1); } code = k5_get_ccache(kcontext,&cache,cc_name); if (code != 0) { debug(F111,"ck_krb5_get_tkts while getting ccache", error_message(code),code); tkt_count = -1; goto exit_k5_get_tkt; } flags = 0; /* turns off OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { if (code == ENOENT) { debug(F111,"ck_krb5_get_tkts (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } else { debug(F111, "ck_krb5_get_tkts while setting cache flags (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } tkt_count = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) { debug(F101,"ck_krb5_get_tkts while retrieving principal name", "",code); tkt_count = -1; goto exit_k5_get_tkt; } if ((code = krb5_unparse_name(kcontext, princ, &defname))) { debug(F101,"ck_krb5_get_tkts while unparsing principal name", "",code); tkt_count = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_get_tkts while starting to retrieve tickets", "",code); tkt_count = -1; goto exit_k5_get_tkt; } while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) { char *sname=NULL; retval = krb5_unparse_name(kcontext, creds.server, &sname); if (retval) { debug(F101, "ck_krb5_get_tkts while unparsing server name","",retval); tkt_count = -1; goto exit_k5_get_tkt; } *list = (struct tkt_list_item *) malloc(sizeof(struct tkt_list_item)); (*list)->name = sname; (*list)->next = NULL; list = &((*list)->next); krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); tkt_count++; } if (code == KRB5_CC_END) { if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_get_tkts while finishing ticket retrieval", "",code); tkt_count = -1; goto exit_k5_get_tkt; } flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { debug(F101,"ck_krb5_get_tkts while closing ccache", "",code); tkt_count = -1; goto exit_k5_get_tkt; } } else { debug(F101,"ck_krb5_get_tkts while retrieving a ticket","",code); tkt_count = -1; goto exit_k5_get_tkt; } exit_k5_get_tkt: krb5_free_principal(kcontext,princ); krb5_free_unparsed_name(kcontext,defname); krb5_cc_close(kcontext,cache); krb5_free_context(kcontext); return(tkt_count); #else /* HEIMDAL */ return(-1); #endif /* HEIMDAL */ #else /* KRB5 */ return(0); #endif /* KRB5 */ } char * #ifdef CK_ANSIC ck_krb5_get_next_tkt(VOID) #else ck_krb5_get_next_tkt() #endif { #ifdef KRB5 #ifndef HEIMDAL static char * s=NULL; struct tkt_list_item * next=NULL; if ( s ) { free(s); s = NULL; } if ( k5_tkt_list == NULL ) return(NULL); next = k5_tkt_list->next; s = k5_tkt_list->name; free(k5_tkt_list); k5_tkt_list = next; return(s); #else /* HEIMDAL */ return("Not implemented"); #endif /* HEIMDAL */ #else /* KRB5 */ return(NULL); #endif /* KRB5 */ } char * #ifdef CK_ANSIC ck_krb5_tkt_flags(char * cc_name, char * tktname) #else ck_krb5_tkt_flags(cc_name,tktname) char * cc_name; char * tktname; #endif { #ifdef KRB5 #ifndef HEIMDAL krb5_context kcontext; krb5_error_code retval; krb5_ccache cache = NULL; krb5_cc_cursor cur; krb5_creds creds; krb5_principal princ=NULL; krb5_flags flags=0; krb5_error_code code=0; char * flag_str = ""; if ( !ck_krb5_is_installed() ) return(""); retval = krb5_init_context(&kcontext); if (retval) { debug(F101,"ck_krb5_tkt_flags while initializing krb5","",retval); return(""); } code = k5_get_ccache(kcontext,&cache,cc_name); if (code != 0) { debug(F111,"ck_krb5_tkt_isvalid while getting ccache", error_message(code),code); goto exit_k5_get_tkt; } flags = 0; /* turns off OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { if (code == ENOENT) { debug(F111,"ck_krb5_tkt_flags (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } else { debug(F111, "ck_krb5_tkt_flags while setting cache flags (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) { debug(F101,"ck_krb5_tkt_flags while retrieving principal name", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_unparse_name(kcontext, princ, &defname))) { debug(F101,"ck_krb5_tkt_flags while unparsing principal name", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_tkt_flags while starting to retrieve tickets", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_timeofday(kcontext, &now))) { if (!status_only) debug(F101,"ck_krb5_tkt_flags while getting time of day.", "",code); retval = -1; goto exit_k5_get_tkt; } while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) { char *sname=NULL; retval = krb5_unparse_name(kcontext, creds.server, &sname); if (retval) { debug(F101, "ck_krb5_tkt_flags while unparsing server name","",retval); retval = -1; krb5_free_cred_contents(kcontext, &creds); goto exit_k5_get_tkt; } if ( !strcmp(sname,tktname) ) { /* we found the ticket we are looking for */ flag_str = flags_string(&creds); krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); code = KRB5_CC_END; break; } krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); } if (code == KRB5_CC_END) { if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_tkt_flags while finishing ticket retrieval", "",code); goto exit_k5_get_tkt; } flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { debug(F101,"ck_krb5_tkt_flags while closing ccache", "",code); goto exit_k5_get_tkt; } } else { debug(F101,"ck_krb5_tkt_flags while retrieving a ticket","",code); goto exit_k5_get_tkt; } exit_k5_get_tkt: krb5_free_principal(kcontext,princ); krb5_free_unparsed_name(kcontext,defname); krb5_cc_close(kcontext,cache); krb5_free_context(kcontext); return(flag_str); #else /* HEIMDAL */ return("Not implemented"); #endif /* HEIMDAL */ #else /* KRB5 */ return(""); #endif /* KRB5 */ } int #ifdef CK_ANSIC ck_krb5_tkt_isvalid(char * cc_name, char * tktname) #else ck_krb5_tkt_isvalid(cc_name,tktname) char * cc_name; char * tktname; #endif { #ifdef KRB5 #ifndef HEIMDAL krb5_context kcontext=NULL; krb5_error_code retval; krb5_ccache cache = NULL; krb5_cc_cursor cur; krb5_creds creds; krb5_principal princ=NULL; krb5_flags flags=0; krb5_error_code code=0; #ifdef CHECKADDRS krb5_address ** myAddrs=NULL; krb5_address ** p=NULL; BOOL Addrfound = FALSE; #endif /*CHECKADDRS*/ if ( !ck_krb5_is_installed() ) return(-1); retval = krb5_init_context(&kcontext); if (retval) { debug(F101,"ck_krb5_tkt_isvalid while initializing krb5","",retval); return(-1); } code = k5_get_ccache(kcontext,&cache,cc_name); if (code != 0) { debug(F111,"ck_krb5_tkt_isvalid while getting ccache", error_message(code),code); goto exit_k5_get_tkt; } flags = 0; /* turns off OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { if (code == ENOENT) { debug(F111,"ck_krb5_tkt_isvalid (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } else { debug(F111, "ck_krb5_tkt_isvalid while setting cache flags (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) { debug(F101,"ck_krb5_tkt_isvalid while retrieving principal name", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_unparse_name(kcontext, princ, &defname))) { debug(F101,"ck_krb5_tkt_isvalid while unparsing principal name", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_tkt_isvalid while starting to retrieve tickets", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_timeofday(kcontext, &now))) { if (!status_only) debug(F101,"ck_krb5_tkt_isvalid while getting time of day.", "",code); retval = -1; goto exit_k5_get_tkt; } while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) { char *sname=NULL; retval = krb5_unparse_name(kcontext, creds.server, &sname); if (retval) { debug(F101, "ck_krb5_tkt_isvalid while unparsing server name","",retval); retval = -1; krb5_free_cred_contents(kcontext, &creds); goto exit_k5_get_tkt; } if ( !strcmp(sname,tktname) ) { /* we found the ticket we are looking for */ /* We add a 5 minutes fudge factor to compensate for potential */ /* clock skew errors between the KDC and K95's host OS */ retval = ((creds.times.starttime > 0) && now >= (creds.times.starttime - 300) && now < (creds.times.endtime + 300) && !(creds.ticket_flags & TKT_FLG_INVALID)); #ifdef CHECKADDRS if ( retval && krb5_checkaddrs && creds.addresses && creds.addresses[0] ) { /* if we think it is valid, then lets check the IP Addresses */ /* to make sure it is valid for our current connection. */ /* Also make sure it's for the correct IP address */ retval = krb5_os_localaddr(kcontext, &myAddrs); if (retval) { com_err(NULL, retval, "retrieving my IP address"); krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); code = KRB5_CC_END; retval = -1; break; } /* See if any of our addresses match any in cached credentials */ for (Addrfound=FALSE, p=myAddrs; (Addrfound==FALSE) && (*p); p++ ) { if (krb5_address_search(kcontext, *p, creds.addresses)) { Addrfound = TRUE; } } krb5_free_addresses(k5_context, myAddrs); if (Addrfound) { krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); code = KRB5_CC_END; retval = 1; break; } else { krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); code = KRB5_CC_END; retval = 0; break; } } #endif /* CHECKADDRS */ krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); code = KRB5_CC_END; break; } krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); } if (code == KRB5_CC_END) { if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_tkt_isvalid while finishing ticket retrieval", "",code); retval = -1; goto exit_k5_get_tkt; } flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { debug(F101,"ck_krb5_tkt_isvalid while closing ccache", "",code); retval = -1; goto exit_k5_get_tkt; } } else { debug(F101,"ck_krb5_tkt_isvalid while retrieving a ticket","",code); retval = -1; goto exit_k5_get_tkt; } exit_k5_get_tkt: krb5_free_principal(kcontext,princ); krb5_free_unparsed_name(kcontext,defname); krb5_cc_close(kcontext,cache); krb5_free_context(kcontext); return(retval); #else /* HEIMDAL */ return(-1); #endif /* HEIMDAL */ #else /* KRB5 */ return(-1); #endif /* KRB5 */ } int #ifdef CK_ANSIC ck_krb5_is_tgt_valid(VOID) #else ck_krb5_is_tgt_valid() #endif { #ifdef KRB5 #ifndef HEIMDAL char tgt[256]; char * s; int rc = 0; s = ck_krb5_getrealm(krb5_d_cc); ckmakmsg(tgt,sizeof(tgt),"krbtgt/",s,"@",s); rc = ck_krb5_tkt_isvalid(krb5_d_cc,tgt); debug(F111,"ck_krb5_is_tgt_valid",tgt,rc); return(rc>0); #else /* HEIMDAL */ return(-1); #endif /* HEIMDAL */ #else /* KRB5 */ return(0); #endif /* KRB5 */ } int #ifdef CK_ANSIC ck_krb5_tkt_time(char * cc_name, char * tktname) #else ck_krb5_tkt_time(cc_name, tktname) char * cc_name; char * tktname; #endif { #ifdef KRB5 #ifndef HEIMDAL krb5_context kcontext; krb5_error_code retval; krb5_ccache cache = NULL; krb5_cc_cursor cur; krb5_creds creds; krb5_principal princ=NULL; krb5_flags flags=0; krb5_error_code code=0; if ( !ck_krb5_is_installed() ) return(-1); retval = krb5_init_context(&kcontext); if (retval) { debug(F101,"ck_krb5_list_creds while initializing krb5","",retval); return(-1); } code = k5_get_ccache(kcontext,&cache,cc_name); if (code != 0) { debug(F111,"ck_krb5_tkt_time while getting ccache", error_message(code),code); retval = -1; goto exit_k5_get_tkt; } flags = 0; /* turns off OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { if (code == ENOENT) { debug(F111,"ck_krb5_list_creds (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } else { debug(F111, "ck_krb5_list_creds while setting cache flags (ticket cache)", krb5_cc_get_name(kcontext, cache),code); } retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) { debug(F101,"ck_krb5_list_creds while retrieving principal name", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_unparse_name(kcontext, princ, &defname))) { debug(F101,"ck_krb5_list_creds while unparsing principal name", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_list_creds while starting to retrieve tickets", "",code); retval = -1; goto exit_k5_get_tkt; } if ((code = krb5_timeofday(kcontext, &now))) { if (!status_only) debug(F101,"ck_krb5_list_creds while getting time of day.", "",code); krb5_free_context(kcontext); return(-1); } while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) { char *sname=NULL; retval = krb5_unparse_name(kcontext, creds.server, &sname); if (retval) { debug(F101, "ck_krb5_list_creds while unparsing server name","",retval); retval = -1; krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); goto exit_k5_get_tkt; } if ( !strcmp(sname,tktname) ) { /* we found the ticket we are looking for */ int valid = (creds.times.starttime && now > creds.times.starttime && now < creds.times.endtime && !(creds.ticket_flags & TKT_FLG_INVALID)); if ( valid ) { retval = creds.times.endtime - now; } else retval = 0; krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); code = KRB5_CC_END; break; } krb5_free_unparsed_name(kcontext,sname); krb5_free_cred_contents(kcontext, &creds); } if (code == KRB5_CC_END) { if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) { debug(F101,"ck_krb5_list_creds while finishing ticket retrieval", "",code); retval = -1; goto exit_k5_get_tkt; } flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */ if ((code = krb5_cc_set_flags(kcontext, cache, flags))) { debug(F101,"ck_krb5_list_creds while closing ccache", "",code); retval = -1; goto exit_k5_get_tkt; } } else { debug(F101,"ck_krb5_list_creds while retrieving a ticket","",code); retval = -1; goto exit_k5_get_tkt; } exit_k5_get_tkt: krb5_free_principal(kcontext,princ); krb5_free_unparsed_name(kcontext,defname); krb5_cc_close(kcontext,cache); krb5_free_context(kcontext); return(retval); #else /* HEIMDAL */ return(-1); #endif /* HEIMDAL */ #else /* KRB5 */ return(-1); #endif /* KRB5 */ } char * #ifdef CK_ANSIC ck_krb5_get_cc_name(void) #else ck_krb5_get_cc_name() #endif { #ifdef KRB5 #ifndef HEIMDAL static char cc_name[CKMAXPATH+1]=""; krb5_context kcontext = NULL; krb5_ccache ccache = NULL; krb5_error_code code; char * p=NULL; cc_name[0] = '\0'; if ( !ck_krb5_is_installed() ) return(cc_name); p = getenv("KRB5CCNAME"); if ( !p ) { code = krb5_init_context(&kcontext); if (code) { com_err("ck_krb5_get_cc_name",code,"while init_context"); return(cc_name); } if ((code = krb5_cc_default(kcontext, &ccache))) { com_err("ck_krb5_get_cc_name",code,"while getting default ccache"); goto exit_k5_get_cc; } ckmakmsg(cc_name,sizeof(cc_name), (char *)krb5_cc_get_type(kcontext,ccache),":", (char *)krb5_cc_get_name(kcontext,ccache),NULL); } else { ckstrncpy(cc_name,p,CKMAXPATH); } if ( !strncmp("FILE:",cc_name,5) ) { for ( p=cc_name; *p ; p++ ) if ( *p == '\\' ) *p = '/'; } exit_k5_get_cc: if ( ccache ) krb5_cc_close(kcontext,ccache); if ( kcontext ) krb5_free_context(kcontext); return(cc_name); #else /* HEIMDAL */ return("Not implemented"); #endif /* HEIMDAL */ #else /* KRB5 */ return(""); #endif /* KRB5 */ } char * #ifdef CK_ANSIC ck_krb5_getrealm(char * cc_name) #else ck_krb5_getrealm(cc_name) char * cc_name; #endif { #ifdef KRB5 #ifndef HEIMDAL static char realm[256]=""; krb5_context kcontext; krb5_ccache ccache = NULL; krb5_error_code code; krb5_principal me=NULL; realm[0] = '\0'; if ( !ck_krb5_is_installed() ) return(realm); code = krb5_init_context(&kcontext); if (code) { return(realm); } code = k5_get_ccache(kcontext,&ccache,cc_name); if (code != 0) { goto exit_k5_getrealm; } code = krb5_cc_get_principal(kcontext, ccache, &me); if (code) code = krb5_parse_name(kcontext, "foo", &me); if (code) { goto exit_k5_getrealm; } if ( krb5_princ_realm(kcontext, me)->length < sizeof(realm) ) { memcpy(realm,krb5_princ_realm(kcontext, me)->data, krb5_princ_realm(kcontext, me)->length); /* safe */ realm[krb5_princ_realm(kcontext, me)->length]='\0'; } exit_k5_getrealm: if ( me ) krb5_free_principal(kcontext,me); if ( ccache ) krb5_cc_close(kcontext,ccache); if (kcontext) krb5_free_context(kcontext); return(realm); #else /* HEIMDAL */ return("Not implemented"); #endif /* HEIMDAL */ #else /* KRB5 */ return(""); #endif /* KRB5 */ } char * #ifdef CK_ANSIC ck_krb5_getprincipal(char * cc_name) #else ck_krb5_getprincipal(cc_name) char * cc_name; #endif { #ifdef KRB5 #ifndef HEIMDAL static char principal[UIDBUFLEN+1]=""; krb5_context kcontext; krb5_ccache ccache = NULL; krb5_error_code code; krb5_principal me; char * p=NULL; int i; principal[0] = '\0'; if ( !ck_krb5_is_installed() ) return(principal); code = krb5_init_context(&kcontext); if (code) { return(principal); } code = k5_get_ccache(kcontext,&ccache,cc_name); if (code != 0) { goto exit_k5_getprincipal; } if ((code = krb5_cc_get_principal(kcontext, ccache, &me))) { goto exit_k5_getprincipal; } if ((code = krb5_unparse_name (kcontext, me, &p))) { krb5_free_principal(kcontext,me); goto exit_k5_getprincipal; } ckstrncpy(principal,p,UIDBUFLEN); i = ckindex("@",principal,0,0,0); if (i) principal[i-1] = '\0'; krb5_free_unparsed_name(kcontext,p); exit_k5_getprincipal: if ( ccache ) krb5_cc_close(kcontext,ccache); if (kcontext) krb5_free_context(kcontext); return(principal); #else /* HEIMDAL */ return("Not implemented"); #endif /* HEIMDAL */ #else /* KRB5 */ return(""); #endif /* KRB5 */ } #ifndef CRYPT_DLL int ck_get_crypt_table(struct keytab ** pTable, int * pN) { #ifdef CK_ENCRYPTION return(get_crypt_table(pTable, pN)); #else /* ENCRYPTION */ int i=0; #ifndef OS2 char * tmpstring = NULL; #endif /* OS2 */ if ( *pTable ) { for ( i=0 ; i < *pN ; i++ ) free( (*pTable)[i].kwd ) ; free ( *pTable ) ; } *pTable = NULL; *pN = 0; *pTable = malloc( sizeof(struct keytab) * 2 ) ; if ( !(*pTable) ) return(0); #ifdef OS2 (*pTable)[0].kwd =strdup("automatic"); #else /* OS2 */ makestr(&tmpstring,"automatic"); (*pTable)[0].kwd = tmpstring; tmpstring = NULL; #endif /* OS2 */ (*pTable)[0].kwval = ENCTYPE_ANY; (*pTable)[0].flgs = 0; #ifdef OS2 (*pTable)[1].kwd =strdup("none"); #else /* OS2 */ makestr(&tmpstring,"none"); (*pTable)[1].kwd = tmpstring; tmpstring = NULL; #endif /* OS2 */ (*pTable)[1].kwval = 999; (*pTable)[1].flgs = 0; (*pN) = 2; return(2); #endif /* ENCRYPTION */ } VOID ck_encrypt_send_support() { #ifdef CK_ENCRYPTION encrypt_send_support(); #endif /* ENCRYPTION */ } #endif /* CRYPT_DLL */ /* * * Kstream * * Emulates the kstream package in Kerberos 4 * */ int kstream_destroy() { if (g_kstream != NULL) { auth_destroy(); /* Destroy authorizing */ free(g_kstream); g_kstream=NULL; } return 0; } VOID #ifdef CK_ANSIC kstream_set_buffer_mode(int mode) #else kstream_set_buffer_mode(mode) int mode; #endif { } int #ifdef CK_ANSIC kstream_create_from_fd(int fd, kstream_ptr data) #else kstream_create_from_fd(fd,data) int fd; kstream_ptr data; #endif { int n; g_kstream = malloc(sizeof(struct kstream_int)); if (g_kstream == NULL) return 0; g_kstream->fd = fd; n = auth_init(g_kstream); /* Initialize authorizing */ if (n) { free(g_kstream); g_kstream = NULL; return 0; } g_kstream->encrypt = NULL; g_kstream->decrypt = NULL; g_kstream->encrypt_type = ENCTYPE_ANY; g_kstream->decrypt_type = ENCTYPE_ANY; return 1; } #ifdef CK_KERBEROS #ifdef RLOGCODE static int do_lencheck, use_ivecs; extern int rlog_inband; #ifdef KRB5 void rcmd_stream_init_krb5(in_keyblock, encrypt_flag, lencheck, am_client, protonum) krb5_keyblock *in_keyblock; int encrypt_flag; int lencheck; int am_client; enum krb5_kcmd_proto protonum; { krb5_error_code status; size_t blocksize; if (!encrypt_flag) return; desinbuf.data = des_inbuf; desoutbuf.data = des_outpkt+4; /* Set up des buffers */ k5_session_key = in_keyblock; do_lencheck = lencheck; if ( protonum == KCMD_OLD_PROTOCOL ) { use_ivecs = 0; return; } use_ivecs = 1; if (status = krb5_c_block_size(k5_context, #ifdef HEIMDAL k5_session_key->keytype, #else k5_session_key->enctype, #endif &blocksize)) { /* XXX what do I do? */ printf("fatal kerberos 5 crypto library error\n"); ttclos(0); return; } encivec_i[0].length = encivec_i[1].length = encivec_o[0].length = encivec_o[1].length = blocksize; if ((encivec_i[0].data = malloc(encivec_i[0].length * 4)) == NULL) { /* XXX what do I do? */ printf("fatal malloc failed\n"); ttclos(0); return; } encivec_i[1].data = encivec_i[0].data + encivec_i[0].length; encivec_o[0].data = encivec_i[1].data + encivec_i[1].length; encivec_o[1].data = encivec_o[0].data + encivec_o[0].length; /* is there a better way to initialize this? */ memset(encivec_i[0].data, am_client, blocksize); memset(encivec_o[0].data, 1 - am_client, blocksize); memset(encivec_i[1].data, 2 | am_client, blocksize); memset(encivec_o[1].data, 2 | (1 - am_client), blocksize); } #endif /* KRB5 */ int #ifdef CK_ANSIC ck_krb_rlogin(CHAR * hostname, int port, CHAR * localuser, CHAR * remoteuser, CHAR * term_speed, struct sockaddr_in * l_addr, struct sockaddr_in * r_addr, int kversion, int encrypt_flag) #else /* CK_ANSIC */ ck_krb_rlogin(hostname, port, localuser, remoteuser, term_speed, l_addr, r_addr, encrypt_flag) CHAR * hostname; int port; CHAR * localuser; CHAR * remoteuser; CHAR * term_speed; struct sockaddr_in * l_addr; struct sockaddr_in * r_addr; int kversion; int encrypt_flag; #endif /* CK_ANSIC */ { unsigned long status; char * realm=NULL; extern int ttyfd; int c; long msglen; debug(F111,"ck_krb_rlogin",hostname,port); if ( kversion == 4 && !ck_krb4_is_installed() ) { printf("?Kerberos 4 is not installed\r\n"); return(-1); } else if ( kversion == 5 && !ck_krb5_is_installed() ) { printf("?Kerberos 5 is not installed\r\n"); return(-1); } if ( encrypt_flag && !ck_crypt_is_installed() ) { printf("?Encryption is not installed\r\n"); return(-1); } if ( kversion == 5 ) { #ifdef KRB5 krb5_flags authopts=0; krb5_ccache ccache=NULL; char *cksumbuf=NULL; char *service=NULL; char * kcmd_version=NULL; enum krb5_kcmd_proto use_proto; krb5_data cksumdat; krb5_creds *get_cred = 0; krb5_error_code status; krb5_error *error = 0; krb5_ap_rep_enc_part *rep_ret = NULL; krb5_data outbuf; int rc; int server_seqno=0; char ** realmlist=NULL; int buflen; char tgt[256]; debug(F100,"ck_krb_rlogin version 5","",0); realm = ck_krb5_realmofhost((char *)hostname); if (!realm) { ckstrncpy(strTmp, "Can't find realm for host \"",AUTHTMPBL); ckstrncat(strTmp, (char *)hostname,AUTHTMPBL); ckstrncat(strTmp, "\"",AUTHTMPBL); printf("?Kerberos 5 error: %s\r\n",strTmp); krb5_errno = KRB5_ERR_HOST_REALM_UNKNOWN; makestr(&krb5_errmsg,strTmp); return(0); } ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm); debug(F110,"ck_rlog_rlogin TGT",tgt,0); if ( krb5_autoget && !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) || (ck_krb5_is_tgt_valid() > 0)) ) ck_krb5_autoget_TGT(realm); buflen = strlen((char *)term_speed) + strlen((char *)remoteuser) + 64; if ((cksumbuf = malloc(buflen)) == 0) { printf("Unable to allocate memory for checksum buffer.\r\n"); return(-1); } ckmakmsg(cksumbuf,buflen,ckuitoa((unsigned short) ntohs(port)),":", (char *)term_speed,(char *)remoteuser); cksumdat.data = cksumbuf; cksumdat.length = strlen(cksumbuf); status = krb5_init_context(&k5_context); if (status) { debug(F110,"ck_krb_rlogin()","unable to init_context",0); return(-1); } desinbuf.data = des_inbuf; desoutbuf.data = des_outpkt+4; /* Set up des buffers */ rc = k5_get_ccache(k5_context,&ccache,NULL); if (rc != 0) { com_err(NULL, rc, "while getting ccache."); return(0); } service = krb5_d_srv ? krb5_d_srv : KRB5_SERVICE_NAME; if (!(get_cred = (krb5_creds *)calloc(1, sizeof(krb5_creds)))) { printf("ck_krb_rlogin: no memory\r\n"); return(-1); } memset(get_cred,0,sizeof(krb5_creds)); status = krb5_sname_to_principal(k5_context, (char *) hostname, service, KRB5_NT_SRV_HST, &get_cred->server); if (status) { printf("ck_krb_rlogin: krb5_sname_to_principal failed: %s\r\n", error_message(status)); return(-1); } ttoc(0); if (status = krb5_cc_get_principal(k5_context, ccache, &get_cred->client) ) { (void) krb5_cc_close(k5_context, ccache); krb5_free_creds(k5_context, get_cred); goto bad; } if (krb5_rlog_ver == KCMD_OLD_PROTOCOL) #ifdef HEIMDAL get_cred->session.keytype=ETYPE_DES_CBC_CRC; #else get_cred->keyblock.enctype=ENCTYPE_DES_CBC_CRC; #endif /* Get ticket from credentials cache or kdc */ status = krb5_get_credentials(k5_context, 0, ccache, get_cred, &ret_cred ); krb5_free_creds(k5_context, get_cred); get_cred = NULL; (void) krb5_cc_close(k5_context, ccache); if (status) goto bad; /* Reset internal flags; these should not be set. */ authopts &= (~OPTS_FORWARD_CREDS); authopts &= (~OPTS_FORWARDABLE_CREDS); if (krb5_auth_con_init(k5_context, &auth_context)) goto bad; if (krb5_auth_con_setflags(k5_context, auth_context, KRB5_AUTH_CONTEXT_RET_TIME)) goto bad; /* Only need local address for mk_cred() to send to krlogind */ if (!krb5_d_no_addresses) if (status = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR )) goto bad; /* Here is where we start to handle the new protocol in earnest */ if ( krb5_rlog_ver == KCMD_PROTOCOL_COMPAT_HACK ) { krb5_boolean is_des; if (status = krb5_c_enctype_compare( k5_context, #ifdef HEIMDAL ETYPE_DES_CBC_CRC, ret_cred->session.keytype, #else /* HEIMDAL */ ENCTYPE_DES_CBC_CRC, ret_cred->keyblock.enctype, #endif /* HEIMDAL */ &is_des)) { krb5_free_creds(k5_context, ret_cred); ret_cred = NULL; goto bad; } if ( is_des ) { kcmd_version = "KCMDV0.1"; use_proto = KCMD_OLD_PROTOCOL; } else { authopts = AP_OPTS_USE_SUBKEY; kcmd_version = "KCMDV0.2"; use_proto = KCMD_NEW_PROTOCOL; } } else { use_proto = krb5_rlog_ver; switch ( krb5_rlog_ver ) { case KCMD_NEW_PROTOCOL: authopts = AP_OPTS_USE_SUBKEY; kcmd_version = "KCMDV0.2"; break; case KCMD_OLD_PROTOCOL: kcmd_version = "KCMDV0.1"; break; default: goto bad; } } /* call Kerberos library routine to obtain an authenticator, pass it over the socket to the server, and obtain mutual authentication. */ status = krb5_sendauth(k5_context, &auth_context, (krb5_pointer) &ttyfd, kcmd_version, ret_cred->client, ret_cred->server, authopts, &cksumdat, ret_cred, 0, &error, &rep_ret, NULL ); #ifdef HEIMDAL krb5_data_free(&cksumdat); #else krb5_free_data_contents(k5_context,&cksumdat); #endif if (status) { if ( !quiet ) printf("Couldn't authenticate to server: %s\r\n", error_message(status)); if (error) { if ( !quiet ) { #ifdef HEIMDAL int xerror = error->error_code; char *xtext = *error->e_text; #else int xerror = error->error; char *xtext = error->text.length ? error->text.data : NULL; #endif printf("Server returned error code %d (%s)\r\n", xerror, error_message(ERROR_TABLE_BASE_krb5 + xerror)); if (xtext) { printf("Error text sent from server: %s\r\n", xtext); } } krb5_free_error(k5_context, error); error = 0; } goto bad; } if (rep_ret) { #ifdef HEIMDAL server_seqno = *rep_ret->seq_number; #else server_seqno = rep_ret->seq_number; #endif krb5_free_ap_rep_enc_part(k5_context, rep_ret); } (void) ttol(remoteuser, strlen((char *)remoteuser)+1); (void) ttol(term_speed, strlen((char *)term_speed)+1); (void) ttol(localuser, strlen((char *)localuser)+1); if (forward_flag) { /* Forward credentials (global) */ if (status = krb5_fwd_tgt_creds( k5_context, auth_context, (char *)hostname, ret_cred->client, ret_cred->server, 0, (forwardable_flag ? OPTS_FORWARDABLE_CREDS : 0), &outbuf ) ) { printf("Error forwarding credentials: %s\r\n", error_message(status)); goto bad2; } /* Send forwarded credentials */ status = krb5_write_message(k5_context, (krb5_pointer)&ttyfd, &outbuf ); } else { /* Dummy write to signal no forwarding */ bad2: outbuf.length = 0; status = krb5_write_message(k5_context, (krb5_pointer)&ttyfd, &outbuf); } if ((c = ttinc(0)) < 0) { if (c==-1) { perror((char *)hostname); } else { printf("ck_krb_rlogin: bad connection with remote host\r\n"); } status = -1; goto bad; } if (c != 0) { while ((c = ttinc(1)) >= 0) { (void) printf("%c",c); if (c == '\n') break; } status = -1; goto bad; } if ( status == 0 ) { /* success */ krb5_keyblock * key = 0; if ( use_proto == KCMD_NEW_PROTOCOL ) { int on = 1; rlog_inband = 1; setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof on); status = krb5_auth_con_getlocalsubkey( k5_context, auth_context, &key); if ((status || !key) && encrypt_flag ) goto bad2; } if ( key == 0 ) { #ifdef HEIMDAL key = &ret_cred->session; #else /* HEIMDAL */ key = &ret_cred->keyblock; #endif /* HEIMDAL */ } rcmd_stream_init_krb5(key, encrypt_flag, 1, 1, use_proto); if ( encrypt_flag ) rlog_encrypt = 1; } return (0); /* success */ bad: if ( status && !quiet ) { printf("Kerberos authentication error: %s\r\n", error_message(status)); } if (ret_cred) { krb5_free_creds(k5_context, ret_cred); ret_cred = NULL; } return (status); #else /* KRB5 */ return(-1); #endif /* KRB5 */ } else if (kversion == 4) { #ifdef KRB4 char tgt[4*REALM_SZ+1]; debug(F100,"ck_krb_rlogin version 4","",0); realm = (char *)krb_realmofhost(hostname); if (!realm) { strcpy(strTmp, "Can't find realm for host \""); ckstrncat(strTmp, hostname,AUTHTMPBL); ckstrncat(strTmp, "\"",AUTHTMPBL); printf("?Kerberos 4 error: %s\r\n",strTmp); krb4_errno = 0; makestr(&krb4_errmsg,strTmp); return(0); } ckmakmsg(tgt,sizeof(tgt),"krbtgt.",realm,"@",realm); status = ck_krb4_tkt_isvalid(tgt); if ( status <= 0 && krb4_autoget ) ck_krb4_autoget_TGT(realm); ttoc(0); /* write a NUL */ status = krb_sendauth(encrypt_flag?KOPT_DO_MUTUAL:0, ttyfd, &k4_auth, krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME, hostname, realm, (unsigned long) getpid(), &k4_msg_data, &cred, #ifdef CK_ENCRYPTION &k4_sched, #else /* ENCRYPTION */ NULL, #endif /* ENCRYPTION */ l_addr, r_addr, "KCMDV0.1"); debug(F111,"ck_krb_rlogin","krb_sendauth",status); if (status != KSUCCESS) { printf( "krb_sendauth failed: %s\r\n", krb_get_err_text_entry(status) ); return(-1); } ttol(remoteuser,strlen(remoteuser)+1); ttol(term_speed,strlen(term_speed)+1); reread: if ((c = ttinc(0)) < 0) { printf("rcmd: bad connection with remote host\r\n"); return(-1); } debug(F111,"ck_krb_rlogin","first byte",c); if (c != 0) { char *check = "ld.so: warning:"; /* If rlogind was compiled on SunOS4, and it somehow got the shared library version numbers wrong, it may give an ld.so warning about an old version of a shared library. Just ignore any such warning. Note that the warning is a characteristic of the server; we may not ourselves be running under SunOS4. */ if (c == 'l') { char *p; char cc; p = &check[1]; while ((c = ttinc(0)) >= 0) { if (*p == '\0') { if (c == '\n') break; } else { if (c != *p) break; ++p; } } if (*p == '\0') goto reread; } printf(check); while ((c = ttinc(1)) >= 0) { printf("%c",c); if (c == '\n') break; } debug(F110,"ck_krb_rlogin","fatal error 1",0); return(-1); } #ifdef CK_ENCRYPTION if ( encrypt_flag ) { /* if we are encrypting we need to setup the encryption */ /* routines. */ des_key_sched(cred.session, k4_sched); rlog_encrypt = 1; } #endif /* ENCRYPTION */ #else /* KRB4 */ return(-1); #endif /* KRB4 */ } return(0); /* success */ } #define SRAND srand #define RAND rand #define RAND_TYPE int static long random_confounder(size, fillin) size_t size; char * fillin; { static int seeded = 0; register unsigned char *real_fill; RAND_TYPE rval; if (!seeded) { /* time() defined in 4.12.2.4, but returns a time_t, which is an "arithmetic type" (4.12.1) */ rval = (RAND_TYPE) time(0); SRAND(rval); rval = RAND(); rval ^= getpid(); SRAND(rval); seeded = 1; } real_fill = (unsigned char *)fillin; while (size > 0) { rval = RAND(); *real_fill = rval & 0xff; real_fill++; size--; if (size) { *real_fill = (rval >> 8) & 0xff; real_fill++; size--; } } return 0; } #ifdef KRB5 int krb5_des_avail(fd) int fd; { return(nstored); } int krb5_des_read(fd, buf, len, secondary) int fd; register char *buf; int len; int secondary; { int nreturned = 0; long net_len,rd_len; int cc; krb5_error_code status; unsigned char c; krb5_data plain; krb5_enc_data cipher; debug(F111,"krb5_des_read","len",len); debug(F111,"krb5_des_read","rlog_encrypt",rlog_encrypt); if ( !rlog_encrypt ) { cc = net_read(fd, buf, len); debug(F111,"krb5_des_read","chars read",cc); if ( cc < 0 ) netclos(); return(cc); } if (nstored >= len) { if ( buf ) { memcpy(buf, store_ptr, len); /* safe */ store_ptr += len; nstored -= len; return(len); } else return(0); } else if (nstored) { if ( buf ) { memcpy(buf, store_ptr, nstored); /* safe */ nreturned += nstored; buf += nstored; len -= nstored; nstored = 0; } else return(0); } /* See the comment in v4_des_read. */ while (1) { cc = net_read(fd, &c, 1); /* we should check for non-blocking here, but we'd have to make it save partial reads as well. */ if (cc <= 0) { return cc; /* read error */ } if (cc == 1) { if (c == 0 || !do_lencheck) break; } } rd_len = c; if ((cc = net_read(fd, &c, 1)) != 1) return 0; rd_len = (rd_len << 8) | c; if ((cc = net_read(fd, &c, 1)) != 1) return 0; rd_len = (rd_len << 8) | c; if ((cc = net_read(fd, &c, 1)) != 1) return 0; rd_len = (rd_len << 8) | c; if (status = krb5_c_encrypt_length(k5_context, #ifdef HEIMDAL k5_session_key->keytype, #else k5_session_key->enctype, #endif use_ivecs ? rd_len + 4 : rd_len, (size_t *)&net_len)) { errno = status; return(-1); } if ((net_len <= 0) || (net_len > sizeof(des_inbuf))) { /* preposterous length; assume out-of-sync; only recourse is to close connection, so return 0 */ printf("Read size problem.\r\n"); return(0); } if ((cc = net_read(fd, desinbuf.data, net_len)) != net_len ) { /* pipe must have closed, return 0 */ printf( "Read error: length received %d != expected %d.\r\n", cc, net_len ); return(cc); } /* decrypt info */ cipher.enctype = ENCTYPE_UNKNOWN; cipher.ciphertext.length = net_len; cipher.ciphertext.data = desinbuf.data; plain.length = sizeof(storage); plain.data = storage; if ( status = krb5_c_decrypt(k5_context, #ifdef HEIMDAL *k5_session_key, #else k5_session_key, #endif KCMD_KEYUSAGE, use_ivecs ? encivec_i + secondary : 0, &cipher,&plain) ) { /* probably out of sync */ printf("Cannot decrypt data from network: %s\r\n", error_message(status)); errno = EIO; return(-1); } store_ptr = storage; nstored = rd_len; if ( use_ivecs ) { int rd_len2; rd_len2 = storage[0] & 0xff; rd_len2 <<= 8; rd_len2 |= storage[1] & 0xff; rd_len2 <<= 8; rd_len2 |= storage[2] & 0xff; rd_len2 <<= 8; rd_len2 |= storage[3] & 0xff; if (rd_len2 != rd_len) { /* cleartext length trashed? */ errno = EIO; return -1; } store_ptr += 4; } if ( !buf ) return(0); #ifdef RLOGCODE /* blah */ if (rlog_inband && (ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN)) { int i, left, n; for (i = 0; i < nstored; i++) { if (store_ptr[i] == '\377' && store_ptr[i+1] == '\377') { left = nstored - i; n = rlog_ctrl(&store_ptr[i], left); if (n < 0) { left -= (-n); nstored = left; /* flush before, and (-n) bytes */ if (left > 0) memmove(store_ptr, &store_ptr[i-n], left); } else if (n) { left -= n; nstored -= n; if (left > 0) memmove(store_ptr, &store_ptr[n], left); } } } } #endif /* RLOGCODE */ if (nstored > len) { memcpy(buf, store_ptr, len); /* safe */ nreturned += len; store_ptr += len; nstored -= len; } else { memcpy(buf, store_ptr, nstored); /* safe */ nreturned += nstored; nstored = 0; } return(nreturned); } int krb5_des_write(fd, buf, len, secondary) int fd; char *buf; int len; int secondary; { char tmpbuf[2*RLOG_BUFSIZ+8]; unsigned char *len_buf = (unsigned char *) tmpbuf; krb5_error_code status; krb5_data plain; krb5_enc_data cipher; debug(F111,"krb5_des_write","rlog_encrypt",rlog_encrypt); if ( !rlog_encrypt ) { int cc = net_write(fd, buf, len); debug(F111,"net_write","chars written",cc); return(cc != len ? -1 : len); } if (use_ivecs) { unsigned char *lenbuf2 = (unsigned char *) tmpbuf; if (len + 4 > sizeof(tmpbuf)) abort (); lenbuf2[0] = (len & 0xff000000) >> 24; lenbuf2[1] = (len & 0xff0000) >> 16; lenbuf2[2] = (len & 0xff00) >> 8; lenbuf2[3] = (len & 0xff); memcpy (tmpbuf + 4, buf, len); plain.data = tmpbuf; plain.length = len + 4; } else { plain.data = buf; plain.length = len; } cipher.ciphertext.length = sizeof(des_outpkt)-4; cipher.ciphertext.data = desoutbuf.data; if ( status = krb5_c_encrypt(k5_context, k5_session_key, KCMD_KEYUSAGE, use_ivecs ? encivec_o + secondary : 0, &plain, &cipher)) { printf("Write encrypt problem: %s.\r\n", error_message(status)); errno = EIO; return(-1); } desoutbuf.length = cipher.ciphertext.length; len_buf = (unsigned char *) des_outpkt; len_buf[0] = (len & 0xff000000) >> 24; len_buf[1] = (len & 0xff0000) >> 16; len_buf[2] = (len & 0xff00) >> 8; len_buf[3] = (len & 0xff); if (net_write(fd, des_outpkt,desoutbuf.length+4) != desoutbuf.length+4){ printf("Could not write out all data\r\n"); return(-1); } else return(len); } #endif /* KRB5 */ #ifdef KRB4 /* * Note that the encrypted rlogin packets take the form of a four-byte * length followed by encrypted data. On writing the data out, a significant * performance penalty is suffered (at least one RTT per character, two if we * are waiting for a shell to echo) by writing the data separately from the * length. So, unlike the input buffer, which just contains the output * data, the output buffer represents the entire packet. */ int krb4_des_avail(fd) int fd; { return(nstored); } int krb4_des_read(fd, buf, len) int fd; register char *buf; int len; { int nreturned = 0; unsigned long net_len, rd_len; int cc; unsigned char c; int gotzero = 0; debug(F111,"krb4_des_read","rlog_encrypt",rlog_encrypt); debug(F111,"krb4_des_read","len",len); if ( !rlog_encrypt ) { cc = net_read(fd, buf, len); debug(F111,"krb4_des_read","chars read",cc); if ( cc < 0 ) netclos(); return(cc); } if (nstored >= len) { if ( buf ) { debug(F111,"krb4_des_read (nstored >= len)","nstored",nstored); memcpy(buf, store_ptr, len); /* safe */ store_ptr += len; nstored -= len; return(len); } else return(0); } else if (nstored) { if ( buf ) { debug(F111,"krb4_des_read (nstored)","nstored",nstored); memcpy(buf, store_ptr, nstored); /* safe */ nreturned += nstored; buf += nstored; len -= nstored; nstored = 0; } else return(0); } /* We're fetching the length which is MSB first, and the MSB has to be zero unless the client is sending more than 2^24 (16M) bytes in a single write (which is why this code is in rlogin but not rcp or rsh.) The only reasons we'd get something other than zero are: -- corruption of the tcp stream (which will show up when everything else is out of sync too) -- un-caught Berkeley-style "pseudo out-of-band data" which happens any time the user hits ^C twice. The latter is *very* common, as shown by an 'rlogin -x -d' using the CNS V4 rlogin. Mark EIchin 1/95 */ debug(F110,"krb4_des_read", "about to call net_read() this will block", 0 ); do { cc = net_read(fd, &c, 1); debug(F111,"net_read","chars read",cc); if (cc <= 0) { netclos(); return(-1); } if (cc != 1) return 0; /* read error */ if (cc == 1) { if (c == 0) gotzero = 1; } } while (!gotzero); debug(F110,"krb4_des_read","gotzero",0); cc = net_read(fd, &c, 1); debug(F111,"net_read","chars read",cc); if (cc < 0) { netclos(); return(-1); } else if ( cc != 1 ) return(0); net_len = c; cc = net_read(fd, &c, 1); debug(F111,"net_read","chars read",cc); if (cc < 0) { netclos(); return(-1); } else if ( cc != 1 ) return(0); net_len = (net_len << 8) | c; debug(F111,"net_read","chars read",cc); cc = net_read(fd, &c, 1); if (cc < 0) { netclos(); return(-1); } else if ( cc != 1 ) return(0); net_len = (net_len << 8) | c; debug(F111,"krb4_des_read","net_len",net_len); /* Note: net_len is unsigned */ if (net_len > sizeof(des_inbuf)) { /* XXX preposterous length, probably out of sync. act as if pipe closed */ return(0); } /* the writer tells us how much real data we are getting, but we need to read the pad bytes (8-byte boundary) */ #ifndef roundup #define roundup(x,y) ((((x)+(y)-1)/(y))*(y)) #endif /* roundup */ rd_len = roundup(net_len, 8); debug(F111,"krb4_des_read","rd_len",rd_len); cc = net_read(fd, des_inbuf, rd_len); debug(F111,"net_read","chars read",cc); if (cc < 0) { netclos(); return(-1); } else if ( cc != rd_len ) return(0); ckhexdump("krb4_des_read des_inbuf",des_inbuf,8); #ifdef CK_ENCRYPTION #ifdef KRB524 (void) des_pcbc_encrypt(des_inbuf, storage, (net_len < 8) ? 8 : net_len, k4_sched, cred.session, DECRYPT); #else /* KRB524 */ (void) des_pcbc_encrypt((Block *)des_inbuf, (Block *)storage, (net_len < 8) ? 8 : net_len, k4_sched, &cred.session, DECRYPT); #endif /* KRB524 */ #endif /* ENCRYPTION */ ckhexdump("krb4_des_read storage",storage,8); /* * when the cleartext block is < 8 bytes, it is "right-justified" * in the block, so we need to adjust the pointer to the data */ if (net_len < 8) store_ptr = storage + 8 - net_len; else store_ptr = storage; nstored = net_len; if ( !buf ) return(0); if (nstored > len) { memcpy(buf, store_ptr, len); /* safe */ nreturned += len; store_ptr += len; nstored -= len; } else { memcpy(buf, store_ptr, nstored); /* safe */ nreturned += nstored; nstored = 0; } debug(F111,"net_read","nreturned",nreturned); return(nreturned); } int krb4_des_write(fd, buf, len) int fd; char *buf; int len; { static char garbage_buf[8]; unsigned char *len_buf = (unsigned char *) des_outpkt; int cc; debug(F111,"krb4_des_write","rlog_encrypt",rlog_encrypt); if ( !rlog_encrypt ) { cc = net_write(fd, buf, len); debug(F111,"net_write","chars written",cc); return(cc); } /* * pcbc_encrypt outputs in 8-byte (64 bit) increments * * it zero-fills the cleartext to 8-byte padding, * so if we have cleartext of < 8 bytes, we want * to insert random garbage before it so that the ciphertext * differs for each transmission of the same cleartext. * if len < 8 - sizeof(long), sizeof(long) bytes of random * garbage should be sufficient; leave the rest as-is in the buffer. * if len > 8 - sizeof(long), just garbage fill the rest. */ if (len < 8) { random_confounder(8 - len, garbage_buf); /* this "right-justifies" the data in the buffer */ (void) memcpy(garbage_buf + 8 - len, buf, len); /* safe */ ckhexdump("krb4_des_write garbage_buf",garbage_buf,8); } else ckhexdump("krb4_des_write buf",buf,8); #ifdef CK_ENCRYPTION #ifdef KRB524 (void) des_pcbc_encrypt((len < 8) ? garbage_buf : buf, des_outpkt+4, (len < 8) ? 8 : len, k4_sched, cred.session, ENCRYPT); #else /* KRB524 */ (void) des_pcbc_encrypt((Block *)((len < 8) ? garbage_buf : buf), (Block *)(des_outpkt+4), (len < 8) ? 8 : len, k4_sched, &cred.session, ENCRYPT); #endif /* KRB524 */ #endif /* ENCRYPTION */ if ( len < 8 ) ckhexdump("krb4_des_write (post pcbc) garbage_buf",garbage_buf,8); else ckhexdump("krb4_des_write (post pcbc) buf",buf,8); ckhexdump("krb4_des_write (des_outpkt+4)",(des_outpkt+4),8); /* tell the other end the real amount, but send an 8-byte padded packet */ len_buf[0] = (len & 0xff000000) >> 24; len_buf[1] = (len & 0xff0000) >> 16; len_buf[2] = (len & 0xff00) >> 8; len_buf[3] = (len & 0xff); ckhexdump("krb4_des_write des_outpkt len",des_outpkt,12); cc = net_write(fd, des_outpkt, roundup(len,8)+4); debug(F111,"net_write","chars written",cc); return(len); } #endif /* KRB4 */ #endif /* RLOGCODE */ #ifdef KRB524 #ifndef OS2 /* The following functions are missing from the compatibility library */ const char * krb_get_err_text_entry(r) int r; { extern char krb_err_text[]; return(krb_err_txt[r]); } #endif /* OS2 */ #endif /* KRB524 */ #endif /* CK_KERBEROS */ #ifdef CK_KERBEROS #ifdef KRB5_U2U /* Kerberos 5 User to User Client */ int k5_user_to_user_client_auth() { extern int ttyfd; register int retval, i; char **srealms; /* realm(s) of server */ char *princ; /* principal in credentials cache */ krb5_ccache cc; krb5_creds creds, *new_creds; krb5_data reply, msg, msgtext, princ_data; krb5_ticket * ticket = NULL; if (retval = k5_get_ccache(k5_context,&cc,NULL)) { com_err("uu-client", retval, "getting credentials cache"); return(-1); } memset ((char*)&creds, 0, sizeof(creds)); if (retval = krb5_cc_get_principal(k5_context, cc, &creds.client)) { com_err("uu-client", retval, "getting principal name"); return(-1); } if (retval = krb5_get_host_realm(k5_context, szHostName, &srealms)) { com_err("uu-client", retval, "getting realms for \"%s\"", szHostName); return(-1); } if (retval = krb5_build_principal_ext(k5_context, &creds.server, krb5_princ_realm(k5_context, creds.client)->length, krb5_princ_realm(k5_context, creds.client)->data, 6, "krbtgt", krb5_princ_realm(k5_context, creds.client)->length, krb5_princ_realm(k5_context, creds.client)->data, 0)) { com_err("uu-client", retval, "setting up tgt server name"); return(-1); } /* Get TGT from credentials cache */ if (retval = krb5_get_credentials(k5_context, KRB5_GC_CACHED, cc, &creds, &new_creds)) { com_err("uu-client", retval, "getting TGT"); return(-1); } if (retval = krb5_unparse_name(k5_context, creds.client, &princ)) { com_err("uu-client", retval, "printing principal name"); return(-1); } i = strlen(princ) + 1; princ_data.data = princ; princ_data.length = i; /* include null terminator for server's convenience */ retval = krb5_write_message(k5_context, (krb5_pointer) &ttyfd, &princ_data); if (retval) { com_err("uu-client", retval, "sending principal name to server"); return(-1); } krb5_free_unparsed_name(k5_context,princ); retval = krb5_write_message(k5_context, (krb5_pointer) &ttyfd, &new_creds->ticket); if (retval) { com_err("uu-client", retval, "sending ticket to server"); return(-1); } retval = krb5_read_message(k5_context, (krb5_pointer) &ttyfd, &reply); if (retval) { com_err("uu-client", retval, "reading reply from server"); return(-1); } if (retval = krb5_auth_con_init(k5_context, &auth_context)) { com_err("uu-client", retval, "initializing the auth_context"); return(-1); } if (!krb5_d_no_addresses) { if (retval = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR | KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) { com_err("uu-client", retval, "generating addrs for auth_context"); return(-1); } } if (retval = krb5_auth_con_setflags(k5_context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE)) { com_err("uu-client", retval, "initializing the auth_context flags"); return(-1); } if (retval = krb5_auth_con_setuseruserkey(k5_context, auth_context, &new_creds->keyblock)) { com_err("uu-client", retval, "setting useruserkey for authcontext"); return(-1); } /* read the ap_req to get the session key */ retval = krb5_rd_req(k5_context, &auth_context, &reply, NULL, NULL, NULL, &ticket); if (retval) { com_err("uu-client", retval, "reading AP_REQ from server"); return(-1); } if (k5_u2u_read_msg(k5_context,&msg) < 0) return(-1); if ( strcmp("Kermit implements Kerberos 5 User to User",msg.data) ) return(-1); krb5_free_data_contents(k5_context,&msg); msgtext.data = "As do I! :-)"; msgtext.length = strlen(msgtext.data)+1; if (k5_u2u_write_msg(k5_context,&msgtext) < 0) return(-1); if (retval = krb5_unparse_name(k5_context, #ifdef HEIMDAL ticket->client, #else /* HEIMDAL */ ticket->enc_part2->client, #endif /* HEIMDAL */ &princ)) com_err("uu-client", retval, "while unparsing client name"); else { ckstrncpy(szUserNameAuthenticated,princ,UIDBUFLEN); validUser = AUTH_VALID; authentication_version = AUTHTYPE_KERBEROS_V5; if ( !quiet ) printf("Peer name is \"%s\"\n", princ); krb5_free_unparsed_name(k5_context,princ); } return 0; } /* Kerberos 5 User to User Server */ int k5_user_to_user_server_auth() { krb5_data pname_data, tkt_data; int retval; krb5_creds creds, *new_creds; krb5_ccache cc; krb5_data msg, msgtext; extern int ttyfd; if (retval = krb5_read_message(k5_context, (krb5_pointer) &ttyfd, &pname_data)) { com_err ("uu-server", retval, "reading pname"); return(-1); } /* client sends it already null-terminated. */ if ( !quiet ) printf ("Peer name is \"%s\".\n", pname_data.data); ckstrncpy(szUserNameAuthenticated,pname_data.data,UIDBUFLEN); validUser = AUTH_VALID; authentication_version = AUTHTYPE_KERBEROS_V5; if (retval = krb5_read_message(k5_context, (krb5_pointer) &ttyfd, &tkt_data)) { com_err ("uu-server", retval, "reading ticket data"); return(-1); } if (retval = k5_get_ccache(k5_context,&cc,NULL)) { com_err("uu-server", retval, "getting credentials cache"); return(-1); } memset ((char*)&creds, 0, sizeof(creds)); if (retval = krb5_cc_get_principal(k5_context, cc, &creds.client)) { com_err("uu-server", retval, "getting principal name"); return(-1); } if (retval = krb5_parse_name(k5_context, pname_data.data, &creds.server)) { com_err("uu-server", retval, "parsing client name"); return(-1); } creds.second_ticket = tkt_data; if (retval = krb5_get_credentials(k5_context, KRB5_GC_USER_USER, cc, &creds, &new_creds)) { com_err("uu-server", retval, "getting user-user ticket"); return(-1); } /* send a ticket/authenticator to the other side, so it can get the key we're using for the krb_safe below. */ if (retval = krb5_auth_con_init(k5_context, &auth_context)) { com_err("uu-server", retval, "making auth_context"); return(-1); } if (retval = krb5_auth_con_setflags(k5_context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE)) { com_err("uu-server", retval, "initializing the auth_context flags"); return(-1); } if (!krb5_d_no_addresses) { if (retval = krb5_auth_con_genaddrs(k5_context, auth_context, ttyfd, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR | KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) { com_err("uu-server", retval, "generating addrs for auth_context"); return(-1); } } if (retval = krb5_auth_con_setuseruserkey(k5_context, auth_context, &new_creds->keyblock)) { com_err("uu-server", retval, "setting useruserkey for authcontext"); return(-1); } if (retval = krb5_mk_req_extended(k5_context, &auth_context, AP_OPTS_USE_SESSION_KEY | AP_OPTS_MUTUAL_REQUIRED, NULL, new_creds, &msg)) { com_err("uu-server", retval, "making AP_REQ"); return(-1); } retval = krb5_write_message(k5_context, (krb5_pointer) &ttyfd, &msg); if (retval) { com_err("uu-server", retval, "writing message to client"); return(-1); } krb5_free_data_contents(k5_context,&msg); msgtext.data = "Kermit implements Kerberos 5 User to User"; msgtext.length = strlen(msgtext.data)+1; if (k5_u2u_write_msg(k5_context,&msgtext) < 0) return(-1); if (k5_u2u_read_msg(k5_context,&msg) < 0) return(-1); if ( strcmp("As do I! :-)",msg.data) ) return(-1); krb5_free_data_contents(k5_context,&msg); return(0); } int k5_u2u_read_msg(krb5_context context, int fd, krb5_data * msg) { int retval; krb5_data reply; retval = krb5_read_message(context, (krb5_pointer) &fd, &reply); if (retval) { com_err("uu-client", retval, "reading reply"); return(-1); } if (retval = krb5_rd_priv(context, auth_context, &reply, msg, NULL)) { com_err("uu-client", retval, "decoding reply"); return(-1); } return(0); } int k5_u2u_write_msg(krb5_context context, int fd, krb5_data * msgtext) { int retval; krb5_data msg; if (retval = krb5_mk_priv(k5_context, auth_context, msgtext, &msg, NULL)) { com_err("uu-server", retval, "encoding message"); return(-1); } retval = krb5_write_message(k5_context, (krb5_pointer) &fd, &msg); krb5_free_data_contents(k5_context,&msg); if (retval) { com_err("uu-server", retval, "writing message"); return(-1); } return(0); } int krb5_u2u_avail(fd) int fd; { return(nstored); } int krb5_u2u_read(fd, buf, len) int fd; register char *buf; int len; { int nreturned = 0; krb5_data msg; debug(F111,"krb5_u2u_read","len",len); if ( !buf ) return(0); if (nstored >= len) { memcpy(buf, store_ptr, len); /* safe */ store_ptr += len; nstored -= len; return(len); } else if (nstored) { memcpy(buf, store_ptr, nstored); /* safe */ nreturned += nstored; buf += nstored; len -= nstored; nstored = 0; } if (k5_u2u_read_msg(k5_context, fd, &msg) < 0) return(-1); if ( msg.length <= len ) { memcpy(buf, msg.data, msg.length); nreturned += msg.length; nstored = 0; } else { memcpy(buf, msg.data, len); nreturned += len; if ( msg.length - len < sizeof(storage) ) { store_ptr = storage; nstored = msg.length - len; memcpy(storage,msg.data+len,nstored); } else { nstored = 0; return(-1); } } return(nreturned); } int krb5_u2u_write(fd, buf, len) int fd; char *buf; int len; { krb5_data msg; msg.length = len; msg.data = buf; if ( k5_u2u_write_msg(k5_context, fd, &msg) < 0 ) return(-1); else return(len); } #endif /* KRB5_U2U */ #endif /* CK_KERBEROS */ #ifdef CK_FORWARD_X /* Copyright (c) 1988 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ /* Modified for stand-alone compiling by * Peter 'Luna' Runestig */ #include #include #include #include #include #define Time_t time_t #include "ckcfnp.h" /* Prototypes (must be last) */ void #ifdef CK_ANSIC XauDisposeAuth (Xauth *auth) #else XauDisposeAuth (auth) Xauth *auth; #endif /* CK_ANSIC */ { if (auth) { if (auth->address) (void) free (auth->address); if (auth->number) (void) free (auth->number); if (auth->name) (void) free (auth->name); if (auth->data) { (void) bzero (auth->data, auth->data_length); (void) free (auth->data); } free ((char *) auth); } return; } char * XauFileName () { char *slashDotXauthority = "/.Xauthority"; char *name; static char *buf=NULL; static int bsize=0; int size, namelen; extern char * tn_fwdx_xauthority; if ( tn_fwdx_xauthority ) return(tn_fwdx_xauthority); if ((name = getenv ("XAUTHORITY"))) return(name); name = zhome(); if ( !name ) return(NULL); namelen = strlen (name); size = namelen + strlen(slashDotXauthority) + 1; if (size > bsize) { if (buf) free (buf); buf = malloc ((unsigned) size); if (!buf) return 0; bsize = size; } ckstrncpy (buf, name, bsize); if ( name[namelen-1] != '/' #ifdef OS2 && name[namelen-1] != '\\' #endif /* OS2 */ ) ckstrncat (buf, slashDotXauthority, bsize); else ckstrncat (buf, &slashDotXauthority[1], bsize); return(buf); } static int #ifdef CK_ANSIC binaryEqual (const char *a, const char *b, int len) #else binaryEqual (a, b, len) const char *a, *b; int len; #endif /* CK_ANSIC */ { while (len--) if (*a++ != *b++) return 0; return 1; } #ifndef R_OK #define R_OK 04 #endif /* R_OK */ Xauth * #ifdef CK_ANSIC XauGetAuthByAddr (unsigned int family, unsigned int address_length, const char *address, unsigned int number_length, const char *number, unsigned int name_length, const char *name) #else XauGetAuthByAddr (family, address_length, address, number_length, number, name_length, name) unsigned int family; unsigned int address_length; const char *address; unsigned int number_length; const char *number; unsigned int name_length; const char *name; #endif /* CK_ANSIC */ { FILE *auth_file; char *auth_name; Xauth *entry; auth_name = XauFileName(); if (!auth_name) return 0; if (access (auth_name, R_OK) != 0) /* checks REAL id */ return 0; auth_file = fopen (auth_name, "rb"); if (!auth_file) return 0; for (;;) { entry = XauReadAuth (auth_file); if (!entry) break; /* * Match when: * either family or entry->family are FamilyWild or * family and entry->family are the same * and * either address or entry->address are empty or * address and entry->address are the same * and * either number or entry->number are empty or * number and entry->number are the same * and * either name or entry->name are empty or * name and entry->name are the same */ /* if ((family == FamilyWild || entry->family == FamilyWild || (entry->family == family && address_length == entry->address_length && binaryEqual (entry->address, address, (int)address_length))) && (number_length == 0 || entry->number_length == 0 || (number_length == entry->number_length && binaryEqual (entry->number, number, (int)number_length))) && (name_length == 0 || entry->name_length == 0 || (entry->name_length == name_length && binaryEqual (entry->name, name, (int)name_length)))) */ /* the original matching code above doesn't seem to meet the matching * algorithm, it doesn't check if "address_length == 0 || * entry->address_length == 0". / Luna 2000-02-09 */ if ((family == FamilyWild || entry->family == FamilyWild || entry->family == family) && (address_length == 0 || entry->address_length == 0 || (address_length == entry->address_length && binaryEqual (entry->address, address, (int)address_length))) && (number_length == 0 || entry->number_length == 0 || (number_length == entry->number_length && binaryEqual (entry->number, number, (int)number_length))) && (name_length == 0 || entry->name_length == 0 || (entry->name_length == name_length && binaryEqual (entry->name, name, (int)name_length)))) break; XauDisposeAuth (entry); } (void) fclose (auth_file); return entry; } static int #ifdef CK_ANSIC read_short (unsigned short *shortp, FILE *file) #else read_short (shortp, file) unsigned short *shortp; FILE *file; #endif /* CK_ANSIC */ { unsigned char file_short[2]; if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) return 0; *shortp = file_short[0] * 256 + file_short[1]; return 1; } static int #ifdef CK_ANSIC read_counted_string (unsigned short *countp, char **stringp, FILE *file) #else read_counted_string (countp, stringp, file) unsigned short *countp; char **stringp; FILE *file; #endif /* CK_ANSIC */ { unsigned short len; char *data; if (read_short (&len, file) == 0) return 0; if (len == 0) { data = 0; } else { data = malloc ((unsigned) len); if (!data) return 0; if (fread (data, (int) sizeof (char), (int) len, file) != len) { bzero (data, len); free (data); return 0; } } *stringp = data; *countp = len; return 1; } Xauth * #ifdef CK_ANSIC XauReadAuth (FILE *auth_file) #else XauReadAuth (auth_file) FILE *auth_file; #endif /* CK_ANSIC */ { Xauth local; Xauth *ret; if (read_short (&local.family, auth_file) == 0) return 0; if (read_counted_string (&local.address_length, &local.address, auth_file) == 0) return 0; if (read_counted_string (&local.number_length, &local.number, auth_file) == 0) { if (local.address) free (local.address); return 0; } if (read_counted_string (&local.name_length, &local.name, auth_file) == 0) { if (local.address) free (local.address); if (local.number) free (local.number); return 0; } if (read_counted_string (&local.data_length, &local.data, auth_file) == 0) { if (local.address) free (local.address); if (local.number) free (local.number); if (local.name) free (local.name); return 0; } ret = (Xauth *) malloc (sizeof (Xauth)); if (!ret) { if (local.address) free (local.address); if (local.number) free (local.number); if (local.name) free (local.name); if (local.data) { bzero (local.data, local.data_length); free (local.data); } return 0; } *ret = local; return ret; } static int #ifdef CK_ANSIC write_short (unsigned short s, FILE *file) #else write_short (s, file) unsigned short s; FILE *file; #endif /* CK_ANSIC */ { unsigned char file_short[2]; file_short[0] = (s & (unsigned)0xff00) >> 8; file_short[1] = s & 0xff; if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1) return 0; return 1; } static int #ifdef CK_ANSIC write_counted_string (unsigned short count, char *string, FILE *file) #else write_counted_string (count, string, file) unsigned short count; char *string; FILE *file; #endif /* CK_ANSIC */ { if (write_short (count, file) == 0) return 0; if (fwrite (string, (int) sizeof (char), (int) count, file) != count) return 0; return 1; } int #ifdef CK_ANSIC XauWriteAuth (FILE *auth_file, Xauth *auth) #else XauWriteAuth (auth_file, auth) FILE *auth_file; Xauth *auth; #endif /* CK_ANSIC */ { if (write_short (auth->family, auth_file) == 0) return 0; if (write_counted_string (auth->address_length, auth->address, auth_file) == 0) return 0; if (write_counted_string (auth->number_length, auth->number, auth_file) == 0) return 0; if (write_counted_string (auth->name_length, auth->name, auth_file) == 0) return 0; if (write_counted_string (auth->data_length, auth->data, auth_file) == 0) return 0; return 1; } #ifdef KRB5 #ifdef K5_XAUTH /* * functions to encode/decode Kerberos V5 principals * into something that can be reasonable spewed over * the wire * * Author: Tom Yu * * Still needs to be fixed up wrt signed/unsigned lengths, but we'll worry * about that later. */ /* * XauKrb5Encode * * this function encodes the principal passed to it in a format that can * easily be dealt with by stuffing it into an X packet. Encoding is as * follows: * length count of the realm name * realm * component count * length of component * actual principal component * etc.... * * Note that this function allocates a hunk of memory, which must be * freed to avoid nasty memory leak type things. All counts are * byte-swapped if needed. (except for the total length returned) * * nevermind.... stuffing the encoded packet in net byte order just to * always do the right thing. Don't have to frob with alignment that way. */ int XauKrb5Encode(princ, outbuf) krb5_principal princ; /* principal to encode */ krb5_data *outbuf; /* output buffer */ { CARD16 i, numparts, totlen = 0, plen, rlen; char *cp, *pdata; rlen = krb5_princ_realm(princ)->length; numparts = krb5_princ_size(princ); totlen = 2 + rlen + 2; /* include room for realm length and component count */ for (i = 0; i < numparts; i++) totlen += krb5_princ_component(princ, i)->length + 2; /* add 2 bytes each time for length */ if ((outbuf->data = (char *)malloc(totlen)) == NULL) return -1; cp = outbuf->data; *cp++ = (char)((int)(0xff00 & rlen) >> 8); *cp++ = (char)(0x00ff & rlen); memcpy(cp, krb5_princ_realm(princ)->data, rlen); /* safe */ cp += rlen; *cp++ = (char)((int)(0xff00 & numparts) >> 8); *cp++ = (char)(0x00ff & numparts); for (i = 0; i < numparts; i++) { plen = krb5_princ_component(princ, i)->length; pdata = krb5_princ_component(princ, i)->data; *cp++ = (char)((int)(0xff00 & plen) >> 8); *cp++ = (char)(0x00ff & plen); memcpy(cp, pdata, plen); /* safe */ cp += plen; } outbuf->length = totlen; return 0; } /* * XauKrb5Decode * * This function essentially reverses what XauKrb5Encode does. * return value: 0 if okay, -1 if malloc fails, -2 if inbuf format bad */ int XauKrb5Decode(inbuf, princ) krb5_data inbuf; krb5_principal *princ; { CARD16 i, numparts, plen, rlen; CARD8 *cp, *pdata; if (inbuf.length < 4) { return -2; } *princ = (krb5_principal)malloc(sizeof (krb5_principal_data)); if (*princ == NULL) return -1; bzero(*princ, sizeof (krb5_principal_data)); cp = (CARD8 *)inbuf.data; rlen = *cp++ << 8; rlen |= *cp++; if (inbuf.length < 4 + (int)rlen + 2) { krb5_free_principal(*princ); return -2; } krb5_princ_realm(*princ)->data = (char *)malloc(rlen); if (krb5_princ_realm(*princ)->data == NULL) { krb5_free_principal(*princ); return -1; } krb5_princ_realm(*princ)->length = rlen; memcpy(krb5_princ_realm(*princ)->data, cp, rlen); /* safe */ cp += rlen; numparts = *cp++ << 8; numparts |= *cp++; krb5_princ_name(*princ) = (krb5_data *)malloc(numparts * sizeof (krb5_data)); if (krb5_princ_name(*princ) == NULL) { krb5_free_principal(*princ); return -1; } krb5_princ_size(*princ) = 0; for (i = 0; i < numparts; i++) { if (cp + 2 > (CARD8 *)inbuf.data + inbuf.length) { krb5_free_principal(*princ); return -2; } plen = *cp++ << 8; plen |= *cp++; if (cp + plen > (CARD8 *)inbuf.data + inbuf.length) { krb5_free_principal(*princ); return -2; } pdata = (CARD8 *)malloc(plen); if (pdata == NULL) { krb5_free_principal(*princ); return -1; } krb5_princ_component(*princ, i)->data = (char *)pdata; krb5_princ_component(*princ, i)->length = plen; memcpy(pdata, cp, plen); /* safe */ cp += plen; krb5_princ_size(*princ)++; } return 0; } #endif /* K5_XAUTH */ #endif /* KRB5 */ #endif /* CK_FORWARD_X */ #endif /* CK_AUTHENTICATION */ /* C K _ A U T H _ I N I T * Initialize the Kerberos system for a pending connection * hostname - a reverse DNS lookup of the hostname when possible * ipaddr - the ip address of the host * username - the name the user wants to connect under not necessarily * the same as principal * socket - the socket handle (ttyfd in Kermit speak) * * Returns: 1 on success and 0 on failure */ int #ifdef CK_ANSIC ck_auth_init( char * hostname, char * ipaddr, char * username, int socket ) #else /* CK_ANSIC */ ck_auth_init( hostname, ipaddr, username, socket ) char * hostname; char * ipaddr; char *username; int socket; #endif /* CK_ANSIC */ { #ifdef CK_AUTHENTICATION #ifdef OS2 if ( !ck_security_loaddll() ) { TELOPT_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF; return(0); } #endif /* OS2 */ #endif /* CK_AUTHENTICAITON */ #ifdef CK_ENCRYPTION if ( !!ck_crypt_is_installed() ) { TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } #endif /* CK_ENCRYPTION */ if (!hostname) hostname = ""; if (!ipaddr) ipaddr = ""; if (!username) username = ""; debug(F110,"ck_auth_init Username",username,0); debug(F110,"ck_auth_init Hostname",hostname,0); debug(F110,"ck_auth_init Ipaddr",ipaddr,0); ckstrncpy( szUserName, username, UIDBUFLEN ); ckstrncpy( szHostName, hostname, UIDBUFLEN ); ckstrncpy( szIP, ipaddr, 16 ); szUserNameRequested[0] = '\0'; szUserNameAuthenticated[0] = '\0'; validUser = AUTH_REJECT; accept_complete = 0; authentication_version = AUTHTYPE_NULL; #ifdef CK_AUTHENTICATION auth_how = 0; auth_crypt = 0; auth_fwd = 0; mutual_complete = 0; if ( sstelnet ) str_data[3] = TELQUAL_REPLY; else str_data[3] = TELQUAL_IS; #endif /* CK_AUTHENTICATION */ #ifdef CK_SRP srp_waitresp = 0; #endif /* SRP */ #ifdef CK_KERBEROS #ifdef KRB5 /* free previous ret_cred */ if ( ret_cred ) { #ifdef CK_ENCRYPTION #ifdef HEIMDAL if ( k5_session_key == &ret_cred->session) k5_session_key = NULL; #else /* HEIMDAL */ if ( k5_session_key == &ret_cred->keyblock) k5_session_key = NULL; #endif /* HEIMDAL */ #endif /* CK_ENCRYPTION */ krb5_free_creds(k5_context, ret_cred); ret_cred = NULL; } if (k5_ticket) { krb5_free_ticket(k5_context, k5_ticket); k5_ticket = NULL; } /* and context */ if ( k5_context ) { krb5_free_context(k5_context); k5_context = NULL; } /* create k5_context */ krb5_init_context(&k5_context); #ifndef MIT_CURRENT #ifndef NO_KRB5_INIT_ETS /* This routine is a no-op in Kerberos 1.4.x and later */ /* and in some installations it can't be found in which case */ /* define NO_KRB5_INIT_ETS */ if (k5_context) krb5_init_ets(k5_context); #endif /* NO_KRB5_INIT_ETS */ #endif /* MIT_CURRENT */ #ifdef KRB524_CONV krb524_init_ets(k5_context); #endif /* KRB524_CONV */ memset(&k5_auth,0,sizeof(k5_auth)); if (auth_context) { krb5_auth_con_free(k5_context, auth_context); auth_context = 0; } #ifdef CK_ENCRYPTION if (k5_session_key) { krb5_free_keyblock(k5_context, k5_session_key); k5_session_key = 0; } #endif /* ENCRYPTION */ #ifdef TLS_VERIFY krb5_tls_verified = 0; #endif /* TLS_VERIFY */ #endif /* KRB5 */ #ifdef KRB4 #ifdef CK_ENCRYPTION /* Initialize buffers used for authentication */ memset(&k4_session_key, 0, sizeof(k4_session_key)); memset(&k4_challenge, 0, sizeof(k4_challenge)); #endif /* CK_ENCRYPTION */ #endif /* KRB4 */ #ifdef RLOGCODE rlog_encrypt = 0; #endif /* RLOGCODE */ nstored = 0; store_ptr = storage; memset(storage,0,sizeof(storage)); #endif /* CK_KERBEROS */ #ifdef CK_ENCRYPTION kstream_destroy(); if (!kstream_create_from_fd(socket, NULL)) return(0); #endif /* CK_ENCRYPTION */ return(1); } void #ifdef CK_ANSIC auth_finished(int result) #else auth_finished(result) int result; #endif /* CK_ANSIC */ { extern char uidbuf[]; extern int sstelnet; validUser = result; switch (result) { case AUTH_REJECT: /* Rejected */ if (sstelnet) uidbuf[0] = '\0'; authentication_version = AUTHTYPE_NULL; break; case AUTH_UNKNOWN: /* We don't know who he is, but he's okay */ if (sstelnet) strcpy(uidbuf,"(unknown)"); break; case AUTH_OTHER: /* We know him, but not his name */ if (sstelnet) strcpy(uidbuf,"(other)"); break; case AUTH_USER: /* We know he name */ case AUTH_VALID: /* We know him, and he needs no password */ if (sstelnet) strcpy(uidbuf,szUserNameRequested); break; } } #ifdef MACOSX #ifdef KRB5 krb5_error_code ck_krb5_write_message(krb5_context con, krb5_pointer ptr, krb5_data *data) { int fd = *((int *)ptr); long msglen; msglen = htonl(data->length); if (net_write(fd,(CHAR *)&msglen,4) != 4) { return(-1); } if ( data->length ) { if (net_write(fd,data->data,data->length) != data->length) { return(-1); } } return(0); } krb5_error_code ck_krb5_read_message( krb5_context context, krb5_pointer ptr, krb5_data * data) { extern int ttyfd; int fd = *((int *)ptr); long msglen; char *p; int i, rc; if (net_read(fd,&msglen,4) < 0) return(-1); data->length = ntohl(msglen); if ( data->length ) { data->data = malloc(data->length); i = 0; while ( i < data->length ) { if ((rc = net_read(fd,&data->data[i],(data->length - i))) < 0) return(-1); i += rc; } } return(0); } #endif /* KRB5 */ #endif /* MACOSX */ #endif /* CK_SECURITY */ ckuath.h000664 045065 024037 00000021016 14767402040 012617 0ustar00fdckermit000000 000000 /* C K U A T H . H -- "C-Kermit to Authentication" interface */ /* Author: Jeffrey E Altman , Secure Endpoints Inc., New York City. Copyright (C) 1999, 2009, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ /* * Based on a concatenation of all necessary include files distributed with * the Kerberos 5 NT Alpha 2 Telnet package from MIT. */ #ifndef KRB5_KERMIT_H #define KRB5_KERMIT_H #ifndef BOOL #define BOOL int #endif /* Header file for encrypted-stream library. * Written by Ken Raeburn (Raeburn@Cygnus.COM). * Copyright (C) 1991, 1992, 1994 by Cygnus Support. * * Permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation. * Cygnus Support makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #ifndef K5STREAM_H #define K5STREAM_H #ifdef COMMENT /* We can't possibly know where krb5.h is, so can't hardwire its location into this code. The Makefile target has to find; see examples in linux+krb5-new and netbsd+krb5-new. - fdc, 2 December 2022 */ #ifdef CK_KERBEROS #include /* Type defs. */ #endif /* def CK_KERBEROS */ #endif /* COMMENT */ typedef void *kstream_ptr; /* Data send on the kstream */ struct kstream_data_block { kstream_ptr ptr; size_t length; }; typedef struct kstream_int { /* Object we pass around */ int fd; /* Open socket descriptor */ int (*encrypt)(struct kstream_data_block *, /* output */ struct kstream_data_block *); /* input */ int encrypt_type; int (*decrypt)(struct kstream_data_block *, /* output */ struct kstream_data_block *); /* input */ int decrypt_type; } *kstream; /* Prototypes */ int kstream_destroy(); void kstream_set_buffer_mode(int); int kstream_create_from_fd(int fd, kstream_ptr); int kstream_write(void *, size_t); int kstream_read(void *, size_t); #endif /* K5STREAM_H */ /* * Implements Telnet authentication and encryption */ #ifndef TELNET_AUTH_H #define TELNET_AUTH_H int auth_parse(unsigned char *, int); int auth_init(kstream); void auth_destroy(void); int auth_encrypt(struct kstream_data_block *, struct kstream_data_block *); int auth_decrypt(struct kstream_data_block *, struct kstream_data_block *); extern BOOL forward_flag; extern BOOL forwardable_flag; extern BOOL forwarded_tickets; #endif /* TEL_AUTH_H */ /* C-Kermit specific functions */ _PROTOTYP(void auth_finished,(int)); _PROTOTYP(int ck_auth_init, (char *, char *, char *, int)); _PROTOTYP(int ck_tn_auth_valid, (VOID)); _PROTOTYP(int ck_tn_auth_in_progress,(VOID)); _PROTOTYP(int ck_tn_sb_auth, (char *, int)); _PROTOTYP(int ck_tn_sb_encrypt, (char *, int)); _PROTOTYP(int ck_tn_auth_request, (VOID)); _PROTOTYP(void ck_tn_encrypt, (char *, int)); _PROTOTYP(void ck_tn_decrypt, (char *, int)); _PROTOTYP(void ck_tn_enc_start, (VOID)); _PROTOTYP(void ck_tn_enc_stop, (VOID)); _PROTOTYP(int ck_tn_authenticated, (VOID)); #ifdef CK_ENCRYPTION _PROTOTYP(int ck_tn_encrypting, (VOID)); _PROTOTYP(int ck_tn_decrypting, (VOID)); #endif /* CK_ENCRYPTION */ #ifdef CK_SSL _PROTOTYP(int ck_tn_tls_negotiate, (VOID)); _PROTOTYP(int SendSSLAuthSB, (int, void *, int)); #endif /* CK_SSL */ #ifdef CK_KERBEROS /* Define MIT_CURRENT to compile the code for use with versions of */ /* Kerberos later than KRB5 1.0.5. Note. This will not compile */ /* successfully in Kermit 95 due to the segmentation of crypto */ /* into a separate DLL. */ #ifndef KRB5_INIT_ETS /* krb5_init_ets() is a no-op in Kerberos 1.4.x and later */ /* and in some installations it can't be found so now by default */ /* we don't use it. */ #define NO_KRB5_INIT_ETS #endif /* KRB5_INIT_ETS */ #define KRB_DEFTIM 600 /* Default lifetime (minutes) */ /* Kerberos structure definitions */ struct krb_op_data { /* Operational data for all actions */ int version; /* Kerberos version */ char * cache; /* Kerberos cache file */ }; struct krb4_init_data { /* INITIALIZE data structure */ int lifetime; char * principal; /* Principal string */ char * instance; char * realm; /* Realm string */ char * password; /* Kerberos password */ int preauth; /* Use preauth mode? */ int verbose; /* Verbose output? */ }; #define KRB5_NUM_OF_ADDRS 16 struct krb5_init_data { /* INITIALIZE data structure */ int forwardable; /* Switch values */ int proxiable; /* Correspond to switch names... */ int lifetime; int renew; int renewable; int validate; char * postdate; char * service; char * principal; /* Principal string */ char * instance; char * realm; /* Realm string */ char * password; /* Kerberos password */ int preauth; /* Use preauth mode? */ int verbose; /* Verbose output? */ int getk4; /* Get K4 TGT? */ char * addrs[KRB5_NUM_OF_ADDRS+1]; /* List of IP Addresses */ int no_addresses; /* Do not include IP Addresses */ }; struct krb5_list_cred_data { /* List Credentials data */ int encryption; int flags; int addr; }; _PROTOTYP(int ck_krb5_autoget_TGT, (char *)); _PROTOTYP(int ck_krb5_initTGT, (struct krb_op_data *,struct krb5_init_data *, struct krb4_init_data *)); _PROTOTYP(int ck_krb5_destroy, (struct krb_op_data *)); _PROTOTYP(int ck_krb5_list_creds, (struct krb_op_data *, struct krb5_list_cred_data *)); _PROTOTYP(char * ck_krb5_getrealm, (char *)); _PROTOTYP(char * ck_krb5_getprincipal, (char *)); _PROTOTYP(char * ck_krb5_get_cc_name, (VOID)); _PROTOTYP(int ck_krb4_autoget_TGT, (char *)); _PROTOTYP(int ck_krb4_initTGT, (struct krb_op_data *,struct krb4_init_data *)); _PROTOTYP(int ck_krb4_destroy, (struct krb_op_data *)); _PROTOTYP(int ck_krb4_list_creds, (struct krb_op_data *)); _PROTOTYP(char * ck_krb4_getrealm, (VOID)); _PROTOTYP(char * ck_krb4_getprincipal, (VOID)); _PROTOTYP(int ck_krb4_get_tkts, (VOID)); _PROTOTYP(char * ck_krb4_get_next_tkt, (VOID)); _PROTOTYP(int ck_krb4_tkt_isvalid,(char *)); _PROTOTYP(int ck_krb4_is_tgt_valid,(VOID)); _PROTOTYP(int ck_krb4_tkt_time,(char *)); _PROTOTYP(int ck_krb5_get_tkts, (char *)); _PROTOTYP(char * ck_krb5_get_next_tkt, (VOID)); _PROTOTYP(int ck_krb5_tkt_isvalid,(char *,char *)); _PROTOTYP(char * ck_krb5_tkt_flags,(char *,char *)); _PROTOTYP(int ck_krb5_is_tgt_valid,(VOID)); _PROTOTYP(int ck_krb5_tkt_time,(char *,char *)); _PROTOTYP(int krb4_des_avail,(int)); _PROTOTYP(int krb4_des_write,(int,char *,int)); _PROTOTYP(int krb4_des_read, (int,char *,int)); _PROTOTYP(int krb5_des_avail,(int)); _PROTOTYP(int krb5_des_write,(int,char *,int,int)); _PROTOTYP(int krb5_des_read, (int,char *,int,int)); _PROTOTYP(int krb5_u2u_avail,(int)); _PROTOTYP(int krb5_u2u_write,(int,char *,int)); _PROTOTYP(int krb5_u2u_read, (int,char *,int)); _PROTOTYP(int k5_user_to_user_server_auth,(VOID)); _PROTOTYP(int k5_user_to_user_client_auth,(VOID)); #endif /* CK_KERBEROS */ _PROTOTYP(int ck_krb5_is_installed,(void)); _PROTOTYP(int ck_krb4_is_installed,(void)); _PROTOTYP(int ck_srp_is_installed,(void)); _PROTOTYP(int ck_ntlm_is_installed,(void)); _PROTOTYP(int ck_crypt_is_installed,(void)); _PROTOTYP(int ck_ssleay_is_installed,(void)); _PROTOTYP(int ck_gssapi_is_installed,(void)); _PROTOTYP(int ck_krypto_is_installed,(void)); _PROTOTYP(VOID ck_encrypt_send_support,(VOID)); _PROTOTYP(int ck_get_crypt_table,(struct keytab **, int *)); _PROTOTYP(char * ck_krb4_realmofhost,(char *)); _PROTOTYP(char * ck_krb5_realmofhost,(char *)); #define FORWARD /* allow forwarding of credential */ #ifdef FORWARD _PROTOTYP(int kerberos5_forward,(VOID)); #endif /* FORWARD */ #define AUTHTYPLSTSZ 8 #endif /*KRB5_KERMIT_H*/ ckucmd.c000664 045065 024037 00000715301 14767403131 012612 0ustar00fdckermit000000 000000 #include "ckcsym.h" char *cmdv = "Command package 10.0.184, 19 Sept 2023"; /* C K U C M D -- Interactive command package for Unix */ /* (In reality, it's for all platforms, not just Unix) */ /* Author: Frank da Cruz (fdc@columbia.edu), Formerly of Columbia University Academic Information Systems, New York City. Since 1 July 2011, Open Source Kermit Project. Most recent update: Tue May 2 19:18:22 2023 Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Note: the name of these files really should be ckccmd.h and ckccmd.c because they are for all platforms, not just Unix. But "don't fix what ain't broke". */ #define FUNCTIONTEST #define TOKPRECHECK #define DOCHKVAR /* Command-terminal-to-C-Kermit character mask */ #ifdef OS2 /* K95 */ int cmdmsk = 255; /* (always was 255) */ #else /* All others... */ int cmdmsk = 255; /* 31 Dec 2000 (was 127) */ #endif /* OS2 */ #ifdef BS_DIRSEP /* Directory separator is backslash */ #undef BS_DIRSEP #endif /* BS_DIRSEP */ #ifdef OS2 #define BS_DIRSEP #endif /* BS_DIRSEP */ #define CKUCMD_C #include "ckcdeb.h" /* Formats for debug(), etc. */ #include "ckcker.h" /* Needed for BIGBUFOK definition */ #include "ckcnet.h" /* Needed for server-side Telnet */ #include "ckucmd.h" /* Needed for everything */ #include "ckuusr.h" /* Needed for prompt length */ #ifndef NOARROWKEYS #ifndef NOESCSEQ #ifdef VMSORUNIX #define USE_ARROWKEYS /* Use arrow keys for command recall */ #endif /* VMSORUNIX */ #endif /* NOESCSEQ */ #endif /* NOARROWKEYS */ #undef CKUCMD_C _PROTOTYP( int nlookup, (struct keytab [], char *, int, int *) ); _PROTOTYP( int unhex, (char) ); _PROTOTYP( static VOID cmdclrscn, (void) ); #ifdef CKLEARN _PROTOTYP( VOID learncmd, (char *) ); #endif /* CKLEARN */ static char *moname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static char *fullmonthname[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; struct keytab cmonths[] = { { "april", 4, 0 }, { "august", 8, 0 }, { "december", 12, 0 }, { "february", 2, 0 }, { "january", 1, 0 }, { "july", 7, 0 }, { "june", 6, 0 }, { "march", 3, 0 }, { "may", 5, 0 }, { "november", 11, 0 }, { "october", 10, 0 }, { "september", 9, 0 } }; #ifndef NOICP /* The rest only if interactive command parsing selected */ #ifndef NOSPL _PROTOTYP( int chkvar, (char *) ); extern int askflag, echostars; #endif /* NOSPL */ #ifdef CKROOT extern int ckrooterr; #endif /* CKROOT */ #ifdef IKSD extern int inserver; #endif /* IKSD */ int cmfldflgs = 0; /* Flags for cmfld() */ int cmkwflgs = 0; /* Flags from last keyword parse */ static int nomsg = 0; static int blocklvl = 0; /* Block nesting level */ static int linebegin = 0; /* Flag for at start of a line */ static int quoting = 1; /* Quoting is allowed */ static int swarg = 0; /* Parsing a switch argument */ static int xcmfdb = 0; /* Flag for parsing chained fdbs... */ static int chsrc = 0; /* Source of character, 1 = tty */ static int newcmd = 0; /* See addcmd() */ #ifdef BS_DIRSEP static int dirnamflg = 0; #endif /* BS_DIRSEP */ /* Modeled after the DECSYSTEM-20 command parser (the COMND JSYS), RIP. Features: . parses and verifies keywords, filenames, text strings, numbers, other data . displays appropriate menu or help message when user types "?" . does keyword and filename completion when user types ESC or TAB . does partial keyword and filename completion . accepts any unique abbreviation for a keyword . allows keywords to have attributes, like "invisible" and "abbreviation" . can supply defaults for fields omitted by user . provides command retry and recall . provides character, word, and line deletion (but only from the end) . accepts input from keyboard, command files, macros, or redirected stdin . allows for full or half duplex operation, character or line input . allows \-escapes for special characters . allows specification of a user exit to expand variables, etc. . settable prompt, protected from deletion, dynamically re-evaluated each time . allows chained parse functions. Functions: cmsetp - Set prompt (cmprom is prompt string) cmsavp - Save current prompt cmgetp = Get current prompt prompt - Issue prompt cmini - Clear the command buffer (before parsing a new command) cmres - Reset command buffer pointers (before reparsing) cmkey - Parse a keyword or token (also cmkey2) cmswi - Parse a switch cmnum - Parse a number cmifi - Parse an input file name cmofi - Parse an output file name (also cmifip, cmifi2, ...) cmdir - Parse a directory name (also cmdirp) cmfld - Parse an arbitrary field cmtxt - Parse a text string cmdate - Parse a date-time string cmcfm - Parse command confirmation (end of line) cmfdb - Parse any of a list of the foregoing (chained parse functions) Return codes: -9: like -2 except this module already printed the error message -3: no input provided when required -2: input was invalid (e.g. not a number when a number was required) -1: reparse required (user deleted into a preceding field) 0 or greater: success See individual functions for greater detail. Before using these routines, the caller should #include "ckucmd.h" and set the program's prompt by calling cmsetp(). If the file parsing functions cmifi, cmofi, or cmdir are to be used, this module must be linked with a ck?fio file system support module for the appropriate system, e.g. ckufio for Unix. If the caller puts the terminal in character wakeup ("cbreak") mode with no echo, then these functions will provide line editing -- character, word, and line deletion, as well as keyword and filename completion upon ESC and help strings, keyword, or file menus upon '?'. If the caller puts the terminal into character wakeup/noecho mode, care should be taken to restore it before exit from or interruption of the program. If the character wakeup mode is not set, the system's own line editor may be used. NOTE: Contrary to expectations, many #ifdef's have been added to this module. Any operation requiring an #ifdef (like clear screen, get character from keyboard, erase character from screen, etc) should eventually be turned into a call to a function that is defined in ck?tio.c, but then all the ck?tio.c modules would have to be changed... */ /* Includes */ #include "ckcker.h" #include "ckcasc.h" /* ASCII character symbols */ #include "ckucmd.h" /* Command parsing definitions */ #ifdef OSF13 #ifdef CK_ANSIC #ifdef _NO_PROTO #undef _NO_PROTO #endif /* _NO_PROTO */ #endif /* CK_ANSIC */ #endif /* OSF13 */ #ifndef OS2 #ifndef HPUXPRE65 #include /* Error number symbols */ #else #ifndef ERRNO_INCLUDED #include /* Error number symbols */ #endif /* ERRNO_INCLUDED */ #endif /* HPUXPRE65 */ #endif /* OS2 */ /* Error number symbols - any compiler targeting Windows * and non-watcom compilers targeting OS/2. */ #ifdef OS2 #ifdef NT #include #else /* NT */ #ifndef __WATCOMC__ #include #endif /* __WATCOMC__ */ #endif /* NT */ #endif /* OS2 */ #ifdef OS2 #ifndef NT #define INCL_NOPM #define INCL_VIO /* Needed for ckocon.h */ #include #undef COMMENT #else #define APIRET ULONG #include #endif /* NT */ #include "ckocon.h" #include #endif /* OS2 */ #ifdef OSK #define cc ccount /* OS-9/68K compiler bug */ #endif /* OSK */ #ifdef GEMDOS /* Atari ST */ #ifdef putchar #undef putchar #endif /* putchar */ #define putchar(x) conoc(x) #endif /* GEMDOS */ #ifdef CK_AUTODL extern int cmdadl, justone; #endif /* CK_AUTODL */ extern int timelimit, nzxopts, nopush, nolocal, xcmdsrc, keepallchars; #ifdef CKSYSLOG #ifdef UNIX #ifdef CKXPRINTF /* Our printf macro conflicts with */ #undef printf /* use of "printf" in syslog.h */ #endif /* CKXPRINTF */ #ifdef RTAIX #include #else /* RTAIX */ #include #endif /* RTAIX */ #ifdef CKXPRINTF #define printf ckxprintf #endif /* CKXPRINTF */ #endif /* UNIX */ #endif /* CKSYSLOG */ /* This block moved here from further down 24 March 2023 */ #include "ckcdeb.h" #include "ckucmd.h" #include "ckcasc.h" #include "ckcfnp.h" /* Prototypes (must be last) */ /* Local variables */ static int psetf = 0, /* Flag that prompt has been set */ cc = 0, /* Character count */ dpx = 0, /* Duplex (0 = full) */ inword = 0; /* In the middle of getting a word */ char *dfprom = "Command? "; /* Default prompt */ #ifndef NOLASTFILE char *lastfile = NULL; /* Last filespec */ static char *tmplastfile = NULL; /* Last filespec candidate */ #endif /* NOLASTFILE */ int cmflgs; /* Command flags */ int cmfsav; /* A saved version of them */ static char pushc = NUL; static char brkchar = NUL; #define CMDEFAULT 1023 static char cmdefault[CMDEFAULT+1]; #ifdef DCMDBUF char *cmdbuf = NULL; /* Command buffer */ char *savbuf = NULL; /* Buffer to save copy of command */ char *atmbuf = NULL; /* Atom buffer - for current field */ char *atxbuf = NULL; /* For expanding the atom buffer */ char *prevcmd = NULL; static char *atybuf = NULL; /* For copying atom buffer */ static char *filbuf = NULL; /* File name buffer */ static char *cmprom = NULL; /* Program's prompt */ static char *cmprxx = NULL; /* Program's prompt, unevaluated */ #ifdef CK_RECALL /* Command recall is available only if we can make profligate use of malloc(). */ #define R_MAX 10 /* How many commands to save */ int cm_recall = R_MAX; /* Size of command recall buffer */ int on_recall = 1; /* Recall feature is ON */ static int no_recall = 0; /* Recall OFF for this cmd only */ static int force_add = 0; /* Force cmd into recall buffer */ static int last_recall = -1; /* Last recall-related action */ /* -1 = none 0 = CR (a command was entered) 1 = Up 2 = Down */ int in_recall = 0; /* Recall buffers are init'd */ static int current = -1, /* Pointer to current command */ rlast = -1; /* Index of last command in buffer */ static char **recall = NULL; /* Array of recall buffer pointers */ #endif /* CK_RECALL */ #else /* !DCMDBUF */ char cmdbuf[CMDBL+4]; /* Command buffer */ char savbuf[CMDBL+4]; /* Buffer to save copy of command */ char atmbuf[ATMBL+4]; /* Atom buffer */ char atxbuf[CMDBL+4]; /* For expanding the atom buffer */ char prevcmd[CMDBL+4]; /* For displaying the last command */ static char atybuf[ATMBL+4]; /* For copying atom buffer */ static char filbuf[ATMBL+4]; /* File name buffer */ static char cmprom[PROMPTL+1]; /* Program's prompt */ static char cmprxx[PROMPTL+1]; /* Program's prompt, unevaluated */ #endif /* DCMDBUF */ /* Command buffer pointers */ #define PPVLEN VNAML /* 20080305 Wolfram Sang (was 24) */ char ppvnambuf[PPVLEN+1] = { NUL, NUL }; char * cmbptr = NULL; /* Current position (for export) */ static char *bp, /* Current command buffer position */ *pp, /* Start of current field */ *np; /* Start of next field */ static int ungw, /* For ungetting words */ atxn; /* Expansion buffer (atxbuf) length */ #ifdef OS2 extern int wideresult; #endif /* OS2 */ extern int cmd_cols, cmd_rows, local, quiet; #ifdef TNCODE #ifdef IAC #undef IAC #endif /* IAC */ #define IAC 255 #endif /* TNCODE */ _PROTOTYP( static int gtword, (int) ); _PROTOTYP( static int addbuf, (char *) ); _PROTOTYP( static int setatm, (char *, int) ); _PROTOTYP( static VOID cmdnewl, (char) ); _PROTOTYP( static VOID cmdchardel, (void) ); _PROTOTYP( static VOID cmdecho, (char, int) ); _PROTOTYP( static int test, (int, int) ); #ifdef GEMDOS _PROTOTYP( extern char *strchr, (char *, int) ); #endif /* GEMDOS */ extern char * dftty; /* The following are for use with chained FDB's */ static int crflag = 0; /* Carriage return was typed */ static int qmflag = 0; /* Question mark was typed */ static int esflag = 0; /* Escape was typed */ /* Directory separator */ #ifdef GEMDOS static char dirsep = '\\'; #else #ifdef datageneral static char dirsep = ':'; #else #ifdef MAC static char dirsep = ':'; #else #ifdef VMS static char dirsep = '.'; #else #ifdef STRATUS static char dirsep = '>'; #else static char dirsep = '/'; /* UNIX, OS/2, OS-9, Amiga, etc. */ #endif /* STRATUS */ #endif /* VMS */ #endif /* MAC */ #endif /* datageneral */ #endif /* GEMDOS */ /* H A S N O P A T H */ /* Returns 0 if filespec s includes any path segments; 1 if it doesn't. */ int #ifdef CK_ANSIC hasnopath(char * s) #else hasnopath(s) char * s; #endif /* CK_ANSIC */ { char * p = NULL; if (!s) return(0); if (!*s) return(0); zstrip(s,&p); return(ckstrcmp(s,p,CKMAXPATH,filecase) == 0 ? 1 : 0); } /* C K S P R E A D -- Print string double-spaced */ #ifdef CK_ANSIC /* static function prototypes - fdc 30 November 2022 */ static char * ckspread( char * ); #endif /* CK_ANSIC */ static char * sprptr = NULL; static char * #ifdef CK_ANSIC ckspread( char * s ) #else ckspread(s) char * s; #endif /* CK_ANSIC */ { int n = 0; char * p; n = strlen(s); if (sprptr) free(sprptr); sprptr = malloc(n + n + 3); if (sprptr) { p = sprptr; while (*s) { *p++ = *s++; *p++ = SP; } *p = NUL; } return(sprptr ? sprptr : ""); } /* T E S T -- Bit test */ #ifdef CK_ANSIC static int test( int, int ); #endif /* CK_ANSIC */ static int #ifdef CK_ANSIC test( int x, int m ) #else test(x,m) int x, m; #endif /* CK_ANSIC */ { /* Returns 1 if any bits from m are on in x, else 0 */ return((x & m) ? 1 : 0); } /* K W D H E L P -- Given a keyword table, print keywords in columns. */ /* Call with: s - keyword table n - number of entries pat - pattern (left substring) that must match for each keyword pre - prefix to add to each keyword post - suffix to add to each keyword off - offset on first screenful, allowing room for introductory text xhlp - 1 to print any CM_INV keywords that are not also abbreviations. 2 to print CM_INV keywords if CM_HLP also set 4 if it's a switch table (to show ':' if CM_ARG) 8 print any keywords that CONTAIN the pattern Arranges keywords in columns with width based on longest keyword. Does "more?" prompting at end of screen. Uses global cmd_rows and cmd_cols for screen size. */ VOID #ifdef CK_ANSIC kwdhelp( struct keytab s[], int n, char *pat, char *pre, char *post, int off, int xhlp ) #else kwdhelp( s, n, pat, pre, post, off, xhlp ) struct keytab s[]; int n, off, xhlp; char *pat, *pre, *post; #endif /* CK_ANSIC */ /* kwdhelp */ { int width = 0; int cc; int cols, height, i, j, k, lc, n2 = 0; char *b = NULL, *p, *q; char *pa, *px; char **s2 = NULL; char *tmpbuf = NULL; cc = strlen(pat); if (!s) return; /* Nothing to do */ if (n < 1) return; /* Ditto */ if (off < 0) off = 0; /* Offset for first page */ if (!pre) pre = ""; /* Handle null string pointers */ if (!post) post = ""; lc = off; /* Screen-line counter */ if (xhlp & 4) /* For switches */ tmpbuf = (char *)malloc(TMPBUFSIZ+1); if ((s2 = (char **) malloc(n * sizeof(char *)))) { for (i = 0; i < n; i++) { /* Find longest keyword */ s2[i] = NULL; if (xhlp & 8) { if (ckindex(pat,s[i].kwd,0,0,0) < 1) /* for SHOW FUNCTIONS */ continue; } else if (ckstrcmp(s[i].kwd,pat,cc,0)) /* for regular keywords */ continue; if (s[i].flgs & CM_PSH /* NOPUSH or nopush screening */ #ifndef NOPUSH && nopush #endif /* NOPUSH */ ) continue; if (s[i].flgs & CM_LOC /* NOLOCAL or nolocal screening */ #ifndef NOLOCAL && nolocal #endif /* NOLOCAL */ ) continue; if (s[i].flgs & CM_INV) { #ifdef COMMENT /* This code does not show invisible keywords at all except for "help ?" */ /* and then only help topics (CM_HLP) in the top-level keyword list. */ if ((xhlp & 2) == 0) continue; else if ((s[i].flgs & CM_HLP) == 0) continue; #else /* This code shows invisible keywords that are not also abbreviations when */ /* ? was typed AFTER the beginning of the field so the user can find out */ /* what they are and (for example) why completion doesn't work at this point */ if (s[i].flgs & CM_ABR) continue; else if ((xhlp & 3) == 0) continue; else if ((xhlp & 2) && ((s[i].flgs & CM_HLP) == 0)) continue; #endif /* COMMENT */ } j = strlen(s[i].kwd); if (!(xhlp & 4) || !tmpbuf) { /* Regular keyword table */ s2[n2++] = s[i].kwd; /* Copy pointers to visible ones */ } else { /* Switches */ ckmakmsg(tmpbuf, /* Make a copy that shows ":" if */ TMPBUFSIZ, /* the switch takes an argument. */ s[i].kwd, (s[i].flgs & CM_ARG) ? ":" : "", NULL, NULL ); makestr(&(s2[n2]),tmpbuf); if (s[i].flgs & CM_ARG) j++; n2++; } if (j > width) width = j; } /* Column width */ n = n2; } if (s2 && (b = (char *) malloc(cmd_cols + 1))) { /* Make a line buffer */ char * bx; bx = b + cmd_cols; width += (int)strlen(pre) + (int)strlen(post) + 2; cols = cmd_cols / width; /* How many columns? */ if (cols < 1) cols = 1; height = n / cols; /* How long is each column? */ if (n % cols) height++; /* Add one for remainder, if any */ for (i = 0; i < height; i++) { /* Loop for each row */ for (j = 0; j < cmd_cols; j++) /* First fill row with blanks */ b[j] = SP; for (j = 0; j < cols; j++) { /* Loop for each column in row */ k = i + (j * height); /* Index of next keyword */ if (k < n) { /* In range? */ pa = pre; px = post; p = s2[k]; /* Point to verb name */ q = b + (j * width) + 1; /* Where to copy it to */ while ((q < bx) && (*q++ = *pa++)) ; /* Copy prefix */ q--; /* Back up over NUL */ while ((q < bx) && (*q++ = *p++)) ; /* Copy filename */ q--; /* Back up over NUL */ while ((q < bx) && (*q++ = *px++)) ; /* Copy suffix */ if (j < cols - 1) { q--; *q = SP; /* Replace the space */ } } } p = b + cmd_cols - 1; /* Last char in line */ while (*p-- == SP) ; /* Trim */ *(p+2) = NUL; printf("%s\n",b); /* Print the line */ if (++lc > (cmd_rows - 2)) { /* Screen full? */ if (!askmore()) /* Do more-prompting... */ goto xkwdhelp; else lc = 0; } } /* printf("\n"); */ /* Blank line at end of report */ } else { /* Malloc failure, no columns */ for (i = 0; i < n; i++) { if (s[i].flgs & CM_INV) /* Use original keyword table */ continue; /* skipping invisible entries */ printf("%s%s%s\n",pre,s[i].kwd,post); if (++lc > (cmd_rows - 2)) { /* Screen full? */ if (!askmore()) /* Do more-prompting... */ goto xkwdhelp; else lc = 0; } } } xkwdhelp: if (xhlp & 4) { if (tmpbuf) free((char *)tmpbuf); for (i = 0; i < n; i++) if (s2[i]) free(s2[i]); } if (s2) free(s2); /* Free array copy */ if (b) free(b); /* Free line buffer */ return; } /* X F I L H E L P -- Given a file list, print names in columns. */ /* Call with: n - number of entries pre - prefix to add to each filename post - suffix to add to each filename off - offset on first screenful, allowing room for introductory text cmdirflg - 1 if only directory names should be listed, 0 to list all files fs - call fileselect() to decide whether to include each file. The rest of the args are the same as for fileselect(). Arranges filenames in columns with width based on longest filename. Does "more?" prompting at end of screen. Uses global cmd_rows and cmd_cols for screen size. */ int #ifdef CK_ANSIC xfilhelp( int n, char *pre, char *post, int off, int cmdirflag, int fs, char *sa, char *sb, char *sna, char *snb, CK_OFF_T minsiz, CK_OFF_T maxsiz, int nbu, int nxlist, char ** xlist ) #else xfilhelp(n,pre,post,off,cmdirflg, fs,sa,sb,sna,snb,minsiz,maxsiz,nbu,nxlist,xlist) int n, off; char *pre, *post; int cmdirflg; int fs; char *sa,*sb,*sna,*snb; CK_OFF_T minsiz,maxsiz; int nbu,nxlist; char ** xlist; #endif /* CK_ANSIC */ { char filbuf[CKMAXPATH + 1]; /* Temp buffer for one filename */ int width = 0; int cols, height, i, j, k, lc, n2 = 0, rc = 0, itsadir = 0; char *b = NULL, *p, *q; char *pa, *px; char **s2 = NULL; #ifdef VMS char * cdp = zgtdir(); #endif /* VMS */ if (n < 1) return(0); if (off < 0) off = 0; /* Offset for first page */ if (!pre) pre = ""; /* Handle null string pointers */ if (!post) post = ""; lc = off; /* Screen-line counter */ if ((s2 = (char **) malloc(n * sizeof(char *)))) { for (i = 0; i < n; i++) { /* Loop through filenames */ itsadir = 0; s2[i] = NULL; /* Initialize each pointer to NULL */ znext(filbuf); /* Get next filename */ if (!filbuf[0]) /* Shouldn't happen */ break; #ifdef COMMENT itsadir = isdir(filbuf); /* Is it a directory? */ if (cmdirflg && !itsadir) /* No, listing directories only? */ continue; /* So skip this one. */ #endif /* COMMENT */ if (fs) if (fileselect(filbuf, sa,sb,sna,snb, minsiz,maxsiz,nbu,nxlist,xlist) < 1) { continue; } #ifdef VMS ckstrncpy(filbuf,zrelname(filbuf,cdp),CKMAXPATH); #endif /* VMS */ j = strlen(filbuf); #ifndef VMS if (itsadir && j < CKMAXPATH - 1 && j > 0) { if (filbuf[j-1] != dirsep) { filbuf[j++] = dirsep; filbuf[j] = NUL; } } #endif /* VMS */ if (!(s2[n2] = malloc(j+1))) { printf("?Memory allocation failure\n"); rc = -9; goto xfilhelp; } if (j <= CKMAXPATH) { strcpy(s2[n2],filbuf); n2++; } else { printf("?Name too long - %s\n", filbuf); rc = -9; goto xfilhelp; } if (j > width) /* Get width of widest one */ width = j; } n = n2; /* How many we actually got */ } sh_sort(s2,NULL,n,0,0,filecase); /* Alphabetize the list */ rc = 1; if (s2 && (b = (char *) malloc(cmd_cols + 1))) { /* Make a line buffer */ char * bx; bx = b + cmd_cols; width += (int)strlen(pre) + (int)strlen(post) + 2; cols = cmd_cols / width; /* How many columns? */ if (cols < 1) cols = 1; height = n / cols; /* How long is each column? */ if (n % cols) height++; /* Add one for remainder, if any */ for (i = 0; i < height; i++) { /* Loop for each row */ for (j = 0; j < cmd_cols; j++) /* First fill row with blanks */ b[j] = SP; for (j = 0; j < cols; j++) { /* Loop for each column in row */ k = i + (j * height); /* Index of next filename */ if (k < n) { /* In range? */ pa = pre; px = post; p = s2[k]; /* Point to filename */ q = b + (j * width) + 1; /* and destination */ while ((q < bx) && (*q++ = *pa++)) ; /* Copy prefix */ q--; /* Back up over NUL */ while ((q < bx) && (*q++ = *p++)) ; /* Copy filename */ q--; /* Back up over NUL */ while ((q < bx) && (*q++ = *px++)) ; /* Copy suffix */ if (j < cols - 1) { q--; *q = SP; /* Replace the space */ } } } p = b + cmd_cols - 1; /* Last char in line */ while (*p-- == SP) ; /* Trim */ *(p+2) = NUL; printf("%s\n",b); /* Print the line */ if (++lc > (cmd_rows - 2)) { /* Screen full? */ if (!askmore()) { /* Do more-prompting... */ rc = 0; goto xfilhelp; } else lc = 0; } } printf("\n"); /* Blank line at end of report */ goto xfilhelp; } else { /* Malloc failure, no columns */ for (i = 0; i < n; i++) { znext(filbuf); if (!filbuf[0]) break; printf("%s%s%s\n",pre,filbuf,post); if (++lc > (cmd_rows - 2)) { /* Screen full? */ if (!askmore()) { /* Do more-prompting... */ rc = 0; goto xfilhelp; } else lc = 0; } } xfilhelp: if (b) free(b); for (i = 0; i < n2; i++) if (s2[i]) free(s2[i]); if (s2) free((char *)s2); return(rc); } } /* Simpler front end for xfilhelp() with shorter arg list when no file selection is needed. */ int #ifdef CK_ANSIC filhelp( int n, char * pre, char * post, int off, int cmdirflg ) #else filhelp(n,pre,post,off,cmdirflg) int n, off; char *pre, *post; int cmdirflg; #endif /* CK_ANSIC */ { /* filhelp */ return(xfilhelp(n,pre,post,off,cmdirflg, 0,NULL,NULL,NULL,NULL, (CK_OFF_T)0,(CK_OFF_T)0,0,0,(char **)NULL)); } /* C M S E T U P -- Set up command buffers */ #ifdef DCMDBUF int cmsetup() { if (!(cmdbuf = malloc(CMDBL + 4))) return(-1); if (!(savbuf = malloc(CMDBL + 4))) return(-1); savbuf[0] = '\0'; if (!(prevcmd = malloc(CMDBL + 4))) return(-1); prevcmd[0] = '\0'; if (!(atmbuf = malloc(ATMBL + 4))) return(-1); if (!(atxbuf = malloc(CMDBL + 4))) return(-1); if (!(atybuf = malloc(ATMBL + 4))) return(-1); if (!(filbuf = malloc(ATMBL + 4))) return(-1); if (!(cmprom = malloc(PROMPTL + 4))) return(-1); if (!(cmprxx = malloc(PROMPTL + 4))) return(-1); #ifdef CK_RECALL cmrini(cm_recall); #endif /* CK_RECALL */ return(0); } #endif /* DCMDBUF */ /* C M S E T P -- Set the program prompt. */ VOID #ifdef CK_ANSIC cmsetp( char * s ) #else cmsetp(s) char *s; #endif /* CK_ANSIC */ { if (!s) s = ""; ckstrncpy(cmprxx,s,PROMPTL); psetf = 1; /* Flag that prompt has been set. */ } /* C M S A V P -- Save a copy of the current prompt. */ VOID #ifdef CK_ANSIC cmsavp(char s[], int n) #else cmsavp(s,n) char s[]; int n; #endif /* CK_ANSIC */ /* cmsavp */ { if (psetf) /* But not if no prompt is set. */ ckstrncpy(s,cmprxx,n); } char * cmgetp() { return(cmprxx); } int cmgbrk() { return(brkchar); } int cmgkwflgs() { return(cmkwflgs); } /* P R O M P T -- Issue the program prompt. */ VOID #ifdef CK_ANSIC prompt( xx_strp f ) #else prompt(f) xx_strp f; #endif /* CK_ANSIC */ { char *sx, *sy; int n; #ifdef CK_SSL extern int ssl_active_flag, tls_active_flag; #endif /* CK_SSL */ if (psetf == 0) /* If no prompt set, set default. */ cmsetp(dfprom); sx = cmprxx; /* Unevaluated copy */ if (f) { /* If conversion function given */ sy = cmprom; /* Evaluate it */ #ifdef COMMENT debug(F101,"prompt sx","",sx); debug(F101,"prompt sy","",sy); #endif /* COMMENT */ n = PROMPTL; if ((*f)(sx,&sy,&n) < 0) /* If evaluation failed */ sx = cmprxx; /* revert to unevaluated copy */ else if (!*cmprom) /* ditto if it came up empty */ sx = cmprxx; else sx = cmprom; } else ckstrncpy(cmprom,sx,PROMPTL); cmprom[PROMPTL-1] = NUL; if (!*sx) /* Don't print if empty */ return; #ifdef OSK fputs(sx, stdout); #else #ifdef MAC printf("%s", sx); #else #ifdef IKSD if (inserver) { /* Print the prompt. */ ttoc(CK_CR); /* If TELNET Server */ ttoc(NUL); /* must folloW CR by NUL */ printf("%s",sx); } else #endif /* IKSD */ printf("\r%s",sx); #ifdef CK_SSL if (!(ssl_active_flag || tls_active_flag)) #endif /* CK_SSL */ fflush(stdout); /* Now! */ #endif /* MAC */ #endif /* OSK */ } #ifndef NOSPL VOID #ifdef CK_ANSIC pushcmd( char * s) /* For use with IF command. */ #else pushcmd( s ) char * s; #endif /* CK_ANSIC */ { if (!s) s = np; ckstrncpy(savbuf,s,CMDBL); /* Save the dependent clause, */ cmres(); /* and clear the command buffer. */ debug(F110, "pushcmd savbuf", savbuf, 0); } VOID #ifdef CK_ANSIC pushqcmd( char * s ) /* For use with ELSE command. */ #else pushqcmd(s) char * s; #endif /* CK_ANSIC */ { char c, * p = savbuf; /* Dest */ if (!s) s = np; /* Source */ while (*s) { /* Get first nonwhitespace char */ if (*s != SP) break; else s++; } if (*s != '{') { /* If it's not "{" */ pushcmd(s); /* do regular pushcmd */ return; } while ((c = *s++)) { /* Otherwise insert quotes */ if (c == CMDQ) *p++ = CMDQ; *p++ = c; } cmres(); /* and clear the command buffer. */ debug(F110, "pushqcmd savbuf", savbuf, 0); } #endif /* NOSPL */ #ifdef COMMENT /* no longer used... */ VOID popcmd() { ckstrncpy(cmdbuf,savbuf,CMDBL); /* Put back the saved material */ *savbuf = '\0'; /* and clear the save buffer */ cmres(); } #endif /* COMMENT */ /* C M R E S -- Reset pointers to beginning of command buffer. */ VOID cmres() { inword = 0; /* We're not in a word */ cc = 0; /* Character count is zero */ /* Initialize pointers */ pp = cmdbuf; /* Beginning of current field */ bp = cmdbuf; /* Current position within buffer */ np = cmdbuf; /* Where to start next field */ cmfldflgs = 0; cmflgs = -5; /* Parse not yet started. */ ungw = 0; /* Don't need to unget a word. */ } /* C M I N I -- Clear the command and atom buffers, reset pointers. */ /* The argument specifies who is to echo the user's typein -- 1 means the cmd package echoes 0 somebody else (system, front end, terminal) echoes */ VOID #ifdef CK_ANSIC cmini( int d ) #else cmini(d) int d; #endif /* CK_ANSIC */ { /* cmini */ #ifdef DCMDBUF if (!atmbuf) if (cmsetup()<0) fatal("fatal error: unable to allocate command buffers"); #endif /* DCMDBUF */ #ifdef USE_MEMCPY memset(cmdbuf,0,CMDBL); memset(atmbuf,0,ATMBL); #else for (bp = cmdbuf; bp < cmdbuf+CMDBL; bp++) *bp = NUL; for (bp = atmbuf; bp < atmbuf+ATMBL; bp++) *bp = NUL; #endif /* USE_MEMCPY */ *atmbuf = *savbuf = *atxbuf = *atybuf = *filbuf = NUL; blocklvl = 0; /* Block level is 0 */ linebegin = 1; /* At the beginning of a line */ dpx = d; /* Global copy of the echo flag */ debug(F101,"cmini dpx","",dpx); crflag = 0; /* Reset flags */ qmflag = 0; esflag = 0; #ifdef CK_RECALL no_recall = 0; /* Start out with recall enabled */ #endif /* CK_RECALL */ cmres(); /* Sets bp etc */ newcmd = 1; /* See addcmd() */ } #ifndef NOSPL /* The following bits are to allow the command package to call itself in the middle of a parse. To do this, begin by calling cmpush, and end by calling cmpop. As you can see, this is rather expensive. */ #ifdef DCMDBUF struct cmp { int i[5]; /* stack for integers */ char *c[3]; /* stack for pointers */ char *b[8]; /* stack for buffer contents */ }; struct cmp *cmp = 0; #else int cmp_i[CMDDEP+1][5]; /* Stack for integers */ char *cmp_c[CMDDEP+1][5]; /* for misc pointers */ char *cmp_b[CMDDEP+1][7]; /* for buffer contents pointers */ #endif /* DCMDBUF */ int cmddep = -1; /* Current stack depth */ int cmpush() { /* Save the command environment */ char *cp; /* Character pointer */ if (cmddep >= CMDDEP) /* Enter a new command depth */ return(-1); cmddep++; debug(F101,"&cmpush to depth","",cmddep); #ifdef DCMDBUF /* allocate memory for cmp if not already done */ if (!cmp && !(cmp = (struct cmp *) malloc(sizeof(struct cmp)*(CMDDEP+1)))) fatal("cmpush: no memory for cmp"); cmp[cmddep].i[0] = cmflgs; /* First do the global ints */ cmp[cmddep].i[1] = cmfsav; cmp[cmddep].i[2] = atxn; cmp[cmddep].i[3] = ungw; cmp[cmddep].c[0] = bp; /* Then the global pointers */ cmp[cmddep].c[1] = pp; cmp[cmddep].c[2] = np; #else cmp_i[cmddep][0] = cmflgs; /* First do the global ints */ cmp_i[cmddep][1] = cmfsav; cmp_i[cmddep][2] = atxn; cmp_i[cmddep][3] = ungw; cmp_c[cmddep][0] = bp; /* Then the global pointers */ cmp_c[cmddep][1] = pp; cmp_c[cmddep][2] = np; #endif /* DCMDBUF */ /* Now the buffers themselves. A lot of repititious code... */ #ifdef DCMDBUF cp = malloc((int)strlen(cmdbuf)+1); /* 0: Command buffer */ if (cp) strcpy(cp,cmdbuf); cmp[cmddep].b[0] = cp; if (cp == NULL) return(-1); cp = malloc((int)strlen(savbuf)+1); /* 1: Save buffer */ if (cp) strcpy(cp,savbuf); cmp[cmddep].b[1] = cp; if (cp == NULL) return(-1); cmp[cmddep].b[2] = NULL; cp = malloc((int)strlen(atmbuf)+1); /* 3: Atom buffer */ if (cp) strcpy(cp,atmbuf); cmp[cmddep].b[3] = cp; if (cp == NULL) return(-1); cp = malloc((int)strlen(atxbuf)+1); /* 4: Expansion buffer */ if (cp) strcpy(cp,atxbuf); cmp[cmddep].b[4] = cp; if (cp == NULL) return(-1); cp = malloc((int)strlen(atybuf)+1); /* 5: Atom buffer copy */ if (cp) strcpy(cp,atybuf); cmp[cmddep].b[5] = cp; if (cp == NULL) return(-1); cp = malloc((int)strlen(filbuf)+1); /* 6: File name buffer */ if (cp) strcpy(cp,filbuf); cmp[cmddep].b[6] = cp; if (cp == NULL) return(-1); #else cp = malloc((int)strlen(cmdbuf)+1); /* 0: Command buffer */ if (cp) strcpy(cp,cmdbuf); cmp_b[cmddep][0] = cp; if (cp == NULL) return(-1); cp = malloc((int)strlen(savbuf)+1); /* 1: Save buffer */ if (cp) strcpy(cp,savbuf); cmp_b[cmddep][1] = cp; if (cp == NULL) return(-1); cmp_b[cmddep][2] = NULL; cp = malloc((int)strlen(atmbuf)+1); /* 3: Atom buffer */ if (cp) strcpy(cp,atmbuf); cmp_b[cmddep][3] = cp; if (cp == NULL) return(-1); cp = malloc((int)strlen(atxbuf)+1); /* 4: Expansion buffer */ if (cp) strcpy(cp,atxbuf); cmp_b[cmddep][4] = cp; if (cp == NULL) return(-1); cp = malloc((int)strlen(atybuf)+1); /* 5: Atom buffer copy */ if (cp) strcpy(cp,atybuf); cmp_b[cmddep][5] = cp; if (cp == NULL) return(-1); cp = malloc((int)strlen(filbuf)+1); /* 6: File name buffer */ if (cp) strcpy(cp,filbuf); cmp_b[cmddep][6] = cp; if (cp == NULL) return(-1); #endif /* DCMDBUF */ cmini(dpx); /* Initize the command parser */ return(0); } int cmpop() { /* Restore the command environment */ if (cmddep < 0) { debug(F100,"&cmpop called from top level","",0); return(-1); /* Don't pop too much! */ } #ifdef DCMDBUF cmflgs = cmp[cmddep].i[0]; /* First do the global ints */ cmfsav = cmp[cmddep].i[1]; atxn = cmp[cmddep].i[2]; ungw = cmp[cmddep].i[3]; bp = cmp[cmddep].c[0]; /* Then the global pointers */ pp = cmp[cmddep].c[1]; np = cmp[cmddep].c[2]; #else cmflgs = cmp_i[cmddep][0]; /* First do the global ints */ cmfsav = cmp_i[cmddep][1]; atxn = cmp_i[cmddep][2]; ungw = cmp_i[cmddep][3]; bp = cmp_c[cmddep][0]; /* Then the global pointers */ pp = cmp_c[cmddep][1]; np = cmp_c[cmddep][2]; #endif /* DCMDBUF */ /* Now the buffers themselves. */ /* Note: strncpy(), not ckstrncpy() -- Here we WANT the NUL padding... */ #ifdef DCMDBUF if (cmp[cmddep].b[0]) { strncpy(cmdbuf,cmp[cmddep].b[0],CMDBL); /* 0: Command buffer */ free(cmp[cmddep].b[0]); cmp[cmddep].b[0] = NULL; } if (cmp[cmddep].b[1]) { strncpy(savbuf,cmp[cmddep].b[1],CMDBL); /* 1: Save buffer */ free(cmp[cmddep].b[1]); cmp[cmddep].b[1] = NULL; } if (cmp[cmddep].b[3]) { strncpy(atmbuf,cmp[cmddep].b[3],ATMBL); /* 3: Atomic buffer! */ free(cmp[cmddep].b[3]); cmp[cmddep].b[3] = NULL; } if (cmp[cmddep].b[4]) { strncpy(atxbuf,cmp[cmddep].b[4],ATMBL); /* 4: eXpansion buffer */ free(cmp[cmddep].b[4]); cmp[cmddep].b[4] = NULL; } if (cmp[cmddep].b[5]) { strncpy(atybuf,cmp[cmddep].b[5],ATMBL); /* 5: Atom buffer copY */ free(cmp[cmddep].b[5]); cmp[cmddep].b[5] = NULL; } if (cmp[cmddep].b[6]) { strncpy(filbuf,cmp[cmddep].b[6],ATMBL); /* 6: Filename buffer */ free(cmp[cmddep].b[6]); cmp[cmddep].b[6] = NULL; } #else if (cmp_b[cmddep][0]) { strncpy(cmdbuf,cmp_b[cmddep][0],CMDBL); /* 0: Command buffer */ free(cmp_b[cmddep][0]); cmp_b[cmddep][0] = NULL; } if (cmp_b[cmddep][1]) { strncpy(savbuf,cmp_b[cmddep][1],CMDBL); /* 1: Save buffer */ free(cmp_b[cmddep][1]); cmp_b[cmddep][1] = NULL; } if (cmp_b[cmddep][3]) { strncpy(atmbuf,cmp_b[cmddep][3],ATMBL); /* 3: Atomic buffer! */ free(cmp_b[cmddep][3]); cmp_b[cmddep][3] = NULL; } if (cmp_b[cmddep][4]) { strncpy(atxbuf,cmp_b[cmddep][4],ATMBL); /* 4: eXpansion buffer */ free(cmp_b[cmddep][4]); cmp_b[cmddep][4] = NULL; } if (cmp_b[cmddep][5]) { strncpy(atybuf,cmp_b[cmddep][5],ATMBL); /* 5: Atom buffer copY */ free(cmp_b[cmddep][5]); cmp_b[cmddep][5] = NULL; } if (cmp_b[cmddep][6]) { strncpy(filbuf,cmp_b[cmddep][6],ATMBL); /* 6: Filename buffer */ free(cmp_b[cmddep][6]); cmp_b[cmddep][6] = NULL; } #endif /* DCMDBUF */ cmddep--; /* Rise, rise */ debug(F101,"&cmpop to depth","",cmddep); return(cmddep); } #endif /* NOSPL */ #ifdef COMMENT VOID /* Not used */ stripq(s) char *s; { /* Function to strip '\' quotes */ char *t; while (*s) { if (*s == CMDQ) { for (t = s; *t != '\0'; t++) *t = *(t+1); } s++; } } #endif /* COMMENT */ /* Convert tabs to spaces, one for one */ VOID #ifdef CK_ANSIC untab( char * s ) #else untab(s) char *s; #endif /* CK_ANSIC */ { /* untab */ while (*s) { if (*s == HT) *s = SP; s++; } } /* C M N U M -- Parse a number in the indicated radix */ /* The radix is specified in the arg list. Parses unquoted numeric strings in the given radix. Parses backslash-quoted numbers in the radix indicated by the quote: \nnn = \dnnn = decimal, \onnn = octal, \xnn = Hexadecimal. If these fail, then if a preprocessing function is supplied, that is applied and then a second attempt is made to parse an unquoted decimal string. And if that fails, the preprocessed string is passed to an arithmetic expression evaluator. Returns: -3 if no input present when required, -2 if user typed an illegal number, -1 if reparse needed, 0 otherwise, with argument n set to the number that was parsed */ /* This is the traditional cmnum() that gets an int */ int #ifdef CK_ANSIC cmnum( char * xhlp, char * xdef, int radix, int * n, xx_strp f ) #else cmnum(xhlp,xdef,radix,n,f) char *xhlp, *xdef; int radix, *n; xx_strp f; #endif /* CK_ANSIC */ { CK_OFF_T z = (CK_OFF_T)0, check; int x; x = cmnumw(xhlp,xdef,radix,&z,f); *n = z; check = *n; if (check != z) { printf("?Magnitude of result too large for integer - %s\n",ckfstoa(z)); return(-9); } return(x); } /* This is the new cmnum() that gets a "wide" result, whatever CK_OFF_T is defined to be, normally 32 or 64 bits, depending on the platform. fdc, 24 Dec 2005. */ int #ifdef CK_ANSIC cmnumw( char * xhlp, char * xdef, int radix, CK_OFF_T * n, xx_strp f ) #else cmnumw(xhlp,xdef,radix,n,f) char *xhlp, *xdef; int radix; CK_OFF_T *n; xx_strp f; #endif /* CK_ANSIC */ { /* cmnumw */ int x; char *s, *zp, *zq; #ifdef COMMENT char lbrace, rbrace; #endif /* COMMENT */ if (!xhlp) xhlp = ""; if (!xdef) xdef = ""; #ifdef COMMENT if (cmfldflgs & 1) { lbrace = '('; rbrace = ')'; } else { lbrace = '{'; rbrace = '}'; } #endif /* COMMENT */ if (radix != 10 && radix != 8) { /* Just do bases 8 and 10 */ printf("cmnum: illegal radix - %d\n",radix); return(-2); } /* Easy to add others but there has never been a need for it. */ x = cmfld(xhlp,xdef,&s,(xx_strp)0); debug(F101,"cmnum: cmfld","",x); if (x < 0) return(x); /* Parse a field */ zp = atmbuf; /* Edit 192 - Allow any number field to be braced. This lets us include spaces in expressions, but perhaps more important lets us have user-defined functions in numeric fields. */ zp = brstrip(zp); /* Strip braces */ if (cmfldflgs & 1 && *zp == '(') { /* Parens too.. */ x = (int) strlen(atmbuf); if (x > 0) { if (*(atmbuf+x-1) == ')') { *(atmbuf+x-1) = NUL; zp++; } } } if (chknum(zp)) { /* Check for number */ if (radix == 8) { /* If it's supposed to be octal */ zp = ckradix(zp,8,10); /* convert to decimal */ if (!zp) return(-2); if (!strcmp(zp,"-1")) return(-2); } errno = 0; /* Got one, we're done. */ *n = ckatofs(zp); if (errno) { perror(zp); return(-9); } debug(F101,"cmnum 1st chknum ok","",*n); return(0); } else if ((x = xxesc(&zp)) > -1) { /* Check for backslash escape */ #ifndef OS2 *n = x; #else *n = wideresult; #endif /* OS2 */ debug(F101,"cmnum xxesc ok","",*n); return(*zp ? -2 : 0); } else if (f) { /* If conversion function given */ zq = atxbuf; /* Try that */ atxn = CMDBL; if ((*f)(zp,&zq,&atxn) < 0) /* Convert */ return(-2); zp = atxbuf; } debug(F110,"cmnum zp 1",zp,0); if (!*zp) zp = xdef; /* Result empty, substitute default */ debug(F110,"cmnum zp 2",zp,0); if (chknum(zp)) { /* Check again for decimal number */ if (radix == 8) { /* If it's supposed to be octal */ zp = ckradix(zp,8,10); /* convert to decimal */ if (!zp) return(-2); if (!strcmp(zp,"-1")) return(-2); } errno = 0; *n = ckatofs(zp); if (errno) { perror(zp); return(-9); } debug(F101,"cmnum 2nd chknum ok","",*n); return(0); #ifndef NOSPL } else if ((x = xxesc(&zp)) > -1) { /* Check for backslash escape */ #ifndef OS2 *n = x; #else *n = wideresult; #endif /* OS2 */ debug(F101,"cmnum xxesc 2 ok","",*n); return(*zp ? -2 : 0); } else if (f) { /* Not numeric, maybe an expression */ char * p; p = evala(zp); if (chknum(p)) { if (radix == 8) { /* If it's supposed to be octal */ zp = ckradix(zp,8,10); /* convert to decimal */ if (!zp) return(-2); if (!strcmp(zp,"-1")) return(-2); } errno = 0; *n = ckatofs(p); if (errno) { perror(p); return(-9); } debug(F101,"cmnum exp eval ok","",*n); return(0); } else return(-2); #endif /* NOSPL */ } else { /* Not numeric */ return(-2); } } #ifdef CKCHANNELIO extern int z_error; #endif /* CKCHANNELIO */ /* C M O F I -- Parse the name of an output file */ /* Depends on the external function zchko(); if zchko() not available, use cmfld() to parse output file names. Returns: -9 like -2, except message already printed, -3 if no input present when required, -2 if permission would be denied to create the file, -1 if reparse needed, 0 or 1 if file can be created, with xp pointing to name. 2 if given the name of an existing directory. */ int #ifdef CK_ANSIC cmofi( char * xhlp, char * xdef, char ** xp, xx_strp f ) #else cmofi(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; #endif /* CK_ANSIC */ { int x; char *s, *zq; #ifdef DOCHKVAR int tries; #endif /* DOCHKVAR */ #ifdef DTILDE char *dirp; #endif /* DTILDE */ cmfldflgs = 0; if (!xhlp) xhlp = ""; if (!xdef) xdef = ""; if (*xhlp == NUL) xhlp = "Output file"; *xp = ""; debug(F110,"cmofi xdef",xdef,0); x = cmfld(xhlp,xdef,&s,(xx_strp)0); debug(F111,"cmofi cmfld returns",s,x); if (x < 0) return(x); s = brstrip(s); /* Strip enclosing braces */ debug(F110,"cmofi 1.5",s,0); #ifdef DOCHKVAR tries = 0; { char *p = s; /* This is really ugly. If we skip conversion the first time through, then variable names like \%a will be used as filenames (e.g. creating a file called %A in the root directory). If we DON'T skip conversion the first time through, then single backslashes used as directory separators in filenames will be misinterpreted as variable lead-ins. So we prescan to see if it has any variable references. But this module is not supposed to know anything about variables, functions, etc, so this code does not really belong here, but rather it should be at the same level as zzstring(). */ /* Hmmm, this looks a lot like chkvar() except it that includes \nnn number escapes. But why? This makes commands like "mkdir c:\123" impossible. And in fact, "mkdir c:\123" creates a directory called "c:{". What's worse, rmdir(), which *does* call chkvar(), won't let us remove it. So let's at least try making cmofi() symmetrical with cmifi()... */ #ifdef COMMENT char * q; while ( (tries == 0) && (p = strchr(p,CMDQ)) ) { q = *(p+1); /* Char after backslash */ if (!q) /* None, quit */ break; if (isupper(q)) /* If letter, convert to lowercase */ q = tolower(q); if (isdigit(q)) { /* If it's a digit, */ tries = 1; /* assume it's a backslash code */ break; } switch (q) { case CMDQ: /* Double backslash */ tries = 1; /* so call the conversion function */ break; case '%': /* Variable or array reference */ case '&': /* must be followed by letter */ if (isalpha(*(p+2)) || (*(p+2) >= '0' && *(p+2) <= '9')) tries = 1; break; case 'm': case 'v': case '$': /* \m(), \v(), \$() */ if (*(p+2) == '(') if (strchr(p+2,')')) tries = 1; break; case 'f': /* \Fname() */ if (strchr(p+2,'(')) if (strchr(p+2,')')) tries = 1; break; case '{': /* \{...} */ if (strchr(p+2,'}')) tries = 1; break; case 'd': case 'o': /* Decimal or Octal number */ if (isdigit(*(p+2))) tries = 1; break; case 'x': /* Hex number */ if (isdigit(*(p+2)) || ((*(p+2) >= 'a' && *(p+2) <= 'f') || ((*(p+2) >= 'A' && *(p+2) <= 'F')))) tries = 1; default: break; } p++; } #else #ifndef NOSPL if (f) { /* If a conversion function is given */ char *s = p; /* See if there are any variables in */ while (*s) { /* the string and if so, expand them */ if (chkvar(s)) { tries = 1; break; } s++; } } #endif /* NOSPL */ #endif /* COMMENT */ } #ifdef OS2 #ifdef COMMENT o_again: #endif /* COMMENT */ #endif /* OS2 */ if (tries == 1) #endif /* DOCHKVAR */ if (f) { /* If a conversion function is given */ zq = atxbuf; /* do the conversion. */ atxn = CMDBL; if ((x = (*f)(s,&zq,&atxn)) < 0) return(-2); s = atxbuf; if (!*s) /* Result empty, substitute default */ s = xdef; } debug(F111,"cmofi 2",s,x); #ifdef DTILDE dirp = tilde_expand(s); /* Expand tilde, if any, */ if (*dirp != '\0') { /* right in the atom buffer. */ if (setatm(dirp,1) < 0) { printf("?Name too long\n"); return(-9); } } s = atmbuf; debug(F110,"cmofi 3",s,0); #endif /* DTILDE */ if (iswild(s)) { printf("?Wildcards not allowed - %s\n",s); return(-2); } debug(F110,"cmofi 4",s,0); #ifdef CK_TMPDIR /* isdir() function required for this! */ if (isdir(s)) { debug(F110,"cmofi 5: is directory",s,0); *xp = s; return(2); } #endif /* CK_TMPDIR */ /* Fixed 19 September 2023 by Piotr Kolasinski */ /* Previously: if (strcmp(s,CTTNAM) && (zchko(s) < 0)) */ if ((strcmp(s,CTTNAM) == 0) && (zchko(s) < 0)) { /* write to console OK */ #ifdef COMMENT #ifdef OS2 /* We don't try again because we already prescanned the string to see if if it contained anything that could be used by zzstring(). */ if (tries++ < 1) goto o_again; #endif /* OS2 */ #endif /* COMMENT */ /* Note: there are certain circumstances where zchko() can give a false positive, so don't rely on it to catch every conceivable situation in which the given output file can't be created. In other words, we print a message and fail here if we KNOW the file can't be created. If we succeed but the file can't be opened, the code that tries to open the file has to print a message. */ debug(F110,"cmofi 6: failure",s,0); #ifdef CKROOT if (ckrooterr) printf("?Off Limits: %s\n",s); else #endif /* CKROOT */ printf("?Write permission denied - %s\n",s); #ifdef CKCHANNELIO z_error = FX_ACC; #endif /* CKCHANNELIO */ return(-9); } else { debug(F110,"cmofi 7: ok",s,0); *xp = s; return(x); } } /* C M I F I -- Parse the name of an existing file */ /* This function depends on the external functions: zchki() - Check if input file exists and is readable. zxpand() - Expand a wild file specification into a list. znext() - Return next file name from list. If these functions aren't available, then use cmfld() to parse filenames. */ /* Returns -4 EOF -3 if no input present when required, -2 if file does not exist or is not readable, -1 if reparse needed, 0 or 1 otherwise, with: xp pointing to name, wild = 1 if name contains '*' or '?', 0 otherwise. */ #ifdef COMMENT /* This horrible hack has been replaced - see further down */ /* C M I O F I -- Parse an input file OR the name of a nonexistent file. Use this when an existing file is wanted (so we get help, completion, etc), but if a file of the given name does not exist, the name of a new file is accepted. For example, with the EDIT command (edit an existing file, or create a new file). Returns -9 if file does not exist. It is up to the caller to check creatability. */ static int nomsg = 0; int cmiofi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; { int msgsave, x; msgsave = nomsg; nomsg = 1; x = cmifi2(xhlp,xdef,xp,wild,0,NULL,f,0); nomsg = msgsave; return(x); } #endif /* COMMENT */ int #ifdef CK_ANSIC cmifi ( char * xhlp, char * xdef, char ** xp, int * wild, xx_strp f ) #else cmifi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; #endif /* CK_ANSIC */ { return(cmifi2(xhlp,xdef,xp,wild,0,NULL,f,0)); } /* cmifip() is called when we want to supply a path or path list to search in case the filename that the user gives is (a) not absolute, and (b) can't be found as given. The path string can be the name of a single directory, or a list of directories separated by the PATHSEP character, defined in ckucmd.h. Look in ckuusr.c and ckuus3.c for examples of usage. */ int #ifdef CK_ANSIC cmifip( char * xhlp, char * xdef, char ** xp, int * wild, int d, char * path, xx_strp f) #else cmifip(xhlp,xdef,xp,wild,d,path,f) char *xhlp,*xdef,**xp; int *wild, d; char * path; xx_strp f; #endif /* CK_ANSIC */ { return(cmifi2(xhlp,xdef,xp,wild,0,path,f,0)); } /* C M D I R -- Parse a directory name */ /* This function depends on the external functions: isdir(s) - Check if string s is the name of a directory zchki(s) - Check if input file s exists and what type it is. If these functions aren't available, then use cmfld() to parse dir names. Returns -9 For all sorts of reasons, after printing appropriate error message. -4 EOF -3 if no input present when required, -2 if out of space or other internal error, -1 if reparse needed, 0 or 1, with xp pointing to name, if directory specified, */ int #ifdef CK_ANSIC cmdir( char * xhlp, char * xdef, char ** xp, xx_strp f ) #else cmdir(xhlp,xdef,xp,f) char *xhlp; char *xdef; char **xp; xx_strp f; #endif /* CK_ANSIC */ { int wild; return(cmifi2(xhlp,xdef,xp,&wild,0,NULL,f,1)); } /* Like CMDIR but includes PATH search */ int #ifdef CK_ANSIC cmdirp(char * xhlp, char * xdef, char ** xp, char * path, xx_strp f) #else cmdirp(xhlp,xdef,xp,path,f) char *xhlp, *xdef, **xp; char * path; xx_strp f; #endif /* CK_ANSIC */ { int wild; return(cmifi2(xhlp,xdef,xp,&wild,0,path,f,1)); } /* cmifi2() is the base filename parser called by cmifi, cmifip, cmdir, etc. Use it directly when you also want to parse a directory or device name as an input file, as in the DIRECTORY command. Call with: xhlp -- help message on ? xdef -- default response xp -- pointer to result (in our space, must be copied from here) wild -- flag set upon return to indicate if filespec was wild d -- 0 to parse files, 1 to parse files or directories Add 2 to inhibit following of symlinks. path -- search path for files f -- pointer to string processing function (e.g. to evaluate variables) dirflg -- 1 to parse *only* directories, 0 otherwise */ int #ifdef CK_ANSIC cmifi2( char * xhlp, char * xdef, char ** xp, int * wild, int d, char * path, xx_strp f, int dirflg ) #else cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg) char *xhlp,*xdef,**xp; int *wild, d; char * path; xx_strp f; int dirflg; #endif /* CK_ANSIC */ /* cmifi2 */ { extern int recursive, diractive, cdactive, dblquo; int i, x, itsadir, xc, expanded = 0, nfiles = 0, children = -1; int qflag = 0; long y; CK_OFF_T filesize; char *sp = NULL, *zq, *np = NULL; char *sv = NULL; #ifdef DTILDE char *dirp; #endif /* DTILDE */ #ifndef NOPARTIAL #ifndef OS2 #ifdef OSK /* This large array is dynamic for OS-9 -- should do for others too... */ extern char **mtchs; #else #ifdef UNIX /* OK, for UNIX too */ extern char **mtchs; #else #ifdef VMS extern char **mtchs; #else extern char *mtchs[]; #endif /* VMS */ #endif /* UNIX */ #endif /* OSK */ #endif /* OS2 */ #endif /* NOPARTIAL */ if (!xhlp) xhlp = ""; if (!xdef) xdef = ""; #ifndef NOLASTFILE makestr(&tmplastfile,NULL); #endif /* NOLASTFILE */ nzxopts = 0; /* zxpand() options */ debug(F101,"cmifi d","",d); if (d & 2) { /* d & 2 means don't follow symlinks */ d ^= 2; nzxopts = ZX_NOLINKS; } debug(F101,"cmifi nzxopts","",nzxopts); cmfldflgs = 0; if (path) if (!*path) path = NULL; if (path) { /* Make a copy we can poke */ x = strlen(path); np = (char *) malloc(x + 1); if (np) { strcpy(np, path); path = sp = np; } } debug(F110,"cmifi2 path",path,0); ckstrncpy(cmdefault,xdef,CMDEFAULT); /* Copy default */ xdef = cmdefault; inword = 0; /* Initialize counts & pointers */ cc = 0; xc = 0; *xp = ""; /* Pointer to result string */ if ((x = cmflgs) != 1) { /* Already confirmed? */ #ifdef BS_DIRSEP dirnamflg = 1; x = gtword(0); /* No, get a word */ dirnamflg = 0; #else x = gtword(0); /* No, get a word */ #endif /* BS_DIRSEP */ } else { /* If so, use default, if any. */ if (setatm(xdef,1) < 0) { printf("?Default name too long\n"); if (np) free(np); return(-9); } } i_path: *xp = atmbuf; /* Point to result. */ while (1) { xc += cc; /* Count this character. */ debug(F111,"cmifi gtword",atmbuf,xc); debug(F101,"cmifi switch x","",x); switch (x) { /* x = gtword() return code */ case -10: if (gtimer() > timelimit) { #ifdef IKSD if (inserver) { printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", timelimit); doexit(GOOD_EXIT,0); } #endif /* IKSD */ /* if (!quiet) printf("?Timed out\n"); */ return(-10); } else { x = gtword(0); continue; } case -9: printf("Command or field too long\n"); case -4: /* EOF */ case -2: /* Out of space. */ case -1: /* Reparse needed */ if (np) free(np); return(x); case 1: /* CR */ case 0: /* SP */ if (xc == 0) /* If no input... */ *xp = xdef; /* substitute the default */ #ifndef NOLASTFILE makestr(&tmplastfile,*xp); /* Make a copy before bstripping */ #endif /* #ifndef NOLASTFILE */ *xp = brstrip(*xp); /* Strip braces */ if (**xp == NUL) { /* 12 mar 2001 */ if (np) free(np); return(-3); } debug(F110,"cmifi brstrip",*xp,0); #ifndef NOSPL if (f) { /* If a conversion function is given */ #ifdef DOCHKVAR char *s = *xp; /* See if there are any variables in */ int x; while (*s) { /* the string and if so, expand them */ x = chkvar(s); /* debug(F111,"cmifi chkvar",*xp,x); */ if (x) { #endif /* DOCHKVAR */ zq = atxbuf; atxn = CMDBL; if ((*f)(*xp,&zq,&atxn) < 0) { if (np) free(np); return(-2); } *xp = atxbuf; if (!atxbuf[0]) *xp = xdef; #ifdef DOCHKVAR break; } s++; } #endif /* DOCHKVAR */ } #endif /* NOSPL */ if (**xp == NUL) { /* 12 mar 2001 */ if (np) free(np); return(-3); } #ifdef DTILDE if (dirflg) { dirp = tilde_expand(*xp); /* Expand tilde, if any, */ if (*dirp != '\0') { /* in the atom buffer. */ if (setatm(dirp,1) < 0) { printf("Expanded name too long\n"); if (np) free(np); return(-9); } } *xp = atmbuf; debug(F110,"cmifi tilde_expand",*xp,0); } #endif /* DTILDE */ if (!sv) { /* Only do this once */ sv = malloc((int)strlen(*xp)+1); /* Make a safe copy */ if (!sv) { printf("?cmifi: malloc error\n"); if (np) free(np); return(-9); } strcpy(sv,*xp); debug(F110,"cmifi sv",sv,0); } /* This is to get around "cd /" failing because "too many directories match" */ expanded = 0; /* Didn't call zxpand */ #ifdef datageneral debug(F110,"cmifi isdir 1",*xp,0); { int y; char *s; s = *xp; y = strlen(s); if (y > 1 && (s[y-1] == ':' || s[y-1] == '^' || s[y-1] == '=') ) s[y-1] = NUL; } debug(F110,"cmifi isdir 2",*xp,0); #endif /* datageneral */ #ifdef VMS if (dirflg) { if (!strcmp(*xp,"..")) { /* For UNIXers... */ setatm("-",0); *xp = atmbuf; } else if (!strcmp(*xp,".")) { setatm("[]",0); *xp = atmbuf; } } #endif /* VMS */ itsadir = isdir(*xp); /* Is it a directory? */ debug(F111,"cmifi itsadir",*xp,itsadir); #ifdef VMS /* If they said "blah" where "blah.dir" is a directory... */ /* change it to [.blah]. */ if (!itsadir) { char tmpbuf[600]; int flag = 0; char c, * p; p = *xp; while ((c = *p++) && !flag) if (ckstrchr(".[]:*?<>",c)) flag = 1; debug(F111,"cmifi VMS dirname flag",*xp,flag); if (!flag) { ckmakmsg(tmpbuf,TMPBUFSIZ,"[.",*xp,"]",NULL); itsadir = isdir(tmpbuf); if (itsadir) { setatm(tmpbuf,0); *xp = atmbuf; } debug(F111,"cmifi VMS dirname flag itsadir",*xp,itsadir); } } else if (itsadir == 1 && *(xp[0]) == '.' && *(xp[1])) { char *p; if (p = malloc(cc + 4)) { ckmakmsg(p,cc+4,"[",*xp,"]",NULL); setatm(p,0); *xp = atmbuf; debug(F110,"cmdir .foo",*xp,0); free(p); } } else if (itsadir == 2 && !diractive) { int x; /* [FOO]BAR.DIR instead of [FOO.BAR] */ char *p; p = malloc(cc + 4); if (p) { x = cvtdir(*xp,p,ATMBL); /* Convert to [FOO.BAR] */ if (x > 0) { setatm(p,0); *xp = atmbuf; debug(F110,"cmdir cvtdir",*xp,0); } free(p); } } #endif /* VMS */ debug(F101,"cmifi dirflg","",dirflg); debug(F101,"cmifi diractive","",diractive); if (dirflg) { /* Parsing a directory name? */ /* Yes, does it contain wildcards? */ if (iswild(*xp) || (diractive && (!strcmp(*xp,".") || !strcmp(*xp,".."))) ) { nzxopts |= ZX_DIRONLY; /* Match only directory names */ if (matchdot) nzxopts |= ZX_MATCHDOT; if (recursive) nzxopts |= ZX_RECURSE; debug(F111,"cmifi nzxopts 2",*xp,nzxopts); y = nzxpand(*xp,nzxopts); debug(F111,"cmifi nzxpand 2",*xp,y); nfiles = y; expanded = 1; } else { #ifdef VMS /* This is to allow (e.g.) "cd foo", where FOO.DIR;1 is in the current directory. */ debug(F111,"cmdir itsadir",*xp,itsadir); if (!itsadir) { char *s; int n; s = *xp; n = strlen(s); if (n > 0 && #ifdef COMMENT *s != '[' && s[n-1] != ']' && *s != '<' && s[n-1] != '>' && #else ckindex("[",s,0,0,1) == 0 && ckindex("<",s,0,0,1) == 0 && #endif /* COMMENT */ s[n-1] != ':') { char * dirbuf = NULL; dirbuf = (char *)malloc(n+4); if (dirbuf) { if (*s == '.') ckmakmsg(dirbuf,n+4,"[",s,"]",NULL); else ckmakmsg(dirbuf,n+4,"[.",s,"]",NULL); itsadir = isdir(dirbuf); debug(F111,"cmdir dirbuf",dirbuf,itsadir); if (itsadir) { setatm(dirbuf,0); *xp = atmbuf; debug(F110,"cmdir new *xp",*xp,0); } free(dirbuf); } /* This is to allow CDPATH to work in VMS... */ } else if (n > 0) { char * p; int i, j, k, d; char rb[2] = "]"; if (p = malloc(x + 8)) { ckstrncpy(p,*xp,x+8); i = ckindex(".",p,-1,1,1); d = ckindex(".dir",p,0,0,0); j = ckindex("]",p,-1,1,1); if (j == 0) { j = ckindex(">",p,-1,1,1); rb[0] = '>'; } k = ckindex(":",p,-1,1,1); if (i < j || i < k) i = 0; if (d < j || d < k) d = 0; /* Change [FOO]BAR or [FOO]BAR.DIR */ /* to [FOO.BAR] */ if (j > 0 && j < n) { p[j-1] = '.'; if (d > 0) p[d-1] = NUL; ckstrncat(p,rb,x+8); debug(F110,"cmdir xxx",p,0); } itsadir = isdir(p); debug(F111,"cmdir p",p,itsadir); if (itsadir) { setatm(p,0); *xp = atmbuf; debug(F110,"cmdir new *xp",*xp,0); } free(p); } } } #endif /* VMS */ y = (!itsadir) ? 0 : 1; debug(F111,"cmifi y itsadir",*xp,y); } } else { /* Parsing a filename. */ debug(F110,"cmifi *xp pre-zxpand",*xp,0); #ifndef COMMENT nzxopts |= (d == 0) ? ZX_FILONLY : 0; /* So always expand. */ if (matchdot) nzxopts |= ZX_MATCHDOT; if (recursive) nzxopts |= ZX_RECURSE; y = nzxpand(*xp,nzxopts); #else /* Here we're trying to fix a problem in which a directory name is accepted */ /* as a filename, but this breaks too many other things. */ /* nzxopts = 0; */ if (!d) { if (itsadir & !iswild(*xp)) { debug(F100,"cmifi dir when filonly","",0); printf("?Not a regular file: \"%s\"\n",*xp); if (sv) free(sv); if (np) free(np); return(-9); } else { nzxopts |= ZX_FILONLY; if (matchdot) nzxopts |= ZX_MATCHDOT; if (recursive) nzxopts |= ZX_RECURSE; y = nzxpand(*xp,nzxopts); } } #endif /* COMMENT */ nfiles = y; debug(F111,"cmifi y nzxpand",*xp,y); debug(F111,"cmifi y atmbuf",atmbuf,itsadir); expanded = 1; } /* domydir() calls zxrewind() so we MUST call nzxpand() here */ if (!expanded && diractive) { debug(F110,"cmifi diractive catch-all zxpand",*xp,0); nzxopts |= (d == 0) ? ZX_FILONLY : (dirflg ? ZX_DIRONLY : 0); if (matchdot) nzxopts |= ZX_MATCHDOT; if (recursive) nzxopts |= ZX_RECURSE; y = nzxpand(*xp,nzxopts); debug(F111,"cmifi diractive nzxpand",*xp,y); nfiles = y; expanded = 1; } *wild = (iswild(sv) || (y > 1)) && (itsadir == 0); #ifdef RECURSIVE if (!*wild) *wild = recursive; #endif /* RECURSIVE */ debug(F111,"cmifi sv wild",sv,*wild); debug(F101,"cmifi y","",y); if (dirflg && *wild && cdactive) { if (y > 1) { printf("?Wildcard matches more than one directory\n"); if (sv) free(sv); if (np) free(np); return(-9); } else { znext(*xp); } } if (itsadir && d && !dirflg) { /* It's a directory and not wild */ if (sv) free(sv); /* and it's ok to parse directories */ if (np) free(np); #ifndef NOLASTFILE makestr(&lastfile,tmplastfile); #endif /* NOLASTFILE */ return(x); } if (y == 0) { /* File was not found */ int dosearch = 0; dosearch = (path != NULL); /* A search path was given */ if (dosearch) { dosearch = hasnopath(sv); /* Filename includes no path */ debug(F111,"cmifip hasnopath",sv,dosearch); } if (dosearch) { /* Search the path... */ char * ptr = path; char c; while (1) { c = *ptr; if (c == PATHSEP || c == NUL) { if (!*path) { path = NULL; break; } *ptr = NUL; #ifdef UNIX /* By definition of CDPATH, an empty member denotes the current directory */ if (!*path) ckstrncpy(atmbuf,".",ATMBL); else #endif /* UNIX */ ckstrncpy(atmbuf,path,ATMBL); #ifdef VMS atmbuf[ATMBL] = NUL; /* If we have a logical name, evaluate it recursively */ if (*(ptr-1) == ':') { /* Logical name ends in : */ char *p; int n; while (((n = strlen(atmbuf)) > 0) && atmbuf[n-1] == ':') { atmbuf[n-1] = NUL; for (p = atmbuf; *p; p++) if (islower(*p)) *p = toupper(*p); debug(F111,"cmdir CDPATH LN 1",atmbuf,n); p = getenv(atmbuf); debug(F110,"cmdir CDPATH LN 2",p,0); if (!p) break; strncpy(atmbuf,p,ATMBL); atmbuf[ATMBL] = NUL; } } #else #ifdef OS2 if (*(ptr-1) != '\\' && *(ptr-1) != '/') ckstrncat(atmbuf,"\\",ATMBL); #else #ifdef UNIX if (*(ptr-1) != '/') ckstrncat(atmbuf,"/",ATMBL); #else #ifdef datageneral if (*(ptr-1) != ':') ckstrncat(atmbuf,":",ATMBL); #endif /* datageneral */ #endif /* UNIX */ #endif /* OS2 */ #endif /* VMS */ ckstrncat(atmbuf,sv,ATMBL); debug(F110,"cmifip add path",atmbuf,0); if (c == PATHSEP) ptr++; path = ptr; break; } ptr++; } x = 1; inword = 0; cc = 0; xc = (int) strlen(atmbuf); *xp = ""; goto i_path; } if (d) { if (sv) free(sv); if (np) free(np); return(-2); } else { if (!nomsg) { #ifdef CKROOT if (ckrooterr) printf("?Off Limits: %s\n",sv); else #endif /* CKROOT */ if (!quiet) printf("?No %s match - %s\n", dirflg ? "directories" : "files", sv); } if (sv) free(sv); if (np) free(np); return(-9); } } else if (y < 0) { #ifdef CKROOT if (ckrooterr) printf("?Off Limits: %s\n",sv); else #endif /* CKROOT */ printf("?Too many %s match - %s\n", dirflg ? "directories" : "files", sv); if (sv) free(sv); if (np) free(np); return(-9); } else if (*wild || y > 1) { if (sv) free(sv); if (np) free(np); #ifndef NOLASTFILE makestr(&lastfile,tmplastfile); #endif /* NOLASTFILE */ return(x); } /* If not wild, see if it exists and is readable. */ debug(F111,"cmifi sv not wild",sv,*wild); if (expanded) znext(*xp); /* Get first (only?) matching file */ if (dirflg) /* Maybe wild and expanded */ itsadir = isdir(*xp); /* so do this again. */ filesize = dirflg ? itsadir : zchki(*xp); /* Check accessibility */ if (expanded) { #ifdef ZXREWIND nfiles = zxrewind(); /* Rewind so next znext() gets 1st */ #else nzxopts |= dirflg ? ZX_DIRONLY : 0; if (matchdot) nzxopts |= ZX_MATCHDOT; if (recursive) nzxopts |= ZX_RECURSE; nfiles = nzxpand(*xp,nzxopts); #endif /* ZXREWIND */ } debug(F111,"cmifi nfiles",*xp,nfiles); debug(F101,"cmifi filesize","",filesize); free(sv); /* done with this */ sv = NULL; if (dirflg && !filesize) { printf("?Not a directory - %s\n",*xp); #ifdef CKCHANNELIO z_error = FX_ACC; #endif /* CKCHANNELIO */ return(-9); } else if (filesize == (CK_OFF_T)-3) { if (!xcmfdb) { if (diractive) /* Don't show filename if we're not allowed to see it */ printf("?Read permission denied\n"); else printf("?Read permission denied - %s\n",*xp); } if (np) free(np); #ifdef CKCHANNELIO z_error = FX_ACC; #endif /* CKCHANNELIO */ return(xcmfdb ? -6 : -9); } else if (filesize == (CK_OFF_T)-2) { if (!recursive) { if (np) free(np); if (d) { #ifndef NOLASTFILE makestr(&lastfile,tmplastfile); #endif /* NOLASTFILE */ return(0); } if (!xcmfdb) printf("?File not readable - %s\n",*xp); #ifdef CKCHANNELIO z_error = FX_ACC; #endif /* CKCHANNELIO */ return(xcmfdb ? -6 : -9); } } else if (filesize < (CK_OFF_T)0) { if (np) free(np); if (!nomsg && !xcmfdb) printf("?File not found - %s\n",*xp); #ifdef CKCHANNELIO z_error = FX_FNF; #endif /* CKCHANNELIO */ return(xcmfdb ? -6 : -9); } if (np) free(np); #ifndef NOLASTFILE makestr(&lastfile,tmplastfile); #endif /* NOLASTFILE */ return(x); #ifndef MAC case 2: /* ESC */ debug(F101,"cmifi esc, xc","",xc); if (xc == 0) { if (*xdef) { printf("%s ",xdef); /* If at beginning of field */ #ifdef GEMDOS fflush(stdout); #endif /* GEMDOS */ inword = cmflgs = 0; addbuf(xdef); /* Supply default. */ if (setatm(xdef,0) < 0) { printf("Default name too long\n"); if (np) free(np); return(-9); } } else { /* No default */ bleep(BP_WARN); } break; } if (**xp == '{') { /* Did user type opening brace... */ *xp = *xp + 1; xc--; cc--; qflag = '}'; } else if (dblquo && **xp == '"') { /* or doublequote? */ *xp = *xp + 1; /* If so ignore it and space past it */ xc--; cc--; qflag = '"'; } #ifndef NOSPL if (f) { /* If a conversion function is given */ #ifdef DOCHKVAR char *s = *xp; /* See if there are any variables in */ while (*s) { /* the string and if so, expand it. */ if (chkvar(s)) { #endif /* DOCHKVAR */ zq = atxbuf; atxn = CMDBL; if ((x = (*f)(*xp,&zq,&atxn)) < 0) { if (np) free(np); return(-2); } #ifdef DOCHKVAR /* reduce cc by number of \\ consumed by conversion */ /* function (needed for OS/2, where \ is path separator) */ cc -= (strlen(*xp) - strlen(atxbuf)); #endif /* DOCHKVAR */ *xp = atxbuf; if (!atxbuf[0]) { /* Result empty, use default */ *xp = xdef; cc = strlen(xdef); } #ifdef DOCHKVAR break; } s++; } #endif /* DOCHKVAR */ } #endif /* NOSPL */ #ifdef DTILDE if (dirflg && *(*xp) == '~') { debug(F111,"cmifi tilde_expand A",*xp,cc); dirp = tilde_expand(*xp); /* Expand tilde, if any... */ if (!dirp) dirp = ""; if (*dirp) { int i, xx; char * sp; xc = cc; /* Length of ~thing */ xx = setatm(dirp,0); /* Copy expansion to atom buffer */ debug(F111,"cmifi tilde_expand B",atmbuf,cc); if (xx < 0) { printf("Expanded name too long\n"); if (np) free(np); return(-9); } debug(F111,"cmifi tilde_expand xc","",xc); for (i = 0; i < xc; i++) { cmdchardel(); /* Back up over ~thing */ bp--; } xc = cc; /* How many new ones we just got */ sp = atmbuf; printf("%s",sp); /* Print them */ while ((*bp++ = *sp++)) ; /* Copy to command buffer */ bp--; /* Back up over NUL */ } *xp = atmbuf; } #endif /* DTILDE */ sp = *xp + cc; #ifdef UNIXOROSK if (!strcmp(atmbuf,"..")) { printf(" "); ckstrncat(cmdbuf," ",CMDBL); cc++; bp++; *wild = 0; *xp = atmbuf; break; } else if (!strcmp(atmbuf,".")) { bleep(BP_WARN); if (np) free(np); return(-1); } else { /* This patches a glitch when user types "./foo" */ /* in which the next two chars are omitted from the */ /* expansion. There should be a better fix, however, */ /* since there is no problem with "../foo". */ char *p = *xp; if (*p == '.' && *(p+1) == '/') cc -= 2; } #endif /* UNIXOROSK */ #ifdef datageneral *sp++ = '+'; /* Data General AOS wildcard */ #else *sp++ = '*'; /* Others */ #endif /* datageneral */ *sp-- = '\0'; #ifdef GEMDOS if (!strchr(*xp, '.')) /* abde.e -> abcde.e* */ strcat(*xp, ".*"); /* abc -> abc*.* */ #endif /* GEMDOS */ /* Add wildcard and expand list. */ #ifdef COMMENT /* This kills partial completion when ESC given in path segment */ nzxopts |= dirflg ? ZX_DIRONLY : (d ? 0 : ZX_FILONLY); #else /* nzxopts = 0; */ #endif /* COMMENT */ if (matchdot) nzxopts |= ZX_MATCHDOT; if (recursive) nzxopts |= ZX_RECURSE; y = nzxpand(*xp,nzxopts); nfiles = y; debug(F111,"cmifi nzxpand",*xp,y); if (y > 0) { #ifdef OS2 znext(filbuf); /* Get first */ #ifdef ZXREWIND zxrewind(); /* Must "rewind" */ #else nzxpand(*xp,nxzopts); #endif /* ZXREWIND */ #else /* Not OS2 */ ckstrncpy(filbuf,mtchs[0],CKMAXPATH); #endif /* OS2 */ } else *filbuf = '\0'; filbuf[CKMAXPATH] = NUL; *sp = '\0'; /* Remove wildcard. */ debug(F111,"cmifi filbuf",filbuf,y); debug(F111,"cmifi *xp",*xp,cc); *wild = (y > 1); if (y == 0) { if (!nomsg) { #ifdef CKROOT if (ckrooterr) printf("?Off Limits: %s\n",atmbuf); else #endif /* CKROOT */ printf("?No %s match - %s\n", dirflg ? "directories" : "files", atmbuf); if (np) free(np); return(-9); } else { bleep(BP_WARN); if (np) free(np); return(-1); } } else if (y < 0) { #ifdef CKROOT if (ckrooterr) printf("?Off Limits: %s\n",atmbuf); else #endif /* CKROOT */ printf("?Too many %s match - %s\n", dirflg ? "directories" : "files", atmbuf); if (np) free(np); return(-9); } else if (y > 1 /* Not unique */ #ifndef VMS || (y == 1 && isdir(filbuf)) /* Unique directory */ #endif /* VMS */ ) { #ifndef NOPARTIAL /* Partial filename completion */ int j, k; #ifndef OS2 char c; #endif /* OS2 */ k = 0; debug(F111,"cmifi partial",filbuf,cc); #ifdef OS2 { int cur = 0, len = 0, len2 = 0, min = strlen(filbuf), found = 0; char localfn[CKMAXPATH+1]; len = min; for (j = 1; j <= y; j++) { znext(localfn); if (dirflg && !isdir(localfn)) continue; found = 1; len2 = strlen(localfn); for (cur = cc; cur < len && cur < len2 && cur <= min; cur++ ) { /* OS/2 or Windows, case doesn't matter */ if (tolower(filbuf[cur]) != tolower(localfn[cur])) break; } if (cur < min) min = cur; } if (!found) min = cc; filbuf[min] = NUL; if (min > cc) k++; } #else /* OS2 */ for (i = cc; (c = filbuf[i]); i++) { for (j = 1; j < y; j++) if (mtchs[j][i] != c) break; if (j == y) k++; else filbuf[i] = filbuf[i+1] = NUL; } #endif /* OS2 */ #ifndef VMS /* isdir() function required for this! */ if (y == 1 && isdir(filbuf)) { /* Dont we already know this? */ int len; len = strlen(filbuf); if (len > 0 && len < ATMBL - 1) { if (filbuf[len-1] != dirsep) { filbuf[len] = dirsep; filbuf[len+1] = NUL; } } /* At this point, before just doing partial completion, we should look first to see if the given directory does indeed have any subdirectories (dirflg) or files (!dirflg); if it doesn't we should do full completion. Otherwise, the result looks funny to the user and "?" blows up the command for no good reason. */ { int flags = 0; filbuf[len+1] = '*'; filbuf[len+2] = NUL; if (dirflg) flags = ZX_DIRONLY; children = nzxpand(filbuf,flags); debug(F111,"cmifi children",filbuf,children); filbuf[len+1] = NUL; nzxpand(filbuf,flags); /* Restore previous list */ if (children == 0) goto NOSUBDIRS; } if (len + 1 > cc) k++; } /* Add doublequotes if there are spaces in the name */ { int x; if (qflag) { x = (qflag == '}'); /* (or braces) */ } else { x = !dblquo; } if (filbuf[0] != '"' && filbuf[0] != '{') k = dquote(filbuf,ATMBL,x); } #endif /* VMS */ debug(F111,"cmifi REPAINT filbuf",filbuf,k); if (k > 0) { /* Got more characters */ debug(F101,"cmifi REPAINT cc","",cc); debug(F101,"cmifi REPAINT xc","",xc); debug(F110,"cmifi REPAINT bp-cc",bp-cc,0); debug(F110,"cmifi REPAINT bp-xc",bp-xc,0); sp = filbuf + cc; /* Point to new ones */ if (qflag || strncmp(filbuf,bp-cc,cc)) { /* Repaint? */ int x; x = cc; if (qflag) x++; for (i = 0; i < x; i++) { cmdchardel(); /* Back up over old partial spec */ bp--; } sp = filbuf; /* Point to new word start */ debug(F110,"cmifi erase ok",sp,0); } cc = k; /* How many new ones we just got */ printf("%s",sp); /* Print them */ while ((*bp++ = *sp++)) ; /* Copy to command buffer */ bp--; /* Back up over NUL */ debug(F110,"cmifi partial cmdbuf",cmdbuf,0); if (setatm(filbuf,0) < 0) { printf("?Partial name too long\n"); if (np) free(np); return(-9); } debug(F111,"cmifi partial atmbuf",atmbuf,cc); *xp = atmbuf; } #endif /* NOPARTIAL */ bleep(BP_WARN); } else { /* Unique, complete it. */ #ifndef VMS #ifdef CK_TMPDIR /* isdir() function required for this! */ NOSUBDIRS: debug(F111,"cmifi unique",filbuf,children); if (isdir(filbuf) && children > 0) { int len; len = strlen(filbuf); if (len > 0 && len < ATMBL - 1) { if (filbuf[len-1] != dirsep) { filbuf[len] = dirsep; filbuf[len+1] = NUL; } } sp = filbuf + cc; bleep(BP_WARN); printf("%s",sp); cc++; while ((*bp++ = *sp++)) ; bp--; if (setatm(filbuf,0) < 0) { printf("?Directory name too long\n"); if (np) free(np); return(-9); } debug(F111,"cmifi directory atmbuf",atmbuf,cc); *xp = atmbuf; } else { /* Not a directory or dirflg */ #endif /* CK_TMPDIR */ #endif /* VMS */ #ifndef VMS /* VMS dir names are special */ #ifndef datageneral /* VS dirnames must not end in ":" */ if (dirflg) { int len; len = strlen(filbuf); if (len > 0 && len < ATMBL - 1) { if (filbuf[len-1] != dirsep) { filbuf[len] = dirsep; filbuf[len+1] = NUL; } } } #endif /* datageneral */ #endif /* VMS */ sp = filbuf + cc; /* Point past what user typed. */ { int x; if (qflag) { x = (qflag == '}'); } else { x = !dblquo; } if (filbuf[0] != '"' && filbuf[0] != '{') dquote(filbuf,ATMBL,x); } if (qflag || strncmp(filbuf,bp-cc,cc)) { /* Repaint? */ int x; x = cc; if (qflag) x++; for (i = 0; i < x; i++) { cmdchardel(); /* Back up over old partial spec */ bp--; } sp = filbuf; /* Point to new word start */ debug(F111,"cmifi after erase sp=",sp,cc); } printf("%s ",sp); /* Print the completed name. */ #ifdef GEMDOS fflush(stdout); #endif /* GEMDOS */ addbuf(sp); /* Add the characters to cmdbuf. */ if (setatm(filbuf,0) < 0) { /* And to atmbuf. */ printf("?Completed name too long\n"); if (np) free(np); return(-9); } inword = cmflgs = 0; *xp = brstrip(atmbuf); /* Return pointer to atmbuf. */ if (dirflg && !isdir(*xp)) { printf("?Not a directory - %s\n", filbuf); if (np) free(np); return(-9); } if (np) free(np); #ifndef NOLASTFILE makestr(&lastfile,tmplastfile); #endif /* NOLASTFILE */ return(0); #ifndef VMS #ifdef CK_TMPDIR } #endif /* CK_TMPDIR */ #endif /* VMS */ } break; case 3: /* Question mark - file menu wanted */ if (*xhlp == NUL) printf(dirflg ? " Directory name" : " Input file specification"); else printf(" %s",xhlp); #ifdef GEMDOS fflush(stdout); #endif /* GEMDOS */ /* If user typed an opening quote or brace, just skip past it */ if (**xp == '"' || **xp == '{') { *xp = *xp + 1; xc--; cc--; } #ifndef NOSPL if (f) { /* If a conversion function is given */ #ifdef DOCHKVAR char *s = *xp; /* See if there are any variables in */ while (*s) { /* the string and if so, expand them */ if (chkvar(s)) { #endif /* DOCHKVAR */ zq = atxbuf; atxn = CMDBL; if ((x = (*f)(*xp,&zq,&atxn)) < 0) { if (np) free(np); return(-2); } #ifdef DOCHKVAR /* reduce cc by number of \\ consumed by conversion */ /* function (needed for OS/2, where \ is path separator) */ cc -= (strlen(*xp) - strlen(atxbuf)); #endif /* DOCHKVAR */ *xp = atxbuf; #ifdef DOCHKVAR break; } s++; } #endif /* DOCHKVAR */ } #endif /* NOSPL */ debug(F111,"cmifi ? *xp, cc",*xp,cc); sp = *xp + cc; /* Insert "*" at end */ #ifdef datageneral *sp++ = '+'; /* Insert +, the DG wild card */ #else *sp++ = '*'; #endif /* datageneral */ *sp-- = '\0'; #ifdef GEMDOS if (! strchr(*xp, '.')) /* abde.e -> abcde.e* */ strcat(*xp, ".*"); /* abc -> abc*.* */ #endif /* GEMDOS */ debug(F110,"cmifi ? wild",*xp,0); nzxopts |= dirflg ? ZX_DIRONLY : (d ? 0 : ZX_FILONLY); debug(F101,"cmifi matchdot","",matchdot); if (matchdot) nzxopts |= ZX_MATCHDOT; if (recursive) nzxopts |= ZX_RECURSE; y = nzxpand(*xp,nzxopts); nfiles = y; *sp = '\0'; if (y == 0) { if (nomsg) { printf(": %s\n",atmbuf); printf("%s%s",cmprom,cmdbuf); fflush(stdout); if (np) free(np); return(-1); } else { #ifdef CKROOT if (ckrooterr) printf("?Off Limits: %s\n",atmbuf); else #endif /* CKROOT */ printf("?No %s match - %s\n", dirflg ? "directories" : "files", atmbuf); if (np) free(np); return(-9); } } else if (y < 0) { #ifdef CKROOT if (ckrooterr) printf("?Off Limits: %s\n",atmbuf); else #endif /* CKROOT */ printf("?Too many %s match - %s\n", dirflg ? "directories" : "files", atmbuf); if (np) free(np); return(-9); } else { printf(", one of the following:\n"); if (filhelp((int)y,"","",1,dirflg) < 0) { if (np) free(np); return(-9); } } printf("%s%s",cmprom,cmdbuf); fflush(stdout); break; #endif /* MAC */ } #ifdef BS_DIRSEP dirnamflg = 1; x = gtword(0); /* No, get a word */ dirnamflg = 0; #else x = gtword(0); /* No, get a word */ #endif /* BS_DIRSEP */ *xp = atmbuf; } } /* C M F L D -- Parse an arbitrary field */ /* Returns: -3 if no input present when required, -2 if field too big for buffer, -1 if reparse needed, 0 otherwise, xp pointing to string result. NOTE: Global flag keepallchars says whether this routine should break on CR or LF: needed for MINPUT targets and DECLARE initializers, where we want to keep control characters if the user specifies them (March 2003). It might have been better to change the calling sequence but that was not practical. */ int #ifdef CK_ANSIC cmfld(char * xhlp, char * xdef, char ** xp, xx_strp f ) #else cmfld(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; #endif /* CK_ANSIC */ { int x, xc, isavar = 0; char *zq; inword = 0; /* Initialize counts & pointers */ cc = 0; xc = 0; *xp = ""; debug(F110,"cmfld xdef 1",xdef,0); if (!xhlp) xhlp = ""; if (!xdef) xdef = ""; ckstrncpy(cmdefault,xdef,CMDEFAULT); /* Copy default */ xdef = cmdefault; debug(F111,"cmfld xdef 2",xdef,cmflgs); debug(F111,"cmfld atmbuf 1",atmbuf,xc); if ((x = cmflgs) != 1) { /* Already confirmed? */ x = gtword(0); /* No, get a word */ } else { if (setatm(xdef,0) < 0) { /* If so, use default, if any. */ printf("?Default too long\n"); return(-9); } } *xp = atmbuf; /* Point to result. */ debug(F111,"cmfld atmbuf 2",atmbuf,cmflgs); while (1) { xc += cc; /* Count the characters. */ debug(F111,"cmfld gtword",atmbuf,xc); debug(F101,"cmfld x","",x); switch (x) { case -9: printf("Command or field too long\n"); case -4: /* EOF */ case -3: /* Empty. */ case -2: /* Out of space. */ case -1: /* Reparse needed */ return(x); case 1: /* CR */ case 0: /* SP */ debug(F111,"cmfld 1",atmbuf,xc); if (xc == 0) { /* If no input, return default. */ if (setatm(xdef,0) < 0) { printf("?Default too long\n"); return(-9); } } *xp = atmbuf; /* Point to what we got. */ debug(F111,"cmfld 2",atmbuf,((f) ? 1 : 0)); if (f) { /* If a conversion function is given */ zq = atxbuf; /* employ it now. */ atxn = CMDBL; if ((*f)(*xp,&zq,&atxn) < 0) return(-2); debug(F111,"cmfld 3",atxbuf,xc); /* fdc 2013/12/06 - allow a field to be empty if it is the name of a variable that has no value. */ isavar = (atmbuf[0] == '\\'); /* Remember if it was a var */ /* Replace by new value -- for MINPUT only keep all chars */ if (setatm(atxbuf,keepallchars ? 3:1) < 0) { /* 16 Mar 2003 */ printf("Value too long\n"); return(-9); } *xp = atmbuf; } debug(F111,"cmfld 4",atmbuf,xc); if (**xp == NUL) { /* If variable evaluates to null */ if (setatm(xdef,0) < 0) { printf("?Default too long\n"); return(-9); } /* If still empty, return -3 unless it was a variable */ if (**xp == NUL) x = (isavar ? 0 : -3); /* fdc 2013/12/06 */ } debug(F111,"cmfld returns",*xp,x); return(x); case 2: /* ESC */ if (xc == 0 && *xdef) { printf("%s ",xdef); /* If at beginning of field, */ #ifdef GEMDOS fflush(stdout); #endif /* GEMDOS */ addbuf(xdef); /* Supply default. */ inword = cmflgs = 0; if (setatm(xdef,0) < 0) { printf("?Default too long\n"); return(-9); } else /* Return as if whole field */ return(0); /* typed, followed by space. */ } else { bleep(BP_WARN); } break; case 3: /* Question mark */ debug(F110,"cmfld QUESTIONMARK",cmdbuf,0); if (*xhlp == NUL) printf(" Please complete this field"); else printf(" %s",xhlp); printf("\n%s%s",cmprom,cmdbuf); fflush(stdout); break; } debug(F111,"cmfld gtword A x",cmdbuf,x); x = gtword(0); debug(F111,"cmfld gtword B x",cmdbuf,x); } } /* C M T X T -- Get a text string, including confirmation */ /* Print help message 'xhlp' if ? typed, supply default 'xdef' if null string typed. Returns: -1 if reparse needed or buffer overflows. 1 otherwise. with cmflgs set to return code, and xp pointing to result string. */ int #ifdef CK_ANSIC cmtxt( char * xhlp, char * xdef, char ** xp, xx_strp f) #else cmtxt(xhlp,xdef,xp,f) char *xhlp; char *xdef; char **xp; xx_strp f; #endif /* CK_ANSIC */ { int x, i; char *xx, *zq; static int xc; if (!xhlp) xhlp = ""; if (!xdef) xdef = ""; cmfldflgs = 0; cmdefault[0] = NUL; if (*xdef) ckstrncpy(cmdefault,xdef,CMDEFAULT); /* Copy default */ xdef = cmdefault; debug(F101,"cmtxt cmflgs","",cmflgs); inword = 0; /* Start atmbuf counter off at 0 */ cc = 0; if (cmflgs == -1) { /* If reparsing, */ *xp = pp; xc = (int)strlen(*xp); /* get back the total text length, */ bp = *xp; /* and back up the pointers. */ np = *xp; pp = *xp; } else { /* otherwise, */ /* debug(F100,"cmtxt: fresh start","",0); */ *xp = ""; /* start fresh. */ xc = 0; } *atmbuf = NUL; /* And empty the atom buffer. */ rtimer(); /* Reset timer */ if ((x = cmflgs) != 1) { int done = 0; while (!done) { x = gtword(0); /* Get first word. */ *xp = pp; /* Save pointer to it. */ /* debug(F111,"cmtxt:",*xp,cc); */ if (x == -10) { if (gtimer() > timelimit) { /* if (!quiet) printf("?Timed out\n"); */ return(x); } } else done = 1; } } while (1) { /* Loop for each word in text. */ xc += cc; /* Char count for all words. */ /* debug(F111,"cmtxt gtword",atmbuf,xc); */ /* debug(F101,"cmtxt x","",x); */ switch (x) { case -10: if (gtimer() > timelimit) { #ifdef IKSD extern int inserver; if (inserver) { printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", timelimit); doexit(GOOD_EXIT,0); } #endif /* IKSD */ /* if (!quiet) printf("?Timed out\n"); */ return(-10); } else { x = gtword(0); continue; } case -9: /* Buffer overflow */ printf("Command or field too long\n"); case -4: /* EOF */ #ifdef MAC case -3: /* Quit/Timeout */ #endif /* MAC */ case -2: /* Overflow */ case -1: /* Deletion */ return(x); case 0: /* Space */ xc++; /* Just count it */ break; case 1: /* CR or LF */ if (xc == 0) *xp = xdef; if (f) { /* If a conversion function is given */ char * sx = atxbuf; zq = atxbuf; /* Point to the expansion buffer */ atxn = CMDBL; /* specify its length */ /* debug(F111,"cmtxt calling (*f)",*xp,atxbuf); */ if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2); sx = atxbuf; #ifndef COMMENT cc = 0; while (*sx++) cc++; /* (faster than calling strlen) */ #else cc = (int)strlen(atxbuf); #endif /* COMMENT */ /* Should be equal to (CMDBL - atxn) but isn't always. */ /* Why not? */ if (cc < 1) { /* Nothing in expansion buffer? */ *xp = xdef; /* Point to default string instead. */ #ifndef COMMENT sx = xdef; while (*sx++) cc++; /* (faster than calling strlen) */ #else cc = strlen(xdef); #endif /* COMMENT */ } else { /* Expansion function got something */ *xp = atxbuf; /* return pointer to it. */ } debug(F111,"cmtxt (*f)",*xp,cc); } else { /* No expansion function */ #ifndef COMMENT /* Avoid a strlen() call */ xx = *xp; cc = 0; while (*xx++) cc++; #else /* NO! xc is apparently not always set appropriately */ cc = xc; #endif /* COMMENT */ } xx = *xp; #ifdef COMMENT /* strlen() no longer needed */ for (i = (int)strlen(xx) - 1; i > 0; i--) #else for (i = cc - 1; i > 0; i--) #endif /* COMMENT */ if (xx[i] != SP) /* Trim trailing blanks */ break; else xx[i] = NUL; return(x); case 2: /* ESC */ if (xc == 0) { /* Nothing typed yet */ if (*xdef) { /* Have a default for this field? */ printf("%s ",xdef); /* Yes, supply it */ inword = cmflgs = 0; #ifdef GEMDOS fflush(stdout); #endif /* GEMDOS */ cc = addbuf(xdef); } else bleep(BP_WARN); /* No default */ } else { /* Already in field */ int x; char *p; x = strlen(atmbuf); if (ckstrcmp(atmbuf,xdef,x,0)) { /* Matches default? */ bleep(BP_WARN); /* No */ } else if ((int)strlen(xdef) > x) { /* Yes */ p = xdef + x; printf("%s ", p); #ifdef GEMDOS fflush(stdout); #endif /* GEMDOS */ addbuf(p); inword = cmflgs = 0; debug(F110,"cmtxt: addbuf",cmdbuf,0); } else { bleep(BP_WARN); } } break; case 3: /* Question Mark */ if (*xhlp == NUL) printf(" Text string"); else printf(" %s",xhlp); printf("\n%s%s",cmprom,cmdbuf); fflush(stdout); break; default: printf("?Unexpected return code from gtword() - %d\n",x); return(-2); } x = gtword(0); } } /* C M K E Y -- Parse a keyword */ /* Call with: table -- keyword table, in 'struct keytab' format; n -- number of entries in table. if the table is alphabetic order, n is positive. if the table is numeric order, n is negative. xhlp -- pointer to help string; xdef -- pointer to default keyword; f -- string preprocessing function (e.g. to evaluate variables) pmsg -- 0 = don't print error messages 1 = print error messages 2 = include CM_HLP keywords even if invisible 3 = 1+2 4 = parse a switch (keyword possibly ending in : or =) 8 = don't strip comments (used, e.g., for "help #") Returns: -3 -- no input supplied and no default available -2 -- input doesn't uniquely match a keyword in the table -1 -- user deleted too much, command reparse required n >= 0 -- value associated with keyword as defined in the keyword table */ /* Front ends for cmkey(): cmkey() - The normal keyword parser cmkeyx() - Like cmkey() but suppresses error messages cmswi() - Switch parser */ int #ifdef CK_ANSIC cmkey( struct keytab table[], int n, char *xhlp, char * xdef, xx_strp f ) #else cmkey(table,n,xhlp,xdef,f) struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; #endif /* CK_ANSIC */ { /* cmkey */ return(cmkey2(table,n,xhlp,xdef,"",f,1)); } int #ifdef CK_ANSIC cmkeyx(struct keytab table[], int n, char * xhlp, char * xdef, xx_strp f ) #else cmkeyx(table,n,xhlp,xdef,f) struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; #endif /* CK_ANSIC */ /* cmkeyx */ { return(cmkey2(table,n,xhlp,xdef,"",f,0)); } int #ifdef CK_ANSIC cmswi(struct keytab table[], int n, char * xhlp, char * xdef, xx_strp f) #else cmswi(table,n,xhlp,xdef,f) struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; #endif /* CK_ANSIC */ { /* cmswi */ return(cmkey2(table,n,xhlp,xdef,"",f,4)); } /* c m k e y 2 -- The normal keyword parsing function */ int #ifdef CK_ANSIC cmkey2( struct keytab table[], int n, char * xhlp, char * xdef, char * tok, xx_strp f, int pmsg ) #else cmkey2(table,n,xhlp,xdef,tok,f,pmsg) struct keytab table[]; int n; char *xhlp, *xdef; char *tok; xx_strp f; int pmsg; #endif /* CK_ANSIC */ /* cmkey2 */ { extern int havetoken; int i, tl, y, z = 0, zz, xc, wordlen = 0, cmswitch; int numeric = 0; char *xp, *zq; if (!xhlp) xhlp = ""; if (!xdef) xdef = ""; debug(F101,"cmkey lookup entry n","",n); numeric = 0; if (n < 0) { /* Using a numeric-order table */ debug(F101,"cmkey called for numeric nlookup n","",n); numeric = 1; n = -n; /* rather than an alphabetic one */ } debug(F101,"cmkey lookup entry n","",n); cmfldflgs = 0; if (!table) { printf("?Keyword table missing\n"); return(-9); } tl = (int)strlen(tok); inword = xc = cc = 0; /* Clear character counters. */ cmswitch = pmsg & 4; /* Flag for parsing a switch */ debug(F101,"cmkey: pmsg","",pmsg); debug(F101,"cmkey: cmflgs","",cmflgs); debug(F101,"cmkey: cmswitch","",cmswitch); ppvnambuf[0] = NUL; if ((zz = cmflgs) == 1) { /* Command already entered? */ if (setatm(xdef,0) < 0) { /* Yes, copy default into atom buf */ printf("?Default too long\n"); return(-9); } rtimer(); /* Reset timer */ } else { /* Otherwise get a command word */ rtimer(); /* Reset timer */ if (pmsg & 8) /* 8 is for parsing HELP tokens */ zz = gtword(4); else zz = gtword((pmsg == 4) ? 1 : 0); } debug(F101,"cmkey table length","",n); debug(F101,"cmkey cmflgs","",cmflgs); debug(F101,"cmkey cc","",cc); while (1) { xc += cc; debug(F111,"cmkey gtword xc",atmbuf,xc); debug(F101,"cmkey gtword zz","",zz); switch (zz) { case -10: /* Timeout */ if (gtimer() < timelimit) { if (pmsg & 8) /* 8 is for parsing HELP tokens */ zz = gtword(4); else zz = gtword((pmsg == 4) ? 1 : 0); continue; } else { #ifdef IKSD extern int inserver; if (inserver) { printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", timelimit); doexit(GOOD_EXIT,0); } #endif /* IKSD */ return(-10); } case -5: return(cmflgs = 0); case -9: printf("Command or field too long\n"); case -4: /* EOF */ case -3: /* Null Command/Quit/Timeout */ case -2: /* Buffer overflow */ case -1: /* Or user did some deleting. */ return(cmflgs = zz); case 1: /* CR */ case 0: /* User terminated word with space */ case 4: /* or switch ending in : or = */ wordlen = cc; /* Length if no conversion */ if (cc == 0) { /* Supply default if we got nothing */ if ((wordlen = setatm(xdef,(zz == 4) ? 2 : 0)) < 0) { printf("?Default too long\n"); return(-9); } } if (zz == 1 && cc == 0) /* Required field missing */ return(-3); if (f) { /* If a conversion function is given */ char * p2; zq = atxbuf; /* apply it */ p2 = atxbuf; atxn = CMDBL; if ((*f)(atmbuf,&zq,&atxn) < 0) return(-2); debug(F110,"cmkey atxbuf after *f",atxbuf,0); if (!*p2) /* Supply default if we got nothing */ p2 = xdef; ckstrncpy(ppvnambuf,atmbuf,PPVLEN); if ((wordlen = setatm(p2,(zz == 4) ? 2 : 0)) < 0) { printf("Evaluated keyword too long\n"); return(-9); } #ifdef M_UNGW /* This bit lets us save more than one "word". For example, "define \%x echo one two three", "\%x". It works too, but it breaks labels, and therefore WHILE and FOR loops, etc. */ if (p2[wordlen] >= SP) { p2 += wordlen; while (*p2 == SP) p2++; if (*p2) { ungword(); pp = p2; } } #endif /* M_UNGW */ } #ifdef COMMENT /* ^^^ */ if (cmswitch && *atmbuf != '/') { if (pmsg & 1) { bleep(BP_FAIL); printf("?Not a switch - %s\n",atmbuf); } cmflgs = -2; return(-6); } #endif /* COMMENT */ if (cmswitch) { int i; for (i = 0; i < wordlen; i++) { if (atmbuf[i] == ':' || atmbuf[i] == '=') { brkchar = atmbuf[i]; atmbuf[i] = NUL; break; } } } #ifdef TOKPRECHECK /* This was an effective optimization but it breaks sometimes on labels. */ if (tl && !isalpha(atmbuf[0])) { /* Precheck for token */ for (i = 0; i < tl; i++) { /* Save function call to ckstrchr */ if (tok[i] == atmbuf[0]) { debug(F000,"cmkey token:",atmbuf,*atmbuf); ungword(); /* Put back the following word */ return(-5); /* Special return code for token */ } } } #endif /* TOKPRECHECK */ /* Look up word in its table, which can be in alphabetic or numeric order */ if (numeric) { /* Numeric table */ debug(F101,"cmkey numeric calling nlookup ","",numeric); y = nlookup(table,atmbuf,n,&z); debug(F111,"cmkey nlookup",atmbuf,y); } else { /* Alphabetic table */ debug(F101,"cmkey NOT numeric calling lookup ","",numeric); y = lookup(table,atmbuf,n,&z); debug(F111,"cmkey lookup",atmbuf,y); } debug(F101,"cmkey zz","",zz); debug(F101,"cmkey cmflgs","",cmflgs); debug(F101,"cmkey crflag","",crflag); switch (y) { case -3: /* Nothing to look up */ break; case -2: /* Ambiguous */ cmflgs = -2; if (pmsg & 1) { bleep(BP_FAIL); printf("?Ambiguous - %s\n",atmbuf); return(-9); } return(-2); case -1: /* Not found at all */ #ifndef TOKPRECHECK if (tl) { for (i = 0; i < tl; i++) /* Check for token */ if (tok[i] == *atmbuf) { /* Got one */ debug(F000,"cmkey token:",atmbuf,*atmbuf); ungword(); /* Put back the following word */ return(-5); /* Special return code for token */ } } #endif /* TOKPRECHECK */ if (tl == 0) { /* No tokens were included */ #ifdef OS2 /* In OS/2 and Windows, allow for a disk letter like DOS */ if (isalpha(*atmbuf) && *(atmbuf+1) == ':') return(-7); #endif /* OS2 */ if ((pmsg & 1) && !quiet) { bleep(BP_FAIL); printf("?No keywords match - %s\n",atmbuf); /* cmkey */ } return(cmflgs = -9); } else { if (cmflgs == 1 || cmswitch) /* cmkey2 or cmswi */ return(cmflgs = -6); else return(cmflgs = -2); /* The -6 code is to let caller try another table */ } break; default: #ifdef CK_RECALL if (test(table[z].flgs,CM_NOR)) no_recall = 1; #endif /* CK_RECALL */ if (zz == 4) swarg = 1; cmkwflgs = table[z].flgs; break; } return(y); case 2: /* User terminated word with ESC */ debug(F101,"cmkey Esc cc","",cc); if (cc == 0) { if (*xdef != NUL) { /* Nothing in atmbuf */ printf("%s ",xdef); /* Supply default if any */ #ifdef GEMDOS fflush(stdout); #endif /* GEMDOS */ addbuf(xdef); if (setatm(xdef,0) < 0) { printf("?Default too long\n"); return(-9); } inword = cmflgs = 0; debug(F111,"cmkey: default",atmbuf,cc); } else { debug(F101,"cmkey Esc pmsg","",pmsg); #ifdef COMMENT /* Chained FDBs... The idea is that this function might not have a default, but the next one might. But if it doesn't, there is no way to come back to this one. To be revisited later... */ if (xcmfdb) /* Chained fdb -- try next one */ return(-3); #endif /* COMMENT */ if (pmsg & (1|4)) { /* So for now just beep */ bleep(BP_WARN); } break; } } if (f) { /* If a conversion function is given */ char * pp; zq = atxbuf; /* apply it */ pp = atxbuf; atxn = CMDBL; if ((*f)(atmbuf,&zq,&atxn) < 0) return(-2); if (!*pp) pp = xdef; if (setatm(pp,0) < 0) { printf("Evaluated keyword too long\n"); return(-9); } } if (numeric) { /* Numeric table */ y = nlookup(table,atmbuf,n,&z); debug(F111,"cmkey nlookup n",atmbuf,n); /* table length */ debug(F111,"cmkey nlookup y",atmbuf,y); /* return value */ debug(F111,"cmkey nlookup z",atmbuf,z); /* last match */ } else { /* Alphabetic table */ y = lookup(table,atmbuf,n,&z); debug(F111,"cmkey lookup n",atmbuf,n); debug(F111,"cmkey lookup y",atmbuf,y); debug(F111,"cmkey lookup z",atmbuf,z); } if (y == -2 && z >= 0 && z < n) { /* Ambiguous */ #ifndef NOPARTIAL int j, k, len = 9999; /* Do partial completion */ int start = 0; /* where to start searching */ /* Skip past any abbreviations in the table */ for ( ; z < n; z++) { if ((table[z].flgs & CM_ABR) == 0) break; if (!(table[z].flgs & CM_HLP) || (pmsg & 2)) break; } if (numeric) { /* Numeric table */ start = 0; /* search whole table */ } else { /* Alphabetic table */ start = z + 1; /* start here */ } for (j = start; j < n; j++) { if (ckstrcmp(atmbuf,table[j].kwd,cc,0)) break; if (table[j].flgs & CM_ABR) continue; if ((table[j].flgs & CM_HLP) && !(pmsg & 2)) continue; k = ckstrpre(table[z].kwd,table[j].kwd); if (k < len) len = k; /* Length of longest common prefix */ } if (len != 9999 && len > cc) { ckstrncat(atmbuf,table[z].kwd+cc,ATMBL); atmbuf[len] = NUL; printf("%s",atmbuf+cc); ckstrncat(cmdbuf,atmbuf+cc,CMDBL); xc += (len - cc); cc = len; } #endif /* NOPARTIAL */ bleep(BP_WARN); break; } else if (y == -3) { bleep(BP_WARN); break; } else if (y == -1) { /* Not found */ if ((pmsg & 1) && !quiet) { bleep(BP_FAIL); printf("?No keywords match - \"%s\"\n",atmbuf); } cmflgs = -2; return(-9); } /* If we found it, but it's a help-only keyword and the "help" bit is not set in pmsg, then not found. */ debug(F101,"cmkey flgs","",table[z].flgs); if (test(table[z].flgs,CM_HLP) && ((pmsg & 2) == 0)) { if ((pmsg & 1) && !quiet) { bleep(BP_FAIL); printf("?No keywords match - %s\n",atmbuf); } cmflgs = -2; return(-9); } /* See if the keyword just found has the CM_ABR bit set in its flgs field, and if so, search forwards in the table for a keyword that has the same kwval but does not have CM_ABR (or CM_INV?) set, and then expand using the full keyword. WARNING: This assumes that (a) keywords are in alphabetical order, and (b) the CM_ABR bit is set only if the the abbreviated keyword is a true abbreviation (left substring) of the full keyword. */ if (test(table[z].flgs,CM_ABR)) { int zz; for (zz = z+1; zz < n; zz++) if ((table[zz].kwval == table[z].kwval) && (!test(table[zz].flgs,CM_ABR)) && (!test(table[zz].flgs,CM_INV))) { z = zz; break; } } xp = table[z].kwd + cc; if (cmswitch && test(table[z].flgs,CM_ARG)) { #ifdef VMS printf("%s=",xp); brkchar = '='; #else printf("%s:",xp); brkchar = ':'; #endif /* VMS */ } else { printf("%s ",xp); brkchar = SP; } #ifdef CK_RECALL if (test(table[z].flgs,CM_NOR)) no_recall = 1; #endif /* CK_RECALL */ cmkwflgs = table[z].flgs; #ifdef GEMDOS fflush(stdout); #endif /* GEMDOS */ addbuf(xp); if (cmswitch && test(table[z].flgs,CM_ARG)) { bp--; /* Replace trailing space with : */ #ifdef VMS *bp++ = '='; #else *bp++ = ':'; #endif /* VMS */ *bp = NUL; np = bp; swarg = 1; } inword = 0; cmflgs = 0; return(y); case 3: /* User typed "?" */ if (f) { /* If a conversion function is given */ char * pp; zq = atxbuf; /* do the conversion now. */ pp = atxbuf; atxn = CMDBL; if ((*f)(atmbuf,&zq,&atxn) < 0) return(-2); if (setatm(pp,0) < 0) { printf("?Evaluated keyword too long\n"); return(-9); } } if (numeric) { y = nlookup(table,atmbuf,n,&z); /* Numeric table */ } else { y = lookup(table,atmbuf,n,&z); /* Alphabetic table */ } if (y == -1) { /* Strictly speaking if the main keyword table search fails, then we should look in the token table if one is given. But in practice, tokens are also included in the main keyword table. */ cmflgs = -2; if ((pmsg & 1) && !quiet) { bleep(BP_FAIL); printf(" No keywords match\n"); return(-9); } return(-2); } #ifndef COMMENT /* This is to allow ?-help to work immediately after a token */ /* without having to type an intermediate space */ if (tl) { for (i = 0; i < tl; i++) /* Check for token */ if (tok[i] == *atmbuf) { /* Got one */ debug(F000,"cmkey token:",atmbuf,*atmbuf); ungword(); /* Put back the following word */ cmflgs = 3; /* Force help next time around */ return(-5); /* Special return code for token */ } } #endif /* COMMENT */ if (*xhlp == NUL) printf(" One of the following:\n"); else printf(" %s, one of the following:\n",xhlp); { int x; x = pmsg & (2|4); /* See kwdhelp() comments */ if (atmbuf[0]) /* If not at beginning of field */ x |= 1; /* also show invisibles */ kwdhelp(table,n,atmbuf,"","",1,x); } #ifndef NOSPL if (!havetoken) { extern int topcmd; if (tl > 0 && topcmd != XXHLP) /* This is bad... */ printf("or a macro name (\"do ?\" for a list) "); } #endif /* NOSPL */ if (*atmbuf == NUL && !havetoken) { if (tl == 1) printf("or the token %c\n",*tok); else if (tl > 1) printf("or one of the tokens: %s\n",ckspread(tok)); } printf("\n%s%s", cmprom, cmdbuf); fflush(stdout); break; default: printf("\n%d - Unexpected return code from gtword\n",zz); return(cmflgs = -2); } zz = (pmsg & 8) ? gtword(4) : gtword((pmsg == 4) ? 1 : 0); debug(F111,"cmkey gtword zz",atmbuf,zz); } } int #ifdef CK_ANSIC chktok( char * tlist ) #else chktok(tlist) char *tlist; #endif /* CK_ANSIC */ { char *p; p = tlist; while (*p != NUL && *p != *atmbuf) p++; return((*p) ? (int) *p : 0); } /* Routines for parsing and converting dates and times */ #define isdatesep(c) (ckstrchr(" -/._",c)) #define CMDATEBUF 1024 char cmdatebuf[CMDATEBUF+4] = { NUL, NUL }; static char * cmdatebp = cmdatebuf; char * cmdatemsg = NULL; char * cmdatestr = NULL; static struct keytab timeunits[] = { { "days", TU_DAYS, 0 }, { "months", TU_MONTHS, 0 }, { "weeks", TU_WEEKS, 0 }, { "wks", TU_WEEKS, 0 }, { "years", TU_YEARS, 0 }, { "yrs", TU_YEARS, 0 } }; static int nunits = (sizeof(timeunits) / sizeof(struct keytab)); #define SYM_NOW 0 #define SYM_TODA 1 #define SYM_TOMO 2 #define SYM_YEST 3 static struct keytab symdaytab[] = { { "now", SYM_NOW, 0 }, { "today", SYM_TODA, 0 }, { "tomorrow", SYM_TOMO, 0 }, { "yesterday", SYM_YEST, 0 } }; static int nsymdays = (sizeof(symdaytab) / sizeof(struct keytab)); static struct keytab daysofweek[] = { { "Friday", 5, 0 }, { "Monday", 1, 0 }, { "Saturday", 6, 0 }, { "Sunday", 0, 0 }, { "Thursday", 4, 0 }, { "Tuesday", 2, 0 }, { "Wednesday", 3, 0 } }; static struct keytab usatz[] = { /* RFC 822 timezones */ { "cdt", 5, 0 }, /* Values are GMT offsets */ { "cst", 6, 0 }, { "edt", 4, 0 }, { "est", 5, 0 }, { "gmt", 0, 0 }, { "mdt", 6, 0 }, { "mst", 7, 0 }, { "pdt", 7, 0 }, { "pst", 8, 0 }, { "utc", 0, 0 }, { "zulu", 0, 0 } }; static int nusatz = (sizeof(usatz) / sizeof(struct keytab)); /* C M C V T D A T E -- Converts free-form date to standard form. */ /* Call with s = pointer to free-format date, time, or date and time. t = 0: return time only if time was given in s. t = 1: always return time (00:00:00 if no time given in s). t = 2: allow time to be > 24:00:00. Returns: NULL on failure; Pointer to "yyyymmdd hh:mm:ss" (local date-time) on success. */ /* Before final release the following long lines should be wrapped. Until then we leave them long since wrapping them wrecks EMACS's C indentation. */ /* asctime pattern */ static char * atp1 = "[A-Z][a-z][a-z] [A-Z][a-z][a-z] [ 0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]"; /* asctime pattern with timezone */ static char * atp2 = "[A-Z][a-z][a-z] [A-Z][a-z][a-z] [ 0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [A-Z][A-Z][A-Z] [0-9][0-9][0-9][0-9]"; #define DATEBUFLEN 127 #define YYYYMMDD 24 /* Year-month-day buffer */ #define isleap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0) static int mdays[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; #define NEED_DAYS 1 #define NEED_HRS 2 #define NEED_MINS 3 #define NEED_SECS 4 #define NEED_FRAC 5 #define DELTABUF 256 static char deltabuf[DELTABUF]; static char * deltabp = deltabuf; char * #ifdef CK_ANSIC cmdelta( int yy, int mo, int dd, int hh, int mm, int ss, int sign, int dyy, int dmo, int ddd, int dhh, int dmm, int dss) #else cmdelta(yy, mo, dd, hh, mm, ss, sign, dyy, dmo, ddd, dhh, dmm, dss) int yy, mo, dd, hh, mm, ss, sign, dyy, dmo, ddd, dhh, dmm, dss; #endif /* CK_ANSIC */ { /* cmdelta */ long t1, t2, t3, t4; long d1 = 0, d2; char datebuf[DATEBUFLEN+1]; #ifdef DEBUG if (deblog) { debug(F101,"cmdelta yy","",yy); debug(F101,"cmdelta mo","",mo); debug(F101,"cmdelta dd","",dd); debug(F101,"cmdelta hh","",hh); debug(F101,"cmdelta mm","",mm); debug(F101,"cmdelta ss","",ss); debug(F101,"cmdelta sign","",sign); debug(F101,"cmdelta dyy","",dyy); debug(F101,"cmdelta dmo","",dmo); debug(F101,"cmdelta ddd","",ddd); debug(F101,"cmdelta dhh","",dhh); debug(F101,"cmdelta dmm","",dmm); debug(F101,"cmdelta dss","",dss); } #endif /* DEBLOG */ if (yy < 0 || yy > 9999) { makestr(&cmdatemsg,"Base year out of range"); debug(F111,"cmdelta",cmdatemsg,-1); return(NULL); } if (mo < 1 || mo > 12) { makestr(&cmdatemsg,"Base month out of range"); debug(F111,"cmdelta",cmdatemsg,-1); return(NULL); } { int i = mdays[mo]; if (mo == 2) if (isleap(yy)) i++; if (dd < 1 || dd > i) { makestr(&cmdatemsg,"Base day out of range"); debug(F111,"cmdelta",cmdatemsg,-1); return(NULL); } } if (hh < 0 || hh > 23) { makestr(&cmdatemsg,"Base hour out of range"); debug(F111,"cmdelta",cmdatemsg,-1); return(NULL); } if (mm < 0 || mm > 59) { makestr(&cmdatemsg,"Base minute out of range"); debug(F111,"cmdelta",cmdatemsg,-1); return(NULL); } if (ss < 0 || ss > 60) { makestr(&cmdatemsg,"Base second out of range"); debug(F111,"cmdelta",cmdatemsg,-1); return(NULL); } sign = (sign < 0) ? -1 : 1; if (dmo != 0) { if (sign > 0) { mo += (sign * dmo); if (mo > 12) { yy += mo / 12; mo = mo % 12; } } else if (sign < 0) { while (dmo > 12) { yy--; dmo -= 12; } if (dmo < mo) { mo -= dmo; } else { yy--; mo = 12 - (dmo - mo); } } } if (dyy != 0) { yy += (sign * dyy); if (yy > 9999 || yy < 0) { makestr(&cmdatemsg,"Result year out of range"); debug(F111,"cmdelta",cmdatemsg,-1); return(NULL); } } sprintf(datebuf,"%04d%02d%02d %02d:%02d:%02d",yy,mo,dd,hh,mm,ss); d1 = mjd(datebuf); debug(F111,"cmdelta mjd",datebuf,d1); t1 = hh * 3600 + mm * 60 + ss; /* Base time to secs since midnight */ t2 = dhh * 3600 + dmm * 60 + dss; /* Delta time, ditto */ t3 = t1 + (sign * t2); /* Get sum (or difference) */ d2 = (sign * ddd); /* Delta days */ d2 += t3 / 86400L; t4 = t3 % 86400L; /* Fractional part of day */ if (t4 < 0) { /* If negative */ d2--; /* one less delta day */ t4 += 86400L; /* get positive seconds */ } hh = (int) (t4 / 3600L); mm = (int) (t4 % 3600L) / 60; ss = (int) (t4 % 3600L) % 60; sprintf(datebuf,"%s %02d:%02d:%02d", mjd2date(d1+d2),hh,mm,ss); { int len, k, n; char * p; len = strlen(datebuf); k = deltabp - (char *)deltabuf; /* Space used */ n = DELTABUF - k - 1; /* Space left */ if (n < len) { /* Not enough? */ deltabp = deltabuf; /* Wrap around */ n = DELTABUF; } ckstrncpy(deltabp,datebuf,n); p = deltabp; deltabp += len + 1; return(p); } } /* Convert Delta Time to Seconds */ int #ifdef CK_ANSIC delta2sec( char * s, long * result) #else delta2sec(s,result) char * s; long * result; #endif /* CK_ANSIC */ { long ddays = 0L, zz; int dsign = 1, dhours = 0, dmins = 0, dsecs = 0, units; int state = NEED_DAYS; char *p, *p2, *p3, c = 0; char buf[64]; if (!s) s = ""; if (!*s) return(-1); if ((int)strlen(s) > 63) return(-1); ckstrncpy(buf,s,64); p = buf; if (*p != '+' && *p != '-') return(-1); if (*p++ == '-') dsign = -1; while (*p == SP) /* Skip intervening spaces */ p++; while (state) { /* FSA to parse delta time */ if (state < 0 || !isdigit(*p)) return(-1); p2 = p; /* Get next numeric field */ while (isdigit(*p2)) p2++; c = *p2; /* And break character */ *p2 = NUL; /* Terminate the number */ switch (state) { /* Interpret according to state */ case NEED_DAYS: /* Initial */ if ((c == '-') || /* VMS format */ ((c == 'd' || c == 'D') && !isalpha(*(p2+1)))) { /* Days */ ddays = atol(p); if (!*(p2+1)) state = 0; else /* if anything is left */ state = NEED_HRS; /* now we want hours. */ } else if (c == ':') { /* delimiter is colon */ dhours = atoi(p); /* so it's hours */ state = NEED_MINS; /* now we want minutes */ } else if (!c) { /* end of string */ dhours = atoi(p); /* it's still hours */ state = 0; /* and we're done */ } else if (isalpha(c) || c == SP) { if (c == SP) { /* It's a keyword? */ p2++; /* Skip spaces */ while (*p2 == SP) p2++; } else { /* or replace first letter */ *p2 = c; } p3 = p2; /* p2 points to beginning of keyword */ while (isalpha(*p3)) /* Find end of keyword */ p3++; c = *p3; /* NUL it out so we can look it up */ if (*p3) /* p3 points to keyword terminator */ *p3 = NUL; if ((units = lookup(timeunits,p2,nunits,NULL)) < 0) return(-1); *p2 = NUL; /* Re-terminate the number */ *p3 = c; while (*p3 == SP) /* Point at field after units */ p3++; p2 = p3; switch (units) { case TU_DAYS: ddays = atol(p); break; default: return(-1); } if (*p2) { state = NEED_HRS; p2--; } else state = 0; } else { /* Anything else */ state = -1; /* is an error */ } break; case NEED_HRS: /* Looking for hours */ if (c == ':') { dhours = atoi(p); state = NEED_MINS; } else if (!c) { dhours = atoi(p); state = 0; } else { state = -1; } break; case NEED_MINS: /* Looking for minutes */ if (c == ':') { dmins = atoi(p); state = NEED_SECS; } else if (!c) { dmins = atoi(p); state = 0; } else { state = -1; } break; case NEED_SECS: /* Looking for seconds */ if (c == '.') { dsecs = atoi(p); state = NEED_FRAC; } else if (!c) { dsecs = atoi(p); state = 0; } else { state = -1; } break; case NEED_FRAC: /* Fraction of second */ if (!c && rdigits(p)) { if (*p > '4') dsecs++; state = 0; } else { state = -1; } break; } if (c) /* next field if any */ p = p2 + 1; } if (state < 0) return(-1); /* if days > 24854 and sizeof(long) == 32 we overflow */ zz = ddays * 86400L; if (zz < 0L) /* This catches it */ return(-2); zz += dhours * 3600L + dmins * 60L + dsecs; zz *= dsign; *result = zz; return(0); } /* C M C V T D A T E cmcvtdate(date-time-string, format-selector) Converts the given free-format date-time (s) to various formats (t): t = 1: yyyy-mmm-dd hh:mm:ss (mmm = English 3-letter month abbreviation) t = 2: dd-mmm-yyyy hh:mm:ss (ditto) t = 3: yyyymmddhhmmss (all numeric) t = 4: Day Mon dd hh:mm:ss yyyy (asctime) t = 5: yyyy:mm:dd:hh:mm:ss (all numeric with all fields delimited) t = 6: dd month-spelled-out yyyy hh:mm:ss Other: yyyymmdd hh:mm:dd If t is negative (-1 through -6) result is date only. */ char * #ifdef CK_ANSIC cmcvtdate(char * s, int t ) #else cmcvtdate(s,t) char * s; int t; #endif /* CK_ANSIC */ { int x, i, j, k, hh, mm, ss, ff, pmflag = 0, nodate = 0, len, dow; int units, isgmt = 0, gmtsign = 0, d = 0, state = 0, nday; int kn = 0, ft[8], isletter = 0, f2len = 0; int zhh = 0; /* Timezone adjustments */ int zmm = 0; int zdd = 0; int dsign = 1; /* Delta-time adjustments */ int ddays = 0; int dmonths = 0; int dyears = 0; int dhours = 0; int dmins = 0; int dsecs = 0; int havedelta = 0; char * fld[8], * p = "", * p2, * p3; /* Assorted buffers and pointers */ char * s2, * s3; char * year = NULL, * month = NULL, * day = NULL; char datesep = 0; char tmpbuf[16]; char xbuf[DATEBUFLEN+1]; char ybuf[DATEBUFLEN+1]; char zbuf[DATEBUFLEN+1]; char yyyymmdd[YYYYMMDD]; char dbuf[26]; char daybuf[3]; char monbuf[3]; char yearbuf[5]; char cc; char * dp = NULL; /* Result pointer */ char * newdate = NULL; char * datepat = "[12][0-9][0-9][0-9]:[0-9][0-9]:[0-9][0-9]"; if (!s) s = ""; tmpbuf[0] = NUL; len = strlen(s); while (*s == SP) s++; /* Gobble any leading blanks */ if (ckmatch(datepat,s,0,4)) { /* Check for Apache web log format */ int i, j = 0; newdate = (char *)malloc((len + 1) * sizeof(char *)); for (i = 0; i <= len; i++) { /* Loop to remove colons */ if (s[i] != ':') newdate[j++] = s[i]; if (s[i] == NUL) break; } s = newdate; /* Replace arg with result */ } if (isalpha(*s)) /* Remember if 1st char is a letter */ isletter = 1; debug(F110,"cmcvtdate",s,len); if (len == 0) { /* No arg - return current date-time */ dp = ckdate(); goto xcvtdate; } if (len > DATEBUFLEN) { /* Check length of arg */ makestr(&cmdatemsg,"Date-time string too long"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } hh = 0; /* Init time to 00:00:00.0 */ mm = 0; ss = 0; ff = 0; ztime(&p); if (!p) p = ""; if (*p) { /* Init time to current time */ x = ckstrncpy(dbuf,p,26); if (x > 17) { hh = atoi(&dbuf[11]); mm = atoi(&dbuf[14]); ss = atoi(&dbuf[17]); } } ckstrncpy(yyyymmdd,zzndate(),YYYYMMDD); /* Init date to current date */ ckstrncpy(yearbuf,yyyymmdd,5); ckstrncpy(monbuf,&yyyymmdd[4],3); ckstrncpy(daybuf,&yyyymmdd[6],3); year = yearbuf; month = monbuf; day = daybuf; nday = atoi(daybuf); ckstrncpy(xbuf,s,DATEBUFLEN); /* Make a local copy we can poke */ s = xbuf; /* Point to it */ s[len] = NUL; if (s[0] == ':') { p = s; goto dotime; } /* Special preset formats... */ if (len >= 14) { /* FTP MDTM all-numeric date */ char c; c = s[14]; /* e.g. 19980615100045.014 */ s[14] = NUL; x = rdigits(s); s[14] = c; if (x) { ckstrncpy(yyyymmdd,s,8+1); year = NULL; p = &s[8]; goto dotime; } } x = 0; /* Becomes > 0 for asctime format */ if (isalpha(s[0])) { if (len == 24) { /* Asctime format? */ /* Sat Jul 14 15:57:32 2001 */ x = ckmatch(atp1,s,0,0); debug(F111,"cmcvtdate asctime",s,x); } else if (len == 28) { /* Or Asctime plus timezone? */ /* Sat Jul 14 15:15:39 EDT 2001 */ x = ckmatch(atp2,s,0,0); debug(F111,"cmcvtdate asctime+timezone",s,x); } } if (x > 0) { /* Asctime format */ int xx; strncpy(yearbuf,s + len - 4,4); yearbuf[4] = NUL; for (i = 0; i < 3; i++) tmpbuf[i] = s[i+4]; tmpbuf[3] = NUL; if ((xx = lookup(cmonths,tmpbuf,12,NULL)) < 0) { makestr(&cmdatemsg,"Invalid month"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } debug(F101,"cmcvtdate asctime month","",xx); monbuf[0] = (xx / 10) + '0'; monbuf[1] = (xx % 10) + '0'; monbuf[2] = NUL; daybuf[0] = (s[8] == ' ' ? '0' : s[8]); daybuf[1] = s[9]; daybuf[2] = NUL; xbuf[0] = SP; for (i = 11; i < 19; i++) xbuf[i-10] = s[i]; xbuf[9] = NUL; ckmakmsg(zbuf,18,yearbuf,monbuf,daybuf,xbuf); debug(F110,"cmcvtdate asctime ok",zbuf,0); if (len == 24) { dp = zbuf; goto xcvtdate; } else { int n; n = ckmakmsg(ybuf,DATEBUFLEN-4,zbuf," ",NULL,NULL); ybuf[n++] = s[20]; ybuf[n++] = s[21]; ybuf[n++] = s[22]; ybuf[n++] = NUL; ckstrncpy(xbuf,ybuf,DATEBUFLEN); s = xbuf; isletter = 0; } } /* Check for day of week */ p = s; while (*p == SP) p++; dow = -1; if (*p) { p2 = p; cc = NUL; while (1) { if (*p2 == ',' || *p2 == SP || !*p2) { cc = *p2; /* Save break char */ *p2 = NUL; /* NUL it out */ p3 = p2; /* Remember this spot */ if ((dow = lookup(daysofweek,p,7,NULL)) > -1) { debug(F111,"cmcvtdate dow",p,dow); s = p2; if (cc == ',' || cc == SP) { /* Point to next field */ s++; while (*s == SP) s++; } p = s; debug(F111,"cmcvtdate dow new p",p,dow); break; } else if (isalpha(*p) && cc == ',') { makestr(&cmdatemsg,"Unrecognized day of week"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } else { *p3 = cc; break; } } p2++; } } len = strlen(s); /* Update length */ debug(F111,"cmcvtdate s",s,len); debug(F111,"cmcvtdate dow",s,dow); if (dow > -1) { /* Have a day-of-week number */ long zz; int n, j; zz = mjd(zzndate()); /* Get today's MJD */ debug(F111,"cmcvtdate zz","",zz); j = (((int)(zz % 7L)) + 3) % 7; /* Today's day-of-week number */ debug(F111,"cmcvtdate j","",j); hh = 0; /* Init time to midnight */ mm = 0; ss = 0; if (j == dow) { ckstrncpy(yyyymmdd,zzndate(),YYYYMMDD); year = NULL; } else { n = dow - j; /* Days from now */ if (dow < j) n += 7; if (n < 0) n += 7; /* Add to MJD */ zz += n; ckstrncpy(yyyymmdd,mjd2date(zz),YYYYMMDD); /* New date */ year = NULL; } debug(F111,"cmcvtdate A",yyyymmdd,len); if (len == 0) { /* No more fields after this */ ckmakmsg(zbuf,18,yyyymmdd," 00:00:00",NULL,NULL); dp = zbuf; goto xcvtdate; } isletter = 0; if (rdigits(p) && len < 8) /* Next field is time? */ goto dotime; /* If so go straight to time section */ if (isdigit(*p)) { if (*(p+1) == ':') goto dotime; else if (isdigit(*(p+1)) && (*(p+2) == ':')) goto dotime; } } debug(F111,"cmcvtdate B s",s,dow); debug(F111,"cmcvtdate B p",p,dow); if (*s == '+' || *s == '-') { /* Delta time only - skip ahead. */ p = s; goto delta; } #ifdef COMMENT /* What is the purpose of this? It breaks parsing of email dates like "Wed, 13 Feb 2002 17:43:02 -0800 (PST)". Removing this code fixes the problem and Kermit still passes the 'dates' script. - fdc, Sat Nov 26 10:52:45 2005. */ if (dow > -1) { /* Day of week given followed by something that is not a time */ /* or a delta so it can't be valid */ makestr(&cmdatemsg,"Invalid tokens after day of week"); debug(F111,"cmcvtdate fail",cmdatemsg,-1); return(NULL); } #endif /* COMMENT */ /* Handle "today", "yesterday", "tomorrow", and +/- n units */ if (ckstrchr("TtYyNn",s[0])) { int i, k; char c; long jd; jd = mjd(ckdate()); debug(F111,"cmcvtdate mjd",s,jd); /* Symbolic date: TODAY, TOMORROW, etc...? */ s2 = s; /* Find end of keyword */ i = 0; while (isalpha(*s2)) { /* and get its length */ i++; s2++; } c = *s2; /* Zap but save delimiter */ *s2 = NUL; k = lookup(symdaytab,s,nsymdays,NULL); /* Look up keyword */ *s2 = c; /* Replace delimiter */ if (k < 0) /* Keyword not found */ goto normal; s3 = &s[i]; while (*s3 == SP) /* Skip whitespace */ s3++; if (*s3 == '_' || *s3 == ':') s3++; switch (k) { /* Have keyword */ case SYM_NOW: /* NOW */ ckstrncpy(ybuf,ckdate(),DATEBUFLEN); ckstrncpy(yyyymmdd,ybuf,YYYYMMDD); year = NULL; if (*s3) { /* No overwriting current time. */ ckstrncat(ybuf," ",DATEBUFLEN); ckstrncat(ybuf,s3,DATEBUFLEN); } break; default: /* Yesterday, Today, and Tomorrow */ if (k == SYM_TOMO) { /* TOMORROW */ strncpy(ybuf,mjd2date(jd+1),8); } else if (k == SYM_YEST) { /* YESTERDAY */ strncpy(ybuf,mjd2date(jd-1),8); } else { /* TODAY */ strncpy(ybuf,ckdate(),8); } strncpy(ybuf+8," 00:00:00",DATEBUFLEN-8); /* Default time is 0 */ ckstrncpy(yyyymmdd,ybuf,YYYYMMDD); year = NULL; if (*s3) { /* If something follows keyword... */ if (isdigit(*s3)) { /* Time - overwrite default time */ strncpy(ybuf+8,s+i,DATEBUFLEN-8); } else { /* Something else, keep default time */ ckstrncat(ybuf," ",DATEBUFLEN); /* and append */ ckstrncat(ybuf,s3,DATEBUFLEN); /* whatever we have */ } } } s = ybuf; /* Point to rewritten date-time */ len = strlen(s); /* Update length */ isletter = 0; /* Cancel this */ } /* Regular free-format non-symbolic date */ normal: debug(F111,"cmcvtdate NORMAL",s,len); debug(F111,"cmcvtdate dow",s,dow); if (yyyymmdd[0] && !year) { ckstrncpy(yearbuf,yyyymmdd,5); ckstrncpy(monbuf,&yyyymmdd[4],3); ckstrncpy(daybuf,&yyyymmdd[6],3); year = yearbuf; month = monbuf; day = daybuf; nday = atoi(daybuf); } if (isdigit(s[0])) { /* Time without date? */ p = s; if (s[1] == ':') { debug(F111,"cmcvtdate NORMAL X1",s,len); goto dotime; } else if (len > 1 && isdigit(s[1]) && s[2] == ':') { debug(F111,"cmcvtdate NORMAL X2",s,len); goto dotime; } else if (rdigits(s) && len < 8) { debug(F111,"cmcvtdate NORMAL X3",s,len); goto dotime; } } if (len >= 8 && isdigit(*s)) { /* Check first for yyyymmdd* */ debug(F111,"cmcvtdate NORMAL A",s,len); cc = s[8]; s[8] = NUL; /* Isolate first 8 characters */ if (rdigits(s)) { /* Have valid time separator? */ p2 = cc ? ckstrchr(" Tt_-:",cc) : NULL; if (!cc || p2) { ckstrncpy(yyyymmdd,s,YYYYMMDD); /* Valid separator */ year = NULL; s += 8; /* or time not given */ if (cc) s++; /* Keep date */ p = s; /* and go handle time */ goto dotime; } else if (!p2) { if (isdigit(cc)) makestr(&cmdatemsg,"Numeric date too long"); else makestr(&cmdatemsg,"Invalid date-time separator"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } } s[8] = cc; /* Put this back! */ } debug(F111,"cmcvtdate NORMAL non-yyyymmdd",s,len); /* Free-format date -- figure it out */ #ifdef COMMENT if (*s && !isdigit(*s)) { makestr(&cmdatemsg,"Unrecognized word in date"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } #endif /* COMMENT */ for (i = 0; i < 8; i++) /* Field types */ ft[i] = -1; fld[i = 0] = (p = s); /* First field */ while (*p) { /* Get next two fields */ if (isdatesep(*p)) { /* Have a date separator */ if (i == 0) { datesep = *p; } else if (i == 1 && *p != datesep) { makestr(&cmdatemsg,"Inconsistent date separators"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } *p++ = NUL; /* Replace by NUL */ if (*p) { /* Now we're at the next field */ while (*p == SP) p++; /* Skip leading spaces */ if (!*p) break; /* Make sure we still have something */ if (i == 2) /* Last one? */ break; fld[++i] = p; /* No, record pointer to this one */ } else { break; } } else if ((*p == 'T' || *p == 't') && isdigit(*(p+1))) { /* Time */ *p++ = NUL; break; } else if (*p == ':') { if (i == 0 && p == s) { nodate = 1; break; } else if (i != 0) { /* After a date */ if (i == 2) { /* OK as date-time separator (VMS) */ *p++ = NUL; break; } if (i < 2) makestr(&cmdatemsg,"Too few fields in date"); else makestr(&cmdatemsg,"Misplaced time separator"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } nodate = 1; /* Or without a date */ break; } p++; } if (p > s && i == 0) /* Make sure we have a date */ nodate = 1; /* No date. */ if (nodate && dow > -1) { /* Have implied date from DOW? */ goto dotime; /* Use, use that, go do time. */ } else if (nodate) { /* No date and no implied date */ char *tmp = NULL; /* Substitute today's date */ ztime(&tmp); if (!tmp) tmp = ""; if (!*tmp) { makestr(&cmdatemsg,"Problem supplying current date"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } ckstrncpy(dbuf,tmp,26); /* Reformat */ if (dbuf[8] == SP) dbuf[8] = '0'; fld[0] = dbuf+8; /* dd */ dbuf[10] = NUL; fld[1] = dbuf+4; /* mmm */ dbuf[7] = NUL; fld[2] = dbuf+20; /* yyyy */ dbuf[24] = NUL; hh = atoi(&dbuf[11]); mm = atoi(&dbuf[14]); ss = atoi(&dbuf[17]); p = s; /* Back up source pointer to reparse */ } else if (i < 2) { makestr(&cmdatemsg,"Too few fields in date"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } /* Have three date fields - see what they are */ for (k = 0, j = 0; j < 3; j++) { /* Get number of non-numeric fields */ ft[j] = rdigits(fld[j]); debug(F111,"cmcvtdate fld",fld[j],j); if (ft[j] == 0) k++; } kn = k; /* How many numeric fields */ month = NULL; /* Strike out default values */ year = NULL; day = NULL; if (k == 2 && ft[2] > 0) { /* Jul 20, 2001 */ int xx; xx = strlen(fld[1]); p3 = fld[1]; if (xx > 0) if (p3[xx-1] == ',') { p3[xx-1] = NUL; if (rdigits(p3)) { k = 1; ft[1] = 1; } else p3[xx-1] = ','; } } if (k > 1) { /* We can have only one non-numeric */ if (nodate) makestr(&cmdatemsg,"Unrecognized word in date"); else if (!ft[2] && isdigit(*(fld[2]))) makestr(&cmdatemsg,"Invalid date-time separator"); else makestr(&cmdatemsg,"Too many non-numeric fields in date"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } if (!ft[0]) { k = 0; } else if (!ft[1]) { k = 1; } else if (!ft[2]) { makestr(&cmdatemsg,"Non-digit in third date field"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } else k = -1; if (k > -1) { if ((x = lookup(cmonths,fld[k],12,NULL)) < 0) { makestr(&cmdatemsg,"Unknown month"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } sprintf(tmpbuf,"%02d",x); month = tmpbuf; } f2len = strlen(fld[2]); /* Length of 3rd field */ if (k == 0) { /* monthname dd, yyyy */ day = fld[1]; year = fld[2]; } else if (((int)strlen(fld[0]) == 4)) { /* yyyy-xx-dd */ year = fld[0]; day = fld[2]; if (!month) month = fld[1]; /* yyyy-mm-dd */ } else if (f2len == 4) { /* xx-xx-yyyy */ year = fld[2]; if (month) { /* dd-name-yyyy */ day = fld[0]; } else { /* xx-xx-yyyy */ int f0, f1; f0 = atoi(fld[0]); f1 = atoi(fld[1]); if (((f0 > 12) && (f1 <= 12)) || (f1 <= 12 && f0 == f1)) { day = fld[0]; /* mm-dd-yyyy */ month = fld[1]; } else if ((f0 <= 12) && (f1 > 12)) { if (!rdigits(fld[1])) { makestr(&cmdatemsg,"Day not numeric"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } else { day = fld[1]; /* dd-mm-yyyy */ } month = fld[0]; } else { if (!f0 || !f1) makestr(&cmdatemsg,"Day or month out of range"); else makestr(&cmdatemsg,"Day and month are ambiguous"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } } } else if ((f2len < 4) && /* dd mmm yy (RFC822) */ !rdigits(fld[1]) && /* middle field is monthname */ rdigits(fld[2])) { int tmpyear; day = fld[0]; if (!fld[2][1]) { makestr(&cmdatemsg,"Too few digits in year"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } tmpyear = atoi(fld[2]); if (tmpyear < 50) /* RFC 2822 windowing */ tmpyear += 2000; else /* This includes 3-digit years. */ tmpyear += 1900; year = ckitoa(tmpyear); } else if ((f2len < 4) && (k < 0) && ((int)strlen(fld[0]) < 4)) { makestr(&cmdatemsg,"Ambiguous numeric date"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } else if ((f2len > 4) && ft[2]) { makestr(&cmdatemsg,"Too many digits in year"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } else { makestr(&cmdatemsg,"Unexpected date format"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } x = atoi(month); sprintf(tmpbuf,"%02d",x); /* 2-digit numeric month */ /* state = 1 = hours state = 2 = minutes state = 3 = seconds state = 4 = fractions of seconds */ dotime: if (isletter && (s == p)) { makestr(&cmdatemsg,"Unknown date-time word"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } if (!year && yyyymmdd[0]) { debug(F110,"cmcvtdate dotime yyyymmdd",yyyymmdd,0); for (i = 0; i < 4; i++) yearbuf[i] = yyyymmdd[i]; yearbuf[4] = NUL; monbuf[0] = yyyymmdd[4]; monbuf[1] = yyyymmdd[5]; monbuf[2] = NUL; daybuf[0] = yyyymmdd[6]; daybuf[1] = yyyymmdd[7]; daybuf[2] = NUL; day = daybuf; nday = atoi(daybuf); month = monbuf; year = yearbuf; } if (!year) { makestr(&cmdatemsg,"Internal error - date not defaulted"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } /* Get here with day, month, and year set */ debug(F110,"cmcvtdate dotime day",day,0); debug(F110,"cmcvtdate dotime month",month,0); debug(F110,"cmcvtdate dotime year",year,0); debug(F110,"cmcvtdate dotime s",s,0); debug(F110,"cmcvtdate dotime p",p,0); x = atoi(month); if (x > 12 || x < 1) { makestr(&cmdatemsg,"Month out of range"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } nday = atoi(day); i = mdays[x]; if (x == 2) if (isleap(atoi(year))) i++; if (nday > i || nday < 1) { makestr(&cmdatemsg,"Day out of range"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } if (!*p && t == 0) { sprintf(zbuf,"%04d%02d%02d",atoi(year),atoi(month),nday); dp = zbuf; goto xcvtdate; } if (*p == '+' || *p == '-') { /* GMT offset without a time */ hh = 0; /* so default time to 00:00:00 */ mm = 0; ss = 0; goto cmtimezone; /* and go do timezone */ } if (*p && !isdigit(*p) && *p != ':') { makestr(&cmdatemsg,"Invalid time"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } sprintf(yyyymmdd,"%s%s%02d",year,month,(char)nday); /* for tz calculations... */ state = 1; /* Initialize time-parsing FSA */ hh = 0; /* hours */ mm = 0; /* minutes */ ss = 0; /* seconds */ ff = -1; /* fraction */ d = 0; /* Digit counter */ p2 = p; /* Preliminary digit count... */ while (isdigit(*p2)) { d++; p2++; } if (d > 6) { makestr(&cmdatemsg,"Too many time digits"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } d = (d & 1 && *p2 != ':') ? 1 : 0; /* Odd implies leading '0' */ while (*p) { /* Get the time, if any */ if (isdigit(*p)) { /* digit */ if (d++ > 1) { state++; d = 1; } switch (state) { case 1: /* Hours */ hh = hh * 10 + (*p - '0'); break; case 2: /* Minutes */ mm = mm * 10 + (*p - '0'); break; case 3: /* Seconds */ ss = ss * 10 + (*p - '0'); break; case 4: /* Fraction of second */ if (ff < 0) ff = (*p > '4') ? 1 : 0; break; } } else if (*p == ':') { /* Colon */ state++; d = 0; if (state > 3) { makestr(&cmdatemsg,"Too many time fields"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } } else if (*p == '.') { if (state == 3) { state = 4; d = 0; } else { makestr(&cmdatemsg,"Improper fraction"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } } else if (*p == SP) { /* Space */ while (*p && (*p == SP)) /* position to first nonspace */ p++; break; } else if (isalpha(*p)) { /* AM/PM/Z or timezone */ break; } else if (*p == '+' || *p == '-') { /* GMT offset */ break; } else { makestr(&cmdatemsg,"Invalid time characters"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } p++; } if (!*p) /* If nothing left */ goto xcmdate; /* go finish up */ /* At this point we have HH, MM, SS, and FF */ /* Now handle the rest: AM, PM, and/or timezone info */ if (!ckstrcmp(p,"am",2,0)) { /* AM/PM... */ pmflag = 0; p += 2; } else if (!ckstrcmp(p,"a.m.",4,0)) { pmflag = 0; p += 4; } else if (!ckstrcmp(p,"pm",2,0)) { pmflag = 1; p += 2; } else if (!ckstrcmp(p,"p.m.",4,0)) { pmflag = 1; p += 4; } if (pmflag && hh < 12) /* If PM was given */ hh += 12; /* add 12 to the hour */ /* Now handle timezone */ cmtimezone: debug(F110,"cmcvtdate timezone",p,0); zhh = 0; /* GMT offset HH */ zmm = 0; /* GMT offset MM */ gmtsign = 0; /* Sign of GMT offset */ isgmt = 0; /* 1 if time is GMT */ while (*p && *p == SP) /* Gobble spaces */ p++; if (!*p) /* If nothing left */ goto xcmdate; /* we're done */ if (isalpha(*p)) { /* Something left */ int zone = 0; /* Alphabetic must be timezone */ p2 = p; /* Isolate timezone */ p++; while (isalpha(*p)) p++; p3 = p; cc = *p; *p = NUL; p = p2; /* Have timezone, look it up */ zone = lookup(usatz,p,nusatz,NULL); debug(F111,"cmcvtdate timezone alpha",p,zone); if (zone < 0) { /* Not found */ makestr(&cmdatemsg,"Unknown timezone"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } isgmt++; /* All dates are GMT from here down */ if (zone != 0) { /* But not this one so make it GMT */ hh += zone; /* RFC 822 timezone: EST etc */ debug(F101,"cmcvtdate hh + zone","",hh); if (hh > 23) { /* Offset crosses date boundary */ int i; long jd; jd = mjd(yyyymmdd); /* Get MJD */ jd += hh / 24; /* Add new day(s) */ hh = hh % 24; /* and convert back to yyyymmdd */ ckstrncpy(yyyymmdd,mjd2date(jd),YYYYMMDD); debug(F111,"cmcvtdate zone-adjusted date",yyyymmdd,hh); for (i = 0; i < 4; i++) yearbuf[i] = yyyymmdd[i]; yearbuf[4] = NUL; monbuf[0] = yyyymmdd[4]; monbuf[1] = yyyymmdd[5]; monbuf[2] = NUL; daybuf[0] = yyyymmdd[6]; daybuf[1] = yyyymmdd[7]; daybuf[2] = NUL; day = daybuf; nday = atoi(daybuf); month = monbuf; year = yearbuf; } } p = p3; /* Put back whatever we poked above */ *p = cc; } else if (*p == '+' || *p == '-') { /* GMT/UTC offset */ p3 = p; debug(F110,"cmcvtdate timezone GMT offset",p,0); gmtsign = (*p == '+') ? -1 : 1; isgmt++; p++; while (*p == SP) p++; d = 0; p2 = p; while (isdigit(*p)) { /* Count digits */ d++; p++; } if (d != 4) { /* Strict RFC [2]822 */ isgmt = 0; /* If not exactly 4 digits */ p = p3; /* it's not a GMT offset. */ goto delta; /* So treat it as a delta time. */ } d = (d & 1 && *p != ':') ? 1 : 0; /* Odd implies leading '0' */ p = p2; debug(F111,"cmcvtdate GMT offset sign",p,gmtsign); debug(F101,"cmcvtdate GMT offset d","",d); state = 1; while (*p) { if (isdigit(*p)) { /* digit */ if (d++ > 1) { state++; d = 1; } switch (state) { case 1: zhh = zhh * 10 + (*p - '0'); break; case 2: zmm = zmm * 10 + (*p - '0'); break; default: /* Ignore seconds or fractions */ break; } } else if (*p == ':') { /* Colon */ state++; d = 0; } else if (*p == SP || *p == '(') { break; } else { p = p3; /* Maybe it's not a GMT offset. */ goto delta; /* So treat it as a delta time. */ } p++; } } debug(F110,"cmcvtdate source string after timezone",p,0); if (*p) { /* Anything left? */ p2 = p; while (*p2 == SP) /* Skip past spaces */ p2++; if (*p2 == '(') { /* RFC-822 comment? */ int pc = 1; /* paren counter */ p2++; while (*p2) { if (*p2 == ')') { if (--pc == 0) { p2++; break; } } else if (*p2 == ')') { pc++; } p2++; } while (*p2 == SP) /* Skip past spaces */ p2++; if (!*p2) /* Anything left? */ *p = NUL; /* No, erase comment */ } if (!*p2) /* Anything left? */ goto xcmdate; /* No, done. */ p = p2; delta: debug(F110,"cmcvtdate delta yyyymmdd",yyyymmdd,0); debug(F110,"cmcvtdate delta year",year,0); debug(F110,"cmcvtdate delta p",p,0); if (*p == '+' || *p == '-') { /* Delta time */ int state = NEED_DAYS; /* Start off looking for days */ char c = 0; dsign = 1; /* Get sign */ if (*p++ == '-') dsign = -1; while (*p == SP) /* Skip intervening spaces */ p++; while (state) { /* FSA to parse delta time */ if (state < 0 || !isdigit(*p)) { makestr(&cmdatemsg,"Invalid delta time"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } p2 = p; /* Get next numeric field */ while (isdigit(*p2)) p2++; c = *p2; /* And break character */ *p2 = NUL; /* Terminate the number */ switch (state) { /* Interpret according to state */ case NEED_DAYS: /* Initial */ if ((c == '-') || /* VMS format */ ((c == 'd' || c == 'D') && !isalpha(*(p2+1)))) { /* Days */ ddays = atoi(p); if (!*(p2+1)) state = 0; else /* if anything is left */ state = NEED_HRS; /* now we want hours. */ } else if ((c == 'W' || c == 'w') && !isalpha(*(p2+1))) { ddays = atoi(p) * 7; /* weeks... */ if (!*(p2+1)) state = 0; else state = NEED_HRS; } else if ((c == 'M' || c == 'm') && !isalpha(*(p2+1))) { dmonths = atoi(p); /* months... */ if (!*(p2+1)) state = 0; else state = NEED_HRS; } else if ((c == 'Y' || c == 'y') && !isalpha(*(p2+1))) { dyears = atoi(p); /* years... */ if (!*(p2+1)) state = 0; else state = NEED_HRS; } else if (c == ':') { /* delimiter is colon */ dhours = atoi(p); /* so it's hours */ state = NEED_MINS; /* now we want minutes */ } else if (!c) { /* end of string */ dhours = atoi(p); /* it's still hours */ state = 0; /* and we're done */ } else if (isalpha(c) || c == SP) { if (c == SP) { /* It's a keyword? */ p2++; /* Skip spaces */ while (*p2 == SP) p2++; } else { /* or replace first letter */ *p2 = c; } p3 = p2; /* p2 points to beginning of keyword */ while (isalpha(*p3)) /* Find end of keyword */ p3++; c = *p3; /* NUL it out so we can look it up */ if (*p3) /* p3 points to keyword terminator */ *p3 = NUL; units = lookup(timeunits,p2,nunits,NULL); if (units < 0) { makestr(&cmdatemsg,"Invalid units in delta time"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } *p2 = NUL; /* Re-terminate the number */ *p3 = c; while (*p3 == SP) /* Point at field after units */ p3++; p2 = p3; switch (units) { case TU_DAYS: ddays = atoi(p); break; case TU_WEEKS: ddays = atoi(p) * 7; break; case TU_MONTHS: dmonths = atoi(p); break; case TU_YEARS: dyears = atoi(p); break; } if (*p2) { state = NEED_HRS; p2--; } else state = 0; } else { /* Anything else */ state = -1; /* is an error */ } break; case NEED_HRS: /* Looking for hours */ debug(F000,"cmcvtdate NEED_HRS",p,c); if (c == ':') { dhours = atoi(p); state = NEED_MINS; } else if (!c) { dhours = atoi(p); state = 0; } else { state = -1; } break; case NEED_MINS: /* Looking for minutes */ if (c == ':') { dmins = atoi(p); state = NEED_SECS; } else if (!c) { dmins = atoi(p); state = 0; } else { state = -1; } break; case NEED_SECS: /* Looking for seconds */ if (c == '.') { dsecs = atoi(p); state = NEED_FRAC; } else if (!c) { dsecs = atoi(p); state = 0; } else { state = -1; } break; case NEED_FRAC: /* Fraction of second */ if (!c && rdigits(p)) { if (*p > '4') dsecs++; state = 0; } else { state = -1; } break; } if (c) /* next field if any */ p = p2 + 1; } havedelta = 1; } else { makestr(&cmdatemsg,"Extraneous material at end"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } } xcmdate: if ((t != 2 && hh > 24) || hh < 0) { /* Hour range check */ makestr(&cmdatemsg,"Invalid hours"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } if (mm > 59) { /* Minute range check */ makestr(&cmdatemsg,"Invalid minutes"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } if (ff > 0) { /* Fraction of second? */ if (ss < 59) { ss++; ff = 0; } else if (mm < 59) { ss = 0; mm++; ff = 0; } else if (hh < 24) { ss = 0; mm = 0; hh++; ff = 0; } /* Must add a day -- leave ff at 1... */ /* (DO SOMETHING ABOUT THIS LATER) */ } if (ss > 60) { /* Seconds range check */ makestr(&cmdatemsg,"Invalid seconds"); /* 60 is ok because of */ debug(F111,"cmcvtdate",cmdatemsg,-1); /* Leap Second. */ return(NULL); } if ((mm < 0 || ss < 0) || (t != 2 && (ss > 0 || mm > 0) && hh > 23)) { makestr(&cmdatemsg,"Invalid minutes or seconds"); debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } debug(F110,"cmcvtdate year",year,0); debug(F110,"cmcvtdate month",month,0); debug(F101,"cmcvtdate nday","",nday); debug(F101,"cmcvtdate hh","",hh); debug(F101,"cmcvtdate mm","",mm); debug(F101,"cmcvtdate ss","",ss); debug(F101,"cmcvtdate gmtsign","",gmtsign); debug(F101,"cmcvtdate zhh","",zhh); debug(F101,"cmcvtdate zmm","",zmm); debug(F101,"cmcvtdate isgmt","",isgmt); #ifdef ZLOCALTIME /* Handle timezone -- first convert to GMT */ zdd = 0; /* Days changed */ if (isgmt && (zmm || zhh)) { /* If GMT offset given */ long sec1, sec2, zz; sec1 = ss + 60 * mm + 3600 * hh; sec2 = gmtsign * (60 * zmm + 3600 * zhh); sec1 += sec2; if (sec1 < 0) { sec1 = 0 - sec1; zdd = 0L - (sec1 / 86400L); sec1 = sec1 % 86400L; } else if (sec1 > 86400L) { zdd = sec1 / 86400L; sec1 = sec1 % 86400L; } ss = sec1 % 60; zz = sec1 / 60; mm = zz % 60; hh = zz / 60; debug(F101,"cmcvtdate NEW hh","",hh); debug(F101,"cmcvtdate NEW mm","",mm); debug(F101,"cmcvtdate NEW dd","",zdd); /* At this point hh:mm:ss is in GMT and zdd is the calendar adjustment */ } #endif /* ZLOCALTIME */ if (yyyymmdd[0] && !year) { ckstrncpy(yearbuf,yyyymmdd,5); ckstrncpy(monbuf,&yyyymmdd[4],3); ckstrncpy(daybuf,&yyyymmdd[6],3); year = yearbuf; month = monbuf; day = daybuf; nday = atoi(daybuf); } sprintf(zbuf,"%04d%02d%02d %02d:%02d:%02d", /* SAFE */ atoi(year),atoi(month),nday,hh,mm,ss ); dp = zbuf; #ifdef ZLOCALTIME /* Now convert from GMT to local time */ if (isgmt) { /* If GMT convert to local time */ debug(F110,"cmcvtdate GMT 1",dp,0); if (zdd) { /* Apply any calendar adjustment */ long zz; zz = mjd(dp) + zdd; sprintf(zbuf,"%s %02d:%02d:%02d",mjd2date(zz),hh,mm,ss); } debug(F110,"cmcvtdate GMT 2",dp,0); if ((p = zlocaltime(dp))) { debug(F110,"cmcvtdate asctime zlocaltime",p,0); if (p) ckstrncpy(zbuf,p,18); } debug(F110,"cmcvtdate GMT 3",dp,0); for (i = 0; i < 4; i++) yearbuf[i] = dp[i]; yearbuf[4] = NUL; monbuf[0] = dp[4]; monbuf[1] = dp[5]; monbuf[2] = NUL; daybuf[0] = dp[6]; daybuf[1] = dp[7]; daybuf[2] = NUL; day = daybuf; nday = atoi(daybuf); month = monbuf; year = yearbuf; hh = atoi(&dp[9]); mm = atoi(&dp[12]); ss = atoi(&dp[15]); } #endif /* ZLOCALTIME */ #ifdef DEBUG if (deblog) { debug(F101,"cmcvtdate hour","",hh); debug(F101,"cmcvtdate minute","",mm); debug(F101,"cmcvtdate second","",ss); } #endif /* DEBLOG */ makestr(&cmdatemsg,NULL); if (havedelta) { #ifdef DEBUG if (deblog) { debug(F110,"cmcvtdate base ",dp,0); debug(F101,"cmcvtdate delta sign","",dsign); debug(F101,"cmcvtdate delta yrs ","",dyears); debug(F101,"cmcvtdate delta mos ","",dmonths); debug(F101,"cmcvtdate delta days","",ddays); debug(F101,"cmcvtdate delta hrs ","",dhours); debug(F101,"cmcvtdate delta mins","",dmins); debug(F101,"cmcvtdate delta secs","",dsecs); } #endif /* DEBLOG */ if (!(dp = cmdelta(atoi(year), atoi(month), nday, hh, mm, ss, dsign, dyears, dmonths, ddays, dhours, dmins, dsecs))) { debug(F111,"cmcvtdate",cmdatemsg,-1); return(NULL); } } xcvtdate: /* Exit point for success */ { int len, k, n; char * p; debug(F110,"cmcvtdate xcvtdate dp",dp,0); if (!dp) dp = ""; /* Shouldn't happen */ if (!*dp) return(NULL); /* ... */ len = strlen(dp); debug(F111,"cmcvtdate result",dp,len); k = cmdatebp - (char *)cmdatebuf; /* Space used */ n = CMDATEBUF - k - 1; /* Space left */ if (n < len) { /* Not enough? */ cmdatebp = cmdatebuf; /* Wrap around */ n = CMDATEBUF; } ckstrncpy(cmdatebp,dp,n); p = cmdatebp; cmdatebp += len + 1; return(p); } } int #ifdef CK_ANSIC cmvdate( char * d ) /* Verify date-time */ #else cmvdate(d) char * d; #endif /* CK_ANSIC */ { int i; if (!d) return(0); if ((int)strlen(d) != 17) return(0); for (i = 0; i < 8; i++) { if (!isdigit(d[i])) return(0); } if (!isdigit(d[9]) || !isdigit(d[10]) || !isdigit(d[12]) || !isdigit(d[13]) || !isdigit(d[15]) || !isdigit(d[16])) return(0); if (!ckstrchr(" Tt_-:",d[8])) return(0); if (d[11] != ':' && d[14] != ':') return(0); return(1); } /* c m d i f f d a t e -- Get difference between two date-times */ char * #ifdef CK_ANSIC cmdiffdate(char * d1, char * d2 ) #else cmdiffdate(d1,d2) char * d1, * d2; #endif /* CK_ANSIC */ { char d1buf[9], d2buf[9]; char x1buf[18], x2buf[18]; char * p; int hh1 = 0, mm1 = 0, ss1 = 0; int hh2 = 0, mm2 = 0, ss2 = 0; int hh, mm, ss; int sign; long jd1, jd2, jd, f1, f2, fx; static char result[24], *rp; debug(F110,"cmdiffdate d1 A",d1,0); debug(F110,"cmdiffdate d2 A",d2,0); if (!(p = cmcvtdate(d1,1))) /* Convert dates to standard format */ return(NULL); ckstrncpy(x1buf,p,18); d1 = x1buf; if (!(p = cmcvtdate(d2,1))) return(NULL); ckstrncpy(x2buf,p,18); d2 = x2buf; debug(F110,"cmdiffdate d1 B",d1,0); debug(F110,"cmdiffdate d2 B",d2,0); if (!cmvdate(d1) || !cmvdate(d2)) return(NULL); hh1 = atoi(&d1[9]); /* Get hours, minutes, and seconds */ mm1 = atoi(&d1[12]); /* for first date */ ss1 = atoi(&d1[15]); ckstrncpy(d1buf,d1,9); hh2 = atoi(&d2[9]); /* ditto for second date */ mm2 = atoi(&d2[12]); ss2 = atoi(&d2[15]); ckstrncpy(d2buf,d2,9); jd1 = mjd(d1buf); /* Get the two Julian dates */ jd2 = mjd(d2buf); f1 = ss1 + 60 * mm1 + 3600 * hh1; /* Convert first time to seconds */ f2 = ss2 + 60 * mm2 + 3600 * hh2; /* Ditto for second time */ debug(F101,"cmdiffdate jd1","",jd1); debug(F101,"cmdiffdate f1","",f1); debug(F101,"cmdiffdate jd2","",jd2); debug(F101,"cmdiffdate f2","",f2); if (jd2 > jd1 || (jd1 == jd2 && f2 > f1)) { sign = -1; if (f1 > f2) {jd2--; f2 += 86400L;} jd = jd2 - jd1; fx = f2 - f1; } else { sign = 1; if (f2 > f1) {jd1--; f1 += 86400L;} jd = jd1 - jd2; fx = f1 - f2; } debug(F111,"cmdiffdate sign jd",sign<0?"-":"+",jd); debug(F101,"cmdiffdate fx","",fx); hh = (int) (fx / 3600L); /* Convert seconds to hh:mm:ss */ mm = (int) (fx % 3600L) / 60L; ss = (int) (fx % 3600L) % 60L; rp = result; /* Format the result */ *rp++ = (sign < 0) ? '-' : '+'; if (jd != 0 && hh+mm+ss == 0) { sprintf(rp,"%ldd",jd); } else if (jd == 0) { if (ss == 0) sprintf(rp,"%d:%02d",hh,mm); else sprintf(rp,"%d:%02d:%02d",hh,mm,ss); } else { if (ss == 0) sprintf(rp,"%ldd%d:%02d",jd,hh,mm); else sprintf(rp,"%ldd%d:%02d:%02d",jd,hh,mm,ss); } debug(F110,"cmdiffdate result",result,0); return((char *)result); } #ifndef NOSPL /* s h u f f l e d a t e -- Rearrange date string */ /* Call with: A date string in standard format: yyyymmdd hh:mm:ss (time optional). Options: 1: Reformat date to yyyy-mmm-dd (mmm = English month abbreviation). 2: Reformat date to dd-mmm-yyyy (mmm = English month abbreviation). 3: Reformat as numeric yyyymmddhhmmss. 4: Reformat in asctime() format Sat Nov 26 11:10:34 2005 5: Reformat as delimited numeric yyyy:mm:dd:hh:mm:ss. Returns: Pointer to result if args valid, otherwise original arg pointer. Result is normally date and time in the given format but if called with a negative opt (-1 through -6) result is date only. */ char * #ifdef CK_ANSIC shuffledate(char * p, int opt ) #else shuffledate(p,opt) char * p; int opt; #endif /* CK_ANSIC */ { extern char * wkdays[]; int len; char ibuf[32]; static char obuf[128]; char c; int yy, dd, mm; char * monthstring = NULL; #ifdef HAVE_LOCALE #define MONTHBUFLEN 32 char monthbuf[MONTHBUFLEN]; _PROTOTYP( char * locale_monthname, (int, int) ); extern int nolocale; #endif /* HAVE_LOCALE */ int notime = 0; if (!p) p = ""; if (!*p) p = ckdate(); if (opt < 0) { /* Negative opt means no time */ notime = 1; opt = -opt; } if (opt < 1 || opt > 6) return(p); len = strlen(p); if (len < 8 || len > 31) return(p); if (opt == 4) { /* Asctime format (26 Nov 2005) */ char c, * s; long z; int k; ckstrncpy(ibuf,p,31); k = len; while (k >= 0 && ibuf[k] == CK_CR || ibuf[k] == LF) ibuf[k--] = NUL; while (k >= 0 && ibuf[k] == SP || ibuf[k] == HT) ibuf[k--] = NUL; if (k < 9) ckstrncpy(&ibuf[8]," 00:00:00",9); p = ibuf; z = mjd(p); /* Convert to modified Julian date */ z = z % 7L; if (z < 0) { z = 0 - z; k = 6 - ((int)z + 3) % 7; } else { k = ((int)z + 3) % 7; /* Day of week */ } s = wkdays[k]; obuf[0] = s[0]; /* Day of week */ obuf[1] = s[1]; obuf[2] = s[2]; obuf[3] = SP; /* Space */ c = p[6]; p[6] = NUL; mm = atoi(&ibuf[4]); /* Month */ s = moname[mm-1]; /* Name of month */ p[6] = c; obuf[4] = s[0]; /* Month */ obuf[5] = s[1]; obuf[6] = s[2]; obuf[7] = SP; /* Space */ if (p[6] == '0') /* Date of month */ obuf[8] = SP; else obuf[8] = p[6]; obuf[9] = p[7]; if (notime) { /* Just the date */ obuf[10] = p[0]; /* Year */ obuf[11] = p[1]; obuf[12] = p[2]; obuf[13] = p[3]; obuf[14] = NUL; } else { /* Date and time */ ckstrncpy(&obuf[10],&p[8],10); /* Time */ obuf[19] = SP; /* Space */ obuf[20] = p[0]; /* Year */ obuf[21] = p[1]; obuf[22] = p[2]; obuf[23] = p[3]; obuf[24] = NUL; } return((char *)obuf); } if (opt == 5) { /* 20130722 All fields delimited */ /* yyyymmdd hh:mm:ss */ /* 0123456789012345678 */ /* yyyy:mm:dd:hh:mm:ss */ char sep = ':'; int i = 0; obuf[i++] = p[0]; /* y */ obuf[i++] = p[1]; /* y */ obuf[i++] = p[2]; /* y */ obuf[i++] = p[3]; /* y */ obuf[i++] = sep; /* */ obuf[i++] = p[4]; /* m */ obuf[i++] = p[5]; /* m */ obuf[i++] = sep; /* */ obuf[i++] = p[6]; /* d */ obuf[i++] = p[7]; /* d */ if (notime) { obuf[i++] = NUL; } else { obuf[i++] = sep; /* */ obuf[i++] = p[9]; /* h */ obuf[i++] = p[10]; /* h */ obuf[i++] = sep; /* */ obuf[i++] = p[12]; /* m */ obuf[i++] = p[13]; /* m */ obuf[i++] = sep; /* */ obuf[i++] = p[15]; /* s */ obuf[i++] = p[16]; /* s */ obuf[i++] = NUL; /* end */ } return((char *)obuf); } if (opt == 3) { ckstrncpy(obuf,p,48); /* yyyymmdd hh:mm:ss */ /* 01234567890123456 */ /* yyyymmddhhmmss */ obuf[8] = obuf[9]; if (notime) { obuf[9] = NUL; } else { obuf[9] = obuf[10]; obuf[10] = obuf[12]; obuf[11] = obuf[13]; obuf[12] = obuf[15]; obuf[13] = obuf[16]; obuf[14] = NUL; } return((char *)obuf); } ckstrncpy(ibuf,p,32); c = ibuf[4]; /* Warning: not "Y10K compliant" */ ibuf[4] = NUL; if (!rdigits(ibuf)) return(p); yy = atoi(ibuf); if (yy < 1 || yy > 9999) return(p); ibuf[4] = c; c = ibuf[6]; ibuf[6] = NUL; if (!rdigits(&ibuf[4])) return(p); mm = atoi(&ibuf[4]); if (mm < 1 || mm > 12) return(p); ibuf[6] = c; c = ibuf[8]; ibuf[8] = NUL; if (!rdigits(&ibuf[6])) return(p); dd = atoi(&ibuf[6]); ibuf[8] = c; if (dd < 1 || mm > 31) return(p); #ifdef HAVE_LOCALE /* We truncate the month name to 3 characters even though some some locales use longer "short month names". Fixing this will require some redesign which can be done if ever anybody complains. */ if (!nolocale) { /* If user didn't do --nolocale */ char *s = NULL; if (opt == 1 || opt == 2) { /* Short month name */ s = locale_monthname(mm-1,1); /* Get short month name */ if (!s) s = moname[mm-1]; /* Allow for error */ ckstrncpy(monthbuf,s,MONTHBUFLEN); /* Copy it to this buffer */ monthbuf[3] = NUL; /* Truncate it at 3 */ } else { s = locale_monthname(mm-1,0); /* Get full month name */ if (!s) s = fullmonthname[mm-1]; /* Allow for error */ ckstrncpy(monthbuf,s,MONTHBUFLEN); } monthstring = monthbuf; /* Point to it */ } else #endif /* HAVE_LOCALE */ /* Otherwise use old month name table */ monthstring = (opt == 6) ? fullmonthname[mm-1] : moname[mm-1]; switch (opt) { case 1: sprintf(obuf,"%04d-%s-%02d%s",yy,monthstring,dd,&ibuf[8]); if (notime) obuf[11] = NUL; break; case 2: sprintf(obuf,"%02d-%s-%04d%s",dd,monthstring,yy,&ibuf[8]); if (notime) obuf[11] = NUL; break; case 6: sprintf(obuf,"%d %s %d%s", dd, monthstring, yy, &ibuf[8]); if (notime) { int tmp; tmp = (int)strlen(obuf) - 9; obuf[tmp] = NUL; } break; default: return(p); } return((char *)obuf); } #endif /* NOSPL */ /* C K C V T D A T E -- Like cmcvtdate(), but returns string. */ /* For use by date-related functions */ /* See calling conventions for cmcvtdate() above. */ char * #ifdef CK_ANSIC ckcvtdate(char * p, int t ) #else ckcvtdate(p,t) char * p; int t; #endif /* CK_ANSIC */ { char * s; if (!(s = cmcvtdate(p,t))) return(""); /* \fblah() error message */ else return(s); } /* C M D A T E -- Parse a date and/or time */ /* Accepts date in various formats. If the date is recognized, this routine returns 0 or greater with the result string pointer pointing to a buffer containing the date as "yyyymmdd hh:mm:ss". */ int #ifdef CK_ANSIC cmdate( char * xhlp, char * xdef, char ** xp, int quiet, xx_strp f ) #else cmdate(xhlp,xdef,xp,quiet,f) char *xhlp, *xdef, **xp; int quiet; xx_strp f; #endif /* CK_ANSIC */ { int x, rc; char *o, *s, *zq, *dp; cmfldflgs = 0; if (!xhlp) xhlp = ""; if (!xdef) xdef = ""; if (!*xhlp) xhlp = "Date and/or time"; *xp = ""; rc = cmfld(xhlp,xdef,&s,(xx_strp)0); debug(F101,"cmdate cmfld rc","",rc); if (rc < 0) return(rc); debug(F110,"cmdate 1",s,0); o = s; /* Remember what they typed. */ s = brstrip(s); debug(F110,"cmdate 2",s,0); x = 0; if (f) { /* If a conversion function is given */ char * pp; zq = atxbuf; /* do the conversion. */ pp = atxbuf; atxn = CMDBL; if ((x = (*f)(s,&zq,&atxn)) < 0) return(-2); if (!*pp) pp = xdef; if (setatm(pp,0) < 0) { if (!quiet) printf("?Evaluated date too long\n"); return(-9); } s = atxbuf; } dp = cmcvtdate(s,1); if (!dp) { if (!quiet) printf("?%s\n",cmdatemsg); return(-9); } *xp = dp; return(0); } #ifdef CK_RECALL /* Command-recall functions */ /* C M R I N I -- Initialize or change size of command recall buffer */ int #ifdef CK_ANSIC cmrini( int n ) #else cmrini(n) int n; #endif /* CK_ANSIC */ { int i; if (recall && in_recall) { /* Free old storage, if any */ for (i = 0; i < cm_recall; i++) { if (recall[i]) { free(recall[i]); recall[i] = NULL; } } free(recall); recall = NULL; } cm_recall = n; /* Set new size */ rlast = current = -1; /* Initialize pointers */ if (n > 0) { recall = (char **)malloc((cm_recall + 1) * sizeof(char *)); if (!recall) return(1); for (i = 0; i < cm_recall; i++) { recall[i] = NULL; } in_recall = 1; /* Recall buffers init'd */ } return(0); } /* C M A D D N E X T -- Force addition of next command */ VOID cmaddnext() { if (on_recall && in_recall) { /* Even if it doesn't come */ force_add = 1; /* from the keyboard */ newcmd = 1; no_recall = 0; } } /* C M G E T C M D -- Find most recent matching command */ char * #ifdef CK_ANSIC cmgetcmd( char * s ) #else cmgetcmd(s) char * s; #endif /* CK_ANSIC */ { int i; for (i = current; i >= 0; i--) { /* Search backward thru history list */ if (!recall[i]) continue; /* This one's null, skip it */ if (ckmatch(s,recall[i],0,1)) /* Match? */ return(recall[i]); /* Yes, return pointer */ } return(NULL); /* No match, return NULL pointer */ } #endif /* CK_RECALL */ /* A D D C M D -- Add a command to the recall buffer */ VOID #ifdef CK_ANSIC addcmd( char * s ) #else addcmd(s) char * s; #endif /* CK_ANSIC */ { int len = 0, nq = 0; char * p; #ifdef CKLEARN extern int learning; #endif /* CKLEARN */ if (xcmdsrc) /* Only for interactive commands */ return; if (!newcmd) /* The command has been here already */ return; /* so ignore it. */ newcmd = 0; /* It's new but do this only once. */ if (!s) s = cmdbuf; if (s[0]) len = strlen(s); if (len < 1) /* Don't save empty commands */ return; p = s; while (*p) { if (*p++ == '?') nq++; } /* Count question marks */ #ifdef CKLEARN if (learning) /* If a learned script is active */ learncmd(s); /* record this command. */ #endif /* CKLEARN */ debug(F010,"CMD(P)",s,0); /* Maybe record it in the debug log */ #ifdef CKSYSLOG if (ckxlogging) { /* Maybe record it in syslog */ if (ckxsyslog >= SYSLG_CX || ckxsyslog >= SYSLG_CM) cksyslog(SYSLG_CX, 1, "command", s, NULL); } #endif /* CKSYSLOG */ #ifdef CK_RECALL last_recall = 0; if (on_recall && /* Command recall is on? */ cm_recall > 0 && /* Recall buffer size is > 0? */ !no_recall) { /* Not not saving this command? */ if (!force_add && rlast > -1) /* If previous command was identical */ if (!strcmp(s,recall[rlast])) /* don't add another copy */ return; force_add = 0; /* Reset now in case it was set */ if (rlast >= cm_recall - 1) { /* Recall buffer full? */ int i; if (recall[0]) { /* Discard oldest command */ free(recall[0]); recall[0] = NULL; } for (i = 0; i < rlast; i++) { /* The rest */ recall[i] = recall[i+1]; /* move back */ } rlast--; /* Now we have one less */ } rlast++; /* Index of last command in buffer */ current = rlast; /* Also now the current command */ if (current >= cm_recall) { /* Shouldn't happen */ printf("?Command history error\n"); /* but if it does */ on_recall = 0; /* turn off command saving */ #ifdef COMMENT } else if (nq > 0) { /* Have at least one question mark */ recall[current] = malloc(len+nq+1); if (recall[current]) { p = recall[current]; while (*s) { if (*s == '?') *p++ = '\\'; *p++ = *s++; } *p = NUL; } #endif /* COMMENT */ } else { /* Normal case, just copy */ recall[current] = malloc(len+1); if (recall[current]) ckstrncpy(recall[current],s,len+1); } } #endif /* CK_RECALL */ } #ifdef CK_RECALL /* C M H I S T O R Y */ VOID cmhistory() { int i, lc = 1; for (i = 0; i <= current; i++) { printf(" %s\n", recall[i]); if (++lc > (cmd_rows - 2)) { /* Screen full? */ if (!askmore()) /* Do more-prompting... */ break; else lc = 0; } } } int #ifdef CK_ANSIC savhistory( char * s, int disp ) #else savhistory(s,disp) char *s; int disp; #endif /* CK_ANSIC */ { FILE * fp; int i; fp = fopen(s, disp ? "a" : "w"); if (!fp) { perror(s); return(0); } for (i = 0; i <= current; i++) fprintf(fp,"%s\n", recall[i]); fclose(fp); return(1); } #endif /* CK_RECALL */ #ifdef COMMENT /* apparently not used */ int cmgetlc(s) char * s; { /* Get leading char */ char c; while ((c = *s++) <= SP) { if (!c) break; } return(c); } #endif /* COMMENT */ /* C M C F M -- Parse command confirmation (end of line) */ /* Returns -2: User typed anything but whitespace or newline -1: Reparse needed 0: Confirmation was received */ int cmcfm() { int x, xc; debug(F101,"cmcfm: cmflgs","",cmflgs); debug(F110,"cmcfm: atmbuf",atmbuf,0); inword = xc = cc = 0; setatm("",0); /* (Probably unnecessary) */ while (cmflgs != 1) { x = gtword(0); xc += cc; switch (x) { case -9: printf("Command or field too long\n"); case -4: /* EOF */ case -2: case -1: return(x); case 1: /* End of line */ if (xc > 0) { if (xcmfdb) { return(-6); } else { printf("?Not confirmed - %s\n",atmbuf); return(-9); } } else break; /* Finish up below */ case 2: /* ESC */ if (xc == 0) { bleep(BP_WARN); continue; /* or fall thru. */ } case 0: /* Space */ if (xc == 0) /* If no chars typed, continue, */ continue; /* else fall thru. */ /* else fall thru... */ case 3: /* Question mark */ if (xc > 0) { if (xcmfdb) { return(-6); } else { printf("?Not confirmed - %s\n",atmbuf); return(-9); } } printf( "\n Press the Return or Enter key to confirm the command\n"); printf("%s%s",cmprom,cmdbuf); fflush(stdout); continue; } } debok = 1; return(0); } /* The following material supports chained parsing functions. */ /* See ckucmd.h for FDB and OFDB definitions. */ struct OFDB cmresult = { /* Universal cmfdb result holder */ NULL, /* Address of succeeding FDB struct */ 0, /* Function code */ NULL, /* String result */ 0, /* Integer result */ (CK_OFF_T)0 /* Wide result */ }; VOID #ifdef CK_ANSIC cmfdbi( struct FDB * p, /* Initialize an FDB */ int fc, char * s1, char * s2, char * s3, int n1, int n2, xx_strp f, struct keytab * k, struct FDB * nxt ) #else /* CK_ANSIC */ cmfdbi(p,fc,s1,s2,s3,n1,n2,f,k,nxt) struct FDB * p; int fc; char * s1, * s2, * s3; int n1, n2; xx_strp f; struct keytab * k; struct FDB * nxt ; #endif /* CK_ANSIC */ { p->fcode = fc; p->hlpmsg = s1; p->dflt = s2; p->sdata = s3; p->ndata1 = n1; p->ndata2 = n2; p->spf = f; p->kwdtbl = k; p->nxtfdb = nxt; } /* C M F D B -- Parse a field with several possible functions */ int #ifdef CK_ANSIC cmfdb( struct FDB * fdbin ) #else cmfdb(fdbin) struct FDB * fdbin; #endif /* CK_ANSIC */ { #ifndef NOSPL extern int x_ifnum; /* IF NUMERIC - disables warnings */ #endif /* NOSPL */ struct FDB * in = fdbin; struct OFDB * out = &cmresult; int x = 0, n, r; CK_OFF_T w = (CK_OFF_T)0; char *s, *xp, *m = NULL; int errbits = 0; xp = bp; out->fcode = -1; /* Initialize output struct */ out->fdbaddr = NULL; out->sresult = NULL; out->nresult = 0; /* Currently we make one trip through the FDBs. So if the user types Esc or Tab at the beginning of a field, only the first FDB is examined for a default. If the user types ?, help is given only for one FDB. We should search through the FDBs for all matching possibilities -- and in particular display the pertinent context-sensitive help for each function, rather than the only the first one that works, and then rewind the FDB pointer so we are not locked out of the earlier ones. */ cmfldflgs = 0; while (1) { /* Loop through the chain of FDBs */ nomsg = 1; xcmfdb = 1; s = NULL; n = 0; debug(F101,"cmfdb in->fcode","",in->fcode); switch (in->fcode) { /* Current parsing function code */ case _CMNUM: r = in->ndata1; if (r != 10 && r != 8) r = 10; #ifndef NOSPL x_ifnum = 1; /* Disables warning messages */ #endif /* NOSPL */ x = cmnum(in->hlpmsg,in->dflt,r,&n,in->spf); #ifndef NOSPL x_ifnum = 0; #endif /* NOSPL */ debug(F101,"cmfdb cmnum","",x); if (x < 0) errbits |= 1; break; case _CMNUW: /* Wide cmnum - 24 Dec 2005 */ r = in->ndata1; if (r != 10 && r != 8) r = 10; #ifndef NOSPL x_ifnum = 1; /* Disables warning messages */ #endif /* NOSPL */ x = cmnumw(in->hlpmsg,in->dflt,r,&w,in->spf); #ifndef NOSPL x_ifnum = 0; #endif /* NOSPL */ debug(F101,"cmfdb cmnumw","",w); if (x < 0) errbits |= 1; break; case _CMOFI: x = cmofi(in->hlpmsg,in->dflt,&s,in->spf); debug(F101,"cmfdb cmofi","",x); if (x < 0) errbits |= 2; break; case _CMIFI: x = cmifi2(in->hlpmsg, in->dflt, &s, &n, in->ndata1, in->sdata, in->spf, in->ndata2 ); debug(F101,"cmfdb cmifi2 x","",x); debug(F101,"cmfdb cmifi2 n","",n); if (x < 0) errbits |= 4; break; case _CMFLD: cmfldflgs = in->ndata1; x = cmfld(in->hlpmsg,in->dflt,&s,in->spf); debug(F101,"cmfdb cmfld","",x); if (x < 0) errbits |= 8; break; case _CMTXT: x = cmtxt(in->hlpmsg,in->dflt,&s,in->spf); debug(F101,"cmfdb cmtxt","",x); if (x < 0) errbits |= 16; break; case _CMKEY: x = cmkey2(in->kwdtbl, in->ndata1, in->hlpmsg,in->dflt,in->sdata,in->spf,in->ndata2); debug(F101,"cmfdb cmkey","",x); if (x < 0) errbits |= ((in->ndata2 & 4) ? 32 : 64); break; case _CMCFM: x = cmcfm(); debug(F101,"cmfdb cmcfm","",x); if (x < 0) errbits |= 128; break; default: debug(F101,"cmfdb - unexpected function code","",in->fcode); printf("?cmfdb - unexpected function code: %d\n",in->fcode); } debug(F101,"cmfdb x","",x); debug(F101,"cmfdb cmflgs","",cmflgs); debug(F101,"cmfdb crflag","",crflag); debug(F101,"cmfdb qmflag","",qmflag); debug(F101,"cmfdb esflag","",esflag); if (x > -1) { /* Success */ out->fcode = in->fcode; /* Fill in output struct */ out->fdbaddr = in; out->sresult = s; out->nresult = (in->fcode == _CMKEY) ? x : n; out->wresult = w; out->kflags = (in->fcode == _CMKEY) ? cmkwflgs : 0; debug(F111,"cmfdb out->nresult",out->sresult,out->nresult); debug(F111,"cmfdb out->wresult",out->sresult,out->wresult); nomsg = 0; xcmfdb = 0; /* debug(F111,"cmfdb cmdbuf & crflag",cmdbuf,crflag); */ if (crflag) { cmflgs = 1; } return(x); /* and return */ } in = in->nxtfdb; /* Failed, get next parsing function */ nomsg = 0; xcmfdb = 0; if (!in) { /* No more */ debug(F101,"cmfdb failure x","",x); debug(F101,"cmfdb failure errbits","",errbits); if (x == -6) x = -9; if (x == -9) { #ifdef CKROOT if (ckrooterr) m = "Off Limits"; else #endif /* CKROOT */ /* Make informative messages for a few common cases */ switch (errbits) { case 4+32: m = "Does not match filename or switch"; break; case 4+64: m = "Does not match filename or keyword"; break; case 1+32: m = "Not a number or valid keyword"; break; case 1+64: m = "Not a number or valid switch"; break; default: m = "Not valid in this position"; } printf("?%s: \"%s\"\n",m, atmbuf); } return(x); } if (x != -2 && x != -6 && x != -9 && x != -3) /* Editing or somesuch */ return(x); /* Go back and reparse */ pp = np = bp = xp; /* Back up pointers */ cmflgs = -1; /* Force a reparse */ #ifndef NOSPL if (!askflag) { /* If not executing ASK-class cmd... */ #endif /* NOSPL */ if (crflag) { /* If CR was typed, put it back */ pushc = LF; /* But as a linefeed */ } else if (qmflag) { /* Ditto for Question mark */ pushc = '?'; } else if (esflag) { /* and Escape or Tab */ pushc = ESC; } #ifndef NOSPL } #endif /* NOSPL */ } } /* C M I O F I -- Parse an input file OR the name of a nonexistent file. Replaces the commented-out version above. This one actually works and has the expected straightforward interface. */ int #ifdef CK_ANSIC cmiofi( char *xhlp, char *xdef, char **xp, int *wild, xx_strp f ) #else cmiofi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; #endif /* CK_ANSIC */ { int x; struct FDB f1, f2; cmfdbi(&f1,_CMIFI,xhlp,xdef,"",0,0,f,NULL,&f2); cmfdbi(&f2,_CMOFI,"","","",0,0,f,NULL,NULL); x = cmfdb(&f1); if (x < 0) { if (x == -3) { x = -9; printf("?Filename required\n"); } } *wild = cmresult.nresult; *xp = cmresult.sresult; return(x); } /* G T W O R D -- Gets a "word" from the command input stream */ /* Usage: retcode = gtword(brk); brk = 0 for normal word breaks (space, CR, Esc, ?) brk = 1 to add ':' and '=' (for parsing switches). These characters act as break characters only if the first character of the field is slash ('/'), i.e. switch introducer. brk = 4 to not strip comments (used only for "help #" and "help ;"). Returns: -10 Timelimit set and timed out -9 if input was too long -4 if end of file (e.g. pipe broken) -3 if null field -2 if command buffer overflows -1 if user did some deleting 0 if word terminates with SP or tab 1 if ... CR 2 if ... ESC 3 if ... ? (question mark) 4 if ... : or = and called with brk != 0 With: pp pointing to beginning of word in buffer bp pointing to after current position atmbuf containing a copy of the word cc containing the number of characters in the word copied to atmbuf */ int ungword() { /* Unget a word */ debug(F101,"ungword cmflgs","",cmflgs); if (ungw) return(0); cmfsav = cmflgs; ungw = 1; cmflgs = 0; return(0); } /* Un-un-get word. Undo ungword() if it has been done. */ VOID unungw() { debug(F010,"unungw atmbuf",atmbuf,0); if (ungw) { ungw = 0; cmflgs = cmfsav; atmbuf[0] = NUL; } } static int #ifdef CK_ANSIC gtword( int brk ) #else gtword(brk) int brk; #endif /* CK_ANSIC */ { int c; /* Current char */ int cq = 0; /* Next char */ int quote = 0; /* Flag for quote character */ int echof = 0; /* Flag for whether to echo */ int comment = 0; /* Flag for in comment */ char *cp = NULL; /* Comment pointer */ int eintr = 0; /* Flag for syscall interrupted */ int bracelvl = 0; /* nested brace counter [jrs] */ int iscontd = 0; /* Flag for continuation */ int realtty = 0; /* Stdin is really a tty */ char firstnb = NUL; char lastchar = NUL; char prevchar = NUL; char lbrace, rbrace; int dq = 0; /* Doublequote flag */ int dqn = 0; /* and count */ int isesc = 0; #ifdef FUNCTIONTEST /* September 2018 - Code to prevent spaces in function argument list to cause a word break during command parsing. Matching code also added to setatm(). */ int fndebug = 0; int fnstate = 0; /* Function-parsing state */ int fnparens = 0; /* Parens counter */ #endif /* FUNCTIONTEST */ #ifdef RTU extern int rtu_bug; #endif /* RTU */ #ifdef IKSD extern int inserver; #endif /* IKSD */ extern int kstartactive; #ifdef datageneral extern int termtype; /* DG terminal type flag */ extern int con_reads_mt; /* Console read asynch is active */ if (con_reads_mt) connoi_mt(); /* Task would interfere w/cons read */ #endif /* datageneral */ #ifdef COMMENT #ifdef DEBUG if (deblog) { debug(F101,"gtword brk","",brk); debug(F101,"gtword cmfldflgs","",cmfldflgs); debug(F101,"gtword swarg","",swarg); debug(F101,"gtword dpx","",dpx); debug(F101,"gtword echof","",echof); #ifndef NOSPL debug(F101,"gtword askflag","",askflag); debug(F101,"gtword timelimit","",timelimit); #ifndef NOLOCAL #ifndef NOXFER #ifdef CK_AUTODL debug(F101,"gtword cmdadl","",cmdadl); #endif /* CK_AUTODL */ #endif /* NOXFER */ #endif /* NOLOCAL */ #endif /* NOSPL */ } #endif /* DEBUG */ #endif /* COMMENT */ realtty = is_a_tty(0); /* Stdin is really a tty? */ if (cmfldflgs & 1) { lbrace = '('; rbrace = ')'; } else { lbrace = '{'; rbrace = '}'; } crflag = 0; qmflag = 0; esflag = 0; if (swarg) { /* No leading space for switch args */ inword = 1; swarg = 0; } if (ungw) { /* Have a word saved? */ #ifdef M_UNGW /* Experimental code to allow ungetting multiple words. */ /* See comments in ckmkey2() above. */ int x; if (np > pp) pp = np; while (*pp == SP) pp++; if (!*pp) { ungw = 0; cmflgs = cmfsav; } else { if ((x = setatm(pp,2)) < 0) { printf("?Saved word too long\n"); return(-9); } if (pp[x] >= SP) { char *p2; p2 = pp; p2 += x; while (*p2 == SP) p2++; if (*p2) { np = p2; ungword(); } } else { ungw = 0; cmflgs = cmfsav; debug(F010,"gtword ungw return atmbuf",atmbuf,0); } } return(cmflgs); #else /* You would think the following should be: while (*pp == SP) pp++; but you would be wrong -- making this change breaks GOTO. */ while (*pp++ == SP) ; if (setatm(pp,2) < 0) { printf("?Saved word too long\n"); return(-9); } ungw = 0; cmflgs = cmfsav; debug(F010,"gtword ungw return atmbuf",atmbuf,0); return(cmflgs); #endif /* M_UNGW */ } pp = np; /* Start of current field */ #ifdef FUNCTIONTEST #ifdef DEBUG if (deblog) { debug(F110,"gtword cmdbuf",cmdbuf,0); debug(F110,"gtword bp",bp,0); debug(F110,"gtword pp",pp,0); } #endif /* DEBUG */ #endif /* FUNCTIONTEST */ { /* If we are reparsing we have to recount any braces or doublequotes */ char * p = pp; char c; if (*p == '"') dq++; while ((c = *p++)) if (c == lbrace) bracelvl++; else if (c == rbrace) bracelvl--; else if (dq && c == '"') dqn++; } while (bp < cmdbuf+CMDBL) { /* Big get-a-character loop */ echof = 0; /* Assume we don't echo because */ chsrc = 0; /* character came from reparse buf. */ #ifdef BS_DIRSEP CMDIRPARSE: #endif /* BS_DIRSEP */ c = *bp; cq = *(bp+1); debug(F000,"CHAR C","",c); /* FUNCTIONTEST */ if (!c) { /* If no char waiting in reparse buf */ debug(F100,"XXX gtword no chars waiting","",0); if ((dpx #ifndef NOSPL || echostars #endif /* NOSPL */ ) && (!pushc #ifndef NOSPL || askflag #endif /* NOSPL */ )) /* Get from tty, set echo flag */ echof = 1; c = cmdgetc(timelimit); /* Read a command character. */ #ifdef DEBUG debug(F101,"gtword c","",c); #endif /* DEBUG */ if (timelimit && c < -1) { /* Timed out */ return(-10); } #ifndef NOXFER /* The following allows packet recognition in the command parser. Presently it works only for Kermit packets, and if our current protocol happens to be anything besides Kermit, we simply force it to Kermit. We don't use the APC mechanism here for mechanical reasons, and also because this way, it works even with minimally configured interactive versions. Add Zmodem later... */ #ifdef CK_AUTODL if ((!local && cmdadl) /* Autodownload enabled? */ #ifdef IKS_OPTION || TELOPT_SB(TELOPT_KERMIT).kermit.me_start #endif /* IKS_OPTION */ ) { int k; k = kstart((CHAR)c); /* Kermit S or I packet? */ if (k) { int ksign = 0; if (k < 0) { /* Minus-Protocol? */ #ifdef NOSERVER goto noserver; /* Need server mode for this */ #else ksign = 1; /* Remember */ k = 0 - k; /* Convert to actual protocol */ justone = 1; /* Flag for protocol module */ #endif /* NOSERVER */ } else justone = 0; k--; /* Adjust kstart's return value */ if (k == PROTO_K) { extern int protocol, g_proto; extern CHAR sstate; g_proto = protocol; protocol = PROTO_K; /* Crude... */ sstate = ksign ? 'x' : 'v'; cmdbuf[0] = NUL; return(-3); } } } #ifdef NOSERVER noserver: #endif /* NOSERVER */ #endif /* CK_AUTODL */ #endif /* NOXFER */ chsrc = 1; /* Remember character source is tty. */ brkchar = c; #ifdef IKSD if (inserver && c < 0) { /* End of session? */ debug(F111,"gtword c < 0","exiting",c); return(-4); /* Cleanup and terminate */ } #endif /* IKSD */ #ifdef OS2 if (c < 0) { /* Error */ if (c == -3) { /* Empty word? */ if (blocklvl > 0) /* In a block */ continue; /* so keep looking for block end */ else return(-3); /* Otherwise say we got nothing */ } else { /* Not empty word */ return(-4); /* So some kind of i/o error */ } } #else #ifdef MAC if (c == -3) /* Empty word... */ if (blocklvl > 0) continue; else return(-3); #endif /* MAC */ #endif /* OS2 */ if (c == EOF) { /* This can happen if stdin not tty. */ #ifdef EINTR /* Some operating and/or C runtime systems return EINTR for no good reason, when the end of the standard input "file" is encountered. In cases like this, we get into an infinite loop; hence the eintr counter, which is reset to 0 upon each call to this routine. */ debug(F101,"gtword EOF","",errno); if (errno == EINTR && ++eintr < 4) /* When bg'd process is */ continue; /* fg'd again. */ #endif /* EINTR */ return(-4); } c &= cmdmsk; /* Strip any parity bit */ } /* if desired. */ /* Now we have the next character */ isesc = (c == ESC); /* A real ESC? */ if (!firstnb && c > SP) { /* First nonblank */ firstnb = c; if (c == '"') /* Starts with doublequote */ dq = 1; } if (c == '"') /* Count doublequotes */ dqn++; #ifdef FUNCTIONTEST /* gtword() */ if (fnstate == 0 && c == '\\') { fnstate = 1; if (fndebug) printf("g%d%c/",fnstate,c); } else if (fnstate == 1 && c == '\\') { /* because gtword doubles the backslash */ fnstate = 1; if (fndebug) printf("g%d%c/",fnstate,c); } else if (fnstate == 1) { fnstate = (c == 'f' || c == 'F') ? 2 : 0; if (fndebug) printf("g%d%c/",fnstate,c); } else if (fnstate == 2 && isalpha(c)) { fnstate = 3; if (fndebug) printf("g%d%c/",fnstate,c); } else if (fnstate == 3 && isalpha(c)) { fnstate = 4; if (fndebug) printf("g%d%c/",fnstate,c); } else if (fnstate == 4 && c == '(') { fnstate = 5; fnparens++; if (fndebug) printf("g%d%c/",fnstate,c); } else if (fnstate == 5 && c == ')') { fnparens--; if (fnparens == 0) { fnstate = 0; } if (fndebug) printf("g%d%c/",fnstate,c); } #endif /* FUNCTIONTEST */ if (quote && (c == CK_CR || c == LF)) { /* Enter key following quote */ *bp++ = CMDQ; /* Double it */ *bp = NUL; quote = 0; } if (quote == 0) { /* If this is not a quoted character */ switch (c) { case CMDQ: /* Got the quote character itself */ if (!comment && quoting) quote = 1; /* Flag it if not in a comment */ break; case FF: /* Formfeed. */ c = NL; /* Replace with newline */ cmdclrscn(); /* Clear the screen */ break; case HT: /* Horizontal Tab */ if (comment) /* If in comment, */ c = SP; /* substitute space */ else /* otherwise */ c = ESC; /* substitute ESC (for completion) */ break; case ';': /* Trailing comment */ case '#': if (! (brk & 4) ) { /* If not keeping comments */ if (inword == 0 && quoting) { /* If not in a word */ comment = 1; /* start a comment. */ cp = bp; /* remember where it starts. */ } } break; } if (!kstartactive && /* Not in possible Kermit packet */ !comment && c == SP) { /* Space not in comment */ *bp++ = (char) c; /* deposit in buffer if not already */ debug(F101,"gtword SPACE fnstate","",fnstate); debug(F101,"gtword SPACE inword","",inword); #ifdef BEBOX if (echof) { cmdecho((char) c, 0); /* Echo what was typed. */ fflush(stdout); fflush(stderr); } #else if (echof) { cmdecho((char) c, 0); /* Echo what was typed. */ if (timelimit) fflush(stdout); } #endif /* BEBOX */ if (inword == 0 #ifdef FUNCTIONTEST && !fnstate #endif /* FUNCTIONTEST */ ) { /* If leading, gobble it. */ pp++; continue; } else { #ifdef FUNCTIONTEST if (fnstate == 5) { /* Space inside function arg list */ debug(F101,"SP in fn arglist fnstate","",fnstate); continue; } #endif /* FUNCTIONTEST */ if ((!dq && ((*pp != lbrace) || (bracelvl == 0))) || (dq && dqn > 1 && *(bp-2) == '"')) { np = bp; /* If field-terminating space, return. */ cmbptr = np; if (setatm(pp,0) < 0) { printf("?Field too long error 1\n"); debug(F111,"gtword too long #1",pp,strlen(pp)); return(-9); } brkchar = c; #ifdef FUNCTIONTEST debug(F110,"XXX atmbuf",atmbuf,0); debug(F110,"XXX pp",pp,0); debug(F101,"XXX brkchar","",c); #endif /* FUNCTIONTEST */ inword = cmflgs = 0; return(0); } continue; } } if (c == lbrace) { bracelvl++; /* debug(F101,"gtword bracelvl++","",bracelvl); */ } if (c == rbrace && bracelvl > 0) { bracelvl--; /* debug(F101,"gtword bracelvl--","",bracelvl); */ if (linebegin) blocklvl--; } if ((c == '=' || c == ':') && /* ^^^ */ !kstartactive && !comment && brk /* && (firstnb == '/') */ ) { *bp++ = (char) c; /* Switch argument separator */ /* debug(F111,"gtword switch argsep",cmdbuf,brk); */ #ifdef BEBOX if (echof) { cmdecho((char) c, 0); /* Echo what was typed. */ fflush(stdout); fflush(stderr); } #else if (echof) { cmdecho((char) c, 0); /* Echo what was typed. */ if (timelimit) fflush(stdout); } #endif /* BEBOX */ if ((*pp != lbrace) || (bracelvl == 0)) { np = bp; cmbptr = np; if (setatm(pp,2) < 0) { /* ^^^ */ printf("?Field too long error 1\n"); debug(F111,"gtword too long #1",pp,strlen(pp)); return(-9); } inword = cmflgs = 0; brkchar = c; return(4); } } if (c == LF || c == CK_CR) { /* CR or LF. */ if (echof) { cmdnewl((char)c); /* echo it. */ #ifdef BEBOX fflush(stdout); fflush(stderr); #endif /* BEBOX */ } { /* Trim trailing comment and whitespace */ char *qq; if (comment) { /* Erase comment */ while (bp >= cp) /* Back to comment pointer */ *bp-- = NUL; bp++; pp = bp; /* Adjust other pointers */ inword = 0; /* and flags */ comment = 0; cp = NULL; } qq = inword ? pp : (char *)cmdbuf; /* Erase trailing whitespace */ while (bp > qq && (*(bp-1) == SP || *(bp-1) == HT)) { bp--; /* debug(F000,"erasing","",*bp); */ *bp = NUL; } lastchar = (bp > qq) ? *(bp-1) : NUL; prevchar = (bp > qq+1) ? *(bp-2) : NUL; } if (linebegin && blocklvl > 0) /* Blank line in {...} block */ continue; linebegin = 1; /* At beginning of next line */ iscontd = prevchar != CMDQ && (lastchar == '-' || lastchar == lbrace); debug(F101,"gtword iscontd","",iscontd); if (iscontd) { /* If line is continued... */ if (chsrc) { /* If reading from tty, */ if (*(bp-1) == lbrace) { /* Check for "begin block" */ *bp++ = SP; /* Insert a space for neatness */ blocklvl++; /* Count block nesting level */ } else { /* Or hyphen */ bp--; /* Overwrite the hyphen */ } *bp = NUL; /* erase the dash, */ continue; /* and go back for next char now. */ } } else if (blocklvl > 0) { /* No continuation character */ if (chsrc) { /* But we're in a "block" */ *bp++ = ','; /* Add comma */ *bp = NUL; continue; } } else { /* No continuation, end of command. */ *bp = NUL; /* Terminate the command string. */ if (comment) { /* If we're in a comment, */ comment = 0; /* Say we're not any more, */ *cp = NUL; /* cut it off. */ } np = bp; /* Where to start next field. */ cmbptr = np; if (setatm(pp,0) < 0) { /* Copy field to atom buffer */ debug(F111,"gtword too long #2",pp,strlen(pp)); printf("?Field too long error 2\n"); return(-9); } inword = 0; /* Not in a word any more. */ crflag = 1; /* debug(F110,"gtword","crflag is set",0); */ #ifdef CK_RECALL current = rlast; #endif /* CK_RECALL */ cmflgs = 1; if (!xcmdsrc #ifdef CK_RECALL || force_add #endif /* CK_RECALL */ ) addcmd(cmdbuf); return(cmflgs); } } /* This section handles interactive help, completion, editing, and history. Rearranged as a switch statement executed only if we're at top level since there is no need for any of this within command files and macros: Aug 2000. Jun 2001: Even if at top level, skip this if the character was fetched from the reparse or recall buffer, or if stdin is redirected. */ if ((xcmdsrc == 0 /* Only at top level */ #ifndef NOSPL || askflag /* or user is typing ASK response */ #endif /* NOSPL */ ) && chsrc != 0 && realtty) { /* from the real keyboard */ /* Use ANSI / VT100 up and down arrow keys for command recall. */ if (isesc && ( #ifdef IKSD inserver #else 0 #endif /* IKSD */ #ifdef USE_ARROWKEYS || 1 #endif /* USE_ARROWKEYS */ ) ) { /* A real ESC was typed */ int x = 0; #ifndef NOARROWKEYS msleep(200); /* Wait 1/5 sec */ x = cmdconchk(); /* Was it followed by anything? */ debug(F101,"Arrowkey ESC cmdconchk","",x); if (x > 1) { /* If followed by at least 2 chars */ int c2; c2 = cmdgetc(0); /* Get the first one */ debug(F101,"Arrowkey ESC c2","",c2); if (c2 != '[' && c2 != 'O') { /* If not [ or O */ pushc = c2; /* Push it and take the ESC solo */ } else { c2 = cmdgetc(0); /* Get the second one */ debug(F101,"Arrowkey ESC c3","",c2); switch (c2) { #ifndef NORECALL case 'A': /* Up */ c = BEL; c = C_UP; break; case 'B': /* Down */ c = BEL; c = C_DN; break; case 'C': /* Right */ case 'D': /* Left */ #else default: #endif /* NORECALL */ c = BEL; /* We don't use these yet */ break; } } } #endif /* NOARROWKEYS */ } switch (c) { case '?': /* ?-Help */ #ifndef NOSPL if (askflag) /* No help in ASK response */ break; #endif /* NOSPL */ if (quoting && !kstartactive && !comment ) { cmdecho((char) c, 0); *bp = NUL; if (setatm(pp,0) < 0) { debug(F111,"gtword too long ?",pp,strlen(pp)); printf("?Too long\n"); return(-9); } qmflag = 1; return(cmflgs = 3); } case ESC: /* Esc or Tab completion */ if (!comment) { *bp = NUL; if (setatm(pp,0) < 0) { debug(F111,"gtword too long Esc",pp,strlen(pp)); printf("?Too long\n"); return(-9); } esflag = 1; return(cmflgs = 2); } else { bleep(BP_WARN); continue; } case BS: /* Character deletion */ case RUB: if (bp > cmdbuf) { /* If still in buffer... */ cmdchardel(); /* erase it. */ bp--; /* point behind it, */ if (*bp == lbrace) bracelvl--; /* Adjust brace count */ if (*bp == rbrace) bracelvl++; if ((*bp == SP) && /* Flag if current field gone */ (*pp != lbrace || bracelvl == 0)) inword = 0; *bp = NUL; /* Erase character from buffer. */ } else { /* Otherwise, */ bleep(BP_WARN); cmres(); /* and start parsing a new command. */ *bp = *atmbuf = NUL; } if (pp < bp) continue; else return(cmflgs = -1); case LDEL: /* ^U, line deletion */ while ((bp--) > cmdbuf) { cmdchardel(); *bp = NUL; } cmres(); /* Restart the command. */ *bp = *atmbuf = NUL; inword = 0; return(cmflgs = -1); case WDEL: /* ^W, word deletion */ if (bp <= cmdbuf) { /* Beep if nothing to delete */ bleep(BP_WARN); cmres(); *bp = *atmbuf = NUL; return(cmflgs = -1); } bp--; /* Back up over any trailing nonalphanums */ /* This is dependent on ASCII collating sequence */ /* but isalphanum() is not available everywhere. */ for ( ; (bp >= cmdbuf) && ((*bp < '0') || ((*bp > '9') && (*bp < '@')) || ((*bp > 'Z') && (*bp < 'a')) || (*bp > 'z')); bp-- ) { cmdchardel(); *bp = NUL; } /* Now delete back to rightmost remaining nonalphanum */ for ( ; (bp >= cmdbuf) && (*bp) ; bp--) { if ((*bp < '0') || (*bp > '9' && *bp < '@') || (*bp > 'Z' && *bp < 'a') || (*bp > 'z')) break; cmdchardel(); *bp = NUL; } bp++; inword = 0; return(cmflgs = -1); case RDIS: { /* ^R, redisplay */ char *cpx; char cx; *bp = NUL; printf("\n%s",cmprom); cpx = cmdbuf; while ((cx = *cpx++)) { cmdecho(cx,0); } fflush(stdout); continue; } #ifndef NOLASTFILE case VT: if (lastfile) { printf("%s ",lastfile); #ifdef GEMDOS fflush(stdout); #endif /* GEMDOS */ inword = cmflgs = 0; addbuf(lastfile); /* Supply default. */ if (setatm(lastfile,0) < 0) { printf("Last name too long\n"); if (np) free(np); return(-9); } } else { /* No default */ bleep(BP_WARN); } return(0); #endif /* NOLASTFILE */ } #ifdef CK_RECALL if (on_recall && /* Reading commands from keyboard? */ (cm_recall > 0) && /* Saving commands? */ (c == C_UP || c == C_UP2)) { /* Go up one */ if (last_recall == 2 && current > 0) current--; if (current < 0) { /* Nowhere to go, */ bleep(BP_WARN); continue; } if (recall[current]) { /* We have a previous command */ while ((bp--) > cmdbuf) { /* Erase current line */ cmdchardel(); *bp = NUL; } ckstrncpy(cmdbuf,recall[current],CMDBL); #ifdef OSK fflush(stdout); write(fileno(stdout), "\r", 1); printf("%s%s",cmprom,cmdbuf); #else printf("\r%s%s",cmprom,cmdbuf); #endif /* OSK */ current--; } last_recall = 1; return(cmflgs = -1); /* Force a reparse */ } if (on_recall && /* Reading commands from keyboard? */ (cm_recall > 0) && /* Saving commands? */ (c == C_DN)) { /* Down one */ int x = 1; if (last_recall == 1) x++; if (current + x > rlast) { /* Already at bottom, beep */ bleep(BP_WARN); continue; } current += x; /* OK to go down */ if (recall[current]) { while ((bp--) > cmdbuf) { /* Erase current line */ cmdchardel(); *bp = NUL; } ckstrncpy(cmdbuf,recall[current],CMDBL); #ifdef OSK fflush(stdout); write(fileno(stdout), "\r", 1); printf("%s%s",cmprom,cmdbuf); #else printf("\r%s%s",cmprom,cmdbuf); #endif /* OSK */ last_recall = 2; return(cmflgs = -1); /* Force reparse */ } } #endif /* CK_RECALL */ } if (c < SP && quote == 0) { /* Any other unquoted control char */ if (!chsrc) { /* If cmd file, point past it */ bp++; } else { bleep(BP_WARN); } continue; /* continue, don't put in buffer */ } linebegin = 0; /* Not at beginning of line */ #ifdef BEBOX if (echof) { cmdecho((char) c, 0); /* Echo what was typed. */ fflush (stdout); fflush(stderr); } #else #ifdef NOSPL if (echof || chsrc) #else if (echof || (echostars && chsrc)) #endif /* NOSPL */ cmdecho((char) c, 0); /* Echo what was typed. */ #endif /* BEBOX */ } else { /* This character was quoted. */ int qf = 1; quote = 0; /* Unset the quote flag. */ /* debug(F000,"gtword quote 0","",c); */ /* Quote character at this level is only for SP, ?, and controls */ /* If anything else was quoted, leave quote in, and let */ /* the command-specific parsing routines handle it, e.g. \007 */ if (c > 32 && c != '?' && c != RUB && chsrc != 0) { /* debug(F000,"gtword quote 1","",c); */ *bp++ = CMDQ; /* Deposit \ if it came from tty */ qf = 0; /* and don't erase it from screen */ linebegin = 0; /* Not at beginning of line */ #ifdef BS_DIRSEP /* This is a hack to handle "cd \" or "cd foo\" on OS/2 and similar systems. If we were called from cmdir() and the previous character was the quote character, i.e. backslash, and this character is the command terminator, then we stuff an extra backslash into the buffer without echoing, then we stuff the carriage return back in again, and go back and process it, this time with the quote flag off. */ } else if (dirnamflg && (c == CK_CR || c == LF || c == SP)) { /* debug(F000,"gtword quote 2","",c); */ *bp++ = CMDQ; linebegin = 0; /* Not at beginning of line */ *bp = (c == SP ? SP : CK_CR); goto CMDIRPARSE; #endif /* BS_DIRSEP */ } #ifdef BEBOX if (echof) { cmdecho((char) c, qf); /* Echo what was typed. */ fflush (stdout); fflush(stderr); } #else if (echof) cmdecho((char) c, qf); /* Now echo quoted character */ #endif /* BEBOX */ /* debug(F111,"gtword quote",cmdbuf,c); */ } #ifdef COMMENT if (echof) cmdecho((char) c,quote); /* Echo what was typed. */ #endif /* COMMENT */ if (!comment) inword = 1; /* Flag we're in a word. */ if (quote) continue; /* Don't deposit quote character. */ if (c != NL) { /* Deposit command character. */ *bp++ = (char) c; /* and make sure there is a NUL */ #ifdef COMMENT *bp = NUL; /* after it */ #endif /* COMMENT */ } } /* End of big while */ bleep(BP_WARN); printf("?Command too long, maximum length: %d.\n",CMDBL); cmflgs = -2; return(-9); } /* Utility functions */ /* A D D B U F -- Add the string pointed to by cp to the command buffer */ static int #ifdef CK_ANSIC addbuf( char * cp ) #else addbuf(cp) char *cp; #endif /* CK_ANSIC */ { int len = 0; while ((*cp != NUL) && (bp < cmdbuf+CMDBL)) { *bp++ = *cp++; /* Copy and */ len++; /* count the characters. */ } *bp++ = SP; /* Put a space at the end */ *bp = NUL; /* Terminate with a null */ np = bp; /* Update the next-field pointer */ cmbptr = np; return(len); /* Return the length */ } /* S E T A T M -- Deposit a token in the atom buffer. */ /* Break on space, newline, carriage return, or NUL. Call with: cp = Pointer to string to copy to atom buffer. fcode = 0 means break on whitespace or EOL. fcode = 1 means don't break on space. fcode = 2 means break on space, ':', or '='. fcode = 3 means copy the whole string. Null-terminate the result. Return length of token, and also set global "cc" to this length. Return -1 if token was too long. */ static int #ifdef CK_ANSIC setatm( char *cp, int fcode ) #else setatm(cp,fcode) char *cp; int fcode; #endif /* CK_ANSIC */ { char *ap, *xp, *dqp = NULL, lbrace, rbrace; int bracelvl = 0, dq = 0; int c; /* current char */ #ifdef FUNCTIONTEST /* September 2018 - Code to prevent spaces in function argument list to cause a word break during command parsing. Matching code also added to setatm(). */ int fnstate = 0; /* Function-parsing state */ int fnparens = 0; /* Parens counter */ int fndebug = 0; #endif /* FUNCTIONTEST */ register char * s; register int n = 0; #ifdef FUNCTIONTEST /* printf("---------------------------------\n"); printf("SETATM...\n"); printf("CP=[%s]\n",cp); */ #endif /* FUNCTIONTEST */ if (cmfldflgs & 1) { /* Handle grouping */ lbrace = '('; rbrace = ')'; } else { lbrace = '{'; rbrace = '}'; } cc = 0; /* Character counter */ ap = atmbuf; /* Address of atom buffer */ s = cp; while (*s++) n++; /* Save a call to strlen */ if (n > ATMBL) { printf("?Command buffer overflow\n"); return(-1); } /* debug(F111,"setatm",cp,n); */ if (cp == ap) { /* In case source is atom buffer */ xp = atybuf; /* make a copy */ #ifdef COMMENT strncpy(xp,ap,ATMBL); /* so we can copy it back, edited. */ cp = xp; #else s = ap; while ((*xp++ = *s++)) ; /* We already know it's big enough */ cp = xp = atybuf; #endif /* COMMENT */ } *ap = NUL; /* Zero the atom buffer */ if (fcode == 1) { /* Trim trailing blanks */ while (--n >= 0 && cp[n] == SP) ; cp[n+1] = NUL; } while (*cp == SP) { /* Trim leading spaces */ cp++; n--; } if (*cp == '"') { /* Starts with doublequote? */ dq = 1; dqp = cp; } while (*cp) { c = *cp; #ifdef FUNCTIONTEST /* setatm() */ if (fnstate == 0 && c == '\\') { fnstate = 1; if (fndebug) printf("s%d%c/",fnstate,c); } else if (fnstate == 1) { fnstate = (c == 'f' || c == 'F') ? 2 : 0; if (fndebug) printf("s%d%c/",fnstate,c); } else if (fnstate == 2 && isalpha(c)) { fnstate = 3; if (fndebug) printf("s%d%c/",fnstate,c); } else if (fnstate == 3 && isalpha(c)) { fnstate = 4; if (fndebug) printf("s%d%c/",fnstate,c); } else if (fnstate == 4 && c == '(') { fnstate = 5; fnparens++; if (fndebug) printf("s%d%c/",fnstate,c); } else if (fnstate == 5 && c == ')') { fnparens--; if (fnparens == 0) { fnstate = 0; } if (fndebug) printf("s%d%c/",fnstate,c); } #endif /* FUNCTIONTEST */ if (*cp == lbrace) bracelvl++; else if (*cp == rbrace) bracelvl--; if (bracelvl < 0) bracelvl = 0; if (bracelvl == 0) { if (dq) { if (*cp == SP || *cp == HT) { if (cp > dqp+1) { if (*(cp-1) == '"' && *(cp-2) != CMDQ) { break; } } } } else if ((*cp == SP || *cp == HT) && fcode != 1 && fcode != 3) { #ifdef FUNCTIONTEST if (fnstate == 0) #endif /* FUNCTIONTEST */ break; } if ((fcode == 2) && (*cp == '=' || *cp == ':')) break; if ((fcode != 3) && (*cp == LF || *cp == CK_CR)) break; } *ap++ = *cp++; cc++; } *ap = NUL; /* Terminate the string. */ #ifdef FUNCTIONTEST /* printf("ATMBUF=[%s]\n", atmbuf); */ #endif /* FUNCTIONTEST */ /* debug(F111,"setatm result",atmbuf,cc); */ return(cc); /* Return length. */ } /* These functions attempt to hide system dependencies from the mainline code in gtword(). Dummy arg for cmdgetc() needed for compatibility with coninc(), ttinc(), etc, since a pointer to this routine can be passed in place of those to tn_doop(). No longer static. Used by askmore(). Fri Aug 20 15:03:34 1999. */ #define CMD_CONINC /* How we get keyboard chars */ int #ifdef CK_ANSIC cmdgetc( int timelimit ) /* Get a character from the tty. */ #else cmdgetc(timelimit) int timelimit; #endif /* CK_ANSIC */ { int c; #ifdef IKSD extern int inserver; #endif /* IKSD */ #ifdef CK_LOGIN extern int x_logged; #endif /* CK_LOGIN */ #ifdef TNCODE static int got_cr = 0; extern int ckxech; int tx = 0, is_tn = 0; #endif /* TNCODE */ if (pushc #ifndef NOSPL && !askflag #endif /* NOSPL */ ) { debug(F111,"cmdgetc()","pushc",pushc); c = pushc; pushc = NUL; if (xcmfdb && c == '?') /* Don't echo ? twice if chaining. */ cmdchardel(); return(c); } #ifdef datageneral { char ch; c = dgncinb(0,&ch,1); /* -1 is EOF, -2 TO, * -c is AOS/VS error */ if (c == -2) { /* timeout was enabled? */ resto(channel(0)); /* reset timeouts */ c = dgncinb(0,&ch,1); /* retry this now! */ } if (c < 0) return(-4); /* EOF or some error */ else c = (int) ch & 0177; /* Get char without parity */ /* echof = 1; */ } #else /* Not datageneral */ #ifndef MINIX2 if ( #ifdef IKSD (!local && inserver) || #endif /* IKSD */ timelimit > 0) { #ifdef TNCODE GETNEXTCH: is_tn = !pushc && !local && sstelnet; #endif /* TNCODE */ #ifdef COMMENT c = coninc(timelimit > 0 ? 1 : 0); #else /* COMMENT */ /* This is likely to break the asktimeout... */ c = coninc(timelimit); #endif /* COMMENT */ /* debug(F101,"cmdgetc coninc","",c); */ #ifdef TNCODE if (c >= 0 && is_tn) { /* Server-side Telnet */ switch (c) { case IAC: /* debug(F111,"gtword IAC","c",c); */ got_cr = 0; if ((tx = tn_doop((CHAR)(c & 0xff),ckxech,coninc)) == 0) { goto GETNEXTCH; } else if (tx <= -1) { /* I/O error */ /* If there was a fatal I/O error then ttclos() */ /* has been called and the next GETNEXTCH attempt */ /* will be !is_tn since ttclos() sets sstelnet = 0 */ doexit(BAD_EXIT,-1); /* (or return(-4)? */ } else if (tx == 1) { /* ECHO change */ ckxech = dpx = 1; /* Get next char */ goto GETNEXTCH; } else if (tx == 2) { /* ECHO change */ ckxech = dpx = 0; /* Get next char */ goto GETNEXTCH; } else if (tx == 3) { /* Quoted IAC */ c = 255; /* proceeed with it. */ } #ifdef IKS_OPTION else if (tx == 4) { /* IKS State Change */ goto GETNEXTCH; } #endif /* IKS_OPTION */ else if (tx == 6) { /* Remote Logout */ doexit(GOOD_EXIT,0); } else { goto GETNEXTCH; /* Unknown, get next char */ } break; #ifdef COMMENT case CR: if (!TELOPT_U(TELOPT_BINARY)) { if (got_cr) { /* This means the sender is violating Telnet */ /* protocol because we received two CRs in a */ /* row without getting either LF or NUL. */ /* This will not solve the problem but it */ /* will at least allow two CRs to do something */ /* whereas before the user would have to guess */ /* to send LF or NUL after the CR. */ debug(F100,"gtword CR telnet error","",0); c = LF; } else { debug(F100,"gtword skipping CR","",0); got_cr = 1; /* Remember a CR was received */ goto GETNEXTCH; } } else { debug(F100,"gtword CR to LF","",0); c = LF; } break; case LF: if (!TELOPT_U(TELOPT_BINARY)) { got_cr = 0; debug(F100,"gtword LF","",0); } else { if (got_cr) { got_cr = 0; debug(F100,"gtword skipping LF","",0); goto GETNEXTCH; } } break; case NUL: if (!TELOPT_U(TELOPT_BINARY) && got_cr) { c = LF; debug(F100,"gtword NUL to LF","",0); } else { debug(F100,"gtword NUL","",0); } got_cr = 0; break; #else /* COMMENT */ case CK_CR: if ( !TELOPT_U(TELOPT_BINARY) && got_cr ) { /* This means the sender is violating Telnet */ /* protocol because we received two CRs in a */ /* row without getting either LF or NUL. */ /* This will not solve the problem but it */ /* will at least allow two CRs to do something */ /* whereas before the user would have to guess */ /* to send LF or NUL after the CR. */ debug(F100,"gtword CR telnet error","",0); } else { got_cr = 1; /* Remember a CR was received */ } /* debug(F100,"gtword CR to LF","",0); */ c = LF; break; case LF: if (got_cr) { got_cr = 0; /* debug(F100,"gtword skipping LF","",0); */ goto GETNEXTCH; } break; case NUL: if (got_cr) { got_cr = 0; /* debug(F100,"gtword skipping NUL","",0); */ goto GETNEXTCH; #ifdef COMMENT } else { debug(F100,"gtword NUL","",0); #endif /* COMMENT */ } break; #endif /* COMMENT */ #ifdef IKSD case ETX: /* Ctrl-C... */ case EOT: /* EOT = EOF */ if (inserver #ifdef CK_LOGIN && !x_logged #endif /* CK_LOGIN */ ) return(-4); break; #endif /* IKSD */ default: got_cr = 0; } } #endif /* TNCODE */ } else { #ifdef OS2 c = coninc(0); #else /* OS2 */ #ifdef CMD_CONINC #undef CMD_CONINC #endif /* CMD_CONINC */ c = getchar(); #endif /* OS2 */ } #else /* MINIX2 */ #undef getc #ifdef CMD_CONINC #undef CMD_CONINC #endif /* CMD_CONINC */ c = getc(stdin); /* debug(F101,"cmdgetc getc","",c); */ #endif /* MINIX2 */ #ifdef RTU if (rtu_bug) { #ifdef CMD_CONINC #undef CMD_CONINC #endif /* CMD_CONINC */ c = getchar(); /* RTU doesn't discard the ^Z */ rtu_bug = 0; } #endif /* RTU */ #endif /* datageneral */ return(c); /* Return what we got */ } /* #ifdef USE_ARROWKEYS */ /* Mechanism to use for peeking into stdin buffer */ #ifndef USE_FILE_CNT /* stdin->__cnt */ #ifndef USE_FILE__CNT /* Note: two underscores */ #ifdef HPUX /* HPUX 7-11 */ #ifndef HPUX5 #ifndef HPUX6 #define USE_FILE__CNT #endif /* HPUX6 */ #endif /* HPUX5 */ #else #ifdef ANYSCO /* SCO UNIX, OSR5, Unixware, etc */ #ifndef OLD_UNIXWARE /* But not Unixware 1.x or 2.0 */ #ifndef UNIXWARE2 /* or 2.1.0 */ #define USE_FILE__CNT #endif /* UNIXWARE2 */ #endif /* OLD_UNIXWARE */ #endif /* ANYSCO */ #endif /* HPUX */ #endif /* USE_FILE__CNT */ #endif /* USE_FILE_CNT */ #ifndef USE_FILE_R /* stdin->_r */ #ifndef USE_FILE_CNT #ifndef USE_FILE__CNT #ifdef BSD44 /* {Free,Open,Net}BSD, BSDI */ #define USE_FILE_R #endif /* BSD44 */ #endif /* USE_FILE__CNT */ #endif /* USE_FILE_CNT */ #endif /* USE_FILE_R */ #ifndef USE_FILE_R /* stdin->_cnt */ #ifndef USE_FILE_CNT #ifndef USE_FILE__CNT #define USE_FILE_CNT /* Everybody else (but Linux) */ #endif /* USE_FILE__CNT */ #endif /* USE_FILE_CNT */ #endif /* USE_FILE_R */ /* c m d c o n c h k How many characters are waiting to be read at the console? Normally conchk() would tell us, but in Unix and VMS cmdgetc() uses stdio getchar(), thus bypassing coninc()/conchk(), so we have to peek into the stdin buffer, which is totally nonportable. Which is why this routine is, at least for now, used only for checking for arrow-key sequences from the keyboard after an ESC was read. Wouldn't it be nice if the stdio package had a function that returned the number of bytes waiting to be read from its buffer? Returns 0 or greater always. */ int cmdconchk() { int x = 0, y; y = pushc ? 1 : 0; /* Have command character pushed? */ #ifdef OS2 x = conchk(); /* Check device-driver buffer */ if (x < 0) x = 0; #else /* OS2 */ #ifdef CMD_CONINC /* See cmdgetc() */ x = conchk(); /* Check device-driver buffer */ if (x < 0) x = 0; #else /* CMD_CONINC */ /* Here we must look inside the stdin buffer - highly platform dependent */ #ifdef __FILE_defined /* glibc 2.28 1 Aug 2018 */ x = (int) ((stdin->_IO_read_end) - (stdin->_IO_read_ptr)); debug(F101,"cmdconchk __FILE_defined","",x); #else /* __FILE_defined */ #ifdef _IO_file_flags /* Linux (glibc 2.28 removed this symbol */ x = (int) ((stdin->_IO_read_end) - (stdin->_IO_read_ptr)); debug(F101,"cmdconchk _IO_file_flags","",x); #else /* _IO_file_flags */ #ifdef USE_FILE_CNT /* Traditional */ #ifdef VMS debug(F101,"cmdconchk (*stdin)->_cnt","",(*stdin)->_cnt); x = (*stdin)->_cnt; #else #ifdef NOARROWKEYS debug(F101,"cmdconchk NOARROWKEYS x","",0); #else debug(F101,"cmdconchk stdin->_cnt","",stdin->_cnt); x = stdin->_cnt; /* THIS BLOWS UP IN GLIBC >= 2.28 */ #endif /* NOARROWKEYS */ #endif /* VMS */ if (x == 0) x = conchk(); if (x < 0) x = 0; #else /* USE_FILE_CNT */ #ifdef USE_FILE__CNT /* HP-UX */ debug(F101,"cmdconchk stdin->__cnt","",stdin->__cnt); x = stdin->__cnt; if (x == 0) x = conchk(); if (x < 0) x = 0; #else /* USE_FILE_CNT */ #ifdef USE_FILE_R /* FreeBSD, OpenBSD, etc */ debug(F101,"cmdconchk stdin->_r","",stdin->_r); x = stdin->_r; if (x == 0) x = conchk(); if (x < 0) x = 0; /* Fill in any others here... */ #endif /* USE_FILE_R */ #endif /* USE_FILE__CNT */ #endif /* USE_FILE_CNT */ #endif /* _IO_file_flags */ #endif /* __FILE_defined */ #endif /* CMD_CONINC */ #endif /* OS2 */ return(x + y); } /* #endif */ /* USE_ARROWKEYS */ static VOID cmdclrscn() { /* Clear the screen */ ck_cls(); } static VOID /* What to echo at end of command */ #ifdef CK_ANSIC cmdnewl(char c) #else cmdnewl(c) char c; #endif /* CK_ANSIC */ /* cmdnewl */ { #ifdef OS2 #ifdef IKSD extern int inserver; if (inserver && c == LF) putchar(CK_CR); #endif /* IKSD */ #endif /* OS2 */ putchar(c); /* c is the terminating character */ #ifdef WINTCP /* what is this doing here? */ if (c == CK_CR) putchar(NL); #endif /* WINTCP */ /* A.A. Chernov, who sent in changes for FreeBSD, said we also needed this for SVORPOSIX because "setup terminal by termios and curses does not convert \r to \n, so additional \n needed in newline function." But it is also very likely to result in unwanted blank lines. */ #ifdef BSD44 if (c == CK_CR) putchar(NL); #endif /* BSD44 */ #ifdef COMMENT /* OS2 no longer needs this as all CR are converted to NL in coninc() */ /* This eliminates the ugly extra blank lines discussed above. */ #ifdef OS2 if (c == CK_CR) putchar(NL); #endif /* OS2 */ #endif /* COMMENT */ #ifdef aegis if (c == CK_CR) putchar(NL); #endif /* aegis */ #ifdef AMIGA if (c == CK_CR) putchar(NL); #endif /* AMIGA */ #ifdef datageneral if (c == CK_CR) putchar(NL); #endif /* datageneral */ #ifdef GEMDOS if (c == CK_CR) putchar(NL); #endif /* GEMDOS */ #ifdef STRATUS if (c == CK_CR) putchar(NL); #endif /* STRATUS */ } static VOID cmdchardel() { /* Erase a character from the screen */ #ifndef NOSPL if (!echostars) #endif /* NOSPL */ if (!dpx) return; #ifdef datageneral /* DG '\b' is EM (^y or \031) */ if (termtype == 1) /* Erase a character from non-DG screen, */ dgncoub(1,"\010 \010",3); else #endif /* datageneral */ printf("\b \b"); #ifdef GEMDOS fflush(stdout); #else #ifdef BEBOX fflush(stdout); #endif /* BEBOX */ #endif /* GEMDOS */ } static VOID #ifdef CK_ANSIC cmdecho(char c, int quote) #else cmdecho(c,quote) char c; int quote; #endif /* CK_ANSIC */ { /* cmdecho */ #ifdef NOSPL if (!dpx) return; #else if (!echostars) { if (!dpx) return; } else { c = (char)echostars; } #endif /* NOSPL */ /* Echo tty input character c */ if (quote) { putchar(BS); putchar(SP); putchar(BS); #ifdef isprint putchar((CHAR) (isprint(c) ? c : '^' )); #else putchar((CHAR) ((c >= SP && c < DEL) ? c : '^')); #endif /* isprint */ } else { putchar(c); } #ifdef OS2 if (quote==1 && c==CK_CR) putchar((CHAR) NL); #endif /* OS2 */ if (timelimit) fflush(stdout); } /* Return pointer to current position in command buffer. */ char * cmpeek() { return(np); } #ifdef CK_ANSIC /* static function prototypes - fdc 30 November 2022 */ static int addbuf( char * ); static int gtword( int ); static int setatm( char *, int ); static int test( int, int ); #endif /* CK_ANSIC */ /* X X E S C -- Interprets backslash codes */ /* Returns the int value of the backslash code if it is > -1 and < 256 */ /* and updates the string pointer to first character after backslash code. */ /* If the argument is invalid, leaves pointer unchanged and returns -1. */ int #ifdef CK_ANSIC xxesc( char ** s ) /* Expand backslash escapes */ #else xxesc(s) char **s; #endif /* CK_ANSIC */ { int x, y, brace, radix; /* Returns the int value */ char hd = '9'; /* Highest digit in radix */ char *p; p = *s; /* pointer to beginning */ if (!p) return(-1); /* watch out for null pointer */ x = *p++; /* character at beginning */ if (x != CMDQ) return(-1); /* make sure it's a backslash code */ x = *p; /* it is, get the next character */ if (x == '{') { /* bracketed quantity? */ p++; /* begin past bracket */ x = *p; brace = 1; } else brace = 0; switch (x) { /* Start interpreting */ case 'd': /* Decimal radix indicator */ case 'D': p++; /* Just point past it and fall thru */ case '0': /* Starts with digit */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': radix = 10; /* Decimal */ hd = '9'; /* highest valid digit */ break; case 'o': /* Starts with o or O */ case 'O': radix = 8; /* Octal */ hd = '7'; /* highest valid digit */ p++; /* point past radix indicator */ break; case 'x': /* Starts with x or X */ case 'X': radix = 16; /* Hexadecimal */ p++; /* point past radix indicator */ break; default: /* All others */ #ifdef COMMENT *s = p+1; /* Treat as quote of next char */ return(*p); #else return(-1); #endif /* COMMENT */ } /* For OS/2, there are "wide" characters required for the keyboard * binding, i.e \644 and similar codes larger than 255 (byte). * For this purpose, give up checking for < 256. If someone means * \266 should result in \26 followed by a "6" character, he should * always write \{26}6 anyway. Now, return only the lower byte of * the result, i.e. 10, but eat up the whole \266 sequence and * put the wide result 266 into a global variable. Yes, that's not * the most beautiful programming style but requires the least * amount of changes to other routines. */ if (*p == '{') { /* Sun May 11 20:00:40 2003 */ brace = 1; /* Allow {} after radix indicator */ p++; } if (radix <= 10) { /* Number in radix 8 or 10 */ for ( x = y = 0; (*p) && (*p >= '0') && (*p <= hd) #ifdef OS2 && (y < 5) && (x*radix < KMSIZE); /* the maximum needed value \8196 is 4 digits long */ /* while as octal it requires \1377, i.e. 5 digits */ #else && (y < 3) && (x*radix < 256); #endif /* OS2 */ p++,y++) { x = x * radix + (int) *p - 48; } #ifdef OS2 wideresult = x; /* Remember wide result */ x &= 255; #endif /* OS2 */ if (y == 0 || x > 255) { /* No valid digits? */ *s = p; /* point after it */ return(-1); /* return failure. */ } } else if (radix == 16) { /* Special case for hex */ if ((x = unhex(*p++)) < 0) { *s = p - 1; return(-1); } if ((y = unhex(*p++)) < 0) { *s = p - 2; return(-1); } x = ((x << 4) & 0xF0) | (y & 0x0F); #ifdef OS2 wideresult = x; if ((y = unhex(*p)) >= 0) { p++; wideresult = ((x << 4) & 0xFF0) | (y & 0x0F); x = wideresult & 255; } #endif /* OS2 */ } else x = -1; if (brace && *p == '}' && x > -1) /* Point past closing brace, if any */ p++; *s = p; /* Point to next char after sequence */ return(x); /* Return value of sequence */ } int /* Convert hex string to int */ #ifdef CK_ANSIC unhex(char x) #else unhex(x) char x; #endif /* CK_ANSIC */ /* unhex */ { if (x >= '0' && x <= '9') /* 0-9 is offset by hex 30 */ return(x - 0x30); else if (x >= 'A' && x <= 'F') /* A-F offset by hex 37 */ return(x - 0x37); else if (x >= 'a' && x <= 'f') /* a-f offset by hex 57 */ return(x - 0x57); /* (obviously ASCII dependent) */ else return(-1); } /* L O O K U P -- Lookup the string in the given array of strings */ /* Call this way: v = lookup(table,word,n,&x); table - a 'struct keytab' table. cmd - the target string to look up in the table (a.k.a word) n - the number of elements in the table. if n is negative, this desgnates a numeric-order table instead of an alphabetic one (e.g. for "set speed") x - address of an integer for returning the table array index, or NULL if you don't need a table index. The keyword table must be arranged in ascending alphabetical order; alphabetic case doesn't matter but letters are treated as lowercase for purposes of ordering; thus "^" and "_" come *before* the letters, not after them. Returns the keyword's associated value (zero or greater) if found, with the variable x set to the keyword-table index. If is lookup() is not successful, it returns: -3 if nothing to look up (target was null), -2 if ambiguous, -1 if not found. A match is successful if the target matches a keyword exactly, or if the target is a prefix of exactly one keyword. It is ambiguous if the target matches two or more keywords from the table. Lookup() is the critical routine in scripts and so is optimized with a simple static cache plus some other tricks. */ #ifdef USE_LUCACHE /* Lookup cache */ extern int lusize; /* (initialized in ckuus5.c) */ extern char * lucmd[]; extern int luval[]; extern int luidx[]; extern struct keytab * lutab[]; long luhits = 0L; long lucalls = 0L; long xxhits = 0L; long luloop = 0L; #endif /* USE_LUCACHE */ int #ifdef CK_ANSIC lookup( struct keytab table[], char *cmd, int n, int *x ) #else lookup(table,cmd,n,x) char *cmd; struct keytab table[]; int n, *x; #endif /* CK_ANSIC */ { register int i, m; int v, len, cmdlen = 0; char c = NUL, c1, *s; /* Get 1st char of search object, if it's null return -3. */ if (!cmd || n < 1) /* Defense de nullarg */ return(-3); c1 = *cmd; /* First character */ if (!c1) /* Make sure there is one */ return(-3); if (isupper(c1)) /* If letter make it lowercase */ c1 = tolower(c1); #ifdef USE_LUCACHE /* lookup() cache */ m = lusize; lucalls++; /* Count this lookup() call */ for (i = 0; i < m; i++) { /* Loop thru cache */ if (*(lucmd[i]) == c1) { /* Same as 1st char of search item? */ if (lutab[i] == table) { /* Yes - same table too? */ if (!strcmp(cmd,lucmd[i])) { /* Yes - compare */ if (x) *x = luidx[i]; /* Match - return index */ luhits++; /* Count cache hit */ return(luval[i]); /* Return associated value */ } } } } #endif /* USE_LUCACHE */ /* Not null, not in cache, look it up */ s = cmd; while (*s++) cmdlen++; /* Length of target */ /* Quick binary search to find last table entry whose first character is lexically less than the first character of the search object. This is the starting point of the next loop, which must go in sequence since it compares adjacent table entries. */ if (n < 5) { /* Not worth it for small tables */ i = 0; } else { int lo = 0; int hi = n; int count = 0; while (lo+2 < hi && ++count < 12) { i = lo + ((hi - lo) / 2); c = *(table[i].kwd); if (isupper(c)) c = tolower(c); if (c < c1) { lo = i; } else { hi = i; } } i = (c < c1) ? lo+1 : lo; #ifdef USE_LUCACHE if (i > 0) xxhits++; #endif /* USE_LUCACHE */ } for ( ; i < n-1; i++) { #ifdef USE_LUCACHE luloop++; #endif /* USE_LUCACHE */ v = 0; c = *(table[i].kwd); if (c) { if (isupper(c)) c = tolower(c); /* The following is a big performance booster but makes it */ /* absolutely essential that all lookup() tables are in order. */ if (c > c1) /* Leave early if past our mark */ return(-1); #ifdef DEBUG /* Use LOG DEBUG to check */ if (deblog) { if (ckstrcmp(table[i].kwd,table[i+1].kwd,0,0) > 0) { printf("TABLE OUT OF ORDER [%s] [%s]\n", table[i].kwd,table[i+1].kwd); } } #endif /* DEBUG */ if (c == c1) { len = 0; s = table[i].kwd; while (*s++) len++; if ((len == cmdlen && !ckstrcmp(table[i].kwd,cmd,len,0)) || ((v = !ckstrcmp(table[i].kwd,cmd,cmdlen,0)) && ckstrcmp(table[i+1].kwd,cmd,cmdlen,0))) { if (x) *x = i; return(table[i].kwval); } } else v = 0; } if (v) { /* Ambiguous */ if (x) *x = i; /* Set index of first match */ return(-2); } } /* Last (or only) element */ if (!ckstrcmp(table[n-1].kwd,cmd,cmdlen,0)) { if (x) *x = n-1; /* debug(F111,"lookup",table[i].kwd,table); */ return(table[n-1].kwval); } else return(-1); } /* n l o o k u p Like lookup, but for a list of numbers sorted in numeric, rather than alphabetic, order, as in SET SPEED. All entries in the table must be numeric strings (integer or floating point) -- not numbers. */ int #ifdef CK_ANSIC nlookup( struct keytab table[], char *word, int n, int * x ) #else nlookup(table,word,n,x) char *word; struct keytab table[]; int n, *x; #endif /* CK_ANSIC */ { register int i; int kwdlen, wordlen = 0, matches = 0, maxlen = 0; char * s = word; int tmp = 0; int firstmatch = -1; int lastmatch = -1; int lastlen = 0; char * this = NULL; /* Get 1st char of search object, if it's null return -3. */ debug(F111,"nlookup",word,n); while (*s++) wordlen++; /* Length of word to look up */ if (!wordlen) { /* Make sure there is a word */ return(-3); } s = word; /* Pointer to target word */ debug(F111,"nlookup wordlen",s,wordlen); /* Word to look up and length */ for (i = 0; i < n; i++) { /* Loop through the table */ this = table[i].kwd; if (!isfloat(this,0)) { /* If this happens the table is not numeric when it should be */ printf("NOT A NUMBER: %s\n",this); *x = -1; return(-1); } kwdlen = (int)strlen(this); /* Keyword table entry length */ maxlen = kwdlen; if (wordlen > maxlen) maxlen = wordlen; #ifdef COMMENT /* This can crash if locale not set */ tmp = ckstrcmp(this,word,maxlen,0); #else tmp = strncmp(this,word,wordlen); #endif /* COMMENT */ if (tmp) { debug(F111,"nlookup no match",table[lastmatch].kwd,tmp); } else { debug(F111,">>> nlookup match",this,wordlen); debug(F101,">>> nlookup kwdlen","",kwdlen); if (kwdlen == wordlen) { /* this works */ debug(F111,"nlookup DIRECT HIT",word,table[i].kwval); *x = i; /* Direct hit */ return(table[i].kwval); /* Done */ return(i); } matches++; /* Count matches */ if (firstmatch < 0) /* Remember first match */ firstmatch = i; lastmatch = i; /* Remember last match */ lastlen = kwdlen; /* and last keyword length */ } } if (i > n) i = 0; /* Loop exhausted makes i too large by one */ switch(matches) { case 0: /* No matches */ *x = -1; return(-1); case 1: /* One match */ *x = lastmatch; return(table[lastmatch].kwval); default: /* Multiple matches: ambiguous */ *x = firstmatch; return(-2); } } /* x l o o k u p Like lookup, but requires a full (but case-independent) match and does NOT require the table to be in order. */ int #ifdef CK_ANSIC xlookup( struct keytab table[], char *cmd, int n, int * x ) #else xlookup(table,cmd,n,x) struct keytab table[]; char *cmd; int n, *x; #endif /* CK_ANSIC */ { register int i; int len, cmdlen, one = 0; register char c, c2, * s, * s2; if (!cmd) cmd = ""; /* Check args */ if (!*cmd || n < 1) return(-3); c = *cmd; /* First char of string to look up */ if (!*(cmd+1)) { /* Special handling for 1-char names */ cmdlen = 1; if (isupper(c)) c = tolower(c); one = 1; } else { cmdlen = 0; s = cmd; while (*s++) cmdlen++; c = *cmd; if (isupper(c)) c = tolower(c); } if (cmdlen < 1) return(-3); for (i = 0; i < n; i++) { s = table[i].kwd; /* This entry */ if (!s) s = ""; if (!*s) continue; /* Empty table entry */ c2 = *s; if (isupper(c2)) c2 = tolower(c2); if (c != c2) continue; /* First char doesn't match */ if (one) { /* Name is one char long */ if (!*(s+1)) { if (x) *x = i; *cmd = c; return(table[i].kwval); /* So is table entry */ } } else { /* Otherwise do string comparison */ s2 = s; len = 0; while (*s2++) len++; if (len == cmdlen && !ckstrcmp(s,cmd,-1,0)) { if (x) *x = i; return(table[i].kwval); } } } return(-1); } /* Reverse lookup */ char * #ifdef CK_ANSIC rlookup( struct keytab table[], int n, int x ) #else rlookup(table,n,x) struct keytab table[]; int n, x; #endif /* CK_ANSIC */ { int i; for (i = 0; i < n; i++) { if (table[i].kwval == x) return(table[i].kwd); } return(NULL); } int #ifdef CK_ANSIC cmdsquo( int x ) #else cmdsquo(x) int x; #endif /* CK_ANSIC */ { quoting = x; return(1); } int cmdgquo() { return(quoting); } #endif /* NOICP */ ckucmd.h000664 045065 024037 00000022375 14767402050 012620 0ustar00fdckermit000000 000000 /* C K U C M D . H -- Header file for interactive command parser */ /* Author: Frank da Cruz Columbia University Kermit Project, New York City. Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Note: the name of these files really should be ckccmd.h and ckccmd.c because they are for all platforms, not just Unix. But "don't fix what ain't broke". Previous update: Sat Sep 24 14:05:17 2022 -fdc Removed redundant arrow-key #ifdefs (they only need to be in ckcdeb.h) Last update: Sat Sep 23 20:19:19 2023 -fdc Raised CMDBL and TMPBUFSIZ from 4092 to 16384 for SunOS 4 */ #ifndef CKUCMD_H #define CKUCMD_H /* Command recall */ #ifdef pdp11 /* Not enough room for this */ #ifndef NORECALL #define NORECALL #endif /* NORECALL */ #endif /* pdp11 */ #ifdef DYNAMIC /* Dynamic command buffers */ /* Use malloc() to allocate the many command-related buffers in ckucmd.c. */ #ifndef DCMDBUF #ifndef NORECALL #define NORECALL #endif /* NORECALL */ #endif /* DCMDBUF */ #ifndef NORECALL #define CK_RECALL #else #ifdef CK_RECALL #undef CK_RECALL #endif /* CK_RECALL */ #endif /* NORECALL */ #else #ifndef NORECALL #define NORECALL #endif /* NORECALL */ #endif /* DYNAMIC */ #ifdef NORECALL #ifdef CK_RECALL #undef CK_RECALL #endif /* CK_RECALL */ #endif /* NORECALL */ /* Special getchars */ #ifdef VMS #ifdef getchar /* This is for VMS GCC */ #undef getchar #endif /* getchar */ #define getchar() vms_getchar() int vms_getchar(void); #endif /* VMS */ #ifdef aegis #undef getchar #define getchar() coninc(0) #endif /* aegis */ #ifdef AMIGA #undef getchar #define getchar() coninc(0) #endif /* AMIGA */ #ifdef Plan9 #undef getchar #define getchar() coninc(0) #undef putchar #define putchar(c) conoc(c) #undef printf #define printf conprint #endif /* Plan9 */ /* Sizes of things */ #ifndef CMDDEP #ifdef BIGBUFOK #define CMDDEP 64 /* Maximum command recursion depth */ #else #define CMDDEP 20 #endif /* BIGBUFOK */ #endif /* CMDDEP */ #define HLPLW 78 /* Width of ?-help line */ #define HLPCW 19 /* Width of ?-help column */ #define HLPBL 100 /* Help string buffer length */ #ifdef BIGBUFOK #define ATMBL 10238 /* Command atom buffer length */ #else #ifdef NOSPL #define ATMBL 256 #else #define ATMBL 1024 #endif /* NOSPL */ #endif /* BIGBUFOK */ #ifndef CMDBL #ifdef NOSPL /* No script programming language, save some space */ #define CMDBL 608 /* Command buffer length */ #else #ifdef BIGBUFOK #define CMDBL 32763 #else #ifdef SUNOS4 /* fdc 23 September 2023 */ #define CMDBL 16384 #else #define CMDBL 4092 #endif /* SUNOS4 */ #endif /* BIGBUFOK */ #endif /* NOSPL */ #endif /* CMDBL */ /* Special characters */ #define RDIS 0022 /* Redisplay (^R) */ #define LDEL 0025 /* Delete line (^U) */ #define WDEL 0027 /* Delete word (^W) */ #ifdef CK_RECALL #define C_UP 0020 /* Go Up in recall buffer (^P) */ #define C_UP2 0002 /* Alternate Go Up (^B) for VMS */ #define C_DN 0016 /* Go Down in recall buffer (^N) */ #endif /* CK_RECALL */ /* Keyword flags (bits, powers of 2) */ #define CM_INV 1 /* Invisible keyword */ #define CM_ABR 2 /* Abbreviation for another keyword */ #define CM_HLP 4 /* Help-only keyword */ #define CM_ARG 8 /* An argument is required */ #define CM_NOR 16 /* No recall for this command */ #define CM_PRE 32 /* Long-form cmdline arg for prescan */ #define CM_PSH 64 /* Command disabled if nopush */ #define CM_LOC 128 /* Command disabled if nolocal */ /* A long-form command line option is a keyword using the regular struct keytab and lookup mechanisms. Flags that make sense in this context are CM_ARG, indicating this option requires an argument (operand), and CM_PRE, which means this option must be processed before the initialization file. The absence of CM_PRE means the option is to be processed after the initialization file in the normal manner. */ /* Token flags (numbers) */ #define CMT_COM 0 /* Comment (; or #) */ #define CMT_SHE 1 /* Shell escape (!) */ #define CMT_LBL 2 /* Label (:) */ #define CMT_FIL 3 /* Indirect filespec (@) (not used) */ /* Path separator for path searches */ #ifdef OS2 #define PATHSEP ';' #else #ifdef UNIX #define PATHSEP ':' #else #define PATHSEP ',' #endif /* UNIX */ #endif /* OS2 */ #ifndef CK_KEYTAB #define CK_KEYTAB /* Keyword Table Template perhaps already defined in ckcdeb.h */ struct keytab { /* Keyword table */ char *kwd; /* Pointer to keyword string */ int kwval; /* Associated value */ int flgs; /* Flags (as defined above) */ }; #endif /* CK_KEYTAB */ /* String preprocessing function */ #ifdef CK_ANSIC /* ANSI C */ #ifdef M_SYSV /* SCO Microsoft C wants no args */ typedef int (*xx_strp)(); #else typedef int (*xx_strp)(char *, char **, int *); #endif /* M_SYSV */ #else /* Not ANSI C */ typedef int (*xx_strp)(); #endif /* CK_ANSIC */ /* FLDDB struct */ typedef struct FDB { int fcode; /* Function code */ char * hlpmsg; /* Help message */ char * dflt; /* Default */ char * sdata; /* Additional string data */ int ndata1; /* Additional numeric data 1 */ int ndata2; /* Additional numeric data 2 */ xx_strp spf; /* String processing function */ struct keytab * kwdtbl; /* Keyword table */ struct FDB * nxtfdb; /* Pointer to next alternative */ } fdb; typedef struct OFDB { struct FDB * fdbaddr; /* Address of succeeding FDB struct */ int fcode; /* Function code */ char * sresult; /* String result */ int nresult; /* Integer result */ int kflags; /* Keyword flags if any */ CK_OFF_T wresult; /* Long integer ("wide") result */ } ofdb; #ifndef CKUCMD_C extern struct OFDB cmresult; #endif /* CKUCMD_C */ /* Codes for primary parsing function */ #define _CMNUM 0 /* Number */ #define _CMOFI 1 /* Output file */ #define _CMIFI 2 /* Input file */ #define _CMFLD 3 /* Arbitrary field */ #define _CMTXT 4 /* Text string */ #define _CMKEY 5 /* Keyword */ #define _CMCFM 6 /* Confirmation */ #define _CMDAT 7 /* Date/time */ #define _CMNUW 8 /* Wide version of cmnum */ /* Function prototypes */ _PROTOTYP( int xxesc, (char **) ); _PROTOTYP( int cmrini, (int) ); _PROTOTYP( VOID cmsetp, (char *) ); _PROTOTYP( VOID cmsavp, (char [], int) ); _PROTOTYP( char * cmgetp, (void) ); _PROTOTYP( VOID prompt, (xx_strp) ); _PROTOTYP( VOID pushcmd, (char *) ); _PROTOTYP( VOID cmres, (void) ); _PROTOTYP( VOID cmini, (int) ); _PROTOTYP( int cmgbrk, (void) ); _PROTOTYP( int cmgkwflgs, (void) ); _PROTOTYP( int cmpush, (void) ); _PROTOTYP( int cmpop, (void) ); _PROTOTYP( VOID untab, (char *) ); _PROTOTYP( int cmnum, (char *, char *, int, int *, xx_strp ) ); _PROTOTYP( int cmnumw, (char *, char *, int, CK_OFF_T *, xx_strp ) ); _PROTOTYP( int cmofi, (char *, char *, char **, xx_strp ) ); _PROTOTYP( int cmifi, (char *, char *, char **, int *, xx_strp ) ); _PROTOTYP( int cmiofi, (char *, char *, char **, int *, xx_strp ) ); _PROTOTYP( int cmifip,(char *, char *, char **, int *, int, char *, xx_strp )); _PROTOTYP( int cmifi2,(char *,char *,char **,int *,int,char *,xx_strp,int )); _PROTOTYP( int cmdir, (char *, char *, char **, xx_strp ) ); _PROTOTYP( int cmdirp, (char *, char *, char **, char *, xx_strp ) ); _PROTOTYP( int cmfld, (char *, char *, char **, xx_strp ) ); _PROTOTYP( int cmtxt, (char *, char *, char **, xx_strp ) ); _PROTOTYP( int cmkey, (struct keytab [], int, char *, char *, xx_strp) ); _PROTOTYP( int cmkeyx, (struct keytab [], int, char *, char *, xx_strp) ); _PROTOTYP( int cmkey2,(struct keytab [],int,char *,char *,char *,xx_strp,int)); _PROTOTYP( int cmswi, (struct keytab [], int, char *, char *, xx_strp) ); _PROTOTYP( int cmdate,(char *, char *, char **, int, xx_strp) ); _PROTOTYP( char * cmpeek, (void) ); _PROTOTYP( int cmfdb, (struct FDB *) ); _PROTOTYP( VOID cmfdbi, (struct FDB *, int, char *, char *, char *, int, int, xx_strp, struct keytab *, struct FDB *) ); _PROTOTYP( int chktok, (char *) ); _PROTOTYP( int cmcfm, (void) ); _PROTOTYP( int lookup, (struct keytab [], char *, int, int *) ); _PROTOTYP( VOID kwdhelp, (struct keytab[],int,char *,char *,char *,int,int) ); _PROTOTYP( int ungword, (void) ); _PROTOTYP( VOID unungw, (void) ); _PROTOTYP( int cmdsquo, (int) ); _PROTOTYP( int cmdgquo, (void) ); _PROTOTYP( char * ckcvtdate, (char *, int) ); _PROTOTYP( int cmdgetc, (int)); #ifndef NOARROWKEYS _PROTOTYP( int cmdconchk, (void) ); #endif /* NOARROWKEYS */ #ifdef CK_RECALL _PROTOTYP( char * cmgetcmd, (char *) ); _PROTOTYP( VOID addcmd, (char *) ); _PROTOTYP( VOID cmaddnext, (void) ); #endif /* CK_RECALL */ _PROTOTYP( char * cmcvtdate, (char *, int) ); _PROTOTYP( char * cmdiffdate, (char *, char *) ); _PROTOTYP( char * cmdelta, (int, int,int,int,int,int,int,int,int,int,int,int,int )); _PROTOTYP( char * shuffledate, (char *, int) ); _PROTOTYP( int filhelp, (int, char *, char *, int, int) ); _PROTOTYP( int xfilhelp, (int, char *, char *, int, int, int, char *, char *, char *, char *, CK_OFF_T, CK_OFF_T, int, int, char **) ); _PROTOTYP( int delta2sec, (char *, long *) ); #ifdef DCMDBUF _PROTOTYP( int cmsetup, (void) ); #endif /* DCMDBUF */ #endif /* CKUCMD_H */ /* End of ckucmd.h */ ckucns.c000664 045065 024037 00000232130 14767402053 012626 0ustar00fdckermit000000 000000 #include "ckcsym.h" char *connv = "CONNECT Command for UNIX:select(), 10.0.143, 15 Apr 2023"; /* C K U C N S -- Terminal connection to remote system, for UNIX */ /* Author: Frank da Cruz , Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ /* This version of the UNIX CONNECT module uses select(), which is required for Kerberos encryption. Thus it can be used only on UNIX systems that support select() on both TCP/IP and serial connections. A separate module that uses a completely portable fork() structure can be used on systems where select() is not available or does not work as required. */ #include "ckcdeb.h" /* Common things first */ #ifndef NOLOCAL #ifdef OSF13 #ifdef CK_ANSIC #ifdef _NO_PROTO #undef _NO_PROTO #endif /* _NO_PROTO */ #endif /* CK_ANSIC */ #endif /* OSF13 */ #include /* Error numbers */ #ifndef NOTIMEH #include /* For FD_blah */ #ifdef SYSTIMEH /* (IRIX 5.3) */ #include #endif /* SYSTIMEH */ #endif /* NOTIMEH */ #ifdef BSD42HACK /* Why is this necessary? */ #ifndef DCLTIMEVAL #define DCLTIMEVAL #endif /* DCLTIMEVAL */ #endif /* BSD42HACK */ /* Kermit-specific includes */ #include "ckcasc.h" /* ASCII characters */ #include "ckcker.h" /* Kermit things */ #include "ckucmd.h" /* For xxesc() prototype */ #include "ckcnet.h" /* Network symbols */ #include "ckuusr.h" #ifndef NOCSETS #include "ckcxla.h" /* Character set translation */ #endif /* NOCSETS */ #ifdef BEBOX #include #include #include #endif /* BEBOX */ #include /* Signals */ /* All the following is for select()... */ #ifdef CKTIDLE /* Timeouts only for SET TERM IDLE */ #ifndef DCLTIMEVAL #ifdef UNIXWARE #ifndef UW7 #define DCLTIMEVAL #endif /* UW7 */ #endif /* UNIXWARE */ #endif /* DCLTIMEVAL */ #ifdef DCLTIMEVAL /* Declare timeval ourselves */ struct timeval { long tv_sec; long tv_usec; }; #else /* !DCLTIMEVAL */ #ifndef NOSYSTIMEBH #ifdef SYSTIMEBH #include #endif /* SYSTIMEBH */ #endif /* NOSYSTIMEBH */ #endif /* DCLTIMEVAL */ #endif /* CKTIDLE */ #ifndef SCO_OSR504 #ifdef SELECT_H #include #endif /* SELECT_H */ #endif /* SCO_OSR504 */ #ifndef FD_SETSIZE #ifdef CK_FORWARD_X #define FD_SETSIZE 256 #else #define FD_SETSIZE 32 #endif /* CK_FORWARD_X */ #endif /* FD_SETSIZE */ #ifdef HPUX #ifndef HPUX10 #ifndef HPUX1100 /* The three interior args to select() are (int *) rather than (fd_set *) */ #ifndef INTSELECT #define INTSELECT #endif /* INTSELECT */ #endif /* HPUX1100 */ #endif /* HPUX10 */ #endif /* HPUX */ #ifdef CK_AUTHENTICATION #include "ckuath.h" /* fdc 2021-12-17 */ #endif /* CK_AUTHENTICATION */ #include "ckcfnp.h" /* Prototypes (must be last) */ /* Internal function prototypes */ #ifdef NEWFTP #endif /* NEWFTP */ _PROTOTYP( VOID ttflux, (void) ); _PROTOTYP( VOID doesc, (char) ); _PROTOTYP( int hconne, (void) ); #ifndef NOSHOW _PROTOTYP( VOID shomdm, (void) ); #endif /* NOSHOW */ _PROTOTYP( static int kbget, (void) ); _PROTOTYP( static int ckcputf, (void) ); /* External variables */ extern struct ck_p ptab[]; extern int local, escape, duplex, parity, flow, seslog, sessft, debses, mdmtyp, ttnproto, cmask, cmdmsk, network, nettype, sosi, tnlm, xitsta, what, ttyfd, ttpipe, quiet, backgrd, pflag, tt_crd, tt_lfd, tn_nlm, ttfdflg, tt_escape, justone, carrier, ttpty, hwparity; #ifndef NODIAL extern int dialmhu, dialsta; #endif /* NODIAL */ #ifdef CKLEARN extern FILE * learnfp; extern int learning; static ULONG learnt1; static char learnbuf[LEARNBUFSIZ] = { NUL, NUL }; static int learnbc = 0; static int learnbp = 0; static int learnst = 0; #endif /* CKLEARN */ extern long speed; extern char ttname[], sesfil[], myhost[], *ccntab[]; #ifdef TNCODE extern int tn_b_nlm, tn_rem_echo; #endif /* TNCODE */ #ifdef CK_TRIGGER extern char * tt_trigger[], * triggerval; #endif /* CK_TRIGGER */ #ifdef CKTIDLE extern int tt_idlelimit, tt_idleact; extern char * tt_idlestr; static int idlelimit = 0; #endif /* CKTIDLE */ extern int cx_status; /* CONNECT status code */ extern int nopush; #ifdef CK_APC extern int apcactive; /* Application Program Command (APC) */ extern int apcstatus; /* items ... */ static int apclength = 0; #ifdef DCMDBUF extern char *apcbuf; #else extern char apcbuf[]; #endif /* DCMDBUF */ static int apcbuflen = APCBUFLEN - 2; extern int protocol; #endif /* CK_APC */ #ifndef NOXFER extern int autodl; /* Auto download */ #endif /* NOXFER */ #ifdef CK_AUTODL extern CHAR ksbuf[]; extern CHAR stchr; extern int kstartactive; #endif /* CK_AUTODL */ #ifdef CK_ENCRYPTION extern int me_auth; #endif /* CK_ENCRYPTION */ #ifdef CK_XYZ #ifdef XYZ_INTERNAL static int zmdlok = 1; /* Zmodem autodownloads available */ #else static int zmdlok = 0; /* Depends on external protocol def */ #endif /* XYZ_INTERNAL */ #else static int zmdlok = 0; /* Not available at all */ #endif /* CK_XYZ */ #ifndef NOSETKEY /* Keyboard mapping */ extern KEY *keymap; /* Single-character key map */ extern MACRO *macrotab; /* Key macro pointer table */ static MACRO kmptr = NULL; /* Pointer to current key macro */ #endif /* NOSETKEY */ /* Global variables local to this module */ static int active = 0, quitnow = 0, /* Q was typed */ dohangup = 0, /* H was typed */ inshift = 0, /* SO/SI shift states */ outshift = 0; static char ecbuf[10], *ecbp; /* Escape char buffer & pointer */ #ifdef CK_SMALL #define IBUFL 1536 /* Input buffer length */ #else #define IBUFL 4096 #endif /* CK_SMALL */ static int obc = 0; /* Output buffer count */ #ifndef OXOS #define OBUFL 1024 /* Output buffer length */ #else #define OBUFL IBUFL #endif /* OXOS */ #ifdef BIGBUFOK #define TMPLEN 4096 /* Temporary message buffer length */ #else #define TMPLEN 200 #endif /* BIGBUFOK */ #ifdef DYNAMIC static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */ #else static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN]; #endif /* DYNAMIC */ #ifdef TNCODE static char tnopt[4]; #endif /* TNCODE */ #ifdef DYNAMIC static char *ibp; /* Input buffer pointer */ #else static char *ibp = ibuf; /* Input buffer pointer */ #endif /*DYNAMIC */ static int ibc = 0; /* Input buffer count */ #ifdef DYNAMIC static char *obp; /* Output buffer pointer */ #else static char *obp = obuf; /* Output buffer pointer */ #endif /* DYNAMIC */ /* Character-set items */ static int unicode = 0; #ifndef NOCSETS #ifdef CK_ANSIC /* ANSI C prototypes... */ extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */ extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */ static CHAR (*sxo)(CHAR); /* Local translation functions */ static CHAR (*rxo)(CHAR); /* for output (sending) terminal chars */ static CHAR (*sxi)(CHAR); /* and for input (receiving) terminal chars. */ static CHAR (*rxi)(CHAR); #else /* Not ANSI C... */ extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */ extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */ static CHAR (*sxo)(); /* Local translation functions */ static CHAR (*rxo)(); /* for output (sending) terminal chars */ static CHAR (*sxi)(); /* and for input (receiving) terminal chars. */ static CHAR (*rxi)(); #endif /* CK_ANSIC */ extern int language; /* Current language. */ static int langsv; /* For remembering language setting. */ extern struct csinfo fcsinfo[]; /* File character set info. */ extern int tcsr, tcsl; /* Terminal character sets, remote & local. */ static int tcs; /* Intermediate ("transfer") character set. */ static int tcssize = 0; /* Size of tcs */ #ifdef UNICODE /* UTF-8 support */ #ifdef CK_ANSIC extern int (*xl_ufc[MAXFCSETS+1])(USHORT); /* Unicode to FCS */ extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */ extern int (*xuf)(USHORT); /* Translation function UCS to FCS */ extern USHORT (*xfu)(CHAR); /* Translation function FCS to UCS */ #else extern int (*xl_ufc[MAXFCSETS+1])(); extern USHORT (*xl_fcu[MAXFCSETS+1])(); extern int (*xuf)(); extern USHORT (*xfu)(); #endif /* CK_ANSIC */ #endif /* UNICODE */ #endif /* NOCSETS */ static int printing = 0; /* We do not need to parse and recognize escape sequences if we are being built without character-set support AND without APC support. */ #ifdef NOESCSEQ #ifdef XPRINT #undef XPRINT #endif /* XPRINT */ #else /* NOESCSEQ not defined from outside */ #ifdef NOCSETS /* No character sets */ #ifndef CK_APC /* No APC */ #ifndef XPRINT /* No transparent printing */ #define NOESCSEQ /* So no escape sequence recognizer */ #endif /* XPRINT */ #endif /* CK_APC */ #endif /* NOCSETS */ #endif /* NOESCSEQ */ /* inesc[] and oldesc[] made global 2010/03/01 for INPUT command */ static int escseq = 0; /* 1 = Recognizer is active */ /* static */ int inesc[2] = { 0, 0 }; /* State of sequence recognizer */ /* static */ int oldesc[2] = { -1, -1 }; /* Previous state of recognizer */ #ifdef NOESCSEQ #define ES_NORMAL 0 /* Normal, not in an escape sequence */ #define chkaes(x,y) 0 #else /* As of C-Kermit 5A(178), the CONNECT command skips past ANSI escape sequences to avoid translating the characters within them. This allows the CONNECT command to work correctly with a host that uses a 7-bit ISO 646 national character set, in which characters like '[' would normally be converted to accented letters, ruining the terminal's interpretation (and generation) of escape sequences. As of 5A(190), the CONNECT command responds to APC escape sequences (ESC _ text ESC \) if the user SETs TERMINAL APC ON or UNCHECKED, and the program was built with CK_APC defined. Non-ANSI/ISO-compliant escape sequences are not handled. */ /* States for the escape-sequence recognizer. */ #define ES_NORMAL 0 /* Normal, not in an escape sequence */ #define ES_GOTESC 1 /* Current character is ESC */ #define ES_ESCSEQ 2 /* Inside an escape sequence */ #define ES_GOTCSI 3 /* Inside a control sequence */ #define ES_STRING 4 /* Inside DCS,OSC,PM, or APC string */ #define ES_TERMIN 5 /* 1st char of string terminator */ /* ANSI escape sequence handling. Only the 7-bit form is treated, because translation is not a problem in the 8-bit environment, in which all GL characters are ASCII and no translation takes place. So we don't check for the 8-bit single-character versions of CSI, DCS, OSC, APC, or ST. Here is the ANSI sequence recognizer state table, followed by the code that implements it. Definitions: CAN = Cancel 01/08 Ctrl-X SUB = Substitute 01/10 Ctrl-Z DCS = Device Control Sequence 01/11 05/00 ESC P CSI = Control Sequence Introducer 01/11 05/11 ESC [ ST = String Terminator 01/11 05/12 ESC \ OSC = Operating System Command 01/11 05/13 ESC ] PM = Privacy Message 01/11 05/14 ESC ^ APC = Application Program Command 01/11 05/15 ESC _ ANSI escape sequence recognizer: State Input New State ; Commentary NORMAL (start) ; Start in NORMAL state (any) CAN NORMAL ; ^X cancels (any) SUB NORMAL ; ^Z cancels NORMAL ESC GOTESC ; Begin escape sequence NORMAL other ; NORMAL control or graphic character GOTESC ESC ; Start again GOTESC [ GOTCSI ; CSI GOTESC P STRING ; DCS introducer, consume through ST GOTESC ] STRING ; OSC introducer, consume through ST GOTESC ^ STRING ; PM introducer, consume through ST GOTESC _ STRING ; APC introducer, consume through ST GOTESC 0..~ NORMAL ; 03/00 through 17/14 = Final character GOTESC other ESCSEQ ; Intermediate or ignored control character ESCSEQ ESC GOTESC ; Start again ESCSEQ 0..~ NORMAL ; 03/00 through 17/14 = Final character ESCSEQ other ; Intermediate or ignored control character GOTCSI ESC GOTESC ; Start again GOTCSI @..~ NORMAL ; 04/00 through 17/14 = Final character GOTCSI other ; Intermediate char or ignored control char STRING ESC TERMIN ; Maybe have ST STRING other ; Consume all else TERMIN \ NORMAL ; End of string TERMIN other STRING ; Still in string */ #ifdef XPRINT /* Transparent print support */ /* We can't just print each byte as it comes in because then the printer-off sequence would be sent to the printer. Thus we have to buffer up escape sequences and print them only when they are complete AND we know they are not the printer-off sequence. All printing is done via zsoutx(ZMFILE,s,n). This allows for strings that contain NULs. Don't mix calls to zsoutx() with calls to zchout(), or the output will be scrambled. Also note that when printing a saved-up escape sequence, we never print its final character because that will be printed in the mainline code, upon return from chkaes(). Note that the printer-on sequence is passed to the screen; this is unavoidable, since we don't know what it is until after we get to the end, and for screen display purposes we can't buffer up escape sequences for numerous reasons. Therefore we also must output the printer-off sequence, otherwise a real terminal or emulator will be stuck in print mode. */ extern int tt_print; #define ESCBUFLEN 63 static char escbuf[ESCBUFLEN+1] = { NUL, NUL }; static int escbufc = 0; static int dontprint = 0; VOID printon() { /* Turn printing on */ int x, pp; char * p; extern int printpipe, noprinter; extern char * printername; if (noprinter) { debug(F110,"PRINTER ON NOPRINTER","",0); return; } p = printername; pp = printpipe; if (!p) p = ""; if (!*p) { #ifdef ANYBSD p = "lpr"; #else p = "lp"; #endif /* ANYBSD */ pp = 1; debug(F110,"PRINTER DEFAULT",p,0); } debug(F111,"PRINTER ON",p,pp); if (pp) { /* Printing to pipe */ x = zxcmd(ZMFILE,p); } else { /* Append to file */ struct filinfo xx; xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0; xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = ""; xx.lblopts = 0; x = zopeno(ZMFILE,p,NULL,&xx); } debug(F101,"PRINTER OPEN","",x); printing = 1; } VOID printoff() { /* Turn printing off */ int x; extern int noprinter; if (noprinter) { printing = 0; debug(F100,"PRINTER OFF NOPRINTER","",0); return; } debug(F100,"PRINTER OFF","",0); if (printing) { x = zclose(ZMFILE); debug(F101,"PRINTER CLOSE","",x); printing = 0; } } #endif /* XPRINT */ /* C H K A E S -- Check ANSI Escape Sequence. Call with EACH character in input stream. src = 0 means c is incoming from remote; 1 = char from keyboard. Sets global inesc[src] variable according to escape sequence state. Returns 0 normally, 1 if an APC sequence is to be executed. Handles transparent printing internally. */ int #ifdef CK_ANSIC chkaes(char c, int src) #else chkaes(c,src) char c; int src; #endif /* CK_ANSIC */ /* chkaes */ { debug(F111,"chkaes entry inesc",ckitoa(src),inesc[src]); debug(F101,"chkaes c","",c); if (src < 0 || src > 1) /* Don't allow bad args. */ return(0); oldesc[src] = inesc[src]; /* Remember previous state */ #ifdef XPRINT if (inesc[src] && !src) { /* Save up escape seq for printing */ if (!c) return(0); /* Ignore NULs */ if (escbufc < ESCBUFLEN) { escbuf[escbufc++] = c; escbuf[escbufc] = NUL; debug(F111,"ESCBUF 1",escbuf,escbufc); } else { /* Buffer overrun */ if (printing && escbufc) /* Print what's there so far */ zsoutx(ZMFILE,escbuf,escbufc); escbufc = 1; /* clear it out */ escbuf[0] = c; /* and start off fresh buffer */ escbuf[1] = NUL; /* with this character. */ } } #endif /* XPRINT */ if (c == CAN || c == SUB) { /* CAN and SUB cancel any sequence */ #ifdef XPRINT if (!src) { if (printing && escbufc > 1) zsoutx(ZMFILE,escbuf,escbufc-1); escbufc = 0; /* Clear buffer */ escbuf[0] = NUL; } #endif /* XPRINT */ inesc[src] = ES_NORMAL; } else /* Otherwise */ switch (inesc[src]) { /* enter state switcher */ case ES_NORMAL: /* NORMAL state */ if (c == ESC) { /* Got an ESC */ inesc[src] = ES_GOTESC; /* Change state to GOTESC */ #ifdef XPRINT if (!src) { escbufc = 1; /* Clear escape sequence buffer */ escbuf[0] = c; /* and deposit the ESC */ escbuf[1] = NUL; debug(F111,"ESCBUF 2",escbuf,escbufc); } #endif /* XPRINT */ } break; /* Otherwise stay in NORMAL state */ case ES_GOTESC: /* GOTESC state - prev char was ESC*/ if (c == '[') { /* Left bracket after ESC is CSI */ inesc[src] = ES_GOTCSI; /* Change to GOTCSI state */ } else if (c == 'P' || (c > 0134 && c < 0140)) { /* P, ], ^, or _ */ inesc[src] = ES_STRING; /* Switch to STRING-absorption state */ #ifdef XPRINT debug(F111,"ESCBUF STRING",escbuf,escbufc); #endif /* XPRINT */ #ifdef CK_APC /* If APC not disabled */ if (!src && c == '_' && (apcstatus & APC_ON)) { debug(F100,"CONNECT APC begin","",0); apcactive = APC_REMOTE; /* Set APC-Active flag */ apclength = 0; /* and reset APC buffer pointer */ } #endif /* CK_APC */ } else if (c > 057 && c < 0177) { /* Final character '0' thru '~' */ inesc[src] = ES_NORMAL; /* Back to normal */ #ifdef XPRINT if (!src) { if (printing && escbufc > 1) { /* Dump esc seq buf to printer */ zsoutx(ZMFILE,escbuf,escbufc-1); debug(F111,"ESCBUF PRINT 1",escbuf,escbufc); } escbufc = 0; /* Clear parameter buffer */ escbuf[0] = NUL; } #endif /* XPRINT */ } else if (c != ESC) { /* ESC in an escape sequence... */ inesc[src] = ES_ESCSEQ; /* starts a new escape sequence */ } break; /* Intermediate or ignored ctrl char */ case ES_ESCSEQ: /* ESCSEQ -- in an escape sequence */ if (c > 057 && c < 0177) { /* Final character '0' thru '~' */ inesc[src] = ES_NORMAL; /* Return to NORMAL state. */ #ifdef XPRINT if (!src) { if (printing && escbufc > 1) { zsoutx(ZMFILE,escbuf,escbufc-1); debug(F111,"ESCBUF PRINT 2",escbuf,escbufc); } escbufc = 0; /* Clear escseq buffer */ escbuf[0] = NUL; } #endif /* XPRINT */ } else if (c == ESC) { /* ESC ... */ inesc[src] = ES_GOTESC; /* starts a new escape sequence */ } break; /* Intermediate or ignored ctrl char */ case ES_GOTCSI: /* GOTCSI -- In a control sequence */ if (c > 077 && c < 0177) { /* Final character '@' thru '~' */ #ifdef XPRINT if (!src && tt_print) { /* Printer enabled? */ if (c == 'i') { /* Final char is "i"? */ char * p = (char *) (escbuf + escbufc - 4); if (!strncmp(p, "\033[5i", 4)) { /* Turn printer on */ printon(); } else if (!strncmp(p, "\033[4i", 4)) { /* Or off... */ int i; printoff(); /* Turn off printer. */ dontprint = 1; for (i = 0; i < escbufc; i++) /* And output the */ ckcputc(escbuf[i]); /* sequence. */ } else if (printing && escbufc > 1) { zsoutx(ZMFILE,escbuf,escbufc-1); debug(F011,"ESCBUF PRINT 3",escbuf,escbufc); } } else if (printing && escbufc > 1) { zsoutx(ZMFILE,escbuf,escbufc-1); debug(F111,"ESCBUF PRINT 4",escbuf,escbufc); } } if (!src) { escbufc = 0; /* Clear esc sequence buffer */ escbuf[0] = NUL; } #endif /* XPRINT */ inesc[src] = ES_NORMAL; /* Return to NORMAL. */ } else if (c == ESC) { /* ESC ... */ inesc[src] = ES_GOTESC; /* starts over. */ } break; case ES_STRING: /* Inside a string */ if (c == ESC) /* ESC may be 1st char of terminator */ inesc[src] = ES_TERMIN; /* Go see. */ #ifdef CK_APC else if (apcactive) { /* If in APC */ if (apclength < apcbuflen) { /* and there is room... */ apcbuf[apclength++] = c; /* deposit this character. */ } else { /* Buffer overrun */ apcactive = 0; /* Discard what we got */ apclength = 0; /* and go back to normal */ apcbuf[0] = 0; /* Not pretty, but what else */ inesc[src] = ES_NORMAL; /* can we do? (ST might not come) */ } } #endif /* CK_APC */ break; /* Absorb all other characters. */ case ES_TERMIN: /* Maybe a string terminator */ if (c == '\\') { /* which must be backslash */ inesc[src] = ES_NORMAL; /* If so, back to NORMAL */ #ifdef XPRINT if (!src) { if (printing && escbufc > 1) { /* If printing... */ /* Print esc seq buffer */ zsoutx(ZMFILE,escbuf,escbufc-1); debug(F111,"ESCBUF PRINT 5",escbuf,escbufc); } escbufc = 0; /* Clear escseq buffer */ escbuf[0] = NUL; } #endif /* XPRINT */ #ifdef CK_APC if (!src && apcactive) { /* If it was an APC string, */ debug(F101,"CONNECT APC terminated","",c); apcbuf[apclength] = NUL; /* terminate it and then ... */ return(1); } #endif /* CK_APC */ } else { /* It's not a backslash so... */ inesc[src] = ES_STRING; /* back to string absorption. */ #ifdef CK_APC if (apcactive) { /* In APC string */ if (apclength+1 < apcbuflen) { /* If enough room */ apcbuf[apclength++] = ESC; /* deposit the Esc */ apcbuf[apclength++] = c; /* and this character too. */ } else { /* Buffer overrun */ apcactive = 0; apclength = 0; apcbuf[0] = 0; inesc[src] = ES_NORMAL; } } #endif /* CK_APC */ } } /* switch() */ debug(F111,"chkaes exit inesc",ckitoa(src),inesc[src]); return(0); } #endif /* NOESCSEQ */ VOID #ifdef CK_ANSIC LOGCHAR(char c) #else LOGCHAR(c) char c; #endif /* CK_ANSIC */ /* LOGCHAR */ { /* Log character c to session log */ /* but skip over escape sequences if session log is text */ if (escseq) { if ((sessft == XYFT_T) && (debses == 0) && (inesc[0] != ES_NORMAL || oldesc[0] != ES_NORMAL)) return; } logchar(c); } /* C K C P U T C -- C-Kermit CONNECT Put Character to Screen */ /* Output is buffered to avoid slow screen writes on fast connections. */ static int ckcputf() { /* Dump the console output buffer */ int x = 0; if (obc > 0) /* If we have any characters, */ x = conxo(obc,obuf); /* dump them, */ obp = obuf; /* reset the pointer */ obc = 0; /* and the counter. */ return(x); /* Return conxo's return code */ } /* NOTE: This is probably the right place for character-set translation, rather than down below in the mainline code. ckcputc() would act like xpnbyte() in ckcfns.c, and ckcgetc() would act like xgnbyte(). This would shield the rest of the code from all the complexities of many-to-one and one-to-many conversions, and would allow handling of Kanji and other CJK sets along with UTF-8 and the rest. */ int #ifdef CK_ANSIC ckcputc( int c ) #else ckcputc(c) int c; #endif /* CK_ANSIC */ { int x; *obp++ = c & 0xff; /* Deposit the character */ obc++; /* Count it */ if (ibc == 0 || /* If input buffer about empty */ obc == OBUFL) { /* or output buffer full */ debug(F101,"CONNECT CKCPUTC obc","",obc); x = conxo(obc,obuf); /* dump the buffer, */ obp = obuf; /* reset the pointer */ obc = 0; /* and the counter. */ return(x); /* Return conxo's return code */ } else return(0); } /* C K C G E T C -- C-Kermit CONNECT Get Character */ /* Buffered read from communication device. Returns the next character, refilling the buffer if necessary. On error, returns ttinc's return code (see ttinc() description). Dummy argument for compatible calling conventions with ttinc() so a pointer to this function can be passed to tn_doop(). */ int #ifdef CK_ANSIC ckcgetc( int dummy ) #else ckcgetc(dummy) int dummy; #endif /* CK_ANSIC */ { int c, n; #ifdef CK_SSL extern int ssl_active_flag, tls_active_flag; #endif /* CK_SSL */ #ifdef CK_ENCRYPTION /* No buffering for possibly encrypted connections */ if (network && IS_TELNET() && TELOPT_ME(TELOPT_AUTHENTICATION)) return(ttinc(0)); #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if (ssl_active_flag || tls_active_flag) return(ttinc(0)); #endif /* CK_SSL */ if (ibc < 1) { /* Need to refill buffer? */ ibc = 0; /* Yes, reset count */ ibp = ibuf; /* and buffer pointer */ c = ttinc(0); /* Read one character, blocking */ if (c < 0) { /* If error, return error code */ return(c); } else { /* Otherwise, got one character */ *ibp++ = c; /* Advance buffer pointer */ ibc++; /* and count. */ } if ((n = ttchk()) > 0) { /* Any more waiting? */ if (n > (IBUFL - ibc)) /* Get them all at once. */ n = IBUFL - ibc; /* Don't overflow buffer */ if ((n = ttxin(n,(CHAR *)ibp)) > 0) { ibc += n; /* Advance counter */ } } else if (n < 0) { /* Error? */ return(n); /* Return the error code */ } ibp = ibuf; /* Point to beginning of buffer */ } c = *ibp++ & 0xff; /* Get next character from buffer */ ibc--; /* Reduce buffer count */ /* debug(F000,"CKCGETC","",c); */ return(c); /* Return the character */ } /* Keyboard handling, buffered for speed, which is needed when C-Kermit is in CONNECT mode between two other computers that are transferring data. */ static char *kbp; /* Keyboard input buffer pointer */ static int kbc; /* Keyboard input buffer count */ #ifdef CK_SMALL /* Keyboard input buffer length */ #define KBUFL 32 /* Small for PDP-11 UNIX */ #else #define KBUFL 257 /* Regular kernel size for others */ #endif /* CK_SMALL */ #ifdef DYNAMIC static char *kbuf = NULL; #else static char kbuf[KBUFL]; #endif /* DYNAMIC */ /* Macro for reading keystrokes. */ #define CONGKS() (((--kbc)>=0) ? ((int)(*kbp++) & 0377) : kbget()) /* Note that we call read() directly here, normally a no-no, but in this case we know it's UNIX and we're only doing what coninc(0) would have done, except we're reading a block of characters rather than just one. There is, at present, no conxin() analog to ttxin() for chunk reads, and instituting one would only add function-call overhead as it would only be a wrapper for a read() call anyway. Another note: We stick in this read() till the user types something. But we know they already did, since select() said so. Therefore something would need to be mighty wrong before we get stuck here. */ static int /* Keyboard buffer filler */ kbget() { #ifdef EINTR int tries = 10; /* If read() is interrupted, */ int ok = 0; while (tries-- > 0) { /* try a few times... */ #endif /* EINTR */ kbc = conchk(); /* How many chars waiting? */ debug(F101,"kbget kbc","",kbc); if (kbc < 1) kbc = 1; /* If none or dunno, wait for one. */ else if (kbc > KBUFL) /* If too many, */ kbc = KBUFL; /* only read this many. */ if ((kbc = read(0, kbuf, kbc)) < 1) { /* Now read it/them. */ debug(F101,"CONNECT kbget errno","",errno); /* Got an error. */ #ifdef EINTR if (errno == EINTR) /* Interrupted system call. */ continue; /* Try again, up to limit. */ else /* Something else. */ #endif /* EINTR */ return(-1); /* Pass along read() error. */ } #ifdef EINTR else { ok = 1; break; } } if (!ok) return(-1); #endif /* EINTR */ kbp = kbuf; /* Adjust buffer pointer, */ kbc--; /* count, */ return((int)(*kbp++) & 0377); /* and return first character. */ } #ifdef BEBOX /* * CreateSocketPair -- * * This procedure creates a connected socket pair * * Results: * 0 if OK, the error if not OK. * * Side effects: * None */ int socketpair(int *pair) { int servsock; int val; struct sockaddr_in serv_addr, cli_addr; extern char myipaddr[]; debug(F110,"socketpair",myipaddr,0); if (myipaddr[0] == 0) getlocalipaddr(); servsock = socket(AF_INET, SOCK_STREAM, 0); if (servsock == 0) { return h_errno; } debug(F111,"socketpair","socket",servsock); memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(0); val = sizeof(serv_addr); if (bind(servsock, (struct sockaddr *) &serv_addr, val) < 0) { closesocket(servsock); return h_errno; } debug(F111,"socketpair","bind",0); listen(servsock, 1); debug(F111,"socketpair","listen",0); if (getsockname(servsock, (struct sockaddr *) &serv_addr, &val) < 0) { closesocket(servsock); return h_errno; } debug(F111,"socketpair","getsockname",0); pair[0] = socket(AF_INET, SOCK_STREAM, 0); if (pair[0] == 0) { closesocket(servsock); return h_errno; } debug(F111,"socketpair","socket",pair[0]); memset(&cli_addr, 0, sizeof(cli_addr)); cli_addr.sin_family = AF_INET; cli_addr.sin_addr.s_addr = inet_addr(myipaddr[0]?myipaddr:"127.0.0.1"); cli_addr.sin_port = serv_addr.sin_port; if (connect(pair[0],(struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) { closesocket(pair[0]); closesocket(servsock); return h_errno; } debug(F111,"socketpair","connect",0); pair[1] = accept(servsock, (struct sockaddr *) &serv_addr, &val); if (pair[1] == 0) { closesocket(pair[0]); closesocket(servsock); return h_errno; } debug(F111,"socketpair","accept",pair[1]); closesocket(servsock); debug(F111,"socketpair","closesocket",0); return 0; } long kbdread(void * param) { int sock = (int) param; char ch; int rc = 0; debug(F111,"kbdread","sock",sock); while (rc >= 0) { rc = read(fileno(stdin), &ch, 1); /* Read a character. */ if (rc > 0) { rc = send(sock,&ch,1,0); /* debug(F000,"kbdread","send()",ch); */ printf("\r\ngot: %c rc = %d\r\n",ch,rc); } else msleep(100); } debug(F110,"kbdread","terminating",0); return(rc); } #endif /* BEBOX */ #ifdef CKLEARN static VOID #ifdef CK_ANSIC learnchar( int c ) /* Learned script keyboard character */ #else learnchar(c) int c; #endif /* CK_ANSIC */ { int cc; char xbuf[8]; if (!learning || !learnfp) return; switch (learnst) { /* Learn state... */ case 0: /* Neutral */ case 1: /* Net */ if (learnbc > 0) { /* Have net characters? */ char buf[LEARNBUFSIZ]; int i, j, n; ULONG t; t = (ULONG) time(0); /* Calculate INPUT timeout */ j = t - learnt1; j += (j / 4) > 0 ? (j / 4) : 1; /* Add some slop */ if (j < 2) j = 2; /* 2 seconds minimum */ fputs("\nINPUT ",learnfp); /* Give INPUT command for them */ fputs(ckitoa(j),learnfp); fputs(" {",learnfp); learnt1 = t; n = LEARNBUFSIZ; if (learnbc < LEARNBUFSIZ) { /* Circular buffer */ n = learnbc; /* hasn't wrapped yet. */ learnbp = 0; } j = 0; /* Copy to linear buffer */ for (i = 0; i < n; i++) { /* Number of chars in circular buf */ cc = learnbuf[(learnbp + i) % LEARNBUFSIZ]; /* Later account for prompts that end with a newline? */ if (cc == CK_CR && j > 0) { if (buf[j-1] != LF) j = 0; } buf[j++] = cc; } for (i = 0; i < j; i++) { /* Now copy out the buffer */ cc = buf[i]; /* interpreting control chars */ if (cc == 0) { /* We don't INPUT NULs */ continue; } else if (cc < SP || /* Controls need quoting */ (cc > 126 && cc < 160)) { ckmakmsg(xbuf,8,"\\{",ckitoa((int)cc),"}",NULL); fputs(xbuf,learnfp); } else { /* Plain character */ putc(cc,learnfp); } } fputs("}\nIF FAIL STOP 1 INPUT timeout",learnfp); learnbc = 0; } learnbp = 0; fputs("\nPAUSE 1\nOUTPUT ",learnfp); /* Emit OUTPUT and fall thru */ case 2: /* Already in Keyboard state */ if (c == 0) { fputs("\\N",learnfp); } else if (c == -7) { fputs("\\B",learnfp); } else if (c == -8) { fputs("\\L",learnfp); } else if (c < SP || (c > 126 && c < 160)) { ckmakmsg(xbuf,8,"\\{",ckitoa((int)c),"}",NULL); fputs(xbuf,learnfp); } else { putc(c,learnfp); } } } #endif /* CKLEARN */ static int printbar = 0; #define OUTXBUFSIZ 15 static CHAR inxbuf[OUTXBUFSIZ+1]; /* Host-to-screen expansion buffer */ static int inxcount = 0; /* and count */ static CHAR outxbuf[OUTXBUFSIZ+1]; /* Keyboard-to-host expansion buf */ static int outxcount = 0; /* and count */ int conect() { int rc = 0; /* Return code: 0 = fail, 1 = OK */ int i, x = 0, prev = -1; /* Reason code in cx_status */ #ifdef CKLEARN int crflag = 0; #endif /* CKLEARN */ register int c = -1, c2, csave; /* Characters */ #ifdef TNCODE int tx; /* For Telnet negotiations */ #endif /* TNCODE */ int apcrc = 0; /* For APC and transparent print */ int n, kbin, scrnout; /* select() items... */ fd_set in, out, err; /* File descriptor sets */ int gotnet = 0; /* Flag for net ready to read */ int gotkbd = 0; /* Flag for keyboard ready to read */ int oldprt = 0; /* Used with printing */ int msgflg = 0; char cbuf[2]; /* Ditto */ #ifdef BEBOX int tid = 0; /* Thread ID */ int pair[2]; /* Socket Pair */ CHAR ch; CHAR buf[64]; #endif /* BEBOX */ cx_status = CSX_INTERNAL; debok = 1; #ifdef BEBOX { /* Create a socket pair to be used for the keyboard input */ if (socketpair(pair)) { debug(F110,"conect","unable to create socket pair",0); return(-1); } debug(F111,"connect","socket pair[0]",pair[0]); debug(F111,"connect","socket pair[1]",pair[1]); /* Assign one end of the socket to kbin */ kbin = pair[0]; tid = spawn_thread(kbdread, "Kbd to Socket Pair", B_NORMAL_PRIORITY, (void *)pair[1] ); resume_thread(tid); debug(F110,"connect","tid",tid); } #else /* BEBOX */ kbin = fileno(stdin); /* stdin file descriptor */ #endif /* BEBOX */ scrnout = fileno(stdout); /* stdout file descriptor */ #ifdef CK_TRIGGER makestr(&triggerval,NULL); /* Reset trigger */ #endif /* CK_TRIGGER */ #ifdef XPRINT escbufc = 0; /* Reset esc-sequence buffer */ escbuf[0] = NUL; #endif /* XPRINT */ cbuf[1] = NUL; ttimoff(); /* Turn off any timer interrupts */ if (!local) { /* Be sure we're not in remote mode */ #ifdef NETCONN #ifdef NEWFTP if (ftpisconnected()) printf("Sorry, you can't CONNECT to an FTP server\n"); else #endif /* NEWFTP */ printf("Sorry, you must SET LINE or SET HOST first\n"); #else printf("Sorry, you must SET LINE first\n"); #endif /* NETCONN */ return(0); } if (speed < 0L && network == 0 && ttfdflg == 0) { printf("Sorry, you must SET SPEED first\n"); return(0); } #ifdef TCPSOCKET if (network && !ttpipe && (nettype != NET_TCPB && nettype != NET_PTY)) { printf("Sorry, network type not supported\n"); return(0); } #endif /* TCPSOCKET */ #ifdef DYNAMIC if (!ibuf) { if (!(ibuf = malloc(IBUFL+1))) { /* Allocate input line buffer */ printf("Sorry, CONNECT input buffer can't be allocated\n"); return(0); } else { ibp = ibuf; ibc = 0; } } if (!obuf) { if (!(obuf = malloc(OBUFL+1))) { /* Allocate output line buffer */ printf("Sorry, CONNECT output buffer can't be allocated\n"); return(0); } else { obp = obuf; obc = 0; } } if (!kbuf) { if (!(kbuf = malloc(KBUFL+1))) { /* Allocate keyboard input buffer */ printf("Sorry, CONNECT keyboard buffer can't be allocated\n"); return(0); } } if (!temp) { if (!(temp = malloc(TMPLEN+1))) { /* Allocate temporary buffer */ printf("Sorry, CONNECT temporary buffer can't be allocated\n"); return(0); } } #else obp = obuf; obc = 0; #endif /* DYNAMIC */ kbp = kbuf; /* Always clear these. */ *kbp = NUL; /* No need to preserve them between */ kbc = 0; /* CONNECT sessions. */ #ifdef DEBUG if (deblog) { debug(F101,"CONNECT conect entry ttyfd","",ttyfd); debug(F101,"CONNECT conect entry ibc","",ibc); debug(F101,"CONNECT conect entry obc","",obc); debug(F101,"CONNECT conect entry kbc","",kbc); #ifdef CK_TRIGGER debug(F110,"CONNECT conect trigger",tt_trigger[0],0); #endif /* CK_TRIGGER */ if (ttyfd > -1) { n = ttchk(); debug(F101,"CONNECT conect entry ttchk","",n); } } #endif /* DEBUG */ if (ttyfd < 0) { /* If communication device not open */ #ifdef TTLEBUF int n = le_inbuf(); debug(F111,"CONNECT le_inbuf()","ttyfd < 0",n); if (n > 0) { while (n--) { CHAR ch; le_getchar(&ch); conoc(ch); } return(0); } #endif /* TTLEBUF */ debug(F101,"CONNECT ttnproto","",ttnproto); debug(F111,"CONNECT opening",ttname,0); /* Open it now */ if (ttopen(ttname, &local, network ? -nettype : mdmtyp, 0 ) < 0) { ckmakmsg(temp,TMPLEN,"Sorry, can't open ",ttname,NULL,NULL); perror(temp); debug(F110,"CONNECT open failure",ttname,0); return(0); } #ifdef IKS_OPTION /* If peer is in Kermit server mode, return now. */ if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start) { cx_status = CSX_IKSD; return(0); } #endif /* IKS_OPTION */ } dohangup = 0; /* Hangup not requested yet */ msgflg = !quiet #ifdef CK_APC && !apcactive #endif /* CK_APC */ ; if (msgflg) { #ifdef NETCONN if (network) { #ifdef CK_ENCRYPTION extern int me_encrypt, u_encrypt; if (ck_tn_encrypting() && ck_tn_decrypting()) printf("SECURE connection to host %s",ttname); else #endif /* CK_ENCRYPTION */ if (ttpipe || ttpty) printf("Connecting via command \"%s\"",ttname); else printf("Connecting to host %s",ttname); } else { #endif /* NETCONN */ printf("Connecting to %s",ttname); if (speed > -1L) printf(", speed %ld",speed); #ifdef NETCONN } #endif /* NETCONN */ if (tt_escape) { printf("\r\n"); shoesc(escape); printf("Type the escape character followed by C to get back,\r\n"); printf("or followed by ? to see other options.\r\n"); } else { printf(".\r\n\nESCAPE CHARACTER IS DISABLED\r\n\n"); } if (seslog) { extern int slogts; char * s = ""; switch (sessft) { case XYFT_D: s = "debug"; break; case XYFT_T: s = slogts ? "timestamped-text" : "text"; break; default: s = "binary"; } printf("Session Log: %s, %s (%d) \r\n",sesfil,s,sessft); } if (debses) printf("Debugging Display...)\r\n"); } /* Condition console terminal and communication line */ if (conbin((char)escape) < 0) { printf("Sorry, can't condition console terminal\n"); fflush(stdout); return(0); } debug(F101,"CONNECT cmask","",cmask); debug(F101,"CONNECT cmdmsk","",cmdmsk); debug(F101,"CONNECT speed before ttvt","",speed); if ((n = ttvt(speed,flow)) < 0) { /* Enter "virtual terminal" mode */ if (!network) { debug(F101,"CONNECT ttvt","",n); tthang(); /* Hang up and close the device. */ ttclos(0); dologend(); if (ttopen(ttname, /* Open it again... */ &local, network ? -nettype : mdmtyp, 0 ) < 0) { cx_status = CSX_INTERNAL; ckmakmsg(temp,TMPLEN,"Sorry, can't reopen ",ttname,NULL,NULL); perror(temp); return(0); } #ifdef IKS_OPTION if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start) { cx_status = CSX_IKSD; return(0); } #endif /* IKS_OPTION */ if (ttvt(speed,flow) < 0) { /* Try virtual terminal mode again. */ conres(); /* Failure this time is fatal. */ printf("Sorry, Can't condition communication line\n"); cx_status = CSX_INTERNAL; return(0); } } } debug(F101,"CONNECT ttvt ok, escape","",escape); /* Despite ttvt() this is still needed in HP-UX */ /* because of the HP-9000 key.*/ signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); debug(F101,"CONNECT carrier-watch","",carrier); if ((!network #ifdef TN_COMPORT || istncomport() #endif /* TN_COMPORT */ ) && (carrier != CAR_OFF)) { int x; x = ttgmdm(); debug(F100,"CONNECT ttgmdm","",x); if ((x > -1) && !(x & BM_DCD)) { #ifndef NOHINTS extern int hints; #endif /* NOHINTS */ debug(F100,"CONNECT ttgmdm CD test fails","",x); conres(); printf("?Carrier required but not detected.\n"); #ifndef NOHINTS cx_status = CSX_CARRIER; if (!hints) return(0); printf("***********************************\n"); printf(" Hint: To CONNECT to a serial device that\n"); printf(" is not presenting the Carrier Detect signal,\n"); printf(" first tell C-Kermit to:\n\n"); printf(" SET CARRIER-WATCH OFF\n\n"); printf("***********************************\n\n"); #endif /* NOHINTS */ return(0); } debug(F100,"CONNECT ttgmdm ok","",0); } /* Now we are connected. */ if (msgflg || printbar) printf("----------------------------------------------------\r\n"); fflush(stdout); #ifndef NOCSETS /* Set up character set translations */ unicode = 0; /* Assume Unicode won't be involved */ tcs = 0; /* "Transfer" or "Other" charset */ sxo = rxo = NULL; /* Initialize byte-to-byte functions */ sxi = rxi = NULL; if (tcsr != tcsl) { /* Remote and local sets differ... */ #ifdef UNICODE if (tcsr == FC_UTF8 || /* Remote charset is UTF-8 */ tcsl == FC_UTF8) { /* or local one is. */ xuf = xl_ufc[tcsl]; /* Incoming Unicode to local */ if (xuf || tcsl == FC_UTF8) { tcs = (tcsr == FC_UTF8) ? tcsl : tcsr; /* The "other" set */ xfu = xl_fcu[tcs]; /* Local byte to remote Unicode */ if (xfu) unicode = (tcsr == FC_UTF8) ? 1 : 2; } tcssize = fcsinfo[tcs].size; /* Size of other character set. */ } else { #endif /* UNICODE */ tcs = gettcs(tcsr,tcsl); /* Get intermediate set. */ sxo = xls[tcs][tcsl]; /* translation function */ rxo = xlr[tcs][tcsr]; /* pointers for output functions */ sxi = xls[tcs][tcsr]; /* and for input functions. */ rxi = xlr[tcs][tcsl]; #ifdef UNICODE } #endif /* UNICODE */ } /* This is to prevent use of zmstuff() and zdstuff() by translation functions. They only work with disk i/o, not with communication i/o. Luckily Russian translation functions don't do any stuffing... */ langsv = language; #ifndef NOCYRIL if (language != L_RUSSIAN) #endif /* NOCYRIL */ language = L_USASCII; #ifdef COMMENT #ifdef DEBUG if (deblog) { debug(F101,"CONNECT tcs","",tcs); debug(F101,"CONNECT tcsl","",tcsl); debug(F101,"CONNECT tcsr","",tcsr); debug(F101,"CONNECT fcsinfo[tcsl].size","",fcsinfo[tcsl].size); debug(F101,"CONNECT fcsinfo[tcsr].size","",fcsinfo[tcsr].size); debug(F101,"CONNECT unicode","",unicode); } #endif /* DEBUG */ #endif /* COMMENT */ #ifdef CK_XYZ #ifndef XYZ_INTERNAL { extern int binary; /* See about ZMODEM autodownloads */ char * s; s = binary ? ptab[PROTO_Z].p_b_rcmd : ptab[PROTO_Z].p_t_rcmd; if (!s) s = ""; zmdlok = (*s != NUL); /* OK if we have external commands */ } #endif /* XYZ_INTERNAL */ #endif /* CK_XYZ */ #ifndef NOESCSEQ /* We need to activate the escape-sequence recognition feature when: (a) translation is elected, AND (b) the local and/or remote set is a 7-bit set other than US ASCII; Or: SET SESSION-LOG is TEXT (so we can strip escape sequences out of the log); Or: SET TERMINAL APC is not OFF (handled in the next statement). */ escseq = (tcs != TC_TRANSP) && /* Not transparent */ (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */ (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */ #endif /* NOESCSEQ */ #endif /* NOCSETS */ #ifndef NOESCSEQ if (!escseq) { /* 2009/10/22 */ if (seslog && !sessft) escseq = 1; } #ifdef CK_APC escseq = escseq || (apcstatus & APC_ON); apcactive = 0; /* An APC command is not active */ apclength = 0; /* ... */ #endif /* CK_APC */ #ifdef XPRINT escseq |= tt_print; #endif /* XPRINT */ /* Initial state of recognizer */ inesc[0] = ES_NORMAL; /* Remote to screen */ inesc[1] = ES_NORMAL; /* Keyboard to remote */ debug(F101,"CONNECT escseq","",escseq); #endif /* NOESCSEQ */ if (ttyfd > -1) { /* (just in case...) */ what = W_CONNECT; /* Keep track of what we're doing */ active = 1; } #ifdef CKLEARN if (learning) { /* Learned script active... */ learnbp = 0; /* INPUT buffer pointer */ learnbc = 0; /* INPUT buffer count */ learnst = 0; /* State (0 = neutral, none) */ learnt1 = (ULONG) time(0); } #endif /* CKLEARN */ #ifdef CKTIDLE idlelimit = tt_idlelimit; #endif /* CKTIDLE */ while (active) { /* Big loop... */ debug(F100,"CONNECT top of loop","",0); FD_ZERO(&in); /* Clear select() structs */ FD_ZERO(&out); FD_ZERO(&err); gotkbd = 0; gotnet = ttpeek(); /* Something sitting in ckutio buf */ debug(F101,"CONNECT ttpeek","",gotnet); if ( #ifndef NOSETKEY !kmptr /* Check for key macro active */ #else 1 #endif /* NOSETKEY */ ) { if (obc) { /* No key macro - set up for select */ FD_SET(ttyfd, &out); /* Have stuff to send to net */ } else { FD_SET(kbin, &in); /* Need to read stuff from keyboard */ } #ifdef BEBOX if (!(ibc || gotnet > 0)) FD_SET(ttyfd, &in); /* Need to read stuff from net */ #else /* BEBOX */ if (ibc || gotnet > 0) { FD_SET(scrnout, &out); /* Have stuff to put on screen */ } else { FD_SET(ttyfd, &in); /* Need to read stuff from net */ } #endif /* BEBOX */ FD_SET(ttyfd, &err); #ifdef CK_FORWARD_X fwdx_init_fd_set(&in); #endif /* CK_FORWARD_X */ /* Wait till the first one of the above is ready for i/o */ /* or TERM IDLE-SEND is active and we time out. */ errno = 0; #ifdef CKTIDLE /* This really could be moved out of the loop... */ if (idlelimit) { /* Idle timeout set */ struct timeval tv; if (idlelimit > 0) { /* Positive = sec */ tv.tv_sec = (long) idlelimit; tv.tv_usec = 0L; } else { /* Negative = millisec */ long u = (0 - idlelimit); tv.tv_sec = u / 1000L; tv.tv_usec = ((u % 1000L) * 1000L); } #ifdef INTSELECT c = select(FD_SETSIZE,(int *)&in,(int *)&out,(int *)&err, &tv); #else c = select(FD_SETSIZE, &in, &out, &err, &tv); #endif /* INTSELECT */ } else #endif /* CKTIDLE */ #ifdef INTSELECT c = select(FD_SETSIZE, (int *)&in, (int *)&out, (int *)&err, 0); #else c = select(FD_SETSIZE, &in, &out, &err, 0); #endif /* INTSELECT */ if (c < 1) { #ifdef CKTIDLE if (c == 0) { /* Timeout */ debug(F101,"CONNECT select() timeout","",tt_idleact); switch (tt_idleact) { case IDLE_HANG: { /* Hang up */ int x = 0; #ifndef NODIAL if (dialmhu) x = mdmhup(); if (x < 1) #endif /* NODIAL */ tthang(); /* fall thru deliberately... */ } case IDLE_RET: /* Return to command mode */ cx_status = CSX_IDLE; active = 0; continue; case IDLE_OUT: /* OUTPUT a string */ if (tt_idlestr) { int len = strlen(tt_idlestr); if (len > 0) ttol((CHAR *)tt_idlestr,len); else ttoc(NUL); /* No string, send a NUL */ } else ttoc(NUL); /* No string, send a NUL */ continue; case IDLE_EXIT: /* Exit from Kermit */ doexit(GOOD_EXIT,xitsta); #ifdef TNCODE case IDLE_TAYT: /* Send Telnet Are You There? */ if (network && IS_TELNET()) { tnopt[0] = (CHAR) IAC; tnopt[1] = (CHAR) TN_AYT; tnopt[2] = NUL; if (ttol((CHAR *)tnopt,2) < 0) active = 0; } continue; case IDLE_TNOP: /* Send Telnet NOP */ if (network && IS_TELNET()) { tnopt[0] = (CHAR) IAC; tnopt[1] = (CHAR) TN_NOP; tnopt[2] = NUL; if (ttol((CHAR *)tnopt,2) < 0) active = 0; } continue; #endif /* TNCODE */ } } #endif /* CKTIDLE */ debug(F101,"CONNECT select() errno","",errno); /* A too-big first arg to select() gets EBADF */ #ifdef EINTR if (c == -1) { if (errno == EINTR) { continue; } } #endif /* EINTR */ sleep(1); continue; } #ifndef BEBOX #ifdef DEBUG if (FD_ISSET(scrnout, &out)) { debug(F100,"CONNECT SELECT scrnout","",0); } #endif /* DEBUG */ #endif /* BEBOX */ #ifdef CK_FORWARD_X fwdx_check_sockets(&in); #endif /* CK_FORWARD_X */ if (FD_ISSET(ttyfd, &in)) { /* Read from net? */ debug(F110,"CONNECT SELECT ttyfd","in",0); FD_CLR(ttyfd, &in); gotnet = 1; /* Net is ready */ } if (FD_ISSET(kbin, &in)) { /* Read from keyboard? */ debug(F100,"CONNECT SELECT kbin","",0); FD_CLR(kbin, &in); gotkbd = 1; /* Keyboard is ready */ } if (FD_ISSET(ttyfd, &err)) { debug(F110,"CONNECT SELECT ttyfd","err",0); FD_CLR(ttyfd, &err); #ifdef NETPTY #ifdef HAVE_PTYTRAP /* Special handling for HP-UX pty i/o */ if (ttpty) { if (pty_trap_handler(ttyfd) > 0) { ttclos(0); goto conret1; } continue; } #endif /* HAVE_PTYTRAP */ #endif /* NETPTY */ gotnet = 1; /* Net is ready (don't set if pty) */ } } #ifdef DEBUG if (deblog) { debug(F101,"CONNECT gotkbd","",gotkbd); debug(F101,"CONNECT kbc","",kbc); #ifdef COMMENT #ifndef NOSETKEY debug(F101,"CONNECT kmptr","",kmptr); #endif /* NOSETKEY */ #endif /* COMMENT */ } #endif /* DEBUG */ while (gotkbd || kbc > 0 /* If we have keyboard chars */ #ifndef NOSETKEY || kmptr #endif /* NOSETKEY */ ) { #ifndef NOSETKEY if (kmptr) { /* Have current macro? */ debug(F100,"CONNECT kmptr non NULL","",0); if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */ debug(F100,"CONNECT macro empty, continuing","",0); kmptr = NULL; /* If no more chars, */ continue; /* Reset pointer and continue */ } debug(F000,"CONNECT char from macro","",c); } else { /* No macro... */ #endif /* NOSETKEY */ #ifdef BEBOX { int rc = 0; if ((rc = recv(kbin,buf,1,0)) > 0) c = buf[0]; else c = -1; debug(F111,"recv","rc",rc); printf("\r\nrecv: %c rc=%d\r\n",buf[0],rc); } #else /* BEBOX */ c = CONGKS(); /* Yes, read from keyboard */ #endif /* BEBOX */ gotkbd = 0; /* Turn off select() result flag */ #ifndef NOSETKEY } #endif /* NOSETKEY */ if (c == -1) { #ifdef EINTR if (errno == EINTR) continue; #endif /* EINTR */ cx_status = CSX_IOERROR; conoc(BEL); goto conret0; } c &= cmdmsk; /* Do any requested masking */ #ifndef NOSETKEY /* Note: kmptr is NULL if we got character c from the keyboard, and it is not NULL if it came from a macro. In the latter case, we must avoid expanding it again. */ if (!kmptr && macrotab[c]) { /* Macro definition for c? */ debug(F000,"CONNECT macro key",macrotab[c],c); kmptr = macrotab[c]; /* Yes, set up macro pointer */ continue; /* and restart the loop, */ } else c = keymap[c]; /* else use single-char keymap */ #endif /* NOSETKEY */ if ( #ifndef NOSETKEY !kmptr && #endif /* NOSETKEY */ (tt_escape && ((c & 0xff) == escape))) { /* Escape char? */ debug(F000,"CONNECT got escape","",c); #ifdef BEBOX if (recv(kbin,buf,1,0)>=0) c = buf[0]; else c = -1; #else /* BEBOX */ c = CONGKS() & 0x7f; /* Read argument */ #endif /* BEBOX */ doesc((char) c); /* Handle it */ continue; /* Back to loop */ } csave = c; /* Save it before translation */ /* for local echoing. */ #ifdef CKLEARN crflag = (c == CK_CR); /* Remember if it was CR. */ #endif /* CKLEARN */ #ifndef NOCSETS if (inesc[1] == ES_NORMAL) { /* If not inside escape seq.. */ /* Translate character sets */ #ifdef UNICODE int x; if (unicode == 1) { /* Remote is UTF-8 */ outxcount = b_to_u((CHAR)c,outxbuf,OUTXBUFSIZ,tcssize); outxbuf[outxcount] = NUL; } else if (unicode == 2) { /* Local is UTF-8 */ x = u_to_b((CHAR)c); if (x < 0) continue; outxbuf[0] = (unsigned)(x & 0xff); outxcount = 1; outxbuf[outxcount] = NUL; } else { #endif /* UNICODE */ if (sxo) c = (*sxo)((char)c); /* Local-intermediate */ if (rxo) c = (*rxo)((char)c); /* Intermediate-remote */ outxbuf[0] = c; outxcount = 1; outxbuf[outxcount] = NUL; #ifdef UNICODE } #endif /* UNICODE */ } else { outxbuf[0] = c; outxcount = 1; outxbuf[outxcount] = NUL; } if (escseq) apcrc = chkaes((char)c,1); #else /* NOCSETS */ outxbuf[0] = c; outxcount = 1; outxbuf[outxcount] = NUL; #endif /* NOCSETS */ debug(F111,"OUTXBUF",outxbuf,outxcount); for (i = 0; i < outxcount; i++) { c = outxbuf[i]; /* If Shift-In/Shift-Out is selected and we have a 7-bit connection, handle shifting here. */ if (sosi) { /* Shift-In/Out selected? */ if (cmask == 0177) { /* In 7-bit environment? */ if (c & 0200) { /* 8-bit character? */ if (outshift == 0) { /* If not shifted, */ ttoc(dopar(SO)); /* shift. */ outshift = 1; } } else { if (outshift == 1) { /* 7-bit character */ ttoc(dopar(SI)); /* If shifted, */ outshift = 0; /* unshift. */ } } } if (c == SO) outshift = 1; /* User typed SO */ if (c == SI) outshift = 0; /* User typed SI */ } c &= cmask; /* Apply Kermit-to-host mask now. */ if (c == '\015') { /* Carriage Return */ int stuff = -1; if (tnlm) { /* TERMINAL NEWLINE ON */ stuff = LF; /* Stuff LF */ #ifdef TNCODE } else if (network && /* TELNET NEWLINE ON/OFF/RAW */ IS_TELNET()) { switch (!TELOPT_ME(TELOPT_BINARY) ? tn_nlm : tn_b_nlm){ case TNL_CRLF: stuff = LF; break; case TNL_CRNUL: stuff = NUL; break; } #endif /* TNCODE */ } if (stuff > -1) { ttoc(dopar('\015')); /* Send CR */ if (duplex) conoc('\015'); /* Maybe echo CR */ c = stuff; /* Char to stuff */ csave = c; } } #ifdef TNCODE /* If user types the 0xff character (TELNET IAC), it must be doubled. */ else /* Not CR */ if ((dopar((CHAR) c) == IAC) && /* IAC (0xff) */ network && IS_TELNET()) { /* Send one now */ ttoc((char)IAC); /* and the other one just below. */ } #endif /* TNCODE */ /* Send the character */ x = ttoc((char)dopar((CHAR) c)); if (x > -1) { #ifdef CKLEARN if (learning) { /* Learned script active */ if (crflag) { /* User typed CR */ learnchar(CK_CR); /* Handle CR */ learnst = 0; /* Shift to Neutral */ } else { learnchar(c); /* Not CR */ learnst = 2; /* Change state to Keyboard */ } } #endif /* CKLEARN */ if (duplex) { /* If half duplex, must echo */ if (debses) conol(dbchr(csave)); /* the original char */ else /* not the translated one */ conoc((char)csave); if (seslog) { /* And maybe log it too */ c2 = csave; if (sessft == 0 && csave == '\r') c2 = '\n'; LOGCHAR((char)c2); } } } else { perror("\r\nCan't send character"); cx_status = CSX_IOERROR; active = 0; break; } } } if (FD_ISSET(ttyfd, &out)) { FD_CLR(ttyfd, &out); } while (gotnet > 0 || ibc > 0) { gotnet = 0; prev = c; c = ckcgetc(0); /* Get next character */ if (c < 0) { /* Failed... */ ckcputf(); /* Flush CONNECT output buffer */ if (msgflg) { printf("\r\nCommunications disconnect "); #ifdef COMMENT if (c == -3 #ifdef ultrix /* This happens on Ultrix if there's no carrier */ && errno != EIO #endif /* ultrix */ #ifdef UTEK /* This happens on UTEK if there's no carrier */ && errno != EWOULDBLOCK #endif /* UTEK */ ) perror("\r\nCan't read character"); #endif /* COMMENT */ } #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ dologend(); tthang(); /* Hang up the connection */ debug(F111,"CONNECT i/o error 1",ck_errstr(),errno); cx_status = CSX_HOSTDISC; goto conret0; } #ifdef TNCODE tx = 0; if ((c == NUL) && network && IS_TELNET()) { if (prev == CK_CR) { /* Discard of if peer */ if (!TELOPT_U(TELOPT_BINARY)) { /* not in binary mode */ debug(F111,"CONNECT NUL",ckitoa(prev),c); ckcputf(); /* Flush screen output buffer */ break; } } } debug(F111,"CONNECT","c",c); debug(F111,"CONNECT","network",network); debug(F111,"CONNECT","IS_TELNET",IS_TELNET()); if ((c == IAC) && network && IS_TELNET()) { #ifdef CK_ENCRYPTION int x_auth = TELOPT_ME(TELOPT_AUTHENTICATION); #else int x_auth = 0; #endif /* CK_ENCRYPTION */ int me_bin = TELOPT_ME(TELOPT_BINARY); int u_bin = TELOPT_U(TELOPT_BINARY); debug(F100,"CONNECT got IAC","",0); ckcputf(); /* Dump screen-output buffer */ if ((tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc)) == 0) { if (me_bin != TELOPT_ME(TELOPT_BINARY)) { me_bin = TELOPT_ME(TELOPT_BINARY); } else if (u_bin != TELOPT_U(TELOPT_BINARY)) { u_bin = TELOPT_U(TELOPT_BINARY); #ifdef CK_ENCRYPTION /* Here we have to push back any bytes we have read using block reads, so we can read them again using single-character reads, so they can be decrypted in case there was a switch to encryption in the block. Note that we can't handle switches in the encryption state itself this way -- which would be nice, since it would eliminate the need for single-character reads. Why? Because if a series of characters has already been decrypted that shouldn't have been, then (a) it's ruined, and (b) so is the state of the decryption machine. Too bad. */ } else if (TELOPT_ME(TELOPT_AUTHENTICATION) != 0 && TELOPT_ME(TELOPT_AUTHENTICATION) != x_auth ) { if (ttpushback((CHAR *)ibp,ibc) > -1) { ibc = 0; ibp = ibuf; } #endif /* CK_ENCRYPTION */ } continue; } else if (tx == -1) { /* I/O error */ if (msgflg) printf("\r\nCommunications disconnect "); #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ dologend(); debug(F111,"CONNECT i/o error 2",ck_errstr(),errno); cx_status = CSX_IOERROR; goto conret0; } else if (tx == -2) { /* I/O error */ if (msgflg) printf("\r\nConnection closed by peer"); #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ dologend(); debug(F111,"CONNECT i/o error 3",ck_errstr(),errno); cx_status = CSX_IOERROR; goto conret0; } else if (tx == -3) { /* I/O error */ if (msgflg) printf("\r\nConnection closed due to telnet policy"); #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ dologend(); debug(F111,"CONNECT i/o error 4",ck_errstr(),errno); cx_status = CSX_IOERROR; goto conret0; } else if ((tx == 1) && (!duplex)) { /* ECHO change */ duplex = 1; /* Turn on local echo */ continue; } else if ((tx == 2) && (duplex)) { /* ECHO change */ duplex = 0; continue; } else if (tx == 3) { /* Quoted IAC */ c = parity ? 127 : 255; } #ifdef IKS_OPTION else if (tx == 4) { /* IKS State Change */ if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start && !tcp_incoming ) { /* here we need to print a msg that the other */ /* side is in SERVER mode and that REMOTE */ /* commands should be used. And CONNECT mode */ /* should be ended. */ cx_status = CSX_IKSD; active = 0; } } #endif /* IKS_OPTION */ else if (tx == 6) { /* DO LOGOUT was received */ if (msgflg) printf("\r\nRemote Logout "); #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ debug(F100,"CONNECT Remote Logout","",0); cx_status = CSX_TRIGGER; goto conret0; } else continue; /* Negotiation OK, get next char. */ } else if (parity) c &= 0x7f; /* I'm echoing for the remote */ if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo) ttoc((char)c); #endif /* TNCODE */ #ifdef CKLEARN /* Learned script: Record incoming chars if not in Keyboard state */ if (learning && learnst != 2) { /* Learned script active */ learnbuf[learnbp++] = c; /* Save for INPUT command */ if (learnbp >= LEARNBUFSIZ) /* in circular buffer */ learnbp = 0; /* wrapping if at end. */ learnbc++; /* Count this byte. */ learnst = 1; /* State is Net. */ } #endif /* CKLEARN */ if (debses) { /* Output character to screen */ char *s; /* Debugging display... */ s = dbchr(c); /* Make char into string */ while (*s) { /* Output each char from string */ ckcputc(*s); if (seslog) /* And maybe log it. */ LOGCHAR((char)*s); s++; } } else { /* Regular display ... */ c &= cmask; /* Apply Kermit-to-remote mask */ if (seslog && sessft) /* If binary session log */ LOGCHAR((char)c); /* log the character now. */ #ifndef NOXFER #ifdef CK_AUTODL /* Autodownload. Check for Kermit S packet prior to translation, since that can change the packet and make it unrecognizable (as when the terminal character set is an ISO 646 one)... Ditto for Zmodem start packet. */ if (autodl /* Autodownload enabled? */ #ifdef IKS_OPTION || TELOPT_SB(TELOPT_KERMIT).kermit.me_start #endif /* IKS_OPTION */ ) { int k = 0; if (kstartactive || c == stchr /* Kermit S or I packet? */ #ifdef COMMENT || adl_kmode == ADLSTR /* Not used in C-Kermit */ #endif /* COMMENT */ ) k = kstart((CHAR)c); #ifdef CK_XYZ if (!k && zmdlok) /* Or an "sz" start? */ k = zstart((CHAR)c); #endif /* CK_XYZ */ if (k) { int ksign = 0; debug(F101,"CONNECT autodownload k","",k); if (k < 0) { /* Minus-Protocol? */ #ifdef NOSERVER goto noserver; /* Need server mode for this */ #else ksign = 1; /* Remember */ k = 0 - k; /* Convert to actual protocol */ justone = 1; /* Flag for protocol module */ #endif /* NOSERVER */ } else justone = 0; k--; /* Adjust [kz]start's return value */ if (k == PROTO_K #ifdef CK_XYZ || k == PROTO_Z #endif /* CK_XYZ */ ) { /* Damage the packet so that it doesn't trigger */ /* autodownload detection downstream. */ if (k == PROTO_K) { int i, len = strlen((char *)ksbuf); for (i = 0; i < len; i++) ckcputc(BS); } #ifdef CK_XYZ else { int i; for (i = 0; i < 3; i++) ckcputc(CAN); } #endif /* CK_XYZ */ #ifndef NOICP /* sprintf is safe here (builtin keywords) */ sprintf(apcbuf, "set proto %s, %s, set proto %s", ptab[k].p_name, ksign ? "server" : "receive", ptab[protocol].p_name ); apclength = strlen(apcbuf); debug(F111,"CONNECT ksbuf",ksbuf,k); debug(F110,"CONNECT autodownload",apcbuf,0); apcactive = APC_LOCAL; ckcputf(); /* Force screen update */ cx_status = CSX_APC; goto conret1; #else /* Here's another way that doesn't require APC, but then we'll have to change all the other CONNECT modules, and then the mainline code that calls them. */ { extern char sstate; sstate = ksign ? 'x' : 'v'; proto(); } #endif /* NOICP */ } } } #ifdef NOSERVER noserver: #endif /* NOSERVER */ #endif /* CK_AUTODL */ #endif /* NOXFER */ if (sosi) { /* Handle SI/SO */ if (c == SO) { /* Shift Out */ inshift = 1; continue; } else if (c == SI) { /* Shift In */ inshift = 0; continue; } if (inshift) c |= 0200; } inxbuf[0] = c; /* In case there is no translation */ inxcount = 1; /* ... */ #ifndef NOCSETS if (inesc[0] == ES_NORMAL /* If not in an escape sequence */ && !printing /* and not in transparent print */ ) { /* Translate character sets */ #ifdef UNICODE int x; if (unicode == 1) { /* Remote is UTF-8 */ x = u_to_b((CHAR)c); if (x == -1) continue; else if (x == -2) { /* LS or PS */ inxbuf[0] = CK_CR; inxbuf[1] = LF; inxcount = 2; } else if (x == -9) { /* UTF-8 error */ inxbuf[0] = '?'; inxbuf[1] = u_to_b2(); inxcount = 2; } else { inxbuf[0] = (unsigned)(x & 0xff); } c = inxbuf[0]; } else if (unicode == 2) { /* Local is UTF-8 */ inxcount = b_to_u((CHAR)c,inxbuf,OUTXBUFSIZ,tcssize); c = inxbuf[0]; } else { #endif /* UNICODE */ if (sxi) c = (*sxi)((CHAR)c); if (rxi) c = (*rxi)((CHAR)c); inxbuf[0] = c; #ifdef UNICODE } #endif /* UNICODE */ } #endif /* NOCSETS */ #ifndef NOESCSEQ if (escseq) { /* If handling escape sequences */ oldprt = printing; /* remember printer state */ apcrc = chkaes((char)c,0); /* and update escseq state. */ if (printing && !oldprt) /* If printer was turned on */ continue; /* don't print final char of escseq */ } #ifdef CK_APC /* If we are handling APCs, we have several possibilities at this point: 1. Ordinary character to be written to the screen. 2. An Esc; we can't write it because it might be the beginning of an APC. 3. The character following an Esc, in which case we write Esc, then char, but only if we have not just entered an APC sequence. */ if (escseq && (apcstatus & APC_ON)) { if (inesc[0] == ES_GOTESC) /* Don't write ESC yet */ continue; else if (oldesc[0] == ES_GOTESC && !apcactive) { ckcputc(ESC); /* Write saved ESC */ if (seslog && !sessft) LOGCHAR((char)ESC); } else if (apcrc) { /* We have an APC */ debug(F111,"CONNECT APC complete",apcbuf,apclength); ckcputf(); /* Force screen update */ cx_status = CSX_APC; goto conret1; } } #endif /* CK_APC */ #endif /* NOESCSEQ */ debug(F111,"INXBUF",inxbuf,inxcount); for (i = 0; i < inxcount; i++) { /* Loop thru */ c = inxbuf[i]; /* input expansion buffer... */ if ( #ifdef CK_APC !apcactive && /* Don't display APC sequences */ #endif /* CK_APC */ !printing /* or transparent print material */ ) { c &= cmdmsk; /* Apply command mask. */ /* Handle bare carriage returns and linefeeds */ /* SET TERM CR-DISPLAY CRLF? */ if (c == CK_CR && tt_crd) { ckcputc(c); /* Yes, output CR */ if (seslog && !sessft) LOGCHAR((char)c); c = LF; /* and insert a linefeed */ } if (c == LF && tt_lfd) { /* SET TERM CR-DISPLA CRLF? */ ckcputc(CK_CR); /* Yes, output CR */ if (seslog && !sessft) LOGCHAR((char)CK_CR); } #ifndef NOESCSEQ if (dontprint) { /* Do transparent printing. */ dontprint = 0; continue; } else #endif /* NOESCSEQ */ ckcputc(c); /* Write character to screen */ } if (seslog && !sessft) { /* Handle session log. */ LOGCHAR((char)c); } #ifdef XPRINT if (printing && !inesc[0]) { /* zchout() can't be used because */ /* it's buffered differently. */ cbuf[0] = c; zsoutx(ZMFILE,(char *)cbuf,1); } #endif /* XPRINT */ #ifdef CK_TRIGGER /* Check for trigger string */ if (tt_trigger[0]) { int i; if ((i = autoexitchk((CHAR)c)) > -1) { makestr(&triggerval,tt_trigger[i]); ckcputf(); /* Force screen update */ #ifdef NOSETBUF fflush(stdout); /* I mean really force it */ #endif /* NOSETBUF */ cx_status = CSX_TRIGGER; goto conret1; } } #endif /* CK_TRIGGER */ } } } #ifndef BEBOX if (FD_ISSET(scrnout, &out)) { FD_CLR(scrnout, &out); } #endif /* BEBOX */ } /* End of big loop */ conret1: /* Come here to succeed */ rc = 1; conret0: /* Common exit point */ #ifdef BEBOX { long ret_val; closesocket(pair[0]); closesocket(pair[1]); x = kill(tid,SIGKILLTHR); /* Kill thread */ wait_for_thread (tid, &ret_val); } #endif /* BEBOX */ #ifdef CKLEARN if (learning && learnfp) fputs("\n",learnfp); #endif /* CKLEARN */ conres(); if (dohangup > 0) { #ifdef NETCONN if (network #ifdef TNCODE && !TELOPT_ME(TELOPT_COMPORT) #endif /* TNCODE */ ) ttclos(0); #endif /* NETCONN */ #ifndef COMMENT /* This is bad because if they said SET MODEM HANGUP-METHOD MODEM-COMMAND, they mean it -- we shouldn't fall back on tthang() if mdmhup() fails, because maybe they have some special kind of connection. On the other hand, making this change prevents dialing from working at all in some cases. Further study needed. */ #ifndef NODIAL if (dohangup > 1) /* User asked for it */ if (mdmhup() < 1) /* Maybe hang up via modem */ #endif /* NODIAL */ tthang(); /* And make sure we don't hang up */ #else if (!network) { /* Serial connection. */ #ifndef NODIAL if (dialmhu) /* Hang up the way they said to. */ mdmhup(); else #endif /* NODIAL */ tthang(); } #endif /* COMMENT */ dologend(); dohangup = 0; /* again unless requested again. */ } if (quitnow) /* Exit now if requested. */ doexit(GOOD_EXIT,xitsta); if (msgflg #ifdef CK_APC && !apcactive #endif /* CK_APC */ ) printf("(Back at %s)", *myhost ? myhost : "local UNIX system"); #ifdef CK_APC if (!apcactive) #endif /* CK_APC */ printf("\n"); what = W_NOTHING; /* So console modes set right. */ #ifndef NOCSETS language = langsv; /* Restore language */ #endif /* NOCSETS */ #ifdef CK_APC debug(F101,"CONNECT exit apcactive","",apcactive); debug(F101,"CONNECT exit justone","",justone); #endif /* CK_APC */ if (msgflg) { #ifdef CK_APC if (apcactive == APC_LOCAL) printf("\n"); #endif /* CK_APC */ printf("----------------------------------------------------\n"); printbar = 1; } else printbar = 0; fflush(stdout); return(rc); } /* H C O N N E -- Give help message for connect. */ #define CXM_SER 1 /* Serial connections only */ #define CXM_NET 2 /* Network only (but not Telnet) */ #define CXM_TEL 4 /* Telnet only */ static struct hmsgtab { char * hmsg; int hflags; } hlpmsg[] = { {" ? or H for this message", 0}, {" 0 (zero) to send the NUL (0) character", 0}, {" B to send a BREAK signal (0.275sec)", CXM_SER}, #ifdef NETCONN {" B to send a network BREAK", CXM_NET}, {" B to send a Telnet BREAK", CXM_TEL}, #endif /* NETCONN */ #ifdef CK_LBRK {" L to send a Long BREAK (1.5sec)", CXM_SER}, #endif /* CK_LBRK */ #ifdef NETCONN {" I to send a network interrupt packet", CXM_NET}, {" I to send a Telnet Interrupt request", CXM_TEL}, #ifdef TNCODE {" A to send Telnet Are-You-There?", CXM_TEL}, #endif /* TNCODE */ #endif /* NETCONN */ {" U to hangup and close the connection", 0}, {" Q to hangup and quit Kermit", 0}, {" S for status", 0}, #ifdef NOPUSH {" ! to push to local shell (disabled)", 0}, {" Z to suspend (disabled)", 0}, #else {" ! to push to local shell", 0}, #ifdef NOJC {" Z to suspend (disabled)", 0}, #else {" Z to suspend", 0}, #endif /* NOJC */ #endif /* NOPUSH */ {" \\ backslash code:", 0}, {" \\nnn decimal character code", 0}, {" \\Onnn octal character code", 0}, {" \\Xhh hexadecimal character code;", 0}, {" terminate with Carriage Return.", 0}, {" Type the escape character again to send the escape character itself,", 0}, {" or press the space-bar to resume the CONNECT session.", 0}, {NULL, 0} }; int hconne() { int c, i, cxtype; if (network) cxtype = IS_TELNET() ? CXM_TEL : CXM_NET; else cxtype = CXM_SER; conol("\r\n----------------------------------------------------\r\n"); conoll("Press:"); conol(" C to return to "); conoll(*myhost ? myhost : "the C-Kermit prompt"); for (i = 0; hlpmsg[i].hmsg; i++) { if (!(hlpmsg[i].hflags) || (hlpmsg[i].hflags == cxtype)) conoll(hlpmsg[i].hmsg); } conol("Press a key>"); /* Prompt for command. */ c = CONGKS() & 0177; /* Get character, strip any parity. */ /* No key mapping or translation here */ if (c != CMDQ) conoll(""); conoll("----------------------------------------------------"); return(c); /* Return it. */ } /* D O E S C -- Process an escape character argument */ VOID #ifdef CK_ANSIC doesc(char c) #else doesc(c) char c; #endif /* CK_ANSIC */ /* doesc */ { CHAR d; debug(F101,"CONNECT doesc","",c); while (1) { if (c == escape) { /* Send escape character */ d = dopar((CHAR) c); ttoc((char) d); return; } else /* Or else look it up below. */ if (isupper(c)) c = tolower(c); switch(c) { case 'c': /* Escape back to prompt */ case '\03': cx_status = CSX_ESCAPE; #ifdef NOICP conoll(""); conoll(""); conoll( " WARNING: This version of C-Kermit has no command processor to escape" ); conoll( " back to. To return to your local system, log out from the remote and/or" ); conoll( " use the escape character followed by the letter U to close (hang Up) the" ); conoll( " connection. Resuming your session..." ); conoll(""); return; #else active = 0; conol("\r\n"); return; #endif /* NOICP */ case 'b': /* Send a BREAK signal */ case '\02': #ifdef CKLEARN learnchar(-7); #endif /* CKLEARN */ ttsndb(); return; #ifdef NETCONN case 'i': /* Send Interrupt */ case '\011': #ifdef TCPSOCKET if (network && IS_TELNET()) { /* TELNET */ temp[0] = (CHAR) IAC; /* I Am a Command */ temp[1] = (CHAR) TN_IP; /* Interrupt Process */ temp[2] = NUL; ttol((CHAR *)temp,2); } else #endif /* TCPSOCKET */ conoc(BEL); return; #ifdef TCPSOCKET case 'a': /* "Are You There?" */ case '\01': if (network && IS_TELNET()) { temp[0] = (CHAR) IAC; /* I Am a Command */ temp[1] = (CHAR) TN_AYT; /* Are You There? */ temp[2] = NUL; ttol((CHAR *)temp,2); } else conoc(BEL); return; #endif /* TCPSOCKET */ #endif /* NETCONN */ #ifdef CK_LBRK case 'l': /* Send a Long BREAK signal */ #ifdef CKLEARN learnchar(-8); #endif /* CKLEARN */ ttsndlb(); return; #endif /* CK_LBRK */ case 'u': /* Hangup */ /* case '\010': */ /* No, too dangerous */ cx_status = CSX_USERDISC; dohangup = 2; active = 0; conol("\r\nHanging up "); return; case 'q': /* Quit */ cx_status = CSX_USERDISC; dohangup = 2; quitnow = 1; active = 0; conol("\r\n"); return; case 's': /* Status */ conoll(""); conoll("----------------------------------------------------"); #ifdef PTYORPIPE if (ttpipe) ckmakmsg(temp,TMPLEN," Pipe: \"",ttname,"\"",NULL); else if (ttpty) ckmakmsg(temp,TMPLEN," Pty: \"",ttname,"\"",NULL); else #endif /* PTYORPIPE */ ckmakmsg(temp, TMPLEN, " ", (network ? "Host" : "Device"), ": ", ttname ); conoll(temp); /* The following sprintf's are safe, temp[] size is at least 200 */ if (!network && speed >= 0L) { sprintf(temp,"Speed %ld", speed); conoll(temp); } sprintf(temp," Terminal echo: %s", duplex ? "local" : "remote"); conoll(temp); sprintf(temp," Terminal bytesize: %d", (cmask == 0177) ? 7 : 8); conoll(temp); sprintf(temp," Command bytesize: %d", (cmdmsk == 0177) ? 7 : 8); conoll(temp); if (hwparity) sprintf(temp," Parity[hardware]: %s",parnam(hwparity)); else sprintf(temp," Parity: %s", parnam(parity)); conoll(temp); #ifndef NOXFER sprintf(temp," Autodownload: %s", autodl ? "on" : "off"); conoll(temp); #endif /* NOXFER */ ckmakmsg(temp, /* (would not be safe for sprintf) */ TMPLEN, " Session log: ", *sesfil ? sesfil : "(none)", NULL, NULL ); conoll(temp); #ifndef NOSHOW if (!network) shomdm(); #endif /* NOSHOW */ #ifdef CKLOGDIAL { long z; z = dologshow(0); if (z > -1L) { sprintf(temp," Elapsed time: %s",hhmmss(z)); conoll(temp); } } #endif /* CKLOGDIAL */ conoll("----------------------------------------------------"); return; case 'h': /* Help */ case '?': /* Help */ c = hconne(); continue; case '0': /* Send a null */ c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return; case 'z': case '\032': /* Suspend */ #ifndef NOPUSH if (!nopush) stptrap(0); else conoc(BEL); #else conoc(BEL); #endif /* NOPUSH */ return; case '@': /* Start inferior command processor */ case '!': #ifndef NOPUSH if (!nopush) { conres(); /* Put console back to normal */ zshcmd(""); /* Fork a shell. */ if (conbin((char)escape) < 0) { cx_status = CSX_INTERNAL; printf("Error resuming CONNECT session\n"); active = 0; } } else conoc(BEL); #else conoc(BEL); #endif /* NOPUSH */ return; case SP: /* Space, ignore */ return; default: /* Other */ #ifndef NOICP if (c == CMDQ) { /* Backslash escape */ int x; ecbp = ecbuf; *ecbp++ = c; while (((c = (CONGKS() & cmdmsk)) != '\r') && (c != '\n')) *ecbp++ = c; *ecbp = NUL; ecbp = ecbuf; x = xxesc(&ecbp); /* Interpret it */ if (x >= 0) { /* No key mapping here */ c = dopar((CHAR) x); ttoc((char) c); return; } else { /* Invalid backslash code. */ conoc(BEL); return; } } #endif /* NOICP */ conoc(BEL); return; /* Invalid esc arg, beep */ } } } #endif /* NOLOCAL */ ckucon.c000664 045065 024037 00000243355 14767402060 012633 0ustar00fdckermit000000 000000 #include "ckcsym.h" char *connv = "CONNECT Command for UNIX:fork(), 10.0.119, 13 May 2023"; /* C K U C O N -- Terminal connection to remote system, for UNIX */ /* Author: Frank da Cruz , Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. NOTE: This module has been superseded on most platforms by ckucns.c, which uses select() rather than fork() for multiplexing its i/o. This module is still needed for platforms that do not support select(), and also for its X.25 support. Although the two modules share large amounts of code, their structure is radically different and therefore attempts at merging them have so far been unsuccessful. (November 1998.) Special thanks to Eduard Vopicka, Prague University of Economics, Czech Republic, for valuable contributions to this module in July 1994, and to Neal P. Murphy of the Motorola Cellular Infrastructure Group in 1996 for rearranging the code to allow operation on the BeBox, yet still work in regular UNIX. CR symbol changed to CK_CR in C-Kermit 10.0 due to conflict with a Windows header file. */ #include "ckcdeb.h" /* Common things first */ #ifndef NOLOCAL #ifdef BEOSORBEBOX static double time_started = 0.0; #include _PROTOTYP( static long concld, (void *) ); #else _PROTOTYP( static VOID concld, (void) ); #endif /* BEOSORBEBOX */ #ifdef NEXT #undef NSIG #include /* For wait() */ #endif /* NEXT */ #include /* Signals */ #ifndef HPUXPRE65 #include /* Error number symbols */ #else #ifndef ERRNO_INCLUDED #include /* Error number symbols */ #endif /* ERRNO_INCLUDED */ #endif /* HPUXPRE65 */ #ifdef ZILOG /* Longjumps */ #include #else #include #endif /* ZILOG */ #include "ckcsig.h" /* Kermit-specific includes */ #include "ckcasc.h" /* ASCII characters */ #include "ckcker.h" /* Kermit things */ #include "ckucmd.h" /* For xxesc() prototype */ #include "ckcnet.h" /* Network symbols */ #ifndef NOCSETS #include "ckcxla.h" /* Character set translation */ #endif /* NOCSETS */ #include "ckcfnp.h" /* Prototypes (must be last) */ /* Internal function prototypes */ _PROTOTYP( VOID ttflux, (void) ); _PROTOTYP( VOID doesc, (char) ); _PROTOTYP( VOID logchar, (char) ); _PROTOTYP( int hconne, (void) ); #ifndef NOSHOW _PROTOTYP( VOID shomdm, (void) ); #endif /* NOSHOW */ _PROTOTYP( static int kbget, (void) ); _PROTOTYP( static int pipemsg, (int) ); _PROTOTYP( static int ckcputf, (void) ); _PROTOTYP( static VOID ck_sndmsg, (void) ); /* For inter-fork signaling. Normally we use SIGUSR1, except on SCO, where we use SIGUSR2 because SIGUSR1 is used by the system. You can define CK_FORK_SIG to be whatever other signal you might want to use at compile time. We don't use SIGUSR2 everywhere because in some systems, like UnixWare, the default action for SIGUSR2 is to kill the process that gets it. */ #ifndef CK_FORK_SIG #ifndef SIGUSR1 /* User-defined signals */ #define SIGUSR1 30 #endif /* SIGUSR1 */ #ifndef SIGUSR2 #define SIGUSR2 31 #endif /* SIGUSR2 */ #ifdef M_UNIX #define CK_FORK_SIG SIGUSR2 /* SCO - use SIGUSR2 */ #else #define CK_FORK_SIG SIGUSR1 /* Others - use SIGUSR1 */ #endif /* M_UNIX */ #endif /* CK_FORK_SIG */ /* External variables */ extern struct ck_p ptab[]; extern int local, escape, duplex, parity, flow, seslog, sessft, debses, mdmtyp, ttnproto, cmask, cmdmsk, network, nettype, deblog, sosi, tnlm, xitsta, what, ttyfd, ttpipe, quiet, backgrd, pflag, tt_crd, tt_lfd, tn_nlm, ttfdflg, tt_escape, justone, carrier, hwparity; extern long speed; extern char ttname[], sesfil[], myhost[], *ccntab[]; #ifdef TNCODE extern int tn_b_nlm, tn_rem_echo; #endif /* TNCODE */ #ifdef CK_TRIGGER extern char * tt_trigger[], * triggerval; #endif /* CK_TRIGGER */ extern int nopush; #ifdef CK_APC extern int apcactive; /* Application Program Command (APC) */ extern int apcstatus; /* items ... */ static int apclength = 0; #ifdef DCMDBUF extern char *apcbuf; #else extern char apcbuf[]; #endif /* DCMDBUF */ static int apcbuflen = APCBUFLEN - 2; extern int protocol; /* Auto download */ #endif /* CK_APC */ extern int autodl; #ifdef CK_AUTODL extern CHAR ksbuf[]; #endif /* CK_AUTODL */ #ifdef CK_XYZ #ifdef XYZ_INTERNAL static int zmdlok = 1; /* Zmodem autodownloads available */ #else static int zmdlok = 0; /* Depends on external protocol def */ #endif /* XYZ_INTERNAL */ #else static int zmdlok = 0; /* Not available at all */ #endif /* CK_XYZ */ #ifndef NOSETKEY /* Keyboard mapping */ extern KEY *keymap; /* Single-character key map */ extern MACRO *macrotab; /* Key macro pointer table */ static MACRO kmptr = NULL; /* Pointer to current key macro */ #endif /* NOSETKEY */ /* Global variables local to this module */ static int quitnow = 0, /* Q was typed */ jbset = 0, /* Flag whether jmp buf is set. */ dohangup = 0, /* H was typed */ sjval, /* Setjump return value */ goterr = 0, /* Fork/pipe creation error flag */ inshift = 0, /* SO/SI shift states */ outshift = 0; int active = 0; /* Lower fork active flag */ static PID_T parent_id = (PID_T)0; /* Process ID of keyboard fork */ static char ecbuf[10], *ecbp; /* Escape char buffer & pointer */ #ifdef CK_SMALL #define IBUFL 1536 /* Input buffer length */ #else #define IBUFL 4096 #endif /* CK_SMALL */ static int obc = 0; /* Output buffer count */ #ifndef OXOS #define OBUFL 1024 /* Output buffer length */ #else #define OBUFL IBUFL #endif /* OXOS */ #ifdef BIGBUFOK #define TMPLEN 4096 /* Temporary message buffer length */ #else #define TMPLEN 200 #endif /* BIGBUFOK */ #ifdef DYNAMIC static char *ibuf = NULL, *obuf = NULL, *temp = NULL; /* Buffers */ #else static char ibuf[IBUFL], obuf[OBUFL], temp[TMPLEN]; #endif /* DYNAMIC */ #ifdef DYNAMIC static char *ibp; /* Input buffer pointer */ #else static char *ibp = ibuf; /* Input buffer pointer */ #endif /*DYNAMIC */ static int ibc = 0; /* Input buffer count */ #ifdef DYNAMIC static char *obp; /* Output buffer pointer */ #else static char *obp = obuf; /* Output buffer pointer */ #endif /* DYNAMIC */ /* X.25 items */ #ifdef ANYX25 static char *p; /* General purpose pointer */ char x25ibuf[MAXIX25]; /* Input buffer */ char x25obuf[MAXOX25]; /* Output buffer */ int ibufl; /* Length of input buffer */ int obufl; /* Length of output buffer */ unsigned char tosend = 0; int linkid, lcn; static int dox25clr = 0; #ifndef IBMX25 extern CHAR padparms[]; #endif /* IBMX25 */ #endif /* ANYX25 */ static int xpipe[2] = {-1, -1}; /* Pipe descriptor for child-parent messages */ static PID_T pid = (PID_T) 0; /* Process ID of child */ /* Character-set items */ static int unicode = 0; static int escseq = 0; /* 1 = Recognizer is active */ int inesc = 0; /* State of sequence recognizer */ int oldesc = -1; /* Previous state of recognizer */ #define OUTXBUFSIZ 15 static CHAR inxbuf[OUTXBUFSIZ+1]; /* Host-to-screen expansion buffer */ static int inxcount = 0; /* and count */ static CHAR outxbuf[OUTXBUFSIZ+1]; /* Keyboard-to-host expansion buf */ static int outxcount = 0; /* and count */ #ifndef NOCSETS #ifdef CK_ANSIC /* ANSI C prototypes... */ extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */ extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */ static CHAR (*sxo)(CHAR); /* Local translation functions */ static CHAR (*rxo)(CHAR); /* for output (sending) terminal chars */ static CHAR (*sxi)(CHAR); /* and for input (receiving) terminal chars. */ static CHAR (*rxi)(CHAR); #else /* Not ANSI C... */ extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */ extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */ static CHAR (*sxo)(); /* Local translation functions */ static CHAR (*rxo)(); /* for output (sending) terminal chars */ static CHAR (*sxi)(); /* and for input (receiving) terminal chars. */ static CHAR (*rxi)(); #endif /* CK_ANSIC */ extern int language; /* Current language. */ static int langsv; /* For remembering language setting. */ extern struct csinfo fcsinfo[]; /* File character set info. */ extern int tcsr, tcsl; /* Terminal character sets, remote & local. */ static int tcs; /* Intermediate ("transfer") character set. */ static int tcssize = 0; /* Size of tcs */ #ifdef UNICODE /* UTF-8 support */ #ifdef CK_ANSIC extern int (*xl_ufc[MAXFCSETS+1])(USHORT); /* Unicode to FCS */ extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */ extern int (*xuf)(USHORT); /* Translation function UCS to FCS */ extern USHORT (*xfu)(CHAR); /* Translation function FCS to UCS */ #else extern int (*xl_ufc[MAXFCSETS+1])(); extern USHORT (*xl_fcu[MAXFCSETS+1])(); extern int (*xuf)(); extern USHORT (*xfu)(); #endif /* CK_ANSIC */ #endif /* UNICODE */ #endif /* NOCSETS */ /* We do not need to parse and recognize escape sequences if we are being built without character-set support AND without APC support. */ #ifdef NOCSETS /* No character sets */ #ifndef CK_APC /* No APC */ #ifndef NOESCSEQ #define NOESCSEQ /* So no escape sequence recognizer */ #endif /* NOESCSEQ */ #endif /* CK_APC */ #endif /* NOCSETS */ /* Child process events and messages */ #define CEV_NO 0 /* No event */ #define CEV_HUP 1 /* Communications hangup */ #define CEV_PAD 2 /* X.25 - change PAD parameters */ #define CEV_DUP 3 /* Toggle duplex */ #define CEV_APC 4 /* Execute APC */ #ifdef TNCODE #define CEV_MEBIN 5 /* Change of me_binary */ #define CEV_UBIN 6 /* Change of u_binary */ #endif /* TNCODE */ #define CEV_ADL 7 /* Autodownload */ #define CEV_AUL 8 /* Autoupload */ #define CEV_TRI 9 /* Trigger string */ #ifdef NOESCSEQ #define chkaes(x,y) 0 #else /* As of edit 178, the CONNECT command skips past ANSI escape sequences to avoid translating the characters within them. This allows the CONNECT command to work correctly with a host that uses a 7-bit ISO 646 national character set, in which characters like '[' would normally be translated into accented characters, ruining the terminal's interpretation (and generation) of escape sequences. As of edit 190, the CONNECT command responds to APC escape sequences (ESC _ text ESC \) if the user SETs TERMINAL APC ON or UNCHECKED, and the program was built with CK_APC defined. Non-ANSI/ISO-compliant escape sequences are not handled. */ /* States for the escape-sequence recognizer. */ #define ES_NORMAL 0 /* Normal, not in an escape sequence */ #define ES_GOTESC 1 /* Current character is ESC */ #define ES_ESCSEQ 2 /* Inside an escape sequence */ #define ES_GOTCSI 3 /* Inside a control sequence */ #define ES_STRING 4 /* Inside DCS,OSC,PM, or APC string */ #define ES_TERMIN 5 /* 1st char of string terminator */ /* ANSI escape sequence handling. Only the 7-bit form is treated, because translation is not a problem in the 8-bit environment, in which all GL characters are ASCII and no translation takes place. So we don't check for the 8-bit single-character versions of CSI, DCS, OSC, APC, or ST. Here is the ANSI sequence recognizer state table, followed by the code that implements it. Definitions: CAN = Cancel 01/08 Ctrl-X SUB = Substitute 01/10 Ctrl-Z DCS = Device Control Sequence 01/11 05/00 ESC P CSI = Control Sequence Introducer 01/11 05/11 ESC [ ST = String Terminator 01/11 05/12 ESC \ OSC = Operating System Command 01/11 05/13 ESC ] PM = Privacy Message 01/11 05/14 ESC ^ APC = Application Program Command 01/11 05/15 ESC _ ANSI escape sequence recognizer: State Input New State ; Commentary NORMAL (start) ; Start in NORMAL state (any) CAN NORMAL ; ^X cancels (any) SUB NORMAL ; ^Z cancels NORMAL ESC GOTESC ; Begin escape sequence NORMAL other ; NORMAL control or graphic character GOTESC ESC ; Start again GOTESC [ GOTCSI ; CSI GOTESC P STRING ; DCS introducer, consume through ST GOTESC ] STRING ; OSC introducer, consume through ST GOTESC ^ STRING ; PM introducer, consume through ST GOTESC _ STRING ; APC introducer, consume through ST GOTESC 0..~ NORMAL ; 03/00 through 17/14 = Final character GOTESC other ESCSEQ ; Intermediate or ignored control character ESCSEQ ESC GOTESC ; Start again ESCSEQ 0..~ NORMAL ; 03/00 through 17/14 = Final character ESCSEQ other ; Intermediate or ignored control character GOTCSI ESC GOTESC ; Start again GOTCSI @..~ NORMAL ; 04/00 through 17/14 = Final character GOTCSI other ; Intermediate char or ignored control char STRING ESC TERMIN ; Maybe have ST STRING other ; Consume all else TERMIN \ NORMAL ; End of string TERMIN other STRING ; Still in string */ /* chkaes() -- Check ANSI Escape Sequence. Call with EACH character in input stream. Sets global inesc variable according to escape sequence state. Returns 0 normally, 1 if an APC sequence is to be executed. */ int #ifdef CK_ANSIC chkaes(char c, int src) #else chkaes(c) char c; int src; #endif /* CK_ANSIC */ /* chkaes */ { oldesc = inesc; /* Remember previous state */ if (c == CAN || c == SUB) /* CAN and SUB cancel any sequence */ inesc = ES_NORMAL; else /* Otherwise */ switch (inesc) { /* enter state switcher */ case ES_NORMAL: /* NORMAL state */ if (c == ESC) /* Got an ESC */ inesc = ES_GOTESC; /* Change state to GOTESC */ break; /* Otherwise stay in NORMAL state */ case ES_GOTESC: /* GOTESC state */ if (c == '[') /* Left bracket after ESC is CSI */ inesc = ES_GOTCSI; /* Change to GOTCSI state */ else if (c == 'P' || (c > 0134 && c < 0140)) { /* P, [, ^, or _ */ inesc = ES_STRING; /* Switch to STRING-absorption state */ #ifdef CK_APC if (c == '_' && pid == 0 && /* APC handled in child only */ (apcstatus & APC_ON)) { /* and only if not disabled. */ debug(F100,"CONNECT APC begin","",0); apcactive = APC_REMOTE; /* Set APC-Active flag */ apclength = 0; /* and reset APC buffer pointer */ } #endif /* CK_APC */ } else if (c > 057 && c < 0177) /* Final character '0' thru '~' */ inesc = ES_NORMAL; /* Back to normal */ else if (c != ESC) /* ESC in an escape sequence... */ inesc = ES_ESCSEQ; /* starts a new escape sequence */ break; /* Intermediate or ignored ctrl char */ case ES_ESCSEQ: /* ESCSEQ -- in an escape sequence */ if (c > 057 && c < 0177) /* Final character '0' thru '~' */ inesc = ES_NORMAL; /* Return to NORMAL state. */ else if (c == ESC) /* ESC ... */ inesc = ES_GOTESC; /* starts a new escape sequence */ break; /* Intermediate or ignored ctrl char */ case ES_GOTCSI: /* GOTCSI -- In a control sequence */ if (c > 077 && c < 0177) /* Final character '@' thru '~' */ inesc = ES_NORMAL; /* Return to NORMAL. */ else if (c == ESC) /* ESC ... */ inesc = ES_GOTESC; /* starts over. */ break; /* Intermediate or ignored ctrl char */ case ES_STRING: /* Inside a string */ if (c == ESC) /* ESC may be 1st char of terminator */ inesc = ES_TERMIN; /* Go see. */ #ifdef CK_APC else if (apcactive && (apclength < apcbuflen)) /* If in APC, */ apcbuf[apclength++] = c; /* deposit this character. */ else { /* Buffer overrun */ apcactive = 0; /* Discard what we got */ apclength = 0; /* and go back to normal */ apcbuf[0] = 0; /* Not pretty, but what else */ inesc = ES_NORMAL; /* can we do? (ST might not come) */ } #endif /* CK_APC */ break; /* Absorb all other characters. */ case ES_TERMIN: /* May have a string terminator */ if (c == '\\') { /* which must be backslash */ inesc = ES_NORMAL; /* If so, back to NORMAL */ #ifdef CK_APC if (apcactive) { /* If it was an APC string, */ debug(F101,"CONNECT APC terminated","",c); apcbuf[apclength] = NUL; /* terminate it and then ... */ return(1); } #endif /* CK_APC */ } else { /* Otherwise */ inesc = ES_STRING; /* Back to string absorption. */ #ifdef CK_APC if (apcactive && (apclength+1 < apcbuflen)) { /* In APC string */ apcbuf[apclength++] = ESC; /* deposit the Esc character */ apcbuf[apclength++] = c; /* and this character too */ } #endif /* CK_APC */ } } return(0); } #endif /* NOESCSEQ */ /* Connect state parent/child communication signal handlers */ /* Routines used by the child process */ static int pipemsg(n) int n; { /* Send message ID to parent */ int code = n & 255; return(write(xpipe[1], &code, sizeof(code))); } /* Environment pointer for CK_FORK_SIG signal handling in child... */ #ifdef CK_POSIX_SIG static sigjmp_buf sig_env; #else static jmp_buf sig_env; #endif /* CK_POSIX_SIG */ static SIGTYP /* CK_FORK_SIG handling in child ... */ forkint(foo) int foo; { /* It is important to disable CK_FORK_SIG before longjmp */ signal(CK_FORK_SIG, SIG_IGN); /* Set to ignore CK_FORK_SIG */ debug(F100,"CONNECT forkint - CK_FORK_SIG", "", 0); /* Force return from ck_sndmsg() */ cklongjmp(sig_env, 1); /* NOTREACHED */ } static VOID ck_sndmsg() { /* Executed by child only ... */ debug(F100,"CONNECT ck_sndmsg, active", "", active); if ( #ifdef CK_POSIX_SIG sigsetjmp(sig_env,1) #else setjmp(sig_env) #endif /* CK_POSIX_SIG */ == 0) { debug(F100,"CONNECT ck_sndmsg signaling parent","",0); signal(CK_FORK_SIG, forkint); /* Set up signal handler */ kill(parent_id, CK_FORK_SIG); /* Kick the parent */ debug(F100,"ck_sndmsg pausing","",0); for (;;) pause(); /* Wait for CK_FORK_SIG or SIGKILL */ /* NOTREACHED */ } /* We come here from forkint() via [sig]cklongjmp(sig_env,1) */ debug(F100,"CONNECT ck_sndmsg is parent - returning", "", 0); } /* Routines used by the parent process */ #ifdef CK_POSIX_SIG /* Environment pointer for CONNECT errors */ static sigjmp_buf con_env; #else static jmp_buf con_env; #endif /* CK_POSIX_SIG */ /* pipeint() handles CK_FORK_SIG signals from the lower (port) fork. It reads a function code from the pipe that connects the two forks, then reads additional data from the pipe, then handles it. */ static SIGTYP pipeint(arg) int arg; { /* Dummy argument */ int code, cx, x, i /* , n */ ; #ifndef NOCCTRAP extern ckjmpbuf cmjbuf; #endif /* NOCCTRAP */ /* IMPORTANT: At this point, the child fork is waiting for CK_FORK_SIG (eventually for SIGKILL) inside of ck_sndmsg(). So we can't get any subsequent CK_FORK_SIG from child before we send it CK_FORK_SIG. */ signal(CK_FORK_SIG, SIG_IGN); /* Ignore CK_FORK_SIG now */ debug(F101,"CONNECT pipeint arg","",arg); read(xpipe[0], &code, sizeof(code)); /* Get function code from pipe */ debug(F101,"CONNECT pipeint code","",code); cx = code & 255; /* 8-bit version of function code */ #ifndef NOCCTRAP #ifndef NOICP #define USECCJMPBUF #endif /* NOICP */ #endif /* NOCCTRAP */ /* Read info passed back up to us by the lower fork, depending on the function requested. The same number of items must be read from the pipe in the same order as the lower fork put them there. Trying to read something that's not there makes the program hang uninterruptibly. Pay close attention -- notice how we fall through some of the cases rather than break; that's deliberate. */ switch (cx) { #ifdef CK_TRIGGER case CEV_TRI: /* Trigger string */ debug(F100,"CONNECT trigger","",0); read(xpipe[0], (char *)&i, sizeof(i)); /* Trigger index */ debug(F101,"CONNECT trigger index","",i); makestr(&triggerval,tt_trigger[i]); /* Make a copy of the trigger */ debug(F110,"CONNECT triggerval",triggerval,0); read(xpipe[0], (char *)&ibc, sizeof(ibc)); /* Copy child's */ debug(F101,"CONNECT trigger ibc (upper)","",ibc); /* input buffer. */ if (ibc > 0) { read(xpipe[0], (char *)&ibp, sizeof(ibp)); read(xpipe[0], ibp, ibc); } /* Fall thru... */ #endif /* CK_TRIGGER */ case CEV_HUP: /* The CEV_HUP case is executed when the other side has hung up on us. In some cases, this happens before we have had a chance to execute the setjmp(con_env,1) call, and in that case we'd better not take the longjmp! A good example is when you TELNET to port 13 on the local host; it prints its asctime() string (26 chars) and then closes the connection. */ #ifdef CK_TRIGGER if (cx == CEV_TRI) sjval = CEV_TRI; /* Set global variable. */ else #endif /* CK_TRIGGER */ sjval = CEV_HUP; if (jbset) { /* jmp_buf is initialized */ cklongjmp(con_env,sjval); /* so do the right thing. */ } else { int x = 0; #ifdef USECCJMPBUF /* jmp_buf not init'd yet a close approximation... */ #ifdef CK_TRIGGER if (cx == CEV_HUP) #endif /* CK_TRIGGER */ ttclos(0); /* Close our end of the connection */ if (pid) { debug(F101,"CONNECT trigger killing pid","",pid); #ifdef BEOSORBEBOX { long ret_val; x = kill(pid,SIGKILLTHR); /* Kill lower fork */ wait_for_thread (pid, &ret_val); } #else #ifdef Plan9 x = kill(pid, SIGKILL); /* (should always use this really) */ #else x = kill(pid,9); /* Kill lower fork (history) */ #endif /* Plan9 */ wait((WAIT_T *)0); /* Wait till gone. */ if (x < 0) { printf("ERROR: Failure to kill pid %ld: %s, errno=%d\n", (long) pid, ck_errstr(), errno); debug(F111,"CONNECT error killing stale pid", ck_errstr(),errno); } pid = (PID_T) 0; #endif /* BEOSORBEBOX */ } conres(); /* Reset the console. */ if (!quiet) { printf("\r\n(Back at %s)\r\n", *myhost ? myhost : #ifdef UNIX "local UNIX system" #else "local system" #endif /* UNIX */ ); } what = W_NOTHING; /* So console modes are set right. */ printf("\r\n"); /* prevent prompt-stomping */ cklongjmp(cmjbuf,0); /* Do what the Ctrl-C handler does */ #else printf("\r\nLongjump failure - fatal\r\n"); doexit(GOOD_EXIT,-1); /* Better than dumping core... */ #endif /* USECCJMPBUF */ } #ifdef USECCJMPBUF #undef USECCJMPBUF #endif /* USECCJMPBUF */ case CEV_DUP: /* Child sends duplex change */ read(xpipe[0], (char *)&duplex, sizeof(duplex)); debug(F101,"CONNECT pipeint duplex","",duplex); break; #ifdef TNCODE case CEV_MEBIN: /* Child sends me_binary change */ read(xpipe[0], (char *)&TELOPT_ME(TELOPT_BINARY), sizeof(TELOPT_ME(TELOPT_BINARY)) ); debug(F101,"CONNECT pipeint me_binary","",TELOPT_ME(TELOPT_BINARY)); break; case CEV_UBIN: /* Child sends u_binary change */ read(xpipe[0], (char *)&TELOPT_U(TELOPT_BINARY), sizeof(TELOPT_U(TELOPT_BINARY)) ); debug(F101,"CONNECT pipeint u_binary","",TELOPT_U(TELOPT_BINARY)); break; #endif /* TNCODE */ #ifdef CK_APC case CEV_AUL: /* Autoupload */ justone = 1; debug(F100,"CONNECT autoupload at parent","",0); #ifdef CK_AUTODL case CEV_ADL: /* Autodownload */ apcactive = APC_LOCAL; if (!justone) debug(F100,"CONNECT autodownload at parent","",0); /* Copy child's Kermit packet if any */ read(xpipe[0], (char *)&x, sizeof(x)); debug(F101,"CONNECT trigger ibc (upper)","",ibc); if (x > 0) read(xpipe[0], (char *)ksbuf, x+1); #endif /* CK_AUTODL */ case CEV_APC: /* Application Program Command */ read(xpipe[0], (char *)&apclength, sizeof(apclength)); read(xpipe[0], apcbuf, apclength+1); /* Include trailing zero byte */ debug(F111,"CONNECT APC at parent",apcbuf,apclength); read(xpipe[0], (char *)&ibc, sizeof(ibc)); /* Copy child's */ if (ibc > 0) { /* input buffer. */ read(xpipe[0], (char *)&ibp, sizeof(ibp)); read(xpipe[0], ibp, ibc); } obc = 0; obp = obuf; *obuf = NUL; /* Because port fork flushed */ sjval = CEV_APC; cklongjmp(con_env,sjval); /* NOTREACHED */ #endif /* CK_APC */ #ifdef SUNX25 case CEV_PAD: /* X.25 PAD parameter change */ debug(F100,"CONNECT pipeint PAD change","",0); read(xpipe[0],padparms,MAXPADPARMS); sjval = CEV_PAD; /* Set global variable. */ #ifdef COMMENT /* We might not need to do this... */ cklongjmp(con_env,sjval); /* NOTREACHED */ #else /* COMMENT */ break; #endif /* COMMENT */ #endif /* SUNX25 */ } signal(CK_FORK_SIG, pipeint); /* Set up signal handler */ kill(pid, CK_FORK_SIG); /* Signal the port fork ... */ } /* C K C P U T C -- C-Kermit CONNECT Put Character to Screen */ /* Output is buffered to avoid slow screen writes on fast connections. NOTE: These could (easily?) become macros ... */ static int ckcputf() { /* Dump the output buffer */ int x = 0; if (obc > 0) /* If we have any characters, */ x = conxo(obc,obuf); /* dump them, */ obp = obuf; /* reset the pointer */ obc = 0; /* and the counter. */ return(x); /* Return conxo's return code */ } int ckcputc(c) int c; { int x; *obp++ = c & 0xff; /* Deposit the character */ obc++; /* Count it */ if (ibc == 0 || /* If input buffer about empty */ obc == OBUFL) { /* or output buffer full */ debug(F101,"CONNECT CKCPUTC obc","",obc); x = conxo(obc,obuf); /* dump the buffer, */ obp = obuf; /* reset the pointer */ obc = 0; /* and the counter. */ return(x); /* Return conxo's return code */ } else return(0); } /* C K C G E T C -- C-Kermit CONNECT Get Character */ /* Buffered read from communication device. Returns the next character, refilling the buffer if necessary. On error, returns ttinc's return code (see ttinc() description). Dummy argument for compatible calling conventions with ttinc(). NOTE: We don't have a macro for this because we have to pass a pointer to this function as an argument to tn_doop(). */ int ckcgetc(dummy) int dummy; { int c, n; #ifdef CK_SSL extern int ssl_active_flag, tls_active_flag; #endif /* CK_SSL */ #ifdef CK_ENCRYPTION /* No buffering for possibly encrypted connections */ if (network && IS_TELNET() && TELOPT_ME(TELOPT_AUTHENTICATION)) return(ttinc(0)); #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if (ssl_active_flag || tls_active_flag) return(ttinc(0)); #endif /* CK_SSL */ #ifdef COMMENT /* too much */ debug(F101,"CONNECT CKCGETC 1 ibc","",ibc); /* Log */ #endif /* COMMENT */ if (ibc < 1) { /* Need to refill buffer? */ ibc = 0; /* Yes, reset count */ ibp = ibuf; /* and buffer pointer */ /* debug(F100,"CONNECT CKCGETC 1 calling ttinc(0)","",0); */ #ifdef COMMENT /* This check is not worth the overhead. Scenario: ttchk() returns 0, so we fall through to the blocking ttinc(). While in ttinc(), the connection is lost. But the read() that ttinc() calls does not notice, and never returns. This happens at least in HP-UX, and can be seen when we turn off the modem. */ if (!network && (carrier != CAR_OFF)) if ((n = ttchk()) < 0) /* Make sure connection is not lost */ return(n); #endif /* COMMENT */ c = ttinc(0); /* Read one character, blocking */ /* debug(F101,"CONNECT CKCGETC 1 ttinc(0)","",c); */ if (c < 0) { /* If error, return error code */ return(c); } else { /* Otherwise, got one character */ *ibp++ = c; /* Advance buffer pointer */ ibc++; /* and count. */ } if ((n = ttchk()) > 0) { /* Any more waiting? */ if (n > (IBUFL - ibc)) /* Get them all at once. */ n = IBUFL - ibc; /* Don't overflow buffer */ if ((n = ttxin(n,(CHAR *)ibp)) > 0) { #ifdef CK_ENCRYPTION if (TELOPT_U(TELOPT_ENCRYPTION)) ck_tn_decrypt(ibp,n); #endif /* CK_ENCRYPTION */ ibc += n; /* Advance counter */ } } else if (n < 0) { /* Error? */ return(n); /* Return the error code */ } debug(F101,"CONNECT CKCGETC 2 ibc","",ibc); /* Log how many */ ibp = ibuf; /* Point to beginning of buffer */ } c = *ibp++ & 0xff; /* Get next character from buffer */ ibc--; /* Reduce buffer count */ return(c); /* Return the character */ } /* Keyboard handling, buffered for speed, which is needed when C-Kermit is in CONNECT mode between two other computers that are transferring data. */ static char *kbp; /* Keyboard input buffer pointer */ static int kbc; /* Keyboard input buffer count */ #ifdef CK_SMALL /* Keyboard input buffer length */ #define KBUFL 32 /* Small for PDP-11 UNIX */ #else #define KBUFL 257 /* Regular kernel size for others */ #endif /* CK_SMALL */ #ifdef DYNAMIC static char *kbuf = NULL; #else static char kbuf[KBUFL]; #endif /* DYNAMIC */ /* Macro for reading keystrokes. */ #define CONGKS() (((--kbc)>=0) ? ((int)(*kbp++) & 0377) : kbget()) /* Note that we call read() directly here, normally a no-no, but in this case we know it's UNIX and we're only doing what coninc(0) would have done, except we're reading a block of characters rather than just one. There is, at present, no conxin() analog to ttxin() for chunk reads, and instituting one would only add function-call overhead as it would only be a wrapper for a read() call anyway. */ /* Another note: We stick in this read() till the user types something. But the other (lower) fork is running too, and on TELNET connections, it will signal us to indicate echo-change negotiations, and this can interrupt the read(). Some UNIXes automatically restart the interrupted system call, others return from it with errno == EINTR. */ static int /* Keyboard buffer filler */ kbget() { #ifdef EINTR int tries = 10; /* If read() is interrupted, */ int ok = 0; while (tries-- > 0) { /* try a few times... */ #endif /* EINTR */ if ((kbc = conchk()) < 1) /* How many chars waiting? */ kbc = 1; /* If none or dunno, wait for one. */ else if (kbc > KBUFL) /* If too many, */ kbc = KBUFL; /* only read this many. */ if ((kbc = read(0, kbuf, kbc)) < 1) { /* Now read it/them. */ debug(F101,"CONNECT kbget errno","",errno); /* Got an error. */ #ifdef EINTR if (errno == EINTR) /* Interrupted system call. */ continue; /* Try again, up to limit. */ else /* Something else. */ #endif /* EINTR */ return(-1); /* Pass along read() error. */ } #ifdef EINTR else { ok = 1; break; } } if (!ok) return(-1); #endif /* EINTR */ kbp = kbuf; /* Adjust buffer pointer, */ kbc--; /* count, */ return((int)(*kbp++) & 0377); /* and return first character. */ } /* C O N C L D -- Interactive terminal connection child function */ static #ifdef BEOSORBEBOX long #else VOID #endif /* BEOSORBEBOX */ concld ( #ifdef BEOSORBEBOX void *bevoid #endif /* BEOSORBEBOX */ ) { int n; /* General purpose counter */ int i; /* For loops... */ int c = -1; /* c is a character, but must be signed integer to pass thru -1, which is the modem disconnection signal, and is different from the character 0377 */ int prev; #ifdef TNCODE int tx; /* tn_doop() return code */ #endif /* TNCODE */ #ifdef CK_TRIGGER int ix; /* Trigger index */ #endif /* CK_TRIGGER */ #ifndef NOESCSEQ int apcrc; #endif /* NOESCSEQ */ #ifdef COMMENT int conret = 0; /* Return value from conect() */ jbchksum = -1L; #endif /* COMMENT */ jbset = 0; /* jmp_buf not set yet, don't use it */ debug(F101,"CONNECT concld entry","",CK_FORK_SIG); /* *** */ /* Inferior reads, prints port input */ if (priv_can()) { /* Cancel all privs */ printf("?setuid error - fatal\n"); doexit(BAD_EXIT,-1); } signal(SIGINT, SIG_IGN); /* In case these haven't been */ signal(SIGQUIT, SIG_IGN); /* inherited from above... */ signal(CK_FORK_SIG, SIG_IGN); /* CK_FORK_SIG not expected yet */ inshift = outshift = 0; /* Initial SO/SI shift state. */ { /* Wait for parent's setup */ int i; while ((i = read(xpipe[0], &c, 1)) <= 0) { if (i < 0) { debug(F101,"CONNECT concld setup error","",i); debug(F111,"CONNECT concld setup error",ck_errstr(),errno); pipemsg(CEV_HUP); /* Read error - hangup */ ck_sndmsg(); /* Send and wait to be killed */ /* NOTREACHED */ } /* Restart interrupted read() */ } } close(xpipe[0]); xpipe[0] = -1; /* Child - prevent future reads */ #ifdef DEBUG if (deblog) { debug(F100,"CONNECT starting port fork","",0); debug(F101,"CONNECT port fork ibc","",ibc); debug(F101,"CONNECT port fork obc","",obc); } #endif /* DEBUG */ what = W_CONNECT; while (1) { /* Fresh read, wait for a character. */ #ifdef ANYX25 if (network && (nettype == NET_SX25)) { bzero(x25ibuf,sizeof(x25ibuf)) ; if ((ibufl = ttxin(MAXIX25,(CHAR *)x25ibuf)) < 0) { #ifndef IBMX25 if (ibufl == -2) { /* PAD parms changes */ pipemsg(CEV_PAD); write(xpipe[1],padparms,MAXPADPARMS); ck_sndmsg(); } else { #endif /* IBMX25 */ if (!quiet) printf("\r\nCommunications disconnect "); dologend(); pipemsg(CEV_HUP); ck_sndmsg(); /* Wait to be killed */ /* NOTREACHED */ #ifndef IBMX25 } #endif /* IBMX25 */ /* pause(); <--- SHOULD BE OBSOLETE NOW! */ /* BECAUSE pause() is done inside of ck_sndmsg() */ } if (debses) { /* Debugging output */ p = x25ibuf ; while (ibufl--) { c = *p++; conol(dbchr(c)); } } else { if (seslog && sessft) /* Binary session log */ logchar((char)c); /* Log char before translation */ if (sosi #ifndef NOCSETS || tcsl != tcsr #endif /* NOCSETS */ ) { /* Character at a time */ for (i = 1; i < ibufl; i++) { c = x25ibuf[i] & cmask; if (sosi) { /* Handle SI/SO */ if (c == SO) { inshift = 1; continue; } else if (c == SI) { inshift = 0; continue; } if (inshift) c |= 0200; } #ifndef NOCSETS if (inesc == ES_NORMAL) { #ifdef UNICODE int x; if (unicode == 1) { /* Remote is UTF-8 */ x = u_to_b((CHAR)c); if (x == -1) continue; else if (x == -2) { /* LS or PS */ inxbuf[0] = CR; inxbuf[1] = LF; inxcount = 2; } else { inxbuf[0] = (unsigned)(x & 0xff); } c = inxbuf[0]; } else if (unicode == 2) { /* Local is UTF-8 */ inxcount = b_to_u((CHAR)c,inxbuf,OUTXBUFSIZ,tcssize); c = inxbuf[0]; } else { #endif /* UNICODE */ if (sxi) c = (*sxi)((CHAR)c); if (rxi) c = (*rxi)((CHAR)c); inxbuf[0] = c; #ifdef UNICODE } #endif /* UNICODE */ } #endif /* NOCSETS */ c &= cmdmsk; /* Apply command mask. */ conoc(c); /* Output to screen */ if (seslog && !sessft) /* and session log */ logchar(c); } } else { /* All at once */ for (i = 1; i < ibufl; i++) x25ibuf[i] &= (cmask & cmdmsk); conxo(ibufl,x25ibuf); if (seslog) zsoutx(ZSFILE,x25ibuf,ibufl); } } continue; } else { /* Not X.25... */ #endif /* ANYX25 */ /* Get the next communication line character from our internal buffer. If the buffer is empty, refill it. */ prev = c; /* Remember previous character */ c = ckcgetc(0); /* Get next character */ /* debug(F101,"CONNECT c","",c); */ if (c < 0) { /* Failed... */ debug(F101,"CONNECT disconnect ibc","",ibc); debug(F101,"CONNECT disconnect obc","",obc); ckcputf(); /* Flush CONNECT output buffer */ if (!quiet) { printf("\r\nCommunications disconnect "); #ifdef COMMENT if ( c == -3 #ifdef ultrix /* This happens on Ultrix if there's no carrier */ && errno != EIO #endif /* ultrix */ #ifdef UTEK /* This happens on UTEK if there's no carrier */ && errno != EWOULDBLOCK #endif /* UTEK */ ) perror("\r\nCan't read character"); #endif /* COMMENT */ } #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ tthang(); /* Hang up the connection */ debug(F111,"CONNECT concld i/o error",ck_errstr(),errno); pipemsg(CEV_HUP); ck_sndmsg(); /* Wait to be killed */ } #ifdef COMMENT /* too much... */ debug(F101,"CONNECT ** PORT","",c); /* Got character c OK. */ #endif /* COMMENT */ #ifdef TNCODE /* Handle TELNET negotiations... */ if ((c == NUL) && network && IS_TELNET()) { if (prev == CK_CR) /* Discard of */ if (!TELOPT_U(TELOPT_BINARY)) continue; } if ((c == IAC) && network && IS_TELNET()) { int me_bin = TELOPT_ME(TELOPT_BINARY); int u_bin = TELOPT_U(TELOPT_BINARY); debug(F100,"CONNECT got IAC","",0); ckcputf(); /* Dump screen-output buffer */ if ((tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc)) == 0) { if (me_bin != TELOPT_ME(TELOPT_BINARY)) { debug(F101, "CONNECT TELNET me_bin", "", TELOPT_ME(TELOPT_BINARY) ); pipemsg(CEV_MEBIN); /* Tell parent */ write(xpipe[1], &TELOPT_ME(TELOPT_BINARY), sizeof(TELOPT_ME(TELOPT_BINARY)) ); ck_sndmsg(); /* Tell the parent fork */ } else if (u_bin != TELOPT_U(TELOPT_BINARY)) { debug(F101, "CONNECT TELNET u_bin", "", TELOPT_U(TELOPT_BINARY) ); pipemsg(CEV_UBIN); /* Tell parent */ write(xpipe[1], &TELOPT_U(TELOPT_BINARY), sizeof(TELOPT_U(TELOPT_BINARY)) ); ck_sndmsg(); /* Tell the parent fork */ } continue; } else if (tx == -1) { /* I/O error */ if (!quiet) printf("\r\nCommunications disconnect "); #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ dologend(); debug(F111,"CONNECT concld i/o error 2",ck_errstr(),errno); pipemsg(CEV_HUP); ck_sndmsg(); /* Wait to be killed */ /* NOTREACHED */ } else if (tx == -3) { /* I/O error */ if (!quiet) printf("\r\nConnection closed due to telnet policy "); #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ dologend(); debug(F111,"CONNECT concld i/o error 2",ck_errstr(),errno); pipemsg(CEV_HUP); ck_sndmsg(); /* Wait to be killed */ /* NOTREACHED */ } else if (tx == -2) { /* I/O error */ if (!quiet) printf("\r\nConnection closed by peer "); #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ dologend(); debug(F111,"CONNECT concld i/o error 2",ck_errstr(),errno); pipemsg(CEV_HUP); ck_sndmsg(); /* Wait to be killed */ /* NOTREACHED */ } else if ((tx == 1) && (!duplex)) { /* ECHO change */ duplex = 1; /* Turn on local echo */ debug(F101,"CONNECT TELNET duplex change","",duplex); pipemsg(CEV_DUP); /* Tell parent */ write(xpipe[1], &duplex, sizeof(duplex)); ck_sndmsg(); /* Tell the parent fork */ continue; } else if ((tx == 2) && (duplex)) { /* ECHO change */ duplex = 0; debug(F101,"CONNECT TELNET duplex change","",duplex); pipemsg(CEV_DUP); write(xpipe[1], &duplex, sizeof(duplex)); ck_sndmsg(); continue; } else if (tx == 3) { /* Quoted IAC */ c = parity ? 127 : 255; } #ifdef IKS_OPTION else if (tx == 4) { /* IKS State Change */ if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start && !tcp_incoming ) { /* here we need to print a msg that the other */ /* side is in SERVER mode and that REMOTE */ /* commands should be used. And CONNECT mode */ /* should be ended. */ active = 0; } } #endif /* IKS_OPTION */ else if (tx == 6) { /* DO LOGOUT received */ if (!quiet) printf("\r\nRemote Logout "); #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ debug(F100,"CONNECT Remote Logout","",0); pipemsg(CEV_HUP); ck_sndmsg(); /* Wait to be killed */ /* NOTREACHED */ } else continue; /* Negotiation OK, get next char. */ } else if (parity) c &= 0x7f; if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo) ttoc(c); /* I'm echoing for the remote */ #endif /* TNCODE */ if (debses) { /* Output character to screen */ char *s; /* Debugging display... */ s = dbchr(c); while (*s) ckcputc(*s++); } else { /* Regular display ... */ c &= cmask; /* Apply Kermit-to-remote mask */ #ifdef CK_AUTODL /* Autodownload. Check for Kermit S packet prior to translation, since that can change the packet and make it unrecognizable (as when the terminal character set is an ISO 646 one)... Ditto for Zmodem start packet. */ if (autodl /* Autodownload enabled? */ #ifdef IKS_OPTION || TELOPT_SB(TELOPT_KERMIT).kermit.me_start #endif /* IKS_OPTION */ ) { int k; k = kstart((CHAR)c); /* Kermit S or I packet? */ #ifdef CK_XYZ if (!k && zmdlok) /* Or an "sz" start? */ k = zstart((CHAR)c); #endif /* CK_XYZ */ if (k) { int ksign = 0; debug(F101,"CONNECT autodownload k","",k); if (k < 0) { /* Minus-Protocol? */ #ifdef NOSERVER goto noserver; /* Need server mode for this */ #else ksign = 1; /* Remember */ k = 0 - k; /* Convert to actual protocol */ justone = 1; /* Flag for protocol module */ #endif /* NOSERVER */ } else justone = 0; k--; /* Adjust [kz]start's return value */ if (k == PROTO_K #ifdef CK_XYZ || k == PROTO_Z #endif /* CK_XYZ */ ) { /* Now damage the packet so that it does not */ /* trigger autodownload detection on subsquent */ /* links. */ if (k == PROTO_K) { int i, len = strlen((char*)ksbuf); for (i = 0; i < len; i++) ckcputc(BS); } #ifdef CK_XYZ else { int i; for (i = 0; i < 3; i++) ckcputc(CAN); } #endif /* CK_XYZ */ /* Notify parent */ pipemsg(justone ? CEV_AUL : CEV_ADL); /* Send our memory back up to the top fork thru the pipe. CAREFUL -- Write this stuff in the same order it is to be read! */ /* Copy our Kermit packet to the parent fork */ n = (int) strlen((char *)ksbuf); write(xpipe[1], (char *)&n, sizeof(n)); if (n > 0) write(xpipe[1], (char *)ksbuf, n+1); debug(F111,"CONNECT autodownload ksbuf",ksbuf,n); debug(F101,"CONNECT autodownload justone","", justone); /* Construct the APC command */ sprintf(apcbuf, "set proto %s, %s, set proto %s", ptab[k].p_name, ksign ? "server" : "receive", ptab[protocol].p_name ); apclength = strlen(apcbuf); debug(F111,"CONNECT ksbuf",ksbuf,k); debug(F110,"CONNECT autodownload",apcbuf,0); apcactive = APC_LOCAL; ckcputf(); /* Force screen update */ /* Write buffer including trailing NUL byte */ debug(F101,"CONNECT write xpipe apclength","", apclength); write(xpipe[1], (char *)&apclength, sizeof(apclength) ); debug(F110,"CONNECT write xpipe apcbuf",apcbuf,0); write(xpipe[1], apcbuf, apclength+1); /* Copy our input buffer to the parent fork */ debug(F101,"CONNECT autodownload complete ibc", "",ibc); debug(F101,"CONNECT autodownload complete obc", "",obc); write(xpipe[1], (char *)&ibc, sizeof(ibc)); if (ibc > 0) { write(xpipe[1], (char *)&ibp, sizeof(ibp)); write(xpipe[1], ibp, ibc); } ck_sndmsg(); /* Wait to be killed */ /* NOTREACHED */ } } } #ifdef NOSERVER noserver: #endif /* NOSERVER */ #endif /* CK_AUTODL */ if (sosi) { /* Handle SI/SO */ if (c == SO) { /* Shift Out */ inshift = 1; continue; } else if (c == SI) { /* Shift In */ inshift = 0; continue; } if (inshift) c |= 0200; } inxbuf[0] = c; /* In case there is no translation */ inxcount = 1; /* ... */ #ifndef NOCSETS if (inesc == ES_NORMAL) { /* If not in an escape sequence */ #ifdef UNICODE int x; /* Translate character sets */ CHAR ch; ch = c; if (unicode == 1) { /* Remote is UTF-8 */ x = u_to_b(ch); if (x < 0) continue; inxbuf[0] = (unsigned)(x & 0xff); c = inxbuf[0]; } else if (unicode == 2) { /* Local is UTF-8 */ inxcount = b_to_u(ch,inxbuf,OUTXBUFSIZ,tcssize); c = inxbuf[0]; } else { #endif /* UNICODE */ if (sxi) c = (*sxi)((CHAR)c); if (rxi) c = (*rxi)((CHAR)c); inxbuf[0] = c; #ifdef UNICODE } #endif /* UNICODE */ } #endif /* NOCSETS */ #ifndef NOESCSEQ if (escseq) /* If handling escape sequences */ apcrc = chkaes((char)c,1); /* update our state */ #ifdef CK_APC /* If we are handling APCs, we have several possibilities at this point: 1. Ordinary character to be written to the screen. 2. An Esc; we can't write it because it might be the beginning of an APC. 3. The character following an Esc, in which case we write Esc, then char, but only if we have not just entered an APC sequence. */ if (escseq && (apcstatus & APC_ON)) { if (inesc == ES_GOTESC) /* Don't write ESC yet */ continue; else if (oldesc == ES_GOTESC && !apcactive) { ckcputc(ESC); /* Write saved ESC */ if (seslog && !sessft) logchar((char)ESC); } else if (apcrc) { /* We have an APC */ debug(F111,"CONNECT APC complete",apcbuf,apclength); ckcputf(); /* Force screen update */ pipemsg(CEV_APC); /* Notify parent */ write(xpipe[1], (char *)&apclength, sizeof(apclength) ); /* Write buffer including trailing NUL byte */ write(xpipe[1], apcbuf, apclength+1); /* Copy our input buffer to the parent fork */ debug(F101,"CONNECT APC complete ibc","",ibc); debug(F101,"CONNECT APC complete obc","",obc); write(xpipe[1], (char *)&ibc, sizeof(ibc)); if (ibc > 0) { write(xpipe[1], (char *)&ibp, sizeof(ibp)); write(xpipe[1], ibp, ibc); } ck_sndmsg(); /* Wait to be killed */ /* NOTREACHED */ } } #endif /* CK_APC */ #endif /* NOESCSEQ */ for (i = 0; i < inxcount; i++) { /* Loop thru */ c = inxbuf[i]; /* input expansion buffer... */ if ( #ifdef CK_APC !apcactive /* Ignore APC sequences */ #else 1 #endif /* CK_APC */ ) { c &= cmdmsk; /* Apply command mask. */ /* SET TERM CR-DISPLAY CRLF? */ if (c == CK_CR && tt_crd) { ckcputc(c); /* Yes, output CR */ if (seslog && !sessft) logchar((char)c); c = LF; /* and insert a linefeed */ } if (c == LF && tt_lfd) { /* SET TERM CR-DISPLA CRLF? */ ckcputc(CK_CR); /* Yes, output CR */ if (seslog && !sessft) logchar((char)CK_CR); } ckcputc(c); /* Write character to screen */ } if (seslog && !sessft) /* Handle session log */ logchar((char)c); #ifdef CK_TRIGGER /* Check for trigger string */ if (tt_trigger[0]) if ((ix = autoexitchk((CHAR)c)) > -1) { ckcputf(); /* Force screen update */ #ifdef NOSETBUF fflush(stdout); /* I mean really force it */ #endif /* NOSETBUF */ pipemsg(CEV_TRI); /* Send up trigger indication */ write(xpipe[1], (char *)&ix, sizeof(ix)); /* index */ write(xpipe[1], (char *)&ibc, sizeof(ibc)); if (ibc > 0) { write(xpipe[1], (char *)&ibp, sizeof(ibp)); write(xpipe[1], ibp, ibc); } debug(F100,"CONNECT concld trigger","",0); ck_sndmsg(); /* Wait to be killed */ active = 0; /* Shouldn't be necessary... */ break; } /* NOTREACHED */ #endif /* CK_TRIGGER */ } } #ifdef ANYX25 } #endif /* ANYX25 */ } } /* C O N E C T -- Interactive terminal connection */ int conect() { int n; /* General purpose counter */ int i; /* For loops... */ int c; /* c is a character, but must be signed integer to pass thru -1, which is the modem disconnection signal, and is different from the character 0377 */ int c2; /* A copy of c */ int csave; /* Another copy of c */ #ifndef NOESCSEQ int apcrc; #endif /* NOESCSEQ */ int conret = 0; /* Return value from conect() */ int msgflg = 0; /* jbchksum = -1L; */ jbset = 0; /* jmp_buf not set yet, don't use it */ debok = 1; debug(F101,"CONNECT fork signal","",CK_FORK_SIG); debug(F101,"CONNECT entry pid","",pid); msgflg = !quiet #ifdef CK_APC && !apcactive #endif /* CK_APC */ ; /* The following is to handle a fork left behind if we exit CONNECT mode without killing it, and then return to CONNECT mode. This happened in HP-UX, where the Reset key would raise SIGINT even though SIGINT was set to SIG_IGN. The code below fixes the symptom; the real fix is in the main SIGINT handler (if SIGINT shows up during CONNECT, just return rather than taking the longjmp). */ if (pid) { /* This should be 0 */ int x = 0; debug(F101,"CONNECT entry killing stale pid","",pid); printf("WARNING: Old CONNECT fork seems to be active.\n"); printf("Attempting to remove it..."); #ifdef BEOSORBEBOX { long ret_val; x = kill(pid,SIGKILLTHR); /* Kill lower fork */ wait_for_thread (pid, &ret_val); } #else #ifdef Plan9 x = kill(pid,SIGKILL); /* Kill lower fork */ #else x = kill(pid,9); #endif /* Plan9 */ #endif /* BEOSORBEBOX */ wait((WAIT_T *)0); /* Wait till gone. */ if (x < 0) { printf("ERROR: Failure to kill pid %d: %s, errno=%d\n", (int) pid, ck_errstr(), errno); debug(F111,"CONNECT error killing stale pid",ck_errstr(),pid); } pid = (PID_T) 0; printf("\n"); } signal(CK_FORK_SIG, SIG_IGN); /* Initial CK_FORK_SIG handling, */ /* The following ttimoff() call should not be necessary, but evidently there are cases where a timer is left active and then goes off, taking a longjmp to nowhere after the program's stack has changed. In any case, this is safe because the CONNECT module uses no timer of any kind, and no other timer should be armed while Kermit is in CONNECT mode. */ ttimoff(); /* Turn off any timer interrupts */ #ifdef CK_TRIGGER makestr(&triggerval,NULL); /* Reset trigger */ #endif /* CK_TRIGGER */ if (!local) { #ifdef NETCONN printf("Sorry, you must SET LINE or SET HOST first\n"); #else printf("Sorry, you must SET LINE first\n"); #endif /* NETCONN */ goto conret0; } if (speed < 0L && network == 0 && ttfdflg == 0) { printf("Sorry, you must SET SPEED first\n"); goto conret0; } #ifdef TCPSOCKET if (network && (nettype != NET_TCPB) #ifdef SUNX25 && (nettype != NET_SX25) #endif /* SUNX25 */ #ifdef IBMX25 && (nettype != NET_IX25) #endif /* IBMX25 */ #ifdef NETCMD && (nettype != NET_CMD) #endif /* NETCMD */ #ifdef NETPTY && (nettype != NET_PTY) #endif /* NETPTY */ ) { printf("Sorry, network type not supported\n"); goto conret0; } #endif /* TCPSOCKET */ #ifdef DYNAMIC if (!ibuf) { if (!(ibuf = malloc(IBUFL+1))) { /* Allocate input line buffer */ printf("Sorry, CONNECT input buffer can't be allocated\n"); goto conret0; } else { ibp = ibuf; ibc = 0; } } if (!obuf) { if (!(obuf = malloc(OBUFL+1))) { /* Allocate output line buffer */ printf("Sorry, CONNECT output buffer can't be allocated\n"); goto conret0; } else { obp = obuf; obc = 0; } } if (!kbuf) { if (!(kbuf = malloc(KBUFL+1))) { /* Allocate keyboard input buffer */ printf("Sorry, CONNECT keyboard buffer can't be allocated\n"); goto conret0; } } if (!temp) { if (!(temp = malloc(TMPLEN+1))) { /* Allocate temporary buffer */ printf("Sorry, CONNECT temporary buffer can't be allocated\n"); goto conret0; } } #else #ifdef COMMENT ibp = ibuf; ibc = 0; #endif /* COMMENT */ obp = obuf; obc = 0; #endif /* DYNAMIC */ kbp = kbuf; /* Always clear these. */ *kbp = NUL; /* No need to preserve them between */ kbc = 0; /* CONNECT sessions. */ #ifdef DEBUG if (deblog) { debug(F101,"CONNECT conect entry ttyfd","",ttyfd); debug(F101,"CONNECT conect entry ibc","",ibc); debug(F101,"CONNECT conect entry obc","",obc); debug(F101,"CONNECT conect entry kbc","",kbc); #ifdef CK_TRIGGER debug(F110,"CONNECT conect trigger",tt_trigger[0],0); #endif /* CK_TRIGGER */ if (ttyfd > -1) { n = ttchk(); debug(F101,"CONNECT conect entry ttchk","",n); } } #endif /* DEBUG */ if (ttyfd < 0) { /* If communication device not open */ debug(F101,"CONNECT ttnproto","",ttnproto); debug(F111,"CONNECT opening",ttname,0); /* Open it now */ if (ttopen(ttname, &local, network ? -nettype : mdmtyp, 0 ) < 0) { ckmakmsg(temp,TMPLEN,"Sorry, can't open ",ttname,NULL,NULL); perror(temp); debug(F110,"CONNECT open failure",ttname,0); goto conret0; } #ifdef IKS_OPTION /* If peer is in Kermit server mode, return now. */ if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start) return(0); #endif /* IKS_OPTION */ } dohangup = 0; /* Hangup not requested yet */ #ifdef ANYX25 dox25clr = 0; /* X.25 clear not requested yet */ #endif /* ANYX25 */ if (msgflg) { #ifdef NETCONN if (network) { if (ttpipe) printf("Connecting via command \"%s\"",ttname); else printf("Connecting to host %s",ttname); #ifdef ANYX25 if (nettype == NET_SX25 || nettype == NET_IX25) printf(", Link ID %d, LCN %d",linkid,lcn); #endif /* ANYX25 */ } else { #endif /* NETCONN */ printf("Connecting to %s",ttname); if (speed > -1L) printf(", speed %ld",speed); #ifdef NETCONN } #endif /* NETCONN */ if (tt_escape) { printf("\r\n"); shoesc(escape); printf("Type the escape character followed by C to get back,\r\n"); printf("or followed by ? to see other options.\r\n"); } else { printf(".\r\n\nESCAPE CHARACTER IS DISABLED\r\n\n"); } if (seslog) { extern int slogts; char * s = ""; switch (sessft) { case XYFT_D: s = "debug"; break; case XYFT_T: s = slogts ? "timestamped-text" : "text"; break; default: s = "binary"; } printf("Session Log: %s, %s\r\n",sesfil,s); } if (debses) printf("Debugging Display...)\r\n"); printf("----------------------------------------------------\r\n"); fflush(stdout); } /* Condition console terminal and communication line */ if (conbin((char)escape) < 0) { printf("Sorry, can't condition console terminal\n"); goto conret0; } debug(F101,"CONNECT cmask","",cmask); debug(F101,"CONNECT cmdmsk","",cmdmsk); debug(F101,"CONNECT speed before ttvt","",speed); if ((n = ttvt(speed,flow)) < 0) { /* Enter "virtual terminal" mode */ if (!network) { debug(F101,"CONNECT ttvt","",n); tthang(); /* Hang up and close the device. */ ttclos(0); dologend(); if (ttopen(ttname, /* Open it again... */ &local, network ? -nettype : mdmtyp, 0 ) < 0) { ckmakmsg(temp,TMPLEN,"Sorry, can't reopen ",ttname,NULL,NULL); perror(temp); goto conret0; } #ifdef IKS_OPTION if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start) return(0); #endif /* IKS_OPTION */ if (ttvt(speed,flow) < 0) { /* Try virtual terminal mode again. */ conres(); /* Failure this time is fatal. */ printf("Sorry, Can't condition communication line\n"); goto conret0; } } } debug(F101,"CONNECT ttvt ok, escape","",escape); debug(F101,"CONNECT carrier-watch","",carrier); if ((!network #ifdef TN_COMPORT || istncomport() #endif /* TN_COMPORT */ ) && (carrier != CAR_OFF)) { int x; x = ttgmdm(); debug(F100,"CONNECT ttgmdm","",x); if ((x > -1) && !(x & BM_DCD)) { #ifndef NOHINTS extern int hints; #endif /* NOHINTS */ debug(F100,"CONNECT ttgmdm CD test fails","",x); conres(); printf("?Carrier required but not detected.\n"); #ifndef NOHINTS if (!hints) return(0); printf("***********************************\n"); printf(" Hint: To CONNECT to a serial device that\n"); printf(" is not presenting the Carrier Detect signal,\n"); printf(" first tell C-Kermit to:\n\n"); printf(" SET CARRIER-WATCH OFF\n\n"); printf("***********************************\n\n"); #endif /* NOHINTS */ goto conret0; } debug(F100,"CONNECT ttgmdm ok","",0); } #ifndef NOCSETS /* Set up character set translations */ unicode = 0; /* Assume Unicode won't be involved */ tcs = 0; /* "Transfer" or "Other" charset */ sxo = rxo = NULL; /* Initialize byte-to-byte functions */ sxi = rxi = NULL; if (tcsr != tcsl) { /* Remote and local sets differ... */ #ifdef UNICODE if (tcsr == FC_UTF8 || /* Remote charset is UTF-8 */ tcsl == FC_UTF8) { /* or local one is. */ xuf = xl_ufc[tcsl]; /* Incoming Unicode to local */ if (xuf || tcsl == FC_UTF8) { tcs = (tcsr == FC_UTF8) ? tcsl : tcsr; /* The "other" set */ xfu = xl_fcu[tcs]; /* Local byte to remote Unicode */ if (xfu) unicode = (tcsr == FC_UTF8) ? 1 : 2; } tcssize = fcsinfo[tcs].size; /* Size of other character set. */ } else { #endif /* UNICODE */ tcs = gettcs(tcsr,tcsl); /* Get intermediate set. */ sxo = xls[tcs][tcsl]; /* translation function */ rxo = xlr[tcs][tcsr]; /* pointers for output functions */ sxi = xls[tcs][tcsr]; /* and for input functions. */ rxi = xlr[tcs][tcsl]; #ifdef UNICODE } #endif /* UNICODE */ } /* This is to prevent use of zmstuff() and zdstuff() by translation functions. They only work with disk i/o, not with communication i/o. Luckily Russian translation functions don't do any stuffing... */ langsv = language; #ifndef NOCYRIL if (language != L_RUSSIAN) #endif /* NOCYRIL */ language = L_USASCII; #ifdef COMMENT #ifdef DEBUG if (deblog) { debug(F101,"CONNECT tcs","",tcs); debug(F101,"CONNECT tcsl","",tcsl); debug(F101,"CONNECT tcsr","",tcsr); debug(F101,"CONNECT fcsinfo[tcsl].size","",fcsinfo[tcsl].size); debug(F101,"CONNECT fcsinfo[tcsr].size","",fcsinfo[tcsr].size); debug(F101,"CONNECT unicode","",unicode); } #endif /* DEBUG */ #endif /* COMMENT */ #ifdef CK_XYZ #ifndef XYZ_INTERNAL { extern int binary; /* See about ZMODEM autodownloads */ char * s; s = binary ? ptab[PROTO_Z].p_b_rcmd : ptab[PROTO_Z].p_t_rcmd; if (!s) s = ""; zmdlok = (*s != NUL); /* OK if we have external commands */ } #endif /* XYZ_INTERNAL */ #endif /* CK_XYZ */ #ifndef NOESCSEQ /* We need to activate the escape-sequence recognition feature when: (a) translation is elected, AND (b) the local and/or remote set is a 7-bit set other than US ASCII. Or: SET TERMINAL APC is not OFF (handled in the next statement). */ escseq = (tcs != TC_TRANSP) && /* Not transparent */ (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */ (fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */ #endif /* NOESCSEQ */ #endif /* NOCSETS */ #ifndef NOESCSEQ #ifdef CK_APC escseq = escseq || (apcstatus & APC_ON); apcactive = 0; /* An APC command is not active */ apclength = 0; /* ... */ #endif /* CK_APC */ inesc = ES_NORMAL; /* Initial state of recognizer */ debug(F101,"CONNECT escseq","",escseq); #endif /* NOESCSEQ */ parent_id = getpid(); /* Get parent's pid for signalling */ debug(F101,"CONNECT parent pid","",parent_id); if (xpipe[0] > -1) /* If old pipe hanging around, close */ close(xpipe[0]); xpipe[0] = -1; if (xpipe[1] > -1) close(xpipe[1]); xpipe[1] = -1; goterr = 0; /* Error flag for pipe & fork */ if (pipe(xpipe) != 0) { /* Create new pipe to pass info */ perror("Can't make pipe"); /* between forks. */ debug(F101,"CONNECT pipe error","",errno); goterr = 1; } else #ifdef BEOSORBEBOX { pid = spawn_thread(concld, "Lower Fork", B_NORMAL_PRIORITY, NULL); resume_thread(pid); } #else if ((pid = fork()) == (PID_T) -1) { /* Pipe OK, make port fork. */ perror("Can't make port fork"); debug(F101,"CONNECT fork error","",errno); goterr = 1; } #endif /* BEOSORBEBOX */ debug(F101,"CONNECT created fork, pid","",pid); if (goterr) { /* Failed to make pipe or fork */ conres(); /* Reset the console. */ if (msgflg) { printf("\r\nCommunications disconnect (Back at %s)\r\n", *myhost ? myhost : #ifdef UNIX "local UNIX system" #else "local system" #endif /* UNIX */ ); } printf("\n"); what = W_NOTHING; /* So console modes are set right. */ #ifndef NOCSETS language = langsv; /* Restore language */ #endif /* NOCSETS */ parent_id = (PID_T) 0; /* Clean up */ goto conret1; } debug(F101,"CONNECT fork pid","",pid); /* Upper fork (KEYB fork) reads keystrokes and sends them out. */ if (pid) { /* pid != 0, so I am the upper fork. */ /* Before doing anything significant, the child fork must wait for a go-ahead character from xpipe[0]. Before starting to wait, we have enough time to clear buffers and set up the signal handler. When done with this, we will allow the child to continue by satisfying its pending read. Remember the child and parent have separate address space. The child has its own copy of input buffers, so we must clear the input buffers in the parent. Otherwise strange effects may occur, like chunks of characters repeatedly echoed on terminal screen. The child process is designed to empty its input buffers by reading all available characters and either echoing them on the terminal screen or saving them for future use in the parent. The latter case happens during APC processing - see the code around CEV_APC occurrences to see how the child passes its ibuf etc to parent via xpipe, for preservation until the next entry to this module, to ensure that no characters are lost between CONNECT sessions. */ /* This one needs a bit of extra explanation... In addition to the CONNECT module's own buffers, which are communicated and synchronized via xpipe, the low-level UNIX communication routines (ttinc, ttxin, etc) are also buffered, statically, in the ckutio.c module. But when the two CONNECT forks split off, the lower fork is updating this buffer's pointers and counts, but the upper fork never finds out about it and still has the old ones. The following UNIX-specific call to the ckutio.c module takes care of this... Without it, we get dual echoing of incoming characters. */ ttflux(); /* At this point, perhaps you are wondering why we use forks at all. It is simply because there is no other method portable among all UNIX variations. Not threads, not select(), ... (Yes, select() is more common now; it might actually be worth writing a variation of this module that works like BSD Telnet, one fork, driven by select()). */ ibp = ibuf; /* Clear ibuf[]. */ ibc = 0; /* Child now has its own copy */ signal(CK_FORK_SIG, pipeint); /* Handler for messages from child. */ write(xpipe[1], ibuf, 1); /* Allow child to proceed */ close(xpipe[1]); xpipe[1] = -1; /* Parent - prevent future writes */ what = W_CONNECT; /* Keep track of what we're doing */ active = 1; debug(F101,"CONNECT keyboard fork duplex","",duplex); /* Catch communication errors or mode changes in lower fork. Note: Some C compilers (e.g. Cray UNICOS) interpret the ANSI C standard about setjmp() in a way that disallows constructions like: if ((var = [sig]setjmp(env)) == 0) ... which prevents the value returned by cklongjmp() from being used at all. So the signal handlers set a global variable, sjval, instead. */ if ( #ifdef CK_POSIX_SIG sigsetjmp(con_env,1) #else setjmp(con_env) #endif /* CK_POSIX_SIG */ == 0) { /* Normal entry... */ jbset = 1; /* Now we have a longjmp buffer */ sjval = CEV_NO; /* Initialize setjmp return code. */ debug(F101,"CONNECT setjmp normal entry","",sjval); #ifdef ANYX25 if (network && (nettype == NET_SX25 || nettype == NET_IX25)) { obufl = 0; bzero (x25obuf,sizeof(x25obuf)); } #endif /* ANYX25 */ /* Here is the big loop that gets characters from the keyboard and sends them out the communication device. There are two components to the communication path: the connection from the keyboard to C-Kermit, and from C-Kermit to the remote computer. The treatment of the 8th bit of keyboard characters is governed by SET COMMAND BYTESIZE (cmdmsk). The treatment of the 8th bit of characters sent to the remote is governed by SET TERMINAL BYTESIZE (cmask). This distinction was introduced in edit 5A(164). */ while (active) { #ifndef NOSETKEY if (kmptr) { /* Have current macro? */ debug(F100,"CONNECT kmptr non NULL","",0); if ((c = (CHAR) *kmptr++) == NUL) { /* Get char from it */ kmptr = NULL; /* If no more chars, */ debug(F100,"CONNECT macro empty, continuing","",0); continue; /* reset pointer and continue */ } debug(F000,"CONNECT char from macro","",c); } else /* No macro... */ #endif /* NOSETKEY */ c = CONGKS(); /* Read from keyboard */ #ifdef COMMENT /* too much... */ debug(F101,"CONNECT ** KEYB","",c); #endif /* COMMENT */ if (c == -1) { /* If read() got an error... */ debug(F101,"CONNECT keyboard read errno","",errno); #ifdef COMMENT /* This seems to cause problems. If read() returns -1, the signal has already been delivered, and nothing will wake up the pause(). */ pause(); /* Wait for transmitter to finish. */ #else #ifdef A986 /* On Altos machines with Xenix 3.0, pressing DEL in connect mode brings us here (reason unknown). The console line discipline at this point has intr = ^C. The communications tty has intr = DEL but we get here after pressing DEL on the keyboard, even when the remote system has been set not to echo. With A986 defined, we stay in the read loop and beep only if the offending character is not DEL. */ if ((c & 127) != 127) conoc(BEL); #else #ifdef EINTR /* This can be caused by the other fork signalling this one about an echoing change during TELNET negotiations. */ if (errno == EINTR) continue; #endif /* EINTR */ conoc(BEL); /* Otherwise, beep */ active = 0; /* and terminate the read loop */ continue; #endif /* A986 */ #endif /* COMMENT */ } c &= cmdmsk; /* Do any requested masking */ #ifndef NOSETKEY /* Note: kmptr is NULL if we got character c from the keyboard, and it is not NULL if it came from a macro. In the latter case, we must avoid expanding it again. */ if (!kmptr && macrotab[c]) { /* Macro definition for c? */ kmptr = macrotab[c]; /* Yes, set up macro pointer */ continue; /* and restart the loop, */ } else c = keymap[c]; /* else use single-char keymap */ #endif /* NOSETKEY */ if ( #ifndef NOSETKEY !kmptr && #endif /* NOSETKEY */ (tt_escape && (c & 0xff) == escape)) { /* Escape char? */ debug(F000,"CONNECT got escape","",c); c = CONGKS() & 0177; /* Got esc, get its arg */ /* No key mapping here */ doesc((char) c); /* Now process it */ } else { /* It's not the escape character */ csave = c; /* Save it before translation */ /* for local echoing. */ #ifndef NOCSETS if (inesc == ES_NORMAL) { /* If not inside escape seq.. */ /* Translate character sets */ #ifdef UNICODE int x; CHAR ch; ch = c; if (unicode == 1) { /* Remote is UTF-8 */ outxcount = b_to_u(ch,outxbuf,OUTXBUFSIZ,tcssize); outxbuf[outxcount] = NUL; } else if (unicode == 2) { /* Local is UTF-8 */ x = u_to_b(ch); /* So translate to remote byte */ if (x < 0) continue; outxbuf[0] = (unsigned)(x & 0xff); outxcount = 1; outxbuf[outxcount] = NUL; } else { #endif /* UNICODE */ /* Local-to-intermediate */ if (sxo) c = (*sxo)((char)c); /* Intermediate-to-remote */ if (rxo) c = (*rxo)((char)c); outxbuf[0] = c; outxcount = 1; outxbuf[outxcount] = NUL; #ifdef UNICODE } #endif /* UNICODE */ } if (escseq) apcrc = chkaes((char)c,0); #else outxbuf[0] = c; outxcount = 1; outxbuf[outxcount] = NUL; #endif /* NOCSETS */ for (i = 0; i < outxcount; i++) { c = outxbuf[i]; /* If Shift-In/Shift-Out is selected and we have a 7-bit connection, handle shifting here. */ if (sosi) { /* Shift-In/Out selected? */ if (cmask == 0177) { /* In 7-bit environment? */ if (c & 0200) { /* 8-bit character? */ if (outshift == 0) { /* If not shifted, */ ttoc(dopar(SO)); /* shift. */ outshift = 1; } } else { if (outshift == 1) { /* 7-bit character */ ttoc(dopar(SI)); /* If shifted, */ outshift = 0; /* unshift. */ } } } if (c == SO) outshift = 1; /* User typed SO */ if (c == SI) outshift = 0; /* User typed SI */ } c &= cmask; /* Apply Kermit-to-host mask now. */ #ifdef SUNX25 if (network && nettype == NET_SX25) { if (padparms[PAD_ECHO]) { if (debses) conol(dbchr(c)) ; else if ((c != padparms[PAD_CHAR_DELETE_CHAR]) && (c != padparms[PAD_BUFFER_DELETE_CHAR]) && (c != padparms[PAD_BUFFER_DISPLAY_CHAR])) conoc(c) ; if (seslog && !sessft) logchar(c); } if (c== CK_CR && (padparms[PAD_LF_AFTER_CR] == 4 || padparms[PAD_LF_AFTER_CR] == 5)) { if (debses) conol(dbchr(LF)) ; else conoc(LF) ; if (seslog && !sessft) logchar(LF); } if (c == padparms[PAD_BREAK_CHARACTER]) { breakact(); } else if (padparms[PAD_DATA_FORWARD_TIMEOUT]) { tosend = 1; x25obuf [obufl++] = c; } else if (((c == padparms[PAD_CHAR_DELETE_CHAR])|| (c == padparms[PAD_BUFFER_DELETE_CHAR]) || (c == padparms[PAD_BUFFER_DISPLAY_CHAR])) && (padparms[PAD_EDITING])) { if (c == padparms[PAD_CHAR_DELETE_CHAR]) { if (obufl > 0) { conol("\b \b"); obufl--; } else {} } else if (c == padparms[PAD_BUFFER_DELETE_CHAR]) { conol ("\r\nPAD Buffer Deleted\r\n"); obufl = 0; } else if (c==padparms[PAD_BUFFER_DISPLAY_CHAR]) { conol("\r\n"); conol(x25obuf); conol("\r\n"); } else {} } else { x25obuf [obufl++] = c; if (obufl == MAXOX25) tosend = 1; else if (c == CK_CR) tosend = 1; } if (tosend) { if (ttol((CHAR *)x25obuf,obufl) < 0) { perror ("\r\nCan't send characters"); active = 0; } else { bzero (x25obuf,sizeof(x25obuf)); obufl = 0; tosend = 0; } } else {}; } else { #endif /* SUNX25 */ if (c == '\015') { /* Carriage Return */ int stuff = -1; if (tnlm) { /* TERMINAL NEWLINE ON */ stuff = LF; /* Stuff LF */ #ifdef TNCODE } else if (network && /* TELNET NEWLINE */ IS_TELNET()) { switch (!TELOPT_ME(TELOPT_BINARY) ? tn_nlm : tn_b_nlm ) { case TNL_CRLF: stuff = LF; break; case TNL_CRNUL: stuff = NUL; break; } #endif /* TNCODE */ } if (stuff > -1) { ttoc(dopar('\015')); /* Send CR */ if (duplex) conoc('\015'); /* Echo CR */ c = stuff; /* Char to stuff */ csave = c; } } #ifdef TNCODE /* If user types the 0xff character (TELNET IAC), it must be doubled. */ else /* Not CR */ if ((dopar((CHAR) c) == IAC) && /* IAC (0xff) */ network && IS_TELNET()) { /* Send one copy now */ /* and the other one just below. */ ttoc((char)IAC); } #endif /* TNCODE */ /* Send the character */ if (ttoc((char)dopar((CHAR) c)) > -1) { if (duplex) { /* If half duplex, must echo */ if (debses) conol(dbchr(csave)); /* original char */ else /* not the translated one */ conoc((char)csave); if (seslog) { /* And maybe log it too */ c2 = csave; if (sessft == 0 && csave == '\r') c2 = '\n'; logchar((char)c2); } } } else { perror("\r\nCan't send character"); active = 0; } #ifdef SUNX25 } #endif /* SUNX25 */ } /* for... */ } } /* now active == 0 */ signal(CK_FORK_SIG, SIG_IGN); /* Turn off CK_FORK_SIG */ sjval = CEV_NO; /* Set to hangup */ } /* Come here on termination of child */ /* cklongjmp() executed in pipeint() (parent only!) comes here */ /* Now the child fork is gone or is waiting for CK_FORK_SIG in ck_sndmsg(). So we can't get (in the parent) any subsequent CK_FORK_SIG signals until we signal the child with CK_FORK_SIG. */ debug(F100,"CONNECT signaling port fork","",0); signal(CK_FORK_SIG, SIG_IGN); /* Turn this off */ debug(F101,"CONNECT killing port fork","",pid); if (pid) { int x = 0; #ifdef BEOSORBEBOX { long ret_val; x = kill(pid,SIGKILLTHR); /* Kill lower fork */ wait_for_thread(pid, &ret_val); } #else #ifdef Plan9 x = kill(pid,SIGKILL); /* Kill lower fork */ #else x = kill(pid,9); #endif /* Plan9 */ #endif /* BEOSORBEBOX */ wait((WAIT_T *)0); /* Wait till gone. */ if (x < 0) { printf("WARNING: Failure to kill fork, pid %d: %s, errno=%d\n", (int) pid, ck_errstr(), errno); debug(F111,"CONNECT error killing pid",ck_errstr(),errno); } debug(F101,"CONNECT killed port fork","",pid); pid = (PID_T) 0; } if (sjval == CEV_HUP) { /* Read error on comm device */ dohangup = 1; /* so we want to hang up our side */ #ifdef NETCONN if (network) { /* and/or close network connection */ ttclos(0); dologend(); #ifdef SUNX25 if (nettype == NET_SX25) /* If X.25, restore the PAD params */ initpad(); #endif /* SUNX25 */ } #endif /* NETCONN */ } #ifdef CK_APC if (sjval == CEV_APC) { /* Application Program Command rec'd */ apcactive = APC_REMOTE; /* Flag APC as active */ active = 0; /* Flag CONNECT as inactive */ } #endif /* CK_APC */ conres(); /* Reset the console. */ if (dohangup > 0) { /* If hangup requested, do that. */ #ifndef NODIAL if (dohangup > 1) /* User asked for it */ if (mdmhup() < 1) /* Maybe hang up via modem */ #endif /* NODIAL */ tthang(); /* And make sure we don't hang up */ dohangup = 0; /* again unless requested again. */ } #ifdef COMMENT #ifdef NETCONN #ifdef SIGPIPE if (network && sigpiph) /* Restore previous SIGPIPE handler */ (VOID) signal(SIGPIPE, sigpiph); #endif /* SIGPIPE */ #endif /* NETCONN */ #endif /* COMMENT */ #ifdef ANYX25 if (dox25clr) { /* If X.25 Clear requested */ x25clear(); /* do that. */ #ifndef IBMX25 initpad(); #endif /* IBMX25 */ dox25clr = 0; /* But only once. */ } #endif /* ANYX25 */ if (quitnow) doexit(GOOD_EXIT,xitsta); /* Exit now if requested. */ if (msgflg) printf("(Back at %s)", *myhost ? myhost : "local UNIX system"); #ifdef CK_APC if (!apcactive) #endif /* CK_APC */ printf("\n"); what = W_NOTHING; /* So console modes set right. */ #ifndef NOCSETS language = langsv; /* Restore language */ #endif /* NOCSETS */ parent_id = (PID_T) 0; goto conret1; } #ifndef BEOSORBEBOX else { /* *** */ /* Inferior reads, prints port input */ concld(/* (void *)&pid */); } #endif /* BEOSORBEBOX */ conret1: conret = 1; conret0: signal(CK_FORK_SIG, SIG_IGN); /* In case this wasn't done already */ debug(F101,"CONNECT conect exit ibc","",ibc); debug(F101,"CONNECT conect exit obc","",obc); close(xpipe[0]); xpipe[0] = -1; /* Close the pipe */ close(xpipe[1]); xpipe[1] = -1; if (msgflg) { #ifdef CK_APC if (apcactive == APC_LOCAL) printf("\n"); #endif /* CK_APC */ printf("----------------------------------------------------\r\n"); } fflush(stdout); return(conret); } /* H C O N N E -- Give help message for connect. */ int hconne() { int c; static char *hlpmsg[] = { "\r\n ? for this message", "\r\n 0 (zero) to send a null", "\r\n B to send a BREAK", #ifdef CK_LBRK "\r\n L to send a Long BREAK", #endif /* CK_LBRK */ #ifdef NETCONN "\r\n I to send a network interrupt packet", #ifdef TCPSOCKET "\r\n A to send Are You There?", #endif /* TCPSOCKET */ #ifdef ANYX25 "\r\n R to reset X.25 virtual circuit", #endif /* ANYX25 */ #endif /* NETCONN */ "\r\n U to hangup and close the connection", "\r\n Q to hangup and quit Kermit", "\r\n S for status", #ifdef NOPUSH "\r\n ! to push to local shell (disabled)", "\r\n Z to suspend (disabled)", #else "\r\n ! to push to local shell", #ifdef NOJC "\r\n Z to suspend (disabled)", #else "\r\n Z to suspend", #endif /* NOJC */ #endif /* NOPUSH */ "\r\n \\ backslash code:", "\r\n \\nnn decimal character code", "\r\n \\Onnn octal character code", "\r\n \\Xhh hexadecimal character code", "\r\n terminate with carriage return.", "\r\n Type the escape character again to send the escape character, or", "\r\n press the space-bar to resume the CONNECT command.\r\n", "" }; conol("\r\n----------------------------------------------------"); conol("\r\nPress C to return to "); conol(*myhost ? myhost : "the C-Kermit prompt"); conol(", or:"); conola(hlpmsg); /* Print the help message. */ conol("Command>"); /* Prompt for command. */ c = CONGKS() & 0177; /* Get character, strip any parity. */ /* No key mapping or translation here */ if (c != CMDQ) conoll(""); conoll("----------------------------------------------------"); return(c); /* Return it. */ } /* D O E S C -- Process an escape character argument */ VOID #ifdef CK_ANSIC doesc(char c) #else doesc(c) char c; #endif /* CK_ANSIC */ /* doesc */ { CHAR d; debug(F101,"CONNECT doesc","",c); while (1) { if (c == escape) { /* Send escape character */ d = dopar((CHAR) c); ttoc((char) d); return; } else /* Or else look it up below. */ if (isupper(c)) c = tolower(c); switch(c) { case 'c': /* Escape back to prompt */ case '\03': active = 0; conol("\r\n"); return; case 'b': /* Send a BREAK signal */ case '\02': ttsndb(); return; #ifdef NETCONN case 'i': /* Send Interrupt */ case '\011': #ifdef TCPSOCKET #ifndef IP #define IP 244 #endif /* IP */ if (network && IS_TELNET()) { /* TELNET */ temp[0] = (CHAR) IAC; /* I Am a Command */ temp[1] = (CHAR) IP; /* Interrupt Process */ temp[2] = NUL; ttol((CHAR *)temp,2); } else #endif /* TCPSOCKET */ #ifdef SUNX25 if (network && (nettype == NET_SX25)) { (VOID) x25intr(0); /* X.25 interrupt packet */ conol("\r\n"); } else #endif /* SUNX25 */ conoc(BEL); return; #ifdef TCPSOCKET case 'a': /* "Are You There?" */ case '\01': #ifndef AYT #define AYT 246 #endif /* AYT */ if (network && IS_TELNET()) { temp[0] = (CHAR) IAC; /* I Am a Command */ temp[1] = (CHAR) AYT; /* Are You There? */ temp[2] = NUL; ttol((CHAR *)temp,2); } else conoc(BEL); return; #endif /* TCPSOCKET */ #endif /* NETCONN */ #ifdef CK_LBRK case 'l': /* Send a Long BREAK signal */ ttsndlb(); return; #endif /* CK_LBRK */ case 'u': /* Hangup */ /* case '\010': */ /* No, too dangerous */ #ifdef ANYX25 if (network && (nettype == NET_SX25 || nettype == NET_IX25)) dox25clr = 1; else #endif /* ANYX25 */ dohangup = 2; active = 0; conol("\r\nHanging up "); return; #ifdef ANYX25 case 'r': /* Reset the X.25 virtual circuit */ case '\022': if (network && (nettype == NET_SX25 || nettype == NET_IX25)) (VOID) x25reset(0,0); conol("\r\n"); return; #endif /* ANYX25 */ case 'q': /* Quit */ dohangup = 2; quitnow = 1; active = 0; conol("\r\n"); return; case 's': /* Status */ conoll(""); conoll("----------------------------------------------------"); #ifdef NETCMD if (ttpipe) ckmakmsg(temp,TMPLEN," Pipe: \"",ttname,"\"",NULL); else #endif /* NETCMD */ ckmakmsg(temp, TMPLEN, " ", (network ? "Host" : "Device"), ": ", ttname ); conoll(temp); if (!network && speed >= 0L) { sprintf(temp,"Speed %ld", speed); conoll(temp); } sprintf(temp," Terminal echo: %s", duplex ? "local" : "remote"); conoll(temp); sprintf(temp," Terminal bytesize: %d", (cmask == 0177) ? 7 : 8); conoll(temp); sprintf(temp," Command bytesize: %d", (cmdmsk == 0177) ? 7 : 8 ); conoll(temp); if (hwparity) sprintf(temp," Parity[hardware]: %s",parnam((char)hwparity)); else sprintf(temp," Parity: %s", parnam((char)parity)); conoll(temp); sprintf(temp," Autodownload: %s", autodl ? "on" : "off"); conoll(temp); ckmakmsg(temp, /* (would not be safe for sprintf) */ TMPLEN, " Session log: ", *sesfil ? sesfil : "(none)", NULL, NULL ); conoll(temp); #ifndef NOSHOW if (!network) shomdm(); #endif /* NOSHOW */ #ifdef CKLOGDIAL { long z; z = dologshow(0); if (z > -1L) { sprintf(temp," Elapsed time: %s",hhmmss(z)); conoll(temp); } } #endif /* CKLOGDIAL */ conoll("----------------------------------------------------"); return; case 'h': /* Help */ case '?': /* Help */ c = hconne(); continue; case '0': /* Send a null */ c = '\0'; d = dopar((CHAR) c); ttoc((char) d); return; case 'z': case '\032': /* Suspend */ #ifndef NOPUSH if (!nopush) stptrap(0); else conoc(BEL); #else conoc(BEL); #endif /* NOPUSH */ return; case '@': /* Start inferior command processor */ case '!': #ifndef NOPUSH if (!nopush) { conres(); /* Put console back to normal */ zshcmd(""); /* Fork a shell. */ if (conbin((char)escape) < 0) { printf("Error resuming CONNECT session\n"); active = 0; } } else conoc(BEL); #else conoc(BEL); #endif /* NOPUSH */ return; case SP: /* Space, ignore */ return; default: /* Other */ if (c == CMDQ) { /* Backslash escape */ int x; ecbp = ecbuf; *ecbp++ = c; while (((c = (CONGKS() & cmdmsk)) != '\r') && (c != '\n')) *ecbp++ = c; *ecbp = NUL; ecbp = ecbuf; x = xxesc(&ecbp); /* Interpret it */ if (x >= 0) { /* No key mapping here */ c = dopar((CHAR) x); ttoc((char) c); return; } else { /* Invalid backslash code. */ conoc(BEL); return; } } conoc(BEL); return; /* Invalid esc arg, beep */ } } } #endif /* NOLOCAL */ ckudia.c000664 045065 024037 00000731341 14767403136 012613 0ustar00fdckermit000000 000000 #include "ckcsym.h" char *dialv = "Dial Command, 10.0.165, 15 Apr 2023"; /* C K U D I A -- Module for automatic modem dialing. */ /* Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ /* Authors: Original (version 1, 1985) author: Herm Fischer, Encino, CA. Contributed to Columbia University in 1985 for inclusion in C-Kermit 4.0. Author and maintainer since 1985: Frank da Cruz, fdc@columbia.edu. Contributions by many others throughout the years, including: Jeffrey Altman, Mark Berryman, Fernando Cabral, John Chmielewski, Joe Doupnik, Richard Hill, Larry Jacobs, Eric Jones, Tom Kloos, Bob Larson, Peter Mauzey, Joe Orost, Kevin O'Gorman, Kai Uwe Rommel, Dan Schullman, Warren Tucker, and many others. */ /* Entry points: ckdial(char * number) Dial a number or answer a call dialhup() Hang up a dialed connection mdmhup() Use modem commands to hang up All other routines are static. Don't call dialhup() or mdmhup() without first calling ckdial(). */ /* This module calls externally defined system-dependent functions for communications i/o, as described in the C-Kermit Program Logic Manual: https://kermitproject.org/ckcplm.html and thus should be portable to all systems that implement those functions, and where alarm() and signal() work. HOW TO ADD SUPPORT FOR ANOTHER MODEM: 1. In ckuusr.h, define a modem-type number symbol (n_XXX) for the new modem, the next highest one. 2. In ckuusr.h, adjust MAX_MDM to the new number of modem types. The remaining steps are in this module: 3. Create a MDMINF structure for it. NOTE: The wake_str should include all invariant setup info, e.g. enable result codes, BREAK transparency, modulation negotiation, etc. See ckcker.h for MDMINF struct definition. 4. Add the address of the MDMINF structure to the modemp[] array, according to the numerical value of the modem-type number. 5. Add the user-visible (SET MODEM) name and corresponding modem number to the mdmtab[] array, in alphabetical order by modem-name string. 6. If this falls into a class like is_rockwell, is_supra, etc, add the new one to the definition of the class. 7. Adjust the gethrn() routine to account for any special numeric result codes (if it's a Hayes compatible modem). 8. Read through the code and add any modem-specific sections as necessary. For most modern Hayes-compatible modems, no specific code will be needed. NOTE: The MINIDIAL symbol is used to build this module to include support for only a minimum number of standard and/or generally useful modem types, namely Hayes 1200 and 2400, ITU-T (CCITT) V.25bis and V.25ter (V.250), Generic-High-Speed, "Unknown", and None. When adding support for a new modem type, keep it outside of the MINIDIAL sections unless it deserves to be in it. */ #include "ckcdeb.h" #ifndef NOLOCAL #ifndef NODIAL #ifndef NOICP #ifndef CK_ATDT #define CK_ATDT #endif /* CK_ATDT */ #ifndef NOOLDMODEMS /* Unless instructed otherwise, */ #define OLDMODEMS /* keep support for old modems. */ #endif /* NOOLDMODEMS */ #ifndef M_OLD /* Hide old modem keywords in SET MODEM table. */ #define M_OLD 0 /* Define as CM_INV to make them invisible. */ #endif /* M_OLD */ #ifndef M_ALIAS #define M_ALIAS 64 #endif /* M_ALIAS */ #ifndef MAC #include #endif /* MAC */ #include "ckcasc.h" #include "ckcker.h" #include "ckucmd.h" #include "ckcnet.h" #include "ckuusr.h" #ifdef OS2ONLY #define INCL_VIO /* Needed for ckocon.h */ #define INCL_WINERRORS /* Needed for WinGetLastError() */ #include #undef COMMENT #include "ckocon.h" #endif /* OS2ONLY */ #ifdef NT #include #ifdef CK_TAPI #include #endif /* CK_TAPI */ #include #include "cknwin.h" #ifdef CK_TAPI #include "ckntap.h" #endif /* CK_TAPI */ #include "ckothr.h" #include "ckosyn.h" #ifdef CK_LOGIN void setntcreds(); /* ckofio.c */ #endif /* CK_LOGIN */ #endif /* NT */ #ifdef OS2 #include "ckowin.h" _PROTOTYP( int scriptwrtbuf, (unsigned short)); #endif /* OS2 */ #ifndef ZILOG #ifdef NT #include #else /* NT */ #include #endif /* NT */ #else #include #endif /* ZILOG */ #include "ckcsig.h" /* C-Kermit signal processing */ #ifdef CK_ANSIC /* static function prototypes - fdc 30 November 2022 */ static VOID dologdial( char * ); static VOID ttslow( char *, int ); static VOID waitfor( char * ); static int ddinc( int ); static int dialfail( int ); #endif /* CK_ANSIC */ #include "ckcfnp.h" /* Prototypes (must be last) */ #ifdef MAC #define signal msignal #define SIGTYP long #define alarm malarm #define SIG_IGN 0 #define SIGALRM 1 #define SIGINT 2 SIGTYP (*msignal(int type, SIGTYP (*func)(int)))(int); #endif /* MAC */ #ifdef AMIGA #define signal asignal #define alarm aalarm #define SIGALRM (_NUMSIG+1) #define SIGTYP void SIGTYP (*asignal(int type, SIGTYP (*func)(int)))(int); unsigned aalarm(unsigned); #endif /* AMIGA */ #ifdef STRATUS /* VOS doesn't have alarm(), but it does have some things we can work with. However, we have to catch all the signals in one place to do this, so we intercept the signal() routine and call it from our own replacement. */ #define signal vsignal #define alarm valarm SIGTYP (*vsignal(int type, SIGTYP (*func)(int)))(int); int valarm(int interval); #ifdef putchar #undef putchar #endif /* putchar */ #define putchar(x) conoc(x) #ifdef getchar #undef getchar #endif /* getchar */ #define getchar(x) coninc(0) #endif /* STRATUS */ #ifdef OS2 #ifdef putchar #undef putchar #endif /* putchar */ #define putchar(x) conoc(x) #endif /* OS2 */ #ifndef NOHINTS extern int hints; #endif /* NOHINTS */ #ifdef CK_TAPI extern int tttapi; extern int tapipass; #endif /* CK_TAPI */ #ifdef CKLOGDIAL extern int dialog; #endif /* CKLOGDIAL */ char * dialmsg[] = { /* DIAL status strings */ /* Keyed to numbers defined in ckcker.h -- keep in sync! */ "DIAL succeeded", /* 0 DIA_OK */ "Modem type not specified", /* 1 DIA_NOMO */ "Communication device not specified", /* 2 DIA_NOLI */ "Communication device can't be opened", /* 3 DIA_OPEN */ "Speed not specified", /* 4 DIA_NOSP */ "Pre-DIAL hangup failed", /* 5 DIA_HANG */ "Internal error", /* 6 DIA_IE */ "Device input/output error", /* 7 DIA_IO */ "DIAL TIMEOUT expired", /* 8 DIA_TIMO */ "Interrupted by user", /* 9 DIA_INTR */ "Modem not ready", /* 10 DIA_NRDY */ "Partial dial OK", /* 11 DIA_PART */ "Dial directory lookup error", /* 12 DIA_DIR */ "Hangup OK", /* 13 DIA_HUP */ NULL, /* 14 (undef) */ NULL, /* 15 (undef) */ NULL, /* 16 (undef) */ NULL, /* 17 (undef) */ NULL, /* 18 (undef) */ "No response from modem", /* 19 DIA_NRSP */ "Modem command error", /* 20 DIA_ERR */ "Failure to initialize modem", /* 21 DIA_NOIN */ "Phone busy", /* 22 DIA_BUSY */ "No carrier", /* 23 DIA_NOCA */ "No dialtone", /* 24 DIA_NODT */ "Incoming call", /* 25 DIA_RING */ "No answer", /* 26 DIA_NOAN */ "Disconnected", /* 27 DIA_DISC */ "Answered by voice", /* 28 DIA_VOIC */ "Access denied / forbidden call", /* 29 DIA_NOAC */ "Blacklisted", /* 30 DIA_BLCK */ "Delayed", /* 31 DIA_DELA */ "Fax connection", /* 32 DIA_FAX */ "Digital line", /* 33 DIA_DIGI */ "TAPI dialing failure", /* 34 DIA_TAPI */ NULL /* 34 */ }; #ifdef COMMENT #ifdef NOSPL static #endif /* NOSPL */ char modemmsg[128] = { NUL, NUL }; /* DIAL response from modem */ #endif /* COMMENT */ #ifdef NTSIG extern int TlsIndex; #endif /* NTSIG */ int mdmtyp = n_GENERIC; /* Default modem type */ int mdmset = 0; /* User explicitly set a modem type */ int /* SET DIAL parameters */ dialhng = 1, /* DIAL HANGUP, default is ON */ dialdpy = 0, /* DIAL DISPLAY, default is OFF */ mdmspd = 0, /* DIAL SPEED-MATCHING (0 = OFF) */ mdmspk = 1, /* MODEM SPEAKER */ mdmvol = 2, /* MODEM VOLUME */ dialtmo = 0, /* DIAL TIMEOUT */ dialatmo = -1, /* ANSWER TIMEOUT */ dialksp = 0, /* DIAL KERMIT-SPOOF, 0 = OFF */ dialidt = 0, /* DIAL IGNORE-DIALTONE */ #ifndef CK_RTSCTS /* If we can't do RTS/CTS then there's no flow control at first. */ /* So we might easily lose the echo to the init string and the OK */ /* and then give "No response from modem" errors. */ dialpace = 150, /* DIAL PACING */ #else dialpace = -1, #endif /* CK_RTSCTS */ /* 0 = RS232 (drop DTR); 1 = MODEM-COMMAND (e.g. +++ATH0) */ dialmhu = DEFMDMHUP; /* MODEM HANGUP-METHOD */ int dialec = 1, /* DIAL ERROR-CORRECTION */ dialdc = 1, /* DIAL COMPRESSION */ #ifdef VMS /* VMS can only use Xon/Xoff */ dialfc = FLO_XONX, /* DIAL FLOW-CONTROL */ #else dialfc = FLO_AUTO, #endif /* VMS */ dialmth = XYDM_D, /* DIAL METHOD (Tone, Pulse, Defalt) */ dialmauto = 1, /* DIAL METHOD is AUTO */ dialesc = 0; /* DIAL ESCAPE */ int telephony = 0; /* Command-line '-T' option */ long dialmax = 0L, /* Modem's max interface speed */ dialcapas = 0L; /* Modem's capabilities */ int dialsta = DIA_UNK; /* Detailed return code (ckuusr.h) */ #ifdef COMMENT int ans_cid = 0; /* SET ANSWER parameters */ int ans_rings = 0; /* (not used yet...) */ #endif /* COMMENT */ int is_rockwell = 0; int is_motorola = 0; int is_supra = 0; int is_hayeshispd = 0; /* Dialing directory list */ char *dialdir[MAXDDIR]; /* DIAL DIRECTORY filename array */ int ndialdir = 0; /* How many dial directories */ /* User overrides for built-in modem commands */ char *dialini = NULL; /* MODEM INIT-STRING none */ char *dialmstr = NULL; /* MODEM DIALMODE-STRING */ char *dialmprmt = NULL; /* MODEM DIALMODE-PROMPT */ char *dialcmd = NULL; /* MODEM DIAL-COMMAND, default none */ char *dialname = NULL; /* Descriptive name for modem */ char *dialdcon = NULL; /* DC ON command */ char *dialdcoff = NULL; /* DC OFF command */ char *dialecon = NULL; /* EC ON command */ char *dialecoff = NULL; /* EC OFF command */ char *dialaaon = NULL; /* Autoanswer ON command */ char *dialaaoff = NULL; /* Autoanswer OFF command */ char *dialhcmd = NULL; /* Hangup command */ char *dialhwfc = NULL; /* Hardware flow control command */ char *dialswfc = NULL; /* (Local) software f.c. command */ char *dialnofc = NULL; /* No (Local) flow control command */ char *dialtone = NULL; /* Command to force tone dialing */ char *dialpulse = NULL; /* ..to force pulse dialing */ char *dialx3 = NULL; /* Ignore dialtone */ char *mdmname = NULL; char *dialspon = NULL; /* Speaker On command */ char *dialspoff = NULL; /* Speaker Off command */ char *dialvol1 = NULL; /* Volume Low command */ char *dialvol2 = NULL; /* Volume Medium command */ char *dialvol3 = NULL; /* Volume High command */ char *dialini2 = NULL; /* Second init string */ /* Phone number options */ char *dialnpr = NULL; /* DIAL PREFIX, ditto */ char *diallac = NULL; /* DIAL LOCAL-AREA-CODE, ditto */ char *diallcc = NULL; /* DIAL LOCAL-COUNTRY-CODE, ditto */ char *dialixp = NULL; /* DIAL INTL-PREFIX */ char *dialixs = NULL; /* DIAL INTL-SUFFIX */ char *dialldp = NULL; /* DIAL LD-PREFIX */ char *diallds = NULL; /* DIAL LD-SUFFIX */ char *diallcp = NULL; /* DIAL LOCAL-PREFIX */ char *diallcs = NULL; /* DIAL LOCAL-SUFFIX */ char *dialpxi = NULL; /* DIAL PBX-INTERNAL-PREFIX */ char *dialpxo = NULL; /* DIAL PBX-OUTSIDE-PREFIX */ char *dialsfx = NULL; /* DIAL SUFFIX */ char *dialtfp = NULL; /* DIAL TOLL-FREE-PREFIX */ char *callid_date = NULL; /* Caller ID strings */ char *callid_time = NULL; char *callid_name = NULL; char *callid_nmbr = NULL; char *callid_mesg = NULL; extern char * d_name; extern char * dialtfc[]; /* DIAL TOLL-FREE-AREA-CODE */ extern char * dialpxx[]; /* DIAL PBX-EXCHANGE */ extern int ntollfree; extern int ndialpxx; extern char * dialpucc[]; /* DIAL Pulse countries */ extern int ndialpucc; extern char * dialtocc[]; /* DIAL Tone countries */ extern int ndialtocc; char *dialmac = NULL; /* DIAL macro */ /* Countries where pulse dialing must be used (tone is not available) */ static char * pulsecc[] = { NULL }; /* (Unknown at present) */ /* Countries where tone dialing may safely be the default. */ /* "+" marks countries where pulse is also allowed. */ /* Both Pulse and Tone are allowed in Austria & Switzerland but it is not */ /* yet known if Tone is universally in those countries. */ static char * tonecc[] = { "1", /* + North American Numbering Plan */ "31", /* Netherlands */ "32", /* Belgium */ "33", /* France */ "352", /* Luxembourg */ "353", /* Ireland */ "354", /* Iceland */ "358", /* Finland */ "39", /* Italy */ "44", /* + UK */ "45", /* Denmark */ "46", /* Sweden */ "47", /* Norway */ "49", /* + Germany */ NULL }; #ifndef MINIDIAL /* Telebit model codes: ATI Model Numbers Examples --- ------------- -------- 123 Telebit in "total Hayes-1200" emulation mode 960 Telebit in Conventional Command (Hayes) mode 961 RA12C IBM PC internal original Trailblazer 962 RA12E External original Trailblazer 963 RM12C Rackmount original Trailblazer 964 T18PC IBM PC internal Trailblazer-Plus (TB+) 965 T18SA, T2SAA, T2SAS External TB+, T1600, T2000, T3000, WB, and later 966 T18RMM Rackmount TB+ 967 T2MC IBM PS/2 internal TB+ 968 T1000 External T1000 969 ? Qblazer 970 Qblazer Plus 971 T2500 External T2500 972 T2500 Rackmount T2500 */ /* Telebit model codes */ #define TB_UNK 0 /* Unknown Telebit model */ #define TB_BLAZ 1 /* Original TrailBlazer */ #define TB_PLUS 2 /* TrailBlazer Plus */ #define TB_1000 3 /* T1000 */ #define TB_1500 4 /* T1500 */ #define TB_1600 5 /* T1600 */ #define TB_2000 6 /* T2000 */ #define TB_2500 7 /* T2500 */ #define TB_3000 8 /* T3000 */ #define TB_QBLA 9 /* Qblazer */ #define TB_WBLA 10 /* WorldBlazer */ #define TB__MAX 10 /* Highest number */ char *tb_name[] = { /* Array of model names */ "Unknown", /* TB_UNK */ "TrailBlazer", /* TB_BLAZ */ "TrailBlazer-Plus", /* TB_PLUS */ "T1000", /* TB_1000 */ "T1500", /* TB_1500 */ "T1600", /* TB_1600 */ "T2000", /* TB_2000 */ "T2500", /* TB_2500 */ "T3000", /* TB_3000 */ "Qblazer", /* TB_QBLA */ "WorldBlazer", /* TB_WBLA */ "" }; #endif /* MINIDIAL */ extern int flow, local, mdmtyp, quiet, backgrd, parity, seslog, network; extern int carrier, duplex, mdmsav, reliable, setreliable; extern int ttnproto, nettype; extern long speed; extern char ttname[], sesfil[]; #ifndef NOXFER extern CHAR stchr; extern int interrupted; #endif /* NOXFER */ /* Failure codes */ #define F_TIME 1 /* timeout */ #define F_INT 2 /* interrupt */ #define F_MODEM 3 /* modem-detected failure */ #define F_MINIT 4 /* cannot initialize modem */ #ifndef CK_TAPI static #endif /* CK_TAPI */ #ifdef OS2 volatile #endif /* OS2 */ int fail_code = 0; /* Default failure reason. */ static int xredial = 0; static int func_code; /* 0 = dialing, nonzero = answering */ static int partial; static int mymdmtyp = 0; #define DW_NOTHING 0 /* What we are doing */ #define DW_INIT 1 #define DW_DIAL 2 static int dial_what = DW_NOTHING; /* Nothing at first. */ static int nonverbal = 0; /* Hayes in numeric response mode */ static MDMINF * mp; static CHAR escbuf[6]; static long mdmcapas; _PROTOTYP (static VOID dreset, (void) ); _PROTOTYP (static int (*xx_ok), (int,int) ); _PROTOTYP (static int ddinc, (int) ); _PROTOTYP (int dialhup, (void) ); _PROTOTYP (int getok, (int,int) ); _PROTOTYP (char * ck_time, (void) ); _PROTOTYP (static VOID ttslow, (char *, int) ); #ifdef COMMENT _PROTOTYP (static VOID xcpy, (char *, char *, unsigned int) ); #endif /* COMMENT */ _PROTOTYP (static VOID waitfor, (char *) ); _PROTOTYP (static VOID dialoc, (char) ); _PROTOTYP (static int didweget, (char *, char *) ); _PROTOTYP (static VOID spdchg, (long) ); _PROTOTYP (static int dialfail, (int) ); _PROTOTYP (static VOID gethrw, (void) ); _PROTOTYP (static VOID gethrn, (void) ); int dialudt = n_UDEF; /* Number of user-defined type */ /* BEGIN MDMINF STRUCT DEFINITIONS */ /* Declare structures containing modem-specific information. REMEMBER that only the first SEVEN characters of these names are guaranteed to be unique. First declare the three types that are allowed for MINIDIAL versions. */ static MDMINF CCITT = /* CCITT / ITU-T V.25bis autodialer */ /* According to V.25bis: . Even parity is required for giving commands to the modem. . Commands might or might not echo. . Responses ("Indications") from the modem are terminated by CR and LF. . Call setup is accomplished by: - DTE raises DTR (V.24 circuit 108) [ttopen() does this] - Modem raises CTS (V.24 circuit 106) [C-Kermit ignores this] - DTE issues a call request command ("CRN") - Modem responds with "VAL" ("command accepted") - If the call is completed: modem responds with "CNX" ("call connected"); modem turns CTS (106) OFF; modem turns DSR (107) ON; else: modem responds with "CFI " ("call failure indication"). . To clear a call, the DTE turns DTR (108) OFF. . There is no mention of the Carrier Detect circuit (109) in the standard. . There is no provision for "escaping back" to the modem's command mode. It is not known whether there exists in real life a pure V.25bis modem. If there is, this code has never been tested on it. See the Digitel entry. */ { "Any CCITT / ITU-T V.25bis conformant modem", "", /* pulse command */ "", /* tone command */ 40, /* dial_time -- programmable -- */ ",:", /* pause_chars -- "," waits for programmable time */ /* ":" waits for dial tone */ 10, /* pause_time (seconds, just a guess) */ "", /* wake_str (none) */ 200, /* wake_rate (msec) */ "VAL", /* wake_prompt */ "", /* dmode_str (none) */ "", /* dmode_prompt (none) */ "CRN%s\015", /* dial_str */ 200, /* dial_rate (msec) */ 0, /* No esc_time */ 0, /* No esc_char */ "", /* No hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "CIC\015", /* aa_on_str */ "DIC\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ CKD_V25, /* capas */ NULL /* No ok_fn */ }; static MDMINF HAYES = /* Hayes 2400 and compatible modems */ { "Hayes Smartmodem 2400 and compatibles", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATE1Q0V1&S0&C1&D2\015", /* wake_str */ #else #ifdef VMS "ATQ0&S1\015", /* wake_str */ #else "ATQ0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str, user supplies D or T */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 2400L, /* max_speed */ CKD_AT, /* capas */ getok /* ok_fn */ }; /* The intent of the "unknown" modem is to allow KERMIT to support unknown modems by having the user type the entire autodial sequence (possibly including control characters, etc.) as the "phone number". The protocol and other characteristics of this modem are unknown, with some "reasonable" values being chosen for some of them. The only way to detect if a connection is made is to look for carrier. */ static MDMINF UNKNOWN = /* Information for "Unknown" modem */ { "Unknown", /* name */ "", /* pulse command */ "", /* tone command */ 30, /* dial_time */ "", /* pause_chars */ 0, /* pause_time */ "", /* wake_str */ 0, /* wake_rate */ "", /* wake_prompt */ "", /* dmode_str */ NULL, /* dmode_prompt */ "%s\015", /* dial_str */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; #ifndef MINIDIAL static MDMINF ATTISN = /* AT&T ISN Network */ { "", /* pulse command */ "", /* tone command */ "AT&T ISN Network", 30, /* Dial time */ "", /* Pause characters */ 0, /* Pause time */ "\015\015\015\015", /* Wake string */ 900, /* Wake rate */ "DIAL", /* Wake prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "%s\015", /* dial_str */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; static MDMINF ATTMODEM = /* information for AT&T switched-network modems */ /* "Number" following "dial" can include: p's and * t's to indicate pulse or tone (default) dialing, * + for wait for dial tone, , for pause, r for * last number dialed, and, except for 2224B, some * comma-delimited options like o12=y, before number. * "Important" options for the modems: * * All: Except for 2224B, enable option 12 for "transparent * data," o12=y. If a computer port used for both * incoming and outgoing calls is connected to the * modem, disable "enter interactive mode on carriage * return," EICR. The Kermit "dial" command can * function with EIA leads standard, EIAS. * * 2212C: Internal hardware switches at their default * positions (four rockers down away from numbers) * unless EICR is not wanted (rocker down at the 4). * For EIAS, rocker down at the 1. * * 2224B: Front-panel switch position 1 must be up (at the 1, * closed). Disable EICR with position 2 down. * For EIAS, position 4 down. * All switches on the back panel down. * * 2224CEO: All front-panel switches down except either 5 or 6. * Enable interactive flow control with o16=y. * Select normal asynchronous mode with o34=0 (zero). * Disable EICR with position 3 up. For EIAS, 1 up. * Reset the modem after changing switches. * * 2296A: If option 00 (zeros) is present, use o00=0. * Enable interactive flow control with o16=y. * Select normal asynchronous mode with o34=0 (zero). * (available in Microcom Networking version, but * not necessarily other models of the 2296A). * Enable modem-port flow control (if available) with * o42=y. Enable asynchronous operation with o50=y. * Disable EICR with o69=n. For EIAS, o66=n, using * front panel. */ { "AT&T switched-network modems", "", /* pulse command */ "", /* tone command */ 20, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ "+", /* wake_str */ 0, /* wake_rate */ "", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "at%s\015", /* dial_str */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ CKD_AT, /* capas */ NULL /* ok_fn */ }; static MDMINF ATTDTDM = /* AT&T Digital Terminal Data Module */ /* For dialing: KYBD switch down, others usually up. */ { "AT&T Digital Terminal Data Module", "", /* pulse command */ "", /* tone command */ 20, /* dial_time */ "", /* pause_chars */ 0, /* pause_time */ "", /* wake_str */ 0, /* wake_rate */ "", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "%s\015", /* dial_str */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; static MDMINF DIGITEL = /* Digitel DT-22 CCITT variant used in Brazil */ /* Attempts to adhere strictly to the V.25bis specification do not produce good results in real life. The modem for which this code was developed: (a) ignores parity; (b) sometimes terminates responses with LF CR instead of CR LF; (c) has a Hayes-like escape sequence; (d) supports a hangup ("HUP") command. Information from Fernando Cabral in Brasilia. */ { "Digitel DT-22 CCITT dialer", "", /* pulse command */ "", /* tone command */ 40, /* dial_time -- programmable -- */ ",:", /* pause_chars -- "," waits for programmable time */ /* ":" waits for dial tone */ 10, /* pause_time (seconds, just a guess) */ "HUP\015", /* wake_str (Not Standard CCITT) */ 200, /* wake_rate (msec) */ "VAL", /* wake_prompt */ "", /* dmode_str (none) */ "", /* dmode_prompt (none) */ "CRN%s\015", /* dial_str */ 200, /* dial_rate (msec) */ 1100, /* esc_time (Not Standard CCITT) */ 43, /* esc_char (Not Standard CCITT) */ "HUP\015", /* hup_str (Not Standard CCITT) */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "CIC\015", /* aa_on_str */ "DIC\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ CKD_V25, /* capas */ getok /* ok_fn */ }; static MDMINF H_1200 = /* Hayes 1200 and compatible modems */ { "Hayes Smartmodem 1200 and compatibles", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATE1Q0V1\015", /* wake_str */ #else "ATQ0\015", /* wake_str */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 1200L, /* max_speed */ CKD_AT, /* capas */ getok /* ok_fn */ }; static MDMINF H_ULTRA = /* Hayes high-speed */ { "Hayes Ultra/Optima/Accura 96/144/288", /* U,O,A */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATE1Q0V1X4N1Y0&S0&C1&D2S37=0S82=128\015", /* wake_str */ #else #ifdef VMS "ATQ0X4N1Y0&S1S37=0S82=128\015", /* wake_str */ #else "ATQ0X4N1Y0S37=0S82=128\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ /* OK for U,O */ "AT&K4\015", /* swfc_str */ /* OK for U,O */ "AT&K0\015", /* nofc_str */ /* OK for U,O */ "AT&Q5S36=7S48=7\015", /* ec_on_str */ /* OK for U,O */ "AT&Q0\015", /* ec_off_str */ /* OK for U,O */ "ATS46=2\015", /* dc_on_str */ "ATS46=0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ /* (varies) */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF H_ACCURA = /* Hayes Accura */ { /* GUESSING IT'S LIKE ULTRA & OPTIMA */ "Hayes Accura", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATE1Q0V1X4N1Y0&S0&C1&D2S37=0\015", /* wake_str */ #else #ifdef VMS "ATQ0X4N1Y0&S1S37=0\015", /* wake_str */ #else "ATQ0X4N1Y0S37=0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q5S36=7S48=7\015", /* ec_on_str */ "AT&Q0\015", /* ec_off_str */ "ATS46=2\015", /* dc_on_str */ "ATS46=0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ /* (varies) */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF PPI = /* Practical Peripherals */ { "Practical Peripherals V.22bis or higher with V.42 and V.42bis", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef COMMENT /* In newer models S82 (BREAK handling) was eliminated, causing an error. */ #ifdef OS2 "ATQ0X4N1&S0&C1&D2S37=0S82=128\015", /* wake_str */ #else "ATQ0X4N1S37=0S82=128\015", /* wake_str */ #endif /* OS2 */ #else /* So now we use Y0 instead */ #ifdef OS2 "ATE1Q0V1X4N1&S0&C1&D2Y0S37=0\015", /* wake_str */ #else #ifdef VMS "ATQ0X4N1Y0&S1S37=0\015", /* wake_str */ #else "ATQ0X4N1Y0S37=0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ #endif /* COMMENT */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q5S36=7S48=7\015", /* ec_on_str */ "AT&Q0S36=0S48=128\015", /* ec_off_str */ "ATS46=2\015", /* dc_on_str */ "ATS46=0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF DATAPORT = /* AT&T Dataport */ { "AT&T / Paradyne DataPort V.32 or higher", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ /* Note: S41=0 (use highest modulation) omitted, since it is not supported on the V.32 and lower models. So let's not touch it. */ #ifdef OS2 "ATQ0E1V1X6&S0&C1&D2&Q0Y0\\K5S78=0\015", /* wake_str */ #else #ifdef VMS "ATQ0E1X6&S1&Q0Y0\\K5S78=0\015", /* wake_str */ #else "ATQ0E1X6&Q0Y0\\K5S78=0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT\\Q3\015", /* hwfc_str */ "AT\\Q1\\X0\015", /* swfc_str */ "AT\\Q0\015", /* nofc_str */ "AT\\N7\015", /* ec_on_str */ "AT\\N0\015", /* ec_off_str */ "AT%C1\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF UCOM_AT = /* Microcom DeskPorte FAST ES 28.8 */ { "Microcom DeskPorte FAST 28.8", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATE1Q0V1X4\\N0F0&S0&C1&D2\\K5\015", /* wake_str */ #else #ifdef VMS "ATQ0X4F0&S1\\K5\015", /* wake_str */ #else "ATQ0X4F0\\K5\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT\\Q3\015", /* hwfc_str */ "AT\\Q1\015", /* swfc_str */ "AT\\H0\\Q0\015", /* nofc_str */ "AT\\N3\015", /* ec_on_str */ "AT\\N0\015", /* ec_off_str */ "AT%C3\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "AT-J0\015", /* sb_on_str */ "AT-J1\015", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF ZOOM = /* Zoom Telephonics V.32bis */ { "Zoom Telephonics V.32bis", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATE1Q0V1N1W1X4&S0&C1&D2S82=128S95=47\015", /* wake_str */ #else #ifdef VMS "ATQ0E1N1W1X4&S1S82=128S95=47\015", /* wake_str */ #else "ATQ0E1N1W1X4S82=128S95=47\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q5S36=7S48=7\015", /* ec_on_str */ "AT&Q0\015", /* ec_off_str */ "ATS46=138\015", /* dc_on_str */ "ATS46=136\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF ZYXEL = /* ZyXEL U-Series */ { "ZyXEL U-Series V.32bis or higher", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATE1Q0V1&S0&C1&D2&N0X5&Y1\015", /* wake_str */ #else #ifdef VMS "ATQ0E1&S1&N0X5&Y1\015", /* wake_str */ #else "ATQ0E1&N0X5&Y1\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&H3\015", /* hwfc_str */ "AT&H4\015", /* swfc_str */ "AT&H0\015", /* nofc_str */ "AT&K3\015", /* ec_on_str */ "AT&K0\015", /* ec_off_str */ "AT&K4\015", /* dc_on_str */ "AT&K3\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF ZOLTRIX = /* Zoltrix */ { "Zoltrix V.32bis and V.34 modems with Rockwell ACI chipset", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATE1Q0V1F0W1X4Y0&S0&C1&D2\\K5S82=128S95=41\015", /* wake_str */ #else #ifdef VMS "ATQ0E1F0W1X4Y0&S1\\K5S82=128S95=41\015", /* wake_str */ #else "ATQ0E1F0W1X4Y0\\K5S82=128S95=41\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4S32=17S33=19\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT\\N3\015", /* ec_on_str */ "AT\\N1\015", /* ec_off_str */ "ATS46=138%C3\015", /* dc_on_str */ "ATS46=136%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "AT\\N0\015", /* sb_on_str */ "AT&Q0\015", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF MOTOROLA = { /* Motorola FasTalk II or Lifestyle */ /* "\E" and "\X" commands removed - Motorola Lifestyle doesn't have them. \E0 = Don't echo while online \X0 = Process Xon/Xoff but don't pass through */ "Motorola FasTalk II or Lifestyle", /* Name */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATE1Q0V1X4&S0&C1&D2\\K5\\V1\015", /* wake_str */ #else #ifdef VMS "ATQ0E1X4&S1\\K5\\V1\015", /* wake_str */ #else "ATQ0E1X4\\K5\\V1\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT\\Q3\015", /* hwfc_str */ "AT\\Q1\015", /* swfc_str */ "AT\\Q0\015", /* nofc_str */ "AT\\N6\015", /* ec_on_str */ "AT\\N1\015", /* ec_off_str */ "AT%C1\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "AT\\J0\015", /* sb_on_str */ "AT\\J1\015", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF BOCA = /* Boca */ { "BOCA 14.4 Faxmodem", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATE1Q0V1F1N1W1&S0&C1&D2\\K5S37=11S82=128S95=47X4\015", /* wake_str */ #else #ifdef VMS "ATQ0E1F1N1W1&S1\\K5S37=11S82=128S95=47X4\015", /* wake_str */ #else "ATQ0E1F1N1W1\\K5S37=11S82=128S95=47X4\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT\\N3S36=7S48=7\015", /* ec_on_str */ "AT\\N1\015", /* ec_off_str */ "ATS46=138\015", /* dc_on_str */ "ATS46=136\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF INTEL = /* Intel */ { "Intel High-Speed Faxmodem", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATE1Q0V1Y0X4&S0&C1&D2\\K1\\V2S25=50\015", /* wake_str */ #else #ifdef VMS "ATQ0E1Y0X4&S1\\K1\\V2S25=50\015", /* wake_str */ #else "ATQ0E1Y0X4\\K1\\V2S25=50\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "ATB1+FCLASS=0\015", /* dmode_str */ "OK\015", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT\\G1\\Q3\015", /* hwfc_str */ "AT\\G1\\Q1\\X0\015", /* swfc_str */ "AT\\G0\015", /* nofc_str */ "AT\\J0\\N3\"H3\015", /* ec_on_str */ "AT\\N1\015", /* ec_off_str */ "AT%C1\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF MULTITECH = /* Multitech */ { "Multitech MT1432 or MT2834 Series", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ /* #P0 (= no parity) is not listed in the manual for newer models */ /* so it has been removed from all three copies of the Multitech wake_str */ #ifdef OS2 "ATE1Q0V1X4&S0&C1&D2&E8&Q0\015", /* wake_str */ #else #ifdef VMS "ATQ0E1X4&S1&E8&Q0\015", /* wake_str */ #else "ATQ0E1X4&E8&Q0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&E4&E7&E8&E11&E13\015", /* hwfc_str */ "AT&E5&E6&E8&E11&E13\015", /* swfc_str */ "AT&E3&E7&E8&E10&E12\015", /* nofc_str */ "AT&E1\015", /* ec_on_str */ "AT&E0\015", /* ec_off_str */ "AT&E15\015", /* dc_on_str */ "AT&E14\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "AT$BA0\015", /* sb_on_str (= "baud adjust off") */ "AT$BA1\015", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF SUPRA = /* Supra */ { "SupraFAXModem 144 or 288", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1N1W0X4Y0&S0&C1&D2\\K5S82=128\015", /* wake_str */ #else #ifdef VMS "ATQ0E1N1W0X4Y0&S1\\K5S82=128\015", /* wake_str */ #else "ATQ0E1N1W0X4Y0\\K5S82=128\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q5\\N3S48=7\015", /* ec_on_str */ "AT&Q0\\N1\015", /* ec_off_str */ "AT%C1S46=138\015", /* dc_on_str */ "AT%C0S46=136\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM\015", /* sp_off_str */ "ATL\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF SUPRAX = /* Supra Express */ { "Diamond Supra Express V.90", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1W0X4&C1&D2&S0\\K5\015", /* wake_str */ #else #ifdef VMS "ATQ0E1W0X4&S1\\K5\015", /* wake_str */ #else "ATQ0E1W0X4\\K5\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT\\N3\015", /* ec_on_str */ "AT\\N1\015", /* ec_off_str */ "AT%C2\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM\015", /* sp_off_str */ "ATL\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 230400L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF MAXTECH = /* MaxTech */ { "MaxTech XM288EA or GVC FAXModem", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4Y0&S0&C1&D2&L0&M0\\K5\015", /* wake_str */ #else #ifdef VMS "ATQ0E1X4Y0&L0&M0&S1\\K5\015", /* wake_str */ #else "ATQ0E1X4Y0&L0&M0\\K5\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT\\Q3\015", /* hwfc_str */ "AT\\Q1\\X0\015", /* swfc_str */ "AT\\Q0\015", /* nofc_str */ "AT\\N6\015", /* ec_on_str */ "AT\\N0\015", /* ec_off_str */ "AT\\N6%C1\015", /* dc_on_str */ "AT\\N6%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF ROLM = /* IBM / Siemens / Rolm 8000, 9000, 9751 CBX DCM */ { "IBM/Siemens/Rolm CBX Data Communications Module", "", /* pulse command */ "", /* tone command */ 60, /* dial_time */ "", /* pause_chars */ 0, /* pause_time */ "\015\015", /* wake_str */ 50, /* wake_rate */ "MODIFY?", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "CALL %s\015", /* dial_str */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 19200L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; static MDMINF USR = /* USR Courier and Sportster modems */ { "US Robotics Courier, Sportster, or compatible", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4&A3&S0&C1&D2&N0&Y3S14=0\015", /* wake_str */ #else #ifdef SUNOS4 "ATQ0X4&A3&S0&N0&Y3S14=0\015", /* wake_str -- needs &S0 in SunOS */ #else #ifdef VMS "ATQ0X4&A3&S1&N0&Y3S14=0\015", /* wake_str -- needs &S1 in VMS */ #else "ATQ0X4&A3&N0&Y3S14=0\015", /* wake_str */ #endif /* VMS */ #endif /* SUNOS4 */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&H1&R2&I0\015", /* hwfc_str */ "AT&H2&R1&I2\015", /* swfc_str */ "AT&H0&R1&I0\015", /* nofc_str */ "AT&M4&B1\015", /* ec_on_str */ "AT&M0\015", /* ec_off_str */ "AT&K1\015", /* dc_on_str */ "AT&K0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF USRX2 = /* USR XJ-CC1560 X2 56K */ { "US Robotics / Megahertz CC/XJ-CC1560 X2", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4&A3&S0&B2&C1&D2&N0\015", /* wake_str */ #else #ifdef VMS "ATQ0X4&A3&B2&N0&S1\015", /* wake_str */ #else "ATQ0X4&A3&B2&N0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&H1&I0\015", /* hwfc_str */ "AT&H2&I2\015", /* swfc_str */ "AT&H0&I0\015", /* nofc_str */ "AT&M4\015", /* ec_on_str */ "AT&M0\015", /* ec_off_str */ "AT&K1\015", /* dc_on_str */ "AT&K0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "AT&B1\015", /* sb_on_str */ "AT&B0\015", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF OLDTB = /* Old Telebits */ { "Telebit TrailBlazer, T1000, T1500, T2000, T2500", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 60, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "\021AAAAATQ0E1V1X1&S0&C1&D2S12=50S50=0S54=3\015", /* wake_str. */ #else #ifdef VMS "\021AAAAATQ0X1S12=50S50=0S54=3\015", /* wake_str. */ #else "\021AAAAATQ0X1&S1S12=50S50=0S54=3\015", /* wake_str. */ #endif /* VMS */ #endif /* OS2 */ 100, /* wake_rate = 100 msec */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str, Note: no T or P */ 80, /* dial_rate */ 1100, /* esc_time (guard time) */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "ATS58=2S68=2\015", /* hwfc_str */ "ATS58=3S68=3S69=0\015", /* swfc_str */ "ATS58=0S68=0\015", /* nofc_str */ "ATS66=1S95=2\015", /* ec_on_str */ "ATS95=0\015", /* ec_off_str */ "ATS110=1S96=1\015", /* dc_on_str */ "ATS110=0S96=0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 19200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW|CKD_TB|CKD_KS, /* capas */ getok /* ok_fn */ }; static MDMINF NEWTB = /* New Telebits */ { "Telebit T1600, T3000, QBlazer, WorldBlazer, etc.", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 60, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "\021AAAAATQ0E1V1X2&S0&C1&D2S12=50S50=0S61=0S63=0\015", /* wake_str. */ #else #ifdef VMS "\021AAAAATQ0X2&S1S12=50S50=0S61=0S63=0\015", /* wake_str. */ #else "\021AAAAATQ0X2S12=50S50=0S61=0S63=0\015", /* wake_str. */ #endif /* VMS */ #endif /* OS2 */ 100, /* wake_rate = 100 msec */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str, Note: no T or P */ 80, /* dial_rate */ 1100, /* esc_time (guard time) */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "ATS58=2S68=2\015", /* hwfc_str */ "ATS58=3S68=3\015", /* swfc_str */ "ATS58=0S68=0\015", /* nofc_str */ "ATS180=3\015", /* ec_on_str */ "ATS180=0\015", /* ec_off_str */ "ATS190=1\015", /* dc_on_str */ "ATS190=0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 38400L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW|CKD_TB|CKD_KS, /* capas */ getok /* ok_fn */ }; #endif /* MINIDIAL */ static MDMINF DUMMY = /* dummy information for modems that are handled elsewhere */ { "(dummy)", "", /* pulse command */ "", /* tone command */ 30, /* dial_time */ "", /* pause_chars */ 0, /* pause_time */ "", /* wake_str */ 0, /* wake_rate */ "", /* wake_prompt */ "", /* dmode_str */ NULL, /* dmode_prompt */ "%s\015", /* dial_str */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; #ifndef MINIDIAL static MDMINF RWV32 = /* Generic Rockwell V.32 */ { "Generic Rockwell V.32 modem", /* ATI3, ATI4, and ATI6 for details */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4Y0&S0&C1&D2%E2\\K5+FCLASS=0N1S37=0\015", /* wake_str */ #else #ifdef VMS "ATQ0X4Y0&S1%E2\\K5+FCLASS=0N1S37=0\015", /* wake_str */ #else "ATQ0X4Y0%E2\\K5+FCLASS=0N1S37=0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4S32=17S33=19\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q6\015", /* ec_on_str */ "AT&Q0\015", /* ec_off_str */ "AT%C1\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF RWV32B = /* Generic Rockwell V.32bis */ { "Generic Rockwell V.32bis modem", /* ATI3, ATI4, and ATI6 for details */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4Y0&S0&C1&D2%E2\\K5+FCLASS=0N1S37=0\015", /* wake_str */ #else #ifdef VMS "ATQ0X4Y0&S1%E2\\K5+FCLASS=0N1S37=0\015", /* wake_str */ #else "ATQ0X4Y0%E2\\K5+FCLASS=0N1S37=0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4S32=17S33=19\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q5\015", /* ec_on_str */ "AT&Q0\015", /* ec_off_str */ "ATS%C1\015", /* dc_on_str */ "ATS%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF RWV34 = /* Generic Rockwell V.34 Data/Fax */ { "Generic Rockwell V.34 modem", /* ATI3, ATI4, and ATI6 for details */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0V1X4Y0&C1&D2&S0%E2\\K5+FCLASS=0\015", /* wake_str */ #else #ifdef VMS "ATQ0V1X4Y0&C1&D2&S1%E2\\K5+FCLASS=0\015", /* wake_str */ #else "ATQ0V1X4Y0&C1&D2%E2\\K5+FCLASS=0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4S32=17S33=19\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q5\015", /* ec_on_str */ "AT&Q0\015", /* ec_off_str */ "ATS%C3\015", /* dc_on_str */ "ATS%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF RWV90 = /* Generic Rockwell V.90 Data/Fax */ { "Generic Rockwell V.90 56K modem", /* ATI3, ATI4, and ATI6 for details */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0V1N1X4Y0&C1&D2&S0%E2\\K5+FCLASS=0S37=0\015", /* K95 */ #else #ifdef VMS "ATQ0V1N1X4Y0&C1&D2&S1%E2\\K5+FCLASS=0S37=0\015", /* wake_str */ #else "ATQ0V1N1X4Y0&C1&D2%E2\\K5+FCLASS=0S37=0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4S32=17S33=19\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q5\015", /* ec_on_str */ "AT&Q0\015", /* ec_off_str */ "AT%C3\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF MWAVE = /* IBM Mwave */ { "IBM Mwave Adapter", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4Y0&S0&C1&D2&M0&Q0&N1\\K3\\T0%E2S28=0\015", /* wake_str */ #else #ifdef VMS "ATQ0X4Y0&M0&S1&Q0&N1&S0\\K3\\T0%E2S28=0\015", /* wake_str */ #else "ATQ0X4Y0&M0&Q0&N1&S0\\K3\\T0%E2S28=0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT\\Q3\015", /* hwfc_str */ "", /* swfc_str (it doesn't!) */ "AT\\Q0\015", /* nofc_str */ "AT\\N7\015", /* ec_on_str */ "AT\\N0\015", /* ec_off_str */ "AT%C1\"H3\015", /* dc_on_str */ "AT%C0\"H0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW, /* capas */ getok /* ok_fn */ }; static MDMINF TELEPATH = /* Gateway 2000 Telepath */ { "Gateway 2000 Telepath II 28.8", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4&S0&C1&D2&N0&Y2#CLS=0S13=0S15=0S19=0\015", /* wake_str */ #else #ifdef VMS "ATQ0X4&N0&S1&Y1#CLS=0S13=0S15=0S19=0\015", /* wake_str */ #else "ATQ0X4&N0&Y1#CLS=0S13=0S15=0S19=0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&H1&R2\015", /* hwfc_str */ "AT&H2&I2S22=17S23=19\015", /* swfc_str */ "AT&H0&I0&R1\015", /* nofc_str */ "AT&M4&B1\015", /* ec_on_str -- also fixes speed */ "AT&M0\015", /* ec_off_str */ "AT&K1\015", /* dc_on_str */ "AT&K0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF CARDINAL = /* Cardinal - based on Rockwell V.34 */ { "Cardinal MVP288X Series", /* ATI3, ATI4, and ATI6 for details */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4W1Y0%E2&S0&C1&D2\\K5+FCLASS=0+MS=11,1\015", /* wake_str */ #else #ifdef VMS "ATQ0X4W1Y0&S1%E2\\K5+FCLASS=0+MS=11,1\015", /* wake_str */ #else "ATQ0X4W1Y0%E2\\K5+FCLASS=0+MS=11,1\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4S32=17S33=19\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q5S36=7S48=7\\N3\015", /* ec_on_str */ "AT&Q0S48=128\\N1\015", /* ec_off_str */ "ATS46=138%C1\015", /* dc_on_str */ "ATS46=136%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF LUCENT = /* Lucent Venus or Data/Fax modem */ { "Lucent Venus chipset", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0V1N1X4Y0&C1&D2&S0%E2\\K5+FCLASS=0S37=0\015", /* K95 */ #else #ifdef VMS "ATQ0V1N1X4Y0&C1&D2&S1%E2\\K5+FCLASS=0S37=0\015", /* VMS */ #else "ATQ0V1N1X4Y0&C1&D2%E2\\K5+FCLASS=0S37=0\015", /* All others */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4S32=17S33=19\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q5\015", /* ec_on_str */ "AT&Q0\015", /* ec_off_str */ "AT%C1\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF CONEXANT = /* Conexant family */ { "Conexant family of modems", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0V1X4&C1&D2&S0%E1+FCLASS=0\015", /* K95 */ #else #ifdef VMS "ATQ0V1X4&C1&D2&S1%E1+FCLASS=0\015", /* VMS */ #else "ATQ0V1X4&C1&D2%E1+FCLASS=0\015", /* UNIX etc */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4S32=17S33=19\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q5\015", /* ec_on_str */ "AT&Q0\015", /* ec_off_str */ "AT%C3\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF PCTEL = /* PCTel chipset */ { "PCTel chipset", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0V1N1X4Y0&C1&D2&S0%E2\\K5S37=0\015", /* K95 */ #else #ifdef VMS "ATQ0V1N1X4Y0&C1&D2&S1%E2\\K5S37=0\015", /* VMS */ #else "ATQ0V1N1X4Y0&C1&D2%E2\\K5S37=0\015", /* UNIX etc */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4S32=17S33=19\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT\\N3\015", /* ec_on_str */ "AT\\N0\015", /* ec_off_str */ "AT%C1\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF ZOOMV34 = /* Zoom Telephonics V.34 */ { "Zoom Telephonics V.34", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0V1N1W1X4&S0&C1&D2S82=128\015", /* wake_str */ #else #ifdef VMS "ATQ0V1N1W1X4&S1S82=128\015", /* wake_str */ #else "ATQ0V1N1W1X4S82=128S015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4\015S32=17S33=19", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q5\015", /* ec_on_str */ "AT&Q0\015", /* ec_off_str */ "ATS%C3\015", /* dc_on_str */ "ATS%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF ZOOMV90 = /* ZOOM V.90 */ { "Zoom V.90 56K", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0V1N1X4Y0&C1&D2&S0%E2\\K5+FCLASS=0S37=0\015", /* K95 */ #else #ifdef VMS "ATQ0V1N1X4Y0&C1&D2&S1%E2\\K5+FCLASS=0S37=0\015", /* VMS */ #else "ATQ0V1N1X4Y0&C1&D2%E2\\K5+FCLASS=0S37=0\015", /* All others */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4S32=17S33=19\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q5\015", /* ec_on_str */ "AT&Q0\015", /* ec_off_str */ "AT%C1\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF ZOOMV92 = /* ZOOM V.92 */ { "Zoom V.92 with V.44 compression", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0V1N1X4Y0&C1&D2&S0%E2\\K5+FCLASS=0S37=0+MS=V92\015", /* K95 */ #else #ifdef VMS "ATQ0V1N1X4Y0&C1&D2&S1%E2\\K5+FCLASS=0S37=0+MS=V92\015", /* VMS */ #else "ATQ0V1N1X4Y0&C1&D2%E2\\K5+FCLASS=0S37=0+MS=V92\015", /* All others */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4S32=17S33=19\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT&Q5\015", /* ec_on_str */ "AT&Q0\015", /* ec_off_str */ "AT%C1+DCS=1,1\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; /* Now the "old" modems, all grouped together, and also within "if not defined MINIDIAL"... */ #ifdef OLDMODEMS static MDMINF CERMETEK = /* Information for "Cermetek Info-Mate 212 A" modem */ { "Cermetek Info-Mate 212 A", "", /* pulse command */ "", /* tone command */ 20, /* dial_time */ "BbPpTt", /* pause_chars */ 0, /* pause_time */ " XY\016R\015", /* wake_str */ 200, /* wake_rate */ "", /* wake_prompt */ "", /* dmode_str */ NULL, /* dmode_prompt */ "\016D '%s'\015", /* dial_str */ 200, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 1200L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; static MDMINF DF03 = /* information for "DEC DF03-AC" modem */ { "Digital DF03-AC", "", /* pulse command */ "", /* tone command */ 27, /* dial_time */ "=", /* pause_chars */ 15, /* pause_time */ "\001\002", /* wake_str */ 0, /* wake_rate */ "", /* wake_prompt */ "", /* dmode_str */ NULL, /* dmode_prompt */ "%s", /* dial_str */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; static MDMINF DF100 = /* information for "DEC DF100-series" modem */ /* * The telephone "number" can include "P"s and/or "T"s * within it to indicate that subsequent digits are * to be dialed using pulse or tone dialing. The * modem defaults to pulse dialing. You may modify * the dial string below to explicitly default all * dialing to pulse or tone, but doing so prevents * the use of phone numbers that you may have stored * in the modem's memory. */ { "Digital DF-100", "", /* pulse command */ "", /* tone command */ 30, /* dial_time */ "=", /* pause_chars */ 15, /* pause_time */ "\001", /* wake_str */ 0, /* wake_rate */ "", /* wake_prompt */ "", /* dmode_str */ NULL, /* dmode_prompt */ "%s#", /* dial_str */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; static MDMINF DF200 = /* information for "DEC DF200-series" modem */ /* * The telephone "number" can include "P"s and/or "T"s * within it to indicate that subsequent digits are * to be dialed using pulse or tone dialing. The * modem defaults to pulse dialing. You may modify * the dial string below to explicitly default all * dialing to pulse or tone, but doing so prevents * the use of phone numbers that you may have stored * in the modem's memory. */ { "Digital DF-200", "", /* pulse command */ "", /* tone command */ 30, /* dial_time */ "=W", /* pause_chars */ /* =: second tone; W: 5 secs */ 15, /* pause_time */ /* worst case */ "\002", /* wake_str */ /* allow stored number usage */ 0, /* wake_rate */ "", /* wake_prompt */ "", /* dmode_str */ NULL, /* dmode_prompt */ #ifdef COMMENT "%s!", /* dial_str */ #else " d %s\015", #endif /* COMMENT */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; static MDMINF GDC = /* information for "GeneralDataComm 212A/ED" modem */ { "GeneralDataComm 212A/ED", "", /* pulse command */ "", /* tone command */ 32, /* dial_time */ "%", /* pause_chars */ 3, /* pause_time */ "\015\015", /* wake_str */ 500, /* wake_rate */ "$", /* wake_prompt */ "D\015", /* dmode_str */ ":", /* dmode_prompt */ "T%s\015", /* dial_str */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 1200L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; static MDMINF PENRIL = /* information for "Penril" modem */ { "Penril modem", "", /* pulse command */ "", /* tone command */ 50, /* dial_time */ "", /* pause_chars */ 0, /* pause_time */ "\015\015", /* wake_str */ 300, /* wake_rate */ ">", /* wake_prompt */ "k\015", /* dmode_str */ ":", /* dmode_prompt */ "%s\015", /* dial_str */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; static MDMINF RACAL = /* Racal Vadic VA4492E */ { "Racal Vadic VA4492E", "", /* pulse command */ "", /* tone command */ 35, /* dial_time (manual says modem is hardwired to 60) */ "Kk", /* pause_chars */ 5, /* pause_time */ "\005\015", /* wake_str, ^E^M */ 50, /* wake_rate */ "*", /* wake_prompt */ "D\015", /* dmode_str */ "?", /* dmode_prompt */ "%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 5, /* esc_char, ^E */ "\003\004", /* hup_str, ^C^D */ 0, /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; static MDMINF VENTEL = /* Information for Ven-Tel modem */ { "Ven-Tel", "", /* pulse command */ "", /* tone command */ 20, /* dial_time */ "%", /* pause_chars */ 5, /* pause_time */ "\015\015\015", /* wake_str */ 300, /* wake_rate */ "$", /* wake_prompt */ "K\015", /* dmode_str (was "") */ "Number to call: ", /* dmode_prompt (was NULL) */ "%s\015", /* dial_str (was "") */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; static MDMINF CONCORD = /* Info for Condor CDS 220 2400b modem */ { "Concord Condor CDS 220 2400b", "", /* pulse command */ "", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ "\015\015", /* wake_str */ 20, /* wake_rate */ "CDS >", /* wake_prompt */ "", /* dmode_str */ NULL, /* dmode_prompt */ "", /* dial_str */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char */ "", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_off_str */ "", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 2400L, /* max_speed */ 0, /* capas */ NULL /* ok_fn */ }; #endif /* OLDMODEMS */ static MDMINF MICROCOM = /* Microcom modems in native SX mode */ /* (long answer only) */ { "Microcom MNP modems in SX command mode", "DP\015", /* pulse command */ "DT\015", /* tone command */ 35, /* dial_time */ ",!@", /* pause_chars (! and @ aren't pure pauses) */ 3, /* pause_time */ /* The following sets 8 bits, no parity, BREAK passthru, and SE0 disables the escape character, which is a single character with no guard time, totally unsafe, so we have no choice but to disable it. Especially since, by default, it is Ctrl-A, which is Kermit's packet-start character. We would change it to something else, which would enable "mdmhup()", but the user wouldn't know about it. Very bad. Note: SE1 sets it to Ctrl-A, SE2 sets it to Ctrl-B, etc (1..31 allowed). Also SE/Q sets it to "Q". */ "SE0;S1P4;SBRK5\015", /* wake_str */ 100, /* wake_rate */ "!", /* wake_prompt */ "", /* dmode_str */ NULL, /* dmode_prompt */ "D%s\015", /* dial_str - number up to 39 chars */ 0, /* dial_rate */ 0, /* esc_time */ 0, /* esc_char - we can't use this */ "", /* hup_str - it's "H" but can't use */ "SF13\015", /* hwfc_str */ "SF11\015", /* swfc_str */ "SF10\015", /* nofc_str */ "BAOFF;SMAUT\015", /* ec_on_str */ "BAON;SMDIR\015", /* ec_off_str */ "COMP1\015", /* dc_on_str */ "COMP0\015", /* dc_off_str */ "AA", /* aa_on_str */ "", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "SA2", /* sp_off_str */ "SA0", /* sp_on_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 0L, /* max_speed */ CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW|CKD_KS, /* capas */ getok /* ok_fn */ }; static MDMINF MICROLINK = /* MicroLink ... */ { /* 14.4TQ,TL,PC;28.8TQ,TQV;2440T/TR */ "ELSA MicroLink 14.4, 28.8, 33.6 or 56K", /* ELSA GmbH, Aachen */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4&S0\\D0&C1&D2\\K5\015", /* wake_str */ #else #ifdef VMS "ATQ0X4&S1\\K5\015", /* wake_str */ #else "ATQ0X4\\K5\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H\015", /* hup_str */ "AT\\Q3\015", /* hwfc_str */ "AT\\Q1\\X0\015", /* swfc_str */ "AT\\Q0\015", /* nofc_str */ "AT\\N3\015", /* ec_on_str */ "AT\\N0\015", /* ec_off_str */ "AT%C3\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "\\J0", /* sb_on_str (?) */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF ULINKV250 = /* MicroLink V.250 */ { /* 56Kflex, V.90; V.250 command set */ "ELSA MicroLink 56K V.250", /* ELSA GmbH, Aachen */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 /* \D0 = DSR & CTS always on but hwfc overrides on CTS. */ "ATQ0E1V1X4&S0\\D0&C1&D2\015", /* wake_str */ #else #ifdef VMS "ATQ0X4&S1\015", /* wake_str */ #else "ATQ0X4\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT+IFC=2,2\015", /* hwfc_str */ "AT+IFC=1,1\015", /* swfc_str */ "AT+IFC=0,0\015", /* nofc_str */ "AT+ES=3,0\015", /* ec_on_str */ "AT+ES=1,0\015", /* ec_off_str */ "AT+DS=3,0,2048,32\015", /* dc_on_str */ "AT+DS=0,0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str (?) */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; #endif /* MINIDIAL */ static MDMINF ITUTV250 = /* ITU-T V.250 conforming modem */ { "Any ITU-T V.25ter/V.250 conformant modem", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ "ATQ0E1V1X4&C1&D2\015", /* wake_str (no &Sn in V.25) */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT+IFC=2,2\015", /* hwfc_str */ "AT+IFC=1,1\015", /* swfc_str */ "AT+IFC=0,0\015", /* nofc_str */ "AT+ES=3,0,2;+EB=1,0,30\015", /* ec_on_str */ "AT+ES=0\015", /* ec_off_str */ "AT+DS=3,0\015", /* dc_on_str */ "AT+DS=0,0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; #ifndef CK_TAPI static #endif /* CK_TAPI */ MDMINF GENERIC = /* Generic high speed ... */ { "Generic high-speed AT command set", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ "", /* wake_str */ 0, /* wake_rate */ "", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_on_str */ "", /* sp_off_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW, /* capas */ getok /* ok_fn */ }; #ifndef MINIDIAL static MDMINF XJACK = /* Megahertz X-Jack */ { "Megahertz X-Jack XJ3144 / CC6144", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4N1&C1&D2\\K5\015", /* wake_str */ #else "ATQ0X4N1\\K5\015", /* wake_str */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT\\N3&Q5\015", /* ec_on_str */ "AT\\N1&Q0\015", /* ec_off_str */ "AT%C3\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF SPIRITII = /* QuickComm Spirit II */ { "QuickComm Spirit II", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ "AT&F\015", /* wake_str */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H\015", /* hup_str */ "AT*F3\015", /* hwfc_str */ "AT*F2\015", /* swfc_str */ "AT*F0\015", /* nofc_str */ "AT*E6\015", /* ec_on_str */ "AT*E0\015", /* ec_off_str */ "AT*E9\015", /* dc_on_str */ "AT*E0\015", /* dc_off_str */ "ATS0=2\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF MONTANA = { /* Motorola Montana */ "Motorola Montana", /* Name */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4&S0&C1&D2\\K5\\V1\015", /* wake_str */ #else #ifdef VMS "ATQ0E1X4&S1\\K5\\V1\015", /* wake_str */ #else "ATQ0E1X4\\K5\\V1\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT\\Q3\015", /* hwfc_str */ "AT\\Q1\015", /* swfc_str */ "AT\\Q0\015", /* nofc_str */ "AT\\N4\015", /* ec_on_str */ "AT\\N1\015", /* ec_off_str */ "AT%C1\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "AT\\J0\015", /* sb_on_str */ "AT\\J1\015", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF COMPAQ = { /* Compaq Data+Fax Modem */ "Compaq Data+Fax Modem", /* Name */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4&S0&C1&D2\015", /* wake_str */ #else #ifdef VMS "ATQ0E1X4&S1\015", /* wake_str */ #else "ATQ0E1X4\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT\\Q3\015", /* hwfc_str (same as &K3) */ "AT\\Q1\015", /* swfc_str (same as &K4) */ "AT\\Q0\015", /* nofc_str (same as &K0) */ "AT\\N3\015", /* ec_on_str */ "AT\\N0\015", /* ec_off_str */ "AT%C1\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "AT\\N3\015", /* sb_on_str */ "AT\\N1\015", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL0\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF FUJITSU = { /* Fujitsu */ "Fujitsu Fax/Modem Adapter", /* Name */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4&S0&C1&D2\\K5\\N3\015", /* wake_str */ #else #ifdef VMS "ATQ0E1X4&S1\\K5\\N3\015", /* wake_str */ #else "ATQ0E1X4\\K5\\N3\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\\Q3\015", /* hwfc_str */ "AT&K4\\Q1\015", /* swfc_str */ "AT&K0\\Q0\015", /* nofc_str */ "AT\\N3\015", /* ec_on_str */ "AT\\N0\015", /* ec_off_str */ "AT%C1", /* dc_on_str */ "AT%C0", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "AT\\J0\015", /* sb_on_str */ "AT\\J1\015", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF MHZATT = /* Megahertz AT&T V.34 */ { "Megahertz AT&T V.34", "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4N1&C1&D2\\K5\015", /* wake_str */ #else "ATQ0X4N1\\K5\015", /* wake_str */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT\\N3\015", /* ec_on_str */ "AT\\N0\015", /* ec_off_str */ "AT%C1\"H3\015", /* dc_on_str */ "AT%C0\"H0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "AT\\J0\015", /* sb_on_str */ "AT\\J1\015", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF SUPRASON = /* SupraSonic */ { "Diamond SupraSonic 288V+", /* Diamond Multimedia Systems Inc */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1N1W0X4Y0&S0&C1&D2\015", /* wake_str */ #else #ifdef VMS "ATQ0E1N1W0X4Y0&S1\015", /* wake_str */ #else "ATQ0E1N1W0X4Y0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4\015", /* swfc_str */ "AT&K\015", /* nofc_str */ "AT&Q5\\N3S48=7\015", /* ec_on_str */ "AT&Q0\\N1\015", /* ec_off_str */ "AT%C3S46=138\015", /* dc_on_str */ "AT%C0S46=136\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM\015", /* sp_off_str */ "ATL\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF BESTDATA = /* Best Data */ { "Best Data Fax Modem", /* Best Data Fax Modem */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1N1W0X4Y0&S0&C1&D2\015", /* wake_str */ #else #ifdef VMS "ATQ0E1N1W0X4Y0&S1\015", /* wake_str */ #else "ATQ0E1N1W0X4Y0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4\015", /* swfc_str */ "AT&K\015", /* nofc_str */ "AT&Q6\\N3\015", /* ec_on_str */ "AT&Q0\\N1\015", /* ec_off_str */ "AT%C3\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "AT\\N3\015", /* sb_on_str */ "AT\\N0\015", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF ATT1900 = /* AT&T Secure Data STU III 1900 */ { "AT&T Secure Data STU III Model 1900", /* name */ "", /* pulse command */ "", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4\015", /* wake_str */ #else "ATQ0E1X4\015", /* wake_str */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_on_str */ "", /* sp_off_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 9600L, /* max_speed */ CKD_AT|CKD_SB|CKD_HW, /* capas */ getok /* ok_fn */ }; /* Experimentation showed that hardly any of the documented commands did anything other that print ERROR. At first there was no communication at all at 9600 bps -- turns out the interface speed was stuck at 2400. ATS28=130 (given at 2400 bps) allowed it to work at 9600. */ static MDMINF ATT1910 = /* AT&T Secure Data STU III 1910 */ { /* Adds V.32bis, V.42, V.42bis */ "AT&T Secure Data STU III Model 1910", /* name */ /* Believe it or not, "ATT" and "ATP" result in ERROR */ "", /* pulse command */ "", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0E1V1X4\015", /* wake_str */ #else "ATQ0E1X4\015", /* wake_str */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ #ifdef COMMENT /* These are evidently read-only registers */ "ATS46=138S47=0\015", /* ec_on_str */ "ATS46=138S47=128\015", /* ec_off_str */ "ATS46=138S47=0\015", /* dc_on_str */ "ATS46=138S47=128\015", /* dc_off_str */ #else "", "", "", "", #endif /* COMMENT */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_on_str */ "", /* sp_off_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 9600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW, /* capas */ getok /* ok_fn */ }; static MDMINF KEEPINTOUCH = /* AT&T KeepinTouch Card Modem */ { "AT&T KeepinTouch V.32bis Card Modem", /* Name */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 /* This used to include &C1&S0&D2+Q0 but that gives ERROR */ "ATQ0E1V1X4&S0&C1&D2\\K5\015", /* wake_str */ #else #ifdef VMS "ATQ0E1X4&S1\\K5\015", /* wake_str */ #else "ATQ0E1X4\\K5\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT\\Q3\015", /* hwfc_str */ "AT\\Q1\\X0\015", /* swfc_str */ "AT\\Q0\015", /* nofc_str */ "AT\\N3-J1\015", /* ec_on_str */ "AT\\N1\015", /* ec_off_str */ "AT%C3\"H3\015", /* dc_on_str */ "AT%C0\"H0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "ATN0\\J0\015", /* sb_on_str */ "ATN1\\J1\015", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 57600L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF ROLM_AT = /* Rolm data phone with AT command set */ { "Rolm 244PC or 600 Series with AT Command Set", "", /* pulse command */ "", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATE1Q0V1\015", /* wake_str */ #else "ATQ0\015", /* wake_str */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATDT%s\015", /* dial_str -- always Tone */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "", /* hwfc_str */ "", /* swfc_str */ "", /* nofc_str */ "", /* ec_on_str */ "", /* ec_off_str */ "", /* dc_on_str */ "", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "", /* sb_on_str */ "", /* sb_off_str */ "", /* sp_on_str */ "", /* sp_off_str */ "", /* vol1_str */ "", /* vol2_str */ "", /* vol3_str */ "", /* ignoredt */ "", /* ini2 */ 19200L, /* max_speed */ CKD_AT, /* capas */ getok /* ok_fn */ }; static MDMINF ATLAS = /* Atlas / Newcom ixfC 33.6 */ { "Atlas / Newcom 33600ixfC Data/Fax Modem", /* Name */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATZ0&FQ0V1&C1&D2\015", /* wake_str */ #else "ATZ0&FQ0V1\015", /* wake_str */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT\"H3\015", /* ec_on_str */ "AT\"H0\015", /* ec_off_str */ "AT%C1\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "ATN0\\J0\015", /* sb_on_str */ "ATN1\\J1\015", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF CODEX = { /* Motorola Codex */ "Motorola Codex 326X Series", /* Name - AT&V to see settings */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 /* &M0=Async (not sync) */ /* *MM0=Automatic modulation negotiation */ /* *DE22=Automatic data rate */ "ATZQ0E1V1X4Y0*DE22*MM0&C1&M0&S0&D2\015", /* wake_str */ #else #ifdef VMS "ATZQ0E1V1X4Y0*DE22*MM0&C1&M0&S1\015", /* wake_str */ #else "ATZQ0E1V1X4Y0*DE22*MM0&C1&M0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT*MF1*FL3\015", /* hwfc_str */ "AT*MF1*FL1\015", /* swfc_str */ "AT*MF0*FL0\015", /* nofc_str */ "AT*EC0*SM3*SC0\015", /* ec_on_str */ "AT*SM0\015", /* ec_off_str */ "AT*DC1\015", /* dc_on_str */ "AT*DC0\015", /* dc_off_str */ "AT*AA5S0=1\015", /* aa_on_str */ "AT*AA5S0=0\015", /* aa_off_str */ "AT*SC1\015", /* sb_on_str */ "AT*SC0\015", /* sb_off_str */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3*BD2\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF MT5634ZPX = /* Multitech */ { "Multitech MT5634ZPX", /* name */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATE1Q0V1X4&S0&C1&D2&Q0\015", /* wake_str */ #else #ifdef VMS "ATQ0E1X4&S1&Q0\015", /* wake_str */ #else "ATQ0E1X4&Q0\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT&K3\015", /* hwfc_str */ "AT&K4\015", /* swfc_str */ "AT&K0\015", /* nofc_str */ "AT\\N3\015", /* ec_on_str */ "AT\\N1\015", /* ec_off_str */ "AT%C1\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "AT\\J0\015", /* sb_on_str */ "AT\\J1\015", /* sb_off_str (NOT SUPPORTED) */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; static MDMINF MOTSM56 = /* Motorola SM56 Chipset */ { "Motorola SM56 V.90 chipset", /* name */ "ATP\015", /* pulse command */ "ATT\015", /* tone command */ 35, /* dial_time */ ",", /* pause_chars */ 2, /* pause_time */ #ifdef OS2 "ATQ0V1X4&S0&C1&D2*MM16\015", /* wake_str */ #else #ifdef VMS "ATQ0V1X4&S1&C1&D2*MM16\015", /* wake_str */ #else "ATQ0V1X4&C1&D2*MM16\015", /* wake_str */ #endif /* VMS */ #endif /* OS2 */ 0, /* wake_rate */ "OK\015", /* wake_prompt */ "", /* dmode_str */ "", /* dmode_prompt */ "ATD%s\015", /* dial_str */ 0, /* dial_rate */ 1100, /* esc_time */ 43, /* esc_char */ "ATQ0H0\015", /* hup_str */ "AT\\Q3\015", /* hwfc_str */ "AT\\Q1\015", /* swfc_str */ "AT\\Q0\015", /* nofc_str */ "AT\\N7\015", /* ec_on_str */ "AT\\N1\015", /* ec_off_str */ "AT%C1\015", /* dc_on_str */ "AT%C0\015", /* dc_off_str */ "ATS0=1\015", /* aa_on_str */ "ATS0=0\015", /* aa_off_str */ "AT\\J0\015", /* sb_on_str */ "AT\\J1\015", /* sb_off_str (NOT SUPPORTED) */ "ATM1\015", /* sp_on_str */ "ATM0\015", /* sp_off_str */ "ATL1\015", /* vol1_str */ "ATL2\015", /* vol2_str */ "ATL3\015", /* vol3_str */ "ATX3\015", /* ignoredt */ "", /* ini2 */ 115200L, /* max_speed */ CKD_AT|CKD_SB|CKD_EC|CKD_DC|CKD_HW|CKD_SW, /* capas */ getok /* ok_fn */ }; #endif /* MINIDIAL */ /* END MDMINF STRUCT DEFINITIONS */ /* Table to convert modem numbers to MDMINF struct pointers. The entries MUST be in ascending order by modem number, without any "gaps" in the numbers, and starting from one (1). */ MDMINF *modemp[] = { #ifdef MINIDIAL NULL, /* 0 */ &CCITT, /* 1 */ &HAYES, /* 2 */ &UNKNOWN, /* 3 */ &DUMMY, /* 4 */ &GENERIC, /* 5 */ &ITUTV250 /* 6 */ #else /* Not MINIDIAL */ NULL, /* 0 */ &ATTDTDM, /* 1 */ &ATTISN, /* 2 */ &ATTMODEM, /* 3 */ &CCITT, /* 4 */ #ifdef OLDMODEMS &CERMETEK, /* 5 */ &DF03, /* 6 */ &DF100, /* 7 */ &DF200, /* 8 */ &GDC, /* 9 */ #else NULL, NULL, NULL, NULL, NULL, #endif /* OLDMODEMS */ &HAYES, /* 10 */ #ifdef OLDMODEMS &PENRIL, /* 11 */ &RACAL, /* 12 */ #else NULL, NULL, #endif /* OLDMODEMS */ &UNKNOWN, /* 13 */ #ifdef OLDMODEMS &VENTEL, /* 14 */ &CONCORD, /* 15 */ #else NULL, NULL, #endif /* OLDMODEMS */ &DUMMY, /* 16 */ &ROLM, /* 17 */ #ifdef OLDMODEMS &MICROCOM, /* 18 */ #else NULL, #endif /* OLDMODEMS */ &USR, /* 19 USR Courier and Sportster */ &OLDTB, /* 20 Old Telebits */ &DIGITEL, /* 21 Digitel CCITT */ &H_1200, /* 22 Hayes 1200 */ &H_ULTRA, /* 23 Hayes Ultra */ &H_ACCURA, /* 24 Hayes Optima */ &PPI, /* 25 PPI */ &DATAPORT, /* 26 Dataport */ &BOCA, /* 27 Boca */ &MOTOROLA, /* 28 Motorola UDS MOTOROLA */ NULL, /* 29 Digicomm */ NULL, /* 30 Dynalink */ &INTEL, /* 31 Intel */ &UCOM_AT, /* 32 Microcom in AT mode */ &MULTITECH, /* 33 Multitech */ &SUPRA, /* 34 Supra */ &ZOLTRIX, /* 35 Zoltrix */ &ZOOM, /* 36 Zoom */ &ZYXEL, /* 37 ZyXEL */ &DUMMY, /* 38 TAPI */ &NEWTB, /* 39 New-Telebit */ &MAXTECH, /* 40 MaxTech */ &DUMMY, /* 41 User-defined */ &RWV32, /* 42 Rockwell V.32 */ &RWV32B, /* 43 Rockwell V.32bis */ &RWV34, /* 44 Rockwell V.34 */ &MWAVE, /* 45 IBM Mwave */ &TELEPATH, /* 46 Gateway 2000 Telepath II 28.8 */ &MICROLINK, /* 47 MicroLink modems */ &CARDINAL, /* 48 Cardinal */ &GENERIC, /* 49 Generic high-speed */ &XJACK, /* 50 Megahertz-Xjack */ &SPIRITII, /* 51 QuickComm Spirit II */ &MONTANA, /* 52 Motorola Montana */ &COMPAQ, /* 53 Compaq Data+Fax */ &FUJITSU, /* 54 Fujitsu */ &MHZATT, /* 55 Megahertz AT&T V.34 */ &SUPRASON, /* 56 Suprasonic */ &BESTDATA, /* 57 Best Data */ &ATT1900, /* 58 AT&T Secure Data STU III 1900 */ &ATT1910, /* 59 AT&T Secure Data STU III 1910 */ &KEEPINTOUCH, /* 60 AT&T KeepinTouch */ &USRX2, /* 61 USR XJ-1560 X2 */ &ROLM_AT, /* 62 Rolm with AT command set */ &ATLAS, /* 63 Atlas / Newcom */ &CODEX, /* 64 Motorola Codex */ &MT5634ZPX, /* 65 Multitech MT5634ZPX */ &ULINKV250, /* 66 Microlink V.250 56K */ &ITUTV250, /* 67 Generic ITU-T V.250 */ &RWV90, /* 68 Rockwell V.90 56K */ &SUPRAX, /* 69 Diamond Supra Express V.90 */ &LUCENT, /* 70 Lucent Venus chipset */ &PCTEL, /* 71 PCTel */ &CONEXANT, /* 72 Conexant */ &ZOOMV34, /* 73 Zoom V.34 */ &ZOOMV90, /* 74 Zoom V.90 */ &ZOOMV92, /* 75 Zoom V.92 */ &MOTSM56 /* 76 Motorola SM56 chipset */ #endif /* MINIDIAL */ }; /* * Declare modem names and associated numbers for command parsing, * and also for doing number-to-name translation. * * The entries must be in alphabetical order by modem name. */ struct keytab mdmtab[] = { #ifndef MINIDIAL "3com-usr-megahertz-56k", n_USRX2, CM_INV, "acer-v90", n_RWV90, M_ALIAS, "atlas-newcom-33600ifxC", n_ATLAS, 0, "att-1900-stu-iii", n_ATT1900, 0, "att-1910-stu-iii", n_ATT1910, 0, "att-7300", n_ATTUPC, 0, "att-dataport", n_DATAPORT, 0, "att-dtdm", n_ATTDTDM, 0, "att-isn", n_ATTISN, 0, "att-keepintouch", n_KEEPINTOUCH, 0, "att-switched-net", n_ATTMODEM, 0, "att7300", n_ATTUPC, CM_INV, /* old name */ "attdtdm", n_ATTDTDM, CM_INV, /* old name */ "attisn", n_ATTISN, CM_INV, /* old name */ "attmodem", n_ATTMODEM, CM_INV, /* old name */ "bestdata", n_BESTDATA, 0, "boca", n_BOCA, 0, "cardinal", n_CARDINAL, 0, #endif /* MINIDIAL */ "ccitt-v25bis", n_CCITT, CM_INV, /* Name changed to ITU-T */ #ifndef MINIDIAL #ifdef OLDMODEMS "cermetek", n_CERMETEK, M_OLD, #endif /* OLDMODEMS */ "compaq", n_COMPAQ, 0, #ifdef OLDMODEMS "concord", n_CONCORD, M_OLD, #endif /* OLDMODEMS */ "conexant", n_CONEXANT, 0, "courier", n_USR, CM_INV, "dataport", n_DATAPORT, CM_INV, /* == att-dataport */ #ifdef OLDMODEMS "df03-ac", n_DF03, M_OLD, "df100-series", n_DF100, M_OLD, "df200-series", n_DF200, M_OLD, #endif /* OLDMODEMS */ "digitel-dt22", n_DIGITEL, 0, #endif /* MINIDIAL */ "direct", 0, CM_INV, /* Synonym for NONE */ #ifndef MINIDIAL "fujitsu", n_FUJITSU, 0, "gateway-telepath", n_TELEPATH, 0, #ifdef OLDMODEMS "gdc-212a/ed", n_GDC, M_OLD, "ge", n_GENERIC, CM_INV|CM_ABR, "gen", n_GENERIC, CM_INV|CM_ABR, "gendatacomm", n_GDC, CM_INV, /* Synonym for GDC */ #endif /* OLDMODEMS */ #endif /* MINIDIAL */ "gene", n_GENERIC, CM_INV|CM_ABR, "generic", n_GENERIC, 0, "generic-high-speed",n_GENERIC, CM_INV, "h", n_HAYES, CM_INV|CM_ABR, "ha", n_HAYES, CM_INV|CM_ABR, "hay", n_HAYES, CM_INV|CM_ABR, "haye", n_HAYES, CM_INV|CM_ABR, "hayes", n_HAYES, CM_INV|CM_ABR, /* Hayes 2400 */ #ifndef MINIDIAL "hayes-1200", n_H_1200, 0, #endif /* MINIDIAL */ "hayes-2400", n_HAYES, 0, #ifndef MINIDIAL "hayes-high-speed", n_H_ACCURA, 0, "hayes-accura", n_H_ACCURA, CM_INV, "hayes-optima", n_H_ACCURA, CM_INV, "hayes-ultra", n_H_ULTRA, CM_INV, "hst-courier", n_USR, CM_INV, /* Synonym for COURIER */ "intel", n_INTEL, 0, #endif /* MINIDIAL */ "itu-t-v250", n_ITUTV250, 0, "itu-t-v25bis", n_CCITT, 0, /* New name for CCITT */ "itu-t-v25ter/v250",n_ITUTV250, CM_INV, #ifndef MINIDIAL "lucent", n_LUCENT, 0, "maxtech", n_MAXTECH, 0, "megahertz-att-v34", n_MHZATT, 0, /* Megahertzes */ "megahertz-xjack", n_XJACK, CM_INV|CM_ABR, "megahertz-xjack-33.6", n_XJACK, 0, "megahertz-xjack-56k", n_USRX2, 0, /* 3COM/USR/Megahertz 33.6 PC Card */ "mi", n_MICROCOM, CM_INV|CM_ABR, "mic", n_MICROCOM, CM_INV|CM_ABR, "micr", n_MICROCOM, CM_INV|CM_ABR, "micro", n_MICROCOM, CM_INV|CM_ABR, "microc", n_MICROCOM, CM_INV|CM_ABR, "microco", n_MICROCOM, CM_INV|CM_ABR, "microcom", n_MICROCOM, CM_INV|CM_ABR, "microcom-at-mode", n_UCOM_AT, 0, /* Microcom DeskPorte, etc */ "microcom-sx-mode", n_MICROCOM, 0, /* Microcom AX,QX,SX, native mode */ "microlink", n_MICROLINK, 0, "microlink-v250", n_ULINKV250, 0, "motorola-codex", n_CODEX, 0, "motorola-fastalk", n_MOTOROLA, 0, "motorola-lifestyle",n_MOTOROLA, 0, "motorola-montana", n_MONTANA, 0, "motorola-sm56-v90",n_MOTSM56, 0, "mt5634zpx", n_MT5634ZPX, 0, "multitech", n_MULTI, 0, "mwave", n_MWAVE, 0, #endif /* MINIDIAL */ "none", 0, 0, #ifndef MINIDIAL #ifndef OLDTBCODE "old-telebit", n_TELEBIT, 0, #endif /* OLDTBCODE */ "pctel", n_PCTEL, 0, #ifdef OLDMODEMS "penril", n_PENRIL, M_OLD, #endif /* OLDMODEMS */ "ppi", n_PPI, 0, #ifdef OLDMODEMS "racalvadic", n_RACAL, M_OLD, #endif /* OLDMODEMS */ "rockwell-v32", n_RWV32, 0, "rockwell-v32bis", n_RWV32B, 0, "rockwell-v34", n_RWV34, 0, "rockwell-v90", n_RWV90, 0, "rolm", n_ROLM, CM_INV|CM_ABR, "rolm-244pc", n_ROLMAT, 0, "rolm-600-series", n_ROLMAT, 0, "rolm-dcm", n_ROLM, 0, "smartlink-v90", n_USR, M_ALIAS, "spirit-ii", n_SPIRITII, 0, "sportster", n_USR, M_ALIAS, "sup", n_SUPRA, CM_INV|CM_ABR, "supr", n_SUPRA, CM_INV|CM_ABR, "supra", n_SUPRA, CM_INV|CM_ABR, "supra-express-v90",n_SUPRAX, 0, "suprafaxmodem", n_SUPRA, 0, "suprasonic", n_SUPRASON, 0, #ifdef CK_TAPI "tapi", n_TAPI, 0, #endif /* CK_TAPI */ "te", n_TBNEW, CM_INV|CM_ABR, "tel", n_TBNEW, CM_INV|CM_ABR, "telebit", n_TBNEW, 0, "telepath", n_TELEPATH, CM_INV, #endif /* MINIDIAL */ "unknown", n_UNKNOWN, 0, "user-defined", n_UDEF, 0, #ifndef MINIDIAL "usr", n_USR, CM_INV|CM_ABR, "usr-212a", n_HAYES, CM_INV|M_ALIAS, "usr-courier", n_USR, CM_INV, "usr-megahertz-56k", n_USRX2, 0, "usr-sportster", n_USR, CM_INV, "usr-xj1560-x2", n_USRX2, CM_INV, "usrobotics", n_USR, 0, "v25bis", n_CCITT, CM_INV, /* Name changed to ITU-T */ #ifdef OLDMODEMS "ventel", n_VENTEL, M_OLD, #endif /* OLDMODEMS */ "zoltrix-v34", n_ZOLTRIX, 0, "zoltrix-hsp-v90", n_PCTEL, M_ALIAS, "zoltrix-hcf-v90", n_ITUTV250, 0, "zoo", n_ZOOM, CM_INV|CM_ABR, "zoom", n_ZOOM, CM_INV|CM_ABR, "zoom-v32bis", n_ZOOM, 0, "zoom-v34", n_ZOOMV34, 0, "zoom-v90", n_ZOOMV90, 0, "zoom-v92", n_ZOOMV92, 0, "zyxel", n_ZYXEL, 0, #endif /* MINIDIAL */ "", 0, 0 }; int nmdm = (sizeof(mdmtab) / sizeof(struct keytab)) - 1; /* Number of modems */ #define CONNECTED 1 /* For completion status */ #define D_FAILED 2 #define D_PARTIAL 3 static int tries = 0; static int mdmecho = 0; /* Assume modem does not echo */ static char *p; /* For command strings & messages */ #define LBUFL 200 static char lbuf[LBUFL+4]; char modemmsg[LBUFL+4] = { NUL, NUL }; /* DIAL response from modem */ #ifdef DYNAMIC #define RBUFL 256 static char *rbuf = NULL; #else #define RBUFL 63 static char rbuf[RBUFL+1]; #endif /* DYNAMIC */ #ifdef DYNAMIC #define FULLNUML 256 char *fbuf = NULL; /* For full (prefixed) phone number */ #else #define FULLNUML 100 char fbuf[FULLNUML]; #endif /* DYNAMIC */ static ckjmpbuf sjbuf; #ifdef CK_ANSIC static SIGTYP (*savalrm)(int); /* For saving alarm handler */ static SIGTYP (*savint)(int); /* For saving interrupt handler */ #else static SIGTYP (*savalrm)(); /* For saving alarm handler */ static SIGTYP (*savint)(); /* For saving interrupt handler */ #endif /* CK_ANSIC */ #ifdef CKLOGDIAL static VOID #ifdef CK_ANSIC dologdial( char *s ) #else dologdial(s) char *s; #endif /* CK_ANSIC */ { char buf2[16]; char * r = NULL; int x, m, n; extern char cxlogbuf[], uidbuf[], myhost[]; if (!s) s = ""; if ((x = strlen(s)) > 0) { /* Replace spaces by underscores */ r = (char *)malloc(x+1); if (r) { int i; for (i = 0; i <= x; i++) { if (s[i] != 0 && s[i] <= SP) r[i] = '_'; else r[i] = s[i]; } s = r; } } p = ckdate(); n = ckstrncpy(cxlogbuf,p,CXLOGBUFL); if (!uidbuf[0]) { debug(F100,"dologdial uidbuf empty","",0); ckstrncpy(uidbuf,(char *)whoami(),UIDBUFLEN); } m = strlen(uidbuf)+strlen(myhost)+strlen(ttname)+strlen(s)+strlen(buf2)+32; if (n+m < CXLOGBUFL-1) { p = cxlogbuf+n; if (diallcc && diallac) { buf2[0] = '+'; ckmakmsg(&buf2[1],15,diallcc,"(",diallac,")"); } else { ckstrncpy(buf2,"Unknown",16); } sprintf(p," %s %s T=DIAL H=%s D=%s N=%s O=%s ", /* safe (prechecked) */ uidbuf, ckgetpid(), myhost, ttname, s, buf2 ); debug(F110,"dologdial cxlogbuf",cxlogbuf,0); } else sprintf(p,"LOGDIAL BUFFER OVERFLOW"); if (r) free(r); } #endif /* CKLOGDIAL */ #ifndef MINIDIAL #ifdef COMMENT static VOID xcpy(to,from,len) /* Copy the given number of bytes */ register char *to, *from; register unsigned int len; { while (len--) *to++ = *from++; } #endif /* COMMENT */ #endif /* MINIDIAL */ static SIGTYP #ifdef CK_ANSIC dialtime(int foo) /* Timer interrupt handler */ #else dialtime(foo) int foo; /* Timer interrupt handler */ #endif /* CK_ANSIC */ /* dialtime */ { fail_code = F_TIME; /* Failure reason = timeout */ debug(F100,"dialtime caught SIGALRM","",0); #ifdef BEBOX #ifdef BE_DR_7 alarm_expired(); #endif /* BE_DR_7 */ #endif /* BEBOX */ #ifdef OS2 signal(SIGALRM, dialtime); #endif /* OS2 */ #ifdef __EMX__ signal(SIGALRM, SIG_ACK); /* Needed for OS/2 */ #endif /* __EMX__ */ #ifdef OSK /* OS-9 */ /* We are in an intercept routine but do not perform a F$RTE (done implicitly by RTS), so we have to decrement the sigmask as F$RTE does. Warning: longjump only restores the CPU registers, NOT the FPU registers. So, don't use FPU at all or at least don't use common FPU (double or float) register variables. */ sigmask(-1); #endif /* OSK */ #ifdef NTSIG if (foo == SIGALRM) PostAlarmSigSem(); else PostCtrlCSem(); #else /* NTSIG */ #ifdef NT cklongjmp(ckjaddr(sjbuf),1); #else /* NT */ cklongjmp(sjbuf,1); #endif /* NT */ #endif /* NTSIG */ /* NOTREACHED */ SIGRETURN; } static SIGTYP #ifdef CK_ANSIC dialint(int foo) /* Keyboard interrupt handler */ #else dialint(foo) int foo; #endif /* CK_ANSIC */ /* dialint */ { fail_code = F_INT; debug(F100,"dialint caught SIGINT","",0); #ifdef OS2 signal(SIGINT, dialint); debug(F100,"dialint() SIGINT caught -- dialint restored","",0) ; #endif /* OS2 */ #ifdef __EMX__ signal(SIGINT, SIG_ACK); /* Needed for OS/2 */ #endif /* __EMX__ */ #ifdef OSK /* OS-9, see comment in dialtime() */ sigmask(-1); #endif /* OSK */ #ifdef NTSIG PostCtrlCSem() ; #ifdef CK_TAPI PostTAPIConnectSem(); PostTAPIAnswerSem(); #endif /* CK_TAPI */ #else /* NTSIG */ #ifdef NT cklongjmp(ckjaddr(sjbuf),1); #else /* NT */ cklongjmp(sjbuf,1); #endif /* NT */ #endif /* NT */ SIGRETURN; } /* Routine to read a character from communication device, handling TELNET protocol negotiations in case we're connected to the modem through a TCP/IP TELNET modem server. */ static int #ifdef CK_ANSIC ddinc( int n ) #else ddinc(n) int n; #endif /* CK_ANSIC */ { #ifdef TNCODE int c = 0; int done = 0; debug(F101,"ddinc entry n","",n); while (!done) { c = ttinc(n); /* debug(F000,"ddinc","",c); */ if (c < 0) return(c); #ifndef OS2 if ((c == IAC) && network && IS_TELNET()) { switch (tn_doop((CHAR)(c & 0xff),duplex,ttinc)) { case 2: duplex = 0; continue; case 1: duplex = 1; default: continue; } } else done = 1; #else /* OS2 */ done = !(c == IAC && network && IS_TELNET()); scriptwrtbuf(c); /* TELNET negotiations handled by emulator */ #endif /* OS2 */ } return(c & 0xff); #else /* TNCODE */ return(ttinc(n)); #endif /* TNCODE */ } static VOID #ifdef CK_ANSIC ttslow( char *s, int millisec ) /* Output s-l-o-w-l-y */ #else ttslow(s,millisec) char *s; int millisec; #endif /* CK_ANSIC */ { #ifdef TCPSOCKET extern int tn_nlm, tn_b_nlm; #endif /* TCPSOCKET */ debug(F111,"ttslow",s,millisec); if (dialdpy && (duplex || !mdmecho)) { /* Echo the command in case modem */ printf("%s\n",s); /* isn't echoing commands. */ #ifdef OS2 { char *s2 = s; /* Echo to emulator */ while (*s2) { scriptwrtbuf((USHORT)*s2++); } scriptwrtbuf((USHORT)CK_CR); scriptwrtbuf((USHORT)LF); } #endif /* OS2 */ } for (; *s; s++) { ttoc(*s); #ifdef TCPSOCKET if (*s == CK_CR && network && IS_TELNET()) { if (!TELOPT_ME(TELOPT_BINARY) && tn_nlm != TNL_CR) ttoc((char)((tn_nlm == TNL_CRLF) ? LF : NUL)); else if (TELOPT_ME(TELOPT_BINARY) && (tn_b_nlm == TNL_CRLF || tn_b_nlm == TNL_CRNUL)) ttoc((char)((tn_b_nlm == TNL_CRLF) ? LF : NUL)); } #endif /* TCPSOCKET */ if (millisec > 0) msleep(millisec); } } /* * Wait for a string of characters. * * The characters are waited for individually, and other characters may * be received "in between". This merely guarantees that the characters * ARE received, and in the order specified. */ static VOID #ifdef CK_ANSIC waitfor( char *s ) #else waitfor(s) char *s; #endif /* CK_ANSIC */ { CHAR c, x; while ((c = *s++)) { /* while more characters remain... */ do { /* wait for the character */ x = (CHAR) (ddinc(0) & 0177); debug(F000,"dial waitfor got","",x); if (dialdpy) { if (x != LF) conoc(x); if (x == CK_CR) conoc(LF); } } while (x != c); } } static int #ifdef CK_ANSIC didweget( char *s, char *r ) /* Looks in string s for response r */ #else didweget(s,r) char *s, *r; #endif /* CK_ANSIC */ { int lr = (int)strlen(r); /* 0 means not found, 1 means found it */ int i; debug(F110,"didweget",r,0); debug(F110," in",s,0); for (i = (int)strlen(s)-lr; i >= 0; i--) if ( s[i] == r[0] ) if ( !strncmp(s+i,r,lr) ) return( 1 ); return( 0 ); } /* R E S E T -- Reset alarms, etc. on exit. */ static VOID dreset() { debug(F100,"dreset resetting alarm and signal handlers","",0); alarm(0); signal(SIGALRM,savalrm); /* restore alarm handler */ signal(SIGINT,savint); /* restore interrupt handler */ debug(F100,"dreset alarm and signal handlers reset","",0); } /* Call this routine when the modem reports that it has connected at a certain speed, giving that speed as the argument. If the connection speed is not the same as Kermit's current communication speed, AND the modem interface speed is not locked (i.e. DIAL SPEED-MATCHING is not ON), then change the device speed to the one given. */ static VOID #ifdef CK_ANSIC spdchg(long s) #else spdchg(s) long s; #endif /* CK_ANSIC */ /* spdchg */ { int s2; if (!mdmspd) /* If modem interface speed locked, */ return; /* don't do this. */ if (speed != s) { /* Speeds differ? */ s2 = s / 10L; /* Convert to cps expressed as int */ if (ttsspd(s2) < 0) { /* Change speed. */ printf(" WARNING - speed change to %ld failed.\r\n",s); } else { printf(" Speed changed to %ld.\r\n",s); speed = s; /* Update global speed variable */ } } } /* Display all characters received from modem dialer through this routine, for consistent handling of carriage returns and linefeeds. */ static VOID #ifdef CK_ANSIC dialoc(char c) #else dialoc(c) char c; #endif /* CK_ANSIC */ { /* dialoc */ /* Dial Output Character */ if (dialdpy) { if (c != LF) conoc(c); /* Don't echo LF */ if (c == CK_CR) conoc(LF); /* Echo CR as CRLF */ } } #ifndef NOSPL char * #ifdef CK_ANSIC getdm( int x ) /* Return dial modifier */ #else getdm(x) int x; #endif /* CK_ANSIC */ { MDMINF * mp; int m; int ishayes = 0; m = mdmtyp; if (m < 1) if (mdmsav > -1) m = mdmsav; if (m < 1) return(""); #ifndef MINIDIAL if (m == n_TAPI) m = n_HAYES; #endif /* MINIDIAL */ mp = modemp[m]; ishayes = (dialcapas ? dialcapas : mp->capas) & CKD_AT; switch (x) { case VN_DM_LP: return(ishayes ? "," : ""); case VN_DM_SP: #ifdef MINIDIAL return(""); #else return(m == n_USR ? "/" : ""); #endif /* MINIDIAL */ case VN_DM_PD: return(ishayes ? "P" : ""); case VN_DM_TD: return(ishayes ? "T" : ""); case VN_DM_WA: return(ishayes ? "@" : ""); case VN_DM_WD: return(ishayes ? "W" : ""); case VN_DM_RC: return(ishayes ? ";" : ""); case VN_DM_HF: return(ishayes ? "!" : ""); case VN_DM_WB: return(ishayes ? "$" : ""); } return(""); } #endif /* NOSPL */ static VOID getdialmth() { if (dialmauto && diallcc) { /* If DIAL METHOD AUTO... */ int i; /* and we know our area code... */ for (i = 0; i < ndialtocc; i++) { /* First check Tone countries list */ if (!strcmp(dialtocc[i],diallcc)) { dialmth = XYDM_T; break; } } for (i = 0; i < ndialpucc; i++) { /* Then Pulse countries list */ if (!strcmp(dialpucc[i],diallcc)) { dialmth = XYDM_P; break; } } } } VOID /* Get dialing defaults from environment */ getdialenv() { char *p = NULL; int i, x; makestr(&p,getenv("K_DIAL_DIRECTORY")); if (p) { int i; xwords(p,(MAXDDIR - 2),dialdir,0); for (i = 0; i < (MAXDDIR - 1); i++) { if (!dialdir[i+1]) break; else dialdir[i] = dialdir[i+1]; } ndialdir = i; } xmakestr(&diallcc,getenv("K_COUNTRYCODE")); /* My country code */ xmakestr(&dialixp,getenv("K_LD_PREFIX")); /* My long-distance prefix */ xmakestr(&dialldp,getenv("K_INTL_PREFIX")); /* My international prefix */ xmakestr(&dialldp,getenv("K_TF_PREFIX")); /* Ny Toll-free prefix */ #ifndef NOICP p = getenv("K_DIAL_METHOD"); /* Local dial method */ if (p) if (*p) { extern struct keytab dial_m[]; extern int ndial_m; i = lookup(dial_m,p,ndial_m,&x); if (i > -1) { if (i == XYDM_A) { dialmauto = 1; dialmth = XYDM_D; } else { dialmauto = 0; dialmth = i; } } } #endif /* NOICP */ p = NULL; xmakestr(&p,getenv("K_TF_AREACODE")); /* Toll-free areacodes */ if (p) { int i; xwords(p,7,dialtfc,0); for (i = 0; i < 8; i++) { if (!dialtfc[i+1]) break; else dialtfc[i] = dialtfc[i+1]; } ntollfree = i; free(p); } for (i = 0; i < MAXTPCC; i++) { /* Clear Tone/Pulse country lists */ dialtocc[i] = NULL; dialpucc[i] = NULL; } for (i = 0; i < MAXTPCC; i++) { /* Init Tone country list */ if (tonecc[i]) makestr(&(dialtocc[i]),tonecc[i]); else break; } ndialtocc = i; for (i = 0; i < MAXTPCC; i++) { /* Init Pulse country list */ if (pulsecc[i]) makestr(&(dialpucc[i]),pulsecc[i]); else break; } ndialpucc = i; if (diallcc) { /* Have country code */ if (!strcmp(diallcc,"1")) { /* If it's 1 */ if (!dialldp) /* Set these prefixes... */ makestr(&dialldp,"1"); if (!dialtfp) makestr(&dialtfp,"1"); if (!dialixp) makestr(&dialixp,"011"); if (ntollfree == 0) { /* Toll-free area codes */ if ((dialtfc[0] = malloc(4))) { ckstrncpy(dialtfc[0],"800",4); /* 1970-something */ ntollfree++; if ((dialtfc[1] = malloc(4))) { ckstrncpy(dialtfc[1],"888",4); /* 1996 */ ntollfree++; if ((dialtfc[2] = malloc(4))) { ckstrncpy(dialtfc[2],"877",4); /* 5 April 1998 */ ntollfree++; if ((dialtfc[3] = malloc(4))) { ckstrncpy(dialtfc[3],"866",4); /* 2000? */ ntollfree++; } } } } } } else if (!strcmp(diallcc,"358") && ((int) strcmp(zzndate(),"19961011") > 0) ) { /* Finland */ if (!dialldp) /* Long-distance prefix */ makestr(&dialldp,"9"); if (!dialixp) /* International dialing prefix */ makestr(&dialixp,"990"); } else { /* Not NANP or Finland */ if (!dialldp) makestr(&dialldp,"0"); if (!dialixp) makestr(&dialixp,"00"); } } xmakestr(&diallac,getenv("K_AREACODE")); xmakestr(&dialpxo,getenv("K_PBX_OCP")); xmakestr(&dialpxi,getenv("K_PBX_ICP")); p = getenv("K_PBX_XCH"); #ifdef COMMENT xmakestr(&dialpxx,p); #else if (p) if (*p) { char * s = NULL; char * pp[MAXPBXEXCH+2]; makestr(&s,p); /* Make a copy for poking */ if (s) { xwords(s,MAXPBXEXCH+1,pp,0); /* Note: pp[] is 1-based. */ for (i = 0; i <= MAXPBXEXCH; i++) { if (!pp[i+1]) break; makestr(&(dialpxx[i]),pp[i+1]); ndialpxx++; } makestr(&s,NULL); /* Free poked copy */ } } #endif /* COMMENT */ } static int #ifdef CK_ANSIC dialfail( int x ) #else dialfail(x) int x; #endif /* CK_ANSIC */ { char * s; fail_code = x; debug(F101,"ckudial dialfail","",x); dreset(); /* Reset alarm and signal handlers */ printf("%s Failure: ", func_code == 0 ? "DIAL" : "ANSWER"); if (dialdpy) { /* If showing progress */ debug(F100,"dial display is on","",0); p = ck_time(); /* get current time; */ if (*p) printf("%s: ",p); } switch (fail_code) { /* Type of failure */ case F_TIME: /* Timeout */ if (dial_what == DW_INIT) printf ("Timed out while trying to initialize modem.\n"); else if (dial_what == DW_DIAL) printf ("%s interval expired.\n", func_code == 0 ? "DIAL TIMEOUT" : "ANSWER timeout"); else printf("Timeout.\n"); fflush(stdout); if (mdmcapas & CKD_AT) ttoc('\015'); /* Send CR to interrupt dialing */ /* Some Hayes modems don't fail with BUSY on busy lines */ dialsta = DIA_TIMO; debug(F110,"dial","timeout",0); break; case F_INT: /* Dialing interrupted */ printf ("Interrupted.\n"); fflush(stdout); #ifndef NOXFER interrupted = 1; #endif /* NOXFER */ debug(F111,"dial","interrupted",mdmcapas & CKD_AT); if (mdmcapas & CKD_AT) ttoc('\015'); /* Send CR to interrupt dialing */ dialsta = DIA_INTR; break; case F_MODEM: /* Modem detected a failure */ debug(F110,"dialfail()","lbuf",0); if (strlen(lbuf) > 0) { /* was (lbuf && *lbuf) */ printf(" \""); for (s = lbuf; *s; s++) if (isprint(*s)) putchar(*s); /* Display printable reason */ printf ("\""); } else printf(func_code == 0 ? " Call not completed." : " Call did not come in." ); printf("\n"); debug(F110,"dial",lbuf,0); if (dialsta < 0) dialsta = DIA_UNSP; break; case F_MINIT: /* Failure to initialize modem */ printf ("Error initializing modem.\n"); debug(F110,"dial","modem init",0); dialsta = DIA_NOIN; break; default: printf("unknown\n"); debug(F110,"dial","unknown",0); fflush(stdout); if (mdmcapas & CKD_AT) ttoc('\015'); /* Send CR to interrupt dialing */ dialsta = DIA_INTR; } #ifdef DYNAMIC if (rbuf) free(rbuf); rbuf = NULL; if (fbuf) free(fbuf); fbuf = NULL; #endif /* DYNAMIC */ if (dialsta < 0) dialsta = DIA_UERR; /* Set failure code */ return(0); /* Return zero (important) */ } /* C K D I A L -- Dial up the remote system */ /* Returns 1 if call completed, 0 otherwise */ static int mdmwait, mdmstat = 0; #ifndef CK_TAPI static #endif /* CK_TAPI */ int waitct; int mdmwaitd = 10 ; /* dialtmo / mdmwait difference */ static char c; static char *telnbr; static int wr = 0; /* wr = wake rate */ static char * ws; /* ws = wake string */ static char * xnum = NULL; static int inited = 0; static SIGTYP #ifdef CK_ANSIC _dodial(void * threadinfo) #else /* CK_ANSIC */ _dodial(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ /* _dodial */ { char c2; char *dcmd, *s, *flocmd = NULL; int x = 0, n = F_TIME; #ifdef NTSIG signal( SIGINT, dialint ); if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); } #endif /* NTSIG */ dcmd = dialcmd ? dialcmd : mp->dial_str; if ((int)strlen(dcmd) + (int)strlen(telnbr) > (LBUFL - 2)) { printf("DIAL command + phone number too long!\n"); dreset(); #ifdef DYNAMIC if (rbuf) free(rbuf); rbuf = NULL; if (fbuf) free(fbuf); fbuf = NULL; #endif /* DYNAMIC */ #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; /* No conversation with modem to complete dialing */ } makestr(&xnum,telnbr); getdialmth(); /* Get dial method */ #ifdef CK_ATDT /* Combine the SET DIAL METHOD command with the DIAL command string */ if (!dialcmd && /* Using default DIAL command */ (mdmcapas & CKD_AT) && /* AT command set only */ ((dialmth == XYDM_T && !dialtone) || /* and using default */ (dialmth == XYDM_P && !dialpulse))) { /* modem commands... */ char c; debug(F110,"dial atdt xnum 1",xnum,0); s = dcmd; debug(F110,"dial atdt s",s,0); if (*telnbr != 'T' && *telnbr != 'P' && *telnbr != 't' && *telnbr != 'p' && !ckstrcmp(s,"atd",3,0) && s[3] != 'T' && s[3] != 'P' && s[3] != 't' && s[3] != 'p') { char xbuf[200]; c = (dialmth == XYDM_T) ? 'T' : 'P'; if (islower(s[0])) c = tolower(c); if ((int)strlen(telnbr) < 199) { sprintf(xbuf,"%c%s",c,telnbr); makestr(&xnum,xbuf); } } } #endif /* CK_ATDT */ debug(F111,"_dodial",xnum,xredial); /* Hang up the modem (in case it wasn't "on hook") */ /* But only if SET DIAL HANGUP ON... */ if (!xredial) { /* Modem not initalized yet. */ inited = 0; } if (!xredial || !inited) { if (dialhup() < 0) { /* Hangup first */ debug(F100,"_dodial dialhup failed","",0); #ifndef MINIDIAL if (mdmcapas & CKD_TB) /* Telebits might need a BREAK */ ttsndb(); /* first. */ #endif /* MINIDIAL */ if (dialhng && dialsta != DIA_PART) { /* If hangup failed, */ ttclos(0); /* close and reopen the device. */ if (ttopen(ttname,&local,mymdmtyp,0) < 0) { printf("Sorry, Can't hang up communication device.\n"); printf("Try 'set line %s' again.\n",ttname); dialsta = DIA_HANG; #ifdef DYNAMIC if (rbuf) free(rbuf); rbuf = NULL; if (fbuf) free(fbuf); fbuf = NULL; #endif /* DYNAMIC */ dreset(); #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; } } } inited = 0; /* We hung up so must reinit */ } #ifndef MINIDIAL /* Don't start talking to Rolm too soon */ if (mymdmtyp == n_ROLM && dialsta != DIA_PART) msleep(500); #endif /* MINIDIAL */ if (dialsta != DIA_PART /* Some initial setups. */ #ifndef MINIDIAL && mymdmtyp != n_ATTUPC #endif /* MINIDIAL */ ) { fail_code = F_MINIT; /* Default failure code */ dial_what = DW_INIT; /* What I'm Doing Now */ if (dialdpy) { /* If showing progress, */ p = ck_time(); /* get timestamp. */ if (!inited) if (*p) printf(" Initializing: %s...\n",p); } } #ifndef MINIDIAL #ifdef ATT7300 if (mymdmtyp == n_ATTUPC) { /* For ATT7300/Unix PC's with their special internal modem. Whole dialing process is handled right here, an exception to the normal structure. Timeout and user interrupts are enabled during dialing. attdial() is in file ckutio.c. - jrd */ _PROTOTYP( int attdial, (char *, long, char *) ); fail_code = F_MODEM; /* Default failure code */ dial_what = DW_DIAL; if (dialdpy) { /* If showing progress */ p = ck_time(); /* get current time; */ if (*p) printf(" Dialing: %s...\n",p); } alarm(waitct); /* Set alarm */ if (attdial(ttname,speed,telnbr)) { /* dial internal modem */ dreset(); /* reset alarms, etc. */ printf(" Call failed.\r\n"); dialhup(); /* Hangup the call */ #ifdef DYNAMIC if (rbuf) free(rbuf); rbuf = NULL; if (fbuf) free(fbuf); fbuf = NULL; #endif /* DYNAMIC */ dialsta = DIA_UERR; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; /* return failure */ } dreset(); /* reset alarms, etc. */ ttpkt(speed,FLO_DIAX,parity); /* cancel dialing ioctl */ if (!quiet && !backgrd) { if (dialdpy) { printf("\n"); printf(" Call complete.\r\n"); } else if (modemmsg[0]) printf(" Call complete: \"%s\".\r\n",(char *)modemmsg); else printf(" Call complete.\r\n"); } #ifdef CKLOGDIAL dologdial(telnbr); #endif /* CKLOGDIAL */ dialsta = DIA_OK; #ifdef DYNAMIC if (rbuf) free(rbuf); rbuf = NULL; if (fbuf) free(fbuf); fbuf = NULL; #endif /* DYNAMIC */ #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; /* No conversation with modem to complete dialing */ } else #endif /* ATT7300 */ #ifdef CK_TAPI if (tttapi && !tapipass) { /* TAPI Dialing */ switch (func_code) { case 0: /* Dial */ if (cktapidial(telnbr)) { fail_code = 0; if (partial) { dialsta = DIA_PART; } else { dialsta = DIA_OK; speed = ttgspd(); } } else { if (dialsta == DIA_PART) cktapihangup(); if (!fail_code) fail_code = F_MODEM; dialsta = DIA_TAPI; } break; case 1: { /* Answer */ #ifdef __WATCOMC__ long strttime = time((unsigned long *)NULL); #else long strttime = time((long *)NULL); #endif /* __WATCOMC__ */ long diff = 0; do { if (dialatmo > 0) { strttime += diff; waitct -= diff; } fail_code = 0; if (cktapianswer()) { /* SUCCESS */ dialsta = DIA_OK; speed = ttgspd(); break; } else { /* FAILURE */ if (fail_code) { dialsta = DIA_TAPI; break; } else { fail_code = F_MODEM; dialsta = DIA_TAPI; } } if (dialatmo > 0) { #ifdef __WATCOMC__ diff = time((unsigned long *)NULL) - strttime; #else diff = time((long *)NULL) - strttime; #endif /* __WATCOMC__ */ } } while ((dialatmo > 0) ? (diff < waitct) : 1); break; } } #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; } else #endif /* CK_TAPI */ #endif /* MINIDIAL */ /* Modems with AT command set... */ if ((mdmcapas & CKD_AT) && dialsta != DIA_PART) { if (dialpace > -1) /* Set intercharacter pacing */ wr = dialpace; else wr = mp->wake_rate; if (dialini) /* Get wakeup/init string */ ws = dialini; else ws = mp->wake_str; #ifdef COMMENT if (!ws) ws = "\015"; /* If none, use CR */ #endif /* COMMENT */ /* First get the modem's attention and enable result codes */ for (tries = 0; tries < 5; tries++) { /* Send short command */ if (tries > 0) { ttoc('\015'); /* AT must go first for speed */ msleep(wr); /* detection. */ } if (mymdmtyp == n_GENERIC) /* Force word result codes */ ttslow("ATQ0V1\015",wr); /* for generic modem type */ else ttslow("ATQ0\015",wr); mdmstat = getok(tries < 2 ? 2 : tries, 1); /* Get response */ if (mdmstat > 0) break; /* OK - done */ if (dialdpy && tries > 0) { printf("\r\n No response from modem"); if (tries == 4) { printf(".\r\n"); dialsta = DIA_NRSP; #ifdef DYNAMIC if (rbuf) free(rbuf); rbuf = NULL; if (fbuf) free(fbuf); fbuf = NULL; #endif /* DYNAMIC */ #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; /* return failure */ } printf(", retrying%s...\r\n", (tries > 1) ? " again" : ""); fflush(stdout); } ttflui(); switch (tries) { case 0: msleep(100); break; case 1: ttsndb(); break; default: if (network) { ttsndb(); } else { if (tries == 2) { tthang(); ttflui(); } else { mdmhup(); } inited = 0; } } fflush(stdout); } debug(F101,"_dodial ATQ0 mdmstat","",mdmstat); if (xredial && inited) { /* Redialing... */ ttoc('\015'); /* Cancel previous */ msleep(250); /* Wait a bit */ #ifdef COMMENT /* This wasn't the problem... */ ttflui(); /* Clear out stuff from modem setup */ ttslow("ATS7=60\015",wr); /* Redo carrier wait */ getok(4,1); /* Get response */ #endif /* COMMENT */ alarm(0); /* Just in case... */ ttflui(); /* Clear out stuff from modem setup */ goto REDIAL; /* Skip setup - we already did it */ } /* Do flow control next because a long init string echoing back could cause data overruns, causing us to miss the OK, or (worse) to get out of sync entirely. */ x = 0; /* User said SET DIAL FLOW RTS/CTS */ if (dialfc == FLO_RTSC || /* Even if Kermit's FLOW isn't... */ (dialfc == FLO_AUTO && flow == FLO_RTSC)) { if (dialhwfc) { /* User-defined HWFC string */ if (*dialhwfc) { x = 1; flocmd = dialhwfc; } } else if ((mdmcapas & CKD_HW) && *(mp->hwfc_str)) { x = 1; flocmd = mp->hwfc_str; } } else if (dialfc == FLO_XONX || /* User said SET DIAL FLOW SOFT */ (dialfc == FLO_AUTO && flow == FLO_XONX)) { if (dialswfc) { if (*dialswfc) { x = 1; flocmd = dialswfc; } } else if ((mdmcapas & CKD_SW) && *(mp->swfc_str)) { x = 1; flocmd = mp->swfc_str; } } else if (dialfc == FLO_NONE) { /* User said SET DIAL FLOW NONE */ if (dialnofc) { if (*dialnofc) { x = 1; flocmd = dialnofc; } } else if (mp->nofc_str && *(mp->nofc_str)) { x = 1; flocmd = mp->nofc_str; } } if (x) { /* Send the flow control command */ debug(F110,"_dodial flocmd",flocmd,0); for (tries = 4; tries > 0; tries--) { /* Send the command */ ttslow(flocmd,wr); mdmstat = getok(5,1); if (mdmstat > 0) break; if (dialdpy && tries > 1) printf(" No response from modem, retrying%s...\n", (tries < 4) ? " again" : ""); } #ifdef CK_TTSETFLOW #ifdef CK_RTSCTS /* So far only ckutio.c has ttsetflow(). We have just told the modem to turn on RTS/CTS flow control and the modem has said OK. But we ourselves have not turned it on yet because of the disgusting ttpkt(...FLO_DIAL...) hack. So now, if the computer does not happen to be asserting RTS, the modem will no longer send characters to it. So at EXACTLY THIS POINT, we must enable RTS/CTS in the device driver. */ if (dialfc == FLO_RTSC || (dialfc == FLO_AUTO && flow == FLO_RTSC)) { ttsetflow(FLO_RTSC); } #endif /* CK_RTSCTS */ #endif /* CK_TTSETFLOW */ } ttflui(); /* Clear out stuff from modem setup */ msleep(250); if (!ws) goto xdialec; /* No init string */ if (!*ws) goto xdialec; for (tries = 4; tries > 0; tries--) { /* Send init string */ ttslow(ws,wr); mdmstat = getok(4,1); /* Get response */ if (mdmstat > 0) break; if (dialdpy && tries > 1) printf(" No response from modem, retrying%s...\n", (tries < 4) ? " again" : ""); } debug(F101,"_dodial wake_str mdmstat","",mdmstat); if (mdmstat < 1) { /* Initialized OK? */ dialfail(F_MINIT); /* No, fail. */ #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; } #ifndef MINIDIAL } else if (mymdmtyp == n_ATTDTDM && dialsta != DIA_PART) { /* AT&T ... */ ttsndb(); /* Send BREAK */ #endif /* MINIDIAL */ } else if (dialsta != DIA_PART) { /* All others */ /* Place modem into command mode */ ws = dialini ? dialini : mp->wake_str; if (ws && (int)strlen(ws) > 0) { debug(F111,"_dodial default, wake string", ws, wr); ttslow(ws, wr); } else debug(F100,"_dodial no wake_str","",0); if (mp->wake_prompt && (int)strlen(mp->wake_prompt) > 0) { debug(F110,"_dodial default, waiting for wake_prompt", mp->wake_prompt,0); alarm(10); waitfor(mp->wake_prompt); alarm(0); } else debug(F100,"_dodial no wake_prompt","",0); } /* Handle error correction, data compression, and flow control... */ xdialec: if (dialsta != DIA_PART) { alarm(0); /* Turn off alarm */ debug(F100,"_dodial got wake prompt","",0); msleep(500); /* Allow settling time */ /* Enable/disable error-correction */ x = 0; if (dialec) { /* DIAL ERROR-CORRECTION is ON */ if (dialecon) { /* SET DIAL STRING ERROR-CORRECTION */ if (*dialecon) { x = 1; ttslow(dialecon, wr); } } else if ((mdmcapas & CKD_EC) && *(mp->ec_on_str)) { x = 1; ttslow(mp->ec_on_str, wr); } #ifdef COMMENT else printf( "WARNING - I don't know how to turn on EC for this modem\n" ); #endif /* COMMENT */ } else { if (dialecoff) { /* DIAL ERROR-CORRECTION OFF */ if (*dialecoff) { x = 1; ttslow(dialecoff, wr); } } else if ((mdmcapas & CKD_EC) && *(mp->ec_off_str)) { x = 1; ttslow(mp->ec_off_str, wr); } #ifdef COMMENT else printf( "WARNING - I don't know how to turn off EC for this modem\n" ); #endif /* COMMENT */ } /* debug(F101,"ckudia xx_ok","",xx_ok); */ if (x && xx_ok) { /* Look for OK response */ debug(F100,"ckudia calling xx_ok for EC","",0); x = (*xx_ok)(5,1); debug(F101,"ckudia xx_ok","",x); if (x < 0) { printf("WARNING - Trouble enabling error-correction.\n"); printf( " Likely cause: Your modem is an RPI model, which does not have built-in\n"); printf(" error correction and data compression."); } } /* Enable/disable data compression */ if (x > 0) x = 0; if (dialdc) { if (x < 0 || !dialec) { printf( "WARNING - You can't have compression without error correction.\n"); } else if (dialdcon) { /* SET DIAL STRING ... */ if (*dialdcon) { x = 1; ttslow(dialdcon, wr); } } else if ((mdmcapas & CKD_DC) && *(mp->dc_on_str)) { x = 1; ttslow(mp->dc_on_str, wr); } #ifdef COMMENT else printf( "WARNING - I don't know how to turn on DC for this modem\n" ); #endif /* COMMENT */ } else { if (dialdcoff) { if (*dialdcoff) { x = 1; ttslow(dialdcoff, wr); } } else if ((mdmcapas & CKD_DC) && *(mp->dc_off_str)) { x = 1; ttslow(mp->dc_off_str, wr); } #ifdef COMMENT else printf( "WARNING - I don't know how to turn off compression for this modem\n" ); #endif /* COMMENT */ } if (x && xx_ok) { /* Look for OK response */ x = (*xx_ok)(5,1); if (x < 0) printf("WARNING - Trouble enabling compression\n"); } } #ifndef NOXFER #ifndef MINIDIAL if (mdmcapas & CKD_KS && dialsta != DIA_PART) { /* Kermit spoof */ int r; /* Register */ char tbcmdbuf[64]; /* Command buffer */ switch (mymdmtyp) { case n_MICROCOM: /* Microcoms in SX mode */ if (dialksp) sprintf(tbcmdbuf,"APM1;KMC%d\015",stchr); /* safe */ else sprintf(tbcmdbuf,"APM0\015"); /* safe */ ttslow(tbcmdbuf, MICROCOM.wake_rate); alarm(3); waitfor(mp->wake_prompt); alarm(0); break; case n_TELEBIT: /* Old and new Telebits */ case n_TBNEW: if (!dialksp) { sprintf(tbcmdbuf,"ATS111=0\015"); /* safe */ } else { switch (parity) { /* S111 value depends on parity */ case 'e': r = 12; break; case 'm': r = 13; break; case 'o': r = 11; break; case 's': r = 14; break; case 0: default: r = 10; break; } sprintf(tbcmdbuf,"ATS111=%d S112=%d\015",r,stchr); /* safe */ } ttslow(tbcmdbuf, wr); /* Not all Telebit models have the Kermit spoof, so ignore response. */ if (xx_ok) { /* Get modem's response */ x = (*xx_ok)(5,1); } } } #endif /* MINIDIAL */ #endif /* NOXFER */ /* Speaker */ if (mymdmtyp != n_GENERIC && (mdmcapas & CKD_AT) && (dialsta != DIA_PART) && !dialspon && !dialspoff && !dialvol1 && !dialvol2 &&!dialvol3) { /* AT command set and commands have not been customized */ /* so combine speaker and volume commands. */ if (mdmspk) sprintf(lbuf,"ATM1L%d%c",mdmvol,13); /* safe */ else sprintf(lbuf,"ATM0%c",13); /* safe */ ttslow(lbuf,wr); /* Send command */ getok(5,1); /* Get but ignore response */ } else if (dialsta != DIA_PART) { /* Customized or not AT commands */ x = 0; /* Do it the hard way */ if (mdmspk) { if (dialspon) { if (*dialspon) { x = 1; ttslow(dialspon,wr); } } else { if (mp->sp_on_str[0]) { x = 1; ttslow(mp->sp_on_str,wr); } } } else { /* s = dialspoff ? dialspoff : mp->sp_off_str; */ if (dialspoff) { if (*dialspoff) { x = 1; ttslow(dialspoff,wr); } } else { if (mp->sp_off_str[0]) { x = 1; ttslow(mp->sp_off_str,wr); } } } if (x) { if (xx_ok) /* Get response */ x = (*xx_ok)(5,1); if (x && mdmspk) { /* Good response and speaker on? */ switch (mdmvol) { /* Yes, send volume command. */ case 0: case 1: s = dialvol1 ? dialvol1 : mp->vol1_str; break; case 2: s = dialvol2 ? dialvol2 : mp->vol2_str; break; case 3: s = dialvol3 ? dialvol3 : mp->vol3_str; break; default: s = NULL; } if (s) if (*s) { /* Send volume command. */ ttslow(s, wr); if (xx_ok) /* Get response but ignore it */ (*xx_ok)(5,1); } } } } #ifndef CK_ATDT /* Dialing Method */ if (dialmth && dialsta != DIA_PART) { /* If dialing method specified... */ char *s = ""; /* Do it here... */ if (dialmth == XYDM_T && dialtone) /* Tone */ s = dialtone; else if (dialmth == XYDM_P && dialpulse) /* Pulse */ s = dialpulse; if (s) if (*s) { ttslow(s, wr); if (xx_ok) /* Get modem's response */ (*xx_ok)(5,1); /* (but ignore it...) */ } } #endif /* CK_ATDT */ if (dialidt) { /* Ignore dialtone? */ char *s = ""; s = dialx3 ? dialx3 : mp->ignoredt; if (s) if (*s) { ttslow(s, wr); if (xx_ok) /* Get modem's response */ (*xx_ok)(5,1); /* (but ignore it...) */ } } { char *s = ""; /* Last-minute init string? */ s = dialini2 ? dialini2 : mp->ini2; if (s) if (*s) { ttslow(s, wr); if (xx_ok) /* Get modem's response */ (*xx_ok)(5,1); /* (but ignore it...) */ } } if (func_code == 1) { /* ANSWER (not DIAL) */ char *s; s = dialaaon ? dialaaon : mp->aa_on_str; if (!s) s = ""; if (*s) { /* Here we would handle caller ID */ ttslow(s, (dialpace > -1) ? wr : mp->dial_rate); if (xx_ok) /* Get modem's response */ (*xx_ok)(5,1); /* (but ignore it...) */ } else { printf( "WARNING - I don't know how to enable autoanswer for this modem.\n" ); } /* And skip all the phone-number & dialing stuff... */ alarm(waitct); /* This much time allowed. */ debug(F101,"_dodial ANSWER waitct","",waitct); } else { /* DIAL (not ANSWER) */ if (dialsta != DIA_PART) { /* Last dial was not partial */ char *s = ""; #ifdef COMMENT s = dialaaoff ? dialaaoff : mp->aa_off_str; #endif /* COMMENT */ if (s) if (*s) { ttslow(s, (dialpace > -1) ? wr : mp->dial_rate); if (xx_ok) /* Get modem's response */ (*xx_ok)(5,1); /* (but ignore it...) */ } /* Put modem into dialing mode, if the modem requires it. */ if (mp->dmode_str && *(mp->dmode_str)) { ttslow(mp->dmode_str, (dialpace > -1) ? wr : mp->dial_rate); savalrm = signal(SIGALRM,dialtime); alarm(10); /* Wait for prompt, if any expected */ if (mp->dmode_prompt && *(mp->dmode_prompt)) { waitfor(mp->dmode_prompt); msleep(300); } alarm(0); /* Turn off alarm on dialing prompts */ signal(SIGALRM,savalrm); /* Restore alarm */ } } /* AT-Command-Set non-Generic modem */ if (mdmcapas & CKD_AT && mymdmtyp != n_GENERIC && dialsta != DIA_PART) { if (mdmwait > 255) /* If larger than maximum, */ mdmwait = 255; /* make it maximum. */ if (dialesc > 0 && /* Modem escape character is set */ dialmhu > 0) { /* Hangup method is modem command */ int x = dialesc; if (dialesc < 0 || dialesc > 127) x = 128; sprintf(lbuf, "ATS2=%dS7=%d\015", dialesc ? x : mp->esc_char, mdmwait); /* safe */ } else sprintf(lbuf,"ATS7=%d%c",mdmwait,13); /* safe */ ttslow(lbuf,wr); /* Set it. */ mdmstat = getok(5,1); /* Get response from modem */ /* If it gets an error, go ahead anyway */ debug(F101,"_dodial S7 mdmstat","",mdmstat); } ttflui(); /* Clear out stuff from modem setup */ inited = 1; /* Remember modem is initialized */ REDIAL: if ((int)strlen(dcmd) + (int)strlen(xnum) > LBUFL) ckstrncpy(lbuf,"NUMBER TOO LONG!",LBUFL); else sprintf(lbuf, dcmd, xnum); /* safe (prechecked) */ debug(F110,"dialing",lbuf,0); /* Send the dialing string */ ttslow(lbuf,dialpace > -1 ? wr : mp->dial_rate); fail_code = F_MODEM; /* New default failure code changes */ dial_what = DW_DIAL; /* and our state, too. */ if (dialdpy) { /* If showing progress */ p = ck_time(); /* get current time; */ if (*p) printf(" Dialing: %s...\n",p); #ifdef VMS printf(" \n"); fflush(stdout); #endif /* VMS */ } alarm(waitct); /* This much time allowed. */ debug(F101,"_dodial waitct","",waitct); #ifndef MINIDIAL #ifdef OLDMODEMS switch (mymdmtyp) { case n_RACAL: /* Acknowledge dialing string */ sleep(3); ttflui(); ttoc('\015'); break; case n_VENTEL: waitfor("\012\012"); /* Ignore the first two strings */ break; default: break; } #endif /* OLDMODEMS */ #endif /* MINIDIAL */ } /* Check for connection */ mdmstat = 0; /* No status yet */ lbuf[0] = NUL; /* Default reason for failure */ debug(F101,"dial awaiting response, mymdmtyp","",mymdmtyp); #ifndef NOSPL modemmsg[0] = NUL; #endif /* NOSPL */ while (mdmstat == 0) { /* Till we get a result or time out */ if ((mdmcapas & CKD_AT) && nonverbal) { /* AT command set */ gethrn(); /* In digit result mode */ if (partial && dialsta == DIA_ERR) { /* If we get an error here, the phone is still off hook so we have to hang it up. */ dialhup(); dialsta = DIA_ERR; /* (because dialhup() changes it) */ } continue; } else if (mymdmtyp == n_UNKNOWN) { /* Unknown modem type */ int x, y = waitct; mdmstat = D_FAILED; /* Assume failure. */ while (y-- > -1) { x = ttchk(); if (x > 0) { if (x > LBUFL) x = LBUFL; x = ttxin(x,(CHAR *)lbuf); if ((x > 0) && dialdpy) conol(lbuf); } else if (network #ifdef TN_COMPORT && !istncomport() #endif /* TN_COMPORT */ && x < 0) { /* Connection dropped */ inited = 0; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ dialsta = DIA_IO; /* Call it an I/O error */ #ifdef DYNAMIC if (rbuf) free(rbuf); rbuf = NULL; if (fbuf) free(fbuf); fbuf = NULL; #endif /* DYNAMIC */ SIGRETURN; } x = ttgmdm(); /* Try to read modem signals */ if (x < 0) break; /* Can't, fail. */ if (x & BM_DCD) { /* Got signals OK. Carrier present? */ mdmstat = CONNECTED; /* Yes, done. */ break; } /* No, keep waiting. */ sleep(1); } continue; } for (n = -1; n < LBUFL-1; ) { /* Accumulate modem response */ int xx; c2 = (char) (xx = ddinc(0)); /* Read a character, blocking */ if (xx < 1) /* Ignore NULs and errors */ continue; /* (Timeout will handle errors) */ else /* Real character, keep it */ lbuf[++n] = (char) (c2 & 0177); dialoc(lbuf[n]); /* Maybe echo it */ if (mdmcapas & CKD_V25) { /* V.25bis dialing... */ /* This assumes that V.25bis indications are all at least 3 characters long and are terminated by either CRLF or LFCR. */ if (mymdmtyp == n_CCITT) { if (n < 3) continue; if ((lbuf[n] == CK_CR) && (lbuf[n-1] == LF)) break; if ((lbuf[n] == LF) && (lbuf[n-1] == CK_CR)) break; } #ifndef MINIDIAL else if (mymdmtyp == n_DIGITEL) { if (((lbuf[n] == CK_CR) && (lbuf[n-1] == LF)) || ((lbuf[n] == LF) && (lbuf[n-1] == CK_CR))) break; else continue; } #endif /* MINIDIAL */ } else { /* All others, break on CR or LF */ if ( lbuf[n] == CK_CR || lbuf[n] == LF ) break; } } lbuf[++n] = '\0'; /* Terminate response from modem */ debug(F111,"_dodial modem response",lbuf,n); #ifndef NOSPL ckstrncpy(modemmsg,lbuf,LBUFL); /* Call result message */ lbuf[79] = NUL; { int x; /* Strip junk from end */ x = (int)strlen(modemmsg) - 1; while (x > -1) { if (modemmsg[x] < (char) 33) modemmsg[x] = NUL; else break; x--; } } #endif /* NOSPL */ if (mdmcapas & CKD_AT) { /* Hayes AT command set */ gethrw(); /* in word result mode */ if (partial && dialsta == DIA_ERR) { dialhup(); dialsta = DIA_ERR; /* (because dialhup() changes it) */ } continue; } else if (mdmcapas & CKD_V25) { /* CCITT command set */ if (didweget(lbuf,"VAL")) { /* Dial command confirmation */ #ifndef MINIDIAL if (mymdmtyp == n_CCITT) #endif /* MINIDIAL */ continue; /* Go back and read more */ #ifndef MINIDIAL /* Digitel doesn't give an explicit connect confirmation message */ else { int n; for (n = -1; n < LBUFL-1; ) { lbuf[++n] = c2 = (char) (ddinc(0) & 0177); dialoc(lbuf[n]); if (((lbuf[n] == CK_CR) && (lbuf[n-1] == LF)) || ((lbuf[n] == LF) && (lbuf[n-1] == CK_CR))) break; } mdmstat = CONNECTED; /* Assume we're connected */ if (dialdpy && carrier != CAR_OFF) { #ifdef TN_COMPORT if (istncomport()) { int i; for (i = 0; i < 5; i++) { debug(F100,"TN Com Port DCD wait...","",0); if ((n = ttgmdm()) >= 0) { if ((n & BM_DCD)) break; msleep(500); tnc_wait( (CHAR *)"_dodial waiting for DCD",1); } } } else #endif /* TN_COMPORT */ sleep(1); /* Wait a second */ n = ttgmdm(); /* Try to read modem signals */ if ((n > -1) && ((n & BM_DCD) == 0)) printf("WARNING - no carrier\n"); } } #endif /* MINIDIAL */ /* Standard V.25bis stuff */ } else if (didweget(lbuf,"CNX")) { /* Connected */ mdmstat = CONNECTED; } else if (didweget(lbuf, "INV")) { mdmstat = D_FAILED; /* Command error */ dialsta = DIA_ERR; ckstrncpy(lbuf,"INV",LBUFL); } else if (didweget(lbuf,"CFI")) { /* Call Failure */ if (didweget(lbuf,"AB")) { /* Interpret reason code */ ckstrncpy(lbuf,"AB: Timed out",LBUFL); dialsta = DIA_TIMO; } else if (didweget(lbuf,"CB")) { ckstrncpy(lbuf,"CB: Local DCE Busy",LBUFL); dialsta = DIA_NRDY; } else if (didweget(lbuf,"ET")) { ckstrncpy(lbuf,"ET: Busy",LBUFL); dialsta = DIA_BUSY; } else if (didweget(lbuf, "NS")) { ckstrncpy(lbuf,"NS: Number not stored",LBUFL); dialsta = DIA_ERR; } else if (didweget(lbuf,"NT")) { ckstrncpy(lbuf,"NT: No answer",LBUFL); dialsta = DIA_NOAN; } else if (didweget(lbuf,"RT")) { ckstrncpy(lbuf,"RT: Ring tone",LBUFL); dialsta = DIA_RING; } else if (didweget(lbuf,"PV")) { ckstrncpy(lbuf,"PV: Parameter value error",LBUFL); dialsta = DIA_ERR; } else if (didweget(lbuf,"PS")) { ckstrncpy(lbuf,"PS: Parameter syntax error",LBUFL); dialsta = DIA_ERR; } else if (didweget(lbuf,"MS")) { ckstrncpy(lbuf,"MS: Message syntax error",LBUFL); dialsta = DIA_ERR; } else if (didweget(lbuf,"CU")) { ckstrncpy(lbuf,"CU: Command unknown",LBUFL); dialsta = DIA_ERR; } else if (didweget(lbuf,"FC")) { ckstrncpy(lbuf,"FC: Forbidden call",LBUFL); dialsta = DIA_NOAC; } mdmstat = D_FAILED; } else if (didweget(lbuf,"INC")) { /* Incoming Call */ ckstrncpy(lbuf,"INC: Incoming call",LBUFL); dialsta = DIA_RING; mdmstat = D_FAILED; } else if (didweget(lbuf,"DLC")) { /* Delayed Call */ ckstrncpy(lbuf,"DLC: Delayed call",LBUFL); dialsta = DIA_NOAN; mdmstat = D_FAILED; } else /* Response was probably an echo. */ #ifndef MINIDIAL if (mymdmtyp == n_CCITT) #endif /* MINIDIAL */ continue; #ifndef MINIDIAL else /* Digitel: If no error, connect. */ mdmstat = CONNECTED; #endif /* MINIDIAL */ break; } else if (n) { /* Non-Hayes-compatibles... */ switch (mymdmtyp) { #ifndef MINIDIAL case n_ATTMODEM: /* Careful - "Connected" / "Not Connected" */ if (didweget(lbuf,"Busy")) { mdmstat = D_FAILED; dialsta = DIA_BUSY; } else if (didweget(lbuf,"Not connected") || didweget(lbuf,"Not Connected")) { mdmstat = D_FAILED; dialsta = DIA_NOCA; } else if (didweget(lbuf,"No dial tone") || didweget(lbuf,"No Dial Tone")) { mdmstat = D_FAILED; dialsta = DIA_NODT; } else if (didweget(lbuf,"No answer") || didweget(lbuf,"No Answer")) { mdmstat = D_FAILED; dialsta = DIA_NOAN; } else if (didweget(lbuf,"Answered") || didweget(lbuf,"Connected")) { mdmstat = CONNECTED; dialsta = DIA_OK; } break; case n_ATTISN: if (didweget(lbuf,"ANSWERED")) { mdmstat = CONNECTED; dialsta = DIA_OK; } else if (didweget(lbuf,"BUSY")) { mdmstat = D_FAILED; dialsta = DIA_BUSY; } else if (didweget(lbuf,"DISCONNECT")) { mdmstat = D_FAILED; dialsta = DIA_DISC; } else if (didweget(lbuf,"NO ANSWER")) { mdmstat = D_FAILED; dialsta = DIA_NOAN; } else if (didweget(lbuf,"WRONG ADDRESS")) { mdmstat = D_FAILED; dialsta = DIA_NOAC; } break; case n_ATTDTDM: if (didweget(lbuf,"ANSWERED")) { mdmstat = CONNECTED; } else if (didweget(lbuf,"BUSY")) { mdmstat = D_FAILED; dialsta = DIA_BUSY; } else if (didweget(lbuf,"CHECK OPTIONS")) { mdmstat = D_FAILED; dialsta = DIA_ERR; } else if (didweget(lbuf,"DISCONNECTED")) { mdmstat = D_FAILED; dialsta = DIA_DISC; } else if (didweget(lbuf,"DENIED")) { mdmstat = D_FAILED; dialsta = DIA_NOAC; } #ifdef DEBUG #ifdef ATT6300 /* Horrible hack lost in history. */ else if (deblog && didweget(lbuf,"~~")) mdmstat = CONNECTED; #endif /* ATT6300 */ #endif /* DEBUG */ break; #ifdef OLDMODEMS case n_CERMETEK: if (didweget(lbuf,"\016A")) { mdmstat = CONNECTED; ttslow("\016U 1\015",200); /* Make transparent*/ } break; case n_DF03: /* Because response lacks CR or NL . . . */ c = (char) (ddinc(0) & 0177); dialoc(c); debug(F000,"dial df03 got","",c); if ( c == 'A' ) mdmstat = CONNECTED; if ( c == 'B' ) mdmstat = D_FAILED; break; case n_DF100: /* DF100 has short response codes */ if (strcmp(lbuf,"A") == 0) { mdmstat = CONNECTED; /* Attached */ dialsta = DIA_OK; } else if (strcmp(lbuf,"N") == 0) { mdmstat = D_FAILED; dialsta = DIA_NOAN; /* No answer or no dialtone */ } else if (strcmp(lbuf,"E") == 0 || /* Error */ strcmp(lbuf,"R") == 0) { /* "Ready" (?) */ mdmstat = D_FAILED; dialsta = DIA_ERR; /* Command error */ } /* otherwise fall thru... */ case n_DF200: if (didweget(lbuf,"Attached")) { mdmstat = CONNECTED; dialsta = DIA_OK; /* * The DF100 will respond with "Attached" even if DTR * and/or carrier are not present. Another reason to * (also) wait for carrier? */ } else if (didweget(lbuf,"Busy")) { mdmstat = D_FAILED; dialsta = DIA_BUSY; } else if (didweget(lbuf,"Disconnected")) { mdmstat = D_FAILED; dialsta = DIA_DISC; } else if (didweget(lbuf,"Error")) { mdmstat = D_FAILED; dialsta = DIA_ERR; } else if (didweget(lbuf,"No answer")) { mdmstat = D_FAILED; dialsta = DIA_NOAN; } else if (didweget(lbuf,"No dial tone")) { mdmstat = D_FAILED; dialsta = DIA_NODT; } else if (didweget(lbuf,"Speed:)")) { mdmstat = D_FAILED; dialsta = DIA_ERR; } /* * It appears that the "Speed:..." response comes after an * "Attached" response, so this is never seen. HOWEVER, * it would be very handy to detect this and temporarily * reset the speed, since it's a nuisance otherwise. * If we wait for some more input from the modem, how do * we know if it's from the remote host or the modem? * Carrier reportedly doesn't get set until after the * "Speed:..." response (if any) is sent. Another reason * to (also) wait for carrier. */ break; case n_GDC: if (didweget(lbuf,"ON LINE")) mdmstat = CONNECTED; else if (didweget(lbuf,"NO CONNECT")) mdmstat = D_FAILED; break; case n_PENRIL: if (didweget(lbuf,"OK")) { mdmstat = CONNECTED; } else if (didweget(lbuf,"BUSY")) { mdmstat = D_FAILED; dialsta = DIA_BUSY; } else if (didweget(lbuf,"NO RING")) { mdmstat = D_FAILED; dialsta = DIA_NOCA; } break; case n_RACAL: if (didweget(lbuf,"ON LINE")) mdmstat = CONNECTED; else if (didweget(lbuf,"FAILED CALL")) mdmstat = D_FAILED; break; #endif /* OLDMODEMS */ case n_ROLM: if (didweget(lbuf,"CALLING")) mdmstat = 0; else if (didweget(lbuf,"COMPLETE")) mdmstat = CONNECTED; else if (didweget(lbuf,"FAILED") || didweget(lbuf,"ABANDONDED")) { mdmstat = D_FAILED; dialsta = DIA_NOCA; } else if (didweget(lbuf,"NOT AVAILABLE") || didweget(lbuf,"LACKS PERMISSION") || didweget(lbuf,"NOT A DATALINE") || didweget(lbuf,"INVALID DATA LINE NUMBER") || didweget(lbuf,"INVALID GROUP NAME")) { mdmstat = D_FAILED; dialsta = DIA_NOAC; } else if (didweget(lbuf,"BUSY")) { mdmstat = D_FAILED; dialsta = DIA_BUSY; } else if (didweget(lbuf,"DOES NOT ANSWER")) { mdmstat = D_FAILED; dialsta = DIA_NOAN; } break; #ifdef OLDMODEMS case n_VENTEL: if (didweget(lbuf,"ONLINE!") || didweget(lbuf,"Online!")) { mdmstat = CONNECTED; } else if (didweget(lbuf,"BUSY") || didweget(lbuf,"Busy")) { mdmstat = D_FAILED; dialsta = DIA_BUSY; } else if (didweget(lbuf,"DEAD PHONE")) { mdmstat = D_FAILED; dialsta = DIA_DISC; } break; case n_CONCORD: if (didweget(lbuf,"INITIATING")) mdmstat = CONNECTED; else if (didweget(lbuf,"BUSY")) { mdmstat = D_FAILED; dialsta = DIA_BUSY; } else if (didweget(lbuf,"CALL FAILED")) { mdmstat = D_FAILED; dialsta = DIA_NOCA; } break; #endif /* OLDMODEMS */ case n_MICROCOM: /* "RINGBACK" means phone line ringing, continue */ if (didweget(lbuf,"NO CONNECT")) { mdmstat = D_FAILED; dialsta = DIA_NOCA; } else if (didweget(lbuf,"BUSY")) { mdmstat = D_FAILED; dialsta = DIA_BUSY; } else if (didweget(lbuf,"NO DIALTONE")) { mdmstat = D_FAILED; dialsta = DIA_NODT; } else if (didweget(lbuf,"COMMAND ERROR")) { mdmstat = D_FAILED; dialsta = DIA_ERR; } else if (didweget(lbuf,"IN USE")) { mdmstat = D_FAILED; dialsta = DIA_NOAC; } else if (didweget(lbuf,"CONNECT")) { mdmstat = CONNECTED; /* trailing speed ignored */ } break; #endif /* MINIDIAL */ default: printf( "PROGRAM ERROR - No response handler for modem type %d\n", mymdmtyp); mdmstat = D_FAILED; dialsta = DIA_ERR; } } } /* while (mdmstat == 0) */ debug(F101,"_dodial alarm off","",x); alarm(0); if (mdmstat == D_FAILED) { /* Failure detected by modem */ dialfail(F_MODEM); #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; } else if (mdmstat == D_PARTIAL ) { /* Partial dial command OK */ msleep(500); debug(F100,"dial partial","",0); } else { /* Call was completed */ int x; msleep(700); /* In case modem signals blink */ debug(F100,"dial succeeded","",0); if ( #ifndef MINIDIAL mymdmtyp != n_ROLM /* Rolm has weird modem signaling */ #else 1 #endif /* MINIDIAL */ ) { alarm(3); /* In case ttpkt() gets stuck... */ ttpkt(speed,FLO_DIAX,parity); /* Cancel dialing state ioctl */ alarm(0); } /* In case CD went off in the interval between call completion and return from ttpkt()... */ if (carrier != CAR_OFF) { if ((x = ttgmdm()) >= 0) { #ifdef TN_COMPORT if (istncomport() && !(x & BM_DCD)) { int i; for (i = 0; i < 5; i++) { msleep(500); tnc_wait((CHAR *)"_dodial waiting for DCD",1); if ((x = ttgmdm()) >= 0) { if ((x & BM_DCD)) break; } } } #endif /* TN_COMPORT */ if (!(x & BM_DCD)) printf("WARNING: Carrier seems to have dropped...\n"); } } } dreset(); /* Reset alarms and signals. */ if (!quiet && !backgrd) { if (dialdpy && (p = ck_time())) { /* If DIAL DISPLAY ON, */ printf(" %sall complete: %s.\n", /* include timestamp. */ (mdmstat == D_PARTIAL) ? "Partial c" : "C", p ); } else if (modemmsg[0]) { printf (" %sall complete: \"%s\".\n", (mdmstat == D_PARTIAL) ? "Partial c" : "C", (char *)modemmsg ); } else { printf (" %sall complete.\n", (mdmstat == D_PARTIAL) ? "Partial c" : "C" ); } } #ifdef CKLOGDIAL dologdial(telnbr); #endif /* CKLOGDIAL */ #ifdef DYNAMIC if (rbuf) free(rbuf); rbuf = NULL; if (fbuf) free(fbuf); fbuf = NULL; #endif /* DYNAMIC */ dialsta = (mdmstat == D_PARTIAL) ? DIA_PART : DIA_OK; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; } static SIGTYP #ifdef CK_ANSIC faildial(void * threadinfo) #else /* Not CK_ANSIC */ faildial(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ /* faildial */ { debug(F100,"longjmp returns to dial routine","",0); dialfail(fail_code); SIGRETURN; } /* nbr = number to dial (string) x1 = Retry counter x2 = Number counter fc = Function code: 0 == DIAL 1 == ANSWER 2 == INIT/CONFIG 3 == PARTIAL DIAL */ int #ifdef OLD_DIAL #ifdef CK_ANSIC ckdial( char *nbr ) #else ckdial(nbr) char *nbr; #endif /* CK_ANSIC */ #else #ifdef CK_ANSIC ckdial( char *nbr, int x1, int x2, int fc, int redial ) #else ckdial(nbr, x1, x2, fc, redial) char *nbr; int x1, x2, fc, redial; #endif /* CK_ANSIC */ #endif /* OLD_DIAL */ /* ckdial */ { #define ERMSGL 100 /* fdc 13 November 2022 (was 50) */ char errmsg[ERMSGL], *erp; /* For error messages */ char *s; long spdmax; #ifdef OS2 extern int term_io; int term_io_sav = term_io; #endif /* OS2 */ char *mmsg = "Sorry, DIAL memory buffer can't be allocated\n"; /* A DIAL command implies a SET MODEM TYPE command and therefore enables hanging up by modem commands rather than dropping DTR. */ mdmset = 1; /* See mdmhup() */ partial = 0; if (fc == 3) { /* Partial dial requested */ partial = 1; /* Set flag */ fc = 0; /* Treat like regular dialing */ } func_code = fc; /* Make global to this module */ telnbr = nbr; xredial = redial; debug(F111,"ckdial entry partial",ckitoa(fc),partial); debug(F111,"ckdial entry number",nbr,redial); if (fc == 1) { /* ANSWER command? */ /* Reset caller ID strings */ if (callid_date) makestr(&callid_date,NULL); if (callid_time) makestr(&callid_time,NULL); if (callid_name) makestr(&callid_name,NULL); if (callid_nmbr) makestr(&callid_nmbr,NULL); if (callid_mesg) makestr(&callid_mesg,NULL); } #ifdef CK_TAPI_X if (tttapi && tapipass) { if (modemp[n_TAPI] = cktapiGetModemInf()) { mymdmtyp = n_TAPI; } else { mymdmtyp = mdmtyp; modemp[n_TAPI] = &GENERIC; } } else #endif /* CK_TAPI */ mymdmtyp = mdmtyp; if (mymdmtyp < 0) { /* Whoa, network dialing... */ if (mdmsav > -1) mymdmtyp = mdmsav; } if (mymdmtyp < 0) { printf("Invalid modem type %d - internal error.\n",mymdmtyp); dialsta = DIA_NOMO; return(0); } dial_what = DW_NOTHING; /* Doing nothing at first. */ nonverbal = 0; /* These are ONLY for the purpose of interpreting numeric result codes. */ is_motorola = #ifdef MINIDIAL 0 #else mymdmtyp == n_SUPRA || mymdmtyp == n_SUPRASON; #endif /* MINIDIAL */ ; is_motorola = #ifdef MINIDIAL 0 #else mymdmtyp == n_MOTOROLA || mymdmtyp == n_MONTANA; #endif /* MINIDIAL */ ; is_rockwell = #ifdef MINIDIAL 0 #else mymdmtyp == n_RWV32 || mymdmtyp == n_RWV32B || mymdmtyp == n_RWV34 || mymdmtyp == n_RWV90 || mymdmtyp == n_BOCA || mymdmtyp == n_TELEPATH || mymdmtyp == n_CARDINAL || mymdmtyp == n_BESTDATA || mymdmtyp == n_CONEXANT || mymdmtyp == n_PCTEL #endif /* MINIDIAL */ ; is_hayeshispd = #ifdef MINIDIAL 0 #else mymdmtyp == n_H_ULTRA || mymdmtyp == n_H_ACCURA || mymdmtyp == n_PPI #endif /* MINIDIAL */ ; is_supra = #ifdef MINIDIAL 0 #else mymdmtyp == n_SUPRA || mymdmtyp == n_SUPRAX || mymdmtyp == n_SUPRASON #endif /* MINIDIAL */ ; mp = modemp[mymdmtyp]; /* Set pointer to modem info */ if (!mp) { printf("Sorry, handler for this modem type not yet filled in.\n"); dialsta = DIA_NOMO; return 0; } debug(F110,"dial number",telnbr,0); #ifdef COMMENT debug(F110,"dial prefix",(dialnpr ? dialnpr : ""), 0); #endif /* COMMENT */ #ifdef DYNAMIC *lbuf = NUL; debug(F101,"DIAL lbuf malloc ok","",LBUFL+1); if (!rbuf) { /* This one might already have been allocated by getok() */ if (!(rbuf = malloc(RBUFL+1))) { /* Allocate input line buffer */ printf("%s", mmsg); dialsta = DIA_IE; return 0; } else debug(F101,"DIAL rbuf malloc ok","",RBUFL+1); } if (!(fbuf = malloc(FULLNUML+1))) { /* Allocate input line buffer */ printf("%s", mmsg); dialsta = DIA_IE; if (rbuf) free(rbuf); rbuf = NULL; return 0; } debug(F101,"DIAL fbuf malloc ok","",FULLNUML+1); #endif /* DYNAMIC */ /* NOTE: mdmtyp, not mymdmtyp */ if (ttopen(ttname,&local,mdmtyp,0) < 0) { /* Open, no carrier wait */ erp = errmsg; #ifdef COMMENT /* This gets compiler warnings */ if ((int)strlen(ttname) < (ERMSGL - 18)) /* safe, checked */ sprintf(erp,"Sorry, can't open %s",ttname); else sprintf(erp,"Sorry, can't open device"); #else /* fdc 13 November 2022 */ /* Safe and portable replacement for snprinf() AND sprintf() */ ckmakmsg(erp,ERMSGL,"Sorry, can't open ",ttname,NULL,NULL); #endif /* COMMENT */ perror(errmsg); dialsta = DIA_OPEN; #ifdef DYNAMIC if (rbuf) free(rbuf); rbuf = NULL; if (fbuf) free(fbuf); fbuf = NULL; #endif /* DYNAMIC */ return 0; } #ifdef CK_TAPI if (!tttapi) { #endif /* CK_TAPI */ /* Condition console terminal and communication line */ /* Place line into "clocal" dialing state, */ /* important mainly for System V UNIX. */ if (ttpkt(speed,FLO_DIAL,parity) < 0) { ttclos(0); /* If ttpkt fails do all this... */ if (ttopen(ttname,&local,mymdmtyp,0) < 0) { erp = errmsg; if ((int)strlen(ttname) < (ERMSGL - 18)) /* safe, checked */ sprintf(erp,"Sorry, can't reopen %s",ttname); else sprintf(erp,"Sorry, can't reopen device"); perror(errmsg); dialsta = DIA_OPEN; #ifdef DYNAMIC if (rbuf) free(rbuf); rbuf = NULL; if (fbuf) free(fbuf); fbuf = NULL; #endif /* DYNAMIC */ return 0; } /* And try again. */ if ((ttpkt(speed,FLO_DIAL,parity) < 0) #ifdef UNIX && (strcmp(ttname,"/dev/null")) #else #ifdef OSK && (strcmp(ttname,"/nil")) #endif /* OSK */ #endif /* UNIX */ #ifdef CK_TAPI && !tttapi #endif /* CK_TAPI */ ) { printf("Sorry, Can't condition communication line\n"); printf("Try 'set line %s' again\n",ttname); dialsta = DIA_OPEN; #ifdef DYNAMIC if (rbuf) free(rbuf); rbuf = NULL; if (fbuf) free(fbuf); fbuf = NULL; #endif /* DYNAMIC */ return 0; } } #ifdef CK_TAPI } #endif /* CK_TAPI */ /* Modem's escape sequence... */ if (dialesc < 0 || dialesc > 127) c = NUL; else c = (char) (dialesc ? dialesc : mp->esc_char); mdmcapas = dialcapas ? dialcapas : mp->capas; xx_ok = mp->ok_fn; /* Pointer to response reader */ if (mdmcapas & CKD_AT) { /* Hayes compatible */ escbuf[0] = c; escbuf[1] = c; escbuf[2] = c; escbuf[3] = NUL; /* In case this modem type is user-defined */ if (!xx_ok) xx_ok = getok; } else { /* Other */ escbuf[0] = c; escbuf[1] = NUL; /* In case user-defined */ if (mdmcapas & CKD_V25) if (!xx_ok) xx_ok = getok; } /* Partial dialing */ if (mdmcapas & CKD_AT #ifndef MINIDIAL || mymdmtyp == n_MICROCOM #endif /* MINIDIAL */ ) { int x; x = (int) strlen(telnbr); if (x > 0) { if (telnbr[x-1] == ';') { partial = 1; debug(F110,"ckdial sets partial=1:",telnbr,0); } else if (partial) { ckmakmsg(fbuf,FULLNUML,telnbr,";",NULL,NULL); /* add one */ telnbr = fbuf; } } } msleep(500); debug(F101,"ckdial dialtmo","",dialtmo); /* Timeout */ if (fc == 1) { /* ANSWER */ waitct = (dialatmo > -1) ? dialatmo : 0; } else { /* DIAL */ if (dialtmo < 1) { /* Automatic computation. */ #ifdef CK_TAPI if (tttapi && !tapipass) { waitct = 1 * (int)strlen(telnbr) ; /* Worst case dial time */ waitct += 60; /* dialtone + completion wait times */ for (s = telnbr; *s; s++) { /* add in pause characters time */ if (*s == ',') { waitct += 2; /* unless it was changed in the modem */ } else if (*s == 'W' || *s == 'w' || *s == '$' || *s == '@' ) { waitct += 8; } } } else { #endif /* CK_TAPI */ waitct = 1 * (int)strlen(telnbr) ; /* dialtone + completion wait times */ waitct += mp->dial_time; for (s = telnbr; *s; s++) { for (p = mp->pause_chars; *p; p++) if (*s == *p) { waitct += mp->pause_time; break; } } #ifdef CK_TAPI } #endif /* CK_TAPI */ } else { waitct = dialtmo; /* User-specified timeout */ } debug(F101,"ckdial waitct A","",waitct); } /* waitct is our alarm() timer. mdmwait is how long we tell the modem to wait for carrier. We set mdmwait to be 5 seconds less than waitct, to increase the chance that we get a response from the modem before timing out. */ if (waitct <= 0) { /* 0 or negative means wait forever */ #ifdef COMMENT waitct = 254; /* These were backwards in 7.0.196 */ mdmwait = 0; #else waitct = 0; /* Fixed in 7.0.198. */ mdmwait = 254; #endif /* COMMENT */ } else { if (dialtmo < 1) { /* Automatic computation. */ #ifdef XWAITCT /* Addtl wait slop can be defined at compile time */ waitct += XWAITCT; #endif /* XWAITCT */ if (waitct < 60 + mdmwaitd) waitct = 60 + mdmwaitd; } if (mdmcapas & CKD_AT) { /* AT command-set modems */ mdmwait = waitct; /* S7 timeout = what user asked for */ waitct += mdmwaitd; /* Kermit timeout a bit later */ } else { /* Non-AT */ mdmwait = waitct; /* no difference */ } } debug(F101,"ckdial waitct B","",waitct); if (fc == 1) { /* ANSWER */ #ifdef COMMENT /* This is wrong. mdmwait is the value given to S7 in Hayeslike modems. When in autoanswer mode, this is the amount of time the modem waits for carrier once ringing starts. Whereas waitct is the timeout given to the ANSWER command, which is an entirely different thing. Since the default ANSWER timeout is 0 (meaning "wait forever"), the following statement sets S7 to 0, which, on some modems (like the USR Sportster) makes it hang up and report NO CARRIER the instant the phone rings. */ mdmwait = waitct; #else if (mdmwait <= 0) mdmwait = 60; /* Always wait 60 seconds. */ #endif /* COMMENT */ } if (!quiet && !backgrd) { /* Print information messages. */ #ifdef VMS printf(" \n"); fflush(stdout); #endif /* VMS */ if (fc == 1) printf(" Waiting for phone call...\n"); else printf(" %srying: %s...\n", x1 > 0 ? "Ret" : "T", telnbr); if (x1 == 0 && x2 == 0 && dialsta != DIA_PART) { if (network) { printf(" Via modem server: %s, modem: %s\n", ttname, gmdmtyp() ); } else { #ifdef CK_TAPI if (tttapi && !tapipass) printf(" Device: %s, modem: %s", ttname, "TAPI" ); else #endif /* CK_TAPI */ printf(" Device: %s, modem: %s", ttname, gmdmtyp() ); if (speed > -1L) printf(", speed: %ld\n", speed); else printf(", speed: (unknown)\n"); } spdmax = dialmax > 0L ? dialmax : mp->max_speed; #ifndef NOHINTS if (hints && !quiet && !network && spdmax > 0L && speed > spdmax #ifdef CK_TAPI && (!tttapi || tapipass) #endif /* CK_TAPI */ ) { printf("\n*************************\n"); printf( "Interface speed %ld might be too high for this modem type.\n", speed ); printf( "If dialing fails, SET SPEED to %ld or less and try again.\n", spdmax ); printf("(Use SET HINTS OFF to suppress future hints.)\n"); printf("*************************\n"); printf("\n"); } #endif /* NOHINTS */ printf(" %s timeout: ", fc == 0 ? "Dial" : "Answer"); if (waitct > 0) printf("%d seconds\n",mdmwait); else printf(" (none)\n"); printf( #ifdef MAC " Type Command-. to cancel.\n" #else #ifdef UNIX " To cancel: type your interrupt character (normally Ctrl-C).\n" #else " To cancel: type Ctrl-C (hold down Ctrl, press C).\n" #endif /* UNIX */ #endif /* MAC */ ); } } debug(F111,"ckdial",ttname,(int) (speed / 10L)); debug(F101,"ckdial timeout","",waitct); #ifdef OS2 term_io = 0; #endif /* OS2 */ /* Set timer and interrupt handlers. */ savint = signal( SIGINT, dialint ) ; /* And terminal interrupt handler. */ cc_alrm_execute(ckjaddr(sjbuf), 0, dialtime, _dodial, faildial); signal(SIGINT, savint); #ifdef OS2 if (dialsta == DIA_OK) /* Dialing is completed */ DialerSend(OPT_KERMIT_CONNECT, 0); term_io = term_io_sav; #endif /* OS2 */ if (dialsta == DIA_PART || dialsta == DIA_OK) { /* This is needed, e.g., for Telnet modem servers */ if (reliable != SET_OFF || !setreliable) { reliable = SET_OFF; /* Transport is not reliable */ debug(F101,"ckdial reliable","",reliable); } return(1); /* Dial attempt succeeded */ } else { return(0); /* Dial attempt failed */ } } /* ckdial */ /* getok() - wait up to n seconds for OK (0) or ERROR (4) response from modem. Use with Hayeslike or CCITT modems for reading the reply to a nondialing command. Second argument says whether to be strict about numeric result codes, i.e. to require they be preceded by CR or else be the first character in the response, e.g. to prevent the ATH0 echo from looking like a valid response. Strict == 0 is needed for ATI on Telebit, which can return the model number concatenated with the numeric response code, e.g. "9620" ("962" is the model number, "0" is the response code). getok() Returns: 0 if it timed out, 1 if it succeeded, -1 on modem command, i/o, or other error. */ static ckjmpbuf okbuf; static SIGTYP #ifdef CK_ANSIC oktimo(int foo) /* Alarm handler for getok(). */ #else oktimo(foo) int foo; /* Alarm handler for getok(). */ #endif /* CK_ANSIC */ /* oktimo */ { #ifdef OS2 alarm(0); /* signal(SIGALRM,SIG_IGN); */ debug(F100,"oktimo() SIGALRM caught -- SIG_IGN set","",0) ; #endif /* OS2 */ #ifdef OSK /* OS-9, see comment in dialtime(). */ sigmask(-1); #endif /* OSK */ #ifdef NTSIG if ( foo == SIGALRM ) PostAlarmSigSem(); else PostCtrlCSem(); #else /* NTSIG */ #ifdef NT cklongjmp(ckjaddr(okbuf),1); #else /* NT */ cklongjmp(okbuf,1); #endif /* NTSIG */ #endif /* NT */ /* NOTREACHED */ SIGRETURN; } static int okstatus, okn, okstrict; static SIGTYP #ifdef CK_ANSIC dook(void * threadinfo) #else /* CK_ANSIC */ dook(threadinfo) VOID * threadinfo ; #endif /* CK_ANSIC */ /* dook */ { CHAR c; int i, x; #ifdef IKSD extern int inserver; #endif /* IKSD */ #ifdef NTSIG signal(SIGINT,oktimo); if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); } #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef NT #ifdef IKSD if (inserver) setntcreds(); #endif /* IKSD */ #endif /* NT */ #endif /* CK_LOGIN */ if (mdmcapas & CKD_V25) { /* CCITT, easy... */ waitfor("VAL"); okstatus = 1; debug(F111,"Modem_Response(V25)","VAL",okstatus); #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; #ifndef MINIDIAL } else if (mymdmtyp == n_MICROCOM) { /* Microcom in SX mode, also easy */ waitfor(MICROCOM.wake_prompt); /* (I think...) */ debug(F111,"Modem_Response(Microcom)",MICROCOM.wake_prompt,okstatus); okstatus = 1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; #endif /* MINIDIAL */ } else { /* Hayes & friends, start here... */ okstatus = 0; /* No status yet. */ for (x = 0; x < RBUFL; x++) /* Initialize response buffer */ rbuf[x] = SP; /* to all spaces */ rbuf[RBUFL] = NUL; /* and terminate with NUL. */ while (okstatus == 0) { /* While no status... */ x = ddinc(okn); /* Read a character */ if (x < 0) { /* I/O error */ okstatus = -1; #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; } #ifdef COMMENT /* too much */ debug(F101,"getok ddinc","",x); /* Got a character. */ #endif /* COMMENT */ c = (char) (x & 0x7f); /* Get low order 7 bits */ if (!c) /* Don't deposit NULs */ continue; /* or else didweget() won't work */ if (dialdpy) conoc((char)c); /* Echo it if requested */ for (i = 0; i < RBUFL-1; i++) /* Rotate buffer */ rbuf[i] = rbuf[i+1]; rbuf[RBUFL-1] = c; /* Deposit character at end */ #ifdef COMMENT /* too much */ debug(F000,"getok:",rbuf,(int) c); /* Log it */ #endif /* COMMENT */ switch (c) { /* Interpret it. */ case CK_CR: /* Got a carriage return. */ switch(rbuf[RBUFL-2]) { /* Look at character before it. */ case '0': /* 0 = OK numeric response */ if (!okstrict || rbuf[RBUFL-3] == CK_CR || rbuf[RBUFL-3] == SP) { nonverbal = 1; okstatus = 1; /* Good response */ } debug(F111,"Modem_Response(Hayes)","0",okstatus); break; case '4': /* 4 = ERROR numeric response */ #ifndef MINIDIAL /* Or Telebit model number 964! */ if (mymdmtyp == n_TELEBIT && isdigit(rbuf[RBUFL-3]) && isdigit(rbuf[RBUFL-4])) break; else #endif /* MINIDIAL */ if (!okstrict || rbuf[RBUFL-3] == CK_CR || rbuf[RBUFL-3] == SP) { nonverbal = 1; okstatus = -1; /* Bad command */ } debug(F111,"Modem_Response(Hayes)","4",okstatus); break; } if (dialdpy && nonverbal) /* If numeric results, */ conoc(LF); /* echo a linefeed too. */ break; case LF: /* Got a linefeed. */ /* Note use of explicit octal codes in the string for CR and LF. We want real CR and LF here, not whatever the compiler happens to replace \r and \n with... */ if (!strcmp(rbuf+RBUFL-4,"OK\015\012")) { /* Good response */ okstatus = 1; debug(F111,"Modem_Response(Hayes)","OK",okstatus); } if (!strcmp(rbuf+RBUFL-3,"OK\012")) { /* Good response */ okstatus = 1; debug(F111,"Modem_Response(Hayes)","OK",okstatus); } else if (!strcmp(rbuf+RBUFL-7,"ERROR\015\012")) { /* Error */ okstatus = -1; debug(F111,"Modem_Response(Hayes)","ERROR",okstatus); } else if (!strcmp(rbuf+RBUFL-6,"ERROR\012")) { /* Error */ okstatus = -1; debug(F111,"Modem_Response(Hayes)","ERROR",okstatus); } break; /* Check whether modem echoes its commands... */ case 't': /* Got little t */ if (!strcmp(rbuf+RBUFL-3,"\015at") || /* See if it's "at" */ !strcmp(rbuf+RBUFL-3," at")) mdmecho = 1; /* debug(F111,"MDMECHO-t",rbuf+RBUFL-2,mdmecho); */ break; case 'T': /* Got Big T */ if (!strcmp(rbuf+RBUFL-3,"\015AT") || /* See if it's "AT" */ !strcmp(rbuf+RBUFL-3," AT")) mdmecho = 1; /* debug(F111,"MDMECHO-T",rbuf+RBUFL-3,mdmecho); */ break; default: /* Other characters, accumulate. */ okstatus = 0; break; } } } debug(F101,"getok","",okstatus); /* <-- It's a lie (why?) */ #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; } static SIGTYP #ifdef CK_ANSIC failok(void * threadinfo) #else /* CK_ANSIC */ failok(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ /* failok */ { debug(F100,"longjmp returned to getok()","",0); debug(F100,"getok timeout","",0); SIGRETURN; } int #ifdef CK_ANSIC getok( int n, int strict ) #else getok(n, strict) int n, strict; #endif /* CK_ANSIC */ { debug(F101,"getok entry n","",n); okstatus = 0; okn = n; okstrict = strict; #ifdef DYNAMIC if (!rbuf) { if (!(rbuf = malloc(RBUFL+1))) { /* Allocate input line buffer */ dialsta = DIA_IE; return(-1); } debug(F101,"GETOK rbuf malloc ok","",RBUFL+1); } #endif /* DYNAMIC */ mdmecho = 0; /* Assume no echoing of commands */ debug(F100,"about to alrm_execute dook()","",0); alrm_execute( ckjaddr(okbuf), n, oktimo, dook, failok ) ; debug(F100,"returning from alrm_execute dook()","",0); ttflui(); /* Flush input buffer */ return(okstatus); /* Return status */ } /* G E T H R N -- Get Hayes Result Numeric */ static VOID gethrn() { char c; int x; /* Hayes numeric result codes (Hayes 1200 and higher): 0 = OK 1 = CONNECT at 300 bps (or 1200 bps on Hayes 1200 with basic code set) 2 = RING 3 = NO CARRIER 4 = ERROR (in command line) 5 = CONNECT 1200 (extended code set) Hayes 2400 and higher: 6 = NO DIALTONE 7 = BUSY 8 = NO ANSWER 9 = (there is no 9) 10 = CONNECT 2400 Reportedly, the codes for Hayes V.32 modems are: 1x = CONNECT 5x = CONNECT 1200 9x = CONNECT 2400 11x = CONNECT 4800 12x = CONNECT 9600 Where: x: suffix: R = RELIABLE RC = RELIABLE COMPRESSED L = LAPM LC = LAPM COMPRESSED And for Telebits, all the above, except no suffix in numeric mode, plus: 11 = CONNECT 4800 12 = CONNECT 9600 13 = CONNECT 14400 14 = CONNECT 19200 15 = CONNECT 38400 16 = CONNECT 57600 20 = CONNECT 300/REL (= MNP) 22 = CONNECT 1200/REL (= MNP) 23 = CONNECT 2400/REL (= MNP) 46 = CONNECT 7512 (i.e. 75/1200) 47 = CONNECT 1275 (i.e. 1200/75) 48 = CONNECT 7200 49 = CONNECT 12000 50 = CONNECT FAST (not on T1600/3000) 52 = RRING 53 = DIALING 54 = NO PROMPTTONE 61 = CONNECT FAST/KERM (Kermit spoof) 70 = CONNECT FAST/COMP (PEP + compression) 71 = CONNECT FAST/KERM/COMP (PEP + compression + Kermit spoof) And for others, lots of special cases below... */ #define NBUFL 8 char nbuf[NBUFL+1]; /* Response buffer */ int i = 0, j = 0; /* Buffer pointers */ debug(F101,"RESPONSE mdmecho","",mdmecho); if (mdmecho) { /* Sponge up dialing string echo. */ while (1) { c = (char) (ddinc(0) & 0x7f); debug(F000,"SPONGE","",c); dialoc(c); if (c == CK_CR) break; } } while (mdmstat == 0) { /* Read response */ for (i = 0; i < NBUFL; i++) /* Clear the buffer */ nbuf[i] = '\0'; i = 0; /* Reset the buffer pointer. */ c = (char) (ddinc(0) & 0177); /* Get first digit of response. */ /* using an untimed, blocking read. */ debug(F000,"RESPONSE-A","",c); dialoc(c); /* Echo it if requested. */ if (!isdigit(c)) /* If not a digit, keep looking. */ continue; nbuf[i++] = c; /* Got first digit, save it. */ while (c != CK_CR && i < 8) { /* Read chars up to CR */ x = ddinc(0) & 0177; /* Get a character. */ c = (char) x; /* Got it OK. */ debug(F000,"RESPONSE-C","",c); if (c != CK_CR) /* If it's not a carriage return, */ nbuf[i++] = c; /* save it. */ dialoc(c); /* Echo it. */ } nbuf[i] = '\0'; /* Done, terminate the buffer. */ debug(F110,"dial hayesnv lbuf",lbuf,0); debug(F111,"dial hayesnv got",nbuf,i); /* Separate any non-numeric suffix from the numeric result code with a null. */ for (j = i-1; (j > -1) && !isdigit(nbuf[j]); j--) nbuf[j+1] = nbuf[j]; j++; nbuf[j++] = '\0'; debug(F110,"dial hayesnv numeric",nbuf,0); debug(F111,"dial hayesnv suffix ",nbuf+j,j); /* Probably phone number echoing. */ if ((int)strlen(nbuf) > 3) continue; /* Now read and interpret the results... */ i = atoi(nbuf); /* Convert to integer */ switch (i) { case 0: mdmstat = D_PARTIAL; /* OK response */ break; case 1: /* CONNECT */ mdmstat = CONNECTED; /* Could be any speed */ break; case 2: /* RING */ if (dialdpy) printf("\r\n Local phone is ringing!\r\n"); mdmstat = D_FAILED; dialsta = DIA_RING; break; case 3: /* NO CARRIER */ if (dialdpy) printf("\r\n No Carrier.\r\n"); mdmstat = D_FAILED; dialsta = DIA_NOCA; break; case 4: /* ERROR */ if (dialdpy) printf("\r\n Modem Command Error.\r\n"); mdmstat = D_FAILED; dialsta = DIA_ERR; break; case 5: /* CONNECT 1200 */ spdchg(1200L); /* Change speed if necessary. */ mdmstat = CONNECTED; break; case 6: /* NO DIALTONE */ #ifndef MINIDIAL if (mymdmtyp == n_MICROLINK && atoi(diallcc) == 49 && dialdpy) printf("\r\n Dial Locked.\r\n"); /* Germany */ else #endif /* MINIDIAL */ if (dialdpy) printf("\r\n No Dialtone.\r\n"); mdmstat = D_FAILED; dialsta = DIA_NODT; break; case 7: /* BUSY */ if (dialdpy) printf("\r\n Busy.\r\n"); mdmstat = D_FAILED; dialsta = DIA_BUSY; break; case 8: /* NO ANSWER */ #ifndef MINIDIAL if (mymdmtyp == n_MICROLINK && atoi(diallcc) == 41 && dialdpy) printf("\r\n Dial Locked.\r\n"); /* Switzerland */ else #endif /* MINIDIAL */ if (dialdpy) printf("\r\n No Answer.\r\n"); mdmstat = D_FAILED; dialsta = DIA_NOAN; break; case 9: #ifndef MINIDIAL if (mymdmtyp == n_XJACK || mymdmtyp == n_SUPRAX) { spdchg(600); break; } /* fall thru */ #endif /* MINIDIAL */ case 10: /* CONNECT 2400 */ spdchg(2400L); /* Change speed if necessary. */ mdmstat = CONNECTED; break; #ifndef MINIDIAL /* Starting here, we get different meanings from different manufacturers */ case 11: if (mymdmtyp == n_USR) { if (dialdpy) printf(" Ringing...\r\n"); } else { spdchg(4800L); /* CONNECT 4800 */ mdmstat = CONNECTED; } break; case 12: if (mymdmtyp == n_USR) { if (dialdpy) printf("\r\n Answered by voice.\r\n"); mdmstat = D_FAILED; dialsta = DIA_VOIC; } else if (mymdmtyp == n_KEEPINTOUCH) { spdchg(7200L); mdmstat = CONNECTED; } else { spdchg(9600L); mdmstat = CONNECTED; } break; case 13: if (mymdmtyp == n_ATT1900 || mymdmtyp == n_ATT1910) { if (dialdpy) printf(" Wait...\r\n"); break; } else if (mymdmtyp == n_USR || mymdmtyp == n_USRX2) spdchg(9600L); else if (is_rockwell || is_supra || mymdmtyp == n_ZOLTRIX || mymdmtyp == n_XJACK) spdchg(7200L); else if (mymdmtyp != n_MICROLINK) spdchg(14400L); mdmstat = CONNECTED; break; case 14: if (is_rockwell || is_supra || mymdmtyp == n_XJACK) spdchg(12000L); else if (mymdmtyp == n_DATAPORT || mymdmtyp == n_MICROLINK) spdchg(14400L); else if (mymdmtyp == n_KEEPINTOUCH) spdchg(9600L); else if (mymdmtyp != n_USR && mymdmtyp != n_ZOLTRIX) spdchg(19200L); mdmstat = CONNECTED; break; case 15: if (is_rockwell || is_supra || mymdmtyp == n_ZOLTRIX || mymdmtyp == n_XJACK) spdchg(14400L); else if (mymdmtyp == n_USR) spdchg(1200L); else if (mymdmtyp == n_ZYXEL || mymdmtyp == n_INTEL) spdchg(7200L); else if (mymdmtyp == n_DATAPORT) spdchg(19200L); else spdchg(38400L); mdmstat = CONNECTED; break; case 16: if (is_rockwell || is_supra || mymdmtyp == n_ZOLTRIX || mymdmtyp == n_XJACK) spdchg(19200L); else if (mymdmtyp == n_USR) spdchg(2400L); else if (mymdmtyp == n_DATAPORT) spdchg(7200L); else if (mymdmtyp != n_ZYXEL && mymdmtyp != n_INTEL) /* 12000 */ spdchg(57600L); mdmstat = CONNECTED; break; case 17: if (mymdmtyp != n_DATAPORT || mymdmtyp == n_XJACK) /* 16800 */ spdchg(38400L); else if (mymdmtyp == n_ZYXEL || mymdmtyp == n_INTEL) spdchg(14400L); else if (mymdmtyp == n_KEEPINTOUCH) spdchg(14400L); else if (mymdmtyp == n_USR) spdchg(9600L); mdmstat = CONNECTED; break; case 18: if (is_rockwell || is_supra || mymdmtyp == n_ZOLTRIX || mymdmtyp == n_XJACK || mymdmtyp == n_MHZATT || mymdmtyp == n_LUCENT) spdchg(57600L); else if (mymdmtyp == n_INTEL) spdchg(19200L); else if (mymdmtyp == n_USR || mymdmtyp == n_USRX2) spdchg(4800L); mdmstat = CONNECTED; break; case 19: if (mymdmtyp == n_DATAPORT) spdchg(300L); else if (mymdmtyp == n_ZYXEL || mymdmtyp == n_INTEL) spdchg(38400L); else spdchg(115200L); mdmstat = CONNECTED; break; case 20: if (mymdmtyp == n_USR || mymdmtyp == n_USRX2) spdchg(7200L); else if (mymdmtyp == n_DATAPORT) spdchg(2400L); else if (mymdmtyp == n_ZYXEL || mymdmtyp == n_INTEL) spdchg(57600L); else spdchg(300L); mdmstat = CONNECTED; break; case 21: if (mymdmtyp == n_DATAPORT) spdchg(4800L); mdmstat = CONNECTED; break; case 22: if (is_rockwell || is_supra || mymdmtyp == n_XJACK) spdchg(8880L); else if (mymdmtyp == n_DATAPORT) spdchg(9600L); else if (mymdmtyp == n_KEEPINTOUCH) spdchg(300L); else if (!is_hayeshispd) spdchg(1200L); mdmstat = CONNECTED; break; case 23: if (is_hayeshispd || is_supra || mymdmtyp == n_MULTI || mymdmtyp == n_XJACK) spdchg(8880L); else if (mymdmtyp != n_DATAPORT && !is_rockwell) /* 12000 */ spdchg(2400L); mdmstat = CONNECTED; break; case 24: if (is_rockwell || is_supra || mymdmtyp == n_XJACK) { mdmstat = D_FAILED; dialsta = DIA_DELA; /* Delayed */ break; } else if (is_hayeshispd || mymdmtyp == n_LUCENT) spdchg(7200L); else if (mymdmtyp == n_DATAPORT) spdchg(14400L); else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) spdchg(1200L); mdmstat = CONNECTED; break; case 25: if (mymdmtyp == n_USR || mymdmtyp == n_USRX2) spdchg(14400L); else if (mymdmtyp == n_LUCENT) spdchg(12000L); else if (is_motorola) spdchg(9600L); else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) spdchg(2400L); mdmstat = CONNECTED; break; case 26: if (mymdmtyp == n_DATAPORT) spdchg(19200L); else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) spdchg(4800L); mdmstat = CONNECTED; break; case 27: if (mymdmtyp == n_DATAPORT) spdchg(38400L); else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) spdchg(7200L); else if (mymdmtyp == n_MHZATT) spdchg(8880L); mdmstat = CONNECTED; break; case 28: if (mymdmtyp == n_DATAPORT) spdchg(7200L); else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) spdchg(9600L); else if (mymdmtyp == n_MHZATT || mymdmtyp == n_LUCENT) spdchg(38400L); mdmstat = CONNECTED; break; case 29: if (is_motorola) spdchg(4800L); else if (mymdmtyp == n_DATAPORT) spdchg(19200L); mdmstat = CONNECTED; break; case 30: if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(14400L); mdmstat = CONNECTED; } /* fall thru on purpose... */ case 31: if (mymdmtyp == n_UCOM_AT || mymdmtyp == n_MICROLINK) { spdchg(4800L); mdmstat = CONNECTED; } else if (is_motorola) { spdchg(57600L); mdmstat = CONNECTED; } break; case 32: if (is_rockwell || is_supra || mymdmtyp == n_XJACK) { mdmstat = D_FAILED; dialsta = DIA_BLCK; /* Blacklisted */ } else if (mymdmtyp == n_UCOM_AT || mymdmtyp == n_MICROLINK) { spdchg(9600L); mdmstat = CONNECTED; } else if (mymdmtyp == n_KEEPINTOUCH) { spdchg(300L); mdmstat = CONNECTED; } else if (mymdmtyp == n_INTEL) { spdchg(2400L); mdmstat = CONNECTED; } break; case 33: /* FAX connection */ if (is_rockwell || is_supra || mymdmtyp == n_ZOLTRIX || mymdmtyp == n_XJACK) { mdmstat = D_FAILED; dialsta = DIA_FAX; } else if (mymdmtyp == n_UCOM_AT || is_motorola || mymdmtyp == n_MICROLINK ) { spdchg(9600L); mdmstat = CONNECTED; } else if (mymdmtyp == n_MHZATT) { spdchg(115200L); mdmstat = CONNECTED; } break; case 34: if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(1200L); mdmstat = CONNECTED; } else if (mymdmtyp == n_MICROLINK) { spdchg(7200L); mdmstat = CONNECTED; } break; case 35: if (is_rockwell) { spdchg(300L); dialsta = CONNECTED; } else if (is_motorola) { spdchg(14400L); mdmstat = CONNECTED; } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(2400L); mdmstat = CONNECTED; } else if (mymdmtyp == n_MICROLINK) { spdchg(7200L); mdmstat = CONNECTED; } else if (mymdmtyp == n_ZOLTRIX || mymdmtyp == n_XJACK) /* DATA */ mdmstat = CONNECTED; break; case 36: if (mymdmtyp == n_UCOM_AT) { spdchg(19200L); mdmstat = CONNECTED; } else if (is_motorola) { spdchg(1200L); mdmstat = CONNECTED; } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(4800L); mdmstat = CONNECTED; } break; case 37: if (mymdmtyp == n_UCOM_AT) { spdchg(19200L); mdmstat = CONNECTED; } else if (is_motorola) { spdchg(2400L); mdmstat = CONNECTED; } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(7200L); mdmstat = CONNECTED; } break; case 38: if (is_motorola) { spdchg(4800L); mdmstat = CONNECTED; } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(9600L); mdmstat = CONNECTED; } /* fall thru on purpose... */ case 39: if (mymdmtyp == n_UCOM_AT) { spdchg(38400L); mdmstat = CONNECTED; } else if (is_motorola) { spdchg(9600L); mdmstat = CONNECTED; } else if (mymdmtyp == n_MICROLINK) { spdchg(14400L); mdmstat = CONNECTED; } break; case 40: if (mymdmtyp == n_UCOM_AT) { mdmstat = D_FAILED; dialsta = DIA_NOCA; } else if (is_motorola || mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(14400L); mdmstat = CONNECTED; } break; case 41: if (is_motorola) { spdchg(19200L); mdmstat = CONNECTED; } break; case 42: if (mymdmtyp == n_KEEPINTOUCH) { spdchg(300L); mdmstat = CONNECTED; } else if (is_motorola) { spdchg(38400L); mdmstat = CONNECTED; } /* fall thru on purpose... */ case 43: if (mymdmtyp == n_UCOM_AT) { spdchg(57600L); mdmstat = CONNECTED; } else if (mymdmtyp == n_USRX2) mdmstat = CONNECTED; /* 168000 */ break; case 44: if (is_rockwell) { spdchg(8800L); dialsta = CONNECTED; } else if (is_motorola) { spdchg(7200L); mdmstat = CONNECTED; } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(1200L); mdmstat = CONNECTED; } break; case 45: if (is_motorola) { spdchg(57600L); mdmstat = CONNECTED; } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(2400L); mdmstat = CONNECTED; } else if (n_USR) { spdchg(14400L); mdmstat = CONNECTED; } break; case 46: if (is_rockwell) spdchg(1200L); else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) spdchg(4800L); else spdchg(8880L); /* 75/1200 split speed */ mdmstat = CONNECTED; break; case 47: if (is_rockwell) spdchg(2400L); else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) spdchg(7200L); else printf("CONNECT 1200/75 - Not supported by C-Kermit\r\n"); mdmstat = CONNECTED; break; case 48: if (is_rockwell) spdchg(4800L); else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) spdchg(9600L); else spdchg(7200L); mdmstat = CONNECTED; break; case 49: if (is_rockwell) spdchg(7200L); mdmstat = CONNECTED; break; case 50: /* CONNECT FAST */ if (is_rockwell) spdchg(9600L); else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) spdchg(14400L); mdmstat = CONNECTED; break; case 51: if (mymdmtyp == n_UCOM_AT) { mdmstat = D_FAILED; dialsta = DIA_NODT; } break; case 52: /* RRING */ if (mymdmtyp == n_TELEBIT) if (dialdpy) printf(" Ringing...\r\n"); break; case 53: /* DIALING */ if (mymdmtyp == n_TELEBIT) if (dialdpy) printf(" Dialing...\r\n"); break; case 54: if (is_rockwell) { spdchg(19200L); mdmstat = CONNECTED; } else if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(1200L); mdmstat = CONNECTED; } else if (mymdmtyp == n_TELEBIT) { if (dialdpy) printf("\r\n No Prompttone.\r\n"); mdmstat = D_FAILED; dialsta = DIA_NODT; } break; case 55: if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(2400L); mdmstat = CONNECTED; } break; case 56: if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(4800L); mdmstat = CONNECTED; } break; case 57: if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(7200L); mdmstat = CONNECTED; } break; case 58: if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(9600L); mdmstat = CONNECTED; } break; case 59: if (mymdmtyp == n_INTEL) /* 12000 */ mdmstat = CONNECTED; break; case 60: if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(14400L); mdmstat = CONNECTED; } break; case 64: if (mymdmtyp == n_INTEL) { spdchg(1200L); mdmstat = CONNECTED; } else if (is_supra) { spdchg(28800L); mdmstat = CONNECTED; } break; case 65: if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(2400L); mdmstat = CONNECTED; } break; case 66: if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(4800L); mdmstat = CONNECTED; } break; case 67: if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(7200L); mdmstat = CONNECTED; } break; case 68: if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(9600L); mdmstat = CONNECTED; } break; case 69: if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) /* 12000 */ mdmstat = CONNECTED; break; case 70: if (mymdmtyp == n_INTEL || mymdmtyp == n_KEEPINTOUCH) { spdchg(14400L); mdmstat = CONNECTED; } break; case 73: if (mymdmtyp == n_UCOM_AT) { spdchg(115200L); mdmstat = CONNECTED; break; } /* else fall thru */ if (mymdmtyp == n_TELEBIT) /* Early models only */ mdmstat = CONNECTED; break; case 85: if (mymdmtyp == n_USR || mymdmtyp == n_USRX2) spdchg(19200L); mdmstat = CONNECTED; break; case 91: /* 21600 */ case 99: /* 24000 */ case 103: /* 26400 */ if (mymdmtyp == n_USRX2) mdmstat = CONNECTED; break; case 107: if (mymdmtyp == n_USR || mymdmtyp == n_USRX2) { spdchg(28800L); mdmstat = CONNECTED; } break; case 151: /* 312000 */ case 155: /* 336000 */ if (mymdmtyp == n_USRX2) mdmstat = CONNECTED; break; #endif /* MINIDIAL */ default: #ifndef MINIDIAL if (mymdmtyp == n_USR || mymdmtyp == n_USRX2 || is_hayeshispd || is_rockwell) #endif /* MINIDIAL */ if (i > 12) /* There are hundreds of them... */ mdmstat = CONNECTED; break; } } if (mdmstat == CONNECTED && nbuf[j] != '\0') { if (dialdpy) { printf("\r\n"); if (nbuf[j] == 'R') printf(" RELIABLE"); if (nbuf[j] == 'L') printf(" LAPM"); if (nbuf[j+1] == 'C') printf(" COMPRESSED"); printf("\r\n"); } ckstrncpy(lbuf,nbuf,LBUFL); /* (for messages...) */ } } static VOID /* Get Hayes Result in Word mode */ gethrw() { char *cptr, *s; long conspd; if (mdmspd && !network) { s = lbuf; while (*s != '\0' && *s != 'C') s++; cptr = (*s == 'C') ? s : NULL; conspd = 0L; if ((cptr != NULL) && !strncmp(cptr,"CONNECT ",8)) { if ((int)strlen(cptr) < 9) /* Just CONNECT, */ conspd = 300L; /* use 300 bps */ else if (isdigit(*(cptr+8))) /* not CONNECT FAST */ conspd = atol(cptr + 8); /* CONNECT nnnn */ if (conspd != speed) { if ((conspd / 10L) > 0) { if (ttsspd((int) (conspd / 10L)) < 0) { printf(" Can't change speed to %ld\r\n", conspd); } else { speed = conspd; mdmstat = CONNECTED; if ( !quiet && !backgrd ) printf(" Speed changed to %ld\r\n", conspd); } } } /* Expanded to handle any conceivable speed */ } } #ifndef MINIDIAL if (mymdmtyp == n_TELEBIT) { if (didweget(lbuf,"CONNECT FAST/KERM")) { mdmstat = CONNECTED; if (dialdpy) printf("FAST/KERM "); return; } } #endif /* MINIDIAL */ if (didweget(lbuf,"RRING") || didweget(lbuf,"RINGING") || didweget(lbuf,"DIALING")) { mdmstat = 0; } else if (didweget(lbuf,"CONNECT")) { mdmstat = CONNECTED; } else if (didweget(lbuf,"OK")) { if (partial) { mdmstat = D_PARTIAL; } else { mdmstat = D_FAILED; dialsta = DIA_ERR; } } else if (didweget(lbuf,"NO CARRIER")) { mdmstat = D_FAILED; dialsta = DIA_NOCA; } else if (didweget(lbuf,"NO DIALTONE")) { mdmstat = D_FAILED; dialsta = DIA_NODT; } else if (didweget(lbuf,"NO DIAL TONE")) { mdmstat = D_FAILED; dialsta = DIA_NODT; } else if (didweget(lbuf,"BUSY")) { mdmstat = D_FAILED; dialsta = DIA_BUSY; } else if (didweget(lbuf,"NO ANSWER")) { mdmstat = D_FAILED; dialsta = DIA_NOAN; } else if (didweget(lbuf,"VOICE")) { mdmstat = D_FAILED; dialsta = DIA_VOIC; } else if (didweget(lbuf,"VCON")) { mdmstat = D_FAILED; dialsta = DIA_VOIC; } else if (didweget(lbuf,"NO PROMPT TONE")) { mdmstat = D_FAILED; dialsta = DIA_NODT; } else if (didweget(lbuf,"REMOTE ACCESS FAILED")) { mdmstat = D_FAILED; dialsta = DIA_NOCA; } else if (didweget(lbuf,"FAX")) { mdmstat = D_FAILED; dialsta = DIA_FAX; } else if (didweget(lbuf,"WAIT - CONNECTING") || didweget(lbuf,"WAIT-CONNECTING")) { /* AT&T STU-III 19xx */ mdmstat = 0; } else if (didweget(lbuf,"DELAYED")) { mdmstat = D_FAILED; dialsta = DIA_DELA; } else if (didweget(lbuf,"BLACKLISTED")) { mdmstat = D_FAILED; dialsta = DIA_BLCK; } else if (didweget(lbuf,"COMPRESSION")) { mdmstat = 0; } else if (didweget(lbuf,"PROTOCOL")) { mdmstat = 0; } else if (didweget(lbuf,"DIAL LOCKED")) { /* Germany, Austria, Schweiz */ mdmstat = D_FAILED; dialsta = DIA_BLCK; } else if ( didweget(lbuf,"RING") || didweget(lbuf,"RING1") || /* Distinctive Ring 1 */ didweget(lbuf,"RING2") || /* Distinctive Ring 2 */ didweget(lbuf,"RING3") ) { mdmstat = (func_code == 0) ? D_FAILED : 0; dialsta = DIA_RING; } else if (didweget(lbuf,"ERROR")) { mdmstat = D_FAILED; dialsta = DIA_ERR; } else if (didweget(lbuf,"CARRIER")) { /* Boca / Rockwell family */ #ifdef COMMENT if (is_rockwell) #endif /* COMMENT */ mdmstat = 0; #ifdef COMMENT /* Does CARRIER ever mean the same as CONNECT? */ else mdmstat = CONNECTED; #endif /* COMMENT */ } else if (didweget(lbuf,"DATA")) { /* Boca / Rockwell family */ /* This message is sent when the modem is in FAX mode */ /* So setting this to CONNECTED may not be appropriate */ /* We must send ATO\015 to the modem in response */ /* Then we will get a CONNECTED message */ mdmstat = CONNECTED; } else if (didweget(lbuf,"DIGITAL LINE")) { mdmstat = D_FAILED; dialsta = DIA_DIGI; } else if (didweget(lbuf,"DATE")) { /* Caller ID Date */ debug(F110,"CALLID DATE",lbuf,0); /* Format is "DATE = MMDD" */ makestr(&callid_date,lbuf); } else if (didweget(lbuf,"TIME")) { /* Caller ID Time */ /* Format is "TIME = HHMM" */ debug(F110,"CALLID TIME",lbuf,0); makestr(&callid_time,lbuf); } else if (didweget(lbuf,"NAME")) { /* Caller ID Name */ /* Format is "NAME = " */ debug(F110,"CALLID NAME",lbuf,0); makestr(&callid_name,lbuf); } else if (didweget(lbuf,"NMBR")) { /* Caller ID Number */ /* Format is "NMBR = , 'P' or 'O'" */ /* 'P' means Privacy Requested */ /* 'O' means Out of Service or Not available */ debug(F110,"CALLID NMBR",lbuf,0); makestr(&callid_nmbr,lbuf); } else if (didweget(lbuf,"MESG")) { /* Caller ID Unrecognized Message */ /* Format is "MESG = " */ debug(F110,"CALLID MESG",lbuf,0); makestr(&callid_mesg,lbuf); } } /* Maybe hang up the phone, depending on various SET DIAL parameters. */ int dialhup() { int x = 0; if (dialhng && dialsta != DIA_PART) { /* DIAL HANGUP ON? */ x = mdmhup(); /* Try modem-specific method first */ debug(F101,"dialhup mdmhup","",x); if (x > 0) { /* If it worked, */ dialsta = DIA_HUP; if (dialdpy) printf(" Modem hangup OK\r\n"); /* fine. */ } else if (network /* If we're telnetted to */ #ifdef TN_COMPORT && !istncomport() /* (without RFC 2217) */ #endif /* TN_COMPORT */ ) { dialsta = DIA_HANG; if (dialdpy) /* a modem server, just print a msg */ printf(" WARNING - modem hangup failed\r\n"); /* don't hangup! */ return(0); } else { /* Otherwise */ x = tthang(); /* Tell the OS to turn off DTR. */ if (x > 0) { /* Yes, tell results from tthang() */ dialsta = DIA_HUP; if (dialdpy) printf(" Hangup OK\r\n"); } else if (x == 0) { if (dialdpy) printf(" Hangup skipped\r\n"); } else { dialsta = DIA_HANG; if (dialdpy) perror(" Hangup error"); } ttflui(); } } else if (dialdpy) printf(" Hangup skipped\r\n"); /* DIAL HANGUP OFF */ return(x); } /* M D M H U P -- Sends escape sequence to modem, then sends its hangup command. Returns: 0: If modem type is 0 (direct serial connection), or if modem type is < 0 (network connection), or if no action taken because DIAL MODEM-HANGUP is OFF) or because no hangup string for current modem type, or C-Kermit is in remote mode, or if action taken but there was no positive response from modem; 1: Success: modem is in command state and acknowledged the hangup command; -1: On modem command error. */ int mdmhup() { #ifdef MDMHUP int m, x = 0; int xparity; int savcarr; extern int ttcarr; char *s, c; MDMINF * mp = NULL; debug(F101,"mdmhup dialmhu","",dialmhu); /* MODEM-HANGUP METHOD */ debug(F101,"mdmhup local","",local); if (dialmhu == 0 || local == 0) /* If DIAL MODEM-HANGUP is OFF, */ return(0); /* or not in local mode, fail. */ debug(F101,"mdmhup dialsta","",dialsta); debug(F101,"mdmhup mdmset","",mdmset); if (dialsta != DIA_OK && !mdmset) /* It's not a dialed connection */ return(0); #ifdef CK_TAPI if (tttapi && !tapipass) /* Don't hangup if using TAPI */ return(0); #endif /* CK_TAPI */ #ifdef COMMENT /* No, we still need this for modems that ignore DTR */ if (mymdmtyp == n_GENERIC && !network) return(0); #endif /* COMMENT */ debug(F101,"mdmhup dialesc","",dialesc); if (dialesc < 0) return(0); /* No modem escape-character, fail. */ savcarr = ttcarr; ttcarr = CAR_OFF; x = ttchk(); ttcarr = savcarr; debug(F101,"mdmhup ttchk","",x); if (x < 0) /* There appears to be no connection */ return(0); x = 0; #ifdef OS2 /* In OS/2, if CARRIER is OFF, and there is indeed no carrier signal, any attempt to do i/o at this point can hang the program. This might be true for other operating systems too. */ if (!network /* Not a network connection */ #ifdef TN_COMPORT || istncomport() #endif /* TN_COMPORT */ ) { m = ttgmdm(); /* Get modem signals */ if ((m > -1) && (m & BM_DCD == 0)) /* Check for carrier */ return(0); /* No carrier, skip the rest */ } #endif /* OS2 */ debug(F111,"mdmhup network",ttname,network); debug(F101,"mdmhup mymdmtyp","",mymdmtyp); debug(F101,"mdmhup mdmtyp","",mdmtyp); /* In case of HANGUP before DIAL */ if (network && mdmtyp < 1) /* SET HOST but no subsequent */ return(0); /* SET MODEM TYPE... */ if (mymdmtyp == 0 && mdmtyp > 0) mymdmtyp = mdmtyp; if (mymdmtyp < 1) /* Not using a modem */ return(0); if (mymdmtyp > 0) /* An actual modem... */ mp = modemp[mymdmtyp]; if (!mp) { /* Get pointer to its MDMINF struct */ debug(F100,"mdmhup no MDMINF","",0); return(0); } mdmcapas = dialcapas ? dialcapas : mp->capas; xx_ok = mp->ok_fn; /* Pointer to response reader */ s = dialhcmd ? dialhcmd : mp->hup_str; /* Get hangup command */ if (!s) s = ""; debug(F110,"mdmhup hup_str",s,0); if (!*s) return(0); /* If none, fail. */ if (ttpkt(speed,FLO_DIAL,parity) < 0) /* Condition line for dialing */ return(-1); xparity = parity; /* Set PARITY to NONE temporarily */ parity = 0; /* In case they gave a SET MODEM ESCAPE command recently... */ if (dialesc < 0 || dialesc > 127) c = NUL; else c = (char) (dialesc ? dialesc : mp->esc_char); if (mdmcapas & CKD_AT) { /* Hayes compatible */ escbuf[0] = c; escbuf[1] = c; escbuf[2] = c; escbuf[3] = NUL; } else { /* Other */ escbuf[0] = c; escbuf[1] = NUL; } debug(F110,"mdmhup escbuf",escbuf,0); if (escbuf[0]) { /* Have escape sequence? */ debug(F101,"mdmhup esc_time",0,mp->esc_time); if (mp->esc_time) /* If we have a guard time */ msleep(mp->esc_time); /* Pause for guard time */ debug(F100,"mdmhup pause 1 OK","",0); #ifdef NETCONN /* Send modem's escape sequence */ if (network) { /* Must catch errors here. */ if (ttol((CHAR *)escbuf,(int)strlen((char *)escbuf)) < 0) { parity = xparity; return(-1); } debug(F110,"mdmhup ttslow net ok",escbuf,0); } else { #endif /* NETCONN */ ttslow((char *)escbuf,wr); /* Send escape sequence */ debug(F110,"mdmhup ttslow ok",escbuf,0); #ifdef NETCONN } #endif /* NETCONN */ if (mp->esc_time) /* Pause for guard time again */ msleep(mp->esc_time); else msleep(500); /* Wait half a sec for echoes. */ debug(F100,"mdmhup pause 1 OK","",0); #ifdef COMMENT ttflui(); /* Flush response or echo, if any */ debug(F100,"mdmhup ttflui OK","",0); #endif /* COMMENT */ } ttslow(s,wr); /* Now Send hangup string */ debug(F110,"mdmhup ttslow ok",s,0); /* This is not exactly right, but it works. If we are online: the modem says OK when it gets the escape sequence, and it says NO CARRIER when it gets the hangup command. If we are offline: the modem does NOT say OK (or anything else) when it gets the esc sequence, but it DOES say OK (and not NO CARRIER) when it gets the hangup command. So the following function should read the OK in both cases. Of course, this is somewhat Hayes-specific... */ if (xx_ok) { /* Look for OK response */ debug(F100,"mdmhup calling response function","",0); x = (*xx_ok)(3,1); /* Give it 3 seconds, be strict. */ debug(F101,"mdmhup hangup response","",x); msleep(500); /* Wait half a sec */ ttflui(); /* Get rid of NO CARRIER, if any */ } else { /* No OK function, */ x = 1; /* so assume it worked */ debug(F101,"mdmhup no ok_fn","",x); } parity = xparity; /* Restore prevailing parity */ return(x); /* Return OK function's return code. */ #else /* MDMHUP not defined. */ debug(F100,"mdmhup MDMHUP not defined","",0); return(0); /* Always fail. */ #endif /* MDMHUP */ } #endif /* NOICP */ #else /* NODIAL */ int mdmtyp = 0; /* Default modem type */ int /* To allow NODIAL versions to */ mdmhup() { /* call mdmhup(), so calls to */ return(0); /* mdmhup() need not be within */ } /* #ifndef NODIAL conditionals */ #endif /* NODIAL */ #else int mdmtyp = 0; /* Default modem type */ #endif /* NOLOCAL */ ckufio.c000664 045065 024037 00000776306 14767403156 012647 0ustar00fdckermit000000 000000 /* C K U F I O -- Kermit file system support for UNIX, Aegis, and Plan 9 */ #define CK_NONBLOCK /* See zoutdump() */ #ifdef aegis char *ckzv = "Aegis File support, 10.0.234, 05 May 2023"; #else #ifdef Plan9 char *ckzv = "Plan 9 File support, 10.0.234, 05 May 2023"; #else char *ckzv = "UNIX File support, 9.0.234, 05 May 2023"; #endif /* Plan9 */ #endif /* aegis */ /* Author: Frank da Cruz , Columbia University 1974-2011; the Open Source Kermit Project 2011-???? Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ /* NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be compatible with C preprocessors that support only #ifdef, #else, #endif, #define, and #undef. Please do not use #if, logical operators, or other preprocessor features in any of the portable C-Kermit modules. You can, of course, use these constructions in platform-specific modules where you know they are supported. */ /* Include Files */ #ifdef MINIX2 #define _MINIX #endif /* MINIX2 */ #include "ckcsym.h" #include "ckcdeb.h" #include "ckcasc.h" #ifndef NOCSETS #include "ckcxla.h" #endif /* NOCSETS */ #ifdef COMMENT /* This causes trouble in C-Kermit 8.0. I don't remember the original */ /* reason for this being here but it must have been needed at the time... */ #ifdef OSF13 #ifdef CK_ANSIC #ifdef _NO_PROTO #undef _NO_PROTO #endif /* _NO_PROTO */ #endif /* CK_ANSIC */ #endif /* OSF13 */ #endif /* COMMENT */ #ifndef HPUXPRE65 #include /* Error number symbols */ #else #ifndef ERRNO_INCLUDED #include /* Error number symbols */ #endif /* ERRNO_INCLUDED */ #endif /* HPUXPRE65 */ #include #ifdef MINIX2 #undef MINIX #undef CKSYSLOG #include #include #define NOFILEH #endif /* MINIX2 */ #ifdef MINIX #include #include #include #else #ifdef POSIX #include #else #ifdef SVR3 #include #endif /* SVR3 */ #endif /* POSIX */ #endif /* MINIX */ /* Directory Separator macros, to allow this module to work with both UNIX and OS/2: Because of ambiguity with the command line editor escape \ character, the directory separator is currently left as / for OS/2 too, because the OS/2 kernel also accepts / as directory separator. */ #ifndef DIRSEP #define DIRSEP '/' #endif /* DIRSEP */ #ifndef ISDIRSEP #define ISDIRSEP(c) ((c)=='/') #endif /* ISDIRSEP */ #ifdef SDIRENT #define DIRENT #endif /* SDIRENT */ #ifdef XNDIR #include #else /* !XNDIR */ #ifdef NDIR #include #else /* !NDIR, !XNDIR */ #ifdef RTU #include "/usr/lib/ndir.h" #else /* !RTU, !NDIR, !XNDIR */ #ifdef DIRENT #ifdef SDIRENT #include #else #include #endif /* SDIRENT */ #else #include #endif /* DIRENT */ #endif /* RTU */ #endif /* NDIR */ #endif /* XNDIR */ #ifdef __NetBSD__ #include #else #ifdef HAVEWAITH /* for FreeBSD, OpenBSD */ #include #endif /* HAVEWAITH */ #endif /* __NetBSD__ */ #ifdef UNIX /* Pointer arg to wait() allowed */ #define CK_CHILD /* Assume this is safe in all UNIX */ #endif /* UNIX */ extern int binary, recursive, stathack; #ifdef CK_CTRLZ extern int eofmethod; #endif /* CK_CTRLZ */ #include /* Password file for shell name */ #ifdef CK_SRP #include /* SRP Password file */ #endif /* CK_SRP */ #ifdef HPUX10_TRUSTED #include #include #endif /* HPUX10_TRUSTED */ #ifdef COMMENT /* Moved to ckcdeb.h */ #ifdef POSIX #define UTIMEH #else #ifdef HPUX9 #define UTIMEH #endif /* HPUX9 */ #endif /* POSIX */ #endif /* COMMENT */ #ifdef SYSUTIMEH /* if requested, */ #include /* for extra fields required by */ #else /* 88Open spec. */ #ifdef UTIMEH /* or if requested */ #include /* (SVR4, POSIX) */ #ifndef BSD44 #ifndef V7 /* Not sure why this is here. What it implies is that the code bracketed by SYSUTIMEH is valid on all platforms on which we support time functionality. But we know that is not true because the BSD44 and V7 platforms do not support sys/utime.h and the data structures which are defined in them. Now this worked before because prior to today's changes the UTIMEH definition for BSD44 and V7 did not take place until after SYSUTIMEH was defined. It also would not have been a problem if the ordering of all the time blocks was consistent. All but one of the blocks were BSD44, V7, SYSUTIMEH, . That one case is where this problem was triggered. */ #define SYSUTIMEH /* Use this for both cases. */ #endif /* V7 */ #endif /* BSD44 */ #endif /* UTIMEH */ #endif /* SYSUTIMEH */ #ifndef NOTIMESTAMP #ifdef POSIX #ifndef AS400 #define TIMESTAMP #endif /* AS400 */ #endif /* POSIX */ #ifdef BSD44 /* BSD 4.4 */ #ifndef TIMESTAMP #define TIMESTAMP /* Can do file dates */ #endif /* TIMESTAMP */ #include #ifndef NOSYSTIMEBH /* */ #include #endif /* NOSYSTIMEBH */ #else /* Not BSD44 */ #ifdef BSD4 /* BSD 4.3 and below */ #define TIMESTAMP /* Can do file dates */ #include /* Need this */ #ifndef NOSYSTIMEBH /* */ #include /* Need this if really BSD */ #endif /* NOSYSTIMEBH */ #else /* Not BSD 4.3 and below */ #ifdef SVORPOSIX /* System V or POSIX */ #ifndef TIMESTAMP #define TIMESTAMP #endif /* TIMESTAMP */ #include /* void tzset(); (the "void" type upsets some compilers) */ #ifndef IRIX60 #ifndef ultrix #ifndef CONVEX9 /* ConvexOS 9.0, supposedly POSIX, has extern char *timezone(int,int) */ #ifndef Plan9 extern long timezone; #endif /* Plan9 */ #endif /* CONVEX9 */ #endif /* ultrix */ #endif /* IRIX60 */ #endif /* SVORPOSIX */ #endif /* BSD4 */ #endif /* BSD44 */ #ifdef COHERENT #include #endif /* COHERENT */ /* Is `y' a leap year? */ #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0) /* Number of leap years from 1970 to `y' (not including `y' itself). */ #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400) #endif /* NOTIMESTAMP */ #ifdef CIE #include /* File status */ #else #include #endif /* CIE */ /* Macro to alleviate isdir() calls internal to this module */ static struct stat STATBUF; #define xisdir(a) ((stat(a,&STATBUF)==-1)?0:(S_ISDIR(STATBUF.st_mode)?1:0)) extern char uidbuf[]; extern int xferlog; extern char * xferfile; int iklogopen = 0; static time_t timenow; #define IKSDMSGLEN CKMAXPATH+512 static char iksdmsg[IKSDMSGLEN]; extern int local; extern int server, en_mkd, en_cwd, en_del; /* Functions (n is one of the predefined file numbers from ckcker.h): zopeni(n,name) -- Opens an existing file for input. zopeno(n,name,attr,fcb) -- Opens a new file for output. zclose(n) -- Closes a file. zchin(n,&c) -- Gets the next character from an input file. zsinl(n,&s,x) -- Read a line from file n, max len x, into address s. zsout(n,s) -- Write a null-terminated string to output file, buffered. zsoutl(n,s) -- Like zsout, but appends a line terminator. zsoutx(n,s,x) -- Write x characters to output file, unbuffered. zchout(n,c) -- Add a character to an output file, unbuffered. zchki(name) -- Check if named file exists and is readable, return size. zchko(name) -- Check if named file can be created. zchkspa(name,n) -- Check if n bytes available to create new file, name. znewn(name,s) -- Make a new unique file name based on the given name. zdelet(name) -- Delete the named file. zxpand(string) -- Expands the given wildcard string into a list of files. znext(string) -- Returns the next file from the list in "string". zxrewind() -- Rewind zxpand list. zxcmd(n,cmd) -- Execute the command in a lower fork on file number n. zclosf() -- Close input file associated with zxcmd()'s lower fork. zrtol(n1,n2) -- Convert remote filename into local form. zltor(n1,n2) -- Convert local filename into remote form. zchdir(dirnam) -- Change working directory. zhome() -- Return pointer to home directory name string. zkself() -- Kill self, log out own job. zsattr(struct zattr *) -- Return attributes for file which is being sent. zstime(f, struct zattr *, x) - Set file creation date from attribute packet. zrename(old, new) -- Rename a file. zcopy(source,destination) -- Copy a file. zmkdir(path) -- Create the directory path if possible zfnqfp(fname,len,fullpath) - Determine full path for file name. zgetfs(name) -- return file size regardless of accessibility zchkpid(pid) -- tell if PID is valid and active */ /* Kermit-specific includes */ /* Definitions here supersede those from system include files. ckcdeb.h is included above. */ #include "ckcker.h" /* Kermit definitions */ #include "ckucmd.h" /* For keyword tables */ #include "ckuver.h" /* Version herald */ char *ckzsys = HERALD; /* File access checking ... There are two calls to access() in this module. If this program is installed setuid or setgid on a Berkeley-based UNIX system that does NOT incorporate the saved-original-effective-uid/gid feature, then, when we have swapped the effective and original uid/gid, access() fails because it uses what it thinks are the REAL ids, but we have swapped them. This occurs on systems where ANYBSD is defined, NOSETREU is NOT defined, and SAVEDUID is NOT defined. So, in theory, we should take care of this situation like so: ifdef ANYBSD ifndef NOSETREU ifndef SAVEDUID define SW_ACC_ID endif endif endif But we can't test such a general scheme everywhere, so let's only do this when we know we have to... */ #ifdef NEXT /* NeXTSTEP 1.0-3.0 */ #define SW_ACC_ID #endif /* NEXT */ /* Support for tilde-expansion in file and directory names */ #ifdef POSIX #define NAMEENV "LOGNAME" #else #ifdef BSD4 #define NAMEENV "USER" #else #ifdef ATTSV #define NAMEENV "LOGNAME" #endif /* ATTSV */ #endif /* BSD4 */ #endif /* POSIX */ /* Berkeley Unix Version 4.x */ /* 4.1bsd support from Charles E Brooks, EDN-VAX */ #ifdef BSD4 #ifdef MAXNAMLEN #define BSD42 #endif /* MAXNAMLEN */ #endif /* BSD4 */ /* Definitions of some system commands */ char *DELCMD = "rm -f "; /* For file deletion */ char *CPYCMD = "cp "; /* For file copy */ char *RENCMD = "mv "; /* For file rename */ char *PWDCMD = "pwd "; /* For saying where I am */ #ifdef COMMENT #ifdef HPUX10 char *DIRCMD = "/usr/bin/ls -l "; /* For directory listing */ char *DIRCM2 = "/usr/bin/ls -l "; /* For directory listing, no args */ #else char *DIRCMD = "/bin/ls -l "; /* For directory listing */ char *DIRCM2 = "/bin/ls -l "; /* For directory listing, no args */ #endif /* HPUX10 */ #else char *DIRCMD = "ls -l "; /* For directory listing */ char *DIRCM2 = "ls -l "; /* For directory listing, no args */ #endif /* COMMENT */ char *TYPCMD = "cat "; /* For typing a file */ #ifdef HPUX char *MAILCMD = "mailx"; /* For sending mail */ #else #ifdef DGUX540 char *MAILCMD = "mailx"; #else #ifdef UNIX #ifdef CK_MAILCMD char *MAILCMD = CK_MAILCMD; /* CFLAGS override */ #else char *MAILCMD = "Mail"; /* Default */ #endif /* CK_MAILCMD */ #else char *MAILCMD = ""; #endif /* UNIX */ #endif /* HPUX */ #endif /* DGUX40 */ #ifdef UNIX #ifdef ANYBSD /* BSD uses lpr to spool */ #ifdef DGUX540 /* And DG/UX */ char * PRINTCMD = "lp"; #else char * PRINTCMD = "lpr"; #endif /* DGUX540 */ #else /* Sys V uses lp */ #ifdef TRS16 /* except for Tandy-16/6000... */ char * PRINTCMD = "lpr"; #else char * PRINTCMD = "lp"; #endif /* TRS16 */ #endif /* ANYBSD */ #else /* Not UNIX */ #define PRINTCMD "" #endif /* UNIX */ #ifdef FT18 /* Fortune For:Pro 1.8 */ #undef BSD4 #endif /* FT18 */ #ifdef BSD4 char *SPACMD = "pwd ; df ."; /* Space in current directory */ #else #ifdef FT18 char *SPACMD = "pwd ; du ; df ."; #else char *SPACMD = "df "; #endif /* FT18 */ #endif /* BSD4 */ char *SPACM2 = "df "; /* For space in specified directory */ #ifdef FT18 #define BSD4 #endif /* FT18 */ #ifdef BSD4 char *WHOCMD = "finger "; #else char *WHOCMD = "who "; #endif /* BSD4 */ /* More system-dependent includes, which depend on symbols defined */ /* in the Kermit-specific includes. Oh what a tangled web we weave... */ #ifdef COHERENT /* */ #define NOFILEH #endif /* COHERENT */ #ifdef MINIX #define NOFILEH #endif /* MINIX */ #ifdef aegis #define NOFILEH #endif /* aegis */ #ifdef unos #define NOFILEH #endif /* unos */ #ifndef NOFILEH #include #endif /* NOFILEH */ #ifndef is68k /* Whether to include */ #ifndef BSD41 /* All but a couple UNIXes have it. */ #ifndef FT18 #ifndef COHERENT #include #endif /* COHERENT */ #endif /* FT18 */ #endif /* BSD41 */ #endif /* is68k */ #ifdef COHERENT #ifdef _I386 #include #else #include #endif /* _I386 */ #endif /* COHERENT */ extern int inserver; /* I am IKSD */ int guest = 0; /* Anonymous user */ #ifdef IKSD extern int isguest; extern char * anonroot; #endif /* IKSD */ #ifdef CK_LOGIN #define GUESTPASS 256 static char guestpass[GUESTPASS] = { NUL, NUL }; /* Anonymous "password" */ static int logged_in = 0; /* Set when user is logged in */ static int askpasswd = 0; /* Have OK user, must ask for passwd */ #ifdef CK_PAM extern int gotemptypasswd; #endif /* CK_PAM */ #endif /* CK_LOGIN */ #ifdef CKROOT static char ckroot[CKMAXPATH+1] = { NUL, NUL }; static int ckrootset = 0; int ckrooterr = 0; #endif /* CKROOT */ _PROTOTYP( VOID ignorsigs, (void) ); _PROTOTYP( VOID restorsigs, (void) ); #ifdef SELECT _PROTOTYP( int ttwait, (int, int) ); /* ckutio.c */ #endif /* SELECT */ /* Change argument to "(const char *)" if this causes trouble. Or... if it causes trouble, then maybe it was already declared in a header file after all, so you can remove this prototype. */ #ifndef NDGPWNAM /* If not defined No Declare getpwnam... */ #ifndef _POSIX_SOURCE #ifndef NEXT #ifndef SVR4 /* POSIX already gave prototypes for these. */ #ifdef IRIX40 _PROTOTYP( struct passwd * getpwnam, (const char *) ); #else #ifdef IRIX51 _PROTOTYP( struct passwd * getpwnam, (const char *) ); #else #ifdef M_UNIX _PROTOTYP( struct passwd * getpwnam, (const char *) ); #else #ifdef HPUX9 _PROTOTYP( struct passwd * getpwnam, (const char *) ); #else #ifdef HPUX10 _PROTOTYP( struct passwd * getpwnam, (const char *) ); #else #ifdef DCGPWNAM _PROTOTYP( struct passwd * getpwnam, (const char *) ); #else _PROTOTYP( struct passwd * getpwnam, (char *) ); #endif /* DCGPWNAM */ #endif /* HPUX10 */ #endif /* HPUX9 */ #endif /* M_UNIX */ #endif /* IRIX51 */ #endif /* IRIX40 */ #ifndef SUNOS4 #ifndef HPUX9 #ifndef HPUX10 #ifndef _SCO_DS _PROTOTYP( struct passwd * getpwuid, (PWID_T) ); #endif /* _SCO_DS */ #endif /* HPUX10 */ #endif /* HPUX9 */ #endif /* SUNOS4 */ _PROTOTYP( struct passwd * getpwent, (void) ); #endif /* SVR4 */ #endif /* NEXT */ #endif /* _POSIX_SOURCE */ #endif /* NDGPWNAM */ #ifdef CK_SHADOW /* Shadow Passwords... */ #include #endif /* CK_SHADOW */ #ifdef CK_PAM /* PAM... */ #ifdef MACOSX #include #else /* MACOSX */ #include #endif /* MACOSX */ #ifndef PAM_SERVICE_TYPE /* Defines which PAM service we are */ #define PAM_SERVICE_TYPE "kermit" #endif /* PAM_SERVICE_TYPE */ #ifdef __APPLE__ #include #include #endif /* __APPLE__ */ #ifdef SOLARIS #define PAM_CONST #else /* SOLARIS */ #define PAM_CONST CONST #endif static char * pam_pw = NULL; int #ifdef CK_ANSIC pam_cb(int num_msg, PAM_CONST struct pam_message **msg, struct pam_response **resp, void *appdata_ptr ) #else /* CK_ANSIC */ pam_cb(num_msg, msg, resp, appdata_ptr) int num_msg; PAM_CONST struct pam_message **msg; struct pam_response **resp; void *appdata_ptr; #endif /* CK_ANSIC */ { int i; debug(F111,"pam_cb","num_msg",num_msg); for (i = 0; i < num_msg; i++) { char message[PAM_MAX_MSG_SIZE]; /* Issue prompt and get response */ debug(F111,"pam_cb","Message",i); debug(F111,"pam_cb",msg[i]->msg,msg[i]->msg_style); if (msg[i]->msg_style == PAM_ERROR_MSG) { debug(F111,"pam_cb","PAM ERROR",0); fprintf(stdout,"%s\n", msg[i]->msg); return(0); } else if (msg[i]->msg_style == PAM_TEXT_INFO) { debug(F111,"pam_cb","PAM TEXT INFO",0); fprintf(stdout,"%s\n", msg[i]->msg); return(0); } else if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF) { debug(F111,"pam_cb","Reading response, no echo",0); /* Ugly hack. We check to see if a password has been pushed */ /* into zvpasswd(). This would be true if the password was */ /* received by REMOTE LOGIN. */ if (pam_pw) { ckstrncpy(message,pam_pw,PAM_MAX_MSG_SIZE); } else readpass((char *)msg[i]->msg,message,PAM_MAX_MSG_SIZE); } else if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON) { debug(F111,"pam_cb","Reading response, with echo",0); readtext((char *)msg[i]->msg,message,PAM_MAX_MSG_SIZE); } else { debug(F111,"pam_cb","unknown style",0); return(0); } /* Allocate space for this message's response structure */ resp[i] = (struct pam_response *) malloc(sizeof (struct pam_response)); if (!resp[i]) { int j; debug(F110,"pam_cb","malloc failure",0); for (j = 0; j < i; j++) { free(resp[j]->resp); free(resp[j]); } return(0); } /* Allocate a buffer for the response */ resp[i]->resp = (char *) malloc((int)strlen(message) + 1); if (!resp[i]->resp) { int j; debug(F110,"pam_cb","malloc failure",0); for (j = 0; j < i; j++) { free(resp[j]->resp); free(resp[j]); } free(resp[i]); return(0); } /* Return the results back to PAM */ strcpy(resp[i]->resp, message); /* safe (prechecked) */ resp[i]->resp_retcode = 0; } debug(F110,"pam_cb","Exiting",0); return(0); } #endif /* CK_PAM */ /* Define macros for getting file type */ #ifdef OXOS /* Olivetti X/OS 2.3 has S_ISREG and S_ISDIR defined incorrectly, so we force their redefinition. */ #undef S_ISREG #undef S_ISDIR #endif /* OXOS */ #ifdef UTSV /* Same deal for Amdahl UTSV */ #undef S_ISREG #undef S_ISDIR #endif /* UTSV */ #ifdef UNISYS52 /* And for UNISYS UTS V 5.2 */ #undef S_ISREG #undef S_ISDIR #endif /* UNISYS52 */ #ifdef ICLSVR3 /* And for old ICL versions */ #undef S_ISREG #undef S_ISDIR #endif /* ICLSVR3 */ #ifdef ISDIRBUG /* Also allow this from command line */ #ifdef S_ISREG #undef S_ISREG #endif /* S_ISREG */ #ifdef S_ISDIR #undef S_ISDIR #endif /* S_ISDIR */ #endif /* ISDIRBUG */ #ifndef _IFMT #ifdef S_IFMT #define _IFMT S_IFMT #else #define _IFMT 0170000 #endif /* S_IFMT */ #endif /* _IFMT */ #ifndef S_ISREG #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif /* S_ISREG */ #ifndef S_ISDIR #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif /* S_ISDIR */ /* The following mainly for NeXTSTEP... */ #ifndef S_IWUSR #define S_IWUSR 0000200 #endif /* S_IWUSR */ #ifndef S_IRGRP #define S_IRGRP 0000040 #endif /* S_IRGRP */ #ifndef S_IWGRP #define S_IWGRP 0000020 #endif /* S_IWGRP */ #ifndef S_IXGRP #define S_IXGRP 0000010 #endif /* S_IXGRP */ #ifndef S_IROTH #define S_IROTH 0000004 #endif /* S_IROTH */ #ifndef S_IWOTH #define S_IWOTH 0000002 #endif /* S_IWOTH */ #ifndef S_IXOTH #define S_IXOTH 0000001 #endif /* S_IXOTH */ #ifdef COMMENT /* 2024-03-23 SMS. * Code here was changed to use CKMAXNAM instead of MAXNAMLEN. * CKMAXNAM is defined in ckcdeb.h, instead of defining MAXNAMLEN here. */ /* Define maximum length for a file name if not already defined. NOTE: This applies to a path segment (directory or file name), not the entire path string, which can be CKMAXPATH bytes long. */ #ifdef QNX #ifdef _MAX_FNAME #define MAXNAMLEN _MAX_FNAME #else #define MAXNAMLEN 48 #endif /* _MAX_FNAME */ #else #ifndef MAXNAMLEN #ifdef sun #define MAXNAMLEN 255 #else #ifdef FILENAME_MAX #define MAXNAMLEN FILENAME_MAX #else #ifdef NAME_MAX #define MAXNAMLEN NAME_MAX #else #ifdef _POSIX_NAME_MAX #define MAXNAMLEN _POSIX_NAME_MAX #else #ifdef _D_NAME_MAX #define MAXNAMLEN _D_NAME_MAX #else #ifdef DIRSIZ #define MAXNAMLEN DIRSIZ #else #define MAXNAMLEN 14 #endif /* DIRSIZ */ #endif /* _D_NAME_MAX */ #endif /* _POSIX_NAME_MAX */ #endif /* NAME_MAX */ #endif /* FILENAME_MAX */ #endif /* sun */ #endif /* MAXNAMLEN */ #endif /* QNX */ #endif /* COMMENT 2024-03-23 SMS. */ #ifdef COMMENT /* As of 2001-11-03 this is handled in ckcdeb.h */ /* Longest pathname ... */ /* Beware: MAXPATHLEN is one of UNIX's dirty little secrets. Where is it defined? Who knows... , , , , ... There is not necessarily even a definition for it anywhere, or it might have another name. If you get it wrong, bad things happen with getcwd() and/or getwd(). If you allocate a buffer that is too short, getwd() might write over memory and getcwd() will fail with ERANGE. The definitions of these functions (e.g. in SVID or POSIX.1) do not tell you how to determine the maximum path length in order to allocate a buffer that is the right size. */ /* 2021-10-31 SMS. * Hence, use ckcdeb.h:CKMAXPATH, and forget about MAXPATHLEN here. * Considerable tidying here should be possible. */ #ifdef BSD44 #include /* For MAXPATHLEN */ #endif /* BSD44 */ #ifdef COHERENT #include /* for MAXPATHLEN, needed for -DDIRENT */ #endif /* COHERENT */ #endif /* COMMENT */ #ifdef MAXPATHLEN #ifdef MAXPATH #undef MAXPATH #endif /* MAXPATH */ #define MAXPATH MAXPATHLEN #else #ifdef PATH_MAX #define MAXPATH PATH_MAX #else #ifdef _POSIX_PATH_MAX #define MAXPATH _POSIX_PATH_MAX #else #ifdef BSD42 #define MAXPATH 1024 #else #ifdef SVR4 #define MAXPATH 1024 #else #define MAXPATH 255 #endif /* SVR4 */ #endif /* BSD42 */ #endif /* _POSIX_PATH_MAX */ #endif /* PATH_MAX */ #endif /* MAXPATHLEN */ /* Maximum number of filenames for wildcard expansion */ #ifndef MAXWLD /* Already defined in ckcdeb.h so the following is superfluous. */ /* Don't expect changing them to have any effect. */ #ifdef CK_SMALL #define MAXWLD 50 #else #ifdef BIGBUFOK #define MAXWLD 102400 #else #define MAXWLD 8192 #endif /* BIGBUFOK */ #endif /* CK_SMALL */ #endif /* MAXWLD */ static int maxnames = MAXWLD; /* Define the size of the string space for filename expansion. */ #ifndef DYNAMIC #ifdef PROVX1 #define SSPACE 500 #else #ifdef BSD29 #define SSPACE 500 #else #ifdef pdp11 #define SSPACE 500 #else #ifdef aegis #define SSPACE 10000 /* Size of string-generating buffer */ #else /* Default static buffer size */ #ifdef BIGBUFOK #define SSPACE 65000 /* Size of string-generating buffer */ #else #define SSPACE 2000 /* size of string-generating buffer */ #endif /* BIGBUFOK */ #endif /* aegis */ #endif /* pdp11 */ #endif /* BSD29 */ #endif /* PROVX1 */ static char sspace[SSPACE]; /* Buffer for generating filenames */ #else /* is DYNAMIC */ #ifdef CK_64BIT #define SSPACE 2000000000 /* Two billion bytes */ #else #ifdef BIGBUFOK #define SSPACE 10000000 /* Ten million */ #else #define SSPACE 10000 /* Ten thousand */ #endif /* BIGBUFOK */ #endif /* CK_64BIT */ char *sspace = (char *)0; #endif /* DYNAMIC */ static int ssplen = SSPACE; /* Length of string space buffer */ #ifdef DCLFDOPEN /* fdopen() needs declaring because it's not declared in */ _PROTOTYP( FILE * fdopen, (int, char *) ); #endif /* DCLFDOPEN */ #ifdef DCLPOPEN /* popen() needs declaring because it's not declared in */ _PROTOTYP( FILE * popen, (char *, char *) ); #endif /* DCLPOPEN */ extern int nopush; /* More internal function prototypes */ /* * The path structure is used to represent the name to match. * Each slash-separated segment of the name is kept in one * such structure, and they are linked together, to make * traversing the name easier. */ struct path { char npart[CKMAXNAM+4]; /* name part of path segment */ struct path *fwd; /* forward ptr */ }; #ifndef NOPUSH _PROTOTYP( int shxpand, (char *, char *[], int ) ); #endif /* NOPUSH */ _PROTOTYP( static int fgen, (char *, char *[], int ) ); _PROTOTYP( static VOID traverse, (struct path *, char *, char *) ); _PROTOTYP( static VOID addresult, (char *, int) ); #ifdef COMMENT /* Replaced by ckmatch() */ _PROTOTYP( static int match, (char *, char *) ); #endif /* COMMENT */ _PROTOTYP( char * whoami, (void) ); _PROTOTYP( UID_T real_uid, (void) ); _PROTOTYP( static struct path *splitpath, (char *p) ); _PROTOTYP( char * zdtstr, (time_t) ); _PROTOTYP( time_t zstrdt, (char *, int) ); /* Some systems define these symbols in include files, others don't... */ #ifndef R_OK #define R_OK 4 /* For access */ #endif /* R_OK */ #ifndef W_OK #define W_OK 2 #endif /* W_OK */ #ifndef X_OK #define X_OK 1 #endif /* X_OK */ #ifndef O_RDONLY #define O_RDONLY 000 #endif /* O_RDONLY */ /* syslog and wtmp items for Internet Kermit Service */ extern char * clienthost; /* From ckcmai.c. */ static char fullname[CKMAXPATH+1]; static char tmp2[CKMAXPATH+1]; extern int ckxlogging; #ifdef CKXPRINTF /* Our printf macro conflicts with */ #undef printf /* use of "printf" in syslog.h */ #endif /* CKXPRINTF */ #ifdef CKSYSLOG #ifdef RTAIX #include #else /* RTAIX */ #include #endif /* RTAIX */ #endif /* CKSYSLOG */ #ifdef CKXPRINTF #define printf ckxprintf #endif /* CKXPRINTF */ #ifdef CK_AUTHENTICATION #include "ckuath.h" /* fdc 2021-12-17 */ #endif /* CK_AUTHENTICATION */ #include "ckuusr.h" #include "ckcnet.h" /* struct sockaddr */ #include "ckcfnp.h" /* Prototypes (must be last) */ int ckxanon = 1; /* Anonymous login ok */ int ckxperms = 0040; /* Anonymous file permissions */ int ckxpriv = 1; /* Priv'd login ok */ #ifndef XFERFILE #define XFERFILE "/var/log/iksd.log" #endif /* XFERFILE */ /* wtmp logging for IKSD... */ #ifndef CKWTMP /* wtmp logging not selected */ int ckxwtmp = 0; /* Know this at runtime */ #else /* wtmp file details */ int ckxwtmp = 1; #ifdef UTMPBUG /* Unfortunately... */ /* Some versions of Linux have a file that contains "enum utlogin { local, telnet, rlogin, screen, ... };" This clobbers any program that uses any of these words as variable names, function names, macro names, etc. (Other versions of Linux have this declaration within #if 0 ... #endif.) There is nothing we can do about this other than to not include the stupid file. But we need stuff from it, so... */ #include #include #define UT_LINESIZE 32 #define UT_NAMESIZE 32 #define UT_HOSTSIZE 256 struct timeval { time_t tv_sec; time_t tv_usec; }; struct exit_status { short int e_termination; /* Process termination status. */ short int e_exit; /* Process exit status. */ }; struct utmp { short int ut_type; /* Type of login */ pid_t ut_pid; /* Pid of login process */ char ut_line[UT_LINESIZE]; /* NUL-terminated devicename of tty */ char ut_id[4]; /* Inittab id */ char ut_user[UT_NAMESIZE]; /* Username (not NUL terminated) */ char ut_host[UT_HOSTSIZE]; /* Hostname for remote login */ struct exit_status ut_exit; /* Exit status */ long ut_session; /* Session ID, used for windowing */ struct timeval ut_tv; /* Time entry was made */ int32_t ut_addr_v6[4]; /* Internet address of remote host */ char pad[20]; /* Reserved */ }; #define ut_time ut_tv.tv_sec /* Why should Linux be like anything else? */ #define ut_name ut_user /* ... */ extern void logwtmp __P ((__const char *__ut_line, __const char *__ut_name, __const char *__ut_host)); #else /* Not UTMPBUG */ #ifndef HAVEUTMPX /* Who has */ #ifdef SOLARIS #define HAVEUTMPX #else #ifdef IRIX60 #define HAVEUTMPX #else #ifdef CK_SCOV5 #define HAVEUTMPX #else #ifdef HPUX100 #define HAVEUTMPX #else #ifdef UNIXWARE #define HAVEUTMPX #endif /* UNIXWARE */ #endif /* HPUX100 */ #endif /* CK_SCOV5 */ #endif /* IRIX60 */ #endif /* SOLARIS */ #endif /* HAVEUTMPX */ #ifdef HAVEUTMPX #include #else #ifdef OSF50 /* Because the time_t in the utmp struct is 64 bits but time() wants 32 */ #define __V40_OBJ_COMPAT 1 #endif /* OSF50 */ #include #ifdef OSF50 #undef __V40_OBJ_COMPAT #endif /* OSF50 */ #endif /* HAVEUTMPX */ #endif /* UTMPBUG */ #ifdef CK_ANSIC /* Prototypes for static functions - fdc 30 November 2022 */ static VOID addresult( char *, int ); static VOID getfullname(char * ); static VOID traverse(struct path *, char *, char * ); static int checkuser( char * ); static int fgen( char *, char[] *, int ); static int initspace( char[] *, int ); static struct path * splitpath( char * ); struct passwd * sgetpwnam( char * ); struct zfnfp * zfnqfp( char *, int, char * ); #endif /* CK_ANSIC */ #ifdef HAVEUTMPX #define UTMPSTRUCT utmpx #else #define UTMPSTRUCT utmp #endif /* HAVEUTMPX */ #ifndef WTMPFILE #ifdef QNX #define WTMPFILE "/usr/adm/wtmp.1" #else #ifdef LINUX #define WTMPFILE "/var/log/wtmp" #else #define WTMPFILE "/usr/adm/wtmp" #endif /* QNX */ #endif /* LINUX */ #endif /* WTMPFILE */ char * wtmpfile = NULL; static int wtmpfd = 0; static char cksysline[32] = { NUL, NUL }; #ifndef HAVEUTHOST /* Does utmp include ut_host[]? */ #ifdef HAVEUTMPX /* utmpx always does */ #define HAVEUTHOST #else #ifdef LINUX /* Linux does */ #define HAVEUTHOST #else #ifdef SUNOS4 /* SunOS does */ #define HAVEUTHOST #else #ifdef AIX41 /* AIX 4.1 and later do */ #define HAVEUTHOST #endif /* AIX41 */ #endif /* SUNOS4 */ #endif /* LINUX */ #endif /* HAVEUTMPX */ #endif /* HAVEUTHOST */ #ifdef UW200 PID_T _vfork() { /* To satisfy a library foulup */ return(fork()); /* in Unixware 2.0.x */ } #endif /* UW200 */ VOID #ifdef CK_ANSIC logwtmp(const char * line, const char * name, const char * host) #else logwtmp(line, name, host) char *line, *name, *host; #endif /* CK_ANSIC */ /* logwtmp */ { struct UTMPSTRUCT ut; struct stat buf; int dummy; /* time_t time(); */ if (!ckxwtmp) return; if (!wtmpfile) makestr(&wtmpfile,WTMPFILE); if (!line) line = ""; if (!name) name = ""; if (!host) host = ""; if (!wtmpfd && (wtmpfd = open(wtmpfile, O_WRONLY|O_APPEND, 0)) < 0) { ckxwtmp = 0; debug(F110,"WTMP open failed",line,0); return; } if (!fstat(wtmpfd, &buf)) { ckstrncpy(ut.ut_line, line, sizeof(ut.ut_line)); #ifdef FREEBSD9 ckstrncpy(ut.ut_user, name, sizeof(ut.ut_user)); #else ckstrncpy(ut.ut_name, name, sizeof(ut.ut_name)); #endif /* FREEBSD9 */ #ifdef HAVEUTHOST /* Not portable */ ckstrncpy(ut.ut_host, host, sizeof(ut.ut_host)); #endif /* HAVEUTHOST */ #ifdef HAVEUTMPX time(&ut.ut_tv.tv_sec); #else #ifdef LINUX /* In light of the following comment perhaps the previous line should */ /* be "#ifndef COMMENT". */ { /* * On 64-bit platforms sizeof(time_t) and sizeof(ut.ut_time) * are not the same and attempt to use an address of * ut.ut_time as an argument to time() call may cause * "unaligned access" trap. */ time_t zz; time(&zz); ut.ut_time = zz; } #else #ifdef CK_64BIT { /* Now (Jan 2006) we can do this for any 64-bit build */ time_t zz; time(&zz); ut.ut_time = zz; } #else time(&ut.ut_time); #endif /* CK_64BIT */ #endif /* LINUX */ #endif /* HAVEUTMPX */ if (write(wtmpfd, (char *)&ut, sizeof(struct UTMPSTRUCT)) != sizeof(struct UTMPSTRUCT)) { #ifndef NOFTRUNCATE #ifndef COHERENT dummy = ftruncate(wtmpfd, buf.st_size); /* Error, undo partial write */ #else chsize(wtmpfd, buf.st_size); /* Error, undo any partial write */ #endif /* COHERENT */ #endif /* NOFTRUNCATE */ debug(F110,"WTMP write error",line,0); } else { debug(F110,"WTMP record OK",line,0); return; } } } #endif /* CKWTMP */ #ifdef CKSYSLOG /* C K S Y S L O G -- C-Kermit system logging function, For use by other modules. This module can, but doesn't have to, use it. Call with: n = SYSLG_xx values defined in ckcdeb.h s1, s2, s3: strings. */ VOID cksyslog(n, m, s1, s2, s3) int n, m; char * s1, * s2, * s3; { int level; if (!ckxlogging) /* syslogging */ return; if (!s1) s1 = ""; /* Fix null args */ if (!s2) s2 = ""; if (!s3) s3 = ""; switch (n) { /* Translate Kermit level */ case SYSLG_DB: /* to syslog level */ level = LOG_DEBUG; break; default: level = m ? LOG_INFO : LOG_ERR; } debug(F110,"cksyslog s1",s1,0); debug(F110,"cksyslog s2",s2,0); debug(F110,"cksyslog s3",s3,0); errno = 0; syslog(level, "%s: %s %s", s1, s2, s3); /* Write syslog record */ debug(F101,"cksyslog errno","",errno); } #endif /* CKSYSLOG */ /* Declarations */ int ck_znewn = -1; #ifdef UNIX char startupdir[MAXPATH+1]; #endif /* UNIX */ int pexitstat = -2; /* Process exit status */ FILE *fp[ZNFILS] = { /* File pointers */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; /* Flags for each file indicating whether it was opened with popen() */ int ispipe[ZNFILS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* Buffers and pointers used in buffered file input and output. */ #ifdef DYNAMIC extern char *zinbuffer, *zoutbuffer; #else extern char zinbuffer[], zoutbuffer[]; #endif /* DYNAMIC */ extern char *zinptr, *zoutptr; extern int zincnt, zoutcnt; extern int wildxpand, wildena; /* Wildcard handling */ static CK_OFF_T iflen = (CK_OFF_T)-1; /* Input file length */ static PID_T pid = 0; /* pid of child fork */ static int fcount = 0; /* Number of files in wild group */ static int nxpand = 0; /* Copy of fcount */ static char nambuf[CKMAXPATH+4]; /* Buffer for a pathname */ #ifndef NOFRILLS #define ZMBUFLEN 200 static char zmbuf[ZMBUFLEN]; /* For mail, remote print strings */ #endif /* NOFRILLS */ char **mtchs = NULL; /* Matches found for filename */ char **mtchptr = NULL; /* Pointer to current match */ /* Z K S E L F -- Kill Self: log out own job, if possible. */ /* Note, should get current pid, but if your system doesn't have */ /* getppid(), then just kill(0,9)... */ #ifndef SVR3 #ifndef POSIX #ifndef OSFPC /* Already declared in unistd.h for SVR3 and POSIX */ #ifdef CK_ANSIC extern PID_T getppid(void); #else #ifndef PS2AIX10 #ifndef COHERENT extern PID_T getppid(); #endif /* COHERENT */ #endif /* PS2AIX10 */ #endif /* CK_ANSIC */ #endif /* OSFPC */ #endif /* POSIX */ #endif /* SVR3 */ int zkself() { /* For "bye", but no guarantee! */ #ifdef PROVX1 return(kill(0,9)); #else #ifdef V7 return(kill(0,9)); #else #ifdef TOWER1 return(kill(0,9)); #else #ifdef FT18 return(kill(0,9)); #else #ifdef aegis return(kill(0,9)); #else #ifdef COHERENT return(kill((PID_T)getpid(),1)); #else #ifdef PID_T exit(kill((PID_T)getppid(),1)); return(0); #else exit(kill(getppid(),1)); return(0); #endif #endif #endif #endif #endif #endif #endif } static VOID #ifdef CK_ANSIC getfullname( char * name ) #else getfullname(name) char * name; #endif /* CK_ANSIC */ { char *p = (char *)fullname; int len = 0; fullname[0] = '\0'; /* If necessary we could also chase down symlinks here... */ #ifdef COMMENT /* This works but is incompatible with wuftpd */ if (isguest && anonroot) { ckstrncpy(fullname,anonroot,CKMAXPATH); len = strlen(fullname); if (len > 0) if (fullname[len-1] == '/') len--; } p += len; #endif /* COMMENT */ zfnqfp(name, CKMAXPATH - len, p); while (*p) { if (*p < '!') *p = '_'; p++; } } /* D O I K L O G -- Open Kermit-specific ftp-like transfer log. */ VOID /* Called in ckcmai.c */ doiklog() { if (iklogopen) /* Already open? */ return; if (xferlog) { /* Open iksd log if requested */ if (!xferfile) /* If no pathname given */ makestr(&xferfile,XFERFILE); /* use this default */ if (*xferfile) { xferlog = open(xferfile, O_WRONLY | O_APPEND | O_CREAT, 0660); debug(F101,"doiklog open","",xferlog); if (xferlog < 0) { #ifdef CKSYSLOG syslog(LOG_ERR, "xferlog open failure %s: %m", xferfile); #endif /* CKSYSLOG */ debug(F101,"doiklog open errno","",errno); xferlog = 0; } else iklogopen = 1; } else xferlog = 0; #ifdef CKSYSLOG if (xferlog && ckxlogging) syslog(LOG_INFO, "xferlog: %s open ok", xferfile); #endif /* CKSYSLOG */ } } /* Z O P E N I -- Open an existing file for input. */ /* Returns 1 on success, 0 on failure */ int #ifdef CK_ANSIC zopeni( int n, char *name ) #else zopeni(n,name) int n; char *name; #endif /* CK_ANSIC */ { int x; debug(F111,"zopeni",name,n); if ((x = chkfn(n)) != 0) { debug(F111,"zopeni chkfn",ckitoa(n),x); return(0); } zincnt = 0; /* Reset input buffer */ if (n == ZSYSFN) { /* Input from a system function? */ #ifdef COMMENT /*** Note, this function should not be called with ZSYSFN ***/ /*** Always call zxcmd() directly, and give it the real file number ***/ /*** you want to use. ***/ return(zxcmd(n,name)); /* Try to fork the command */ #else debug(F110,"zopeni called with ZSYSFN, failing!",name,0); *nambuf = '\0'; /* No filename. */ return(0); /* fail. */ #endif /* COMMENT */ } if (n == ZSTDIO) { /* Standard input? */ if (is_a_tty(0)) { fprintf(stderr,"Terminal input not allowed"); debug(F110,"zopeni: attempts input from unredirected stdin","",0); return(0); } fp[ZIFILE] = stdin; ispipe[ZIFILE] = 0; return(1); } #ifdef CKROOT debug(F111,"zopeni setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(name)) { debug(F110,"zopeni setroot violation",name,0); return(0); } #endif /* CKROOT */ fp[n] = fopen(name,"r"); /* Real file, open it. */ /* debug(F111,"zopeni fopen", name, fp[n]); */ #ifdef ZDEBUG /* printf("ZOPENI fp[%d]=%ld\n",n,fp[n]); */ #endif /* ZDEBUG */ ispipe[n] = 0; if (xferlog #ifdef CKSYSLOG || ((ckxsyslog >= SYSLG_FA) && ckxlogging) #endif /* CKSYSLOG */ ) { getfullname(name); debug(F110,"zopeni fullname",fullname,0); } if (fp[n] == NULL) { #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_FA && ckxlogging) { syslog(LOG_INFO, "file[%d] %s: open failed (%m)", n, fullname); perror(fullname); } else #endif /* CKSYSLOG */ perror(name); return(0); } else { #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_FA && ckxlogging) syslog(LOG_INFO, "file[%d] %s: open read ok", n, fullname); #endif /* CKSYSLOG */ clearerr(fp[n]); return(1); } } #ifdef QNX #define DONDELAY #else #ifdef O_NDELAY #define DONDELAY #endif /* O_NDELAY */ #endif /* QNX */ /* Z O P E N O -- Open a new file for output. */ /*ARGSUSED*/ /* zz not used */ int #ifdef CK_ANSIC zopeno( int n, char *name, struct zattr *zz, struct filinfo *fcb ) #else zopeno(n,name,zz,fcb) int n; char *name; struct zattr *zz; struct filinfo *fcb; #endif /* CK_ANSIC */ { char p[8]; int append = 0; int istty = 0, filefd = 0; /* As of Version 5A, the attribute structure and the file information */ /* structure are included in the arglist. */ #ifdef DEBUG debug(F111,"zopeno",name,n); if (fcb) { debug(F101,"zopeno fcb disp","",fcb->dsp); debug(F101,"zopeno fcb type","",fcb->typ); debug(F101,"zopeno fcb char","",fcb->cs); } else { debug(F100,"zopeno fcb is NULL","",0); } #endif /* DEBUG */ if (chkfn(n) != 0) /* Already open? */ return(0); /* Nothing to do. */ if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */ fp[ZOFILE] = stdout; ispipe[ZOFILE] = 0; #ifdef COMMENT /* This seems right but it breaks client server ops */ fp[n] = stdout; ispipe[n] = 0; #endif /* COMMENT */ #ifdef COMMENT #ifdef DEBUG if (n != ZDFILE) debug(F101,"zopeno fp[n]=stdout","",fp[n]); #endif /* DEBUG */ #endif /* COMMENT */ zoutcnt = 0; zoutptr = zoutbuffer; return(1); } /* A real file. Open it in desired mode (create or append). */ #ifdef CKROOT debug(F111,"zopeno setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(name)) { debug(F110,"zopeno setroot violation",name,0); return(0); } #endif /* CKROOT */ ckstrncpy(p,"w",8); /* Assume write/create mode */ if (fcb) { /* If called with an FCB... */ if (fcb->dsp == XYFZ_A) { /* Does it say Append? */ ckstrncpy(p,"a",8); /* Yes. */ debug(F100,"zopeno append","",0); append = 1; } } if (xferlog #ifdef CKSYSLOG || ((ckxsyslog >= SYSLG_FC) && ckxlogging) #endif /* CKSYSLOG */ ) { getfullname(name); debug(F110,"zopeno fullname",fullname,0); } { /* Allow tty devices to opened as output files 2009/10/20 */ int fd, flags = 0; debug(F110,"zopeno attempting to open",name,0); if (!ckstrcmp(name,"/dev/",5,1)) { /* If it's a tty... */ #ifdef O_NONBLOCK flags = O_NONBLOCK; #else #ifdef O_NDELAY flags = O_NDELAY; #else #ifdef FNDELAY flags = FNDELAY; #endif /* FNDELAY */ #endif /* O_NDELAY */ #endif /* O_NONBLOCK */ } debug(F111,"zopeno open flags",name,flags); fd = open(name,O_WRONLY|flags,0600); debug(F111,"zopeno open",name,fd); if (fd > -1) { if (isatty(fd)) { filefd = fd; istty++; } } } debug(F111,"zopeno istty",name,istty); debug(F110,"zopeno fopen arg",p,0); if (istty) fp[n] = fdopen(filefd,p); else fp[n] = fopen(name,p); /* Try to open the file */ ispipe[ZIFILE] = 0; #ifdef ZDEBUG printf("ZOPENO fp[%d]=%ld\n",n,fp[n]); #endif /* ZDEBUG */ if (fp[n] == NULL) { /* Failed */ debug(F101,"zopeno failed errno","",errno); if (istty) close(filefd); #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_FC && ckxlogging) syslog(LOG_INFO, "file[%d] %s: %s failed (%m)", n, fullname, append ? "append" : "create" ); #endif /* CKSYSLOG */ #ifdef COMMENT /* Let upper levels print message. */ perror("Can't open output file"); #endif /* COMMENT */ } else { /* Succeeded */ extern int zofbuffer, zofblock, zobufsize; debug(F101, "zopeno zobufsize", "", zobufsize); if (n == ZDFILE || n == ZTFILE) { /* If debug or transaction log */ setbuf(fp[n],NULL); /* make it unbuffered. */ #ifdef DONDELAY } else if (n == ZOFILE && !zofblock) { /* blocking or nonblocking */ int flags; if ((flags = fcntl(fileno(fp[n]),F_GETFL,0)) > -1) fcntl(fileno(fp[n]),F_SETFL, flags | #ifdef QNX O_NONBLOCK #else O_NDELAY #endif /* QNX */ ); debug(F100,"zopeno ZOFILE nonblocking","",0); #endif /* DONDELAY */ } else if (n == ZOFILE && !zofbuffer) { /* buffered or unbuffered */ setbuf(fp[n],NULL); debug(F100,"zopeno ZOFILE unbuffered","",0); } #ifdef CK_LOGIN /* Enforce anonymous file-creation permission */ if (isguest) if (n == ZWFILE || n == ZMFILE || n == ZOFILE || n == ZDFILE || n == ZTFILE || n == ZPFILE || n == ZSFILE) chmod(name,ckxperms); #endif /* CK_LOGIN */ #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_FC && ckxlogging) syslog(LOG_INFO, "file[%d] %s: %s ok", n, fullname, append ? "append" : "create" ); #endif /* CKSYSLOG */ debug(F100, "zopeno ok", "", 0); } zoutcnt = 0; /* (PWP) reset output buffer */ zoutptr = zoutbuffer; return((fp[n] != NULL) ? 1 : 0); } /* Z C L O S E -- Close the given file. */ /* Returns 0 if arg out of range, 1 if successful, -1 if close failed. */ int #ifdef CK_ANSIC zclose( int n ) #else zclose(n) int n; #endif /* CK_ANSIC */ { int x = 0, x2 = 0; int dummy; extern CK_OFF_T ffc; debug(F101,"zclose file number","",n); if (chkfn(n) < 1) return(0); /* Check range of n */ if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */ x2 = zoutdump(); if (fp[ZSYSFN] || ispipe[n]) { /* If file is really pipe */ #ifndef NOPUSH x = zclosf(n); /* do it specially */ #else x = EOF; #endif /* NOPUSH */ debug(F101,"zclose zclosf","",x); /* debug(F101,"zclose zclosf fp[n]","",fp[n]); */ } else { if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]); fp[n] = NULL; #ifdef COMMENT if (n == ZCTERM || n == ZSTDIO) /* See zopeno() */ if (fp[ZOFILE] == stdout) fp[ZOFILE] = NULL; #endif /* COMMENT */ } iflen = -1L; /* Invalidate file length */ if (x == EOF) { /* if we got a close error */ debug(F101,"zclose fclose fails","",x); return(-1); } else if (x2 < 0) { /* or error flushing last buffer */ debug(F101,"zclose error flushing last buffer","",x2); return(-1); /* then return an error */ } else { /* Print log record compatible with wu-ftpd */ if (xferlog && (n == ZIFILE || n == ZOFILE)) { char * s, *p; extern char ttname[]; if (!iklogopen) (VOID) doiklog(); /* Open log if necessary */ debug(F101,"zclose iklogopen","",iklogopen); if (iklogopen) { int len; char * fnam; timenow = time(NULL); #ifdef CK_LOGIN if (logged_in) s = clienthost; else #endif /* CK_LOGIN */ s = (char *)ttname; if (!s) s = ""; if (!*s) s = "*"; #ifdef CK_LOGIN if (logged_in) { p = guestpass; if (!*p) p = "*"; } else #endif /* CK_LOGIN */ p = whoami(); len = 24 + 12 + (int)strlen(s) + 16 + (int)strlen(fullname) + 1 + 1 + 1 + 1 + (int)strlen(p) + 6 + 2 + 12; fnam = fullname; if (!*fnam) fnam = "(pipe)"; if (len > IKSDMSGLEN) sprintf(iksdmsg, /* SAFE */ "%.24s [BUFFER WOULD OVERFLOW]\n",ctime(&timenow)); else sprintf(iksdmsg, /* SAFE */ "%.24s %d %s %s %s %c %s %c %c %s %s %d %s\n", ctime(&timenow), /* date/time */ gtimer(), /* elapsed secs */ s, /* peer name */ ckfstoa(ffc), /* byte count */ fnam, /* full pathname of file */ (binary ? 'b' : 'a'), /* binary or ascii */ "_", /* options = none */ n == ZIFILE ? 'o' : 'i', /* in/out */ #ifdef CK_LOGIN (isguest ? 'a' : 'r'), /* User type */ #else 'r', #endif /* CK_LOGIN */ p, /* Username or guest passwd */ #ifdef CK_LOGIN logged_in ? "iks" : "kermit", /* Record ID */ #else "kermit", #endif /* CK_LOGIN */ 0, /* User ID on client system unknown */ "*" /* Ditto */ ); debug(F110,"zclose iksdmsg",iksdmsg,0); dummy = write(xferlog, iksdmsg, (int)strlen(iksdmsg)); } } debug(F101,"zclose returns","",1); return(1); } } /* Z C H I N -- Get a character from the input file. */ /* Returns -1 if EOF, 0 otherwise with character returned in argument */ int #ifdef CK_ANSIC zchin( int n, int *c ) #else zchin(n,c) int n; int *c; #endif /* CK_ANSIC */ { int a; #ifdef IKSD if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) { a = coninc(0); if (*c < 0) return(-1); } else #endif /* IKSD */ /* (PWP) Just in case this gets called when it shouldn't. */ if (n == ZIFILE) { a = zminchar(); /* Note: this catches Ctrl-Z */ if (a < 0) /* (See zinfill()...) */ return(-1); } else { a = getc(fp[n]); if (a == EOF) return(-1); #ifdef CK_CTRLZ /* If SET FILE EOF CTRL-Z, first Ctrl-Z marks EOF */ if (!binary && a == 0x1A && eofmethod == XYEOF_Z) return(-1); #endif /* CK_CTRLZ */ } *c = (CHAR) a & 0377; return(0); } /* Z S I N L -- Read a line from a file */ /* Writes the line into the address (*s) provided by the caller, maximum length x. n is the Kermit "channel number". Writing terminates when newline is encountered, newline is not copied. Writing also terminates upon EOF or if length x is exhausted. Returns 0 on success, -1 on EOF or error. */ int #ifdef CK_ANSIC zsinl( int n, char *s, int x ) #else zsinl(n,s,x) int n, x; char *s; #endif /* CK_ANSIC */ { int a, z = 0; /* z is return code. */ int count = 0; int len = 0; char *buf; extern CHAR feol; /* Line terminator */ if (!s || chkfn(n) < 1) /* Make sure file is open, etc */ return(-1); buf = s; s[0] = '\0'; /* Don't return junk */ a = -1; /* Current character, none yet. */ while (x--) { /* Up to given length */ int old = 0; if (feol) /* Previous character */ old = a; if (zchin(n,&a) < 0) { /* Read a character from the file */ debug(F101,"zsinl zchin fail","",count); if (count == 0) z = -1; /* EOF or other error */ break; } else count++; if (feol) { /* Single-character line terminator */ if (a == feol) break; } else { /* CRLF line terminator */ if (a == '\015') /* CR, get next character */ continue; if (old == '\015') { /* Previous character was CR */ if (a == '\012') { /* This one is LF, so we have a line */ break; } else { /* Not LF, deposit CR */ *s++ = '\015'; x--; len++; } } } *s = a; /* Deposit character */ s++; len++; } *s = '\0'; /* Terminate the string */ debug(F011,"zsinl",buf,len); return(z); } /* Z X I N -- Read x bytes from a file */ /* Reads x bytes (or less) from channel n and writes them to the address provided by the caller. Returns number of bytes read on success, 0 on EOF or error. */ int #ifdef CK_ANSIC zxin( int n, char *s, int x ) #else zxin(n,s,x) int n, x; char *s; #endif /* CK_ANSIC */ { #ifdef IKSD if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) { int a, i; a = ttchk(); if (a < 1) return(0); for (i = 0; i < a && i < x; i++) s[i] = coninc(0); return(i); } #endif /* IKSD */ return(fread(s, sizeof (char), x, fp[n])); } /* Z I N F I L L -- Buffered file input. (re)fill the file input buffer with data. All file input should go through this routine, usually by calling the zminchar() macro defined in ckcker.h. Returns: Value 0..255 on success, the character that was read. -1 on end of file. -2 on any kind of error other than end of file. -3 timeout when reading from pipe (Kermit packet mode only). */ int zinfill() { extern int kactive, srvping; errno = 0; #ifdef ZDEBUG printf("ZINFILL fp[%d]=%ld\n",ZIFILE,fp[ZIFILE]); #endif /* ZDEBUG */ #ifdef IKSD if (inserver && !local && fp[ZIFILE] == stdin) { int a, i; a = ttchk(); if (a < 0) return(-2); for (i = 0; i < a && i < INBUFSIZE; i++) { zinbuffer[i] = coninc(0); } zincnt = i; /* set pointer to beginning, (== &zinbuffer[0]) */ zinptr = zinbuffer; if (zincnt == 0) return(-1); zincnt--; /* One less char in buffer */ return((int)(*zinptr++) & 0377); /* because we return the first */ } #endif /* IKSD */ debug(F101,"zinfill kactive","",kactive); if (!(kactive && ispipe[ZIFILE])) { if (feof(fp[ZIFILE])) { debug(F100,"ZINFILL feof","",0); #ifdef ZDEBUG printf("ZINFILL EOF\n"); #endif /* ZDEBUG */ return(-1); } } clearerr(fp[ZIFILE]); #ifdef SELECT /* Here we can call select() to get a timeout... */ if (kactive && ispipe[ZIFILE]) { int secs, z = 0; #ifndef NOXFER if (srvping) { secs = 1; debug(F101,"zinfill calling ttwait","",secs); z = ttwait(fileno(fp[ZIFILE]),secs); debug(F101,"zinfill ttwait","",z); } #endif /* NOXFER */ if (z == 0) return(-3); } #endif /* SELECT */ #ifdef DEBUG if (deblog) { int i; debug(F101,"ZINFILL INBUFSIZE","",INBUFSIZE); #ifdef USE_MEMCPY memset(zinbuffer, 0xFF, INBUFSIZE); #else for (i = 0; i < INBUFSIZE; i++) { zinbuffer[i] = 0xFF; #ifdef COMMENT /* Too much! */ debug(F101,"ZINFILL zinbuffer[i]","",i); #endif /* COMMENT */ } #endif /* USE_MEMCPY */ ckstrncpy(zinbuffer,"zinbuffer is a valid buffer",INBUFSIZE); /* debug(F111,"ZINFILL about to call fread",zinbuffer,zinbuffer); */ } #endif /* DEBUG */ /* Note: The following read MUST be nonblocking when reading from a pipe and we want timeouts to work. See zxcmd(). */ zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]); debug(F101,"ZINFILL fread","",zincnt); /* Just the size */ #ifdef ZDEBUG printf("FREAD=%d\n",zincnt); #endif /* ZDEBUG */ #ifdef CK_CTRLZ /* If SET FILE EOF CTRL-Z, first Ctrl-Z marks EOF */ if (zincnt > 0 && !binary && eofmethod == XYEOF_Z) { register int i; for (i = 0; i < zincnt; i++) { if (zinbuffer[i] == SUB) { zincnt = i; /* Stop at first Ctrl-Z */ if (i == 0) return(-1); break; } } } #endif /* CK_CTRLZ */ if (zincnt == 0) { /* Got nothing? */ if (ferror(fp[ZIFILE])) { debug(F100,"ZINFILL ferror","",0); debug(F101,"ZINFILL errno","",errno); #ifdef ZDEBUG printf("ZINFILL errno=%d\n",errno); #endif /* ZDEBUG */ #ifdef EWOULDBLOCK return((errno == EWOULDBLOCK) ? -3 : -2); #else return(-2); #endif /* EWOULDBLOCK */ } /* In case feof() didn't work just above -- sometimes it doesn't... */ if (feof(fp[ZIFILE]) ) { debug(F100,"ZINFILL count 0 EOF return -1","",0); return (-1); } else { debug(F100,"ZINFILL count 0 not EOF return -2","",0); return(-2); } } zinptr = zinbuffer; /* set pointer to beginning, (== &zinbuffer[0]) */ zincnt--; /* One less char in buffer */ return((int)(*zinptr++) & 0377); /* because we return the first */ } /* Z S O U T -- Write a string out to the given file, buffered. */ /* Returns 0 on success, -1 on failure */ int #ifdef CK_ANSIC zsout( int n, char *s ) #else zsout(n,s) int n; char *s; #endif /* CK_ANSIC */ { int rc = 0; rc = chkfn(n); if (rc < 1) return(-1); /* Keep this, prevents memory faults */ if (!s) return(0); /* Null pointer, do nothing, succeed */ if (!*s) return(0); /* empty string, ditto */ #ifdef IKSD /* This happens with client-side Kermit server when a REMOTE command was sent from the server to the client and the server is supposed to display the text, but of course there is no place to display it since it is in remote mode executing Kermit protocol. */ if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) { #ifdef COMMENT return(ttol(s,((int)strlen(s)) < 0) ? -1 : 0); #else return(0); #endif /* COMMENT */ } #endif /* IKSD */ if (n == ZSFILE) { int k; k = strlen(s); rc = write(fileno(fp[n]),s,k); return((rc == k) ? 0 : -1); } rc = fputs(s,fp[n]) == EOF ? -1 : 0; if (n == ZWFILE) fflush(fp[n]); return(rc); } /* Z S O U T L -- Write string to file, with line terminator, buffered */ /* Returns 0 on success, -1 on failure */ int #ifdef CK_ANSIC zsoutl( int n, char *s ) #else zsoutl(n,s) int n; char *s; #endif /* CK_ANSIC */ { if (zsout(n,s) < 0) return(-1); #ifdef IKSD if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) { #ifdef COMMENT return(ttoc(LF)); #else return(0); /* See comments in zsout() */ #endif /* COMMENT */ } #endif /* IKSD */ if (n == ZSFILE) /* Session log is unbuffered */ return(write(fileno(fp[n]),"\n",1) == 1 ? 0 : -1); else if (fputs("\n",fp[n]) == EOF) return(-1); if (n == ZDIFIL || n == ZWFILE) /* Flush connection log records */ fflush(fp[n]); return(0); } /* Z S O U T X -- Write x characters to file, unbuffered. */ /* Returns number of characters written on success, -1 on failure */ int #ifdef CK_ANSIC zsoutx( int n, char *s, int x ) #else zsoutx(n,s,x) int n, x; char *s; #endif /* CK_ANSIC */ { int k; if (!s) return(0); if (!*s) return(0); #ifdef IKSD if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) { #ifdef COMMENT return(ttol(s,x)); /* See comments in zsout() */ #else return(x); #endif /* COMMENT */ } #endif /* IKSD */ if ((k = (int)strlen(s)) > x) x = k; /* Nothing else would make sense */ #ifdef COMMENT if (chkfn(n) < 1) return(-1); return(write(fp[n]->_file,s,x)); #endif /* COMMENT */ return(write(fileno(fp[n]),s,x) == x ? x : -1); } /* Z C H O U T -- Add a character to the given file. */ /* Should return 0 or greater on success, -1 on failure (e.g. disk full) */ int #ifdef CK_ANSIC zchout(register int n, char c) #else zchout(n,c) register int n; char c; #endif /* CK_ANSIC */ /* zchout() */ { /* if (chkfn(n) < 1) return(-1); */ #ifdef IKSD if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) { #ifdef COMMENT return(ttoc(c)); #else return(0); /* See comments in zsout() */ #endif /* COMMENT */ } #endif /* IKSD */ if (n == ZSFILE) /* Use unbuffered for session log */ return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1); /* Buffered for everything else */ if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */ return(ferror(fp[n])?-1:0); /* Check to make sure */ else /* Otherwise... */ return(0); /* There was no error. */ } /* (PWP) buffered character output routine to speed up file IO */ int zoutdump() { int x; char * zp; zoutptr = zoutbuffer; /* Reset buffer pointer in all cases */ #ifdef DEBUG if (deblog) debug(F101,"zoutdump zoutcnt","",zoutcnt); #endif /* DEBUG */ if (zoutcnt == 0) { /* Nothing to output */ return(0); } else if (zoutcnt < 0) { /* Unexpected negative argument */ zoutcnt = 0; /* Reset output buffer count */ return(-1); /* and fail. */ } #ifdef IKSD if (inserver && !local && fp[ZOFILE] == stdout) { #ifdef COMMENT x = ttol(zoutbuffer,zoutcnt); #else x = 1; /* See comments in zsout() */ #endif /* COMMENT */ zoutcnt = 0; return(x > 0 ? 0 : -1); } #endif /* IKSD */ /* Frank Prindle suggested that replacing this fwrite() by an fflush() followed by a write() would improve the efficiency, especially when writing to stdout. Subsequent tests showed a 5-fold improvement. */ #ifdef COMMENT if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) ... #endif /* COMMENT */ #ifndef CK_NONBLOCK fflush(fp[ZOFILE]); #endif /* CK_NONBLOCK */ zp = zoutbuffer; while (zoutcnt > 0) { if ((x = write(fileno(fp[ZOFILE]),zp,zoutcnt)) > -1) { #ifdef DEBUG if (deblog) /* Save a function call... */ debug(F101,"zoutdump wrote","",x); #endif /* DEBUG */ zoutcnt -= x; /* Adjust output buffer count */ zp += x; /* and pointer */ } else { #ifdef DEBUG if (deblog) { debug(F101,"zoutdump write error","",errno); debug(F101,"zoutdump write returns","",x); } #endif /* DEBUG */ zoutcnt = 0; /* Reset output buffer count */ return(-1); /* write() failed */ } } return(0); } /* C H K F N -- Internal function to verify file number is ok */ /* 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 #ifdef CK_ANSIC chkfn( int n ) #else chkfn(n) int n; #endif /* CK_ANSIC */ { /* if (n != ZDFILE) debug(F101,"chkfn","",n); */ if (n < 0 || n >= ZNFILS) { if (n != ZDFILE) debug(F101,"chkfn out of range","",n); return(-1); } else { /* if (n != ZDFILE) debug(F101,"chkfn fp[n]","",fp[n]); */ return((fp[n] == NULL) ? 0 : 1); } } /* Z G E T F S -- Return file size regardless of accessibility */ /* Used for directory listings, etc. Returns: The size of the file in bytes, 0 or greater, if the size can be learned. -1 if the file size can not be obtained. Also (and this is a hack just for UNIX): If the argument is the name of a symbolic link, the global variable zgfs_link is set to 1, and the global buffer linkname[] gets the link value. And it sets zgfs_dir to 1 if it's a directory, otherwise 0. This lets us avoid numerous redundant calls to stat(). */ int zgfs_link = 0; int zgfs_dir = 0; time_t zgfs_mtime = 0; unsigned int zgfs_mode = 0; #ifdef CKSYMLINK char linkname[CKMAXPATH+1]; #ifndef _IFLNK #define _IFLNK 0120000 #endif /* _IFLNK */ #endif /* CKSYMLINK */ CK_OFF_T #ifdef CK_ANSIC zgetfs( char * name ) #else zgetfs(name) char *name; #endif /* CK_ANSIC */ { struct stat buf; char fnam[CKMAXPATH+4]; CK_OFF_T size = (CK_OFF_T)-1; int x; int needrlink = 0; char * s; if (!name) name = ""; if (!*name) return(-1); #ifdef UNIX x = strlen(name); if (x == 9 && !strcmp(name,"/dev/null")) return(0); #endif /* UNIX */ s = name; #ifdef DTILDE if (*s == '~') { s = tilde_expand(s); if (!s) s = ""; if (!*s) s = name; } #endif /* DTILDE */ x = ckstrncpy(fnam,s,CKMAXPATH); s = fnam; debug(F111,"zgetfs fnam",s,x); if (x > 0 && s[x-1] == '/') s[x-1] = '\0'; zgfs_dir = 0; /* Assume it's not a directory */ zgfs_link = 0; /* Assume it's not a symlink */ zgfs_mtime = 0; /* No time yet */ zgfs_mode = 0; /* No permission bits yet */ #ifdef CKSYMLINK /* We're doing symlinks? */ #ifdef USE_LSTAT /* OK to use lstat()? */ x = lstat(s,&buf); debug(F101,"STAT","",1); if (x < 0) /* stat() failed */ return(-1); if ( /* Now see if it's a symlink */ #ifdef S_ISLNK S_ISLNK(buf.st_mode) #else #ifdef _IFLNK ((_IFMT & buf.st_mode) == _IFLNK) #endif /* _IFLNK */ #endif /* S_ISLNK */ ) { zgfs_link = 1; /* It's a symlink */ linkname[0] = '\0'; /* Get the name */ x = readlink(s,linkname,CKMAXPATH); debug(F101,"zgetfs readlink",s,x); if (x > -1 && x < CKMAXPATH) { /* It's a link */ linkname[x] = '\0'; size = buf.st_size; /* Remember size of link */ x = stat(s,&buf); /* Now stat the linked-to file */ debug(F101,"STAT","",2); if (x < 0) /* so we can see if it's a directory */ return(-1); } else { ckstrncpy(linkname,"(lookup failed)",CKMAXPATH); } } #else /* !USE_LSTAT */ x = stat(s,&buf); /* No lstat(), use stat() instead */ debug(F101,"STAT","",3); if (x < 0) return(-1); #endif /* USE_LSTAT */ /* Do we need to call readlink()? */ #ifdef NOLINKBITS /* lstat() does not work in SCO operating systems. From "man NS lstat": lstat obtains information about the file named by path. In the case of a symbolic link, lstat returns information about the link, and not the file named by the link. It is only used by the NFS automount daemon and should not be utilized by users. */ needrlink = 1; debug(F101,"zgetfs forced needrlink","",needrlink); #else #ifdef S_ISLNK needrlink = S_ISLNK(buf.st_mode); debug(F101,"zgetfs S_ISLNK needrlink","",needrlink); #else #ifdef _IFLNK needrlink = (_IFMT & buf.st_mode) == _IFLNK; debug(F101,"zgetfs _IFLNK needrlink","",needrlink); #else needrlink = 1; debug(F101,"zgetfs default needrlink","",needrlink); #endif /* _IFLNK */ #endif /* S_ISLNK */ #endif /* NOLINKBITS */ if (needrlink) { linkname[0] = '\0'; errno = 0; x = readlink(s,linkname,CKMAXPATH); #ifdef DEBUG debug(F111,"zgetfs readlink",s,x); if (x < 0) debug(F101,"zgetfs readlink errno","",errno); else debug(F110,"zgetfs readlink result",linkname,0); #endif /* DEBUG */ if (x > -1 && x < CKMAXPATH) { zgfs_link = 1; linkname[x] = '\0'; } } #else /* !CKSYMLINK */ x = stat(s,&buf); /* Just stat the file */ debug(F111,"zgetfs stat",s,x); if (x < 0) /* and get the size */ return(-1); #endif /* CKSYMLINK */ zgfs_mtime = buf.st_mtime; zgfs_mode = buf.st_mode; zgfs_dir = (S_ISDIR(buf.st_mode)) ? 1 : 0; /* Set "is directory" flag */ debug(F111,"zgetfs size",s,size); debug(F111,"zgetfs st_size",s,buf.st_size); return((size < 0L) ? buf.st_size : size); /* Return the size */ } /* Z C H K I -- Check if input file exists and is readable */ /* Returns: >= 0 if the file can be read (returns the size). -1 if file doesn't exist or can't be accessed, -2 if file exists but is not readable (e.g. a directory file). -3 if file exists but protected against read access. For Berkeley Unix, a file must be of type "regular" to be readable. Directory files, special files, and symbolic links are not readable. */ CK_OFF_T #ifdef CK_ANSIC zchki( char * name ) #else zchki(name) char *name; #endif /* CK_ANSIC */ { struct stat buf; char * s; int x, itsadir = 0; extern int zchkid, diractive, matchfifo; if (!name) return(-1); x = strlen(name); if (x < 1) return(-1); s = name; #ifdef UNIX if (x == 9 && !strcmp(s,"/dev/null")) return(0); if (x == 8 && !strcmp(s,"/dev/tty")) return(0); #endif /* UNIX */ #ifdef DTILDE if (*s == '~') { s = tilde_expand(s); if (!s) s = ""; if (!*s) s = name; } #endif /* DTILDE */ #ifdef CKROOT debug(F111,"zchki setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(name)) { debug(F110,"zchki setroot violation",name,0); return(-1); } #endif /* CKROOT */ /* In (at least) Mac OS X 10.6, stat(filename) returns 1 even if the file does not exist. This was causing empty backup files to be created. Now we also double-check by looking at ERRNO. - fdc 2021-05-07 */ errno = 0; /* Reset errno just to be safe */ x = stat(s,&buf); debug(F101,"STAT","",5); debug(F111,"zchki stat return code",s,x); debug(F101,"zchki stat errno","",errno); debug(F110,"zchki stat errmsg",ck_errstr(),0); if (x < 0) { /* File doesn't exist */ debug(F111,"zchki stat fails",s,errno); return(-1); /* The following is provisional... On some Mac OS X / OS X / macOS versions, stat() returns 0 ("success") when the filename given does not correspond to an existing file, where every other OS returns -1 ("failure"). In this case, however, errno to a nonzero value, which I would have expected to be ENOENT, but in the case that was reported, it was ENOTTY, which I wouldn't have expected. There's nothing in Google about this. - fdc, 8 May 2022. */ } else if ( errno ) { debug(F111,"zchki stat returns 0 but with a nonzero errno",s,errno); return(-1); } /* Another possibility might be to look in the stat buf, but for what? Or to use access() rather that stat(). But all of these approaches have their portability risks. */ if (S_ISDIR (buf.st_mode)) itsadir = 1; if (!(itsadir && zchkid)) { /* Unless this... */ if (!S_ISREG (buf.st_mode) /* Must be regular file */ #ifdef S_ISFIFO && (!matchfifo || !S_ISFIFO (buf.st_mode)) /* or FIFO */ #endif /* S_ISFIFO */ ) { debug(F111,"zchki not regular file (or fifo)",s,matchfifo); return(-2); } } debug(F111,"zchki stat ok:",s,x); if (diractive) { /* If listing don't check access */ x = 1; } else { #ifdef SW_ACC_ID debug(F100,"zchki swapping ids for access()","",0); priv_on(); #endif /* SW_ACC_ID */ if ((x = access(s,R_OK)) < 0) x = access(s,X_OK); /* For RUN-class commands */ #ifdef SW_ACC_ID priv_off(); debug(F100,"zchki swapped ids restored","",0); #endif /* SW_ACC_ID */ } if (x < 0) { /* Is the file accessible? */ debug(F111,"zchki access failed:",s,x); /* No */ return(-3); } else { iflen = buf.st_size; /* Yes, remember size */ ckstrncpy(nambuf,s,CKMAXPATH); /* and name globally. */ debug(F111,"zchki access ok:",s,iflen); return((iflen > -1L) ? iflen : 0L); } } /* Z C H K O -- Check if output file can be created */ /* Returns -1 if write permission for the file would be denied, 0 otherwise. NOTE: The design is flawed. There is no distinction among: . Can I overwrite an existing file? . Can I create a file (or directory) in an existing directory? . Can I create a file (or directory) and its parent(s)? */ int #ifdef CK_ANSIC zchko( char * name ) #else zchko(name) char *name; #endif /* CK_ANSIC */ { int i, x, itsadir = 0; char *s = NULL; char * oname; extern int zchkod; /* Used by IF WRITEABLE */ debug(F110,"zchko entry",name,0); if (!name) return(-1); /* Watch out for null pointer. */ oname = name; #ifdef CKROOT debug(F111,"zchko setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(name)) { debug(F110,"zchko setroot violation",name,0); errno = EACCES; return(-1); } #endif /* CKROOT */ x = (int)strlen(name); /* Get length of filename */ debug(F111,"zchko len",name,x); debug(F111,"zchko zchkod",name,zchkod); #ifdef UNIX /* Writing to null device is OK. */ if (x == 9 && !strcmp(name,"/dev/null")) return(0); if (x == 8 && !strcmp(name,"/dev/tty")) return(0); #endif /* UNIX */ s = name; #ifdef DTILDE if (*s == '~') { s = tilde_expand(s); if (!s) s = ""; if (!*s) s = name; x = strlen(s); } #endif /* DTILDE */ name = s; s = NULL; /* zchkod is a global flag meaning we're checking not to see if the directory file is writeable, but if it's OK to create files IN the directory. */ if (!zchkod && isdir(name)) { /* Directories are not writeable */ debug(F111,"zchko isdir",name,1); return(-1); } s = malloc(x+3); /* Must copy because we can't */ if (!s) { /* write into our argument. */ fprintf(stderr,"zchko: Malloc error 46\n"); return(-1); } ckstrncpy(s,name,x+3); #ifdef UNIX #ifdef NOUUCP { /* 2009/10/20 */ /* Allow tty devices to opened as output files */ int fd, istty = 0, flags = 0; debug(F110,"zchko attempting to open",name,0); if (!ckstrcmp(name,"/dev/",5,1)) { /* If tty (2016/02/16) */ /* Don't block on lack of Carrier or other modem signals */ #ifdef O_NONBLOCK flags = O_NONBLOCK; #else #ifdef O_NDELAY flags = O_NDELAY; #else #ifdef FNDELAY flags = FNDELAY; #endif /* FNDELAY */ #endif /* O_NDELAY */ #endif /* O_NONBLOCK */ } debug(F111,"zchko open mode",name,flags); /* Must attempt to open it so isatty() can be used */ fd = open(name,O_WRONLY|O_CREAT|flags,0600); debug(F111,"zchko open",name,fd); if (fd > -1) { /* to get a file descriptor */ if (isatty(fd)) /* for isatty() */ istty++; debug(F111,"zchko isatty",name,istty); /* Failure to close this file caused creation of spurious backup file when downloading */ fd = close(fd); /* 2022-05-09 */ if (zdelet(name) == 0) { /* 2022-05-09 */ debug(F110,"zchko delete ok",name,0); } else { debug(F111,"zchko delete failed",name,errno); } if (istty) { goto doaccess; } } else { debug(F111,"zchko open errno",name,errno); x = -1; goto xzchko; /* fdc 2015/01/12 */ /* previously control fell through causing core dumps */ /* on builds with -DNOUUCP */ } } #endif /* NOUUCP */ #endif /* UNIX */ if (zchkod) goto doaccess; /* fdc 20160129 */ /* The following code gets the name of the containing directory so we can use access() to check if we are allowed to create files in it. */ for (i = x; i > 0; i--) { /* Strip filename from right. */ if (ISDIRSEP(s[i-1])) { itsadir = 1; break; } } debug(F101,"zchko i","",i); debug(F101,"zchko itsadir","",itsadir); #ifdef COMMENT /* X/OPEN XPG3-compliant systems fail if argument ends with "/"... */ if (i == 0) /* If no path, use current directory */ strcpy(s,"./"); else /* Otherwise, use given one. */ s[i] = '\0'; #else #ifdef COMMENT /* The following does not work for "foo/bar" where the foo directory does not exist even though we could create it: access("foo/.") fails, but access("foo") works OK. */ /* So now we use "path/." if path given, or "." if no path given. */ s[i++] = '.'; /* Append "." to path. */ s[i] = '\0'; #else /* So NOW we strip path segments from the right as long as they don't */ /* exist -- we only call access() for path segments that *do* exist.. */ /* (But this isn't quite right either since now zchko(/foo/bar/baz/xxx) */ /* succeeds when I have write access to foo and bar but baz doesn't exit.) */ if (itsadir && i > 0) { s[i-1] = '\0'; while (s[0] && !isdir(s)) { for (i = (int)strlen(s); i > 0; i--) { if (ISDIRSEP(s[i-1])) { s[i-1] = '\0'; break; } } if (i == 0) s[0] = '\0'; } } else { s[i++] = '.'; /* Append "." to path. */ s[i] = '\0'; } #endif /* COMMENT */ #endif /* COMMENT */ if (!s[0]) ckstrncpy(s,".",x+3); doaccess: #ifdef SW_ACC_ID debug(F110,"zchko swapping ids for access()",s,0); priv_on(); #endif /* SW_ACC_ID */ x = access(s,W_OK); /* Check access of path. */ debug(F110,"zchko access",s,x); #ifdef SW_ACC_ID priv_off(); debug(F100,"zchko swapped ids restored","",0); #endif /* SW_ACC_ID */ xzchko: /* Exit point */ if (x < 0) debug(F111,"zchko access failed:",s,errno); else debug(F111,"zchko access ok:",s,x); if (s) free(s); /* Free temporary storage */ return((x < 0) ? -1 : 0); /* and return. */ } /* Z D E L E T -- Delete the named file. */ /* Returns: -1 on error, 0 on success */ int #ifdef CK_ANSIC zdelet( char * name ) #else zdelet(name) char *name; #endif /* CK_ANSIC */ { int x; #ifdef CK_LOGIN if (isguest) return(-1); #endif /* CK_LOGIN */ #ifdef CKROOT debug(F111,"zdelet setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(name)) { debug(F110,"zdelet setroot violation",name,0); return(-1); } #endif /* CKROOT */ x = unlink(name); debug(F111,"zdelet",name,x); #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_FC && ckxlogging) { fullname[0] = '\0'; zfnqfp(name,CKMAXPATH,fullname); debug(F110,"zdelet fullname",fullname,0); if (x < 0) syslog(LOG_INFO, "file[] %s: delete failed (%m)", fullname); else syslog(LOG_INFO, "file[] %s: delete ok", fullname); } #endif /* CKSYSLOG */ return(x); } /* Z R T O L -- Convert remote filename into local form */ VOID #ifdef CK_ANSIC zrtol( char *name, char *name2 ) #else zrtol(name,name2) char *name, *name2; #endif /* CK_ANSIC */ { nzrtol(name,name2,1,0,CKMAXPATH); } VOID #ifdef CK_ANSIC nzrtol( char *name, char *name2, int fncnv, int fnrpath, int max ) #else nzrtol(name,name2,fncnv,fnrpath,max) char *name,*name2;int fncnv,fnrpath,max; #endif /* CK_ANSIC */ { /* nzrtol */ char *s, *p; int flag = 0, n = 0; char fullname[CKMAXPATH+1]; int devnull = 0; int acase = 0; if (!name2) return; if (!name) name = ""; debug(F111,"nzrtol name",name,fncnv); #ifdef DTILDE s = name; if (*s == '~') { s = tilde_expand(s); if (!s) s = ""; if (*s) name = s; } #endif /* DTILDE */ /* Handle the path -- we don't have to convert its format, since */ /* the standard path format and our (UNIX) format are the same. */ fullname[0] = NUL; devnull = !strcmp(name,"/dev/null"); if (!devnull && fnrpath == PATH_OFF) { /* RECEIVE PATHNAMES OFF */ zstrip(name,&p); strncpy(fullname,p,CKMAXPATH); } else if (!devnull && fnrpath == PATH_ABS) { /* REC PATHNAMES ABSOLUTE */ strncpy(fullname,name,CKMAXPATH); } else if (!devnull && isabsolute(name)) { /* RECEIVE PATHNAMES RELATIVE */ ckmakmsg(fullname,CKMAXPATH,".",name,NULL,NULL); } else { /* Ditto */ ckstrncpy(fullname,name,CKMAXPATH); } fullname[CKMAXPATH] = NUL; debug(F110,"nzrtol fullname",fullname,0); #ifndef NOTRUNCATE /* The maximum length for any segment of a filename is CKMAXNAM, defined above. On some platforms (at least QNX) if a segment exceeds this limit, the open fails with ENAMETOOLONG, so we must prevent it by truncating each overlong name segment to the maximum segment length before passing the name to open(). This must be done even when file names are literal, so as not to halt a file transfer unnecessarily. */ { char buf[CKMAXPATH+1]; /* New temporary buffer on stack */ char *p = fullname; /* Source and */ char *s = buf; /* destination pointers */ int i = 0, n = 0; debug(F101,"nzrtol sizing CKMAXNAM","",CKMAXNAM); while (*p && n < CKMAXPATH) { /* Copy name to new buffer */ if (++i > CKMAXNAM) { /* If this segment too long */ while (*p && *p != '/') /* skip past the rest... */ p++; i = 0; /* and reset counter. */ } else if (*p == '/') { /* End of this segment. */ i = 0; /* Reset counter. */ } *s++ = *p++; /* Copy this character. */ n++; } *s = NUL; ckstrncpy(fullname,buf,CKMAXPATH); /* Copy back to original buffer. */ debug(F111,"nzrtol sizing",fullname,n); } #endif /* NOTRUNCATE */ if (!fncnv || devnull) { /* Not converting */ ckstrncpy(name2,fullname,max); /* We're done. */ return; } name = fullname; /* Converting */ p = name2; for (; *name != '\0' && n < CKMAXNAM; name++) { if (*name > SP) flag = 1; /* Strip leading blanks and controls */ if (flag == 0 && *name < '!') continue; if (fncnv > 0) { if (*name == SP) { *p++ = '_'; n++; continue; } if (isupper(*name)) /* Check for mixed case */ acase |= 1; else if (islower(*name)) acase |= 2; } *p++ = *name; n++; } *p-- = '\0'; /* Terminate */ while (*p < '!' && p > name2) /* Strip trailing blanks & controls */ *p-- = '\0'; if (*name2 == '\0') { /* Nothing left? */ ckstrncpy(name2,"NONAME",max); /* do this... */ } else if (acase == 1) { /* All uppercase? */ p = name2; /* So convert all letters to lower */ while (*p) { if (isupper(*p)) *p = tolower(*p); p++; } } debug(F110,"nzrtol new name",name2,0); } /* Z S T R I P -- Strip device & directory name from file specification */ /* Strip pathname from filename "name", return pointer to result in name2 */ static char work[CKMAXPATH+1]; VOID #ifdef CK_ANSIC zstrip( char *name, char **name2 ) #else zstrip(name,name2) char *name, **name2; #endif /* CK_ANSIC */ { char *cp, *pp; int n = 0; debug(F110,"zstrip before",name,0); if (!name) { *name2 = ""; return; } pp = work; #ifdef DTILDE /* Strip leading tilde */ if (*name == '~') name++; debug(F110,"zstrip after tilde-stripping",name,0); #endif /* DTILDE */ for (cp = name; *cp; cp++) { if (ISDIRSEP(*cp)) { pp = work; n = 0; } else { *pp++ = *cp; if (n++ >= CKMAXPATH) break; } } *pp = '\0'; /* Terminate the string */ *name2 = work; debug(F110,"zstrip after",*name2,0); } /* Z L T O R -- Local TO Remote */ VOID #ifdef CK_ANSIC zltor( char *name, char *name2 ) #else zltor(name,name2) char *name, *name2; #endif /* CK_ANSIC */ { nzltor(name,name2,1,0,CKMAXPATH); } /* N Z L T O R -- New Local TO Remote */ /* fncnv = 0 for no conversion, > 0 for regular conversion, < 0 for minimal. */ VOID #ifdef CK_ANSIC nzltor( char *name, char *name2, int fncnv, int fnspath, int max ) #else nzltor(name,name2,fncnv,fnspath,max) char *name,*name2;int fncnv,fnspath,max; #endif /* CK_ANSIC */ { /* nzltor */ char *cp, *pp; #ifdef COMMENT int dc = 0; #endif /* COMMENT */ int n = 0; char *dotp = NULL; char *dirp = NULL; char fullname[CKMAXPATH+1]; char *p; CHAR c; #ifndef NOCSETS extern int fcharset, /* tcharset, */ language; int langsv; _PROTOTYP ( CHAR (*sxo), (CHAR) ) = NULL; /* Translation functions */ #ifdef CK_ANSIC extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); #else extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); #endif /* CK_ANSIC */ langsv = language; language = L_USASCII; #ifdef COMMENT /* Proper translation of filenames must be done elsewhere */ n = tcharset ? tcharset : TC_USASCII; sxo = xls[n][fcharset]; #else sxo = xls[TC_USASCII][fcharset]; #endif /* COMMENT */ #endif /* NOCSETS */ debug(F110,"nzltor name",name,0); /* Handle pathname */ fullname[0] = NUL; if (fnspath == PATH_OFF) { /* PATHNAMES OFF */ zstrip(name,&p); ckstrncpy(fullname,p,CKMAXPATH); } else { /* PATHNAMES RELATIVE or ABSOLUTE */ char * p = name; while (1) { if (!strncmp(p,"../",3)) p += 3; else if (!strncmp(p,"./",2)) p += 2; else break; } if (fnspath == PATH_ABS) { /* ABSOLUTE */ zfnqfp(p,CKMAXPATH,fullname); } else { /* RELATIVE */ ckstrncpy(fullname,p,CKMAXPATH); } } debug(F110,"nzltor fullname",fullname,0); if (!fncnv) { /* Not converting */ ckstrncpy(name2,fullname,max); /* We're done. */ #ifndef NOCSETS langsv = language; #endif /* NOCSETS */ return; } name = fullname; /* Converting */ #ifdef aegis char *namechars; int tilde = 0, bslash = 0; if ((namechars = getenv("NAMECHARS")) != NULL) { if (ckstrchr(namechars, '~' ) != NULL) tilde = '~'; if (ckstrchr(namechars, '\\') != NULL) bslash = '\\'; } else { tilde = '~'; bslash = '\\'; } #endif /* aegis */ pp = work; /* Output buffer */ for (cp = name, n = 0; *cp && n < max; cp++,n++) { /* Convert name chars */ c = *cp; #ifndef NOCSETS if (sxo) c = (*sxo)(c); /* Convert to ASCII */ #endif /* NOCSETS */ if (fncnv > 0 && islower(c)) /* Uppercase letters */ *pp++ = toupper(c); /* Change tilde to hyphen */ else if (c == '~') *pp++ = '-'; else if (fncnv > 0 && c == '#') /* Change number sign to 'X' */ *pp++ = 'X'; else if (c == '*' || c == '?') /* Change wildcard chars to 'X' */ *pp++ = 'X'; else if (c == ' ') /* Change space to underscore */ *pp++ = '_'; else if (c < ' ') /* Change controls to 'X' */ *pp++ = 'X'; else if (fncnv > 0 && c == '.') { /* Change dot to underscore */ dotp = pp; /* Remember where we last did this */ *pp++ = '_'; } else { if (c == '/') dirp = pp; *pp++ = c; } } *pp = NUL; /* Tie it off. */ #ifdef COMMENT if (dotp) *dotp = '.'; /* Restore last dot (if any) */ #else if (dotp > dirp) *dotp = '.'; /* Restore last dot in file name */ #endif /* COMMENT */ cp = name2; /* If nothing before dot, */ if (*work == '.') *cp++ = 'X'; /* insert 'X' */ ckstrncpy(cp,work,max); #ifndef NOCSETS language = langsv; #endif /* NOCSETS */ debug(F110,"nzltor name2",name2,0); } /* Z C H D I R -- Change directory */ /* Call with: dirnam = pointer to name of directory to change to, which may be "" or NULL to indicate user's home directory. Returns: 0 on failure 1 on success */ int #ifdef CK_ANSIC zchdir( char * dirnam ) #else zchdir(dirnam) char *dirnam; #endif /* CK_ANSIC */ { char *hd, *sp; #ifdef IKSDB _PROTOTYP (int slotdir,(char *,char *)); #endif /* IKSDB */ #ifndef NOSPL extern struct mtab *mactab; /* Main macro table */ extern int nmac; /* Number of macros */ #endif /* NOSPL */ debug(F110,"zchdir",dirnam,0); if (!dirnam) dirnam = ""; if (!*dirnam) /* If argument is null or empty, */ dirnam = zhome(); /* use user's home directory. */ sp = dirnam; debug(F110,"zchdir 2",dirnam,0); #ifdef DTILDE hd = tilde_expand(dirnam); /* Attempt to expand tilde */ if (!hd) hd = ""; if (*hd == '\0') hd = dirnam; /* in directory name. */ #else hd = dirnam; #endif /* DTILDE */ debug(F110,"zchdir 3",hd,0); #ifdef CKROOT debug(F111,"zchdir setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(hd)) { debug(F110,"zchdir setroot violation",hd,0); return(0); } #endif /* CKROOT */ #ifdef pdp11 /* Just to save some space */ return((chdir(hd) == 0) ? 1 : 0); #else if (chdir(hd) == 0) { /* Try to cd */ #ifdef IKSDB #ifdef CK_LOGIN if (inserver && ikdbopen) slotdir(isguest ? anonroot : "", zgtdir()); #endif /* CK_LOGIN */ #endif /* IKSDB */ #ifndef NOSPL if (nmac) { /* Any macros defined? */ int k; /* Yes */ static int on_cd = 0; if (!on_cd) { on_cd = 1; k = mlook(mactab,"on_cd",nmac); /* Look this up */ if (k >= 0) { /* If found, */ if (dodo(k,zgtdir(),0) > -1) /* set it up, */ parser(1); /* and execute it */ } on_cd = 0; } } #endif /* NOSPL */ return(1); } return(0); #endif /* pdp11 */ } int #ifdef CK_ANSIC zchkpid(unsigned long xpid) #else zchkpid(xpid) unsigned long xpid; #endif /* CK_ANSIC */ { return((kill((PID_T)xpid,0) < 0) ? 0 : 1); } /* Z H O M E -- Return pointer to user's home directory */ static char * zhomdir = NULL; char * zhome() { char * home; #ifdef CKROOT if (ckrootset) return((char *)ckroot); #endif /* CKROOT */ #ifdef Plan9 home = getenv("home"); #else home = getenv("HOME"); #endif /* Plan9 */ makestr(&zhomdir,home); return(home ? zhomdir : "."); } /* Z G T D I R -- Returns a pointer to the current directory */ /* The "preferred" interface for getting the current directory in modern UNIX is getcwd() [POSIX 1003.1 5.2.2]. However, on certain platforms (such as SunOS), it is implemented by forking a shell, feeding it the pwd command, and returning the result, which is not only inefficient but also can result in stray messages to the terminal. In such cases -- as well as when getcwd() is not available at all -- getwd() can be used instead by defining USE_GETWD. However, note that getwd() provides no buffer-length argument and therefore no safeguard against memory leaks. */ #ifndef USE_GETWD #ifdef BSD42 #define USE_GETWD #else #ifdef SUNOS4 #define USE_GETWD #endif /* SUNOS4 */ #endif /* BSD42 */ #endif /* USE_GETWD */ #ifdef pdp11 #define CWDBL 80 /* Save every byte we can... */ #else #define CWDBL CKMAXPATH #endif /* pdp11 */ static char cwdbuf[CWDBL+2]; /* NOTE: The getcwd() prototypes are commented out on purpose. If you get compile-time warnings, search through your system's header files to see which one has the needed prototype, and #include it. Usually it is . See the section for including in ckcdeb.h and make any needed adjustments there (and report them). */ char * zgtdir() { char * buf = cwdbuf; char * s; #ifdef USE_GETWD extern char *getwd(); s = getwd(buf); debug(F110,"zgtdir BSD4 getwd()",s,0); if (!s) s = "./"; return(s); #else #ifdef BSD44 #ifdef DCLGETCWD _PROTOTYP( char * getcwd, (char *, SIZE_T) ); #endif /* DCLGETCWD */ debug(F101,"zgtdir BSD44 CWDBL","",CWDBL); s = getcwd(buf,CWDBL); if (!s) s = "./"; return(s); #else #ifdef MINIX2 #ifdef DCLGETCWD _PROTOTYP( char * getcwd, (char *, SIZE_T) ); #endif /* DCLGETCWD */ debug(F101,"zgtdir MINIX2 CWDBL","",CWDBL); s = getcwd(buf,CWDBL); if (!s) s = "./"; return(s); #else #ifdef SVORPOSIX #ifdef COMMENT /* This non-ANSI prototype can be fatal at runtime! (e.g. in SCO3.2v5.0.5). */ /* Anyway it's already prototyped in some header file that we have included. */ extern char *getcwd(); #else #ifdef DCLGETCWD _PROTOTYP( char * getcwd, (char *, SIZE_T) ); #endif /* DCLGETCWD */ #endif /* COMMENT */ debug(F101,"zgtdir SVORPOSIX CWDBL","",CWDBL); s = getcwd(buf,CWDBL); if (!s) s = "./"; return(s); #else #ifdef COHERENT #ifdef _I386 #ifdef DCLGETCWD extern char *getcwd(); #endif /* DCLGETCWD */ debug(F101,"zgtdir COHERENT _I386 CWDBL","",CWDBL); s = getcwd(buf,CWDBL); if (!s) s = "./"; return(s); #else extern char *getwd(); debug(F101,"zgtdir COHERENT CWDBL","",CWDBL); s = getwd(buf); if (!s) s = "./"; return(s); #endif /* _I386 */ #else #ifdef SUNOS4 debug(F101,"zgtdir SUNOS CWDBL","",CWDBL); s = getcwd(buf,CWDBL); if (!s) s = "./"; return(s); #else return("./"); #endif /* SUNOS4 */ #endif /* COHERENT */ #endif /* SYSVORPOSIX */ #endif /* MINIX2 */ #endif /* BSD44 */ #endif /* USE_GETWD */ } /* Z X C M D -- Run a system command so its output can be read like a file */ #ifndef NOPUSH int #ifdef CK_ANSIC zxcmd( int filnum, char *comand ) #else zxcmd(filnum,comand) int filnum; char *comand; #endif /* CK_ANSIC */ { int out; int pipes[2]; extern int kactive; /* From ckcpro.c and ckcmai.c */ if (nopush) { debug(F100,"zxcmd fails: nopush","",0); return(-1); } debug(F111,"zxcmd",comand,filnum); if (chkfn(filnum) < 0) return(-1); /* Need a valid Kermit file number. */ if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */ return(0); out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ; debug(F101,"zxcmd out",comand,out); /* Output to a command */ if (out) { /* Need popen() to do this. */ ckstrncpy(fullname,"(pipe)",CKMAXPATH); #ifdef NOPOPEN return(0); /* no popen(), fail. */ #else /* Use popen() to run the command. */ #ifdef _POSIX_SOURCE /* Strictly speaking, popen() is not available in POSIX.1 */ #define DCLPOPEN #endif /* _POSIX_SOURCE */ debug(F110,"zxcmd out",comand,0); if (priv_chk()) { debug(F100,"zxcmd priv_chk failed","",0); return(0); } errno = 0; fp[filnum] = popen(comand,"w"); debug(F111,"zxcmd popen",fp[filnum] ? "OK" : "Failed", errno); if (fp[filnum] == NULL) return(0); #ifdef COMMENT /* I wonder what this is all about... */ close(pipes[0]); /* Don't need the input side */ fp[filnum] = fdopen(pipes[1],"w"); /* Open output stream. */ fp[ZSYSFN] = fp[filnum]; /* Remember. */ #endif /* COMMENT */ ispipe[filnum] = 1; zoutcnt = 0; /* (PWP) reset input buffer */ zoutptr = zoutbuffer; return(1); #endif /* NOPOPEN */ } /* Input from a command */ #ifdef SNI541 /* SINIX-L 5.41 does not like fdopen() */ return(0); #else if (pipe(pipes) != 0) { debug(F100,"zxcmd pipe failure","",0); return(0); /* can't make pipe, fail */ } /* Create a fork in which to run the named process */ if (( #ifdef aegis pid = vfork() /* child */ #else pid = fork() /* child */ #endif /* aegis */ ) == 0) { /* We're in the fork. */ char *shpath, *shname, *shptr; /* Find user's preferred shell */ #ifndef aegis struct passwd *p; char *defshell; #ifdef HPUX10 /* Default shell */ defshell = "/usr/bin/sh"; #else #ifdef Plan9 defshell = "/bin/rc"; #else defshell = "/bin/sh"; #endif /* Plan9 */ #endif /* HPUX10 */ #endif /* aegis */ if (priv_can()) exit(1); /* Turn off any privileges! */ debug(F101,"zxcmd pid","",pid); close(pipes[0]); /* close input side of pipe */ close(0); /* close stdin */ if (open("/dev/null",0) < 0) return(0); /* replace input by null */ #ifndef OXOS #ifndef SVORPOSIX dup2(pipes[1],1); /* BSD: replace stdout & stderr */ dup2(pipes[1],2); /* by the pipe */ #else close(1); /* AT&T: close stdout */ if (dup(pipes[1]) != 1) /* Send stdout to the pipe */ return(0); close(2); /* Send stderr to the pipe */ if (dup(pipes[1]) != 2) return(0); #endif /* SVORPOSIX */ #else /* OXOS */ dup2(pipes[1],1); dup2(pipes[1],2); #endif /* OXOS */ close(pipes[1]); /* Don't need this any more. */ #ifdef aegis if ((shpath = getenv("SERVERSHELL")) == NULL) shpath = "/bin/sh"; #else shpath = getenv("SHELL"); /* What shell? */ if (shpath == NULL) { p = getpwuid( real_uid() ); /* Get login data */ /* debug(F111,"zxcmd shpath","getpwuid()",p); */ if (p == (struct passwd *)NULL || !*(p->pw_shell)) shpath = defshell; else shpath = p->pw_shell; } #endif /* aegis */ shptr = shname = shpath; while (*shptr != '\0') if (*shptr++ == '/') shname = shptr; debug(F110,shpath,shname,0); restorsigs(); /* Restore ignored signals */ execl(shpath,shname,"-c",comand,(char *)NULL); /* Execute the cmd */ exit(0); /* just punt if it failed. */ } else if (pid == (PID_T) -1) { debug(F100,"zxcmd fork failure","",0); return(0); } debug(F101,"zxcmd pid","",pid); close(pipes[1]); /* Don't need the output side */ ispipe[filnum] = 1; /* Remember it's a pipe */ fp[filnum] = fdopen(pipes[0],"r"); /* Open a stream for input. */ #ifdef DONDELAY #ifdef SELECT if (filnum == ZIFILE && kactive) { /* Make pipe reads nonblocking */ int flags, x; if ((flags = fcntl(fileno(fp[filnum]),F_GETFL,0)) > -1) { debug(F101,"zxcmd fcntl 1 pipe flags","",flags); x = fcntl(fileno(fp[filnum]),F_SETFL, flags | #ifdef QNX O_NONBLOCK #else O_NDELAY #endif /* QNX */ ); debug(F101,"zxcmd fcntl 2 result","",x); } } #endif /* SELECT */ #endif /* DONDELAY */ #endif /* SNI541 */ fp[ZSYSFN] = fp[filnum]; /* Remember. */ zincnt = 0; /* (PWP) reset input buffer */ zinptr = zinbuffer; fullname[0] = '\0'; return(1); } /* zxcmd */ /* Z C L O S F - wait for the child fork to terminate and close the pipe. */ /* Used internally by zclose - returns -1 on failure, 1 on success. */ int #ifdef CK_ANSIC zclosf( int filnum ) #else zclosf(filnum) int filnum; #endif /* CK_ANSIC */ { int wstat, out; int statusp; debug(F101,"zclosf filnum","",filnum); out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ; debug(F101,"zclosf out","",out); #ifndef NOPOPEN if (ispipe[filnum] /* In UNIX we use popen() only for output files */ && out ) { int x; x = pclose(fp[filnum]); pexitstat = x >> 8; debug(F101,"zclosf pclose","",x); debug(F101,"zclosf pexitstat","",pexitstat); fp[filnum] = fp[ZSYSFN] = NULL; ispipe[filnum] = 0; return((x != 0) ? -1 : 1); } #endif /* NOPOPEN */ /* debug(F101,"zclosf fp[filnum]","", fp[filnum]); */ /* debug(F101,"zclosf fp[ZSYSFN]","", fp[ZSYSFN]); */ if (pid != (PID_T) 0) { debug(F101,"zclosf killing pid","",pid); #ifdef Plan9 kill(pid, SIGKILL); #else kill(pid,9); #endif /* Plan9 */ #ifndef CK_CHILD /* This is the original code (before 20 April 1997) and has proven totally portable. But it does not give us the process's return code. */ while ((wstat = wait((WAIT_T *)0)) != pid && wstat != -1) ; #else /* Here we try to get the return code. Let's hope this is portable too. */ while ((wstat = wait(&statusp)) != pid && wstat != -1) ; pexitstat = (statusp & 0xff) ? statusp : statusp >> 8; debug(F101,"zclosf wait statusp","",statusp); debug(F101,"zclosf wait pexitstat","",pexitstat); #endif /* CK_CHILD */ pid = 0; } fclose(fp[filnum]); fp[filnum] = fp[ZSYSFN] = NULL; ispipe[filnum] = 0; /* debug(F101,"zclosf fp[filnum]","",fp[filnum]); */ #ifdef CK_CHILD return(pexitstat == 0 ? 1 : -1); #else return(1); #endif /* CK_CHILD */ } #else /* NOPUSH */ int zxcmd(filnum,comand) int filnum; char *comand; { return(0); } int zclosf(filnum) int filnum; { return(EOF); } #endif /* NOPUSH */ /* Z X P A N D -- Expand a wildcard string into an array of strings */ /* As of C-Kermit 7.0, this API is obsolete, replaced by nzxpand(), and this function is only used internally. See nzxpand() below. Returns the number of files that match fnarg, with data structures set up so that first file (if any) will be returned by the next znext() call. Depends on external variable wildxpand: 0 means we expand wildcards internally, nonzero means we call the shell to do it. AND in C-Kermit 8.0.212 and later, on extern wildena: 1 means wildcards are enabled, 0 means disabled, the characters are taken literally. */ static int xdironly = 0; static int xfilonly = 0; static int xmatchdot = 0; static int xrecursive = 0; static int xnobackup = 0; static int xnolinks = 0; static char *freeptr = NULL, **resptr = NULL; /* Copies of caller's args */ static int remlen; /* Remaining space in caller's array */ static int numfnd = 0; /* Number of matches found */ #define MINSPACE 1024 static int #ifdef CK_ANSIC initspace( char * resarry[], int len ) #else initspace(resarry,len) char * resarry[]; int len; #endif /* CK_ANSIC */ { #ifdef DYNAMIC if (len < MINSPACE) len = MINSPACE; if (!sspace) { /* Need to allocate string space? */ while (len >= MINSPACE) { if ((sspace = malloc(len+2))) { /* Got it. */ debug(F101,"fgen string space","",len); break; } len = (len / 2) + (len / 4); /* Didn't, reduce by 3/4 */ } if (len <= MINSPACE) { /* Did we get it? */ fprintf(stderr,"fgen can't malloc string space\n"); return(-1); } ssplen = len; } #endif /* DYNAMIC */ freeptr = sspace; /* This is where matches are copied. */ resptr = resarry; /* Static copies of these so */ remlen = len; /* recursive calls can alter them. */ debug(F101,"initspace ssplen","",ssplen); return(0); } /* Z S E T F I L -- Query or change the size of file list buffers. fc = 1: Change current string space to n, return new size. fc = 2: Return current string space size. fc = 3: Change current maxnames to n, return new maxnames. fc = 4: Return current maxnames. Returns < 0 on error. */ int #ifdef CK_ANSIC zsetfil( int n, int fc ) #else zsetfil(n, fc) int n, fc; #endif /* CK_ANSIC */ { #ifdef DYNAMIC switch (fc) { case 1: /* Stringspace */ if (sspace) { free(sspace); sspace = NULL; } if (initspace(mtchs,n) < 0) return(-1); case 2: /* Fall thru deliberately */ return(ssplen); case 3: /* Listsize */ if (mtchs) { free((char *)mtchs); mtchs = NULL; } mtchs = (char **)malloc(n * sizeof(char *)); if (!mtchs) return(-1); maxnames = n; case 4: /* Fall thru deliberately */ return(maxnames); } #endif /* DYNAMIC */ return(-1); } #ifndef NONZXPAND #ifndef pdp11 static #endif /* pdp11 */ #endif /* NONZXPAND */ int #ifdef CK_ANSIC zxpand( char *fnarg ) #else zxpand(fnarg) char *fnarg; #endif /* CK_ANSIC */ { extern int diractive; char fnbuf[CKMAXPATH+8], * fn, * p; #ifdef DTILDE /* Built with tilde-expansion? */ char *tnam; #endif /* DTILDE */ int x; int haveonedir = 0; if (!fnarg) { /* If no argument provided */ nxpand = fcount = 0; return(0); /* Return zero files found */ } debug(F110,"zxpand entry",fnarg,0); debug(F101,"zxpand xdironly","",xdironly); debug(F101,"zxpand xfilonly","",xfilonly); if (!*fnarg) { /* If no argument provided */ nxpand = fcount = 0; return(0); /* Return zero files found */ } #ifdef CKROOT debug(F111,"zxpand setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(fnarg)) { debug(F110,"zxpand setroot violation",fnarg,0); nxpand = fcount = 0; return(0); } #endif /* CKROOT */ #ifdef COMMENT /* This would have been perfect, except it makes us return fully qualified pathnames for all files. */ zfnqfp(fnarg,CKMAXPATH,fnbuf); debug(F110,"zxpand zfnqfp",fnbuf,0); s = zgtdir(); debug(F110,"zxpand zgtdir",s,0); p = fnbuf; while (*p && *s) /* Make it relative */ if (*s++ != *p++) break; fn = (*s) ? fnbuf : p; debug(F110,"zxpand fn 0",fn,0); if (!*fn) { fn = fnbuf; fnbuf[0] = '*'; fnbuf[1] = '\0'; } debug(F110,"zxpand fn 0.5",fn,0); #else #ifdef DTILDE /* Built with tilde-expansion? */ if (*fnarg == '~') { /* Starts with tilde? */ tnam = tilde_expand(fnarg); /* Try to expand it. */ ckstrncpy(fnbuf,tnam,CKMAXPATH); } else #endif /* DTILDE */ ckstrncpy(fnbuf,fnarg,CKMAXPATH); fn = fnbuf; /* Point to what we'll work with */ #endif /* COMMENT */ debug(F110,"zxpand fn 1",fn,0); if (!*fn) /* But make sure something is there */ return(0); p = fn + (int)strlen(fn) - 1; if (*p == '/') { /* If last char = / it must be a dir */ if (!xfilonly && !iswild(p)) haveonedir++; ckstrncat(fn, "*", CKMAXPATH+8); /* so append '*' */ } else if (p > fn) { /* If ends in "/." */ if (*(p-1) == '/' && *p == '.') /* change '.' to '*' */ *p = '*'; } else if (p == fn) { /* If it's '.' alone */ if (*p == '.') /* change '.' to '*' */ *p = '*'; } debug(F110,"zxpand fn 2",fn,0); x = isdir(fn); /* Is it a directory? */ debug(F111,"zxpand isdir 1",fn,x); if (x) { /* If so, make it into a wildcard */ if (!xfilonly && !iswild(p)) haveonedir++; if ((x = strlen(fn)) > 0) { if (!ISDIRSEP(fn[x-1])) fn[x++] = DIRSEP; fn[x++] = '*'; fn[x] = '\0'; } } debug(F111,"zxpand fn 3 haveonedir",fn,haveonedir); /* The following allows us to parse a single directory name without opening the directory and looking at its contents. The diractive flag is a horrible hack (especially since DIR /NORECURSIVE turns it off), but otherwise we'd have to change the API. */ debug(F111,"zxpand fn 3 diractive",fn,diractive); if (!diractive && haveonedir) { fcount = 0; if (!mtchs) { mtchs = (char **)malloc(maxnames * sizeof(*mtchs)); if (!mtchs) return(nxpand = fcount); } fcount = 1; debug(F110,"zxpand haveonedir A1",fnarg,0); initspace(mtchs,ssplen); addresult(fnarg,1); if (numfnd < 0) return(-1); mtchptr = mtchs; /* Save pointer for next. */ debug(F111,"zxpand haveonedir A2",*mtchptr,numfnd); return(nxpand = fcount); } #ifndef NOPUSH if (!nopush && wildxpand) /* Who is expanding wildcards? */ fcount = (mtchs == NULL && /* Shell */ (mtchs = (char **)malloc(maxnames * sizeof(*mtchs))) == NULL) ? 0 : shxpand(fn,mtchs,maxnames); else #endif /* NOPUSH */ fcount = (mtchs == NULL && /* Kermit */ (mtchs = (char **)malloc(maxnames * sizeof(*mtchs))) == NULL) ? 0 : fgen(fn,mtchs,maxnames); /* Look up the file. */ if (fcount == 0 && haveonedir) { fcount = 1; debug(F110,"zxpand haveonedir B",fnarg,0); addresult(fnarg,1); if (numfnd < 0) return(-1); } mtchptr = mtchs; /* Save pointer for next. */ nxpand = fcount; #ifdef DEBUG if (deblog) { if (fcount > 1) debug(F111,"zxpand ok",mtchs[0],fcount); else debug(F101,"zxpand fcount","",fcount); } #endif /* DEBUG */ return(fcount); } #ifndef NONZXPAND /* N Z X P A N D -- Expand a file list, with options. */ /* Call with: s = 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 s, with data structures set up so that first file (if any) will be returned by the next znext() call. */ int #ifdef CK_ANSIC nzxpand( char * s, int flags ) #else nzxpand(s,flags) char * s; int flags; #endif /* CK_ANSIC */ { char * p; int x; debug(F111,"nzxpand",s,flags); x = flags & (ZX_DIRONLY|ZX_FILONLY); xdironly = (x == ZX_DIRONLY); xfilonly = (x == ZX_FILONLY); if (xdironly && xfilonly) { xdironly = 0; xfilonly = 0; } xmatchdot = (flags & ZX_MATCHDOT); debug(F111,"nzxpand xmatchdot 1",s,xmatchdot); /* If xmatchdot not set by caller but pattern implies it, set it anyway */ if (!xmatchdot && ((p = ckstrchr(s,'.')))) { if (p == s && p[1] != '/') { xmatchdot = 1; debug(F111,"nzxpand xmatchdot 2",s,xmatchdot); } else if (p > s) { xmatchdot = (*(p-1) == ',') || (*(p-1) == '{') || (*(p-1) == '/'); debug(F111,"nzxpand xmatchdot 3",s,xmatchdot); } } xrecursive = (flags & ZX_RECURSE); xnobackup = (flags & ZX_NOBACKUP); xnolinks = (flags & ZX_NOLINKS); #ifdef DEBUG if (deblog) { debug(F101,"nzxpand xdironly","",xdironly); debug(F101,"nzxpand xfilonly","",xfilonly); debug(F101,"nzxpand xmatchdot","",xmatchdot); debug(F101,"nzxpand xrecursive","",xrecursive); debug(F101,"nzxpand xnobackup","",xnobackup); debug(F101,"nzxpand xnolinks","",xnolinks); } #endif /* DEBUG */ x = zxpand(s); if (x > 1) sh_sort(mtchs,NULL,x,0,0,1); /* Alphabetize the list */ xdironly = 0; xfilonly = 0; xmatchdot = 0; xrecursive = 0; xnobackup = 0; xnolinks = 0; return(x); } #endif /* NONZXPAND */ #ifndef NOZXREWIND /* Z X R E W I N D -- Rewinds the zxpand() list */ int zxrewind() { /* if (!mtchs) return(-1); */ fcount = nxpand; mtchptr = mtchs; return(nxpand); } #endif /* NOZXREWIND */ /* Z N E X T -- Get name of next file from list created by zxpand(). */ /* Returns >0 if there's another file, with its name copied into the arg string, or 0 if no more files in list. */ int #ifdef CK_ANSIC znext( char *fn ) #else znext(fn) char *fn; #endif /* CK_ANSIC */ { if (fcount-- > 0) { ckstrncpy(fn,*mtchptr++,CKMAXPATH); } else { fn[0] = '\0'; } #ifndef COMMENT debug(F111,"znext",fn,fcount+1); return(fcount+1); #else debug(F111,"znext",fn,fcount); /* Return 0 if no filename to return */ return(fcount); #endif /* COMMENT */ } /* Z C H K S P A -- Check if there is enough space to store the file */ /* Call with file specification f, size n in bytes. Returns -1 on error, 0 if not enough space, 1 if enough space. */ /*ARGSUSED*/ int #ifdef CK_ANSIC zchkspa(char *f, CK_OFF_T n) #else zchkspa(f,n) char *f; CK_OFF_T n; #endif /* CK_ANSIC */ /* zchkspa() */ { /* In UNIX there is no good (and portable) way. */ return(1); /* Always say OK. */ } #ifdef COMMENT /* (not used) */ /* I S B A C K U P -- Tells if given file has a backup suffix */ /* Returns: -1: Invalid argument 0: File does not have a backup suffix >0: Backup suffix number */ int isbackup(fn) char * fn; { /* Get backup suffix number */ int i, j, k, x, state, flag; if (!fn) /* Watch out for null pointers. */ return(-1); if (!*fn) /* And empty names. */ return(-1); flag = state = 0; for (i = (int)strlen(fn) - 1; (!flag && (i > 0)); i--) { switch (state) { case 0: /* State 0 - final char */ if (fn[i] == '~') /* Is tilde */ state = 1; /* Switch to next state */ else /* Otherwise */ flag = 1; /* Quit - no backup suffix. */ break; case 1: /* State 1 - digits */ if (fn[i] == '~' && fn[i-1] == '.') { /* Have suffix */ return(atoi(&fn[i+1])); } else if (fn[i] >= '0' && fn[i] <= '9') { /* In number part */ continue; /* Keep going */ } else { /* Something else */ flag = 1; /* Not a backup suffix - quit. */ } break; } } return(0); } #endif /* COMMENT */ /* Z N E W N -- Make a new name for the given file */ /* Given the name, fn, of a file that already exists, this function builds a new name of the form ".~~", where is argument name (fn), and is a version number, one higher than any existing version number for that file, up to 99999. This format is consistent with that used by GNU EMACS. If the constructed name is too long for the system's maximum, enough characters are truncated from the end of to allow the version number to fit. If no free version numbers exist between 1 and 99999, a version number of "xxxx" is used. Returns a pointer to the new name in argument s. */ #ifdef pdp11 #define ZNEWNBL 63 /* Name buffer length */ #define ZNEWNMD 3 /* Max digits for version number */ #else #define ZNEWNBL CKMAXPATH #define ZNEWNMD 4 #endif /* pdp11 */ #define MAXBUDIGITS 5 static char znewbuf[ZNEWNBL+12]; VOID #ifdef CK_ANSIC znewn( char *fn, char **s ) #else znewn(fn,s) char *fn, **s; #endif /* CK_ANSIC */ { char * buf; /* Pointer to buffer for new name */ char * xp, * namepart = NULL; /* Pointer to filename part */ struct zfnfp * fnfp; /* znfqfp() result struct pointer */ int d = 0, t, fnlen, buflen; int n, i, k, flag, state; int max = CKMAXNAM; /* Maximum name length */ char * dname = NULL; buf = znewbuf; *s = NULL; /* Initialize return value */ if (!fn) fn = ""; /* Check filename argument */ i = strlen(fn); /* If incoming file already has a backup suffix, remove it. */ /* Then we'll tack a new on later, which will be the highest for this file. */ if (i <= max && i > 0 && fn[i-1] == '~') { char * p; i--; debug(F111,"znewn suffix removal",fn,i); if ((dname = (char *)malloc(i+1))) { ckstrncpy(dname,fn,i+1); p = dname; for (flag = state = 0; (!flag && (i > 0)); i--) { switch (state) { case 0: /* State 0 - final char */ if (p[i] == '~') /* Is tilde */ state = 1; /* Switch to next state */ else /* Otherwise */ flag = 1; /* Quit - no backup suffix. */ break; case 1: /* State 1 - digits */ if (p[i] == '~' && p[i-1] == '.') { /* Have suffix */ p[i-1] = NUL; /* Trim it */ fn = dname; debug(F111,"znewn suffix removal 2",fn,i); flag = 1; /* done */ } else if (p[i] >= '0' && p[i] <= '9') { /* Number part */ continue; /* Keep going */ } else { /* Something else */ flag = 1; /* Not a backup suffix - quit. */ } break; } } } } if ((fnlen = strlen(fn)) < 1) { /* Get length */ if (dname) free(dname); return; } debug(F111,"znewn",fn,fnlen); debug(F101,"znewn max 1","",max); if (max < 14) max = 14; /* Make max reasonable for any UNIX */ if (max > ZNEWNBL) max = ZNEWNBL; debug(F101,"znewn max 2","",max); if ((fnfp = zfnqfp(fn, ZNEWNBL, buf))) { /* Get fully qualified name */ namepart = fnfp->fname; /* Isolate the filename */ k = strlen(fn); /* Length of name part */ debug(F111,"znewn namepart",namepart,k); } else { if (dname) free(dname); return; } buflen = fnfp->len; /* Length of fully qualified name */ debug(F111,"znewn len",buf,buflen); if (k + MAXBUDIGITS + 3 < max) { /* Backup name fits - no overflow */ /* Make pattern for backup names */ ckstrncpy(buf+buflen,".~*~",ZNEWNBL+12-buflen); n = nzxpand(buf,ZX_FILONLY); /* Expand the pattern */ debug(F111,"znewn A matches",buf,n); while (n-- > 0) { /* Find any existing name.~n~ files */ xp = *mtchptr++; /* Point at matching name */ t = atoi(xp+buflen+2); /* Get number */ if (t > d) d = t; /* Save d = highest version number */ } sprintf(buf+buflen,".~%d~",d+1); /* Yes, make "name.~~" */ debug(F110,"znewn A newname",buf,0); } else { /* Backup name would be too long */ int xlen; /* So we have to eat back into it */ int delta; char buf2[ZNEWNBL+12]; delta = max - k; debug(F101,"znewn B delta","",delta); for (i = MAXBUDIGITS; i > 0; i--) { /* In this case the format of */ ckstrncpy(buf2,buf,ZNEWNBL+12); /* the backup name depends on */ xlen = buflen - i - 3 + delta; /* how many digits are in the */ ckstrncpy(buf2+xlen,".~*~",ZNEWNBL+12-xlen); /* backup number */ n = nzxpand(buf2,ZX_FILONLY); debug(F111,"znewn B matches",buf2,n); if (n > 0) break; } while (n-- > 0) { /* Find any existing name.~n~ files */ xp = *mtchptr++; /* Point at matching name */ t = atoi(xp+xlen+2); /* Get number */ if (t > d) d = t; /* Save d = highest version number */ } if (d > 0) /* If the odometer turned over... */ if ((d % 10) == 9) /* back up one space. */ xlen--; sprintf(buf2+xlen,".~%d~",d+1); /* This just fits */ ckstrncpy(buf,buf2,ZNEWNBL+12); /* (we could be more clever here...) */ debug(F110,"znewn B new name",buf,0); } *s = buf; /* Point to new name */ ck_znewn = d+1; /* Also make it available globally */ if (dname) free(dname); return; } /* Z R E N A M E -- Rename a file */ /* Call with old and new names. If new name is the name of a directory, the 'old' file is moved to that directory. Returns 0 on success, -1 on failure. */ int #ifdef CK_ANSIC zrename( char *old, char *new ) #else zrename(old,new) char *old, *new; #endif /* CK_ANSIC */ { char *p, *s; int x; if (!old) old = ""; if (!new) new = ""; debug(F110,"zrename old",old,0); debug(F110,"zrename new",new,0); if (!*old) return(-1); if (!*new) return(-1); #ifdef IKSD #ifdef CK_LOGIN if (inserver && isguest) return(-1); #endif /* CK_LOGIN */ #endif /* IKSD */ #ifdef CKROOT debug(F111,"zrename setroot",ckroot,ckrootset); if (ckrootset) { if (!zinroot(old)) { debug(F110,"zrename old: setroot violation",old,0); return(-1); } if (!zinroot(new)) { debug(F110,"zrename new: setroot violation",new,0); return(-1); } } #endif /* CKROOT */ p = NULL; s = new; if (isdir(new)) { char *q = NULL; x = strlen(new); if (!(p = malloc(strlen(new) + strlen(old) + 2))) return(-1); strcpy(p,new); /* (safe) Directory part */ if (!ISDIRSEP(*(new+x-1))) /* Separator, if needed */ strcat(p,"/"); /* (safe) */ zstrip(old,&q); /* Strip path part from old name */ strcat(p,q); /* cat to new directory (safe) */ s = p; debug(F110,"zrename dir",s,0); } #ifdef DEBUG else debug(F110,"zrename no dir",s,0); #endif /* DEBUG */ #ifdef IKSD if (inserver && (!ENABLED(en_del))) { if (zchki(s) > -1) /* Destination file exists? */ return(-1); } #endif /* IKSD */ x = -1; /* Return code. */ #ifdef RENAME /* Atomic, preferred, uses a single system call, rename(), if available. */ x = rename(old,s); debug(F111,"zrename rename()",old,x); if (x) x = -1; #endif /* RENAME */ /* If rename() failed or not available try link()/unlink() */ if (x < 0) { if (zchko(old) > -1) { /* Requires write access to orignal */ x = link(old,s); debug(F111,"zrename link()",old,x); if (x > -1) { /* Make a link with the new name. */ x = unlink(old); debug(F111,"zrename unlink()",old,x); } /* If link/unlink failed copy and delete */ if (x < 0) { x = zcopy(old,s); debug(F111,"zrename zcopy()",old,x); if (x > -1) { x = zdelet(old); debug(F111,"zrename zdelet()",old,x); } } } } fullname[0] = '\0'; /* Clear this out for next time. */ #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_FC && ckxlogging) { zfnqfp(old,CKMAXPATH,fullname); tmp2[0] = '\0'; zfnqfp(s,CKMAXPATH,tmp2); if (x > -1) syslog(LOG_INFO,"file[] %s: renamed to %s ok", fullname, tmp2); else syslog(LOG_INFO,"file[] %s: rename to %s failed (%m)",fullname,tmp2); } #endif /* CKSYSLOG */ if (p) free(p); return(x); } /* Z C O P Y -- Copy a single file. */ /* Call with source and destination names. If destination is a directory, the source file is copied to that directory with its original 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. */ int #ifdef CK_ANSIC zcopy( char *source, char *destination ) #else zcopy(source,destination) char *source, *destination; #endif /* CK_ANSIC */ { char *src, *dst; /* Local pointers to filenames */ int x, y, rc; /* Workers */ int in = -1, out = -1; /* i/o file descriptors */ struct stat srcbuf; /* Source file info buffer */ int perms; /* Output file permissions */ char buf[1024]; /* File copying buffer */ if (!source) source = ""; if (!destination) destination = ""; debug(F110,"zcopy src arg",source,0); debug(F110,"zcopy dst arg",destination,0); if (!*source) return(-1); if (!*destination) return(-1); #ifdef IKSD #ifdef CK_LOGIN if (inserver && isguest) return(-4); #endif /* CK_LOGIN */ #endif /* IKSD */ #ifdef CKROOT debug(F111,"zcopy setroot",ckroot,ckrootset); if (ckrootset) { if (!zinroot(source)) { debug(F110,"zcopy source: setroot violation",source,0); return(-1); } if (!zinroot(destination)) { debug(F110,"zcopy destination: setroot violation",destination,0); return(-1); } } #endif /* CKROOT */ src = source; dst = destination; if (stat(src,&srcbuf) == 0) { /* Get source file info */ struct stat dstbuf; /* Destination file info buffer */ debug(F101,"STAT","",6); if (stat(dst,&dstbuf) == 0) { debug(F101,"STAT","",7); if (srcbuf.st_dev == dstbuf.st_dev) if (srcbuf.st_ino == dstbuf.st_ino) { debug(F100,"zcopy files identical: stat()","",0); return(-5); } } } else { /* stat() failed... */ debug(F101,"STAT","",8); debug(F111,"source file not found",src,errno); return(-3); } fullname[0] = '\0'; /* Get full pathnames */ if (zfnqfp(source,CKMAXPATH,fullname)) src = fullname; debug(F110,"zcopy src",src,0); tmp2[0] = '\0'; if (zfnqfp(destination,CKMAXPATH,tmp2)) dst = tmp2; debug(F110,"zcopy dst 1",dst,0); if (!strcmp(src,dst)) { /* Src and dst are same file? */ debug(F100,"zcopy files identical: strcmp()","",0); /* This... */ return(-5); /* should not happen. */ } if (isdir(src)) { /* Source file is a directory? */ debug(F110,"zcopy source is directory",src,0); return(-2); /* Fail */ } if (isdir(dst)) { /* Destination is a directory? */ char *q = NULL; /* Yes, add filename to it. */ x = strlen(dst); if (x < 1) return(-1); if (!ISDIRSEP(*(dst+x-1))) { /* Add separator if needed */ tmp2[x++] = '/'; tmp2[x] = '\0'; } debug(F111,"zcopy dst 2",dst,x); zstrip(src,&q); /* Strip path part from old name */ ckstrncpy(tmp2+x,q,CKMAXPATH-x); /* Concatenate it to new name */ } debug(F110,"zcopy dst 3",dst,0); #ifdef IKSD if (inserver && (!ENABLED(en_del))) { if (zchki(dst) > -1) /* Destination file exists? */ return(-4); } #endif /* IKSD */ perms = umask(0); /* Get user's umask */ umask(perms); /* Put it back! */ perms ^= 0777; /* Flip the bits */ perms &= 0666; /* Zero execute bits from umask */ perms |= (srcbuf.st_mode & 0111); /* OR in source file's execute bits */ rc = -1; /* Default return code */ errno = 0; /* Reset errno */ in = open(src, O_RDONLY, 0); /* Open source file */ debug(F111,"zcopy open source",src,in); if (in > -1) { /* If open... */ /* Open destination file */ #ifdef O_TRUNC out = open(dst, O_WRONLY|O_CREAT|O_TRUNC, perms); #else out = open(dst, O_WRONLY|O_CREAT, perms); #endif /* O_TRUNC */ debug(F111,"zcopy open dest",dst,out); if (out > -1) { /* If open... */ while ((x = read(in,buf,1024)) > 0) { /* Copy in 1K blocks */ y = write(out,buf,x); if (y < 0) { /* On write failure */ x = -1; rc = -6; /* Indicate i/o error */ break; } } debug(F101,"zcopy final read","",x); debug(F101,"zcopy errno","",errno); rc = (x == 0) ? 0 : -6; /* In case of read failure */ } } if (in > -1) close(in); /* Close files */ if (out > -1) close(out); if (rc == -1) { /* Set return code */ switch (errno) { case ENOENT: rc = -3; break; case EACCES: rc = -4; break; case EIO: rc = -6; } } #ifdef CKSYSLOG if (rc > -1 && ckxsyslog >= SYSLG_FC && ckxlogging) { if (rc) syslog(LOG_INFO,"file[] %s: copy to %s failed (%m)", fullname, tmp2); else syslog(LOG_INFO,"file[] %s: copy to %s ok", fullname, tmp2); } #endif /* CKSYSLOG */ return(rc); } /* Z S A T T R */ /* Fills in a Kermit file attribute structure for the file which is to be sent. Returns 0 on success with the structure filled in, or -1 on failure. If any string member is null, then it should be ignored. If any numeric member is -1, then it should be ignored. */ #ifdef CK_PERMS #ifdef CK_GPERMS #undef CK_GPERMS #endif /* CK_GPERMS */ #ifdef UNIX #ifndef S_IRUSR #define S_IRUSR 0400 #endif /* S_IRUSR */ #ifndef S_IWUSR #define S_IXUSR 0200 #endif /* S_IWUSR */ #ifndef S_IXUSR #define S_IXUSR 0100 #endif /* S_IXUSR */ #endif /* UNIX */ #ifdef S_IRUSR #ifdef S_IWUSR #ifdef S_IXUSR #define CK_GPERMS #endif /* S_IXUSR */ #endif /* S_IWUSR */ #endif /* S_IRUSR */ static char gperms[2]; #endif /* CK_GPERMS */ static char lperms[24]; #ifdef CK_PERMS static char xlperms[24]; /* Z S E T P E R M -- Set permissions of a file */ int #ifdef CK_ANSIC zsetperm( char * f, int code ) #else zsetperm(f,code) char * f; int code; #endif /* CK_ANSIC */ { int x; #ifdef CK_SCO32V4 mode_t mask; #else int mask; #endif /* CK_SCO32V4 */ mask = code; if (inserver && guest) { debug(F110,"zsetperm guest",f,0); return(0); } x = chmod(f,mask); if (x < 0) { debug(F111,"zsetperm error",f,errno); return(0); } debug(F111,"zsetperm ok",f,mask); return(1); } /* Z G P E R M -- Get permissions of a file as an octal string */ char * #ifdef CK_ANSIC zgperm( char *f ) #else zgperm(f) char *f; #endif /* CK_ANSIC */ { extern int diractive; int x; char *s = (char *)xlperms; struct stat buf; debug(F110,"zgperm",f,0); if (!f) return("----------"); if (!*f) return("----------"); #ifdef DTILDE /* Built with tilde-expansion? */ if (*f == '~') { /* Starts with tilde? */ f = tilde_expand(f); /* Try to expand it. */ } #endif /* DTILDE */ #ifdef CKROOT debug(F111,"zgperm setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(f)) { debug(F110,"zgperm setroot violation",f,0); return("----------"); } #endif /* CKROOT */ #ifdef USE_LSTAT if (diractive) x = lstat(f,&buf); else #endif /* USE_LSTAT */ x = stat(f,&buf); debug(F101,"STAT","",9); if (x < 0) return("----------"); sprintf(s,"%o",buf.st_mode); debug(F110,"zgperm",s,0); return(s); } /* Like zgperm() but returns permissions in "ls -l" string format */ static char xsperms[24]; char * #ifdef CK_ANSIC ziperm( char * f ) #else ziperm(f) char * f; #endif /* CK_ANSIC */ { extern int diractive; int x; char *s = (char *)xsperms; struct stat buf; unsigned int perms = 0; debug(F110,"ziperm",f,0); if (!f) return(NULL); if (!*f) return(NULL); #ifdef DTILDE /* Built with tilde-expansion? */ if (*f == '~') { /* Starts with tilde? */ f = tilde_expand(f); /* Try to expand it. */ } #endif /* DTILDE */ if (diractive && zgfs_mode != 0) { perms = zgfs_mode; /* zgetfs() already got them */ } else { #ifdef USE_LSTAT if (diractive) x = lstat(f,&buf); else #endif /* USE_LSTAT */ x = stat(f,&buf); debug(F101,"STAT","",10); if (x < 0) return("----------"); perms = buf.st_mode; } switch (perms & S_IFMT) { case S_IFDIR: *s++ = 'd'; break; case S_IFCHR: /* Character special */ *s++ = 'c'; break; case S_IFBLK: /* Block special */ *s++ = 'b'; break; case S_IFREG: /* Regular */ *s++ = '-'; break; #ifdef S_IFLNK case S_IFLNK: /* Symbolic link */ *s++ = 'l'; break; #endif /* S_IFLNK */ #ifdef S_IFSOCK case S_IFSOCK: /* Socket */ *s++ = 's'; break; #endif /* S_IFSOCK */ #ifdef S_IFIFO #ifndef Plan9 #ifndef COHERENT case S_IFIFO: /* FIFO */ *s++ = 'p'; break; #endif /* COHERENT */ #endif /* Plan9 */ #endif /* S_IFIFO */ #ifdef S_IFWHT case S_IFWHT: /* Whiteout */ *s++ = 'w'; break; #endif /* S_IFWHT */ default: /* Unknown */ *s++ = '?'; break; } if (perms & S_IRUSR) /* Owner's permissions */ *s++ = 'r'; else *s++ = '-'; if (perms & S_IWUSR) *s++ = 'w'; else *s++ = '-'; switch (perms & (S_IXUSR | S_ISUID)) { case 0: *s++ = '-'; break; case S_IXUSR: *s++ = 'x'; break; case S_ISUID: *s++ = 'S'; break; case S_IXUSR | S_ISUID: *s++ = 's'; break; } if (perms & S_IRGRP) /* Group permissions */ *s++ = 'r'; else *s++ = '-'; if (perms & S_IWGRP) *s++ = 'w'; else *s++ = '-'; switch (perms & (S_IXGRP | S_ISGID)) { case 0: *s++ = '-'; break; case S_IXGRP: *s++ = 'x'; break; case S_ISGID: *s++ = 'S'; break; case S_IXGRP | S_ISGID: *s++ = 's'; break; } if (perms & S_IROTH) /* World permissions */ *s++ = 'r'; else *s++ = '-'; if (perms & S_IWOTH) *s++ = 'w'; else *s++ = '-'; switch ( #ifdef Plan9 perms & (S_IXOTH) #else perms & (S_IXOTH | S_ISVTX) #endif ) { case 0: *s++ = '-'; break; case S_IXOTH: *s++ = 'x'; break; #ifndef Plan9 case S_ISVTX: *s++ = 'T'; break; case S_IXOTH | S_ISVTX: *s++ = 't'; break; #endif /* Plan9 */ } *s = '\0'; debug(F110,"ziperm",xsperms,0); return((char *)xsperms); } #else char * zgperm(f) char *f; { return("----------"); } char * ziperms(f) char *f; { return("----------"); } #endif /* CK_PERMS */ int #ifdef CK_ANSIC zsattr( struct zattr *xx ) #else zsattr(xx) struct zattr *xx; #endif /* CK_ANSIC */ { CK_OFF_T k; int x; struct stat buf; k = iflen % 1024; /* File length in K */ if (k) k = 1L; xx->lengthk = (iflen / 1024) + k; xx->type.len = 0; /* File type can't be filled in here */ xx->type.val = ""; if (*nambuf) { xx->date.val = zfcdat(nambuf); /* File creation date */ xx->date.len = (int)strlen(xx->date.val); } else { xx->date.len = 0; xx->date.val = ""; } xx->creator.len = 0; /* File creator */ xx->creator.val = ""; xx->account.len = 0; /* File account */ xx->account.val = ""; xx->area.len = 0; /* File area */ xx->area.val = ""; xx->password.len = 0; /* Area password */ xx->password.val = ""; xx->blksize = -1L; /* File blocksize */ xx->xaccess.len = 0; /* File access */ xx->xaccess.val = ""; xx->encoding.len = 0; /* Transfer syntax */ xx->encoding.val = 0; xx->disp.len = 0; /* Disposition upon arrival */ xx->disp.val = ""; xx->lprotect.len = 0; /* Local protection */ xx->lprotect.val = ""; xx->gprotect.len = 0; /* Generic protection */ xx->gprotect.val = ""; x = -1; if (*nambuf) x = stat(nambuf,&buf); debug(F101,"STAT","",11); if (x >= 0) { debug(F111,"zsattr buf.st_mode & 0777",nambuf,buf.st_mode & 0777); /* UNIX filemode as an octal string without filetype bits */ sprintf(lperms,"%o",buf.st_mode & 0777); xx->lprotect.len = (int)strlen(lperms); xx->lprotect.val = (char *)lperms; x = 0; #ifdef CK_GPERMS /* Generic permissions only if we have stat.h symbols defined */ if (buf.st_mode & S_IRUSR) x |= 1; /* Read */ if (buf.st_mode & S_IWUSR) x |= (2+16); /* Write and Delete */ if (buf.st_mode & S_IXUSR) x |= 4; /* Execute */ gperms[0] = tochar(x); gperms[1] = NUL; xx->gprotect.len = 1; xx->gprotect.val = (char *)gperms; #endif /* CK_GPERMS */ } debug(F111,"zsattr lperms",xx->lprotect.val,xx->lprotect.len); debug(F111,"zsattr gperms",xx->gprotect.val,xx->gprotect.len); xx->systemid.val = "U1"; /* U1 = UNIX */ xx->systemid.len = 2; /* System ID */ xx->recfm.len = 0; /* Record format */ xx->recfm.val = ""; xx->sysparam.len = 0; /* System-dependent parameters */ xx->sysparam.val = ""; xx->length = iflen; /* Length */ return(0); } /* Z F C D A T -- Get file creation date */ /* Call with pointer to filename. On success, returns pointer to modification date in yyyymmdd hh:mm:ss format. On failure, returns pointer to null string. */ static char datbuf[40]; char * #ifdef CK_ANSIC zdtstr(time_t timearg) #else zdtstr(timearg) time_t timearg; #endif /* CK_ANSIC */ /* zdtstr */ { #ifndef TIMESTAMP return(""); #else struct tm * time_stamp; int yy, ss; debug(F101,"zdtstr timearg","",timearg); if (timearg < 0) return(""); time_stamp = localtime(&(timearg)); if (!time_stamp) { debug(F100,"localtime returns null","",0); return(""); } /* We assume that tm_year is ALWAYS years since 1900. Any platform where this is not the case will have problems starting in 2000. */ yy = time_stamp->tm_year; /* Year - 1900 */ debug(F101,"zdtstr tm_year","",time_stamp->tm_year); if (yy > 1000) { debug(F101,"zstrdt YEAR-2000 ALERT 1: localtime year","",yy); } yy += 1900; debug(F101,"zdatstr year","",yy); if (time_stamp->tm_mon < 0 || time_stamp->tm_mon > 11) return(""); if (time_stamp->tm_mday < 0 || time_stamp->tm_mday > 31) return(""); if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 23) return(""); if (time_stamp->tm_min < 0 || time_stamp->tm_min > 59) return(""); ss = time_stamp->tm_sec; /* Seconds */ if (ss < 0 || ss > 59) /* Some systems give a BIG number */ ss = 0; sprintf(datbuf, #ifdef pdp11 /* For some reason, 2.1x BSD sprintf gets the last field wrong. */ "%04d%02d%02d %02d:%02d:00", #else "%04d%02d%02d %02d:%02d:%02d", #endif /* pdp11 */ yy, time_stamp->tm_mon + 1, time_stamp->tm_mday, time_stamp->tm_hour, time_stamp->tm_min #ifndef pdp11 , ss #endif /* pdp11 */ ); yy = (int)strlen(datbuf); debug(F111,"zdatstr",datbuf,yy); if (yy > 17) datbuf[17] = '\0'; return(datbuf); #endif /* TIMESTAMP */ } char * #ifdef CK_ANSIC zfcdat( char *name ) #else zfcdat(name) char *name; #endif /* CK_ANSIC */ { #ifdef TIMESTAMP struct stat buffer; extern int diractive; unsigned int mtime; int x; char * s; if (!name) return(""); s = name; if (!*s) return(""); #ifdef CKROOT debug(F111,"zfcdat setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(name)) { debug(F110,"zfcdat setroot violation",name,0); return(""); } #endif /* CKROOT */ #ifdef DTILDE if (*s == '~') { s = tilde_expand(s); if (!s) s = ""; if (!*s) s = name; } #endif /* DTILDE */ datbuf[0] = '\0'; x = 0; debug(F111,"zfcdat",s,diractive); if (diractive && zgfs_mtime) { mtime = zgfs_mtime; } else { #ifdef USE_LSTAT if (diractive) { x = lstat(s,&buffer); debug(F101,"STAT","",12); debug(F101,"zfcdat lstat","",x); } else { #endif /* USE_LSTAT */ x = stat(s,&buffer); debug(F101,"STAT","",13); debug(F101,"zfcdat stat","",x); #ifdef USE_LSTAT } #endif /* USE_LSTAT */ if (x != 0) { #ifdef USE_LSTAT debug(F111,"zfcdat stat failed",s,errno); #else debug(F111,"zfcdat lstat failed",s,errno); #endif /* USE_LSTAT */ return(""); } debug(F101,"zfcdat buffer.st_mtime","",buffer.st_mtime); mtime = buffer.st_mtime; } return(zdtstr(mtime)); #else return(""); #endif /* TIMESTAMP */ } #ifndef NOTIMESTAMP /* Z S T R D T -- Converts local date string to internal representation */ /* In our case (UNIX) this is seconds since midnite 1 Jan 1970 UTC, suitable for comparison with UNIX file dates. As far as I know, there is no library or system call -- at least nothing reasonably portable -- to convert local time to UTC. */ time_t #ifdef CK_ANSIC zstrdt( char * date, int len ) #else zstrdt(date,len) char * date; int len; #endif /* CK_ANSIC */ { #ifdef M_UNIX /* SCO UNIX 3.2v2.0 and ODT 2.0 lack prototypes for ftime(). ODT 3.0 (3.2v4.2 OS) has a prototype, which may vary in dependence on the XPG4 supplement presence. So always use what the system header file supplies in ODT 3.0... */ #ifndef ODT30 #ifndef _SCO_DS extern void ftime(); /* extern void ftime(struct timeb *) */ #endif /* _SCO_DS */ #endif /* ODT30 */ #else #ifndef M_XENIX #ifndef __APPLE__ extern int ftime(); #endif #endif /* M_XENIX */ #endif /* M_UNIX */ /* And this should have been declared always through a header file */ #ifdef HPUX10 time_t tmx; long days; #else #ifdef BSD44 time_t tmx; long days; #else #ifdef LINUX time_t tmx; long days; #else long tmx, days; #endif /* LINUX */ #endif /* BSD44 */ #endif /* HPUX10 */ int i, n, isleapyear; /* J F M A M J J A S O N D */ /* 31 28 31 30 31 30 31 31 30 31 30 31 */ static int monthdays [13] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 }; char s[5]; struct tm *time_stamp; #ifdef BSD44 struct timeval tp[2]; long xtimezone = 0L; #else #ifdef V7 struct utimbuf { time_t timep[2]; /* New access and modificaton time */ } tp; char *tz; long timezone; /* In case timezone not defined in .h file */ #else #ifdef SYSUTIMEH struct utimbuf tp; #else struct utimbuf { time_t atime; time_t mtime; } tp; #endif /* SYSUTIMEH */ #endif /* V7 */ #endif /* BSD44 */ #ifdef ANYBSD long timezone = 0L; static struct timeb tbp; #endif /* ANYBSD */ #ifdef BEBOX long timezone = 0L; #endif /* BEBOX */ debug(F111,"zstrdt",date,len); if ((len == 0) || (len != 17) || (date[8] != ' ') || (date[11] != ':') || (date[14] != ':') ) { debug(F111,"Bad creation date ",date,len); return(-1); } debug(F111,"zstrdt date check 1",date,len); for(i = 0; i < 8; i++) { if (!isdigit(date[i])) { debug(F111,"Bad creation date ",date,len); return(-1); } } debug(F111,"zstrdt date check 2",date,len); i++; for (; i < 16; i += 3) { if ((!isdigit(date[i])) || (!isdigit(date[i + 1]))) { debug(F111,"Bad creation date ",date,len); return(-1); } } debug(F111,"zstrdt date check 3",date,len); #ifdef COMMENT /* was BSD44 */ /* man gettimeofday on BSDI 3.1 says: "The timezone field is no longer used; timezone information is stored out- side the kernel. See ctime(3) for more information." So this chunk of code is effectively a no-op, at least in BSDI 3.x. */ { int x; struct timezone tzp; x = gettimeofday(NULL, &tzp); debug(F101,"zstrdt BSD44 gettimeofday","",x); if (x > -1) xtimezone = tzp.tz_minuteswest * 60L; else xtimezone = 0L; debug(F101,"zstrdt BSD44 timezone","",xtimezone); } #else #ifdef ANYBSD debug(F100,"zstrdt BSD calling ftime","",0); ftime(&tbp); debug(F100,"zstrdt BSD back from ftime","",0); timezone = tbp.timezone * 60L; debug(F101,"zstrdt BSD timezone","",timezone); #else #ifdef SVORPOSIX tzset(); /* Set timezone */ #else #ifdef V7 if ((tz = getenv("TZ")) == NULL) timezone = 0; /* UTC/GMT */ else timezone = atoi(&tz[3]); /* Set 'timezone'. */ timezone *= 60L; #endif /* V7 */ #endif /* SVORPOSIX */ #endif /* ANYBSD */ #endif /* COMMENT (was BSD44) */ debug(F100,"zstrdt so far so good","",0); s[4] = '\0'; for (i = 0; i < 4; i++) /* Fix the year */ s[i] = date[i]; n = atoi(s); debug(F111,"zstrdt year",s,n); if (n < 1970) { debug(F100,"zstrdt fails - year","",n); return(-1); } /* Previous year's leap days. This won't work after year 2100. */ isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0); days = (long) (n - 1970) * 365; days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400; s[2] = '\0'; for (i = 4; i < 16; i += 2) { s[0] = date[i]; s[1] = date[i + 1]; n = atoi(s); switch (i) { case 4: /* MM: month */ if ((n < 1 ) || ( n > 12)) { debug(F111,"zstrdt 4 bad date ",date,len); return(-1); } days += monthdays [n]; if (isleapyear && n > 2) ++days; continue; case 6: /* DD: day */ if ((n < 1 ) || ( n > 31)) { debug(F111,"zstrdt 6 bad date ",date,len); return(-1); } tmx = (days + n - 1) * 24L * 60L * 60L; i++; /* Skip the space */ continue; case 9: /* hh: hour */ if ((n < 0 ) || ( n > 23)) { debug(F111,"zstrdt 9 bad date ",date,len); return(-1); } tmx += n * 60L * 60L; i++; /* Skip the colon */ continue; case 12: /* mm: minute */ if ((n < 0 ) || ( n > 59)) { debug(F111,"zstrdt 12 bad date ",date,len); return(-1); } #ifdef COMMENT /* (was BSD44) */ /* Correct for time zone */ tmx += xtimezone; debug(F101,"zstrdt BSD44 tmx","",tmx); #else #ifdef ANYBSD tmx += timezone; #else #ifndef CONVEX9 /* Don't yet know how to do this here */ #ifdef ultrix tmx += (long) timezone; #else #ifdef Plan9 { extern time_t tzoffset; tmx += tzoffset; } #else #ifndef BSD44 #ifndef NOTIMEZONE tmx += timezone; #endif /* NOTIMEZONE */ #endif /* BSD44 */ #endif /* Plan9 */ #endif /* ultrix */ #endif /* CONVEX9 */ #endif /* ANYBSD */ #endif /* COMMENT (was BSD44) */ tmx += n * 60L; i++; /* Skip the colon */ continue; case 15: /* ss: second */ if ((n < 0 ) || ( n > 59)) { debug(F111,"zstrdt 15 bad date ",date,len); return(-1); } tmx += n; } time_stamp = localtime(&tmx); debug(F101,"zstrdt tmx 1","",tmx); if (!time_stamp) return(-1); #ifdef COMMENT /* Why was this here? */ time_stamp = localtime(&tmx); debug(F101,"zstrdt tmx 2","",tmx); #endif /* COMMENT */ #ifdef BSD44 { /* New to 7.0 - Works in at at least BSDI 3.1 and FreeBSD 2.2.7 */ long zz; zz = time_stamp->tm_gmtoff; /* Seconds away from Zero Meridian */ debug(F101,"zstrdt BSD44 tm_gmtoff","",zz); tmx -= zz; debug(F101,"zstrdt BSD44 tmx 3 (GMT)","",tmx); } #else /* Daylight Savings Time adjustment. Do this everywhere BUT in BSD44 because in BSD44, tm_gmtoff also includes the DST adjustment. */ if (time_stamp->tm_isdst) { tmx -= 60L * 60L; debug(F101,"zstrdt tmx 3 (DST)","",tmx); } #endif /* BSD44 */ n = time_stamp->tm_year; if (n < 300) { n += 1900; } } return(tmx); } #ifdef ZLOCALTIME /* Z L O C A L T I M E -- GMT/UTC time string to local time string */ /* Call with: "yyyymmdd hh:mm:ss" GMT/UTC date-time. Returns: "yyyymmdd hh:mm:ss" local date-time on success, NULL on failure. */ static char zltimbuf[64]; char * #ifdef CK_ANSIC zlocaltime( char * gmtstring ) #else zlocaltime(gmtstring) char * gmtstring; #endif /* CK_ANSIC */ { #ifdef M_UNIX /* SCO UNIX 3.2v2.0 and ODT 2.0 lack prototypes for ftime(). ODT 3.0 (3.2v4.2 OS) has a prototype, which may vary in dependence on the XPG4 supplement presence. So always use what the system header file supplies in ODT 3.0... */ #ifndef ODT30 #ifndef _SCO_DS extern void ftime(); /* extern void ftime(struct timeb *) */ #endif /* _SCO_DS */ #endif /* ODT30 */ #else #ifndef M_XENIX #ifndef __APPLE__ extern int ftime(); #endif /* __APPLE__*/ #endif /* M_XENIX */ #endif /* M_UNIX */ /* And this should have been declared always through a header file */ #ifdef HPUX10 time_t tmx; long days; #else #ifdef BSD44 time_t tmx; long days; #else #ifdef LINUX time_t tmx; long days; #else long tmx, days; #endif /* LINUX */ #endif /* BSD44 */ #endif /* HPUX10 */ int i, n, x, isleapyear; /* J F M A M J J A S O N D */ /* 31 28 31 30 31 30 31 31 30 31 30 31 */ static int monthdays [13] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 }; char s[5]; struct tm *time_stamp; #ifdef BSD44 struct timeval tp[2]; #else #ifdef V7 struct utimbuf { time_t timep[2]; /* New access and modificaton time */ } tp; #else #ifdef SYSUTIMEH struct utimbuf tp; #else struct utimbuf { time_t atime; time_t mtime; } tp; #endif /* SYSUTIMEH */ #endif /* V7 */ #endif /* BSD44 */ #ifdef ANYBSD static struct timeb tbp; #endif /* ANYBSD */ char * date = gmtstring; int len; len = strlen(date); debug(F111,"zlocaltime",date,len); if ((len == 0) || (len != 17) || (date[8] != ' ') || (date[11] != ':') || (date[14] != ':') ) { debug(F111,"Bad creation date ",date,len); return(NULL); } debug(F111,"zlocaltime date check 1",date,len); for(i = 0; i < 8; i++) { if (!isdigit(date[i])) { debug(F111,"Bad creation date ",date,len); return(NULL); } } debug(F111,"zlocaltime date check 2",date,len); i++; for (; i < 16; i += 3) { if ((!isdigit(date[i])) || (!isdigit(date[i + 1]))) { debug(F111,"Bad creation date ",date,len); return(NULL); } } debug(F111,"zlocaltime date check 3",date,len); debug(F100,"zlocaltime so far so good","",0); s[4] = '\0'; for (i = 0; i < 4; i++) /* Fix the year */ s[i] = date[i]; n = atoi(s); debug(F111,"zlocaltime year",s,n); if (n < 1970) { debug(F100,"zlocaltime fails - year","",n); return(NULL); } /* Previous year's leap days. This won't work after year 2100. */ isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0); days = (long) (n - 1970) * 365; days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400; s[2] = '\0'; for (i = 4; i < 16; i += 2) { s[0] = date[i]; s[1] = date[i + 1]; n = atoi(s); switch (i) { case 4: /* MM: month */ if ((n < 1 ) || ( n > 12)) { debug(F111,"zlocaltime 4 bad date ",date,len); return(NULL); } days += monthdays [n]; if (isleapyear && n > 2) ++days; continue; case 6: /* DD: day */ if ((n < 1 ) || ( n > 31)) { debug(F111,"zlocaltime 6 bad date ",date,len); return(NULL); } tmx = (days + n - 1) * 24L * 60L * 60L; i++; /* Skip the space */ continue; case 9: /* hh: hour */ if ((n < 0 ) || ( n > 23)) { debug(F111,"zlocaltime 9 bad date ",date,len); return(NULL); } tmx += n * 60L * 60L; i++; /* Skip the colon */ continue; case 12: /* mm: minute */ if ((n < 0 ) || ( n > 59)) { debug(F111,"zlocaltime 12 bad date ",date,len); return(NULL); } tmx += n * 60L; i++; /* Skip the colon */ continue; case 15: /* ss: second */ if ((n < 0 ) || ( n > 59)) { debug(F111,"zlocaltime 15 bad date ",date,len); return(NULL); } tmx += n; } /* At this point tmx is the time_t representation of the argument date-time string without any timezone or DST adjustments. Therefore it should be the same as the time_t representation of the GMT/UTC time. Now we should be able to feed it to localtime() and have it converted to a struct tm representing the local time equivalent of the given UTC time. */ time_stamp = localtime(&tmx); if (!time_stamp) return(NULL); } /* Now we simply reformat the struct tm to a string */ x = time_stamp->tm_year; if (time_stamp->tm_year < 70 || time_stamp->tm_year > 8099) return(NULL); if (time_stamp->tm_mon < 0 || time_stamp->tm_mon > 11) return(NULL); if (time_stamp->tm_mday < 1 || time_stamp->tm_mday > 31) return(NULL); if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 24) return(NULL); if (time_stamp->tm_min < 0 || time_stamp->tm_min > 60) return(NULL); if (time_stamp->tm_sec < 0 || time_stamp->tm_sec > 60) return(NULL); sprintf(zltimbuf,"%04d%02d%02d %02d:%02d:%02d", time_stamp->tm_year + 1900, time_stamp->tm_mon + 1, time_stamp->tm_mday, time_stamp->tm_hour, time_stamp->tm_min, time_stamp->tm_sec ); return((char *)zltimbuf); } #endif /* ZLOCALTIME */ #endif /* NOTIMESTAMP */ /* Z S T I M E -- Set modification date/time+permissions for incoming file */ /* Call with: f = 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. yy->lprotect.val & yy->gprotect.val are permission/protection values. x = is a function code: 0 means to set the file's attributes as given. 1 means compare the date in struct yy with the file creation date. IMPORTANT: if you are calling this routine only to set a certain attribute but not others, you MUST set yy->blah.len to 0 for each blah not being set. Returns: -1 on any kind of error. 0 if x is 0 and the attributes were 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. */ int #ifdef CK_ANSIC zstime( char *f, struct zattr *yy, int x ) #else zstime(f,yy,x) char *f; struct zattr *yy; int x; #endif /* CK_ANSIC */ /* zstime */ { int r = -1; /* Return code */ #ifdef CK_PERMS int setperms = 0; #endif /* CK_PERMS */ int setdate = 0; /* It is ifdef'd TIMESTAMP because it might not work on V7. bk@kullmar.se. */ #ifdef TIMESTAMP #ifdef BSD44 #ifndef __APPLE__ #ifndef HAVE_UTIMES extern int utimes(); #endif /* HAVE_UTIMES */ #endif /* __APPLE__ */ #endif /* BSD44 */ struct stat sb; /* At least, the declarations for int functions are not needed anyway */ #ifdef BSD44 struct timeval tp[2]; long xtimezone; #else #ifdef V7 struct utimbuf { time_t timep[2]; /* New access and modificaton time */ } tp; char *tz; long timezone; /* In case not defined in .h file */ #else #ifdef SYSUTIMEH struct utimbuf tp; #else struct utimbuf { time_t atime; time_t mtime; } tp; #endif /* SYSUTIMEH */ #endif /* V7 */ #endif /* BSD44 */ long tm = 0L; if (!f) f = ""; if (!*f) return(-1); if (!yy) return(-1); #ifdef CKROOT debug(F111,"zstime setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(f)) { debug(F110,"zstime setroot violation",f,0); return(0); } #endif /* CKROOT */ if (yy->date.len == 0) { /* No date in struct */ if (yy->lprotect.len > 0) { /* So go do permissions */ goto zsperms; } else { debug(F100,"zstime: nothing to do","",0); return(0); } } if ((tm = zstrdt(yy->date.val,yy->date.len)) < 0) { debug(F101,"zstime: zstrdt fails","",0); return(-1); } debug(F101,"zstime: tm","",tm); debug(F111,"zstime: A-pkt date ok ",yy->date.val,yy->date.len); if (stat(f,&sb)) { /* Get the time for the file */ debug(F101,"STAT","",14); debug(F111,"zstime: Can't stat file:",f,errno); return(-1); } debug(F101,"STAT","",15); setdate = 1; zsperms: #ifdef CK_PERMS { int i, x = 0, xx, flag = 0; char * s; char obuf[24]; #ifdef COMMENT #ifdef DEBUG if (deblog) { debug(F111,"zstime lperms",yy->lprotect.val,yy->lprotect.len); debug(F111,"zstime gperms",yy->gprotect.val,yy->gprotect.len); debug(F110,"zstime system id",yy->systemid.val,0); sprintf(obuf,"%o",sb.st_mode); debug(F110,"zstime file perms before",obuf,0); } #endif /* DEBUG */ #endif /* COMMENT */ #ifdef CK_LOGIN debug(F101,"zstime isguest","",isguest); debug(F101,"zstime ckxperms","",ckxperms); if (isguest) { #ifdef COMMENT /* Clear owner permissions */ sb.st_mode &= (unsigned) 0177077; /* (16 bits) */ #else /* Set permissions from ckxperms variable */ sb.st_mode = ckxperms; #endif /* COMMENT */ debug(F101,"zstime isguest sb.st_mode","",sb.st_mode); #ifdef COMMENT /* We already set them in zopeno() */ setperms = 1; #endif /* COMMENT */ flag = 0; } else #endif /* CK_LOGIN */ if ((yy->lprotect.len > 0 && /* Have local-format permissions */ yy->systemid.len > 0 && /* from A-packet... */ #ifdef UNIX !strcmp(yy->systemid.val,"U1") /* AND you are same as me */ #else 0 #endif /* UNIX */ ) || (yy->lprotect.len < 0) /* OR by inheritance from old file */ ) { flag = 1; s = yy->lprotect.val; /* UNIX filemode */ xx = yy->lprotect.len; if (xx < 0) /* len < 0 means inheritance */ xx = 0 - xx; for (i = 0; i < xx; i++) { /* Decode octal string */ if (*s <= '7' && *s >= '0') { x = 8 * x + (int)(*s) - '0'; } else { flag = 0; break; } s++; } #ifdef DEBUG sprintf(obuf,"%o",x); debug(F110,"zstime octal lperm",obuf,0); #endif /* DEBUG */ } else if (!flag && yy->gprotect.len > 0) { int g; #ifdef CK_SCO32V4 mode_t mask; #else int mask; #endif /* CK_SCO32V4 */ mask = umask(0); /* Get umask */ debug(F101,"zstime mask 1","",mask); umask(mask); /* Put it back */ mask ^= 0777; /* Flip the bits */ debug(F101,"zstime mask 2","",mask); debug(F101,"zstime yy->gprotect.len","",yy->gprotect.len); /* Decode generic protection */ if (yy->gprotect.len < 1 || yy->gprotect.len > 99) { g = 0; /* protect against bogus value */ } else { debug(F110,"zstime yy->gprotect.val",yy->gprotect.val,0); g = xunchar(*(yy->gprotect.val)); } debug(F101,"zstime gprotect","",g); #ifdef S_IRUSR debug(F100,"zstime S_IRUSR","",0); if (g & 1) x |= S_IRUSR; /* Read permission */ flag = 1; #endif /* S_IRUSR */ #ifdef S_IWUSR debug(F100,"zstime S_IWUSR","",0); if (g & 2) x |= S_IWUSR; /* Write permission */ if (g & 16) x |= S_IWUSR; /* Delete permission */ flag = 1; #endif /* S_IWUSR */ #ifdef S_IXUSR debug(F100,"zstime S_IXUSR","",0); if (g & 4) /* Has execute permission bit */ x |= S_IXUSR; else /* Doesn't have it */ mask &= 0666; /* so also clear it out of mask */ flag = 1; #endif /* S_IXUSR */ debug(F101,"zstime mask x","",x); x |= mask; debug(F101,"zstime mask x|mask","",x); } debug(F101,"zstime flag","",flag); if (flag) { #ifdef S_IFMT debug(F101,"zstime S_IFMT x","",x); sb.st_mode = (sb.st_mode & S_IFMT) | x; setperms = 1; #else #ifdef _IFMT debug(F101,"zstime _IFMT x","",x); sb.st_mode = (sb.st_mode & _IFMT) | x; setperms = 1; #endif /* _IFMT */ #endif /* S_IFMT */ } #ifdef DEBUG sprintf(obuf,"%04o",sb.st_mode); debug(F111,"zstime file perms after",obuf,setperms); #endif /* DEBUG */ } #endif /* CK_PERMS */ debug(F101,"zstime: sb.st_atime","",sb.st_atime); #ifdef BSD44 tp[0].tv_sec = sb.st_atime; /* Access time first */ tp[1].tv_sec = tm; /* Update time second */ debug(F100,"zstime: BSD44 modtime","",0); #else #ifdef V7 tp.timep[0] = tm; /* Set modif. time to creation date */ tp.timep[1] = sb.st_atime; /* Don't change the access time */ debug(F100,"zstime: V7 modtime","",0); #else #ifdef SYSUTIMEH tp.modtime = tm; /* Set modif. time to creation date */ tp.actime = sb.st_atime; /* Don't change the access time */ debug(F100,"zstime: SYSUTIMEH modtime","",0); #else tp.mtime = tm; /* Set modif. time to creation date */ tp.atime = sb.st_atime; /* Don't change the access time */ debug(F100,"zstime: default modtime","",0); #endif /* SYSUTIMEH */ #endif /* V7 */ #endif /* BSD44 */ switch (x) { /* Execute desired function */ case 0: /* Set the creation date of the file */ #ifdef CK_PERMS /* And permissions */ /* NOTE: If we are inheriting permissions from a previous file, and the previous file was a directory, this would turn the new file into a directory too, but it's not, so we try to unset the right bit. Luckily, this code will probably never be executed since the upper level modules do not allow reception of a file that has the same name as a directory. NOTE 2: We change the permissions *before* we change the modification time, otherwise changing the permissions would set the mod time to the present time. */ { int x; debug(F101,"zstime setperms","",setperms); if (S_ISDIR(sb.st_mode)) { debug(F101,"zstime DIRECTORY bit on","",sb.st_mode); sb.st_mode ^= 0040000; debug(F101,"zstime DIRECTORY bit off","",sb.st_mode); } if (setperms) { x = chmod(f,sb.st_mode); debug(F101,"zstime chmod","",x); } } if (x < 0) return(-1); #endif /* CK_PERMS */ if (!setdate) /* We don't have a date */ return(0); /* so skip the following... */ if ( #ifdef BSD44 utimes(f,tp) #else utime(f,&tp) #endif /* BSD44 */ ) { /* Fix modification time */ debug(F111,"zstime 0: can't set modtime for file",f,errno); r = -1; } else { /* Including the modtime here is not portable */ debug(F110,"zstime 0: modtime set for file",f,0); r = 0; } break; case 1: /* Compare the dates */ /* This was st_atime, which was wrong. We want the file-data modification time, st_mtime. */ debug(F111,"zstime 1: compare",f,sb.st_mtime); debug(F111,"zstime 1: compare","packet",tm); r = (sb.st_mtime < tm) ? 0 : 1; break; default: /* Error */ r = -1; } #endif /* TIMESTAMP */ return(r); } /* Find initialization file. */ #ifdef NOTUSED int zkermini() { /* nothing here for Unix. This function added for benefit of VMS Kermit. */ return(0); } #endif /* NOTUSED */ #ifndef UNIX /* Historical -- not used in Unix any more (2001-11-03) */ #ifndef NOFRILLS int zmail(p,f) char *p; char *f; { /* Send file f as mail to address p */ /* Returns 0 on success 2 if mail delivered but temp file can't be deleted -2 if mail can't be delivered -1 on file access error The UNIX version always returns 0 because it can't get a good return code from zsyscmd. */ int n; #ifdef CK_LOGIN if (isguest) return(-2); #endif /* CK_LOGIN */ if (!f) f = ""; if (!*f) return(-1); #ifdef CKROOT debug(F111,"zmail setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(f)) { debug(F110,"zmail setroot violation",f,0); return(-1); } #endif /* CKROOT */ #ifdef BSD4 /* The idea is to use /usr/ucb/mail, rather than regular mail, so that */ /* a subject line can be included with -s. Since we can't depend on the */ /* user's path, we use the convention that /usr/ucb/Mail = /usr/ucb/mail */ /* and even if Mail has been moved to somewhere else, this should still */ /* find it... The search could be made more reliable by actually using */ /* access() to see if /usr/ucb/Mail exists. */ n = strlen(f); n = n + n + 15 + (int)strlen(p); if (n > ZMBUFLEN) return(-2); #ifdef DGUX540 sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f); #else sprintf(zmbuf,"Mail -s %c%s%c %s < %s", '"', f, '"', p, f); #endif /* DGUX540 */ zsyscmd(zmbuf); #else #ifdef SVORPOSIX #ifndef OXOS sprintf(zmbuf,"mail %s < %s", p, f); #else /* OXOS */ sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f); #endif /* OXOS */ zsyscmd(zmbuf); #else *zmbuf = '\0'; #endif #endif return(0); } #endif /* NOFRILLS */ #endif /* UNIX */ #ifndef NOFRILLS int #ifdef CK_ANSIC zprint( char *p, char *f ) /* Print file f with options p */ #else zprint(p,f) char *p; char *f; #endif /* CK_ANSIC */ { extern char * printername; /* From ckuus3.c */ extern int printpipe; int n; #ifdef CK_LOGIN if (isguest) return(-2); #endif /* CK_LOGIN */ if (!f) f = ""; if (!*f) return(-1); #ifdef CKROOT debug(F111,"zprint setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(f)) { debug(F110,"zprint setroot violation",f,0); return(-1); } #endif /* CKROOT */ debug(F110,"zprint file",f,0); debug(F110,"zprint flags",p,0); debug(F110,"zprint printername",printername,0); debug(F101,"zprint printpipe","",printpipe); #ifdef UNIX /* Note use of standard input redirection. In some systems, lp[r] runs setuid to lp (or ...?), so if user has sent a file into a directory that lp does not have read access to, it can't be printed unless it is fed to lp[r] as standard input. */ if (printpipe && printername) { n = 8 + (int)strlen(f) + (int)strlen(printername); if (n > ZMBUFLEN) return(-2); sprintf(zmbuf,"cat %s | %s", f, printername); } else if (printername) { n = 8 + (int)strlen(f) + (int)strlen(printername); if (n > ZMBUFLEN) return(-2); sprintf(zmbuf,"cat %s >> %s", f, printername); } else { n = 4 + (int)strlen(PRINTCMD) + (int)strlen(p) + (int)strlen(f); if (n > ZMBUFLEN) return(-2); sprintf(zmbuf,"%s %s < %s", PRINTCMD, p, f); } debug(F110,"zprint command",zmbuf,0); zsyscmd(zmbuf); #else /* Not UNIX */ *zmbuf = '\0'; #endif /* UNIX */ return(0); } #endif /* NOFRILLS */ /* Wildcard expansion functions... */ static char scratch[MAXPATH+4]; /* Used by both methods */ static int oldmtchs = 0; /* Let shell (ls) expand them. */ #ifdef COMMENT static char *lscmd = "/bin/ls -d"; /* Command to use. */ #else static char *lscmd = "echo"; /* Command to use. */ #endif /* COMMENT */ #ifndef NOPUSH int #ifdef CK_ANSIC shxpand( char *pat, char *namlst[], int len ) #else shxpand(pat,namlst,len) char *pat, *namlst[]; int len; #endif /* CK_ANSIC */ { char *fgbuf = NULL; /* Buffer for forming ls command */ char *p, *q; /* Workers */ int i, x, retcode, itsadir; char c; x = (int)strlen(pat) + (int)strlen(lscmd) + 3; /* Length of ls command */ for (i = 0; i < oldmtchs; i++) { /* Free previous file list */ if (namlst[i] ) { /* If memory is allocated */ free(namlst[i]); /* Free the memory */ namlst[i] = NULL ; /* Remember no memory is allocated */ } } oldmtchs = 0 ; /* Remember there are no matches */ fgbuf = malloc(x); /* Get buffer for command */ if (!fgbuf) return(-1); /* Fail if cannot */ ckmakmsg(fgbuf,x,lscmd," ",pat,NULL); /* Form the command */ zxcmd(ZIFILE,fgbuf); /* Start the command */ i = 0; /* File counter */ p = scratch; /* Point to scratch area */ retcode = -1; /* Assume failure */ while ((x = zminchar()) != -1) { /* Read characters from command */ c = (char) x; if (c == ' ' || c == '\n') { /* Got newline or space? */ *p = '\0'; /* Yes, terminate string */ p = scratch; /* Point back to beginning */ if (zchki(p) == -1) /* Does file exist? */ continue; /* No, continue */ itsadir = isdir(p); /* Yes, is it a directory? */ if (xdironly && !itsadir) /* Want only dirs but this isn't */ continue; /* so skip. */ if (xfilonly && itsadir) /* It's a dir but want only files */ continue; /* so skip. */ x = (int)strlen(p); /* Keep - get length of name */ q = malloc(x+1); /* Allocate space for it */ if (!q) goto shxfin; /* Fail if space can't be obtained */ strcpy(q,scratch); /* (safe) Copy name to space */ namlst[i++] = q; /* Copy pointer to name into array */ if (i >= len) goto shxfin; /* Fail if too many */ } else { /* Regular character */ *p++ = c; /* Copy it into scratch area */ } } retcode = i; /* Return number of matching files */ shxfin: /* Common exit point */ free(fgbuf); /* Free command buffer */ fgbuf = NULL; zclosf(ZIFILE); /* Delete the command fork. */ oldmtchs = i; /* Remember how many files */ return(retcode); } #endif /* NOPUSH */ /* Directory-reading functions for UNIX originally written for C-Kermit 4.0 by Jeff Damens, CUCCA, 1984. */ static char * xpat = NULL; /* Global copy of fgen() pattern */ static char * xpatlast = NULL; /* Rightmost segment of pattern*/ static int xpatslash = 0; /* Slash count in pattern */ static int xpatwild = 0; /* Original pattern is wild */ static int xleafwild = 0; /* Last segment of pattern is wild */ static int xpatabsolute = 0; #ifdef aegis static char bslash; #endif /* aegis */ /* S P L I T P A T H */ /* Splits the slash-separated portions of the argument string into a list of path structures. Returns the head of the list. The structures are allocated by malloc, so they must be freed. Splitpath is used internally by the filename generator. Input: A path string. Returns: A linked list of the slash-separated segments of the input. */ static struct path * #ifdef CK_ANSIC splitpath( char *p ) #else splitpath(p) char *p; #endif /* CK_ANSIC */ { struct path *head,*cur,*prv; int i; debug(F111,"splitpath",p,xrecursive); head = prv = NULL; if (!p) return(NULL); if (!*p) return(NULL); if (!strcmp(p,"**")) { /* Fix this */ p = "*"; } if (ISDIRSEP(*p)) p++; /* Skip leading slash if any */ /* Make linked list of path segments from pattern */ while (*p) { cur = (struct path *) malloc(sizeof (struct path)); /* debug(F101,"splitpath malloc","",cur); */ if (cur == NULL) { debug(F100,"splitpath malloc failure","",0); prv -> fwd = NULL; return((struct path *)NULL); } cur -> fwd = NULL; if (head == NULL) /* First, make list head */ head = cur; else /* Not first, link into chain */ prv -> fwd = cur; prv = cur; /* Link from previous to this one */ #ifdef aegis /* treat backslash as "../" */ if (bslash && *p == bslash) { strcpy(cur->npart, ".."); /* safe */ ++p; } else { for (i=0; i < CKMAXNAM && *p && *p != '/' && *p != bslash; i++) cur -> npart[i] = *p++; cur -> npart[i] = '\0'; /* end this segment */ if (i >= CKMAXNAM) while (*p && *p != '/' && *p != bslash) p++; } if (*p == '/') p++; #else /* General case (UNIX) */ for (i = 0; i < CKMAXNAM && !ISDIRSEP(*p) && *p != '\0'; i++) { cur -> npart[i] = *p++; } cur -> npart[i] = '\0'; /* End this path segment */ if (i >= CKMAXNAM) while (!ISDIRSEP(*p) && *p != '\0') p++; if (ISDIRSEP(*p)) p++; #endif /* aegis */ } if (prv) { makestr(&xpatlast,prv -> npart); debug(F110,"splitpath xpatlast",xpatlast,0); } #ifdef DEBUG /* Show original path list */ if (deblog) { for (i = 0, cur = head; cur; i++) { debug(F111,"SPLITPATH",cur -> npart, i); cur = cur -> fwd; } } #endif /* DEBUG */ return(head); } /* F G E N -- Generate File List */ /* File name generator. It is passed a string, possibly containing wildcards, and an array of character pointers. It finds all the matching filenames and stores pointers to them in the array. The returned strings are allocated from a static buffer local to this module (so the caller doesn't have to worry about deallocating them); this means that successive calls to fgen will wipe out the results of previous calls. Input: A wildcard string, an array to write names to, the length of the array. Returns: The number of matches. The array is filled with filenames that matched the pattern. If there wasn't enough room in the array, -1 is returned. Originally by: Jeff Damens, CUCCA, 1984. Many changes since then. */ static int #ifdef CK_ANSIC fgen( char *pat, char *resarry[], int len ) #else fgen(pat,resarry,len) char *pat,*resarry[]; int len; #endif /* CK_ANSIC */ { struct path *head; char *sptr, *s; int n; #ifdef aegis char *namechars; int tilde = 0, bquote = 0; if ((namechars = getenv("NAMECHARS")) != NULL) { if (ckstrchr(namechars, '~' ) != NULL) tilde = '~'; if (ckstrchr(namechars, '\\') != NULL) bslash = '\\'; if (ckstrchr(namechars, '`' ) != NULL) bquote = '`'; } else { tilde = '~'; bslash = '\\'; bquote = '`'; } sptr = scratch; /* copy "`node_data", etc. anchors */ if (bquote && *pat == bquote) while (*pat && *pat != '/' && *pat != bslash) *sptr++ = *pat++; else if (tilde && *pat == tilde) *sptr++ = *pat++; while (*pat == '/') *sptr++ = *pat++; if (sptr == scratch) { strcpy(scratch,"./"); /* safe */ sptr = scratch+2; } if (!(head = splitpath(pat))) return(-1); #else /* not aegis */ debug(F111,"fgen pat",pat,len); debug(F110,"fgen current directory",zgtdir(),0); debug(F101,"fgen stathack","",stathack); scratch[0] = '\0'; xpatwild = 0; xleafwild = 0; xpatabsolute = 0; if (!(head = splitpath(pat))) /* Make the path segment list */ return(-1); sptr = scratch; #ifdef COMMENT if (strncmp(pat,"./",2) && strncmp(pat,"../",3)) { #endif /* COMMENT */ if (!ISDIRSEP(*pat)) /* If name is not absolute */ *sptr++ = '.'; /* put "./" in front. */ *sptr++ = DIRSEP; #ifdef COMMENT } #endif /* COMMENT */ *sptr = '\0'; #endif /* aegis */ makestr(&xpat,pat); /* Save copy of original pattern */ debug(F110,"fgen scratch",scratch,0); for (n = 0, s = xpat; *s; s++) /* How many slashes in the pattern */ if (*s == DIRSEP) /* since these are fences for */ n++; /* pattern matching */ xpatslash = n; debug(F101,"fgen xpatslash","",xpatslash); numfnd = 0; /* None found yet */ if (initspace(resarry,ssplen) < 0) return(-1); xpatwild = iswild(xpat); /* Original pattern is wild? */ xpatabsolute = isabsolute(xpat); xleafwild = iswild(xpatlast); debug(F111,"fgen xpat",xpat,xpatwild); debug(F111,"fgen xpatlast",xpatlast,xleafwild); debug(F101,"fgen xpatabsolute","",xpatabsolute); traverse(head,scratch,sptr); /* Go walk the directory tree. */ while (head != NULL) { /* Done - free path segment list. */ struct path *next = head -> fwd; free((char *)head); head = next; } debug(F101,"fgen","",numfnd); return(numfnd); /* Return the number of matches */ } /* Define LONGFN (long file names) automatically for BSD 2.9 and 4.2 */ /* LONGFN can also be defined on the cc command line. */ #ifdef BSD29 #ifndef LONGFN #define LONGFN #endif #endif #ifdef BSD42 #ifndef LONGFN #define LONGFN #endif #endif /* T R A V E R S E -- Traverse a directory tree. Walks the directory tree looking for matches to its arguments. The algorithm is, briefly: If the current pattern segment contains no wildcards, that segment is added to what we already have. If the name so far exists, we call ourselves recursively with the next segment in the pattern string; otherwise, we just return. If the current pattern segment contains wildcards, we open the name we've accumulated so far (assuming it is really a directory), then read each filename in it, and, if it matches the wildcard pattern segment, add that filename to what we have so far and call ourselves recursively on the next segment. Finally, when no more pattern segments remain, we add what's accumulated so far to the result array and increment the number of matches. Inputs: A pattern path list (as generated by splitpath), a string pointer that points to what we've traversed so far (this can be initialized to "/" to start the search at the root directory, or to "./" to start the search at the current directory), and a string pointer to the end of the string in the previous argument, plus the global "recursive", "xmatchdot", and "xdironly" flags. Returns: void, with: mtchs[] containing the array of filename string pointers, and: numfnd containing the number of filenames. Although it might be poor practice, the mtchs[] array is revealed to the outside in case it needs it; for example, to be sorted prior to use. (It is poor practice because not all platforms implement file lists the same way; some don't use an array at all.) Note that addresult() acts as a second-level filter; due to selection criteria outside of the pattern, it might decline to add files that this routine asks it to, e.g. because we are collecting only directory names but not the names of regular files. WARNING: In the course of C-Kermit 7.0 development, this routine became ridiculously complex, in order to meet approximately sixty specific requirements. DON'T EVEN THINK ABOUT MODIFYING THIS ROUTINE! Trust me; it is not possible to fix anything in it without breaking something else. This routine badly needs a total redesign and rewrite. Note: There may be some good applications for realpath() and/or scandir() and/or fts_blah() here, on platforms where they are available. */ static VOID #ifdef CK_ANSIC traverse( struct path *pl, char *sofar, char *endcur ) #else traverse(pl,sofar,endcur) struct path *pl; char *sofar, *endcur; #endif /* CK_ANSIC */ { /* Appropriate declarations for directory routines and structures */ /* #define OPENDIR means to use opendir(), readdir(), closedir() */ /* If OPENDIR not defined, we use open(), read(), close() */ #ifdef DIRENT /* New way, */ #define OPENDIR DIR *fd; struct dirent *dirbuf; #else /* !DIRENT */ #ifdef LONGFN /* Old way, with opendir() */ #define OPENDIR DIR *fd; struct direct *dirbuf; #else /* !LONGFN */ int fd; /* Old way, with open() */ struct direct dir_entry; struct direct *dirbuf = &dir_entry; #endif /* LONGFN */ #endif /* DIRENT */ int mopts = 0; /* ckmatch() opts */ int depth = 0; /* Directory tree depth */ char nambuf[CKMAXNAM+4]; /* Buffer for a filename */ int itsadir = 0, segisdir = 0, itswild = 0, mresult, n, x /* , y */ ; struct stat statbuf; /* For file info. */ debug(F101,"STAT","",16); if (pl == NULL) { /* End of path-segment list */ *--endcur = '\0'; /* Terminate string, overwrite trailing slash */ debug(F110,"traverse add: end of path segment",sofar,0); addresult(sofar,-1); return; } if (stathack) { /* This speeds up the search a lot and we still get good results */ /* but it breaks the tagging of directory names done in addresult */ if (xrecursive || xfilonly || xdironly || xpatslash) { itsadir = xisdir(sofar); debug(F101,"STAT","",17); } else itsadir = (strncmp(sofar,"./",2) == 0); } else { itsadir = xisdir(sofar); debug(F101,"STAT","",18); } debug(F111,"traverse entry sofar",sofar,itsadir); #ifdef CKSYMLINK /* We're doing symlinks? */ #ifdef USE_LSTAT /* OK to use lstat()? */ if (itsadir && xnolinks) { /* If not following symlinks */ int x; struct stat buf; x = lstat(sofar,&buf); debug(F111,"traverse lstat 1",sofar,x); if (x > -1 && #ifdef S_ISLNK S_ISLNK(buf.st_mode) #else #ifdef _IFLNK ((_IFMT & buf.st_mode) == _IFLNK) #endif /* _IFLNK */ #endif /* S_ISLNK */ ) itsadir = 0; } #endif /* USE_LSTAT */ #endif /* CKSYMLINK */ if (!xmatchdot && xpatlast[0] == '.') xmatchdot = 1; if (!xmatchdot && xpat[0] == '.' && xpat[1] != '/' && xpat[1] != '.') xmatchdot = 1; /* ckmatch() options */ if (xmatchdot) mopts |= 1; /* Match dot */ if (!xrecursive) mopts |= 2; /* Dirsep is fence */ debug(F111,"traverse entry xpat",xpat,xpatslash); debug(F111,"traverse entry xpatlast",xpatlast,xmatchdot); debug(F110,"traverse entry pl -> npart",pl -> npart,0); #ifdef RECURSIVE if (xrecursive > 0 && !itsadir) { char * s; /* Recursive descent and this is a regular file */ *--endcur = '\0'; /* Terminate string, overwrite trailing slash */ /* Find the nth slash from the right and match from there... */ /* (n == the number of slashes in the original pattern - see fgen) */ if (*sofar == '/') { debug(F110,"traverse xpatslash absolute",sofar,0); s = sofar; } else { debug(F111,"traverse xpatslash relative",sofar,xpatslash); for (s = endcur - 1, n = 0; s >= sofar; s--) { if (*s == '/') { if (++n >= xpatslash) { s++; break; } } } } #ifndef NOSKIPMATCH /* This speeds things up a bit. */ /* If it causes trouble define NOSKIPMATCH and rebuild. */ if (xpat[0] == '*' && !xpat[1]) x = xmatchdot ? 1 : (s[0] != '.'); else #endif /* NOSKIPMATCH */ x = ckmatch(xpat, s, 1, mopts); /* Match with original pattern */ debug(F111,"traverse xpatslash ckmatch",s,x); if (x > 0) { debug(F110,"traverse add: recursive, match, && !isdir",sofar,0); addresult(sofar,itsadir); } return; } #endif /* RECURSIVE */ debug(F111,"traverse sofar 2",sofar,0); segisdir = ((pl -> fwd) == NULL) ? 0 : 1; itswild = wildena ? (iswild(pl -> npart)) : 0; /* 15 Jun 2005 */ debug(F111,"traverse segisdir",sofar,segisdir); debug(F111,"traverse itswild ",pl -> npart,itswild); #ifdef RECURSIVE if (xrecursive > 0) { /* If recursing and... */ if (segisdir && itswild) /* this is a dir and npart is wild */ goto blah; /* or... */ else if (!xpatabsolute && !xpatwild) /* search object is nonwild */ goto blah; /* then go recurse */ } #endif /* RECURSIVE */ if (!itswild) { /* This path segment not wild? */ #ifdef COMMENT strcpy(endcur,pl -> npart); /* (safe) Append next part. */ endcur += (int)strlen(pl -> npart); /* Advance end pointer */ #else /* strcpy() does not account for quoted metacharacters. We must remove the quotes before doing the stat(). */ { int quote = 0; char c, * s; s = pl -> npart; while ((c = *s++)) { if (!quote) { if (c == CMDQ) { quote = 1; continue; } } *endcur++ = c; quote = 0; } } #endif /* COMMENT */ *endcur = '\0'; /* End new current string. */ if (stat(sofar,&statbuf) == 0) { /* If this piece exists... */ debug(F110,"traverse exists",sofar,0); *endcur++ = DIRSEP; /* add slash to end */ *endcur = '\0'; /* and end the string again. */ traverse(pl -> fwd, sofar, endcur); } #ifdef DEBUG else debug(F110,"traverse not found", sofar, 0); #endif /* DEBUG */ return; } *endcur = '\0'; /* End current string */ debug(F111,"traverse sofar 3",sofar,0); if (!itsadir) return; /* Search is recursive or ... */ /* path segment contains wildcards, have to open and search directory. */ blah: debug(F110,"traverse opening directory", sofar, 0); #ifdef OPENDIR debug(F110,"traverse opendir()",sofar,0); if ((fd = opendir(sofar)) == NULL) { /* Can't open, fail. */ debug(F101,"traverse opendir() failed","",errno); return; } while ((dirbuf = readdir(fd))) #else /* !OPENDIR */ debug(F110,"traverse directory open()",sofar,0); if ((fd = open(sofar,O_RDONLY)) < 0) { debug(F101,"traverse directory open() failed","",errno); return; } while (read(fd, (char *)dirbuf, sizeof dir_entry) > 0) #endif /* OPENDIR */ { /* Read each entry in this directory */ int exists; char *eos, *s; exists = 0; /* On some platforms, the read[dir]() can return deleted files, */ /* e.g. HP-UX 5.00. There is no point in grinding through this */ /* routine when the file doesn't exist... */ if ( /* There actually is an inode... */ #ifdef BSD42 dirbuf->d_ino != -1 #else #ifdef unos dirbuf->d_ino != -1 #else #ifdef QNX dirbuf->d_stat.st_ino != 0 #else #ifdef SOLARIS dirbuf->d_ino != 0 #else #ifdef sun dirbuf->d_fileno != 0 #else #ifdef bsdi dirbuf->d_fileno != 0 #else #ifdef __386BSD__ dirbuf->d_fileno != 0 #else #ifdef __FreeBSD__ dirbuf->d_fileno != 0 #else #ifdef ultrix dirbuf->gd_ino != 0 #else #ifdef Plan9 1 #else dirbuf->d_ino != 0 #endif /* Plan9 */ #endif /* ultrix */ #endif /* __FreeBSD__ */ #endif /* __386BSD__ */ #endif /* bsdi */ #endif /* sun */ #endif /* SOLARIS */ #endif /* QNX */ #endif /* unos */ #endif /* BSD42 */ ) exists = 1; if (!exists) continue; ckstrncpy(nambuf, /* Copy the name */ dirbuf->d_name, CKMAXNAM ); if (nambuf[0] == '.') { if (!nambuf[1] || (nambuf[1] == '.' && !nambuf[2])) { debug(F110,"traverse skipping",nambuf,0); continue; /* skip "." and ".." */ } } s = nambuf; /* Copy name to end of sofar */ eos = endcur; while ((*eos = *s)) { s++; eos++; } /* Now we check the file for (a) whether it is a directory, and (b) whether its name matches our pattern. If it is a directory, and if we have been told to build a recursive list, then we must descend regardless of whether it matches the pattern. If it is not a directory and it does not match our pattern, we skip it. Note: sofar is the full pathname, nambuf is the name only. */ /* Do this first to save pointless function calls */ if (nambuf[0] == '.' && !xmatchdot) /* Dir name starts with '.' */ continue; if (stathack) { if (xrecursive || xfilonly || xdironly || xpatslash) { itsadir = xisdir(sofar); /* See if it's a directory */ debug(F101,"STAT","",19); } else { itsadir = 0; } } else { itsadir = xisdir(sofar); debug(F101,"STAT","",20); } #ifdef CKSYMLINK #ifdef USE_LSTAT if (itsadir && xnolinks) { /* If not following symlinks */ int x; struct stat buf; x = lstat(sofar,&buf); debug(F111,"traverse lstat 2",sofar,x); if (x > -1 && #ifdef S_ISLNK S_ISLNK(buf.st_mode) #else #ifdef _IFLNK ((_IFMT & buf.st_mode) == _IFLNK) #endif /* _IFLNK */ #endif /* S_ISLNK */ ) itsadir = 0; } #endif /* USE_LSTAT */ #endif /* CKSYMLINK */ #ifdef RECURSIVE if (xrecursive > 0 && itsadir && (xpatlast[0] == '*') && !xpatlast[1] ) { debug(F110, "traverse add: recursive && isdir && segisdir or match", sofar, segisdir ); addresult(sofar,itsadir); if (numfnd < 0) return; } #endif /* RECURSIVE */ debug(F111,"traverse mresult xpat",xpat,xrecursive); debug(F111,"traverse mresult pl -> npart", pl -> npart, ((pl -> fwd) ? 9999 : 0) ); debug(F111,"traverse mresult sofar segisdir",sofar,segisdir); debug(F111,"traverse mresult sofar itsadir",sofar,itsadir); debug(F101,"traverse mresult xmatchdot","",xmatchdot); /* Match the path so far with the pattern after stripping any leading "./" from either or both. The pattern chosen is the full original pattern if the match candidate (sofar) is not a directory, or else just the name part (pl->npart) if it is. */ { char * s1; /* The pattern */ char * s2 = sofar; /* The path so far */ char * s3; /* Worker */ int opts; /* Match options */ s1 = itsadir ? pl->npart : xpat; #ifndef COMMENT /* I can't explain this but it unbreaks "cd blah/sub" */ if (itsadir && !xrecursive && xpatslash > 0 && segisdir == 0 && itswild) { s1 = xpat; debug(F110,"traverse mresult s1 kludge",s1,0); } #endif /* COMMENT */ if (xrecursive && xpatslash == 0) s2 = nambuf; while ((s1[0] == '.') && (s1[1] == '/')) /* Strip "./" */ s1 += 2; while ((s2[0] == '.') && (s2[1] == '/')) /* Ditto */ s2 += 2; opts = mopts; /* Match options */ if (itsadir) /* Current segment is a directory */ opts = mopts & 1; /* No fences */ s3 = s2; /* Get segment depth */ depth = 0; while (*s3) { if (*s3++ == '/') depth++; } #ifndef NOSKIPMATCH /* This speeds things up a bit. */ /* If it causes trouble define NOSKIPMATCH and rebuild. */ if (depth == 0 && (s1[0] == '*') && !s1[1]) mresult = xmatchdot ? 1 : (s2[0] != '.'); else #endif /* NOSKIPMATCH */ mresult = ckmatch(s1,s2,1,opts); /* Match */ } #ifdef DEBUG if (deblog) { debug(F111,"traverse mresult depth",sofar,depth); debug(F101,"traverse mresult xpatslash","",xpatslash); debug(F111,"traverse mresult nambuf",nambuf,mresult); debug(F111,"traverse mresult itswild",pl -> npart,itswild); debug(F111,"traverse mresult segisdir",pl -> npart,segisdir); } #endif /* DEBUG */ if (mresult || /* If match succeeded */ xrecursive || /* Or search is recursive */ depth < xpatslash /* Or not deep enough to match... */ ) { if ( /* If it's not a directory... */ /* The problem here is that segisdir is apparently not set appropriately. If I leave in the !segisdir test, then "dir /recursive blah" (where blah is a directory name) misses some regular files because sometimes segisdir is set and sometimes it's not. But if I comment it out, then "dir /.txt lists every file in * and does not even open up the subdirectories. However, "dir /rec /.txt" works right. */ #ifdef COMMENT mresult && (!itsadir && !segisdir) #else mresult && /* Matched */ !itsadir && /* sofar is not a directory */ ((!xrecursive && !segisdir) || xrecursive) #endif /* COMMENT */ ) { debug(F110, "traverse add: match && !itsadir",sofar,0); addresult(sofar,itsadir); if (numfnd < 0) return; } else if (itsadir && (xrecursive || mresult)) { struct path * xx = NULL; *eos++ = DIRSEP; /* Add directory separator */ *eos = '\0'; /* to end of segment */ #ifdef RECURSIVE /* Copy previous pattern segment to this new directory */ if (xrecursive > 0 && !(pl -> fwd)) { xx = (struct path *) malloc(sizeof (struct path)); pl -> fwd = xx; if (xx) { xx -> fwd = NULL; strcpy(xx -> npart, pl -> npart); /* safe */ } } #endif /* RECURSIVE */ traverse(pl -> fwd, sofar, eos); /* Traverse new directory */ } } } #ifdef OPENDIR closedir(fd); #else /* !OPENDIR */ close(fd); #endif /* OPENDIR */ } /* * addresult: * Adds a result string to the result array. Increments the number * of matches found, copies the found string into our string * buffer, and puts a pointer to the buffer into the caller's result * array. Our free buffer pointer is updated. If there is no * more room in the caller's array, the number of matches is set to -1. * Input: a result string. * Returns: nothing. */ static VOID #ifdef CK_ANSIC addresult( char *str, int itsadir ) #else addresult(str,itsadir) char *str; int itsadir; #endif /* CK_ANSIC */ { int len; if (!freeptr) { debug(F100,"addresult string space not init'd","",0); initspace(mtchs,ssplen); } if (!str) str = ""; debug(F111,"addresult",str,itsadir); if (!*str) return; if (itsadir < 0) { itsadir = xisdir(str); } if ((xdironly && !itsadir) || (xfilonly && itsadir)) { debug(F111,"addresult skip",str,itsadir); return; } while (str[0] == '.' && ISDIRSEP(str[1])) /* Strip all "./" from front */ str += 2; if (--remlen < 0) { /* Elements left in array of names */ debug(F111,"addresult ARRAY FULL",str,numfnd); numfnd = -1; return; } len = (int)strlen(str); /* Space this will use */ debug(F111,"addresult len",str,len); if (len < 1) return; if ((freeptr + len + itsadir + 1) > (sspace + ssplen)) { debug(F111,"addresult OUT OF SPACE",str,numfnd); #ifdef DYNAMIC printf( "?String space %d exhausted - use SET FILE STRINGSPACE to increase\n",ssplen); #else printf("?String space %d exhausted\n",ssplen); #endif /* DYNAMIC */ numfnd = -1; /* Do not record if not enough space */ return; } strcpy(freeptr,str); /* safe */ /* Tag directory names by putting '/' at the end */ if (itsadir && (freeptr[len-1] == '/')) { freeptr[len++] = DIRSEP; freeptr[len] = '\0'; } if (numfnd >= maxnames) { #ifdef DYNAMIC printf( "?Too many files (%d max) - use SET FILE LISTSIZE to increase\n",maxnames); #else printf("?Too many files - %d max\n",maxnames); #endif /* DYNAMIC */ numfnd = -1; return; } str = freeptr; *resptr++ = freeptr; freeptr += (len + 1); numfnd++; debug(F111,"addresult ADD",str,numfnd); } #ifdef COMMENT /* * match(pattern,string): * pattern matcher. Takes a string and a pattern possibly containing * the wildcard characters '*' and '?'. Returns true if the pattern * matches the string, false otherwise. * Orignally by: Jeff Damens, CUCCA, 1984 * No longer used as of C-Kermit 7.0, now we use ckmatch() instead (ckclib.c). * * Input: a string and a wildcard pattern. * Returns: 1 if match, 0 if no match. */ static int match(pattern, string) char *pattern, *string; { char *psave = NULL, *ssave = NULL; /* Backup pointers for failure */ int q = 0; /* Quote flag */ if (*string == '.' && *pattern != '.' && !xmatchdot) { debug(F110,"match skip",string,0); return(0); } while (1) { for (; *pattern == *string; pattern++,string++) /* Skip first */ if (*string == '\0') return(1); /* End of strings, succeed */ if (*pattern == '\\' && q == 0) { /* Watch out for quoted */ q = 1; /* metacharacters */ pattern++; /* advance past quote */ if (*pattern != *string) return(0); continue; } else q = 0; if (q) { return(0); } else { if (*string != '\0' && *pattern == '?') { pattern++; /* '?', let it match */ string++; } else if (*pattern == '*') { /* '*' ... */ psave = ++pattern; /* remember where we saw it */ ssave = string; /* let it match 0 chars */ } else if (ssave != NULL && *ssave != '\0') { /* if not at end */ /* ...have seen a star */ string = ++ssave; /* skip 1 char from string */ pattern = psave; /* and back up pattern */ } else return(0); /* otherwise just fail */ } } } #endif /* COMMENT */ /* The following two functions are for expanding tilde in filenames Contributed by Howie Kaye, CUCCA, developed for CCMD package. */ /* W H O A M I -- Get user's username. */ /* 1) Get real uid 2) See if the $USER environment variable is set ($LOGNAME on AT&T) 3) If $USER's uid is the same as ruid, realname is $USER 4) Otherwise get logged in user's name 5) If that name has the same uid as the real uid realname is loginname 6) Otherwise, get a name for ruid from /etc/passwd */ char * whoami() { #ifdef DTILDE #ifdef pdp11 #define WHOLEN 100 #else #define WHOLEN 257 #endif /* pdp11 */ static char realname[UIDBUFLEN+1]; /* user's name */ static int ruid = -1; /* user's real uid */ char loginname[UIDBUFLEN+1], envname[256]; /* temp storage */ char *c; struct passwd *p; _PROTOTYP(extern char * getlogin, (void) ); debug(F111,"whoami ruid A",realname,ruid); if (ruid != -1) return(realname); ruid = real_uid(); /* get our uid */ debug(F101,"whoami ruid B","",ruid); if (ruid < 0) ruid = getuid(); debug(F101,"whoami ruid C","",ruid); /* how about $USER or $LOGNAME? */ if ((c = getenv(NAMEENV)) != NULL) { /* check the env variable */ ckstrncpy(envname, c, 255); debug(F110,"whoami envname",envname,0); if ((p = getpwnam(envname)) != NULL) { if (p->pw_uid == ruid) { /* get passwd entry for envname */ ckstrncpy(realname, envname, UIDBUFLEN); /* uid's are same */ debug(F110,"whoami realname",realname,0); return(realname); } } } /* can we use loginname() ? */ if ((c = getlogin()) != NULL) { /* name from utmp file */ ckstrncpy (loginname, c, UIDBUFLEN); debug(F110,"whoami loginname",loginname,0); if ((p = getpwnam(loginname)) != NULL) /* get passwd entry */ if (p->pw_uid == ruid) /* for loginname */ ckstrncpy(realname, envname, UIDBUFLEN); /* if uid's are same */ } /* Use first name we get for ruid */ if ((p = getpwuid(ruid)) == NULL) { /* name for uid */ debug(F101,"whoami no username for ruid","",ruid); realname[0] = '\0'; /* no user name */ ruid = -1; return(NULL); } ckstrncpy(realname, p->pw_name, UIDBUFLEN); debug(F110,"whoami realname from getpwuid",realname,0); return(realname); #else return(NULL); #endif /* DTILDE */ } /* T I L D E _ E X P A N D -- expand ~user to the user's home directory. */ char * #ifdef CK_ANSIC tilde_expand( char *dirname ) #else tilde_expand(dirname) char *dirname; #endif /* CK_ANSIC */ { #ifdef DTILDE #ifdef pdp11 #define BUFLEN 100 #else #define BUFLEN 257 #endif /* pdp11 */ struct passwd *user; static char olddir[BUFLEN+1]; static char oldrealdir[BUFLEN+1]; static char temp[BUFLEN+1]; int i, j; debug(F111,"tilde_expand",dirname,dirname[0]); if (dirname[0] != '~') { /* Not a tilde...return param */ debug(F000,"tilde_expand NOT TILDE","",dirname[0]); return(dirname); } if (!strcmp(olddir,dirname)) { /* Same as last time */ debug(F110,"tilde_expand same as previous",oldrealdir,0); return(oldrealdir); /* so return old answer. */ } else { debug(F110,"tilde_expand working...","",0); j = (int)strlen(dirname); for (i = 0; i < j; i++) /* find username part of string */ if (!ISDIRSEP(dirname[i])) temp[i] = dirname[i]; else break; temp[i] = '\0'; /* tie off with a NULL */ debug(F111,"tilde_expand first part",temp,i); if (i == 1) { /* if just a "~" */ #ifdef IKSD if (inserver) user = getpwnam(uidbuf); /* Get info on current user */ else #endif /* IKSD */ { char * p = whoami(); debug(F110,"tilde_expand p",p,0); if (p) { user = getpwnam(p); debug(F110,"tilde_expand getpwpam ~",user,0); } else { user = NULL; } } } else { debug(F110,"tilde_expand ~user",&temp[1],0); user = getpwnam(&temp[1]); /* otherwise on the specified user */ debug(F110,"tilde_expand getpwpam user",user,0); } } if (user != NULL) { /* valid user? */ ckstrncpy(olddir, dirname, BUFLEN); /* remember the directory */ ckstrncpy(oldrealdir,user->pw_dir, BUFLEN); /* and home directory */ ckstrncat(oldrealdir,&dirname[i], BUFLEN); oldrealdir[BUFLEN] = '\0'; return(oldrealdir); } else { /* invalid? */ ckstrncpy(olddir, dirname, BUFLEN); /* remember for next time */ ckstrncpy(oldrealdir, dirname, BUFLEN); return(oldrealdir); } #else return(NULL); #endif /* DTILDE */ } /* Functions for executing system commands. zsyscmd() executes the system command in the normal, default way for the system. In UNIX, it does what system() does. Thus, its results are always predictable. zshcmd() executes the command using the user's preferred shell. */ int #ifdef CK_ANSIC zsyscmd( char *s ) #else zsyscmd(s) char *s; #endif /* CK_ANSIC */ { #ifdef aegis if (nopush) return(-1); if (!priv_chk()) return(system(s)); #else PID_T shpid; #ifdef COMMENT /* This doesn't work... */ WAIT_T status; #else int status; #endif /* COMMENT */ if (nopush) return(-1); if ((shpid = fork())) { if (shpid < (PID_T)0) return(-1); /* Parent */ while (shpid != (PID_T) wait(&status)) ; return(status); } if (priv_can()) { /* Child: cancel any priv's */ printf("?Privilege cancellation failure\n"); _exit(255); } restorsigs(); /* Restore ignored signals */ #ifdef HPUX10 execl("/usr/bin/sh","sh","-c",s,NULL); perror("/usr/bin/sh"); #else #ifdef Plan9 execl("/bin/rc", "rc", "-c", s, NULL); perror("/bin/rc"); #else execl("/bin/sh","sh","-c",s,NULL); perror("/bin/sh"); #endif /* Plan9 */ #endif /* HPUX10 */ _exit(255); return(0); /* Shut up ANSI compilers. */ #endif /* aegis */ } /* Z _ E X E C -- Overlay ourselves with another program */ #ifndef NOZEXEC #ifdef HPUX5 #define NOZEXEC #else #ifdef ATT7300 #define NOZEXEC #endif /* ATT7300 */ #endif /* HPUX5 */ #endif /* NOZEXEC */ VOID #ifdef CK_ANSIC z_exec( char * p, char ** s, int t ) #else z_exec(p,s,t) char * p, ** s; int t; #endif /* CK_ANSIC */ { #ifdef NOZEXEC printf("EXEC /REDIRECT NOT IMPLEMENTED IN THIS VERSION OF C-KERMIT\n"); debug(F110,"z_exec NOT IMPLEMENTED",p,0); #else int x; extern int ttyfd; debug(F110,"z_exec command",p,0); debug(F110,"z_exec arg 0",s[0],0); debug(F110,"z_exec arg 1",s[1],0); debug(F101,"z_exec t","",t); errno = 0; if (t) { if (ttyfd > 2) { dup2(ttyfd, 0); dup2(ttyfd, 1); /* dup2(ttyfd, 2); */ close(ttyfd); } } restorsigs(); /* Restore ignored signals */ x = execvp(p,s); if (x < 0) debug(F101,"z_exec errno","",errno); #endif /* NOZEXEC */ } /* Z S H C M D -- Execute a shell command (or program thru the shell). Original UNIX code by H. Fischer; copyright rights assigned to Columbia U. Adapted to use getpwuid to find login shell because many systems do not have SHELL in environment, and to use direct calling of shell rather than intermediate system() call. -- H. Fischer (1985); many changes since then. Call with s pointing to command to execute. Returns: -1 on failure to start the command (can't find, can't fork, can't run). 1 if command ran and gave an exit status of 0. 0 if command ran and gave a nonzero exit status. with pexitstatus containing the command's exit status. */ int #ifdef CK_ANSIC zshcmd( char *s ) #else zshcmd(s) char *s; #endif /* CK_ANSIC */ { PID_T pid; #ifdef NOPUSH return(0); #else if (nopush) return(-1); if (!s) return(-1); while (*s == ' ') s++; debug(F110,"zshcmd command",s,0); #ifdef aegis if ((pid = vfork()) == 0) { /* Make child quickly */ char *shpath, *shname, *shptr; /* For finding desired shell */ if (priv_can()) exit(1); /* Turn off privs. */ if ((shpath = getenv("SHELL")) == NULL) shpath = "/com/sh"; #else /* All Unix systems */ if ((pid = fork()) == 0) { /* Make child */ char *shpath, *shname, *shptr; /* For finding desired shell */ struct passwd *p; #ifdef HPUX10 /* Default */ char *defshell = "/usr/bin/sh"; #else #ifdef Plan9 char *defshell = "/bin/rc"; #else char *defshell = "/bin/sh"; #endif /* Plan9 */ #endif /* HPUX10 */ if (priv_can()) exit(1); /* Turn off privs. */ #ifdef COMMENT /* Old way always used /etc/passwd shell */ p = getpwuid(real_uid()); /* Get login data */ if (p == (struct passwd *) NULL || !*(p->pw_shell)) shpath = defshell; else shpath = p->pw_shell; #else /* New way lets user override with SHELL variable, but does not rely on it. */ /* This allows user to specify a different shell. */ shpath = getenv("SHELL"); /* What shell? */ debug(F110,"zshcmd SHELL",shpath,0); { int x = 0; if (!shpath) { x++; } else if (!*shpath) { x++; } if (x) { debug(F100,"zshcmd SHELL not defined","",0); p = getpwuid( real_uid() ); /* Get login data */ if (p == (struct passwd *)NULL || !*(p->pw_shell)) { shpath = defshell; } else { shpath = p->pw_shell; } debug(F110,"zshcmd shpath from getpwuid",shpath,0); } } #endif /* COMMENT */ #endif /* aegis */ shptr = shname = shpath; while (*shptr != '\0') if (*shptr++ == DIRSEP) shname = shptr; restorsigs(); /* Restore ignored signals */ debug(F110,"zshcmd execl shpath",shpath,0); debug(F110,"zshcmd execl shname",shname,0); if (s == NULL || *s == '\0') { /* Interactive shell requested? */ debug(F100,"zshcmd execl interactive","",0); execl(shpath,shname,"-i",NULL); /* Yes, do that */ } else { /* Otherwise, */ debug(F110,"zshcmd execl command",s,0); execl(shpath,shname,"-c",s,NULL); /* exec the given command */ } /* If execl() failed, */ debug(F101,"zshcmd errno","",errno); perror(shpath); /* print reason and */ exit(BAD_EXIT); /* return bad return code. */ } else { /* Parent */ int wstat; /* ... must wait for child */ #ifdef CK_CHILD int child; /* Child's exit status */ #endif /* CK_CHILD */ SIGTYP (*istat)(), (*qstat)(); if (pid == (PID_T) -1) return(-1); /* fork() failed? */ istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */ qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */ debug(F110,"zshcmd parent waiting for child",s,0); #ifdef CK_CHILD while (((wstat = wait(&child)) != pid) && (wstat != -1)) #else while (((wstat = wait((WAIT_T *)0)) != pid) && (wstat != -1)) #endif /* CK_CHILD */ ; /* Wait for fork */ signal(SIGINT,istat); /* Restore interrupts */ signal(SIGQUIT,qstat); #ifdef CK_CHILD pexitstat = (child & 0xff) ? child : child >> 8; debug(F101,"zshcmd exit status","",pexitstat); return(child == 0 ? 1 : 0); /* Return child's status */ #endif /* CK_CHILD */ } return(1); #endif /* NOPUSH */ } /* I S W I L D -- Check if filespec is "wild" */ /* Returns: 0 wildcards disabled or argument is empty or is the name of a single file; 1 if it contains wildcard characters. Note: must match the algorithm used by match(), hence no [a-z], etc. */ int #ifdef CK_ANSIC iswild( char *filespec ) #else iswild(filespec) char *filespec; #endif /* CK_ANSIC */ { char c, *p, *f; int x; int quo = 0; if (!filespec) /* Safety */ return(0); if (!wildena) /* Wildcards disabled - 12 Jun 2005 */ return(0); f = filespec; if (wildxpand) { /* Shell handles wildcarding */ if ((x = nzxpand(filespec,0)) > 1) return(1); if (x == 0) return(0); /* File does not exist */ p = malloc(CKMAXNAM + 20); znext(p); x = (strcmp(filespec,p) != 0); free(p); p = NULL; return(x); } else { /* We do it ourselves */ while ((c = *filespec++) != '\0') { if (c == '\\' && quo == 0) { quo = 1; continue; } if (!quo && (c == '*' || c == '?' #ifdef CKREGEX #ifndef VMS || c == '[' #endif /* VMS */ || c == '{' #endif /* CKREGEX */ )) { debug(F111,"iswild",f,1); return(1); } quo = 0; } debug(F111,"iswild",f,0); return(0); } } /* I S D I R -- Is a Directory. Tell if string pointer s is the name of an existing directory. Returns 1 if directory, 0 if not a directory. The following no longer applies: If the file is a symlink, we return 1 if it is a directory OR if it is a link to a directory and the "xrecursive" flag is NOT set. This is to allow parsing a link to a directory as if it were a directory (e.g. in the CD or IF DIRECTORY command) but still prevent recursive traversal from visiting the same directory twice. */ #ifdef ISDIRCACHE /* This turns out to be unsafe and gives little benefit anyway. */ /* See notes 28 Sep 2003. Thus ISDIRCACHE is not defined. */ static char prevpath[CKMAXPATH+4] = { '\0', '\0' }; static int prevstat = -1; int clrdircache() { debug(F100,"CLEAR ISDIR CACHE","",0); prevstat = -1; prevpath[0] = NUL; } #endif /* ISDIRCACHE */ int #ifdef CK_ANSIC isalink( char *s ) #else isalink(s) char *s; #endif /* CK_ANSIC */ { #ifndef CKSYMLINK return(0); #else int r = 0; char filbuf[CKMAXPATH+4]; if (readlink(s,filbuf,CKMAXPATH) > -1) r = 1; debug(F110,"isalink readlink",s,r); return(r); #endif /* CKSYMLINK */ } int #ifdef CK_ANSIC isdir( char *s ) #else isdir(s) char *s; #endif /* CK_ANSIC */ { int x, needrlink = 0, islink = 0; struct stat statbuf; char fnam[CKMAXPATH+4]; if (!s) return(0); debug(F110,"isdir entry",s,0); #ifdef DTILDE /* 2005-08-13 */ if (*s == '~') { /* Starts with tilde? */ s = tilde_expand(s); /* Attempt to expand tilde */ if (!s) s = ""; debug(F110,"isdir tilde_expand",s,0); } #endif /* DTILDE */ if (!*s) return(0); #ifdef ISDIRCACHE if (prevstat > -1) { if (s[0] == prevpath[0]) { if (!strcmp(s,prevpath)) { debug(F111,"isdir cache hit",s,prevstat); return(prevstat); } } } #endif /* ISDIRCACHE */ #ifdef CKSYMLINK #ifdef COMMENT /* The following over-clever bit has been commented out because it presumes to know when a symlink might be redundant, which it can't possibly know. Using plain old stat() gives Kermit the same results as ls and ls -R, which is just fine: no surprises. */ #ifdef USE_LSTAT if (xrecursive) { x = lstat(s,&statbuf); debug(F111,"isdir lstat",s,x); } else { #endif /* USE_LSTAT */ x = stat(s,&statbuf); debug(F111,"isdir stat",s,x); #ifdef USE_LSTAT } #endif /* USE_LSTAT */ #else x = stat(s,&statbuf); debug(F111,"isdir stat",s,x); #endif /* COMMENT */ if (x == -1) { debug(F101,"isdir errno","",errno); return(0); } islink = 0; if (xrecursive) { #ifdef NOLINKBITS needrlink = 1; #else #ifdef S_ISLNK islink = S_ISLNK(statbuf.st_mode); debug(F101,"isdir S_ISLNK islink","",islink); #else #ifdef _IFLNK islink = (_IFMT & statbuf.st_mode) == _IFLNK; debug(F101,"isdir _IFLNK islink","",islink); #endif /* _IFLNK */ #endif /* S_ISLNK */ #endif /* NOLINKBITS */ if (needrlink) { if (readlink(s,fnam,CKMAXPATH) > -1) islink = 1; } } #else x = stat(s,&statbuf); if (x == -1) { debug(F101,"isdir errno","",errno); return(0); } debug(F111,"isdir stat",s,x); #endif /* CKSYMLINK */ debug(F101,"isdir islink","",islink); debug(F101,"isdir statbuf.st_mode","",statbuf.st_mode); x = islink ? 0 : (S_ISDIR (statbuf.st_mode) ? 1 : 0); #ifdef ISDIRCACHE prevstat = x; ckstrncpy(prevpath,s,CKMAXPATH+1); #endif /* ISDIRCACHE */ return(x); } #ifdef CK_MKDIR /* Some systems don't have mkdir(), e.g. Tandy Xenix 3.2.. */ /* Z M K D I R -- Create directory(s) if necessary */ /* Call with: A pointer to a file specification that might contain directory information. The filename is expected to be included. If the file specification does not include any directory separators, then it is assumed to be a plain file. If one or more directories are included in the file specification, this routine tries to create them if they don't already exist. Returns: 0 or greater on success, i.e. the number of directories created. -1 on failure to create the directory */ int #ifdef CK_ANSIC zmkdir( char *path ) #else zmkdir(path) char *path; #endif /* CK_ANSIC */ { char *xp, *tp, c; int x, count = 0; if (!path) path = ""; if (!*path) return(-1); #ifdef CKROOT debug(F111,"zmkdir setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(path)) { debug(F110,"zmkdir setroot violation",path,0); return(-1); } #endif /* CKROOT */ x = strlen(path); debug(F111,"zmkdir",path,x); if (x < 1 || x > MAXPATH) /* Check length */ return(-1); if (!(tp = malloc(x+1))) /* Make a temporary copy */ return(-1); strcpy(tp,path); /* safe (prechecked) */ #ifdef DTILDE if (*tp == '~') { /* Starts with tilde? */ xp = tilde_expand(tp); /* Attempt to expand tilde */ if (!xp) xp = ""; if (*xp) { char *zp; debug(F110,"zmkdir tilde_expand",xp,0); if (!(zp = malloc(strlen(xp) + 1))) { /* Make a place for it */ free(tp); tp = NULL; return(-1); } free(tp); /* Free previous buffer */ tp = zp; /* Point to new one */ strcpy(tp,xp); /* Copy expanded name to new buffer */ } } #endif /* DTILDE */ debug(F110,"zmkdir tp after tilde_expansion",tp,0); xp = tp; if (ISDIRSEP(*xp)) /* Don't create root directory! */ xp++; /* Go thru filespec from left to right... */ for (; *xp; xp++) { /* Create parts that don't exist */ if (!ISDIRSEP(*xp)) /* Find next directory separator */ continue; c = *xp; /* Got one. */ *xp = NUL; /* Make this the end of the string. */ if (!isdir(tp)) { /* This directory exists already? */ #ifdef CK_LOGIN if (isguest) /* Not allowed for guests */ return(-1); #ifndef NOXFER /* Nor if MKDIR and/or CD are disabled */ else #endif /* CK_LOGIN */ if ((server #ifdef IKSD || inserver #endif /* IKSD */ ) && (!ENABLED(en_mkd) || !ENABLED(en_cwd))) return(-1); #endif /* IKSD */ debug(F110,"zmkdir making",tp,0); x = /* No, try to create it */ #ifdef NOMKDIR -1 /* Systems without mkdir() */ #else mkdir(tp,0777) /* UNIX */ #endif /* NOMKDIR */ ; if (x < 0) { debug(F101,"zmkdir failed, errno","",errno); free(tp); /* Free temporary buffer. */ tp = NULL; return(-1); /* Return failure code. */ } else count++; } *xp = c; /* Replace the separator. */ } free(tp); /* Free temporary buffer. */ return(count); /* Return success code. */ } #endif /* CK_MKDIR */ int #ifdef CK_ANSIC zrmdir( char *path ) #else zrmdir(path) char *path; #endif /* CK_ANSIC */ { #ifdef CK_LOGIN if (isguest) return(-1); #endif /* CK_LOGIN */ if (!path) path = ""; if (!*path) return(-1); #ifdef CKROOT debug(F111,"zrmdir setroot",ckroot,ckrootset); if (ckrootset) if (!zinroot(path)) { debug(F110,"zrmdir setroot violation",path,0); return(-1); } #endif /* CKROOT */ #ifndef NOMKDIR return(rmdir(path)); #else return(-1); #endif /* NOMKDIR */ } /* Z F S E E K -- Position input file pointer */ /* Call with: CK_OFF_T (32 or 64 bits), 0-based, indicating desired position. Returns: 0 on success. -1 on failure. */ #ifndef NORESEND int #ifdef CK_ANSIC zfseek(CK_OFF_T pos) #else zfseek(pos) CK_OFF_T pos; #endif /* CK_ANSIC */ /* zfseek */ { zincnt = -1; /* Must empty the input buffer */ debug(F101,"zfseek","",pos); return(CKFSEEK(fp[ZIFILE], pos, 0)?-1:0); } #endif /* NORESEND */ /* Z F N Q F P -- Convert filename to fully qualified absolute pathname */ /* Given a possibly unqualified or relative file specification fn, zfnqfp() returns the fully qualified filespec for the same file, returning a struct that contains the length (len) of the result, a pointer (fpath) to the whole result, and a pointer (fname) to where the filename starts. Hint: how to get just the directory path, without the filename, into buf[]: fp = zfnqfp(filename,CKMAXPAX,buf); if (fp) buf[fp->fname - fp->fpath] = '\0'; */ static struct zfnfp fnfp = { 0, NULL, NULL }; struct zfnfp * #ifdef CK_ANSIC zfnqfp( char * fname, int buflen, char * buf ) #else zfnqfp(fname, buflen, buf) char * fname; int buflen; char * buf; #endif /* CK_ANSIC */ { char * s; int len; #ifdef MAXPATHLEN char zfntmp[MAXPATHLEN+4]; #else char zfntmp[CKMAXPATH+4]; #endif /* MAXPATHLEN */ char sb[32], * tmp; int i = 0, j = 0, k = 0, x = 0, y = 0; int itsadir = 0; s = fname; if (!s) return(NULL); if (!*s) return(NULL); if (!buf) return(NULL); /* Initialize the data structure */ fnfp.len = ckstrncpy(buf,fname,buflen); fnfp.fpath = buf; fnfp.fname = NULL; len = buflen; debug(F111,"zfnqfp fname",fname,len); #ifdef DTILDE if (*s == '~') { /* Starts with tilde? */ char * xp; xp = tilde_expand(s); /* Attempt to expand tilde */ debug(F110,"zfnqfp xp",xp,0); /* (realpath() doesn't do this) */ if (!xp) xp = ""; if (*xp) s = xp; } #endif /* DTILDE */ #ifdef CKREALPATH /* N.B.: The realpath() result buffer MUST be MAXPATHLEN bytes long */ /* otherwise we write over memory. */ if (!realpath(s,zfntmp)) { debug(F111,"zfnqfp realpath fails",s,errno); #ifdef COMMENT if (errno != ENOENT) return(NULL); #else /* If realpath() fails use the do-it-yourself method */ /* 16 Jan 2002 */ goto norealpath; #endif /* COMMENT */ } len = strlen(zfntmp); if (len > buflen) { debug(F111,"zfnqfp result too long",ckitoa(buflen),len); return(NULL); } else { ckstrncpy(buf,zfntmp,buflen); } if (buf[len-1] != '/') { if ((itsadir = isdir(buf)) && len < (buflen - 1)) { buf[len++] = '/'; buf[len] = NUL; } } fnfp.len = len; fnfp.fpath = buf; debug(F110,"zfnqfp realpath path",fnfp.fpath,0); tmp = buf + fnfp.len - 1; if (!itsadir) { while (tmp >= buf) { if (*tmp == '/') { fnfp.fname = tmp + 1; debug(F110,"zfnqfp realpath name",fnfp.fname,0); break; } tmp--; } } return(&fnfp); #endif /* CKREALPATH */ norealpath: tmp = zfntmp; while (*s) { /* Remove leading "./" (0 or more) */ debug(F110,"zfnqfp while *s",s,0); if (*s == '.' && *(s+1) == '/') { s += 2; while (*s == '/') s++; } else break; } if (!*s) return(NULL); if (*s == '/') { /* Pathname is absolute */ ckstrncpy(buf,s,len); x = strlen(buf); y = 0; } else { /* Pathname is relative */ char * p; if ((p = zgtdir())) { /* So get current directory */ debug(F110,"zfnqfp zgtdir",p,0); x = ckstrncpy(buf,p,len); buf[x++] = '/'; debug(F110,"zfnqfp buf 1",buf,0); len -= x; /* How much room left in buffer */ if ((y = (int)strlen(s)) > len) /* If enough room... */ return(NULL); ckstrncpy(buf+x,s,len); /* ... append the filename */ debug(F110,"zfnqfp buf 2",buf,0); } else { return(NULL); } } /* Buf now holds full path but maybe containing some . or .. tricks */ j = x + y; /* Length of what's in buf */ len = j; debug(F101,"zfnqfp len","",len); /* Catch dangling "/." or "/.." */ if ((j > 1 && buf[j-1] == '.' && buf[j-2] == '/') || (j > 2 && buf[j-1] == '.' && buf[j-2] == '.' && buf[j-3] == '/')) { if (j < buflen - 2) { buf[j] = '/'; buf[j+1] = NUL; } } j = -1; /* j = position of rightmost "/" */ i = 0; /* i = destination index */ tmp[i] = NUL; /* destination is temporary buffer */ for (x = 0; x < len; x++) { /* x = source index */ if (buf[x] == '/') { for (k = 0; k < 4; k++) { sb[k] = buf[x+k]; sb[k+1] = '\0'; if (!sb[k]) break; } if (!strncmp(sb,"/./",3)) { /* Eliminate "./" in "/./" */ x += 1; continue; } else if (!strncmp(sb,"//",2)) { /* Change "//" to "/" */ continue; } else if (!strncmp(sb,"/../",4)) { /* ".." in path */ for (k = i - 1; k >= 0; k--) { /* Back up one level */ if (tmp[k] == '/') { i = k; tmp[i] = NUL; break; } } x += 2; continue; } } if (i >= (buflen - 1)) { debug(F111,"zfnqfp overflow",tmp,i); return(NULL); } tmp[i++] = buf[x]; /* Regular character, copy */ tmp[i] = NUL; if (buf[x] == '/') /* Remember rightmost "/" */ j = i; } ckstrncpy(buf,tmp,buflen-1); /* Copy the result back */ buf[buflen-1] = NUL; if (!buf[0]) { /* If empty, say root */ buf[0] = '/'; buf[2] = NUL; j = 0; i = 1; } if ((itsadir = isdir(buf))) { if (buf[i-1] != '/' && i < (buflen - 1)) { buf[i++] = '/'; buf[i] = NUL; } } if (!itsadir && (j > -1)) { /* Set pointer to basename */ fnfp.fname = (char *)(buf + j); fnfp.fpath = (char *)buf; fnfp.len = i; debug(F111,"zfnqfp path",fnfp.fpath,i); debug(F110,"zfnqfp name",fnfp.fname,0); return(&fnfp); } return(NULL); } /* Z C M P F N -- Compare two filenames */ /* Returns 1 if the two names refer to the same existing file, 0 otherwise. */ int #ifdef CK_ANSIC zcmpfn( char * s1, char * s2 ) #else zcmpfn(s1,s2) char * s1, * s2; #endif /* CK_ANSIC */ { char buf1[CKMAXPATH+1]; char buf2[CKMAXPATH+1]; #ifdef USE_LSTAT char linkname[CKMAXPATH+1]; struct stat buf; #endif /* USE_LSTAT */ int x, rc = 0; if (!s1) s1 = ""; if (!s2) s2 = ""; if (!*s1 || !*s2) return(0); #ifdef CKSYMLINK /* We're doing symlinks? */ #ifdef USE_LSTAT /* OK to use lstat()? */ x = lstat(s1,&buf); if (x > -1 && /* Now see if it's a symlink */ #ifdef S_ISLNK S_ISLNK(buf.st_mode) #else #ifdef _IFLNK ((_IFMT & buf.st_mode) == _IFLNK) #endif /* _IFLNK */ #endif /* S_ISLNK */ ) { linkname[0] = '\0'; /* Get the name */ x = readlink(s1,linkname,CKMAXPATH); if (x > -1 && x < CKMAXPATH) { /* It's a link */ linkname[x] = '\0'; s1 = linkname; } } #endif /* USE_LSTAT */ #endif /* CKSYMLINK */ if (zfnqfp(s1,CKMAXPATH,buf1)) { /* Convert to full pathname */ #ifdef CKSYMLINK /* Same deal for second name... */ #ifdef USE_LSTAT x = lstat(s2,&buf); if (x > -1 && #ifdef S_ISLNK S_ISLNK(buf.st_mode) #else #ifdef _IFLNK ((_IFMT & buf.st_mode) == _IFLNK) #endif /* _IFLNK */ #endif /* S_ISLNK */ ) { linkname[0] = '\0'; x = readlink(s2,linkname,CKMAXPATH); if (x > -1 && x < CKMAXPATH) { linkname[x] = '\0'; s2 = linkname; } } #endif /* USE_LSTAT */ #endif /* CKSYMLINK */ if (zfnqfp(s2,CKMAXPATH,buf2)) { debug(F110,"zcmpfn s1",buf1,0); debug(F110,"zcmpfn s2",buf2,0); if (!strncmp(buf1,buf2,CKMAXPATH)) rc = 1; } } debug(F101,"zcmpfn result","",rc); return(rc); } #ifdef CKROOT /* User-mode chroot() implementation */ int #ifdef CK_ANSIC zsetroot( char * s ) /* Sets the root */ #else zsetroot(s) char * s; #endif /* CK_ANSIC */ { char buf[CKMAXPATH+1]; if (!s) return(-1); if (!*s) return(-1); debug(F110,"zsetroot",s,0); if (!isdir(s)) return(-2); if (!zfnqfp(s,CKMAXPATH,buf)) /* Get full, real path */ return(-3); if (access(buf,R_OK) < 0) { /* Check access */ debug(F110,"zsetroot access denied",buf,0); return(-4); } s = buf; if (ckrootset) { /* If root already set */ if (!zinroot(s)) { /* make sure new root is in it */ debug(F110,"zsetroot new root not in root",ckroot,0); return(-5); } } if (zchdir(buf) < 1) return(-4); /* Change directory to new root */ ckrootset = ckstrncpy(ckroot,buf,CKMAXPATH); /* Now set the new root */ if (ckroot[ckrootset-1] != '/') { ckroot[ckrootset++] = '/'; ckroot[ckrootset] = '\0'; } debug(F111,"zsetroot rootset",ckroot,ckrootset); ckrooterr = 0; /* Reset error flag */ return(1); } char * #ifdef CK_ANSIC zgetroot( void ) /* Returns the root */ #else zgetroot() #endif /* CK_ANSIC */ { if (!ckrootset) return(NULL); return((char *)ckroot); } int #ifdef CK_ANSIC zinroot( char * s ) /* Checks if file s is in the root */ #else zinroot(s) char * s; #endif /* CK_ANSIC */ { int x, n; struct zfnfp * f = NULL; char buf[CKMAXPATH+2]; debug(F111,"zinroot setroot",ckroot,ckrootset); ckrooterr = 0; /* Reset global error flag */ if (!ckrootset) /* Root not set */ return(1); /* so it's ok - no need to check */ if (!(f = zfnqfp(s,CKMAXPATH,buf))) /* Get full and real pathname */ return(0); /* Fail if we can't */ n = f->len; /* Length of full pathname */ debug(F111,"zinroot n",buf,n); if (n < (ckrootset - 1) || n > CKMAXPATH) { /* Bad length */ ckrooterr = 1; /* Fail */ return(0); } if (isdir(buf) && buf[n-1] != '/') { /* If it's a directory name */ buf[n++] = '/'; /* make sure it ends with '/' */ buf[n] = '\0'; } x = strncmp(buf,ckroot,ckrootset); /* Compare, case-sensitive */ debug(F111,"zinroot checked",buf,x); if (x == 0) /* OK */ return(1); ckrooterr = 1; /* Not OK */ return(0); } #endif /* CKROOT */ #ifdef CK_LOGIN /* The following code provides support for user login and logout including anonymous accounts. If this feature is to be supported outside of UNIX, it should be spread out among the ck?fio.c modules... */ #ifndef _PATH_BSHELL #define _PATH_BSHELL "/usr/bin/bash" #endif /* _PATH_BSHELL */ #ifndef _PATH_FTPUSERS #define _PATH_FTPUSERS "/etc/ftpusers" #endif /* _PATH_FTPUSERS */ /* * Helper function for sgetpwnam(). */ char * #ifdef CK_ANSIC sgetsave( char *s ) #else sgetsave(s) char *s; #endif /* CK_ANSIC */ { char *new = malloc((unsigned) strlen(s) + 1); if (new == NULL) { printf("?Local resource failure: malloc\n"); exit(1); /* NOTREACHED */ } (void) strcpy(new, s); /* safe */ return (new); } /* * Save the result of getpwnam(). Used for USER command, since * the data returned must not be clobbered by any other command * (e.g., globbing). */ struct passwd * #ifdef CK_ANSIC sgetpwnam( char *name ) #else sgetpwnam(name) char *name; #endif /* CK_ANSIC */ { static struct passwd save; register struct passwd *p; #ifdef CK_SHADOW register struct spwd *sp; #endif /* CK_SHADOW */ #ifdef HPUX10_TRUSTED struct pr_passwd *pr; #endif /* HPUX10_TRUSTED */ #ifdef CK_SHADOW sp = getspnam(name); if (sp == NULL) { debug(F110,"sgetpwnam","getspnam() fails",0); return (NULL); } #endif /* CK_SHADOW */ #ifdef HPUX10_TRUSTED if ((pr = getprpwnam(name)) == NULL) return(NULL); #endif /* HPUX10_TRUSTED */ p = getpwnam(name); /* debug(F111,"sgetpwnam","getpwnam()",p); */ if (p == NULL) return(NULL); if (save.pw_name) { free(save.pw_name); free(save.pw_passwd); #ifndef ANDROID free(save.pw_gecos); #endif free(save.pw_dir); free(save.pw_shell); } save = *p; save.pw_name = sgetsave(p->pw_name); #ifdef CK_SHADOW save.pw_passwd = sgetsave(sp->sp_pwdp); #else /* CK_SHADOW */ #ifdef HPUX10_TRUSTED if (pr->uflg.fg_encrypt && pr->ufld.fd_encrypt && *pr->ufld.fd_encrypt) save.pw_passwd = sgetsave(pr->ufld.fd_encrypt); else save.pw_passwd = sgetsave(""); #else /* HPUX10_TRUSTED */ save.pw_passwd = sgetsave(p->pw_passwd); #endif /* HPUX10_TRUSTED */ #endif /* CK_SHADOW */ #ifndef ANDROID save.pw_gecos = sgetsave(p->pw_gecos); #endif /* ANDROID */ save.pw_dir = sgetsave(p->pw_dir); save.pw_shell = sgetsave(p->pw_shell); return(&save); } #define CKXLOGBSIZ 256 struct passwd * pw = NULL; char * home = NULL; /* Home directory pointer for glob */ #ifdef CMASK #undef CMASK #endif /* CMASK */ #define CMASK 027 int defumask = CMASK; /* Default umask value */ /* Z V U S E R -- Verify user, Returns 1 if user OK, 0 otherwise. */ /* Sets global passwd pointer pw if named account exists and is acceptable; * sets askpasswd if a PASS command is expected. If logged in previously, * need to reset state. If name is "ftp" or "anonymous", the name is not in * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. * If account doesn't exist, ask for passwd anyway. Otherwise, check user * requesting login privileges. Disallow anyone who does not have a standard * shell as returned by getusershell(). Disallow anyone mentioned in the file * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. */ _PROTOTYP(static int checkuser, (char *) ); char zvuname[64] = { NUL, NUL }; char zvhome[CKMAXPATH+1] = { NUL, NUL }; #define ZENVUSER 70 #define ZENVHOME CKMAXPATH+12 #define ZENVLOGNAME 74 static char zenvuser[ZENVUSER]; static char zenvhome[ZENVHOME]; static char zenvlogname[ZENVLOGNAME]; #ifdef CK_PAM static char pam_data[500]; struct pam_conv pam_conv = {pam_cb, pam_data}; /* PAM structure */ struct pam_handle * pamh = NULL; /* PAM reference handle */ #endif /* CK_PAM */ int #ifdef CK_ANSIC zvuser( char *name ) #else zvuser(name) char *name; #endif /* CK_ANSIC */ { register char *cp = NULL; int x; char *shell; #ifdef GETUSERSHELL _PROTOTYP(char * getusershell, (void) ); #endif /* GETUSERSHELL */ #ifndef NODCLENDUSERSHELL _PROTOTYP(VOID endusershell, (void) ); #endif /* NODCLENDUSERSHELL */ #ifdef CK_PAM int pam_status; const char * reply = NULL; #endif /* CK_PAM */ debug(F111,"user",name,logged_in); if (!name) name = ""; zvuname[0] = NUL; debug(F101,"zvuser ckxsyslog","",ckxsyslog); #ifdef CKSYSLOG debug(F100,"zvuser CKSYSLOG defined","",0); #endif /* CKSYSLOG */ if (logged_in) /* Should not be called if logged in */ return(0); #ifdef CKSYSLOG if (ckxsyslog && ckxlogging) { syslog(LOG_INFO, "login: user %s",name ); } #endif /* CKSYSLOG */ guest = 0; /* Assume not guest */ askpasswd = 0; if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { debug(F101,"zvuser anonymous ckxanon","",ckxanon); if (!ckxanon) { /* Anonymous login not allowed */ #ifdef CKSYSLOG if (ckxsyslog && ckxlogging) { syslog(LOG_INFO, "login: anonymous login not allowed: %s", clienthost ? clienthost : "(unknown host)" ); } #endif /* CKSYSLOG */ return(0); } if (checkuser("ftp") || checkuser("anonymous")) { debug(F100,"zvuser anon forbidden by ftpusers file","",0); #ifdef CKSYSLOG if (ckxsyslog && ckxlogging) { syslog(LOG_INFO, "login: anonymous login forbidden by ftpusers file: %s", clienthost ? clienthost : "(unknown host)" ); } #endif /* CKSYSLOG */ return(0); } else if ((pw = sgetpwnam("ftp")) != NULL) { debug(F100,"zvuser anon sgetpwnam(ftp) OK","",0); guest = 1; askpasswd = 1; ckstrncpy(zvuname,"anonymous",64); return(1); } else { debug(F100,"zvuser anon sgetpwnam(ftp) FAILED","",0); #ifdef CKSYSLOG if (ckxsyslog && ckxlogging) { syslog(LOG_INFO, "login: anonymous getpwnam(ftp) failed: %s", clienthost ? clienthost : "(unknown host)" ); } #endif /* CKSYSLOG */ return(0); } } pw = sgetpwnam(name); if (pw) { /* Of course some UNIX platforms (like AIX) don't have getusershell(). In that case we can't check if the user's account has been "turned off" or somesuch, e.g. by setting their shell to "/etc/nologin" or somesuch, which runs (usually just printing a message and exiting), but which is not listed in /etc/shells. For that matter, if getusershell() is not available, then probably neither is /etc/shells. */ debug(F100,"zvuser sgetpwnam ok","",0); shell = pw->pw_shell; if (!shell) shell = ""; if (!*shell) shell = _PATH_BSHELL; debug(F110,"zvuser shell",shell,0); #ifdef GETUSERSHELL while ((cp = getusershell()) != NULL) { debug(F110,"zvuser getusershell",cp,0); if ((int)strcmp(cp, shell) == 0) break; } debug(F100,"zvuser endusershell 1","",0); #ifndef NODCLENDUSERSHELL (VOID) endusershell(); #else endusershell(); #endif /* NODCLENDUSERSHELL */ debug(F100,"zvuser endusershell 2","",0); #else /* GETUSERSHELL */ cp = ""; /* Do not refuse if we cannot check */ #endif /* GETUSERSHELL */ x = checkuser(name); debug(F101,"zvuser checkuser","",x); if (cp == NULL) { debug(F100,"zvuser refused 1","",0); pw = (struct passwd *) NULL; #ifdef CKSYSLOG if (ckxsyslog && ckxlogging) { syslog(LOG_INFO, "login: invalid shell %s for %s %s",shell, name, clienthost ? clienthost : "(unknown host)" ); } #endif /* CKSYSLOG */ return(0); } else if (x) { debug(F100,"zvuser refused 2","",0); pw = (struct passwd *) NULL; #ifdef CKSYSLOG if (ckxsyslog && ckxlogging) { syslog(LOG_INFO, "login: %s login forbidden by ftpusers file: %s", name, clienthost ? clienthost : "(unknown host)" ); } #endif /* CKSYSLOG */ return(0); } else { x = 0; #ifdef CK_PAM /* Get PAM authentication details */ debug(F110,"zvuser","calling pam_start",0); if ((pam_status = pam_start(PAM_SERVICE_TYPE,name,&pam_conv,&pamh)) != PAM_SUCCESS) { reply = pam_strerror(NULL, pam_status); debug(F110,"zvuser PAM failure",reply,0); printf("%s\n",reply); #ifdef CKSYSLOG if (ckxsyslog && ckxlogging) { syslog(LOG_INFO, "login: %s refused by PAM \"%s\": %s", name,reply, clienthost ? clienthost : "(unknown host)" ); } #endif /* CKSYSLOG */ return(0); } #endif /* CK_PAM */ askpasswd = 1; ckstrncpy(zvuname,name,64); return(1); } } else { x = 0; debug(F100,"zvuser sgetpwnam NULL","",0); #ifdef CKSYSLOG if (ckxsyslog && ckxlogging) { syslog(LOG_INFO, "login: getpwnam(%s) failed: %s",name, clienthost ? clienthost : "(unknown host)" ); } #endif /* CKSYSLOG */ return(0); } #ifdef FTP_KERBEROS if (auth_type && strcmp(auth_type, "KERBEROS_V4") == 0) { #ifdef COMMENT /* Why sprintf and then printf? */ /* Also, what is kerb_ok? And is the test on it right? */ char buf[CKXLOGBSIZ]; sprintf(buf, "Kerberos user %s%s%s@%s is%s authorized as %s%s", kdata.pname, *kdata.pinst ? "." : "", kdata.pinst, kdata.prealm, (kerb_ok = kuserok(&kdata,name) == 0) ? "" : " not", name, kerb_ok ? "" : "; Password required."); printf("%s", buf); #else printf("Kerberos user %s%s%s@%s is%s authorized as %s%s", kdata.pname, *kdata.pinst ? "." : "", kdata.pinst, kdata.prealm, (kerb_ok = kuserok(&kdata,name) == 0) ? "" : " not", name, kerb_ok ? "" : "; Password required."); #endif /* COMMENT */ if (kerb_ok) return(1); } else return(0); #endif /* FTP_KERBEROS */ } /* Check if the given user is in the forbidden-user file */ static int #ifdef CK_ANSIC checkuser( char *name ) #else checkuser(name) char *name; #endif /* CK_ANSIC */ { extern char * userfile; FILE *fd; int i; char line[CKXLOGBSIZ+1]; if (!name) name = ""; i = strlen(name); debug(F111,"checkuser name",name,i); if (!*name) return(1); fd = fopen(userfile ? userfile : _PATH_FTPUSERS, "r"); /* debug(F111,"checkuser userfile",userfile,fd); */ if (fd) { line[0] = '\0'; while (fgets(line, sizeof(line), fd)) { debug(F110,"checkuser line",line,0); if (line[0] <= '#') continue; if (strncmp(line, name, i) == 0) { debug(F110,"checkuser REFUSED",name,0); return(1); } line[0] = '\0'; } (VOID) fclose(fd); } debug(F110,"checkuser OK",name,0); return(0); } /* Z V L O G O U T -- Log out from Internet Kermit Service */ VOID zvlogout() { #ifdef COMMENT /* This could be dangerous */ if (setuid((UID_T)0) < 0) { debug(F100,"zvlogout setuid FAILED","",0); goto bad; } debug(F100,"zvlogout setuid OK","",0); #endif /* COMMENT */ #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_LI && ckxlogging) { cksyslog(SYSLG_LI, 1, "logout",(char *) uidbuf, clienthost); } #endif /* CKSYSLOG */ #ifdef CKWTMP debug(F110,"WTMP logout",cksysline,logged_in); if (logged_in) logwtmp(cksysline, "", ""); #endif /* CKWTMP */ pw = NULL; logged_in = 0; guest = 0; isguest = 0; } #ifdef FTP_KERBEROS kpass(name, p) char *name, *p; { char instance[INST_SZ]; char realm[REALM_SZ]; char tkt_file[20]; KTEXT_ST ticket; AUTH_DAT authdata; unsigned long faddr; struct hostent *hp; if (krb_get_lrealm(realm, 1) != KSUCCESS) return(0); ckstrncpy(tkt_file, TKT_ROOT, 20); ckstrncat(tkt_file, "_ftpdXXXXXX", 20); krb_set_tkt_string(mktemp(tkt_file)); (VOID) ckstrncpy(instance, krb_get_phost(hostname), sizeof(instance)); if ((hp = gethostbyname(instance)) == NULL) return(0); #ifdef HADDRLIST hp = ck_copyhostent(hp); /* safe copy that won't change */ #endif /* HADDRLIST */ bcopy((char *)hp->h_addr, (char *) &faddr, sizeof(faddr)); if (krb_get_pw_in_tkt(name, "", realm, "krbtgt", realm, 1, p) || krb_mk_req(&ticket, "rcmd", instance, realm, 33) || krb_rd_req(&ticket, "rcmd", instance, faddr, &authdata, "") || kuserok(&authdata, name)) { dest_tkt(); return(0); } dest_tkt(); return(1); } #endif /* FTP_KERBEROS */ VOID zsyslog() { #ifdef CKSYSLOG if (ckxsyslog && !ckxlogging) { #ifdef LOG_DAEMON openlog(inserver ? "iksd" : "ckermit", LOG_PID, LOG_DAEMON); #else openlog(inserver ? "iksd" : "ckermit", LOG_PID); #endif /* LOG_DAEMON */ ckxlogging = 1; debug(F100,"zsyslog syslog opened","",0); } #endif /* CKSYSLOG */ } /* Z V P A S S -- Verify password; returns 1 if OK, 0 otherwise */ #ifndef AUTH_USER #define AUTH_USER 3 #endif /* AUTH_USER */ #ifndef AUTH_VALID #define AUTH_VALID 4 #endif /* AUTH_VALID */ #ifdef __FreeBSD__ /* 299 This was necessary in */ #ifndef NODCLINITGROUPS /* FreeBSD 4.4, don't know */ #define NODCLINITGROUPS /* about other versions... */ #endif /* NODCLINITGROUPS */ #endif /* __FreeBSD__ */ int #ifdef CK_ANSIC #else #endif /* CK_ANSIC */ #ifdef CK_ANSIC zvpass( char *p ) #else zvpass(p) char *p; #endif /* CK_ANSIC */ { #ifndef NODCLINITGROUPS _PROTOTYP(int initgroups, (const char *, gid_t) ); #endif /* NODCLINITGROUPS */ char *xpasswd, *salt; char * dir = NULL; #ifdef CK_PAM int pam_status; const char * reply = NULL; #endif /* CK_PAM */ int dummy; if (logged_in || askpasswd == 0) { return(0); } debug(F111,"zvpass",p ? (guest ? p : "xxxxxx") : "(null)",guest); if (!p) p = ""; askpasswd = 0; if (guest && !*p) { /* Guests must specify a password */ #ifdef CKSYSLOG if (ckxsyslog && ckxlogging) { syslog(LOG_INFO, "login: anonymous guests must specify a password" ); } #endif /* CKSYSLOG */ return(0); } if (!guest #ifdef CK_AUTHENTICATION && ck_tn_auth_valid() != AUTH_VALID #endif /* CK_AUTHENTICATION */ ) { /* "ftp" is only account allowed no password */ #ifdef CK_PAM debug(F110,"zvpass","calling pam_set_item(AUTHTOK)",0); if ((pam_status = pam_set_item(pamh,PAM_AUTHTOK,p)) != PAM_SUCCESS) { reply = pam_strerror(pamh, pam_status); debug(F110,"zvpass PAM failure",reply,0); /* if no password given treat as non-fatal error */ /* pam will prompt for password in pam_authenticate() */ if (!p) { printf("%s\n",reply); pam_end(pamh, 0); debug(F100,"zvpass denied","",0); pw = NULL; zvuname[0] = NUL; return(0); } } debug(F110,"zvpass","calling pam_authenticate",0); #ifdef COMMENT if (*p) pam_pw = p; #else /* Make IKSD authentication (using PAM) ask for a password when an invalid username has been given, to avoid disclosing which account names are valid. See #417247 (Debian). */ if (*p #ifdef CK_LOGIN || gotemptypasswd #endif /* CK_LOGIN */ ) pam_pw = p; #endif /* COMMENT */ if ((pam_status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) { reply = pam_strerror(pamh, pam_status); debug(F110,"zvpass PAM failure",reply,0); printf("%s\n",reply); pam_end(pamh, 0); debug(F100,"zvpass denied","",0); pam_pw = NULL; pw = NULL; zvuname[0] = NUL; return(0); } pam_pw = NULL; debug(F110,"zvpass","calling pam_acct_mgmt",0); if ((pam_status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) { reply = pam_strerror(pamh, pam_status); debug(F110,"zvpass PAM failure",reply,0); printf("%s\n",reply); pam_end(pamh, 0); debug(F100,"zvpass denied","",0); pw = NULL; zvuname[0] = NUL; return(0); } debug(F110,"zvpass","PAM validates OK",0); pam_end(pamh,0); #else /* CK_PAM */ if (pw == NULL) salt = "xx"; else salt = pw->pw_passwd; #ifdef HPUX10_TRUSTED xpasswd = bigcrypt(p, salt); #else /* On 64-bit platforms this can give "cast to pointer from integer of different size" warning, but I'm not sure what the effect is at runtime, or what to do about it. */ xpasswd = (char *)crypt(p, salt); #endif /* HPUX10_TRUSTED */ if ( #ifdef FTP_KERBEROS /* null pw_passwd ok if Kerberos password ok */ pw == NULL || ((*pw->pw_passwd != '\0' || strcmp(xpasswd, pw->pw_passwd)) && !kpass(pw->pw_name, p)) #else #ifdef CK_SRP /* check with tpasswd first if there */ pw == NULL || *pw->pw_passwd == '\0' || t_verifypw (pw->pw_name, p) == 0 || (t_verifypw (pw->pw_name, p) < 0 && strcmp (xpasswd, pw->pw_passwd)) #else /* CK_SRP */ /* The strcmp does not catch null passwords! */ (pw == NULL) || (*pw->pw_passwd == '\0') || strcmp(xpasswd, pw->pw_passwd) #endif /* CK_SRP */ #endif /* FTP_KERBEROS */ ) { debug(F100,"zvpass denied","",0); pw = NULL; zvuname[0] = NUL; return(0); } #endif /* CK_PAM */ } dummy = setgid((GID_T)pw->pw_gid); /* Set group ID */ #ifndef NOINITGROUPS dummy = initgroups(pw->pw_name, pw->pw_gid); #endif /* NOINITGROUPS */ logged_in = 1; dir = pw->pw_dir; #ifdef CKWTMP /* Open wtmp before chroot */ if (ckxwtmp) { sprintf(cksysline,"iks_%04x", getpid()); /* safe */ logwtmp(cksysline, pw->pw_name, clienthost ? clienthost : "(unknown host)" ); debug(F110,"WTMP login",cksysline,logged_in); } #endif /* CKWTMP */ /* For anonymous users, we chroot to user ftp's home directory unless started with --anonroot:xxx, in which case we chroot to xxx. We must immediately chdir() to the same directory we chroot() to or else the old current directory remains accessible as "." outside the new root. */ if (guest) { if (anonroot) /* Non-default anonymous root */ dir = anonroot; else makestr(&anonroot,dir); errno = 0; debug(F110,"zvpass anon chroot",dir,0); if (chroot(dir) < 0) { debug(F111,"zvpass anon chroot FAILED",dir,errno); goto bad; } errno = 0; if (chdir("/") < 0) { debug(F111,"zvpass anon chdir FAILED",dir,errno); goto bad; } debug(F110,"zvpass anon chroot/chdir OK",dir,0); } else if (chdir(dir) < 0) { /* Not guest */ #ifdef COMMENT if (chdir("/") < 0) { debug(F110,"Non-guest chdir FAILED",dir,0); goto bad; } else printf("?No directory! Logging in with home=/\n"); #else debug(F110,"zvpass non-guest chdir FAILED",dir,0); goto bad; /* Be conservative at first */ #endif /* COMMENT */ } debug(F110,"zvpass non-guest chdir OK",dir,0); if (setuid((UID_T)pw->pw_uid) < 0) { debug(F101,"zvpass setuid FAILED","",pw->pw_uid); goto bad; } debug(F101,"zvpass setuid OK","",pw->pw_uid); guestpass[0] = '\0'; if (guest) { extern int fncact; isguest = 1; fncact = XYFX_R; /* FILE COLLISION = RENAME */ debug(F110,"GUEST fncact=R",p,0); lset(guestpass,"anonymous:",10,32); ckstrncpy(&guestpass[10],p,GUESTPASS-10); home = "/"; printf("Anonymous login.\r\n"); #ifdef SETPROCTITLE /* proctitle declared where? Obviously this code is never compiled. */ sprintf(proctitle, "%s: anonymous/%.*s", clienthost ? clienthost : "(unk)", sizeof(proctitle) - sizeof(clienthost) - sizeof(": anonymous/"), p); setproctitle(proctitle); #endif /* SETPROCTITLE */ #ifdef CKSYSLOG if (ckxsyslog && ckxlogging) { syslog(LOG_INFO, "login: anonymous %s %s", clienthost ? clienthost : "(unknown host)", p ); } #endif /* CKSYSLOG */ } else { /* Real user */ isguest = 0; home = dir; ckstrncpy(guestpass,zvuname,GUESTPASS); printf("User %s logged in.\r\n", pw->pw_name); #ifdef SETPROCTITLE /* not used */ sprintf(proctitle, "%s: %s", clienthost ? clienthost : "(unk)", pw->pw_name ); setproctitle(proctitle); #endif /* SETPROCTITLE */ #ifdef CKSYSLOG if (ckxsyslog && ckxlogging) syslog(LOG_INFO, "login: %s %s", pw->pw_name, clienthost ? clienthost : "(unknown host)" ); #endif /* CKSYSLOG */ } ckstrncpy(zvhome,home,CKMAXPATH); /* Set environment variables */ #ifndef NOPUTENV ckmakmsg(zenvuser,ZENVUSER,"USER=",zvuname,NULL,NULL); putenv((char *)zenvuser); ckmakmsg(zenvlogname,ZENVLOGNAME,"LOGNAME=",zvuname,NULL,NULL); putenv((char *)zenvlogname); ckmakmsg(zenvhome,ZENVHOME,"HOME=",zvhome,NULL,NULL); putenv((char *)zenvhome); #endif /* NOPUTENV */ /* homdir = (char *)zvhome; */ ckstrncpy((char *)uidbuf,(char *)zvuname,64); (VOID) umask(defumask); #ifdef IKSDB if (ikdbopen) { char * p2; int k; extern char dbrec[]; extern unsigned long myflags; extern unsigned int mydbslot; extern struct iksdbfld dbfld[]; #ifdef CK_AUTHENTICATION extern unsigned long myamode, myatype; #endif /* CK_AUTHENTICATION */ myflags |= DBF_LOGGED; #ifdef DEBUG if (deblog) { debug(F101,"zvpass guest","",guest); debug(F111,"zvpass zvuname",zvuname,0); debug(F110,"zvpass guestpass",guestpass,0); debug(F110,"zvpass dir",dir,0); debug(F110,"zvpass home",home,0); debug(F110,"zvpass anonroot",anonroot,0); } #endif /* DEBUG */ p2 = guest ? guestpass : zvuname; if (guest) { p2 = (char *)guestpass; myflags &= ~DBF_USER; } else { p2 = (char *)zvuname; myflags |= DBF_USER; } k = strlen(p2); strncpy(&dbrec[DB_ULEN],ulongtohex((unsigned long)k,4),4); lset(&dbrec[dbfld[db_USER].off],p2,1024,32); strncpy(&dbrec[DB_FLAGS],ulongtohex(myflags,4),4); #ifdef CK_AUTHENTICATION myamode = ck_tn_auth_valid(); strncpy(&dbrec[DB_AMODE],ulongtohex(myamode,4),4); myatype = ck_tn_authenticated(); strncpy(&dbrec[DB_ATYPE],ulongtohex(myatype,4),4); #endif /* CK_AUTHENTICATION */ if (guest) { p2 = dir; } else { p2 = zgtdir(); if (!p2) p2 = ""; if (!*p2) p2 = home; } strncpy(&dbrec[DB_DLEN], ulongtohex((unsigned long)strlen(p2),4), 4 ); lset(&dbrec[dbfld[db_DIR].off],p2,1024,32); updslot(mydbslot); } #endif /* IKSDB */ return(1); bad: /* Common failure exit */ zvuname[0] = NUL; zvlogout(); return(0); } #endif /* CK_LOGIN */ /* Buggy Xenix 2.3.4 cc needs this line after the endif */ ckupty.c000664 045065 024037 00000145126 14767402101 012661 0ustar00fdckermit000000 000000 char *ckptyv = "Pseudoterminal support, 10.0.107, 16 Apr 2023"; /* C K U P T Y -- C-Kermit pseudoterminal control functions for UNIX */ /* Last update: Sun Apr 16 13:28:14 2023 */ /* Copyright 1995 by the Massachusetts Institute of Technology. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of M.I.T. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. Furthermore if you modify this software you must label your software as modified software and not distribute it in such a fashion that it might be confused with the original M.I.T. software. M.I.T. makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. Modified for use in C-Kermit, and new material added, by: Jeffrey Altman Secure Endpoints Inc., New York City November 1999 Parameterized for pty file descriptor and function code, Dec 2006 - Sep 2009, plus some minor "compliance" nits addressed in 2020. See "HAVE_OPENPTY" section of ckcdeb.h. Frank da Cruz, The Kermit Project, New York City */ /* Built and tested successully on: . 4.4BSD, including BSDI/OS, NetBSD, FreeBSD, OpenBSD, Mac OS X . AIX 4.1 and later . DG/UX 5.4R4.11 . Digital UNIX 3.2 and 4.0 . HP-UX 9.00 and later . IRIX 6.0 and later . Linux . Mac OS X 10.4 . NeXTSTEP 3.x . OpenBSD . QNX 4.25 (except PTY process termination not detected) . SCO OSR5.0.5 . SCO Unixware 7 . SINIX 5.42 . Solaris 2.x and 7 . SunOS 4.1.3 Failures include: . SCO UNIX 3.2v4.2 (compile fails with syntax error in ) . HP-UX 8.00 and earlier (no vhangup or ptsname routines) */ #ifndef NO_PTY_XOPEN_SOURCE #ifdef __FreeBSD__ /* bs 20151224 */ #define NO_PTY_XOPEN_SOURCE #endif /* __FreeBSD__ */ #endif /* NO_PTY_XOPEN_SOURCE */ #ifndef NO_PTY_XOPEN_SOURCE /* fdc 20211207 */ #define _XOPEN_SOURCE 500 /* mdw 20140223 */ #endif /* NO_PTY_XOPEN_SOURCE */ #include /* mdw 20140223 */ #include "ckcsym.h" #include "ckcdeb.h" /* To pick up NETPTY definition */ #ifndef NETPTY /* Selector for PTY support */ char * ptyver = "No PTY support"; #else /* (rest of this module...) */ char * ptyver = "PTY support 8.0.017, 18 Sep 2020"; /* These will no doubt need adjustment... */ #ifndef NEXT #define HAVE_SETSID #endif /* NEXT */ #define HAVE_KILLPG #define HAVE_TTYNAME #define HAVE_WAITPID #ifdef SUNOS41 #define BSD44ORPOSIX #endif /* SUNOS41 */ #ifndef USE_TERMIO #ifdef LINUX #define USE_TERMIO #else #ifdef ATTSV #define USE_TERMIO #else #ifdef HPUX #define USE_TERMIO #else #ifdef AIX #define USE_TERMIO #else #ifdef BSD44ORPOSIX #define USE_TERMIO #else #ifdef IRIX60 #define USE_TERMIO #else #ifdef QNX #define USE_TERMIO #endif /* QNX */ #endif /* IRIX60 */ #endif /* BSD44ORPOSIX */ #endif /* AIX */ #endif /* HPUX */ #endif /* ATTSV */ #endif /* LINUX */ #endif /* USE_TERMIO */ #ifdef QNX #include #endif /* QNX */ #ifdef USE_TERMIO #define POSIX_TERMIOS /* Seems to be a misnomer */ #endif /* USE_TERMIO */ #ifdef NEXT #ifndef GETPGRP_ONEARG #define GETPGRP_ONEARG #endif /* GETPGRP_ONEARG */ #endif /* NEXT */ #ifdef WANT_UTMP /* See ckupty.h */ /* WANT_UTMP is not defined because (a) the utmp/wtmp junk is the most nonportable part of this module, and (b) we're not logging anybody in, we're just running a process, and don't need to write utmp/wtmp records. */ #ifndef HAVE_SETUTXENT /* Who has */ #ifdef SOLARIS #define HAVE_SETUTXENT #else #ifdef IRIX60 #define HAVE_SETUTXENT #else #ifdef CK_SCOV5 #define HAVE_SETUTXENT #else #ifdef HPUX10 #define HAVE_SETUTXENT #else #ifdef UNIXWARE #define HAVE_SETUTXENT #else #ifdef IRIX60 #define HAVE_SETUTXENT #endif /* IRIX60 */ #endif /* UNIXWARE */ #endif /* HPUX10 */ #endif /* CK_SCOV5 */ #endif /* IRIX60 */ #endif /* SOLARIS */ #endif /* HAVE_SETUTXENT */ #ifndef HAVE_UTHOST /* Does utmp include ut_host[]? */ #ifdef HAVE_SETUTXENT /* utmpx always does */ #define HAVE_UTHOST #else #ifdef LINUX /* Linux does */ #define HAVE_UTHOST #else #ifdef SUNOS4 /* SunOS does */ #define HAVE_UTHOST #else #ifdef AIX41 /* AIX 4.1 and later do */ #define HAVE_UTHOST #endif /* AIX41 */ #endif /* SUNOS4 */ #endif /* LINUX */ #endif /* HAVE_SETUTXENT */ #endif /* HAVE_UTHOST */ #ifndef HAVE_UT_HOST #ifndef NO_UT_HOST #define NO_UT_HOST #endif /* NO_UT_HOST */ #endif /* HAVE_UT_HOST */ #endif /* WANT_UTMP */ #ifdef LINUX #define CK_VHANGUP #define HAVE_SYS_SELECT_H #define HAVE_GETUTENT #define HAVE_SETUTENT #define HAVE_UPDWTMP #endif /* LINUX */ #ifdef HPUX10 #define CK_VHANGUP #define VHANG_FIRST #define HAVE_PTSNAME #ifndef HAVE_PTYTRAP #define HAVE_PTYTRAP #endif /* HAVE_PTYTRAP */ #else #ifdef HPUX9 #define CK_VHANGUP #define VHANG_FIRST #define HAVE_PTSNAME #ifndef HAVE_PTYTRAP #define HAVE_PTYTRAP #endif /* HAVE_PTYTRAP */ #endif /* HPUX9 */ #endif /* HPUX10 */ #ifdef SUNOS4 #define CK_VHANGUP #define NO_UT_PID #define VHANG_FIRST #endif /* SUNOS4 */ #ifdef IRIX60 #define CK_VHANGUP #define HAVE__GETPTY #endif /* IRIX60 */ #ifdef SINIX #define HAVE_STREAMS #define HAVE_GRANTPT #define HAVE_PTSNAME #define PUSH_PTEM #define PUSH_LDTERM #define PUSH_TTCOMPAT #endif /* SINIX */ #ifdef ultrix #define MUST_SETPGRP #endif /* ultrix */ #ifdef QNX #define MUST_SETPGRP #define NO_DEVTTY #define INIT_SPTY #endif /* QNX */ #ifdef LINUX #ifdef HAVE_PTMX #define HAVE_GRANTPT #define HAVE_PTSNAME #endif /* HAVE_PTMX */ #else #ifdef HAVE_STREAMS #define HAVE_PTMX #endif /* HAVE_STREAMS */ #endif /* LINUX */ #include "ckupty.h" #ifdef PTYNOBLOCK #ifndef O_NDELAY #ifdef O_NONBLOCK #define O_NDELAY O_NONBLOCK #endif /* O_NONBLOCK */ #endif /* O_NDELAY */ #else /* PTYNOBLOCK */ #ifdef O_NDELAY #undef O_NDELAY #endif /* O_NDELAY */ #define O_NDELAY 0 #endif /* PTYNOBLOCK */ #ifndef ONLCR #define ONLCR 0 #endif /* ONLCR */ #ifdef CK_WAIT_H #include #endif /* CK_WAIT_H */ #ifdef STREAMSPTY #ifndef INIT_SPTY #define INIT_SPTY #endif /* INIT_SPTY */ #include #include #include /* Make sure we don't get the BSD version */ #ifdef HAVE_SYS_TTY_H #include "/usr/include/sys/tty.h" #endif /* HAVE_SYS_TTY_H */ #ifdef HAS_PTYVAR /* Where is this set? */ #include #else /* HAS_PTYVAR */ #ifndef TIOCPKT_FLUSHWRITE #define TIOCPKT_FLUSHWRITE 0x02 #define TIOCPKT_NOSTOP 0x10 #define TIOCPKT_DOSTOP 0x20 #define TIOCPKT_IOCTL 0x40 #endif /* TIOCPKT_FLUSHWRITE */ #endif /* HAS_PTYVAR */ #ifdef HAVE_TTY_H #include #endif /* HAVE_TTY_H */ #include "ckcfnp.h" /* Prototypes (must be last) */ /* Because of the way ptyibuf is used with streams messages, we need ptyibuf+1 to be on a full-word boundary. The following weirdness is simply to make that happen. */ long ptyibufbuf[BUFSIZ/sizeof(long)+1]; char *ptyibuf = ((char *)&ptyibufbuf[1])-1; char *ptyip = ((char *)&ptyibufbuf[1])-1; char ptyibuf2[BUFSIZ]; unsigned char ctlbuf[BUFSIZ]; struct strbuf strbufc, strbufd; int readstream(); #else /* ! STREAMSPTY */ /* I/O data buffers, pointers, and counters. */ char ptyibuf[BUFSIZ], *ptyip = ptyibuf; char ptyibuf2[BUFSIZ]; #endif /* ! STREAMSPTY */ #ifndef USE_TERMIO struct termbuf { struct sgttyb sg; struct tchars tc; struct ltchars ltc; int state; int lflags; } termbuf, termbuf2; #define cfsetospeed(tp,val) (tp)->sg.sg_ospeed = (val) #define cfsetispeed(tp,val) (tp)->sg.sg_ispeed = (val) #define cfgetospeed(tp) (tp)->sg.sg_ospeed #define cfgetispeed(tp) (tp)->sg.sg_ispeed #else /* USE_TERMIO */ #ifdef SYSV_TERMIO #define termios termio #endif /* SYSV_TERMIO */ #ifndef TCSANOW #ifdef TCSETS #define TCSANOW TCSETS #define TCSADRAIN TCSETSW #define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) #else /* TCSETS */ #ifdef TCSETA #define TCSANOW TCSETA #define TCSADRAIN TCSETAW #define tcgetattr(f,t) ioctl(f,TCGETA,(char *)t) #else /* TCSETA */ #define TCSANOW TIOCSETA #define TCSADRAIN TIOCSETAW #define tcgetattr(f,t) ioctl(f,TIOCGETA,(char *)t) #endif /* TCSETA */ #endif /* TCSETS */ #define tcsetattr(f,a,t) ioctl(f,a,t) #define cfsetospeed(tp,val) (tp)->c_cflag &= ~CBAUD;(tp)->c_cflag|=(val) #define cfgetospeed(tp) ((tp)->c_cflag & CBAUD) #ifdef CIBAUD #define cfsetispeed(tp,val) \ (tp)->c_cflag &= ~CIBAUD; (tp)->c_cflag |= ((val)<c_cflag & CIBAUD)>>IBSHIFT) #else /* CIBAUD */ #define cfsetispeed(tp,val) (tp)->c_cflag &= ~CBAUD; (tp)->c_cflag|=(val) #define cfgetispeed(tp) ((tp)->c_cflag & CBAUD) #endif /* CIBAUD */ #endif /* TCSANOW */ struct termios termbuf, termbuf2; /* pty control structure */ #ifdef INIT_SPTY static int spty = -1; #endif /* INIT_SPTY */ #endif /* USE_TERMIO */ #ifndef IXANY /* This was in #ifdef QNX.. */ #define IXANY 0 /* but because of _XOPEN_SOURCE */ #endif /* IXANY */ /* must be universal - does no harm */ static int msg = 0; /* Variables available to other modules */ int pty_fork_active = 0; /* pty fork is active */ PID_T pty_fork_pid = -1; /* pty fork pid */ int pty_slave_fd = -1; /* pty slave file descriptor */ int pty_master_fd = -1; /* pty master file descriptor */ /* termbuf routines (begin) */ /* init_termbuf() copy_termbuf(cp) set_termbuf() These three routines are used to get and set the "termbuf" structure to and from the kernel. init_termbuf() gets the current settings. copy_termbuf() hands in a new "termbuf" to write to the kernel, and set_termbuf() writes the structure into the kernel. */ VOID #ifdef CK_ANSIC init_termbuf( int fd ) #else init_termbuf(fd) int fd; #endif /* CK_ANSIC */ { int ttyfd; int rc = 0; ttyfd = fd; #ifdef HAVE_STREAMS debug(F100,"init_termbuf HAVE_STREAMS","",0); #else debug(F100,"init_termbuf HAVE_STREAMS NOT DEFINED","",0); #endif /* HAVE_STREAMS */ #ifdef STREAMSPTY debug(F100,"init_termbuf STREAMSPTY","",0); #else debug(F100,"init_termbuf STREAMSPTY NOT DEFINED","",0); #endif /* STREAMSPTY */ #ifdef INIT_SPTY debug(F100,"init_termbuf INIT_SPTY","",0); #else debug(F100,"init_termbuf INIT_SPTY NOT DEFINED","",0); #endif /* INIT_SPTY */ debug(F101,"init_termbuf ttyfd","",ttyfd); #ifdef INIT_SPTY debug(F101,"init_termbuf spty","",spty); #endif /* INIT_SPTY */ memset(&termbuf,0,sizeof(termbuf)); memset(&termbuf2,0,sizeof(termbuf2)); #ifndef USE_TERMIO rc = ioctl(ttyfd, TIOCGETP, (char *)&termbuf.sg); rc |= ioctl(ttyfd, TIOCGETC, (char *)&termbuf.tc); rc |= ioctl(ttyfd, TIOCGLTC, (char *)&termbuf.ltc); #ifdef TIOCGSTATE rc |= ioctl(ttyfd, TIOCGSTATE, (char *)&termbuf.state); #endif /* TIOCGSTATE */ #else /* USE_TERMIO */ errno = 0; #ifdef INIT_SPTY rc = tcgetattr(spty, &termbuf); debug(F111,"init_termbuf() tcgetattr(spty)",ckitoa(rc),errno); #else rc = tcgetattr(ttyfd, &termbuf); debug(F111,"init_termbuf() tcgetattr(ttyfd)",ckitoa(rc),errno); #endif /* INIT_SPTY */ #endif /* USE_TERMIO */ if (!rc) termbuf2 = termbuf; } #ifdef TIOCPKT_IOCTL VOID #ifdef CK_ANSIC copy_termbuf( char *cp, int len ) #else copy_termbuf(cp, len) char *cp; int len; #endif /* CK_ANSIC */ { if (len > sizeof(termbuf)) len = sizeof(termbuf); memcpy((char *)&termbuf, cp, len); termbuf2 = termbuf; } #endif /* TIOCPKT_IOCTL */ VOID #ifdef CK_ANSIC set_termbuf( int fd ) /* Only make the necessary changes. */ #else set_termbuf(fd) int fd; #endif /* CK_ANSIC */ { int x; int ttyfd; ttyfd = fd; debug(F101,"set_termbuf ttyfd","",ttyfd); #ifdef INIT_SPTY debug(F101,"set_termbuf spty","",spty); #endif /* INIT_SPTY */ #ifndef USE_TERMIO debug(F100,"set_termbuf USE_TERMIO","",0); if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg))) ioctl(ttyfd, TIOCSETN, (char *)&termbuf.sg); if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc))) ioctl(ttyfd, TIOCSETC, (char *)&termbuf.tc); if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc, sizeof(termbuf.ltc))) ioctl(ttyfd, TIOCSLTC, (char *)&termbuf.ltc); if (termbuf.lflags != termbuf2.lflags) ioctl(ttyfd, TIOCLSET, (char *)&termbuf.lflags); #else /* USE_TERMIO */ x = memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)); debug(F101,"set_termbuf !USE_TERMIO memcmp","",x); x = 1; /* Force this */ if (x) { int x; errno = 0; #ifdef INIT_SPTY debug(F100,"set_termbuf INIT_SPTY","",0); x = tcsetattr(spty, TCSANOW, &termbuf); debug(F111,"set_termbuf tcsetattr(spty)",ckitoa(x),errno); #else debug(F100,"set_termbuf !INIT_SPTY","",0); x = tcsetattr(ttyfd, TCSANOW, &termbuf); debug(F111,"set_termbuf tcsetattr(ttyfd)",ckitoa(x),errno); #endif /* INIT_SPTY */ } #endif /* USE_TERMIO */ } /* termbuf routines (end) */ VOID ptyint_vhangup() { #ifdef CK_VHANGUP _PROTOTYP( int vhangup, (void) ); #ifdef CK_POSIX_SIG struct sigaction sa; /* Initialize "sa" structure. */ sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = SIG_IGN; sigaction(SIGHUP, &sa, (struct sigaction *)0); vhangup(); sa.sa_handler = SIG_DFL; sigaction(SIGHUP, &sa, (struct sigaction *)0); #else /* CK_POSIX_SIG */ signal(SIGHUP,SIG_IGN); vhangup(); signal(SIGHUP,SIG_DFL); #endif /* CK_POSIX_SIG */ #endif /* CK_VHANGUP */ } /* This routine is called twice. It's not particularly important that the setsid() or TIOCSCTTY ioctls succeed (they may not the second time), but rather that we have a controlling terminal at the end. It is assumed that vhangup doesn't exist and confuse the process's notion of controlling terminal on any system without TIOCNOTTY. That is, either vhangup() leaves the controlling terminal in tact, breaks the association completely, or the system provides TIOCNOTTY to get things back into a reasonable state. In practice, vhangup() either breaks the association completely or doesn't effect controlling terminals, so this condition is met. */ long ptyint_void_association() { int con_fd; #ifdef HAVE_SETSID debug(F110, "ptyint_void_association()", "setsid()", 0 ); setsid(); #endif /* HAVE_SETSID */ #ifndef NO_DEVTTY /* Void tty association first */ #ifdef TIOCNOTTY con_fd = open("/dev/tty", O_RDWR); debug(F111, "ptyint_void_association() open(/dev/tty,O_RDWR)", "/dev/tty", con_fd); if (con_fd >= 0) { ioctl(con_fd, TIOCNOTTY, 0); close(con_fd); } #ifdef DEBUG else debug(F101, "ptyint_void_association() open() errno","",errno); #endif /* DEBUG */ #endif /* TIOCNOTTY */ #endif /* NO_DEVTTY */ return(0); } /* PID may be zero for unknown.*/ long #ifdef CK_ANSIC pty_cleanup( char *slave, int pid, int update_utmp ) #else pty_cleanup(slave, pid, update_utmp) char *slave; int pid; int update_utmp; #endif /* CK_ANSIC */ { #ifdef VHANG_LAST int retval, fd; #endif /* VHANG_LAST */ debug(F111,"pty_cleanup()",slave,pid); #ifdef WANT_UTMP if (update_utmp) pty_update_utmp(PTY_DEAD_PROCESS, 0, "", slave, (char *)0, PTY_UTMP_USERNAME_VALID ); #endif /* WANT_UTMP */ #ifdef SETUID chmod(slave, 0666); chown(slave, 0, 0); #endif /* SETUID */ #ifdef HAVE_REVOKE revoke(slave); /* Revoke isn't guaranteed to send a SIGHUP to the processes it dissociates from the terminal. The best solution without a Posix mechanism for forcing a hangup is to killpg() the process group of the pty. This will at least kill the shell and hopefully, the child processes. This is not always the case, however. If the shell puts each job in a process group and doesn't pass along SIGHUP, all processes may not die. */ if (pid > 0) { #ifdef HAVE_KILLPG killpg(pid, SIGHUP); #else kill(-(pid), SIGHUP); #endif /*HAVE_KILLPG*/ } #else /* HAVE_REVOKE*/ #ifdef VHANG_LAST { int status; #ifdef CK_POSIX_SIG sigset_t old, new; sigemptyset(&new); sigaddset(&new, SIGCHLD); sigprocmask(SIG_BLOCK, &new, &old); #else /*CK_POSIX_SIG*/ int mask = sigblock(sigmask(SIGCHLD)); #endif /*CK_POSIX_SIG*/ switch (retval = fork()) { case -1: #ifdef CK_POSIX_SIG sigprocmask(SIG_SETMASK, &old, 0); #else /*CK_POSIX_SIG*/ sigsetmask(mask); #endif /*CK_POSIX_SIG*/ return errno; case 0: ptyint_void_association(); if (retval = (pty_open_ctty(slave, &fd, -1))) exit(retval); ptyint_vhangup(); exit(0); break; default: #ifdef HAVE_WAITPID waitpid(retval, &status, 0); #else /*HAVE_WAITPID*/ wait(&status); #endif /* HAVE_WAITPID */ #ifdef CK_POSIX_SIG sigprocmask(SIG_SETMASK, &old, 0); #else /*CK_POSIX_SIG*/ sigsetmask(mask); #endif /*CK_POSIX_SIG*/ break; } } #endif /*VHANG_LAST*/ #endif /* HAVE_REVOKE*/ #ifndef HAVE_STREAMS slave[strlen("/dev/")] = 'p'; #ifdef SETUID chmod(slave, 0666); chown(slave, 0, 0); #endif /* SETUID */ #endif /* HAVE_STREAMS */ return(0); } long #ifdef CK_ANSIC pty_getpty( int *fd, char *slave, int slavelength ) #else pty_getpty(fd, slave, slavelength) int slavelength; int *fd; char *slave; #endif /* CK_ANSIC */ { char *cp; char *p; int i, ptynum; struct stat stb; #ifndef HAVE_OPENPTY #ifndef HAVE__GETPTY char slavebuf[1024]; #endif /* HAVE__GETPTY */ #endif /* HAVE_OPENPTY */ #ifdef HAVE__GETPTY char *slaveret; /* Temp to hold pointer to slave */ #endif /*HAVE__GETPTY*/ #ifdef HAVE_OPENPTY int slavefd; pty_master_fd = -1; debug(F100,"HAVE_OPENPTY","",0); if (openpty(fd, &slavefd, slave, (struct termios *)0, (struct winsize *)0 ) ) { pty_master_fd = *fd; return(1); } close(slavefd); return(0); #else /* HAVE_OPENPTY */ #ifdef HAVE__GETPTY /* This code is included for Irix; as of version 5.3, Irix has /dev/ptmx, but it fails to work properly; even after calling unlockpt, root gets permission denied opening the pty. The code to support _getpty should be removed if Irix gets working streams ptys in favor of maintaining the least needed code paths. */ debug(F100,"HAVE__GETPTY","",0); if ((slaveret = _getpty(fd, O_RDWR | O_NDELAY, 0600, 0)) == 0) { *fd = -1; return(PTY_GETPTY_NOPTY); } if (strlen(slaveret) > slavelength - 1) { close(*fd); *fd = -1; return(PTY_GETPTY_SLAVE_TOOLONG); } else { ckstrncpy(slave, slaveret, slavelength); } return(0); #else /* HAVE__GETPTY */ *fd = open("/dev/ptym/clone", O_RDWR|O_NDELAY); /* HPUX */ if (*fd >= 0) { debug(F110,"pty_getpty()","open(/dev/ptym/clone) success",0); goto have_fd; } #ifdef HAVE_PTMX debug(F100,"HAVE_PTMX","",0); *fd = open("/dev/ptmx",O_RDWR|O_NDELAY); if (*fd >= 0) { debug(F110,"pty_getpty()","open(/dev/ptmx) success",0); goto have_fd; } #endif /* HAVE_PTMX */ *fd = open("/dev/ptc", O_RDWR|O_NDELAY); /* AIX */ if (*fd >= 0) { debug(F110,"pty_getpty()","open(/dev/ptc) success",0); goto have_fd; } *fd = open("/dev/pty", O_RDWR|O_NDELAY); /* sysvimp */ if (*fd >= 0) debug(F110,"pty_getpty()","open(/dev/pty) success",0); have_fd: /* This would be the pty master */ debug(F101,"pty_getpty fd(A)","",*fd); if (*fd >= 0) { pty_master_fd = *fd; #ifdef HAVE_GRANTPT #ifdef HAVE_PTMX debug(F100,"HAVE_GRANTPT","",0); if (grantpt(*fd) || unlockpt(*fd)) return(PTY_GETPTY_STREAMS); #endif /* HAVE_PTMX */ #endif /* HAVE_GRANTPT */ #ifdef HAVE_PTSNAME debug(F100,"HAVE_PTSNAME","",0); p = (char *)ptsname(*fd); debug(F110,"pty_getpty() ptsname()",p,0); #else #ifdef HAVE_TTYNAME debug(F100,"HAVE_TTYNAME","",0); p = ttyname(*fd); debug(F110,"pty_getpty() ttyname()",p,0); #else /* If we don't have either what do we do? */ return(PTY_GETPTY_NOPTY); /* punt */ #endif /* HAVE_TTYNAME */ #endif /* HAVE_PTSNAME */ if (p) { if (strlen(p) > slavelength - 1) { close (*fd); *fd = -1; return(PTY_GETPTY_SLAVE_TOOLONG); } ckstrncpy(slave, p, slavelength); return(0); } if (fstat(*fd, &stb) < 0) { close(*fd); return(PTY_GETPTY_FSTAT); } ptynum = (int)(stb.st_rdev&0xFF); sprintf(slavebuf, "/dev/ttyp%x", ptynum); /* safe */ if (strlen(slavebuf) > slavelength - 1) { close(*fd); *fd = -1; return(PTY_GETPTY_SLAVE_TOOLONG); } debug(F110,"pty_getpty() slavebuf",slavebuf,0); ckstrncpy(slave, slavebuf, slavelength); return(0); } else { for (cp = "pqrstuvwxyzPQRST";*cp; cp++) { sprintf(slavebuf,"/dev/ptyXX"); /* safe */ slavebuf[sizeof("/dev/pty") - 1] = *cp; slavebuf[sizeof("/dev/ptyp") - 1] = '0'; if (stat(slavebuf, &stb) < 0) break; for (i = 0; i < 16; i++) { slavebuf[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; errno = 0; *fd = open(slavebuf, O_RDWR|O_NDELAY); if (*fd < 0) { debug(F111,"pty_getpty() pty master open error", slavebuf,errno); continue; } debug(F111,"pty_getpty() found pty master",slavebuf,*fd); slavebuf[sizeof("/dev/") - 1] = 't'; /* got pty */ if (strlen(slavebuf) > slavelength -1) { close(*fd); *fd = -1; return(PTY_GETPTY_SLAVE_TOOLONG); } ckstrncpy(slave, slavebuf, slavelength); debug(F110,"pty_getpty slave name",slave,0); pty_master_fd = *fd; return(0); } } return(PTY_GETPTY_NOPTY); } #endif /*HAVE__GETPTY*/ #endif /* HAVE_OPENPTY */ } long #ifdef CK_ANSIC pty_init( void ) #else pty_init() #endif /* CK_ANSIC */ { #ifdef HAVE_PTYM static char dummy; debug(F100,"HAVE_PTYM","",0); tty_bank = &master_name[strlen("/dev/ptym/pty")]; tty_num = &master_name[strlen("/dev/ptym/ptyX")]; slave_bank = &slave_name[strlen("/dev/pty/tty")]; slave_num = &slave_name[strlen("/dev/pty/ttyX")]; #endif return(0L); } /* The following is an array of modules that should be pushed on the stream. See configure.in for caviats and notes about when this array is used and not used. */ #ifdef HAVE_STREAMS #ifndef HAVE_LINE_PUSH static char *push_list[] = { #ifdef PUSH_PTEM "ptem", #endif #ifdef PUSH_LDTERM "ldterm", #endif #ifdef PUSH_TTCOMPAT "ttcompat", #endif 0 }; #endif /* HAVE_LINE_PUSH */ #endif /* HAVE_STREAMS */ long #ifdef CK_ANSIC pty_initialize_slave ( int fd ) #else pty_initialize_slave (fd) int fd; #endif /* CK_ANSIC */ { #ifdef POSIX_TERMIOS #ifndef ultrix struct termios new_termio; #else struct sgttyb b; #endif /* ultrix */ #else struct sgttyb b; #endif /* POSIX_TERMIOS */ int pid; #ifdef POSIX_TERMIOS #ifndef ultrix int rc; #endif /* ultrix */ #endif /* POSIX_TERMIOS */ debug(F111,"pty_initialize_slave()","fd",fd); #ifdef HAVE_STREAMS #ifdef HAVE_LINE_PUSH while (ioctl(fd,I_POP,0) == 0) ; /* Clear out any old lined's */ if (line_push(fd) < 0) { debug(F110,"pty_initialize_slave()","line_push() failed",0); close(fd); fd = -1; return(PTY_OPEN_SLAVE_LINE_PUSHFAIL); } #else /*No line_push */ { char **module = &push_list[0]; while (*module) { if (ioctl(fd, I_PUSH, *(module++)) < 0) { debug(F110,"pty_initialize_slave()","ioctl(I_PUSH) failed",0); return(PTY_OPEN_SLAVE_PUSH_FAIL); } } } #endif /*LINE_PUSH*/ #endif /*HAVE_STREAMS*/ /* Under Ultrix 3.0, the pgrp of the slave pty terminal needs to be set explicitly. Why rlogind works at all without this on 4.3BSD is a mystery. */ #ifdef GETPGRP_ONEARG pid = getpgrp(getpid()); #else pid = getpgrp(); #endif /* GETPGRP_ONEARG */ debug(F111,"pty_initialize_slave()","pid",pid); #ifdef TIOCSPGRP ioctl(fd, TIOCSPGRP, &pid); #endif /* TIOCSPGRP */ #ifdef POSIX_TERMIOS #ifndef ultrix tcsetpgrp(fd, pid); errno = 0; rc = tcgetattr(fd,&new_termio); debug(F111,"pty_initialize_slave tcgetattr(fd)",ckitoa(rc),errno); if (rc == 0) { new_termio.c_cc[VMIN] = 1; new_termio.c_cc[VTIME] = 0; rc = tcsetattr(fd,TCSANOW,&new_termio); debug(F111,"pty_initialize_slave tcsetattr(fd)",ckitoa(rc),errno); } #endif /* ultrix */ #endif /* POSIX_TERMIOS */ return(0L); } #ifdef WANT_UTMP long pty_logwtmp (tty, user, host) char *user, *tty, *host; { #ifdef HAVE_LOGWTMP logwtmp(tty,user,host); return(0); #else struct utmp ut; char *tmpx; char utmp_id[5]; int loggingin = user[0]; /* Will be empty for logout */ #ifndef NO_UT_HOST strncpy(ut.ut_host, host, sizeof(ut.ut_host)); #endif /* NO_UT_HOST */ strncpy(ut.ut_line, tty, sizeof(ut.ut_line)); ut.ut_time = time(0); #ifndef NO_UT_PID ut.ut_pid = getpid(); strncpy(ut.ut_user, user, sizeof(ut.ut_user)); tmpx = tty + strlen(tty) - 2; ckmakmsg(utmp_id,5,"kr",tmpx,NULL,NULL); strncpy(ut.ut_id, utmp_id, sizeof(ut.ut_id)); ut.ut_pid = (loggingin ? getpid() : 0); ut.ut_type = (loggingin ? USER_PROCESS : DEAD_PROCESS); #else strncpy(ut.ut_name, user, sizeof(ut.ut_name)); #endif /* NO_UT_PID */ return(ptyint_update_wtmp(&ut, host, user)); #endif /* HAVE_LOGWTMP */ } #endif /* WANT_UTMP */ /* This routine is called twice. It's not particularly important that the setsid() or TIOCSCTTY ioctls succeed (they may not the second time), but rather that we have a controlling terminal at the end. It is assumed that vhangup doesn't exist and confuse the process's notion of controlling terminal on any system without TIOCNOTTY. That is, either vhangup() leaves the controlling terminal intact, breaks the association completely, or the system provides TIOCNOTTY to get things back into a reasonable state. In practice, vhangup() either breaks the association completely or doesn't effect controlling terminals, so this condition is met. */ long #ifdef CK_ANSIC pty_open_ctty( char * slave, int *fd, int fc ) #else pty_open_ctty(slave, fd, fc) char * slave; int *fd; int fc; #endif /* CK_ANSIC */ { int retval; debug(F110,"pty_open_ctty() slave",slave,0); /* First, dissociate from previous terminal */ if ((retval = ptyint_void_association()) != 0) { debug(F111, "pty_open_ctty()", "ptyint_void_association() failed", retval ); return(retval); } #ifdef MUST_SETPGRP /* The Ultrix (and other BSD tty drivers) require the process group to be zero in order to acquire the new tty as a controlling tty. */ setpgrp(0,0); debug(F101,"pty_open_ctty MUST_SETPGRP setpgrp(0,0)","",errno); #endif /* MUST_SETPGRP */ errno = 0; *fd = open(slave, O_RDWR); debug(F111,"pty_open_ctty open(slave) fd",slave,*fd); if (*fd < 0) { debug(F111,"pty_open_ctty() open failure", slave, errno); return(PTY_OPEN_SLAVE_OPENFAIL); } #ifdef SOLARIS /* This forces the job to have a controlling terminal. */ close(*fd); *fd = open(slave, O_RDWR); debug(F111,"pty_open_ctty close/open(slave) fd",slave,*fd); #ifdef DEBUG /* This shows that /dev/tty exists */ if (deblog) { int x; x = open("/dev/tty", O_RDWR); debug(F111,"pty_open_ctty open(/dev/tty) fd",slave,x); if (x < 0) debug(F111,"pty_open_ctty open(/dev/tty) errno","",errno); debug(F110,"pty_open_ctty ttyname(/dev/tty)",ttyname(x),0); if (x > -1) close(x); } #endif /* DEBUG */ #endif /* SOLARIS */ #ifdef MUST_SETPGRP setpgrp(0, getpid()); #endif /* MUST_SETPGRP */ #ifdef TIOCSCTTY if ( #ifdef COMMENT fc == 0 #else 1 #endif /* COMMENT */ ) { /* TIOCSCTTY = Make this the job's controlling terminal */ errno = 0; retval = ioctl(*fd, TIOCSCTTY, 0); /* Don't check return.*/ debug(F111,"pty_open_ctty() ioctl TIOCSCTTY",ckitoa(retval),errno); } #endif /* TIOCSCTTY */ return(0L); } long #ifdef CK_ANSIC pty_open_slave( char *slave, int *fd, int fc ) #else pty_open_slave(slave, fd, fc) char *slave; int *fd; int fc; #endif /* CK_ANSIC */ { int vfd, testfd; long retval; #ifdef CK_POSIX_SIG struct sigaction sa; sigemptyset(&sa.sa_mask); /* Initialize "sa" structure. */ sa.sa_flags = 0; #endif /* CK_POSIX_SIG */ /* First, chmod and chown the slave. If we have vhangup then we really need pty_open_ctty to make sure our controlling terminal is the pty we're opening. However, if we are using revoke or nothing then we just need a file descriiptor for the pty. Considering some OSes in this category break on the second call to open_ctty (currently OSF but others may), we simply use a descriptor if we can. */ #ifdef VHANG_FIRST if ((retval = pty_open_ctty(slave, &vfd, fc)) != 0) { debug(F111, "pty_open_slave() VHANG_FIRST", "pty_open_ctty() failed", retval ); return(retval); } if (vfd < 0) { debug(F111, "pty_open_slave() VHANG_FIRST", "PTY_OPEN_SLAVE_OPENFAIL", vfd ); return(PTY_OPEN_SLAVE_OPENFAIL); } #endif /* VHANG_FIRST */ if (slave == NULL || *slave == '\0') { debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_TOOSHORT",0); return(PTY_OPEN_SLAVE_TOOSHORT); } #ifdef SETUID if (chmod(slave, 0)) { debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHMODFAIL",0); return(PTY_OPEN_SLAVE_CHMODFAIL); } if (chown(slave, 0, 0 ) == -1 ) { debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_CHOWNFAIL",0); return(PTY_OPEN_SLAVE_CHOWNFAIL); } #endif /* SETUID */ #ifdef VHANG_FIRST ptyint_vhangup(); close(vfd); #endif /* VHANG_FIRST */ if ((retval = ptyint_void_association()) != 0) { debug(F111, "pty_open_slave()", "ptyint_void_association() failed", retval ); return(retval); } #ifdef HAVE_REVOKE if (revoke (slave) < 0 ) { debug(F110,"pty_open_slave()","PTY_OPEN_SLAVE_REVOKEFAIL",0); return(PTY_OPEN_SLAVE_REVOKEFAIL); } #endif /* HAVE_REVOKE */ /* Open the pty for real. */ retval = pty_open_ctty(slave, fd, fc); debug(F111,"pty_open_slave retval",slave,retval); debug(F111,"pty_open_slave fd",slave,*fd); if (retval != 0) { debug(F111,"pty_open_slave()","pty_open_ctty() failed",retval); return(PTY_OPEN_SLAVE_OPENFAIL); } pty_slave_fd = *fd; /* This is not visible to the upper fork */ debug(F111,"pty_open_slave fd ctty'd",slave,pty_slave_fd); retval = pty_initialize_slave(*fd); debug(F111,"pty_open_slave fd init'd",slave,pty_slave_fd); if (retval) { debug(F111,"pty_open_slave()","pty_initialize_slave() failed",retval); return(retval); } /* (VOID)pty_make_raw(*fd); */ debug(F100,"pty_open_slave OK","",*fd); return(0L); } #ifdef WANT_UTMP #ifndef UTMP_FILE #ifdef _PATH_UTMP #define UTMP_FILE _PATH_UTMP #endif /* _PATH_UTMP */ #endif /* UTMP_FILE */ /* If it is *still* missing, assume /etc/utmp */ #ifndef UTMP_FILE #define UTMP_FILE "/etc/utmp" #endif /* UTMP_FILE */ #ifndef NO_UT_PID #define WTMP_REQUIRES_USERNAME #endif /* NO_UT_PID */ long pty_update_utmp(process_type, pid, username, line, host, flags) int process_type; int pid; char *username, *line, *host; int flags; /* pty_update_utmp */ { struct utmp ent, ut; #ifndef HAVE_SETUTENT struct stat statb; int tty; #endif /* HAVE_SETUTENT */ #ifdef HAVE_SETUTXENT struct utmpx utx; #endif /* HAVE_SETUTXENT */ #ifndef NO_UT_PID char *tmpx; char utmp_id[5]; #endif /* NO_UT_PID */ char userbuf[32]; int fd; debug(F100,"pty_update_utmp()","",0); strncpy(ent.ut_line, line+sizeof("/dev/")-1, sizeof(ent.ut_line)); ent.ut_time = time(0); #ifdef NO_UT_PID if (process_type == PTY_LOGIN_PROCESS) return(0L); #else /* NO_UT_PID */ ent.ut_pid = pid; switch (process_type) { case PTY_LOGIN_PROCESS: ent.ut_type = LOGIN_PROCESS; break; case PTY_USER_PROCESS: ent.ut_type = USER_PROCESS; break; case PTY_DEAD_PROCESS: ent.ut_type = DEAD_PROCESS; break; default: return(PTY_UPDATE_UTMP_PROCTYPE_INVALID); } #endif /*NO_UT_PID*/ #ifndef NO_UT_HOST if (host) strncpy(ent.ut_host, host, sizeof(ent.ut_host)); else ent.ut_host[0] = '\0'; #endif /* NO_UT_HOST */ #ifndef NO_UT_PID if (!strcmp (line, "/dev/console")) { char * s = NULL; #ifdef sun #ifdef __SVR4 s = "co"; #else s = "cons"; #endif /* __SVR4 */ #else s = "cons"; #endif /* sun */ strncpy(ent.ut_id, s, 4); } else { tmpx = line + strlen(line)-1; if (*(tmpx-1) != '/') tmpx--; /* last 2 chars unless it's a '/' */ #ifdef __hpux ckstrncpy(utmp_id, tmpx, 5); #else ckmakmsg(utmp_id,5,"kl",tmpx,NULL,NULL); #endif /* __hpux */ strncpy(ent.ut_id, utmp_id, sizeof(ent.ut_id)); } strncpy(ent.ut_user, username, sizeof(ent.ut_user)); #else strncpy(ent.ut_name, username, sizeof(ent.ut_name)); #endif /* NO_UT_PID */ if (username[0]) strncpy(userbuf, username, sizeof(userbuf)); else userbuf[0] = '\0'; #ifdef HAVE_SETUTENT utmpname(UTMP_FILE); setutent(); /* If we need to preserve the user name in the wtmp structure and Our flags tell us we can obtain it from the utmp and we succeed in obtaining it, we then save the utmp structure we obtain, write out the utmp structure and change the username pointer so it is used by update_wtmp. */ #ifdef WTMP_REQUIRES_USERNAME if ((!username[0]) && (flags&PTY_UTMP_USERNAME_VALID) &&line) { struct utmp *utptr; strncpy(ut.ut_line, line, sizeof(ut.ut_line)); utptr = getutline(&ut); if (utptr) strncpy(userbuf,utptr->ut_user,sizeof(ut.ut_user)); } #endif /* WTMP_REQUIRES_USERNAME */ pututline(&ent); endutent(); #ifdef HAVE_SETUTXENT setutxent(); #ifdef HAVE_GETUTMPX getutmpx(&ent, &utx); #else /* HAVE_GETUTMPX */ /* For platforms like HPUX and Dec Unix which don't have getutmpx */ strncpy(utx.ut_user, ent.ut_user, sizeof(ent.ut_user)); strncpy(utx.ut_id, ent.ut_id, sizeof(ent.ut_id)); strncpy(utx.ut_line, ent.ut_line, sizeof(ent.ut_line)); utx.ut_pid = pid; /* kludge for Irix, etc. to avoid trunc. */ utx.ut_type = ent.ut_type; #ifdef UT_EXIT_STRUCTURE_DIFFER utx.ut_exit.ut_exit = ent.ut_exit.e_exit; #else /* UT_EXIT_STRUCTURE_DIFFER */ /* KLUDGE for now; eventually this will be a feature test... See PR#[40] */ #ifdef __hpux utx.ut_exit.__e_termination = ent.ut_exit.e_termination; utx.ut_exit.__e_exit = ent.ut_exit.e_exit; #else /* __hpux */ /* XXX do nothing for now; we don't even know the struct member exists */ #endif /* __hpux */ #endif /* UT_EXIT_STRUCTURE_DIFFER */ utx.ut_tv.tv_sec = ent.ut_time; utx.ut_tv.tv_usec = 0; #endif /* HAVE_GETUTMPX */ if (host) strncpy(utx.ut_host, host, sizeof(utx.ut_host)); else utx.ut_host[0] = 0; pututxline(&utx); endutxent(); #endif /* HAVE_SETUTXENT */ #else /* HAVE_SETUTENT */ if (flags&PTY_TTYSLOT_USABLE) { tty = ttyslot(); } else { int lc; tty = -1; if ((fd = open(UTMP_FILE, O_RDWR)) < 0) return(errno); for (lc = 0; lseek(fd, (off_t)(lc * sizeof(struct utmp)), SEEK_SET) != -1; lc++ ) { if (read(fd, (char *)&ut, sizeof(struct utmp) ) != sizeof(struct utmp) ) break; if (strncmp(ut.ut_line, ent.ut_line, sizeof(ut.ut_line)) == 0) { tty = lc; #ifdef WTMP_REQUIRES_USERNAME if (!username&&(flags&PTY_UTMP_USERNAME_VALID)) strncpy(userbuf, ut.ut_user, sizeof(ut.ut_user)); #endif /* WTMP_REQUIRES_USERNAME */ break; } } close(fd); } if (tty > 0 && (fd = open(UTMP_FILE, O_WRONLY, 0)) >= 0) { lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET); write(fd, (char *)&ent, sizeof(struct utmp)); close(fd); } #endif /* HAVE_SETUTENT */ /* Don't record LOGIN_PROCESS entries. */ if (process_type == PTY_LOGIN_PROCESS) return(0); else return(ptyint_update_wtmp(&ent, host, userbuf)); } #ifndef WTMP_FILE #ifdef _PATH_WTMP #define WTMP_FILE _PATH_WTMP #endif /* _PATH_WTMP */ #endif /* WTMP_FILE */ #ifndef WTMPX_FILE #ifdef _PATH_WTMPX #ifdef HAVE_UPDWTMPX #define WTMPX_FILE _PATH_WTMPX #endif /* HAVE_UPDWTMPX */ #endif /* _PATH_WTMPX */ #endif /* WTMPX_FILE */ /* If it is *still* missing, assume /usr/adm/wtmp */ #ifndef WTMP_FILE #define WTMP_FILE "/usr/adm/wtmp" #endif /* WTMP_FILE */ #ifdef COMMENT /* The following test can not be made portably */ /* #if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) */ /* This is ugly, but the lack of standardization in the utmp/utmpx space, and what glibc implements and doesn't make available, is even worse. */ /* #undef HAVE_UPDWTMPX */ /* Don't use updwtmpx for glibc 2.1 */ /* #endif */ /* __GLIBC__ etc */ #else /* COMMENT */ #ifdef __GLIBC__ #undef HAVE_UPDWTMPX /* Don't use updwtmpx for glibc period */ #endif /* __GLIBC__ */ #endif /* COMMENT */ long ptyint_update_wtmp(ent,host,user) struct utmp *ent; char *host; char *user; { struct utmp ut; struct stat statb; int fd; time_t uttime; #ifdef HAVE_UPDWTMPX struct utmpx utx; getutmpx(ent, &utx); if (host) strncpy(utx.ut_host, host, sizeof(utx.ut_host) ); else utx.ut_host[0] = 0; if (user) strncpy(utx.ut_user, user, sizeof(utx.ut_user)); updwtmpx(WTMPX_FILE, &utx); #endif /* HAVE_UPDWTMPX */ #ifdef HAVE_UPDWTMP #ifndef HAVE_UPDWTMPX /* This is already performed byupdwtmpx if present.*/ updwtmp(WTMP_FILE, ent); #endif /* HAVE_UPDWTMPX*/ #else /* HAVE_UPDWTMP */ if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) >= 0) { if (!fstat(fd, &statb)) { memset((char *)&ut, 0, sizeof(ut)); #ifdef __hpux strncpy(ut.ut_id, ent->ut_id, sizeof (ut.ut_id)); #endif /* __hpux */ strncpy(ut.ut_line, ent->ut_line, sizeof(ut.ut_line)); strncpy(ut.ut_name, ent->ut_name, sizeof(ut.ut_name)); #ifndef NO_UT_HOST strncpy(ut.ut_host, ent->ut_host, sizeof(ut.ut_host)); #endif /* NO_UT_HOST */ time(&uttime); ut.ut_time = uttime; #ifdef HAVE_GETUTENT #ifdef USER_PROCESS if (ent->ut_name) { if (!ut.ut_pid) ut.ut_pid = getpid(); #ifndef __hpux ut.ut_type = USER_PROCESS; #else /* __hpux */ ut.ut_type = ent->ut_type; #endif /* __hpux */ } else { #ifdef EMPTY ut.ut_type = EMPTY; #else ut.ut_type = DEAD_PROCESS; /* For Linux brokenness*/ #endif /* EMPTY */ } #endif /* USER_PROCESS */ #endif /* HAVE_GETUTENT */ if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp)) #ifndef COHERENT ftruncate(fd, statb.st_size); #else chsize(fd, statb.st_size); #endif /* COHERENT */ } close(fd); } #endif /* HAVE_UPDWTMP */ return(0); /* no current failure cases; file not found is not failure! */ } #endif /* WANT_UTMP */ /* This is for ancient Unixes that don't have these tty symbols defined. */ #ifndef PENDIN #define PENDIN ICANON #endif /* PENDIN */ #ifndef FLUSHO #define FLUSHO ICANON #endif /* FLUSHO */ #ifndef IMAXBEL #define IMAXBEL ICANON #endif /* IMAXBEL */ #ifndef EXTPROC #define EXTPROC ICANON #endif /* EXTPROC */ static char Xline[17] = { 0, 0 }; /* getptyslave() Open the slave side of the pty, and do any initialization that is necessary. The return value fd is a file descriptor for the slave side. fc = function code from do_pty() (q.v.) */ int #ifdef CK_ANSIC getptyslave( int * fd, int fc ) #else getptyslave(fd, fc) int * fd, fc; #endif /* CK_ANSIC */ { int ttyfd; int t = -1; long retval; #ifdef TIOCGWINSZ struct winsize ws; extern int cmd_rows, cmd_cols; #endif /* TIOCGWINSZ */ ttyfd = *fd; debug(F111,"getptyslave()","ttyfd",ttyfd); /* * Opening the slave side may cause initilization of the * kernel tty structure. We need remember the state of: * if linemode was turned on * terminal window size * terminal speed * so that we can reset them if we need to. */ if ((retval = pty_open_slave(Xline, &t, fc)) != 0) { perror(Xline); msg++; debug(F111,"getptyslave()","Unable to open slave",retval); return(-1); } debug(F111,"getptyslave","t",t); #ifdef INIT_SPTY spty = t; debug(F111,"getptyslave","spty",spty); #endif /* INIT_SPTY */ #ifdef STREAMSPTY if (ioctl(t,I_PUSH,"pckt") < 0) { debug(F111,"getptyslave()","ioctl(I_PUSH) failed",errno); #ifndef _AIX fatal("I_PUSH pckt"); #endif /* _AIX */ } #endif /* STREAMSPTY */ /* Set up the tty modes as we like them to be. */ #ifdef COMMENT /* Originally like this... But this is the master - we want the slave */ /* Anyway, this fails on Solaris and probably other System V OS's */ init_termbuf(ttyfd); #else init_termbuf(t); #endif /* COMMENT */ #ifdef TIOCGWINSZ if (cmd_rows || cmd_cols) { memset((char *)&ws, 0, sizeof(ws)); ws.ws_col = cmd_cols; ws.ws_row = cmd_rows; debug(F101,"getptyslave() doing TIOCSWINSZ...","",t); ioctl(t, TIOCSWINSZ, (char *)&ws); } #endif /* TIOCGWINSZ */ /* For external protocols, put the pty in no-echo mode */ if (fc == 1) { debug(F100,"getptyslave() setting rawmode","",0); /* iflags */ termbuf.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL); termbuf.c_iflag &= ~(INPCK|IGNPAR|IMAXBEL|IXANY|IXON|IXOFF); termbuf.c_iflag |= IGNBRK; #ifdef IUCLC termbuf.c_iflag &= ~IUCLC; #endif /* IUCLC */ /* oflags */ termbuf.c_oflag &= ~OPOST; #ifdef OXTABS termbuf.c_oflag &= ~OXTABS; #endif /* OXTABS */ #ifdef ONOCR termbuf.c_oflag &= ~ONOCR; #endif /* ONOCR */ #ifdef ONLRET termbuf.c_oflag &= ~ONLRET; #endif /* ONLRET */ #ifdef ONLCR termbuf.c_oflag &= ~ONLCR; #endif /* ONLCR */ /* lflags */ termbuf.c_lflag &= ~ECHO; #ifdef ECHOE termbuf.c_lflag &= ~ECHOE; #endif /* ECHOE */ #ifdef ECHONL termbuf.c_lflag &= ~ECHONL; #endif /* ECHONL */ #ifdef ECHOPRT termbuf.c_lflag &= ~ECHOPRT; #endif /* ECHOPRT */ #ifdef ECHOKE termbuf.c_lflag &= ~ECHOKE; #endif /* ECHOKE */ #ifdef ECHOCTL termbuf.c_lflag &= ~ECHOCTL; #endif /* ECHOCTL */ #ifdef ALTWERASE termbuf.c_lflag &= ~ALTWERASE; #endif /* ALTWERASE */ #ifdef EXTPROC termbuf.c_lflag &= ~EXTPROC; #endif /* EXTPROC */ termbuf.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN); #ifdef NOKERNINFO termbuf.c_lflag |= NOKERNINFO; #endif /* NOKERNINFO */ /* termbuf.c_lflag |= NOFLSH; */ termbuf.c_lflag &= ~NOFLSH; /* cflags */ termbuf.c_cflag &= ~(CSIZE|PARENB|PARODD); termbuf.c_cflag |= CS8|CREAD; #ifdef VMIN termbuf.c_cc[VMIN] = 1; #endif /* VMIN */ } else { /* Regular interactive use */ debug(F100,"getptyslave() setting cooked mode","",0); /* Settings for sgtty based systems */ #ifndef USE_TERMIO termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS; #endif /* USE_TERMIO */ #ifndef OXTABS #define OXTABS 0 #endif /* OXTABS */ /* Settings for UNICOS and HPUX */ #ifdef CRAY termbuf.c_oflag = OPOST|ONLCR|TAB3; termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON; termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; termbuf.c_cflag = EXTB|HUPCL|CS8; #else /* CRAY */ #ifdef HPUX termbuf.c_oflag = OPOST|ONLCR|TAB3; termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON; termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; termbuf.c_cflag = EXTB|HUPCL|CS8; #else /* HPUX */ #ifdef USE_TERMIO /* Settings for all other termios/termio based systems, other than 4.4BSD. In 4.4BSD the kernel does the initial terminal setup. */ #ifdef BSD42 #ifndef BSD44 termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG; termbuf.c_oflag |= ONLCR|OXTABS|OPOST; termbuf.c_iflag |= ICRNL|IGNPAR; termbuf.c_cflag |= HUPCL; termbuf.c_iflag &= ~IXOFF; #endif /* BSD44 */ #else /* BSD42 */ termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG; termbuf.c_oflag |= ONLCR|OXTABS|OPOST; termbuf.c_iflag |= ICRNL|IGNPAR; termbuf.c_cflag |= HUPCL; termbuf.c_iflag &= ~IXOFF; #endif /* BSD42 */ #endif /* USE_TERMIO */ #endif /* HPUX */ #endif /* CRAY */ } /* Set the tty modes, and make this our controlling tty. */ #ifdef COMMENT /* But this is the master - we want the slave */ set_termbuf(ttyfd); #else set_termbuf(t); #endif /* COMMENT */ if (t != 0) dup2(t, 0); if (t != 1) dup2(t, 1); if (t != 2) { if (fc == 0) { dup2(t, 2); } else if (fc == 1) { /* For external protocols, send stderr to /dev/null */ #ifdef COMMENT int xx; #ifndef COMMENT char * s = "/dev/null"; errno = 0; xx = open(s, O_WRONLY); #else char * s = "pty.log"; errno = 0; xx = open(s, O_CREAT, 0644); #endif /* COMMENT */ debug(F111,"getptyslave redirect stderr",s,errno); dup2(xx,2); #endif /* COMMENT */ } } if (t > 2) close(t); if (ttyfd > 2) { close(ttyfd); ttyfd = -1; *fd = ttyfd; } return(0); } #ifdef HAVE_PTYTRAP /* To be called to determine if a trap is pending on a pty if and only if select() cannot be used. */ int pty_trap_pending(fd) int fd; { int pending; int rc; rc = ioctl(fd, TIOCTRAPSTATUS, (char *)&pending, sizeof(pending)); if (rc == 0) { debug(F101,"pty_trap_pending()","",pending); return(pending); } else { debug(F111,"pty_trap_pending()","ioctl() failed",rc); return(-1); } } /* To be called after select() has returned indicating that an exception is waiting on a pty. It should be called with the file descriptor of the pty. Returns -1 on error; 0 if pty is still open; 1 if pty has closed. */ int pty_trap_handler(fd) int fd; { struct request_info ri; memset(&ri,0,sizeof(ri)); if (ioctl(fd,TIOCREQCHECK,(char *)&ri, sizeof(ri)) != 0) { debug(F111,"pty_trap_handler()","ioctl(TIOCREQCHECK) failed",errno); return(-1); } switch (ri.request) { case TIOCOPEN: debug(F110,"pty_trap_handler()","an open() call",0); break; case TIOCCLOSE: debug(F110,"pty_trap_handler()","a close() call",0); break; default: debug(F110,"pty_trap_handler()","an ioctl() call",0); ri.errno_error = EINVAL; } if (ioctl(fd, TIOCREQSET, (char *)&ri,sizeof(ri)) != 0) { debug(F111,"pty_trap_handler()","ioctl(TIOCREQSET) failed",errno); return(-1); } if (ri.request == TIOCCLOSE) return(1); else return(0); } #endif /* HAVE_PTYTRAP */ VOID #ifdef CK_ANSIC exec_cmd( char * s ) #else exec_cmd(s) char * s; #endif /* CK_ANSIC */ { struct stringarray * q; char ** args = NULL; if (!s) return; if (!*s) return; q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0,0); if (!q) return; args = q->a_head + 1; #ifdef DEBUG { int i, n; n = q->a_size; for (i = 0; i <= n; i++) { if (!args[i]) { debug(F111,"exec_cmd arg","NULL",i); break; } else { debug(F111,"exec_cmd arg",args[i],i); if (i == n && args[i]) { debug(F101,"exec_cmd SUBSTITUTING NULL","",i); if (strlen(args[i]) == 0) makestr(&(args[i]),NULL); } } } } #endif /* DEBUG */ execvp(args[0],args); } /* Get a pty, scan input lines. */ /* fc = 0 for interactive access; fc = 1 for running external protocols */ /* Returns -1 on failure and the PID (a positive number) on success */ static int pty_fc = -1; /* Global copy of fc */ int #ifdef CK_ANSIC do_pty( int * fd, char * cmd, int fc ) #else do_pty(fd, cmd, fc) int * fd; char * cmd; int fc; #endif /* CK_ANSIC */ { long retval; int syncpipe[2]; int i, ttyfd; #ifdef HAVE_PTYTRAP int x; #endif /* HAVE_PTYTRAP */ int dummy; debug(F101,"CKUPTY.C do_pty fc","",fc); ttyfd = *fd; pty_master_fd = -2; pty_slave_fd = -2; pty_fork_pid = -2; msg = 0; /* Message counter */ pty_init(); /* Find an available pty to use. */ errno = 0; if ((retval = pty_getpty(&ttyfd, Xline, 20)) != 0) { if (msg++ == 0) perror(Xline); debug(F111,"do_pty()","pty_getpty() fails",retval); *fd = ttyfd; return(-1); } *fd = ttyfd; debug(F111,"do_pty() Xline",Xline,ttyfd); #ifdef SIGTTOU /* Ignoring SIGTTOU keeps the kernel from blocking us. we tweak the tty with an ioctl() (in ttioct() in /sys/tty.c in a BSD kernel) */ signal(SIGTTOU, SIG_IGN); #endif /* SIGTTOU */ /* Start up the command on the slave side of the terminal */ if (pipe(syncpipe) < 0) { debug(F110,"do_pty()","pipe() fails",0); perror("pipe() failed"); msg++; debug(F111,"do_pty()","pipe fails",errno); return(-1); } if ((i = fork()) < 0) { /* XXX - need to clean up the allocated pty */ perror("fork() failed"); msg++; debug(F111,"do_pty()","fork fails",errno); return(-1); } if (i) { /* Wait for child before writing to parent side of pty. */ char c; #ifdef HAVE_PTYTRAP int on = 1; #endif /* HAVE_PTYTRAP */ close(syncpipe[1]); errno = 0; if (read(syncpipe[0], &c, 1) == 0) { /* Slave side died */ perror("Pipe read() failed"); msg++; debug(F110,"do_pty()","Slave fails to initialize",0); close(syncpipe[0]); return(-1); } pty_fork_pid = i; /* So we can clean it up later */ pty_fork_active = 1; debug(F101,"do_pty pty_fork_pid","",pty_fork_pid); #ifdef HAVE_PTYTRAP /* HPUX does not allow the master to read end of file. */ /* Therefore, we must determine that the slave has been */ /* closed by trapping the call to close(). */ errno = 0; x = ioctl(ttyfd, TIOCTRAP, (char *)&on); debug(F111,"do_pty ioctl(TIOCTRAP)",ckitoa(x),errno); #endif /* HAVE_PTYTRAP */ debug(F111,"do_pty()","synchronized - pty_fork_pid",pty_fork_pid); close(syncpipe[0]); } else { int x; debug(F101,"do_pty getptyslave ttyfd A","",ttyfd); debug(F110,"do_pty()","Slave starts",0); x = getptyslave(&ttyfd,fc); debug(F101,"do_pty getptyslave","",x); if (x == 0) { debug(F101,"do_pty getptyslave ttyfd B","",ttyfd); #ifdef WANT_UTMP pty_update_utmp(PTY_USER_PROCESS, getpid(), "KERMIT", Xline, cmd, PTY_TTYSLOT_USABLE ); #endif /* WANT_UTMP */ /* Notify our parent we're ready to continue.*/ debug(F110,"do_pty()","slave synchronizing",0); dummy = write(syncpipe[1],"y",1); close(syncpipe[0]); close(syncpipe[1]); debug(F110,"do_pty cmd",cmd,0); exec_cmd(cmd); debug(F111,"do_pty()","exec_cmd() returns - why?",errno); } *fd = ttyfd; debug(F110,"do_pty()","getptyslave() fails - exiting",0); exit(1); } *fd = ttyfd; pty_fc = fc; return(getpid()); } /* end of do_pty() */ VOID end_pty() { msg = 0; /* Message counter */ debug(F101,"end_pty pty_fork_pid","",pty_fork_pid); if (Xline[0] && pty_fork_pid >= 0) { pty_cleanup(Xline,pty_fork_pid,1); Xline[0] = '\0'; pty_fork_pid = -1; pty_fork_active = 0; debug(F101,"end_pty pty_fork_active","",pty_fork_active); } pty_fc = -1; } #endif /* NETPTY */ ckupty.h000664 045065 024037 00000011305 14767402104 012660 0ustar00fdckermit000000 000000 /* C K U P T Y . H -- Includes and definitions for ckupty.c */ /* Copyright 1995 by the Massachusetts Institute of Technology. Modified for use in C-Kermit by: Jeffrey E Altman Secure Endpoints Inc., New York City November 1999 */ #ifndef __PTY_INT_H__ #include /* #define WANT_UTMP */ /* We don't want all the utmp/wtmp stuff */ #ifdef WANT_UTMP #ifdef HAVE_UTMP_H #include #endif /* HAVE_UTMP_H */ #ifdef HAVE_UTMPX_H #include #endif /* HAVE_UTMPX_H */ #endif /* WANT_UTMP */ #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #ifdef __SCO__ #include #endif /* __SCO__ */ #ifdef HAVE_STDLIB_H #include #endif /* HAVE_STDLIB_H */ #include #include #ifndef SUNOS41 #include #endif /* SUNOS41 */ #include #include #include #include #include #include #include #ifdef HAVE_SYS_LABEL_H /* only SunOS 4? */ #include #include #include #endif /* HAVE_SYS_LABEL_H */ #include #ifdef HPUX #include #endif /* HPUX */ #ifdef sysvimp #include #endif /* sysvimp */ #ifdef COMMENT /* I don't think we actually use this for anything */ /* and it kills Slackware builds, where there is no select.h. */ #ifndef NO_SYS_SELECT_H #ifdef HAVE_SYS_SELECT_H #include #endif /* HAVE_SYS_SELECT_H */ #endif /* NO_SYS_SELECT_H */ #endif /* COMMENT */ #ifdef HAVE_STREAMS #include #include #endif /* HAVE_STREAMS */ #ifdef POSIX_TERMIOS #ifndef ultrix #include #else #include #endif /* ultrix */ #else /* POSIX_TERMIOS */ #include #endif /* POSIX_TERMIOS */ #include /* #include */ #ifndef ultrix #include #endif /* ultrix */ /* #include */ /* (now done in ckcdeb.h) */ #ifdef HAVE_STREAMS /* krlogin doesn't test sys/tty... */ #ifdef HAVE_SYS_TTY_H #include #endif /* HAVE_SYS_TTY_H */ #ifdef HAVE_SYS_PTYVAR_H /* Solaris actually uses packet mode, so the real macros are needed too */ #include #endif /* HAVE_SYS_PTYVAR_H */ #endif /* HAVE_STREAMS */ #ifdef COMMENT /* This block moved to ckcdeb.h */ #ifndef NO_OPENPTY /* For NetBSD, see makefile */ #ifndef HAVE_OPENPTY #ifdef __FreeBSD__ #define HAVE_OPENPTY #else #ifdef MACOSX10 #define HAVE_OPENPTY #endif /* MACOSX10 */ #endif /* __FreeBSD__ */ #endif /* HAVE_OPENPTY */ #endif /* NO_OPENPTY */ #endif /* COMMENT */ #ifdef HAVE_VHANGUP #ifndef OPEN_CTTY_ONLY_ONCE /* Breaks under Ultrix and others where you cannot get controlling terminal twice. */ #define VHANG_first #define VHANG_LAST #endif /* OPEN_CTTY_ONLY_ONCE */ #endif /* HAVE_VHANGUP */ /* Internal functions */ _PROTOTYP(long ptyint_void_association,(void)); _PROTOTYP(long ptyint_open_ctty ,(char *, int *)); _PROTOTYP(VOID ptyint_vhangup, (void)); #ifdef WANT_UTMP _PROTOTYP(long ptyint_update_wtmp, (struct utmp *, char *, char *)); #endif /* WANT_UTMP */ #define __PTY_INT_H__ #endif /* __PTY_INT_H__ */ #ifndef __LIBPTY_H__ #ifdef WANT_UTMP /* Constants for pty_update_utmp */ #define PTY_LOGIN_PROCESS 0 #define PTY_USER_PROCESS 1 #define PTY_DEAD_PROCESS 2 #define PTY_TTYSLOT_USABLE (0x1) /* flags to update_utmp*/ #define PTY_UTMP_USERNAME_VALID (0x2) #endif /* WANT_UTMP */ _PROTOTYP(long pty_init,(void)); _PROTOTYP(long pty_getpty, ( int *, char *, int)); _PROTOTYP(long pty_open_slave, (char *, int *, int)); _PROTOTYP(long pty_open_ctty, (char *, int *, int)); _PROTOTYP(long pty_initialize_slave, (int)); #ifdef WANT_UTMP _PROTOTYP(long pty_update_utmp, (int, int, char *, char *, char *, int)); _PROTOTYP(long pty_logwtmp, (char *, char *, char *)); #endif /* WANT_UTMP */ _PROTOTYP(long pty_cleanup, (char *, int, int)); #define PTY_GETPTY_STREAMS (44806912L) #define PTY_GETPTY_FSTAT (44806913L) #define PTY_GETPTY_NOPTY (44806914L) #define PTY_GETPTY_SLAVE_TOOLONG (44806915L) #define PTY_OPEN_SLAVE_OPENFAIL (44806916L) #define PTY_OPEN_SLAVE_CHMODFAIL (44806917L) #define PTY_OPEN_SLAVE_NOCTTY (44806918L) #define PTY_OPEN_SLAVE_CHOWNFAIL (44806919L) #define PTY_OPEN_SLAVE_LINE_PUSHFAIL (44806920L) #define PTY_OPEN_SLAVE_PUSH_FAIL (44806921L) #define PTY_OPEN_SLAVE_REVOKEFAIL (44806922L) #ifdef WANT_UTMP #define PTY_UPDATE_UTMP_PROCTYPE_INVALID (44806923L) #endif /* WANT_UTMP */ #define PTY_OPEN_SLAVE_TOOSHORT (44806924L) #define ERROR_TABLE_BASE_pty (44806912L) extern struct error_table et_pty_error_table; #define __LIBPTY_H__ #endif /* __LIBPTY_H__ */ ckuscr.c000664 045065 024037 00000044012 14767402107 012632 0ustar00fdckermit000000 000000 #include "ckcsym.h" #include "ckcdeb.h" #ifndef NOICP #ifndef NOSCRIPT char *loginv = "Script Command, 10.0.033, 15 Apr 2023"; /* C K U S C R -- expect-send script implementation */ /* Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Original (version 1, 1985) author: Herm Fischer, Encino, CA. Contributed to Columbia University in 1985 for inclusion in C-Kermit 4.0. Maintained since 1985 by Frank da Cruz, fdc@columbia.edu. The module takes a UUCP-style script of the "expect send [expect send] ..." format. It is intended to operate similarly to the way the common UUCP L.sys login entries work. Conditional responses are supported: expect[-send-expect[...]], as with UUCP. The send keyword EOT sends a Control-d, and the keyword BREAK sends a break. Letters prefixed by '~' are '~b' backspace, '~s' space, '~n' linefeed, '~r' return, '~x' xon, '~t' tab, '~q' ? (not allowed on kermit command lines), '~' ~, '~'', '~"', '~c' don't append return, '~o[o[o]]' octal character. As with some uucp systems, sent strings are followed by ~r (not ~n) unless they end with ~c. Null expect strings (e.g., ~0 or --) cause a short delay, and are useful for sending sequences requiring slight pauses. This module calls externally defined system-dependent functions for communications i/o, as defined in ckcplm.txt, the C-Kermit Program Logic Manual, and thus should be portable to all systems that implement those functions, and where alarm() and signal() work as they do in UNIX. */ #include #ifdef NT #include #else /* NT */ #include #endif /* NT */ #include "ckcasc.h" #include "ckcker.h" #include "ckuusr.h" #include "ckcnet.h" #ifdef OS2 #include "ckosyn.h" #include "ckothr.h" #endif /* OS2 */ #include "ckcsig.h" #include "ckcfnp.h" /* Prototypes (must be last) */ _PROTOTYP( VOID flushi, (void) ); _PROTOTYP( static VOID myflsh, (void) ); _PROTOTYP( static int sequenc, (void) ); _PROTOTYP( static VOID recvseq, (void) ); _PROTOTYP( static int outseq, (void) ); #ifdef OS2 _PROTOTYP( int scriptwrtbuf, (unsigned short)); #ifdef NT #ifdef CK_LOGIN VOID setntcreds(); #endif /* CK_LOGIN */ #endif /* NT */ #endif /* OS2 */ #ifdef MAC #define signal msignal #define SIGTYP long #define alarm malarm #define SIG_IGN 0 #define SIGALRM 1 #define SIGINT 2 SIGTYP (*msignal(int type, SIGTYP (*func)(int)))(int); #endif /* MAC */ #ifdef AMIGA #define signal asignal #define alarm aalarm #define SIGALRM (_NUMSIG+1) #define SIGTYP void SIGTYP (*asignal(int type, SIGTYP (*func)(int)))(int); unsigned aalarm(unsigned); #endif /* AMIGA */ #ifdef STRATUS /* VOS doesn't have alarm(), but it does have some things we can work with. */ /* however, we have to catch all the signals in one place to do this, so */ /* we intercept the signal() routine and call it from our own replacement. */ #define signal vsignal #define alarm valarm SIGTYP (*vsignal(int type, SIGTYP (*func)(int)))(int); int valarm(int interval); #endif /* STRATUS */ extern int sessft; extern int local, flow, seslog, mdmtyp, msgflg, duplex, backgrd, secho, quiet; extern int network, nettype, ttnproto; extern long speed; extern char ttname[]; #ifdef NTSIG extern int TlsIndex; #endif /* NTSIG */ #ifdef IKSD extern int inserver; #endif /* IKSD */ static int is_tn = 0; /* Do Telnet negotiations */ #ifndef NOSPL #ifdef DCMDBUF extern struct cmdptr *cmdstk; #else extern struct cmdptr cmdstk[]; #endif /* DCMDBUF */ extern int techo, cmdlvl; extern int mecho; #endif /* NOSPL */ static int scr_echo; /* Whether to echo script commands */ static int exp_alrm = 15; /* Time to wait for expect string */ #define SND_ALRM 15 /* Time to allow for sending string */ #define NULL_EXP 2 /* Time to pause on null expect strg*/ #define DEL_MSEC 300 /* Milliseconds to pause on ~d */ #define SBUFL 512 static char seq_buf[SBUFL+2], *s; /* expect-send sequence buffer */ static int got_it, no_cr; /* Connect state parent/child communication signal handlers */ #ifdef COMMENT #ifdef CK_POSIX_SIG static sigjmp_buf alrmrng; #else static jmp_buf alrmrng; #endif /* CK_POSIX_SIG */ #else static ckjmpbuf alrmrng; #endif /* COMMENT */ static SIGTYP #ifdef CK_ANSIC scrtime(int foo) /* modem read failure handler, */ #else scrtime(foo) int foo; /* Alarm handler */ #endif /* CK_ANSIC */ /* scrtime */ { #ifdef BEBOX #ifdef BE_DR_7 alarm_expired(); #endif /* BE_DR_7 */ #endif /* BEBOX */ #ifdef NTSIG if (foo == SIGALRM) PostAlarmSigSem(); else PostCtrlCSem(); #else /* NTSIG */ #ifdef NT cklongjmp(ckjaddr(alrmrng),1); #else /* NT */ cklongjmp(alrmrng,1); #endif /* NT */ #endif /* NTSIG */ SIGRETURN; } /* Sequence interpreter -- pick up next sequence from command string, decode escapes and place into seq_buf. If string contains a ~d (delay) then sequenc() returns a 1 expecting to be called again after the ~d executes. */ static int sequenc() { int i; char c, oct_char; no_cr = 0; /* output needs cr appended */ for (i = 0; i < SBUFL; ) { if (*s == '\0' || *s == '-' || isspace(*s) ) { /* done */ seq_buf[i] = '\0'; return(0) ; } if (*s == '~') { /* escape character */ s++; switch (c = *s) { case 'n': seq_buf[i++] = LF; break; case 'r': seq_buf[i++] = CK_CR; break; case 't': seq_buf[i++] = '\t'; break; case 'b': seq_buf[i++] = '\b'; break; case 'q': seq_buf[i++] = '?'; break; #ifdef COMMENT /* The default case should catch these now... */ case '~': seq_buf[i++] = '~'; break; case '-': seq_buf[i++] = '-'; break; #endif /* COMMENT */ case '\'': seq_buf[i++] = '\''; break; case '\"': seq_buf[i++] = '\"'; break; case 's': seq_buf[i++] = ' '; break; case 'x': seq_buf[i++] = '\021'; break; case 'c': no_cr = 1; break; case 'd': { /* send what we have & then */ seq_buf[i] = '\0'; /* expect to send rest after */ no_cr = 1; /* sender delays a little */ s++; return(1); } case 'w': { /* wait count */ exp_alrm = 15; /* default to 15 sec */ if (isdigit(*(s+1))) { s++; exp_alrm = *s & 15; if (isdigit(*(s+1)) ) { s++; exp_alrm = exp_alrm * 10 + (*s & 15); } } break; } default: if ( isdigit(c) ) { /* octal character */ oct_char = (char) (c & 7); /* most significant digit */ if (isdigit( *(s+1) ) ) { s++; oct_char = (char) ((oct_char<<3) | ( *s & 7 )); if (isdigit( *(s+1) ) ) { s++; oct_char = (char) ((oct_char<<3) | ( *s & 7 )); } } seq_buf[i++] = oct_char; break; } else seq_buf[i++] = *s; /* Treat ~ as quote */ } } else seq_buf[i++] = *s; /* Plain old character */ s++; } seq_buf[i] = '\0'; return(0); /* end of space, return anyway */ } /* Output buffering for "recvseq" and "flushi" */ #define MAXBURST 256 /* maximum size of input burst */ static CHAR conbuf[MAXBURST]; /* buffer to hold output for console */ static int concnt = 0; /* number of characters buffered */ static CHAR sesbuf[MAXBURST]; /* buffer to hold output for session log */ static int sescnt = 0; /* number of characters buffered */ static VOID myflsh() { if (concnt > 0) { conxo(concnt, (char *) conbuf); concnt = 0; } if (sescnt > 0) { logstr((char *) sesbuf, sescnt); sescnt = 0; } } /* these variables are used to pass data between the recvseq() */ /* and the dorseq(). They are necessary because in some versions */ /* dorseq() is executed in a separate thread and data cannot be */ /* passed by parameter. */ static char *rseqe, * rseqgot, * rseqtrace ; static int rseql; static SIGTYP #ifdef CK_ANSIC dorseq(void * threadinfo) #else /* CK_ANSIC */ dorseq(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ /* dorseq */ { int i, x; int burst = 0; /* chars remaining in input burst */ #ifdef NTSIG setint(); if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); } #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef NT #ifdef IKSD if (inserver) setntcreds(); #endif /* IKSD */ #endif /* NT */ #endif /* CK_LOGIN */ while (!got_it) { for (i = 0; i < rseql-1; i++) rseqgot[i] = rseqgot[i+1]; x = ttinc(0); /* Read a character */ debug(F101,"recvseq","",x); if (x < 0) { #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; /* Check for error */ } #ifdef NETCONN #ifdef TNCODE /* Check for telnet protocol negotiation */ if (((x & 0xff) == IAC) && is_tn) { /* Telnet negotiation */ myflsh(); burst = 0; switch (tn_doop((CHAR)(x & 0xff),duplex,ttinc)) { case 2: duplex = 0; continue; case 1: duplex = 1; default: continue; } } #endif /* TNCODE */ #endif /* NETCONN */ rseqgot[rseql-1] = (char) (x & 0x7f); /* Got a character */ burst--; /* One less waiting */ if (scr_echo) conbuf[concnt++] = rseqgot[rseql-1]; /* Buffer it */ if (seslog) /* Log it in session log */ #ifdef UNIX if (sessft != 0 || rseqgot[rseql-1] != '\r') #else #ifdef OSK if (sessft != 0 || rseqgot[rseql-1] != '\012') #endif /* OSK */ #endif /* UNIX */ if (rseqgot[rseql-1]) /* Filter out NULs */ sesbuf[sescnt++] = rseqgot[rseql-1]; if ((int)strlen(rseqtrace) < SBUFL-2 ) strcat(rseqtrace,dbchr(rseqgot[rseql-1])); got_it = (!strncmp(rseqe, rseqgot, rseql)); if (burst <= 0) { /* Flush buffered output */ myflsh(); if ((burst = ttchk()) < 0) { /* Get size of next input burst */ #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; } /* prevent overflow of "conbuf" and "sesbuf" */ if (burst > MAXBURST) burst = MAXBURST; } } #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; } static SIGTYP #ifdef CK_ANSIC failrseq(void * threadinfo) #else /* CK_ANSIC */ failrseq(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ /* failrseq */ { got_it = 0; /* Timed out here */ SIGRETURN; } /* Receive sequence -- see if expected response comes, return success (or failure) in got_it. */ static VOID recvseq() { char *e, got[7], trace[SBUFL]; int i, l; sequenc(); l = (int)strlen(e=seq_buf); /* no more than 7 chars allowed */ if (l > 7) { e += l-7; l = 7; } tlog(F111,"expecting sequence",e,(long) l); if (l == 0) { /* null sequence, delay a little */ sleep (NULL_EXP); got_it = 1; tlog(F100,"got it (null sequence)","",0L); return; } *trace = '\0'; for (i = 0; i < 7; i++) got[i]='\0'; rseqtrace = trace; rseqe = e; rseqgot = got; rseql = l; alrm_execute(ckjaddr(alrmrng), exp_alrm, scrtime, dorseq, failrseq); tlog(F110,"received sequence: ",trace,0L); tlog(F101,"returning with got-it code","",(long) got_it); myflsh(); /* Flush buffered output */ return; } /* Output A Sequence starting at pointer s, return 0 if okay, 1 if failed to read (modem hangup or whatever) */ static int oseqret = 0; /* Return code for outseq */ /* Out here to prevent clobbering */ /* by longjmp. */ static SIGTYP #ifdef CK_ANSIC dooseq(void * threadinfo) #else /* CK_ANSIC */ dooseq(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ { int l; char *sb; #ifdef TCPSOCKET extern int tn_nlm, tn_b_nlm; #endif /* TCPSOCKET */ #ifdef NTSIG setint(); if (threadinfo) { /* Thread local storage... */ TlsSetValue(TlsIndex,threadinfo); } #endif /* NTSIG */ #ifdef CK_LOGIN #ifdef NT #ifdef IKSD if (inserver) setntcreds(); #endif /* IKSD */ #endif /* NT */ #endif /* CK_LOGIN */ l = (int)strlen(seq_buf); tlog(F111,"sending sequence ",seq_buf,(long) l); if (!strcmp(seq_buf,"EOT")) { ttoc(dopar('\004')); if (scr_echo) conol(""); if (seslog && duplex) logstr("",5); } else if (!strcmp(seq_buf,"BREAK") || !strcmp(seq_buf,"\\b") || !strcmp(seq_buf,"\\B")) { ttsndb(); if (scr_echo) conol(""); if (seslog) logstr("{BREAK}",7); } else { if (l > 0) { for ( sb = seq_buf; *sb; sb++) *sb = dopar(*sb); /* add parity */ ttol((CHAR *)seq_buf,l); /* send it */ if (scr_echo && duplex) { #ifndef NOLOCAL #ifdef OS2 { /* Echo to emulator */ char *s = seq_buf; while (*s) { scriptwrtbuf((USHORT)*s); } } #endif /* OS2 */ #endif /* NOLOCAL */ conxo(l,seq_buf); } if (seslog && duplex) /* log it */ logstr(seq_buf,strlen(seq_buf)); } if (!no_cr) { ttoc( dopar(CK_CR) ); #ifdef TCPSOCKET if (is_tn) { if (!TELOPT_ME(TELOPT_BINARY) && tn_nlm != TNL_CR) ttoc((char)((tn_nlm == TNL_CRLF) ? dopar(LF) : dopar(NUL))); else if (TELOPT_ME(TELOPT_BINARY) && (tn_b_nlm == TNL_CRLF || tn_b_nlm == TNL_CRNUL)) ttoc((char)((tn_b_nlm == TNL_CRLF) ? dopar(LF) : dopar(NUL))); } #endif /* TCPSOCKET */ if (seslog && duplex) logchar(dopar(CK_CR)); } } #ifdef NTSIG ckThreadEnd(threadinfo); #endif /* NTSIG */ SIGRETURN; } SIGTYP #ifdef CK_ANSIC failoseq(void * threadinfo) #else /* CK_ANSIC */ failoseq(threadinfo) VOID * threadinfo; #endif /* CK_ANSIC */ /* failoseq */ { oseqret = -1; /* else -- alarm rang */ SIGRETURN; } static int outseq() { int delay; oseqret = 0; /* Initialize return code */ while(1) { delay = sequenc(); alrm_execute( ckjaddr(alrmrng), SND_ALRM, scrtime, dooseq, failoseq ) ; if (!delay) return(oseqret); #ifndef MAC msleep(DEL_MSEC); /* delay, loop to next send */ #endif /* MAC */ } } /* L O G I N -- (historical misnomer) Execute the SCRIPT command */ int #ifdef CK_ANSIC dologin( char *cmdstr ) #else dologin(cmdstr) char *cmdstr; #endif /* CK_ANSIC */ { #ifdef OS2 #ifdef NT SIGTYP (* savealm)(int); /* Save incoming alarm function */ #else /* NT */ SIGTYP (* volatile savealm)(int); /* Save incoming alarm function */ #endif /* NT */ #else /* OS2 */ SIGTYP (*savealm)(); /* Save incoming alarm function */ #endif /* OS2 */ char *e; s = cmdstr; /* Make global to this module */ tlog(F100,loginv,"",0L); if (speed < 0L) speed = ttgspd(); if (ttopen(ttname,&local,mdmtyp,0) < 0) { ckmakmsg(seq_buf,SBUFL,"Sorry, can't open ",ttname,NULL,NULL); perror(seq_buf); return(0); } /* Whether to echo script commands ... */ scr_echo = (!quiet && !backgrd && secho); #ifndef NOSPL if (scr_echo && cmdlvl > 1) { if (cmdstk[cmdlvl].src == CMD_TF) scr_echo = techo; if (cmdstk[cmdlvl].src == CMD_MD) scr_echo = mecho; } #endif /* NOSPL */ if (scr_echo) { #ifdef NETCONN if (network) printf("Executing SCRIPT to host %s.\n",ttname); else #endif /* NETCONN */ printf("Executing SCRIPT through %s, speed %ld.\n",ttname,speed); } #ifdef TNCODE /* TELNET input must be scanned for IAC */ is_tn = (local && network && IS_TELNET()) || (!local && sstelnet); #endif /* TNCODE */ *seq_buf = 0; for (e = s; *e; e++) ckstrncat(seq_buf,dbchr(*e),SBUFL); #ifdef COMMENT /* Skip this because it tends to contain a password... */ if (scr_echo) printf("SCRIPT string: %s\n",seq_buf); #endif /* COMMENT */ tlog(F110,"SCRIPT string: ",seq_buf, 0L); /* Condition console terminal and communication line... */ if (ttvt(speed,flow) < 0) { printf("Sorry, Can't condition communication line\n"); return(0); } /* Save initial timer interrupt value */ savealm = signal(SIGALRM,SIG_IGN); flushi(); /* Flush stale input */ /* start expect - send sequence */ while (*s) { /* While not done with buffer */ while (*s && isspace(*s)) s++; /* Skip over separating whitespaces */ /* Gather up expect sequence */ got_it = 0; recvseq(); while (!got_it) { /* Have it yet? */ if (*s++ != '-') /* No, is there a conditional send? */ goto failret; /* No, return failure */ flushi(); /* Yes, flush out input buffer */ if (outseq()) /* If unable to send, */ goto failret; /* return failure. */ if (*s++ != '-') /* If no conditional response here, */ goto failret; /* return failure. */ recvseq(); /* All OK, read response from host. */ } /* Loop back and check got_it */ while (*s && !isspace(*s++) ) ; /* Skip over conditionals */ while (*s && isspace(*s)) s++; /* Skip over separating whitespaces */ flushi(); /* Flush */ if (*s) if (outseq()) goto failret; /* If any */ } signal(SIGALRM,savealm); if (scr_echo) printf("Script successful.\n"); tlog(F100,"Script successful.","",0L); return(1); failret: signal(SIGALRM,savealm); if (scr_echo) printf("Sorry, script failed\n"); tlog(F100,"Script failed","",0L); return(0); } /* F L U S H I -- Flush, but log, SCRIPT input buffer */ VOID flushi() { int n, x; if ( seslog /* Logging session? */ || scr_echo /* Or console echoing? */ #ifdef NETCONN #ifdef TNCODE /* TELNET input must be scanned for IAC */ || is_tn #endif /* TNCODE */ #endif /* NETCONN */ ) { if ((n = ttchk()) < 0) /* Yes, anything in buffer? */ return; if (n > MAXBURST) n = MAXBURST; /* Make sure not too much, */ myflsh(); /* and that buffers are empty. */ while (n-- > 0) { x = ttinc(0); /* Collect a character */ #ifdef NETCONN #ifdef TNCODE /* Check for telnet protocol negotiation */ if (is_tn && ((x & 0xff) == IAC) ) { myflsh(); /* Sync output */ switch (tn_doop((CHAR)(x & 0xff),duplex,ttinc)) { case 2: duplex = 0; break; case 1: duplex = 1; default: break; } /* Recalculate flush count */ if ((n = ttchk()) < 0) return; if (n > MAXBURST) n = MAXBURST; continue; } #endif /* TNCODE */ #endif /* NETCONN */ if (scr_echo) conbuf[concnt++] = (CHAR) x; /* buffer for console */ if (seslog) #ifdef UNIX if (sessft != 0 || x != '\r') #else #ifdef OSK if (sessft != 0 || x != '\012') #endif /* OSK */ #endif /* UNIX */ sesbuf[sescnt++] = (CHAR) x; /* buffer for session log */ } myflsh(); } else ttflui(); /* Otherwise just flush. */ } #else /* NOSCRIPT */ char *loginv = "Script Command Disabled"; #endif /* NOSCRIPT */ #endif /* NOICP */ ckusig.c000664 045065 024037 00000016226 14767402113 012630 0ustar00fdckermit000000 000000 char *ckusigv = "Signal support, 10.0.100, 23 Sep 2022"; /* C K U S I G -- Kermit signal handling for Unix and OS/2 systems */ /* Author: Jeffrey Altman (jaltman@secure-endpoints.com), Secure Endpoints Inc., New York City. Copyright (C) 1985, 2022, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ #include "ckcsym.h" #include "ckcasc.h" /* ASCII character symbols */ #include "ckcdeb.h" /* Debug & other symbols */ #include "ckcker.h" /* Kermit symbols */ #include "ckcnet.h" /* Network symbols */ #ifndef NOSPL #include "ckuusr.h" #endif /* NOSPL */ #include #ifdef NT #include #include #else /* NT */ #include #endif /* NT */ #include "ckcsig.h" #include "ckcfnp.h" /* Prototypes (must be last) */ #ifdef NOCCTRAP extern ckjmpbuf cmjbuf; #endif /* NOCCTRAP */ #ifdef MAC #define signal msignal #define SIGTYP long #define alarm malarm #define SIG_IGN 0 #define SIGALRM 1 #define SIGINT 2 SIGTYP (*msignal(int type, SIGTYP (*func)(int)))(int); #endif /* MAC */ #ifdef STRATUS /* We know these are set here. MUST unset them before the definitions. */ #define signal vsignal #define alarm valarm SIGTYP (*vsignal(int type, SIGTYP (*func)(int)))(int); int valarm(int interval); #endif /* STRATUS */ #ifdef AMIGA #define signal asignal #define alarm aalarm #define SIGALRM (_NUMSIG+1) #define SIGTYP void SIGTYP (*asignal(int type, SIGTYP (*func)(int)))(int); unsigned aalarm(unsigned); #endif /* AMIGA */ #ifdef NTASM DWORD ckgetIP(void) { __asm { mov eax, dword ptr [esp+0x10] jmp ckgetIP + 0x18 } return 1; } #endif /* NTASM */ #ifdef NT DWORD exception_filter( void ) { GetExceptionInformation ; return( EXCEPTION_EXECUTE_HANDLER ) ; } void crash( void ) { int x = 0, y = 0 ; x / y ; } #endif /* NT */ #ifndef NOCCTRAP int #ifdef CK_ANSIC cc_execute( ckjptr(sj_buf), ck_sigfunc dofunc, ck_sigfunc failfunc ) #else cc_execute( sj_buf, dofunc, failfunc) ckjptr(sj_buf); ck_sigfunc dofunc; ck_sigfunc failfunc; #endif /* CK_ANSIC */ /* cc_execute */ { int rc = 0 ; #ifdef NTASM DWORD Eip, Esp ; isinterrupted = 0; sj_buf->retcode = 0 ; sj_buf->Id = GetCurrentThreadId() ; memset( &sj_buf->context, 0, sizeof(CONTEXT) ); sj_buf->context.ContextFlags = CONTEXT_FULL ; #ifndef COMMENT GetThreadContext(GetCurrentThread(), &(sj_buf->context) ) ; __asm { mov ecx,dword ptr [sj_buf] mov dword ptr [ecx+0xc4],esp } sj_buf->context.EFlags = 530 ; sj_buf->context.Eip = ckgetIP()+0x0C ; #else /* COMMENT */ __asm { mov eax, dword ptr [sj_buf] push eax mov eax, 0xfffffffe push eax mov eax, 0x00000039 mov edx,esp int 0x2e pop eax pop eax } #endif /* COMMENT */ #endif /* NTASM */ if ( #ifdef NTASM isinterrupted #else cksetjmp(ckjdref(sj_buf)) #endif /* NTASM */ ) { #ifdef NTASM __asm { mov esp, ESPToRestore } isinterrupted = 0 ; #endif /* NTASM */ (*failfunc)(NULL) ; #ifdef NTASM rc = sj_buf->retcode ; #else /* NTASM */ rc = -1 ; #endif /* NTASM */ } else { #ifdef NT __try { (*dofunc)(NULL); } __except(exception_filter()) { debug(F100,"cc_execute __except","",0); debug(F111, "exception_filter", "_exception_code", etExceptionCode() ); longjmp(ckjdref(sj_buf),SIGINT); } #else /* NT */ (*dofunc)(NULL); #endif /* NT */ } return rc ; } #endif /* NOCCTRAP */ int #ifdef CK_ANSIC /* ANSIC C declaration... */ alrm_execute(ckjptr(sj_buf), int timo, ck_sighand handler, ck_sigfunc dofunc, ck_sigfunc failfunc ) #else /* Not ANSIC C ... */ alrm_execute(sj_buf, timo, handler, dofunc, failfunc ) ckjptr(sj_buf); int timo; ck_sighand handler; ck_sigfunc dofunc; ck_sigfunc failfunc; #endif /* CK_ANSIC */ /* alrm_execute */ { int rc = 0; int savalrm = 0; _PROTOTYP(SIGTYP (*savhandler), (int)); savalrm = alarm(timo); savhandler = signal(SIGALRM, handler); #ifdef NTASM sj_buf->retcode = 0 ; sj_buf->Id = GetCurrentThreadId(); memset(&sj_buf->context, 0, sizeof(CONTEXT)); sj_buf->context.ContextFlags = CONTEXT_FULL; #ifndef COMMENT GetThreadContext(GetCurrentThread(), &(sj_buf->context)); #else __asm { mov eax, dword ptr [sj_buf] push eax mov eax, 0xfffffffe push eax mov eax, 0x00000039 mov edx,esp int 0x2e pop eax pop eax } #endif isinterrupted = 0; #endif /* NTASM */ if ( #ifdef NTASM sj_buf->retcode #else cksetjmp(ckjdref(sj_buf)) #endif /* NTASM */ ) { (*failfunc)(NULL) ; rc = -1 ; } else { #ifdef NT __try { (*dofunc)(NULL) ; } __except( exception_filter() ) { debug(F100,"alrm_execute __except","",0); debug(F111,"exception_filter", "_exception_code", GetExceptionCode() ); longjmp(ckjdref(sj_buf),SIGINT); } #else /* NT */ (*dofunc)(NULL) ; #endif /* NT */ } alarm(savalrm) ; if ( savhandler ) signal( SIGALRM, savhandler ) ; return rc ; } int #ifdef CK_ANSIC /* ANSIC C declaration... */ cc_alrm_execute(ckjptr(sj_buf), int timo, ck_sighand handler, ck_sigfunc dofunc, ck_sigfunc failfunc ) #else /* Not ANSIC C ... */ cc_alrm_execute(sj_buf, timo, handler, dofunc, failfunc ) ckjptr(sj_buf); int timo; ck_sighand handler; ck_sigfunc dofunc; ck_sigfunc failfunc; #endif /* CK_ANSIC */ /* cc_alrm_execute */ { int rc = 0; int savalrm = 0; _PROTOTYP(SIGTYP (*savhandler), (int)); savalrm = alarm(timo); savhandler = signal( SIGALRM, handler ); #ifdef NTASM sj_buf->retcode = 0 ; sj_buf->Id = GetCurrentThreadId() ; memset( &sj_buf->context, 0, sizeof(CONTEXT) ); sj_buf->context.ContextFlags = CONTEXT_FULL ; #ifndef COMMENT GetThreadContext( GetCurrentThread(), &(sj_buf->context) ) ; #else __asm { mov eax, dword ptr [sj_buf] push eax mov eax, 0xfffffffe push eax mov eax, 0x00000039 mov edx,esp int 0x2e pop eax pop eax } #endif isinterrupted = 0; #endif /* NTASM */ if ( #ifdef NTASM sj_buf->retcode #else cksetjmp(ckjdref(sj_buf)) #endif /* NTASM */ ) { (*failfunc)(NULL) ; rc = -1 ; } else { #ifdef NT __try { (*dofunc)(NULL) ; } __except( exception_filter() ) { debug(F100,"cc_alrm_execute __except","",0); debug(F111, "exception_filter", "_exception_code", GetExceptionCode() ); longjmp(ckjdref(sj_buf),SIGINT) ; } #else /* NT */ (*dofunc)(NULL) ; #endif /* NT */ } alarm(savalrm); if (savhandler) signal(SIGALRM,savhandler); return(rc); } ckusig.h000664 045065 024037 00000004107 14767402117 012634 0ustar00fdckermit000000 000000 /* C K U S I G . H */ /* Definitions and prototypes for signal handling */ /* Author: Jeffrey E Altman (jaltman@secure-endpoints.com), Secure Endpoints Inc., New York City. Copyright (C) 1985, 2009, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ #ifdef CK_ANSIC typedef void (*ck_sigfunc)(void *); typedef void (*ck_sighand)(int); #else typedef VOID (*ck_sigfunc)(); typedef VOID (*ck_sighand)(); #endif /* CK_ANSIC */ /* Macros for POSIX vs old-style signal handling. */ #ifdef CK_POSIX_SIG typedef sigjmp_buf ckjmpbuf; #else typedef jmp_buf ckjmpbuf; #endif /* CK_POSIX_SIG */ /* Suppose you want to pass the address of a jmp_buf bar to a function foo. Since jmp_buf is normally defined (typedef'd) as an array, you would do it like this: foo(bar), where foo = foo(jmp_buf bar). But suppose a jmp_buf is (say) a struct rather than an array. Then you must do foo(&bar) where foo is foo(jmp_buf * bar). This is controlled here in the traditional fashion, by ifdefs. By default, we assume that jmp_buf is an array. Define the symbol JBNOTARRAY if jmp_buf is not an array. */ #ifndef JBNOTARRAY #ifdef NT #define JBNOTARRAY #endif /* NT */ #endif /* JBNOTARRAY */ #ifdef JBNOTARRAY typedef ckjmpbuf * ckjptr; #define ckjaddr(x) & x #define ckjdref(x) * x #ifdef CK_POSIX_SIG #define cksetjmp(x) sigsetjmp(x,1) #else #define cksetjmp(x) setjmp(x,1) #endif /* CK_POSIX_SIG */ #else /* jmp_buf is an array */ typedef ckjmpbuf ckjptr; #define ckjaddr(x) x #define ckjdref(x) x #ifdef CK_POSIX_SIG #define cksetjmp sigsetjmp #else #define cksetjmp setjmp #endif /* CK_POSIX_SIG */ #endif /* JBNOTARRAY */ _PROTOTYP( int cc_execute, (ckjptr, ck_sigfunc, ck_sigfunc) ); _PROTOTYP( int alrm_execute, (ckjptr, int timo, ck_sighand handler, ck_sigfunc, ck_sigfunc) ); _PROTOTYP( int cc_alrm_execute, (ckjptr, int timo, ck_sighand handler, ck_sigfunc, ck_sigfunc) ); /* End of ckusig.h */ ckustr.c000664 045065 024037 00000022007 14767402123 012651 0ustar00fdckermit000000 000000 /* * ckustr.c - string extraction/restoration routines */ #include #include #include #include #include "ckcfnp.h" /* Prototypes (must be last) */ /* STR_FILE must be defined as a quoted string on the cc command line, for example: -DSTR_FILE=\\\"/usr/local/lib/cku196.sr\\\" This is the file where the strings go, and where C-Kermit looks for them at runtime. */ #ifdef STR_FILE char *StringFile = STR_FILE; #else char *StringFile = "/usr/local/lib/cku196.sr"; #endif /* STR_FILE */ /* * If _PATH_CTIMED is defined (in ) then use that definition. 2.11BSD * has this defined but 2.10BSD and other systems do not. */ #ifndef _PATH_CTIMED #define _PATH_CTIMED STR_CTIMED #endif extern int errno; static int strfile = -1, ourpid = 0; #define BUFLEN 256 errprep(offset, buf) unsigned short offset; char *buf; { register int pid = getpid(); if (pid != ourpid) { ourpid = pid; if (strfile >= 0) { close(strfile); strfile = -1; } } if (strfile < 0) { char *p, *getenv(); if (p = getenv("KSTR")) if (strlen(p)) StringFile = p; strfile = open(StringFile, 0); if (strfile < 0) { oops: fprintf(stderr, "Cannot find %s\r\n", StringFile); exit(EX_OSFILE); } } if (lseek(strfile, (long) offset, 0) < 0 || read(strfile, buf, BUFLEN) <= 0) goto oops; } /* extracted string front end for printf() */ /*VARARGS1*/ strprerror(fmt, va_alist) int fmt; va_dcl { va_list ap; char buf[BUFLEN]; errprep(fmt, buf); va_start(ap); vprintf(buf, ap); va_end(ap); } /* extracted string front end for sprintf() */ /*VARARGS1*/ strsrerror(fmt, obuf, va_alist) int fmt; char *obuf; va_dcl { char buf[BUFLEN]; va_list ap; errprep(fmt, buf); va_start(ap); vsprintf(obuf, buf, ap); va_end(ap); } /* extracted string front end for fprintf() */ /*VARARGS1*/ strfrerror(fmt, fd, va_alist) int fmt; FILE *fd; va_dcl { va_list ap; char buf[BUFLEN]; errprep(fmt, buf); va_start(ap); vfprintf(fd, buf, ap); va_end(ap); } /* extracted string front end for perror() */ strperror(fmt) int fmt; { char buf[BUFLEN]; register int saverr = errno; errprep(fmt, buf); errno = saverr; perror(buf); } perror(str) char *str; { printf("%s: errno %d\n", str, errno); } /* * The following is needed _only_ on systems which do not have the C library * stubs for the ctime() and getpw*() functions. In 2.11BSD these are * present in the libstubs.a library and accessed via "-lstubs" at link time. * * 2.10BSD's cpp has the BSD2_10 symbol builtin. Other systems without * libstubs.a will need to define (via a -D option in CFLAGS) 'BSD2_10'. */ #ifdef BSD2_10 #include #include #include #include #define SEND_FD W[1] #define RECV_FD R[0] #define CTIME 1 #define ASCTIME 2 #define TZSET 3 #define LOCALTIME 4 #define GMTIME 5 #define OFFTIME 6 #define GETPWENT 7 #define GETPWNAM 8 #define GETPWUID 9 #define SETPASSENT 10 #define ENDPWENT 11 static int R[2], W[2], inited; static char result[256 + 4]; static struct tm tmtmp; static struct passwd _pw, *getandfixpw(); char * ctime(t) time_t *t; { u_char fnc = CTIME; sewer(); write(SEND_FD, &fnc, sizeof fnc); write(SEND_FD, t, sizeof (*t)); getb(RECV_FD, result, 26); return(result); } char * asctime(tp) struct tm *tp; { u_char fnc = ASCTIME; sewer(); write(SEND_FD, &fnc, sizeof fnc); write(SEND_FD, tp, sizeof (*tp)); getb(RECV_FD, result, 26); return(result); } void tzset() { u_char fnc = TZSET; sewer(); write(SEND_FD, &fnc, sizeof fnc); } struct tm * localtime(tp) time_t *tp; { u_char fnc = LOCALTIME; sewer(); write(SEND_FD, &fnc, sizeof fnc); write(SEND_FD, tp, sizeof (*tp)); getb(RECV_FD, &tmtmp, sizeof tmtmp); getb(RECV_FD, result, 24); tmtmp.tm_zone = result; return(&tmtmp); } struct tm * gmtime(tp) time_t *tp; { u_char fnc = GMTIME; sewer(); write(SEND_FD, &fnc, sizeof fnc); write(SEND_FD, tp, sizeof (*tp)); getb(RECV_FD, &tmtmp, sizeof tmtmp); getb(RECV_FD, result, 24); tmtmp.tm_zone = result; return(&tmtmp); } struct tm * offtime(clock, offset) time_t *clock; long offset; { u_char fnc = OFFTIME; sewer(); write(SEND_FD, &fnc, sizeof fnc); write(SEND_FD, clock, sizeof (*clock)); write(SEND_FD, &offset, sizeof offset); getb(RECV_FD, &tmtmp, sizeof tmtmp); tmtmp.tm_zone = ""; return(&tmtmp); } struct passwd * getpwent() { u_char fnc = GETPWENT; sewer(); write(SEND_FD, &fnc, sizeof fnc); return(getandfixpw()); } struct passwd * getpwnam(nam) char *nam; { u_char fnc = GETPWNAM; char lnam[UT_NAMESIZE + 1]; int len; len = strlen(nam); if (len > UT_NAMESIZE) len = UT_NAMESIZE; bcopy(nam, lnam, len); lnam[len] = '\0'; sewer(); write(SEND_FD, &fnc, 1); write(SEND_FD, &len, sizeof (int)); write(SEND_FD, lnam, len); return(getandfixpw()); } struct passwd * getpwuid(uid) uid_t uid; { u_char fnc = GETPWUID; sewer(); write(SEND_FD, &fnc, sizeof fnc); write(SEND_FD, &uid, sizeof (uid_t)); return(getandfixpw()); } setpwent() { return(setpassent(0)); } setpassent(stayopen) int stayopen; { u_char fnc = SETPASSENT; int sts; sewer(); write(SEND_FD, &fnc, sizeof fnc); write(SEND_FD, &stayopen, sizeof (int)); getb(RECV_FD, &sts, sizeof (int)); return(sts); } void endpwent() { u_char fnc = ENDPWENT; sewer(); write(SEND_FD, &fnc, sizeof fnc); return; } /* setpwfile() is deprecated */ void setpwfile(file) char *file; { return; } struct passwd * getandfixpw() { short sz; getb(RECV_FD, &sz, sizeof (int)); if (sz == 0) return(NULL); getb(RECV_FD, &_pw, sizeof (_pw)); getb(RECV_FD, result, sz); _pw.pw_name += (int)result; _pw.pw_passwd += (int)result; _pw.pw_class += (int)result; _pw.pw_gecos += (int)result; _pw.pw_dir += (int)result; _pw.pw_shell += (int)result; return(&_pw); } getb(f, p, n) register int f, n; register char *p; { int i; while (n) { i = read(f, p, n); if (i <= 0) return; p += i; n -= i; } } sewer() { register int pid, ourpid = getpid(); if (inited == ourpid) return; if (inited) { close(SEND_FD); close(RECV_FD); } pipe(W); pipe(R); pid = vfork(); if (pid == 0) { /* child */ alarm(0); /* cancel alarms */ dup2(W[0], 0); /* parent write side to our stdin */ dup2(R[1], 1); /* parent read side to our stdout */ close(SEND_FD); /* copies made, close the... */ close(RECV_FD); /* originals now */ execl(_PATH_CTIMED, "ctimed", 0); _exit(EX_OSFILE); } if (pid == -1) abort(); /* nothing else really to do */ close(W[0]); /* close read side of SEND channel */ close(R[1]); /* close write side of RECV channel */ inited = ourpid; /* don't do this again in this proc */ } XXctime() { if (SEND_FD) close(SEND_FD); if (RECV_FD) close(RECV_FD); SEND_FD = RECV_FD = 0; inited = 0; } #endif /* BSD2_10 */ ckutio.c000664 045065 024037 00001620530 14767403177 012654 0ustar00fdckermit000000 000000 #define CKUTIO_C #ifdef aegis char *ckxv = "Aegis Communications support, 10.0.340, 16 May 2023"; #else #ifdef Plan9 char *ckxv = "Plan 9 Communications support, 10.0.340, 16 May 2023"; #else char *ckxv = "UNIX Communications support, 10.0.340, 16 May 2023"; #endif /* Plan9 */ #endif /* aegis */ /* C K U T I O */ /* C-Kermit interrupt, communications control and I/O functions for UNIX */ /* Author: Frank da Cruz (fdc@columbia.edu), The Kermit Project, Bronx, NY. Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ /* NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be compatible with C preprocessors that support only #ifdef, #else, #endif, #define, and #undef. Please do not use #if, logical operators, or other preprocessor features in any of the portable C-Kermit modules. You can, of course, use these constructions in platform-specific modules when they are supported by all compilers/preprocessors that could be used on that platform. */ extern int nettype; /* Defined in ckcmai.c */ extern int duplex; /* Includes */ #include "ckcsym.h" /* This must go first */ #include "ckcdeb.h" /* This must go second */ /* This is for -DNONET builds external SSH client builds */ #ifndef NETCONN #ifdef SSHCMD #define NETCONN #endif /* SSHCMD */ #endif /* NETCONN */ #ifdef OSF13 #ifdef CK_ANSIC #ifdef _NO_PROTO #undef _NO_PROTO #endif /* _NO_PROTO */ #endif /* CK_ANSIC */ #endif /* OSF13 */ #ifndef HPUXPRE65 #include /* Error number symbols */ #else #ifndef ERRNO_INCLUDED #include /* Error number symbols */ #endif /* ERRNO_INCLUDED */ #endif /* HPUXPRE65 */ #ifdef __386BSD__ #define ENOTCONN 57 #else #ifdef __bsdi__ #define ENOTCONN 57 #else #ifdef __FreeBSD__ #define ENOTCONN 57 #endif /* __FreeBSD__ */ #endif /* __bsdi__ */ #endif /* __386BSD__ */ #ifdef SCO_OSR504 #define NBBY 8 #endif /* SCO_OSR504 */ #ifdef Plan9 #define SELECT #include #include #define FD_SETSIZE (3 * sizeof(long) * 8) static struct timeval tv; #endif /* Plan9 */ #ifdef CLIX #include #endif /* CLIX */ #include "ckcnet.h" /* Symbols for network types. */ #ifdef CK_SSL #include "ck_ssl.h" #endif /* CK_SSL */ /* The directory-related includes are here because we need to test some file-system-related symbols to find out which system we're being compiled under. For example, MAXNAMLEN is defined in BSD4.2 but not 4.1. */ #ifdef SDIRENT /* Directory bits... */ #define DIRENT #endif /* SDIRENT */ #ifdef XNDIR #include #else /* !XNDIR */ #ifdef NDIR #include #else /* !NDIR, !XNDIR */ #ifdef RTU #include "/usr/lib/ndir.h" #else /* !RTU, !NDIR, !XNDIR */ #ifdef DIRENT #ifdef SDIRENT #include #else #include #endif /* SDIRENT */ #else /* !RTU, !NDIR, !XNDIR, !DIRENT, i.e. all others */ #include #endif /* DIRENT */ #endif /* RTU */ #endif /* NDIR */ #endif /* XNDIR */ #ifdef QNX #include #endif /* QNX */ #ifdef HPUX5 #ifndef TCPSOCKET /* I don't know why this is needed here since we never reference bzero(). */ /* But without it C-Kermit won't link in an HP-UX 5.xx non-TCP build. */ void bzero(s,n) char *s; int n; { extern char * memset(); memset(s,0,n); } #endif /* TCPSOCKET */ #endif /* HPUX5 */ /* Definition of HZ, used in msleep() */ #ifdef MIPS #define HZ ( 1000 / CLOCK_TICK ) #else /* MIPS */ #ifdef ATTSV #ifndef NAP #ifdef TRS16 #define HZ ( 1000 / CLOCK_TICK ) #endif /* TRS16 */ #ifdef NAPHACK #define nap(x) (void)syscall(3112, (x)) #define NAP #endif /* NAPHACK */ #endif /* NAP */ #endif /* ATTSV */ #endif /* MIPS */ #ifdef M_UNIX #undef NGROUPS_MAX /* Prevent multiple definition warnings */ #endif /* M_UNIX */ /* NOTE: HP-UX 8.0 has a , but there is no corresponding library routine, so _poll comes up undefined at link time. */ #ifdef CK_POLL #ifndef AIXRS /* IBM AIX needs special handling */ #include /* "standard" (SVID) i/o multiplexing, etc */ #else /* AIXRS */ #ifdef SVR4 /* AIX 3.2 is like SVID... */ #include #else /* But AIX 3.1 is not ... */ #include /* The include file is in include/sys */ #define events reqevents /* And it does not map IBM-specific member */ #define revents rtnevents /* names to the System V equivalents */ #endif /* SVR4 */ #endif /* AIXRS */ #endif /* CK_POLL */ #include /* Signals */ /* For setjmp and longjmp */ #ifndef ZILOG #include #else #include #endif /* ZILOG */ /* The following test differentiates between 4.1 BSD and 4.2 & later. If you have a 4.1BSD system with the DIRENT library, this test could mistakenly diagnose 4.2BSD and then later enable the use of system calls that aren't defined. If indeed there are such systems, we can use some other way of testing for 4.1BSD, or add yet another compile-time switch. */ #ifdef BSD4 #ifdef MAXNAMLEN #ifndef FT21 /* Except for Fortune. */ #ifndef FT18 #ifndef BELLV10 /* And Bell Labs Research UNIX V10 */ #define BSD42 #endif /* BELLV10 */ #endif /* FT18 */ #endif /* FT21 */ #endif /* MAXNAMLEN */ #endif /* BSD4 */ #ifdef SUNOS41 /* From Christian Corti */ #define BSD44ORPOSIX /* Uni Stuttgart */ #define SVORPOSIX /* February 2010 */ #include #include #include #include #endif /* SUNOS41 */ #ifdef SNI542 #include /* 299 for FIONREAD */ #endif /* SNI542 */ /* Minix 2.0 support added by Terry McConnell, Syracuse University No more sgtty interface, posix compliant. */ #ifdef MINIX2 #define _MINIX /* Needed for some Minix header files */ #define BSD44ORPOSIX #define SVORPOSIX #ifndef MINIX3 #define DCLTIMEVAL #endif /* MINIX3 */ #define NOFILEH #include #include #include #include #undef TIOCGETC /* defined in sys/ioctl.h, but not really supported */ #define TANDEM 0 #endif /* MINIX2 */ /* MINIX 1.0 support added by Charles Hedrick, Rutgers University . MINIX also has V7 enabled. */ #ifdef MINIX #define TANDEM 0 #define MYREAD #define NOSYSIOCTLH #include #endif /* MINIX */ #ifdef CK_REDIR /* needed only for REDIRECT command. */ /* If anybody can figure out how to make this work with NeXTSTEP, be my guest! (NeXTBlah/NeXTBlah/bsd/sys/wait.h does not define WEXITSTATUS) */ #ifndef CK_WAIT_H /* If wait.h not already included... */ #ifdef OSF /* force OSF to select POSIX wait */ #ifdef _BSD /* instead of BSD (see ckcdeb.h) */ #define CK_OSF_BSD #undef _BSD #endif /* _BSD */ #endif /* OSF */ #include /* Include it */ #ifdef OSF #ifdef CK_OSF_BSD #define _BSD /* Restore it */ #undef CK_OSF_BSD #endif /* CK_OSF_BSD */ #endif /* OSF */ #endif /* CK_WAIT_H */ #endif /* CK_REDIR */ #include "ckuver.h" /* Version herald */ char *ckxsys = HERALD; #ifdef CK_UTSNAME #include #ifdef TRU64 /* Tru64 UNIX 4.0 and later */ /* Verified on Tru64 4.0F - might break on 4.0E or earlier */ #include /* (don't know about OSF/1 or DU) */ #include #endif /* TRU64 */ #ifdef SOLARIS25 /* Solaris 2.5 and later */ #include /* (don't know about earlier ones) */ #endif /* SOLARIS25 */ #ifdef UW7 #ifndef SYS_NMLN #define SYS_NMLN 257 #endif /* NMLN */ #endif /* UW7 */ #ifdef HPUX9PLUS static int hpis800 = 0; #endif /* HPUX9PLUS */ #ifdef SYS_NMLN #define CK_SYSNMLN SYS_NMLN #else #ifdef _SYS_NMLN #define CK_SYSNMLN _SYS_NMLN #else #ifdef UTSLEN #define CK_SYSNMLN UTSLEN #else #define CK_SYSNMLN 31 #endif /* UTSLEN */ #endif /* _SYS_NMLN */ #endif /* SYS_NMLN */ char unm_mch[CK_SYSNMLN+1] = { '\0', '\0' }; char unm_mod[CK_SYSNMLN+1] = { '\0', '\0' }; char unm_nam[CK_SYSNMLN+1] = { '\0', '\0' }; char unm_rel[CK_SYSNMLN+1] = { '\0', '\0' }; char unm_ver[CK_SYSNMLN+1] = { '\0', '\0' }; #endif /* CK_UTSNAME */ #ifdef CIE #include /* For chasing symlinks, etc. */ #else #include #endif /* CIE */ #ifdef QNX /* 299 */ #ifndef IXANY #define IXANY 0 #endif /* IXANY */ #endif /* QNX */ /* UUCP lockfile material... */ #ifndef NOUUCP #ifdef USETTYLOCK #ifdef HAVE_LOCKDEV /* Red Hat baudboy/lockdev */ /* Watch out: baudboy.h references open() without making sure it has been declared, resulting in warnings on at least Red Hat 7.3. It's declared in fcntl.h, but we don't include that until later. In this case only, we include it here, and then the second include is harmless because in Red Hat Linux (the only place where you find baudboy.h) fcntl.h is protected from multiple inclusion by _FCNTL_H. - fdc, 10 May 2004. NOTE: Although Linux /usr/sbin/lockdev obviates the need for setuid or setgid bits to access the lockfile, C-Kermit will still need them to access the serial port itself unless the port is open for world read/write. Normally setgid uucp does the trick. Extra: HAVE_LOCKDEV has been added als openSuSE >= 11.3 doesn't use baudboy but ttylock. - jb, 26 Jul 2010 */ #include /* This has to come before baudboy */ #ifdef HAVE_BAUDBOY /* Red Hat baudboy/lockdev */ #include #else /* !HAVE_BAUDBOY */ /* openSuSE lock via ttylock */ #include #endif /* HAVE_BAUDBOY */ #define LOCK_DIR "/var/lock" /* (even though we don't care) */ #else /* !HAVE_LOCKDEV */ #ifdef USE_UU_LOCK #ifdef __FreeBSD__ #include /* FreeBSD */ #else #include /* OpenBSD */ #endif /* HAVE_LOCKDEV */ #endif /* __FreeBSD */ #endif /* USE_UU_LOCK */ #else /* USETTYLOCK */ /* Name of UUCP tty device lockfile */ #ifdef LINUXFSSTND #ifndef HDBUUCP #define HDBUUCP #endif /* HDBUUCP */ #endif /* LINUXFSSTND */ #ifdef ACUCNTRL #define LCKDIR #endif /* ACUCNTRL */ /* PIDSTRING means use ASCII string to represent pid in lockfile. */ #ifndef PIDSTRING #ifdef HDBUUCP #define PIDSTRING #else #ifdef BSD44 #define PIDSTRING #else #ifdef RTAIX #define PIDSTRING #else #ifdef AIXRS #define PIDSTRING #else #ifdef COHERENT #define PIDSTRING #endif /* COHERENT */ #endif /* AIXRS */ #endif /* RTAIX */ #endif /* BSD44 */ #endif /* HDBUUCP */ #endif /* PIDSTRING */ /* Now the PIDSTRING exceptions... */ #ifdef PIDSTRING #ifdef HPUX #undef PIDSTRING #endif /* HPUX */ #endif /* PIDSTRING */ #ifdef __bsdi__ /* BSDI (at least thru 1.1) */ #ifdef PIDSTRING #undef PIDSTRING #endif /* PIDSTRING */ #endif /* __bsdi__ */ #ifdef OSF32 /* Digital UNIX (OSF/1) 3.2 */ #ifdef PIDSTRING #undef PIDSTRING #endif /* PIDSTRING */ #endif /* OSF32 */ /* LOCK_DIR is the name of the lockfile directory. If LOCK_DIR is already defined (e.g. on command line), we don't change it. */ #ifndef LOCK_DIR #ifdef MACOSX #define LOCK_DIR "/var/spool/lock" #endif /* MACOSX */ #endif/* LOCK_DIR */ #ifndef LOCK_DIR #ifdef BSD44 #ifdef __386BSD__ #define LOCK_DIR "/var/spool/lock" #else #ifdef __FreeBSD__ #define LOCK_DIR "/var/spool/lock" #else #ifdef __NetBSD__ #define LOCK_DIR "/var/spool/lock" #else #ifdef __OpenBSD__ #define LOCK_DIR "/var/spool/lock" #else /* So which ones is this for? */ /* Probably original 4.4BSD on Vangogh */ /* Plus who knows about Mac OS X... It doesn't even have a cu program */ #define LOCK_DIR "/var/spool/uucp" #endif /* __OpenBSD__ */ #endif /* __NetBSD__ */ #endif /* __FreeBSD__ */ #endif /* __386BSD__ */ #else #ifdef DGUX430 #define LOCK_DIR "/var/spool/locks" #else #ifdef HPUX10 #define LOCK_DIR "/var/spool/locks" #else #ifdef RTAIX /* IBM RT PC AIX 2.2.1 */ #define LOCK_DIR "/etc/locks" #else #ifdef AIXRS #define LOCK_DIR "/etc/locks" #else #ifdef ISIII #define LOCK_DIR "/etc/locks" #else #ifdef HDBUUCP #ifdef M_SYS5 #define LOCK_DIR "/usr/spool/uucp" #else #ifdef M_UNIX #define LOCK_DIR "/usr/spool/uucp" #else #ifdef SVR4 #define LOCK_DIR "/var/spool/locks" #else #ifdef SUNOS4 #define LOCK_DIR "/var/spool/locks" #else #ifdef LINUXFSSTND #define LOCK_DIR "/var/lock" #else #define LOCK_DIR "/usr/spool/locks" #endif /* LINUXFSSTND */ #endif /* SUNOS4 */ #endif /* SVR4 */ #endif /* M_UNIX */ #endif /* M_SYS5 */ #else #ifdef LCKDIR #define LOCK_DIR "/usr/spool/uucp/LCK" #else #ifdef COHERENT #define LOCK_DIR "/usr/spool/uucp" #else #define LOCK_DIR "/usr/spool/uucp" #endif /* COHERENT */ #endif /* LCKDIR */ #endif /* HDBUUCP */ #endif /* ISIII */ #endif /* AIXRS */ #endif /* RTAIX */ #endif /* HPUX10 */ #endif /* DGUX430 */ #endif /* BSD44 */ #endif /* !LOCK_DIR (outside ifndef) */ #ifdef OSF2 /* OSF/1 2.0 or later */ #ifdef LOCK_DIR /* (maybe 1.x too, who knows...) */ #undef LOCK_DIR #define LOCK_DIR "/var/spool/locks" #endif /* LOCK_DIR */ #endif /* OSF2 */ #ifdef COMMENT /* Sorry no more lockf() -- we lock first and THEN open the device. */ #ifdef SVR4 #ifndef BSD44 #ifndef LOCKF #define LOCKF /* Use lockf() on tty device in SVR4 */ #endif /* LOCKF */ #endif /* BSD44 */ #endif /* SVR4 */ #endif /* COMMENT */ #ifdef NOLOCKF /* But NOLOCKF cancels LOCKF */ #ifdef LOCKF #undef LOCKF #endif /* LOCKF */ #endif /* NOLOCKF */ /* More about this below... */ #endif /* USETTYLOCK */ #endif /* NOUUCP */ /* MYREAD means use our internally defined nonblocking buffered read routine. */ #ifdef ATTSV #define MYREAD #endif /* ATTSV */ #ifdef ATT7300 #ifndef MYREAD #define MYREAD #endif /* MYREAD */ /* bits for attmodem: internal modem in use, restart getty */ #define ISMODEM 1 #define DOGETY 512 #endif /* ATT7300 */ #ifdef BSD42 #define MYREAD #endif /* BSD42 */ #ifdef POSIX #define MYREAD #endif /* POSIX */ #ifdef __bsdi__ #ifndef O_NDELAY #define O_NDELAY O_NONBLOCK #endif /* O_NDELAY */ #endif /* __bsdi__ */ /* Variables available to outside world: dftty -- Pointer to default tty name string, like "/dev/tty". dfloc -- 0 if dftty is console, 1 if external line. dfprty -- Default parity dfflow -- Default flow control ckxech -- Flag for who echoes console typein: 1 - The program (system echo is turned off) 0 - The system (or front end, or terminal). functions that want to do their own echoing should check this flag before doing so. flfnam -- Name of lock file, including its path, e.g., "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77" lkflfn -- Name of link to lock file, including its paths haslock -- Flag set if this kermit established a uucp lock. lockpid -- PID of other process that has desired line open, as string. backgrd -- Flag indicating program executing in background ( & on end of shell command). Used to ignore INT and QUIT signals. rtu_bug -- Set by stptrap(). RTU treats ^Z as EOF (but only when we handle SIGTSTP) Functions for assigned communication line (either external or console tty): sysinit() -- System dependent program initialization syscleanup() -- System dependent program shutdown ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access. ttclos() -- Close & reset the tty, releasing any access lock. ttsspd(cps) -- Set the transmission speed of the tty. ttgspd() -- Get (read) the the transmission speed of the tty. ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed. ttvt(speed,flow) -- Put the tty in virtual terminal mode. or in DIALING or CONNECTED modem control state. ttres() -- Restore original tty modes. ttscarr(carrier) -- Set carrier control mode, on/off/auto. ttinl(dest,max,timo) -- Timed read line from the tty. ttinc(timo) -- Timed read character from tty. myread() -- Raw mode bulk buffer read, gives subsequent chars one at a time and simulates FIONREAD. myunrd(c) -- Places c back in buffer to be read (one only) ttchk() -- See how many characters in tty input buffer. ttxin(n,buf) -- Read n characters from tty (untimed). ttol(string,length) -- Write a string to the tty. ttoc(c) -- Write a character to the tty. ttflui() -- Flush tty input buffer. ttsndb() -- Send BREAK signal. ttsndlb() -- Send Long BREAK signal. ttlock(ttname) -- "Lock" tty device against uucp collisions. ttunlck() -- Unlock tty device. For ATT7300/Unix PC, System V: attdial(ttname,speed,telnbr) -- dials ATT7300/Unix PC internal modem offgetty(ttname) -- Turns off getty(1m) for comms line ongetty(ttname) -- Restores getty() to comms line */ /* Functions for console terminal: congm() -- Get console terminal modes. concb(esc) -- Put the console in single-character wakeup mode with no echo. conbin(esc) -- Put the console in binary (raw) mode. conres() -- Restore the console to mode obtained by congm(). conoc(c) -- Unbuffered output, one character to console. conol(s) -- Unbuffered output, null-terminated string to the console. conola(s) -- Unbuffered output, array of strings to the console. conxo(n,s) -- Unbuffered output, n characters to the console. conchk() -- Check if characters available at console (bsd 4.2). Check if escape char (^\) typed at console (System III/V). coninc(timo) -- Timed get a character from the console. congks(timo) -- Timed get keyboard scan code. conint() -- Enable terminal interrupts on the console if not background. connoi() -- Disable terminal interrupts on the console if not background. Time functions msleep(m) -- Millisecond sleep ztime(&s) -- Return pointer to date/time string rtimer() -- Reset timer gtimer() -- Get elapsed time since last call to rtimer() */ /* Conditional Includes */ /* Whether to include */ #ifdef RTU /* RTU doesn't */ #define NOFILEH #endif /* RTU */ #ifdef CIE /* CIE does. */ #undef NOFILEH #endif /* CIE */ #ifdef BSD41 /* 4.1 BSD doesn't */ #define NOFILEH #endif /* BSD41 */ #ifdef is68k /* Integrated Solutions 68000 UNIX */ #define NOFILEH /* e.g. on Plexux P60 and Sun-1 */ #endif /* is68k */ #ifdef MINIX /* MINIX */ #define NOFILEH #endif /* MINIX */ #ifdef COHERENT /* Coherent */ #define NOFILEH #endif /* COHERENT */ #ifndef NOFILEH /* Now include if selected. */ #include #endif /* NOFILEH */ /* POSIX */ #ifdef BSD44ORPOSIX /* POSIX uses termios.h */ #define TERMIOS #ifdef __bsdi__ #ifdef POSIX #undef _POSIX_SOURCE /* Get extra stuff from termios.h */ #endif /* POSIX */ #endif /* __bsdi__ */ #include #ifdef LINUX #include #endif /* LINUX */ #ifdef QNX16 #include #else #ifdef QNX6 #include #endif /* QNX6 */ #endif /* QNX16 */ #ifdef __bsdi__ #ifdef POSIX #define _POSIX_SOURCE #endif /* POSIX */ #endif /* __bsdi__ */ #ifndef BSD44 /* Really POSIX */ #ifndef CK_QNX32 /* was CK_QNX32 */ #define NOSYSIOCTLH /* No ioctl's allowed. */ #undef ultrix /* Turn off any ultrix features. */ #endif /* CK_QNX32 */ #endif /* BSD44 */ #endif /* POSIX */ /* System III, System V */ #ifdef ATTSV #ifndef BSD44 #ifndef POSIX #include #endif /* POSIX */ #endif /* BSD44 */ #ifdef TERMIOX /* Need this for termiox structure, RTS/CTS and DTR/CD flow control */ #include struct termiox rctsx; #else #ifdef STERMIOX #ifdef SCO_OSR504 /* Sorry, this is truly disgusting but it's SCO's fault. */ #ifndef _SVID3 #define _CK_SVID3_X #define _SVID3 #endif /* _SVID3 */ #endif /* SCO_OSR504 */ #include struct termiox rctsx; #ifdef CK_SVID3_X #undef _SVID3 #undef CK_SVID3_X #endif /* CK_SVID3_X */ #endif /* STERMIOX */ #endif /* TERMIOX */ #endif /* ATTSV */ #ifdef COHERENT /* Use termio.h, not sgtty.h for Coherent */ #include #endif /* COHERENT */ #ifdef MINIX /* MINIX uses ioctl's */ #define NOSYSIOCTLH /* but has no */ #endif /* MINIX */ /* Others */ #ifndef NOSYSIOCTLH /* Others use ioctl() */ #ifdef SUN4S5 /* This is to get rid of cpp warning messages that occur because all of these symbols are defined by both termios.h and ioctl.h on the SUN. */ #undef ECHO #undef NL0 #undef NL1 #undef TAB0 #undef TAB1 #undef TAB2 #undef XTABS #undef CR0 #undef CR1 #undef CR2 #undef CR3 #undef FF0 #undef FF1 #undef BS0 #undef BS1 #undef TOSTOP #undef FLUSHO #undef PENDIN #undef NOFLSH #endif /* SUN4S5 */ #include #endif /* NOSYSIOCTLH */ /* We really, really, REALLY want FIONREAD, because it is the only way to find out not just *if* stuff is waiting to be read, but how much, which is critical to our sliding-window and streaming procedures, not to mention efficiency of CONNECT, etc. */ #ifdef BELLV10 #include /* For FIONREAD */ #ifdef FIONREAD #define MYREAD #endif /* MYREAD */ #endif /* BELLV10 */ #ifndef FIONREAD /* It wasn't found in ioctl.h or term*.h - try these places: */ #ifdef UNIXWARE #include #else #ifdef SOLARIS #include #endif /* SOLARIS */ #endif /* UNIXWARE */ #endif /* FIONREAD */ #ifdef XENIX /* Was M_UNIX but XENIX implies M_UNIX and applies to XENIX too */ /* included above via "ckcnet.h" defines FIONREAD as something. Due to this, in_chk() uses the FIONREAD instead of RDCHK and the hot keys during file transfer (X to cancel file etc) do not work because FIONREAD doesn't work even though it is defined. NOTE: This might also be true elsewhere. */ #ifdef FIONREAD #undef FIONREAD #endif /* FIONREAD */ #endif /* XENIX */ #ifdef CK_SCOV5 /* Ditto for SCO OpenServer 5.0 */ #ifndef SCO_OSR507 /* 299 */ #ifdef FIONREAD #undef FIONREAD #endif /* FIONREAD */ #endif /* SCO_OSR507 */ #endif /* CK_SCOV5 */ #ifdef SCO_OSR507 /* 299 */ #ifdef RDCHK #undef RDCHK #endif /* RDCHK */ #endif /* SCO_OSR507 */ /* Whether to include */ #ifndef is68k /* Only a few don't have this one. */ #ifndef BSD41 #ifndef FT21 #ifndef FT18 #ifndef COHERENT #include #endif /* COHERENT */ #endif /* FT18 */ #endif /* FT21 */ #endif /* BSD41 */ #endif /* not is68k */ #ifdef COHERENT #ifdef _I386 #include #else #include #endif /* _I386 */ #endif /* COHERENT */ #ifdef ATT7300 /* Unix PC, internal modem dialer */ #include #endif /* ATT7300 */ #ifdef HPUX /* HP-UX variations. */ #define HPUXJOBCTL #include /* HP-UX modem signals */ #ifdef hp9000s500 /* Model 500 */ #undef HPUXJOBCTL #endif /* hp9000s500 */ #ifdef HPUXPRE65 #undef HPUXJOBCTL typedef long mflag; #endif /* HPUXPRE65 */ #ifdef HPUXJOBCTL #include /* HP-UX Berkeley tty support */ #endif /* HPUXJOBCTL */ #endif /* HPUX */ /* Which time.h files to include... See ckcdeb.h for defaults. Note that 0, 1, 2, or all 3 of these can be included according to the symbol definitions. */ #ifndef NOTIMEH #ifdef TIMEH #include #endif /* TIMEH */ #endif /* NOTIMEH */ #ifndef NOSYSTIMEH #ifdef SYSTIMEH #include #endif /* SYSTIMEH */ #endif /* NOSYSTIMEH */ #ifndef NOSYSTIMEBH #ifdef SYSTIMEBH #include #endif /* SYSTIMEBH */ #endif /* NOSYSTIMEBH */ #ifndef NODCLTIMEVAL #ifdef DCLTIMEVAL /* In certain POSIX builds (like Unixware 7), <[sys/]time.h> refuses to define the structs we need to access the higher speeds, so we have to do it ourselves. */ struct timeval { long tv_sec; long tv_usec; }; struct timezone { int tz_minuteswest; int tz_dsttime; }; #endif /* DCLTIMEVAL */ #endif /* NODCLTIMEVAL */ #ifdef __linux__ /* THIS IS OBSOLETE since about Linux 0.92 */ #ifdef OLINUXHISPEED #include #endif /* OLINUXHISPEED */ #ifdef __alpha__ /* Linux on DEC Alpha */ #ifndef __GLIBC__ /* But not with glibc */ #include #endif /* __GLIBC__ */ #endif /* __alpha__ */ #endif /* __linux__ */ #ifdef NOIEXTEN /* This is broken on some systems */ #undef IEXTEN /* like Convex/OS 9.1 */ #endif /* NOIEXTEN */ #ifndef IEXTEN /* Turn off ^O/^V processing. */ #define IEXTEN 0 /* Needed, at least, on BSDI. */ #endif /* IEXTEN */ /* Pick up definitions needed for select() if we don't have them already. Normally they come from but some systems get them from ... Rather than hardwire all of them into the source, we include it if SELECT_H is defined in compile-time CFLAGS. */ #ifndef SCO_OSR504 #ifdef SELECT_H #include #endif /* SELECT_H */ #endif /* SCO_OSR504 */ #ifdef aegis #include "/sys/ins/base.ins.c" #include "/sys/ins/error.ins.c" #include "/sys/ins/ios.ins.c" #include "/sys/ins/sio.ins.c" #include "/sys/ins/pad.ins.c" #include "/sys/ins/time.ins.c" #include "/sys/ins/pfm.ins.c" #include "/sys/ins/pgm.ins.c" #include "/sys/ins/ec2.ins.c" #include "/sys/ins/type_uids.ins.c" #include #undef TIOCEXCL #undef FIONREAD #endif /* aegis */ #ifdef sxaE50 /* PFU Compact A SX/A TISP V10/L50 */ #undef FIONREAD #endif /* sxaE50 */ /* The following #defines are catch-alls for those systems */ /* that didn't have or couldn't find ... */ #ifndef FREAD #define FREAD 0x01 #endif /* FREAD */ #ifndef FWRITE #define FWRITE 0x10 #endif /* FWRITE */ #ifndef O_RDONLY #define O_RDONLY 000 #endif /* O_RDONLY */ /* This is for ancient Unixes that don't have these tty symbols defined. */ #ifndef PENDIN #define PENDIN ICANON #endif /* PENDIN */ #ifndef FLUSHO #define FLUSHO ICANON #endif /* FLUSHO */ #ifndef EXTPROC #define EXTPROC ICANON #endif /* EXTPROC */ #ifdef SVORPOSIX /* Modem signals are also forbidden in the POSIX world. But some POSIX-based platforms let us at them anyway if we know where to look. */ #ifndef NEEDMDMDEFS /* Doesn't work for Linux */ #ifdef UNIXWARE7 #define NEEDMDMDEFS #endif /* UNIXWARE7 */ #endif /* NEEDMDMDEFS */ #ifdef NEEDMDMDEFS #ifndef TIOCMGET #define TIOCMGET (('t'<<8)|29) #endif /* TIOCMGET */ #ifndef TIOCM_DTR #define TIOCM_DTR 0x0002 #endif /* TIOCM_DTR */ #ifndef TIOCM_RTS #define TIOCM_RTS 0x0004 #endif /* TIOCM_RTS */ #ifndef TIOCM_CTS #define TIOCM_CTS 0x0020 #endif /* TIOCM_CTS */ #ifndef TIOCM_CAR #define TIOCM_CAR 0x0040 #endif /* TIOCM_CAR */ #ifndef TIOCM_RNG #define TIOCM_RNG 0x0080 #endif /* TIOCM_RNG */ #ifndef TIOCM_DSR #define TIOCM_DSR 0x0100 #endif /* TIOCM_DSR */ #endif /* NEEDMDMDEFS */ #endif /* SVORPOSIX */ /* Declarations */ #ifdef OXOS #undef TCGETA #undef TCSETA #undef TCSETAW #undef TCSETAF #define TCGETA TCGETS #define TCSETA TCSETS #define TCSETAW TCSETSW #define TCSETAF TCSETSF #define termio termios #endif /* OXOS */ #ifdef SVORPOSIX /* AT&T Sys V or POSIX */ #ifdef UNIXWAREPOSIX /* UnixWare 7 POSIX build */ /* In Unixware POSIX builds, <[sys/]time.h> refuses to define the structs we need to access the higher speeds, so we have to do it ourselves. */ struct timeval { long tv_sec; long tv_usec; }; struct timezone { int tz_minuteswest; int tz_dsttime; }; #endif /* UNIXWAREPOSIX */ #endif /* SVORPOSIX */ /* MACOS allows setting non posix speeds using IOSSIOSPEED ioctl */ #ifdef MACOSHISPEED #include #define MACOSHISPEED_START B307200 #ifndef B307200 #define B307200 307200 #endif /* B307200 */ #ifndef B460800 #define B460800 460800 #endif /* 460800 */ #ifndef B500000 #define B500000 500000 #endif /* B500000 */ #ifndef B576000 #define B576000 576000 #endif /* B576000 */ #ifndef B614400 #define B614400 614400 #endif /* B614400 */ #ifndef B921600 #define B921600 921600 #endif /* B921600 */ #ifndef B1000000 #define B1000000 1000000 #endif /* B1000000 */ #ifndef B1152000 #define B1152000 1152000 #endif /* B1152000 */ #ifndef B1500000 #define B1500000 1500000 #endif /* B1500000 */ #ifndef B2000000 #define B2000000 2000000 #endif /* B2000000 */ #ifndef B2500000 #define B2500000 2500000 #endif /* B2500000 */ #ifndef B3000000 #define B3000000 3000000 #endif /* B3000000 */ #ifndef B3500000 #define B3500000 3500000 #endif /* B3500000 */ #ifndef B4000000 #define B4000000 4000000 #endif /* B4000000 */ #endif /* MACOSHISPEED */ #ifdef __GNUC__ #ifdef XENIX /* Because Xenix doesn't declare time() if we're using gcc. */ time_t time(); #endif /* XENIX */ #endif /* __GNUC__ */ /* Special stuff for V7 input buffer peeking */ #ifdef V7 int kmem[2] = { -1, -1}; char *initrawq(), *qaddr[2]={0,0}; #define CON 0 #define TTY 1 #endif /* V7 */ /* dftty is the device name of the default device for file transfer */ /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */ #ifdef BEOS char * dftty = NULL; char * dfmdm = "none"; int dfloc = 0; /* that goes in local mode by default */ #else #ifndef DFTTY #ifdef PROVX1 char *dftty = "/dev/com1.dout"; /* Only example so far of a system */ char *dfmdm = "none"; int dfloc = 1; /* that goes in local mode by default */ #else char *dftty = CTTNAM; /* Remote by default, use normal */ char *dfmdm = "none"; int dfloc = 0; /* controlling terminal name. */ #endif /* PROVX1 */ #else char *dftty = DFTTY; /* Default location specified on */ char *dfmdm = "none"; /* command line. */ int dfloc = 1; /* controlling terminal name. */ #endif /* DFTTY */ #endif /* BEOS */ #define CON_RES 0 /* Console state is "reset" */ #define CON_CB 1 /* Console state is CBREAK */ #define CON_BIN 2 /* Console state is binary */ static int constate = CON_RES; #define CONI_RES 0 /* Console interrupts are "reset" */ #define CONI_INT 1 /* Console intterupts are set */ #define CONI_NOI 2 /* Console intterupts are disabled */ static int conistate = CONI_RES; #ifdef CK_SMALL #define CONBUFSIZ 15 #else #define CONBUFSIZ 255 #endif /* CK_SMALL */ static char conbuf[CONBUFSIZ]; /* Console readahead buffer */ static int conbufn = 0; /* Chars in readahead buffer */ static char *conbufp = conbuf; /* Next char in readahead buffer */ char cttnam[DEVNAMLEN+1] = { '\0', '\0' }; /* Determined at runtime */ #ifdef RTU int rtu_bug = 0; /* set to 1 when returning from SIGTSTP */ #endif /* RTU */ int dfprty = DEFPAR; /* Default parity (0 = none) */ int ttprty = 0; /* The parity that is in use. */ static int ttpmsk = 0xff; /* Parity stripping mask. */ int ttmdm = 0; /* Modem in use. */ int ttcarr = CAR_AUT; /* Carrier handling mode. */ int dfflow = FLO_NONE; /* Default flow control is NONE */ int backgrd = 0; /* Assume in foreground (no '&' ) */ #ifdef F_SETFL int iniflags = -1; /* fcntl flags for ttyfd */ #endif /* F_SETFL */ int fdflag = 0; /* Flag for redirected stdio */ int ttfdflg = 0; /* Open File descriptor was given */ int tvtflg = 0; /* Flag that ttvt has been called */ long ttspeed = -1L; /* For saving speed */ int ttflow = -9; /* For saving flow */ int ttld = -1; /* Line discipline */ #ifdef sony_news static int km_con = -1; /* Kanji mode for console tty */ static int km_ext = -1; /* Kanji mode for external device */ #endif /* sony_news */ #ifdef PARSENSE static int needpchk = 1; /* Need parity check */ #else static int needpchk = 0; #endif /* PARSENSE */ extern int stopbits; /* Stop bits */ #ifdef HWPARITY /* Unfortunately we must do this with global variables rather than through the tt...() APIs to avoid changing the APIs and the many modules that use them. If hwparity != 0, this indicates 8 data bits + parity, rather than 7 data bits + parity or 8 data bits and no parity, and overrides the regular parity variable, which is communicated to this module thru ttpkt(), and represented locally by the ttprty variable. */ extern int hwparity; /* Hardware parity */ #endif /* HWPARITY */ #ifdef TCPSOCKET #ifdef TCP_NODELAY static int nodelay_sav = -1; #endif /* TCP_NODELAY */ #endif /* TCPSOCKET */ static int sigint_ign = 0; /* SIGINT is ignored */ /* Having this module rely on external globals is bad, but fixing this requires overhaul of the ck*tio.c modules for all the different operating systems supported by C-Kermit. Left for a future release. */ extern int ttnproto; /* Defined in ckcnet.c */ extern int ttnet; /* Defined in ckcnet.c */ extern int nopush, xfrcan, xfrchr, xfrnum; /* Defined in ckcmai.c */ extern int xsuspend, wasclosed; extern int inserver, local; int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */ int ckmaxfiles = 0; /* Max number of open files */ #ifdef CK_ENCRYPTION /* Kerberos */ #include "ckuath.h" extern int me_encrypt, u_encrypt; #endif /* CK_ENCRYPTION */ #include "ckcker.h" #include "ckucmd.h" #include "ckuusr.h" #include "ckcfnp.h" /* Prototypes */ /* Declarations of variables global within this module */ #ifdef TTLEBUF /* See ckcnet.h */ int ttpush = -1; #define LEBUFSIZ 4096 static CHAR le_buf[LEBUFSIZ]; static int le_start = 0, le_end = 0, le_data = 0; #endif /* TTLEBUF */ #define MSGBUF_SIZE 1024 /* For debugging */ static char msgbuf[MSGBUF_SIZE]; static int gotsigs = 0; static time_t tcount = (time_t)0; /* Elapsed time counter */ static SIGTYP (*saval)() = NULL; /* For saving alarm() handler */ static SIGTYP (*savquit)() = NULL; /* and other signal handlers */ #ifdef SIGUSR1 static SIGTYP (*savusr1)() = NULL; #endif /* SIGUSR1 */ #ifdef SIGUSR2 static SIGTYP (*savusr2)() = NULL; #endif /* SIGUSR2 */ #ifdef SIGPIPE static SIGTYP (*savpipe)() = NULL; #endif /* SIGPIPE */ #ifdef SIGDANGER static SIGTYP (*savdanger)() = NULL; #endif /* SIGDANGER */ #ifndef NOJC static SIGTYP (*jchdlr)() = NULL; /* For checking suspend handler */ #endif /* NOJC */ static int jcshell = -1; /* And flag for result */ /* BREAKNULS is defined for systems that simulate sending a BREAK signal by sending a bunch of NUL characters at low speed. */ #ifdef PROVX1 #ifndef BREAKNULS #define BREAKNULS #endif /* BREAKNULS */ #endif /* PROVX1 */ #ifdef V7 #ifndef BREAKNULS #define BREAKNULS #endif /* BREAKNULS */ #endif /* V7 */ #ifdef BREAKNULS static char /* A string of nulls */ *brnuls = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; #endif /* BREAKNULS */ #ifdef CK_POSIX_SIG /* Longjump buffers */ static sigjmp_buf sjbuf; /* POSIX signal handling */ #else static jmp_buf sjbuf; #endif /* CK_POSIX_SIG */ #ifdef V7 static jmp_buf jjbuf; #endif /* V7 */ /* static */ /* (Not static any more) */ int ttyfd = -1; /* TTY file descriptor */ int ttpipe = 0; /* NETCMD: Use pipe instead of ttyfd */ int ttpty = 0; /* NETPTY: Use pty instead of ttfyd */ #ifdef NETPTY /* These are in ckupty.c */ extern PID_T pty_fork_pid; extern int pty_master_fd, pty_slave_fd; #endif /* NETPTY */ #ifdef NETCMD #ifdef NETCONN static int pipe0[2], pipe1[2]; /* Pipes for net i/o */ #endif /* NETCONN */ static PID_T ttpid = 0; /* Process ID for fork */ static int fdin, fdout; /* File descriptors for pipe */ static FILE * ttout = NULL; /* File pointer for output pipe */ #ifdef DCLFDOPEN /* fdopen() needs declaring because it's not declared in */ _PROTOTYP( FILE * fdopen, (int, char *) ); #endif /* DCLFDOPEN */ #endif /* NETCMD */ extern int pexitstat, quiet; #ifdef Plan9 int ttyctlfd = -1; /* TTY control channel - What? UNIX doesn't have one? */ int consctlfd = -1; /* Console control channel */ int noisefd = -1; /* tone channel */ static int ttylastspeed = -1; /* So we can lie about the speed */ #endif /* Plan9 */ int telnetfd = 0; /* File descriptor is for telnet */ #ifdef NETCONN int x25fd = 0; /* File descriptor is for X.25 */ #endif /* NETCONN */ char lockpid[16] = { '\0', '\0' }; /* PID stored in lockfile, as string */ static int lkf = 0, /* Line lock flag */ cgmf = 0, /* Flag that console modes saved */ xlocal = 0, /* Flag for tty local or remote */ curcarr = 0; /* Carrier mode: require/ignore. */ static int netconn = 0; /* 1 if network connection active */ static char escchr; /* Escape or attn character */ #ifdef CK_SCO32V4 #include #endif /* CK_SCO32V4 */ #ifdef HAVE_TV static struct timeval tv; /* For getting time, from sys/time.h */ #endif /* HAVE_TV */ #ifdef HAVE_TZ static struct timezone tz; #endif /* HAVE_TZ */ #ifdef OSF static struct timeb ftp; /* And from sys/timeb.h */ #endif /* OSF */ #ifdef BSD29 static long xclock; /* For getting time from sys/time.h */ static struct timeb ftp; /* And from sys/timeb.h */ #endif /* BSD29 */ #ifdef BSD41 static long xclock; /* For getting time from sys/time.h */ static struct timeb ftp; /* And from sys/timeb.h */ #endif /* BSD41 */ #ifdef BELLV10 static long xclock; /* For getting time from sys/time.h */ static struct timeb ftp; /* And from sys/timeb.h */ #endif /* BELLV10 */ #ifdef FT21 static long xclock; /* For getting time from sys/time.h */ static struct timeb ftp; /* And from sys/timeb.h */ #endif /* FT21 */ #ifdef TOWER1 static long xclock; /* For getting time from sys/time.h */ static struct timeb ftp; /* And from sys/timeb.h */ #endif /* TOWER1 */ #ifdef COHERENT static long xclock; /* For getting time from sys/time.h */ static struct timeb ftp; /* And from sys/timeb.h */ #endif /* COHERENT */ #ifdef V7 static long xclock; #endif /* V7 */ /* sgtty/termio information... */ #ifdef BSD44ORPOSIX /* POSIX or BSD44 */ static struct termios ttold, ttraw, tttvt, ttcur, ccold, ccraw, cccbrk; #else /* BSD, V7, etc */ #ifdef COHERENT /* Hack alert... */ #define ATTSV #endif /* COHERENT */ #ifdef ATTSV static struct termio ttold = {0}; /* Init'd for word alignment, */ static struct termio ttraw = {0}; /* which is important for some */ static struct termio tttvt = {0}; /* systems, like Zilog... */ static struct termio ttcur = {0}; static struct termio ccold = {0}; static struct termio ccraw = {0}; static struct termio cccbrk = {0}; #else static struct sgttyb /* sgtty info... */ ttold, ttraw, tttvt, ttcur, /* for communication line */ ccold, ccraw, cccbrk; /* and for console */ #ifdef BELLV10 static struct ttydevb /* Device info... */ tdold, tdcur; /* for communication device */ #endif /* BELLV10 */ #ifdef TIOCGETC static struct tchars tchold, tchnoi; static int tcharf; #endif /* TIOCGETC */ #ifdef TIOCGLTC static struct ltchars ltchold, ltchnoi; static int ltcharf; #endif /* TIOCGLTC */ int lmodef = 0; /* Local modes */ int lmode = 0; #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ #ifdef COMMENT /* It picks up the speeds but they don't work */ #ifdef UNIXWARE /* For higher serial speeds */ #ifdef UW7 /* in Unixware 7.0 */ #include /* This picks up 57600 and 115200 */ #endif /* UW7 */ #endif /* UNIXWARE */ #endif /* COMMENT */ #ifdef PROVX1 static struct sgttyb ttbuf; #endif /* PROVX1 */ #ifdef ultrix /* do we really need this? */ static struct sgttyb vanilla; #endif /* ultrix */ #ifdef ATT7300 static int attmodem = 0; /* ATT7300 internal-modem status */ struct updata dialer = {0}; /* Condition dialer for data call */ #endif /* ATT7300 */ #ifndef NOUUCP #define FLFNAML 128 #ifndef USETTYLOCK #ifdef RTAIX char lkflfn[FLFNAML] = { '\0', '\0' }; /* and possible link to it */ #endif /* RTAIX */ char lock2[FLFNAML] = { '\0', '\0' }; /* Name of second lockfile */ #endif /* USETTYLOCK */ #else #define FLFNAML 7 #endif /* NOUUCP */ char flfnam[FLFNAML+1] = { '\0', '\0' }; /* UUCP lock file path name */ int haslock = 0; /* =1 if this kermit locked uucp */ #ifndef OXOS #ifdef SVORPOSIX static int conesc = 0; /* set to 1 if esc char (^\) typed */ #else #ifdef V7 static int conesc = 0; #else #ifdef C70 static int conesc = 0; #endif /* C70 */ #endif /* V7 */ #endif /* SVORPOSIX */ #endif /* OXOS */ /* Local copy of comm device name or network host */ static char ttnmsv[DEVNAMLEN+1] = { '\0', '\0' }; #ifdef USETTYLOCK static char lockname[DEVNAMLEN+1]; /* Ditto, the part after "/dev/". */ #endif /* USETTYLOCK */ #ifdef aegis static status_$t st; /* error status return value */ static short concrp = 0; /* true if console is CRP pad */ static uid_$t ttyuid; /* tty type uid */ static uid_$t conuid; /* stdout type uid */ /* APOLLO Aegis main() * establish acl usage and cleanup handling * this makes sure that CRP pads * get restored to a usable mode */ main(argc,argv) int argc; char **argv; { status_$t status; pfm_$cleanup_rec dirty; PID_T pid = getpid(); /* acl usage according to invoking environment */ default_acl(USE_DEFENV); /* establish a cleanup continuation */ status = pfm_$cleanup(dirty); if (status.all != pfm_$cleanup_set) { /* only handle faults for the original process */ if (pid == getpid() && status.all > pgm_$max_severity) { /* blew up in main process */ status_$t quo; pfm_$cleanup_rec clean; /* restore the console in any case */ conres(); /* attempt a clean exit */ debug(F101, "cleanup fault status", "", status.all); /* doexit(), then send status to continuation */ quo = pfm_$cleanup(clean); if (quo.all == pfm_$cleanup_set) doexit(pgm_$program_faulted,-1); else if (quo.all > pgm_$max_severity) pfm_$signal(quo); /* blew up in doexit() */ } /* send to the original continuation */ pfm_$signal(status); /*NOTREACHED*/ } return(ckcmai(argc, argv)); } #endif /* aegis */ /* ANSI-style prototypes for internal functions. */ /* Functions used outside this module are prototyped in ckcker.h. */ #ifdef apollo _PROTOTYP( SIGTYP timerh, () ); _PROTOTYP( SIGTYP cctrap, () ); _PROTOTYP( SIGTYP esctrp, () ); _PROTOTYP( SIGTYP sig_ign, () ); #else _PROTOTYP( SIGTYP timerh, (int) ); _PROTOTYP( SIGTYP cctrap, (int) ); _PROTOTYP( SIGTYP esctrp, (int) ); #endif /* apollo */ _PROTOTYP( int do_open, (char *) ); _PROTOTYP( static int in_chk, (int, int) ); _PROTOTYP( static int ttrpid, (char *) ); _PROTOTYP( static int ttchkpid, (char *) ); _PROTOTYP( static int ttlock, (char *) ); _PROTOTYP( static int ttunlck, (void) ); _PROTOTYP( static VOID sigchld_handler, (int) ); _PROTOTYP( int mygetbuf, (void) ); _PROTOTYP( int myfillbuf, (void) ); _PROTOTYP( VOID conbgt, (int) ); #ifdef ACUCNTRL _PROTOTYP( VOID acucntrl, (char *, char *) ); #endif /* ACUCNTRL */ #ifdef BSD44ORPOSIX _PROTOTYP( int carrctl, (struct termios *, int) ); #else #ifdef ATTSV _PROTOTYP( int carrctl, (struct termio *, int) ); #else _PROTOTYP( int carrctl, (struct sgttyb *, int) ); #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ #ifdef ATT7300 _PROTOTYP( int attdial, (char *, long, char *) ); _PROTOTYP( int offgetty, (char *) ); _PROTOTYP( int ongetty, (char *) ); #endif /* ATT7300 */ #ifdef BEOSORBEBOX #ifdef SELECT /* BeOS is not capable of using SELECT on anything but sockets */ #undef SELECT #endif /* SELECT */ #include /* #ifdef BE_DR_7 */ static double time_started = 0.0; struct ALARM_STRUCT { thread_id thread; int time; }; static thread_id alarm_thread = -1; static struct ALARM_STRUCT alarm_struct; _PROTOTYP( long do_alarm, (void *) ); _PROTOTYP( unsigned int alarm, (unsigned int) ); _PROTOTYP( void alarm_expired, (void) ); /* #endif */ /* BE_DR_7 */ #endif /* BEOSORBEBOX */ #ifndef xunchar #define xunchar(ch) (((ch) - 32 ) & 0xFF ) /* Character to number */ #endif /* xunchar */ #ifdef CK_ANSIC static char * xxlast(char *s, char c) #else static char * xxlast(s,c) char *s; char c; #endif /* CK_ANSIC */ /* xxlast */ { /* Last occurrence of character c in string s. */ int i; for (i = (int)strlen(s); i > 0; i--) if (s[i-1] == c ) return(s + (i - 1)); return(NULL); } /* Timeout handler for communication line input functions */ /*ARGSUSED*/ SIGTYP #ifdef CK_ANSIC timerh( int foo ) #else timerh(foo) int foo; #endif /* CK_ANSIC */ { ttimoff(); #ifdef BEOSORBEBOX /* #ifdef BE_DR_7 */ alarm_expired(); /* #endif */ /* BE_DR_7 */ #endif /* BEOSORBEBOX */ #ifdef CK_POSIX_SIG siglongjmp(sjbuf,1); #else longjmp(sjbuf,1); #endif /* CK_POSIX_SIG */ } /*ARGSUSED*/ SIGTYP #ifdef CK_ANSIC xtimerh( int foo ) #else xtimerh(foo) int foo; #endif /* CK_ANSIC */ { /* Like timerh() but does not reset the timer itself */ #ifdef BEOSORBEBOX /* #ifdef BE_DR_7 */ alarm_expired(); /* #endif */ /* BE_DR_7 */ #endif /* BEOSORBEBOX */ #ifdef CK_POSIX_SIG siglongjmp(sjbuf,1); #else longjmp(sjbuf,1); #endif /* CK_POSIX_SIG */ } /* Control-C trap for communication line input functions */ int cc_int; /* Flag */ SIGTYP (* occt)(); /* For saving old SIGINT handler */ /*ARGSUSED*/ SIGTYP #ifdef CK_ANSIC cctrap( int foo ) /* Needs arg for ANSI C */ #else cctrap(foo) int foo; #endif /* CK_ANSIC */ { cc_int = 1; /* signal() prototype. */ return; } /* S Y S I N I T -- System-dependent program initialization. */ /* * ttgwsiz() returns: * 1 tt_rows and tt_cols are known, both altered, both > 0 * 0 tt_rows and/or tt_cols are known, both altered, one or both <= 0 * -1 tt_rows and tt_cols are unknown and unaltered */ extern int tt_rows, tt_cols; static int xttgwsiz() { char *p; int rows = 0, cols = 0; p = getenv("LINES"); debug(F110,"xttgwsiz LINES",p,0); if (p) { rows = atol(p); if (rows > 0) { p = getenv("COLUMNS"); debug(F110,"xttgwsiz COLUMNS",p,0); if (p) { cols = atol(p); if (cols > 0) { tt_rows = rows; tt_cols = cols; return(1); } return(0); } } } return(-1); } #ifdef TTLEBUF VOID le_init() { /* LocalEchoInit() */ int i; for (i = 0; i < LEBUFSIZ; i++) le_buf[i] = '\0'; le_start = 0; le_end = 0; le_data = 0; } VOID le_clean() { /* LocalEchoCleanup() */ le_init(); return; } int le_inbuf() { int rc = 0; if (le_start != le_end) { rc = (le_end - le_start + LEBUFSIZ) % LEBUFSIZ; } debug(F111,"le_inbuf","chars waiting",rc); return(rc); } int #ifdef CK_ANSIC le_putchar(CHAR ch) #else le_putchar(ch) CHAR ch; #endif /* CK_ANSIC */ /* le_putchar */ { #ifdef COMMENT /* In UNIX we do not have another thread taking chars out of the buffer */ while ((le_start - le_end == 1) || (le_start == 0 && le_end == LEBUFSIZ - 1)) { /* Buffer is full */ debug(F111,"le_putchar","Buffer is Full",ch); ReleaseLocalEchoMutex() ; msleep(250); RequestLocalEchoMutex( SEM_INDEFINITE_WAIT ) ; } #else if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) { debug(F110,"le_putchar","buffer is full",0); return(-1); } #endif /* COMMENT */ le_buf[le_end++] = ch; if (le_end == LEBUFSIZ) le_end = 0; le_data = 1; return(0); } int #ifdef CK_ANSIC le_puts(CHAR * s, int n) #else le_puts(s,n) CHAR * s; int n; #endif /* CK_ANSIC */ /* le_puts */ { int rc = 0; int i = 0; CHAR * p = (CHAR *)"le_puts"; ckhexdump(p,s,n); for (i = 0; i < n; i++) rc = le_putchar((char)s[i]); debug(F101,"le_puts","",rc); return(rc); } int #ifdef CK_ANSIC le_putstr(CHAR * s) #else le_putstr(s) CHAR * s; #endif /* CK_ANSIC */ /* le_puts */ { CHAR * p; int rc = 0; p = (CHAR *)"le_putstr"; ckhexdump(p,s,(int)strlen((char *)s)); for (p = s; *p && !rc; p++) rc = le_putchar(*p); return(rc); } int #ifdef CK_ANSIC le_getchar(CHAR * pch) #else /* CK_ANSIC */ le_getchar(pch) CHAR * pch; #endif /* CK_ANSIC */ /* le_gatchar */ { int rc = 0; if (le_start != le_end) { *pch = le_buf[le_start]; le_buf[le_start] = 0; le_start++; if (le_start == LEBUFSIZ) le_start = 0; if (le_start == le_end) { le_data = 0; } rc++; } else { *pch = 0; } return(rc); } #endif /* TTLEBUF */ #ifdef COMMENT /* Some systems like OSF/1 use TIOCGSIZE instead of TIOCGWINSZ. But as far as I know, whenever TIOCGSIZE is defined, it is equated to TIOCGWINSZ. For cases where this is not done, try this: */ #ifndef TIOCGWINSZ #ifdef TIOCGSIZE #define TIOCGWINSZ TIOCGSIZE #endif /* TIOCGSIZE */ #endif /* TIOCGWINSZ */ #endif /* COMMENT */ static int tt_xpixel = 0, tt_ypixel = 0; int ttgwsiz() { int x = 0; #ifndef NONAWS #ifdef QNX /* NOTE: TIOCGWSIZ works here too, but only in the 32-bit version. This code works for both the 16- and 32-bit versions. */ extern int dev_size(int, int, int, int *, int *); int r, c; if (dev_size(0, -1, -1, &r, &c) == 0) { debug(F101,"ttgwsiz QNX r","",r); debug(F101,"ttgwsiz QNX c","",c); tt_rows = r; tt_cols = c; return ((r > 0 && c > 0) ? 1 : 0); } else return(xttgwsiz()); #else /* QNX */ #ifdef TIOCGWINSZ /* Note, this was M_UNIX, changed to XENIX to allow cross compilation... */ #ifdef XENIX /* SCO UNIX 3.2v4.0 */ #include /* typedef mblk_t needed by ptem.h */ #include /* for ttgwsiz() */ #endif /* XENIX */ #ifdef I386IX /* Ditto for Interactive */ #include #include #endif /* I386IX */ /* Note, the above might be needed for some other older SVR3 Intel makes... */ struct winsize w; tt_xpixel = 0; tt_ypixel = 0; #ifdef IKSD if (inserver) return(xttgwsiz()); #endif /* IKSD */ x = ioctl(0, (int)TIOCGWINSZ, (char *)&w); debug(F101,"ttgwsiz TIOCGWINSZ","",x); if (x < 0) { return(xttgwsiz()); } else if (w.ws_row > 0 && w.ws_col > 0) { tt_rows = w.ws_row; tt_cols = w.ws_col; tt_xpixel = w.ws_xpixel; tt_ypixel = w.ws_ypixel; debug(F101,"ttgwsiz tt_rows","",tt_rows); debug(F101,"ttgwsiz tt_cols","",tt_cols); return(1); } else { debug(F100,"ttgwsiz TIOCGWINSZ 00","",0); return(xttgwsiz()); } #else return(xttgwsiz()); #endif /* TIOCGWINSZ */ #endif /* QNX */ #endif /* NONAWS */ } #ifdef RLOGCODE _PROTOTYP( int rlog_naws, (void) ); #endif /* RLOGCODE */ #ifndef NOSIGWINCH #ifdef SIGWINCH SIGTYP #ifdef CK_ANSIC winchh( int foo ) /* SIGWINCH handler */ #else winchh(foo) int foo; #endif /* CK_ANSIC */ { int x = 0; #ifdef CK_TTYFD #ifndef VMS extern int ttyfd; #endif /* VMS */ #endif /* CK_TTYFD */ extern int tt_rows, tt_cols, cmd_rows, cmd_cols; #ifdef DEBUG if (deblog) { debug(F100,"***************","",0); debug(F100,"SIGWINCH caught","",0); debug(F100,"***************","",0); #ifdef NETPTY debug(F101,"SIGWINCH pty_fork_pid","",pty_fork_pid); #endif /* NETPTY */ } #endif /* DEUB */ signal(SIGWINCH,winchh); /* Re-arm the signal */ x = ttgwsiz(); /* Get new window size */ cmd_rows = tt_rows; /* Adjust command screen too */ cmd_cols = tt_cols; #ifdef CK_TTYFD if /* If we don't have a connection */ #ifdef VMS /* we're done. */ (vmsttyfd() == -1) #else (ttyfd == -1) #endif /* VMS */ #else (!local) #endif /* CK_TTYFD */ return; #ifdef NETPTY if (pty_fork_pid > -1) { /* "set host" to a PTY? */ int x; #ifdef TIOCSWINSZ struct winsize w; /* Resize the PTY */ errno = 0; w.ws_col = tt_cols; w.ws_row = tt_rows; w.ws_xpixel = tt_xpixel; w.ws_ypixel = tt_ypixel; x = ioctl(ttyfd,TIOCSWINSZ,&w); debug(F101,"winchh TIOCSWINSZ","",x); debug(F101,"winchh TIOCSWINSZ errno","",errno); #endif /* TIOCSWINSZ */ errno = 0; x = kill(pty_fork_pid,SIGWINCH); debug(F101,"winchh kill","",x); debug(F101,"winchh kill errno","",errno); } #endif /* NETPTY */ /* This should be OK. It might seem that sending this from interrupt level could interfere with another TELNET IAC string that was in the process of being sent. But we always send TELNET strings with a single write(), which should prevent mixups. blah_snaws() should protect themselves from being called on the wrong kind of connection. */ #ifdef TCPSOCKET #ifndef NOTTGWSIZ if (x > 0 && tt_rows > 0 && tt_cols > 0) { tn_snaws(); #ifdef RLOGCODE rlog_naws(); #endif /* RLOGCODE */ } #endif /* NOTTGWSIZ */ #endif /* TCPSOCKET */ SIGRETURN; } #endif /* SIGWINCH */ #endif /* NOSIGWINCH */ SIGTYP #ifdef CK_ANSIC sighup( int foo ) /* SIGHUP handler */ #else sighup(foo) int foo; #endif /* CK_ANSIC */ { backgrd = 1; debug(F100,"***************","",0); debug(F100,"SIGHUP received","",0); debug(F100,"***************","",0); doexit(BAD_EXIT,-1); /*NOTREACHED*/ SIGRETURN; /* Shut picky compilers up... */ } #ifdef CK_SCO32V4 /* Exists but there is no prototype in the header files */ _PROTOTYP( char * ttyname, (int) ); #else #ifdef SV68R3V6 _PROTOTYP( char * ttyname, (int) ); #else #ifdef ultrix _PROTOTYP( char * ttyname, (int) ); #else #ifdef HPUX6 _PROTOTYP( char * ttyname, (int) ); #else #ifdef HPUX5 _PROTOTYP( char * ttyname, (int) ); #else #ifdef PS2AIX10 _PROTOTYP( char * ttyname, (int) ); #else #ifdef BSD42 _PROTOTYP( char * ttyname, (int) ); #endif /* BSD42 */ #endif /* PS2AIX10 */ #endif /* HPUX5 */ #endif /* HPUX6 */ #endif /* ultrix */ #endif /* SV68R3V6 */ #endif /* CK_SCO32V4 */ #ifndef SIGUSR1 /* User-defined signals */ #define SIGUSR1 30 #endif /* SIGUSR1 */ #ifndef SIGUSR2 #define SIGUSR2 31 #endif /* SIGUSR2 */ /* ignorsigs() sets certain signals to SIG_IGN. But when a signal is ignored, it remains ignored across exec(), so we have to restore these signals before exec(), which is the purpose of restorsigs(). */ static VOID ignorsigs() { /* Ignore these signals */ savquit = signal(SIGQUIT,SIG_IGN); /* Ignore Quit signal */ #ifdef SIGDANGER /* Ignore danger signals */ /* This signal is sent when the system is low on swap space. Processes that don't handle it are candidates for termination. If swap space doesn't clear out enough, we still might be terminated via kill() -- nothing we can do about that! Conceivably, this could be improved by installing a real signal handler that warns the user, but that would be pretty complicated, since we are not always in control of the screen -- e.g. during remote-mode file transfer. */ savdanger = signal(SIGDANGER,SIG_IGN); /* e.g. in AIX */ #endif /* SIGDANGER */ #ifdef SIGPIPE /* This one comes when a TCP/IP connection is broken by the remote. We prefer to catch this situation by examining error codes from write(). */ savpipe = signal(SIGPIPE,SIG_IGN); #endif /* SIGPIPE */ savusr1 = signal(SIGUSR1,SIG_IGN); /* Ignore user-defined signals */ savusr2 = signal(SIGUSR2,SIG_IGN); } VOID restorsigs() { /* Restore these signals */ (VOID) signal(SIGQUIT,savquit); /* (used in ckufio.c) */ #ifdef SIGDANGER (VOID) signal(SIGDANGER,savdanger); #endif /* SIGDANGER */ #ifdef SIGPIPE (VOID) signal(SIGPIPE,savpipe); #endif /* SIGPIPE */ (VOID) signal(SIGUSR1,savusr1); (VOID) signal(SIGUSR2,savusr2); } int sysinit() { int x; char * s; #ifdef CK_UTSNAME struct utsname name; #endif /* CK_UTSNAME */ extern char startupdir[]; /* BEFORE ANYTHING ELSE: Initialize the setuid package. Change to the user's real user and group ID. If this can't be done, don't run at all. */ x = priv_ini(); #ifdef SUIDDEBUG fprintf(stderr,"PRIV_INI=%d\n",x); #endif /* SUIDDEBUG */ if (x) { if (x & 1) fprintf(stderr,"Fatal: setuid failure.\n"); if (x & 2) fprintf(stderr,"Fatal: setgid failure.\n"); if (x & 4) fprintf(stderr,"Fatal: C-Kermit setuid to root!\n"); exit(1); } signal(SIGINT,SIG_IGN); /* Ignore interrupts at first */ signal(SIGFPE,SIG_IGN); /* Ignore floating-point exceptions */ signal(SIGHUP,sighup); /* Catch SIGHUP */ #ifndef NOSIGWINCH #ifdef SIGWINCH signal(SIGWINCH,winchh); /* Catch window-size change */ #endif /* SIGWINCH */ #endif /* NOSIGWINCH */ #ifdef SIGXFSZ signal(SIGXFSZ,SIG_IGN); /* Ignore writing past file limit */ #endif /* SIGXFSZ */ #ifndef NOJC /* Get the initial job control state. If it is SIG_IGN, that means the shell does not support job control, and so we'd better not suspend ourselves. */ #ifdef SIGTSTP jchdlr = signal(SIGTSTP,SIG_IGN); if (jchdlr == SIG_IGN) { jcshell = 0; debug(F100,"sysinit jchdlr: SIG_IGN","",0); } else if (jchdlr == SIG_DFL) { debug(F100,"sysinit jchdlr: SIG_DFL","",0); jcshell = 1; } else { debug(F100,"sysinit jchdlr: other","",0); jcshell = 3; } (VOID) signal(SIGTSTP,jchdlr); /* Put it back... */ #endif /* SIGTSTP */ #endif /* NOJC */ conbgt(0); /* See if we're in the background */ congm(); /* Get console modes */ (VOID) signal(SIGALRM,SIG_IGN); /* Ignore alarms */ ignorsigs(); /* Ignore some other signals */ #ifdef F_SETFL iniflags = fcntl(0,F_GETFL,0); /* Get stdin flags */ #endif /* F_SETFL */ #ifdef ultrix gtty(0,&vanilla); /* Get sgtty info */ #else #ifdef AUX set42sig(); /* Don't ask! (hakanson@cs.orst.edu) */ #endif /* AUX */ #endif /* ultrix */ /* Warning: on some UNIX systems (SVR4?), ttyname() reportedly opens /dev but never closes it. If it is called often enough, we run out of file descriptors and subsequent open()'s of other devices or files can fail. */ s = NULL; #ifndef MINIX if (isatty(0)) /* Name of controlling terminal */ s = ttyname(0); else if (isatty(1)) s = ttyname(1); else if (isatty(2)) s = ttyname(2); debug(F110,"sysinit ttyname(0)",s,0); #endif /* MINIX */ #ifdef BEOS if (!dftty) makestr(&dftty,s); #endif /* BEOS */ if (s) ckstrncpy((char *)cttnam,s,DEVNAMLEN+1); #ifdef SVORPOSIX #ifndef ANDROID if (!cttnam[0]) ctermid(cttnam); #endif /* ANDROID */ #endif /* SVORPOSIX */ if (!cttnam[0]) ckstrncpy((char *)cttnam,dftty,DEVNAMLEN+1); debug(F110,"sysinit CTTNAM",CTTNAM,0); debug(F110,"sysinit cttnam",cttnam,0); ttgwsiz(); /* Get window (screen) dimensions. */ #ifndef NOSYSCONF #ifdef _SC_OPEN_MAX ckmaxfiles = sysconf(_SC_OPEN_MAX); #endif /* _SC_OPEN_MAX */ #endif /* NOSYSCONF */ #ifdef Plan9 if (!backgrd) { consctlfd = open("/dev/consctl", O_WRONLY); /*noisefd = open("/dev/noise", O_WRONLY)*/ } ckxech = 1; #endif /* Plan9 */ #ifdef CK_UTSNAME if (uname(&name) > -1) { ckstrncpy(unm_mch,name.machine,CK_SYSNMLN); ckstrncpy(unm_nam,name.sysname,CK_SYSNMLN); ckstrncpy(unm_rel,name.release,CK_SYSNMLN); ckstrncpy(unm_ver,name.version,CK_SYSNMLN); #ifdef DEBUG if (deblog) { debug(F110,"sysinit uname machine",unm_mch,0); debug(F110,"sysinit uname sysname",unm_nam,0); debug(F110,"sysinit uname release",unm_rel,0); debug(F110,"sysinit uname version",unm_ver,0); } #endif /* DEBUG */ #ifdef HPUX9PLUS if (name.machine[5] == '8') hpis800 = 1; else hpis800 = 0; debug(F101,"sysinit hpis800","",hpis800); #endif /* HPUX9PLUS */ #ifdef TRU64 getsysinfo(GSI_PLATFORM_NAME, unm_mod, CK_SYSNMLN, 0, 0); debug(F110,"sysinit getsysinfo model",unm_mod,0); #endif /* TRU64 */ #ifdef SOLARIS25 sysinfo(SI_PLATFORM, unm_mod, CK_SYSNMLN); debug(F110,"sysinit sysinfo model",unm_mod,0); #endif /* SOLARIS25 */ } #endif /* CK_UTSNAME */ #ifdef CK_ENVIRONMENT { #ifdef TNCODE extern char tn_env_acct[], tn_env_disp[], tn_env_job[], tn_env_prnt[], tn_env_sys[]; #endif /* TNCODE */ extern char uidbuf[]; extern char * whoami(); char *p; #ifdef CKSENDUID uidbuf[0] = '\0'; #ifdef IKSD if (!inserver) { #endif /* IKSD */ p = getenv("USER"); debug(F110,"sysinit uidbuf from USER",uidbuf,0); if (!p) p = ""; if (!*p) { p = getenv("LOGNAME"); debug(F110,"sysinit uidbuf from LOGNAME",uidbuf,0); } if (!p) p = ""; if (!*p) { p = whoami(); debug(F110,"sysinit uidbuf from whoami()",uidbuf,0); } if (!p) p = ""; ckstrncpy(uidbuf, *p ? p : "UNKNOWN", UIDBUFLEN); #ifdef IKSD } #endif /* IKSD */ debug(F110,"sysinit final uidbuf",uidbuf,0); #endif /* CKSENDUID */ #ifdef TNCODE if ((p = getenv("JOB"))) ckstrncpy(tn_env_job,p,63); if ((p = getenv("ACCT"))) ckstrncpy(tn_env_acct,p,63); if ((p = getenv("PRINTER"))) ckstrncpy(tn_env_prnt,p,63); if ((p = getenv("DISPLAY"))) ckstrncpy(tn_env_disp,p,63); #ifdef aegis ckstrncpy(tn_env_sys,"Aegis",64); #else #ifdef Plan9 ckstrncpy(tn_env_sys,"Plan9",64); #else ckstrncpy(tn_env_sys,"UNIX",64); #endif /* Plan9 */ #endif /* aegis */ #endif /* TNCODE */ } #endif /* CK_ENVIRONMENT */ #ifdef CK_SNDLOC { extern char * tn_loc; char *p; if ((p = getenv("LOCATION"))) if ((tn_loc = (char *)malloc((int)strlen(p)+1))) strcpy(tn_loc,p); /* safe */ } #endif /* CK_SNDLOC */ ckstrncpy(startupdir, zgtdir(), CKMAXPATH); startupdir[CKMAXPATH] = '\0'; x = strlen(startupdir); if (x <= 0) { startupdir[0] = '/'; startupdir[1] = '\0'; } else if (startupdir[x-1] != '/') { startupdir[x] = '/'; startupdir[x+1] = '\0'; } debug(F110,"sysinit startupdir",startupdir,0); #ifdef TTLEBUF le_init(); #endif /* TTLEBUF */ #ifdef BSD44ORPOSIX /* This should catch the ncurses platforms */ /* Some platforms don't have putenv(), like NeXTSTEP */ putenv("NCURSES_NO_SETBUF=1"); #endif /* BSD44ORPOSIX */ return(0); } /* S Y S C L E A N U P -- System-dependent program cleanup. */ int syscleanup() { #ifdef F_SETFL if (iniflags > -1) fcntl(0,F_SETFL,iniflags); /* Restore stdin flags */ #endif /* F_SETFL */ #ifdef ultrix stty(0,&vanilla); /* Get sgtty info */ #endif /* ultrix */ #ifdef NETCMD if (ttpid) kill(ttpid,9); #endif /* NETCMD */ return(0); } /* T T O P E N -- Open a tty for exclusive access. */ /* Call with: 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. But watch out: if a line is already open, or if requested line can't be opened, then lcl remains (and is returned as) -1. modem: Less than zero: ttname is a network host name. Zero or greater: ttname is a terminal device name. Zero means a local connection (don't use modem signals). Positive means use modem signals. timo: 0 = no timer. nonzero = number of seconds to wait for open() to return before timing out. Returns: 0 on success (or, in the case of a PTY, the positive process ID) -5 if device is in use -4 if access to device is denied -3 if access to lock directory denied -2 upon timeout waiting for device to open -1 on other error */ static int ttotmo = 0; /* Timeout flag */ /* Flag kept here to avoid being clobbered by longjmp. */ int #ifdef CK_ANSIC ttopen( char *ttname, int *lcl, int modem, int timo ) #else ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; #endif /* CK_ANSIC */ { #ifdef BSD44 #define ctermid(x) strcpy(x,"") #else #ifdef SVORPOSIX #ifndef CIE #else /* CIE Regulus */ #define ctermid(x) strcpy(x,"") #endif /* CIE */ #endif /* SVORPOSIX */ #endif /* BSD44 */ #ifdef ultrix int temp = 0; #endif /* ultrix */ #ifndef OPENFIRST char fullname[DEVNAMLEN+1]; #endif /* OPENFIRST */ char * fnam; /* Full name after expansion */ int y; #ifndef pdp11 #define NAMEFD /* Feature to allow name to be an open file descriptor */ #endif /* pdp11 */ #ifdef NAMEFD char *p; debug(F101,"ttopen telnetfd","",telnetfd); #endif /* NAMEFD */ debug(F110,"ttopen ttname",ttname,0); debug(F110,"ttopen ttnmsv",ttnmsv,0); debug(F101,"ttopen modem","",modem); debug(F101,"ttopen netconn","",netconn); debug(F101,"ttopen ttyfd","",ttyfd); debug(F101,"ttopen *lcl","",*lcl); debug(F101,"ttopen ttmdm","",ttmdm); debug(F101,"ttopen ttnet","",ttnet); ttpmsk = 0xff; lockpid[0] = '\0'; if (ttyfd > -1) { /* If device already opened */ if (!strncmp(ttname,ttnmsv,DEVNAMLEN)) /* are new & old names equal? */ return(0); /* Yes, nothing to do - just return */ ttnmsv[0] = '\0'; /* No, clear out old name */ ttclos(ttyfd); /* close old connection. */ } wasclosed = 0; /* New connection, not closed yet. */ ttpipe = 0; /* Assume it's not a pipe */ ttpty = 0; /* or a pty... */ debug(F110,"XXX netopen in ifdef NETCONN...","A",0); #ifdef NETCONN /* This is a bit tricky... Suppose that previously Kermit had dialed a telnet modem server ("set host xxx:2001, set modem type usr, dial ..."). Then the connection was closed (ttyfd = -1), and then a REDIAL command was given. At this point we've obliterated the negative modem type hack, and so would treat the IP hostname as a device name, and would then fail because of "No such device or directory". But the previous connection has left behind some clues, so let's use them... */ debug(F110,"XXX netopen in ifdef NETCONN...OK","A",0); if (ttyfd < 0) { /* Connection is not open */ if (!strcmp(ttname,ttnmsv)) { /* Old and new names the same? */ if (((netconn > 0) && (ttmdm < 0)) || ((ttnet > 0) && (!ckstrchr(ttname,'/')) && (ckstrchr(ttname,':'))) ) { int x, rc; x = (ttmdm < 0) ? -ttmdm : ttnet; rc = netopen(ttname, lcl, x); debug(F111,"ttopen REOPEN netopen",ttname,rc); if (rc > -1) { netconn = 1; xlocal = *lcl = 1; } else { netconn = 0; } gotsigs = 0; return(rc); } } } #endif /* NETCONN */ #ifdef MAXNAMLEN debug(F100,"ttopen MAXNAMLEN defined","",0); #else debug(F100,"ttopen MAXNAMLEN *NOT* defined","",0); #endif #ifdef BSD4 debug(F100,"ttopen BSD4 defined","",0); #else debug(F100,"ttopen BSD4 *NOT* defined","",0); #endif /* BSD4 */ #ifdef BSD42 debug(F100,"ttopen BSD42 defined","",0); #else debug(F100,"ttopen BSD42 *NOT* defined","",0); #endif /* BSD42 */ #ifdef MYREAD debug(F100,"ttopen MYREAD defined","",0); #else debug(F100,"ttopen MYREAD *NOT* defined","",0); #endif /* MYREAD */ #ifdef NETCONN if (modem < 0) { /* modem < 0 = code for network */ int x; ttmdm = modem; modem = -modem; /* Positive network type number */ fdflag = 0; /* Stdio not redirected. */ netconn = 1; /* And it's a network connection */ debug(F111,"ttopen net",ttname,modem); #ifdef NAMEFD for (p = ttname; isdigit(*p); p++) /* Check for all digits */ ; /* Believe it or not, this semicolon must be on a new line */ if (*p == '\0' && (telnetfd || x25fd)) { /* Avoid X.121 addresses */ ttyfd = atoi(ttname); /* Is there a way to test it's open? */ ttfdflg = 1; /* We got an open file descriptor */ debug(F111,"ttopen net ttfdflg",ttname,ttfdflg); debug(F101,"ttopen net ttyfd","",ttyfd); ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */ x = 1; /* Return code is "good". */ if (telnetfd) { ttnet = NET_TCPB; if (ttnproto != NP_TCPRAW) ttnproto = NP_TELNET; #ifdef SUNX25 } else if (x25fd) { ttnet = NET_SX25; ttnproto = NP_NONE; #endif /* SUNX25 */ } } else { /* Host name or address given */ #ifdef NETPTY if (modem == NET_PTY) { int x; if (nopush) { debug(F100,"ttopen PTY: nopush","",0); return(-1); } ttnet = NET_PTY; ttnproto = NP_NONE; netconn = 1; /* but we don't use network i/o */ ttpty = 1; debug(F110,"ttopen PTY",ttname,0); x = do_pty(&ttyfd,ttname,0); debug(F101,"ttopen do_pty return code","",x); if (x > -1) { ckstrncpy(ttnmsv,ttname,DEVNAMLEN); xlocal = *lcl = 1; /* It's local */ } else { ttpty = 0; netconn = 0; } gotsigs = 0; return(x); } #endif /* NETPTY */ #ifdef NETCMD /* dup2() is not available on older System V platforms like AT&T 3Bx. For those systems we punt by not defining NETCMD, but we might be able to do better -- see workarounds for this problem in ckufio.c (search for dup2). */ if (modem == NET_CMD) { if (nopush) { debug(F100,"ttopen pipe: nopush","",0); return(-1); } if (pipe(pipe0) || pipe(pipe1)) { perror("Pipe error"); return(-1); } ttpid = fork(); /* Make a fork */ switch (ttpid) { case -1: /* Error making fork */ close(pipe0[0]); close(pipe0[1]); close(pipe1[0]); close(pipe1[1]); perror("Fork error"); return(-1); case 0: /* Child. */ close(pipe0[0]); close(pipe1[1]); dup2(pipe0[1], 1); close(pipe0[1]); dup2(pipe1[0], 0); close(pipe1[0]); /* I can't image what this is; system() executes a shell command. ttname holds the name of terminal device, it's not a command. --fdc Fri Sep 18 15:51:18 2020 system(ttname); */ _exit(0); default: /* Parent */ close(pipe0[1]); close(pipe1[0]); fdin = pipe0[0]; /* Read from pipe */ fdout = pipe1[1]; /* Write to pipe */ ttout = fdopen(fdout,"w"); /* Get stream so we can */ if (!ttout) { /* make it unbuffered. */ perror("fdopen failure"); return(-1); } setbuf(ttout,NULL); ckstrncpy(ttnmsv,ttname,DEVNAMLEN); xlocal = *lcl = 1; /* It's local */ netconn = 1; /* Call it a network connection */ ttmdm = modem; /* Remember network type */ ttyfd = fdin; ttpipe = 1; gotsigs = 0; return(0); } } #endif /* NETCMD */ #endif /* NAMEFD */ debug(F110,"XXX netopen in ifdef NETCONN...","B",0); x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */ debug(F110,"XXX netopen in ifdef NETCONN...OK","B",0); if (x > -1) { ckstrncpy(ttnmsv,ttname,DEVNAMLEN); } else netconn = 0; #ifdef NAMEFD } #endif /* NAMEFD */ #ifdef sony_news /* Sony NEWS */ if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get Kanji mode */ perror("ttopen error getting Kanji mode (network)"); debug(F111,"ttopen error getting Kanji mode","network",0); km_ext = -1; /* Make sure this stays undefined. */ } #endif /* sony_news */ xlocal = *lcl = 1; /* Network connections are local. */ debug(F101,"ttopen net x","",x); #ifdef COMMENT /* Let netopen() do this */ if (x > -1 && !x25fd) x = tn_ini(); /* Initialize TELNET protocol */ #endif /* COMMENT */ gotsigs = 0; return(x); } else { /* Terminal device */ #endif /* NETCONN */ #ifdef NAMEFD /* This code lets you give Kermit an open file descriptor for a serial communication device, rather than a device name. Kermit assumes that the line is already open, locked, conditioned with the right parameters, etc. */ for (p = ttname; isdigit(*p); p++) ; /* Check for all-digits */ if (*p == '\0') { ttyfd = atoi(ttname); /* Is there a way to test it's open? */ debug(F111,"ttopen got open fd",ttname,ttyfd); ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */ if (ttyfd >= 0 && ttyfd < 3) /* If it's stdio... */ xlocal = *lcl = 0; /* we're in remote mode */ else /* otherwise */ xlocal = *lcl = 1; /* local mode. */ netconn = 0; /* Assume it's not a network. */ tvtflg = 0; /* Might need to initialize modes. */ ttmdm = modem; /* Remember modem type. */ fdflag = 0; /* Stdio not redirected. */ ttfdflg = 1; /* Flag we were opened this way. */ debug(F111,"ttopen non-net ttfdflg",ttname,ttfdflg); debug(F101,"ttopen non-net ttyfd","",ttyfd); #ifdef sony_news /* Sony NEWS */ /* Get device Kanji mode */ if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { perror("ttopen error getting Kanji mode"); debug(F101,"ttopen error getting Kanji mode","",0); km_ext = -1; /* Make sure this stays undefined. */ } #endif /* sony_news */ gotsigs = 0; return(0); /* Return success */ } #endif /* NAMEFD */ #ifdef NETCONN } #endif /* NETCONN */ /* Here we have to open a serial device of the given name. */ netconn = 0; /* So it's not a network connection */ occt = signal(SIGINT, cctrap); /* Set Control-C trap, save old one */ sigint_ign = 0; tvtflg = 0; /* Flag for use by ttvt(). */ /* 0 = ttvt not called yet for this device */ fdflag = (!isatty(0) || !isatty(1)); /* Flag for stdio redirected */ debug(F101,"ttopen fdflag","",fdflag); ttmdm = modem; /* Make this available to other fns */ xlocal = *lcl; /* Make this available to other fns */ /* Code for handling bidirectional tty lines goes here. */ /* Use specified method for turning off logins and suppressing getty. */ #ifdef ACUCNTRL /* Should put call to priv_on() here, but that would be very risky! */ acucntrl("disable",ttname); /* acucntrl() program. */ /* and priv_off() here... */ #else #ifdef ATT7300 if ((attmodem & DOGETY) == 0) /* offgetty() program. */ attmodem |= offgetty(ttname); /* Remember response. */ #endif /* ATT7300 */ #endif /* ACUCNTRL */ #ifdef OPENFIRST /* 1985-2001: opens device first then gets lock; reason: Kermit usually has to run setuid or setgid in order to create a lockfile. If you give a SET LINE command for a device that happens to be your job's controlling terminal, Kermit doesn't have to create a lockfile, and in fact should not create one, and would fail if it tried to if it did not have the required privileges. But you can't find out if two tty device names are equivalent until you have a file descriptor that you can give to ttyname(). But this can cause a race condition between Kermit and [m]getty. So see the [#]else part... */ /* In the following section, we open the tty device for read/write. If a modem has been specified via "set modem" prior to "set line" then the O_NDELAY parameter is used in the open, provided this symbol is defined (e.g. in fcntl.h), so that the program does not hang waiting for carrier (which in most cases won't be present because a connection has not been dialed yet). O_NDELAY is removed later on in ttopen(). It would make more sense to first determine if the line is local before doing this, but because ttyname() requires a file descriptor, we have to open it first. See do_open(). Now open the device using the desired treatment of carrier. If carrier is REQUIRED, then open could hang forever, so an optional timer is provided. If carrier is not required, the timer should never go off, and should do no harm... */ ttotmo = 0; /* Flag no timeout */ debug(F101,"ttopen timo","",timo); debug(F101,"ttopen xlocal","",xlocal); if (timo > 0) { int xx; saval = signal(SIGALRM,timerh); /* Timed, set up timer. */ xx = alarm(timo); /* Timed open() */ debug(F101,"ttopen alarm","",xx); if ( #ifdef CK_POSIX_SIG sigsetjmp(sjbuf,1) #else setjmp(sjbuf) #endif /* CK_POSIX_SIG */ ) { ttotmo = 1; /* Flag timeout. */ } else ttyfd = do_open(ttname); ttimoff(); debug(F111,"ttopen","modem",modem); debug(F101,"ttopen ttyfd","",ttyfd); debug(F101,"ttopen alarm return","",ttotmo); } else { errno = 0; ttyfd = do_open(ttname); } debug(F111,"ttopen ttyfd",ttname,ttyfd); if (ttyfd < 0) { /* If couldn't open, fail. */ debug(F101,"ttopen errno","",errno); if (errno > 0 && !quiet) perror(ttname); /* Print message */ #ifdef ATT7300 if (attmodem & DOGETY) /* was getty(1m) running before us? */ ongetty(ttnmsv); /* yes, restart on tty line */ attmodem &= ~DOGETY; /* no phone in use, getty restored */ #else #ifdef ACUCNTRL /* Should put call to priv_on() here, but that would be risky! */ acucntrl("enable",ttname); /* acucntrl() program. */ /* and priv_off() here... */ #endif /* ACUNTRL */ #endif /* ATT7300 */ signal(SIGINT,occt); /* Put old Ctrl-C trap back. */ if (errno == EACCES) { /* Device is protected against user */ debug(F110,"ttopen EACCESS",ttname,0); /* Return -4 */ return(-4); } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */ } #ifdef QNX { extern int qnxportlock; x = qnxopencount(); debug(F101,"ttopen qnxopencount","",x); debug(F101,"ttopen qnxportlock","",qnxportlock); if (x < 0 && qnxportlock) { ttclos(0); printf("?Can't get port open count\n"); printf("(Try again with SET QNX-PORT-LOCK OFF)\n"); return(-1); /* Indicate device is in use */ } if (x > 1) { /* 1 == me */ if (qnxportlock) ttclos(0); return(-2); /* Indicate device is in use */ else if (!quiet) printf("WARNING: \"%s\" looks busy...\n",ttdev); } } #endif /* QNX */ #ifdef Plan9 /* take this opportunity to open the control channel */ if (p9openttyctl(ttname) < 0) #else /* Make sure it's a real tty. */ if (!ttfdflg && !isatty(ttyfd) && strcmp(ttname,"/dev/null")) #endif /* Plan9 */ { fprintf(stderr,"%s is not a terminal device\n",ttname); debug(F111,"ttopen not a tty",ttname,errno); close(ttyfd); ttyfd = -1; wasclosed = 1; signal(SIGINT,occt); return(-1); } #ifdef aegis /* Apollo C runtime claims that console pads are tty devices, which * is reasonable, but they aren't any good for packet transfer. */ ios_$inq_type_uid((short)ttyfd, ttyuid, st); if (st.all != status_$ok) { fprintf(stderr, "problem getting tty object type: "); error_$print(st); } else if (ttyuid != sio_$uid) { /* reject non-SIO lines */ close(ttyfd); ttyfd = -1; wasclosed = 1; errno = ENOTTY; perror(ttname); signal(SIGINT,occt); return(-1); } #endif /* aegis */ sigint_ign = (occt == SIG_IGN) ? 1 : 0; ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */ /* Caller wants us to figure out if line is controlling tty */ if (*lcl < 0) { if (strcmp(ttname,CTTNAM) == 0) { /* "/dev/tty" always remote */ xlocal = 0; debug(F111,"ttopen ttname=CTTNAM",ttname,xlocal); } else if (strcmp(ttname,cttnam) == 0) { xlocal = 0; debug(F111,"ttopen ttname=cttnam",ttname,xlocal); } else if (cttnam[0]) { #ifdef BEBOX_DR7 x = ttnmsv; /* ttyname() is broken */ #else x = ttyname(ttyfd); /* Get real name of ttname. */ #endif /* BEBOX_DR7 */ if (!x) x = ""; if (*x) xlocal = ((strncmp(x,cttnam,DEVNAMLEN) == 0) ? 0 : 1); else xlocal = 1; debug(F111,"ttopen ttyname(ttyfd) xlocal",x,xlocal); } } #ifndef NOFDZERO /* Note, the following code was added so that Unix "idle-line" snoopers */ /* would not think Kermit was idle when it was transferring files, and */ /* maybe log people out. */ if (xlocal == 0) { /* Remote mode */ if (fdflag == 0) { /* Standard i/o is not redirected */ debug(F100,"ttopen setting ttyfd = 0","",0); #ifdef LYNXOS /* On Lynx OS, fd 0 is open for read only. */ dup2(ttyfd,0); #endif /* LYNXOS */ close(ttyfd); /* Use file descriptor 0 */ ttyfd = 0; } else { /* Standard i/o is redirected */ debug(F101,"ttopen stdio redirected","",ttyfd); } } #endif /* NOFDZERO */ /* Now check if line is locked -- if so fail, else lock for ourselves */ /* Note: After having done this, don't forget to delete the lock if you */ /* leave ttopen() with an error condition. */ lkf = 0; /* Check lock */ if (xlocal > 0) { int xx; int xpid; if ((xx = ttlock(ttname)) < 0) { /* Can't lock it. */ debug(F111,"ttopen ttlock fails",ttname,xx); /* WARNING - This close() can hang if tty is an empty socket... */ close(ttyfd); /* Close the device. */ ttyfd = -1; /* Erase its file descriptor. */ wasclosed = 1; signal(SIGINT,occt); /* Put old SIGINT back. */ sigint_ign = (occt == SIG_IGN) ? 1 : 0; if (xx == -2) { /* If lockfile says device in use, */ #ifndef NOUUCP debug(F111,"ttopen reading lockfile pid",flfnam,xx); xpid = ttrpid(flfnam); /* Try to read pid from lockfile */ if (xpid > -1) { /* If we got a pid */ if (!quiet) printf("Locked by process %d\n",xpid); /* tell them. */ sprintf(lockpid,"%d",xpid); /* Record it too */ debug(F110,"ttopen lockpid",lockpid,0); } else if (*flfnam) { extern char *DIRCMD; char *p = NULL; int x; x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2; p = malloc(x); /* Print a directory listing. */ /* Note: priv_on() won't help here, because we do not pass privs along to to inferior processes, in this case ls. So if the real user does not have directory-listing access to the lockfile directory, this will result in something like "not found". That's why we try this only as a last resort. */ if (p) { /* If we got the space... */ ckmakmsg(p,x,DIRCMD," ",flfnam,NULL); zsyscmd(p); /* Get listing. */ if (p) { /* free the space */ free(p); p = NULL; } } } #endif /* NOUUCP */ return(-5); /* Code for device in use */ } else return(-3); /* Access denied */ } else lkf = 1; } #else /* OPENFIRST */ /* 27 Oct 2001: New simpler code that gets the lock first and then opens the device, which eliminates the race condition. The downside is you can no longer say "set line /dev/ttyp0" or whatever, where /dev/ttyp0 is your login terminal, without trying to create a lockfile, which fails if C-Kermit lacks privs, and if it succeeds, it has created a lockfile where it didn't create one before. */ xlocal = *lcl; /* Is the device my login terminal? */ debug(F111,"ttopen xlocal","A",xlocal); fnam = ttname; if (strcmp(ttname,CTTNAM) && netconn == 0) { if (zfnqfp(ttname,DEVNAMLEN+1,fullname)) { if ((int)strlen(fullname) > 0) fnam = fullname; } } debug(F110,"ttopen fnam",fnam,0); if (xlocal < 0) { xlocal = (strcmp(fnam,CTTNAM) != 0); } debug(F111,"ttopen xlocal","B",xlocal); lkf = 0; /* No lock yet */ if (xlocal > 0) { /* If not... */ int xx; int xpid; xx = ttlock(fnam); /* Try to lock it. */ debug(F101,"ttopen ttlock","",xx); if (xx < 0) { /* Can't lock it. */ debug(F111,"ttopen ttlock fails",fnam,xx); if (xx == -2) { /* If lockfile says device in use, */ #ifndef NOUUCP debug(F111,"ttopen reading lockfile pid",flfnam,xx); xpid = ttrpid(flfnam); /* Try to read pid from lockfile */ if (xpid > -1) { /* If we got a pid */ if (!quiet) printf("Locked by process %d\n",xpid); /* tell them. */ ckstrncpy(lockpid,ckitoa(xpid),16); debug(F110,"ttopen lockpid",lockpid,0); #ifndef NOPUSH } else if (flfnam[0] && !nopush) { extern char *DIRCMD; char *p = NULL; int x; x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2; p = malloc(x); /* Print a directory listing. */ /* Note: priv_on() won't help here, because we do not pass privs along to to inferior processes, in this case ls. So if the real user does not have directory-listing access to the lockfile directory, this will result in something like "not found". That's why we try this only as a last resort. */ if (p) { /* If we got the space... */ ckmakmsg(p,x,DIRCMD," ",flfnam,NULL); zsyscmd(p); /* Get listing. */ if (p) { /* free the space */ free(p); p = NULL; } } #endif /* NOPUSH */ } #endif /* NOUUCP */ return(-5); /* Code for device in use */ } else return(-3); /* Access denied */ } else lkf = 1; } /* Have lock -- now it's safe to open the device */ debug(F101,"ttopen lkf","",lkf); debug(F101,"ttopen timo","",timo); ttotmo = 0; /* Flag no timeout */ if (timo > 0) { int xx; saval = signal(SIGALRM,timerh); /* Timed, set up timer. */ xx = alarm(timo); /* Timed open() */ debug(F101,"ttopen alarm","",xx); if ( #ifdef CK_POSIX_SIG sigsetjmp(sjbuf,1) #else setjmp(sjbuf) #endif /* CK_POSIX_SIG */ ) { ttotmo = 1; /* Flag timeout. */ } else { ttyfd = do_open(fnam); } ttimoff(); debug(F111,"ttopen timed ttyfd",fnam,ttyfd); } else { errno = 0; ttyfd = do_open(fnam); debug(F111,"ttopen untimed ttyfd",fnam,ttyfd); } if (ttyfd < 0) { /* If couldn't open, fail. */ debug(F111,"ttopen errno",fnam,errno); debug(F111,"ttopen xlocal","C",xlocal); if (xlocal == 0) { debug(F100,"ttopen substituting 0","",0); ttyfd = 0; } else { if (errno > 0 && !quiet) { debug(F111,"ttopen perror",fnam,errno); perror(fnam); /* Print message */ } if (ttunlck()) /* Release the lock file */ fprintf(stderr,"Warning, problem releasing lock\r\n"); } } if (ttyfd < 0) { /* ttyfd is still < 0? */ #ifdef ATT7300 if (attmodem & DOGETY) /* was getty(1m) running before us? */ ongetty(ttnmsv); /* yes, restart on tty line */ attmodem &= ~DOGETY; /* no phone in use, getty restored */ #else #ifdef ACUCNTRL /* Should put call to priv_on() here, but that would be risky! */ acucntrl("enable",fnam); /* acucntrl() program. */ /* and priv_off() here... */ #endif /* ACUNTRL */ #endif /* ATT7300 */ signal(SIGINT,occt); /* Put old Ctrl-C trap back. */ if (errno == EACCES) { /* Device is protected against user */ debug(F110,"ttopen EACCESS",fnam,0); /* Return -4 */ return(-4); } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */ } /* Make sure it's a real tty. */ #ifdef Plan9 /* take this opportunity to open the control channel */ if (p9openttyctl(fnam) < 0) #else if (!ttfdflg && !isatty(ttyfd) && strcmp(fnam,"/dev/null")) #endif /* Plan9 */ { fprintf(stderr,"%s is not a terminal device\n",fnam); debug(F111,"ttopen not a tty",fnam,errno); if (ttunlck()) /* Release the lock file */ fprintf(stderr,"Warning, problem releasing lock\r\n"); close(ttyfd); ttyfd = -1; wasclosed = 1; signal(SIGINT,occt); return(-1); } #ifdef aegis /* Apollo C runtime claims that console pads are tty devices, which is reasonable, but they aren't any good for packet transfer. */ ios_$inq_type_uid((short)ttyfd, ttyuid, st); if (st.all != status_$ok) { fprintf(stderr, "problem getting tty object type: "); error_$print(st); } else if (ttyuid != sio_$uid) { /* Reject non-SIO lines */ close(ttyfd); ttyfd = -1; wasclosed = 1; errno = ENOTTY; perror(fnam); signal(SIGINT,occt); return(-1); } #endif /* aegis */ sigint_ign = (occt == SIG_IGN) ? 1 : 0; ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */ /* Caller wants us to figure out if line is controlling tty */ if (*lcl < 0) { char * s; if (strcmp(fnam,CTTNAM) == 0) { /* "/dev/tty" always remote */ xlocal = 0; debug(F111,"ttopen fnam=CTTNAM",fnam,xlocal); } else if (strcmp(fnam,cttnam) == 0) { xlocal = 0; debug(F111,"ttopen fnam=cttnam",fnam,xlocal); } else if (cttnam[0]) { #ifdef BEBOX_DR7 s = ttnmsv; /* ttyname() is broken */ #else s = ttyname(ttyfd); /* Get real name of ttname. */ #endif /* BEBOX_DR7 */ if (!s) s = ""; if (*s) xlocal = ((strncmp(s,cttnam,DEVNAMLEN) == 0) ? 0 : 1); else xlocal = 1; debug(F111,"ttopen ttyname(ttyfd) xlocal",s,xlocal); } } #ifndef NOFDZERO /* Note, the following code was added so that Unix "idle-line" snoopers */ /* would not think Kermit was idle when it was transferring files, and */ /* maybe log people out. */ if (xlocal == 0) { /* Remote mode */ if (fdflag == 0) { /* Standard i/o is not redirected */ debug(F100,"ttopen setting ttyfd = 0","",0); #ifdef LYNXOS /* On Lynx OS, fd 0 is open for read only. */ dup2(ttyfd,0); #endif /* LYNXOS */ close(ttyfd); /* Use file descriptor 0 */ ttyfd = 0; } else { /* Standard i/o is redirected */ debug(F101,"ttopen stdio redirected","",ttyfd); } } #endif /* NOFDZERO */ #endif /* OPENFIRST */ /* Got the line, now set the desired value for local. */ if (*lcl != 0) *lcl = xlocal; /* Some special stuff for v7... */ #ifdef V7 #ifndef MINIX if (kmem[TTY] < 0) { /* If open, then skip this. */ qaddr[TTY] = initrawq(ttyfd); /* Init the queue. */ if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) { fprintf(stderr, "Can't read /dev/kmem in ttopen.\n"); perror("/dev/kmem"); exit(1); } } #endif /* !MINIX */ #endif /* V7 */ /* No failure returns after this point */ #ifdef ultrix ioctl(ttyfd, TIOCMODEM, &temp); #ifdef TIOCSINUSE if (xlocal && ioctl(ttyfd, TIOCSINUSE, NULL) < 0) { if (!quiet) perror(fnam); } #endif /* TIOCSINUSE */ #endif /* ultrix */ /* Get tty device settings */ #ifdef BSD44ORPOSIX /* POSIX */ tcgetattr(ttyfd,&ttold); debug(F101,"ttopen tcgetattr ttold.c_lflag","",ttold.c_lflag); tcgetattr(ttyfd,&ttraw); debug(F101,"ttopen tcgetattr ttraw.c_lflag","",ttraw.c_lflag); tcgetattr(ttyfd,&tttvt); debug(F101,"ttopen tcgetattr tttvt.c_lflag","",tttvt.c_lflag); #else /* BSD, V7, and all others */ #ifdef ATTSV /* AT&T UNIX */ ioctl(ttyfd,TCGETA,&ttold); debug(F101,"ttopen ioctl TCGETA ttold.c_lflag","",ttold.c_lflag); ioctl(ttyfd,TCGETA,&ttraw); ioctl(ttyfd,TCGETA,&tttvt); #else #ifdef BELLV10 ioctl(ttyfd,TIOCGETP,&ttold); debug(F101,"ttopen BELLV10 ttold.sg_flags","",ttold.sg_flags); ioctl(ttyfd,TIOCGDEV,&tdold); debug(F101,"ttopen BELLV10 tdold.flags","",tdold.flags); #else gtty(ttyfd,&ttold); debug(F101,"ttopen gtty ttold.sg_flags","",ttold.sg_flags); #endif /* BELLV10 */ #ifdef sony_news /* Sony NEWS */ if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get console Kanji mode */ perror("ttopen error getting Kanji mode"); debug(F101,"ttopen error getting Kanji mode","",0); km_ext = -1; /* Make sure this stays undefined. */ } #endif /* sony_news */ #ifdef TIOCGETC debug(F100,"ttopen TIOCGETC","",0); tcharf = 0; /* In remote mode, also get */ if (xlocal == 0) { /* special characters */ if (ioctl(ttyfd,TIOCGETC,&tchold) < 0) { debug(F100,"ttopen TIOCGETC failed","",0); } else { tcharf = 1; /* It worked. */ ioctl(ttyfd,TIOCGETC,&tchnoi); /* Get another copy */ debug(F100,"ttopen TIOCGETC ok","",0); } } #else debug(F100,"ttopen TIOCGETC not defined","",0); #endif /* TIOCGETC */ #ifdef TIOCGLTC debug(F100,"ttopen TIOCGLTC","",0); ltcharf = 0; /* In remote mode, also get */ if (xlocal == 0) { /* local special characters */ if (ioctl(ttyfd,TIOCGLTC,<chold) < 0) { debug(F100,"ttopen TIOCGLTC failed","",0); } else { ltcharf = 1; /* It worked. */ ioctl(ttyfd,TIOCGLTC,<chnoi); /* Get another copy */ debug(F100,"ttopen TIOCGLTC ok","",0); } } #else debug(F100,"ttopen TIOCGLTC not defined","",0); #endif /* TIOCGLTC */ #ifdef TIOCLGET debug(F100,"ttopen TIOCLGET","",0); lmodef = 0; if (ioctl(ttyfd,TIOCLGET,&lmode) < 0) { debug(F100,"ttopen TIOCLGET failed","",0); } else { lmodef = 1; debug(F100,"ttopen TIOCLGET ok","",0); } #endif /* TIOCLGET */ #ifdef BELLV10 ioctl(ttyfd,TIOCGETP,&ttraw); ioctl(ttyfd,TIOCGETP,&tttvt); #else gtty(ttyfd,&ttraw); /* And a copy of it for packets*/ gtty(ttyfd,&tttvt); /* And one for virtual tty service */ #endif /* BELLV10 */ #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ /* Section for changing line discipline. It's restored in ttres(). */ #ifdef AIXRS #ifndef AIX41 { union txname ld_name; int ld_idx = 0; ttld = 0; do { ld_name.tx_which = ld_idx++; ioctl(ttyfd, TXGETCD, &ld_name); if (!strncmp(ld_name.tx_name, "rts", 3)) ttld |= 1; } while (*ld_name.tx_name); debug(F101,"AIX line discipline","",ttld); } #endif /* AIX41 */ #endif /* AIXRS */ #ifdef BSD41 /* For 4.1BSD only, force "old" tty driver, new one botches TANDEM. */ { int k; ioctl(ttyfd, TIOCGETD, &ttld); /* Get and save line discipline */ debug(F101,"4.1bsd line discipline","",ttld); k = OTTYDISC; /* Switch to "old" discipline */ k = ioctl(ttyfd, TIOCSETD, &k); debug(F101,"4.1bsd tiocsetd","",k); } #endif /* BSD41 */ #ifdef aegis /* This was previously done before the last two TCGETA or gtty above, * in both the ATTSV and not-ATTSV case. If it is not okay to have only * one copy if it here instead, give us a shout! */ sio_$control((short)ttyfd, sio_$raw_nl, false, st); if (xlocal) { /* ignore breaks from local line */ sio_$control((short)ttyfd, sio_$int_enable, false, st); sio_$control((short)ttyfd, sio_$quit_enable, false, st); } #endif /* aegis */ #ifdef VXVE ttraw.c_line = 0; /* STTY line 0 for VX/VE */ tttvt.c_line = 0; /* STTY line 0 for VX/VE */ ioctl(ttyfd,TCSETA,&ttraw); #endif /* vxve */ /* If O_NDELAY was used during open(), then remove it now. */ #ifdef O_NDELAY debug(F100,"ttopen O_NDELAY","",0); if (xlocal > 0) { if (fcntl(ttyfd, F_GETFL, 0) & O_NDELAY) { debug(F100,"ttopen fcntl O_NDELAY","",0); #ifndef aegis if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0) { debug(F100,"ttopen fcntl failure to unset O_NDELAY","",0); perror("Can't unset O_NDELAY"); } #endif /* aegis */ /* Some systems, notably Xenix (don't know how common this is in * other systems), need special treatment to get rid of the O_NDELAY * behaviour on read() with respect to carrier presence (i.e. read() * returning 0 when carrier absent), even though the above fcntl() * is enough to make read() wait for input when carrier is present. * This magic, in turn, requires CLOCAL for working when the carrier * is absent. But if xlocal == 0, presumably you already have CLOCAL * or you have a carrier, otherwise you wouldn't be running this. */ debug(F101,"ttopen xlocal","",xlocal); #ifdef ATTSV #ifdef BSD44ORPOSIX #ifdef COMMENT /* 12 Aug 1997 */ #ifdef __bsdi__ if (xlocal) ttraw.c_cflag |= CLOCAL; #else #ifdef __FreeBSD__ if (xlocal) ttraw.c_cflag |= CLOCAL; #endif /* __FreeBSD__ */ #endif /* __bsdi__ */ #else /* Not COMMENT */ #ifdef CLOCAL if (xlocal) /* Unset this if it's defined. */ ttraw.c_cflag |= CLOCAL; #endif /* CLOCAL */ #endif /* COMMENT */ debug(F101,"ttopen BSD44ORPOSIX calling tcsetattr","",TCSADRAIN); if (tcsetattr(ttyfd, TCSADRAIN, &ttraw) < 0) { debug(F100,"ttopen POSIX tcseattr fails","",0); perror("tcsetattr"); } #else /* !BSD44ORPOSIX */ if (xlocal) { ttraw.c_cflag |= CLOCAL; debug(F100,"ttopen calling ioctl(TCSETA)","",0); errno = 0; if (ioctl(ttyfd, TCSETA, &ttraw) < 0) { debug(F101,"ttopen ioctl(TCSETA) fails","",errno); perror("ioctl(TCSETA)"); } } #endif /* BSD44ORPOSIX */ #endif /* ATTSV */ #ifndef NOCOTFMC /* = NO Close(Open()) To Force Mode Change */ /* Reportedly lets uugetty grab the device in SCO UNIX 3.2 / XENIX 2.3 */ debug(F100,"ttopen executing close/open","",0); close( priv_opn(fnam, O_RDWR) ); /* Magic to force change. */ #endif /* NOCOTFMC */ } } #endif /* O_NDELAY */ /* Instruct the system how to treat the carrier, and set a few other tty * parameters. * * This also undoes the temporary setting of CLOCAL that may have been done * for the close(open()) above (except in Xenix). Also throw in ~ECHO, to * prevent the other end of the line from sitting there talking to itself, * producing garbage when the user performs a connect. * * SCO Xenix unfortunately seems to ignore the actual state of CLOCAL. * Now it thinks CLOCAL is always on. It seems the only real solution for * Xenix is to switch between the lower and upper case device names. * * This section may at some future time expand into setting a complete * collection of tty parameters, or call a function shared with ttpkt()/ * ttvt() that does so. On the other hand, the initial parameters are not * that important, since ttpkt() or ttvt() should always fix that before * any communication is done. Well, we'll see... */ if (xlocal) { curcarr = -2; debug(F100,"ttopen calling carrctl","",0); carrctl(&ttraw, ttcarr == CAR_ON); debug(F100,"ttopen carrctl ok","",0); #ifdef COHERENT #define SVORPOSIX #endif /* COHERENT */ #ifdef SVORPOSIX ttraw.c_lflag &= ~ECHO; ttold.c_lflag &= ~ECHO; #ifdef BSD44ORPOSIX y = tcsetattr(ttyfd, TCSADRAIN, &ttraw); debug(F101,"ttopen tcsetattr","",y); #else y = ioctl(ttyfd, TCSETA, &ttraw); debug(F100,"ttopen ioctl","",y); #endif /* BSD44ORPOSIX */ #else /* BSD, etc */ ttraw.sg_flags &= ~ECHO; ttold.sg_flags &= ~ECHO; #ifdef BELLV10 y = ioctl(ttyfd,TIOCSETP,&ttraw); debug(F100,"ttopen ioctl","",y); #else y = stty(ttyfd,&ttraw); debug(F100,"ttopen stty","",y); #endif /* BELLV10 */ #endif /* SVORPOSIX */ #ifdef COHERENT #undef SVORPOSIX #endif /* COHERENT */ /* ttflui(); */ /* This fails for some reason. */ } /* Get current speed */ #ifndef BEBOX ttspeed = ttgspd(); #else ttspeed = 19200; #endif /* !BEBOX */ debug(F101,"ttopen ttspeed","",ttspeed); /* Done, make entries in debug log, restore Ctrl-C trap, and return. */ debug(F101,"ttopen ttyfd","",ttyfd); debug(F101,"ttopen *lcl","",*lcl); debug(F111,"ttopen lock file",flfnam,lkf); signal(SIGINT,occt); sigint_ign = (occt == SIG_IGN) ? 1 : 0; gotsigs = 0; return(0); } /* D O _ O P E N -- Do the right kind of open() call for the tty. */ int #ifdef CK_ANSIC do_open( char *ttname ) #else do_open(ttname) char *ttname; #endif /* CK_ANSIC */ { int flags; #ifdef QNX6 /* O_NONBLOCK on /dev/tty makes open() fail */ return(priv_opn(ttname, O_RDWR | ( ((int)strcmp(ttname,"/dev/tty") == 0) ? 0 : (ttcarr != CAR_ON) ? O_NONBLOCK : 0) ) ); #else /* !QNX6 */ #ifndef O_NDELAY /* O_NDELAY not defined */ return(priv_opn(ttname,2)); #else /* O_NDELAY defined */ #ifdef ATT7300 /* Open comms line without waiting for carrier so initial call does not hang because state of "modem" is likely unknown at the initial call -jrd. If this is needed for the getty stuff to work, and the open would not work without O_NDELAY when getty is still on, then this special case is ok. Otherwise, get rid of it. -ske */ return(priv_opn(ttname, O_RDWR | O_NDELAY)); #else /* !ATT7300 */ /* Normal case. Use O_NDELAY according to SET CARRIER. See ttscarr(). */ flags = O_RDWR; debug(F101,"do_open xlocal","",xlocal); debug(F111,"do_open flags A",ttname,flags); if (xlocal && (ttcarr != CAR_ON)) flags |= O_NDELAY; debug(F111,"do_open flags B",ttname,flags); return(priv_opn(ttname, flags)); #endif /* !ATT7300 */ #endif /* O_NDELAY */ #endif /* QNX6 */ } /* T T C L O S -- Close the TTY, releasing any lock. */ static int ttc_state = 0; /* ttclose() state */ static char * ttc_nam[] = { "setup", "hangup", "reset", "close" }; int #ifdef CK_ANSIC ttclos( int foo ) /* Arg req'd for signal() prototype */ #else ttclos(foo) int foo; #endif /* CK_ANSIC */ { int xx, x = 0; extern int exithangup; debug(F101,"ttclos ttyfd","",ttyfd); debug(F101,"ttclos netconn","",netconn); debug(F101,"ttclos xlocal","",xlocal); #ifdef NOFDZERO debug(F100,"ttclos NOFDZERO","",0); #endif /* NOFDZERO */ #ifdef COMMENT #ifdef TTLEBUF le_init(); /* No need for any of this */ #endif /* TTLEBUF */ #endif /* COMMENT */ if (ttyfd < 0) /* Wasn't open. */ return(0); #ifdef IKSD /* (Jeff Johnson 16 May 2023) */ if (!inserver) { /* Only if not an IKSD server */ #endif /* IKSD */ if (ttfdflg) /* If we inherited ttyfd from */ return(0); /* another process, don't close it. */ #ifdef IKSD } #endif /* IKSD */ tvtflg = 0; /* (some day get rid of this...) */ gotsigs = 0; #ifdef IKSD if (inserver) { #ifdef TNCODE tn_push(); /* Place any waiting data into input*/ tn_sopt(DO,TELOPT_LOGOUT); /* Send LOGOUT option before close */ TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1; tn_reset(); /* The Reset Telnet Option table. */ #endif /* TNCODE */ #ifdef CK_SSL if (ssl_active_flag) { if (ssl_debug_flag) BIO_printf(bio_err,"calling SSL_shutdown(ssl)\n"); SSL_shutdown(ssl_con); SSL_free(ssl_con); ssl_con = NULL; ssl_active_flag = 0; } if (tls_active_flag) { if (ssl_debug_flag) BIO_printf(bio_err,"calling SSL_shutdown(tls)\n"); SSL_shutdown(tls_con); SSL_free(tls_con); tls_con = NULL; tls_active_flag = 0; } #endif /* CK_SSL */ } #endif /* IKSD */ #ifdef NETCMD debug(F101,"XXX NETCMD ttpipe","",ttpipe); if (ttpipe) { /* We've been using a pipe */ /* ttpipe = 0; */ if (ttpid > 0) { int wstat; int statusp; close(fdin); /* Close these. */ close(fdout); fdin = fdout = -1; kill(ttpid,1); /* Kill fork with SIGHUP */ while (1) { wstat = wait(&statusp); if (wstat == ttpid || wstat == -1) break; pexitstat = (statusp & 0xff) ? statusp : statusp >> 8; } ttpid = 0; } netconn = 0; wasclosed = 1; ttyfd = -1; return(0); } #endif /* NETCMD */ #ifdef NETPTY debug(F101,"XXX NETPTY ttpty","",ttpty); if (ttpty) { #ifndef NODOPTY end_pty(); #endif /* NODOPTY */ close(ttyfd); netconn = 0; wasclosed = 1; ttpty = 0; ttyfd = -1; return(0); } #endif /* NETPTY */ debug(F110,"XXX netclos in ifdef NETCONN...","A",0); #ifdef NETCONN debug(F110,"XXX netclos in ifdef NETCONN...OK","A",0); if (netconn) { /* If it's a network connection. */ debug(F100,"ttclos closing net","",0); netclos(); /* Let the network module close it. */ netconn = 0; /* No more network connection. */ debug(F101,"ttclos ttyfd after netclos","",ttyfd); /* Should be -1 */ return(0); } #endif /* NETCONN */ if (xlocal) { /* We're closing a SET LINE device */ #ifdef FT21 /* Fortune 2.1-specific items ... */ ioctl(ttyfd,TIOCHPCL, NULL); #endif /* FT21 */ #ifdef ultrix /* Ultrix-specific items ... */ #ifdef TIOCSINUSE /* Unset the INUSE flag that we set in ttopen() */ ioctl(ttyfd, TIOCSINUSE, NULL); #endif /* TIOCSINUSE */ ioctl(ttyfd, TIOCNMODEM, &x); #ifdef COMMENT /* What was this? */ ioctl(ttyfd, TIOCNCAR, NULL); #endif /* COMMENT */ #endif /* ultrix */ } /* This is to prevent us from sticking in tthang() or close(). */ #ifdef O_NDELAY #ifndef aegis if (ttyfd > 0) { /* But skip it on stdin. */ debug(F100,"ttclos setting O_NDELAY","",0); x = fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL, 0)|O_NDELAY); #ifdef DEBUG if (deblog && x == -1) { perror("Warning - Can't set O_NDELAY"); debug(F101,"ttclos fcntl failure to set O_NDELAY","",x); } #endif /* DEBUG */ } #endif /* aegis */ #endif /* O_NDELAY */ x = 0; ttc_state = 0; if (xlocal #ifdef NOFDZERO || ttyfd > 0 #endif /* NOFDZERO */ ) { saval = signal(SIGALRM,xtimerh); /* Enable timer interrupt. */ xx = alarm(8); /* Allow 8 seconds. */ debug(F101,"ttclos alarm","",xx); if ( #ifdef CK_POSIX_SIG sigsetjmp(sjbuf,1) #else setjmp(sjbuf) #endif /* CK_POSIX_SIG */ ) { /* Timer went off? */ x = -1; #ifdef DEBUG debug(F111,"ttclos ALARM TRAP errno",ckitoa(ttc_state),errno); printf("ttclos() timeout: %s\n", ttc_nam[ttc_state]); #endif /* DEBUG */ } /* Hang up the device (drop DTR) */ errno = 0; debug(F111,"ttclos A",ckitoa(x),ttc_state); if (ttc_state < 1) { ttc_state = 1; debug(F101,"ttclos exithangup","",exithangup); if (exithangup) { alarm(8); /* Re-arm the timer */ debug(F101,"ttclos calling tthang()","",x); x = tthang(); /* Hang up first, then... */ debug(F101,"ttclos tthang()","",x); } #ifndef CK_NOHUPCL /* Oct 2006 - Leave DTR on if SET EXIT HANGUP OFF. Suggested by Soewono Effendi. */ #ifdef HUPCL else { ttold.c_cflag &= ~HUPCL; /* Let's see how this travels */ #ifdef BSD44ORPOSIX tcsetattr(ttyfd,TCSANOW,&ttold); #else /* !BSD44ORPOSIX */ #ifdef ATTSV ioctl(ttyfd,TCSETAW,&ttold); #else /* !ATTSV */ stty(ttyfd,&ttold); #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ } #endif /* HUPCL */ #endif /* CK_NOHUPCL */ } /* Put back device modes as we found them */ errno = 0; debug(F111,"ttclos B",ckitoa(x),ttc_state); if (ttc_state < 2) { ttc_state = 2; /* Don't try to mess with tty modes if tthang failed() */ /* since it probably won't work. */ if (x > -1) { debug(F101,"ttclos calling ttres()","",x); signal(SIGALRM,xtimerh); /* Re-enable the alarm. */ alarm(8); /* Re-arm the timer */ x = ttres(); /* Reset device modes. */ debug(F101,"ttclos ttres()","",x); alarm(0); } } /* Close the device */ errno = 0; debug(F101,"ttclos C","",ttc_state); if (ttc_state < 3) { ttc_state = 3; errno = 0; debug(F101,"ttclos calling close","",x); signal(SIGALRM,xtimerh); /* Re-enable alarm. */ alarm(8); /* Re-arm the timer */ x = close(ttyfd); /* Close the device. */ debug(F101,"ttclos close()","",x); if (x > -1) ttc_state = 3; } debug(F101,"ttclos D","",ttc_state); ttimoff(); /* Turn off timer. */ if (x < 0) { printf("?WARNING - close failed: %s\n",ttnmsv); #ifdef DEBUG if (deblog) { printf("errno = %d\n", errno); debug(F101,"ttclos failed","",errno); } #endif /* DEBUG */ } /* Unlock after closing but before any getty mumbo jumbo */ debug(F100,"ttclos about to call ttunlck","",0); if (ttunlck()) /* Release uucp-style lock */ fprintf(stderr,"Warning, problem releasing lock\r\n"); } /* For bidirectional lines, restore getty if it was there before. */ #ifdef ACUCNTRL /* 4.3BSD acucntrl() method. */ if (xlocal) { debug(F100,"ttclos ACUCNTRL","",0); acucntrl("enable",ttnmsv); /* Enable getty on the device. */ } #else #ifdef ATT7300 /* ATT UNIX PC (3B1, 7300) method. */ if (xlocal) { debug(F100,"ttclos ATT7300 ongetty","",0); if (attmodem & DOGETY) /* Was getty(1m) running before us? */ ongetty(ttnmsv); /* Yes, restart getty on tty line */ attmodem &= ~DOGETY; /* No phone in use, getty restored */ } #endif /* ATT7300 */ #endif /* System-dependent getty-restoring methods */ #ifdef sony_news km_ext = -1; /* Invalidate device's Kanji-mode */ #endif /* sony_news */ ttyfd = -1; /* Invalidate the file descriptor. */ wasclosed = 1; debug(F100,"ttclos done","",0); return(0); } /* T T H A N G -- Hangup phone line or network connection. */ /* Returns: 0 if it does nothing. 1 if it believes that it hung up successfully. -1 if it believes that the hangup attempt failed. */ #define HUPTIME 500 /* Milliseconds for hangup */ #ifdef COMMENT /* The following didn't work but TIOCSDTR does work */ #ifdef UNIXWARE /* Define HUP_POSIX to force non-POSIX builds to use the POSIX hangup method */ #ifndef POSIX /* Such as Unixware 1.x, 2.x */ #ifndef HUP_POSIX #define HUP_POSIX #endif /* HUP_POSIX */ #endif /* POSIX */ #endif /* UNIXWARE */ #endif /* COMMENT */ #ifndef USE_TIOCSDTR #ifdef __NetBSD__ /* Because the POSIX method (set output speed to 0) doesn't work in NetBSD */ #ifdef TIOCSDTR #ifdef TIOCCDTR #define USE_TIOCSDTR #endif /* TIOCCDTR */ #endif /* TIOCSDTR */ #endif /* __NetBSD__ */ #endif /* USE_TIOCSDTR */ #ifndef HUP_CLOSE_POSIX #ifdef OU8 #define HUP_CLOSE_POSIX #else #ifdef CK_SCOV5 #define HUP_CLOSE_POSIX #endif /* CK_SCOV5 */ #endif /* OU8 */ #endif /* HUP_CLOSE_POSIX */ #ifdef NO_HUP_CLOSE_POSIX #ifdef HUP_CLOSE_POSIX #undef HUP_CLOSE_POSIX #endif /* HUP_CLOSE_POSIX */ #endif /* NO_HUP_CLOSE_POSIX */ int tthang() { #ifdef NOLOCAL return(0); #else int x = 0; /* Sometimes used as return code. */ #ifndef POSIX int z; /* worker */ #endif /* POSIX */ #ifdef COHERENT #define SVORPOSIX #endif /* COHERENT */ #ifdef SVORPOSIX /* AT&T, POSIX, HPUX declarations. */ int spdsav; /* for saving speed */ #ifdef HUP_POSIX int spdsavi; #else #ifdef BSD44ORPOSIX int spdsavi; #endif /* BSD44ORPOSIX */ #endif /* HUP_POSIX */ #ifdef HPUX /* Early versions of HP-UX omitted the mflag typedef. If you get complaints about it, just change it to long (or better still, unsigned long). */ mflag dtr_down = 00000000000, modem_rtn, modem_sav; char modem_state[64]; #endif /* HPUX */ int flags; /* fcntl flags */ unsigned short ttc_save; #endif /* SVORPOSIX */ if (ttyfd < 0) return(0); /* Don't do this if not open */ if (xlocal < 1) return(0); /* Don't do this if not local */ #ifdef NETCMD if (ttpipe) return((ttclos(0) < 0) ? -1 : 1); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return((ttclos(0) < 0) ? -1 : 1); #endif /* NETPTY */ #ifdef NETCONN if (netconn) { /* Network connection. */ #ifdef TN_COMPORT if (istncomport()) { int rc = tnc_set_dtr_state(0); if (rc >= 0) { msleep(HUPTIME); rc = tnc_set_dtr_state(1); } return(rc >= 0 ? 1 : -1); } else #endif /* TN_COMPORT */ return((netclos() < 0) ? -1 : 1); /* Just close it. */ } #endif /* NETCONN */ /* From here down, we handle real tty devices. */ #ifdef HUP_POSIX /* e.g. for Unixware 2, where we don't have a full POSIX build, we still have to use POSIX-style hangup. Thus the duplication of this and the next case, the only difference being we use a local termios struct here, since a different model is used elsewhere. NO LONGER USED as of C-Kermit 8.0 -- it turns out that this method, even though it compiles and executes without error, doesn't actually work (i.e. DTR does not drop), whereas the TIOCSDTR method works just fine, */ { struct termios ttcur; int x; debug(F100,"tthang HUP_POSIX style","",0); x = tcgetattr(ttyfd, &ttcur); /* Get current attributes */ debug(F111,"tthang tcgetattr",ckitoa(errno),x); if (x < 0) return(-1); spdsav = cfgetospeed(&ttcur); /* Get current speed */ debug(F111,"tthang cfgetospeed",ckitoa(errno),spdsav); spdsavi = cfgetispeed(&ttcur); /* Get current speed */ debug(F111,"tthang cfgetispeed",ckitoa(errno),spdsavi); x = cfsetospeed(&ttcur,B0); /* Replace by 0 */ debug(F111,"tthang cfsetospeed",ckitoa(errno),x); if (x < 0) return(-1); x = cfsetispeed(&ttcur,B0); debug(F111,"tthang cfsetispeed",ckitoa(errno),x); if (x < 0) return(-1); x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); debug(F111,"tthang tcsetattr B0",ckitoa(errno),x); if (x < 0) return(-1); msleep(HUPTIME); /* Sleep 0.5 sec */ x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */ if (x < 0) return(-1); debug(F111,"tthang cfsetospeed prev",ckitoa(errno),x); x = cfsetispeed(&ttcur,spdsavi); debug(F111,"tthang cfsetispeed prev",ckitoa(errno),x); if (x < 0) return(-1); x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); debug(F111,"tthang tcsetattr restore",ckitoa(errno),x); if (x < 0) return(-1); return(1); } #else #ifdef BSD44ORPOSIX #ifdef QNX { int x; x = tcdropline(ttyfd,500); debug(F101,"tthang QNX tcdropline","",x); ttcur.c_cflag |= CLOCAL; x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); debug(F101,"tthang QNX tcsetattr restore","",x); if (x < 0) { debug(F101,"tthang QNX tcsetattr restore errno","",errno); return(-1); } /* Fix flags - ensure O_NONBLOCK is off */ errno = 0; debug(F101,"tthang QNX iniflags","",iniflags); if (fcntl(ttyfd, F_SETFL, iniflags) == -1) { debug(F101,"tthang QNX F_SETFL errno","",errno); return(-1); } return(x); } #else /* QNX */ { int x; #ifdef USE_TIOCSDTR debug(F100,"tthang BSD44ORPOSIX USE_TIOCSDTR","",0); errno = 0; x = ioctl(ttyfd, TIOCCDTR, NULL); debug(F111,"tthang BSD44ORPOSIX ioctl TIOCCDTR",ckitoa(errno),x); if (x < 0) return(-1); msleep(HUPTIME); /* Sleep 0.5 sec */ errno = 0; x = ioctl(ttyfd, TIOCSDTR, NULL); debug(F111,"tthang BSD44ORPOSIX ioctl TIOCSDTR",ckitoa(errno),x); if (x < 0) return(-1); #else /* USE_TIOCSDTR */ #ifdef HUP_CLOSE_POSIX /* In OSR5 versions where TIOCSDTR is not defined (up to and including at least 5.0.6a) the POSIX APIs in the "#else" part below are available but don't work, and no other APIs are available that do work. In this case we have to drop DTR by brute force: close and reopen the port. This code actually works, but all the steps are crucial: setting CLOCAL, the O_NDELAY manipulations, etc. */ debug(F100,"tthang HUP_CLOSE_POSIX close/open","",0); debug(F101,"tthang HUP_CLOSE_POSIX O_NONBLOCK","",O_NONBLOCK); debug(F101,"tthang HUP_CLOSE_POSIX O_NDELAY","",O_NDELAY); errno = 0; x = tcgetattr(ttyfd, &ttcur); /* Get current attributes */ debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr","",x); if (x < 0) { debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr errno","",errno); return(-1); } errno = 0; x = close(ttyfd); /* Close without releasing lock */ if (x < 0) { debug(F101,"tthang HUP_CLOSE_POSIX close errno","",errno); return(-1); } errno = 0; x = msleep(500); /* Pause half a second */ if (x < 0) { /* Or if that doesn't work, 1 sec */ debug(F101,"tthang HUP_CLOSE_POSIX msleep errno","",errno); sleep(1); } errno = 0; ttyfd = priv_opn(ttnmsv, (O_RDWR|O_NDELAY)); /* Reopen the device */ debug(F111,"tthang HUP_CLOSE_POSIX reopen",ttnmsv,ttyfd); if (ttyfd < 0) { debug(F101,"tthang HUP_CLOSE_POSIX reopen errno","",errno); return(-1); } debug(F101,"tthang HUP_CLOSE_POSIX re-ttopen ttyfd","",ttyfd); /* Restore previous attributes */ errno = 0; tvtflg = 0; ttcur.c_cflag |= CLOCAL; x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore","",x); if (x < 0) { debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore errno", "",errno); return(-1); } /* Fix flags - ensure O_NDELAY and O_NONBLOCK are off */ errno = 0; if ((x = fcntl(ttyfd, F_GETFL, 0)) == -1) { debug(F101,"tthang HUP_CLOSE_POSIX F_GETFL errno","",errno); return(-1); } debug(F101,"tthang HUP_CLOSE_POSIX flags","",x); errno = 0; x &= ~(O_NONBLOCK|O_NDELAY); debug(F101,"tthang HUP_CLOSE_POSIX flags to set","",x); debug(F101,"tthang HUP_CLOSE_POSIX iniflags","",iniflags); if (fcntl(ttyfd, F_SETFL, x) == -1) { debug(F101,"tthang HUP_CLOSE_POSIX F_SETFL errno","",errno); return(-1); } #ifdef DEBUG if (deblog) { if ((x = fcntl(ttyfd, F_GETFL, 0)) > -1) { debug(F101,"tthang HUP_CLOSE_POSIX flags","",x); debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NONBLOCK", "",x&O_NONBLOCK); debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NDELAY", "",x&O_NDELAY); } } #endif /* DEBUG */ #else /* HUP_CLOSE_POSIX */ /* General BSD44ORPOSIX case (Linux, BSDI, FreeBSD, etc) */ debug(F100,"tthang BSD44ORPOSIX B0","",0); x = tcgetattr(ttyfd, &ttcur); /* Get current attributes */ debug(F111,"tthang BSD44ORPOSIX tcgetattr",ckitoa(errno),x); if (x < 0) return(-1); spdsav = cfgetospeed(&ttcur); /* Get current speed */ debug(F111,"tthang BSD44ORPOSIX cfgetospeed",ckitoa(errno),spdsav); spdsavi = cfgetispeed(&ttcur); /* Get current speed */ debug(F111,"tthang BSD44ORPOSIX cfgetispeed",ckitoa(errno),spdsavi); x = cfsetospeed(&ttcur,B0); /* Replace by 0 */ debug(F111,"tthang BSD44ORPOSIX cfsetospeed",ckitoa(errno),x); if (x < 0) return(-1); x = cfsetispeed(&ttcur,B0); debug(F111,"tthang BSD44ORPOSIX cfsetispeed",ckitoa(errno),x); if (x < 0) return(-1); /* This gets EINVAL on NetBSD 1.4.1 because of B0... */ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); debug(F111,"tthang BSD44ORPOSIX tcsetattr B0",ckitoa(errno),x); if (x < 0) return(-1); msleep(HUPTIME); /* Sleep 0.5 sec */ debug(F101,"tthang BSD44ORPOSIX restore output speed","",spdsav); x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */ debug(F111,"tthang BSD44ORPOSIX cfsetospeed prev",ckitoa(errno),x); if (x < 0) return(-1); debug(F101,"tthang BSD44ORPOSIX restore input speed","",spdsavi); x = cfsetispeed(&ttcur,spdsavi); debug(F111,"tthang BSD44ORPOSIX cfsetispeed prev",ckitoa(errno),x); if (x < 0) return(-1); ttcur.c_cflag |= CLOCAL; /* Don't expect CD after hangup */ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); debug(F111,"tthang BSD44ORPOSIX tcsetattr restore",ckitoa(errno),x); if (x < 0) return(-1); #endif /* HUP_CLOSE_POSIX */ #endif /* USE_TIOCSDTR */ return(1); } #endif /* QNX */ #else /* BSD44ORPOSIX */ #ifdef aegis /* Apollo Aegis */ sio_$control((short)ttyfd, sio_$dtr, false, st); /* DTR down */ msleep(HUPTIME); /* pause */ sio_$control((short)ttyfd, sio_$dtr, true, st); /* DTR up */ return(1); #endif /* aegis */ #ifdef ANYBSD /* Any BSD version. */ #ifdef TIOCCDTR /* Except those that don't have this */ debug(F100,"tthang BSD style","",0); if (ioctl(ttyfd,TIOCCDTR,0) < 0) { /* Clear DTR. */ debug(F101,"tthang TIOCCDTR fails","",errno); return(-1); } msleep(HUPTIME); /* For about 1/2 sec */ errno = 0; x = ioctl(ttyfd,TIOCSDTR,0); /* Restore DTR */ if (x < 0) { /* For some reason, this tends to fail with "no such device or address" but the operation still works, probably because of the close/open later on. So let's not scare the user unnecessarily here. */ debug(F101,"tthang TIOCSDTR errno","",errno); /* Log the error */ x = 1; /* Pretend we succeeded */ } else if (x == 0) x = 1; /* Success */ #ifdef COMMENT #ifdef FT21 ioctl(ttyfd, TIOCSAVEMODES, 0); ioctl(ttyfd, TIOCHPCL, 0); close(ttyfd); /* Yes, must do this twice */ if ((ttyfd = open(ttnmsv,2)) < 0) /* on Fortune computers... */ return(-1); /* (but why?) */ else x = 1; #endif /* FT21 */ #endif /* COMMENT */ #endif /* TIOCCDTR */ close(do_open(ttnmsv)); /* Clear i/o error condition */ errno = 0; #ifdef COMMENT /* This is definitely dangerous. Why was it here? */ z = ttvt(ttspeed,ttflow); /* Restore modes. */ debug(F101,"tthang ttvt returns","",z); return(z < 0 ? -1 : 1); #else return(x); #endif /* COMMENT */ #endif /* ANYBSD */ #ifdef ATTSV /* AT&T UNIX section, includes HP-UX and generic AT&T System III/V... */ #ifdef HPUX /* Hewlett Packard allows explicit manipulation of modem signals. */ #ifdef COMMENT /* Old way... */ debug(F100,"tthang HP-UX style","",0); if (ioctl(ttyfd,MCSETAF,&dtr_down) < 0) /* lower DTR */ return(-1); /* oops, can't. */ msleep(HUPTIME); /* Pause half a second. */ x = 1; /* Set return code */ if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */ if ((modem_rtn & MDCD) != 0) /* Check if CD is low. */ x = -1; /* CD didn't drop, fail. */ } else x = -1; /* Even if above calls fail, RTS & DTR should be turned back on. */ modem_rtn = MRTS | MDTR; if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) x = -1; return(x); #else /* New way, from Hellmuth Michaelis */ debug(F100,"tthang HP-UX style, HPUXDEBUG","",0); if (ioctl(ttyfd,MCGETA,&modem_rtn) == -1) { /* Get current status. */ debug(F100,"tthang HP-UX: can't get modem lines, NO HANGUP!","",0); return(-1); } sprintf(modem_state,"%#lx",modem_rtn); debug(F110,"tthang HP-UX: modem lines = ",modem_state,0); modem_sav = modem_rtn; /* Save current modem signals */ modem_rtn &= ~MDTR; /* Turn DTR bit off */ sprintf(modem_state,"%#lx",modem_rtn); debug(F110,"tthang HP-UX: DTR down = ",modem_state,0); if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) { /* lower DTR */ debug(F100,"tthang HP-UX: can't lower DTR!","",0); return(-1); /* oops, can't. */ } msleep(HUPTIME); /* Pause half a second. */ x = 1; /* Set return code */ if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */ sprintf(modem_state,"%#lx",modem_rtn); debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0); if ((modem_rtn & MDCD) != 0) { /* Check if CD is low. */ debug(F100,"tthang HP-UX: DCD not down","",0); x = -1; /* CD didn't drop, fail. */ } else { debug(F100,"tthang HP-UX: DCD down","",0); } } else { x = -1; debug(F100,"tthang HP-UX: can't get DCD status !","",0); } /* Even if above calls fail, DTR should be turned back on. */ modem_sav |= MDTR; if (ioctl(ttyfd,MCSETAF,&modem_sav) < 0) { x = -1; debug(F100,"tthang HP-UX: can't set saved state","",0); } else { sprintf(modem_state,"%#lx",modem_sav); debug(F110,"tthang HP-UX: final modem lines = ",modem_state,0); } return(x); #endif /* COMMENT */ #else /* AT&T but not HP-UX */ /* SVID for AT&T System V R3 defines ioctl's for handling modem signals. */ /* It is not known how many, if any, systems actually implement them, */ /* so we include them here in ifdef's. */ /* Unixware has the TIOCMxxx symbols defined, but calling ioctl() with them gives error 22 (invalid argument). */ #ifndef _IBMR2 /* No modem-signal twiddling for IBM RT PC or RS/6000. In AIX 3.1 and earlier, the ioctl() call is broken. This code could be activated for AIX 3.1 with PTF 2006 or later (e.g. AIX 3.2), but close/open does the job too, so why bother. */ #ifdef TIOCMBIS /* Bit Set */ #ifdef TIOCMBIC /* Bit Clear */ #ifdef TIOCM_DTR /* DTR */ /* Clear DTR, sleep 300 msec, turn it back on. */ /* If any of the ioctl's return failure, go on to the next section. */ z = TIOCM_DTR; /* Code for DTR. */ #ifdef COMMENT /* This was the cause of the troubles with the Solaris Port Monitor. The problem is: RTS never comes back on. Moral: Don't do it! (But why doesn't it come back on? See the TIOCMBIS call...) */ #ifdef TIOCM_RTS /* Lower RTS too if symbol is known. */ z |= TIOCM_RTS; #endif /* TIOCM_RTS */ #endif /* COMMENT */ debug(F101,"tthang TIOCM signal mask","",z); if (ioctl(ttyfd,TIOCMBIC,&z) > -1) { /* Try to lower DTR. */ debug(F100,"tthang TIOCMBIC ok","",0); msleep(HUPTIME); /* Pause half a second. */ if (ioctl(ttyfd,TIOCMBIS,&z) > -1) { /* Try to turn it back on. */ debug(F100,"tthang TIOCMBIS ok","",0); #ifndef CLSOPN return(1); /* Success, done. */ #endif /* CLSOPN */ } else { /* Couldn't raise, continue. */ debug(F101,"tthang TIOCMBIS errno","",errno); } } else { /* Couldn't lower, continue. */ debug(F101,"tthang TIOCMBIC errno","",errno); } #endif /* TIOCM_DTR */ #endif /* TIOCMBIC */ #endif /* TIOCMBIS */ #endif /* _IBMR2 */ /* General AT&T UNIX case, not HPUX. The following code is highly suspect. No two AT&T-based systems seem to do this the same way. The object is simply to turn off DTR and then turn it back on. SVID says the universal method for turning off DTR is to set the speed to zero, and this does seem to do the trick in all cases. But neither SVID nor any known man pages say how to turn DTR back on again. Some variants, like most Xenix implementations, raise DTR again when the speed is restored to a nonzero value. Others require the device to be closed and opened again, but this is risky because getty could seize the device during the instant it is closed. */ /* Return code for ioctl failures... */ #ifdef ATT6300 x = 1; /* ATT6300 doesn't want to fail... */ #else x = -1; #endif /* ATT6300 */ debug(F100,"tthang get settings","",0); if (ioctl(ttyfd,TCGETA,&ttcur) < 0) /* Get current settings. */ return(x); /* Fail if this doesn't work. */ if ((flags = fcntl(ttyfd,F_GETFL,0)) < 0) /* Get device flags. */ return(x); ttc_save = ttcur.c_cflag; /* Remember current speed. */ spdsav = ttc_save & CBAUD; debug(F101,"tthang speed","",spdsav); #ifdef O_NDELAY debug(F100,"tthang turning O_NDELAY on","",0); fcntl(ttyfd, F_SETFL, flags | O_NDELAY); /* Activate O_NDELAY */ #endif /* O_NDELAY */ #ifdef ATT7300 /* This is the way it is SUPPOSED to work */ ttcur.c_cflag &= ~CBAUD; /* Change the speed to zero. */ #else #ifdef RTAIX ttcur.c_cflag &= ~CBAUD; /* Change the speed to zero. */ #else /* This way really works but may be dangerous */ #ifdef u3b2 ttcur.c_cflag = ~(CBAUD|CLOCAL); /* Special for AT&T 3B2s */ /* (CLOCAL must be OFF) */ #else #ifdef SCO3R2 /* SCO UNIX 3.2 */ /* This is complete nonsense, but an SCO user claimed this change made hanging up work. Comments from other SCO UNIX 3.2 users would be appreciated. */ ttcur.c_cflag = CBAUD|B0; #else #ifdef AIXRS /* AIX on RS/6000 */ /* Can't set speed to zero on AIX 3.1 on RS/6000 64-port adapter, even though you can do it on the built-in port and the 8- and 16-port adapters. (Untested on 128-port adapter.) */ ttcur.c_cflag = CLOCAL|HUPCL|spdsav; /* Speed 0 causes EINVAL */ #else /* None of the above */ /* Set everything, including the speed, to zero, except for the CLOCAL and HUPCL bits. */ ttcur.c_cflag = CLOCAL|HUPCL; #endif /* AIXRS */ #endif /* SCO3R2 */ #endif /* u3b2 */ #endif /* RTAIX */ #endif /* ATT7300 */ #ifdef COMMENT /* and if none of those work, try one of these... */ ttcur.c_cflag = 0; ttcur.c_cflag = CLOCAL; ttcur.c_cflag &= ~(CBAUD|HUPCL); ttcur.c_cflag &= ~(CBAUD|CREAD); ttcur.c_cflag &= ~(CBAUD|CREAD|HUPCL); /* or other combinations */ #endif /* COMMENT */ #ifdef TCXONC debug(F100,"tthang TCXONC","",0); if (ioctl(ttyfd, TCXONC, 1) < 0) { debug(F101,"tthang TCXONC failed","",errno); } #endif /* TCXONC */ #ifdef TIOCSTART debug(F100,"tthang TIOCSTART","",0); if (ioctl(ttyfd, TIOCSTART, 0) < 0) { debug(F101,"tthang TIOCSTART failed","",errno); } #endif /* TIOCSTART */ if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) { /* Fail if we can't. */ debug(F101,"tthang TCSETAF failed","",errno); fcntl(ttyfd, F_SETFL, flags); /* Restore flags */ return(-1); /* before returning. */ } msleep(300); /* Give modem time to notice. */ #ifndef NOCOTFMC /* Now, even though it doesn't say this in SVID or any man page, we have */ /* to close and reopen the device. This is not necessary for all systems, */ /* but it's impossible to predict which ones need it and which ones don't. */ #ifdef ATT7300 /* Special handling for ATT 7300 UNIX PC and 3B1, which have "phone" related ioctl's for their internal modems. attmodem has getty status and modem-in-use bit. Reportedly the ATT7300/3B1 PIOCDISC call is necessary, but also ruins the file descriptor, and no other phone(7) ioctl call can fix it. Whatever it does, it seems to escape detection with PIOCGETA and TCGETA. The only way to undo the damage is to close the fd and then reopen it. */ if (attmodem & ISMODEM) { debug(F100,"tthang attmodem close/open","",0); ioctl(ttyfd,PIOCUNHOLD,&dialer); /* Return call to handset. */ ioctl(ttyfd,PIOCDISC,&dialer); /* Disconnect phone. */ close(ttyfd); /* Close and reopen the fd. */ ttyfd = priv_opn(ttnmsv, O_RDWR | O_NDELAY); attmodem &= ~ISMODEM; /* Phone no longer in use. */ } #else /* !ATT7300 */ /* It seems we have to close and open the device for other AT&T systems */ /* too, and this is the place to do it. The following code does the */ /* famous close(open(...)) magic by default. If that doesn't work for you, */ /* then try uncommenting the following statement or putting -DCLSOPN in */ /* the makefile CFLAGS. */ /* #define CLSOPN */ #ifndef SCO32 /* Not needed by, and harmful to, SCO UNIX 3.2 / Xenix 2.3 */ #ifdef O_NDELAY #define OPENFLGS O_RDWR | O_NDELAY #else #define OPENFLGS O_RDWR #endif #ifndef CLSOPN /* This method is used by default, i.e. unless CLSOPN is defined. */ /* It is thought to be safer because there is no window where getty */ /* can seize control of the device. The drawback is that it might not work. */ debug(F101,"tthang close(open()), OPENFLGS","",OPENFLGS); close(priv_opn(ttnmsv, OPENFLGS)); #else /* This method is used if you #define CLSOPN. It is more likely to work */ /* than the previous method, but it's also more dangerous. */ debug(F101,"tthang close/open, OPENFLGS","",OPENFLGS); close(ttyfd); msleep(10); ttyfd = priv_opn(ttnmsv, OPENFLGS); /* Open it again */ #endif /* CLSOPN */ #undef OPENFLGS #endif /* SCO32 */ #endif /* ATT7300 */ #endif /* NOCOTFMC */ /* Now put all flags & modes back the way we found them. */ /* (Does the order of ioctl & fcntl matter ? ) */ debug(F100,"tthang restore settings","",0); ttcur.c_cflag = ttc_save; /* Get old speed back. */ if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) /* ioctl parameters. */ return(-1); #ifdef O_NDELAY /* This is required for IBM RT and RS/6000, probably helps elsewhere too (?). After closing a modem line, the modem will probably not be asserting carrier any more, so we should not require carrier any more. If this causes trouble on non-IBM UNIXes, change the #ifdef to use _IBMR2 rather than O_NDELAY. */ flags &= ~O_NDELAY; /* Don't require carrier on reopen */ #endif /* O_NDELAY */ if (fcntl(ttyfd,F_SETFL,flags) < 0) /* fcntl parameters */ return(-1); return(1); #endif /* not HPUX */ #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ #endif /* HUP_POSIX */ #endif /* NOLOCAL */ } /* Major change in 5A(174). We used to use LPASS8, if it was defined, to allow 8-bit data and Xon/Xoff flow control at the same time. But this LPASS8 business seems to have been causing trouble for everybody but me! For example, Annex terminal servers, commonly used with Encore computers, do not support LPASS8 even though the Encore itself does. Ditto for many other terminal servers, TELNET connections, rlogin connections, etc etc. Now, reportedly, even vanilla 4.3 BSD systems can't do this right on their serial lines, even though LPASS8 is a feature of 4.3BSD. So let's turn it off for everybody. That means we goes back to using raw mode, with no flow control. Phooey. NOTE: This must be done before the first reference to LPASS8 in this file, and after the last #include statment. */ #ifdef LPASS8 #undef LPASS8 #endif /* LPASS8 */ /* T T R E S -- Restore terminal to "normal" mode. */ /* ske@pkmab.se: There are two choices for what this function should do. * (1) Restore the tty to current "normal" mode, with carrier treatment * according to ttcarr, to be used after every kermit command. (2) Restore * the tty to the state it was in before kermit opened it. These choices * conflict, since ttold can't hold both choices of tty parameters. ttres() * is currently being called as in choice (1), but ttold basically holds * the initial parameters, as in (2), and the description at the beginning * of this file says (2). * * I don't think restoring tty parameters after all kermit commands makes * much of a difference. Restoring them upon exit from kermit may be of * some use in some cases (when the line is not restored automatically on * close, by the operating system). * * I can't choose which one it should be, so I haven't changed it. It * probably works as it is, too. It would probably even work even with * ttres() entirely deleted... * * (from fdc: Actually, this function operates in remote mode too, so * it restores the console (command) terminal to whatever mode it was * in before packet operations began, so that commands work right again.) */ int ttres() { /* Restore the tty to normal. */ int x; if (ttyfd < 0) return(-1); /* Not open. */ if (ttfdflg) return(0); /* Don't mess with terminal modes if */ /* we got ttyfd from another process */ #ifdef NETCONN if (netconn) { /* Network connection */ tvtflg = 0; #ifdef TCPSOCKET #ifdef TCP_NODELAY { extern int tcp_nodelay; /* Just put this back if necessary */ if (ttnet == NET_TCPB) { if (nodelay_sav > -1) { no_delay(ttyfd,nodelay_sav); nodelay_sav = -1; } } } #endif /* TCP_NODELAY */ #ifdef TN_COMPORT if (istncomport()) { int rc = -1; if ((rc = tnsetflow(ttflow)) < 0) return(rc); if (ttspeed <= 0) ttspeed = tnc_get_baud(); else if ((rc = tnc_set_baud(ttspeed)) < 0) return(rc); tnc_set_datasize(8); tnc_set_stopsize(stopbits); #ifdef HWPARITY if (hwparity) { switch (hwparity) { case 'e': /* Even */ debug(F100,"ttres 8 bits + even parity","",0); tnc_set_parity(3); break; case 'o': /* Odd */ debug(F100,"ttres 8 bits + odd parity","",0); tnc_set_parity(2); break; case 'm': /* Mark */ debug(F100,"ttres 8 bits + invalid parity: mark","",0); tnc_set_parity(4); break; case 's': /* Space */ debug(F100,"ttres 8 bits + invalid parity: space","",0); tnc_set_parity(5); break; } } else #endif /* HWPARITY */ { tnc_set_parity(1); /* None */ } tvtflg = 0; return(0); } #endif /* TN_COMPORT */ #endif /* TCPSOCKET */ return(0); } #endif /* NETCONN */ #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ /* Real terminal device, so restore its original modes */ #ifdef BSD44ORPOSIX /* For POSIX like this */ debug(F100,"ttres BSD44ORPOSIX","",0); x = tcsetattr(ttyfd,TCSADRAIN,&ttold); #else /* For all others... */ #ifdef ATTSV /* For AT&T versions... */ debug(F100,"ttres ATTSV","",0); x = ioctl(ttyfd,TCSETAW,&ttold); /* Restore tty modes this way. */ #else /* Here we restore the modes for BSD */ #ifdef LPASS8 /* Undo "pass8" if it were done */ if (lmodef) { if (ioctl(ttyfd,TIOCLSET,&lmode) < 0) debug(F100,"ttres TIOCLSET failed","",0); else debug(F100,"ttres TIOCLSET ok","",0); } #endif /* LPASS8 */ #ifdef CK_DTRCTS /* Undo hardware flow if it were done */ if (lmodef) { if (ioctl(ttyfd,TIOCLSET,&lmode) < 0) debug(F100,"ttres TIOCLSET failed","",0); else debug(F100,"ttres TIOCLSET ok","",0); } #endif /* CK_DTRCTS */ #ifdef TIOCGETC /* Put back special characters */ if (tcharf && (xlocal == 0)) { if (ioctl(ttyfd,TIOCSETC,&tchold) < 0) debug(F100,"ttres TIOCSETC failed","",0); else debug(F100,"ttres TIOCSETC ok","",0); } #endif /* TIOCGETC */ #ifdef TIOCGLTC /* Put back local special characters */ if (ltcharf && (xlocal == 0)) { if (ioctl(ttyfd,TIOCSLTC,<chold) < 0) debug(F100,"ttres TIOCSLTC failed","",0); else debug(F100,"ttres TIOCSLTC ok","",0); } #endif /* TIOCGLTC */ #ifdef BELLV10 debug(F100,"ttres BELLV10","",0); x = ioctl(ttyfd,TIOCSETP,&ttold); /* Restore both structs */ x = ioctl(ttyfd,TIOCSDEV,&tdold); #else debug(F100,"ttres stty","",0); x = stty(ttyfd,&ttold); /* Restore tty modes the old way. */ #endif /* BELLV10 */ if (!xlocal) msleep(100); /* This replaces sleep(1)... */ /* Put back sleep(1) if tty is */ /* messed up after close. */ #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ debug(F101,"ttres result","",x); #ifndef QNX if (x < 0) debug(F101,"ttres errno","",errno); #endif /* QNX */ #ifdef AIXRS #ifndef AIX41 x = ioctl(ttyfd, ttld & 1 ? TXADDCD : TXDELCD, "rts"); debug(F101,"ttres AIX line discipline rts restore","",x); #endif /* AIX41 */ #endif /* AIXRS */ #ifdef BSD41 if (ttld > -1) { /* Put back line discipline */ x = ioctl(ttyfd, TIOCSETD, &ttld); debug(F101,"ttres BSD41 line discipline restore","",x); if (x < 0) debug(F101,"...ioctl errno","",errno); ttld = -1; } #endif /* BSD41 */ #ifdef sony_news x = xlocal ? km_ext : km_con; /* Restore Kanji mode. */ if (x != -1) { /* Make sure we know original modes. */ if (ioctl(ttyfd,TIOCKSET, &x) < 0) { perror("ttres can't set Kanji mode"); debug(F101,"ttres error setting Kanji mode","",x); return(-1); } } debug(F100,"ttres set Kanji mode ok","",0); #endif /* sony_news */ tvtflg = 0; /* Invalidate terminal mode settings */ debug(F101,"ttres return code","",x); return(x); } #ifndef NOUUCP /* T T C H K P I D -- Check lockfile pid */ /* Read pid from lockfile named f, check that it's still valid. If so, return 1. On failure to read pid, return 1. Otherwise, try to delete lockfile f and return 0 if successful, else 1. */ static int #ifdef CK_ANSIC ttchkpid( char *f ) #else ttchkpid(f) char *f; #endif /* CK_ANSIC */ { int pid, mypid, x; pid = ttrpid(f); /* Read pid from file. */ if (pid > -1) { /* If we were able to read the pid.. */ debug(F101,"ttchkpid lock pid","",pid); errno = 0; /* See if process still exists. */ mypid = (int)getpid(); /* Get my own pid. */ debug(F101,"ttchkpid my pid","",mypid); if (pid == mypid) { /* It's me! */ x = -1; /* So I can delete it */ errno = ESRCH; /* pretend it's invalid */ } else { /* It's not me */ x = kill((PID_T)pid, 0); /* See if it's a live process */ debug(F101,"ttchkpid kill errno","",errno); } debug(F101,"ttchkpid pid test","",x); if (x < 0 && errno == ESRCH) { /* pid is invalid */ debug(F111,"removing stale lock",f,pid); if (!backgrd) printf("Removing stale lock %s (pid %d terminated)\n", f, pid); priv_on(); x = unlink(f); /* Remove the lockfile. */ priv_off(); debug(F111,"ttchkpid unlink",f,x); if (x > -1) return(0); /* Device is not locked after all */ else if (!backgrd) perror(f); } return(1); } return(1); /* Failure to read pid */ } #ifdef HPUX /* Aliases (different drivers) for HP-UX dialout devices: */ static char *devprefix[] = { "tty", "ttyd", "cul", "cua", "cuad", "culd", "" }; static int ttydexists = 0; #endif /* HPUX */ /* T T R P I D -- Read pid from lockfile "name" */ static int #ifdef CK_ANSIC ttrpid( char *name ) #else ttrpid(name) char *name; #endif /* CK_ANSIC */ { long len; int x, fd, pid; short spid; char buf[32]; debug(F110,"ttrpid",name,0); if (!name) return(-1); if (!*name) return(-1); priv_on(); len = zchki(name); /* Get file length */ priv_off(); debug(F101,"ttrpid zchki","",len); if (len < 0) return(-1); if (len > 31) return(-1); priv_on(); fd = open(name,O_RDONLY); /* Try to open lockfile. */ priv_off(); debug(F101,"ttrpid fd","",fd); if (fd <= 0) return(-1); /* Here we try to be flexible and allow for all different binary and string formats at runtime, rather than a specific format for each configuration hardwired at compile time. */ pid = -1; #ifndef COHERENT /* COHERENT uses a string PID but without leading spaces or 0's, so there is no way to tell from the file's length whether it contains a string or binary pid. So for COHERENT only, we only allow string pids. For all others, we decide based on the size of the lockfile. */ if (len > 4) { /* If file > 4 bytes it's a string */ #endif /* COHERENT */ x = read(fd,buf,(int)len); debug(F111,"ttrpid string read",buf,x); if (x < 0) { pid = -1; } else { buf[31] = '\0'; x = sscanf(buf,"%d",&pid); /* Get the integer pid from it. */ } #ifndef COHERENT } else if (len == 4) { /* 4 bytes so binary */ x = read(fd, (char *)&pid, 4); /* Read the bytes into an int */ debug(F101,"ttrpid integer read","",x); if (x < 4) pid = -1; } else if (len == 2) { /* 2 bytes binary */ x = read(fd, (char *)&spid, 2); /* Read the bytes into a short */ debug(F101,"ttrpid short read","",x); if (x < 2) pid = -1; else pid = spid; } else pid = -1; #endif /* COHERENT */ close(fd); /* Close the lockfile */ debug(F101,"ttrpid pid","",pid); return(pid); } #endif /* NOUUCP */ /* T T L O C K */ /* This function attempts to coordinate use of the communication device with other copies of Kermit and any other program that follows the UUCP device-locking conventions, which, unfortunately, vary among different UNIX implementations. The idea is to look for a file of a certain name, the "lockfile", in a certain directory. If such a file is found, then the line is presumed to be in use, and Kermit should not use it. If no such file is found, Kermit attempts to create one so that other programs will not use the same line at the same time. Because the lockfile and/or the directory it's in might lack write permission for the person running Kermit, Kermit could find itself running setuid to uucp or other user that does have the necessary permissions. At startup, Kermit has changed its effective uid to the user's real uid, and so ttlock() must switch back to the original effective uid in order to create the lockfile, and then back again to the real uid to prevent unauthorized access to other directories or files owned by the user the program is setuid to. Totally rewritten for C-Kermit 5A to eliminate windows of vulnerability, based on suggestions from Warren Tucker. Call with pointer to name of tty device. Returns: 0 on success -1 on failure Note: Once privileges are turned on using priv_on(), it is essential that they are turned off again before this function returns. */ #ifdef SVR4 /* Lockfile uses device numbers. */ /* Although I can't find this in writing anywhere (e.g. in SVID for SVR4), it is the behavior of the "reference version" of SVR4, i.e. the Intel port from UNIX Systems Laboratories, then called Univel UnixWare, then called Novell UnixWare, then called SCO Unixware, then called Caldera Open UNIX... It also makes much more sense than device-name-based lockfiles since there can be multiple names for the same device, symlinks, etc. */ #ifndef NOLFDEVNO #ifndef LFDEVNO /* Define this for SVR4 */ #ifndef AIXRS /* But not for RS/6000 AIX 3.2, etc. */ #ifndef BSD44 /* If anybody else needs it... */ #ifndef __386BSD__ #ifndef __FreeBSD__ #ifndef HPUX10 #ifndef IRIX51 /* SGI IRIX 5.1 or later */ #ifndef CK_SCOV5 /* SCO Open Server 5.0 */ #define LFDEVNO #endif /* CK_SCOV5 */ #endif /* IRIX51 */ #endif /* HPUX10 */ #endif /* __FreeBSD__ */ #endif /* __386BSD__ */ #endif /* BSD44 */ #endif /* AIXRS */ #endif /* LFDEVNO */ /* ... define it here or on CC */ #endif /* NOLFDEVNO */ #endif /* SVR4 */ /* command line. */ #ifdef COHERENT #define LFDEVNO #endif /* COHERENT */ /* For platforms where the lockfile name is made from device/major/minor device number, as in SVR4. Which, if we must have lockfiles at all, is by far the best format, since it eliminates all the confusion that stems from multiple names (or drivers) for the same port, not to mention symlinks. It might even be a good idea to start using this form even on platforms where it's not supported, alongside the normal forms for those platforms, in order to get people used to it... */ #ifdef LFDEVNO #ifndef major /* If we didn't find it */ #ifdef SVR4 /* then for Sys V R4 */ #include /* look here */ #else /* or for SunOS versions */ #ifdef SUNOS4 /* ... */ #include /* look here */ #else /* Otherwise take a chance: */ #define major(dev) ( (int) ( ((unsigned)(dev) >> 8) & 0xff)) #define minor(dev) ( (int) ( (dev) & 0xff)) #endif /* SUNOS4 */ #endif /* SVR4 */ #endif /* major */ #endif /* LFDEVNO */ /* No advisory locks if F_TLOCK and F_ULOCK are not defined at this point */ #ifdef LOCKF #ifndef F_TLOCK #undef LOCKF #ifndef NOLOCKF #define NOLOCKF #endif /* NOLOCKF */ #endif /* F_TLOCK */ #endif /* LOCKF */ #ifdef LOCKF #ifndef F_ULOCK #undef LOCKF #ifndef NOLOCKF #define NOLOCKF #endif /* NOLOCKF */ #endif /* F_ULOCK */ #endif /* LOCKF */ static char linkto[DEVNAMLEN+1]; static char * linkdev = NULL; #ifndef NOUUCP #ifdef USETTYLOCK #ifdef LOCK_DIR char * uucplockdir = LOCK_DIR; #else char * uucplockdir = ""; #endif /* LOCK_DIR */ #else /* USETTYLOCK */ #ifdef LOCK_DIR char * uucplockdir = LOCK_DIR; #else char * uucplockdir = ""; #endif /* LOCK_DIR */ #endif /* USETTYLOCK */ #else char * uucplockdir = ""; #endif /* NOUUCP */ #ifdef QNX /* Only for QNX4 */ int /* Visible to outside world */ qnxopencount() { /* Get QNX device open count */ struct _dev_info_entry info; int x; x = -1; /* Unknown */ if (ttyfd > -1) { if (!dev_info(ttyfd, &info)) { debug(F101,"ttlock QNX open_count","",info.open_count); x = info.open_count; } } return(x); } #endif /* QNX */ char * ttglckdir() { /* Get Lockfile directory name */ #ifdef __OpenBSD__ return("/var/spool/lock"); #else /* __OpenBSD__ */ #ifdef __FreeBSD__ return("/var/spool/lock"); #else /* __FreeBSD__ */ #ifdef LOCK_DIR char * s = LOCK_DIR; #endif /* LOCK_DIR */ #ifdef NOUUCP return(""); #else /* NOUUCP */ #ifdef LOCK_DIR return(s); #else /* LOCK_DIR */ return(""); #endif /* LOCK_DIR */ #endif /* NOUUCP */ #endif /* __FreeBSD__ */ #endif /* __OpenBSD__ */ } static int #ifdef CK_ANSIC ttlock( char * ttdev ) #else ttlock(ttdev) char *ttdev; #endif /* CK_ANSIC */ { int x, n; int islink = 0; #ifdef __FreeBSD__ char *devname; #endif /* __FreeBSD__ */ #ifdef NOUUCP debug(F100,"ttlock NOUUCP","",0); ckstrncpy(flfnam,"NOLOCK",FLFNAML); haslock = 1; return(0); #else /* !NOUUCP */ #ifdef USETTYLOCK haslock = 0; /* Not locked yet. */ *flfnam = '\0'; /* Lockfile name is empty. */ #ifdef __FreeBSD__ if ((devname = xxlast(ttdev,'/')) != NULL) #ifdef FREEBSD8 ckstrncat(lockname,devname+1,DEVNAMLEN-ckstrncpy(lockname,"pts",4)); #else ckstrncpy(lockname,devname+1,DEVNAMLEN); #endif /* FREEBSD8 */ #else if (!strncmp(ttdev,"/dev/",5) && ttdev[5]) ckstrncpy(lockname,ttdev+5,DEVNAMLEN); #endif /* __FreeBSD__ */ else ckstrncpy(lockname,ttdev,DEVNAMLEN); /* This might be overkill, but it's not clear from the man pages whether ttylock() can be called without calling ttylocked() first, since the doc says that ttylocked() removes any stale lockfiles, but it does not say this about ttylock(). Also the docs don't say what ttylocked() returns in the case when it finds and removes a stale lockfile. So one or both calls to to ttylocked() might be superfluous, but they should do no harm. Also I'm assuming that we have to do all the same ID swapping, etc, with these routines as we do without them. Thus the priv_on/off() sandwich. */ #ifdef USE_UU_LOCK priv_on(); /* Turn on privs */ x = uu_lock(lockname); /* Try to set the lock */ priv_off(); /* Turn privs off */ debug(F111,"ttlock uu_lock",lockname,x); switch (x) { case UU_LOCK_INUSE: return(-2); case UU_LOCK_OK: #ifdef BSD44 ckmakmsg(flfnam,FLFNAML,"/var/spool/lock/LCK..",lockname,NULL,NULL); #endif /* BSD44 */ haslock = 1; return(0); default: return(-1); } #else /* USE_UU_LOCK */ priv_on(); /* Turn on privs */ if (ttylocked(lockname)) { /* This should remove any stale lock */ if (ttylocked(lockname)) { /* so check again. */ priv_off(); return(-5); /* Still locked, fail. */ } } x = ttylock(lockname); /* Lock it. */ priv_off(); /* Turn off privs */ debug(F111,"ttlock lockname",lockname,x); if (x > -1) { /* We don't really know the name of the lockfile, but this is what the man page says it is. In USETTYLOCK builds, it is used only for display by SHOW COMM. */ ckmakmsg(flfnam,FLFNAML,"/etc/locks/LCK..",lockname,NULL,NULL); haslock = 1; } return(x); #endif /* USE_UU_LOCK */ #else /* Systems that don't have ttylock()... */ #ifndef HPUX int lockfd; /* File descriptor for lock file. */ PID_T pid; /* Process id of this process. */ int tries; /* How many times we've tried... */ int dummy; struct stat devbuf; /* For device numbers (SVR4). */ #ifdef PIDSTRING char pid_str[32]; /* My pid in string format. */ #endif /* PIDSTRING */ char *device, *devname; /* Note: ridiculously long to prevent gcc complaints when used in sprintf */ #define LFNAML 5126 /* Max length for lock file name. */ char lockfil[LFNAML]; /* Lock file name */ #ifdef RTAIX char lklockf[LFNAML]; /* Name for link to lock file */ #endif /* RTAIX */ #ifdef CKSYMLINK char symlock[LFNAML]; /* Name for symlink lockfile name */ #endif /* CKSYMLINK */ char tmpnam[LFNAML+30]; /* Temporary lockfile name. */ char *lockdir = LOCK_DIR; /* Defined near top of this file, */ /* or on cc command line. */ haslock = 0; /* Not locked yet. */ *flfnam = '\0'; /* Lockfile name is empty. */ lock2[0] = '\0'; /* Clear secondary lockfile name. */ pid = getpid(); /* Get id of this process. */ /* Construct name of lockfile and temporary file */ /* device = name of tty device without the path, e.g. "ttyh8" */ /* lockfil = name of lock file, without path, e.g. "LCK..ttyh8" */ device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev); if (stat(ttdev,&devbuf) < 0) return(-1); #ifdef CKSYMLINK islink = 1; /* Assume it's a symlink */ linkto[0] = '\0'; /* But we don't know to what */ #ifdef COMMENT /* This is undependable. If it worked it would save the readlink call if we knew the device name was not a link. */ #ifdef S_ISLNK islink = S_ISLNK(devbuf.st_mode); debug(F101,"ttlock stat S_ISLNK","",islink); #endif /* S_ISLNK */ #endif /* COMMENT */ if (islink) { n = readlink(ttdev,linkto,DEVNAMLEN); /* See if it's a link */ debug(F111,"ttlock readlink",ttdev,n); if (n > -1) /* It is */ linkto[n] = '\0'; else /* It's not */ islink = 0; debug(F111,"ttlock link",linkto,islink); } if (islink) { linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto; debug(F110,"ttlock linkdev",linkdev,0); } #endif /* CKSYMLINK */ /* On SCO platforms, if we don't have a symlink, then let's pretend the name given for the device is a symlink, because later we will change the name if it contains any uppercase characters. */ #ifdef CK_SCOV5 /* SCO Open Server 5.0 */ if (!islink) { islink = 1; ckstrncpy(linkto,ttdev,DEVNAMLEN); linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto; debug(F110,"ttlock linkdev",linkdev,0); } #else #ifdef M_XENIX /* SCO Xenix or UNIX */ if (!islink) { islink = 1; ckstrncpy(linkto,ttdev,DEVNAMLEN); linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto; debug(F110,"ttlock linkdev",linkdev,0); } #endif /* M_XENIX */ #endif /* CK_SCOV5 */ #ifdef ISIII /* Interactive System III, PC/IX */ ckstrncpy(lockfil, device, DEVNAMLEN); #else /* not ISIII */ #ifdef LFDEVNO /* Lockfilename has device numbers. */ #ifdef COHERENT sprintf(lockfil,"LCK..%d.%d", /* SAFE */ major(devbuf.st_rdev), /* major device number */ 0x1f & minor(devbuf.st_rdev)); /* minor device number */ #else /* Note: %d changed to %u in 8.0 -- %u is part of SVID for SVR4 */ /* Lockfile name format verified to agree with Solaris cu, Dec 2001 */ sprintf(lockfil,"LK.%03u.%03u.%03u", /* SAFE */ major(devbuf.st_dev), /* device */ major(devbuf.st_rdev), /* major device number */ minor(devbuf.st_rdev)); /* minor device number */ #endif /* COHERENT */ #else /* Not LFDEVNO */ #ifdef PTX /* Dynix PTX */ if ((device != &ttdev[5]) && (strncmp(ttdev,"/dev/",5) == 0)) { if ((int)strlen(device) + 8 < LFNAML) sprintf(lockfil,"LCK..%.3s%s", &ttdev[5], device); else ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML); } else #endif /* PTX */ if ((int)strlen(device) + 5 < LFNAML) sprintf(lockfil,"LCK..%s", device); else ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML); #ifdef RTAIX ckstrncpy(lklockf,device,DEVNAMLEN); #endif /* RTAIX */ #ifdef CKSYMLINK symlock[0] = '\0'; if (islink) ckmakmsg(symlock,LFNAML, "LCK..", linkdev, NULL, NULL); #endif /* CKSYMLINK */ #endif /* LFDEVNO */ #endif /* ISIII */ #ifdef CK_SCOV5 /* SCO Open Server 5.0 */ { /* Lowercase the entire filename. */ /* SCO says we must do this in V5.0 and later. */ /* BUT... watch out for devices -- like Digiboard Portserver */ /* That can have hundreds of ports... */ char *p = (char *)(lockfil + 5); while (*p) { if (isupper(*p)) *p = (char) tolower(*p); p++; } } #ifdef CKSYMLINK if (islink) { /* If no change */ if (!strcmp(lockfil,symlock)) { /* then no second lockfile needed */ islink = 0; symlock[0] = '\0'; } } #endif /* CKSYMLINK */ #else #ifdef M_XENIX /* SCO Xenix or UNIX */ { int x; char c; x = (int)strlen(lockfil) - 1; /* Get last letter of device name. */ if (x > 0) { /* If it's uppercase, lower it. */ c = lockfil[x]; if (c >= 'A' && c <= 'Z') lockfil[x] += ('a' - 'A'); } } #ifdef CKSYMLINK if (islink) { if (!strcmp(lockfil,symlock)) { /* No change */ islink = 0; /* so no second lockfile */ symlock[0] = '\0'; } } #endif /* CKSYMLINK */ #endif /* M_XENIX */ #endif /* CK_SCOV5 */ /* flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..ttyh8" */ /* tmpnam = temporary unique, e.g. "/usr/spool/uucp/LTMP..pid" */ ckmakmsg(flfnam,LFNAML,lockdir,"/",lockfil,NULL); #ifdef RTAIX ckmakmsg(lkflfn,FLFNAML,lockdir,"/",lklockf,NULL); #endif /* RTAIX */ #ifndef LFDEVNO #ifdef CKSYMLINK /* If it's a link then also make a lockfile for the real name */ debug(F111,"ttlock link symlock",symlock,islink); if (islink && symlock[0]) { /* But only if the lockfile names would be different. */ /* WARNING: They won't be, e.g. for /dev/ttyd2 => /hw/ttys/ttyd2 */ ckmakmsg(lock2,FLFNAML,lockdir,"/",symlock,NULL); debug(F110,"ttlock lock2",lock2,0); if (!strcmp(lock2,flfnam)) { /* Are lockfile names the same? */ debug(F100,"ttlock lock2 cleared","",0); lock2[0] = '\0'; /* Clear secondary lockfile name. */ } } #endif /* CKSYMLINK */ #endif /* LFDEVNO */ sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* safe */ debug(F110,"ttlock flfnam",flfnam,0); debug(F110,"ttlock tmpnam",tmpnam,0); priv_on(); /* Turn on privileges if possible. */ lockfd = creat(tmpnam, 0444); /* Try to create temp lock file. */ if (lockfd < 0) { /* Create failed. */ debug(F111,"ttlock creat failed",tmpnam,errno); if (errno == ENOENT) { perror(lockdir); printf("UUCP not installed or Kermit misconfigured\n"); } else { if (!quiet) perror(lockdir); unlink(tmpnam); /* Get rid of the temporary file. */ } priv_off(); /* Turn off privileges!!! */ return(-1); /* Return failure code. */ } /* Now write the pid into the temp lockfile in the appropriate format */ #ifdef PIDSTRING /* For Honey DanBer UUCP, */ sprintf( /* write PID as decimal string */ pid_str, #ifdef LINUXFSSTND /* The "Linux File System Standard" */ #ifdef FSSTND10 /* Version 1.0 calls for */ "%010d\n", /* leading zeros */ #else /* while version 1.2 calls for */ "%10d\n", /* leading spaces */ #endif /* FSSTND10 */ #else #ifdef COHERENT "%d\n", /* with leading nothing */ #else "%10d\n", /* with leading blanks */ #endif /* COHERENT */ #endif /* LINUXFSSTND */ (int) pid ); /* safe */ dummy = write(lockfd, pid_str, 11); debug(F111,"ttlock hdb pid string",pid_str,(int) pid); #else /* Not PIDSTRING, use integer PID */ write(lockfd, (char *)&pid, sizeof(pid) ); debug(F101,"ttlock pid","",(int) pid); #endif /* PIDSTRING */ /* Now try to rename the temp file to the real lock file name. */ /* This will fail if a lock file of that name already exists. */ close(lockfd); /* Close the temp lockfile. */ chmod(tmpnam,0444); /* Permission for a valid lock. */ tries = 0; while (!haslock && tries++ < 2) { haslock = 0; dummy = link(tmpnam,flfnam); /* Create a link to it. */ if (dummy == 0) haslock = 1; if (haslock) { /* If we got the lockfile */ #ifdef RTAIX link(flfnam,lkflfn); #endif /* RTAIX */ #ifdef CKSYMLINK #ifndef LFDEVNO if (islink && lock2[0]) dummy = link(flfnam,lock2); #endif /* LFDEVNO */ #endif /* CKSYMLINK */ #ifdef COMMENT /* Can't do this any more because device is not open yet so no ttyfd. */ #ifdef LOCKF /* Advisory file locking works on SVR4, so we use it. In fact, it is necessary in some cases, e.g. when SLIP is involved. But it still doesn't seem to prevent multiple users accessing the same device by different names. */ while (lockf(ttyfd, F_TLOCK, 0L) != 0) { debug(F111, "ttlock lockf returns errno", "", errno); if ((++tries >= 3) || (errno != EAGAIN)) { x = unlink(flfnam); /* remove the lockfile */ #ifdef RTAIX unlink(lkflfn); /* And any links to it... */ #endif /* RTAIX */ #ifdef CKSYMLINK #ifndef LFDEVNO if (islink && lock2[0]) unlink(lock2); /* ditto... */ #endif /* LFDEVNO */ #endif /* CKSYMLINK */ debug(F111,"ttlock unlink",flfnam,x); haslock = 0; break; } sleep(2); } if (haslock) /* If we got an advisory lock */ #endif /* LOCKF */ #endif /* COMMENT */ break; /* We're done. */ } else { /* We didn't create a new lockfile. */ priv_off(); if (ttchkpid(flfnam)) { /* Check existing lockfile */ priv_on(); /* cause ttchkpid turns priv_off... */ unlink(tmpnam); /* Delete the tempfile */ debug(F100,"ttlock found tty locked","",0); priv_off(); /* Turn off privs */ return(-2); /* Code for device is in use. */ } priv_on(); } } unlink(tmpnam); /* Unlink (remove) the temp file. */ priv_off(); /* Turn off privs */ return(haslock ? 0 : -1); /* Return link's return code. */ #else /* HPUX */ /* HP-UX gets its own copy of this routine, modeled after the observed behavior of the HP-UX 'cu' program. HP-UX serial device names consist of a base name such as "tty", "ttyd", "cua", "cul", "cuad", or "culd", followed by a unit designator which is a string of digits, possibly containing an imbedded letter "p". Examples (for base name "tty"): /dev/tty0, /dev/tty00, dev/ttyd00, /dev/tty0p0 According to the HP-UX UUCP manual of 1988, the "0p0" notation has been used on Series 800 since HP-UX 2.00, and the "non-p" notation was used on other models. In HP-UX 10.00, "0p0" notation was adopted for all models. However, we make and enforce no such distinctions; either notation is accepted on any model or HP-UX version as a valid unit designator. If a valid unit is specified (as opposed to a designer name or symlink), we check for all aliases of the given unit according to the devprefix[] array. If no lockfiles are found for the given unit, we can have the device; we create a lockfile LCK..name in the lockfile directory appropriate for the HP-UX version (/var/spool/locks for 10.00 and later, /usr/spool/uucp for 9.xx and earlier). If it is a "cua" or "cul" device, a second lockfile is created with the "ttyd" prefix. This is exactly what cu does. If the "set line" device does not have a valid unit designator, then it is used literally and no synomyms are searched for and only one lockfile is created. -fdc, March 1998. */ #define LFNAML 80 /* Max length for lock file name. */ int lockfd; /* File descriptor for lock file. */ PID_T pid; /* Process ID of this process. */ int fpid; /* pid found in existing lockfile. */ int tries; /* How many times we've tried... */ int i, k; /* Workers */ char *device, *devname; /* "/dev/xxx", "xxx" */ char *unit, *p; /* p part of xxx */ char lockfil[LFNAML]; /* Lockfile name (no path) */ char tmpnam[LFNAML]; /* Temporary lockfile name. */ #ifdef HPUX10 /* Lockfile directory */ char *lockdir = "/var/spool/locks"; /* Always this for 10.00 and higher */ #else /* HP-UX 9.xx and below */ #ifdef LOCK_DIR char *lockdir = LOCK_DIR; /* Defined near top of this file */ #else char *lockdir = "/usr/spool/uucp"; /* or not... */ #endif /* LOCK_DIR */ #endif /* HPUX10 */ haslock = 0; /* Not locked yet. */ *flfnam = '\0'; /* Lockfile name is empty. */ lock2[0] = '\0'; /* Second one too. */ pid = getpid(); /* Get my process ID */ /* Construct name of lockfile and temporary file... device = name of tty device without the path, e.g. "tty0p0" lockfil = name of lock file, without path, e.g. "LCK..tty0p0" */ device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev); debug(F110,"TTLOCK device",device,0); ckmakmsg(lockfil,LFNAML,"LCK..",device,NULL,NULL); k = 0; /* Assume device is not locked */ n = 0; /* Digit counter */ unit = device; /* Unit = p */ while (*unit && !isdigit(*unit)) /* Search for digit... */ unit++; p = unit; /* Verify p format... */ debug(F110,"TTLOCK unit 1",unit,0); /* The unit number is recognized as: (a) any sequence of digits that runs to the end of the string. (b) any (a) that includes one and only one letter "p", with at least one digit before and after it. */ while (isdigit(*p)) p++, n++; /* Get a run of digits */ if (*p && n > 0) { /* Have a "p"? */ if (*p == 'p' && isdigit(*(p+1))) { p++; n = 0; while (isdigit(*p)) p++, n++; } } if (n == 0 || *p) unit = ""; debug(F110,"TTLOCK unit 2",unit,0); if (*unit) { /* Device name has unit number. */ /* The following loop not only searches for the various lockfile */ /* synonyms, but also removes all -- not just one -- stale lockfile */ /* for the device, should there be more than one. See ttchkpid(). */ ttydexists = 0; for (i = 0; *devprefix[i]; i++) { /* For each driver... */ /* Make device name */ ckmakmsg(lock2,FLFNAML,"/dev/",devprefix[i],unit,NULL); priv_on(); /* Privs on */ k = zchki(lock2) != -1; /* See if device exists */ priv_off(); /* Privs off */ debug(F111,"TTLOCK exist",lock2,k); if (k) { if (!strcmp(devprefix[i],"ttyd")) /* ttyd device exists */ ttydexists = 1; /* Make lockfile name */ ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",devprefix[i],unit); debug(F110,"TTLOCK checking",lock2,0); priv_on(); /* Privs on */ k = zchki(lock2) != -1; /* See if lockfile exists */ priv_off(); /* Privs off */ debug(F111,"TTLOCK check for lock A",lock2,k); if (k) if (ttchkpid(lock2)) { /* If pid still active, fail. */ ckstrncpy(flfnam,lock2,FLFNAML); return(-2); } } } } else { /* Some other device-name format */ /* This takes care of symbolic links, etc... */ /* But does not chase them down! */ ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",device,NULL); priv_on(); k = zchki(lock2) != -1; /* Check for existing lockfile */ priv_off(); debug(F111,"TTLOCK check for lock B",lock2,k); if (k) if (ttchkpid(lock2)) { /* Check pid from lockfile */ ckstrncpy(flfnam,lock2,FLFNAML); debug(F110,"TTLOCK in use",device,0); debug(F101,"TTLOCK returns","",-2); return(-2); } } /* Get here only if there is no (more) lockfile, so now we make one (or two)... flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..cul0p0". tmpnam = unique temporary filname, e.g. "/usr/spool/uucp/LTMP..pid". */ ckmakmsg(flfnam,FLFNAML,lockdir,"/",lockfil,NULL); /* SET LINE device */ /* If dialout device, also make one for corresponding dialin device */ lock2[0] = '\0'; if (!strncmp(device,"cu",2) && *unit && ttydexists) ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..ttyd",unit,NULL); if ((int)strlen(lockdir)+12 < LFNAML) sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* Make temp name */ #ifdef DEBUG if (deblog) { debug(F110,"TTLOCK flfnam",flfnam,0); debug(F110,"TTLOCK lock2",lock2,0); debug(F110,"TTLOCK tmpnam",tmpnam,0); } #endif /* DEBUG */ /* Lockfile permissions... 444 is standard, HP-UX 10.00 uses 664. It doesn't matter. Kermit uses 444; the difference lets us tell whether Kermit created the lock file. */ priv_on(); /* Turn on privileges. */ lockfd = creat(tmpnam, 0444); /* Try to create temporary file. */ if (lockfd < 0) { /* Create failed. */ debug(F111,"TTLOCK creat failed",tmpnam,errno); if (errno == ENOENT) { perror(lockdir); printf("UUCP not installed or Kermit misconfigured\n"); } else { if (!quiet) perror(lockdir); unlink(tmpnam); /* Get rid of the temporary file. */ } priv_off(); /* Turn off privileges!!! */ debug(F101,"TTLOCK returns","",-1); return(-1); /* Return failure code. */ } debug(F110,"TTLOCK temp ok",tmpnam,0); /* Now write our pid into the temp lockfile in integer format. */ i = write(lockfd, (char *)&pid, sizeof(pid)); #ifdef DEBUG if (deblog) { debug(F101,"TTLOCK pid","",pid); debug(F101,"TTLOCK sizeof pid","",sizeof(pid)); debug(F101,"TTLOCK write pid returns","",i); } #endif /* DEBUG */ /* Now try to rename the temporary file to the real lockfile name. This will fail if a lock file of that name already exists, which will catch race conditions with other users. */ close(lockfd); /* Close the temp lockfile. */ chmod(tmpnam,0444); tries = 0; while (!haslock && tries++ < 2) { haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */ debug(F101,"TTLOCK link","",haslock); if (haslock) { /* If we made the lockfile... */ #ifdef COMMENT /* We can't do this any more because we don't have a file descriptor yet. */ #ifdef LOCKF /* Can be canceled with -DNOLOCKF */ /* Create an advisory lock on the device through its file descriptor. This code actually seems to work. If it is executed, and then another process tries to open the same device under a different name to circumvent the lockfile, they get a "device busy" error. */ debug(F100,"TTLOCK LOCKF code...","",0); while ( lockf(ttyfd, F_TLOCK, 0L) != 0 ) { debug(F111, "TTLOCK lockf error", "", errno); if ((++tries >= 3) || (errno != EAGAIN)) { x = unlink(flfnam); /* Remove the lockfile */ if (errno == EACCES && !quiet) printf("Device already locked by another process\n"); haslock = 0; break; } sleep(2); } #endif /* LOCKF */ #endif /* COMMENT */ if (haslock) { /* If we made the lockfile ... */ if (lock2[0]) { /* if there is to be a 2nd lockfile */ lockfd = creat(lock2, 0444); /* Create it */ debug(F111,"TTLOCK lock2 creat", lock2, lockfd); if (lockfd > -1) { /* Created OK, write pid. */ write(lockfd, (char *)&pid, sizeof(pid) ); close(lockfd); /* Close and */ chmod(lock2, 0444); /* set permissions. */ } else { /* Not OK, but don't fail. */ lock2[0] = '\0'; /* Just remember it's not there. */ } } break; /* and we're done. */ } } } unlink(tmpnam); /* Unlink (remove) the temp file. */ priv_off(); /* Turn off privs */ i = haslock ? 0 : -1; /* Our return value */ debug(F101,"TTLOCK returns","",i); return(i); #endif /* HPUX */ #endif /* USETTYLOCK */ #endif /* !NOUUCP */ } /* T T U N L O C K */ static int ttunlck() { /* Remove UUCP lockfile(s). */ #ifndef NOUUCP int x; debug(F111,"ttunlck",flfnam,haslock); #ifdef USETTYLOCK if (haslock && *flfnam) { int x; priv_on(); /* Turn on privs */ #ifdef USE_UU_LOCK x = uu_unlock(lockname); #else /* USE_UU_LOCK */ x = ttyunlock(lockname); /* Try to unlock */ #endif /* USE_UU_LOCK */ priv_off(); /* Turn off privs */ if (x < 0 && !quiet) printf("Warning - Can't remove lockfile: %s\n", flfnam); *flfnam = '\0'; /* Erase the name. */ haslock = 0; return(0); } #else /* No ttylock()... */ if (haslock && *flfnam) { /* Don't remove lockfile if we didn't make it ourselves */ if ((x = ttrpid(flfnam)) != (int)getpid()) { debug(F111,"ttunlck lockfile seized",flfnam,x); printf("Warning - Lockfile %s seized by pid %d\n", flfnam, x ); return(0); } priv_on(); /* Turn privileges on. */ errno = 0; x = unlink(flfnam); /* Remove the lockfile. */ debug(F111,"ttunlck unlink",flfnam,x); if (x < 0) { if (errno && !quiet) perror(ttnmsv); printf("Warning - Can't remove lockfile: %s\n", flfnam); } haslock = 0; *flfnam = '\0'; /* Erase the name. */ #ifdef RTAIX errno = 0; x = unlink(lkflfn); /* Remove link to lockfile */ debug(F111,"ttunlck AIX link unlink",lkflfn,x); if (x < 0) { if (errno && !quiet) perror(ttnmsv); printf("Warning - Can't remove link to lockfile: %s\n", lkflfn); } *lkflfn = '\0'; #else if (lock2[0]) { /* If there is a second lockfile, */ errno = 0; x = unlink(lock2); /* remove it too. */ debug(F111,"ttunlck lock2 unlink",lock2,x); if (x < 0) { if (errno && !quiet) perror(ttnmsv); printf("Warning - Can't remove secondary lockfile: %s\n", lock2 ); } lock2[0] = '\0'; /* Forget its name. */ } #endif /* RTAIX */ #ifdef COMMENT #ifdef LOCKF (VOID) lockf(ttyfd, F_ULOCK, 0L); /* Remove advisory lock */ #endif /* LOCKF */ #endif /* COMMENT */ priv_off(); /* Turn privileges off. */ } #endif /* USETTYLOCK */ #endif /* !NOUUCP */ return(0); } /* 4.3BSD-style UUCP line direction control. (Stan Barber, Rice U, 1980-something...) */ #ifndef NOUUCP #ifdef ACUCNTRL VOID acucntrl(flag,ttname) char *flag, *ttname; { char x[DEVNAMLEN+32], *device, *devname; if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */ return; /* just return. */ device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname); if (strncmp(device,"LCK..",4) == 0) device += 5; ckmakmsg(x,DEVNAMLEN+32,"/usr/lib/uucp/acucntrl ",flag," ",device); debug(F110,"called ",x,0); zsyscmd(x); } #endif /* ACUCNTRL */ #endif /* NOUUCP */ /* T T H F L O W -- Set or Reset hardware flow control. This is an attempt to collect all hardware-flow-control related code into a single module. Thanks to Rick Sladkey and John Kohl for lots of help here. Overview: Hardware flow control is not supported in many UNIX implementions. Even when it is supported, there is no (ha ha) "standard" for the programming interface. In general, 4.3BSD and earlier (sometimes), 4.4BSD, System V, SunOS, AIX, etc, have totally different methods. (And, not strictly relevant here, the programming interface often brings one only to a no-op in the device driver!) Among all these, we have two major types of APIs: those in which hardware flow control is determined by bits in the same termio/termios/sgtty mode word(s) that are used for controlling such items as CBREAK vs RAW mode, and which are also used by the ttvt(), ttpkt(), conbin(), and concb() routines for changing terminal modes. And those that use entirely different mechanisms. In the first category, it is important that any change in the mode bits be reflected in the relevant termio(s)/sgtty structure, so that subsequent changes to that structure do not wipe out the effects of this routine. That is why a pointer, attrs, to the appropriate structure is passed as a parameter to this routine. The second category should give us no worries, since any changes to hardware flow control accomplished by this routine should not affect the termio(s)/ sgtty structures, and therefore will not be undone by later changes to them. The second argument, status, means to turn on hardware flow control if nonzero, and to turn it off if zero. Returns: 0 on apparent success, -1 on probable failure. */ /* The following business is for BSDI, where it was discovered that two separate bits, CCTS_OFLOW and CRTS_IFLOW, are used in hardware flow control, but CTRSCTS is defined (in ) to be just CCTS_OFLOW rather both bits, so hwfc only works in one direction if you use CRTSCTS to control it. Other 4.4BSD-based Unixes such as FreeBSD 4.1, which use these two bits, define CRTSCTS correctly. */ #ifdef FIXCRTSCTS #ifdef CRTSCTS #ifdef CCTS_OFLOW #ifdef CRTS_IFLOW #undef CRTSCTS #define CRTSCTS (CRTS_IFLOW|CCTS_OFLOW) #endif /* CRTS_IFLOW */ #endif /* CCTS_OFLOW */ #endif /* CRTSCTS */ #endif /* FIXCRTSCTS */ static int #ifdef CK_ANSIC tthflow(int flow, int status, #ifdef BSD44ORPOSIX /* POSIX or BSD44 */ struct termios *attrs #else /* System V */ #ifdef ATTSV #ifdef ATT7300 #ifdef UNIX351M /* AT&T UNIX 3.51m can set but not test for hardware flow control */ #define RTSFLOW CTSCD #define CTSFLOW CTSCD #endif /* ATT7300 */ #endif /* UNIX351M */ struct termio *attrs #else /* BSD, V7, etc */ struct sgttyb *attrs /* sgtty info... */ #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ ) #else tthflow(flow, status, attrs) int flow, /* Type of flow control (ckcdeb.h) */ status; /* Nonzero = turn it on */ /* Zero = turn it off */ #ifdef BSD44ORPOSIX /* POSIX or BSD44 */ struct termios *attrs; #else /* System V */ #ifdef ATTSV #ifdef ATT7300 #ifdef UNIX351M /* AT&T UNIX 3.51m can set but not test for hardware flow control */ #define RTSFLOW CTSCD #define CTSFLOW CTSCD #endif /* ATT7300 */ #endif /* UNIX351M */ struct termio *attrs; #else /* BSD, V7, etc */ struct sgttyb *attrs; /* sgtty info... */ #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ #endif /* CK_ANSIC */ { int x = 0; /* tthflow() return code */ #ifdef Plan9 return p9tthflow(flow, status); #else #ifndef OXOS /* NOT Olivetti X/OS... */ /* For SunOS 4.0 and later in the BSD environment ... The declarations are copied and interpreted from the System V header files, so we don't actually have to pull in all the System V junk when building C-Kermit for SunOS in the BSD environment, which would be dangerous because having those symbols defined would cause us to take the wrong paths through the code. The code in this section is used in both the BSD and Sys V SunOS versions. */ #ifdef SUNOS41 /* In SunOS 4.1 and later, we use the POSIX calls rather than ioctl calls because GNU CC uses different formats for the _IOxxx macros than regular CC; the POSIX forms work for both. But the POSIX calls are not available in SunOS 4.0. */ #define CRTSCTS 0x80000000 /* RTS/CTS flow control */ #define TCSANOW 0 /* Do it now */ struct termios { unsigned long c_iflag; /* Input modes */ unsigned long c_oflag; /* Output modes */ unsigned long c_cflag; /* Control modes */ unsigned long c_lflag; /* Line discipline modes */ char c_line; CHAR c_cc[17]; }; struct termios temp; _PROTOTYP( int tcgetattr, (int, struct termios *) ); _PROTOTYP( int tcsetattr, (int, int, struct termios *) ); /* When CRTSCTS is set, SunOS won't do output unless both CTS and CD are asserted. So we don't set CRTSCTS unless CD is up. This should be OK, since we don't need RTS/CTS during dialing, and after dialing is complete, we should have CD. If not, we still communicate, but without RTS/CTS. */ int mflags; /* Modem signal flags */ #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ debug(F101,"tthflow SUNOS41 entry status","",status); if (!status) { /* Turn hard flow off */ if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */ (temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */ temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */ x = tcsetattr(ttyfd,TCSANOW,&temp); } } else { /* Turn hard flow on */ if (ioctl(ttyfd,TIOCMGET,&mflags) > -1 && /* Get modem signals */ (mflags & TIOCM_CAR)) { /* Check for CD */ debug(F100,"tthflow SunOS has CD","",0); if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */ !(temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */ temp.c_cflag |= CRTSCTS; /* Not there, add it */ x = tcsetattr(ttyfd,TCSANOW,&temp); } } else { x = -1; debug(F100,"tthflow SunOS no CD","",0); } } #else #ifdef QNX struct termios temp; #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ debug(F101,"tthflow QNX entry status","",status); if (tcgetattr(ttyfd, &temp) > -1) { /* Get device attributes */ if (!status) { /* Turn hard flow off */ if ((temp.c_cflag & (IHFLOW|OHFLOW)) == (IHFLOW|OHFLOW)) { temp.c_cflag &= ~(IHFLOW|OHFLOW); /* It's there, remove it */ attrs->c_cflag &= ~(IHFLOW|OHFLOW); x = tcsetattr(ttyfd,TCSANOW,&temp); } } else { /* Turn hard flow on */ if ((temp.c_cflag & (IHFLOW|OHFLOW)) != (IHFLOW|OHFLOW)) { temp.c_cflag |= (IHFLOW|OHFLOW); /* Not there, add it */ temp.c_iflag &= ~(IXON|IXOFF); /* Bye to IXON/IXOFF */ ttraw.c_lflag |= IEXTEN; /* Must be on */ x = tcsetattr(ttyfd,TCSANOW,&temp); attrs->c_cflag |= (IHFLOW|OHFLOW); attrs->c_iflag &= ~(IXON|IXOFF); } } } else { x = -1; debug(F100, "tthflow QNX getattr fails", "", 0); } #else #ifdef POSIX_CRTSCTS /* POSIX_CRTSCTS is defined in ckcdeb.h or on CC command line. Note: Do not assume CRTSCTS is a one-bit field! */ struct termios temp; #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ debug(F101,"tthflow POSIX_CRTSCTS entry status","",status); errno = 0; x = tcgetattr(ttyfd, &temp); debug(F111,"tthflow POSIX_CRTSCTS tcgetattr",ckitoa(x),errno); errno = 0; if (x < 0) { x = -1; } else { if (!status) { /* Turn hard flow off */ if ( #ifdef COMMENT /* This can fail because of sign extension */ /* e.g. in Linux where it's Bit 31 */ (temp.c_cflag & CRTSCTS) == CRTSCTS #else (temp.c_cflag & CRTSCTS) != 0 #endif /* COMMENT */ ) { temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */ attrs->c_cflag &= ~CRTSCTS; x = tcsetattr(ttyfd,TCSANOW,&temp); debug(F111,"tthflow POSIX_CRTSCTS OFF tcsetattr", ckitoa(x),errno); } else { /* John Dunlap 2010-01-26 */ debug(F001, "tthflow before forcing off attrs CRTSCTS", "", attrs->c_cflag&CRTSCTS ); attrs->c_cflag &= ~CRTSCTS; /* force it off if !status */ debug(F001, "tthflow after forcing off attrs CRTSCTS", "", attrs->c_cflag&CRTSCTS ); } } else { /* Turn hard flow on */ if ( #ifdef COMMENT /* This can fail because of sign extension */ (temp.c_cflag & CRTSCTS) != CRTSCTS #else (temp.c_cflag & CRTSCTS) == 0 #endif /* COMMENT */ ) { temp.c_cflag |= CRTSCTS; /* Not there, add it */ temp.c_iflag &= ~(IXON|IXOFF|IXANY); /* Bye to IXON/IXOFF */ x = tcsetattr(ttyfd,TCSANOW,&temp); debug(F111,"tthflow POSIX_CRTSCTS ON tcsetattr", ckitoa(x),errno); attrs->c_cflag |= CRTSCTS; attrs->c_iflag &= ~(IXON|IXOFF|IXANY); } } } #else #ifdef SUNOS4 /* SunOS 4.0 (and maybe earlier?). This code is dangerous because it prevents compilation with GNU gcc, which uses different formats for the _IORxxx macros than regular cc. SunOS 4.1 and later can use the POSIX routines above, which work for both cc and gcc. */ #define TCGETS _IOR(T, 8, struct termios) /* Get modes into termios struct */ #define TCSETS _IOW(T, 9, struct termios) /* Set modes from termios struct */ #define CRTSCTS 0x80000000 /* RTS/CTS flow control */ struct termios { unsigned long c_iflag; /* Input modes */ unsigned long c_oflag; /* Output modes */ unsigned long c_cflag; /* Control modes */ unsigned long c_lflag; /* Line discipline modes */ char c_line; CHAR c_cc[17]; }; struct termios temp; #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ debug(F101,"tthflow entry status","",status); if (ioctl(ttyfd,TCGETS,&temp) > -1) { /* Get terminal modes. */ if (status) { /* Turn hard flow on */ temp.c_cflag |= CRTSCTS; /* Add RTS/CTS to them. */ x = ioctl(ttyfd,TCSETS,&temp); /* Set them again. */ attrs->c_cflag |= CRTSCTS; /* Add to global info. */ } else { /* Turn hard flow off */ temp.c_cflag &= ~CRTSCTS; x = ioctl(ttyfd,TCSETS,&temp); attrs->c_cflag &= ~CRTSCTS; } } #else /* Not SunOS 4.0 or later */ #ifdef AIXRS /* IBM AIX RS/6000 */ #ifndef AIX41 /* But only pre-4.x == SVR4 */ #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ if (status) { if ((x = ioctl(ttyfd, TXADDCD, "rts")) < 0 && errno != EBUSY) debug(F100,"hardflow TXADDCD (rts) error", "", 0); } else { if ((x = ioctl(ttyfd, TXDELCD, "rts")) < 0 && errno != EINVAL) debug(F100,"hardflow TXDELCD (rts) error", "", 0); } #endif /* AIX41 */ #else /* Not AIX RS/6000 */ #ifdef ATTSV /* System V... */ #ifdef CK_SCOV5 /* SCO Open Server 5.0 */ #define CK_SCOUNIX #else #ifdef M_UNIX /* SCO UNIX 3.2v4.x or earlier */ #define CK_SCOUNIX #endif /* M_UNIX */ #endif /* CK_SCOV5 */ #ifdef SCO_FORCE_RTSXOFF #ifdef CK_SCOUNIX /* But not SCO OpenServer 5.0.4 */ #ifdef SCO_OSR504 /* or later... */ #undef CK_SCOUNIX #endif /* SCO_OSR504 */ #endif /* CK_SCOUNIX */ #endif /* SCO_FORCE_RTSXOFF */ #ifdef CK_SCOUNIX #ifdef POSIX struct termios temp; #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ debug(F101,"tthflow SCOUNIX POSIX entry status","",status); errno = 0; x = tcgetattr(ttyfd, &temp); debug(F111,"tthflow SCO UNIX POSIX tcgetattr",ckitoa(x),errno); #else /* POSIX */ struct termio temp; #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ debug(F101,"tthflow SCOUNIX non-POSIX entry status","",status); x = ioctl(ttyfd, TCGETA, &temp); debug(F111,"tthflow SCO UNIX non-POSIX TCGETA",ckitoa(x),errno); #endif /* POSIX */ /* This is not really POSIX, since POSIX does not deal with hardware flow control, but we are using the POSIX APIs. In fact, RTSFLOW and CTSFLOW are defined in termio.h, but within #ifndef _POSIX_SOURCE..#endif. So let's try forcing their definitions here. */ #ifndef CTSFLOW #define CTSFLOW 0020000 debug(F101,"tthflow SCO defining CTSFLOW","",CTSFLOW); #else debug(F101,"tthflow SCO CTSFLOW","",CTSFLOW); #endif /* CTSFLOW */ #ifndef RTSFLOW #define RTSFLOW 0040000 debug(F101,"tthflow SCO defining RTSFLOW","",RTSFLOW); #else debug(F101,"tthflow SCO RTSFLOW","",RTSFLOW); #endif /* RTSFLOW */ #ifndef ORTSFL #define ORTSFL 0100000 debug(F101,"tthflow SCO defining ORTSFL","",ORTSFL); #else debug(F101,"tthflow SCO ORTSFL","",ORTSFL); #endif /* ORTSFL */ if (x != -1) { if (status) { /* Turn it ON */ temp.c_cflag |= RTSFLOW|CTSFLOW; attrs->c_cflag |= RTSFLOW|CTSFLOW; #ifdef ORTSFL temp.c_cflag &= ~ORTSFL; attrs->c_cflag &= ~ORTSFL; #endif /* ORTSFL */ temp.c_iflag &= ~(IXON|IXOFF|IXANY); attrs->c_iflag &= ~(IXON|IXOFF|IXANY); } else { /* Turn it OFF */ #ifdef ORTSFL temp.c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL); attrs->c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL); #else /* ORTSFL */ temp.c_cflag &= ~(RTSFLOW|CTSFLOW); attrs->c_cflag &= ~(RTSFLOW|CTSFLOW); #endif /* ORTSFL */ } #ifdef POSIX x = tcsetattr(ttyfd, TCSADRAIN, &temp); #else x = ioctl(ttyfd, TCSETA, &temp); #endif /* POSIX */ debug(F101,"tthflow SCO set modes","",x); } #else /* Not SCO UNIX */ #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ if (!status) { /* Turn it OFF */ #ifdef RTSXOFF debug(F100,"tthflow ATTSV RTS/CTS OFF","",0); rctsx.x_hflag &= ~(RTSXOFF|CTSXON); #ifdef TCSETX x = ioctl(ttyfd,TCSETX,&rctsx); debug(F101,"tthflow ATTSV TCSETX OFF","",x); #else x = -1 debug(F100,"tthflow TCSETX not defined","",0); #endif /* TCSETX */ #else debug(F100,"tthflow ATTSV RTSXOFF not defined","",0); #endif /* RTSXOFF */ #ifdef DTRXOFF debug(F100,"tthflow ATTSV DTR/CD OFF","",0); rctsx.x_hflag &= ~(DTRXOFF|CDXON); x = ioctl(ttyfd,TCSETX,&rctsx); debug(F101,"tthflow ATTSV DTRXOFF OFF","",x); #else debug(F100,"tthflow ATTSV DTRXOFF not defined","",0); #endif /* DTRXOFF */ } else { /* Turn it ON. */ if (flow == FLO_RTSC) { /* RTS/CTS Flow control... */ debug(F100,"tthflow ATTSV RTS/CTS ON","",0); #ifdef RTSXOFF /* This is the preferred way, according to SVID3 */ #ifdef TCGETX x = ioctl(ttyfd,TCGETX,&rctsx); debug(F101,"tthflow TCGETX","",x); if (x > -1) { rctsx.x_hflag |= RTSXOFF | CTSXON; x = ioctl(ttyfd,TCSETX,&rctsx); debug(F100,"tthflow ATTSV ioctl","",x); } #else debug(F100,"tthflow TCGETX not defined","",0); x = -1 #endif /* TCGETX */ #else debug(F100,"tthflow RTSXOFF not defined","",0); x = -1; #endif /* RTSXOFF */ } else if (flow == FLO_DTRC) { /* DTR/CD Flow control... */ debug(F100,"tthflow ATTSV DTR/CD ON","",0); #ifdef DTRXOFF /* This is straight out of SVID R4 */ if (ioctl(ttyfd,TCGETX,&rctsx) > -1) { rctsx.x_hflag &= ~(DTRXOFF|CDXON); x = ioctl(ttyfd,TCSETX,&rctsx); } #else debug(F100,"tthflow ATTSV DTRXOFF not defined","",0); x = -1; #endif /* DTRXOFF */ } } #endif /* CK_SCOUNIX */ #else /* not System V... */ #ifdef CK_DTRCTS #ifdef LDODTR #ifdef LDOCTS #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ x = LDODTR | LDOCTS; /* Found only on UTEK? */ if (flow == FLO_DTRT && status) { /* Use hardware flow control */ if (lmodef) { x = ioctl(ttyfd,TIOCLBIS,&x); if (x < 0) { debug(F100,"hardflow TIOCLBIS error","",0); } else { lmodef++; debug(F100,"hardflow TIOCLBIS ok","",0); } } } else { if (lmodef) { x = ioctl(ttyfd,TIOCLBIC,&x); if (x < 0) { debug(F100,"hardflow TIOCLBIC error","",0); } else { lmodef++; debug(F100,"hardflow TIOCLBIC ok","",0); } } } #endif /* LDODTR */ #endif /* LDOCTS */ #endif /* CK_DTRCTS */ #endif /* ATTSV */ #endif /* AIXRS */ #endif /* SUNOS4 */ #endif /* QNX */ #endif /* POSIX_CRTSCTS */ #endif /* SUNOS41 */ #else /* OXOS */ struct termios temp; /* Olivetti X/OS ... */ #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ x = ioctl(ttyfd,TCGETS,&temp); if (x == 0) { temp.c_cflag &= ~(CRTSCTS|CDTRCTS|CBRKFLOW|CDTRDSR|CRTSDSR); if (status) { switch (flow) { case FLO_RTSC: temp.c_cflag |= CRTSCTS; /* RTS/CTS (hard) */ break; case FLO_DTRT: temp.c_cflag |= CDTRCTS; /* DTR/CTS (hard) */ break; } } x = ioctl(ttyfd,TCSETS,&temp); } #endif /* OXOS */ return(x); #endif /* Plan9 */ } /* T T P K T -- Condition the communication line for packets */ /* or for modem dialing */ /* If called with speed > -1, also set the speed. Returns 0 on success, -1 on failure. NOTE: the "xflow" parameter is supposed to be the currently selected type of flow control, but for historical reasons, this parameter is also used to indicate that we are dialing. Therefore, when the true flow control setting is needed, we access the external variable "flow", rather than trusting our "xflow" argument. */ int #ifdef CK_ANSIC ttpkt(long speed, int xflow, int parity) #else ttpkt(speed,xflow,parity) long speed; int xflow, parity; #endif /* CK_ANSIC */ /* ttpkt */ { #ifndef NOLOCAL int s2; int s = -1; #endif /* NOLOCAL */ int x; extern int flow; /* REAL flow-control setting */ if (ttyfd < 0) return(-1); /* Not open. */ debug(F101,"ttpkt parity","",parity); debug(F101,"ttpkt xflow","",xflow); debug(F101,"ttpkt speed","",(int) speed); ttprty = parity; /* Let other tt functions see these. */ ttspeed = speed; /* Make global copy for this module */ ttpmsk = ttprty ? 0177 : 0377; /* Parity stripping mask */ #ifdef PARSENSE needpchk = ttprty ? 0 : 1; /* Parity check needed? */ #else needpchk = 0; #endif /* PARSENSE */ debug(F101,"ttpkt ttpmsk","",ttpmsk); debug(F101,"ttpkt netconn","",netconn); #ifdef NETCONN /* No mode-changing for telnet */ if (netconn) { #ifdef TCPSOCKET #ifdef TCP_NODELAY if (ttnet == NET_TCPB) { /* But turn off Nagle */ extern int tcp_nodelay; nodelay_sav = tcp_nodelay; no_delay(ttyfd,1); } #endif /* TCP_NODELAY */ #ifdef TN_COMPORT if (istncomport()) { int rc = -1; if (tvtflg == 0 && speed == ttspeed && flow == ttflow /* && ttcarr == curcarr */ ) { debug(F100,"ttpkt modes already set, skipping...","",0); return(0); /* Already been called. */ } if (flow != ttflow) { if ((rc = tnsetflow(flow)) < 0) return(rc); ttflow = flow; } if (speed != ttspeed) { if (speed <= 0) speed = tnc_get_baud(); else if ((rc = tnc_set_baud(speed)) < 0) return(rc); ttspeed = speed; } tnc_set_datasize(8); tnc_set_stopsize(stopbits); #ifdef HWPARITY if (hwparity) { switch (hwparity) { case 'e': /* Even */ debug(F100,"ttres 8 bits + even parity","",0); tnc_set_parity(3); break; case 'o': /* Odd */ debug(F100,"ttres 8 bits + odd parity","",0); tnc_set_parity(2); break; case 'm': /* Mark */ debug(F100,"ttres 8 bits + invalid parity: mark","",0); tnc_set_parity(4); break; case 's': /* Space */ debug(F100,"ttres 8 bits + invalid parity: space","",0); tnc_set_parity(5); break; } } else #endif /* HWPARITY */ { tnc_set_parity(1); /* None */ } tvtflg = 0; return(0); } #endif /* TN_COMPORT */ #endif /* TCPSOCKET */ tvtflg = 0; return(0); } #endif /* NETCONN */ #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ #ifndef Plan9 if (ttfdflg && !isatty(ttyfd)) return(0); #endif /* Plan9 */ #ifdef COHERENT #define SVORPOSIX #endif /* COHERENT */ #ifndef SVORPOSIX /* Berkeley, V7, etc. */ #ifdef LPASS8 /* For some reason, with BSD terminal drivers, you can't set FLOW to XON/XOFF after having previously set it to NONE without closing and reopening the device. Unless there's something I overlooked below... */ if (ttflow == FLO_NONE && flow == FLO_XONX && xlocal == 0) { debug(F101,"ttpkt executing horrible flow kludge","",0); ttclos(0); /* Close it */ x = 0; ttopen(ttnmsv,&x,ttmdm,0); /* Open it again */ } #endif /* LPASS8 */ #endif /* SVORPOSIX */ #ifdef COHERENT /* This must be vestigial since we */ #undef SVORPOSIX /* reverse it a few lines below... */ #endif /* COHERENT */ if (xflow != FLO_DIAL && xflow != FLO_DIAX) ttflow = xflow; /* Now make this available too. */ #ifndef NOLOCAL if (xlocal) { s2 = (int) (speed / 10L); /* Convert bps to cps */ debug(F101,"ttpkt calling ttsspd","",s2); s = ttsspd(s2); /* Check and set the speed */ debug(F101,"ttpkt ttsspd result","",s); carrctl(&ttraw, xflow != FLO_DIAL /* Carrier control */ && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0))); tvtflg = 0; /* So ttvt() will work next time */ } #endif /* NOLOCAL */ #ifdef COHERENT #define SVORPOSIX #endif /* COHERENT */ #ifndef SVORPOSIX /* BSD section */ if (flow == FLO_RTSC || /* Hardware flow control */ flow == FLO_DTRC || flow == FLO_DTRT) { tthflow(flow, 1, &ttraw); debug(F100,"ttpkt hard flow, TANDEM off, RAW on","",0); ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */ ttraw.sg_flags |= RAW; /* Enter raw mode */ } else if (flow == FLO_NONE) { /* No flow control */ debug(F100,"ttpkt no flow, TANDEM off, RAW on","",0); ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */ tthflow(flow, 0, &ttraw); /* Turn off any hardware f/c too */ ttraw.sg_flags |= RAW; /* Enter raw mode */ } else if (flow == FLO_KEEP) { /* Keep device's original setting */ debug(F100,"ttpkt keeping original TANDEM","",0); ttraw.sg_flags &= ~TANDEM; ttraw.sg_flags |= (ttold.sg_flags & TANDEM); /* NOTE: We should also handle hardware flow control here! */ } /* SET FLOW XON/XOFF is in effect, or SET FLOW KEEP resulted in Xon/Xoff */ if ((flow == FLO_XONX) || (ttraw.sg_flags & TANDEM)) { debug(F100,"ttpkt turning on TANDEM","",0); ttraw.sg_flags |= TANDEM; /* So ask for it. */ #ifdef LPASS8 /* Can pass 8-bit data through? */ /* If the LPASS8 local mode is available, then flow control can always */ /* be used, even if parity is none and we are transferring 8-bit data. */ /* But we only need to do all this if Xon/Xoff is requested. */ /* BUT... this tends not to work through IP or LAT connections, terminal */ /* servers, telnet, rlogin, etc, so it is currently disabled. */ x = LPASS8; /* If LPASS8 defined, then */ debug(F100,"ttpkt executing LPASS8 code","",0); if (lmodef) { /* TIOCLBIS must be too. */ x = ioctl(ttyfd,TIOCLBIS,&x); /* Try to set LPASS8. */ if (x < 0) { debug(F100,"ttpkt TIOCLBIS error","",0); } else { lmodef++; debug(F100,"ttpkt TIOCLBIS ok","",0); } } /* But if we use LPASS8 mode, we must explicitly turn off terminal interrupts of all kinds. */ #ifdef TIOCGETC /* Not rawmode, */ if (tcharf && (xlocal == 0)) { /* must turn off */ tchnoi.t_intrc = -1; /* interrupt character */ tchnoi.t_quitc = -1; /* and quit character. */ tchnoi.t_startc = 17; /* Make sure xon */ tchnoi.t_stopc = 19; /* and xoff not ignored. */ #ifndef NOBRKC tchnoi.t_eofc = -1; /* eof character. */ tchnoi.t_brkc = -1; /* brk character. */ #endif /* NOBRKC */ if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) { debug(F100,"ttpkt TIOCSETC failed","",0); } else { tcharf = 1; debug(F100,"ttpkt TIOCSETC ok","",0); } #ifdef COMMENT /* only for paranoid debugging */ if (tcharf) { struct tchars foo; char tchbuf[100]; ioctl(0,TIOCGETC,&foo); sprintf(tchbuf, "intr=%d,quit=%d, start=%d, stop=%d, eof=%d, brk=%d", foo.t_intrc, foo.t_quitc, foo.t_startc, foo.t_stopc, foo.t_eofc, foo.t_brkc); debug(F110,"ttpkt chars",tchbuf,0); } #endif /* COMMENT */ } ttraw.sg_flags |= CBREAK; /* Needed for unknown reason */ #endif /* TIOCGETC */ /* Prevent suspend during packet mode */ #ifdef TIOCGLTC /* Not rawmode, */ if (ltcharf && (xlocal == 0)) { /* must turn off */ ltchnoi.t_suspc = -1; /* suspend character */ ltchnoi.t_dsuspc = -1; /* and delayed suspend character */ if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) { debug(F100,"ttpkt TIOCSLTC failed","",0); } else { ltcharf = 1; debug(F100,"ttpkt TIOCSLTC ok","",0); } } #endif /* TIOCGLTC */ #else /* LPASS8 not defined */ /* Previously, BSD-based implementations always */ /* used rawmode for packets. Now, we use rawmode only if parity is NONE. */ /* This allows the flow control requested above to actually work, but only */ /* if the user asks for parity (which also means they get 8th-bit quoting). */ if (parity) { /* If parity, */ ttraw.sg_flags &= ~RAW; /* use cooked mode */ #ifdef COMMENT /* WHY??? */ if (xlocal) #endif /* COMMENT */ ttraw.sg_flags |= CBREAK; debug(F101,"ttpkt cooked, cbreak, parity","",parity); #ifdef TIOCGETC /* Not rawmode, */ if (tcharf && (xlocal == 0)) { /* must turn off */ tchnoi.t_intrc = -1; /* interrupt character */ tchnoi.t_quitc = -1; /* and quit character. */ tchnoi.t_startc = 17; /* Make sure xon */ tchnoi.t_stopc = 19; /* and xoff not ignored. */ #ifndef NOBRKC tchnoi.t_eofc = -1; /* eof character. */ tchnoi.t_brkc = -1; /* brk character. */ #endif /* NOBRKC */ if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) { debug(F100,"ttpkt TIOCSETC failed","",0); } else { tcharf = 1; debug(F100,"ttpkt TIOCSETC ok","",0); } } #endif /* TIOCGETC */ #ifdef TIOCGLTC /* Not rawmode, */ /* Prevent suspend during packet mode */ if (ltcharf && (xlocal == 0)) { /* must turn off */ ltchnoi.t_suspc = -1; /* suspend character */ ltchnoi.t_dsuspc = -1; /* and delayed suspend character */ if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) { debug(F100,"ttpkt TIOCSLTC failed","",0); } else { ltcharf = 1; debug(F100,"ttpkt TIOCSLTC ok","",0); } } #endif /* TIOCGLTC */ } else { /* If no parity, */ ttraw.sg_flags |= RAW; /* must use 8-bit raw mode. */ debug(F101,"ttpkt setting rawmode, parity","",parity); } #endif /* LPASS8 */ } /* End of Xon/Xoff section */ /* Don't echo, don't map CR to CRLF on output, don't fool with case */ #ifdef LCASE ttraw.sg_flags &= ~(ECHO|CRMOD|LCASE); #else ttraw.sg_flags &= ~(ECHO|CRMOD); #endif /* LCASE */ #ifdef TOWER1 ttraw.sg_flags &= ~ANYP; /* Must set this on old Towers */ #endif /* TOWER1 */ #ifdef BELLV10 if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0) /* Set the new modes. */ return(-1); #else errno = 0; if (stty(ttyfd,&ttraw) < 0) { /* Set the new modes. */ debug(F101,"ttpkt stty failed","",errno); return(-1); } #endif /* BELLV10 */ debug(F100,"ttpkt stty ok","",0); #ifdef sony_news x = xlocal ? km_ext : km_con; /* Put line in ASCII mode. */ if (x != -1) { /* Make sure we know original modes. */ x &= ~KM_TTYPE; x |= KM_ASCII; if (ioctl(ttyfd,TIOCKSET, &x) < 0) { perror("ttpkt can't set ASCII mode"); debug(F101,"ttpkt error setting ASCII mode","",x); return(-1); } } debug(F100,"ttpkt set ASCII mode ok","",0); #endif /* sony_news */ if (xlocal == 0) { /* Turn this off so we can read */ signal(SIGINT,SIG_IGN); /* Ctrl-C chars typed at console */ sigint_ign = 1; } tvtflg = 0; /* So ttvt() will work next time */ debug(F100,"ttpkt success","",0); return(0); #endif /* Not ATTSV or POSIX */ /* AT&T UNIX and POSIX */ #ifdef COHERENT #define SVORPOSIX #endif /* COHERENT */ #ifdef SVORPOSIX if (flow == FLO_XONX) { /* Xon/Xoff */ ttraw.c_iflag |= (IXON|IXOFF); tthflow(flow, 0, &ttraw); } else if (flow == FLO_NONE) { /* None */ /* NOTE: We should also turn off hardware flow control here! */ ttraw.c_iflag &= ~(IXON|IXOFF); tthflow(flow, 0, &ttraw); } else if (flow == FLO_KEEP) { /* Keep */ ttraw.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */ ttraw.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */ /* NOTE: We should also handle hardware flow control here! */ #ifdef POSIX_CRTSCTS /* In Linux case, we do this, which is unlikely to be portable */ ttraw.c_cflag &= ~CRTSCTS; /* Turn off RTS/CTS flag */ ttraw.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */ #endif /* POSIX_CRTSCTS */ } else if (flow == FLO_RTSC || /* Hardware */ flow == FLO_DTRC || flow == FLO_DTRT) { ttraw.c_iflag &= ~(IXON|IXOFF); /* (190) */ tthflow(flow, 1, &ttraw); } ttraw.c_lflag &= ~(ICANON|ECHO); ttraw.c_lflag &= ~ISIG; /* Do NOT check for interrupt chars */ #ifndef OXOS #ifdef QNX if (flow != FLO_RTSC && flow != FLO_DTRC && flow != FLO_DTRT) #endif /* QNX */ #ifndef COHERENT ttraw.c_lflag &= ~IEXTEN; /* Turn off ^O/^V processing */ #endif /* COHERENT */ #else /* OXOS */ ttraw.c_cc[VDISCARD] = ttraw.c_cc[VLNEXT] = CDISABLE; #endif /* OXOS */ ttraw.c_lflag |= NOFLSH; /* Don't flush */ ttraw.c_iflag |= IGNPAR; /* Ignore parity errors */ #ifdef ATTSV #ifdef BSD44 ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY); #else ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY); #endif /* BSD44 */ #else /* POSIX */ ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP); #endif /* ATTSV */ ttraw.c_oflag &= ~OPOST; ttraw.c_cflag &= ~(CSIZE); ttraw.c_cflag |= (CS8|CREAD|HUPCL); #ifdef CSTOPB if (xlocal) { if (stopbits == 2) { ttraw.c_cflag |= CSTOPB; /* 2 stop bits */ debug(F100,"ttpkt 2 stopbits","",0); } else if (stopbits == 1) { ttraw.c_cflag &= ~(CSTOPB); /* 1 stop bit */ debug(F100,"ttpkt 1 stopbit","",0); } } #endif /* CSTOPB */ #ifdef HWPARITY if (hwparity && xlocal) { /* Hardware parity */ ttraw.c_cflag |= PARENB; /* Enable parity */ #ifdef COMMENT /* Uncomment this only if needed -- I don't think it is */ ttraw.c_cflag &= ~(CSIZE); /* Clear out character-size mask */ ttraw.c_cflag |= CS8; /* And set it to 8 */ #endif /* COMMENT */ #ifdef IGNPAR ttraw.c_iflag |= IGNPAR; /* Don't discard incoming bytes */ debug(F100,"ttpkt IGNPAR","",0); /* that have parity errors */ #endif /* IGNPAR */ switch (hwparity) { case 'e': /* Even */ ttraw.c_cflag &= ~(PARODD); debug(F100,"ttpkt 8 bits + even parity","",0); break; case 'o': /* Odd */ ttraw.c_cflag |= PARODD; debug(F100,"ttpkt 8 bits + odd parity","",0); break; case 'm': /* Mark */ case 's': /* Space */ /* PAREXT is mentioned in SVID but the details are not given. */ /* PAREXT is not included in POSIX ISO/IEC 9945-1. */ debug(F100,"ttpkt 8 bits + invalid parity","",0); break; } } else { /* We handle parity ourselves */ #endif /* HWPARITY */ ttraw.c_cflag &= ~(PARENB); /* Don't enable parity */ #ifdef HWPARITY } #endif /* HWPARITY */ #ifdef IX370 ttraw.c_cc[4] = 48; /* So Series/1 doesn't interrupt on every char */ ttraw.c_cc[5] = 1; #else #ifndef VEOF /* for DGUX this is VEOF, not VMIN */ ttraw.c_cc[4] = 1; /* [VMIN] return max of this many characters or */ #else #ifndef OXOS #ifdef VMIN ttraw.c_cc[VMIN] = 1; #endif /* VMIN */ #else /* OXOS */ ttraw.c_min = 1; #endif /* OXOS */ #endif /* VEOF */ #ifndef VEOL /* for DGUX this is VEOL, not VTIME */ ttraw.c_cc[5] = 0; /* [VTIME] when this many secs/10 expire w/no input */ #else #ifndef OXOS #ifdef VTIME ttraw.c_cc[VTIME] = 0; #endif /* VTIME */ #else /* OXOS */ ttraw.c_time = 0; #endif /* OXOS */ #endif /* VEOL */ #endif /* IX370 */ #ifdef VINTR /* Turn off interrupt character */ if (xlocal == 0) /* so ^C^C can break us out of */ ttraw.c_cc[VINTR] = 0; /* packet mode. */ #endif /* VINTR */ #ifdef Plan9 if (p9ttyparity('n') < 0) return -1; #else #ifdef BSD44ORPOSIX errno = 0; #ifdef BEOSORBEBOX ttraw.c_cc[VMIN] = 0; /* DR7 can only poll. */ #endif /* BEOSORBEBOX */ #define TESTING234 #ifdef TESTING234 if (1) { debug(F100,"ttpkt TESTING234 rawmode","",0); /* iflags */ ttraw.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL); ttraw.c_iflag &= ~(INPCK|IGNPAR|IXON|IXOFF); ttraw.c_iflag |= IGNBRK; #ifdef IMAXBEL ttraw.c_iflag &= ~IMAXBEL; #endif /* IMAXBEL */ #ifdef IXANY ttraw.c_iflag &= ~IXANY; #endif /* IXANY */ #ifdef IUCLC ttraw.c_iflag &= ~IUCLC; #endif /* IUCLC */ /* oflags */ ttraw.c_oflag &= ~OPOST; #ifdef OXTABS ttraw.c_oflag &= ~OXTABS; #endif /* OXTABS */ #ifdef ONOCR ttraw.c_oflag &= ~ONOCR; #endif /* ONOCR */ #ifdef ONLRET ttraw.c_oflag &= ~ONLRET; #endif /* ONLRET */ #ifdef ONLCR ttraw.c_oflag &= ~ONLCR; #endif /* ONLCR */ /* lflags */ ttraw.c_lflag &= ~ECHO; #ifdef ECHOE ttraw.c_lflag &= ~ECHOE; #endif /* ECHOE */ #ifdef ECHONL ttraw.c_lflag &= ~ECHONL; #endif /* ECHONL */ #ifdef ECHOPRT ttraw.c_lflag &= ~ECHOPRT; #endif /* ECHOPRT */ #ifdef ECHOKE ttraw.c_lflag &= ~ECHOKE; #endif /* ECHOKE */ #ifdef ECHOCTL ttraw.c_lflag &= ~ECHOCTL; #endif /* ECHOCTL */ #ifdef ALTWERASE ttraw.c_lflag &= ~ALTWERASE; #endif /* ALTWERASE */ #ifdef EXTPROC ttraw.c_lflag &= ~EXTPROC; #endif /* EXTPROC */ ttraw.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN); #ifdef NOKERNINFO ttraw.c_lflag |= NOKERNINFO; #endif /* NOKERNINFO */ /* ttraw.c_lflag |= NOFLSH; */ ttraw.c_lflag &= ~NOFLSH; /* cflags */ ttraw.c_cflag &= ~(CSIZE|PARENB|PARODD); ttraw.c_cflag |= CS8|CREAD; #ifdef VMIN ttraw.c_cc[VMIN] = 1; /* Supposedly needed for AIX */ #endif /* VMIN */ } #endif /* TESTING234 */ debug(F100,"ttpkt calling tcsetattr(TCSETAW)","",0); x = tcsetattr(ttyfd,TCSADRAIN,&ttraw); debug(F101,"ttpkt BSD44ORPOSIX tcsetattr","",x); if (x < 0) { debug(F101,"ttpkt BSD44ORPOSIX tcsetattr errno","",errno); return(-1); } #else /* BSD44ORPOSIX */ x = ioctl(ttyfd,TCSETAW,&ttraw); debug(F101,"ttpkt ATTSV ioctl TCSETAW","",x); if (x < 0) { /* set new modes . */ debug(F101,"ttpkt ATTSV ioctl TCSETAW errno","",errno); return(-1); } #endif /* BSD44ORPOSIX */ #endif /* Plan9 */ tvtflg = 0; debug(F100,"ttpkt ok","",0); return(0); #endif /* ATTSV */ #ifdef COHERENT #undef SVORPOSIX #endif /* COHERENT */ } /* T T S E T F L O W -- Set flow control immediately. */ #ifdef COHERENT #define SVORPOSIX #endif /* COHERENT */ int #ifdef CK_ANSIC ttsetflow( int flow ) #else ttsetflow(flow) int flow; #endif /* CK_ANSIC */ { if (ttyfd < 0) /* A channel must be open */ return(-1); debug(F101,"ttsetflow flow","",flow); #ifdef TN_COMPORT if (netconn && istncomport()) { debug(F101,"ttsetflow net modem","",ttmdm); return(tnsetflow(flow)); } #endif /* TN_COMPORT */ #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ #ifdef COMMENT /* This seems to hurt... */ if (flow == FLO_KEEP) return(0); #endif /* COMMENT */ if (flow == FLO_RTSC || /* Hardware flow control... */ flow == FLO_DTRC || flow == FLO_DTRT) { tthflow(flow, 1, &ttraw); #ifndef SVORPOSIX ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */ #else ttraw.c_iflag &= ~(IXON|IXOFF); #endif /* SVORPOSIX */ } else if (flow == FLO_XONX) { /* Xon/Xoff... */ #ifndef SVORPOSIX ttraw.sg_flags |= TANDEM; #else ttraw.c_iflag |= (IXON|IXOFF); #endif /* SVORPOSIX */ tthflow(FLO_RTSC, 0, &ttraw); /* Turn off hardware flow control */ } else if (flow == FLO_NONE) { /* No flow control */ #ifndef SVORPOSIX ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */ #else ttraw.c_iflag &= ~(IXON|IXOFF); #endif /* SVORPOSIX */ tthflow(FLO_RTSC, 0, &ttraw); /* Turn off any hardware f/c too */ } /* Set the new modes... */ #ifndef SVORPOSIX /* BSD and friends */ #ifdef BELLV10 if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0) return(-1); #else #ifndef MINIX2 if (stty(ttyfd,&ttraw) < 0) return(-1); #endif /* MINIX2 */ #endif /* BELLV10 */ #else #ifdef BSD44ORPOSIX /* POSIX */ if (tcsetattr(ttyfd,TCSADRAIN,&ttraw) < 0) return(-1); #else /* System V */ if (ioctl(ttyfd,TCSETAW,&ttraw) < 0) return(-1); #endif /* BSD44ORPOSIX */ #endif /* SVORPOSIX */ return(0); } #ifdef COHERENT #undef SVORPOSIX #endif /* COHERENT */ /* T T V T -- Condition communication device for use as virtual terminal. */ int #ifdef CK_ANSIC ttvt(long speed, int flow) #else ttvt(speed,flow) long speed; int flow; #endif /* CK_ANSIC */ /* ttvt */ { int s, s2, x; debug(F101,"ttvt ttyfd","",ttyfd); debug(F101,"ttvt tvtflg","",tvtflg); debug(F111,"ttvt speed",ckitoa(ttspeed),speed); debug(F111,"ttvt flow",ckitoa(ttflow),flow); debug(F111,"ttvt curcarr",ckitoa(ttcarr),curcarr); /* Note: NetBSD and maybe other BSD44s have cfmakeraw() */ /* Maybe it would be simpler to use it... */ ttpmsk = 0xff; #ifdef NOLOCAL return(conbin((char)escchr)); #else if (ttyfd < 0) { /* Not open. */ if (ttchk() < 0) return(-1); else /* But maybe something buffered. */ return(0); } #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ #ifdef NETCONN if (netconn) { #ifdef TCPSOCKET #ifdef TCP_NODELAY { extern int tcp_nodelay; if (ttnet == NET_TCPB) { if (nodelay_sav > -1) { no_delay(ttyfd,nodelay_sav); nodelay_sav = -1; } } } #endif /* TCP_NODELAY */ #ifdef TN_COMPORT if (istncomport()) { int rc = -1; if (tvtflg != 0 && speed == ttspeed && flow == ttflow /* && ttcarr == curcarr */ ) { debug(F100,"ttvt modes already set, skipping...","",0); return(0); /* Already been called. */ } if (flow != ttflow) { if ((rc = tnsetflow(flow)) < 0) return(rc); ttflow = flow; } if (speed != ttspeed) { if (speed <= 0) speed = tnc_get_baud(); else if ((rc = tnc_set_baud(speed)) < 0) return(rc); ttspeed = speed; } tnc_set_datasize(8); tnc_set_stopsize(stopbits); #ifdef HWPARITY if (hwparity) { switch (hwparity) { case 'e': /* Even */ debug(F100,"ttres 8 bits + even parity","",0); tnc_set_parity(3); break; case 'o': /* Odd */ debug(F100,"ttres 8 bits + odd parity","",0); tnc_set_parity(2); break; case 'm': /* Mark */ debug(F100,"ttres 8 bits + invalid parity: mark","",0); tnc_set_parity(4); break; case 's': /* Space */ debug(F100,"ttres 8 bits + invalid parity: space","",0); tnc_set_parity(5); break; } } else #endif /* HWPARITY */ { tnc_set_parity(1); /* None */ } tvtflg = 1; return(0); } #endif /* TN_COMPORT */ #endif /* TCPSOCKET */ tvtflg = 1; /* Network connections... */ debug(F100,"ttvt network connection, skipping...","",0); return(0); /* ... require no special setup */ } #endif /* NETCONN */ if (tvtflg != 0 && speed == ttspeed && flow == ttflow /* && ttcarr == curcarr */ ) { debug(F100,"ttvt modes already set, skipping...","",0); return(0); /* Already been called. */ } if (ttfdflg #ifndef Plan9 && !isatty(ttyfd) #endif /* Plan9 */ ) { debug(F100,"ttvt using external fd, skipping...","",0); return(0); } debug(F100,"ttvt setting modes...","",0); if (xlocal) { /* For external lines... */ s2 = (int) (speed / 10L); s = ttsspd(s2); /* Check/set the speed */ carrctl(&tttvt, flow != FLO_DIAL /* Do carrier control */ && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0))); } else s = s2 = -1; #ifdef COHERENT #define SVORPOSIX #endif /* COHERENT */ #ifndef SVORPOSIX /* Berkeley, V7, etc */ if (flow == FLO_RTSC || /* Hardware flow control */ flow == FLO_DTRC || flow == FLO_DTRT) { tthflow(flow, 1, &tttvt); debug(F100,"ttvt hard flow, TANDEM off","",0); tttvt.sg_flags &= ~TANDEM; /* Turn off software flow control */ } else if (flow == FLO_XONX) { /* Xon/Xoff flow control */ debug(F100,"ttvt TANDEM on","",0); tttvt.sg_flags |= TANDEM; /* Ask for it. */ tthflow(flow, 0, &tttvt); /* Turn off hardware f/c */ } else if (flow == FLO_NONE) { debug(F100,"ttvt no flow, TANDEM off, RAW on","",0); tttvt.sg_flags &= ~TANDEM; /* Turn off software flow control */ tthflow(flow, 0, &tttvt); /* Turn off any hardware f/c too */ tttvt.sg_flags |= RAW; /* Enter raw mode */ } else if (flow == FLO_KEEP) { /* Keep device's original setting */ debug(F100,"ttvt keeping original TANDEM","",0); tttvt.sg_flags &= ~TANDEM; tttvt.sg_flags |= (ttold.sg_flags & TANDEM); /* NOTE: We should also handle hardware flow control here! */ } tttvt.sg_flags |= RAW; /* Raw mode in all cases */ #ifdef TOWER1 tttvt.sg_flags &= ~(ECHO|ANYP); /* No echo or parity */ #else tttvt.sg_flags &= ~ECHO; /* No echo */ #endif /* TOWER1 */ #ifdef BELLV10 if (ioctl(ttyfd,TIOCSETP,&tttvt) < 0) /* Set the new modes */ return(-1); #else if (stty(ttyfd,&tttvt) < 0) /* Set the new modes */ return(-1); #endif /* BELLV10 */ #else /* It is ATTSV or POSIX */ if (flow == FLO_XONX) { /* Software flow control */ tttvt.c_iflag |= (IXON|IXOFF); /* On if requested. */ tthflow(flow, 0, &tttvt); /* Turn off hardware f/c */ debug(F100,"ttvt SVORPOSIX flow XON/XOFF","",0); } else if (flow == FLO_NONE) { /* NONE */ tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff */ tthflow(flow, 0, &tttvt); /* Turn off hardware f/c */ debug(F100,"ttvt SVORPOSIX flow NONE","",0); } else if (flow == FLO_KEEP) { tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */ tttvt.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */ #ifdef POSIX_CRTSCTS tttvt.c_cflag &= ~CRTSCTS; /* Turn off RTS/CTS flag */ tttvt.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */ #endif /* POSIX_CRTSCTS */ debug(F100,"ttvt SVORPOSIX flow KEEP","",0); } else if (flow == FLO_RTSC || /* Hardware flow control */ flow == FLO_DTRC || flow == FLO_DTRT) { tttvt.c_iflag &= ~(IXON|IXOFF); /* (196) */ tthflow(flow, 1, &tttvt); debug(F100,"ttvt SVORPOSIX flow HARD","",0); } #ifndef OXOS #ifdef COHERENT tttvt.c_lflag &= ~(ISIG|ICANON|ECHO); #else tttvt.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN); #endif /* COHERENT */ #ifdef QNX /* Needed for hwfc */ if (flow == FLO_RTSC || flow == FLO_DTRC || flow == FLO_DTRT) tttvt.c_lflag |= IEXTEN; #endif /* QNX */ #else /* OXOS */ tttvt.c_lflag &= ~(ISIG|ICANON|ECHO); tttvt.c_cc[VDISCARD] = tttvt.c_cc[VLNEXT] = CDISABLE; #endif /* OXOS */ tttvt.c_iflag |= (IGNBRK|IGNPAR); /* Stop bits */ #ifdef CSTOPB if (xlocal) { if (stopbits == 2) { tttvt.c_cflag |= CSTOPB; /* 2 stop bits */ debug(F100,"ttvt 2 stopbits","",0); } else if (stopbits == 1) { tttvt.c_cflag &= ~(CSTOPB); /* 1 stop bit */ debug(F100,"ttvt 1 stopbit","",0); } } #endif /* CSTOPB */ /* Parity */ #ifdef HWPARITY if (hwparity && xlocal) { /* Hardware parity */ #ifdef COMMENT /* Uncomment this only if needed -- I don't think it is */ ttraw.c_cflag &= ~(CSIZE); /* Clear out character-size mask */ ttraw.c_cflag |= CS8; /* And set it to 8 */ #endif /* COMMENT */ #ifdef IGNPAR debug(F101,"ttvt hwparity IGNPAR","",IGNPAR); tttvt.c_iflag |= IGNPAR; /* Don't discard incoming bytes */ #endif /* IGNPAR */ tttvt.c_cflag |= PARENB; /* Enable parity */ switch (hwparity) { case 'e': /* Even */ tttvt.c_cflag &= ~(PARODD); debug(F100,"ttvt 8 bits + even parity","",0); break; case 'o': /* Odd */ tttvt.c_cflag |= PARODD; debug(F100,"ttvt 8 bits + odd parity","",0); break; case 'm': /* Mark */ case 's': /* Space */ /* PAREXT is mentioned in SVID but the details are not given. */ /* PAREXT is not included in POSIX ISO/IEC 9945-1. */ debug(F100,"ttvt 8 bits + invalid parity","",0); break; } } else { /* We handle parity ourselves */ #endif /* HWPARITY */ tttvt.c_cflag &= ~(PARENB); /* Don't enable parity */ #ifdef HWPARITY } #endif /* HWPARITY */ #ifdef ATTSV #ifdef BSD44 /* Things not to do... */ tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY); #else tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY); #endif /* BSD44 */ #else /* POSIX */ tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP); #endif /* ATTSV */ tttvt.c_cflag &= ~(CSIZE); /* Zero out the char size field */ tttvt.c_cflag |= (CS8|CREAD|HUPCL); /* Char size 8, enable receiver, hup */ tttvt.c_oflag &= ~OPOST; /* Don't postprocess output */ #ifndef VEOF /* DGUX termio has VEOF at entry 4, see comment above */ tttvt.c_cc[4] = 1; #else #ifndef OXOS #ifdef VMIN tttvt.c_cc[VMIN] = 1; #endif /* VMIN */ #else /* OXOS */ tttvt.c_min = 1; #endif /* OXOS */ #endif /* VEOF */ #ifndef VEOL /* DGUX termio has VEOL at entry 5, see comment above */ tttvt.c_cc[5] = 0; #else #ifndef OXOS #ifdef VTIME tttvt.c_cc[VTIME] = 0; #endif /* VTIME */ #else /* OXOS */ tttvt.c_time = 0; #endif /* OXOS */ #endif /* VEOL */ #ifdef Plan9 if (p9ttyparity('n') < 0) return -1; #else #ifdef BSD44ORPOSIX errno = 0; #ifdef BEOSORBEBOX tttvt.c_cc[VMIN] = 0; /* DR7 can only poll. */ #endif /* BEOSORBEBOX */ #ifdef MACOSHISPEED if (speed >= MACOSHISPEED_START) { /* Set baudrate to standart one so tcsetattr() will not fail */ cfsetospeed(&tttvt,B9600); cfsetispeed(&tttvt,B9600); } #endif /* MACOSHISPEED */ x = tcsetattr(ttyfd,TCSADRAIN,&tttvt); debug(F101,"ttvt BSD44ORPOSIX tcsetattr","",x); if (x < 0) { debug(F101,"ttvt BSD44ORPOSIX tcsetattr errno","",errno); return(-1); } #ifdef MACOSHISPEED if (speed >= MACOSHISPEED_START) { x = ioctl(ttyfd, IOSSIOSPEED, &speed); debug(F101,"ttvt IOSSIOSPEED","",x); if (x < 0) return(-1); } #endif /* MACOSHISPEED */ #else /* ATTSV */ x = ioctl(ttyfd,TCSETAW,&tttvt); debug(F101,"ttvt ATTSV ioctl TCSETAW","",x); if (x < 0) { /* set new modes . */ debug(F101,"ttvt ATTSV ioctl TCSETAW errno","",errno); return(-1); } #endif /* BSD44ORPOSIX */ #endif /* Plan9 */ #endif /* ATTSV */ ttspeed = speed; /* Done, remember how we were */ ttflow = flow; /* called, so we can decide how to */ tvtflg = 1; /* respond next time. */ debug(F100,"ttvt ok","",0); return(0); #ifdef COHERENT #undef SVORPOSIX #endif /* COHERENT */ #endif /* NOLOCAL */ } #ifndef NOLOCAL /* Serial speed department . . . */ /* SCO OSR5.0.x might or might not support high speeds. Sometimes they are not defined in the header files but they are supported (e.g. when building with UDK compiler rather than /bin/cc), sometimes vice versa. Even though 5.0.4 was the first release that came with high serial speeds standard, releases back to 5.0.0 could use them if certain patches (or "supplements") were applied to the SIO driver. Plus a lot of SCO installations run third-party drivers. */ #ifdef CK_SCOV5 #ifndef B38400 #define B38400 0000017 #endif /* B38400 */ #ifndef B57600 #define B57600 0000021 #endif /* B57600 */ #ifndef B76800 #define B76800 0000022 #endif /* B76800 */ #ifndef B115200 #define B115200 0000023 #endif /* B115200 */ #ifndef B230400 #define B230400 0000024 #endif /* B230400 */ #ifndef B460800 #define B460800 0000025 #endif /* B460800 */ #ifndef B921600 #define B921600 0000026 #endif /* B921600 */ #endif /* CK_SCOV5 */ /* Plan 9's native speed setting interface lets you set anything you like, but will fail if the hardware doesn't like it, so we allow all the common speeds. */ #ifdef Plan9 #ifndef B50 #define B50 50 #endif /* B50 */ #ifndef B75 #define B75 75 #endif /* B75 */ #ifndef B110 #define B110 110 #endif /* B110 */ #ifndef B134 #define B134 134 #endif /* B134 */ #ifndef B200 #define B200 200 #endif /* B200 */ #ifndef B300 #define B300 300 #endif /* B300 */ #ifndef B1200 #define B1200 1200 #endif /* B1200 */ #ifndef B1800 #define B1800 1800 #endif /* B1800 */ #ifndef B2400 #define B2400 2400 #endif /* B2400 */ #ifndef B4800 #define B4800 4800 #endif /* B4800 */ #ifndef B9600 #define B9600 9600 #endif /* B9600 */ #ifndef B14400 #define B14400 14400 #endif /* B14400 */ #ifndef B19200 #define B19200 19200 #endif /* B19200 */ #ifndef B28800 #define B28800 28800 #endif /* B28800 */ #ifndef B38400 #define B38400 38400 #endif /* B38400 */ #ifndef B57600 #define B57600 57600 #endif /* B57600 */ #ifndef B76800 #define B76800 76800 #endif /* B76800 */ #ifndef B115200 #define B115200 115200 #endif /* B115200 */ #ifndef B230400 #define B230400 230400 #endif /* B230400 */ #ifndef B460800 #define B460800 460800 #endif /* B460800 */ #ifndef B921600 #define B921600 921600 #endif /* B921600 */ #endif /* Plan9 */ /* T T S S P D -- Checks and sets transmission rate. */ /* Call with speed in characters (not bits!) per second. */ /* Returns -1 on failure, 0 if it did nothing, 1 if it changed the speed. */ #ifdef USETCSETSPEED /* The tcsetspeed() / tcgetspeed() interface lets you pass any number at all to be used as a speed to be set, rather than forcing a choice from a predefined list. It seems to be peculiar to UnixWare 7. These are the function codes to be passed to tc[gs]etspeed(), but for some reason they don't seem to be picked up from termios.h. */ #ifndef TCS_ALL #define TCS_ALL 0 #endif /* TCS_ALL */ #ifndef TCS_IN #define TCS_IN 1 #endif /* TCS_IN */ #ifndef TCS_OUT #define TCS_OUT 2 #endif /* TCS_OUT */ #endif /* USETCSETSPEED */ int #ifdef CK_ANSIC ttsspd( int cps ) #else ttsspd(cps) int cps; #endif /* CK_ANSIC */ { int x; #ifdef POSIX /* Watch out, speed_t should be unsigned, so don't compare with -1, etc... */ speed_t #else int #endif /* POSIX */ s, s2; int ok = 1; /* Speed check result, assume ok */ #ifdef OLINUXHISPEED unsigned int spd_flags = 0; struct serial_struct serinfo; #endif /* OLINUXHISPEED */ debug(F101,"ttsspd cps","",cps); debug(F101,"ttsspd ttyfd","",ttyfd); debug(F101,"ttsspd xlocal","",xlocal); if (ttyfd < 0 || xlocal == 0) /* Don't set speed on console */ return(0); #ifdef NETCONN if (netconn) { #ifdef TN_COMPORT if (istncomport()) return(tnc_set_baud(cps * 10)); else #endif /* TN_COMPORT */ return(0); } #endif /* NETCONN */ #ifdef NETCMD if (ttpipe) return(0); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(0); #endif /* NETPTY */ if (cps < 0) return(-1); s = s2 = 0; /* NB: s and s2 might be unsigned */ #ifdef USETCSETSPEED s = cps * 10L; x = tcgetattr(ttyfd,&ttcur); /* Get current speed */ debug(F101,"ttsspd tcgetattr","",x); if (x < 0) return(-1); debug(F101,"ttsspd TCSETSPEED speed","",s); errno = 0; if (s == 8880L) { /* 75/1200 split speed requested */ tcsetspeed(TCS_IN, &ttcur, 1200L); tcsetspeed(TCS_OUT, &ttcur, 75L); } else tcsetspeed(TCS_ALL, &ttcur, s); /* Put new speed in structs */ #ifdef DEBUG if (errno & deblog) { debug(F101,"ttsspd TCSETSPEED errno","",errno); } #endif /* DEBUG */ #ifdef COMMENT tcsetspeed(TCS_ALL, &ttraw, s); tcsetspeed(TCS_ALL, &tttvt, s); tcsetspeed(TCS_ALL, &ttold, s); #else if (s == 8880L) { /* 75/1200 split speed requested */ tcsetspeed(TCS_IN, &ttraw, 1200L); tcsetspeed(TCS_OUT, &ttraw, 75L); tcsetspeed(TCS_IN, &tttvt, 1200L); tcsetspeed(TCS_OUT, &tttvt, 75L); tcsetspeed(TCS_IN, &ttold, 1200L); tcsetspeed(TCS_OUT, &ttold, 75L); } else { tcsetspeed(TCS_ALL, &ttraw, s); tcsetspeed(TCS_ALL, &tttvt, s); tcsetspeed(TCS_ALL, &ttold, s); } #endif /* COMMENT */ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); /* Set the speed */ debug(F101,"ttsspd tcsetattr","",x); if (x < 0) { return(-1); } else { return(1); } #else /* Not USETCSETSPEED */ /* First check that the given speed is valid. */ switch (cps) { #ifndef MINIX case 0: s = B0; break; case 5: s = B50; break; case 7: s = B75; break; #endif /* MINIX */ case 11: s = B110; break; #ifndef MINIX case 13: s = B134; break; case 15: s = B150; break; case 20: s = B200; break; #endif /* MINIX */ case 30: s = B300; break; #ifndef MINIX case 60: s = B600; break; #endif /* MINIX */ case 120: s = B1200; break; #ifndef MINIX case 180: s = B1800; break; #endif /* MINIX */ case 240: s = B2400; break; case 480: s = B4800; break; #ifndef MINIX case 888: s = B75; s2 = B1200; break; /* 888 = 75/1200 split speed */ #endif /* MINIX */ #ifdef B7200 case 720: s = B7200; break; #endif /* B7200 */ case 960: s = B9600; break; #ifdef B14400 case 1440: s = B14400; break; #endif /* B14400 */ #ifdef B19200 case 1920: s = B19200; break; #else #ifdef EXTA case 1920: s = EXTA; break; #endif /* EXTA */ #endif /* B19200 */ #ifdef B28800 case 2880: s = B28800; break; #endif /* B28800 */ #ifdef B38400 case 3840: s = B38400; #ifdef OLINUXHISPEED spd_flags = ~ASYNC_SPD_MASK; /* Nonzero, but zero flags */ #endif /* OLINUXHISPEED */ break; #else /* B38400 not defined... */ #ifdef EXTB case 3840: s = EXTB; break; #endif /* EXTB */ #endif /* B38400 */ #ifdef HPUX #ifdef _B57600 case 5760: s = _B57600; break; #endif /* _B57600 */ #ifdef _B115200 case 11520: s = _B115200; break; #endif /* _B115200 */ #else #ifdef OLINUXHISPEED /* This bit from : "Only note to make is maybe this: When the ASYNC_SPD_CUST flags are set then setting the speed to 38400 will set the custom speed (and ttgspd returns 38400), but speeds 57600 and 115200 won't work any more because I didn't want to mess up the speed flags when someone is doing sophisticated stuff like custom speeds..." */ case 5760: s = B38400; spd_flags = ASYNC_SPD_HI; break; case 11520: s = B38400; spd_flags = ASYNC_SPD_VHI; break; #else #ifdef B57600 case 5760: s = B57600; break; #endif /* B57600 */ #ifdef B76800 case 7680: s = B76800; break; #endif /* B76800 */ #ifdef B115200 case 11520: s = B115200; break; #endif /* B115200 */ #endif /* OLINUXHISPEED */ #ifdef B153600 case 15360: s = B153600; break; #endif /* B153600 */ #ifdef B230400 case 23040: s = B230400; break; #endif /* B230400 */ #ifdef B307200 case 30720: s = B307200; break; #endif /* B307200 */ #ifdef B460800 case 46080: s = B460800; break; #endif /* 460800 */ #ifdef B500000 case 50000: s = B500000; break; #endif /* B500000 */ #ifdef B576000 case 57600: s = B576000; break; #endif /* B576000 */ #ifdef B614400 case 61440: s = B614400; break; #endif /* B614400 */ #ifdef B921600 case 92160: s = B921600; break; #endif /* B921600 */ #ifdef B1000000 case 100000: s = B1000000; break; #endif /* B1000000 */ #ifdef B1152000 case 115200: s = B1152000; break; #endif /* B1152000 */ #ifdef B1500000 case 150000: s = B1500000; break; #endif /* B1500000 */ #ifdef B2000000 case 200000: s = B2000000; break; #endif /* B2000000 */ #ifdef B2500000 case 250000: s = B2500000; break; #endif /* B2500000 */ #ifdef B3000000 case 300000: s = B3000000; break; #endif /* B3000000 */ #ifdef B3500000 case 350000: s = B3500000; break; #endif /* B3500000 */ #ifdef B4000000 case 400000: s = B4000000; break; #endif /* B4000000 */ #endif /* HPUX */ default: ok = 0; /* Good speed not found, so not ok */ break; } debug(F101,"ttsspd ok","",ok); debug(F101,"ttsspd s","",s); if (!ok) { debug(F100,"ttsspd fails","",0); return(-1); } else { if (!s2) s2 = s; /* Set input speed */ #ifdef Plan9 if (p9ttsspd(cps) < 0) return(-1); #else #ifdef BSD44ORPOSIX x = tcgetattr(ttyfd,&ttcur); /* Get current speed */ debug(F101,"ttsspd tcgetattr","",x); if (x < 0) return(-1); #ifdef OLINUXHISPEED debug(F101,"ttsspd spd_flags","",spd_flags); if (spd_flags && spd_flags != ASYNC_SPD_CUST) { if (ioctl(ttyfd, TIOCGSERIAL, &serinfo) < 0) { debug(F100,"ttsspd: TIOCGSERIAL failed","",0); return(-1); } else debug(F100,"ttsspd: TIOCGSERIAL ok","",0); serinfo.flags &= ~ASYNC_SPD_MASK; serinfo.flags |= (spd_flags & ASYNC_SPD_MASK); if (ioctl(ttyfd, TIOCSSERIAL, &serinfo) < 0) return(-1); } #endif /* OLINUXHISPEED */ cfsetospeed(&ttcur,s); cfsetispeed(&ttcur,s2); cfsetospeed(&ttraw,s); cfsetispeed(&ttraw,s2); cfsetospeed(&tttvt,s); cfsetispeed(&tttvt,s2); cfsetospeed(&ttold,s); cfsetispeed(&ttold,s2); #ifdef MACOSHISPEED if (s >= MACOSHISPEED_START) { /* Set baudrate to standart one so tcsetattr() will not fail */ cfsetospeed(&ttcur,B9600); cfsetispeed(&ttcur,B9600); } #endif /* MACOSHISPEED */ x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); debug(F101,"ttsspd tcsetattr","",x); if (x < 0) return(-1); #ifdef MACOSHISPEED if (s >= MACOSHISPEED_START) { x = ioctl(ttyfd, IOSSIOSPEED, &s); debug(F101,"ttsspd IOSSIOSPEED","",x); if (x < 0) return(-1); } #endif /* MACOSHISPEED */ #else #ifdef ATTSV if (cps == 888) return(-1); /* No split speeds, sorry. */ x = ioctl(ttyfd,TCGETA,&ttcur); debug(F101,"ttsspd TCGETA ioctl","",x); if (x < 0) return(-1); ttcur.c_cflag &= ~CBAUD; ttcur.c_cflag |= s; tttvt.c_cflag &= ~CBAUD; tttvt.c_cflag |= s; ttraw.c_cflag &= ~CBAUD; ttraw.c_cflag |= s; ttold.c_cflag &= ~CBAUD; ttold.c_cflag |= s; x = ioctl(ttyfd,TCSETAW,&ttcur); debug(F101,"ttsspd TCSETAW ioctl","",x); if (x < 0) return(-1); #else #ifdef BELLV10 x = ioctl(ttyfd,TIOCGDEV,&tdcur); debug(F101,"ttsspd TIOCGDEV ioctl","",x); if (x < 0) return(-1); tdcur.ispeed = s2; tdcur.ospeed = s; errno = 0; ok = ioctl(ttyfd,TIOCSDEV,&tdcur); debug(F101,"ttsspd BELLV10 ioctl","",ok); if (ok < 0) { perror(ttnmsv); debug(F101,"ttsspd BELLV10 errno","",ok); return(-1); } #else x = gtty(ttyfd,&ttcur); debug(F101,"ttsspd gtty","",x); if (x < 0) return(-1); ttcur.sg_ospeed = s; ttcur.sg_ispeed = s2; tttvt.sg_ospeed = s; tttvt.sg_ispeed = s2; ttraw.sg_ospeed = s; ttraw.sg_ispeed = s2; ttold.sg_ospeed = s; ttold.sg_ispeed = s2; x = stty(ttyfd,&ttcur); debug(F101,"ttsspd stty","",x); if (x < 0) return(-1); #endif /* BELLV10 */ #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ #endif /* Plan9 */ } return(1); /* Return 1 = success. */ #endif /* USETCSETSPEED */ } #endif /* NOLOCAL */ /* C O N G S P D - Get speed of console terminal */ long congspd() { /* This is a disgusting hack. The right way to do this would be to pass an argument to ttgspd(), but then we'd need to change the Kermit API and all of the ck?tio.c modules. (Currently used only for rlogin.) */ int t1; long spd; #ifdef NETCONN int t2 = netconn; netconn = 0; #endif /* NETCONN */ t1 = ttyfd; ttyfd = -1; spd = ttgspd(); debug(F101,"congspd","",spd); #ifdef NETCONN netconn = t2; #endif /* NETCONN */ ttyfd = t1; return(spd); } /* T T S P D L I S T -- Get list of serial speeds allowed on this platform */ #define NSPDLIST 64 static long spdlist[NSPDLIST]; /* As written, this picks up the speeds known at compile time, and thus applies to the computer where C-Kermit was built, rather than to the one where it is running. Suggestions for improvement are always welcome. */ long * #ifdef CK_ANSIC ttspdlist( void ) #else ttspdlist() #endif /* CK_ANSIC */ { int i; for (i = 0; i < NSPDLIST; i++) /* Initialize the list */ spdlist[i] = -1L; i = 1; /* USETCSETSPEED is only for SCO UNIXWARE 7 */ #ifdef USETCSETSPEED /* No way to find out what's legal */ debug(F100,"ttspdlist USETCSETSPEED","",0); spdlist[i++] = 50L; #ifndef UW7 spdlist[i++] = 75L; #endif /* UW7 */ spdlist[i++] = 110L; #ifndef UW7 spdlist[i++] = 134L; #endif /* UW7 */ spdlist[i++] = 150L; spdlist[i++] = 200L; spdlist[i++] = 300L; spdlist[i++] = 600L; spdlist[i++] = 1200L; spdlist[i++] = 1800L; spdlist[i++] = 2400L; spdlist[i++] = 4800L; spdlist[i++] = 8880L; spdlist[i++] = 9600L; spdlist[i++] = 14400L; spdlist[i++] = 19200L; spdlist[i++] = 28800L; #ifndef UW7 spdlist[i++] = 33600L; #endif /* UW7 */ spdlist[i++] = 38400L; spdlist[i++] = 57600L; spdlist[i++] = 76800L; spdlist[i++] = 115200L; #ifndef UW7 spdlist[i++] = 153600L; spdlist[i++] = 230400L; spdlist[i++] = 307200L; spdlist[i++] = 460800L; spdlist[i++] = 921600L; #endif /* UW7 */ #else /* USETCSETSPEED */ debug(F100,"ttspdlist no USETCSETSPEED","",0); #ifdef B50 debug(F101,"ttspdlist B50","",B50); spdlist[i++] = 50L; #endif /* B50 */ #ifdef B75 debug(F101,"ttspdlist B75","",B75); spdlist[i++] = 75L; #endif /* B75 */ #ifdef B110 debug(F101,"ttspdlist B110","",B110); spdlist[i++] = 110L; #endif /* B110 */ #ifdef B134 debug(F101,"ttspdlist B134","",B134); spdlist[i++] = 134L; #endif /* B134 */ #ifdef B150 debug(F101,"ttspdlist B150","",B150); spdlist[i++] = 150L; #endif /* B150 */ #ifdef B200 debug(F101,"ttspdlist B200","",B200); spdlist[i++] = 200L; #endif /* B200 */ #ifdef B300 debug(F101,"ttspdlist B300","",B300); spdlist[i++] = 300L; #endif /* B300 */ #ifdef B600 debug(F101,"ttspdlist B600","",B600); spdlist[i++] = 600L; #endif /* B600 */ #ifdef B1200 debug(F101,"ttspdlist B1200","",B1200); spdlist[i++] = 1200L; #endif /* B1200 */ #ifdef B1800 debug(F101,"ttspdlist B1800","",B1800); spdlist[i++] = 1800L; #endif /* B1800 */ #ifdef B2400 debug(F101,"ttspdlist B2400","",B2400); spdlist[i++] = 2400L; #endif /* B2400 */ #ifdef B4800 debug(F101,"ttspdlist B4800","",B4800); spdlist[i++] = 4800L; #endif /* B4800 */ #ifdef B9600 debug(F101,"ttspdlist B9600","",B9600); spdlist[i++] = 9600L; #endif /* B9600 */ #ifdef B14400 debug(F101,"ttspdlist B14400","",B14400); spdlist[i++] = 14400L; #endif /* B14400 */ #ifdef B19200 debug(F101,"ttspdlist B19200","",B19200); spdlist[i++] = 19200L; #else #ifdef EXTA debug(F101,"ttspdlist EXTA","",EXTA); spdlist[i++] = 19200L; #endif /* EXTA */ #endif /* B19200 */ #ifdef B28800 debug(F101,"ttspdlist B28800","",B28800); spdlist[i++] = 28800L; #endif /* B28800 */ #ifdef B33600 debug(F101,"ttspdlist B33600","",B33600); spdlist[i++] = 33600L; #endif /* B33600 */ #ifdef B38400 debug(F101,"ttspdlist B38400","",B38400); spdlist[i++] = 38400L; #else #ifdef EXTB debug(F101,"ttspdlist EXTB","",EXTB); spdlist[i++] = 38400L; #endif /* EXTB */ #endif /* B38400 */ #ifdef _B57600 debug(F101,"ttspdlist _B57600","",_B57600); spdlist[i++] = 57600L; #else #ifdef B57600 debug(F101,"ttspdlist B57600","",B57600); spdlist[i++] = 57600L; #endif /* B57600 */ #endif /* _B57600 */ #ifdef B76800 debug(F101,"ttspdlist B76800","",B76800); spdlist[i++] = 76800L; #endif /* B76800 */ #ifdef _B115200 debug(F101,"ttspdlist _B115200","",_B115200); spdlist[i++] = 115200L; #else #ifdef B115200 debug(F101,"ttspdlist B115200","",B115200); spdlist[i++] = 115200L; #endif /* B115200 */ #endif /* _B115200 */ #ifdef B153600 debug(F101,"ttspdlist B153600","",B153600); spdlist[i++] = 153600L; #endif /* B153600 */ #ifdef B230400 debug(F101,"ttspdlist B230400","",B230400); spdlist[i++] = 230400L; #endif /* B230400 */ #ifdef B307200 debug(F101,"ttspdlist B307200","",B307200); spdlist[i++] = 307200L; #endif /* B307200 */ #ifdef B460800 debug(F101,"ttspdlist B460800","",B460800); spdlist[i++] = 460800L; #endif /* B460800 */ #ifdef B921600 debug(F101,"ttspdlist B921600","",B921600); spdlist[i++] = 921600L; #endif /* B921600 */ /* The following are new in C-Kermit 10.0 */ #ifdef B1000000 debug(F101,"ttspdlist B1000000","",B1000000); spdlist[i++] = 1000000L; #endif /* B1000000 */ #ifdef B1152000 debug(F101,"ttspdlist B1152000","",B1152000); spdlist[i++] = 1152000L; #endif /* B1152000 */ #ifdef B1500000 debug(F101,"ttspdlist B1500000","",B1500000); spdlist[i++] = 1500000L; #endif /* B1500000 */ #ifdef B2000000 debug(F101,"ttspdlist B2000000","",B2000000); spdlist[i++] = 2000000L; #endif /* B2000000 */ #ifdef B2500000 debug(F101,"ttspdlist B2500000","",B2500000); spdlist[i++] = 2500000L; #endif /* B2500000 */ #ifdef B3000000 debug(F101,"ttspdlist B3000000","",B3000000); spdlist[i++] = 3000000L; #endif /* B3000000 */ #ifdef B3500000 debug(F101,"ttspdlist B3500000","",B3500000); spdlist[i++] = 3500000L; #endif /* B3500000 */ #ifdef B4000000 debug(F101,"ttspdlist B4000000","",B4000000); spdlist[i++] = 4000000L; #endif /* B4000000 */ #endif /* USETCSETSPEED */ spdlist[0] = i - 1; /* Return count in 0th element */ debug(F111,"ttspdlist spdlist","0",spdlist[0]); return((long *)spdlist); } /* T T G S P D - Get speed of currently selected tty line */ /* Unreliable. After SET LINE, it returns an actual speed, but not necessarily the real speed. On some systems, it returns the line's nominal speed, from /etc/ttytab. Even if you SET SPEED to something else, this function might not notice. */ long ttgspd() { /* Get current serial device speed */ #ifdef NOLOCAL return(-1L); #else #ifdef POSIX speed_t /* Should be unsigned */ #else int /* Isn't unsigned */ #endif /* POSIX */ s; int x; long ss; #ifdef OLINUXHISPEED unsigned int spd_flags = 0; struct serial_struct serinfo; #endif /* OLINUXHISPEED */ #ifdef NETCONN if (netconn) { #ifdef TN_COMPORT if (istncomport()) return(tnc_get_baud()); else #endif /* TN_COMPORT */ return(-1); /* -1 if network connection */ } #endif /* NETCONN */ #ifdef NETCMD if (ttpipe) return(-1); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(-1); #endif /* NETPTY */ debug(F101,"ttgspd ttyfd","",ttyfd); #ifdef USETCSETSPEED x = tcgetattr(ttyfd,&ttcur); /* Get current speed */ debug(F101,"ttgspd tcgetattr","",x); if (x < 0) return(-1); errno = 0; s = tcgetspeed(TCS_ALL, &ttcur); debug(F101,"ttsspd TCGETSPEED speed","",s); if (s == 0) { long s1, s2; s1 = tcgetspeed(TCS_IN, &ttcur); s2 = tcgetspeed(TCS_OUT, &ttcur); if (s1 == 1200L && s2 == 75L) return(8880L); } #ifdef DEBUG if (errno & deblog) { debug(F101,"ttsspd TCGETSPEED errno","",errno); } #endif /* DEBUG */ return(s); #else /* Not USETCSETSPEED */ #ifdef Plan9 if (ttyfd < 0) ss = -1; else ss = ttylastspeed; #else #ifdef OLINUXHISPEED debug(F100,"ttgspd Linux OLINUXHISPEED","",0); #endif /* OLINUXHISPEED */ if (ttyfd < 0) { #ifdef BSD44ORPOSIX s = cfgetospeed(&ccold); debug(F101,"ttgspd cfgetospeed 1 POSIX","",s); #else #ifdef ATTSV s = ccold.c_cflag & CBAUD; debug(F101,"ttgspd c_cflag CBAUD 1 ATTSV","",s); #else s = ccold.sg_ospeed; /* (obtained by congm()) */ debug(F101,"ttgspd sg_ospeed 1","",s); #endif /* ATTSV */ #endif /* BSD44POSIX */ } else { #ifdef BSD44ORPOSIX if (tcgetattr(ttyfd,&ttcur) < 0) return(-1); s = cfgetospeed(&ttcur); debug(F101,"ttgspd cfgetospeed 2 BSDORPOSIX","",s); #ifdef OLINUXHISPEED if (ioctl(ttyfd,TIOCGSERIAL,&serinfo) > -1) spd_flags = serinfo.flags & ASYNC_SPD_MASK; debug(F101,"ttgspd spd_flags","",spd_flags); #endif /* OLINUXHISPEED */ #else #ifdef ATTSV x = ioctl(ttyfd,TCGETA,&ttcur); debug(F101,"ttgspd ioctl 2 ATTSV x","",x); debug(F101,"ttgspd ioctl 2 ATTSV errno","",errno); if (x < 0) return(-1); s = ttcur.c_cflag & CBAUD; debug(F101,"ttgspd ioctl 2 ATTSV speed","",s); #else #ifdef BELLV10 x = ioctl(ttyfd,TIOCGDEV,&tdcur); debug(F101,"ttgspd ioctl 2 BELLV10 x","",x); if (x < 0) return(-1); s = tdcur.ospeed; debug(F101,"ttgspd ioctl 2 BELLV10 speed","",s); #else x = gtty(ttyfd,&ttcur); debug(F101,"ttgspd gtty 2 x","",x); debug(F101,"ttgspd gtty 2 errno","",errno); if (x < 0) return(-1); s = ttcur.sg_ospeed; debug(F101,"ttgspd gtty 2 speed","",s); #endif /* BELLV10 */ #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ } debug(F101,"ttgspd code","",s); #ifdef OLINUXHISPEED debug(F101,"ttgspd spd_flags","",spd_flags); #endif /* OLINUXHISPEED */ switch (s) { #ifdef B0 case B0: ss = 0L; break; #endif /* B0 */ #ifndef MINIX /* MINIX defines the Bxx symbols to be bps/100, so B50==B75, B110==B134==B150, etc, making for many "duplicate case in switch" errors, which are fatal. */ #ifdef B50 case B50: ss = 50L; break; #endif /* B50 */ #ifdef B75 case B75: ss = 75L; break; #endif /* B75 */ #endif /* MINIX */ #ifdef B110 case B110: ss = 110L; break; #endif /* B110 */ #ifndef MINIX #ifdef B134 case B134: ss = 134L; break; #endif /* B134 */ #ifdef B150 case B150: ss = 150L; break; #endif /* B150 */ #endif /* MINIX */ #ifdef B200 case B200: ss = 200L; break; #endif /* B200 */ #ifdef B300 case B300: ss = 300L; break; #endif /* B300 */ #ifdef B600 case B600: ss = 600L; break; #endif /* B600 */ #ifdef B1200 case B1200: ss = 1200L; break; #endif /* B1200 */ #ifdef B1800 case B1800: ss = 1800L; break; #endif /* B1800 */ #ifdef B2400 case B2400: ss = 2400L; break; #endif /* B2400 */ #ifdef B4800 case B4800: ss = 4800L; break; #endif /* B4800 */ #ifdef B7200 case B7200: ss = 7200L; break; #endif /* B7200 */ #ifdef B9600 case B9600: ss = 9600L; break; #endif /* B9600 */ #ifdef B19200 case B19200: ss = 19200L; break; #else #ifdef EXTA case EXTA: ss = 19200L; break; #endif /* EXTA */ #endif /* B19200 */ #ifndef MINIX #ifdef B38400 case B38400: ss = 38400L; #ifdef OLINUXHISPEED switch(spd_flags) { case ASYNC_SPD_HI: ss = 57600L; break; case ASYNC_SPD_VHI: ss = 115200L; break; } #endif /* OLINUXHISPEED */ break; #else #ifdef EXTB case EXTB: ss = 38400L; break; #endif /* EXTB */ #endif /* B38400 */ #endif /* MINIX */ #ifdef HPUX #ifdef _B57600 case _B57600: ss = 57600L; break; #endif /* _B57600 */ #ifdef _B115200 case _B115200: ss = 115200L; break; #endif /* _B115200 */ #else #ifdef B57600 case B57600: ss = 57600L; break; #endif /* B57600 */ #ifdef B76800 case B76800: ss = 76800L; break; #endif /* B76800 */ #ifdef B115200 case B115200: ss = 115200L; break; #endif /* B115200 */ #ifdef B153600 case B153600: ss = 153600L; break; #endif /* B153600 */ #ifdef B230400 case B230400: ss = 230400L; break; #endif /* B230400 */ #ifdef B307200 case B307200: ss = 307200L; break; #endif /* B307200 */ #ifdef B460800 case B460800: ss = 460800L; break; #endif /* B460800 */ #endif /* HPUX */ #ifdef B921600 case B921600: ss = 921600L; break; #endif /* B921600 */ #ifdef B1000000 case B1000000: ss = 1000000L; break; #endif /* B1000000 */ #ifdef B1152000 case B1152000: ss = 1152000L; break; #endif /* B1152000 */ #ifdef B1500000 case B1500000: ss = 1500000L; break; #endif /* B1500000 */ #ifdef B2000000 case B2000000: ss = 2000000L; break; #endif /* B2000000 */ #ifdef B2500000 case B2500000: ss = 2500000L; break; #endif /* B2500000 */ #ifdef B3000000 case B3000000: ss = 3000000L; break; #endif /* B3000000 */ #ifdef B3500000 case B3500000: ss = 3500000L; break; #endif /* B3500000 */ #ifdef B4000000 case B4000000: ss = 4000000L; break; #endif /* B4000000 */ default: ss = -1; break; } #endif /* Plan9 */ debug(F101,"ttgspd speed","",ss); return(ss); #endif /* USETCSETSPEED */ #endif /* NOLOCAL */ } #ifdef MINIX2 /* Another hack alert */ #define MINIX #endif /* MINIX2 */ /* FIONREAD data type... This has been defined as "long" for many, many years, and it worked OK until 64-bit platforms appeared. Thus we use int for 64-bit platforms, but keep long for the others. If we changed the default PEEKTYPE to int, this would probably break 16-bit builds (note that sizeof(long) == sizeof(int) on most 32-bit platforms), many of which we have no way of testing any more. Therefore, do not change the default definition of PEEKTYPE -- only add exceptions to it as needed. */ #ifdef COHERENT #ifdef FIONREAD #undef FIONREAD #endif /* FIONREAD */ /* #define FIONREAD TIOCQUERY */ /* #define PEEKTYPE int */ #else /* Not COHERENT... */ #ifdef OSF32 /* Digital UNIX 3.2 or higher */ #define PEEKTYPE int #else #define PEEKTYPE long /* Elsewhere (see notes above) */ #endif /* OSF32 */ #endif /* COHERENT */ /* ckumyr.c by Kristoffer Eriksson, ske@pkmab.se, 15 Mar 1990. */ #ifdef MYREAD /* Private buffer for myread() and its companions. Not for use by anything * else. ttflui() is allowed to reset them to initial values. ttchk() is * allowed to read my_count. * * my_item is an index into mybuf[]. Increment it *before* reading mybuf[]. * * A global parity mask variable could be useful too. We could use it to * let myread() strip the parity on its own, instead of stripping sign * bits as it does now. */ #ifdef BIGBUFOK #define MYBUFLEN 32768 #else #ifdef pdp11 #define MYBUFLEN 256 #else #define MYBUFLEN 1024 #endif /* pdp11 */ #endif /* BIGBUFOK */ #ifdef ANYX25 #undef MYBUFLEN #define MYBUFLEN 256 /* On X.25 connections, there is an extra control byte at the beginning. */ static CHAR x25buf[MYBUFLEN+1]; /* Communication device input buffer */ static CHAR *mybuf = x25buf+1; #else static CHAR mybuf[MYBUFLEN]; #endif /* ANYX25 */ static int my_count = 0; /* Number of chars still in mybuf */ static int my_item = -1; /* Last index read from mybuf[] */ /* T T P E E K -- Peek into our internal communications input buffers. */ /* NOTE: This routine is peculiar to UNIX, and is used only by the select()-based CONNECT module, ckucns.c. It need not be replicated in the ck?tio.c of other platforms. */ int ttpeek() { #ifdef TTLEBUF int rc = 0; if (ttpush >= 0) rc++; rc += le_inbuf(); if (rc > 0) return(rc); else #endif /* TTLEBUF */ #ifdef MYREAD return(my_count); #else return(0); #endif /* MYREAD */ } /* myread() -- Efficient read of one character from communications line. * * NOTE: myread() and its helpers mygetbuf() and myfillbuf() return raw * bytes from connection, so when the connection is encrypted, these bytes * must be decrypted. * * Uses a private buffer to minimize the number of expensive read() system * calls. Essentially performs the equivalent of read() of 1 character, which * is then returned. By reading all available input from the system buffers * to the private buffer in one chunk, and then working from this buffer, the * number of system calls is reduced in any case where more than one character * arrives during the processing of the previous chunk, for instance high * baud rates or network type connections where input arrives in packets. * If the time needed for a read() system call approaches the time for more * than one character to arrive, then this mechanism automatically compensates * for that by performing bigger read()s less frequently. If the system load * is high, the same mechanism compensates for that too. * * myread() is a macro that returns the next character from the buffer. If the * buffer is empty, mygetbuf() is called. See mygetbuf() for possible error * returns. * * This should be efficient enough for any one-character-at-a-time loops. * For even better efficiency you might use memcpy()/bcopy() or such between * buffers (since they are often better optimized for copying), but it may not * be worth it if you have to take an extra pass over the buffer to strip * parity and check for CTRL-C anyway. * * Note that if you have been using myread() from another program module, you * may have some trouble accessing this macro version and the private variables * it uses. In that case, just add a function in this module, that invokes the * macro. */ #define myread() (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item]) /* Specification: Push back up to one character onto myread()'s queue. * * This implementation: Push back characters into mybuf. At least one character * must have been read through myread() before myunrd() may be used. After * EOF or read error, again, myunrd() can not be used. Sometimes more than * one character can be pushed back, but only one character is guaranteed. * Since a previous myread() must have read its character out of mybuf[], * that guarantees that there is space for at least one character. If push * back was really needed after EOF, a small addition could provide that. * * As of 02/2007 myunrd() is used by ttinl(). */ VOID #ifdef CK_ANSIC myunrd(CHAR ch) #else myunrd(ch) CHAR ch; #endif /* CK_ANSIC */ { if (my_item >= 0) { mybuf[my_item--] = ch; ++my_count; } } /* T T P U S H B A C K -- Put n bytes back into the myread buffer */ static CHAR * pushbuf = NULL; /* static int pushed = 0; */ int #ifdef CK_ANSIC ttpushback( CHAR * s, int n ) #else ttpushback(s,n) CHAR * s; int n; #endif /* CK_ANSIC */ { debug(F101,"ttpushback n","",n); if (pushbuf || n > MYBUFLEN || n < 1) return(-1); debug(F101,"ttpushback my_count","",my_count); if (my_count > 0) { if (!(pushbuf = (CHAR *)malloc(n+1))) return(-1); memcpy(pushbuf,mybuf,my_count); /* pushed = my_count; */ /* (set but never used) */ } memcpy(mybuf,s,n); my_count = n; my_item = -1; return(0); } /* mygetbuf() -- Fill buffer for myread() and return first character. * * This function is what myread() uses when it can't get the next character * directly from its buffer. First, it calls a system dependent myfillbuf() * to read at least one new character into the buffer, and then it returns * the first character just as myread() would have done. This function also * is responsible for all error conditions that myread() can indicate. * * Returns: When OK => a positive character, 0 or greater. * When EOF => -2. * When error => -3, error code in errno. * * Older myread()s additionally returned -1 to indicate that there was nothing * to read, upon which the caller would call myread() again until it got * something. The new myread()/mygetbuf() always gets something. If it * doesn't, then make it do so! Any program that actually depends on the old * behaviour will break. * * The older version also used to return -2 both for EOF and other errors, * and used to set errno to 9999 on EOF. The errno stuff is gone, EOF and * other errors now return different results, although Kermit currently never * checks to see which it was. It just disconnects in both cases. * * Kermit lets the user use the quit key to perform some special commands * during file transfer. This causes read(), and thus also mygetbuf(), to * finish without reading anything and return the EINTR error. This should * be checked by the caller. Mygetbuf() could retry the read() on EINTR, * but if there is nothing to read, this could delay Kermit's reaction to * the command, and make Kermit appear unresponsive. * * The debug() call should be removed for optimum performance. */ int mygetbuf() { int x; errno = 0; #ifdef DEBUG if (deblog && my_count > 0) debug(F101,"mygetbuf IMPROPERLY CALLED with my_count","",my_count); #endif /* DEBUG */ if (my_count <= 0) my_count = myfillbuf(); #ifdef DEBUG #ifdef COMMENT if (deblog) debug(F101, "mygetbuf read", "", my_count); #else /* COMMENT */ ckhexdump("mygetbuf read", mybuf, my_count); #endif /* COMMENT */ #endif /* DEBUG */ x = my_count; if (my_count <= 0) { my_count = 0; my_item = -1; debug(F101,"mygetbuf errno","",errno); #ifdef TCPSOCKET if (netconn && ttnet == NET_TCPB && errno != 0) { if (errno != EINTR) { debug(F101,"mygetbuf TCP error","",errno); ttclos(0); /* Close the connection. */ } return(-3); } #endif /* TCPSOCKET */ if (!netconn && xlocal && errno) { if (errno != EINTR) { debug(F101,"mygetbuf SERIAL error","",errno); x = -3; ttclos(0); /* Close the connection. */ } } return((x < 0) ? -3 : -2); } --my_count; return((unsigned)(0xff & mybuf[my_item = 0])); } /* myfillbuf(): * System-dependent read() into mybuf[], as many characters as possible. * * Returns: OK => number of characters read, always more than zero. * EOF => 0 * Error => -1, error code in errno. * * If there is input available in the system's buffers, all of it should be * read into mybuf[] and the function return immediately. If no input is * available, it should wait for a character to arrive, and return with that * one in mybuf[] as soon as possible. It may wait somewhat past the first * character, but be aware that any such delay lengthens the packet turnaround * time during kermit file transfers. Should never return with zero characters * unless EOF or irrecoverable read error. * * Correct functioning depends on the correct tty parameters being used. * Better control of current parameters is required than may have been the * case in older Kermit releases. For instance, O_NDELAY (or equivalent) can * no longer be sometimes off and sometimes on like it used to, unless a * special myfillbuf() is written to handle that. Otherwise the ordinary * myfillbuf()s may think they have come to EOF. * * If your system has a facility to directly perform the functioning of * myfillbuf(), then use it. If the system can tell you how many characters * are available in its buffers, then read that amount (but not less than 1). * If the system can return a special indication when you try to read without * anything to read, while allowing you to read all there is when there is * something, you may loop until there is something to read, but probably that * is not good for the system load. */ #ifdef SVORPOSIX /* This is for System III/V with VMIN>0, VTIME=0 and O_NDELAY off, * and CLOCAL set any way you like. This way, read() will do exactly * what is required by myfillbuf(): If there is data in the buffers * of the O.S., all available data is read into mybuf, up to the size * of mybuf. If there is none, the first character to arrive is * awaited and returned. */ int myfillbuf() { int fd, n; #ifdef NETCMD if (ttpipe) fd = fdin; else #endif /* NETCMD */ fd = ttyfd; #ifdef sxaE50 /* From S. Dezawa at Fujifilm in Japan. I don't know why this is */ /* necessary for the sxa E50, but it is. */ return read(fd, mybuf, 255); #else #ifdef BEOSORBEBOX while (1) { #ifdef NETCONN if (netconn) { n = netxin(sizeof(mybuf), (char *)mybuf); debug(F101,"BEBOX SVORPOSIX network myfillbuf","",n); } else #endif /* NETCONN */ n = read(fd, mybuf, sizeof(mybuf)); debug(F101,"BEBOX SVORPOSIX notnet myfillbuf","",n); if (n > 0) return(n); snooze(1000.0); } #else /* BEOSORBEBOX */ errno = 0; /* debug(F101,"SVORPOSIX myfillbuf calling read() fd","",fd); */ #ifdef IBMX25 if (netconn && (nettype == NET_IX25)) { /* can't use sizeof because mybuf is a pointer, and not an array! */ n = x25xin( MYBUFLEN, mybuf ); } else #endif /* IBMX25 */ #ifdef CK_SSL if (ssl_active_flag || tls_active_flag) { int error, n = 0; debug(F100,"myfillbuf calling SSL_read() fd","",0); while (n == 0) { if (ssl_active_flag) n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf)); else if (tls_active_flag) n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf)); else break; switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) { case SSL_ERROR_NONE: if (n > 0) return(n); if (n < 0) return(-2); msleep(50); break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: return(-1); case SSL_ERROR_SYSCALL: if (n != 0) return(-1); case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: ttclos(0); return(-3); } } } #endif /* CK_SSL */ #ifdef CK_KERBEROS #ifdef KRB4 #ifdef RLOGCODE if (ttnproto == NP_EK4LOGIN) { debug(F101,"myfillbuf calling krb4_des_read() fd","",ttyfd); if ((n = krb4_des_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0) return(-3); else return(n); } #endif /* RLOGCODE */ #endif /* KRB4 */ #ifdef KRB5 #ifdef RLOGCODE if (ttnproto == NP_EK5LOGIN) { debug(F101,"myfillbuf calling krb5_des_read() fd","",ttyfd); if ((n = krb5_des_read(ttyfd,(char *)mybuf,sizeof(mybuf),0)) < 0) return(-3); else return(n); } #endif /* RLOGCODE */ #ifdef KRB5_U2U if (ttnproto == NP_K5U2U) { debug(F101,"myfillbuf calling krb5_u2u_read() fd","",ttyfd); if ((n = krb5_u2u_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0) return(-3); else return(n); } #endif /* KRB5_U2U */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ #ifdef NETPTY #ifdef HAVE_PTYTRAP /* Special handling for HP-UX pty i/o */ ptyread: if (ttpty && pty_trap_pending(ttyfd) > 0) { debug(F101,"myfillbuf calling pty_trap_handler() fd","",ttyfd); if (pty_trap_handler(ttyfd) > 0) { ttclos(0); return(-3); } } #endif /* HAVE_PTYTRAP */ #endif /* NETPTY */ debug(F101,"myfillbuf calling read() fd","",ttyfd); n = read(fd, mybuf, sizeof(mybuf)); debug(F101,"SVORPOSIX myfillbuf read","",n); debug(F101,"SVORPOSIX myfillbuf errno","",errno); debug(F101,"SVORPOSIX myfillbuf ttcarr","",ttcarr); if (n < 1) { #ifdef NETPTY #ifdef HAVE_PTYTRAP /* When we have a PTY trap in place the connection cannot */ /* be closed until the trap receives a close indication. */ if (n == 0 && ttpty) goto ptyread; #endif /* HAVE_PTYTRAP */ #endif /* NETPTY */ return(-3); } return(n); #endif /* BEOSORBEBOX */ #endif /* sxaE50 */ } #else /* not AT&T or POSIX */ #ifdef aegis /* This is quoted from the old myread(). The semantics seem to be * alright, but maybe errno would not need to be set even when * there is no error? I don't know aegis. */ int myfillbuf() { int count; #ifdef NETCMD if (ttpipe) fd = fdin; else #endif /* NETCMD */ fd = ttyfd; count = ios_$get((short)fd, ios_$cond_opt, mybuf, 256L, st); errno = EIO; if (st.all == ios_$get_conditional_failed) /* get at least one */ count = ios_$get((short)fd, 0, mybuf, 1L, st); if (st.all == ios_$end_of_file) return(-3); else if (st.all != status_$ok) { errno = EIO; return(-1); } return(count > 0 ? count : -3); } #else /* !aegis */ #ifdef FIONREAD /* This is for systems with FIONREAD. FIONREAD returns the number * of characters available for reading. If none are available, wait * until something arrives, otherwise return all there is. */ int myfillbuf() { PEEKTYPE avail = 0; int x, fd; #ifdef NETCMD if (ttpipe) fd = fdin; else #endif /* NETCMD */ fd = ttyfd; #ifdef SUNX25 /* SunLink X.25 support in this routine from Stefaan A. Eeckels, Eurostat (CEC). Depends on SunOS having FIONREAD, not because we use it, but just so this code is grouped correctly within the #ifdefs. Let's hope Solaris keeps it. We call x25xin() instead of read() so that Q-Bit packets, which contain X.25 service-level information (e.g. PAD parameter changes), can be processed transparently to the upper-level code. This is a blocking read, and so we depend on higher-level code (such as ttinc()) to set any necessary alarms. */ extern int nettype; if (netconn && nettype == NET_SX25) { while ((x = x25xin(sizeof(x25buf), x25buf)) < 1) ; return(x - 1); /* "-1" compensates for extra status byte */ } #endif /* SUNX25 */ #ifdef CK_SSL if (ssl_active_flag || tls_active_flag) { int error, n = 0; while (n == 0) { if (ssl_active_flag) n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf)); else n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf)); switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) { case SSL_ERROR_NONE: if (n > 0) return(n); if (n < 0) return(-2); msleep(50); break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: return(-1); case SSL_ERROR_SYSCALL: if (n != 0) return(-1); case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: ttclos(0); return(-2); } } } #endif /* CK_SSL */ #ifdef CK_KERBEROS #ifdef KRB4 #ifdef RLOGCODE if (ttnproto == NP_EK4LOGIN) { if ((x = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0) return(-1); else return(x); } #endif /* RLOGCODE */ #endif /* KRB4 */ #ifdef KRB5 #ifdef RLOGCODE if (ttnproto == NP_EK5LOGIN) { if ((x = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0) return(-1); else return(x); } #endif /* RLOGCODE */ #ifdef KRB5_U2U if (ttnproto == NP_K5U2U) { if ((x = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0) return(-1); else return(x); } #endif /* KRB5_U2U */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ errno = 0; debug(F101,"myfillbuf calling FIONREAD ioctl","",xlocal); x = ioctl(fd, FIONREAD, &avail); #ifdef DEBUG if (deblog) { debug(F101,"myfillbuf FIONREAD","",x); debug(F101,"myfillbuf FIONREAD avail","",avail); debug(F101,"myfillbuf FIONREAD errno","",errno); } #endif /* DEBUG */ if (x < 0 || avail == 0) avail = 1; if (avail > MYBUFLEN) avail = MYBUFLEN; errno = 0; x = read(fd, mybuf, (int) avail); #ifdef DEBUG if (deblog) { debug(F101,"myfillbuf avail","",avail); debug(F101,"myfillbuf read","",x); debug(F101,"myfillbuf read errno","",errno); if (x > 0) ckhexdump("myfillbuf mybuf",mybuf,x); } #endif /* DEBUG */ if (x < 1) x = -3; /* read 0 == connection loss */ return(x); } #else /* !FIONREAD */ /* Add other systems here, between #ifdef and #else, e.g. NETCONN. */ /* When there is no other possibility, read 1 character at a time. */ int myfillbuf() { int x; #ifdef CK_SSL if (ssl_active_flag || tls_active_flag) { int error, n = 0; while (n == 0) { if (ssl_active_flag) n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf)); else count = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf)); switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) { case SSL_ERROR_NONE: if (n > 0) return(n); if (n < 0) return(-2); msleep(50); break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: return(-1); case SSL_ERROR_SYSCALL: if (n != 0) return(-1); case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: ttclos(0); return(-2); } } } #endif /* CK_SSL */ #ifdef CK_KERBEROS #ifdef KRB4 #ifdef RLOGCODE if (ttnproto == NP_EK4LOGIN) { if ((len = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0) return(-1); else return(len); } #endif /* RLOGCODE */ #endif /* KRB4 */ #ifdef KRB5 #ifdef RLOGCODE if (ttnproto == NP_EK5LOGIN) { if ((len = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0) return(-1); else return(len); } #endif /* RLOGCODE */ #ifdef KRB5_U2U if (ttnproto == NP_K5U2U) { if ((len = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0) return(-1); else return(len); } #endif /* KRB5_U2U */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ #ifdef NETCMD if (ttpipe) fd = fdin; else #endif /* NETCMD */ fd = ttyfd; x = read(fd, mybuf, 1); return(x > 0 ? x : -3); } #endif /* !FIONREAD */ #endif /* !aegis */ #endif /* !ATTSV */ #endif /* MYREAD */ /* T T _ T N O P T -- Handle Telnet negotions in incoming data */ /* Call with the IAC that was encountered. Returns: -3: If connection has dropped or gone bad. -2: On Telnet protocol error resulting in inconsistent states. 0: If negotiation OK and caller has nothing to do. 1: If packet start character has changed (new value is in global stchr). 255: If there was a quoted IAC as data. or: Not at all if we got a legitimate Telnet Logout request. */ #ifdef TCPSOCKET static int #ifdef CK_ANSIC tt_tnopt( int n ) /* Handle Telnet options */ #else tt_tnopt(n) int n; #endif /* CK_ANSIC */ { /* In case caller did not already check these conditions... */ if (n == IAC && ((xlocal && netconn && IS_TELNET()) || (!xlocal && sstelnet))) { extern int server; int tx = 0; debug(F100,"ttinl calling tn_doop()","",0); tx = tn_doop((CHAR)(n & 0xff),duplex,ttinc); debug(F111,"ttinl tn_doop() returned","tx",tx); switch (tx) { case 0: return(0); case -1: /* I/O error */ ttimoff(); /* Turn off timer */ return(-3); case -2: /* Connection failed. */ case -3: ttimoff(); /* Turn off timer */ ttclos(0); return(-3); case 1: /* ECHO change */ duplex = 1; return(0); case 2: /* ECHO change */ duplex = 0; return(0); case 3: /* Quoted IAC */ n = 255; return((unsigned)255); #ifdef IKS_OPTION case 4: { if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start && server #ifdef IKSD && !inserver #endif /* IKSD */ ) { /* Remote in Server mode */ ttimoff(); /* Turn off timer */ debug(F100,"u_start and !inserver","",0); return(-2); /* End server mode */ } else if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start && server ) { /* I'm no longer in Server Mode */ debug(F100,"me_start and server","",0); ttimoff(); return(-2); } return(0); } case 5: { /* Start character change */ /* extern CHAR stchr; */ /* start = stchr; */ return(1); } #endif /* IKS_OPTION */ case 6: /* Remote Logout */ ttimoff(); ttclos(0); #ifdef IKSD if (inserver && !local) doexit(GOOD_EXIT,0); else #endif /* IKSD */ return(-2); default: return(0); } } else return(0); } #endif /* TCPSOCKET */ /* T T F L U I -- Flush tty input buffer */ void ttflux() { /* But first... */ #ifdef MYREAD /* Flush internal MYREAD buffer. */ #ifdef TCPSOCKET int dotnopts, x; dotnopts = (((xlocal && netconn && IS_TELNET()) || (!xlocal && sstelnet))); #endif /* TCPSOCKET */ debug(F101,"ttflux my_count","",my_count); #ifdef TCPSOCKET if (dotnopts) { CHAR ch = '\0'; while (my_count > 0) { ch = myread(); #ifdef CK_ENCRYPTION if (TELOPT_U(TELOPT_ENCRYPTION)) ck_tn_decrypt((char *)&ch,1); #endif /* CK_ENCRYPTION */ if (ch == IAC) x = tt_tnopt(ch); } } else #endif /* TCPSOCKET */ #ifdef COMMENT #ifdef CK_ENCRYPTION if (TELOPT_U(TELOPT_ENCRYPTION) && my_count > 0) ck_tn_decrypt(&mybuf[my_item+1],my_count); #endif /* CK_ENCRYPTION */ #endif /* COMMENT */ my_count = 0; /* Reset count to zero */ my_item = -1; /* And buffer index to -1 */ #endif /* MYREAD */ } int ttflui() { int n, fd; #ifdef TCPSOCKET int dotnopts; dotnopts = (((xlocal && netconn && IS_TELNET()) || (!xlocal && sstelnet))); #endif /* TCPSOCKET */ #ifdef NETCMD if (ttpipe) fd = fdin; else #endif /* NETCMD */ fd = ttyfd; #ifdef TTLEBUF ttpush = -1; /* Clear the peek-ahead char */ while (le_data && (le_inbuf() > 0)) { CHAR ch = '\0'; if (le_getchar(&ch) > 0) { /* Clear any more... */ debug(F101,"ttflui le_inbuf ch","",ch); } } #endif /* TTLEBUF */ debug(F101,"ttflui ttpipe","",ttpipe); #ifdef MYREAD /* Flush internal MYREAD buffer *NEXT*, in all cases. */ ttflux(); #endif /* MYREAD */ #ifdef NETCONN /* Network flush is done specially, in the network support module. */ if ((netconn || sstelnet) && !ttpipe && !ttpty) { debug(F100,"ttflui netflui","",0); #ifdef COMMENT #ifdef TN_COMPORT if (istncomport()) tnc_send_purge_data(TNC_PURGE_RECEIVE); #endif /* TN_COMPORT */ #endif /* COMMENT */ #ifndef NOTCPIP return(netflui()); #else return(-1); #endif /* NOTCPIP */ } #endif /* NETCONN */ debug(F101,"ttflui ttyfd","",ttyfd); /* Not network */ if (ttyfd < 0) return(-1); #ifdef aegis sio_$control((short)yfd, sio_$flush_in, true, st); if (st.all != status_$ok) { fprintf(stderr, "flush failed: "); error_$print(st); } else { /* sometimes the flush doesn't work */ for (;;) { char buf[256]; /* eat all the characters that shouldn't be available */ ios_$get((short)fd, ios_$cond_opt, buf, 256L, st); /* (void) */ if (st.all == ios_$get_conditional_failed) break; fprintf(stderr, "flush failed(2): "); error_$print(st); } } #else #ifdef BSD44 /* 4.4 BSD */ n = FREAD; /* Specify read queue */ debug(F100,"ttflui BSD44","",0); ioctl(fd,TIOCFLUSH,&n); #else #ifdef Plan9 #undef POSIX /* Uh oh... */ #endif /* Plan9 */ #ifdef POSIX /* POSIX */ debug(F100,"ttflui POSIX","",0); tcflush(fd,TCIFLUSH); #else #ifdef ATTSV /* System V */ #ifndef VXVE debug(F100,"ttflui ATTSV","",0); ioctl(fd,TCFLSH,0); #endif /* VXVE */ #else /* Not BSD44, POSIX, or Sys V */ #ifdef TIOCFLUSH /* Those with TIOCFLUSH defined */ #ifdef ANYBSD /* Berkeley */ n = FREAD; /* Specify read queue */ debug(F100,"ttflui TIOCFLUSH ANYBSD","",0); ioctl(fd,TIOCFLUSH,&n); #else /* Others (V7, etc) */ debug(F100,"ttflui TIOCFLUSH","",0); ioctl(fd,TIOCFLUSH,0); #endif /* ANYBSD */ #else /* All others... */ /* No system call (that we know about) for input buffer flushing. So see how many there are and read them in a loop, using ttinc(). ttinc() is buffered, so we're not getting charged with a system call per character, just a function call. */ if ((n = ttchk()) > 0) { debug(F101,"ttflui read loop","",n); while ((n--) && ttinc(0) > 0) ; } #endif /* TIOCFLUSH */ #endif /* ATTSV */ #endif /* POSIX */ #ifdef Plan9 #define POSIX #endif /* Plan9 */ #endif /* BSD44 */ #endif /* aegis */ return(0); } int ttfluo() { /* Flush output buffer */ int fd; #ifdef NETCMD if (ttpipe) fd = fdout; else #endif /* NETCMD */ fd = ttyfd; #ifdef Plan9 return 0; #else #ifdef POSIX return(tcflush(fd,TCOFLUSH)); #else #ifdef OXOS return(ioctl(fd,TCFLSH,1)); #else return(0); /* All others, nothing */ #endif /* OXOS */ #endif /* POSIX */ #endif /* Plan9 */ } /* Interrupt Functions */ /* Set up terminal interrupts on console terminal */ #ifndef FIONREAD /* We don't need esctrp() */ #ifndef SELECT /* if we have any of these... */ #ifndef CK_POLL #ifndef RDCHK #ifndef OXOS #ifdef SVORPOSIX SIGTYP esctrp(foo) int foo; { /* trap console escapes (^\) */ signal(SIGQUIT,SIG_IGN); /* ignore until trapped */ conesc = 1; debug(F101,"esctrp caught SIGQUIT","",conesc); } #endif /* SVORPOSIX */ #endif /* OXOS */ #ifdef V7 #ifndef MINIX2 SIGTYP esctrp(foo) int foo; { /* trap console escapes (^\) */ signal(SIGQUIT,SIG_IGN); /* ignore until trapped */ conesc = 1; debug(F101,"esctrp caught SIGQUIT","",conesc); } #endif /* MINIX2 */ #endif /* V7 */ #ifdef C70 SIGTYP esctrp(foo) int foo; { /* trap console escapes (^\) */ conesc = 1; signal(SIGQUIT,SIG_IGN); /* ignore until trapped */ } #endif /* C70 */ #endif /* RDCHK */ #endif /* CK_POLL */ #endif /* SELECT */ #endif /* FIONREAD */ /* C O N B G T -- Background Test */ static int jc = 0; /* 0 = no job control */ /* Call with flag == 1 to prevent signal test, which can not be expected to work during file transfer, when SIGINT probably *is* set to SIG_IGN. Call with flag == 0 to use the signal test, but only if the process-group test fails, as it does on some UNIX systems, where getpgrp() is buggy, requires an argument when the man page says it doesn't, or vice versa. If flag == 0 and the process-group test fails, then we determine background status simply (but not necessarily reliably) from isatty(). conbgt() sets the global backgrd = 1 if we appear to be in the background, and to 0 if we seem to be in the foreground. conbgt() is highly prone to misbehavior. */ VOID #ifdef CK_ANSIC conbgt( int flag ) #else conbgt(flag) int flag; #endif /* CK_ANSIC */ { int x = -1, /* process group or SIGINT test */ y = 0; /* isatty() test */ /* Check for background operation, even if not running on real tty, so that background flag can be set correctly. If background status is detected, then Kermit will not issue its interactive prompt or most messages. If your prompt goes away, you can blame (and fix?) this function. */ /* Use process-group test if possible. */ #ifdef POSIX /* We can do it in POSIX */ #define PGROUP_T #else #ifdef BSD4 /* and in BSD 4.x. */ #define PGROUP_T #else #ifdef HPUXJOBCTL /* and in most HP-UX's */ #define PGROUP_T #else #ifdef TIOCGPGRP /* and anyplace that has this ioctl. */ #define PGROUP_T #endif /* TIOCGPGRP */ #endif /* HPUXJOBCTL */ #endif /* BSD4 */ #endif /* POSIX */ #ifdef MIPS /* Except if it doesn't work... */ #undef PGROUP_T #endif /* MIPS */ #ifdef MINIX #undef PGROUP_T #endif /* MINIX */ #ifdef PGROUP_T /* Semi-reliable process-group test. Check whether this process's group is the same as the controlling terminal's process group. This works if the getpgrp() call doesn't lie (as it does in the SUNOS System V environment). */ PID_T mypgrp = (PID_T)0; /* Kermit's process group */ PID_T ctpgrp = (PID_T)0; /* The terminal's process group */ #ifndef _POSIX_SOURCE /* The getpgrp() prototype is obtained from system header files for POSIX and Sys V R4 compilations. Other systems, who knows. Some complain about a duplicate declaration here, others don't, so it's safer to leave it in if we don't know for certain. */ #ifndef SVR4 #ifndef PS2AIX10 #ifndef HPUX9 extern PID_T getpgrp(); #endif /* HPUX9 */ #endif /* PS2AIX10 */ #endif /* SVR4 */ #endif /* _POSIX_SOURCE */ /* Get my process group. */ #ifdef SVR3 /* Maybe this should be ATTSV? */ /* This function is not described in SVID R2 */ mypgrp = getpgrp(); /* debug(F101,"ATTSV conbgt process group","",(int) mypgrp); */ #else #ifdef POSIX mypgrp = getpgrp(); /* debug(F101,"POSIX conbgt process group","",(int) mypgrp); */ #else #ifdef OSFPC mypgrp = getpgrp(); /* debug(F101,"OSF conbgt process group","",(int) mypgrp); */ #else #ifdef QNX mypgrp = getpgrp(); /* debug(F101,"QNX conbgt process group","",(int) mypgrp); */ #else #ifdef OSF32 /* (was OSF40) */ mypgrp = getpgrp(); /* debug(F101,"Digital UNIX conbgt process group","",(int) mypgrp); */ #else /* BSD, V7, etc */ #ifdef MINIX2 mypgrp = getpgrp(); #else mypgrp = getpgrp(0); #endif /* MINIX2 */ /* debug(F101,"BSD conbgt process group","",(int) mypgrp); */ #endif /* OSF32 */ #endif /* QNX */ #endif /* OSFPC */ #endif /* POSIX */ #endif /* SVR3 */ #ifdef MINIX /* MINIX does not support job control so Kermit is always in foreground */ x = 0; #else /* Not MINIX */ /* Now get controlling tty's process group */ #ifdef BSD44ORPOSIX ctpgrp = tcgetpgrp(1); /* The POSIX way */ /* debug(F101,"POSIX conbgt terminal process group","",(int) ctpgrp); */ #else ioctl(1, TIOCGPGRP, &ctpgrp); /* Or the BSD way */ /* debug(F101,"non-POSIX conbgt terminal process group","",(int) ctpgrp); */ #endif /* BSD44ORPOSIX */ if ((mypgrp > (PID_T) 0) && (ctpgrp > (PID_T) 0)) x = (mypgrp == ctpgrp) ? 0 : 1; /* If they differ, then background. */ else x = -1; /* If error, remember. */ debug(F101,"conbgt process group test","",x); #endif /* PGROUP_T */ #endif /* MINIX */ /* Try to see if job control is available */ #ifdef NOJC /* User override */ jc = 0; /* No job control allowed */ debug(F111,"NOJC","jc",jc); #else #ifdef BSD44 jc = 1; #else #ifdef SVR4ORPOSIX /* POSIX actually tells us */ debug(F100,"SVR4ORPOSIX jc test...","",0); #ifdef _SC_JOB_CONTROL #ifdef __bsdi__ jc = 1; #else #ifdef __386BSD__ jc = 1; #else jc = sysconf(_SC_JOB_CONTROL); /* Whatever system says */ if (jc < 0) { debug(F101,"sysconf fails, jcshell","",jcshell); jc = (jchdlr == SIG_DFL) ? 1 : 0; } else debug(F111,"sysconf(_SC_JOB_CONTROL)","jc",jc); #endif /* __386BSD__ */ #endif /* __bsdi__ */ #else #ifdef _POSIX_JOB_CONTROL jc = 1; /* By definition */ debug(F111,"_POSIX_JOB_CONTROL is defined","jc",jc); #else jc = 0; /* Assume job control not allowed */ debug(F111,"SVR4ORPOSIX _SC/POSIX_JOB_CONTROL not defined","jc",jc); #endif /* _POSIX_JOB_CONTROL */ #endif /* _SC_JOB_CONTROL */ #else #ifdef BSD4 jc = 1; /* Job control allowed */ debug(F111,"BSD job control","jc",jc); #else #ifdef SVR3JC jc = 1; /* JC allowed */ debug(F111,"SVR3 job control","jc",jc); #else #ifdef OXOS jc = 1; /* JC allowed */ debug(F111,"X/OS job control","jc",jc); #else #ifdef HPUX9 jc = 1; /* JC allowed */ debug(F111,"HP-UX 9.0 job control","jc",jc); #else #ifdef HPUX10 jc = 1; /* JC allowed */ debug(F111,"HP-UX 10.0 job control","jc",jc); #else jc = 0; /* JC not allowed */ debug(F111,"job control catch-all","jc",jc); #endif /* HPUX10 */ #endif /* HPUX9 */ #endif /* OXOS */ #endif /* SVR3JC */ #endif /* BSD4 */ #endif /* SVR4ORPOSIX */ #endif /* BSD44 */ #endif /* NOJC */ debug(F101,"conbgt jc","",jc); #ifndef NOJC debug(F101,"conbgt jcshell","",jcshell); /* At this point, if jc == 1 but jcshell == 0, it means that the OS supports job control, but the shell or other process we are running under does not (jcshell is set in sysinit()) and so if we suspend ourselves, nothing good will come of it. So... */ if (jc < 0) jc = 0; if (jc > 0 && jcshell == 0) jc = 0; #endif /* NOJC */ /* Another background test. Test if SIGINT (terminal interrupt) is set to SIG_IGN (ignore), which is done by the shell (sh) if the program is started with '&'. Unfortunately, this is NOT done by csh or ksh so watch out! Note, it's safe to set SIGINT to SIG_IGN here, because further down we always set it to something else. Note: as of 16 Jul 1999, we also skip this test if we set SIGINT to SIG_IGN ourselves. */ if (x < 0 && !flag && !sigint_ign) { /* Didn't get good results above... */ SIGTYP (*osigint)(); osigint = signal(SIGINT,SIG_IGN); /* What is SIGINT set to? */ sigint_ign = 1; x = (osigint == SIG_IGN) ? 1 : 0; /* SIG_IGN? */ /* debug(F101,"conbgt osigint","",osigint); */ /* debug(F101,"conbgt signal test","",x); */ } /* Also check to see if we're running with redirected stdio. */ /* This is not really background operation, but we want to act as though */ /* it were. */ #ifdef IKSD if (inserver) { /* Internet Kermit Server */ backgrd = 0; /* is not in the background */ return; } #endif /* IKSD */ y = (isatty(0) && isatty(1)) ? 1 : 0; debug(F101,"conbgt isatty test","",y); #ifdef BSD29 /* The process group and/or signal test doesn't work under these... */ backgrd = !y; #else #ifdef sxaE50 backgrd = !y; #else #ifdef MINIX backgrd = !y; #else #ifdef MINIX2 backgrd = !y; #else if (x > -1) backgrd = (x || !y) ? 1 : 0; else backgrd = !y; #endif /* BSD29 */ #endif /* sxaE50 */ #endif /* MINIX */ #endif /* MINIX2 */ debug(F101,"conbgt backgrd","",backgrd); } /* C O N I N T -- Console Interrupt setter */ /* First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C). Second arg is pointer to function to handle SIGTSTP (suspend). */ VOID /* Set terminal interrupt traps. */ #ifdef CK_ANSIC #ifdef apollo conint(f,s) SIGTYP (*f)(), (*s)(); #else conint(SIGTYP (*f)(int), SIGTYP (*s)(int)) #endif /* apollo */ #else conint(f,s) SIGTYP (*f)(), (*s)(); #endif /* CK_ANSIC */ /* conint */ { debug(F101,"conint conistate","",conistate); conbgt(0); /* Do background test. */ /* Set the desired handlers for hangup and software termination. */ #ifdef SIGTERM signal(SIGTERM,f); /* Software termination */ #endif /* SIGTERM */ /* Prior to July 1999 we used to call sighup() here but now it's called in sysinit() so SIGHUP can be caught during execution of the init file or a kerbang script. */ /* Now handle keyboard stop, quit, and interrupt signals. */ /* Check if invoked in background -- if so signals set to be ignored. */ /* However, if running under a job control shell, don't ignore them. */ /* We won't be getting any, as we aren't in the terminal's process group. */ debug(F101,"conint backgrd","",backgrd); debug(F101,"conint jc","",jc); if (backgrd && !jc) { /* In background, ignore signals */ debug(F101,"conint background ignoring signals, jc","",jc); #ifdef SIGTSTP signal(SIGTSTP,SIG_IGN); /* Keyboard stop */ #endif /* SIGTSTP */ signal(SIGQUIT,SIG_IGN); /* Keyboard quit */ signal(SIGINT,SIG_IGN); /* Keyboard interrupt */ sigint_ign = 1; conistate = CONI_NOI; } else { /* Else in foreground or suspended */ debug(F101,"conint foreground catching signals, jc","",jc); signal(SIGINT,f); /* Catch terminal interrupt */ sigint_ign = (f == SIG_IGN) ? 1 : 0; #ifdef SIGTSTP /* Keyboard stop (suspend) */ /* debug(F101,"conint SIGSTSTP","",s); */ if (s == NULL) s = SIG_DFL; #ifdef NOJC /* No job control allowed. */ signal(SIGTSTP,SIG_IGN); #else /* Job control allowed */ if (jc) /* if available. */ signal(SIGTSTP,s); else signal(SIGTSTP,SIG_IGN); #endif /* NOJC */ #endif /* SIGTSTP */ #ifndef OXOS #ifdef SVORPOSIX #ifndef FIONREAD /* Watch out, we don't know this... */ #ifndef SELECT #ifndef CK_POLL #ifndef RDCHK signal(SIGQUIT,esctrp); /* Quit signal, Sys III/V. */ #endif /* RDCHK */ #endif /* CK_POLL */ #endif /* SELECT */ #endif /* FIONREAD */ if (conesc) conesc = 0; /* Clear out pending escapes */ #else #ifdef V7 signal(SIGQUIT,esctrp); /* V7 like Sys III/V */ if (conesc) conesc = 0; #else #ifdef aegis signal(SIGQUIT,f); /* Apollo, catch it like others. */ #else signal(SIGQUIT,SIG_IGN); /* Others, ignore like 4D & earlier. */ #endif /* aegis */ #endif /* V7 */ #endif /* SVORPOSIX */ #endif /* OXOS */ conistate = CONI_INT; } } /* C O N N O I -- Reset console terminal interrupts */ VOID connoi() { /* Console-no-interrupts */ debug(F101,"connoi conistate","",conistate); #ifdef SIGTSTP signal(SIGTSTP,SIG_IGN); /* Suspend */ #endif /* SIGTSTP */ conint(SIG_IGN,SIG_IGN); /* Interrupt */ sigint_ign = 1; /* Remember we did this ourselves */ #ifdef SIGQUIT signal(SIGQUIT,SIG_IGN); /* Quit */ #endif /* SIGQUIT */ #ifdef SIGTERM signal(SIGTERM,SIG_IGN); /* Term */ #endif /* SIGTERM */ conistate = CONI_NOI; } /* I N I T R A W Q -- Set up to read /dev/kmem for character count. */ #ifdef V7 /* Used in Version 7 to simulate Berkeley's FIONREAD ioctl call. This eliminates blocking on a read, because we can read /dev/kmem to get the number of characters available for raw input. If your system can't or you won't let the world read /dev/kmem then you must figure out a different way to do the counting of characters available, or else replace this by a dummy function that always returns 0. */ /* * Call this routine as: initrawq(tty) * where tty is the file descriptor of a terminal. It will return * (as a char *) the kernel-mode memory address of the rawq character * count, which may then be read. It has the side-effect of flushing * input on the terminal. */ /* * John Mackin, Physiology Dept., University of Sydney (Australia) * ...!decvax!mulga!physiol.su.oz!john * * Permission is hereby granted to do anything with this code, as * long as this comment is retained unmodified and no commercial * advantage is gained. */ #ifndef MINIX #ifndef MINIX2 #ifndef COHERENT #include #include #endif /* COHERENT */ #endif /* MINIX2 */ #endif /* MINIX */ #ifdef COHERENT #include #include #endif /* COHERENT */ char * initrawq(tty) int tty; { #ifdef MINIX return(0); #else #ifdef MINIX2 return(0); #else #ifdef UTS24 return(0); #else #ifdef BSD29 return(0); #else long lseek(); static struct nlist nl[] = { {PROCNAME}, {NPROCNAME}, {""} }; static struct proc *pp; char *qaddr, *p, c; int m; PID_T pid, me; NPTYPE xproc; /* Its type is defined in makefile. */ int catch(); me = getpid(); if ((m = open("/dev/kmem", 0)) < 0) err("kmem"); nlist(BOOTNAME, nl); if (nl[0].n_type == 0) err("proc array"); if (nl[1].n_type == 0) err("nproc"); lseek(m, (long)(nl[1].n_value), 0); read (m, &xproc, sizeof(xproc)); saval = signal(SIGALRM, catch); if ((pid = fork()) == 0) { while(1) read(tty, &c, 1); } alarm(2); if(setjmp(jjbuf) == 0) { while(1) read(tty, &c, 1); } signal(SIGALRM, SIG_DFL); #ifdef DIRECT pp = (struct proc *) nl[0].n_value; #else if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek"); if (read(m, &pp, sizeof(pp)) != sizeof(pp)) err("no read of proc ptr"); #endif lseek(m, (long)(nl[1].n_value), 0); read(m, &xproc, sizeof(xproc)); if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc"); if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc"); if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc)) err("read proc table"); for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) { if (pp -> p_pid == (short) pid) goto iout; } err("no such proc"); iout: close(m); qaddr = (char *)(pp -> p_wchan); free (p); kill(pid, SIGKILL); wait((WAIT_T *)0); return (qaddr); #endif #endif #endif #endif } /* More V7-support functions... */ static VOID err(s) char *s; { char buf[200]; ckmakmsg(buf,200,"fatal error in initrawq: ", s, NULL, NULL); perror(buf); doexit(1,-1); } static VOID catch(foo) int foo; { longjmp(jjbuf, -1); } /* G E N B R K -- Simulate a modem break. */ #ifdef MINIX #define BSPEED B110 #else #ifdef MINIX2 #define BSPEED B110 #else #define BSPEED B150 #endif /* MINIX2 */ #endif /* MINIX */ #ifndef MINIX2 VOID genbrk(fn,msec) int fn, msec; { struct sgttyb ttbuf; int ret, sospeed, x, y; ret = ioctl(fn, TIOCGETP, &ttbuf); sospeed = ttbuf.sg_ospeed; ttbuf.sg_ospeed = BSPEED; ret = ioctl(fn, TIOCSETP, &ttbuf); y = (int)strlen(brnuls); x = ( BSPEED * 100 ) / msec; if (x > y) x = y; ret = write(fn, brnuls, (( BSPEED * 100 ) / msec )); ttbuf.sg_ospeed = sospeed; ret = ioctl(fn, TIOCSETP, &ttbuf); ret = write(fn, "@", 1); return; } #endif /* MINIX2 */ #ifdef MINIX2 int genbrk(fn,msec) int fn, msec; { struct termios ttbuf; int ret, x, y; speed_t sospeed; ret = tcgetattr(fn, &ttbuf); sospeed = ttbuf.c_ospeed; ttbuf.c_ospeed = BSPEED; ret = tcsetattr(fn,TCSADRAIN, &ttbuf); y = (int)strlen(brnuls); x = ( BSPEED * 100 ) / msec; if (x > y) x = y; ret = write(fn, brnuls, (( BSPEED * 100 ) / msec )); ttbuf.c_ospeed = sospeed; ret = tcsetattr(fn, TCSADRAIN, &ttbuf); ret = write(fn, "@", 1); return ret; } #endif /* MINIX2 */ #endif /* V7 */ /* I N C H K -- Check if chars waiting to be read on given file descriptor. This routine is a merger of ttchk() and conchk(). Call with: channel == 0 to check console. channel == 1 to check communications connection. and: fd = file descriptor. Returns: >= 0: number of characters waiting, 0 or greater, -1: on any kind of error, -2: if there is (definitely) no connection. Note: In UNIX we don't have to call nettchk() because a socket file descriptor works just like in serial i/o, ioctls and all. (But this will change if we add non-file-descriptor channels, such as IBM X.25 for AIX...) */ static int #ifdef CK_ANSIC in_chk( int channel, int fd ) #else in_chk(channel, fd) int channel, fd; #endif /* CK_ANSIC */ { int x, n = 0; /* Workers, n = return value */ extern int clsondisc; /* Close on disconnect */ /* The first section checks to make sure we have a connection, but only if we're in local mode. */ #ifdef DEBUG if (deblog) { debug(F111,"in_chk entry",ckitoa(fd),channel); debug(F101,"in_chk ttyfd","",ttyfd); debug(F101,"in_chk ttpty","",ttpty); } #endif /* DEBUG */ /* But don't say connection is gone if we have any buffered-stuff. */ #ifdef TTLEBUF debug(F101,"in_chk ttpush","",ttpush); if (channel == 1) { if (ttpush >= 0) n++; n += le_inbuf(); if (n > 0) return(n); } #endif /* TTLEBUF */ #ifdef NETPTY #ifdef HAVE_PTYTRAP /* Special handling for HP-UX pty i/o */ if (ttpty && pty_trap_pending(ttyfd) > 0) { if (pty_trap_handler(ttyfd) > 0) { ttclos(0); return(-2); } } #endif /* HAVE_PTYTRAP */ #endif /* NETPTY */ if (channel) { /* Checking communications channel */ if (ttyfd < 0) { /* No connection */ return(-2); /* That's what this means */ } else if (xlocal && /* In local mode */ (!netconn /* Serial connection or */ #ifdef TN_COMPORT || istncomport() /* Telnet Com Port */ #endif /* TN_COMPORT */ ) && ttcarr != CAR_OFF /* with CARRIER WATCH ON (or AUTO) */ #ifdef COMMENT #ifdef MYREAD /* Seems like this would be a good idea but it prevents C-Kermit from popping back to the prompt automatically when carrier drops. However, commenting this out prevents us from seeing the NO CARRIER message. Needs more work... */ && my_count < 1 /* Nothing in our internal buffer */ #endif /* MYREAD */ #endif /* COMMENT */ ) { int x; x = ttgmdm(); /* So get modem signals */ debug(F101,"in_chk close-on-disconnect","",clsondisc); if (x > -1) { /* Check for carrier */ if (!(x & BM_DCD)) { /* No carrier */ debug(F101,"in_chk carrier lost","",x); if (clsondisc) /* If "close-on-disconnect" */ ttclos(0); /* close device & release lock. */ return(-2); /* This means "disconnected" */ } /* In case I/O to device after CD dropped always fails */ /* as in Debian Linux 2.1 and Unixware 2.1... */ } else { debug(F101,"in_chk ttgmdm I/O error","",errno); debug(F101,"in_chk ttgmdm gotsigs","",gotsigs); if (gotsigs) { /* If we got signals before... */ if (errno == 5 || errno == 6) { /* I/O error etc */ if (clsondisc) /* like when modem hangs up */ ttclos(0); return(-2); } } /* If we never got modem signals successfully on this */ /* connection before, we can't conclude that THIS failure */ /* means the connection was lost. */ return(0); } } } /* We seem to have a connection so now see if any bytes are waiting on it */ #ifdef CK_SSL if (ssl_active_flag || tls_active_flag) { n += SSL_pending(ssl_active_flag?ssl_con:tls_con); debug(F101,"in_chk SSL_pending","",n); if (n < 0) { ttclos(0); return(-1); } else if (n > 0) { return(n); } } #endif /* CK_SSL */ #ifdef RLOGCODE #ifdef CK_KERBEROS /* It is not safe to read any data when using encrypted Klogin */ if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN) { #ifdef KRB4 if (ttnproto == NP_EK4LOGIN) { n += krb4_des_avail(ttyfd); debug(F101,"in_chk krb4_des_avail","",n); } #endif /* KRB4 */ #ifdef KRB5 if (ttnproto == NP_EK5LOGIN) { n += krb5_des_avail(ttyfd); debug(F101,"in_chk krb5_des_avail","",n); } #ifdef KRB5_U2U if (ttnproto == NP_K5U2U) { n += krb5_u2u_avail(ttyfd); debug(F101,"in_chk krb5_des_avail","",n); } #endif /* KRB5_U2U */ #endif /* KRB5 */ if (n < 0) /* Is this right? */ return(-1); else return(n); } #endif /* CK_KERBEROS */ #endif /* RLOGCODE */ errno = 0; /* Reset this so we log good info */ #ifdef FIONREAD x = ioctl(fd, FIONREAD, &n); /* BSD and lots of others */ #ifdef DEBUG /* (the more the better) */ if (deblog) { debug(F101,"in_chk FIONREAD return code","",x); debug(F101,"in_chk FIONREAD count","",n); debug(F101,"in_chk FIONREAD errno","",errno); } #endif /* DEBUG */ #else /* FIONREAD not defined */ /* Here, if (netconn && ttnet == NET_TCPB), we might try calling recvmsg() with flags MSG_PEEK|MSG_DONTWAIT on the socket (ttyfd), except this is not portable (MSG_DONTWAIT isn't defined in any of the files that I looked at, but it is needed to prevent the call from blocking), and the msghdr struct differs from place to place, so we would need another avalanche of ifdefs. Still, when FIONREAD is not available, this is the only other known method of asking the OS for the *number* of characters available for reading. */ #ifdef V7 /* UNIX V7: look in kernel memory */ #ifdef MINIX n = 0; /* But not in MINIX */ #else #ifdef MINIX2 n = 0; #else lseek(kmem[TTY], (long) qaddr[TTY], 0); /* 7th Edition Unix */ x = read(kmem[TTY], &n, sizeof(int)); if (x != sizeof(int)) n = 0; #endif /* MINIX2 */ #endif /* MINIX */ #else /* Not V7 */ #ifdef PROVX1 x = ioctl(fd, TIOCQCNT, &ttbuf); /* DEC Pro/3xx Venix V.1 */ n = ttbuf.sg_ispeed & 0377; /* Circa 1984 */ if (x < 0) n = 0; #else #ifdef MYREAD /* Here we skip all the undependable and expensive calls below if we already have something in our internal buffer. This tends to work quite nicely, so the only really bad case remaining is the one in which neither FIONREAD or MYREAD are defined, which is increasingly rare these days. */ if (channel != 0 && my_count > 0) { debug(F101,"in_chk buf my_count","",my_count); n = my_count; /* n was 0 before we got here */ return(n); } #endif /* MYREAD */ /* rdchk(), select(), and poll() tell us *if* data is available to be read, but not how much, so these should be used only as a final resort. Especially since these calls tend to add a lot overhead. */ #ifdef RDCHK /* This mostly SCO-specific */ n = rdchk(fd); debug(F101,"in_chk rdchk","",n); #else /* No RDCHK */ #ifdef SELECT #ifdef Plan9 /* Only allows select on the console ... don't ask */ if (channel == 0) #endif /* Plan9 */ { fd_set rfds; /* Read file descriptors */ #ifdef BELLV10 FD_ZERO(rfds); /* Initialize them */ FD_SET(fd,rfds); /* We want to look at this fd */ #else FD_ZERO(&rfds); /* Initialize them */ FD_SET(fd,&rfds); /* We want to look at this fd */ tv.tv_sec = tv.tv_usec = 0L; /* A 0-valued timeval structure */ #endif /* BELLV10 */ #ifdef Plan9 n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"in_chk Plan 9 select","",n); #else #ifdef BELLV10 n = select( 128, rfds, (fd_set *)0, (fd_set *)0, 0 ); debug(F101,"in_chk BELLV10 select","",n); #else #ifdef BSD44 n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"in_chk BSD44 select","",n); #else #ifdef BSD43 n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"in_chk BSD43 select","",n); #else #ifdef SOLARIS n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"in_chk SOLARIS select","",n); #else #ifdef QNX6 n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"in_chk QNX6 select","",n); #else #ifdef QNX n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"in_chk QNX select","",n); #else #ifdef COHERENT n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"in_chk COHERENT select","",n); #else #ifdef SVR4 n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"in_chk SVR4 select","",n); #else #ifdef __linux__ n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"in_chk LINUX select","",n); #ifdef OSF n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"in_chk OSF select","",n); #else n = select( FD_SETSIZE, &rfds, (int *)0, (int *)0, &tv ); debug(F101,"in_chk catchall select","",n); #endif /* OSF */ #endif /* __linux__ */ #endif /* SVR4 */ #endif /* COHERENT */ #endif /* QNX */ #endif /* QNX6 */ #endif /* SOLARIS */ #endif /* BSD43 */ #endif /* BSD44 */ #endif /* BELLV10 */ #endif /* Plan9 */ } #else /* Not SELECT */ #ifdef CK_POLL { struct pollfd pfd; pfd.fd = fd; pfd.events = POLLIN; pfd.revents = 0; n = poll(&pfd, 1, 0); debug(F101,"in_chk poll","",n); if ((n > 0) && (pfd.revents & POLLIN)) n = 1; } #endif /* CK_POLL */ #endif /* SELECT */ #endif /* RDCHK */ #endif /* PROVX1 */ #endif /* V7 */ #endif /* FIONREAD */ /* From here down, treat console and communication device differently... */ if (channel == 0) { /* Console */ #ifdef SVORPOSIX #ifndef FIONREAD #ifndef SELECT #ifndef CK_POLL #ifndef RDCHK /* This is the hideous hack used in System V and POSIX systems that don't support FIONREAD, rdchk(), select(), poll(), etc, in which the user's CONNECT-mode escape character is attached to SIGQUIT. Used, obviously, only on the console. */ if (conesc) { /* Escape character typed == SIGQUIT */ debug(F100,"in_chk conesc","",conesc); conesc = 0; signal(SIGQUIT,esctrp); /* Restore signal */ n += 1; } #endif /* RDCHK */ #endif /* CK_POLL */ #endif /* SELECT */ #endif /* FIONREAD */ #endif /* SVORPOSIX */ return(n); /* Done with console */ } if (channel != 0) { /* Communications connection */ #ifdef MYREAD #ifndef FIONREAD /* select() or rdchk(), etc, has told us that something is waiting, but we don't know how much. So we do a read to get it and then we know. Note: This read is NOT nonblocking if nothing is there (because of VMIN=1), but it should be safe in this case since the OS tells us at least one byte is waiting to be read, and MYREAD reads return as much as is there without waiting for any more. Controlled tests on Solaris and Unixware (with FIONREAD deliberately undefined) show this to be true. */ debug(F101,"in_chk read my_count","",my_count); debug(F101,"in_chk read n","",n); if (n > 0 && my_count == 0) { /* This also catches disconnects etc */ /* Do what mygetbuf does except don't grab a character */ my_count = myfillbuf(); my_item = -1; /* ^^^ */ debug(F101,"in_chk myfillbuf my_count","",my_count); if (my_count < 0) return(-1); else n = 0; /* NB: n is replaced by my_count */ } #endif /* FIONREAD */ /* Here we add whatever we think is unread to what is still in our our internal buffer. Thus the importance of setting n to 0 just above. */ debug(F101,"in_chk my_count","",my_count); debug(F101,"in_chk n","",n); if (my_count > 0) n += my_count; #endif /* MYREAD */ } debug(F101,"in_chk result","",n); /* Errors here don't prove the connection has dropped so just say 0 */ return(n < 0 ? 0 : n); } /* T T C H K -- Tell how many characters are waiting in tty input buffer */ int ttchk() { int fd; #ifdef NETCMD if (ttpipe) fd = fdin; else #endif /* NETCMD */ fd = ttyfd; return(in_chk(1,fd)); } /* T T X I N -- Get n characters from tty input buffer */ /* Returns number of characters actually gotten, or -1 on failure */ /* Intended for use only when it is known that n characters are actually */ /* Available in the input buffer. */ int #ifdef CK_ANSIC ttxin( int n, CHAR *buf ) #else ttxin(n,buf) int n; CHAR *buf; #endif /* CK_ANSIC */ { register int x = 0, c = -2; #ifdef TTLEBUF register int i = 0; #endif /* TTLEBUF */ int fd; if (n < 1) /* Nothing to do */ return(0); #ifdef TTLEBUF if (ttpush >= 0) { buf[0] = ttpush; /* Put pushed char in buffer*/ ttpush = -1; /* Clear the push buffer */ if (ttchk() > 0) return(ttxin(n-1, &buf[1]) + 1); else return(1); } if (le_data) { while (le_inbuf() > 0) { if (le_getchar(&buf[i])) { i++; n--; } } if (ttchk() > 0) return(ttxin(n,&buf[i])+i); else return(i); } #endif /* TTLEBUF */ #ifdef NETCMD if (ttpipe) fd = fdin; else #endif /* NETCMD */ fd = ttyfd; #ifdef SUNX25 if (netconn && (ttnet == NET_SX25)) /* X.25 connection */ return(x25xin(n,buf)); #endif /* SUNX25 */ #ifdef IBMX25 /* riehm: possibly not needed. Test worked with normal reads and writes */ if (netconn && (ttnet == NET_IX25)) { /* X.25 connection */ x = x25xin(n,buf); if (x > 0) buf[x] = '\0'; return(x); } #endif /* IBMX25 */ #ifdef MYREAD debug(F101,"ttxin MYREAD","",n); while (x < n) { c = myread(); if (c < 0) { debug(F101,"ttxin myread returns","",c); if (c == -3) x = -1; break; } buf[x++] = c & ttpmsk; #ifdef RLOGCODE #ifdef CK_KERBEROS /* It is impossible to know how many characters are waiting */ /* to be read when you are using Encrypted Rlogin or SSL */ /* as the transport since the number of real data bytes */ /* can be greater or less than the number of bytes on the */ /* wire which is what ttchk() returns. */ if (netconn && (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN)) if (ttchk() <= 0) break; #endif /* CK_KERBEROS */ #endif /* RLOGCODE */ #ifdef CK_SSL if (ssl_active_flag || tls_active_flag) if (ttchk() <= 0) break; #endif /* CK_SSL */ } #else debug(F101,"ttxin READ","",n); x = read(fd,buf,n); for (c = 0; c < n; c++) /* Strip any parity */ buf[c] &= ttpmsk; #endif /* MYREAD */ debug(F101,"ttxin x","",x); /* Done */ if (x > 0) buf[x] = '\0'; if (x < 0) x = -1; return(x); } /* T T O L -- Write string s, length n, to communication device. */ /* Returns: >= 0 on success, number of characters actually written. -1 on failure. */ #ifdef CK_ENCRYPTION CHAR * xpacket = NULL; int nxpacket = 0; #endif /* CK_ENCRYPTION */ #define TTOLMAXT 5 int #ifdef CK_ANSIC ttol( CHAR *s, int n ) #else ttol(s,n) int n; CHAR *s; #endif /* CK_ANSIC */ { int x, len, tries, fd; #ifdef CKXXCHAR extern int dblflag; /* For SET SEND DOUBLE-CHARACTER */ extern short dblt[]; CHAR *p = NULL, *p2, *s2, c; int n2 = 0; #endif /* CKXXCHAR */ if (ttyfd < 0) /* Not open? */ return(-3); #ifdef DEBUG if (deblog) { /* debug(F101,"ttol ttyfd","",ttyfd); */ ckhexdump("ttol s",s,n); } #endif /* DEBUG */ #ifdef NETCMD if (ttpipe) fd = fdout; else #endif /* NETCMD */ fd = ttyfd; #ifdef CKXXCHAR /* Double any characters that must be doubled. */ debug(F101,"ttol dblflag","",dblflag); if (dblflag) { p = (CHAR *) malloc(n + n + 1); if (p) { s2 = s; p2 = p; n2 = 0; while (*s2) { c = *s2++; *p2++ = c; n2++; if (dblt[(unsigned) c] & 2) { *p2++ = c; n2++; } } s = p; n = n2; s[n] = '\0'; } #ifdef DEBUG ckhexdump("ttol doubled s",s,n); #endif /* DEBUG */ } #endif /* CKXXCHAR */ tries = TTOLMAXT; /* Allow up to this many tries */ len = n; /* Remember original length */ #ifdef CK_ENCRYPTION /* This is to avoid encrypting a packet that is already encrypted, e.g. when we resend a packet directly out of the packet buffer, and also to avoid encrypting a constant (literal) string, which can cause a memory fault. */ if (TELOPT_ME(TELOPT_ENCRYPTION)) { int x; if (nxpacket < n) { if (xpacket) { free(xpacket); xpacket = NULL; nxpacket = 0; } x = n > 10240 ? n : 10240; xpacket = (CHAR *)malloc(x); if (!xpacket) { fprintf(stderr,"ttol malloc failure\n"); return(-1); } else nxpacket = x; } memcpy((char *)xpacket,(char *)s,n); s = xpacket; ck_tn_encrypt((char *)s,n); } #endif /* CK_ENCRYPTION */ while (n > 0 && (tries-- > 0 #ifdef CK_ENCRYPTION /* keep trying if we are encrypting */ || TELOPT_ME(TELOPT_ENCRYPTION) #endif /* CK_ENCRYPTION */ )) { /* Be persistent */ debug(F101,"ttol try","",TTOLMAXT - tries); #ifdef BEOSORBEBOX if (netconn && !ttpipe && !ttpty) x = nettol((char *)s,n); /* Write string to device */ else #endif /* BEOSORBEBOX */ #ifdef IBMX25 if (ttnet == NET_IX25) /* * this is a more controlled way of writing to X25 * STREAMS, however write should also work! */ x = x25write(ttyfd, s, n); else #endif /* IBMX25 */ #ifdef CK_SSL if (ssl_active_flag || tls_active_flag) { int error; /* Write using SSL */ ssl_retry: if (ssl_active_flag) x = SSL_write(ssl_con, s, n); else x = SSL_write(tls_con, s, n); switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) { case SSL_ERROR_NONE: if (x == n) return(len); s += x; n -= x; goto ssl_retry; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: x = 0; break; case SSL_ERROR_SYSCALL: if (x != 0) return(-1); case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: ttclos(0); return(-3); } } else #endif /* CK_SSL */ #ifdef CK_KERBEROS #ifdef KRB4 #ifdef RLOGCODE if (ttnproto == NP_EK4LOGIN) { return(krb4_des_write(ttyfd,s,n)); } else #endif /* RLOGCODE */ #endif /* KRB4 */ #ifdef KRB5 #ifdef RLOGCODE if (ttnproto == NP_EK5LOGIN) { return(krb5_des_write(ttyfd,(char *)s,n,0)); } else #endif /* RLOGCODE */ #ifdef KRB5_U2U if (ttnproto == NP_K5U2U) { return(krb5_u2u_write(ttyfd,(char *)s,n)); } else #endif /* KRB5_U2U */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ x = write(fd,s,n); /* Write string to device */ if (x == n) { /* Worked? */ debug(F101,"ttol ok","",x); /* OK */ #ifdef CKXXCHAR if (p) free(p); #endif /* CKXXCHAR */ return(len); /* Done */ } else if (x < 0) { /* No, got error? */ debug(F101,"ttol write error","",errno); #ifdef EWOULDBLOCK if (errno == EWOULDBLOCK) { msleep(10); continue; } else #endif /* EWOULDBLOCK */ #ifdef TCPSOCKET if (netconn && ttnet == NET_TCPB) { debug(F101,"ttol TCP error","",errno); ttclos(0); /* Close the connection. */ x = -3; } #endif /* TCPSOCKET */ #ifdef CKXXCHAR if (p) free(p); #endif /* CKXXCHAR */ return(x); } else { /* No error, so partial success */ debug(F101,"ttol partial","",x); /* This never happens */ s += x; /* Point to part not written yet */ n -= x; /* Adjust length */ if (x > 0) msleep(10); /* Wait 10 msec */ } /* Go back and try again */ } #ifdef CKXXCHAR if (p) free(p); #endif /* CKXXCHAR */ return(n < 1 ? len : -1); /* Return the results */ } /* T T O C -- Output a character to the communication line */ /* 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. */ int #ifdef CK_ANSIC ttoc(char c) #else ttoc(c) char c; #endif /* CK_ANSIC */ /* ttoc */ { #define TTOC_TMO 15 /* Timeout in case we get stuck */ int xx, fd; if (ttyfd < 0) /* Check for not open. */ return(-1); #ifdef NETCMD if (ttpipe) fd = fdout; else #endif /* NETCMD */ fd = ttyfd; c &= 0xff; /* debug(F101,"ttoc","",(CHAR) c); */ saval = signal(SIGALRM,timerh); /* Enable timer interrupt */ xx = alarm(TTOC_TMO); /* for this many seconds. */ if (xx < 0) xx = 0; /* Save old alarm value. */ /* debug(F101,"ttoc alarm","",xx); */ if ( #ifdef CK_POSIX_SIG sigsetjmp(sjbuf,1) #else setjmp(sjbuf) #endif /* CK_POSIX_SIG */ ) { /* Timer went off? */ ttimoff(); /* Yes, cancel this alarm. */ if (xx - TTOC_TMO > 0) alarm(xx - TTOC_TMO); /* Restore previous one */ /* debug(F100,"ttoc timeout","",0); */ #ifdef NETCONN if (!netconn) { #endif /* NETCONN */ debug(F101,"ttoc timeout","",c); if (ttflow == FLO_XONX) { debug(F101,"ttoc flow","",ttflow); /* Maybe we're xoff'd */ #ifndef Plan9 #ifdef POSIX /* POSIX way to unstick. */ debug(F100,"ttoc tcflow","",tcflow(ttyfd,TCOON)); #else #ifdef BSD4 /* Berkeley way to do it. */ #ifdef TIOCSTART /* .... Used to be "ioctl(ttyfd, TIOCSTART, 0);". Who knows? */ { int x = 0; debug(F101,"ttoc TIOCSTART","",ioctl(ttyfd, TIOCSTART, &x)); } #endif /* TIOCSTART */ #endif /* BSD4 */ /* Is there a Sys V way to do this? */ #endif /* POSIX */ #endif /* Plan9 */ } #ifdef NETCONN } #endif /* NETCONN */ return(-1); /* Return failure code. */ } else { int rc; #ifdef BEOSORBEBOX #ifdef NETCONN if (netconn && !ttpipe && !ttpty) rc = nettoc(c); else #endif /* BEOSORBEBOX */ #endif /* NETCONN */ #ifdef CK_ENCRYPTION if (TELOPT_ME(TELOPT_ENCRYPTION)) ck_tn_encrypt(&c,1); #endif /* CK_ENCRYPTION */ #ifdef IBMX25 /* riehm: maybe this isn't necessary after all. Test program * worked fine with data being sent and retrieved with normal * read's and writes! */ if (ttnet == NET_IX25) rc = x25write(ttyfd,&c,1); /* as above for X25 streams */ else #endif /* IBMX25 */ #ifdef CK_SSL if (ssl_active_flag || tls_active_flag) { int error; /* Write using SSL */ if (ssl_active_flag) rc = SSL_write(ssl_con, &c, 1); else rc = SSL_write(tls_con, &c, 1); switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)){ case SSL_ERROR_NONE: break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: rc = 0; break; case SSL_ERROR_SYSCALL: if (rc != 0) return(-1); case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: ttclos(0); return(-1); } } else #endif /* CK_SSL */ #ifdef CK_KERBEROS #ifdef KRB4 #ifdef RLOGCODE if (ttnproto == NP_EK4LOGIN) { rc = (krb4_des_write(ttyfd,(char *)&c,1) == 1); } else #endif /* RLOGCODE */ #endif /* KRB4 */ #ifdef KRB5 #ifdef RLOGCODE if (ttnproto == NP_EK5LOGIN) { rc = (krb5_des_write(ttyfd,&c,1,0) == 1); } else #endif /* RLOGCODE */ #ifdef KRB5_U2U if (ttnproto == NP_K5U2U) { rc = (krb5_u2u_write(ttyfd,&c,1) == 1); } else #endif /* KRB5_U2U */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ rc = write(fd,&c,1); /* Try to write the character. */ if (rc < 1) { /* Failed */ ttimoff(); /* Turn off the alarm. */ alarm(xx); /* Restore previous alarm. */ debug(F101,"ttoc errno","",errno); /* Log the error, */ return(-1); /* and return the error code. */ } } ttimoff(); /* Success, turn off the alarm. */ alarm(xx); /* Restore previous alarm. */ return(0); /* Return good code. */ } /* T T I N L -- Read a record (up to break character) from comm line. */ /* Reads up to "max" characters from the connection, terminating on: (a) the packet length field if the "turn" argument is zero, or (b) on the packet-end character (eol) if the "turn" argument is nonzero (c) a certain number of Ctrl-C's in a row Returns: >= 0, the number of characters read upon success; -1 if "max" exceeded, timeout, or other correctable error; -2 on user interruption (c); -3 on fatal error like connection lost. The name of this routine dates from the early days when Kermit packets were, indeed, always lines of text. That was before control-character unprefixing and length-driven packet framing were introduced, which this version handle. NB: this routine is ONLY for reading incoming Kermit packets, nothing else. To read other kinds of incoming material, use ttinc() or ttxin(). The bytes that were input are copied into "dest" with their parity bits stripped if parity was selected. Returns the number of bytes read. Bytes after the eol are available upon the next call to this function. The idea is to minimize the number of system calls per packet, and also to minimize timeouts. This function is the inner loop of the protocol and must be as efficient as possible. The current strategy is to use myread(), a macro to manage buffered (and generally nonblocking) reads. WARNING: This function calls parchk(), which is defined in another module. Normally, ckutio.c does not depend on code from any other module, but there is an exception in this case because all the other ck?tio.c modules also need to call parchk(), so it's better to have it defined in a common place. */ #ifdef CTRLC #undef CTRLC #endif /* CTRLC */ #define CTRLC '\03' /* We have four different declarations here because: (a) to allow Kermit to be built without the automatic parity sensing feature (b) one of each type for ANSI C, one for non-ANSI. */ #ifndef NOXFER static int pushedback = 0; int #ifdef PARSENSE #ifdef CK_ANSIC ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn) #else ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start; #endif /* CK_ANSIC */ #else /* not PARSENSE */ #ifdef CK_ANSIC ttinl(CHAR *dest, int max,int timo, CHAR eol) #else ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol; #endif /* CK_ANSIC */ #endif /* PARSENSE */ /* ttinl */ { #ifndef MYREAD CHAR ch, dum; #endif /* MYREAD */ #ifdef PARSENSE int pktlen = -1; int lplen = 0; int havelen = 0; #endif /* PARSENSE */ int fd; int sopmask = 0xff; /* Start-Of-Packet mask */ #ifdef CKXXCHAR extern short dblt[]; /* Ignore-character table */ extern int ignflag; #endif /* CKXXCHAR */ #ifdef TCPSOCKET extern CHAR stchr; #endif /* TCPSOCKET */ int x; #ifdef STREAMING extern int streaming; extern int sndtyp; #endif /* STREAMING */ if (ttyfd < 0) return(-3); /* Not open. */ /* In February 2007 I fixed ttinl() to work better under the truly awful conditions encountered by the AM-APEX oceanographic floats that gather hurricane data and phone home using Iridium satellite modems, which under certain conditions, can send two packets back to back after a long pause. In this case the second packet would be ignored because the SOH was skipped due to the ttflui() call. But the reworked lookahead/pushback logic broke Kermit transfers on encrypted connections. This was fixed 12-13 August 2007. All of this happened after 8.0.212 Dev.27 was released and before Dev.28, so no harm done other than the delay. */ debug(F101,"ttinl max","",max); debug(F101,"ttinl timo","",timo); #ifdef NETCMD if (ttpipe) fd = fdin; else #endif /* NETCMD */ fd = ttyfd; #ifdef COMMENT if (xlocal && conchk() > 0) /* Allow for console interruptions */ return(-1); #endif /* COMMENT */ *dest = '\0'; /* Clear destination buffer */ if (timo < 0) timo = 0; /* Safety */ if (timo) { /* Don't time out if timo == 0 */ int xx; saval = signal(SIGALRM,timerh); /* Enable timer interrupt */ xx = alarm(timo); /* Set it. */ debug(F101,"ttinl alarm","",xx); } if ( #ifdef CK_POSIX_SIG sigsetjmp(sjbuf,1) #else setjmp(sjbuf) #endif /* CK_POSIX_SIG */ ) { /* Timer went off? */ debug(F100,"ttinl timout","",0); /* Get here on timeout. */ /* debug(F110," with",(char *) dest,0); */ ttimoff(); /* Turn off timer */ return(-1); /* and return error code. */ } else { register int i, n = -1; /* local variables */ int ccn = 0; #ifdef PARSENSE register int flag = 0; debug(F000,"ttinl start","",start); #endif /* PARSENSE */ ttpmsk = ttprty ? 0177 : 0377; /* Set parity stripping mask. */ sopmask = needpchk ? 0177 : ttpmsk; /* And SOP matching mask. */ /* Now read into destination, stripping parity and looking for the */ /* the packet terminator, and also for several Ctrl-C's typed in a row. */ i = 0; /* Destination index */ debug(F101,"ttinl eol","",eol); while (i < max-1) { #ifdef MYREAD errno = 0; /* On encrypted connections myread returns encrypted bytes */ n = myread(); debug(F000,"TTINL myread char","",n); if (n < 0) { /* Timeout or i/o error? */ #ifdef DEBUG if (deblog) { debug(F101,"ttinl myread failure, n","",n); debug(F101,"ttinl myread errno","",errno); } #endif /* DEBUG */ /* Don't let EINTR break packets. */ if (n == -3) { if (errno == EINTR && i > 0) { debug(F111,"ttinl EINTR myread i","continuing",i); continue; } else { debug(F110,"ttinl non-EINTR -3","closing",0); wasclosed = 1; ttimoff(); /* Turn off timer */ ttclos(0); return(n); } } else if (n == -2 && netconn /* && timo == 0 */ ) { /* Here we try to catch broken network connections */ /* even when ioctl() and read() do not catch them */ debug(F111,"ttinl network myread failure","closing",n); wasclosed = 1; ttimoff(); ttclos(0); return(-3); } #ifdef STREAMING /* Streaming and no data to read */ else if (n == 0 && streaming && sndtyp == 'D') return(0); #endif /* STREAMING */ break; /* Break out of while loop */ } #else /* not MYREAD (is this code used anywhere any more?) */ /* The non-MYREAD code dates from the 1980s and was needed on certain platforms where there were no nonblocking reads. -fdc, 2007/02/22. */ if ((n = read(fd, &n, 1)) < 1) break; /* Error - break out of while loop */ #endif /* MYREAD */ /* Get here with char in n */ #ifdef CK_ENCRYPTION if (TELOPT_U(TELOPT_ENCRYPTION) && !pushedback) { CHAR ch = n; ck_tn_decrypt((char *)&ch,1); n = ch; debug(F000,"TTINL decryp char","",n); } pushedback = 0; #endif /* CK_ENCRYPTION */ #ifdef TCPSOCKET if (n == IAC && /* Handle Telnet options */ ((xlocal && netconn && IS_TELNET()) || (!xlocal && sstelnet))) { n = tt_tnopt(n); if (n < 0) return(n); #ifndef NOPARSEN else if (n == 1) start = stchr; #endif /* NOPARSEN */ if (n != 255) /* No data - go back for next char */ continue; } /* Quoted IAC - keep going */ #endif /* TCPSOCKET */ #ifdef CKXXCHAR if (ignflag) if (dblt[(unsigned) n] & 1) /* Character to ignore? */ continue; #endif /* CKXXCHAR */ /* Use parity mask, rather than always stripping parity, to check for cancellation. Otherwise, runs like \x03\x83\x03 in a packet could cancel the transfer when parity is NONE. (Note that \x03\x03\x03 is extremely unlikely due to run-length encoding.) */ /* Check cancellation */ if (!xlocal && xfrcan && ((n & ttpmsk) == xfrchr)) { if (++ccn >= xfrnum) { /* If xfrnum in a row, bail out. */ if (timo) { /* Clear timer. */ ttimoff(); } if (xfrchr < 32) printf("^%c...\r\n",(char)(xfrchr+64)); else printf("Canceled...\r\n"); return(-2); } } else ccn = 0; /* No cancellation, reset counter, */ #ifdef PARSENSE /* Restructured code allows for a new packet to appear somewhere in the middle of a previous one. -fdc, 24 Feb 2007. */ if ((n & sopmask) == start) { /* Start of Packet */ debug(F101,"ttinl SOP i","",i); flag = 1; /* Flag that we are in a packet */ havelen = 0; /* Invalidate previous length */ pktlen = -1; /* (if any) in case we were */ lplen = 0; /* alread processand a packet */ i = 0; /* and reset the dest buffer pointer */ } if (flag == 0) { /* No SOP yet... */ debug(F000,"ttinl skipping","",n); continue; } dest[i++] = n & ttpmsk; /* If we have not been instructed to wait for a turnaround character, we can go by the packet length field. If turn != 0, we must wait for the end of line (eol) character before returning. This is an egregious violation of all principles of layering... (Less egregious in C-Kermit 9.0, in which we go by the length field but also look for the eol in case it arrives early, e.g. if the length field was corrupted upwards.) */ if (!havelen) { if (i == 2) { if ((dest[1] & 0x7f) < 32) /* Garbage in length field */ return(-1); /* fdc - 13 Apr 2010 */ pktlen = xunchar(dest[1] & 0x7f); if (pktlen > 94) /* Rubout in length field */ return(-1); /* fdc - 13 Apr 2010 */ if (pktlen > 1) { havelen = 1; debug(F101,"ttinl pktlen value","",pktlen); } } else if (i == 5 && pktlen == 0) { lplen = xunchar(dest[4] & 0x7f); } else if (i == 6 && pktlen == 0) { pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5; havelen = 1; debug(F101,"ttinl extended length","",pktlen); } } /* Suppose we looked at the sequence number here and found it was out of range? This would mean either (a) incoming packets had SOP unprefixed and we are out of sync, or (b) the packet is damaged. Since (a) is bad practice, let's ignore it. So what should we do here if we know the packet is damaged? 1. Nothing -- keep trying to read the packet till we find what we think is the end, or we time out, and let the upper layer decide what to do. But since either the packet is corrupt or we are out of sync, our criterion for finding the end does not apply and we are likely to time out (or swallow a piece of the next packet) if our assumed length is too long. (This was the behavior prior to version 7.0.) 2. set flag = 0 and continue? This would force us to wait for the next packet to come in, and therefore (in the nonwindowing case), would force a timeout in the other Kermit. 3. set flag = 0 and continue, but only if the window size is > 1 and the window is not blocked? Talk about cheating! 4. Return a failure code and let the upper layer decide what to do. This should be equivalent to 3, but without the cheating. So let's do it that way... But note that we must ignore the parity bit in case this is the first packet and we have not yet run parchk(). */ if (i == 3) { /* Peek at sequence number */ x = xunchar((dest[i-1] & 0x7f)); /* If it's not in range... */ if (x < 0 || x > 63) { debug(F111,"ttinl bad seq",dest,x); if (timo) ttimoff(); return(-1); /* return a nonfatal error */ } } #else /* PARSENSE */ dest[i++] = n & ttpmsk; #endif /* PARSENSE */ /* Check for end of packet */ if ( ((n & ttpmsk) == eol) /* Always break on the eol char */ #ifdef PARSENSE || /* fdc - see notes of 13 Apr 2010 */ /* Purely length-driven if SET HANDSHAKE NONE (i.e. turn == 0). This allows packet terminators and handshake characters to appear literally inside a packet data field. */ (havelen && (i > pktlen+1) && (!turn || (turn && (n & 0x7f) == turn))) /* (turn, not eol) */ #endif /* PARSENSE */ ) { /* Here we have either read the last byte of the packet based on its length field, or else we have read the packet terminator (eol) or the half-duplex line-turnaround char (turn). */ #ifndef PARSENSE debug(F101,"ttinl got eol","",eol); /* (or turn) */ dest[i] = '\0'; /* Yes, terminate the string, */ /* debug(F101,"ttinl i","",i); */ #else /* PARSENSE */ #ifdef DEBUG if (deblog) { if ((n & ttpmsk) != eol) { debug(F101,"ttinl EOP length","",pktlen); debug(F000,"ttinl EOP current char","",n); debug(F101,"ttinl EOP packet buf index","",i); } else debug(F101,"ttinl got eol","",eol); } #endif /* DEBUG */ #ifdef MYREAD /* The packet was read based on its length. This leaves the packet terminator unread, and so ttchk() will always return at least 1 because of this, possibly giving a false positive to the "is there another packet waiting?" test. But if we know the terminator (or any other interpacket junk) is there, we can safely get rid of it. NOTE: This code reworked to (a) execute even if the debug log isn't active; and (b) actually work. -fdc, 2007/02/22. And again 2007/08/12-13 to also work on encrypted connections. */ debug(F101,"TTINL my_count","",my_count); if ((n & ttpmsk) != eol) { /* Not the packet terminator */ int x; while (my_count > 0) { x = myread(); /* (was ttinc(0) */ debug(F000,"TTINL lkread char","",x); #ifdef CK_ENCRYPTION if (TELOPT_U(TELOPT_ENCRYPTION)) { CHAR ch = x; ck_tn_decrypt((char *)&ch,1); x = ch; debug(F000,"TTINL lkdecr char","",x); } #endif /* CK_ENCRYPTION */ /* Note: while it might seem more elegant to simply push back the encrypted byte, that desynchronizes the decryption stream; the flag is necessary so we don't try to decrypt the same byte twice. */ if ((x & ttpmsk) == start) { /* Start of next packet */ myunrd(x); /* Push back the decrypted byte */ pushedback = 1; /* And set flag */ debug(F000,"TTINL lkpush char","",x); break; } } } #endif /* MYREAD */ dest[i] = '\0'; /* Terminate the string, */ if (needpchk) { /* Parity checked yet? */ if (ttprty == 0) { /* No, check. */ if ((ttprty = parchk(dest,start,i)) > 0) { int j; debug(F101,"ttinl senses parity","",ttprty); debug(F110,"ttinl packet before",dest,0); ttpmsk = 0x7f; for (j = 0; j < i; j++) dest[j] &= 0x7f; /* Strip parity from packet */ debug(F110,"ttinl packet after ",dest,0); } else ttprty = 0; /* Restore if parchk error */ } sopmask = ttpmsk; needpchk = 0; } #endif /* PARSENSE */ if (timo) /* Turn off timer if it was on */ ttimoff(); ckhexdump("ttinl got",dest,i); #ifdef STREAMING /* ttinl() was called because there was non-packet */ /* data sitting in the back channel. Ignore it. */ if (streaming && sndtyp == 'D') return(-1); #endif /* STREAMING */ return(i); } } /* End of while() */ ttimoff(); return(n); } } #endif /* NOXFER */ /* T T I N C -- Read a character from the communication line */ /* On success, returns the character that was read, >= 0. On failure, returns -1 or other negative myread error code, or -2 if connection is broken or ttyfd < 0. or -3 if session limit has expired, or -4 if something or other... NOTE: The API does not provide for ttinc() returning a special code upon timeout, but we need it. So for this we have a global variable, ttinctimo. */ static int ttinctimo = 0; /* Yuk */ int #ifdef CK_ANSIC ttinc( int timo ) #else ttinc(timo) int timo; #endif /* CK_ANSIC */ { int n = 0, fd; int is_tn = 0; CHAR ch = 0; ttinctimo = 0; if (ttyfd < 0) return(-2); /* Not open. */ is_tn = (xlocal && netconn && IS_TELNET()) || (!xlocal && sstelnet); #ifdef TTLEBUF if (ttpush >= 0) { debug(F111,"ttinc","ttpush",ttpush); ch = ttpush; ttpush = -1; return(ch); } if (le_data) { if (le_getchar(&ch) > 0) { debug(F111,"ttinc le_getchar","ch",ch); return(ch); } } #endif /* TTLEBUF */ #ifdef NETCMD if (ttpipe) fd = fdin; else #endif /* NETCMD */ fd = ttyfd; if ((timo <= 0) /* Untimed. */ #ifdef MYREAD || (my_count > 0) /* Buffered char already waiting. */ #endif /* MYREAD */ ) { #ifdef MYREAD /* Comm line failure returns -1 thru myread, so no &= 0377 */ n = myread(); /* Wait for a character... */ /* debug(F000,"ttinc MYREAD n","",n); */ #ifdef CK_ENCRYPTION /* debug(F101,"ttinc u_encrypt","",TELOPT_U(TELOPT_ENCRYPTION)); */ if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) { ch = n; ck_tn_decrypt((char *)&ch,1); n = ch; } #endif /* CK_ENCRYPTION */ #ifdef NETPTY if (ttpty && n < 0) { debug(F101,"ttinc error on pty","",n); ttclos(0); return(n); } #endif /* NETPTY */ #ifdef TNCODE if ((n > -1) && is_tn) return((unsigned)(n & 0xff)); else #endif /* TNCODE */ return(n < 0 ? n : (unsigned)(n & ttpmsk)); #else /* MYREAD */ while ((n = read(fd,&ch,1)) == 0) /* Wait for a character. */ /* Shouldn't have to loop in ver 5A. */ debug(F110,"XXX netclos in ifdef NETCONN...","B",0); #ifdef NETCONN debug(F110,"XXX netclos in ifdef NETCONN...OK","B",0); if (netconn) { /* Special handling for net */ netclos(); /* If read() returns 0 it means */ netconn = 0; /* the connection has dropped. */ errno = ENOTCONN; return(-2); } #endif /* NETCONN */ ; /* debug(F101,"ttinc","",ch); */ #ifdef TNCODE if ((n > 0) && is_tn) { #ifdef CK_ENCRYPTION if (TELOPT_U(TELOPT_ENCRYPTION)) { ck_tn_decrypt(&ch,1); n = ch; } #endif /* CK_ENCRYPTION */ return((unsigned)(ch & 0xff)); } else #endif /* TNCODE */ return((n < 0) ? -4 : ((n == 0) ? -1 : (unsigned)(ch & ttpmsk))); #endif /* MYREAD */ } else { /* Timed read */ int oldalarm; saval = signal(SIGALRM,timerh); /* Set up handler, save old one. */ oldalarm = alarm(timo); /* Set alarm, save old one. */ if ( #ifdef CK_POSIX_SIG sigsetjmp(sjbuf,1) #else setjmp(sjbuf) #endif /* CK_POSIX_SIG */ ) { /* Timer expired */ ttinctimo = 1; n = -1; /* set flag */ } else { #ifdef MYREAD n = myread(); /* If managing own buffer... */ debug(F101,"ttinc myread","",n); ch = n; #else n = read(fd,&ch,1); /* Otherwise call the system. */ if (n == 0) n = -1; debug(F101,"ttinc read","",n); #endif /* MYREAD */ #ifdef CK_ENCRYPTION if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) { ck_tn_decrypt((char *)&ch,1); } #endif /* CK_ENCRYPTION */ if (n >= 0) n = (unsigned) (ch & 0xff); else n = (n < 0) ? -4 : -2; /* Special return codes. */ } ttimoff(); /* Turn off the timer */ if (oldalarm > 0) { if (n == -1) /* and restore any previous alarm */ oldalarm -= timo; if (oldalarm < 0) /* adjusted by our timeout interval */ oldalarm = 0; if (oldalarm) { debug(F101,"ttinc restoring oldalarm","",oldalarm); alarm(oldalarm); } } debug(F110,"XXX netclos in ifdef NETCONN...","C",0); #ifdef NETCONN debug(F110,"XXX netclos in ifdef NETCONN...","C",0); if (netconn) { if (n == -2) { /* read() returns 0 */ netclos(); /* on network read failure */ netconn = 0; errno = ENOTCONN; } } #endif /* NETCONN */ #ifdef TNCODE if ((n > -1) && is_tn) return((unsigned)(n & 0xff)); else #endif /* TNCODE */ /* Return masked char or neg. */ return( (n < 0) ? n : (unsigned)(n & ttpmsk) ); } } /* S N D B R K -- Send a BREAK signal of the given duration */ static int #ifdef CK_ANSIC sndbrk(int msec) { /* Argument is milliseconds */ #else sndbrk(msec) int msec; { #endif /* CK_ANSIC */ #ifndef POSIX int x, n; #endif /* POSIX */ #ifdef OXOS #define BSDBREAK #endif /* OXOS */ #ifdef ANYBSD #define BSDBREAK #endif /* ANYBSD */ #ifdef BSD44 #define BSDBREAK #endif /* BSD44 */ #ifdef COHERENT #ifdef BSDBREAK #undef BSDBREAK #endif /* BSDBREAK */ #endif /* COHERENT */ #ifdef BELLV10 #ifdef BSDBREAK #undef BSDBREAK #endif /* BSDBREAK */ #endif /* BELLV10 */ #ifdef PROVX1 char spd; #endif /* PROVX1 */ debug(F101,"ttsndb ttyfd","",ttyfd); if (ttyfd < 0) return(-1); /* Not open. */ #ifdef Plan9 return p9sndbrk(msec); #else #ifdef NETCONN #ifdef NETCMD if (ttpipe) /* Pipe */ return(ttoc('\0')); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(ttoc('\0')); #endif /* NETPTY */ if (netconn) /* Send network BREAK */ return(netbreak()); #endif /* NETCONN */ if (msec < 1 || msec > 5000) return(-1); /* Bad argument */ #ifdef POSIX /* Easy in POSIX */ { int x; debug(F111,"sndbrk POSIX",ckitoa(msec),(msec/375)); errno = 0; x = tcsendbreak(ttyfd,msec / 375); debug(F111,"sndbrk tcsendbreak",ckitoa(errno),x); return(x); } #else #ifdef PROVX1 gtty(ttyfd,&ttbuf); /* Get current tty flags */ spd = ttbuf.sg_ospeed; /* Save speed */ ttbuf.sg_ospeed = B50; /* Change to 50 baud */ stty(ttyfd,&ttbuf); /* ... */ n = (int)strlen(brnuls); /* Send the right number of nulls */ x = msec / 91; if (x > n) x = n; write(ttyfd,brnuls,n); ttbuf.sg_ospeed = spd; /* Restore speed */ stty(ttyfd,&ttbuf); /* ... */ return(0); #else #ifdef aegis sio_$control((short)ttyfd, sio_$send_break, msec, st); return(0); #else #ifdef BSDBREAK n = FWRITE; /* Flush output queue. */ /* Watch out for int vs long problems in &n arg! */ debug(F101,"sndbrk BSDBREAK","",msec); ioctl(ttyfd,TIOCFLUSH,&n); /* Ignore any errors.. */ if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) { /* Turn on BREAK */ perror("Can't send BREAK"); return(-1); } x = msleep(msec); /* Sleep for so many milliseconds */ if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) { /* Turn off BREAK */ perror("BREAK stuck!!!"); doexit(BAD_EXIT,-1); /* Get out, closing the line. */ /* with bad exit status */ } return(x); #else #ifdef ATTSV /* No way to send a long BREAK in Sys V, so send a bunch of regular ones. (Actually, Sys V R4 is *supposed* to have the POSIX tcsendbreak() function, but there's no way for this code to know for sure.) */ debug(F101,"sndbrk ATTSV","",msec); x = msec / 275; for (n = 0; n < x; n++) { /* Reportedly the cast breaks this function on some systems */ /* But then why was it here in the first place? */ if (ioctl(ttyfd,TCSBRK, /* (char *) */ 0) < 0) { perror("Can't send BREAK"); return(-1); } } return(0); #else #ifdef V7 debug(F101,"sndbrk V7","",msec); return(genbrk(ttyfd,250)); /* Simulate a BREAK */ #else debug(F101,"sndbrk catchall","",msec); ttoc(0);ttoc(0);ttoc(0);ttoc(0); return(0); #endif /* V7 */ #endif /* BSDBREAK */ #endif /* ATTSV */ #endif /* aegis */ #endif /* PROVX1 */ #endif /* POSIX */ #endif /* Plan9 */ } /* T T S N D B -- Send a BREAK signal */ int ttsndb() { #ifdef TN_COMPORT if (netconn && istncomport()) return((tnsndb(275L) >= 0) ? 0 : -1); else #endif /* TN_COMPORT */ return(sndbrk(275)); } /* T T S N D L B -- Send a Long BREAK signal */ int ttsndlb() { #ifdef TN_COMPORT if (netconn && istncomport()) return((tnsndb(1800L) >= 0) ? 0 : -1); else #endif /* TN_COMPORT */ return(sndbrk(1500)); } /* M S L E E P -- Millisecond version of sleep(). */ /* Call with number of milliseconds (thousandths of seconds) to sleep. Intended only for small intervals. For big ones, just use sleep(). Highly system-dependent. Returns 0 always, even if it didn't work. */ /* Define MSLFTIME for systems that must use an ftime() loop. */ #ifdef ANYBSD /* For pre-4.2 BSD versions */ #ifndef BSD4 #define MSLFTIME #endif /* BSD4 */ #endif /* ANYBSD */ #ifdef TOWER1 /* NCR Tower OS 1.0 */ #define MSLFTIME #endif /* TOWER1 */ #ifdef COHERENT /* Coherent... */ #ifndef _I386 /* Maybe Coherent/386 should get this, too */ #define MSLFTIME /* Opinions are divided */ #endif /* _I386 */ #endif /* COHERENT */ #ifdef COMMENT #ifdef GETMSEC /* Millisecond timer */ static long msecbase = 0L; /* Unsigned long not portable */ long getmsec() { /* Milliseconds since base time */ struct timeval xv; struct timezone xz; long secs, msecs; if ( #ifdef GTODONEARG gettimeofday(&tv) #else #ifdef PTX gettimeofday(&tv, NULL) #else gettimeofday(&tv, &tz) #endif /* PTX */ #endif /* GTODONEARG */ < 0) return(-1); if (msecbase == 0L) { /* First call, set base time. */ msecbase = tv.tv_sec; debug(F101,"getmsec base","",msecbase); } return(((tv.tv_sec - msecbase) * 1000L) + (tv.tv_usec / 1000L)); } #endif /* GETMSEC */ #endif /* COMMENT */ #ifdef SELECT int #ifdef CK_ANSIC ttwait( int fd, int secs ) #else ttwait(fd, secs) int fd, secs; #endif /* CK_ANSIC */ { int x; fd_set rfds; FD_ZERO(&rfds); FD_SET(fd,&rfds); tv.tv_sec = secs; tv.tv_usec = 0L; errno = 0; if ((x = select(FD_SETSIZE, #ifdef HPUX9 (int *) #else #ifdef HPUX1000 (int *) #endif /* HPUX1000 */ #endif /* HPUX9 */ &rfds, 0, 0, &tv)) < 0) { debug(F101,"ttwait select errno","",errno); return(0); } else { debug(F101,"ttwait OK","",errno); x = FD_ISSET(fd, &rfds); debug(F101,"ttwait select x","",x); return(x ? 1 : 0); } } #endif /* SELECT */ int #ifdef CK_ANSIC msleep( int m ) #else msleep(m) int m; #endif /* CK_ANSIC */ { /* Other possibilities here are: nanosleep(), reportedly defined in POSIX.4. sginap(), IRIX only (back to what IRIX version I don't know). */ #ifdef Plan9 return _SLEEP(m); #else #ifdef BEOSORBEBOX snooze(m*1000); #else /* BEOSORBEBOX */ #ifdef SELECT int t1, x; debug(F101,"msleep SELECT 1","",m); if (m <= 0) return(0); if (m >= 1000) { /* Catch big arguments. */ sleep(m/1000); m = m % 1000; if (m < 10) return(0); } debug(F101,"msleep SELECT 2","",m); #ifdef BELLV10 x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, m ); debug(F101,"msleep BELLV10 select","",x); #else /* BELLV10 */ #ifdef HPUX9 gettimeofday(&tv, &tz); #else #ifndef COHERENT #ifdef GTODONEARG if (gettimeofday(&tv) < 0) #else #ifdef PTX if (gettimeofday(&tv,NULL) < 0) #else #ifdef NOTIMEZONE if (gettimeofday(&tv, NULL) < 0) /* wonder what this does... */ #else if (gettimeofday(&tv, &tz) < 0) #endif /* NOTIMEZONE */ #endif /* PTX */ #endif /* GTODONEARG */ return(-1); t1 = tv.tv_sec; /* Seconds */ #endif /* COHERENT */ #endif /* HPUX9 */ tv.tv_sec = 0; /* Use select() */ tv.tv_usec = m * 1000L; #ifdef BSD44 x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"msleep BSD44 select","",x); #else /* BSD44 */ #ifdef __linux__ x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"msleep __linux__ select","",x); #else /* __linux__ */ #ifdef BSD43 x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"msleep BSD43 select","",x); #else /* BSD43 */ #ifdef QNX6 x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"msleep QNX6 select","",x); #else /* QNX6 */ #ifdef QNX x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"msleep QNX select","",x); #else /* QNX */ #ifdef COHERENT x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"msleep COHERENT select","",x); #else /* COHERENT */ #ifdef HPUX1000 /* 10.00 only, not 10.10 or later */ x = select( 0, (int *)0, (int *)0, (int *)0, &tv ); debug(F101,"msleep HP-UX 10.00 select","",x); #else /* HPUX1000 */ #ifdef SVR4 x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"msleep SVR4 select","",x); #else /* SVR4 */ #ifdef OSF40 x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"msleep OSF40 select","",x); #else /* OSF40 */ #ifdef PTX x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv ); debug(F101,"msleep OSF40 select","",x); #else x = select( 0, (int *)0, (int *)0, (int *)0, &tv ); debug(F101,"msleep catch-all select","",x); #endif /* PTX */ #endif /* OSF40 */ #endif /* HP1000 */ #endif /* SVR4 */ #endif /* COHERENT */ #endif /* QNX */ #endif /* QNX6 */ #endif /* BSD43 */ #endif /* __linux__ */ #endif /* BSD44 */ #endif /* BELLV10 */ return(0); #else /* Not SELECT */ #ifdef CK_POLL /* We have poll() */ struct pollfd pfd; /* Supply a valid address for poll() */ #ifdef ODT30 /* But in SCO ODT 3.0 */ #ifdef NAP /* we should use nap() instead */ debug(F101,"msleep ODT 3.0 NAP","",m); /* because using poll() here */ nap((long)m); /* seems to break dialing. */ return(0); #else debug(F101,"msleep ODT 3.0 POLL","",m); poll(&pfd, 0, m); return(0); #endif /* NAP */ #else debug(F101,"msleep POLL","",m); poll(&pfd, 0, m); return(0); #endif /* ODT30 */ /* We could handle the above more cleanly by just letting nap() always take precedence over poll() in this routine, but there is no way to know whether that would break something else. */ #else /* Not POLL */ #ifdef USLEEP /* "This routine is implemented using setitimer(2); it requires eight system calls...". In other words, it might take 5 minutes to sleep 10 milliseconds... */ debug(F101,"msleep USLEEP","",m); if (m >= 1000) { /* Catch big arguments. */ sleep(m/1000); m = m % 1000; if (m < 10) return(0); } usleep((unsigned int)(m * 1000)); return(0); #else #ifdef aegis time_$clock_t dur; debug(F101,"msleep aegis","",m); dur.c2.high16 = 0; dur.c2.low32 = 250 * m; /* one millisecond = 250 four microsecond ticks */ time_$wait(time_$relative, dur, st); return(0); #else #ifdef PROVX1 debug(F101,"msleep Venix","",m); if (m <= 0) return(0); sleep(-((m * 60 + 500) / 1000)); return(0); #else #ifdef NAP debug(F101,"msleep NAP","",m); nap((long)m); return(0); #else #ifdef ATTSV #ifndef BSD44 extern long times(); /* Or #include ? */ #endif /* BSD44 */ long t1, t2, tarray[4]; int t3; char *cp = getenv("HZ"); int CLOCK_TICK; int hertz; if (cp && (hertz = atoi(cp))) { CLOCK_TICK = 1000 / hertz; } else { /* probably single user mode */ #ifdef HZ CLOCK_TICK = 1000 / HZ; #else static warned = 0; /* HZ always exists in, for instance, SCO Xenix, so you don't have to * make special #ifdefs for XENIX here, like in ver 4F. Also, if you * have Xenix, you have should have nap(), so the best is to use -DNAP * in the makefile. Most systems have HZ. */ CLOCK_TICK = 17; /* 1/60 sec */ if (!warned) { printf("warning: environment variable HZ bad... using HZ=%d\r\n", 1000 / CLOCK_TICK); warned = 1; } #endif /* !HZ */ } debug(F101,"msleep ATTSV","",m); if (m <= 0) return(0); if (m >= 1000) { /* Catch big arguments. */ sleep(m/1000); m = m % 1000; if (m < 10) return(0); } if ((t1 = times(tarray)) < 0) return(-1); while (1) { if ((t2 = times(tarray)) < 0) return(-1); t3 = ((int)(t2 - t1)) * CLOCK_TICK; if (t3 > m) return(t3); } #else /* Not ATTSV */ #ifdef MSLFTIME /* Use ftime() loop... */ int t1, t3 = 0; debug(F101,"msleep MSLFTIME","",m); if (m <= 0) return(0); if (m >= 1000) { /* Catch big arguments. */ sleep(m/1000); m = m % 1000; if (m < 10) return(0); } #ifdef QNX ftime(&ftp); /* void ftime() in QNX */ #else if (ftime(&ftp) < 0) return(-1); /* Get base time. */ #endif /* QNX */ t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm; while (1) { ftime(&ftp); /* Get current time and compare. */ t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1; if (t3 > m) return(0); } #else /* This includes true POSIX, which has no way to do this. */ debug(F101,"msleep busy loop","",m); if (m >= 1000) { /* Catch big arguments. */ sleep(m/1000); m = m % 1000; if (m < 10) return(0); } if (m > 0) while (m > 0) m--; /* Just a dumb busy loop */ return(0); #endif /* MSLFTIME */ #endif /* ATTSV */ #endif /* NAP */ #endif /* PROVX1 */ #endif /* aegis */ #endif /* CK_POLL */ #endif /* SELECT */ #endif /* BEOSORBEBOX */ #endif /* USLEEP */ #endif /* Plan9 */ } /* R T I M E R -- Reset elapsed time counter */ VOID rtimer() { tcount = time( (time_t *) 0 ); } /* G T I M E R -- Get current value of elapsed time counter in seconds */ int gtimer() { int x; x = (int) (time( (time_t *) 0 ) - tcount); debug(F101,"gtimer","",x); return( (x < 0) ? 0 : x ); } #ifdef GFTIMER /* Floating-point timers. Require not only floating point support, but also gettimeofday(). */ static struct timeval tzero; VOID rftimer() { #ifdef GTODONEARG /* Account for Mot's definition */ (VOID) gettimeofday(&tzero); #else (VOID) gettimeofday(&tzero, (struct timezone *)0); #endif /* GTODONEARG */ } CKFLOAT gftimer() { struct timeval tnow, tdelta; CKFLOAT s; #ifdef DEBUG char fpbuf[64]; #endif /* DEBUG */ #ifdef GTODONEARG /* Account for Mot's definition */ (VOID) gettimeofday(&tnow); #else (VOID) gettimeofday(&tnow, (struct timezone *)0); #endif /* GTODONEARG */ tdelta.tv_sec = tnow.tv_sec - tzero.tv_sec; tdelta.tv_usec = tnow.tv_usec - tzero.tv_usec; if (tdelta.tv_usec < 0) { tdelta.tv_sec--; tdelta.tv_usec += 1000000; } s = (CKFLOAT) tdelta.tv_sec + ((CKFLOAT) tdelta.tv_usec / 1000000.0); if (s < GFMINTIME) s = GFMINTIME; #ifdef DEBUG if (deblog) { sprintf(fpbuf,"%f",s); debug(F110,"gftimer",fpbuf,0); } #endif /* DEBUG */ return(s); } #endif /* GFTIMER */ /* Z T I M E -- Return asctime()-format date/time string */ /* NOTE: as a side effect of calling this routine, we can also set the following two variables, giving the micro- and milliseconds (fractions of seconds) of the clock time. Currently this is done only in BSD-based builds that use gettimeofday(). When these variables are not filled in, they are left with a value of -1L. */ static char asctmbuf[64]; VOID #ifdef CK_ANSIC ztime( char **s ) #else ztime(s) char **s; #endif /* CK_ANSIC */ { #ifdef GFTIMER /* The gettimeofday() method, which also sets ztmsec and ztusec, works for all GFTIMER builds. NOTE: ztmsec and ztusec are defined in ckcmai.c, and extern declarations for them are in ckcdeb.h; thus they are declared in this file by inclusion of ckcdeb.h. */ struct tm *tp; ztmsec = -1L; ztusec = -1L; if (!s) debug(F100,"ztime s==NULL","",0); #ifdef GTODONEARG /* No 2nd arg in Motorola SV88 and some others */ if (gettimeofday(&tv) > -1) #else #ifndef COHERENT #ifdef PTX if (gettimeofday(&tv,NULL) > -1) #else #ifdef NOTIMEZONE if (gettimeofday(&tv, NULL) > -1) /* wonder what this does... */ #else if (gettimeofday(&tv, &tz) > -1) #endif /* NOTIMEZONE */ #endif /* PTX */ #endif /* COHERENT */ #endif /* GTODONEARG */ { /* Fill in tm struct */ ztusec = tv.tv_usec; /* Microseconds */ ztmsec = ztusec / 1000L; /* Milliseconds */ #ifdef HPUX9 { time_t zz; zz = tv.tv_sec; tp = localtime(&zz); /* Convert to local time */ } #else #ifdef HPUX1000 { time_t zz; zz = tv.tv_sec; tp = localtime(&zz); } #else #ifdef LINUX { /* avoid unaligned access trap on 64-bit platforms */ time_t zz; zz = tv.tv_sec; tp = localtime(&zz); } #else #ifdef MACOSX tp = localtime((time_t *)&tv.tv_sec); /* Convert to local time */ #else tp = localtime(&tv.tv_sec); #endif /* MACOSX */ #endif /* LINUX */ #endif /* HPUX1000 */ #endif /* HPUX9 */ if (s) { char * s2; s2 = asctime(tp); /* Convert result to ASCII string */ asctmbuf[0] = '\0'; if (s2) ckstrncpy(asctmbuf,s2,64); *s = asctmbuf; debug(F111,"ztime GFTIMER gettimeofday",*s,ztusec); } } #else /* Not GFTIMER */ #undef ZTIMEV7 /* Which systems need to use */ #ifdef COHERENT /* old UNIX Version 7 way... */ #define ZTIMEV7 #endif /* COHERENT */ #ifdef TOWER1 #define ZTIMEV7 #endif /* TOWER1 */ #ifdef ANYBSD #ifndef BSD42 #define ZTIMEV7 #endif /* BSD42 */ #endif /* ANYBSD */ #ifdef V7 #ifndef MINIX #define ZTIMEV7 #endif /* MINIX */ #endif /* V7 */ #ifdef POSIX #define ZTIMEV7 #endif /* POSIX */ #ifdef HPUX1020 /* Prototypes are in , included above. */ time_t clock_storage; clock_storage = time((void *) 0); if (s) { *s = ctime(&clock_storage); debug(F110,"ztime: HPUX 10.20",*s,0); } #else #ifdef ATTSV /* AT&T way */ /* extern long time(); */ /* Theoretically these should */ char *ctime(); /* already been dcl'd in */ time_t clock_storage; clock_storage = time( #ifdef IRIX60 (time_t *) #else #ifdef BSD44 (time_t *) #else (long *) #endif /* BSD44 */ #endif /* IRIX60 */ 0 ); if (s) { *s = ctime( &clock_storage ); debug(F110,"ztime: ATTSV",*s,0); } #else #ifdef PROVX1 /* Venix 1.0 way */ int utime[2]; time(utime); if (s) { *s = ctime(utime); debug(F110,"ztime: PROVX1",*s,0); } #else #ifdef BSD42 /* 4.2BSD way */ char *asctime(); struct tm *localtime(); struct tm *tp; gettimeofday(&tv, &tz); ztusec = tv.tv_usec; ztmsec = tv.tv_usec / 1000L; tp = localtime(&tv.tv_sec); if (s) { *s = asctime(tp); debug(F111,"ztime: BSD42",*s,ztusec); } #else #ifdef MINIX /* MINIX way */ #ifdef COMMENT extern long time(); /* Already got these from */ extern char *ctime(); #endif /* COMMENT */ time_t utime[2]; time(utime); if (s) { *s = ctime(utime); debug(F110,"ztime: MINIX",*s,0); } #else #ifdef ZTIMEV7 /* The regular way */ char *asctime(); struct tm *localtime(); struct tm *tp; long xclock; /* or unsigned long for BeBox? */ time(&xclock); tp = localtime(&xclock); if (s) { *s = asctime(tp); debug(F110,"ztime: ZTIMEV7",*s,0); } #else /* Catch-all for others... */ if (s) { *s = "Day Mon 00 00:00:00 0000\n"; /* Dummy in asctime() format */ debug(F110,"ztime: catch-all",*s,0); } #endif /* ZTIMEV7 */ #endif /* MINIX */ #endif /* BSD42 */ #endif /* PROVX1 */ #endif /* ATTSV */ #endif /* HPUX1020 */ #endif /* GFTIMER */ } /* C O N G M -- Get console terminal modes. */ /* Saves initial console mode, and establishes variables for switching between current (presumably normal) mode and other modes. Should be called when program starts, but only after establishing whether program is in the foreground or background. Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error. */ int congm() { int fd; if (backgrd || !isatty(0)) { /* If in background. */ cgmf = -1; /* Don't bother, modes are garbage. */ return(-1); } if (cgmf > 0) return(0); /* Already did this. */ debug(F100,"congm getting modes","",0); /* Need to do it. */ #ifdef aegis ios_$inq_type_uid(ios_$stdin, conuid, st); if (st.all != status_$ok) { fprintf(stderr, "problem getting stdin objtype: "); error_$print(st); } concrp = (conuid == mbx_$uid); conbufn = 0; #endif /* aegis */ #ifndef BEBOX if ((fd = open(CTTNAM,2)) < 0) { /* Open controlling terminal */ #ifdef COMMENT fprintf(stderr,"Error opening %s\n", CTTNAM); perror("congm"); return(-1); #else fd = 0; #endif /* COMMENT */ } #else fd = 0; #endif /* !BEBOX */ #ifdef BSD44ORPOSIX if (tcgetattr(fd,&ccold) < 0) return(-1); if (tcgetattr(fd,&cccbrk) < 0) return(-1); if (tcgetattr(fd,&ccraw) < 0) return(-1); #else #ifdef ATTSV if (ioctl(fd,TCGETA,&ccold) < 0) return(-1); if (ioctl(fd,TCGETA,&cccbrk) < 0) return(-1); if (ioctl(fd,TCGETA,&ccraw) < 0) return(-1); #ifdef VXVE cccbrk.c_line = 0; /* STTY line 0 for CDC VX/VE */ if (ioctl(fd,TCSETA,&cccbrk) < 0) return(-1); ccraw.c_line = 0; /* STTY line 0 for CDC VX/VE */ if (ioctl(fd,TCSETA,&ccraw) < 0) return(-1); #endif /* VXVE */ #else #ifdef BELLV10 if (ioctl(fd,TIOCGETP,&ccold) < 0) return(-1); if (ioctl(fd,TIOCGETP,&cccbrk) < 0) return(-1); if (ioctl(fd,TIOCGETP,&ccraw) < 0) return(-1); debug(F101,"cccbrk.sg_flags orig","", cccbrk.sg_flags); #else if (gtty(fd,&ccold) < 0) return(-1); if (gtty(fd,&cccbrk) < 0) return(-1); if (gtty(fd,&ccraw) < 0) return(-1); #endif /* BELLV10 */ #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ #ifdef sony_news /* Sony NEWS */ if (ioctl(fd,TIOCKGET,&km_con) < 0) { /* Get console Kanji mode */ perror("congm error getting Kanji mode"); debug(F101,"congm error getting Kanji mode","",0); km_con = -1; /* Make sure this stays undefined. */ return(-1); } #endif /* sony_news */ if (fd > 0) close(fd); cgmf = 1; /* Flag that we got them. */ return(1); } static VOID #ifdef CK_ANSIC congetbuf( int x ) #else congetbuf(x) int x; #endif /* CK_ANSIC */ { int n; n = CONBUFSIZ - (conbufp - conbuf); /* How much room left in buffer? */ if (x > n) { debug(F101,"congetbuf char loss","",x-n); x = n; } x = read(0,conbufp,x); conbufn += x; debug(F111,"congetbuf readahead",conbuf,x); } /* C O N C B -- Put console in cbreak mode. */ /* Returns 0 if ok, -1 if not */ int #ifdef CK_ANSIC concb(char esc) #else concb(esc) char esc; #endif /* CK_ANSIC */ /* concb */ { int x, y = 0; debug(F101,"concb constate","",constate); debug(F101,"concb cgmf","",cgmf); debug(F101,"concb backgrd","",backgrd); if (constate == CON_CB) return(0); if (cgmf < 1) /* Did we get console modes yet? */ if (!backgrd) /* No, in background? */ congm(); /* No, try to get them now. */ if (cgmf < 1) /* Still don't have them? */ return(0); /* Give up. */ debug(F101,"concb ttyfd","",ttyfd); debug(F101,"concb ttfdflg","",ttfdflg); #ifdef COMMENT /* This breaks returning to prompt after protocol with "-l 0" */ /* Commented out July 1998 */ if (ttfdflg && ttyfd >= 0 && ttyfd < 3) return(0); #endif /* COMMENT */ x = isatty(0); debug(F101,"concb isatty","",x); if (!x) return(0); /* Only when running on real ttys */ debug(F101,"concb xsuspend","",xsuspend); if (backgrd) /* Do nothing if in background. */ return(0); escchr = esc; /* Make this available to other fns */ ckxech = 1; /* Program can echo characters */ #ifdef aegis conbufn = 0; if (concrp) return(write(1, "\035\002", 2)); if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);} #endif /* aegis */ #ifdef COHERENT #define SVORPOSIX #endif /* COHERENT */ #ifdef Plan9 x = p9concb(); #else #ifndef SVORPOSIX /* BSD, V7, etc */ debug(F101,"cccbrk.sg_flags concb 1","", cccbrk.sg_flags); debug(F101,"concb stty CBREAK","",0); cccbrk.sg_flags |= (CBREAK|CRMOD); /* Set to character wakeup, */ cccbrk.sg_flags &= ~ECHO; /* no echo. */ debug(F101,"cccbrk.sg_flags concb 2","", cccbrk.sg_flags); errno = 0; /* BSD stty() clears the console buffer. So if anything is waiting in it, we have to read it now to avoid losing it. */ x = conchk(); if (x > 0) congetbuf(x); #ifdef BELLV10 x = ioctl(0,TIOCSETP,&cccbrk); #else x = stty(0,&cccbrk); debug(F101,"cccbrk.sg_flags concb x","", x); #endif /* BELLV10 */ #else /* Sys V and POSIX */ #ifndef OXOS debug(F101,"concb cccbrk.c_flag","",cccbrk.c_lflag); #ifdef QNX /* Don't mess with IEXTEN */ cccbrk.c_lflag &= ~(ICANON|ECHO); #else #ifdef COHERENT cccbrk.c_lflag &= ~(ICANON|ECHO); #else cccbrk.c_lflag &= ~(ICANON|ECHO|IEXTEN); #endif /* COHERENT */ #endif /* QNX */ cccbrk.c_lflag |= ISIG; /* Allow signals in command mode. */ cccbrk.c_iflag |= IGNBRK; /* But ignore BREAK signal */ cccbrk.c_iflag &= ~BRKINT; #else /* OXOS */ debug(F100,"concb OXOS is defined","",0); cccbrk.c_lflag &= ~(ICANON|ECHO); cccbrk.c_cc[VDISCARD] = cccbrk.c_cc[VLNEXT] = CDISABLE; #endif /* OXOS */ #ifdef COMMENT /* Believe it or not, in SCO UNIX, VSUSP is greater than NCC, and so this array reference is out of bounds. It's only a debug() call so who needs it. */ #ifdef VSUSP debug(F101,"concb c_cc[VSUSP]","",cccbrk.c_cc[VSUSP]); #endif /* VSUSP */ #endif /* COMMENT */ #ifndef VINTR debug(F101,"concb c_cc[0]","",cccbrk.c_cc[0]); cccbrk.c_cc[0] = 003; /* Interrupt char is Control-C */ #else debug(F101,"concb c_cc[VINTR]","",cccbrk.c_cc[0]); cccbrk.c_cc[VINTR] = 003; #endif /* VINTR */ #ifndef VQUIT cccbrk.c_cc[1] = escchr; /* escape during packet modes */ #else cccbrk.c_cc[VQUIT] = escchr; #endif /* VQUIT */ #ifndef VEOF cccbrk.c_cc[4] = 1; #else #ifndef OXOS #ifdef VMIN cccbrk.c_cc[VMIN] = 1; #endif /* VMIN */ #else /* OXOS */ cccbrk.c_min = 1; #endif /* OXOS */ #endif /* VEOF */ #ifdef ZILOG cccbrk.c_cc[5] = 0; #else #ifndef VEOL cccbrk.c_cc[5] = 1; #else #ifndef OXOS #ifdef VTIME cccbrk.c_cc[VTIME] = 1; #endif /* VTIME */ #else /* OXOS */ cccbrk.c_time = 1; #endif /* OXOS */ #endif /* VEOL */ #endif /* ZILOG */ errno = 0; #ifdef BSD44ORPOSIX /* Set new modes */ x = tcsetattr(0,TCSADRAIN,&cccbrk); #else /* ATTSV */ /* or the POSIX way */ x = ioctl(0,TCSETAW,&cccbrk); /* the Sys V way */ #endif /* BSD44ORPOSIX */ #endif /* SVORPOSIX */ #ifdef COHERENT #undef SVORPOSIX #endif /* COHERENT */ debug(F101,"concb x","",x); debug(F101,"concb errno","",errno); #ifdef V7 #ifndef MINIX if (kmem[CON] < 0) { qaddr[CON] = initrawq(0); if((kmem[CON] = open("/dev/kmem", 0)) < 0) { fprintf(stderr, "Can't read /dev/kmem in concb.\n"); perror("/dev/kmem"); exit(1); } } #endif /* MINIX */ #endif /* V7 */ #endif /* Plan9 */ if (x > -1) constate = CON_CB; debug(F101,"concb returns","",x); return(x); } /* C O N B I N -- Put console in binary mode */ /* Returns 0 if ok, -1 if not */ int #ifdef CK_ANSIC conbin(char esc) #else conbin(esc) char esc; #endif /* CK_ANSIC */ /* conbin */ { int x; debug(F101,"conbin constate","",constate); if (constate == CON_BIN) return(0); if (!isatty(0)) return(0); /* only for real ttys */ congm(); /* Get modes if necessary. */ debug(F100,"conbin","",0); escchr = esc; /* Make this available to other fns */ ckxech = 1; /* Program can echo characters */ #ifdef aegis conbufn = 0; if (concrp) return(write(1, "\035\002", 2)); if (conuid == input_pad_$uid) { pad_$raw(ios_$stdin, st); return(0); } #endif /* aegis */ #ifdef COHERENT #define SVORPOSIX #endif /* COHERENT */ #ifdef Plan9 return p9conbin(); #else #ifdef SVORPOSIX #ifndef OXOS #ifdef QNX ccraw.c_lflag &= ~(ISIG|ICANON|ECHO); #else #ifdef COHERENT ccraw.c_lflag &= ~(ISIG|ICANON|ECHO); #else ccraw.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN); #endif /* COHERENT */ #endif /* QNX */ #else /* OXOS */ ccraw.c_lflag &= ~(ISIG|ICANON|ECHO); ccraw.c_cc[VDISCARD] = ccraw.c_cc[VLNEXT] = CDISABLE; #endif /* OXOS */ ccraw.c_iflag |= IGNPAR; /* Note that for terminal sessions we disable Xon/Xoff flow control to allow the passage ^Q and ^S as data characters for EMACS, and to allow XMODEM transfers to work when C-Kermit is in the middle, etc. Hardware flow control, if in use, is not affected. */ #ifdef ATTSV #ifdef BSD44 ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF |INPCK|ISTRIP); #else ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF |INPCK|ISTRIP); #endif /* BSD44 */ #else /* POSIX */ ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXOFF|INPCK|ISTRIP); #endif /* ATTSV */ ccraw.c_oflag &= ~OPOST; #ifdef COMMENT /* WHAT THE HECK WAS THIS FOR? The B9600 setting (obviously) prevents CONNECT from working at any speed other than 9600 when you are logged in to the 7300 on a serial line. Maybe some of the other flags are necessary -- if so, put back the ones that are needed. This code is supposed to work the same, no matter whether you are logged in to the 7300 on the real console device, or through a serial port. */ #ifdef ATT7300 ccraw.c_cflag = CLOCAL | B9600 | CS8 | CREAD | HUPCL; #endif /* ATT7300 */ #endif /* COMMENT */ /*** Kermit used to put the console in 8-bit raw mode, but some users have *** pointed out that this should not be done, since some sites actually *** use terminals with parity settings on their Unix systems, and if we *** override the current settings and stop doing parity, then their terminals *** will display blotches for characters whose parity is wrong. Therefore, *** the following two lines are commented out (Larry Afrin, Clemson U): *** *** ccraw.c_cflag &= ~(PARENB|CSIZE); *** ccraw.c_cflag |= (CS8|CREAD); *** *** Sys III/V sites that have trouble with this can restore these lines. ***/ #ifndef VINTR ccraw.c_cc[0] = 003; /* Interrupt char is Ctrl-C */ #else ccraw.c_cc[VINTR] = 003; #endif /* VINTR */ #ifndef VQUIT ccraw.c_cc[1] = escchr; /* Escape during packet mode */ #else ccraw.c_cc[VQUIT] = escchr; #endif /* VQUIT */ #ifndef VEOF ccraw.c_cc[4] = 1; #else #ifndef OXOS #ifdef VMIN ccraw.c_cc[VMIN] = 1; #endif /* VMIN */ #else /* OXOS */ ccraw.c_min = 1; #endif /* OXOS */ #endif /* VEOF */ #ifdef ZILOG ccraw.c_cc[5] = 0; #else #ifndef VEOL ccraw.c_cc[5] = 1; #else #ifndef OXOS #ifdef VTIME ccraw.c_cc[VTIME] = 1; #endif /* VTIME */ #else /* OXOS */ ccraw.c_time = 1; #endif /* OXOS */ #endif /* VEOL */ #endif /* ZILOG */ #ifdef BSD44ORPOSIX x = tcsetattr(0,TCSADRAIN,&ccraw); /* Set new modes. */ #else x = ioctl(0,TCSETAW,&ccraw); #endif /* BSD44ORPOSIX */ #else /* Berkeley, etc. */ x = conchk(); /* Because stty() is destructive */ if (x > 0) congetbuf(x); ccraw.sg_flags |= (RAW|TANDEM); /* Set rawmode, XON/XOFF (ha) */ ccraw.sg_flags &= ~(ECHO|CRMOD); /* Set char wakeup, no echo */ #ifdef BELLV10 x = ioctl(0,TIOCSETP,&ccraw); #else x = stty(0,&ccraw); #endif /* BELLV10 */ #endif /* SVORPOSIX */ #endif /* Plan9 */ if (x > -1) constate = CON_BIN; debug(F101,"conbin returns","",x); return(x); #ifdef COHERENT #undef SVORPOSIX #endif /* COHERENT */ } /* C O N R E S -- Restore the console terminal */ int conres() { int x; debug(F101,"conres cgmf","",cgmf); debug(F101,"conres constate","",constate); if (cgmf < 1) /* Do nothing if modes unchanged */ return(0); if (constate == CON_RES) return(0); if (!isatty(0)) return(0); /* only for real ttys */ debug(F100,"conres isatty ok","",0); ckxech = 0; /* System should echo chars */ #ifdef aegis conbufn = 0; if (concrp) return(write(1, "\035\001", 2)); if (conuid == input_pad_$uid) { pad_$cooked(ios_$stdin, st); constate = CON_RES; return(0); } #endif /* aegis */ #ifdef Plan9 p9conres(); #else #ifdef BSD44ORPOSIX debug(F100,"conres restoring tcsetattr","",0); x = tcsetattr(0,TCSADRAIN,&ccold); #else #ifdef ATTSV debug(F100,"conres restoring ioctl","",0); x = ioctl(0,TCSETAW,&ccold); #else /* BSD, V7, and friends */ #ifdef sony_news /* Sony NEWS */ if (km_con != -1) ioctl(0,TIOCKSET,&km_con); /* Restore console Kanji mode */ #endif /* sony_news */ msleep(100); debug(F100,"conres restoring stty","",0); x = conchk(); /* Because stty() is destructive */ if (x > 0) congetbuf(x); #ifdef BELLV10 x = ioctl(0,TIOCSETP,&ccold); #else x = stty(0,&ccold); #endif /* BELLV10 */ #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ #endif /* Plan9 */ if (x > -1) constate = CON_RES; debug(F101,"conres returns","",x); return(x); } /* C O N O C -- Output a character to the console terminal */ int #ifdef CK_ANSIC conoc(char c) #else conoc(c) char c; #endif /* CK_ANSIC */ /* conoc */ { #ifdef IKSD if (inserver && !local) return(ttoc(c)); #ifdef CK_ENCRYPTION if (inserver && TELOPT_ME(TELOPT_ENCRYPTION)) ck_tn_encrypt(&c,1); #endif /* CK_ENCRYPTION */ #endif /* IKSD */ #ifdef Plan9 return conwrite(&c,1); #else return(write(1,&c,1)); #endif /* Plan9 */ } /* C O N X O -- Write x characters to the console terminal */ int #ifdef CK_ANSIC conxo( int x, char *s ) #else conxo(x,s) int x; char *s; #endif /* CK_ANSIC */ { #ifdef IKSD if (inserver && !local) return(ttol((CHAR *)s,x)); #ifdef CK_ENCRYPTION if (inserver && TELOPT_ME(TELOPT_ENCRYPTION)) ck_tn_encrypt(s,x); #endif /* CK_ENCRYPTION */ #endif /* IKSD */ #ifdef Plan9 return(conwrite(s,x)); #else return(write(1,s,x)); #endif /* Plan9 */ } /* C O N O L -- Write a line to the console terminal */ int #ifdef CK_ANSIC conol( char *s ) #else conol(s) char *s; #endif /* CK_ANSIC */ { int len; if (!s) s = ""; /* Always do this! */ len = strlen(s); if (len == 0) return(0); #ifdef IKSD if (inserver && !local) return(ttol((CHAR *)s,len)); #ifdef CK_ENCRYPTION if (inserver && TELOPT_ME(TELOPT_ENCRYPTION)) { if (nxpacket < len) { if (xpacket) { free(xpacket); xpacket = NULL; nxpacket = 0; } len = len > 10240 ? len : 10240; xpacket = (CHAR *)malloc(len); if (!xpacket) { fprintf(stderr,"ttol malloc failure\n"); return(-1); } else nxpacket = len; } memcpy(xpacket,s,len); s = (char *)xpacket; ck_tn_encrypt(s,len); } #endif /* CK_ENCRYPTION */ #endif /* IKSD */ #ifdef Plan9 return(conwrite(s,len)); #else return(write(1,s,len)); #endif /* Plan9 */ } /* C O N O L A -- Write an array of lines to the console terminal */ int #ifdef CK_ANSIC conola( char *s[] ) #else conola(s) char *s[]; #endif /* CK_ANSIC */ { char * p; int i, x; if (!s) return(0); for (i = 0; ; i++) { p = s[i]; if (!p) p = ""; /* Let's not dump core shall we? */ if (!*p) break; #ifdef IKSD if (inserver && !local) x = ttol((CHAR *)p,(int)strlen(p)); else #endif /* IKSD */ x = conol(p); if (x < 0) return(-1); } return(0); } /* C O N O L L -- Output a string followed by CRLF */ int #ifdef CK_ANSIC conoll( char *s ) #else conoll(s) char *s; #endif /* CK_ANSIC */ { CHAR buf[3]; buf[0] = '\r'; buf[1] = '\n'; buf[2] = '\0'; if (!s) s = ""; #ifdef IKSD if (inserver && !local) { if (*s) ttol((CHAR *)s,(int)strlen(s)); return(ttol(buf,2)); } #endif /* IKSD */ if (*s) conol(s); #ifdef IKSD #ifdef CK_ENCRYPTION if (inserver && TELOPT_ME(TELOPT_ENCRYPTION)) ck_tn_encrypt((char *)buf,2); #endif /* CK_ENCRYPTION */ #endif /* IKSD */ #ifdef Plan9 return(conwrite(buf, 2)); #else return(write(1,buf,2)); #endif /* Plan9 */ } /* C O N C H K -- Return how many characters available at console */ /* We could also use select() here to cover a few more systems that are not covered by any of the following, e.g. HP-UX 9.0x on the model 800. */ int conchk() { static int contyp = 0; /* +1 for isatty, -1 otherwise */ if (contyp == 0) /* This prevents unnecessary */ contyp = (isatty(0) ? 1 : -1); /* duplicated calls to isatty() */ debug(F101,"conchk contyp","",contyp); if (backgrd || (contyp < 0)) return(0); #ifdef aegis if (conbufn > 0) return(conbufn); /* use old count if nonzero */ /* read in more characters */ conbufn = ios_$get(ios_$stdin, ios_$cond_opt, conbuf, (long)sizeof(conbuf), st); if (st.all != status_$ok) conbufn = 0; conbufp = conbuf; return(conbufn); #else #ifdef IKSD if (inserver && !local) return(in_chk(1,ttyfd)); else #endif /* IKSD */ return(in_chk(0,0)); #endif /* aegis */ } /* C O N I N C -- Get a character from the console */ /* Call with timo > 0 to do a timed read, timo == 0 to do an untimed blocking read. Upon success, returns the character. Upon failure, returns -1. A timed read that does not complete within the timeout period returns -2. */ int #ifdef CK_ANSIC coninc( int timo ) #else coninc(timo) int timo; #endif /* CK_ANSIC */ { int n = 0; CHAR ch; int xx; if (conbufn > 0) { /* If something already buffered */ --conbufn; return((unsigned)(*conbufp++ & 0xff)); } errno = 0; /* Clear this */ #ifdef IKSD if (inserver && !local) { xx = ttinc(timo); if (xx < 0) return(ttinctimo ? -2 : -1); else return(xx); } #endif /* IKSD */ #ifdef aegis /* Apollo Aegis only... */ debug(F101,"coninc timo","",timo); fflush(stdout); if (conchk() > 0) { --conbufn; return((unsigned)(*conbufp++ & 0xff)); } #endif /* aegis */ #ifdef TTLEBUF if ( #ifdef IKSD inserver && #endif /* IKSD */ !xlocal ) { if (ttpush >= 0) { debug(F111,"ttinc","ttpush",ttpush); ch = ttpush; ttpush = -1; return(ch); } if (le_data) { if (le_getchar(&ch) > 0) { debug(F111,"ttinc LocalEchoInBuf","ch",ch); return(ch); } } } #endif /* TTLEBUF */ if (timo <= 0) { /* Untimed, blocking read. */ while (1) { /* Keep trying till we get one. */ n = read(0, &ch, 1); /* Read a character. */ if (n == 0) continue; /* Shouldn't happen. */ if (n > 0) { /* If read was successful, */ #ifdef IKSD #ifdef CK_ENCRYPTION debug(F100,"coninc decrypt 1","",0); if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION)) ck_tn_decrypt((char *)&ch,1); #endif /* CK_ENCRYPTION */ #endif /* IKSD */ return((unsigned)(ch & 0xff)); /* return the character. */ } /* Come here if read() returned an error. */ debug(F101, "coninc(0) errno","",errno); /* Log the error. */ #ifndef OXOS #ifdef SVORPOSIX #ifdef CIE /* CIE Regulus has no EINTR symbol? */ #ifndef EINTR #define EINTR 4 #endif /* EINTR */ #endif /* CIE */ /* This routine is used for several different purposes. In CONNECT mode, it is used to do an untimed, blocking read from the keyboard in the lower CONNECT fork. During local-mode file transfer, it reads a character from the console to interrupt the file transfer (like A for a status report, X to cancel a file, etc). Obviously, we don't want the reads in the latter case to be blocking, or the file transfer would stop until the user typed something. Unfortunately, System V does not allow the console device input buffer to be sampled nondestructively (e.g. by conchk()), so a kludge is used instead. During local-mode file transfer, the SIGQUIT signal is armed and trapped by esctrp(), and this routine pretends to have read the quit character from the keyboard normally. But, kludge or no kludge, the read() issued by this command, under System V only, can fail if a signal -- ANY signal -- is caught while the read is pending. This can occur not only when the user types the quit character, but also during telnet negotiations, when the lower CONNECT fork signals the upper one about an echoing mode change. When this happens, we have to post the read() again. This is apparently not a problem in BSD-based UNIX versions. */ if (errno == EINTR) { /* Read interrupted. */ if (conesc) { /* If by SIGQUIT, */ conesc = 0; /* the conesc variable is set, */ return(escchr); /* so return the escape character. */ } else { continue; /* By other signal, try again. */ } } #else /* This might be dangerous, but let's do this on non-System V versions too, since at least one SunOS 4.1.2 user complains of immediate disconnections upon first making a TELNET connection. */ if (errno == EINTR) /* Read interrupted. */ continue; #endif /* SVORPOSIX */ #else /* OXOS */ if (errno == EINTR) /* Read interrupted. */ continue; #endif /* OXOS */ return(-1); /* Error */ } } #ifdef DEBUG if (deblog && timo <= 0) { debug(F100,"coninc timeout logic error","",0); timo = 1; } #endif /* DEBUG */ /* Timed read... */ saval = signal(SIGALRM,timerh); /* Set up timeout handler. */ xx = alarm(timo); /* Set the alarm. */ debug(F101,"coninc alarm set","",timo); if ( #ifdef CK_POSIX_SIG sigsetjmp(sjbuf,1) #else setjmp(sjbuf) #endif /* CK_POSIX_SIG */ ) /* The read() timed out. */ n = -2; /* Code for timeout. */ else n = read(0, &ch, 1); ttimoff(); /* Turn off timer */ if (n > 0) { /* Got character OK. */ #ifdef IKSD #ifdef CK_ENCRYPTION debug(F100,"coninc decrypt 2","",0); if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION)) ck_tn_decrypt((char *)&ch,1); #endif /* CK_ENCRYPTION */ #endif /* IKSD */ return((unsigned)(ch & 0xff)); /* Return it. */ } /* read() returned an error. Same deal as above, but without the loop. */ debug(F101, "coninc(timo) n","",n); debug(F101, "coninc(timo) errno","",errno); #ifndef OXOS #ifdef SVORPOSIX if (n == -1 && errno == EINTR && conesc != 0) { conesc = 0; return(escchr); /* User entered escape character. */ } #endif /* SVORPOSIX */ if (n == 0 && errno > 0) { /* It's an error */ return(-1); } #endif /* ! OXOS */ return(n); } /* C O N G K S -- Console Get Keyboard Scancode */ #ifndef congks /* This function needs to be filled in with the various system-dependent system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full keyboard scan code. Unfortunately there aren't any. */ int congks(timo) int timo; { #ifdef IKSD if (inserver && !local) return(ttinc(timo)); #endif /* IKSD */ return(coninc(timo)); } #endif /* congks */ #ifdef ATT7300 /* A T T D I A L -- Dial up the remote system using internal modem * Purpose: to open and dial a number on the internal modem available on the * ATT7300 UNIX PC. Written by Joe Doupnik. Superceeds version written by * Richard E. Hill, Dickinson, TX. which employed dial(3c). * Uses information in and our status int attmodem. */ attdial(ttname,speed,telnbr) char *ttname,*telnbr; long speed; { char *telnum; attmodem &= ~ISMODEM; /* modem not in use yet */ /* Ensure O_NDELAY is set, else i/o traffic hangs */ /* We turn this flag off once the dial is complete */ fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) | O_NDELAY); /* Condition line, check availability & DATA mode, turn on speaker */ if (ioctl(ttyfd,PIOCOFFHOOK, &dialer) == -1) { printf("cannot access phone\n"); ttclos(0); return (-2); } ioctl(ttyfd,PIOCGETP,&dialer); /* get phone dialer parameters */ if (dialer.c_lineparam & VOICE) { /* phone must be in DATA mode */ printf(" Should not dial with modem in VOICE mode.\n"); printf(" Exit Kermit, switch to DATA and retry call.\n"); ttclos(0); return (-2); } #ifdef ATTTONED /* Old way, tone dialing only. */ dialer.c_lineparam = DATA | DTMF; /* Dial with tones, */ dialer.c_lineparam &= ~PULSE; /* not with pulses. */ #else /* Leave current pulse/tone state alone. */ /* But what about DATA? Add it back if you have trouble. */ /* sys/phone says you get DATA automatically by opening device RDWR */ #endif dialer.c_waitdialtone = 5; /* wait 5 sec for dialtone */ #ifdef COMMENT dialer.c_feedback = SPEAKERON|NORMSPK|RINGON; /* control speaker */ #else /* sys/phone says RINGON used only for incoming voice calls */ dialer.c_feedback &= ~(SOFTSPK|LOUDSPK); dialer.c_feedback |= SPEAKERON|NORMSPK; #endif dialer.c_waitflash = 500; /* 0.5 sec flash hook */ if(ioctl(ttyfd,PIOCSETP,&dialer) == -1) { /* set phone parameters */ printf("Cannot set modem characteristics\n"); ttclos(0); return (-2); } ioctl(ttyfd,PIOCRECONN,0); /* Turns on speaker for pulse */ #ifdef COMMENT fprintf(stderr,"Phone line status. line_par:%o dialtone_wait:%o \ line_status:%o feedback:%o\n", dialer.c_lineparam, dialer.c_waitdialtone, dialer.c_linestatus, dialer.c_feedback); #endif attmodem |= ISMODEM; /* modem is now in-use */ sleep(1); for (telnum = telnbr; *telnum != '\0'; telnum++) /* dial number */ #ifdef ATTTONED /* Tone dialing only */ if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) { perror("Error in dialing"); ttclos(0); return(-2); } #else /* Allow Pulse or Tone dialing */ switch (*telnum) { case 't': case 'T': case '%': /* Tone dialing requested */ dialer.c_lineparam |= DTMF; dialer.c_lineparam &= ~PULSE; if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) { printf("Cannot set modem to tone dialing\n"); ttclos(0); return(-2); } break; case 'd': case 'D': case 'p': case 'P': case '^': dialer.c_lineparam |= PULSE; dialer.c_lineparam &= ~DTMF; if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) { printf("Cannot set modem to pulse dialing\n"); ttclos(0); return(-2); } break; default: if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) { perror("Dialing error"); ttclos(0); return(-2); } break; } #endif ioctl(ttyfd,PIOCDIAL,"@"); /* terminator for data call */ do { /* wait for modems to Connect */ if (ioctl(ttyfd,PIOCGETP,&dialer) != 0) { /* get params */ perror("Cannot get modems to connect"); ttclos(0); return(-2); } } while ((dialer.c_linestatus & MODEMCONNECTED) == 0); /* Turn off O_NDELAY flag now. */ fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY); signal(SIGHUP, sighup); /* hangup on loss of carrier */ return(0); /* return success */ } /* Offgetty, ongetty functions. These function get the 'getty(1m)' off and restore it to the indicated line. Shell's return codes are: 0: Can't do it. Probably a user logged on. 1: No need. No getty on that line. 2: Done, you should restore the getty when you're done. DOGETY System(3), however, returns them as 0, 256, 512, respectively. Thanks to Kevin O'Gorman, Anarm Software Systems. getoff.sh looks like: geton.sh looks like: setgetty $1 0 setgetty $1 1 err=$? exit $? sleep 2 exit $err */ /* O F F G E T T Y -- Turn off getty(1m) for the communications tty line * and get status so it can be restarted after the line is hung up. */ int offgetty(ttname) char *ttname; { char temp[30]; while (*ttname != '\0') ttname++; /* seek terminator of path */ ttname -= 3; /* get last 3 chars of name */ sprintf(temp,"/usr/bin/getoff.sh %s",ttname); return(zsyscmd(temp)); } /* O N G E T T Y -- Turn on getty(1m) for the communications tty line */ int ongetty(ttname) char *ttname; { char temp[30]; while (*ttname != '\0') ttname++; /* comms tty path name */ ttname -= 3; sprintf(temp,"/usr/bin/geton.sh %s",ttname); return(zsyscmd(temp)); } #endif /* ATT7300 */ /* T T S C A R R -- Set ttcarr variable, controlling carrier handling. * * 0 = Off: Always ignore carrier. E.g. you can connect without carrier. * 1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect. * 2 = Auto: For "modem direct": The same as "Off". * For real modem types: Heed carrier during connect, but ignore * it anytime else. Compatible with pre-5A C-Kermit versions. * * As you can see, this setting does not affect dialing, which always ignores * carrier (unless there is some special exception for some modem type). It * does affect ttopen() if it is set before ttopen() is used. This setting * takes effect on the next call to ttopen()/ttpkt()/ttvt(). And they are * (or should be) always called before any communications is tried, which * means that, practically speaking, the effect is immediate. * * Of course, nothing of this applies to remote mode (xlocal = 0). * * Someone has yet to uncover how to manipulate the carrier in the BSD * environment (or any non-termio using environment). Until that time, this * will simply be a no-op for BSD. * * Note that in previous versions, the carrier was most often left unchanged * in ttpkt()/ttvt() unless they were called with FLO_DIAL or FLO_DIAX. This * has changed. Now it is controlled by ttcarr in conjunction with these * modes. */ int #ifdef CK_ANSIC ttscarr( int carrier ) #else ttscarr(carrier) int carrier; #endif /* CK_ANSIC */ { ttcarr = carrier; debug(F101, "ttscarr","",ttcarr); return(ttcarr); } /* C A R R C T L -- Set tty modes for carrier treatment. * * Sets the appropriate bits in a termio or sgttyb struct for carrier control * (actually, there are no bits in sgttyb for that), or performs any other * operations needed to control this on the current system. The function does * not do the actual TCSETA or stty, since often we want to set other bits too * first. Don't call this function when xlocal is 0, or the tty is not opened. * * We don't know how to do anything like carrier control on non-ATTSV systems, * except, apparently, ultrix. See above. It is also known that this doesn't * have much effect on a Xenix system. For Xenix, one should switch back and * forth between the upper and lower case device files. Maybe later. * Presently, Xenix will stick to the mode it was opened with. * * carrier: 0 = ignore carrier, 1 = require carrier. * The current state is saved in curcarr, and checked to save labour. */ #ifdef SVORPOSIX int #ifdef CK_ANSIC #ifdef BSD44ORPOSIX carrctl( struct termios *ttpar, int carrier ) #else carrctl( struct termio *ttpar, int carrier ) #endif /* BSD44ORPOSIX */ #else /* CK_ANSIC */ #ifdef BSD44ORPOSIX carrctl(ttpar, carrier) struct termios *ttpar; int carrier; #else carrctl(ttpar, carrier) struct termio *ttpar; int carrier; #endif /* BSD44ORPOSIX */ #endif /* CK_ANSIC */ { debug(F101, "carrctl","",carrier); if (carrier) ttpar->c_cflag &= ~CLOCAL; else ttpar->c_cflag |= CLOCAL; return(0); } #else /* Berkeley, V7, et al... */ int carrctl(ttpar, carrier) struct sgttyb *ttpar; int carrier; { debug(F101, "carrctl","",carrier); if (carrier == curcarr) return(0); curcarr = carrier; #ifdef ultrix #ifdef COMMENT /* Old code from somebody at DEC that tends to get stuck, time out, etc. */ if (carrier) { ioctl(ttyfd, TIOCMODEM, &temp); ioctl(ttyfd, TIOCHPCL, 0); } else { /* (According to the manuals, TIOCNCAR should be preferred */ /* over TIOCNMODEM...) */ ioctl(ttyfd, TIOCNMODEM, &temp); } #else /* New code from Jamie Watson that, he says, eliminates the problems. */ if (carrier) { ioctl(ttyfd, TIOCCAR); ioctl(ttyfd, TIOCHPCL); } else { ioctl(ttyfd, TIOCNCAR); } #endif /* COMMENT */ #endif /* ultrix */ return(0); } #endif /* SVORPOSIX */ /* T T G M D M -- Get modem signals */ /* Looks for RS-232 modem signals, and returns those that are on in as its return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h. Returns: -3 Not implemented -2 if the communication device does not have modem control (e.g. telnet) -1 on error. >= 0 on success, with a bit mask containing the modem signals that are on. */ /* Define the symbol K_MDMCTL if we have Sys V R3 / 4.3 BSD style modem control, namely the TIOCMGET ioctl. */ #ifdef BSD43 #define K_MDMCTL #endif /* BSD43 */ #ifdef SUNOS4 #define K_MDMCTL #endif /* SUNOS4 */ /* SCO OpenServer R5.0.4. The TIOCMGET definition is hardwired in because it is skipped in termio.h when _POSIX_SOURCE is defined. But _POSIX_SOURCE must be defined in order to get the high serial speeds that are new to 5.0.4. However, the regular SCO drivers do not implement TIOCMGET, so the ioctl() returns -1 with errno 22 (invalid function). But third-party drivers, e.g. for Digiboard, do implement it, and so it should work on ports driven by those drivers. */ #ifdef SCO_OSR504 #ifndef TIOCMGET #define TIOCMGET (('t'<<8)|29) #endif /* TIOCMGET */ #endif /* SCO_OSR504 */ #ifdef CK_SCOV5 /* Because POSIX strictness in won't let us see these. */ #ifndef TIOCM_DTR #define TIOCM_DTR 0x0002 /* data terminal ready */ #define TIOCM_RTS 0x0004 /* request to send */ #define TIOCM_CTS 0x0020 /* clear to send */ #define TIOCM_CAR 0x0040 /* carrier detect */ #define TIOCM_RNG 0x0080 /* ring */ #define TIOCM_DSR 0x0100 /* data set ready */ #define TIOCM_CD TIOCM_CAR #define TIOCM_RI TIOCM_RNG #endif /* TIOCM_DTR */ #endif /* CK_SCOV5 */ #ifdef QNX #define K_MDMCTL #else #ifdef TIOCMGET #define K_MDMCTL #endif /* TIOCMGET */ #endif /* QNX */ /* "A serial communication program that can't read modem signals is like a car without windows." */ int ttgmdm() { #ifdef QNX #include unsigned long y, mdmbits[2]; int x, z = 0; if (xlocal && ttyfd < 0) return(-1); #ifdef NETCONN if (netconn) { /* Network connection */ #ifdef TN_COMPORT if (istncomport()) { gotsigs = 1; return(tngmdm()); } else #endif /* TN_COMPORT */ return(-2); /* No modem signals */ } #endif /* NETCONN */ #ifdef NETCMD if (ttpipe) return(-2); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(-2); #endif /* NETPTY */ mdmbits[0] = 0L; mdmbits[1] = 0L; /* * From : * * SERIAL devices (all Dev.ser versions) * 0 : DTR 8 = Data Bits 0 16 - reserved 24 - reserved * 1 : RTS 9 = Data Bits 1 17 - reserved 25 - reserved * 2 = Out 1 10 = Stop Bits 18 - reserved 26 - reserved * 3 = Int Enable 11 = Par Enable 19 - reserved 27 - reserved * 4 = Loop 12 = Par Even 20 = CTS 28 - reserved * 5 - reserved 13 = Par Stick 21 = DSR 29 - reserved * 6 - reserved 14 : Break 22 = RI 30 - reserved * 7 - reserved 15 = 0 23 = CD 31 - reserved */ errno = 0; x = qnx_ioctl(ttyfd, QCTL_DEV_CTL, &mdmbits[0], 8, &mdmbits[0], 4); debug(F101,"ttgmdm qnx_ioctl","",x); debug(F101,"ttgmdm qnx_ioctl errno","",errno); if (!x) { debug(F101,"ttgmdm qnx_ioctl mdmbits[0]","",mdmbits[0]); debug(F101,"ttgmdm qnx_ioctl mdmbits[1]","",mdmbits[1]); y = mdmbits[0]; if (y & 0x000001L) z |= BM_DTR; /* Bit 0 */ if (y & 0x000002L) z |= BM_RTS; /* Bit 1 */ if (y & 0x100000L) z |= BM_CTS; /* Bit 20 */ if (y & 0x200000L) z |= BM_DSR; /* Bit 21 */ if (y & 0x400000L) z |= BM_RNG; /* Bit 22 */ if (y & 0x800000L) z |= BM_DCD; /* Bit 23 */ debug(F101,"ttgmdm qnx result","",z); debug(F110,"ttgmdm qnx CD = ",(z & BM_DCD) ? "On" : "Off", 0); gotsigs = 1; return(z); } else return(-1); #else /* QNX */ #ifdef HPUX /* HPUX has its own way */ int x, z; #ifdef HPUX10 /* Modem flag word */ mflag y; /* mflag typedef'd in */ #else #ifdef HPUX9 mflag y; #else #ifdef HPUX8 mflag y; #else unsigned long y; /* Not sure about pre-8.0... */ #endif /* HPUX8 */ #endif /* HPUX9 */ #endif /* HPUX10 */ if (xlocal && ttyfd < 0) return(-1); #ifdef NETCONN if (netconn) { /* Network connection */ #ifdef TN_COMPORT if (istncomport()) { gotsigs = 1; return(tngmdm()); } else #endif /* TN_COMPORT */ return(-2); /* No modem signals */ } #endif /* NETCONN */ #ifdef NETCMD if (ttpipe) return(-2); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(-2); #endif /* NETPTY */ if (xlocal) /* Get modem signals */ x = ioctl(ttyfd,MCGETA,&y); else x = ioctl(0,MCGETA,&y); if (x < 0) return(-1); debug(F101,"ttgmdm","",y); z = 0; /* Initialize return value */ /* Now set bits for each modem signal that is reported to be on. */ #ifdef MCTS /* Clear To Send */ debug(F101,"ttgmdm HPUX CTS","",y & MCTS); if (y & MCTS) z |= BM_CTS; #endif #ifdef MDSR /* Data Set Ready */ debug(F101,"ttgmdm HPUX DSR","",y & MDSR); if (y & MDSR) z |= BM_DSR; #endif #ifdef MDCD /* Carrier */ debug(F101,"ttgmdm HPUX DCD","",y & MDCD); if (y & MDCD) z |= BM_DCD; #endif #ifdef MRI /* Ring Indicate */ debug(F101,"ttgmdm HPUX RI","",y & MRI); if (y & MRI) z |= BM_RNG; #endif #ifdef MDTR /* Data Terminal Ready */ debug(F101,"ttgmdm HPUX DTR","",y & MDTR); if (y & MDTR) z |= BM_DTR; #endif #ifdef MRTS /* Request To Send */ debug(F101,"ttgmdm HPUX RTS","",y & MRTS); if (y & MRTS) z |= BM_RTS; #endif gotsigs = 1; return(z); #else /* ! HPUX */ #ifdef K_MDMCTL /* Note, TIOCMGET might already have been defined in or elsewhere. If not, we try including -- if this blows up then more ifdefs are needed. */ #ifndef TIOCMGET #include #endif /* TIOCMGET */ int x, y, z; debug(F100,"ttgmdm K_MDMCTL defined","",0); #ifdef NETCONN if (netconn) { /* Network connection */ #ifdef TN_COMPORT if (istncomport()) { gotsigs = 1; return(tngmdm()); } else #endif /* TN_COMPORT */ return(-2); /* No modem signals */ } #endif /* NETCONN */ #ifdef NETCMD if (ttpipe) return(-2); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(-2); #endif /* NETPTY */ if (xlocal && ttyfd < 0) return(-1); if (xlocal) x = ioctl(ttyfd,TIOCMGET,&y); /* Get modem signals. */ else x = ioctl(0,TIOCMGET,&y); debug(F101,"ttgmdm TIOCMGET ioctl","",x); if (x < 0) { debug(F101,"ttgmdm errno","",errno); return(-1); } debug(F101,"ttgmdm bits","",y); z = 0; /* Initialize return value. */ #ifdef TIOCM_CTS /* Clear To Send */ if (y & TIOCM_CTS) z |= BM_CTS; debug(F101,"ttgmdm TIOCM_CTS defined","",TIOCM_CTS); #else debug(F100,"ttgmdm TIOCM_CTS not defined","",0); #endif #ifdef TIOCM_DSR /* Data Set Ready */ if (y & TIOCM_DSR) z |= BM_DSR; debug(F101,"ttgmdm TIOCM_DSR defined","",TIOCM_DSR); #else debug(F100,"ttgmdm TIOCM_DSR not defined","",0); #endif #ifdef TIOCM_CAR /* Carrier */ if (y & TIOCM_CAR) z |= BM_DCD; debug(F101,"ttgmdm TIOCM_CAR defined","",TIOCM_CAR); #else debug(F100,"ttgmdm TIOCM_CAR not defined","",0); #endif #ifdef TIOCM_RNG /* Ring Indicate */ if (y & TIOCM_RNG) z |= BM_RNG; debug(F101,"ttgmdm TIOCM_RNG defined","",TIOCM_RNG); #else debug(F100,"ttgmdm TIOCM_RNG not defined","",0); #endif #ifdef TIOCM_DTR /* Data Terminal Ready */ if (y & TIOCM_DTR) z |= BM_DTR; debug(F101,"ttgmdm TIOCM_DTR defined","",TIOCM_DTR); #else debug(F100,"ttgmdm TIOCM_DTR not defined","",0); #endif #ifdef TIOCM_RTS /* Request To Send */ if (y & TIOCM_RTS) z |= BM_RTS; debug(F101,"ttgmdm TIOCM_RTS defined","",TIOCM_RTS); #else debug(F100,"ttgmdm TIOCM_RTS not defined","",0); #endif gotsigs = 1; return(z); #else /* !K_MDMCTL catch-All */ debug(F100,"ttgmdm K_MDMCTL not defined","",0); #ifdef TIOCMGET debug(F100,"ttgmdm TIOCMGET defined","",0); #else debug(F100,"ttgmdm TIOCMGET not defined","",0); #endif /* TIOCMGET */ #ifdef _SVID3 debug(F100,"ttgmdm _SVID3 defined","",0); #else debug(F100,"ttgmdm _SVID3 not defined","",0); #endif /* _SVID3 */ #ifdef NETCONN if (netconn) { /* Network connection */ #ifdef TN_COMPORT if (istncomport()) { gotsigs = 1; return(tngmdm()); } else #endif /* TN_COMPORT */ return(-2); /* No modem signals */ } #endif /* NETCONN */ #ifdef NETCMD if (ttpipe) return(-2); #endif /* NETCMD */ #ifdef NETPTY if (ttpty) return(-2); #endif /* NETPTY */ return(-3); /* Sorry, I don't know how... */ #endif /* K_MDMCTL */ #endif /* HPUX */ #endif /* QNX */ } /* P S U S P E N D -- Put this process in the background. */ /* Call with flag nonzero if suspending is allowed, zero if not allowed. Returns 0 on apparent success, -1 on failure (flag was zero, or kill() returned an error code. */ int #ifdef CK_ANSIC psuspend( int flag ) #else psuspend(flag) int flag; #endif /* CK_ANSIC */ { #ifdef RTU extern int rtu_bug; #endif /* RTU */ if (flag == 0) return(-1); #ifdef NOJC return(-1); #else #ifdef SIGTSTP /* The big question here is whether job control is *really* supported. There's no way Kermit can know for sure. The fact that SIGTSTP is defined does not guarantee the Unix kernel supports it, and the fact that the Unix kernel supports it doesn't guarantee that the user's shell (or other process that invoked Kermit) supports it. */ #ifdef RTU rtu_bug = 1; #endif /* RTU */ if (kill(0,SIGSTOP) < 0 #ifdef MIPS /* Let's try this for MIPS too. */ && kill(getpid(),SIGSTOP) < 0 #endif /* MIPS */ ) { /* If job control, suspend the job */ perror("suspend"); debug(F101,"psuspend error","",errno); return(-1); } debug(F100,"psuspend ok","",0); return(0); #else return(-1); #endif /* SIGTSTP */ #endif /* NOJC */ } /* setuid package, by Kristoffer Eriksson, with contributions from Dean Long and fdc. */ /* The following is for SCO when CK_ANSILIBS is defined... */ #ifdef M_UNIX #ifdef CK_ANSILIBS #ifndef NOGETID_PROTOS #define NOGETID_PROTOS #endif /* NOGETID_PROTOS */ #endif /* CK_ANSILIBS */ #endif /* M_UNIX */ #ifndef _POSIX_SOURCE #ifndef SUNOS4 #ifndef NEXT #ifndef PS2AIX10 #ifndef sequent #ifndef HPUX9 #ifndef HPUX10 #ifndef COHERENT #ifndef NOGETID_PROTOS _PROTOTYP( UID_T getuid, (void) ); _PROTOTYP( UID_T geteuid, (void) ); _PROTOTYP( UID_T getreuid, (void) ); _PROTOTYP( UID_T getgid, (void) ); _PROTOTYP( UID_T getegid, (void) ); _PROTOTYP( UID_T getregid, (void) ); #endif /* NOGETID_PROTOS */ #else _PROTOTYP( UID_T getreuid, (void) ); _PROTOTYP( UID_T getregid, (void) ); #endif /* COHERENT */ #endif /* HPUX10 */ #endif /* HPUX9 */ #endif /* sequent */ #endif /* PS2AIX10 */ #endif /* NEXT */ #endif /* SUNOS4 */ #endif /* _POSIX_SOURCE */ /* Subject: Set-user-id To: fdc@watsun.cc.columbia.edu (Frank da Cruz) Date: Sat, 21 Apr 90 4:48:25 MES From: Kristoffer Eriksson This is a set of functions to be used in programs that may be run set-user-id and/or set-group-id. They handle both the case where the program is not run with such privileges (nothing special happens then), and the case where one or both of these set-id modes are used. The program is made to run with the user's real user and group ids most of the time, except for when more privileges are needed. Don't set-user-id to "root". This works on System V and POSIX. In BSD, it depends on the "saved-set-user-id" feature. */ #define UID_ROOT 0 /* Root user and group ids */ #define GID_ROOT 0 /* The following code defines the symbol SETEUID for UNIX systems based on BSD4.4 (either -Encumbered or -Lite). This program will then use seteuid() and setegid() instead of setuid() and setgid(), which still don't allow arbitrary switching. It also avoids setreuid() and setregid(), which are included in BSD4.4 for compatibility only, are insecure, and print warnings to stderr under at least one system (NetBSD 1.0). Note that POSIX systems should still use setuid() and setgid(); the seteuid() and setegid() functions are BSD4.4 extensions to the POSIX model. Mike Long , 8/94. */ #ifdef BSD44 #define SETEUID #endif /* BSD44 */ /* The following construction automatically defines the symbol SETREUID for UNIX versions based on Berkeley Unix 4.2 and 4.3. If this symbol is defined, then this program will use getreuid() and getregid() calls in preference to getuid() and getgid(), which in Berkeley-based Unixes do not allow arbitrary switching back and forth of real & effective uid. This construction also allows -DSETREUID to be put on the cc command line for any system that has and wants to use setre[ug]id(). It also prevents automatic definition of SETREUID if -DNOSETREU is included on the cc command line (or otherwise defined). */ #ifdef FT18 /* None of this for Fortune. */ #define NOSETREU #endif /* FT18 */ #ifdef ANYBSD #ifndef BSD29 #ifndef BSD41 #ifndef SETREUID #ifndef NOSETREU #ifndef SETEUID #define SETREUID #endif /* SETEUID */ #endif /* NOSETREU */ #endif /* SETREUID */ #endif /* !BSD41 */ #endif /* !BSD29 */ #endif /* ANYBSD */ /* Variables for user and group IDs. */ static UID_T realuid = (UID_T) -1, privuid = (UID_T) -1; static GID_T realgid = (GID_T) -1, privgid = (GID_T) -1; /* P R I V _ I N I -- Initialize privileges package */ /* Called as early as possible in a set-uid or set-gid program to store the * set-to uid and/or gid and step down to the users real uid and gid. The * stored id's can be temporarily restored (allowed in System V) during * operations that require the privilege. Most of the time, the program * should execute in unpriviliged state, to not impose any security threat. * * Note: Don't forget that access() always uses the real id:s to determine * file access, even with privileges restored. * * Returns an error mask, with error values or:ed together: * 1 if setuid() fails, * 2 if setgid() fails, and * 4 if the program is set-user-id to "root", which can't be handled. * * Only the return value 0 indicates real success. In case of failure, * those privileges that could be reduced have been, at least, but the * program should be aborted none-the-less. * * Also note that these functions do not expect the uid or gid to change * without their knowing. It may work if it is only done temporarily, but * you're on your own. */ int #ifdef CK_ANSIC priv_ini( void ) #else priv_ini() #endif /* CK_ANSIC */ { int err = 0; #ifndef HAVE_LOCKDEV /* Save real ID:s. */ realuid = getuid(); realgid = getgid(); /* Save current effective ID:s, those set to at program exec. */ privuid = geteuid(); privgid = getegid(); /* If running set-uid, go down to real uid, otherwise remember that * no privileged uid is available. * * Exceptions: * * 1) If the real uid is already "root" and the set-uid uid (the * initial effective uid) is not "root", then we would have trouble * if we went "down" to "root" here, and then temporarily back to the * set-uid uid (not "root") and then again tried to become "root". I * think the "saved set-uid" is lost when changing uid from effective * uid "root", which changes all uid, not only the effective uid. But * in this situation, we can simply go to "root" and stay there all * the time. That should give sufficient privilege (understatement!), * and give the right uids for subprocesses. * * 2) If the set-uid (the initial effective uid) is "root", and we * change uid to the real uid, we can't change it back to "root" when * we need the privilege, for the same reason as in 1). Thus, we can't * handle programs that are set-user-id to "root" at all. The program * should be stopped. Use some other uid. "root" is probably too * privileged for such things, anyway. (The uid is reverted to the * real uid until termination.) * * These two exceptions have the effect that the "root" uid will never * be one of the two uids that are being switched between, which also * means we don't have to check for such cases in the switching * functions. * * Note that exception 1) is handled by these routines (by constantly * running with uid "root", while exception 2) is a serious error, and * is not provided for at all in the switching functions. */ if (realuid == privuid) privuid = (UID_T) -1; /* Not running set-user-id. */ /* If running set-gid, go down to real gid, otherwise remember that * no privileged gid is available. * * There are no exception like there is for the user id, since there * is no group id that is privileged in the manner of uid "root". * There could be equivalent problems for group changing if the * program sometimes ran with uid "root" and sometimes not, but * that is already avoided as explained above. * * Thus we can expect always to be able to switch to the "saved set- * gid" when we want, and back to the real gid again. You may also * draw the conclusion that set-gid provides for fewer hassles than * set-uid. */ #ifdef SUIDDEBUG fprintf(stderr,"UID_ROOT=%d\n",UID_ROOT); fprintf(stderr,"realuid=%d\n",realuid); fprintf(stderr,"privuid=%d\n",privuid); #endif /* SUIDDEBUG */ if (realgid == privgid) /* If not running set-user-id, */ privgid = (GID_T) -1; /* remember it this way. */ err = priv_off(); /* Turn off setuid privilege. */ if (privuid == UID_ROOT) /* If setuid to root, */ err |= 4; /* return this error. */ if (realuid == UID_ROOT) { /* If real id is root, */ privuid = (UID_T) -1; /* stay root at all times. */ #ifdef ATT7300 /* If Kermit installed SUID uucp and user is running as root */ err &= ~1; /* System V R0 does not save UID */ #endif /* ATT7300 */ } #endif /* HAVE_LOCKDEV */ return(err); } /* Macros for hiding the differences in UID/GID setting between various Unix * systems. These macros should always be called with both the privileged ID * and the non-privileged ID. The one in the second argument, will become the * effective ID. The one in the first argument will be retained for later * retrieval. */ #ifdef SETREUID #ifdef SAVEDUID /* On BSD systems with the saved-UID feature, we just juggle the effective * UID back and forth, and leave the real UID at its true value. The kernel * allows switching to both the current real UID, the effective UID, and the * UID which the program is set-UID to. The saved set-UID always holds the * privileged UID for us, and the real UID will always be the non-privileged, * and we can freely choose one of them for the effective UID at any time. */ #define switchuid(hidden,active) setreuid( (UID_T) -1, active) #define switchgid(hidden,active) setregid( (GID_T) -1, active) #else /* SETREUID,!SAVEDUID */ /* On systems with setreXid() but without the saved-UID feature, notably * BSD 4.2, we swap the real and effective UIDs each time. It's * the effective UID that we are interested in, but we have to retain the * unused UID somewhere to enable us to restore it later, and we do this * in the real UID. The kernel only allows switching to either the current * real or the effective UID, unless you're "root". */ #define switchuid(hidden,active) setreuid(hidden,active) #define switchgid(hidden,active) setregid(hidden,active) #endif #else /* !SETREUID, !SAVEDUID */ #ifdef SETEUID /* BSD 4.4 works similarly to System V and POSIX (see below), but uses seteXid() instead of setXid() to change effective IDs. In addition, the seteXid() functions work the same for "root" as for other users. */ #define switchuid(hidden,active) seteuid(active) #define switchgid(hidden,active) setegid(active) #else /* !SETEUID */ /* On System V and POSIX, the only thing we can change is the effective UID * (unless the current effective UID is "root", but initsuid() avoids that for * us). The kernel allows switching to the current real UID or to the saved * set-UID. These are always set to the non-privileged UID and the privileged * UID, respectively, and we only change the effective UID. This breaks if * the current effective UID is "root", though, because for "root" setuid/gid * becomes more powerful, which is why initsuid() treats "root" specially. * Note: That special treatment maybe could be ignored for BSD? Note: For * systems that don't fit any of these four cases, we simply can't support * set-UID. */ #define switchuid(hidden,active) setuid(active) #define switchgid(hidden,active) setgid(active) #endif /* SETEUID */ #endif /* SETREUID */ /* P R I V _ O N -- Turn on the setuid and/or setgid */ /* Go to the privileged uid (gid) that the program is set-user-id * (set-group-id) to, unless the program is running unprivileged. * If setuid() fails, return value will be 1. If getuid() fails it * will be 2. Return immediately after first failure, and the function * tries to restore any partial work done. Returns 0 on success. * Group id is changed first, since it is less serious than user id. */ int priv_on() { #ifndef HAVE_LOCKDEV if (privgid != (GID_T) -1) if (switchgid(realgid,privgid)) return(2); if (privuid != (UID_T) -1) if (switchuid(realuid,privuid)) { if (privgid != (GID_T) -1) if (switchgid(privgid,realgid)) return(2); return(1); } #endif /* HAVE_LOCKDEV */ return(0); } /* P R I V _ O F F -- Turn on the real uid and gid */ /* Return to the unprivileged uid (gid) after an temporary visit to * privileged status, unless the program is running without set-user-id * (set-group-id). Returns 1 for failure in setuid() and 2 for failure * in setgid() or:ed together. The functions tries to return both uid * and gid to unprivileged state, regardless of errors. Returns 0 on * success. */ int priv_off() { int err = 0; #ifndef HAVE_LOCKDEV if (privuid != (UID_T) -1) if (switchuid(privuid,realuid)) err |= 1; if (privgid != (GID_T) -1) if (switchgid(privgid,realgid)) err |= 2; #endif /* HAVE_LOCKDEV */ return(err); } /* Turn off privilege permanently. No going back. This is necessary before * a fork() on BSD43 machines that don't save the setUID or setGID, because * we swap the real and effective ids, and we don't want to let the forked * process swap them again and get the privilege back. It will work on other * machines too, such that you can rely on its effect always being the same, * for instance, even when you're in priv_on() state when this is called. * (Well, that part about "permanent" is on System V only true if you follow * this with a call to exec(), but that's what we want it for anyway.) * Added by Dean Long -- dlong@midgard.ucsc.edu */ int priv_can() { #ifndef HAVE_LOCKDEV #ifdef SETREUID int err = 0; if (privuid != (UID_T) -1) if (setreuid(realuid,realuid)) err |= 1; if (privgid != (GID_T) -1) if (setregid(realgid,realgid)) err |= 2; return(err); #else #ifdef SETEUID int err = 0; if (privuid != (UID_T) -1) if (setuid(realuid)) { debug(F101,"setuid failed","",errno); err |= 1; debug(F101,"ruid","",getuid()); debug(F101,"euid","",geteuid()); } debug(F101,"setuid","",realuid); if (privgid != (GID_T) -1) if (setgid(realgid)) { debug(F101,"setgid failed","",errno); err |= 2; debug(F101,"rgid","",getgid()); debug(F101,"egid","",getegid()); } debug(F101,"setgid","",realgid); return(err); #else /* Easy way of using setuid()/setgid() instead of setreuid()/setregid().*/ return(priv_off()); #endif /* SETEUID */ #endif /* SETREUID */ #else return(0); #endif /* HAVE_LOCKDEV */ } /* P R I V _ O P N -- For opening protected files or devices. */ int #ifdef CK_ANSIC priv_opn( char *name, int modes ) #else priv_opn(name, modes) char *name; int modes; #endif /* CK_ANSIC */ { int x; priv_on(); /* Turn privileges on */ debug(F111,"priv_opn",name,modes); errno = 0; x = open(name, modes); /* Try to open the device */ debug(F101,"priv_opn result","",x); debug(F101,"priv_opn errno","",errno); priv_off(); /* Turn privileges off */ return(x); /* Return open's return code */ } /* P R I V _ C H K -- Check privileges. */ /* Try to turn them off. If turning them off did not succeed, cancel them */ int priv_chk() { int x, y = 0; x = priv_off(); /* Turn off privs. */ if (x != 0 || getuid() == privuid || geteuid() == privuid) y = priv_can(); if (x != 0 || getgid() == privgid || getegid() == privgid) y = y | priv_can(); return(y); } UID_T real_uid() { return(realuid); } VOID ttimoff() { /* Turn off any timer interrupts */ /* int xx; */ /* As of 5A(183), we set SIGALRM to SIG_IGN (to ignore alarms) rather than to SIG_DFL (to catch alarms, or if there is no handler, to exit). This is to cure (mask, really) a deeper problem with stray alarms that occurs on some systems, possibly having to do with sleep(), that caused core dumps. It should be OK to do this, because no code in this module uses nested alarms. (But we still have to watch out for SCRIPT and DIAL...) */ /* xx = */ alarm(0); /* debug(F101,"ttimoff alarm","",xx); */ if (saval) { /* Restore any previous */ signal(SIGALRM,saval); /* alarm handler. */ /* debug(F101,"ttimoff alarm restoring saval","",saval); */ saval = NULL; } else { signal(SIGALRM,SIG_IGN); /* Used to be SIG_DFL */ /* debug(F100,"ttimoff alarm SIG_IGN","",0); */ } } int tt_is_secure() { /* Tells whether the current connection is secure */ if (ttyfd == -1) return(0); if (0 #ifdef SSHBUILTIN || IS_SSH() #endif /* SSHBUILTIN */ #ifdef CK_ENCRYPTION || ck_tn_encrypting() && ck_tn_decrypting() #endif /* CK_ENCRYPTION */ #ifdef CK_SSL || tls_active_flag || ssl_active_flag #endif /* CK_SSL */ #ifdef RLOGCODE #ifdef CK_KERBEROS #ifdef CK_ENCRYPTION || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN #endif /* CK_ENCRYPTION */ #endif /* CK_KERBEROS */ #endif /* RLOGCODE */ ) return(1); return(0); } #ifdef CK_REDIR /* External protocol handler parameters from ckuus3.c */ extern int exp_handler, exp_stderr, exp_timo; #ifdef SELECT #ifdef NETPTY /* The right size is 24576 */ #ifndef PTY_PBUF_SIZE /* Size of buffer to read from pty */ #define PTY_PBUF_SIZE 24576 /* and write to net. */ #endif /* PTY_PBUF_SIZE */ #ifndef PTY_TBUF_SIZE /* Size of buffer to read from net */ #define PTY_TBUF_SIZE 24576 /* and write to pty. */ #endif /* PTY_TBUF_SIZE */ #ifdef O_NDELAY /* Whether to use nonblocking */ #ifndef PTY_NO_NDELAY /* reads on the pseudoterminal */ #ifndef PTY_USE_NDELAY #define PTY_USE_NDELAY #endif /* PTY_USE_NDELAY */ #endif /* PTY_NO_NDELAY */ #endif /* O_NDELAY */ #ifndef HAVE_OPENPTY #ifndef USE_CKUPTY_C #define USE_CKUPTY_C #endif /* USE_CKUPTY_C */ #endif /* HAVE_OPENPTY */ VOID #ifdef CK_ANSIC pty_make_raw( int fd ) #else pty_make_raw(fd) int fd; #endif /* CK_ANSIC */ { int x = -23, i; #ifdef BSD44ORPOSIX /* POSIX */ struct termios tp; #else #ifdef ATTSV /* AT&T UNIX */ #ifdef CK_ANSIC struct termio tp = {0}; #else struct termio tp; #endif /* CK_ANSIC */ #else struct sgttyb tp; /* Traditional */ #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ debug(F101,"pty_make_raw fd","",fd); errno = 0; #ifdef BSD44ORPOSIX /* POSIX */ x = tcgetattr(fd,&tp); debug(F101,"pty_make_raw tcgetattr","",x); #else #ifdef ATTSV /* AT&T UNIX */ x = ioctl(fd,TCGETA,&tp); debug(F101,"pty_make_raw TCGETA ioctl","",x); #else x = gtty(fd,&tp); debug(F101,"pty_make_raw ttty","",x); #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ debug(F101,"pty_make_raw GET errno","",errno); #ifdef USE_CFMAKERAW errno = 0; cfmakeraw(&tp); debug(F101,"pty_make_raw cfmakeraw errno","",errno); #else /* USE_CFMAKERAW */ #ifdef COMMENT /* This very simple version recommended by Serg Iakolev doesn't work */ tp.c_lflag &= ~(ECHO|ICANON|IEXTEN|ISIG); tp.c_iflag &= ~(BRKINT|ICRNL|INPCK|ISTRIP|IXON); tp.c_cflag &= ~(CSIZE|PARENB); tp.c_cflag |= CS8; tp.c_oflag &= ~(OPOST); tp.c_cc[VMIN] = 1; tp.c_cc[VTIME] = 0; debug(F101,"pty_make_raw 1 c_cc[] NCCS","",NCCS); debug(F101,"pty_make_raw 1 iflags","",tp.c_iflag); debug(F101,"pty_make_raw 1 oflags","",tp.c_oflag); debug(F101,"pty_make_raw 1 lflags","",tp.c_lflag); debug(F101,"pty_make_raw 1 cflags","",tp.c_cflag); #else #ifdef COMMENT /* In this version we unset everything and then set only the bits we know we need. */ /* iflags */ tp.c_iflag = 0L; tp.c_iflag |= IGNBRK; #ifdef IMAXBEL tp.c_iflag |= IMAXBEL; #endif /* IMAXBEL */ /* oflags */ tp.c_oflag = 0L; /* lflags */ tp.c_lflag = 0L; #ifdef NOKERNINFO tp.c_lflag |= NOKERNINFO; #endif /* NOKERNINFO */ /* cflags */ tp.c_cflag = 0L; tp.c_cflag |= CS8|CREAD; for (i = 0; i < NCCS; i++) { /* No special characters */ tp.c_cc[i] = 0; } #ifdef VMIN tp.c_cc[VMIN] = 1; /* But always wait for input */ #endif /* VMIN */ debug(F101,"pty_make_raw 2 c_cc[] NCCS","",NCCS); debug(F101,"pty_make_raw 2 iflags","",tp.c_iflag); debug(F101,"pty_make_raw 2 oflags","",tp.c_oflag); debug(F101,"pty_make_raw 2 lflags","",tp.c_lflag); debug(F101,"pty_make_raw 2 cflags","",tp.c_cflag); #else /* COMMENT */ /* In this version we set or unset every single flag explicitly. It works a bit better than the simple version just above, but it's still far from adequate. */ /* iflags */ tp.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL); tp.c_iflag &= ~(INPCK|IGNPAR|IXANY|IXON|IXOFF); tp.c_iflag |= IGNBRK; #ifdef IMAXBEL #ifdef COMMENT tp.c_iflag |= IMAXBEL; #else tp.c_iflag &= ~IMAXBEL; #endif /* COMMENT */ #endif /* IMAXBEL */ #ifdef IUCLC tp.c_iflag &= ~IUCLC; #endif /* IUCLC */ /* oflags */ #ifdef BSDLY tp.c_oflag &= ~BSDLY; #endif /* BSDLY */ #ifdef CRDLY tp.c_oflag &= ~CRDLY; #endif /* CRDLY */ #ifdef FFDLY tp.c_oflag &= ~FFDLY; #endif /* FFDLY */ #ifdef NLDLY tp.c_oflag &= ~NLDLY; #endif /* NLDLY */ #ifdef TABDLY tp.c_oflag &= ~TABDLY; #endif /* TABDLY */ #ifdef VTDLY tp.c_oflag &= ~VTDLY; #endif /* VTDLY */ #ifdef OFDEL tp.c_oflag &= ~OFDEL; #endif /* OFDEL */ #ifdef OFILL tp.c_oflag &= ~OFILL; #endif /* OFILL */ #ifdef OLCUC tp.c_oflag &= ~OLCUC; #endif /* OLCUC */ #ifdef CMSPAR tp.c_oflag &= ~CMSPAR; #endif /* CMSPAR */ tp.c_oflag &= ~OPOST; #ifdef OXTABS tp.c_oflag &= ~OXTABS; #endif /* OXTABS */ #ifdef COMMENT #ifdef ONOCR tp.c_oflag &= ~ONOCR; /* Maybe should be |=? */ tp.c_oflag |= ONOCR; /* makes no difference either way */ #endif /* ONOCR */ #endif /* COMMENT */ #ifdef ONOEOT tp.c_oflag &= ~ONOEOT; #endif /* ONOEOT */ #ifdef ONLRET tp.c_oflag &= ~ONLRET; #endif /* ONLRET */ #ifdef ONLCR tp.c_oflag &= ~ONLCR; #endif /* ONLCR */ #ifdef OCRNL tp.c_oflag &= ~OCRNL; #endif /* OCRNL */ /* lflags */ tp.c_lflag &= ~ECHO; #ifdef ECHOE tp.c_lflag &= ~ECHOE; #endif /* ECHOE */ #ifdef ECHONL tp.c_lflag &= ~ECHONL; #endif /* ECHONL */ #ifdef ECHOPRT tp.c_lflag &= ~ECHOPRT; #endif /* ECHOPRT */ #ifdef ECHOKE tp.c_lflag &= ~ECHOKE; #endif /* ECHOKE */ #ifdef ECHOCTL tp.c_lflag &= ~ECHOCTL; #endif /* ECHOCTL */ #ifdef XCASE tp.c_lflag &= ~XCASE; #endif /* XCASE */ #ifdef ALTWERASE tp.c_lflag &= ~ALTWERASE; #endif /* ALTWERASE */ #ifdef EXTPROC tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN|EXTPROC); #else tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN); #endif /* EXTPROC */ #ifdef NOKERNINFO tp.c_lflag |= NOKERNINFO; #endif /* NOKERNINFO */ #ifndef COMMENT tp.c_lflag &= ~NOFLSH; /* TRY IT THE OTHER WAY? */ #else tp.c_lflag |= NOFLSH; /* No, this way is worse */ #endif /* COMMENT */ /* cflags */ tp.c_cflag &= ~(CSIZE|PARENB|PARODD); tp.c_cflag |= CS8|CREAD; #ifdef MDMBUF tp.c_cflag &= ~(MDMBUF); #else #ifdef CCAR_OFLOW tp.c_cflag &= ~(CCAR_OFLOW); /* two names for the same thing */ #endif /* CCAR_OFLOW */ #endif /* MDMBUF */ #ifdef CCTS_OFLOW tp.c_cflag &= ~(CCTS_OFLOW); #endif /* CCTS_OFLOW */ #ifdef CDSR_OFLOW tp.c_cflag &= ~(CDSR_OFLOW); #endif /* CDSR_OFLOW */ #ifdef CDTR_IFLOW tp.c_cflag &= ~(CDTR_IFLOW); #endif /* CDTR_IFLOW */ #ifdef CRTS_IFLOW tp.c_cflag &= ~(CRTS_IFLOW); #endif /* CRTS_IFLOW */ #ifdef CRTSXOFF tp.c_cflag &= ~(CRTSXOFF); #endif /* CRTSXOFF */ #ifdef CRTSCTS tp.c_cflag &= ~(CRTSCTS); #endif /* CRTSCTS */ #ifdef CLOCAL tp.c_cflag &= ~(CLOCAL); #endif /* CLOCAL */ #ifdef CSTOPB tp.c_cflag &= ~(CSTOPB); #endif /* CSTOPB */ #ifdef HUPCL tp.c_cflag &= ~(HUPCL); #endif /* HUPCL */ for (i = 0; i < NCCS; i++) { /* No special characters */ tp.c_cc[i] = 0; } #ifdef VMIN tp.c_cc[VMIN] = 1; /* But always wait for input */ #endif /* VMIN */ debug(F101,"pty_make_raw 3 c_cc[] NCCS","",NCCS); debug(F101,"pty_make_raw 3 iflags","",tp.c_iflag); debug(F101,"pty_make_raw 3 oflags","",tp.c_oflag); debug(F101,"pty_make_raw 3 lflags","",tp.c_lflag); debug(F101,"pty_make_raw 3 cflags","",tp.c_cflag); #endif /* COMMENT */ #endif /* COMMENT */ errno = 0; #ifdef BSD44ORPOSIX /* POSIX */ x = tcsetattr(fd,TCSANOW,&tp); debug(F101,"pty_make_raw tcsetattr","",x); #else #ifdef ATTSV /* AT&T UNIX */ x = ioctl(fd,TCSETA,&tp); debug(F101,"pty_make_raw ioctl","",x); #else x = stty(fd,&tp); /* Traditional */ debug(F101,"pty_make_raw stty","",x); #endif /* ATTSV */ #endif /* BSD44ORPOSIX */ debug(F101,"pty_make_raw errno","",errno); #endif /* __NetBSD__ */ } static int #ifdef CK_ANSIC pty_chk( int fd ) #else pty_chk(fd) int fd; #endif /* CK_ANSIC */ { int x, n = 0; errno = 0; #ifdef FIONREAD x = ioctl(fd, FIONREAD, &n); /* BSD and most others */ ckmakmsg(msgbuf,500, "pty_chk ioctl FIONREAD errno=", ckitoa(errno), " count=", ckitoa(n)); debug(F100,msgbuf,"",0); #else #ifdef RDCHK n = rdchk(fd); debug(F101,"pty_chk rdchk","",n); #else n = 1; #endif /* RDCHK */ #endif /* FIONREAD */ return((n > -1) ? n : 0); } static int #ifdef CK_ANSIC pty_get_status( int fd, PID_T pid ) #else pty_get_status(fd,pid) int fd; PID_T pid; #endif /* CK_ANSIC */ { int x, status = -1; PID_T w; debug(F101,"pty_get_status fd","",fd); debug(F101,"pty_get_status pid","",pid); if (pexitstat > -1) return(pexitstat); #ifdef COMMENT /* Not only unnecessary but harmful */ errno = 0; x = kill(pty_fork_pid,0); debug(F101,"pty_get_status kill value","",x); debug(F101,"pty_get_status kill errno","",errno); if (x > -1 && errno != ESRCH) return(-1); /* Fork still there */ /* Fork seems to be gone */ #endif /* COMMENT */ errno = 0; x = waitpid(pty_fork_pid,&status,WNOHANG); debug(F111,"pty_get_status waitpid",ckitoa(errno),x); if (x <= 0 && errno == 0) { debug(F101,"pty_get_status waitpid return","",-1); return(-1); } if (x > 0) { if (x != pty_fork_pid) debug(F101, "pty_get_status waitpid pid doesn't match","",pty_fork_pid); debug(F101,"pty_get_status waitpid status","",status); debug(F101,"pty_get_status waitpid errno","",errno); if (WIFEXITED(status)) { debug(F100,"pty_get_status WIFEXITED","",0); status = WEXITSTATUS(status); debug(F101,"pty_get_status fork exit status","",status); #ifdef COMMENT end_pty(); #endif /* COMMENT */ close(fd); pexitstat = status; } else { debug(F100,"pty_get_status waitpid unexpected status","",0); } } debug(F101,"pty_get_status return status","",status); return(status); } /* t t p t y c m d -- Run command on pty and forward to net */ /* Needed for running external protocols on secure connections. For example, if C-Kermit has made an SSL/TLS or Kerberos Telnet connection, and then needs to transfer a file with Zmodem, which is an external program, this routine reads Zmodem's output, encrypts it, and then forwards it out the connection, and reads the encrypted data stream coming in from the connection, decrypts it, and forwards it to Zmodem. Works like a TCP/IP port forwarder except one end is a pty rather than a socket, which introduces some complications: . On most platforms, select() always indicates the output side of the pty has characters waiting to be read, even when it doesn't, even when the pty process has already exited. . Nonblocking reads must be used on the pty, because there is no way on certain platforms (e.g. NetBSD) to find out how many characters are available to be read (the FIONREAD ioctl always says 0). The code also allows for blocking reads (if O_NDELAY and O_NONBLOCK are not defined, or if PTY_NO_NDELAY is defined), but on some platforms this can result in single-byte reads and writes (NetBSD again). . Testing for "EOF" on the pty is problematic. select() never gives any indication. After the pty process has exited and the fork has disappeared, read() can still return with 0 bytes read but without an error (NetBSD); no known test on the pty file descriptor will indicate that it is no longer valid. The process ID of the pty fork can be tested on some platforms (NetBSD, luckily) but not others (Solaris, Linux). On the network side, we use ttinc() and ttoc(), which, for network connections, handle any active security methods. Call with s = command. Returns 0 on failure, 1 on success. fdc - December 2006 - August 2007. NOTE: This code defaults to nonblocking reads if O_NDELAY or O_NONBLOCK are defined in the header files, which should be true of every recent Unix platform. If this causes trouble somewhere, define PTY_NO_NDELAY, e.g. when building C-Kermit: touch ckutio.c make platformname KFLAGS=-DPTY_NO_NODELAY */ static int have_pty = 0; /* Do we have a pty? */ static SIGTYP (*save_sigchld)() = NULL; /* For catching SIGCHLD */ static VOID #ifdef CK_ANSIC sigchld_handler( int sig ) #else sigchld_handler(sig) int sig; #endif /* CK_ANSIC */ { have_pty = 0; /* We don't have a pty */ #ifdef DEBUG if (save_sigchld) { (VOID) signal(SIGCHLD,save_sigchld); save_sigchld = NULL; } if (deblog) { debug(F100,"**************","",0); debug(F100,"SIGCHLD caught","",0); debug(F100,"**************","",0); } #endif /* DEBUG */ } #define HAVE_IAC 1 #define HAVE_CR 2 int #ifdef CK_ANSIC ttptycmd( char *s ) #else ttptycmd(s) char *s; #endif /* CK_ANSIC */ { CHAR tbuf[PTY_TBUF_SIZE]; /* Read from net, write to pty */ int tbuf_avail = 0; /* Pointers for tbuf */ int tbuf_written = 0; static int in_state = 0; /* For TELNET IAC and NVT in */ static int out_prev = 0; /* Simpler scheme for out */ CHAR pbuf[PTY_PBUF_SIZE]; /* Read from pty, write to net */ CHAR dbuf[PTY_PBUF_SIZE + PTY_PBUF_SIZE + 1]; /* Double-size buffer */ int pbuf_avail = 0; /* Pointers for pbuf */ int pbuf_written = 0; int ptyfd = -1; /* Pty file descriptor */ int have_net = 0; /* We have a network connection */ int pty_err = 0; /* Got error on pty */ int net_err = 0; /* Got error on net */ int status = -1; /* Pty process exit status */ int rc = 0; /* Our return code */ int x1 = 0, x2 = 0; /* Workers... */ int c, n, m, t, x; /* Workers */ long seconds_to_wait = 0L; /* select() timeout */ struct timeval tv, *tv2; /* For select() */ #ifdef INTSELECT int in, out, err; /* For select() */ #else fd_set in, out, err; #endif /* INTSELECT */ int nfds = 0; /* For select() */ int pset = 0, tset = 0, pnotset = 0, tnotset = 0; /* stats/debuggin only */ int read_net_bytes = 0; /* Stats */ int write_net_bytes = 0; /* Stats */ int read_pty_bytes = 0; /* Stats */ int write_pty_bytes = 0; /* Stats */ int is_tn = 0; /* TELNET protocol is active */ int masterfd = -1; int slavefd = -1; #ifndef USE_CKUPTY_C struct termios term; struct winsize twin; struct stringarray * q; char ** args = NULL; #endif /* USE_CKUPTY_C */ in_state = 0; /* No previous character yet */ if (ttyfd == -1) { printf("?Sorry, communication channel is not open\n"); return(0); } else { have_net = 1; } if (nopush) { debug(F100,"ttptycmd fail: nopush","",0); return(0); } if (!s) s = ""; /* Defense de bogus arguments */ if (!*s) return(0); pexitstat = -1; /* Fork process exit status */ #ifdef TNCODE is_tn = (xlocal && netconn && IS_TELNET()) || /* Telnet protocol active */ (!xlocal && sstelnet); #endif /* TNCODE */ debug(F110,"ttptycmd command",s,0); debug(F101,"ttptycmd ttyfd","",ttyfd); debug(F101,"ttptycmd is_tn","",is_tn); debug(F101,"ttptycmd ckermit pid","",getpid()); #ifdef USE_CKUPTY_C /* Call ckupty.c module to get and set up the pty fork */ /* fc 1 == "run an external protocol" */ debug(F100,"ttptycmd using ckupty.c","",0); if (do_pty(&ptyfd,s,1) < 0) { /* Start the command on a pty */ debug(F100,"ttptycmd do_pty fails","",0); return(0); } masterfd = ptyfd; pty_master_fd = ptyfd; #ifdef COMMENT slavefd = pty_slave_fd; /* This is not visible to us */ #endif /* COMMENT */ debug(F111,"ttptycmd ptyfd","USE_CKUPTY_C",ptyfd); debug(F111,"ttptycmd masterfd","USE_CKUPTY_C",masterfd); debug(F111,"ttptycmd fork pid","USE_CKUPTY_C",pty_fork_pid); #ifndef SOLARIS /* "ioctl inappropriate on device" for pty master */ pty_make_raw(masterfd); #endif /* SOLARIS */ #else /* USE_CKUPTY_C */ debug(F100,"ttptycmd OPENPTY","",0); if (tcgetattr(0, &term) == -1) { /* Get controlling terminal's modes */ perror("tcgetattr"); return(0); } if (ioctl(0, TIOCGWINSZ, (char *) &twin) == -1) { /* and window size */ perror("ioctl TIOCGWINSZ"); return(0); } if (openpty(&masterfd, &slavefd, NULL, NULL, NULL) == -1) { debug(F101,"ttptycmd openpty failed errno","",errno); perror("opentpy"); return(0); } debug(F101,"ttptycmd openpty masterfd","",masterfd); debug(F101,"ttptycmd openpty slavefd","",slavefd); pty_master_fd = masterfd; pty_slave_fd = slavefd; debug(F101,"ttptycmd openpty pty_master_fd","",pty_master_fd); /* Put pty master in raw mode but let forked app control the slave */ pty_make_raw(masterfd); #ifdef COMMENT #ifdef TIOCREMOTE /* TIOCREMOTE,0 = disable all termio processing */ x = ioctl(masterfd, TIOCREMOTE, 1); debug(F111,"ttptycmd ioctl TIOCREMOTE",ckitoa(x),errno); #endif /* TIOCREMOTE */ #ifdef TIOCTTY /* TIOCTTY,0 = disable all termio processing */ x = ioctl(masterfd, TIOCTTY, 0); debug(F111,"ttptycmd ioctl TIOCTTY",ckitoa(x),errno); #endif /* TIOCTTY */ #endif /* COMMENT */ have_pty = 1; /* We have an open pty */ save_sigchld = signal(SIGCHLD, sigchld_handler); /* Catch fork quit */ pty_fork_pid = fork(); /* Make fork for external protocol */ debug(F101,"ttptycmd pty_fork_pid","",pty_fork_pid); if (pty_fork_pid == -1) { perror("fork"); return(0); } else if (pty_fork_pid == 0) { /* In new fork */ int x; debug(F101,"ttptycmd new fork pid","",getpid()); close(masterfd); /* Slave quarters no masters allowed */ x = setsid(); debug(F101,"ttptycmd new fork setsid","",x); if (x == -1) { perror("ttptycmd setsid"); exit(1); } signal(SIGINT,SIG_IGN); /* Let upper fork catch this */ #ifdef COMMENT #ifdef TIOCSCTTY /* Make pty the controlling terminal for the process */ /* THIS CAUSES AN INFINITE SIGWINCH INTERRUPT LOOP */ x = ioctl(slavefd, TIOCSCTTY, NULL); debug(F101,"ttptycmd TIOCSCTTY","",x); #endif /* TIOCSCTTY */ #endif /* COMMENT */ /* Initialize slave pty modes and size to those of our terminal */ if (tcsetattr(slavefd, TCSANOW, &term) == -1) { perror("ttptycmd tcsetattr"); exit(1); } if (ioctl(slavefd, TIOCSWINSZ, &twin) == -1) { perror("ttptycmd ioctl"); exit(1); } #ifdef COMMENT #ifdef TIOCNOTTY /* Disassociate this process from its terminal */ /* THIS HAS NO EFFECT */ x = ioctl(slavefd, TIOCNOTTY, NULL); debug(F101,"ttptycmd TIOCNOTTY","",x); #endif /* TIOCNOTTY */ #endif /* COMMENT */ #ifdef COMMENT #ifdef SIGTTOU /* Ignore terminal output interrupts */ /* THIS HAS NO EFFECT */ debug(F100,"ttptycmd ignoring SIGTTOU","",0); signal(SIGTTOU, SIG_IGN); #endif /* SIGTTOU */ #ifdef SIGTSTP /* Ignore terminal output interrupts */ /* THIS HAS NO EFFECT */ debug(F100,"ttptycmd ignoring SIGTSTP","",0); signal(SIGTSTP, SIG_IGN); #endif /* SIGTSTP */ #endif /* COMMENT */ pty_make_raw(slavefd); /* Put it in rawmode */ errno = 0; if (dup2(slavefd, STDIN_FILENO) != STDIN_FILENO || dup2(slavefd, STDOUT_FILENO) != STDOUT_FILENO) { debug(F101,"ttptycmd new fork dup2 error","",errno); perror("ttptycmd dup2"); exit(1); } debug(F100,"ttptycmd new fork dup2 ok","",0); /* Parse external protocol command line */ q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0,0); if (!q) { debug(F100,"ttptycmd cksplit failed","",0); exit(1); } else { int i, n; debug(F100,"ttptycmd cksplit ok","",0); n = q->a_size; args = q->a_head + 1; for (i = 0; i <= n; i++) { if (!args[i]) { break; } else { /* sometimes cksplit() doesn't terminate the list */ if ((i == n) && args[i]) { if ((int)strlen(args[i]) == 0) makestr(&(args[i]),NULL); } } } } #ifdef COMMENT /* Putting the slave pty in rawmode should not be necessary because the external protocol program is supposed to do that itself. Yet doing this here cuts down on Zmodem binary-file transmission errors by 30-50% but still doesn't eliminate them. */ pty_make_raw(STDIN_FILENO); pty_make_raw(STDOUT_FILENO); #endif /* COMMENT */ debug(F100,"ttptycmd execvp'ing external protocol","",0); execvp(args[0],args); perror("execvp failed"); debug(F101,"ttptycmd execvp failed","",errno); close(slavefd); exit(1); } /* (there are better ways to do this...) */ msleep(1000); /* Make parent wait for child to be ready */ ptyfd = masterfd; /* We talk to the master */ #endif /* USE_CKUPTY_C */ debug(F101,"ttptycmd ptyfd","",ptyfd); if (ptyfd < 0) { printf("?Failure to get pty\n"); return(-9); } have_pty = 1; /* We have an open pty or we wouldn't he here */ debug(F101,"ttptycmd PTY_PBUF_SIZE","",PTY_PBUF_SIZE); debug(F101,"ttptycmd PTY_TBUF_SIZE","",PTY_TBUF_SIZE); #ifdef PTY_USE_NDELAY /* NOTE: If select() and ioctl(ptyfd,FIONREAD,&n) return true indications on the pty, we don't need nonblocking reads. Performance of either method seems to be about the same, so use whatever works. */ errno = 0; x = fcntl(ptyfd,F_SETFL,fcntl(ptyfd,F_GETFL, 0)|O_NDELAY); ckmakmsg(msgbuf,500, "ttptycmd set O_NDELAY errno=", ckitoa(errno), " fcntl=", ckitoa(x)); debug(F100,msgbuf,"",0); #endif /* PTY_USE_NDELAY */ #ifdef COMMENT /* Not necessary, the protocol module already did this */ #ifdef USE_CFMAKERAW if (tcgetattr(ttyfd, &term) > -1) { cfmakeraw(&term); debug(F101,"ttptycmd net cfmakeraw errno","",errno); x tcsetattr(ttyfd, TCSANOW, &term); debug(F101,"ttptycmd net tcsetattr","",x); debug(F101,"ttptycmd net tcsetattr","",errno); } #else if (local) /* Put network connection in */ ttpkt(ttspeed,ttflow,ttprty); /* "packet mode". */ else conbin((char)escchr); /* OR... pty_make_raw(0) */ #endif /* USE_CFMAKERAW */ #endif /* COMMENT */ #ifdef TNCODE if (is_tn) { debug(F101,"<<< ttptycmd TELOPT_ME_BINARY","",TELOPT_ME(TELOPT_BINARY)); debug(F101,"<<< ttptycmd TELOPT_U_BINARY","",TELOPT_U(TELOPT_BINARY)); } #endif /* TNCODE */ debug(F101,"ttptycmd entering loop - seconds_to_wait","",seconds_to_wait); while (have_pty || have_net) { FD_ZERO(&in); /* Initialize select() structs */ FD_ZERO(&out); FD_ZERO(&err); /* (not used because useless) */ nfds = -1; debug(F101,"ttptycmd loop top have_pty","",have_pty); debug(F101,"ttptycmd loop top have_net","",have_net); /* Pty is open and we have room to read from it? */ if (have_pty && pbuf_avail < PTY_PBUF_SIZE) { debug(F100,"ttptycmd FD_SET ptyfd in","",0); FD_SET(ptyfd, &in); nfds = ptyfd; } /* Network is open and we have room to read from it? */ if (have_net && have_pty && tbuf_avail < PTY_TBUF_SIZE) { debug(F100,"ttptycmd FD_SET ttyfd in","",0); FD_SET(ttyfd, &in); if (ttyfd > nfds) nfds = ttyfd; } /* Pty is open and we have stuff to write to it? */ if (have_pty && tbuf_avail - tbuf_written > 0) { debug(F100,"ttptycmd FD_SET ptyfd out","",0); FD_SET (ptyfd, &out); if (ptyfd > nfds) nfds = ptyfd; } /* Net is open and we have stuff to write to it? */ debug(F101,"ttptycmd pbuf_avail-pbuf_written","", pbuf_avail - pbuf_written); if (have_net && pbuf_avail - pbuf_written > 0) { debug(F100,"ttptycmd FD_SET ttyfd out","",0); FD_SET (ttyfd, &out); if (ttyfd > nfds) nfds = ttyfd; } /* We don't use err because it's not really for errors, */ /* but for out of band data on the TCP socket, which, if it is */ /* to be handled at all, is handled in the tt*() routines */ nfds++; /* 0-based to 1-based */ debug(F101,"ttptycmd nfds","",nfds); if (!nfds) { debug(F100,"ttptycmd NO FDs set for select","",0); if (have_pty) { /* This is not right -- sleeping won't accomplish anything */ debug(F101,"ttptycmd msleep","",100); msleep(100); } else { debug(F100,"ttptycmd no pty - quitting loop","",0); break; } } errno = 0; if (seconds_to_wait > 0L) { /* Timeout in case nothing happens */ tv.tv_sec = seconds_to_wait; /* for a long time */ tv.tv_usec = 0L; tv2 = &tv; } else { tv2 = NULL; } x = select(nfds, &in, &out, NULL, tv2); debug(F101,"ttptycmd select","",x); if (x < 0) { if (errno == EINTR) continue; debug(F101,"ttptycmd select error","",errno); break; } if (x == 0) { debug(F101,"ttptycmd +++ select timeout","",seconds_to_wait); if (have_pty) { status = pty_get_status(ptyfd,pty_fork_pid); debug(F101,"ttptycmd pty_get_status A","",status); if (status > -1) pexitstat = status; have_pty = 0; } break; } /* We want to handle any pending writes first to make room */ /* for new incoming. */ if (FD_ISSET(ttyfd, &out)) { /* Can write to net? */ CHAR * s; s = pbuf + pbuf_written; /* Current spot for sending */ #ifdef TNCODE if (is_tn) { /* ttol() doesn't double IACs */ CHAR c; /* Rewrite string with IACs doubled */ int i; s = pbuf + pbuf_written; /* Source */ x = 0; /* Count */ for (i = 0; i < pbuf_avail - pbuf_written; i++) { c = s[i]; /* Next character */ if (c == IAC) { /* If it's IAC */ dbuf[x++] = c; /* put another one */ debug(F000,">>> QUOTED IAC","",c); } else if (c != 0x0a && out_prev == 0x0d) { /* Bare CR */ if (!TELOPT_ME(TELOPT_BINARY)) { /* NVT rule */ c = 0x00; dbuf[x++] = c; debug(F000,">>> CR-NUL","",c); } } dbuf[x++] = c; /* Copy and count it */ debug(F000,">>> char",ckitoa(in_state),c); out_prev = c; } s = dbuf; /* New source */ } else #endif /* TNCODE */ x = pbuf_avail - pbuf_written; /* How much to send */ debug(F101,"ttptycmd bytes to send","",x); x = ttol(s, x); debug(F101,">>> ttol","",x); if (x < 0) { net_err++; debug(F111,"ttptycmd ttol error",ckitoa(x),errno); x = 0; } write_net_bytes += x; #ifdef COMMENT pbuf_written += x; #else /* 13 October 2021: Bug fix by Ao Huang (Oscar). pbuf_written is the position in the source string. But x is the number of bytes written to the destination string, which is not the same if there was any byte stuffing, e.g. doubling of IACs. The error caused the next source byte to be skipped. */ pbuf_written += pbuf_avail - pbuf_written; #endif /* COMMENT */ } if (FD_ISSET(ptyfd, &out)) { /* Can write to pty? */ debug(F100,"ttptycmd FD_ISSET ptyfd out","",0); errno = 0; #ifndef COMMENT x = write(ptyfd,tbuf + tbuf_written,tbuf_avail - tbuf_written); #else /* Byte loop to rule out data overruns in the pty */ /* (it makes no difference) */ { char *p = tbuf+tbuf_written; int n = tbuf_avail - tbuf_written; for (x = 0; x < n; x++) { msleep(10); if (write(ptyfd,&(p[x]),1) < 0) break; } } #endif /* COMMENT */ debug(F111,"ttptycmd ptyfd write",ckitoa(errno),x); if (x > 0) { tbuf_written += x; write_pty_bytes += x; } else { x = 0; pty_err++; if (pexitstat < 0) { status = pty_get_status(ptyfd,pty_fork_pid); debug(F101,"ttptycmd pty_get_status B","",status); if (status > -1) pexitstat = status; have_pty = 0; } debug(F100,"ttptycmd +++ ptyfd write error","",0); } } if (FD_ISSET(ttyfd, &in)) { /* Can read from net? */ tset++; debug(F100,"ttptycmd FD_ISSET ttyfd in","",0); n = in_chk(1,ttyfd); debug(F101,"ttptycmd in_chk(ttyfd)","",n); if (n < 0 || ttyfd == -1) { debug(F101,"ttptycmd +++ ttyfd errno","",errno); net_err++; } else if (n > 0) { if (n > PTY_TBUF_SIZE - tbuf_avail) n = PTY_TBUF_SIZE - tbuf_avail; debug(F101,"ttptycmd net read size adjusted","",n); if (xlocal && netconn) { /* We have to use a byte loop here because ttxin() does not decrypt or, for that matter, handle Telnet. */ int c; CHAR * p; p = tbuf + tbuf_avail; for (x = 0; x < n; x++) { if ((c = ttinc(0)) < 0) break; if (!is_tn) { /* Not Telnet - keep all bytes */ *p++ = (CHAR)c; debug(F000,"<<< char","",c); #ifdef TNCODE } else { /* Telnet - must handle IAC and NVT */ debug(F000,"<<< char",ckitoa(in_state),c); switch (c) { case 0x00: /* NUL */ if (in_state == HAVE_CR) { debug(F000,"<<< SKIP","",c); } else { *p++ = c; debug(F000,"<<< Keep","",c); } in_state = 0; break; case 0x0d: /* CR */ if (!TELOPT_U(TELOPT_BINARY)) in_state = HAVE_CR; *p++ = c; debug(F000,"<<< Keep","",c); break; #ifdef COMMENT case 0x0f: /* Ctrl-O */ case 0x16: /* Ctrl-V */ *p++ = 0x16; *p++ = c; debug(F000,"<<< QUOT","",c); break; #endif /* COMMENT */ case 0xff: /* IAC */ if (in_state == HAVE_IAC) { debug(F000,"<<< KEEP","",c); *p++ = c; in_state = 0; } else { debug(F000,"<<< SKIP","",c); in_state = HAVE_IAC; } break; default: /* All others */ if (in_state == HAVE_IAC) { #ifdef COMMENT /* tn_doop() will consume an unknown number of bytes and we'll overshoot the for-loop. The only Telnet command I've ever seen arrive here is a Data Mark, which comes when the remote protocol exits and the remote job returns to its shell prompt. On the assumption it's a 1-byte command, we don't write out the IAC or the command, and we clear the state. If we called tn_doop() we'd have no way of knowing how many bytes it took from the input stream. */ int xx; xx = tn_doop((CHAR)c,duplex,ttinc); debug(F111,"<<< DOOP",ckctoa(c),xx); #else debug(F101,"<<< DOOP","",c); #endif /* COMMENT */ in_state = 0; } else { *p++ = c; debug(F000,"<<< keep","",c); in_state = 0; } } #endif /* TNCODE */ } } ckmakmsg(msgbuf,500, "ttptycmd read net [ttinc loop] errno=", ckitoa(errno), " count=", ckitoa(x)); debug(F100,msgbuf,"",0); } else { x = ttxin(n,tbuf+tbuf_avail); debug(F101,"ttptycmd ttxin x","",x); } if (x < 0) { debug(F101,"ttptycmd read net error","",x); net_err++; } tbuf_avail += x; read_net_bytes += x; } } else tnotset++; if (FD_ISSET(ptyfd, &in)) { /* Read from pty? */ pset++; debug(F100,"ttptycmd FD_ISSET ptyfd in","",0); #ifdef PTY_USE_NDELAY n = PTY_PBUF_SIZE; #else /* This does not work on nonblocking channels on certain platforms such as NetBSD. */ n = pty_chk(ptyfd); #endif /* PTY_USE_NDELAY */ debug(F101,"ttptycmd pty_chk() n","",n); if (n < 0) n = 0; if (n > 0) { if (n > PTY_PBUF_SIZE - pbuf_avail) n = PTY_PBUF_SIZE - pbuf_avail; debug(F101,"ttptycmd pty read size adjusted","",n); errno = 0; x = read(ptyfd,pbuf+pbuf_avail,n); #ifdef DEBUG if (deblog) { ckmakmsg(msgbuf,500, "ttptycmd read pty errno=", ckitoa(errno), " count=", ckitoa(x)); debug(F100,msgbuf,"",0); } #endif /* DEBUG */ if (x < 0 && errno == EAGAIN) x = 0; if (x < 0) { /* This works on Solaris and Linux */ pty_err++; /* but not NetBSD */ debug(F100,"TERMINATION TEST A","",0); #ifdef COMMENT if (errno == EIO) rc = 1; #endif /* COMMENT */ if (pexitstat < 0) { status = pty_get_status(ptyfd,pty_fork_pid); debug(F101,"ttptycmd pty_get_status C","",status); if (status > -1) pexitstat = status; } have_pty = 0; x = 0; } if (x == 0 && !pty_err) { /* This works on NetBSD but */ debug(F100,"TERMINATION TEST B","",0); status = pexitstat > -1 ? pexitstat : pty_get_status(ptyfd,pty_fork_pid); debug(F101,"ttptycmd pty_get_status D","",status); if (status > -1) { pexitstat = status; pty_err++; have_pty = 0; } else { /* Select() lied */ pty_err = 0; /* pty still there but has nothing */ msleep(100); /* sleep a bit */ } x = 0; } /* Hopefully the next two are no longer needed... */ if (!pty_err && ( #ifndef PTY_USE_NDELAY x < 1 || errno #else errno != 0 && errno != EAGAIN #endif /* PTY_USE_NDELAY */ )) { debug(F100,"TERMINATION TEST C","",0); pty_err++; debug(F101,"ttptycmd SET pty_err","",pty_err); if (errno == EIO) /* errno == EIO is like EOF */ rc = 1; if (x < 0) x = 0; } #ifdef COMMENT #ifdef DEBUG if (deblog) { pbuf[pbuf_avail + x] = '\0'; debug(F111,"ttptycmd added to pty buffer", pbuf+pbuf_avail,x); } #endif /* DEBUG */ #endif /* COMMENT */ pbuf_avail += x; read_pty_bytes += x; } else { /* n == 0 with blocking reads */ debug(F100, "PTY READ RETURNED ZERO BYTES - SHOULD NOT HAPPEN", "",0); } } else pnotset++; /* If writes have caught up to reads, reset the buffers */ if (pbuf_written == pbuf_avail) pbuf_written = pbuf_avail = 0; if (tbuf_written == tbuf_avail) tbuf_written = tbuf_avail = 0; /* See if we can exit */ x1 = pbuf_avail - pbuf_written; x2 = tbuf_avail - tbuf_written; debug(F101,"ttptycmd pty_err LOOP EXIT TEST pty_err","",pty_err); debug(F101,"ttptycmd pty_err LOOP EXIT TEST x1 [write to net]","",x1); debug(F101,"ttptycmd pty_err LOOP EXIT TEST x2 [write to pty]","",x2); debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc","",rc); debug(F101,"ttptycmd pty_err LOOP EXIT TEST status","",status); debug(F101,"ttptycmd pty_err LOOP EXIT TEST pexitstat","",pexitstat); if (net_err) { /* Net error? */ debug(F101,"ttptycmd net_err LOOP EXIT TEST net_err","",net_err); if (have_net) { if (local) { ttclos(0); printf("?Connection closed\n"); } have_net = 0; } debug(F101,"ttptycmd net_err LOOP EXIT TEST x1","",x1); if (x1 == 0) break; } if (pty_err) { /* Pty error? */ if (have_pty) { if (pexitstat < 0) { status = pty_get_status(ptyfd,pty_fork_pid); debug(F101,"ttptycmd pty_get_status E","",status); if (status > -1) pexitstat = status; } have_pty = 0; } if (x1 == 0 && x2 == 0) { /* If buffers are caught up */ rc = 1; /* set preliminary return to success */ debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc 2","",rc); break; /* and exit the loop */ } } } debug(F101,"ttptycmd +++ have_pty","",have_pty); if (have_pty) { /* In case select() failed */ #ifdef USE_CKUPTY_C end_pty(); close(ptyfd); #else close(slavefd); close(masterfd); #endif /* USE_CKUPTY_C */ } pty_master_fd = -1; debug(F101,"ttptycmd +++ pexitstat","",pexitstat); if (pexitstat < 0) { /* Try one last time to get status */ status = pty_get_status(ptyfd,pty_fork_pid); debug(F101,"ttptycmd pty_get_status F","",status); if (status > -1) pexitstat = status; } debug(F101,"ttptycmd +++ final pexitstat","",pexitstat); if (deblog) { /* Stats for debug log */ debug(F101,"ttptycmd +++ pset ","",pset); debug(F101,"ttptycmd +++ pnotset","",pnotset); debug(F101,"ttptycmd +++ tset ","",tset); debug(F101,"ttptycmd +++ tnotset","",tnotset); debug(F101,"ttptycmd +++ read_pty_bytes","",read_pty_bytes); debug(F101,"ttptycmd +++ write_net_bytes","",write_net_bytes); debug(F101,"ttptycmd +++ read_net_bytes","",read_net_bytes); debug(F101,"ttptycmd +++ write_pty_bytes","",write_pty_bytes); } /* If we got the external protocol's exit status from waitpid(), we use that to set our return code. If not, we fall back on whatever rc was previously set to, namely 1 (success) if the pty fork seemed to terminate, 0 otherwise. */ if (save_sigchld) { /* Restore this if we changed it */ (VOID) signal(SIGCHLD,save_sigchld); save_sigchld = NULL; } msleep(500); x = kill(pty_fork_pid,SIGHUP); /* In case it's still there */ pty_fork_pid = -1; debug(F101,"ttptycmd fork kill SIGHUP","",x); if (pexitstat > -1) rc = (pexitstat == 0 ? 1 : 0); debug(F101,"ttptycmd +++ rc","",rc); if (!local) { /* If in remote mode */ conres(); /* restore console to CBREAK mode */ concb((char)escchr); } return(rc); } #endif /* NETPTY */ #endif /* SELECT */ /* T T R U N C M D -- Redirect an external command over the connection. */ /* TTRUNCMD is the routine that was originally used for running external protocols. It is very simple and works fine provided (a) the connection is not encrypted, and (b) the external protocol uses standard i/o (file descriptors 0 and 1) for file transfer. */ int #ifdef CK_ANSIC ttruncmd( char *s ) #else ttruncmd(s) char *s; #endif /* CK_ANSIC */ { PID_T pid; /* pid of lower fork */ int wstat; /* for wait() */ int x; int statusp; if (ttyfd == -1) { printf("?Sorry, device is not open\n"); return(0); } if (nopush) { debug(F100,"ttruncmd fail: nopush","",0); return(0); } #ifdef NETPTY /*************** It might also be necessary to use the pty routine for other reasons, e.g. because the external program does not use stdio. */ #ifdef NETCONN /* If we have a network connection we use a different routine because (a) if the connection is encrypted, the mechanism used here can't deal with it; and (b) it won't handle any network protocols either, e.g. Telnet, Rlogin, K5 U-to-U, etc. However, this routine works much better (faster, more transparent) on serial connections and when C-Kermit is in remote mode (i.e. is on the far end). */ /* For testing always use this */ if (netconn) return(ttptycmd(s)); #endif /* NETCONN */ /***************/ #else /* NETPTY */ if (tt_is_secure()) { printf("?Sorry, \ external protocols over secure connections not supported in this OS.\n" ); return(0); } #endif /* NETPTY */ conres(); /* Make console normal */ pexitstat = -4; if ((pid = fork()) == 0) { /* Make a child fork */ if (priv_can()) /* Child: turn off privs. */ exit(1); dup2(ttyfd, 0); /* Give stdin/out to the line */ dup2(ttyfd, 1); x = system(s); debug(F101,"ttruncmd system",s,x); _exit(x ? BAD_EXIT : 0); } else { SIGTYP (*istat)(), (*qstat)(); if (pid == (PID_T) -1) /* fork() failed? */ return(0); istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */ qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */ #ifdef COMMENT while (((wstat = wait(&statusp)) != pid) && (wstat != -1)) ; #else /* Not COMMENT */ while (1) { wstat = wait(&statusp); debug(F101,"ttruncmd wait","",wstat); if (wstat == pid || wstat == -1) break; } #endif /* COMMENT */ pexitstat = (statusp & 0xff) ? statusp : statusp >> 8; debug(F101,"ttruncmd wait statusp","",statusp); debug(F101,"ttruncmd wait pexitstat","",pexitstat); signal(SIGINT,istat); /* Restore interrupts */ signal(SIGQUIT,qstat); } concb((char)escchr); /* Restore console to CBREAK mode */ return(statusp == 0 ? 1 : 0); } #endif /* CK_REDIR */ struct tm * #ifdef CK_ANSIC cmdate2tm(char * date, int gmt) /* date as "yyyymmdd hh:mm:ss" */ #else cmdate2tm(date,gmt) char * date; int gmt; #endif { /* date as "yyyymmdd hh:mm:ss" */ static struct tm _tm; time_t now; if (strlen(date) != 17 || date[8] != ' ' || date[11] != ':' || date[14] != ':') return(NULL); time(&now); if (gmt) _tm = *gmtime(&now); else _tm = *localtime(&now); _tm.tm_year = (date[0]-'0')*1000 + (date[1]-'0')*100 + (date[2]-'0')*10 + (date[3]-'0')-1900; _tm.tm_mon = (date[4]-'0')*10 + (date[5]-'0')-1; _tm.tm_mday = (date[6]-'0')*10 + (date[7]-'0'); _tm.tm_hour = (date[9]-'0')*10 + (date[10]-'0'); _tm.tm_min = (date[12]-'0')*10 + (date[13]-'0'); _tm.tm_sec = (date[15]-'0')*10 + (date[16]-'0'); /* Should we set _tm.tm_isdst to -1 here? */ _tm.tm_wday = 0; _tm.tm_yday = 0; return(&_tm); } #ifdef HAVE_LOCALE #include #define DAYNAMERESULT 128 static char daynameresult[DAYNAMERESULT]; /* day = day-of-week number, 0-6 (0=Su, 1=Mo, 2=Tu, ..., 6=Sa). fc = 0 for full name, 1 for standard abbreviation, e.g. Mon, Tue. Returns: Day name according to current locale on success; NULL on failure. Note: nl_langinfo() items are indexed by numbers that vary from platform to platform (e.g. NetBSD and Solaris are totally different). */ char * #ifdef CK_ANSIC locale_dayname( int day, int fc ) #else locale_dayname(day,fc) int day, fc; #endif /* CK_ANSIC */ { /* date as "yyyymmdd hh:mm:ss" */ int n = 0; int x = DAY_1; char * date; char buf[20]; if (day < 0 || day > 6) return(NULL); n = day + 1; if (n > 6) n = 0; /* 2013-10-15 */ if (fc) x = ABDAY_1; ckstrncpy(daynameresult,nl_langinfo(((nl_item)(n+x))),DAYNAMERESULT); return((char *)daynameresult); } #define MONTHNAMERESULT 128 static char monthnameresult[MONTHNAMERESULT]; /* month = month-of-year number, 0-11 (0=Jan, 1=Feb, 2=Mar, ..., 11=Dec). fc = 0 for full name, 1 for standard abbreviation, e.g. Jan, Feb. Returns: Month name according to current locale on success; NULL on failure. */ char * #ifdef CK_ANSIC locale_monthname( int month, int fc ) #else locale_monthname(month,fc) int month, fc; #endif /* CK_ANSIC */ { int n = 0; int x = MON_1; char * date; char buf[20]; char mbuf[4]; if (month < 0 || month > 11) return(NULL); n = month; /* 0-based calendar month number */ if (fc) x = ABMON_1; ckstrncpy(monthnameresult,nl_langinfo(((nl_item)(n+x))),MONTHNAMERESULT); return((char *)monthnameresult); } #endif /* HAVE_LOCALE */ #ifdef OXOS #undef kill #endif /* OXOS */ #ifdef OXOS int priv_kill(pid, sig) int pid, sig; { int i; if (priv_on()) debug(F100,"priv_kill priv_on failed","",0); i = kill(pid, sig); if (priv_off()) debug(F100,"priv_kill priv_off failed","",0); return(i); } #endif /* OXOS */ #ifdef BEOSORBEBOX /* #ifdef BE_DR_7 */ /* alarm() function not supplied with Be OS DR7 - this one contributed by Neal P. Murphy. */ /* This should mimic the UNIX/POSIX alarm() function well enough, with the caveat that one's SIGALRM handler must call alarm_expired() to clean up vars and wait for the alarm thread to finish. */ unsigned int alarm(unsigned int seconds) { long time_left = 0; /* If an alarm is active, turn it off, saving the unused time */ if (alarm_thread != -1) { /* We'll be generous and count partial seconds as whole seconds. */ time_left = alarm_struct.time - ((system_time() - time_started) / 1000000.0); /* Kill the alarm thread */ kill_thread (alarm_thread); /* We need to clean up as though the alarm occured. */ time_started = 0; alarm_struct.thread = -1; alarm_struct.time = 0; alarm_expired(); } /* Set a new alarm clock, if requested. */ if (seconds > 0) { alarm_struct.thread = find_thread(NULL); alarm_struct.time = seconds; time_started = system_time(); alarm_thread = spawn_thread (do_alarm, "alarm_thread", B_NORMAL_PRIORITY, (void *) &alarm_struct ); resume_thread (alarm_thread); } /* Now return [unused time | 0] */ return ((unsigned int) time_left); } /* This function is the departure from UNIX/POSIX alarm handling. In the case of Be's missing alarm() function, this stuff needs to be done in the SIGALRM handler. When Be implements alarm(), this function call can be eliminated from user's SIGALRM signal handlers. */ void alarm_expired(void) { long ret_val; if (alarm_thread != -1) { wait_for_thread (alarm_thread, &ret_val); alarm_thread = -1; } } /* This is the function that snoozes the requisite number of seconds and then SIGALRMs the calling thread. Note that kill() wants a pid_t arg, whilst Be uses thread_id; currently they are both typdef'ed as long, but I'll do the cast anyway. This function is run in a separate thread. */ long do_alarm (void *alarm_struct) { snooze ((double) ((struct ALARM_STRUCT *) alarm_struct)->time * 1000000.0); kill ((pid_t)((struct ALARM_STRUCT *) alarm_struct)->thread, SIGALRM); time_started = 0; ((struct ALARM_STRUCT *) alarm_struct)->thread = -1; ((struct ALARM_STRUCT *) alarm_struct)->time = 0; } /* #endif */ /* BE_DR_7 */ #endif /* BEOSORBEBOX */ #ifdef Plan9 int p9ttyctl(char letter, int num, int param) { char cmd[20]; int len; if (ttyctlfd < 0) return -1; cmd[0] = letter; if (num) len = sprintf(cmd + 1, "%d", param) + 1; else { cmd[1] = param; len = 2; } if (write(ttyctlfd, cmd, len) == len) { cmd[len] = 0; /* fprintf(stdout, "wrote '%s'\n", cmd); */ return 0; } return -1; } int p9ttyparity(char l) { return p9ttyctl('p', 0, l); } int p9tthflow(int flow, int status) { return p9ttyctl('m', 1, status); } int p9ttsspd(int cps) { if (p9ttyctl('b', 1, cps * 10) < 0) return -1; ttylastspeed = cps * 10; return 0; } int p9openttyctl(char *ttname) { char name[100]; if (ttyctlfd >= 0) { close(ttyctlfd); ttyctlfd = -1; ttylastspeed = -1; } sprintf(name, "%sctl", ttname); ttyctlfd = open(name, 1); return ttyctlfd; } int p9concb() { if (consctlfd >= 0) { if (write(consctlfd, "rawon", 5) == 5) return 0; } return -1; } int p9conbin() { return p9concb(); } int p9conres() { if (consctlfd >= 0) { if (write(consctlfd, "rawoff", 6) == 6) return 0; } return -1; } int p9sndbrk(int msec) { if (ttyctlfd >= 0) { char cmd[20]; int i = sprintf(cmd, "k%d", msec); if (write(ttyctlfd, cmd, i) == i) return 0; } return -1; } int conwrite(char *buf, int n) { int x; static int length = 0; static int holdingcr = 0; int normal = 0; for (x = 0; x < n; x++) { char c = buf[x]; if (c == 007) { if (normal) { write(1, buf + (x - normal), normal); length += normal; normal = 0; } /* write(noisefd, "1000 300", 8); */ holdingcr = 0; } else if (c == '\r') { if (normal) { write(1, buf + (x - normal), normal); length += normal; normal = 0; } holdingcr = 1; } else if (c == '\n') { write(1, buf + (x - normal), normal + 1); normal = 0; length = 0; holdingcr = 0; } else if (c == '\b') { if (normal) { write(1, buf + (x - normal), normal); length += normal; normal = 0; } if (length) { write(1, &c, 1); length--; } holdingcr = 0; } else { if (holdingcr) { char b = '\b'; while (length-- > 0) write(1, &b, 1); length = 0; /* compiler bug */ } holdingcr = 0; normal++; } } if (normal) { write(1, buf + (x - normal), normal); length += normal; } return n; } void conprint(char *fmt, ...) { static char buf[1000]; /* not safe if on the stack */ va_list ap; int i; va_start(ap, fmt); i = vsprintf(buf, fmt, ap); conwrite(buf, i); } #endif /* Plan9 */ /* fprintf, printf, perror replacements... */ /* f p r i n t f */ #ifdef UNIX #ifdef CK_ANSIC #include #else /* CK_ANSIC */ #ifdef __GNUC__ #include #else #include #endif /* __GNUC__ */ #endif /* CK_ANSIC */ #ifdef fprintf #undef fprintf static char str1[4096]; static char str2[4096]; int #ifdef CK_ANSIC ckxfprintf(FILE * file, const char * format, ...) #else /* CK_ANSIC */ ckxfprintf(va_alist) va_dcl #endif /* CK_ANSIC */ /* ckxfprintf */ { int i, j, len, got_cr; va_list args; int rc = 0; #ifdef CK_ANSIC va_start(args, format); #else /* CK_ANSIC */ char * format; FILE * file; va_start(args); file = va_arg(args,FILE *); format = va_arg(args,char *); #endif /* CK_ANSIC */ if (!inserver || (file != stdout && file != stderr && file != stdin)) { rc = vfprintf(file,format,args); } else { unsigned int c; rc = vsprintf(str1, format, args); len = strlen(str1); if (len >= sizeof(str1)) { debug(F101,"ckxfprintf() buffer overflow","",len); doexit(BAD_EXIT,1); } for (i = 0, j = 0, got_cr = 0; i < len && j < sizeof(str1)-2; i++, j++ ) { /* We can't use 255 as a case label because of signed chars */ c = (unsigned)(str1[i] & 0xff); #ifdef TNCODE if (c == 255) { if (got_cr && !TELOPT_ME(TELOPT_BINARY)) str2[j++] = '\0'; str2[j++] = IAC; str2[j] = IAC; got_cr = 0; } else #endif /* TNCODE */ switch (c) { case '\r': if (got_cr #ifdef TNCODE && !TELOPT_ME(TELOPT_BINARY) #endif /* TNCODE */ ) str2[j++] = '\0'; str2[j] = str1[i]; got_cr = 1; break; case '\n': if (!got_cr) str2[j++] = '\r'; str2[j] = str1[i]; got_cr = 0; break; default: if (got_cr #ifdef TNCODE && !TELOPT_ME(TELOPT_BINARY) #endif /* TNCODE */ ) str2[j++] = '\0'; str2[j] = str1[i]; got_cr = 0; } } if (got_cr #ifdef TNCODE && !TELOPT_ME(TELOPT_BINARY) #endif /* TNCODE */ ) str2[j++] = '\0'; #ifdef CK_ENCRYPTION #ifdef TNCODE if (TELOPT_ME(TELOPT_ENCRYPTION)) ck_tn_encrypt(str2,j); #endif /* TNCODE */ #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if (inserver && (ssl_active_flag || tls_active_flag)) { /* Write using SSL */ char * p = str2; ssl_retry: if (ssl_active_flag) rc = SSL_write(ssl_con, p, j); else rc = SSL_write(tls_con, p, j); debug(F111,"ckxfprintf","SSL_write",rc); switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) { case SSL_ERROR_NONE: if (rc == j) break; p += rc; j -= rc; goto ssl_retry; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_SYSCALL: if (rc != 0) return(-1); case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: rc = 0; } } else #endif /* CK_SSL */ fwrite(str2,sizeof(char),j,stdout); } va_end(args); return(rc); } #endif /* fprintf */ /* p r i n t f */ #ifdef printf #undef printf int #ifdef CK_ANSIC ckxprintf(const char * format, ...) #else /* CK_ANSIC */ ckxprintf(va_alist) va_dcl #endif /* CK_ANSIC */ /* ckxprintf */ { int i, j, len, got_cr; va_list args; int rc = 0; #ifdef CK_ANSIC va_start(args, format); #else /* CK_ANSIC */ char * format; va_start(args); format = va_arg(args,char *); #endif /* CK_ANSIC */ if (!inserver) { rc = vprintf(format, args); } else { unsigned int c; rc = vsprintf(str1, format, args); len = strlen(str1); if (len >= sizeof(str1)) { debug(F101,"ckxprintf() buffer overflow","",len); doexit(BAD_EXIT,1); } for (i = 0, j = 0, got_cr=0; i < len && j < sizeof(str1)-2; i++, j++ ) { c = (unsigned)(str1[i] & 0xff); #ifdef TNCODE if (c == 255) { if (got_cr && !TELOPT_ME(TELOPT_BINARY)) str2[j++] = '\0'; str2[j++] = IAC; str2[j] = IAC; got_cr = 0; } else #endif /* TNCODE */ switch (c) { case '\r': if (got_cr #ifdef TNCODE && !TELOPT_ME(TELOPT_BINARY) #endif /* TNCODE */ ) str2[j++] = '\0'; str2[j] = str1[i]; got_cr = 1; break; case '\n': if (!got_cr) str2[j++] = '\r'; str2[j] = str1[i]; got_cr = 0; break; default: if (got_cr #ifdef TNCODE && !TELOPT_ME(TELOPT_BINARY) #endif /* TNCODE */ ) str2[j++] = '\0'; str2[j] = str1[i]; got_cr = 0; break; } } if (got_cr #ifdef TNCODE && !TELOPT_ME(TELOPT_BINARY) #endif /* TNCODE */ ) str2[j++] = '\0'; #ifdef CK_ENCRYPTION #ifdef TNCODE if (TELOPT_ME(TELOPT_ENCRYPTION)) ck_tn_encrypt(str2,j); #endif /* TNCODE */ #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if (inserver && (ssl_active_flag || tls_active_flag)) { char * p = str2; /* Write using SSL */ ssl_retry: if (ssl_active_flag) rc = SSL_write(ssl_con, p, j); else rc = SSL_write(tls_con, p, j); debug(F111,"ckxprintf","SSL_write",rc); switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) { case SSL_ERROR_NONE: if (rc == j) break; p += rc; j -= rc; goto ssl_retry; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_SYSCALL: if (rc != 0) return(-1); case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: rc = 0; } } else #endif /* CK_SSL */ rc = fwrite(str2,sizeof(char),j,stdout); } va_end(args); return(rc); } #endif /* printf */ /* p e r r o r */ #ifdef perror #undef perror _PROTOTYP(char * ck_errstr,(VOID)); #ifdef NEXT void #else #ifdef CK_SCOV5 void #else int #endif /* CK_SCOV5 */ #endif /* NEXT */ #ifdef CK_ANSIC ckxperror(const char * str) #else /* CK_ANSIC */ ckxperror(str) char * str; #endif /* CK_ANSIC */ /* ckxperror */ { char * errstr = ck_errstr(); #ifndef NEXT #ifndef CK_SCOV5 return #endif /* CK_SCOV5 */ #endif /* NEXT */ ckxprintf("%s%s %s\n",str,*errstr?":":"",errstr); } #endif /* perror */ #endif /* UNIX */ #ifdef MINIX2 /* Minix doesn't have a gettimeofday call (but MINIX3 does). * We fake one here using time(2) */ #ifndef MINIX3 int gettimeofday(struct timeval *tp, struct timezone *tzp) { tp->tv_usec = 0L; /* Close enough for horseshoes */ if(time(&(tp->tv_sec))==-1) return(-1); return(0); } #endif /* MINIX3 */ #ifndef MINIX3 int readlink(const char *path, void *buf, size_t bufsiz) { errno = ENOSYS; return(-1); } #endif /* MINIX3 */ #endif /* MINIX2 */ ckuus2.c000664 045065 024037 00002101320 14767403361 012555 0ustar00fdckermit000000 000000 /* C K U U S 2 -- User interface strings & help text module for C-Kermit */ /* Authors: Frank da Cruz , The Kermit Project, New York City Jeffrey E Altman Secure Endpoints Inc., New York City David Goodwin, New Zealand. Copyright (C) 1985, 2024, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Last updates: 22 Aug 2022 (HELP TYPE adds /INTERPRET switch). 20 Sep 2022 (HELP COPY adds /INTERPRET, /TOSCREEN switches). 06 Nov 2022 (fixed formatting of HELP SET TELNET). 12 Nov 2022 (converted four function help strings to arrays). 02 Dec 2022 (changed ssh v2 macs list in windows "help ssh"). 03 Dec 2022 (fixed misplaced definition of cr_year). 12 Apr 2023 (ANSI-ize function definitions) 25 Jan 2024 (Added HELP REMOTE STATUS) 03 Feb 2024 (Added HELP REMOTE CWD) This module contains HELP command and other long text strings. IMPORTANT: As of 2022, character string constants longer than about 509 are not portable. Longer strings should be broken up into arrays of strings and accessed with hmsga() rather than hmsg(). The length limit might be lower in older C compilers. */ #include "ckcsym.h" #include "ckcdeb.h" #include "ckcnet.h" #include "ckcasc.h" #include "ckcker.h" #include "ckuusr.h" #include "ckcxla.h" #ifdef OS2 #ifdef NT #include #else /* not NT */ #define INCL_KBD #ifdef OS2MOUSE #define INCL_MOU #endif /* OS2MOUSE */ #define INCL_DOSMISC #define INCL_DOSDEVICES #include /* This pulls in a whole load of stuff */ #undef COMMENT #endif /* NT */ #include "ckocon.h" #include "ckokvb.h" #include "ckokey.h" #include "ckover.h" /* This really should be ckover.h */ #ifdef SSHBUILTIN #include "ckossh.h" #endif #ifndef NOLOCAL int ttgcwsz(); /* ckocon.c */ #endif /* NOLOCAL */ #endif /* OS2 */ #ifdef CK_ANSIC #include "ckcfnp.h" /* Prototypes (must be last) */ static int dohfile( int ); /* Prototype for static func */ #endif /* CK_ANSIC */ extern char * ck_cryear; /* For copyright notice */ extern xx_strp xxstring; extern char * ccntab[]; /* hlptok contains the string for which the user requested help. This is useful for distinguishing synonyms, in case different help text is needed depending on which synonym was given. */ extern char * hlptok; #ifndef NOIKSD extern int inserver; #endif /* IKSD */ #ifndef NOICP extern int cmflgs; #ifdef DCMDBUF extern char *cmdbuf, *atmbuf; #else extern char cmdbuf[], atmbuf[]; #endif /* DCMDBUF */ #endif /* NOICP */ extern char *xarg0; extern int nrmt, nprm, dfloc, local, parity, escape; extern int turn, flow; extern int binary, quiet, keep; extern int success, xaskmore; #ifdef OS2 extern int tt_rows[], tt_cols[]; #else /* OS2 */ extern int tt_rows, tt_cols; #endif /* OS2 */ extern int cmd_rows, cmd_cols; extern long speed; extern char *dftty, *versio, *ckxsys; #ifndef NOHELP extern char *helpfile; #endif /* NOHELP */ extern struct keytab prmtab[]; #ifndef NOXFER extern struct keytab remcmd[]; #endif /* NOXFER */ #ifndef NOICP /* Interactive help strings */ /* Top-level HELP text. IMPORTANT: Also see tophlpi[] for IKSD. */ static char *tophlp[] = { "Trustees of Columbia University in the City of New York.\n", #ifndef NOHELP " Type EXIT to exit.", #ifdef OS2 " Type INTRO for a brief introduction to the C-Kermit Command screen.", #else " Type INTRO for a brief introduction to C-Kermit.", #endif /* OS2 */ " Type LICENSE to see the C-Kermit license.", " Type HELP followed by a command name for help about a specific command.", #ifndef NOPUSH #ifdef UNIX " Type MANUAL to access the C-Kermit manual page.", #else #ifdef VMS " Type MANUAL to access the C-Kermit help topic.", #else " Type MANUAL to access the C-Kermit manual.", #endif /* VMS */ #endif /* UNIX */ #endif /* NOPUSH */ " Type NEWS for news about new features.", " Type SUPPORT to learn how to get technical support.", " Press ? (question mark) at the prompt, or anywhere within a command,", " for a menu (context-sensitive help, menu on demand).", #else "Press ? for a list of commands; see documentation for detailed descriptions.", #endif /* NOHELP */ #ifndef NOCMDL #ifndef NOHELP " ", " Type HELP OPTIONS for help with command-line options.", #endif /* NOHELP */ #endif /* NOCMDL */ " ", #ifndef OS2 #ifdef MAC "Documentation for Command Window: \"Using C-Kermit\" by Frank da Cruz and", "Christine M. Gianone, Digital Press, 1997, ISBN: 1-55558-164-1", #else "DOCUMENTATION: \"Using C-Kermit\" by Frank da Cruz and Christine M. Gianone,", "2nd Edition, Digital Press / Butterworth-Heinemann 1997, ISBN 1-55558-164-1,", "plus supplements at http://www.kermitproject.org/ckermit.html#doc.", #endif /* MAC */ #endif /* OS2 */ #ifdef MAC " ", "Also see the Mac Kermit Doc and Bwr files on the Mac Kermit diskette.\n", #else #ifdef HPUX10 " ", "See the files in /usr/share/lib/kermit/ for additional information.", #endif /* HPUX10 */ #endif /* MAC */ "" }; #ifndef NOIKSD #ifdef NOHELP static char *tophlpi[] = { /* Top-level help for IKSD */ "Trustees of Columbia University in the City of New York.\n", #ifndef NOHELP " Type INTRO for a brief introduction to Kermit commands.", " Type VERSION for version and copyright information.", " Type HELP followed by a command name for help about a specific command.", " Type SUPPORT to learn how to get technical support.", " Type LOGOUT (or EXIT) to log out.", " Press ? (question mark) at the prompt, or anywhere within a command,", " for a menu (context-sensitive help, menu on demand).", #else "Press ? for a list of commands; see documentation for detailed descriptions.", #endif /* NOHELP */ " ", "DOCUMENTATION: \"Using C-Kermit\" by Frank da Cruz and Christine M. Gianone,", "2nd Edition, Digital Press (1997), ISBN 1-55558-164-1. More info at the", "Kermit Project website, http://www.kermitproject.org/.", "" }; #endif /* NOHELP */ #endif /* NOIKSD */ #ifndef NOHELP char *newstxt[] = { #ifdef OS2 "Welcome to Kermit 95 " K95_VERSION_MAJ_MIN_REV ", the Open-Source Successor", "to Columbia Columbia University's Kermit 95 package." #ifdef BETATEST " ", "THIS IS A PRERELEASE TEST VERSION NOT YES SUITABLE FOR PRODUCTION USE.", "FOR DETAILS, SEE http://www.kermitproject.org/ckw10beta.html", #endif /* BETATEST */ " ", "Major new features since the final commercial Kermit 95 release include:", " . Open Source Simplified 3-Clause BSD License", #else "Welcome to C-Kermit 10.0.", "New features since version 9.0 of 2011 include:", #endif /* OS2 */ #ifdef OS2 " . Source code! Kermit 95 is now available under the Revised 3-Clause", " BSD Open Source license.", " . Upgraded from C-Kermit 8.0.206 to the latest C-Kermit 10.0" " . Up-to-date fully exportable SSH v2 client", " . Up-to-date TLS support for http, ftp and telnet", " . PTY support on Windows 10 version 1809 and newer", " . Now available as a 64bit application (x86-64, ARM64, Itanium)", " . Mouse wheel support, customizable with SET MOUSE WHEEL", " (see HELP SET MOUSE for details)", " . X10, X11, URXVT and SGR mouse reporting", #endif /* OS2 */ #ifndef OS2 #ifdef COMMENT " . Full 64-bit memory model on platforms that support it", " . Large file support (64-bit file size) on most platforms", " . Long integer variables and constants in commands and scripts", #endif /* COMMENT */ /* For 10.0 */ " . Updated for longevity... Adapted to 2020s compilers and OS's without", " sacrificing compatability with older platforms going back to the 1970s", " and 1980s; at least that's the intention.", " . The first new C-Kermit release for Windows in 20 years.", " . A simpler version number: 10.0.", " . Updated OpenSSL support for built-in HTTP, FTP, and Telnet clients.", " . New serial port speeds up to 4000000 bps.", " . 'set speed ?' now lists serial speeds in numerical order.", " . New functions and built-in variables for the scripting language.", " . New ability of Kermit scripts to run in a Unix pipelines.", " . New CHANGE command for changing strings in external text files.", " . DIRECTORY command fixed to once again allow multiple filespecs.", " . TOUCH command fixed after being broken in C-Kermit 9.0.", " . Lots more; see https://kermitproject.org/updates.html", #endif /* OS2 */ #ifdef COMMENT /* These were for 9.0 */ " . Bigger maximum command and macro lengths", " . Bigger filename expansion space", " . New super-flexible RENAME command (HELP RENAME)", " . New CHANGE command for changing text files (HELP CHANGE)", " . New COPY and DIRECTORY command options (HELP COPY, HELP DIRECTORY)", " . New TOUCH command (HELP TOUCH)", #ifdef UNIX " . Limited Unix Locale support (HELP SET LOCALE)", #endif /* UNIX */ #ifdef CK_SSL " . Raw SSL/TLS connections for connecting to POP3 and similar services", #endif /* CK_SSL */ " . At the prompt, Ctrl-K recalls most recent filename", " . Scripting and performance improvements", #endif /* COMMENT */ " ", "Documentation:", " . https://www.kermitproject.org/ckbindex.html", " Online index to C-Kermit documentation.", #ifdef OS2 " . https://kermitproject.org/k95manual/index.html", " The Kermit 95 manual from 1995-2003.", #endif /* OS2 */ " . https://www.kermitproject.org/ckututor.html", " C-Kermit tutorial.", " ", "If the release date shown by the VERSION command is long past, be sure to", "check the Kermit website to see if there have been updates:", " ", " https://www.kermitproject.org/ (Kermit Project home page)", " https://www.kermitproject.org/ckermit.html (C-Kermit home page)", #ifdef BETATEST " https://www.kermitproject.org/ckupdates.html (C-Kermit change log)", " https://www.kermitproject.org/ck10devbuilds.html (Beta test builds table)", #endif /* BETATEST */ " ", "If the Kermit Project website is gone, look on Github:", " ", " https://github.com/KermitProject", #ifdef OS2 " https://github.com/search?q=c-kermit+windows", #endif /* OS2 */ "" }; #endif /* NOHELP */ #ifndef NOHELP char *introtxt[] = { #ifdef OS2 "Welcome to Kermit 95, communication software for:", #else #ifdef UNIX "Welcome to UNIX C-Kermit communications software for:", #else #ifdef VMS "Welcome to VMS C-Kermit communications software for:", #else #ifdef VOS "Welcome to VOS C-Kermit communications software for:", #else #ifdef MAC "Welcome to Mac Kermit communications software for:", #else "Welcome to C-Kermit communications software for:", #endif /* MAC */ #endif /* VOS */ #endif /* VMS */ #endif /* UNIX */ #endif /* OS2 */ #ifndef NOXFER " . Error-free and efficient file transfer", #endif /* NOXFER */ #ifndef NOLOCAL #ifdef OS2 " . VT320/220/102/100/52, ANSI, Wyse, Linux, Televideo, and other emulations", #else #ifdef MAC " . VT220 terminal emulation", #else " . Terminal connection", #endif /* MAC */ #endif /* OS2 */ #endif /* NOLOCAL */ #ifndef NOSPL " . Script programming", #endif /* NOSPL */ #ifndef NOICS " . International character set conversion", #endif /* NOICS */ #ifndef NODIAL #ifndef NOSPL " . Numeric and alphanumeric paging", #endif /* NOSPL */ #endif /* NODIAL */ #ifndef NOLOCAL " ", "Supporting:", " . Serial connections, direct or dialed.", #ifndef NODIAL " . Automatic modem dialing", #endif /* NODIAL */ #ifdef TCPSOCKET " . TCP/IP network connections:", #ifdef TNCODE " - Telnet sessions", #endif /* TNCODE */ #ifdef SSHBUILTIN " - SSH v2 connections", #else #ifdef ANYSSH " - SSH connections via external agent", #endif /* ANYSSH */ #endif /* SSHBUILTIN */ #ifdef RLOGCODE " - Rlogin sessions", #endif /* RLOGCODE */ #ifdef NEWFTP " - FTP sessions", #endif /* NEWFTP */ #ifdef CKHTTP " - HTTP 1.1 sessions", #endif /* CKHTTP */ #ifdef IKSD " - Internet Kermit Service", #endif /* IKSD */ #endif /* TCPSOCKET */ #ifdef ANYX25 " . X.25 network connections", #endif /* ANYX25 */ #ifdef OS2 #ifdef DECNET " . DECnet/PATHWORKS LAT Ethernet connections", #endif /* DECNET */ #ifdef SUPERLAT " . Meridian Technologies' SuperLAT connections", #endif /* SUPERLAT */ #ifdef NPIPE " . Named-pipe connections", #endif /* NPIPE */ #ifdef CK_NETBIOS " . NETBIOS connections", #endif /* CK_NETBIOS */ #endif /* OS2 */ #endif /* NOLOCAL */ " ", "While typing commands, you may use the following special characters:", " . DEL, RUBOUT, BACKSPACE, CTRL-H: Delete the most recent character typed.", " . CTRL-W: Delete the most recent word typed.", " . CTRL-U: Delete the current line.", " . CTRL-R: Redisplay the current line.", #ifdef CK_RECALL #ifdef OS2 " . Uparrow: Command recall - go backwards in command recall buffer.", " . Downarrow: Command recall - go forward in command recall buffer.", #ifndef NOIKSD " (Note: Arrow keys can be used only on the PC's physical keyboard.)", #endif /* NOIKSD */ #endif /* OS2 */ " . CTRL-P: Command recall - go backwards in command recall buffer.", " . CTRL-B: Command recall - same as Ctrl-P.", " . CTRL-N: Command recall - go forward in command recall buffer.", #endif /* CK_RECALL */ #ifndef NOLASTFILE " . CTRL-K: Insert the most recently entered local file specifiction.", #endif /* NOLASTFILE */ " . ? (question mark) Display a menu for the current command field." , " . ESC (or TAB or Ctrl-I) Attempt to complete the current field.", " . \\ (backslash) include the following character literally", #ifndef NOSPL " or introduce a backslash code, variable, or function.", #else " or introduce a numeric backslash code.", #endif /* NOSPL */ " ", "IMPORTANT: Since backslash (\\) is Kermit's command-line escape character,", "you must enter DOS, Windows, or OS/2 pathnames using either forward slash (/)" , "or double backslash (\\\\) as the directory separator in most contexts.", "Examples: C:/TMP/README.TXT, C:\\\\TMP\\\\README.TXT.", " ", "Command words other than filenames can be abbreviated in most contexts.", " ", "Basic commands:", " EXIT Exit from Kermit", " HELP Request general help", " HELP command Request help about the given command", " TAKE Execute commands from a file", " TYPE Display a file on your screen", " ORIENTATION Explains directory structure", " ", #ifndef NOXFER "Commands for file transfer:", " SEND Send files", " RECEIVE Receive files", " GET Get files from a Kermit server", #ifdef CK_RESEND " RESEND Recover an interrupted send", " REGET Recover an interrupted get from a server", #endif /* CK_RESEND */ #ifndef NOSERVER " SERVER Be a Kermit server", #endif /* NOSERVER */ " ", "File-transfer speed selection:", " FAST Use fast settings -- THIS IS THE DEFAULT", " CAUTIOUS Use slower, more cautious settings", " ROBUST Use extremely slow and cautious settings", " ", "File-transfer performance fine tuning:", " SET RECEIVE PACKET-LENGTH Kermit packet size", " SET WINDOW Number of sliding window slots", " SET PREFIXING Amount of control-character prefixing", #endif /* NOXFER */ #ifndef NOLOCAL " ", "To make a direct serial connection:", #ifdef OS2 #ifdef NT #ifdef CK_TAPI " SET PORT TAPI Select TAPI communication device", #endif /* CK_TAPI */ " SET PORT Select serial communication device", #else " SET PORT Select serial communication port or server", #endif /* NT */ #else " SET LINE Select serial communication device", #endif /* OS2 */ " SET SPEED Select communication speed", " SET PARITY Communications parity (if necessary)", #ifdef CK_RTSCTS " SET FLOW Communications flow control, such as RTS/CTS", #else " SET FLOW Communications flow control, such as XON/XOFF", #endif /* CK_RTSCTS */ " CONNECT Begin terminal connection", #ifndef NODIAL " ", "To dial out with a modem:", " SET DIAL DIRECTORY Specify dialing directory file (optional)", " SET DIAL COUNTRY-CODE Country you are dialing from (*)", " SET DIAL AREA-CODE Area-code you are dialing from (*)", " LOOKUP Lookup entries in your dialing directory (*)", " SET MODEM TYPE Select modem type", #ifdef OS2 #ifdef NT #ifdef CK_TAPI " SET PORT TAPI Select TAPI communication device", #endif /* CK_TAPI */ " SET PORT Select serial communication device", #else " SET PORT Select serial communication port or server", #endif /* NT */ #else " SET LINE Select serial communication device", #endif /* OS2 */ " SET SPEED Select communication speed", " SET PARITY Communications parity (if necessary)", " DIAL Dial the phone number", " CONNECT Begin terminal connection", " ", #ifdef OS2 "Further info: HELP DIAL, HELP SET MODEM, HELP SET PORT, HELP SET DIAL", #else "Further info: HELP DIAL, HELP SET MODEM, HELP SET LINE, HELP SET DIAL", #endif /* OS2 */ "(*) (For use with optional dialing directory)", #endif /* NODIAL */ #ifdef NETCONN " ", "To make a network connection:", #ifndef NODIAL " SET NETWORK DIRECTORY Specify a network services directory (optional)", " LOOKUP Lookup entries in your network directory", #endif /* NODIAL */ " SET NETWORK TYPE Select network type (if more than one available)", " SET HOST Make a network connection but stay in command mode", " CONNECT Begin terminal connection", #ifdef TNCODE " TELNET Select a Telnet host and CONNECT to it", #endif /* TNCODE */ #ifdef RLOGCODE " RLOGIN Select an Rlogin host and CONNECT to it", #endif /* RLOGCODE */ #ifdef ANYSSH " SSH [ OPEN ] Select an SSH host and CONNECT to it", #endif /* ANYSSH */ #ifdef NEWFTP " FTP [ OPEN ] Make an FTP connection", #endif /* NEWFTP */ #ifdef CKHTTP " HTTP OPEN Make an HTTP connection", #endif /* CKHTTP */ #endif /* NETCONN */ #ifdef NT " ", "To return from the terminal window to the K-95> prompt:", #else #ifdef OS2 " ", "To return from the terminal window to the K/2> prompt:", #else " ", "To return from a terminal connection to the C-Kermit prompt:", #endif /* OS2 */ #endif /* NT */ #ifdef OS2 " \ Press the key or key-combination shown after \"Command:\" in the status line", " (such as Alt-x) or type your escape character followed by the letter C.", #else " Type your escape character followed by the letter C.", #endif /* OS2 */ " ", "To display your escape character:", " SHOW ESCAPE", " ", "To display other settings:", " SHOW COMMUNICATIONS, SHOW TERMINAL, SHOW FILE, SHOW PROTOCOL, etc.", #else /* !NOLOCAL */ " ", "To display settings:", " SHOW COMMUNICATIONS, SHOW FILE, SHOW PROTOCOL, etc.", #endif /* NOLOCAL */ " ", "The manual for C-Kermit is the book \"Using C-Kermit\". For information", "about the manual, visit:", " http://www.kermitproject.org/usingckermit.html", " ", "For an online C-Kermit tutorial, visit:", " http://www.kermitproject.org/ckututor.html", " ", "To learn about script programming and automation:", " http://www.kermitproject.org/ckscripts.html", " ", "For further information about a particular command, type HELP xxx,", "where xxx is the name of the command. For documentation, news of new", "releases, and information about other Kermit software, visit the", "Kermit Project website:", " ", " http://www.kermitproject.org/", " ", "For information about technical support please visit this page:", " ", " http://www.kermitproject.org/support.html", "" }; static char * hmfstrcmp[] = { "\\fstrcmp(s1,s2[,case[,start[,length]]])", " s1, s2 = strings", " case, start, length = numbers or arithmetic expressions.", " case = 0 [default] means to do a case-independent comparison;", " nonzero case requests a case-sensitive comparison.", " The optional start and length arguments apply to both s1 and s2", " and allow specification of substrings if it is not desired to compare", " the whole strings. Results for non-ASCII strings are implentation-", " and locale-dependent.", " Returns a number:", " -1: s1 is lexically less than s2;", " 0: s1 and s2 are lexically equal;", " 2: s1 is lexically greater than s2.", "" }; static char * hmffileinfo[] = { "\\ffileinfo(s1,&a)", " s1 = file specification string", " &a = array designator for results (required)", " Returns a number:", " 0: File not found or not accessible or bad arguments;", " >0: The number of attributes returned in the array, normally 7, 8, or 9", " 1. The file's name", " 2. The full path of the directory where the file resides", " 3. The file's modification date-time yyyymmdd hh:mm:ss", " 4. Platform-specific permissions string, e.g. drwxrwxr-x or RWED,RWE,RE,E", " 5. Platform-specific permissions code, e.g. an octal number like 40775", " 6. The file's size in bytes", " 7. Type: regular file, executable, directory, link, or unknown", " 8. If link, the name of the file linked to", " 9. Transfer mode for file: text or binary.", "" }; static char * hmfdayname[] = { "\\fdayname(s1,n)", " s1 = free-format date OR day-of-week number 1-7 OR leave blank.", " n = function code: 0 to return full name; nonzero to return abbreviation.", " Returns a string: the name of the weekday for the given date or weekday", " number or, if s1 was omitted, of the current date, in the language and", " character-set specified by the locale. If n is nonzero, the result", " is abbreviated in the locale-appropriate way. If given inappropriate", " arguments, the result is empty and an error message is printed.", "" }; static char * hmfmonname[] = { "\\fmonthname(s1,n)", " s1 = free-format date OR month-of-year number 1-12 OR leave blank.", " n = function code: 0 to return full name; nonzero to return abbreviation.", " Returns a string: the name of the month for the given date or month", " number or, if s1 was omitted, of the current date, in the language and", " character-set specified by the locale. If n is nonzero, the result", " is abbreviated in the locale-appropriate way. If given inappropriate", " arguments, the result is empty and an error message is printed.", "" }; static char * hmxymatch[] = { "SET MATCH { DOTFILE, FIFO } { ON, OFF }", " Tells whether wildcards should match dotfiles (files whose names begin", " with period) or UNIX FIFO special files. MATCH FIFO default is OFF.", " MATCH DOTFILE default is OFF in UNIX, ON elsewhere.", "" }; #ifndef NOSEXP static char * hmxysexp[] = { "SET SEXPRESSION { DEPTH-LIMIT, ECHO-RESULT, TRUNCATE-ALL-RESULTS }", " DEPTH-LIMIT sets a limit on the depth of nesting or recursion in", " S-Expressions to prevent the program from crashing from memory exhaustion.", " ECHO-RESULT tells whether S-Expression results should be displayed as", " a result of evaluating an expression; the default is to display only at", " top (interactive) level; OFF means never display; ON means always display.", " TRUNCATE-ALL-RESULTS ON means the results of all arithmetic operations", " should be forced to integers (whole numbers) by discarding any fractional", " part. The default is OFF. SHOW SEXPRESSION displays the current settings." ,"" }; #endif /* NOSEXP */ #ifdef OS2 #ifdef KUI static char * hmxygui[] = { "SET GUI CLOSE OFF", " Disables the System Menu Close and File->Exit functions which could be", " used to exit Kermit. Once disabled these functions cannot be re-enabled", " and the only way to exit Kermit is via the Kermit Script EXIT command.", " ", "SET GUI DIALOGS { ON, OFF }", " ON means that popups, alerts, use GUI dialogs; OFF means to use", " text-mode popups or prompts. ON by default.", " ", "SET GUI FONT name size", " Chooses the font and size. Type \"set gui font ?\" to see the list of", " choices. The size can be a whole number or can contain a decimal point", " and a fraction (which is rounded to the nearest half point).", " ", "SET GUI MENUBAR DISABLED", " Disables menubar functions which could be used to modify the Kermit", " session configuration. Once disabled the menubar functions cannot be", " re-enabled.", " ", "SET GUI MENUBAR VISIBLE { ON, OFF }", " Shows or hides the menubar. When the menu bar is turned off in this way,", " some important items are moved from the menu bar to the window menu", " accessible by right-clicking on the titlebar or window icon. If the ", " menubar was disabled using either the --nomenubar or --nobars command ", " line options, then the menu bar can not be turned back on with this", " command and no additional items appear in the window menu.", " ", "SET GUI RGBCOLOR colorname redvalue greenvalue bluevalue", " Specifies the red-green-blue mixture to be used to render the given", " color name. Type \"set gui rgbcolor\" to see a list of colornames.", " the RGB values are whole numbers from 0 to 255.", " ", "SET GUI TOOLBAR DISABLED", " Disables toolbar functions which could be used to modify the Kermit", " session configuration. Once disabled the toolbar functions cannot be", " re-enabled.", " ", "SET GUI STATUSBAR { ON, OFF }", " Shows or hides the statusbar. Only works if K95G was not started with", " the --nostatusbar or --nobars command line options." " ", "SET GUI TOOLBAR VISIBLE { ON, OFF }", " Shows or hides the toolbar. Only works if K95G was not started with ", " the --notoolbar or --nobars command line options." " ", "SET GUI WINDOW POSITION x y", " Moves the C-Kermit window to the given X,Y coordinates, pixels from top", " left.", " ", "SET GUI WINDOW RESIZE-MODE { CHANGE-DIMENSIONS, SCALE-FONT }", " Default is CHANGE-DIMENSIONS.", "", "SET GUI WINDOW RUN-MODE { MAXIMIZE, MINIMIZE, RESTORE }", " Changes the run mode state of the GUI window.", "" }; #endif /* KUI */ #endif /* OS2 */ static char * hmxxfunc[] = { "KERMIT FUNCTIONS", " ", " Functions are part of Kermit's programming language used in writing", " scripts. They are like functions in other programming languages like C", " and Perl; each function has a name and an argument list, and it returns", " (is replaced by) a value. In a Kermit script, the function name preceded", " by a backslash (\\) and then the letter F; for example:", " ", " \\Findex(string1,string2).", " ", " The argument list is in parentheses. In this example the name of the", " function is 'index', the arguments are string1 and string2, and the return", " value is the starting position of string2 in string1; type HELP FUNC INDEX", " for details.", " ", " Type SHOW FUNCTIONS to see a list of available functions.", " ", " Type HELP FUNCTION xxx more information about specific functions:", " ", " . If xxx matches only one function name the documentation for that", " function is printed; example: HELP FUNCTION INDEX.", " ", " . If xxx matches more than one function name, a list of all functions", " whose names contain xxx is printed; example: HELP FUNCTION DATE.", "" }; #ifdef SSHBUILTIN static const char * hmxxskrm[] = { "SKERMIT [ OPEN ] host [ port ] /PASSWORD:pwd /USER:username", " This is an approximate synonym for: ", " SSH OPEN host port /PASSWORD:pwd /USER:username /SUBSYSTEM:kermit", " Which opens an SSH connection to the host using the kermit subsystem. This", " requires kermit to be registered as a subsystem with the remote SSH server.", " For more details on this, see: https://kermitproject.org/skermit.html", "" }; #endif /* SSHBUILTIN */ #ifdef ANYSSH static char * hmxxssh[] = { #ifdef SSHBUILTIN /* In Kermit 95, help content is provided by the currently loaded SSH backend. * This help text will only be output when no backend is loaded. If K95 was * built with SSHBUILTIN and not SSH_DLL, then the SSH backend is compiled in * so can never not be loaded. */ #ifdef SSH_DLL "SSH LOAD filename", " This command is only available when no SSH backend DLL was loaded on ", " startup, either due to there being no compatible DLL available or due to", " the loading of optional network libraries being disabled via command line", " parameter. ", " ", " This command takes one or more DLL filenames separated by a semicolon (;)", " which will attempted in order. The first DLL that loads successfully will", " enable all SSH commands and be used for all SSH operations until Kermit is", " restarted.", " ", #endif #else /* SSHBUILTIN */ "Syntax: SSH [ options ] [ command ]", " Makes an SSH connection using the external ssh program via the SET SSH", " COMMAND string, which is \"ssh -e none\" by default. Options for the", " external ssh program may be included. If the hostname is followed by a", " command, the command is executed on the host instead of an interactive", " shell.", #endif /* SSHBUILTIN */ "" }; static char *hmxyssh[] = { #ifdef SSHBUILTIN /* In Kermit 95, help content is provided by the currently loaded SSH backend. * This help text will only be output when no backend is loaded. If K95 was * built with SSHBUILTIN and not SSH_DLL, then the SSH backend is compiled in * so can never not be loaded. */ #ifdef SSH_DLL "No SSH backend loaded. If you have a suitable backend DLL, you can load", "it with the SSH LOAD command.", #endif /* SSH_DLL */ #else /* SSHBUILTIN */ "Syntax: SET SSH COMMAND command", " Specifies the external command to be used to make an SSH connection.", " By default it is \"ssh -e none\" (ssh with no escape character).", #endif /* SSHBUILTIN */ "" }; #endif /* ANYSSH */ #ifdef NEWFTP static char *hmxygpr[] = { "Syntax: SET GET-PUT-REMOTE { AUTO, FTP, KERMIT}", " Tells Kermit whether GET, PUT, and REMOTE commands should be directed", " at a Kermit server or an FTP server. The default is AUTO, meaning that", " if you have only one active connection, the appropriate action is taken", " when you give a GET, PUT, or REMOTE command. SET GET-PUT-REMOTE FTP forces" , " Kermit to treat GET, PUT, and REMOTE as FTP client commands; setting this", " to KERMIT forces these commands to be treated as Kermit client commands.", " NOTE: PUT includes SEND, MPUT, MSEND, and all other similar commands.", " Also see HELP REMOTE, HELP SET LOCUS, HELP FTP.", "" }; #endif /* NEWFTP */ #ifdef LOCUS static char *hmxylocus[] = { #ifdef KUI "Syntax: SET LOCUS { ASK, AUTO, LOCAL, REMOTE }", #else "Syntax: SET LOCUS { AUTO, LOCAL, REMOTE }", #endif /* KUI */ " Specifies whether unprefixed file management commands should operate", " locally or (when there is a connection to a remote FTP or Kermit", " server) sent to the server. The affected commands are: CD (CWD), PWD,", " CDUP, DIRECTORY, DELETE, RENAME, MKDIR, and RMDIR. To force any of", " these commands to be executed locally, give it an L-prefix: LCD, LDIR,", " etc. To force remote execution, use the R-prefix: RCD, RDIR, and so", " on. SHOW COMMAND shows the current Locus.", " ", " By default, the Locus for file management commands is switched", " automatically whenever you make or close a connection: if you make an", " FTP connection, the Locus becomes REMOTE; if you close an FTP connection", " or make any other kind of connection, the Locus becomes LOCAL.", #ifdef KUI " ", " There are two kinds of automatic switching: ASK (the default) which", " asks you if it's OK to switch, and AUTO, which switches without asking.", #endif /* KUI */ " ", " If you give a SET LOCUS LOCAL or SET LOCUS REMOTE command, this sets", " the locus as indicated and disables automatic switching.", #ifdef KUI " SET LOCUS AUTO or SET LOCUS ASK restores automatic switching.", " You can also change Locus switching and behavior in the Actions menu.", #else " SET LOCUS AUTO restores automatic switching.", #endif /* KUI */ "", }; #endif /* LOCUS */ #ifdef UNIX #ifndef NOPUTENV static char *hmxxputenv[] = { "Syntax: PUTENV name value", " Creates or modifies the environment variable with the given name to have", " the given value. Purpose: to pass parameters to subprocesses without", " having them appear on the command line. If the value is blank (empty),", " the variable is deleted. The result is visible to this instantiation of", " C-Kermit via \\$(name) and to any inferior processes by whatever method", " they use to access environment variables. The value may be enclosed in", " doublequotes or braces, but it need not be; if it is the outermost", " doublequotes or braces are removed.", " ", " Note the syntax:", " PUTENV name value", " not:", " PUTENV name=value", " ", " There is no equal sign between name and value, and the name itself may", " not include an equal sign.", "", }; #endif /* NOPUTENV */ #endif /* UNIX */ static char *hmxxtak[] = { "Syntax: TAKE filename [ arguments ]", " Tells Kermit to execute commands from the named file. Optional argument", " words, are automatically assigned to the macro argument variables \\%1", " through \\%9. Kermit command files may themselves contain TAKE commands,", " up to any reasonable depth of nesting.", "" }; #ifdef TCPSOCKET static char *hmxxfirew[] = { "Firewall Traversal in C-Kermit", " ", #ifndef NEWFTP #ifndef CKHTTP #ifndef CK_SOCKS #define NOFIREWALL #endif #endif #endif #ifdef NOFIREWALL "This version of Kermit was built with no support for firewall traversal", "protocols. Kermit can be built with support for HTTP Proxy Servers,", "SOCKS authorized firewall traversal, and FTP Passive connection modes.", " ", #else /* NOFIREWALL */ #ifdef CKHTTP "The simplist form of firewall traversal is the HTTP CONNECT command. The", "CONNECT command was implemented to allow a public web server which usually", "resides on the boundary between the public and private networks to forward", "HTTP requests from clients on the private network to public web sites. To", "allow secure web connections, the HTTP CONNECT command authenticates the", "client with a username/password and then establishes a tunnel to the", "desired host.", " ", "Web servers that support the CONNECT command can be configured to allow", "outbound connections for authenticated users to any TCP/IP hostname-port", "combination accessible to the Web server. HTTP CONNECT can be used only", "with TCP-based protocols. Protocols such as Kerberos authentication that", "use UDP/IP cannot be tunneled using HTTP CONNECT.", " ", "SET TCP HTTP-PROXY [switches] [[:]]", " If a hostname or ip-address is specified, Kermit uses the given", " proxy server when attempting outgoing TCP connections. If no hostnamer", " or ip-address is specified, any previously specified Proxy server is", " removed. If no port number is specified, the \"http\" service is used.", " [switches] can be one or more of:", " /AGENT: /USER: /PASSWORD:", " Switch parameters are used when connecting to the proxy server and", " override any other values associated with the connection.", " ", #endif /* CKHTTP */ #ifdef CK_SOCKS "In the early 1990s as firewalls were becoming prevalent, David Koblas", "developed the SOCKS protocol for TCP/IP firewall traversal. Two versions", "of SOCKS are currently in use: Version 4.2 lets TCP/IP client applications", "traverse firewalls, similar to HTTP CONNECT, except that the SOCKS client", "is aware of the public source IP address and port, which can be used within", "the application protocol to assist in securing the connection (e.g. FTP", "sessions secured with GSSAPI Kerberos 5).", " ", "In 1995 the IETF issued SOCKS Protocol Version 5 (RFC 1928), which is", "significantly more general than version 4. Besides supporting client-", "to-server TCP/IP connections, it also includes:", " ", " . Authenticated firewall traversal of UDP/IP packets.", " . Authenticated binding of incoming public ports on the firewall.", " ", "This lets a service on the private network offer public services. It also", "lets client applications like FTP establish a temporary public presence", "that can be used by the FTP server to create a data channel. By allowing", "the client to bind to a public port on the firewall and be aware of the", "public address, SOCKS 5 lets the application protocol communicate this", "information to the server.", " ", #ifdef OS2 #ifdef NT "Kermit 95 supports SOCKS 4.2. The SOCKS Server is specified with:", " ", " SET TCP SOCKS-SERVER hostname/ip-address", " ", "The SOCKS.CONF file is found by examining the ETC environment variable;", "searching in \\WINDOWS on Windows 95/98/ME; or the", "\\WINDOWS\\SYSTEM\\DRIVERS\\ETC directory on NT\\2000\\XP systems.", #else /* NT */ "C-Kermit provides support for SOCKS 4.2 servers when using IBM TCP/IP 2.0,", "IBM OS/2 WARP, or a compatible protocol stack. SOCKS is one popular means", "of implementing a firewall between a private network and the Internet.", " ", "C-Kermit shares the same SOCKS environment variables as IBM Gopher. It also", "supports the use of local SOCKS configuration files.", " ", "To specify the default SOCKS Server, add SET SOCKS_SERVER= to your", "CONFIG.SYS file.", " ", "If you must use a SOCKS Distributed Name Server, add SET SOCKS_NS= to your", "CONFIG.SYS file.", " ", "If you must use a specific with your SOCKS server, be sure to add SET USER=", "to your CONFIG.SYS file. Otherwise, \"os2user\" is used by default.", " ", "The SOCKS configuration file must be placed in the directory pointed to by", "the ETC environment variable as declared in your CONFIG.SYS file. The name", "should be SOCKS.CONF. On a FAT file system, use SOCKS.CNF.", " ", "The format of the lines in the SOCKS configuration file are as follows:", " ", " . # comments", " . deny [*=userlist] dst_addr dst_mask [op port]", " . direct [*=userlist] dst_addr dst_mask [op port]", " . sockd [@=serverlist] [*=userlist] dst_addr dst_mask [op port]", " ", "op must be one of 'eq', 'neq', 'lt', 'gt', 'le', or 'ge'. dst_addr,", "dst_mask, and port may be either numeric or name equivalents.", " ", "C-Kermit ignores the [*=userlist] and [@=serverlist] fields. Matches are", "determined on a first match not a best match basis. Addresses for which no", "match is found default to \"sockd\".", " ", "For completeness: Fields in square brackets are optional. The optional", "@=serverlist field with a 'sockd' line specifies the list of SOCKS servers", "the client should try (in the given order) instead of the default SOCKS", "server. If the @=serverlist part is omitted, then the default SOCKS server", "is used. Commas are used in the userlist and serverlist as separators, no", "white spaces are allowed.", #endif /* NT */ " ", #else /* OS2 */ #ifdef CK_SOCKS5 "This version of C-Kermit supports SOCKS version 5.", #else /* CK_SOCKS5 */ "This version of C-Kermit supports SOCKS version 4.", #endif /* CK_SOCKS5 */ "See the man page (or other system documentation) for information on", "configuring the SOCKS library via the /etc/socks.conf file.", #endif /* OS2 */ " ", #endif /* CK_SOCKS */ #ifdef NEWFTP "FTP is one of the few well-known Internet services that requires", "multiple connections. As described above, FTP originally required the", "server to establish the data connection to the client using a destination", "address and port provided by the client. This doesn't work with port", "filtering firewalls.", " ", "Later, FTP protocol added a \"passive\" mode, in which connections for", "the data channels are created in the reverse direction. Instead of the", "server establishing a connection to the client, the client makes a second", "connection with the server as the destination. This works just fine as", "long as the client is behind the firewall and the server is in public", "address space. If the server is behind a firewall then the traditional", "active mode must be used. If both the client and server are behind their", "own port filtering firewalls then data channels cannot be established.", " ", "In Kermit's FTP client, passive mode is controlled with the command:", " ", " SET FTP PASSIVE-MODE { ON, OFF }", " ", "The default is ON, meaning to use passive mode.", #endif /* NEWFTP */ #endif /* NOFIREWALL */ "" }; #endif /* TCPSOCKET */ static char *hmxxsave[] = { "Syntax: SAVE item filename { NEW, APPEND }", " Saves the requested material in the given file. A new file is created", " by default; include APPEND at the end of the command to append to an", " existing file. Items:", #ifndef NOSETKEY " KEYMAP Saves the current key settings.", #endif /* NOSETKEY */ #ifdef CK_RECALL " COMMAND HISTORY Saves the current command recall (history) buffer", #endif /* CK_RECALL */ #ifdef OS2 " COMMAND SCROLLBACK Saves the current command-screen scrollback buffer", " TERMINAL SCROLLBACK Saves the current terminal-screen scrollback buffer", #endif /* OS2 */ "" }; #ifdef CKROOT static char *hmxxchroot[] = { "Syntax: SET ROOT directoryname", " Sets the root for file access to the given directory and disables access", " to system and shell commands and external programs. Once this command", " is given, no files or directories outside the tree rooted by the given", " directory can be opened, read, listed, deleted, renamed, or accessed in", " any other way. This command can not be undone by a subsequent SET ROOT", " command. Primarily for use with server mode, to restrict access of", " clients to a particular directory tree. Synonym: CHROOT.", "" }; #endif /* CKROOT */ static char *hmxxscrn[] = { "Syntax: SCREEN { CLEAR, CLEOL, MOVE row column }", #ifdef OS2 " Performs screen-formatting actions.", #else " Performs screen-formatting actions. Correct operation of these commands", " depends on proper terminal setup on both ends of the connection -- mainly", " that the host terminal type is set to agree with the kind of terminal or", " the emulation you are viewing C-Kermit through.", #endif /* OS2 */ " ", "SCREEN CLEAR", " Moves the cursor to home position and clears the entire screen.", #ifdef OS2 " Synonyms: CLS, CLEAR SCREEN, CLEAR COMMAND-SCREEN ALL", #else " Synonyms: CLS, CLEAR SCREEN.", #endif /* OS2 */ " ", "SCREEN CLEOL", " Clears from the current cursor position to the end of the line.", #ifdef OS2 " Synonym: CLEAR COMMAND-SCREEN EOL", #endif /* OS2 */ " ", "SCREEN MOVE row column", " Moves the cursor to the indicated row and column. The row and column", " numbers are 1-based so on a 24x80 screen, the home position is 1 1 and", " the lower right corner is 24 80. If a row or column number is given that", " too large for what Kermit or the operating system thinks is your screen", " size, the appropriate number is substituted.", " ", "Also see:", #ifdef OS2 " HELP FUNCTION SCRNCURX, HELP FUNCTION SCRNCURY, HELP FUNCTION SCRSTR,", #endif /* OS2 */ " SHOW VARIABLE TERMINAL, SHOW VARIABLE COLS, SHOW VAR ROWS, SHOW COMMAND.", "" }; #ifndef NOSPL static char *hmfword[] = { "Function \\fword(s1,n1,s2,s3,n2,n3) - Extracts a word from a string.", " s1 = source string.", " n1 = word number (1-based) counting from left; if negative, from right.", " s2 = optional break set.", " s3 = optional include set (or ALL, CSV, or TSV).", " n2 = optional grouping mask.", " n3 = optional separator flag:", " 0 = collapse adjacent separators;", " 1 = don't collapse adjacent separators.", " ", " \\fword() returns the n1th \"word\" of the string s1, according to the", " criteria specified by the other parameters.", " ", " The BREAK SET is the set of all characters that separate words. The", " default break set is all characters except ASCII letters and digits.", " ASCII (C0) control characters are treated as break characters by default,", " as are spacing and punctuation characters, brackets, and so on, and", " all 8-bit characters.", " ", " The INCLUDE SET is the set of characters that are to be treated as ", " parts of words even though they normally would be separators. The", " default include set is empty. Three special symbolic include sets are", " also allowed:", " ", " ALL (meaning include all bytes that are not in the break set)", " CSV (special treatment for Comma-Separated-Value records)", " TSV (special treatment for Tab-Separated-Value records)", " ", " For operating on 8-bit character sets, the include set should be ALL.", " ", " If the GROUPING MASK is given and is nonzero, words can be grouped by", " quotes or brackets selected by the sum of the following:", " ", " 1 = doublequotes: \"a b c\"", " 2 = braces: {a b c}", " 4 = apostrophes: 'a b c'", " 8 = parentheses: (a b c)", " 16 = square brackets: [a b c]", " 32 = angle brackets: ", " ", " Nesting is possible with {}()[]<> but not with quotes or apostrophes.", " ", "Returns string:", " Word number n1, if there is one, otherwise an empty string.", " ", "Also see:", " HELP FUNCTION SPLIT", "" }; static char *hmxxprompt[] = { "Syntax: PROMPT [ text ]", " Enters interactive command level from within a script in such a way that", " the script can be continued with an END or RETURN command. STOP, EXIT,", " SHOW STACK, TRACE, and Ctrl-C all have their normal effects. The PROMPT", " command allows variables to be examined or changed, or any other commands", " to be given, in any number, prior to returning to the script, allowing", " Kermit to serve as its own debugger; adding the PROMPT command to a script", " is like setting a breakpoint. If the optional text is included, it is", " used as the new prompt for this level, e.g. \"prompt Breakpoint_1>\".", "" }; static char *hxxinp[] = { "Syntax: INPUT [ /COUNT:n /CLEAR /NOMATCH /NOWRAP ] \ { number-of-seconds, time-of-day } [ text ]", " ", "Examples:", " INPUT 5 Login:", " INPUT 23:59:59 RING", " INPUT /NOMATCH 10", " INPUT /CLEAR 10 \\13\\10", " INPUT /CLEAR 10 \\13\\10$\32", " INPUT /COUNT:256 10", " INPUT 10 \\fpattern(<*@*.*>)", " ", " Waits up to the given number of seconds, or until the given time of day,", " for the given text to arrive on the connection. For use in script programs", " with IF FAILURE or IF SUCCESS, which tell whether the desired text arrived", " within the given amount of time.", " ", " The text, if given, can be a regular text or it can be a \\fpattern()", " invocation, in which case it is treated as a pattern rather than a literal", " string (HELP PATTERNS for details).", " ", " If the /COUNT: switch is included, INPUT waits for the given number of", " characters to arrive.", " ", " If no text is specified, INPUT waits for the first character that arrives", " and makes it available in the \\v(inchar) variable. This is equivalent to", " including a /COUNT: switch with an argument of 1.", " ", " If the /NOMATCH switch is included, INPUT does not attempt to match any", " characters, but continues reading from the communication connection until", " the timeout interval expires. If the timeout interval is 0, the INPUT", " command does not wait; i.e. the given text must already be available for", " reading for the INPUT command to succeed. If the interval is negative,", " the INPUT command waits forever.", " ", " The INPUT buffer, \\v(input), is normally circular. Incoming material is", " appended to it until it reaches the end, and then it wraps around to the", " beginning. If the /CLEAR switch is given, INPUT clears its buffer before", " reading from the connection.", " ", " Typical example of use:", " ", " INPUT 10 login:", " IF FAIL EXIT 1 \"Timed out waiting for login prompt\"", " LINEOUT myuserid", " INPUT 10 Password:", " IF FAIL EXIT 1 \"Timed out waiting for Password prompt\"", " LINEOUT xxxxxxx", " ", " The /NOWRAP switch means that INPUT should return with failure status", " and with \\v(instatus) set to 6 if its internal buffer fills up before", " any of the other completion criteria are met. This allows for capture", " of the complete incoming data stream (except NUL bytes, which are", " discarded). CAUTION: if the search target (if any) spans the INPUT buffer", " boundary, INPUT will not succeed.", " ", " \ \\v(instatus) values are: 0 (success), 1 (timed out), 2 (keyboard interrupt),", " 3 (internal error), 4 (I/O error or connection lost), 5 (INPUT disabled),", " and 6 (buffer filled and /NOWRAP set); these are shown by \\v(inmessage).", " ", " Also see OUTPUT, MINPUT, REINPUT, SET INPUT and CLEAR. See HELP PAUSE for", " details on time-of-day format and HELP PATTERNS for pattern syntax.", ""}; static char *hxxout[] = { "Syntax: OUTPUT text", " Sends the text out the communications connection, as if you had typed it", " during CONNECT mode. The text may contain backslash codes, variables,", " etc, plus the following special codes:", " ", " \\N - Send a NUL (ASCII 0) character (you can't use \\0 for this).", " \\B - Send a BREAK signal.", " \\L - Send a Long BREAK signal.", " ", "Also see SET OUTPUT.", "" }; static char *hxxcsn[] = { "Compact Substring Notation is a shorthand notation for the built-in", "\\fsubstring() function; 'name' is the name of any macro-type variable:", " \\s(name[n:m])", " Substring of \\m(name) starting at position n, length m", " \\s(name[n_m])", " Substring of \\m(name) from position n to position m", " \\s(name[n]) or \\s(name[n:])", " Substring of \\m(name) from position n to the end", " \\s(name[n.])", " The character at position n", ""}; #endif /* NOSPL */ static char *hxypari[] = { "SET PARITY NONE", " Chooses 8 data bits and no parity.", " ", "SET PARITY { EVEN, ODD, MARK, SPACE }", " Chooses 7 data bits plus the indicated kind of parity.", " Forces 8th-bit prefixing during file transfer.", " ", #ifdef HWPARITY "SET PARITY HARDWARE { EVEN, ODD }", " Chooses 8 data bits plus the indicated kind of parity.", " ", "Also see SET TERMINAL BYTESIZE, SET SERIAL, and SET STOP-BITS.", #else "Also see SET TERMINAL BYTESIZE and SET SERIAL.", #endif /* HWPARITY */ ""}; #ifndef NOLOCAL static char *hxyesc[] = { #ifdef OS2 "Syntax: SET ESCAPE number", " Decimal ASCII value for escape character during CONNECT, normally 29", " (Control-]). Type the escape character followed by C to get back to the", " C-Kermit prompt or followed by ? to see other options, or use the \\Kexit", " keyboard verb, normally assigned to Alt-x.", #else #ifdef NEXT "Syntax: SET ESCAPE number", " Decimal ASCII value for escape character during CONNECT, normally 29", " (Control-]). Type the escape character followed by C to get back to the", " C-Kermit prompt or followed by ? to see other options.", #else "Syntax: SET ESCAPE number", " Decimal ASCII value for escape character during CONNECT, normally 28", " (Control-\\). Type the escape character followed by C to get back to the", " C-Kermit prompt or followed by ? to see other options.", #endif /* NEXT */ #endif /* OS2 */ " ", "You may also enter the escape character as ^X (circumflex followed by a", "letter or one of: @, ^, _, [, \\, or ], to indicate a control character;", "for example, SET ESC ^_ sets your escape character to Ctrl-Underscore.", " ", "You can also specify an 8-bit character (128-255) as your escape character,", "either by typing it literally or by entering its numeric code.", "" }; #endif /* NOLOCAL */ #ifndef NOSPL static char *hxyout[] = { "SET OUTPUT PACING ", " How many milliseconds to pause after sending each OUTPUT character,", " normally 0.", " ", "SET OUTPUT SPECIAL-ESCAPES { ON, OFF }", " Whether to process the special OUTPUT-only escapes \\B, \\L, and \\N.", " Normally ON (they are processed).", "" }; static char *hxyinp[] = { "Syntax: SET INPUT parameter value", " ", #ifdef CK_AUTODL "SET INPUT AUTODOWNLOAD { ON, OFF }", " Controls whether autodownloads are allowed during INPUT command execution.", " ", #endif /* CK_AUTODL */ "SET INPUT BUFFER-LENGTH number-of-bytes", " Removes the old INPUT buffer and creates a new one with the given length.", " ", "SET INPUT CANCELLATION { ON, OFF }", " Whether an INPUT in progress can be can interrupted from the keyboard.", " ", "SET INPUT CASE { IGNORE, OBSERVE }", " Tells whether alphabetic case is to be significant in string comparisons.", " This setting is local to the current macro or command file, and is", " inherited by subordinate macros and take files.", " ", "SET INPUT ECHO { ON, OFF }", " Tells whether to display arriving characters read by INPUT on the screen.", " ", #ifdef CKFLOAT "SET INPUT SCALE-FACTOR ", " A number to multiply all INPUT timeouts by, which may include a fractional", " part, e.g. 2.5. All INPUT commands that specify a timeout in seconds", " (as opposed to a specific time of day) have their time limit adjusted", " automatically by this factor, which is also available in the built-in", " read-only variable \\v(inscale). The default value is 1.0.", " ", #endif /* CKFLOAT */ "SET INPUT SILENCE ", " The maximum number to seconds of silence (no input at all) before the", " INPUT command times out, 0 for no maximum.", " ", #ifdef OS2 "SET INPUT TERMINAL { ON, OFF }", " Determines whether the data received during an INPUT command is displayed", " in the terminal window. Default is ON.", " ", #endif /* OS2 */ "SET INPUT TIMEOUT-ACTION { PROCEED, QUIT }", " Tells whether to proceed or quit from a script program if an INPUT command", " fails. PROCEED (default) allows use of IF SUCCESS / IF FAILURE commands.", " This setting is local to the current macro or command file, and is", " inherited by subordinate macros and take files.", "" }; static char *hxyfunc[] = { "SET FUNCTION DIAGNOSTICS { ON, OFF }", " Whether to issue diagnostic messages for illegal function calls and", " references to nonexistent built-in variables. ON by default.", " ", "SET FUNCTION ERROR { ON, OFF }", " Whether an illegal function call or reference to a nonexistent built-in", " variable should cause a command to fail. OFF by default.", "" }; #endif /* NOSPL */ static char *hxyxyz[] = { #ifdef CK_XYZ #ifdef XYZ_INTERNAL /* This is for built-in protocols */ "Syntax: SET PROTOCOL { KERMIT, XMODEM, YMODEM, ZMODEM } [ s1 s2 [ s3 ] ]", " Selects protocol to use for transferring files. String s1 is a command to", " send to the remote host prior to SENDing files with this protocol in", " binary mode; string s2 is the same thing but for text mode. Use \"%s\" in", " any of these strings to represent the filename(s). If the protocol is", " KERMIT, you may also specify a string s3, the command to start a Kermit", " server on the remote host when you give a GET, REGET, REMOTE, or other", " client command. Use { braces } if any command contains spaces. Examples:", " ", " set proto xmodem {rx %s} {rx -a %s}", " set proto kermit {kermit -YQir} {kermit -YQTr} {kermit -YQx}", #else /* This is for when non-Kermit protocols are external */ "Syntax: \ SET PROTOCOL { KERMIT, XMODEM, YMODEM, ZMODEM } [ s1 s2 s3 s4 s5 s6 ]", " Selects protocol to use for transferring files. s1 and s2 are commands to", " output prior to SENDing with this protocol, to automatically start the", " RECEIVE process on the other end in binary or text mode, respectively.", " If the protocol is KERMIT, s3 is the command to start a Kermit server on", " the remote computer, and there are no s4-s6 commands. Otherwise, s3 and", " s4 are commands used on this computer for sending files with this protocol", " in binary or text mode, respectively; s5 and s6 are the commands for", " receiving files with this protocol. Use \"%s\" in any of these strings", " to represent the filename(s). Use { braces } if any command contains", " spaces. Examples:", " ", " set proto kermit {kermit -YQir} {kermit -YQTr} {kermit -YQx}", " set proto ymodem rb {rb -a} {sb %s} {sb -a %s} rb rb", " ", "External protocols require REDIRECT and external file transfer programs that", "use redirectable standard input/output.", #endif /* XYZ_INTERNAL */ #else "Syntax: \ SET PROTOCOL KERMIT [ s1 [ s2 [ s3 ] ] ]", " Lets you specify the autoupload binary, autoupload text, and autoserver", " command strings to be sent to the remote system in advance of any SEND", " or GET commands. By default these are \"kermit -ir\", \"kermit -r\", and", " \"kermit -x\". Use { braces } around any command that contains spaces.", " Example:", " ", " set proto kermit {kermit -Yir} {kermit -YTr} {kermit -Yx}", #endif /* CK_XYZ */ " ", " SHOW PROTOCOL displays the current settings.", ""}; static char *hmxxbye = "Syntax: BYE\n\ Shut down and log out a remote Kermit server"; #ifdef CK_PERMS #ifdef UNIX static char *hmxxchmod[] = { "Syntax: CHMOD [ switches ] code filespec", " UNIX only. Changes permissions of the given file(s) to the given code,", " which must be an octal number such as 664 or 775. Optional switches:", " ", " /FILES Only change permissions of regular files.", " /DIRECTORIES Only change permissions of directory files.", " /TYPE:BINARY Only change permissions of binary files.", " /TYPE:TEXT Only change permissions of text files.", " /DOTFILES Include files whose names begin with dot (.).", " /RECURSIVE Change permissions in subdirectories too.", " /LIST List each file (synonym: /VERBOSE).", " /NOLIST Operate silently (synonym: /QUIET).", " /PAGE When listing, pause at end of each screen (implies /LIST).", " /NOPAGE When listing, don't pause at end of each screen.", " /SIMULATE Show what would be done but don't actually do it.", "" }; #endif /* UNIX */ #endif /* CK_PERMS */ #ifndef NOSPL #ifndef NOSEXP static char *hmxxsexp[] = { "Syntax: (operation operand [ operand [ ... ] ])", " ", " C-Kermit includes a simple LISP-like S-Expression parser operating on", " numbers only. An S-Expression is always enclosed in parentheses. The", " parentheses can contain (a) a number, (b) a variable, (c) a function that", " returns a number, or (d) an operator followed by one or more operands.", " Operands can be any of (a) through (c) or an S-Expression. Numbers can be", " integers or floating-point. Any operand that is not a number and does not", " start with backslash (\\) is treated as a Kermit macro name. Operators:", " ", " Operator Action Example Value", " EVAL (.) Returns the contained value (6) 6", " QUOTE (') Inhibits evaluation of following value (quote a) a", " SETQ Assigns a value to a global variable (setq a 2) 2", " LET Assigns a value to a local variable (let b -1.3) -1.3", " + Adds all operands (1 or more) (+ a b) 0.7", " - Subtracts all operands (1 or more) (- 9 5 2 1) 1", " * Multiplies all operands (1 or more) (* a (+ b 1) 3) -1.8", " / Divides all operands (1 or more) (/ b a 2) -0.325", " ^ Raise given number to given power (^ 3 2) 9", " ++ Increments a variable (++ a 1.2) 3.2", " -- Decrements a variable (-- a) 1", " ABS Absolute value of 1 operand (abs (* a b 3)) 7.8", " MAX Maximum of all operands (1 or more) (max 1 2 3 4) 4", " MIN Minimum of all operands (1 or more) (min 1 2 3 4) 1", " MOD Modulus of all operands (1 or more) (mod 7 4 2) 1", " TRUNCATE Integer part of floating-point operand (truncate 1.333) 1", " CEILING Ceiling of floating-point operand (ceiling 1.25) 2", " FLOOR Floor of floating-point operand (floor 1.25) 1", " ROUND Operand rounded to nearest integer (round 1.75) 2", " ROUND ...or to given number of decimals (round 1.7584 2) 1.76", " SQRT Square root of 1 operand (sqrt 2) 1.414..", " EXP e (2.71828..) to the given power (exp -1) 0.367..", " SIN Sine of angle expressed in radians (sin (/ pi 2)) 1.0", " COS Cosine of given number (cos pi) -1.0", " TAN Tangent of given number (tan pi) 0.0", " LOG Natural log (base e) of given number (log 2.7183) 1.000..", " LOG10 Log base 10 of given number (log10 1000) 3.0", " ", "Predicate operators return 0 if false, 1 if true, and if it is the outermost", "operator, sets SUCCESS or FAILURE accordingly:", " ", " < Operands in strictly descending order (< 6 5 4 3 2 1) 1", " <= Operands in descending order (<= 6 6 5 4 3 2) 1", " != Operands are not equal (!= 1 1 1.0) 0", " = (==) All operands are equal (= 3 3 3 3) 1", " > Operands in strictly ascending order (> 1 2 3 4 5 6) 1", " >= Operands in ascending order (> 1 1 2 3 4 5) 1", " AND (&&) Operands are all true (and 1 1 1 1 0) 0", " OR (||) At least one operand is true (or 1 1 1 1 0) 1", " XOR Logical Exclusive OR (xor 3 1) 0", " NOT (!) Reverses truth value of operand (not 3) 0", " ", "Bit-oriented operators:", " ", " & Bitwise AND (& 7 2) 2", " | Bitwise OR (| 1 2 3 4) 7", " # Bitwise Exclusive OR (# 3 1) 2", " ~ Reverses all bits (~ 3) -4", " ", "Operators that work on truth values:", " ", " IF Conditional evaluation (if (1) 2 3) 2", " ", "Operators can also be names of Kermit macros that return either numeric", "values or no value at all.", " ", "Built-in constants are:", " ", " t True (1)", " nil False (empty)", " pi The value of Pi (3.1415926...)", " ", "If SET SEXPRESSION TRUNCATE-ALL-RESULTS is ON, all results are trunctated", "to integer values by discarding any fractional part. Otherwise results", "are floating-point if there fractional part and integer otherwise.", "If SET SEXPRESSION ECHO-RESULT is AUTO (the default), the value of the", "S-Expression is printed if the S-Expression is given at top level; if ON,", "it is printed at any level; if OFF it is not printed. At all levels, the", "variable \\v(sexpression) is set to the most recent S-Expression, and", "\\v(svalue) is set to its value. You can use the \\fsexpresssion() function", "to evaluate an S-Expression anywhere in a Kermit command.", "" }; #endif /* NOSEXP */ #endif /* NOSPL */ static char *hmxxgrep[] = { #ifdef UNIXOROSK "Syntax: GREP [ options ] pattern filespec", #else "Syntax: FIND [ options ] pattern filespec", #endif /* UNIXOROSK */ " Searches through the given file or files for the given character string", " or pattern. In the normal case, all lines containing any text that matches" , " the pattern are printed. Pattern syntax is as described in HELP PATTERNS", " except that '*' is implied at the beginning unless the pattern starts with", " '^' and also at the end unless the pattern ends with '$'. Therefore,", " \"grep something *.txt\" lists all lines in all *.txt files that contain", " the word \"something\", but \"grep ^something *.txt\" lists only the lines", " that START with \"something\". The command succeeds if any of the given", " files contains any lines that match the pattern, otherwise it fails.", #ifdef UNIXOROSK " Synonym: FIND.", #else " Synonym: GREP.", #endif /* UNIXOROSK */ " ", "Only one filespec can be given. To search multiple files that can't", "be represented by a wildcard use {file1,file2,file3,...} (in braces).", " ", "File selection options:", " /NOBACKUPFILES", " Excludes backup files (like oofa.txt.~3~) from the search.", " /DOTFILES", " Includes files whose names start with dot (.) in the search.", " /NODOTFILES", " Excludes files whose names start with dot (.) from the search.", #ifdef RECURSIVE " /RECURSIVE", " Searches through files in subdirectories too.", #endif /* RECURSIVE */ " /TYPE:TEXT", " Search only text files (requires FILE SCAN ON).", " /TYPE:BINARY", " Search only binary files (requires FILE SCAN ON).", " ", "Pattern-matching options:", " /NOCASE", " Ignores case of letters when comparing. Depends on the underlying", " operating system APIs to work for non-ASCII character sets.", " /NOMATCH", " Searches for lines that do NOT match the pattern.", " /EXCEPT:pattern", " Exclude lines that match the main pattern that also match this pattern.", " /VERBATIM", " The search string is taken literally; variables are not evaluated.", " This allows you to (for example) search Kermit scripts that contain", " variable names, function names, etc (that begin with '\\').", " ", "Display options:", " /COUNT:variable-name", " For each file, prints only the filename and a count of matching lines", " and assigns the total match count to the variable, if one is given.", " /DISPLAY:number", " How many matching lines to show. The default is to show all matching", " lines. Synonym:/SHOW.", " /NAMEONLY", " Prints the name of each file that contains at least one matching line,", " one name per line, rather than showing each matching line.", " /NOLIST", " Doesn't print anything (but sets SUCCESS or FAILURE appropriately).", " /LINENUMBERS", " Precedes each file line by its line number within the file.", " /PAGE", " Pauses after each screenful.", " /NOPAGE", " Doesn't pause after each screenful.", " ", "Result disposition options:", " /OUTPUT:name", " Sends results to the given file.", " /ARRAY:&x", " Returns the results in the specified array; one line per array element.", " /MACRO:name", " Returns the results in the macro whose name is given. If a macro", " of the same name already exists, the grep results (if there are any)", " replace its previous value. Synonym: DEFINE.", ""}; static char *hmxxdir[] = { #ifdef DOMYDIR "Syntax: DIRECTORY [ switches ] [ filespec [ filespec [ ... ] ] ]", #ifdef LOCUS " If LOCUS is REMOTE or LOCUS is AUTO and you have an FTP connection,", " this command is equivalent to REMOTE DIRECTORY (RDIR). Otherwise:", " ", #endif /* LOCUS */ " Lists local files. The filespec may be a filename, possibly containing", " wildcard characters, or a directory name. If no filespec is given, all", " files in the current directory are listed. If a directory name is given,", " all the files in it are listed. Multiple filespecs can be given.", " Optional switches:", " ", " /BRIEF List filenames only.", #ifdef CK_PERMS " /VERBOSE + Also list permissions, size, and date.", #else " /VERBOSE + Also list date and size.", #endif /* CK_PERMS */ " /FILES Show files but not directories.", " /DIRECTORIES Show directories but not files.", " /ALL + Show both files and directories.", " /ARRAY:&a Store file list in specified array (e.g. \\%a[]).", " /PAGE Pause after each screenful.", " /NOPAGE Don't pause after each screenful.", " /TOP:n Only show the top n lines of the directory listing.", #ifdef UNIXOROSK " /DOTFILES Include files whose names start with dot (period).", " /NODOTFILES + Don't include files whose names start with dot.", " /FOLLOWLINKS Follow symbolic links.", " /NOFOLLOWLINKS + Don't follow symbolic links.", " /NOLINKS Don't list symbolic links at all.", " /BACKUP + Include backup files (names end with .~n~).", " /NOBACKUPFILES Don't include backup files.", #endif /* UNIXOROSK */ " /OUTPUT:file Store directory listing in the given file.", " /HEADING Include heading and summary.", " /NOHEADING + Don't include heading or summary.", " /COUNT:var Put the number of matching files in the given variable.", " /SUMMARY Print only count and total size of matching files.", " /XFERMODE Show pattern-based transfer mode (T=Text, B=Binary).", " /TYPE: Show only files of the specified type (text or binary).", " /MESSAGE:text Add brief message to each listing line.", " /NOMESSAGE + Don't add message to each listing line.", " /NOXFERMODE + Don't show pattern-based transfer mode", " /ISODATE + In verbose listings, show date in ISO 8061 format.", " /ENGLISHDATE In verbose listings, show date in \"English\" format.", #ifdef RECURSIVE " /RECURSIVE Descend through subdirectories.", " /NORECURSIVE + Don't descend through subdirectories.", #endif /* RECURSIVE */ " /SORT:key Sort by key, NAME, DATE, or SIZE; default key is NAME.", " /NOSORT + Don't sort.", " /ASCENDING + If sorting, sort in ascending order.", " /REVERSE If sorting, sort in reverse order.", " ", "Factory defaults are marked with +. Default for paging depends on SET", "COMMAND MORE-PROMPTING. Use SET OPTIONS DIRECTORY [ switches ] to change", "defaults; use SHOW OPTIONS to display customized defaults. Also see", "WDIRECTORY.", #else "Syntax: DIRECTORY [ filespec ]", " Lists the specified file or files. If no filespec is given, all files", " in the current directory are listed.", #endif /* DOMYDIR */ ""}; static char *hmxxtouch[] = { "Syntax: TOUCH [ switches ] filespec", " Updates the modification time of the given file or files to the current", " date and time or to the date and time specified in the /MODTIME: switch.", " If the filespec is the name of a single file that does not exist, the file", " is created. The following switches can be used to restrict the files", " to be touched according to various criteria:", " ", " /FILES Select files but not directories.", " /DIRECTORIES Select directories but not files.", " /ALL + Select both files and directories.", " /AFTER: Select files modified after the given date", " /BEFORE: Select files modified before the given date", " /LARGER: Select files larger than the given size in bytes", " /SMALLER: Select files smaller than the given size in bytes", " /EXCEPT: Exclude the given files (list or pattern)", #ifdef UNIXOROSK " /DOTFILES Include files whose names start with dot (period).", " /NODOTFILES + Don't include files whose names start with dot.", " /FOLLOWLINKS For symbolic link touch the linked-to file, not the link", " /NOFOLLOWLINKS + Select the link itself, not the file it links to.", " /NOLINKS Skip over symbolic links.", " /BACKUP + Include backup files (names end with .~n~).", " /NOBACKUPFILES Don't include backup files.", #endif /* UNIXOROSK */ " /TYPE: Select only files of the given type, TEXT or BINARY.", #ifdef RECURSIVE " /RECURSIVE Descend through subdirectories.", " /NORECURSIVE + Don't descend through subdirectories.", " ", " Action switches:", " ", " /MODTIME: Changes the modification time for the selected files.", " in numeric yyyy:mm:dd:hh:mm:ss format.", " if hh:mm:ss omitted time is set to 00:00:00", " /SIMULATE List files that would be touched, but don't touch them.", " /LIST Show which files are being touched.", #endif /* RECURSIVE */ " ", "Factory defaults are marked with +. Use HELP DATE to learn the date-time", "formats usable with /MODTIME:. If a /MODTIME: switch is not given, each", "selected file gets a modification time equal to the current clock time.", "You can use the /SIMULATE switch in combination with other switches to see", "which files will be affected without actually changing their dates.", ""}; static char *hmxxchange[] = { "Syntax: CHANGE [ switches ] filespec string1 string2", " Changes all occurrences of string1 to string2 in the given file or files.", " Works line by line, does not do multiline or across-line substitutions.", " To remove strings from files, specify string2 as \"\" or omit string2.", " Temporary files are created in the directory indicated by \\v(tmpdir)", " (show var tmpdir). You can select a different temporary directory with", " the SET TEMP-DIRECTORY command. All temporary files are deleted after use." , " ", " String1 and String2 should be enclosed in doublequotes \"\" or braces {} if" , " if they contain spaces. In the event that they already contain braces or", " doublequotes, especially if these are not balanced, some quoting may be", " required. Or you can assign the strings to variables and then use the", " variable names in the CHANGE command; example:", " ", " .a = {value=\"./", " .b = {value=\"../", " change *.html \\m(a) \\m(b)", " ", " Since the CHANGE command works line by line, only text files can be", " changed; C-Kermit automatically skips over binary files.", " ", " File selection switches (factory defaults are marked with +):", " ", " /AFTER: Select files modified after the given date", " /BEFORE: Select files modified before the given date", " /LARGER: Select files larger than the given size in bytes", " /SMALLER: Select files smaller than the given size in bytes", " /EXCEPT: Exclude the given files (list or pattern)", #ifdef UNIXOROSK " /DOTFILES Include files whose names start with dot (period).", " /NODOTFILES + Don't include files whose names start with dot.", #endif /* UNIXOROSK */ #ifdef RECURSIVE " /RECURSIVE Descend through subdirectories.", " /NORECURSIVE + Don't descend through subdirectories.", #endif /* RECURSIVE */ " ", " File disposition switches:", " ", " /BACKUP:name Back up original files to named directory.", " /DESTINATION:name Store resulting changed files in named directory.", " If neither of these options is given, original files are overwritten.", " ", " String selection switches:", " ", " /CASE:{ON,OFF} OFF (default) = ignore case in string1; \ ON = don't ignore", " ", " Action switches:", " ", " /COUNT:name Set named variable to number of files that were changed.", " /SIMULATE List files that would be changed, but don't change them.", " /LIST Show which files are being changed.", " /MODTIME: Modification time for change files, PRESERVE or UPDATE.", " ", "You can use the /SIMULATE switch in combination with other switches to see", "which files will be affected without actually changing them.", ""}; #ifndef NOSPL static char *hmxxkcd[] = { "Syntax: KCD symbolic-directory-name", " Kermit Change Directory: Like CD (q.v.) but (a) always acts locally, and", " (b) takes a symbolic directory name rather than an actual directory name.", " The symbolic names correspond to Kermit's directory-valued built-in", " variables, such as \\v(download), \\v(exedir), and so on. Here's the list:" , " ", #ifdef NT " appdata Your personal Kermit application data directory", " common C-Kermit's application data directory for all users", " desktop Your Windows desktop", #endif /* NT */ " download Your download directory (if any)", #ifdef OS2ORUNIX " exedir The directory where the Kermit executable resides", #endif /* OS2ORUNIX */ " home Your home, login, or default directory", " inidir The directory where Kermit's initialization was found", #ifdef UNIX " lockdir The UNIX UUCP lockfile directory on this computer", #endif /* UNIX */ #ifdef NT " personal Your \"My Documents\" directory", #endif /* NT */ " startup Your current directory at the time Kermit started", " textdir The directory where Kermit text files reside, if any", " tmpdir Your temporary directory", " ", " Also see CD, SET FILE DOWNLOAD, SET TEMP-DIRECTORY.", "" }; #endif /* NOSPL */ static char *hmxxcwd[] = { #ifdef LOCUS " If LOCUS is REMOTE or LOCUS is AUTO and you have an FTP connection,", " this command is equivalent to REMOTE CD (RCD). Otherwise:", " ", #endif /* LOCUS */ #ifdef vms "Syntax: CD [ directory or device:directory ]", " Change Working Directory. Equivalent to VMS SET DEFAULT command.", #else #ifdef datageneral "Change Working Directory, equivalent to AOS/VS 'dir' command.", #else #ifdef OS2 "Syntax: CD [ disk or directory name ]", " Change Disk or Directory. If a disk or directory name is not specified,", " your current directory becomes the one specified by HOME environment", " variable, if any. A disk letter must be followed by a colon.", #else "Syntax: CD [ directory name ]", " Change Directory. Changes your current, working, default directory to the", " one given, so that future non-absolute filename references are relative to", " this directory. If the directory name is omitted, your home (login)", " directory is supplied.", #endif /* OS2 */ #endif /* datageneral */ #endif /* vms */ " C-Kermit's default prompt shows your current directory.", " Synonyms: LCD, CWD.", #ifdef LOCUS " Also see: SET LOCUS, PWD, CDUP, BACK, REMOTE CD (RCD), SET CD, SET PROMPT.", #else " Also see: PWD, CDUP, BACK, REMOTE CD (RCD), SET CD, SET PROMPT.", #endif /* LOCUS */ #ifndef NOSPL " And see: HELP KCD.", #endif /* NOSPL */ " Relevant environment variables: CDPATH, HOME.", ""}; static char *hmxxdel[] = { "Syntax: DELETE [ switches... ] filespec", #ifdef LOCUS " If LOCUS is REMOTE or LOCUS is AUTO and you have an FTP connection,", " this command is equivalent to REMOTE DELETE (RDELETE). Otherwise:", " ", #endif /* LOCUS */ " Deletes a file or files on the computer where C-Kermit is running.", " The filespec may denote a single file or can include wildcard characters", " to match multiple files. RM is a synonym for DELETE. Switches include:", " ", "/AFTER:date-time", #ifdef VMS " Specifies that only those files created after the given date-time are", #else " Specifies that only those files modified after the given date-time are", #endif /* VMS */ " to be deleted. HELP DATE for info about date-time formats.", " ", "/BEFORE:date-time", #ifdef VMS " Specifies that only those files modified before the given date-time", #else " Specifies that only those files modified before the given date-time", #endif /* VMS */ " are to be deleted.", " ", "/NOT-AFTER:date-time", #ifdef VMS " Specifies that only those files modified at or before the given date-time", #else " Specifies that only those files modified at or before the given date-time", #endif /* VMS */ " are to be deleted.", " ", "/NOT-BEFORE:date-time", #ifdef VMS " Specifies that only those files modified at or after the given date-time", #else " Specifies that only those files modified at or after the given date-time", #endif /* VMS */ " are to be deleted.", " ", "/LARGER-THAN:number", " Specifies that only those files longer than the given number of bytes are", " to be deleted.", " ", "/SMALLER-THAN:number", " Specifies that only those files smaller than the given number of bytes are", " to be sent.", " ", "/EXCEPT:pattern", " Specifies that any files whose names match the pattern, which can be a", " regular filename or may contain wildcards, are not to be deleted. To", " specify multiple patterns (up to 8), use outer braces around the group", " and inner braces around each pattern:", " ", " /EXCEPT:{{pattern1}{pattern2}...}", " ", #ifdef UNIXOROSK "/DOTFILES", " Include (delete) files whose names begin with \".\".", " ", "/NODOTFILES", " Skip (don't delete) files whose names begin with \".\".", " ", #endif /* UNIXOROSK */ "/TYPE:TEXT", " Delete only regular text files (requires FILE SCAN ON as it is by default)", " ", "/TYPE:BINARY", " Delete only regular binary files (requires FILE SCAN ON)", " ", "/DIRECTORIES", " Include directories. If this switch is not given, only regular files", " are deleted. If it is given, Kermit attempts to delete any directories", " that match the given file specification, which succeeds only if the", " directory is empty.", " ", #ifdef RECURSIVE "/RECURSIVE", " The DELETE command applies to the entire directory tree rooted in the", " current or specified directory. When the /DIRECTORIES switch is also", " given, Kermit deletes all the (matching) files in each directory before", " attempting to delete the directory itself.", " ", #endif /* RECURSIVE */ #ifdef UNIX #ifdef RECURSIVE "/ALL", " This is a shortcut for /RECURSIVE /DIRECTORIES /DOTFILES.", #else "/ALL", " This is a shortcut for /DIRECTORIES /DOTFILES.", #endif /* RECURSIVE */ #else /* !UNIX */ #ifdef RECURSIVE "/ALL", " This is a shortcut for /RECURSIVE /DIRECTORIES.", #else "/ALL", " This is a synonym for /DIRECTORIES.", #endif /* RECURSIVE */ #endif /* UNIX */ " ", "/LIST", " List each file and tell whether it was deleted. Synonyms: /LOG, /VERBOSE.", " ", "/NOLIST", " Don't list files while deleting. Synonyms: /NOLOG, /QUIET.", " ", "/HEADING", " Print heading and summary information.", " ", "/NOHEADING", " Don't print heading and summary information.", " ", "/SUMMARY", " Like /HEADING /NOLIST, but only prints the summary line.", " ", "/PAGE", " If listing, pause after each screenful.", " ", "/NOPAGE", " Don't pause after each screenful.", " ", "/ASK", " Interactively ask permission to delete each file. Reply Yes or OK to", " delete it, No not to delete it, Quit to cancel the DELETE command, and", " Go to go ahead and delete all the rest of the files without asking.", " ", "/NOASK", " Delete files without asking permission.", " ", "/SIMULATE", " Preview files selected for deletion without actually deleting them.", " Implies /LIST.", " ", "Use SET OPTIONS DELETE to make selected switches effective for every DELETE", "command \ unless you override them; use SHOW OPTIONS to see selections currently", #ifdef LOCUS "in effect. Also see HELP SET LOCUS, HELP PURGE, HELP WILDCARD.", #else "in effect. Also see HELP PURGE, HELP WILDCARD.", #endif /* LOCUS */ ""}; #ifndef NOHTTP static char *hmxxhttp[] = { "Syntax:", #ifdef CK_SSL "HTTP [ ] OPEN [{ /SSL, /TLS }] ", #else "HTTP [ ] OPEN ", #endif /*CK_SSL */ " Instructs Kermit to open a new connection for HTTP communication with", " the specified host on the specified port. The default port is \"http\".", #ifdef CK_SSL " If /SSL or /TLS are specified or if the service is \"https\" or port 443,", " a secure connection will be established using the current authentication", " settings. See HELP SET AUTH for details.", #endif /* CK_SSL */ " If are specified, they are applied to all subsequent HTTP", " actions (GET, PUT, ...) until an HTTP CLOSE command is executed.", " A URL can be included in place of the hostname and service or port.", " ", "HTTP CLOSE", " Instructs Kermit to close any open HTTP connection and clear any saved", " switch values.", " ", "HTTP [ ] CONNECT [:]", " Instructs the server to establish a connection with the specified host", " and to redirect all data transmitted between Kermit and the host for the", " life of the connection.", " ", "HTTP [ ] GET [ ]", " Retrieves the named file on the currently open HTTP connection. The", " default local filename is the same as the remote filename, but with any", " path stripped. If you want the file to be displayed on the screen instead", " of stored on disk, include the /TOSCREEN switch and omit the local", " filename. If you give a URL instead of a remote filename, this commands", " opens the connection, GETs the file, and closes the connection; the same", " is true for the remaining HTTP commands for which you can specify a", " remote filename, directory name, or path.", " ", "HTTP [ ] HEAD [ ]", " Like GET except without actually getting the file; instead it gets only", " the headers, storing them into the given file (if a local filename is", " specified), one line per header item as shown in the /ARRAY: switch", " description.", " ", "HTTP [ ] INDEX [ ]", " Retrieves the file listing for the given server directory.", " NOTE: This command is not supported by most Web servers, and even when", " the server understand it, there is no stardard response format.", " ", "HTTP [ ] POST [ /MIME-TYPE: ] ", " [ ]", " Used to send a response as if it were sent from a form. The data to be", " posted must be read from a file.", " ", "HTTP [ ] PUT [ /MIME-TYPE: ] ", " [ ]", " Uploads the given local file to server file. If the remote filename is", " omitted, the local name is used, but with any path stripped.", " ", "HTTP [ ] DELETE ", " Instructs the server to delete the specified filename.", " ", "where are:", "/AGENT:", " Identifies the client to the server; \"C-Kermit\"", " by default.", " ", "/HEADER:", " Used for specifying any optional headers. A list of headers is provided", " using braces for grouping:", " ", " /HEADER:{{:}{:}...}", " ", " For a listing of valid value and formats see RFC 1945:", " \"Hypertext Transfer Protocol -- HTTP/1.0\". A maximum of eight headers", " may be specified.", " ", "/TOSCREEN", " Display server responses on the screen.", " ", "/USER:", " In case a page requires a username for access.", " ", "/PASSWORD:", " In case a page requires a password for access.", " ", "/ARRAY:", " Tells Kermit to store the response headers in the given array, one line", " per element. The array need not be declared in advance. Example:", " ", " http /array:c get kermit/index.html", " show array c", " Dimension = 9", " 1. Date: Fri, 26 Nov 1999 23:12:22 GMT", " 2. Server: Apache/1.3.4 (Unix)", " 3. Last-Modified: Mon, 06 Sep 1999 22:35:58 GMT", " 4. ETag: \"bc049-f72-37d441ce\"", " 5. Accept-Ranges: bytes", " 6. Content-Length: 3954", " 7. Connection: close ", " 8. Content-Type: text/html", " ", "As you can see, the header lines are like MIME e-mail header lines:", "identifier, colon, value. The /ARRAY switch is the only method available", "to a script to process the server responses for a POST or PUT command.", " ", "" }; #endif /* NOHTTP */ #ifdef CK_KERBEROS static char *hmxxauth[] = { "Syntax:", "AUTHENTICATE { KERBEROS4, KERBEROS5 [ switches ] } [ switches ]", " Obtains or destroys Kerberos tickets and lists information about them.", " Actions are INITIALIZE, DESTROY, and LIST-CREDENTIALS. KERBEROS4 can be", " abbreviated K4 or KRB4; KERBEROS5 can be abbreviated K5 or KRB5. Use ? to", " see which keywords, switches, or other quantities are valid at each point", " in the command.", " ", " The actions are INITIALIZE, DESTROY, and LIST-CREDENTIALS:", " ", " AUTH { K4, K5 } { INITIALIZE [switches], DESTROY,", " LIST-CREDENTIALS [switches] }", " ", " The INITIALIZE action is the most complex, and its format is different", " for Kerberos 4 and Kerberos 5. The format for Kerberos 4 is:", " ", " AUTH K4 INITIALIZE [ /INSTANCE: /LIFETIME: -", " /PASSWORD: /PREAUTH /REALM: ]", " ", " All switches are optional. Kerberos 4 INITIALIZE switches are:", " ", " /INSTANCE:", " Allows an Instance (such as a hostname) to be specified.", " ", " /LIFETIME:", " Specifies the requested lifetime in minutes for the ticket. If no", " lifetime is specified, 600 minutes is used. If the lifetime is greater", " than the maximum supported by the ticket granting service, the resulting", " lifetime is shortened accordingly.", " ", " /NOT-PREAUTH", " Instructs Kermit to send a ticket getting ticket (TGT) request to the", " KDC without any preauthentication data.", " ", " /PASSWORD:", " Allows a password to be included on the command line or in a script", " file. If no /PASSWORD switch is included, you are prompted on a separate" , " line. The password switch is provided on a use-at-your-own-risk basis", " for use in automated scripts. WARNING: Passwords should not be stored in" , " files.", " ", " /PREAUTH", " Instructs Kermit to send a preauthenticated Ticket-Getting Ticket (TGT)", " request to the KDC instead of a plaintext request. The default when", " supported by the Kerberos libraries.", " ", " /REALM:", " Allows a realm to be specified (overriding the default realm).", " ", " ", " Your identity in the given or default Kerberos realm, of the form:", " userid[.instance[.instance]]@[realm] ", " Can be omitted if it is the same as your username or SET LOGIN USERID", " value on the client system.", " ", " The format for Kerberos 5 is as follows:", " ", " AUTH K5 [ /CACHE: ] { INITIALIZE [ switches ], DESTROY,", " LIST-CREDENTIALS ...}", " ", "The INITIALIZE command for Kerberos 5 can include a number of switches;", "all are optional:", " ", "AUTH K5 [ /CACHE: ] INITITIALIZE [ /ADDRESSES:", " /FORWARDABLE /KERBEROS4 /LIFETIME: /PASSWORD:", " /POSTDATE: /PROXIABLE /REALM: /RENEW /RENEWABLE:", " /SERVICE: /VALIDATE ]", " ", " All Kerberos 5 INITIALIZE switches are optional:", " ", " /ADDRESSES:{list of ip-addresses}", " Specifies a list of IP addresses that should be placed in the Ticket", " Getting Ticket in addition to the local machine addresses.", " ", " /FORWARDABLE", " Requests forwardable tickets.", " ", " /INSTANCE:", " Allows an Instance (such as a hostname) to be specified.", " ", " /KERBEROS4", " Instructs Kermit to get Kerberos 4 tickets in addition to Kerberos 5", " tickets. If Kerberos 5 tickets are not supported by the server, a", " mild warning is printed and Kerberos 4 tickets are requested.", " ", " /LIFETIME:", " Specifies the requested lifetime in minutes for the ticket. If no", " lifetime is specified, 600 minutes is used. If the lifetime is greater", " than the maximum supported by the ticket granting service, the resulting", " lifetime is shortened.", " ", " /NO-KERBEROS4", " Instructs Kermit to not attempt to retrieve Kerberos 4 credentials.", " ", " /NOT-FORWARDABLE", " Requests non-forwardable tickets.", " ", " /NOT-PROXIABLE", " Requests non-proxiable tickets.", " ", " /PASSWORD:", " Allows a password to be included on the command line or in a script", " file. If no /PASSWORD switch is included, you are prompted on a separate" , " line. The password switch is provided on a use-at-your-own-risk basis", " for use in automated scripts. WARNING: Passwords should not be stored in" , " files.", " ", " /POSTDATE:", " Requests a postdated ticket, valid starting at . Postdated", " tickets are issued with the invalid flag set, and need to be fed back to", " the KDC before use with the /VALIDATE switch. Type HELP DATE for info", " on date-time formats.", " ", " /PROXIABLE", " Requests proxiable tickets.", " ", " /REALM:", " Allows an alternative realm to be specified.", " ", " /RENEW", " Requests renewal of a renewable Ticket-Granting Ticket. Note that ", " an expired ticket cannot be renewed even if it is within its renewable ", " lifetime.", " ", " /RENEWABLE:", " Requests renewable tickets, with a total lifetime of minutes.", " ", " /SERVICE:", " Allows a service other than the ticket granting service to be specified.", " ", " /VALIDATE", " Requests that the Ticket Granting Ticket in the cache (with the invalid", " flag set) be passed to the KDC for validation. If the ticket is within", " its requested time range, the cache is replaced with the validated", " ticket.", " ", " ", " Your identity in the given or default Kerberos realm, of the form:", " userid[/instance][@realm] ", " Can be omitted if it is the same as your username or SET LOGIN USERID", " value on the client system.", " ", " Note: Kerberos 5 always attempts to retrieve a Ticket-Getting Ticket (TGT)", " using the preauthenticated TGT request.", " ", " AUTHORIZE K5 LIST-CREDENTIALS [ /ADDRESSES /FLAGS /ENCRYPTION ]", " ", " Shows start time, expiration time, service or principal name, plus", " the following additional information depending the switches:", " ", " /ADDRESSES displays the hostnames and/or IP addresses embedded within", " the tickets.", " ", " /FLAGS provides the following information (if applicable) for each ticket:", " F - Ticket is Forwardable", " f - Ticket was Forwarded", " P - Ticket is Proxiable", " p - Ticket is a Proxy", " D - Ticket may be Postdated", " d - Ticket has been Postdated", " i - Ticket is Invalid", " R - Ticket is Renewable", " I - Ticket is the Initial Ticket", " H - Ticket has been authenticated by Hardware", " A - Ticket has been Pre-authenticated", " ", " /ENCRYPTION displays the encryption used by each ticket (if applicable):", " DES-CBC-CRC", " DES-CBC-MD4", " DES-CBC-MD5", " DES3-CBC-SHA", "" }; #endif /* CK_KERBEROS */ #ifndef NOCSETS static char *hmxxassoc[] = { "ASSOCIATE FILE-CHARACTER-SET ", " Tells C-Kermit that whenever the given file-character set is selected, and", " SEND CHARACTER-SET (q.v.) is AUTOMATIC, the given transfer character-set", " is selected automatically.", " ", "ASSOCIATE XFER-CHARACTER-SET ", " Tells C-Kermit that whenever the given transfer-character set is selected,", " either by command or by an announcer attached to an incoming text file,", " and SEND CHARACTER-SET is AUTOMATIC, the specified file character-set is", " to be selected automatically. Synonym: ASSOCIATE TRANSFER-CHARACTER-SET.", " ", "Use SHOW ASSOCIATIONS to list the current character-set associations, and", "SHOW CHARACTER-SETS to list the current settings.", "" }; #endif /* NOCSETS */ static char *hmxxpat[] = { "A \"pattern\" is notation used in a search string when searching through", "text. C-Kermit uses three kinds of patterns: floating patterns, anchored", "patterns, and wildcards. Wildcards are anchored patterns that are used to", "match file names; type HELP WILDCARD to learn about them.", " ", "In a pattern, certain characters are special:", " ", "* Matches any sequence of zero or more characters. For example, \"k*t\"", " matches all strings that start with \"k\" and end with \"t\" including", " \"kt\", \"kit\", \"knight\", or \"kermit\".", " ", #ifdef VMS "% Matches any single character. For example, \"k%%%%t\" matches all strings", #else "? Matches any single character. For example, \"k????t\" matches all strings", #endif /* VMS */ " that are exactly 6 characters long and start with \"k\" and end with", #ifdef VMS " with \"t\".", #else " with \"t\". When typing commands at the prompt, you must precede any", " question mark to be used for matching by a backslash (\\) to override the", " normal function of question mark in interactive commands, which is to", " provide menus and file lists.", #endif /* VMS */ " ", #ifdef OS2ORUNIX #ifdef CKREGEX "[abc]", " Square brackets enclosing a list of characters matches any character in", " the list. Example: h[aou]t matches hat, hot, and hut.", " ", "[a-z]", " Square brackets enclosing a range of characters matches any character in", " the range; a hyphen (-) separates the low and high elements of the range.", " For example, [a-z] matches any character from a to z.", " ", "[acdm-z]", " Lists and ranges may be combined. This example matches a, c, d, or any", " letter from m through z.", " ", "{string1,string2,...}", " Braces enclose a list of strings to be matched. For example:", " ker{mit,nel,beros} matches kermit, kernel, and kerberos. The strings", " may themselves contain *, ?, [abc], [a-z], or other lists of strings.", #endif /* CKREGEX */ #endif /* OS2ORUNIX */ #ifndef NOSPL " ", "To force a special pattern character to be taken literally, precede it with", "a backslash, e.g. [a\\-z] matches a, hyphen, or z rather than a through z.", " ", "A floating pattern can also include the following special characters:", " ", "^ (First character of pattern) Anchors the pattern at the beginning.", "$ (Last character of pattern) Anchors the pattern at the end.", " ", "If a floating pattern does not start with \"^\", the pattern can match", "anywhere in the string instead of only at the beginning; in other words, a", "leading \"*\" is assumed. Similarly, if the pattern doesn't end with \"$\",", "a trailing \"*\" is assumed.", " ", "The following commands and functions use floating patterns:", " GREP [ ] ", " TYPE /MATCH: ", " \\farraylook(,)", " \\fsearch(,[,])", " \\frsearch(,[,])", " The /EXCEPT: clause in SEND, GET, DELETE, etc.", " ", "Example:", " \\fsearch(abc,xxabcxxx) succeeds because xxabcxx contains abc.", " \\fsearch(^abc,xxabcxx) fails because xxabcxx does not start with abc.", " ", "All other commands and functions use anchored patterns, meaning that ^ and $", "are not treated specially, and * is not assumed at the beginning or end of", "the pattern. This is true mainly of filename patterns (wildcards), since", "you would not want a command like \"delete x\" to delete all files whose", "names contained \"x\"!", " ", "You can use anchored patterns not only in filenames, but also in SWITCH", "case labels, in the INPUT and MINPUT commands, and in file binary- and", "text-patterns for filenames. The IF MATCH pattern is also anchored.", #endif /* NOSPL */ "" }; static char *hmxxwild[] = { "A \"wildcard\" is a notation used in a filename to match multiple files.", "For example, in \"send *.txt\" the asterisk is a wildcard. Kermit commands", "that accept filenames also accepts wildcards, except commands that are", "allowed to operate on only one file, such as TRANSMIT.", "This version of Kermit accepts the following wildcards:", " ", "* Matches any sequence of zero or more characters. For example, \"ck*.c\"", " matches all files whose names start with \"ck\" and end with \".c\"", " including \"ck.c\".", " ", #ifdef VMS "% Matches any single character. For example, \"ck%.c\" matches all files", #else "? Matches any single character. For example, \"ck?.c\" matches all files", #endif /* VMS */ " whose names are exactly 5 characters long and start with \"ck\" and end", #ifdef VMS " with \".c\".", #else " with \".c\". When typing commands at the prompt, you must precede any", " question mark to be used for matching by a backslash (\\) to override the", " normal function of question mark in interactive commands, which is to", " provide menus and file lists. You don't, however, need to quote filename", " question marks in command files (script programs).", #endif /* VMS */ " ", #ifdef OS2ORUNIX #ifdef CKREGEX "[abc]", " Square brackets enclosing a list of characters matches any character in", " the list. Example: ckuusr.[ch] matches ckuusr.c and ckuusr.h.", " ", "[a-z]", " Square brackets enclosing a range of characters matches any character in", " the range; a hyphen (-) separates the low and high elements of the range.", " For example, [a-z] matches any character from a to z.", " ", "[acdm-z]", " Lists and ranges may be combined. This example matches a, c, d, or any", " letter from m through z.", " ", "{string1,string2,...}", " Braces enclose a list of strings to be matched. For example:", " ck{ufio,vcon,cmai}.c matches ckufio.c, ckvcon.c, or ckcmai.c. The strings", " may themselves contain *, ?, [abc], [a-z], or other lists of strings.", #endif /* CKREGEX */ #endif /* OS2ORUNIX */ " ", "To force a special pattern character to be taken literally, precede it with", "a backslash, e.g. [a\\-z] matches a, hyphen, or z rather than a through z.", "Or tell Kermit to SET WILDCARD-EXPANSION OFF before entering or referring", "to the filename.", " ", #ifndef NOSPL "Similar notation can be used in general-purpose string matching. Type HELP", "PATTERNS for details. Also see HELP SET MATCH.", #endif /* NOSPL */ "" }; #ifndef NOXFER static char *hmxxfast[] = { "FAST, CAUTIOUS, and ROBUST are predefined macros that set several", "file-transfer parameters at once to achieve the desired file-transfer goal.", "FAST chooses a large packet size, a large window size, and a fair amount of", "control-character unprefixing at the risk of possible failure on some", "connections. FAST is the default tuning in C-Kermit 7.0 and later. In case", "FAST file transfers fail for you on a particular connection, try CAUTIOUS.", "If that fails too, try ROBUST. You can also change the definitions of each", "macro with the DEFINE command. To see the current definitions, type", "\"show macro fast\", \"show macro cautious\", or \"show macro robust\".", "" }; #endif /* NOXFER */ #ifdef VMS static char * hmxxpurge[] = { "Syntax: PURGE [ switches ] [ filespec ]", " Runs the DCL PURGE command. Switches and filespec are not parsed or", " verified by Kermit, but passed directly to DCL.", "" }; #else #ifdef CKPURGE static char * hmxxpurge[] = { "Syntax: PURGE [ switches ] [ filespec ]", " Deletes backup files; that is, files whose names end in \".~n~\", where", " n is a number. PURGE by itself deletes all backup files in the current", " directory. Switches:", " ", "/AFTER:date-time", #ifdef VMS " Specifies that only those files created after the given date-time are", #else " Specifies that only those files modified after the given date-time are", #endif /* VMS */ " to be purged. HELP DATE for info about date-time formats.", " ", "/BEFORE:date-time", #ifdef VMS " Specifies that only those files modified before the given date-time", #else " Specifies that only those files modified before the given date-time", #endif /* VMS */ " are to be purged.", " ", "/NOT-AFTER:date-time", #ifdef VMS " Specifies that only those files modified at or before the given date-time", #else " Specifies that only those files modified at or before the given date-time", #endif /* VMS */ " are to be purged.", " ", "/NOT-BEFORE:date-time", #ifdef VMS " Specifies that only those files modified at or after the given date-time", #else " Specifies that only those files modified at or after the given date-time", #endif /* VMS */ " are to be purged.", " ", "/LARGER-THAN:number", " Specifies that only those files longer than the given number of bytes are", " to be purged.", " ", "/SMALLER-THAN:number", " Specifies that only those files smaller than the given number of bytes are", " to be purged.", " ", "/EXCEPT:pattern", " Specifies that any files whose names match the pattern, which can be a", " regular filename or may contain wildcards, are not to be purged. To", " specify multiple patterns (up to 8), use outer braces around the group", " and inner braces around each pattern:", " ", " /EXCEPT:{{pattern1}{pattern2}...}", " ", #ifdef UNIXOROSK "/DOTFILES", " Include (purge) files whose names begin with \".\".", " ", "/NODOTFILES", " Skip (don't purge) files whose names begin with \".\".", " ", #endif /* UNIXOROSK */ #ifdef RECURSIVE "/RECURSIVE", " Descends through the current or specified directory tree.", " ", #endif /* RECURSIVE */ "/KEEP:n", " Retain the 'n' most recent (highest-numbered) backup files for each file.", " By default, none are kept. If /KEEP is given without a number, 1 is used.", " ", "/LIST", " Display each file as it is processed and say whether it is purged or kept.", " Synonyms: /LOG, /VERBOSE.", " ", "/NOLIST", " The PURGE command should operate silently (default).", " Synonyms: /NOLOG, /QUIET.", " ", "/HEADING", " Print heading and summary information.", " ", "/NOHEADING", " Don't print heading and summary information.", " ", "/PAGE", " When /LIST is in effect, pause at the end of each screenful, even if", " COMMAND MORE-PROMPTING is OFF.", " ", "/NOPAGE", " Don't pause, even if COMMAND MORE-PROMPTING is ON.", " ", "/ASK", " Interactively ask permission to delete each backup file.", " ", "/NOASK", " Purge backup files without asking permission.", " ", "/SIMULATE", " Inhibits the actual deletion of files; use to preview which files would", " actually be deleted. Implies /LIST.", " ", "Use SET OPTIONS PURGE [ switches ] to change defaults; use SHOW OPTIONS to", "display customized defaults. Also see HELP DELETE, HELP WILDCARD.", "" }; #endif /* CKPURGE */ #endif /* VMS */ static char *hmxxclo[] = { "Syntax: CLOSE [ item ]", " Close the indicated item. The default item is CONNECTION, which is the", " current SET LINE or SET HOST connection. The other items are:", " ", #ifdef CKLOGDIAL " CX-LOG (connection log, opened with LOG CX)", #endif /* CKLOGDIAL */ #ifndef NOLOCAL " SESSION-LOG (opened with LOG SESSION)", #endif /* NOLOCAL */ #ifdef TLOG " TRANSACTION-LOG (opened with LOG TRANSACTIONS)", #endif /* TLOG */ " PACKET-LOG (opened with LOG PACKETS)", #ifdef DEBUG " DEBUG-LOG (opened with LOG DEBUG)", #endif /* DEBUG */ #ifndef NOSPL " READ-FILE (opened with OPEN READ)", " WRITE-FILE (opened with OPEN WRITE or OPEN APPEND)", #endif /* NOSPL */ " ", "Type HELP LOG and HELP OPEN for further info.", "" }; #ifdef CKLEARN static char * hmxxlearn[] = { "Syntax: LEARN [ /ON /OFF /CLOSE ] [ filename ]", " Records a login script. If you give a filename, the file is opened for", " subsequent recording. If you don't give any switches, /ON is assumed.", " /ON enables recording to the current file (if any); /OFF disables", " recording. /CLOSE closes the current file (if any). After LEARN /CLOSE", " or exit from Kermit, your script is available for execution by the TAKE", " command.", "" }; #endif /* CKLEARN */ #ifdef CK_MINPUT static char *hmxxminp[] = { "Syntax: MINPUT [ switches ] n [ string1 [ string2 [ ... ] ] ]", "Example: MINPUT 5 Login: {Username: } {NO CARRIER} BUSY RING", " For use in script programs. Waits up to n seconds for any one of the", " strings to arrive on the communication device. If no strings are given,", " the command waits for any character at all to arrive. Strings are", " separated by spaces; use {braces} or \"doublequotes\" for grouping. If", " any of the strings is encountered within the timeout interval, the command", " succeeds and the \\v(minput) variable is set to the number of the string", " that was matched: 1, 2, 3, etc. If none of the strings arrives, the", " command times out, fails, and \\v(minput) is set to 0. In all other", " respects, MINPUT is like INPUT. See HELP INPUT for the available switches", " and other details of operation.", "" }; #endif /* CK_MINPUT */ #ifndef NOLOCAL static char *hmxxcon[] = { "Syntax: CONNECT (or C, or CQ) [ switches ]", " Connect to a remote computer via the serial communications device given in", #ifdef OS2 " the most recent SET PORT command, or to the network host named in the most", #else " the most recent SET LINE command, or to the network host named in the most", #endif /* OS2 */ " recent SET HOST command. Type the escape character followed by C to get", " back to the C-Kermit prompt, or followed by ? for a list of CONNECT-mode", #ifdef OS2 " escape commands. You can also assign the \\Kexit verb to the key or", " key-combination of your choice; by default it is assigned to Alt-x.", #else " escape commands.", " ", "Include the /QUIETLY switch to suppress the informational message that", "tells you how to escape back, etc. CQ is a synonym for CONNECT /QUIETLY.", #endif /* OS2 */ " ", "Other switches include:", #ifdef CK_TRIGGER " ", "/TRIGGER:string", " One or more strings to look for that will cause automatic return to", " command mode. To specify one string, just put it right after the", " colon, e.g. \"/TRIGGER:Goodbye\". If the string contains any spaces, you", " must enclose it in braces, e.g. \"/TRIGGER:{READY TO SEND...}\". To", " specify more than one trigger, use the following format:", " ", " /TRIGGER:{{string1}{string2}...{stringn}}", " ", " Upon return from CONNECT mode, the variable \\v(trigger) is set to the", " trigger string, if any, that was actually encountered. This value, like", " all other CONNECT switches applies only to the CONNECT command with which", " it is given, and overrides (temporarily) any global SET TERMINAL TRIGGER", " string that might be in effect.", #endif /* CK_TRIGGER */ #ifdef OS2 " ", "/IDLE-LIMIT:number", " The number of seconds of idle time, after which Kermit returns", " automatically to command mode; default 0 (no limit).", " ", "/IDLE-INTERVAL:number", " The number of seconds of idle time, after which Kermit automatically", " transmits the idle string.", " ", "/IDLE-STRING:string", " The string to transmit whenever the idle interval has passed.", " ", "/TIME-LIMIT:number", " The maximum number of seconds for which the CONNECT session may last.", " The default is 0 (no limit). If a nonzero number is given, Kermit returns", " automatically to command mode after this many seconds.", #endif /* OS2 */ "" }; #endif /* NOLOCAL */ static char *hmxxmget[] = { "Syntax: MGET [ switches... ] remote-filespec [ remote-filespec ... ]", " ", "Just like GET (q.v.) except allows a list of remote file specifications,", "separated by spaces.", "" }; static char *hmxxget[] = { "Syntax: GET [ switches... ] remote-filespec [ as-name ]", " Tells the other Kermit, which must be in (or support autoswitching into)", " server mode, to send the named file or files. If the remote-filespec or", " the as-name contain spaces, they must be enclosed in braces. If as-name", " is the name of an existing local directory, incoming files are placed in", " that directory; if it is the name of directory that does not exist, Kermit", " tries to create it. Optional switches include:", " ", "/AS-NAME:text", " Specifies \"text\" as the name to store the incoming file under, or", " directory to store it in. You can also specify the as-name as the second", " filename on the GET command line.", " ", "/BINARY", " Performs this transfer in binary mode without affecting the global", " transfer mode.", " ", "/COMMAND", " Receives the file into the standard input of a command, rather than saving", " it on disk. The /AS-NAME or the second \"filename\" on the GET command", " line is interpreted as the name of a command.", " ", "/DELETE", " Asks the other Kermit to delete the file (or each file in the group)", " after it has been transferred successfully.", " ", "/EXCEPT:pattern", " Specifies that any files whose names match the pattern, which can be a", " regular filename, or may contain \"*\" and/or \"?\" metacharacters,", " are to be refused. To specify multiple patterns (up to 8), use outer", " braces around the group, and inner braces around each pattern:", " ", " /EXCEPT:{{pattern1}{pattern2}...}", " ", "/FILENAMES:{CONVERTED,LITERAL}", " Overrides the global SET FILE NAMES setting for this transfer only.", " ", "/FILTER:command", " Causes the incoming file to passed through the given command (standard", " input/output filter) before being written to disk.", " ", #ifdef VMS "/IMAGE", " Transfer in image mode.", " ", #endif /* VMS */ #ifdef CK_LABELED "/LABELED", " VMS and OS/2 only: Specifies labeled transfer mode.", " ", #endif /* CK_LABELED */ "/MOVE-TO:directory-name", " Specifies that each file that arrives should be moved to the specified", " directory after, and only if, it has been received successfully.", " ", "/PATHNAMES:{OFF,ABSOLUTE,RELATIVE,AUTO}", " Overrides the global SET RECEIVE PATHNAMES setting for this transfer.", " ", "/PIPES:{ON,OFF}", " Overrides the TRANSFER PIPES setting for this command only. ON allows", " reception of files with names like \"!tar xf -\" to be automatically", " directed to a pipeline.", " ", "/QUIET", " Suppresses the file-transfer display.", " ", "/RECOVER", " Used to recover from a previously interrupted transfer; GET /RECOVER", " is equivalent REGET. Works only in binary mode.", " ", "/RECURSIVE", " Tells the server to descend through the directory tree when locating", " the files to be sent.", " ", "/RENAME-TO:string", " Specifies that each file that arrives should be renamed as specified", " after, and only if, it has been received successfully. The string can", " be a filename, a directory name, an expression involving variables, etc.", " ", "/TEXT", " Performs this transfer in text mode without affecting the global", " transfer mode.", " ", "/TRANSPARENT", " Inhibits character-set translation of incoming text files for the duration", " of the GET command without affecting subsequent commands.", " ", "Also see HELP MGET, HELP SEND, HELP RECEIVE, HELP SERVER, HELP REMOTE.", ""}; static char *hmxxlg[] = { "Syntax: LOG (or L) log-type [ filename [ { NEW, APPEND } ] ]", " ", "Record information in a log file:", " ", #ifdef CKLOGDIAL "CX", " Connections made with SET LINE, SET PORT, SET HOST, DIAL, TELNET, etc.", " The default filename is CX.LOG in your home directory and APPEND is the", " default mode for opening.", " ", #endif /* CKLOGDIAL */ #ifdef DEBUG "DEBUG", " Debugging information, to help track down bugs in the C-Kermit program.", " The default log name is debug.log in current directory.", " ", #endif /* DEBUG */ "PACKETS", " Kermit packets, to help with protocol problems. The default filename is", " packet.log in current directory.", " ", #ifndef NOLOCAL "SESSION", " Records your CONNECT session (default: session.log in current directory).", " ", #endif /* NOLOCAL */ #ifdef TLOG "TRANSACTIONS", " Names and statistics about files transferred (default: transact.log in", " current directory; see HELP SET TRANSACTION-LOG for transaction-log format", " options.)", " ", #endif /* TLOG */ "If you include the APPEND keyword after the filename, the existing log file,", "if any, is appended to; otherwise a new file is created (except APPEND is", "the default for the connection log). Use CLOSE to stop logging.", #ifdef OS2ORUNIX " ", "Note: The filename can also be a pipe, e.g.:", " ", " log transactions |lpr", " log debug {| grep \"^TELNET\" > debug.log}", " ", "Braces are required if the pipeline or filename contains spaces.", #endif /* OS2ORUNIX */ "" }; #ifndef NOSCRIPT static char *hmxxlogi[] = { "\ Syntax: SCRIPT text", " A limited and cryptic \"login assistant\", carried over from old C-Kermit", " releases for comptability, but not recommended for use. Instead, please", " use the full script programming language described in chapters 17-19 of", " \"Using C-Kermit\".", " ", " Login to a remote system using the text provided. The login script", " is intended to operate similarly to UNIX uucp \"L.sys\" entries.", " A login script is a sequence of the form:", " ", " expect send [expect send] . . .", " ", " where 'expect' is a prompt or message to be issued by the remote site, and", " 'send' is the names, numbers, etc, to return. The send may also be the", " keyword EOT to send Control-D, or BREAK (or \\\\b) to send a break signal.", " Letters in send may be prefixed by ~ to send special characters:", " ", " ~b backspace, ~s space, ~q '?', ~n linefeed, ~r return, ~c don\'t", " append a return, and ~o[o[o]] for octal of a character. As with some", " UUCP systems, sent strings are followed by ~r unless they end with ~c.", " ", " Only the last 7 characters in each expect are matched. A null expect,", " e.g. ~0 or two adjacent dashes, causes a short delay. If you expect", " that a sequence might not arrive, as with uucp, conditional sequences", " may be expressed in the form:", " ", " -send-expect[-send-expect[...]]", " ", " where dashed sequences are followed as long as previous expects fail.", "" }; #endif /* NOSCRIPT */ #ifndef NOFRILLS static char * hmxxtyp[] = { "Syntax: TYPE [ switches... ] file", " Displays a file on the screen. Pauses automatically at end of each", " screenful if COMMAND MORE-PROMPTING is ON. Optional switches:", " ", " /PAGE", " Pause at the end of each screenful even if COMMAND MORE-PROMPTING OFF.", " Synonym: /MORE", " /NOPAGE", " Don't pause at the end of each screen even if COMMAND MORE-PROMPTING ON." , " /HEAD:n", " Only type the first 'n' lines of the file.", " /TAIL:n", " Only type the last 'n' lines of the file.", " /MATCH:pattern", " Only type lines that match the given pattern. HELP WILDCARDS for info", " info about patterns. /HEAD and /TAIL apply after /MATCH.", " /PREFIX:string", " Print the given string at the beginning of each line.", " /NUMBER", " Add line numbers (conflicts with /PREFIX)", " /WIDTH:number", " Truncate each line at the given column number before printing.", #ifdef KUI " Or when combined with /GUI specifies the width of the dialog box.", " /HEIGHT:number", " When combined with /GUI specifies the height of the dialog box.", " /GUI:string", " Displays the contents of the file in a new scrollable GUI window.", " The string (require) is the title for the window.", #endif /* KUI */ " /COUNT", " Count lines (and matches) and print the count(s) but not the lines.", #ifdef UNICODE " /CHARACTER-SET:name", " Translates from the named character set.", #ifndef OS2 " /TRANSLATE-TO:name", " Translates to the named character set (default = current file charset).", #endif /* OS2 */ " /TRANSPARENT", " Inhibits character-set translation.", #endif /* UNICODE */ #ifdef TYPEINTERPRET " /INTERPRET", " Shows the file with Kermit backslash escapes interpreted.", #endif /* TYPEINTERPRET */ " /OUTPUT:name", " Sends results to the given file. If this switch is omitted, the", " results appear on your screen. This switch overrides any express or", " implied /PAGE switch.", " ", "You can use SET OPTIONS TYPE to set the defaults for /PAGE or /NOPAGE and", "/WIDTH. Use SHOW OPTIONS to see current TYPE options.", "" }; static char * hmxxcle[] = { "Syntax: CLEAR [ item-name ]", " ", "Clears the named item. If no item is named, DEVICE-AND-INPUT is assumed.", " ", " ALARM Clears any pending alarm (see SET ALARM).", #ifdef CK_APC " APC-STATUS Clears Application Program Command status.", #endif /* CK_APC */ #ifdef PATTERNS " BINARY-PATTERNS Clears the file binary-patterns list.", #endif /* PATTERNS */ #ifdef OS2 " COMMAND-SCREEN Clears the current command screen.", #endif /* OS2 */ " DEVICE Clears the current port or network input buffer.", " DEVICE-AND-INPUT Clears both the device and the INPUT buffer.", " DIAL-STATUS Clears the \\v(dialstatus) variable.", " \ INPUT Clears the INPUT-command buffer and the \\v(input) variable.", " KEYBOARD-BUFFER Clears the command terminal keyboard input buffer.", #ifdef OS2 " \ SCROLLBACK empties the scrollback buffer including the current screen.", #endif /* OS2 */ " SEND-LIST Clears the current SEND list (see ADD).", #ifdef OS2 " \ TERMINAL-SCREEN Clears the current screen a places it into the scrollback.", " buffer.", #endif /* OS2 */ #ifdef PATTERNS " TEXT-PATTERNS Clears the file text-patterns list.", #endif /* PATTERNS */ ""}; #endif /* NOFRILLS */ static char * hmxxdate[] = { "Syntax: DATE [ date-time [ timezone ] ] [ delta-time ]", " Prints a date-time in standard format: yyyymmdd_hh:mm:ss.", " Various date-time formats are accepted:", " ", " . The date, if given, must precede the time.", " . The year must be four digits or else a 2-digit format dd mmm yy,", " in which case if (yy < 50) yyyy = yy + 2000; else yyyy = yy + 1900.", " . If the year comes first, the second field is the month.", " . The day, month, and year may be separated by spaces, /, -, or underscore." ," . The date and time may be separated by spaces or underscore.", " . The month may be numeric (1 = January) or spelled out or abbreviated in", " English.", " . The time may be in 24-hour format or 12-hour format.", " . If the hour is 12 or less, AM is assumed unless AM or PM is included.", " . If the date is omitted but a time is given, the current date is supplied." , " . If the time is given but date omitted, 00:00:00 is supplied.", " . If both the date and time are omitted, the current date and time are", " supplied.", " ", " The following shortcuts can also be used in place of dates:", " ", " NOW", " Stands for the current date and time.", " ", " TODAY", " Today's date, optionally followed by a time; 00:00:00 if no time given.", " ", " YESTERDAY", " Yesterday's date, optionally followed by a time (default 00:00:00).", " ", " TOMORROW", " Tomorrows's date, optionally followed by a time (default 00:00:00).", " ", " Timezone specifications are similar to those used in e-mail and HTTP", " headers, either a USA timezone name, e.g. EST, or a signed four-digit", " timezone offset, {+,-}hhmm, e.g., -0500; it is used to convert date-time," , " a local time in that timezone, to GMT which is then converted to the", " local time at the host. If no timezone is given, the date-time is local." ," To convert local time (or a time in a specified timezone) to UTC (GMT),", " use the function \\futcdate().", " ", " Delta times are given as {+,-}[number date-units][hh[:mm[:ss]]]", " A date in the future/past relative to the date-time; date-units may be", " DAYS, WEEKS, MONTHS, YEARS: +3days, -7weeks, +3:00, +1month 8:00.", " ", "All the formats shown above are acceptable as arguments to date-time switches" , "such as /AFTER: or /BEFORE:, and to functions such as \\fcvtdate(),", "\\fdiffdate(), and \\futcdate(), that take date-time strings as arguments.", "" }; #ifndef NOXFER static char * hmxxsen[] = { "Syntax: SEND (or S) [ switches...] [ filespec [ as-name ] ]", " Sends the file or files specified by filespec. If the filespec is omitted", " the SEND-LIST is used (HELP ADD for more info). The filespec may contain", " wildcard characters. An 'as-name' may be given to specify the name(s)", " the files(s) are sent under; if the as-name is omitted, each file is", " sent under its own name. Also see HELP MSEND, HELP WILDCARD.", " Optional switches include:", " ", #ifndef NOSPL "/ARRAY:", " Specifies that the data to be sent comes from the given array, such as", " \\&a[]. A range may be specified, e.g. SEND /ARRAY:&a[100:199]. Leave", " the brackets empty or omit them altogether to send the whole 1-based array." , " Include /TEXT to have Kermit supply a line terminator at the end of each", " array element (and translate character sets if character-set translations", " are set up), or /BINARY to treat the array as one long string of characters" , " to be sent as-is. If an as-name is not specified, the array is sent with", " the name _ARRAY_X_, where \"X\" is replaced by actual array letter.", " ", #endif /* NOSPL */ "/AS-NAME:", " Specifies as the name to send the file under instead of its real", " name. This is equivalent to giving an as-name after the filespec.", " ", "/BINARY", " Performs this transfer in binary mode without affecting the global", " transfer mode.", " ", "/TEXT", " Performs this transfer in text mode without affecting the global", " transfer mode.", " ", "/TRANSPARENT", " Inhibits character-set translation for text files for the duration of", " the SEND command without affecting subsequent commands.", " ", "/NOBACKUPFILES", " Skip (don't send) Kermit or EMACS backup files (files with names that", " end with .~n~, where n is a number).", " ", #ifdef UNIXOROSK "/DOTFILES", " Include (send) files whose names begin with \".\".", " ", "/NODOTFILES", " Don't send files whose names begin with \".\".", " ", "/FOLLOWLINKS", " Send files that are pointed to by symbolic links.", " ", "/NOFOLLOWLINKS", " Skip over symbolic links (default).", " ", #endif /* UNIXOROSK */ #ifdef VMS "/IMAGE", " Performs this transfer in image mode without affecting the global", " transfer mode.", " ", #endif /* VMS */ #ifdef CK_LABELED "/LABELED", " Performs this transfer in labeled mode without affecting the global", " transfer mode.", " ", #endif /* CK_LABELED */ "/COMMAND", " Sends the output from a command, rather than the contents of a file.", " The first \"filename\" on the SEND command line is interpreted as the name", " of a command; the second (if any) is the as-name.", " ", "/FILENAMES:{CONVERTED,LITERAL}", " Overrides the global SET FILE NAMES setting for this transfer only.", " ", "/PATHNAMES:{OFF,ABSOLUTE,RELATIVE}", " Overrides the global SET SEND PATHNAMES setting for this transfer.", " ", "/FILTER:command", " Specifies a command \ (standard input/output filter) to pass the file through", " before sending it.", " ", "/DELETE", " Deletes the file (or each file in the group) after it has been sent", " successfully (applies only to real files).", " ", "/QUIET", " When sending in local mode, this suppresses the file-transfer display.", " ", "/RECOVER", " Used to recover from a previously interrupted transfer; SEND /RECOVER", " is equivalent RESEND (use in binary mode only).", " ", "/RECURSIVE", " Tells C-Kermit to look not only in the given or current directory for", " files that match the filespec, but also in all its subdirectories, and", " all their subdirectories, etc.", " ", "/RENAME-TO:name", " Tells C-Kermit to rename each source file that is sent successfully to", " the given name (usually you should include \\v(filename) in the new name,", " which is replaced by the original filename.", " ", "/MOVE-TO:directory", " Tells C-Kermit to move each source file that is sent successfully to", " the given directory.", " ", "/STARTING:number", " Starts sending the file from the given byte position.", " SEND /STARTING:n filename is equivalent to PSEND filename n.", " ", "/SUBJECT:text", " Specifies the subject of an email message, to be used with /MAIL. If the", " text contains spaces, it must be enclosed in braces.", " ", "/MAIL:address", " Sends the file as e-mail to the given address; use with /SUBJECT:.", " ", "/PRINT:options", " Sends the file to be printed, with optional options for the printer.", " ", #ifdef CK_XYZ "/PROTOCOL:name", " Uses the given protocol to send the file (Kermit, Zmodem, etc) for this", " transfer without changing global protocol.", " ", #endif /* CK_XYZ */ "/AFTER:date-time", #ifdef VMS " Specifies that only those files created after the given date-time are", #else " Specifies that only those files modified after the given date-time are", #endif /* VMS */ " to be sent. HELP DATE for info about date-time formats.", " ", "/BEFORE:date-time", #ifdef VMS " Specifies that only those files modified before the given date-time", #else " Specifies that only those files modified before the given date-time", #endif /* VMS */ " are to be sent.", " ", "/NOT-AFTER:date-time", #ifdef VMS " Specifies that only those files modified at or before the given date-time", #else " Specifies that only those files modified at or before the given date-time", #endif /* VMS */ " are to be sent.", " ", "/NOT-BEFORE:date-time", #ifdef VMS " Specifies that only those files modified at or after the given date-time", #else " Specifies that only those files modified at or after the given date-time", #endif /* VMS */ " are to be sent.", " ", "/LARGER-THAN:number", " Specifies that only those files longer than the given number of bytes are", " to be sent.", " ", "/SMALLER-THAN:number", " Specifies that only those files smaller than the given number of bytes are", " to be sent.", " ", "/EXCEPT:pattern", " Specifies that any files whose names match the pattern, which can be a", " regular filename, or may contain \"*\" and/or \"?\" metacharacters,", " are not to be sent. To specify multiple patterns (up to 8), use outer", " braces around the group, and inner braces around each pattern:", " ", " /EXCEPT:{{pattern1}{pattern2}...}", " ", "/TYPE:{ALL,TEXT,BINARY}", " Send only files of the given type (see SET FILE SCAN).", " ", "/LISTFILE:filename", " Specifies the name of a file that contains the list of names of files", " that are to be sent. The filenames should be listed one name per line", " in this file (but a name can contain wildcards).", " ", "Also see HELP RECEIVE, HELP GET, HELP SERVER, HELP REMOTE.", ""}; static char *hmxxrc[] = { "Syntax: RECEIVE (or R) [ switches... ] [ as-name ]", " Wait for a file to arrive from the other Kermit, which must be given a", " SEND command. If the optional as-name is given, the incoming file or", " files are stored under that name, otherwise it will be stored under", #ifndef CK_TMPDIR " the name it arrives with.", #else #ifdef OS2 " the name it arrives with. If the filespec denotes a disk and/or", " directory, the incoming file or files will be stored there.", #else " the name it arrives with. If the filespec denotes a directory, the", " incoming file or files will be placed in that directory.", #endif /* OS2 */ #endif /* CK_TMPDIR */ " ", "Optional switches include:", " ", "/AS-NAME:text", " Specifies \"text\" as the name to store the incoming file under.", " You can also specify the as-name as a filename on the command line.", " ", "/BINARY", " Skips text-mode conversions unless the incoming file arrives with binary", " attribute", " ", "/COMMAND", " Receives the file into the standard input of a command, rather than saving", " it on disk. The /AS-NAME or the \"filename\" on the RECEIVE command line", " is interpreted as the name of a command.", " ", "/EXCEPT:pattern", " Specifies that any files whose names match the pattern, which can be a", " regular filename, or may contain \"*\" and/or \"?\" metacharacters,", " are to be refused. To specify multiple patterns (up to 8), use outer", " braces around the group, and inner braces around each pattern:", " ", " /EXCEPT:{{pattern1}{pattern2}...}", " ", "/FILENAMES:{CONVERTED,LITERAL}", " Overrides the global SET FILE NAMES setting for this transfer only.", " ", "/FILTER:command", " Causes the incoming file to passed through the given command (standard", " input/output filter) before being written to disk.", " ", #ifdef VMS "/IMAGE", " Receives the file in image mode.", " ", #endif /* VMS */ #ifdef CK_LABELED "/LABELED", " Specifies labeled transfer mode.", " ", #endif /* CK_LABELED */ "/MOVE-TO:directory-name", " Specifies that each file that arrives should be moved to the specified", " directory after, and only if, it has been received successfully.", " ", "/PATHNAMES:{OFF,ABSOLUTE,RELATIVE,AUTO}", " Overrides the global SET RECEIVE PATHNAMES setting for this transfer.", " ", "/PIPES:{ON,OFF}", " Overrides the TRANSFER PIPES setting for this command only. ON allows", " reception of files with names like \"!tar xf -\" to be automatically", " directed to a pipeline.", " ", "/PROTOCOL:name", " Use the given protocol to receive the incoming file(s).", " ", "/QUIET", " When receiving in local mode, this suppresses the file-transfer display.", " ", "/RECURSIVE", " Equivalent to /PATHNAMES:RELATIVE.", " ", "/RENAME-TO:string", " Specifies that each file that arrives should be renamed as specified", " after, and only if, it has been received successfully. The string should", " normally contain variables like \\v(filename) or \\v(filenum).", " ", "/TEXT", " Forces text-mode conversions unless the incoming file has the binary", " attribute", " ", "/TRANSPARENT", " Inhibits character-set translation of incoming text files for the duration", " of the RECEIVE command without affecting subsequent commands.", " ", "Also see HELP SEND, HELP GET, HELP SERVER, HELP REMOTE.", "" }; #ifndef NORESEND static char *hmxxrsen = "\ Syntax: RESEND filespec [name]\n\n\ Resends the file or files, whose previous transfer was interrupted.\n\ Picks up from where previous transfer left off, IF the receiver kept the\n\ partially received file. Works only for binary-mode transfers.\n\ Requires file-transfer partner to support recovery. Synonym: REPUT."; static char *hmxxrget = "\ Syntax: REGET filespec\n\n\ Ask a server to RESEND a file to C-Kermit."; static char *hmxxpsen = "\ Syntax: PSEND filespec position [name]\n\n\ Just like SEND, except sends the file starting at the given byte position."; #endif /* NORESEND */ #ifndef NOMSEND static char *hmxxmse[] = { "Syntax: MSEND [ switches... ] filespec [ filespec [ ... ] ]", " Sends the files specified by the filespecs. One or more filespecs may be", " listed, separated by spaces. Any or all filespecs may contain wildcards", " and they may be in different directories. Alternative names cannot be", " given. Switches include /BINARY /DELETE /MAIL /PROTOCOL /QUIET /RECOVER", " /TEXT /TYPE; see HELP SEND for descriptions.", "" }; #endif /* NOMSEND */ static char *hmxxadd[] = { #ifndef NOMSEND "ADD SEND-LIST filespec [ [ ] ]", " Adds the specified file or files to the current SEND list. Use SHOW", " SEND-LIST and CLEAR SEND-LIST to display and clear the list; use SEND", " by itself to send the files from it.", " ", #endif /* NOMSEND */ #ifdef PATTERNS "ADD BINARY-PATTERNS [ [ ... ] ]", " Adds the pattern(s), if any, to the SET FILE BINARY-PATTERNS list.", " ", "ADD TEXT-PATTERNS [ [ ... ] ]", " Adds the pattern(s), if any, to the SET FILE TEXT-PATTERNS list.", " Use SHOW PATTERNS to see the lists. See HELP SET FILE for further info.", #endif /* PATTERNS */ ""}; static char *hmxxremv[] = { #ifdef PATTERNS "REMOVE BINARY-PATTERNS [ [ ... ] ]", " Removes the pattern(s), if any, from the SET FILE BINARY-PATTERNS list", " ", "REMOVE TEXT-PATTERNS [ [ ... ] ]", " Removes the given patterns from the SET FILE TEXT-PATTERNS list.", " Use SHOW PATTERNS to see the lists. See HELP SET FILE for further info.", #endif /* PATTERNS */ ""}; #endif /* NOXFER */ #ifndef NOSERVER static char *hmxxser = "Syntax: SERVER\n\ Enter server mode on the current connection. All further commands\n\ are taken in packet form from the other Kermit program. Use FINISH,\n\ BYE, or REMOTE EXIT to get C-Kermit out of server mode."; #endif /* NOSERVER */ static char *hmhset[] = { " The SET command establishes communication, file, scripting, or other", " parameters. The SHOW command can be used to display the values of", " SET parameters. Help is available for each individual parameter;", " type HELP SET ? to see what's available.", "" }; #ifndef NOSETKEY static char *hmhskey[] = { "Syntax: SET KEY k text", "Or: SET KEY CLEAR", " Configure the key whose \"scan code\" is k to send the given text when", " pressed during CONNECT mode. SET KEY CLEAR restores all the default", " key mappings. If there is no text, the default key binding is restored", #ifndef NOCSETS " for the key k. SET KEY mappings take place before terminal character-set", " translation.", #else " the key k.", #endif /* NOCSETS */ #ifdef OS2 " ", " The text may contain \"\\Kverbs\" to denote actions, to stand for DEC", " keypad, function, or editing keys, etc. For a list of available keyboard", " verbs, type SHOW KVERBS.", #endif /* OS2 */ " ", " To find out the scan code and mapping for a particular key, use the", " SHOW KEY command.", ""}; #endif /* NOSETKEY */ static char *hmxychkt[] = { "Syntax: SET BLOCK-CHECK number", " ", "Type of block check to be used for error detection on file-transfer", "packets: 1, 2, 3, 4, or 5. This command must be given to the file", "sender prior to the transfer.", " ", "Type 1 is standard and supported by all Kermit protocol implementations,", " but it's only a 6-bit checksum, represented in a single printable ASCII", " character. It's fine for reliable connections (error-correcting modems,", " TCP/IP, etc) but type 3 is recommended for connections where errors can", " occur.", " ", "Type 2 is a 12-bit checksum represented in two printable characters.", " ", "Type 3 is a 16-bit cyclic redundancy check, the strongest error", " detection method supported by Kermit protocol, represented in three", " printable characters.", " ", "Type 4 (alias \"BLANK-FREE-2\") is a 12-bit checksum guaranteed to", " contain no blanks in its representation; this is needed for connections", " where trailing blanks are stripped from incoming lines of text.", " ", "Type 5 (alias \"FORCE-3\") means to force a Type 3 block check on", " every packet, including the first packet, which normally has a type 1", " block check. This is for use in critical applications on noisy", " connections. As with types 2, 3, and 4, if the Kermit file", " transfer partner does not support this type, the transfer fails", " immediately at the beginning of the transfer.", "" }; static char * hmxydeb[] = { "Syntax: SET DEBUG { SESSION, ON, OFF, TIMESTAMP, MESSAGES }", " ", "SET DEBUG ON", #ifdef DEBUG " Opens a debug log file named debug.log in the current directory.", " Use LOG DEBUG if you want specify a different log file name or path.", #else " (Has no effect in this version of Kermit.)", #endif /* DEBUG */ " ", "SET DEBUG OFF", " Stops debug logging and session debugging.", " ", "SET DEBUG SESSION", #ifndef NOLOCAL " Displays control and 8-bit characters symbolically during CONNECT mode.", " Equivalent to SET TERMINAL DEBUG ON.", #else " (Has no effect in this version of Kermit.)", #endif /* NOLOCAL */ " ", "SET DEBUG TIMESTAMP { ON, OFF }", " Enables/Disables timestamps on debug log entries.", " ", "SET DEBUG MESSAGES { ON, OFF, STDERR } [C-Kermit 9.0]", " Enables/Disables messages printed by the DEBUG command.", " SET DEBUG OFF causes DEBUG messages not to be printed.", " SET DEBUG ON sends DEBUG messages to standard output (stdout);", " SET DEBUG STDERR sends DEBUG messages to standard error (stderr);", "" }; #ifdef CK_SPEED static char *hmxyqctl[] = { "Syntax: SET CONTROL-CHARACTER { PREFIXED, UNPREFIXED } { ..., ALL }", " ", " is the numeric ASCII code for a control character 1-31,127-159,255." , " The word \"ALL\" means all characters in this range.", " ", " PREFIXED means the given control character must be converted to a", " printable character and prefixed, the default for all control characters.", " ", " UNPREFIXED means you think it is safe to send the given control", " character as-is, without a prefix. USE THIS OPTION AT YOUR OWN RISK!", " ", " SHOW CONTROL to see current settings. SET CONTROL PREFIXED ALL is", " recommended for safety. You can include multiple values in one", " command, separated by spaces.", "" }; #endif /* CK_SPEED */ #ifndef NODIAL static char *hxymodm[] = { "Syntax: SET MODEM ...", " ", "Note: Many of the SET MODEM parameters are configured automatically when", "you SET MODEM TYPE, according to the modem's capabilities. SHOW MODEM to", "see them. Also see HELP DIAL and HELP SET DIAL.", " ", "SET MODEM TYPE ", " Tells Kermit which kind of modem you have, so it can issue the", " appropriate modem-specific commands for configuration, dialing, and", " hanging up. For a list of the modem types known to Kermit, type \"set", " modem type ?\". The default modem type is GENERIC, which should work", " with any AT command-set modem that is configured for error correction,", " data compression, and hardware flow control. Use SET MODEM TYPE NONE", " for direct serial, connections. Use SET MODEM TYPE USER-DEFINED to use", " a type of modem that is not built in to Kermit, and then use SET MODEM", " CAPABILITIES, SET MODEM, DIAL-COMMAND, and SET MODEM COMMAND to tell", " Kermit how to configure and control it.", " ", "SET MODEM CAPABILITIES ", " Use this command for changing Kermit's idea of your modem's capabilities,", " for example, if your modem is supposed to have built-in error correction", " but in fact does not. Also use this command to define the capabilities", " of a USER-DEFINED modem. Capabilities are:", " ", " AT AT-commands", " DC data-compression", " EC error-correction", " HWFC hardware-flow", " ITU v25bis-commands", " SWFC software-flow", " KS kermit-spoof", " SB speed-buffering", " TB Telebit", " ", "SET MODEM CARRIER-WATCH { AUTO, ON, OFF }", " Synonym for SET CARRIER-WATCH (q.v.)", " ", "SET MODEM COMPRESSION { ON, OFF }", " Enables/disables the modem's data compression feature, if any.", " ", "SET MODEM DIAL-COMMAND ", " The text replaces Kermit's built-in modem dialing command. It must", " include '%s' (percent s) as a place-holder for the telephone numbers", " given in your DIAL commands.", " ", "SET MODEM ERROR-CORRECTION { ON, OFF }", " Enables/disables the modem's error-correction feature, if any.", " ", "SET MODEM ESCAPE-CHARACTER number", " Numeric ASCII value of modem's escape character, e.g. 43 for '+'.", " For Hayes-compatible modems, Kermit uses three copies, e.g. \"+++\".", " ", "SET MODEM FLOW-CONTROL {AUTO, NONE, RTS/CTS, XON/XOFF}", " Selects the type of local flow control to be used by the modem.", " ", "SET MODEM HANGUP-METHOD { MODEM-COMMAND, RS232-SIGNAL, DTR }", " How hangup operations should be done. MODEM-COMMAND means try to", " escape back to the modem's command processor and give a modem-specific", " hangup command. RS232-SIGNAL means turn off the DTR signal. DTR is a", " synonym for RS232-SIGNAL.", " ", "SET MODEM KERMIT-SPOOF {ON, OFF}", " If the selected modem type supports the Kermit protocol directly,", " use this command to turn its Kermit protocol function on or off.", " ", "SET MODEM MAXIMUM-SPEED ", " Specify the maximum interface speed for the modem.", " ", "SET MODEM NAME ", " Descriptive name for a USER-DEFINED modem.", " ", "SET MODEM SPEAKER {ON, OFF}", " Turns the modem's speaker on or off during dialing.", " ", "SET MODEM SPEED-MATCHING {ON, OFF}", " ON means that C-Kermit changes its serial interface speed to agree with", " the speed reported by the modem's CONNECT message, if any. OFF means", " Kermit should not change its interface speed.", " ", "SET MODEM VOLUME {LOW, MEDIUM, HIGH}", " Selects the desired modem speaker volume for when the speaker is ON.", " ", "SET MODEM COMMAND commands are used to override built-in modem commands for", "each modem type, or to fill in commands for the USER-DEFINED modem type.", "Omitting the optional [ text ] restores the built-in modem-specific command,", "if any:", " ", "SET MODEM COMMAND AUTOANSWER {ON, OFF} [ text ]", " Modem commands to turn autoanswer on and off.", " ", "SET MODEM COMMAND COMPRESSION {ON, OFF} [ text ]", " Modem commands to turn data compression on and off.", " ", "SET MODEM COMMAND ERROR-CORRECTION {ON, OFF} [ text ]", " Modem commands to turn error correction on and off.", " ", "SET MODEM COMMAND HANGUP [ text ]", " Command that tells the modem to hang up the connection.", " ", "SET MODEM COMMAND IGNORE-DIALTONE [ text ]", " Command that tells the modem not to wait for dialtone before dialing.", " ", "SET MODEM COMMAND INIT-STRING [ text ]", " The 'text' is a replacement for C-Kermit's built-in initialization command", " for the modem.", " ", "SET MODEM COMMAND PREDIAL-INIT [ text ]", " A second INIT-STRING that is to be sent to the modem just prior to \ dialing.", " ", "SET MODEM COMMAND HARDWARE-FLOW [ text ]", " Modem command to enable hardware flow control (RTS/CTS) in the modem.", " ", "SET MODEM COMMAND SOFTWARE-FLOW [ text ]", " Modem command to enable local software flow control (Xon/Xoff) in modem.", " ", "SET MODEM COMMAND SPEAKER { ON, OFF } [ text ]", " Modem command to turn the modem's speaker on or off.", " ", "SET MODEM COMMAND NO-FLOW-CONTROL [ text ]", " Modem command to disable local flow control in the modem.", " ", "SET MODEM COMMAND PULSE [ text ]", " Modem command to select pulse dialing.", " ", "SET MODEM COMMAND TONE [ text ]", " Modem command to select tone dialing.", " ", "SET MODEM COMMAND VOLUME { LOW, MEDIUM, HIGH } [ text ]", " Modem command to set the modem's speaker volume.", ""}; static char *hmxydial[] = { "The SET DIAL command establishes or changes all parameters related to", "dialing the telephone. Also see HELP DIAL and HELP SET MODEM. Use SHOW", "DIAL to display all of the SET DIAL values.", " ", "SET DIAL COUNTRY-CODE ", " Tells Kermit the telephonic country-code of the country you are dialing", " from, so it can tell whether a portable-format phone number from your", " dialing directory will result in a national or an international call.", " Examples: 1 for USA, Canada, Puerto Rico, etc; 7 for Russia, 39 for Italy,", " 351 for Portugal, 47 for Norway, 44 for the UK, 972 for Israel, 81 for", " Japan, ...", " ", " If you have not already set your DIAL INTL-PREFIX and LD-PREFIX, then this", " command sets default values for them: 011 and 1, respectively, for country", " code 1; 00 and 0, respectively, for all other country codes. If these are", " not your true international and long-distance dialing prefixes, then you", " should follow this command by DIAL INTL-PREFIX and LD-PREFIX to let Kermit", " know what they really are.", " ", "SET DIAL AREA-CODE [ ]", " Tells Kermit the area or city code that you are dialing from, so it can", " tell whether a portable-format phone number from the dialing directory is", " local or long distance. Be careful not to include your long-distance", " dialing prefix as part of your area code; for example, the area code for", " central London is 171, not 0171.", " ", "SET DIAL CONFIRMATION {ON, OFF}", " Kermit does various transformations on a telephone number retrieved from", " the dialing directory prior to dialing (use LOOKUP to see them).", " In case the result might be wrong, you can use SET DIAL CONFIRM ON to have", " Kermit ask you if it is OK to dial the number, and if not, to let you type", " in a replacement.", " ", "SET DIAL CONNECT { AUTO, ON, OFF }", " Whether to CONNECT (enter terminal mode) automatically after successfully", " dialing. ON means to do this; OFF means not to. AUTO (the default) means", " do it if the DIAL command was given interactively, but don't do it if the", " DIAL command was issued from a macro or command file. If you specify ON", " or AUTO, you may follow this by one of the keywords VERBOSE or QUIET, to", " indicate whether the verbose 4-line 'Connecting...' message is to be", " displayed if DIAL succeeds and Kermit goes into CONNECT mode.", " ", "SET DIAL CONVERT-DIRECTORY {ASK, ON, OFF}", " The format of Kermit's dialing directory changed in version 5A(192). This", " command tells Kermit what to do when it encounters an old-style directory:", " ASK you whether to convert it, or convert it automatically (ON), or leave", " it alone (OFF). Old-style directories can still be used without", " conversion, but the parity and speed fields are ignored.", " ", "SET DIAL DIRECTORY [ filename [ filename [ filename [ ... ] ] ] ]", " The name(s) of your dialing directory file(s). If you do not supply any", " filenames, the dialing directory feature is disabled and all numbers are", " dialed literally as given in the DIAL command. If you supply more than", " one directory, all of them are searched.", " ", "SET DIAL SORT {ON, OFF}", " When multiple entries are obtained from your dialing directory, they are", " sorted in \"cheapest-first\" order. If this does not produce the desired", " effect, SET DIAL SORT OFF to disable sorting, and the numbers will be", " dialed in the order in which they were found.", " ", "SET DIAL DISPLAY {ON, OFF}", " Whether to display dialing progress on the screen; default is OFF.", " ", "SET DIAL HANGUP {ON, OFF}", " Whether to hang up the phone prior to dialing; default is ON.", " ", "SET DIAL IGNORE-DIALTONE {ON, OFF}", " Whether to ignore dialtone when dialing; default is OFF.", " ", #ifndef NOSPL "SET DIAL MACRO [ name ]", " Specify the name of a macro to execute on every phone number dialed, just", " prior to dialing it, in order to perform any last-minute alterations.", " ", #endif /* NOSPL */ "SET DIAL METHOD {AUTO, DEFAULT, TONE, PULSE}", " Whether to use the modem's DEFAULT dialing method, or to force TONE or", " PULSE dialing. AUTO (the default) means to choose tone or pulse dialing", " based on the country code. (Also see SET DIAL TONE-COUNTRIES and SET DIAL", " PULSE-COUNTRIES.)", " ", "SET DIAL PACING number", " How many milliseconds to pause between sending each character to the modem", " dialer. The default is -1, meaning to use the number from the built-in", " modem database.", " ", "SET DIAL PULSE-COUNTRIES [ cc [ cc [ ... ] ] ]", " Sets the list of countries in which pulse dialing is required. Each cc", " is a country code.", " ", "SET DIAL TEST { ON, OFF }", " OFF for normal dialing. Set to ON to test dialing procedures without", " actually dialing.", " ", "SET DIAL TONE-COUNTRIES [ cc [ cc [ ... ] ] ]", " Sets the list of countries in which tone dialing is available. Each cc", " is a country code.", " ", "SET DIAL TIMEOUT number", " How many seconds to wait for a dialed call to complete. Use this command", " to override the DIAL command's automatic timeout calculation. A value", " of 0 turns off this feature and returns to Kermit's automatic dial", " timeout calculation.", " ", "SET DIAL RESTRICT { INTERNATIONAL, LOCAL, LONG-DISTANCE, NONE }", " Prevents placing calls of the type indicated, or greater. For example", " SET DIAL RESTRICT LONG prevents placing of long-distance and international", " calls. If this command is not given, there are no restrictions. Useful", " when dialing a list of numbers fetched from a dialing directory.", " ", "SET DIAL RETRIES ", " How many times to redial each number if the dialing result is busy or no", " no answer, until the call is successfully answered. The default is 0", " because automatic redialing is illegal in some countries.", " ", "SET DIAL INTERVAL ", " How many seconds to pause between automatic redial attempts; default 10.", " ", "The following commands apply to all phone numbers, whether given literally", "or found in the dialing directory:", " ", "SET DIAL PREFIX [ text ]", " Establish a prefix to be applied to all phone numbers that are dialed,", " for example to disable call waiting.", " ", "SET DIAL SUFFIX [ text ]", " Establish a suffix to be added after all phone numbers that are dialed.", " ", "The following commands apply only to portable-format numbers obtained from", "the dialing directory; i.e. numbers that start with a \"+\" sign and", "country code, followed by area code in parentheses, followed by the phone", "number.", " ", "SET DIAL LC-AREA-CODES [ ]", " Species a list of area codes to which dialing is local, i.e. does not", " require the LD-PREFIX. Up to 32 area codes may be listed, separated by", " spaces. Any area codes in this list will be included in the final dial", " string so do not include your own area code if it should not be dialed.", " ", "SET DIAL LC-PREFIX [ ]", " Specifies a prefix to be applied to local calls made from portable dialing", " directory entries. Normally no prefix is used for local calls.", " ", "SET DIAL LC-SUFFIX [ ]", " Specifies a suffix to be applied to local calls made from portable dialing", " directory entries. Normally no suffix is used for local calls.", " ", "SET DIAL LD-PREFIX [ ]", " Your long-distance dialing prefix, to be used with portable dialing", " directory entries that result in long-distance calls.", " ", "SET DIAL LD-SUFFIX [ ]", " Long-distance dialing suffix, if any, to be used with portable dialing", " directory entries that result in long-distance calls. This would normally", " be used for appending a calling-card number to the phone number.", " ", "SET DIAL FORCE-LONG-DISTANCE { ON, OFF }", " Whether to force long-distance dialing for calls that normally would be", " local. For use (e.g.) in France.", " ", "SET DIAL TOLL-FREE-AREA-CODE [ [ [ ... ] ] ]", " Tells Kermit the toll-free area code(s) in your country.", " ", "SET DIAL TOLL-FREE-PREFIX [ ]", " You toll-free dialing prefix, in case it is different from your long-", " distance dialing prefix.", " ", "SET DIAL INTL-PREFIX ", " Your international dialing prefix, to be used with portable dialing", " directory entries that result in international calls.", " ", "SET DIAL INTL-SUFFIX ", " International dialing suffix, if any, to be used with portable dialing", " directory entries that result in international calls.", " ", "SET DIAL PBX-OUTSIDE-PREFIX ", " Use this to tell Kermit how to get an outside line when dialing from a", " Private Branch Exchange (PBX).", " ", "SET DIAL PBX-EXCHANGE [ [ ... ] ]", " If PBX-OUTSIDE-PREFIX is set, then you can use this command to tell Kermit", " the leading digits of one or more local phone numbers that identify it as", " being on your PBX, so it can make an internal call by deleting those digits" , " from the phone number.", " ", "SET DIAL PBX-INTERNAL-PREFIX ", " If PBX-EXCHANGE is set, and Kermit determines from it that a call is", " internal, then this prefix, if any, is added to the number prior to", " \ dialing. Use this if internal calls from your PBX require a special prefix.", "" }; #endif /* NODIAL */ static char *hmxyflo[] = { "Syntax: SET FLOW [ switch ] value", " ", #ifndef NOLOCAL " Selects the type of flow control to use during file transfer, terminal", " connection, and script execution.", #else " Selects the type of flow control to use during file transfer.", #endif /* NOLOCAL */ " ", " Switches let you associate a particular kind of flow control with each", " kind of connection: /REMOTE, /MODEM, /DIRECT-SERIAL, /TCPIP, etc; type", " \"set flow ?\" for a list of available switches. Then whenever you make", " a connection, the associated flow-control is chosen automatically.", " The flow-control values are NONE, KEEP, XON/XOFF, and possibly RTS/CTS", " and some others; again, type \"set flow ?\" for a list. KEEP tells Kermit", " not to try to change the current flow-control method for the connection.", " ", " If you omit the switch and simply supply a value, this value becomes the", " current flow control type, overriding any default value that might have", " been chosen in your most recent SET LINE, SET PORT, or SET HOST, or other", " connection-establishment command.", " ", " Type SHOW FLOW-CONTROL to see the current defaults for each connection type" , " as well as the current connection type and flow-control setting. SHOW", " COMMUNICATIONS also shows the current flow-control setting.", ""}; static char *hmxyf[] = { "Syntax: SET FILE parameter value", " ", "Sets file-related parameters. Use SHOW FILE to view them. Also see SET", "(and SHOW) TRANSFER and PROTOCOL.", " ", #ifdef VMS "SET FILE TYPE { TEXT, BINARY, IMAGE, LABELED }", #else #ifdef STRATUS "SET FILE TYPE { TEXT, BINARY, LABELED }", #else #ifdef MAC "SET FILE TYPE { TEXT, BINARY, MACBINARY }", #else "SET FILE TYPE { TEXT, BINARY }", #endif /* STRATUS */ #endif /* MAC */ #endif /* VMS */ " How file contents are to be treated during file transfer in the absence", " of any other indication. TYPE can be TEXT for conversion of record format", " and character set, which is usually needed when transferring text files", " between unlike platforms (such as UNIX and Windows), or BINARY for no", " conversion if TRANSFER MODE is MANUAL, which is not the default. Use", " BINARY with TRANSFER MODE MANUAL for executable programs or binary data or", " whenever you wish to duplicate the original contents of the file, byte for" , " byte. In most modern Kermit programs, the file sender informs the receiver" , " of the file type automatically. However, when sending files from C-Kermit", " to an ancient or non-Columbia Kermit implementation, you might need to set", " the corresponding file type at the receiver as well.", " ", #ifdef VMS " FILE TYPE settings of TEXT and BINARY have no effect when sending files,", " since VMS C-Kermit determines each file's type automatically from its", " record format: binary for fixed, text for others. For incoming files,", " these settings are effective only in the absence of a file-type indication", " from the sender.", " ", " You may include an optional record-format after the word BINARY. This may", " be FIXED (the default) or UNDEFINED. UNDEFINED is used when you need to", " receive binary files in binary mode and have them stored with UNDEFINED", " record format, which is required by certain VMS applications.", " ", " Two additional VMS file types are also supported: IMAGE and LABELED.", " IMAGE means raw block i/o, no interference from RMS, applies to file", " transmission only, and overrides the normal automatica file type", " determination. LABELED means to send or interpret RMS attributes", " with the file.", " ", #else " When TRANSFER MODE is AUTOMATIC (as it is by default), various automatic", " methods (depending on the platform) are used to determine whether a file", " is transferred in text or binary mode; these methods (which might include", " content scan (see SET FILE SCAN below), filename pattern matching (SET FILE" , " PATTERNS), client/server \"kindred-spirit\" recognition, or source file", " record format) supersede the FILE TYPE setting but can, themselves, be", " superseded by including a /BINARY or /TEXT switch in the SEND, GET, or", " RECEIVE command.", " ", " When TRANSFER MODE is MANUAL, the automatic methods are skipped for sending" , " files; the FILE TYPE setting is used instead, which can be superseded on", " a per-command basis with a /TEXT or /BINARY switch.", #endif /* VMS */ " ", #ifndef NOXFER "SET FILE BYTESIZE { 7, 8 }", " Normally 8. If 7, Kermit truncates the 8th bit of all file bytes.", " ", #ifndef NOCSETS "SET FILE CHARACTER-SET name", " Tells the encoding of the local file, ASCII by default.", " The names ITALIAN, PORTUGUESE, NORWEGIAN, etc, refer to 7-bit ISO-646", " national character sets. LATIN1 is the 8-bit ISO 8859-1 Latin Alphabet 1", " for Western European languages.", " NEXT is the 8-bit character set of the NeXT workstation.", " The CPnnn sets are for PCs. MACINTOSH-LATIN is for the Macintosh.", #ifndef NOLATIN2 " LATIN2 is ISO 8859-2 for Eastern European languages that are written with", " Roman letters. Mazovia is a PC code page used in Poland.", #endif /* NOLATIN2 */ #ifdef CYRILLIC " KOI-CYRILLIC, CYRILLIC-ISO, and CP866 are 8-bit Cyrillic character sets.", " SHORT-KOI is a 7-bit ASCII coding for Cyrillic. BULGARIA-PC is a PC code", " page used in Bulgaria", #endif /* CYRILLIC */ #ifdef HEBREW " HEBREW-ISO is ISO 8859-8 Latin/Hebrew. CP862 is the Hebrew PC code page.", " HEBREW-7 is like ASCII with the lowercase letters replaced by Hebrew.", #endif /* HEBREW */ #ifdef GREEK " GREEK-ISO is ISO 8859-7 Latin/Greek. CP869 is the Greek PC code page.", " ELOT-927 is like ASCII with the lowercase letters replaced by Greek.", #endif /* GREEK */ #ifdef KANJI " JAPANESE-EUC, JIS7-KANJI, DEC-KANJI, and SHIFT-JIS-KANJI are Japanese", " Kanji character sets.", #endif /* KANJI */ #ifdef UNICODE " UCS-2 is the 2-byte form of the Universal Character Set.", " UTF-8 is the serialized form of the Universal Character Set.", #endif /* UNICODE */ " Type SET FILE CHAR ? for a complete list of file character sets.", " ", "SET FILE DEFAULT 7BIT-CHARACTER-SET", " When automatically switching among different kinds of files while sending", " this tells the character set to be used for 7-bit text files.", " ", "SET FILE DEFAULT 8BIT-CHARACTER-SET", " This tells the character set to be used for 8-bit text files when", " switching automatically among different kinds of files.", " ", #endif /* NOCSETS */ "SET FILE COLLISION option", " Tells what to do when a file arrives that has the same name as", " an existing file. The options are:", " BACKUP (default) - Rename the old file to a new, unique name and store", " the incoming file under the name it was sent with.", " OVERWRITE - Overwrite (replace) the existing file; doesn't work for", " a Kermit server unless you also tell it to ENABLE DELETE.", " APPEND - Append the incoming file to the end of the existing file.", " REJECT - Refuse and/or discard the incoming file (= DISCARD).", " RENAME - Give the incoming file a unique name.", " UPDATE - Accept the incoming file only if newer than the existing file.", " ", "SET FILE DESTINATION { DISK, PRINTER, SCREEN, NOWHERE }", " DISK (default): Store incoming files on disk.", " PRINTER: Send incoming files to SET PRINTER device.", " SCREEN: Display incoming files on screen (local mode only).", " NOWHERE: Do not put incoming files anywhere (use for calibration).", " ", "SET FILE DISPLAY option", " Selects the format of the file transfer display for local-mode file", " transfer. The choices are:", " ", " BRIEF A line per file, showing size, mode, status, and throughput.", " SERIAL One dot is printed for every K bytes transferred.", " CRT Numbers are continuously updated on a single screen line.", " This format can be used on any video display terminal.", #ifdef CK_CURSES " FULLSCREEN A fully formatted 24x80 screen showing lots of information.", " This requires a terminal or terminal emulator.", #endif /* CK_CURSES */ " NONE No file transfer display at all.", " ", "SET FILE DOWNLOAD-DIRECTORY [ ]", " The directory into which all received files should be placed. By default,", " received files go into your current directory.", " ", #endif /* NOXFER */ #ifdef CK_CTRLZ "SET FILE EOF { CTRL-Z, LENGTH }", " End-Of-File detection method, normally LENGTH. Applies only to text-mode", " transfers. When set to CTRL-Z, this makes the file sender treat the first", " Ctrl-Z in the input file as the end of file (EOF), and it makes the file", " receiver tack a Ctrl-Z onto the end of the output file if it does not", " already end with Ctrl-Z.", " ", #endif /* CK_CTRLZ */ "SET FILE END-OF-LINE { CR, CRLF, LF }", " Use this command to specify nonstandard line terminators for text files.", " ", #ifndef NOXFER "SET FILE INCOMPLETE { AUTO, KEEP, DISCARD }", " What to do with an incompletely received file: KEEP, DISCARD, or AUTO.", " AUTO (the default) means DISCARD if transfer is in text mode, KEEP if it", " is in binary mode.", " ", #ifdef VMS "SET FILE LABEL { ACL, BACKUP-DATE, NAME, OWNER, PATH } { ON, OFF }", " Tells which items to include (ON) or exclude (OFF) in labeled file", " transfers", " ", #else #ifdef OS2 "SET FILE LABEL { ARCHIVE, READ-ONLY, HIDDEN, SYSTEM, EXTENDED } { ON, OFF }", " Tells which items to include (ON) or exclude (OFF) in labeled file", " transfers.", " ", #endif /* OS2 */ #endif /* VMS */ #ifdef UNIX #ifdef DYNAMIC "SET FILE LISTSIZE number", " Changes the size of the internal wildcard expansion list. Use SHOW FILE", " to see the current size. Use this command to increase the size if you get", " a \"?Too many files\" error. Also see SET FILE STRINGSPACE.", " ", #endif /* DYNAMIC */ #endif /* UNIX */ "SET FILE NAMES { CONVERTED, LITERAL }", " File names are normally CONVERTED to \"common form\" during transmission", " (e.g. lowercase to uppercase, extra periods changed to underscore, etc).", " LITERAL means use filenames literally (useful between like systems). Also", " see SET SEND PATHNAMES and SET RECEIVE PATHNAMES.", " ", #ifdef UNIX "SET FILE OUTPUT { { BUFFERED, UNBUFFERED } [ size ], BLOCKING, NONBLOCKING }", " Lets you control the disk output buffer for incoming files. Buffered", " blocking writes are normal. Nonblocking writes might be faster on some", " systems but might also be risky, depending on the underlying file service.", " Unbuffered writes might be useful in critical applications to ensure that", " cached disk writes are not lost in a crash, but will probably also be", " slower. The optional size parameter after BUFFERED or UNBUFFERED lets you", " change the disk output buffer size; this might make a difference in", " performance.", " ", #endif /* UNIX */ #ifdef PATTERNS "SET FILE PATTERNS { ON, OFF, AUTO }", " ON means to use filename pattern lists to determine whether to send a file", " in text or binary mode. OFF means to send all files in the prevailing", " mode. AUTO (the default) is like ON if the other Kermit accepts Attribute", " packets and like OFF otherwise. FILE PATTERNS are used only if FILE SCAN", " is OFF (see SET FILE SCAN).", " ", "SET FILE BINARY-PATTERNS [ [ ... ] ]", " Zero or more filename patterns which, if matched, cause a file to be sent", " in binary mode when FILE PATTERNS are ON. HELP WILDCARDS for a description" , " of pattern syntax. SHOW PATTERNS to see the current file pattern lists.", " ", "SET FILE TEXT-PATTERNS [ [ ... ] ]", " Zero or more filename patterns which, if matched, cause a file to be sent", " in text mode when FILE PATTERNS is ON; if a file does not match a text or", " binary pattern, the prevailing SET FILE TYPE is used.", " ", #endif /* PATTERNS */ #ifdef VMS "SET FILE RECORD-LENGTH number", " Sets the record length for received files of type BINARY. Use this to", " receive VMS BACKUP savesets or other fixed-format files that do not use", " the default record length of 512.", " ", #endif /* VMS */ "SET FILE SCAN { ON [ size ], OFF }", " If TRANSFER MODE is AUTOMATIC and FILE SCAN is ON (as it is by default)", " Kermit peeks at the file's contents to see if it's text or binary. Use", " SET FILE SCAN OFF to disable file peeking, while still keeping TRANSFER", " MODE automatic to allow name patterns and other methods. The optional", " size is the number of file bytes to scan, 49152 by default. -1 means to", " scan the whole file. Also see SET FILE PATTERNS.", " ", #ifdef UNIX #ifdef DYNAMIC "SET FILE STRINGSPACE number", " Changes the size (in bytes) of the internal buffer that holds lists of", " filenames such as wildcard expansion lists. Use SHOW FILE to see the", " current size. Use this command to increase the size if you get a", " \"?String space exhausted\" error. Also see SET FILE LISTSIZE.", " ", #endif /* DYNAMIC */ #endif /* UNIX */ #ifdef UNICODE "SET FILE UCS BOM { ON, OFF }", " Whether to write a Byte Order Mark when creating a UCS-2 file.", " ", "SET FILE UCS BYTE-ORDER { BIG-ENDIAN, LITTLE-ENDIAN }", " Byte order to use when creating UCS-2 files, and to use when reading UCS-2", " files that do not start with a Byte Order Mark.", " ", #endif /* UNICODE */ "SET FILE WARNING { ON, OFF }", " SET FILE WARNING is superseded by the newer command, SET FILE", " COLLISION. SET FILE WARNING ON is equivalent to SET FILE COLLISION RENAME", " and SET FILE WARNING OFF is equivalent to SET FILE COLLISION OVERWRITE.", #endif /* NOXFER */ "" }; static char *hmxyhsh[] = { "Syntax: SET HANDSHAKE { NONE, XON, LF, BELL, ESC, CODE number }", " Character to use for half duplex line turnaround handshake during file", " transfer. C-Kermit waits for this character from the other computer", " before sending its next packet. Default is NONE; you can give one of the", " other names like BELL or ESC, or use SET HANDSHAKE CODE to specify the", " numeric code value of the handshake character. Type SET HANDSH ? for a", " complete list of possibilities.", "" }; #ifndef NOSERVER static char *hsetsrv[] = { "SET SERVER CD-MESSAGE {ON,OFF}", " Tells whether the server, after successfully executing a REMOTE CD", " command, should send the contents of the new directory's READ.ME", " (or similar) file to your screen.", " ", "SET SERVER CD-MESSAGE FILE name", " Tells the name of the file to be displayed as a CD-MESSAGE, such as", " READ.ME (SHOW SERVER tells the current CD-MESSAGE FILE name).", " To specify more than one filename to look for, use {{name1}{name2}..}.", " Synonym: SET CD MESSAGE FILE .", " ", "SET SERVER DISPLAY {ON,OFF}", " Tells whether local-mode C-Kermit during server operation should put a", " file transfer display on the screen. Default is OFF.", " ", "SET SERVER GET-PATH [ directory [ directory [ ... ] ] ]", " Tells the C-Kermit server where to look for files whose names it receives", " from client GET commands when the names are not fully specified pathnames.", " Default is no GET-PATH, so C-Kermit looks only in its current directory.", " ", "SET SERVER IDLE-TIMEOUT seconds", " Idle time limit while in server mode, 0 for no limit.", #ifndef OS2 " NOTE: SERVER IDLE-TIMEOUT and SERVER TIMEOUT are mutually exclusive.", #endif /* OS2 */ " ", "SET SERVER KEEPALIVE {ON,OFF}", " Tells whether C-Kermit should send \"keepalive\" packets while executing", " REMOTE HOST commands, which is useful in case the command takes a long", " time to produce any output and therefore might cause the operation to time", " out. ON by default; turn it OFF if it causes trouble with the client or", " slows down the server too much.", " ", "SET SERVER LOGIN [ username [ password [ account ] ] ]", " Sets up a username and optional password which must be supplied before", " the server will respond to any commands other than REMOTE LOGIN. The", " account is ignored. If you enter SET SERVER LOGIN by itself, then login", " is no longer required. Only one SET SERVER LOGIN command can be in effect", " at a time; C-Kermit does not support multiple user/password pairs.", " ", "SET SERVER TIMEOUT n", " Server command wait timeout interval, how often the C-Kermit server issues", " a NAK while waiting for a command packet. Specify 0 for no NAKs at all.", " Default is 0.", "" }; #endif /* NOSERVER */ static char *hmhrmt[] = { #ifdef NEWFTP "The REMOTE command sends file management instructions or other commands", "to a Kermit or FTP server. If you have a single connection, the command is", "directed to the server you are connected to; if you have multiple connections" , "the command is directed according to your GET-PUT-REMOTE setting.", #else "The REMOTE command sends file management instructions or other commands", "to a Kermit server. There should already be a Kermit running in server", "mode on the other end of the connection.", #endif /* NEWFTP */ "Type REMOTE ? to see a list of available remote commands. Type HELP REMOTE", "xxx to get further information about a particular remote command xxx.", " ", "All REMOTE commands except LOGIN and LOGOUT have R-command shortcuts;", "for example, RDIR for REMOTE DIR, RCD for REMOTE CD, etc.", " ", #ifdef NEWFTP #ifdef LOCUS "Also see: HELP SET LOCUS, HELP FTP, HELP SET GET-PUT-REMOTE.", #else "Also see: HELP FTP, HELP SET GET-PUT-REMOTE.", #endif /* LOCUS */ #else #ifdef LOCUS "Also see: HELP SET LOCUS.", #endif /* LOCUS */ #endif /* NEWFTP */ "" }; #ifndef NOSPL static char *ifhlp[] = { "Syntax: IF [NOT] condition commandlist", " ", "If the condition is (is not) true, do the commandlist. The commandlist", "can be a single command, or a list of commands separated by commas or", "enclosed in braces. The condition can be a single condition or a group of", "conditions separated by AND (&&) or OR (||) and enclosed in parentheses.", "If parentheses are used they must be surrounded by spaces. Examples:", " ", " IF EXIST oofa.txt ", " IF ( EXIST oofa.txt || = \\v(nday) 3 ) ", " IF ( EXIST oofa.txt || = \\v(nday) 3 ) { , , ... }", " ", "The conditions are:", " ", " SUCCESS - The previous command succeeded", " OK - Synonym for SUCCESS", " FAILURE - The previous command failed", " ERROR - Synonym for FAILURE", " FLAG - Succeeds if SET FLAG ON, fails if SET FLAG OFF", " BACKGROUND - C-Kermit is running in the background", #ifdef CK_IFRO " FOREGROUND - C-Kermit is running in the foreground", " REMOTE-ONLY - C-Kermit was started with the -R command-line option", #else " FOREGROUND - C-Kermit is running in the foreground", #endif /* CK_IFRO */ " KERBANG - A Kerbang script is running", " ALARM - SET ALARM time has passed", " ASKTIMEOUT - The most recent ASK, ASKQ, GETC, or GETOK timed out", " EMULATION - Succeeds if executed while in CONNECT mode", #ifdef OS2 " TAPI - Current connection is via a Microsoft TAPI device", #endif /* OS2 */ " ", " MS-KERMIT - Program is MS-DOS Kermit", " C-KERMIT - Program is C-Kermit", " WINDOWS - Program is Kermit 95", " GUI - Program runs in a GUI window", " ", " AVAILABLE CRYPTO - Encryption is available", " AVAILABLE KERBEROS4 - Kerberos 4 authentication is available", " AVAILABLE KERBEROS5 - Kerberos 5 authentication is available", " AVAILABLE NTLM - NTLM authentication is available", " AVAILABLE SRP - SRP authentication is available", " AVAILABLE SSL - SSL/TLS authentication is available", " MATCH string pattern - Succeeds if string matches pattern", #ifdef CKFLOAT " FLOAT number - Succeeds if floating-point number", #endif /* CKFLOAT */ " COMMAND word - Succeeds if word is built-in command", " DEFINED variablename or macroname - The named variable or macro is defined", " DECLARED arrayname - The named array is declared", " NUMERIC variable or constant - The variable or constant is numeric", " FUNCTION name - The name is of a built-in function", " EXIST filename - The named file exists", " ABSOLUTE filename - The filename is absolute, not relative", " BINARY filename - The file is a binary regular file", " TEXT filename - The file is a text regular file", #ifdef CK_TMPDIR " DIRECTORY string - The string is the name of a directory", #endif /* CK_TMPDIR */ #ifdef UNIX " LINK string - The string is a symbolic link", #endif /* UNIX */ " READABLE filename - Succeeds if the file is readable", " WRITEABLE filename - Succeeds if the file is writeable", #ifdef ZFCDAT " NEWER file1 file2 - The 1st file is newer than the 2nd one", #endif /* ZFCDAT */ " OPEN { READ-FILE,SESSION-LOG,...} - The given file or log is open", #ifndef NOLOCAL " OPEN CONNECTION - A connection is open", #endif /* NOLOCAL */ " KBHIT - A key has been pressed", " TRUE - always succeeds", " FALSE - always fails", " ", " VERSION - equivalent to \"if >= \\v(version) ...\"", " ", " EQUAL s1 s2 - s1 and s2 (character strings or variables) are equal", " LLT s1 s2 - s1 is lexically (alphabetically) less than s2", " LLE s1 s2 - s1 is lexically less than or equal to s2", " LGT s1 s2 - s1 is lexically (alphabetically) greater than s2", " LGE s1 s2 - s1 is lexically greater than or equal to s2", " NEQ s1 s2 - s1 is not equal to s2", " ", " = n1 n2 - n1 and n2 (numbers or variables containing numbers) are equal", " < n1 n2 - n1 is arithmetically less than n2", " <= n1 n2 - n1 is arithmetically less than or equal to n2", " > n1 n2 - n1 is arithmetically greater than n2", " >= n1 n2 - n1 is arithmetically greater than or equal to n2", " != n1 n2 - n1 is not equal to n2", " ", " (number by itself) - fails if the number is 0, succeeds otherwise", " ", " (variable name) - If value numeric: succeeds if nonzero, fails if zero", " NOTE: variable name must not be the same as keyword", " ", "The IF command may be followed on the next line by an ELSE command. Example:", " ", " IF < \\%x 10 ECHO It's less", " ELSE echo It's not less", " ", "It can also include an ELSE part on the same line if braces are used:", " ", " IF < \\%x 10 { ECHO It's less } ELSE { ECHO It's not less }", " ", "Multiple commands can be enclosed in braces, separated by commas:", " ", " IF > \\%n \\m(max) { echo \\%n > old max \\m(max), .max := \\%n }", " ", "When braces are used the command may split onto multiple lines:", " ", " IF > \\%n \\m(max) {", " echo \"\\%n greater than old max \\m(max)\"", " .max := \\%n", " } else if < \\%n \\m(min) {", " echo \"\\%n less than old min \\m(min)\"", " .min := \\%n", " }", " ", "Also see HELP WILDCARD (for IF MATCH pattern syntax).", "" }; static char *hmxxeval[] = { "Syntax: EVALUATE variable expression", " Evaluates the expression and assigns its value to the given variable.", " The expression can contain numbers and/or numeric-valued variables or", " functions, combined with mathematical operators and parentheses in", " traditional notation. Operators include +-/*(), etc. Example:", " EVALUATE \\%n (1+1) * (\\%a / 3).", " ", " NOTE: Prior to C-Kermit 7.0, the syntax was \"EVALUATE expression\"", " (no variable), and the result was printed. Use SET EVAL { OLD, NEW }", " to choose the old or new behavior, which is NEW by default.", " ", "Alse see: HELP FUNCTION EVAL.", "" }; #endif /* NOSPL */ static char *hmxxexit[] = { "Syntax: EXIT (or QUIT) [ number [ text ] ]", " Exits from the Kermit program, closing all open files and devices.", " If a number is given it becomes Kermit's exit status code. If text is", " included, it is printed. Also see SET EXIT.", "" }; #ifndef NOSPL static char *ifxhlp[] = { "\ Syntax: XIF condition { commandlist } [ ELSE { commandlist } ]", " Obsolete. Same as IF (see HELP IF).", "" }; static char *forhlp[] = { "\ Syntax: FOR variablename initial-value final-value increment { commandlist }", " FOR loop. Execute the comma-separated commands in the commandlist the", " number of times given by the initial value, final value and increment.", " Example: FOR \\%i 10 1 -1 { pause 1, echo \\%i }", "" }; static char *whihlp[] = { "\ Syntax: WHILE condition { commandlist }", " WHILE loop. Execute the comma-separated commands in the bracketed", " commandlist while the condition is true. Conditions are the same as for", " IF commands.", "" }; static char *swihlp[] = { "Syntax: SWITCH { case-list }", " Selects from a group of commands based on the value of a variable.", " The case-list is a series of lines like these:", " ", " :x, command, command, ..., break", " ", " where \"x\" is a possible value for the variable. At the end of the", " case-list, you can put a \"default\" label to catch when the variable does", " not match any of the labels:", " ", " :default, command, command, ...", " ", "The case label \"x\" can be a character, a string, a variable, a function", "invocation, a pattern, or any combination of these. See HELP WILDCARDS", "for information about patterns.", ""}; static char *openhlp[] = { "Syntax: OPEN mode filename", " For use with READ and WRITE commands. Open the local file in the", " specified mode: READ, WRITE, or APPEND. !READ and !WRITE mean to read", " from or write to a system command rather than a file. Examples:", " ", " OPEN READ oofa.txt", " OPEN !READ sort foo.bar", "" }; static char *hxxask[] = { "Syntax: ASK [ switches ] variablename [ prompt ]", "Example: ASK \\%n { What is your name\\? }", " Issues the prompt and defines the variable to be whatever is typed in", " response, up to the terminating carriage return. Use braces to preserve", " leading and/or trailing spaces in the prompt.", " ", "Syntax: ASKQ [ switches ] variablename [ prompt ]", "Example: ASKQ \\%p { Password:}", " Like ASK except the response does not echo on the screen or, if specified", " it echoes as asterisks or other specified character.", " ", "Switches:", " /DEFAULT:text", " Text to supply if the user enters a blank response or the /TIMEOUT", " limit expired with no response.", " ", " /ECHO:char", " (ASKQ only) Character to be echoed each time the user presses a key", " corresponding to a printable character. This lets users see what they are", " doing when they are typing (e.g.) passwords, and makes editing easier.", " ", #ifdef OS2 " /POPUP", " The prompt and response dialog takes place in a text-mode popup.", " Kermit 95 only; in other C-Kermit versions /POPUP is ignored.", " ", #ifdef KUI " /GUI", " The prompt and response dialog takes place in a GUI popup.", " Kermit 95 only; this switch is ignored elsewhere", " ", #endif /* KUI */ #endif /* OS2 */ " /TIMEOUT:number", " If the response is not entered within the given number of seconds, the", " command fails. This is equivalent to setting ASK-TIMER to a positive", " number, except it applies only to this command. Also see SET ASK-TIMER.", " NOTE: If a /DEFAULT: value was also given, it is supplied automatically", " upon timeout and the command does NOT fail.", " ", " /QUIET", " Suppresses \"?Timed out\" message when /TIMEOUT is given and user doesn't", " respond within the time limit.", ""}; static char *hxxgetc[] = { "Syntax: GETC [ switches] [ variablename [ prompt ] ]", "Example: GETC \\%c { Type any character to continue...}", " Issues the prompt and sets the variable to the first character you type.", " Use braces to preserve leading and/or trailing spaces in the prompt.", " ", "Switches:", " /CHECK", " GETC /CHECK (no variable or prompt is given when /CHECK is used)", " succeeds if characters are waiting to be read and fails if not.", " ", " /QUIET", " In case of errors, no error message is issued.", " ", " /TIMEOUT:n", " Gives GETC a time limit of n seconds to wait for a character to appear;", " if no character appears within n seconds, GETC fails and (if a /QUIET", " switch was not given, an error message is printed.", /* "Also see SET ASK-TIMER.", */ ""}; static char *hmxytimer[] = { "Syntax: SET ASK-TIMER number", " For use with ASK, ASKQ, GETOK, and GETC. If ASK-TIMER is set to a number", " greater than 0, these commands will time out after the given number of", " seconds with no response. This command is \"sticky\", so to revert to", " \ untimed ASKs after a timed one, use SET ASK-TIMER 0. Also see IF ASKTIMEOUT.", ""}; static char *hxxdot[] = { "Syntax: . ", " Assigns the value to the variable in the manner indicated by the", " assignment operator:", " = Copies without evaluation (like DEFINE).", " := Copies with evaluation (like ASSIGN).", " ::= Copies with arithmetic evaluation (like EVALUATE).", ""}; static char *hxxdef[] = { "Syntax: DEFINE name [ definition ]", " Defines a macro or variable. Its value is the definition, taken", " literally. No expansion or evaluation of the definition is done. Thus", " if the definition includes any variable or function references, their", " names are included, rather than their values (compare with ASSIGN). If", " the definition is omitted, then the named variable or macro is undefined.", " If a variable of the same name already exists, its value is replaced by", " the new value.", " ", "A typical macro definition looks like this:", " ", " DEFINE name command, command, command, ...", " ", "for example:", " ", " DEFINE vax set parity even, set duplex full, set flow xon/xoff", " ", "which defines a Kermit command macro called 'vax'. The definition is a", "comma-separated list of Kermit commands. Use the DO command to execute", "the macro, or just type its name, followed optionally by arguments.", " ", "The definition of a variable can be anything at all, for example:", " ", " DEFINE \\%a Monday", " DEFINE \\%b 3", " ", "These variables can be used almost anywhere, for example:", " ", " ECHO Today is \\%a", " SET BLOCK-CHECK \\%b", "" }; static char *hxxass[] = { "Syntax: ASSIGN variablename string.", "Example: ASSIGN \\%a My name is \\%b.", " Assigns the current value of the string to the variable (or macro).", " The definition string is fully evaluated before it is assigned, so that", " the values of any variables that are contained are used, rather than their", " names. Compare with DEFINE. To illustrate the difference, try this:", " ", " DEFINE \\%a hello", " DEFINE \\%x \\%a", " ASSIGN \\%y \\%a", " DEFINE \\%a goodbye", " ECHO \\%x \\%y", " ", " This prints 'goodbye hello'.", "" }; static char *hxxdec[] = { "Syntax: DECREMENT variablename [ amount ]", " Decrement (subtract one from) the value of a variable if the current value", " is numeric. If an optional amount is specified (as a number, a variable,", " \ or an arithmetic expression that evaluates to a number, or any combination)", " the variable is decremented by that number instead of 1. The result is", " always an integer. If floating-point numbers are given, the result is", " truncated.", " ", "Examples: DECR \\%a, DECR days 7, DECR x \\%n, DECR sum \\%x+12", "" }; static char *hxxinc[] = { "Syntax: INCREMENT variablename [ number ]", " Increment (add one to) the value of a variable if the current value is", " numeric. If an optional amount is specified (as a number, a variable,", " \ or an arithmetic expression that evaluates to a number, or any combination)", " the variable is incremented by that number instead of 1. The result is", " always an integer. If floating-point numbers are given, the result is", " truncated.", " ", "Examples: INCR \\%a, INCR dollars 100, INCR size \\%n, INCR total \\%x/10", "" }; #endif /* NOSPL */ #ifdef ANYX25 #ifndef IBMX25 static char *hxxpad[] = { "Syntax: PAD command", "X.25 PAD commands:", " ", " PAD CLEAR - Clear the virtual call", " PAD STATUS - Return the status of virtual call", " PAD RESET - Send a reset packet", " PAD INTERRUPT - Send an interrupt packet", ""}; #endif /* IBMX25 */ static char *hxyx25[] = { "Syntax: SET X.25 option { ON [ data ], OFF }", " ", "X.25 call options:", " CLOSED-USER-GROUP { ON index, OFF }", " Enable or disable closed user group call, where index is the group", " index, 0 to 99.", " REVERSE-CHARGE { ON, OFF }", " Tell whether you want to reverse the charges for the call.", " CALL-USER-DATA { ON string, OFF }", " Specify call user-data for the X.25 call.", ""}; #endif /* ANYX25 */ static char *hxyprtr[] = { #ifdef PRINTSWI "Syntax: SET PRINTER [ switches ] [ name ]", " ", " Specifies the printer to be used for transparent-print, autoprint, and", " screen-dump material during terminal emulation, as well as for the PRINT", " command, plus various options governing print behavior.", " ", "Switches for specifying the printer by type:", " ", "/NONE", " Include this switch to specify that all printer actions should simply be", " skipped. Use this, for example, if you have no printer.", " ", "/DOS-DEVICE[:name]", " Include this to declare a DOS printer and to specify its name, such as", " PRN, LPT1, etc.", " ", #ifdef NT "/WINDOWS-QUEUE[:[queue-name]]", " Include this to declare a Windows printer and specify its queue name.", " Type question mark (?) after the colon (:) to see a list of known queue", " names. If the colon is absent, the switch indicates the currently", " selected printer is a Windows Print Queue. If the colon is provided", " and the name is absent, the Windows Print Queue chosen as the Default", " Printer is selected.", " ", #endif /* NT */ "/FILE[:name]", " Specifies that all printer material is to be appended to the named file,", " rather than being sent to a printer. If the file does not exist, it is", " created the first time any material is to be printed.", " ", "/PIPE[:name]", " Specifies that all printer material is to be sent as standard input to", " the program or command whose name is given. Example:", " ", " SET PRINTER /PIPE:{textps > lpt1}", " ", "If you give a printer name without specifying any of these switches, then it", "is assumed to be a DOS printer device or filename unless the name given", "(after removing enclosing braces, if any) starts with \"|\", \ in which case it", "is a pipe. Examples:", " ", " SET PRINTER LPT1 <-- DOS device", " SET PRINTER {| textps > lpt1} <-- Pipe", " ", "The next group of switches tells whether the printer is one-way or", "bidirectional (two-way):", " ", "/OUTPUT-ONLY", " Include this to declare the printer capable only of receiving material to", " be printed, but not sending anything back. This is the normal kind of", " printer, Kermit's default kind, and the opposite of /BIDIRECTIONAL.", " ", "/BIDIRECTIONAL", " Include this to declare the printer bidirectional. This is the opposite ", " of /OUTPUT-ONLY. You can also use this option with serial printers, even", " if they aren't bidirectional, in case you need to specify speed, flow", " control, or parity.", " ", "The next group applies only to bidirectional and/or serial printers:", " ", "/FLOW-CONTROL:{NONE,XON/XOFF,RTS/CTS,KEEP}", " Flow control to use with a serial bidirectional printer, default KEEP;", #ifdef NT " i.e. use whatever the Windows driver for the port normally uses.", #else " i.e. use whatever the OS/2 driver for the port normally uses.", #endif /* NT */ " ", "/PARITY:{NONE,EVEN,ODD,SPACE,MARK}", " Parity to use with a serial printer, default NONE; i.e. use 8 data bits", " and no parity. If you omit the colon and the keyword, NONE is selected.", " ", "/SPEED:number", " Interface speed, in bits per second, to use with a serial printer, such as", " 2400, 9600, 19200, etc. Type SET PRINTER /SPEED:? for a list of possible", " speeds.", " ", "The next group deals with print jobs -- how to identify them, how to start", "them, how to terminate them:", " ", "/TIMEOUT[:number]", " Used with host-directed transparent or auto printing, this is the number", " of seconds to wait after the host closes the printer before terminating", " the print job if the printer is not opened again during the specified", " amount of time.", " ", "/JOB-HEADER-FILE[:filename]", " The name of a file to be sent to the printer at the beginning of each", " print job, as a burst page, or to configure the printer. Normally no file", " is is sent.", " ", "/END-OF-JOB-STRING[:string]", " String of characters to be sent to the printer at the end of the print", " job, usually used to force the last or only page out of the printer. When", " such a string is needed, it usually consists of a single formfeed: \"set", " printer /end-of-job:{\\12}\". No end-of-job string is sent unless you", " specify one with this option. If the string contains any spaces or", " control characters (even in backslash notation, as above), enclose it in", " braces.", " ", "The next group is for use with printers that print only PostScript:", " ", "/POSTSCRIPT or /PS", " Indicates that Kermit should convert all text to PostScript before sending", " it to the printer. The fixed-pitch Courier-11 font is used.", " ", "/WIDTH:number", " Specifies the width of the page in characters. If this switch is not", " given, 80 is used.", " ", "/HEIGHT:number", " Specifies the height of the page in lines. If this switch is not given", " 66 is used.", " ", "/NOPOSTSCRIPT or /NOPS", " Indicates that Kermit should not convert all text to PostScript before", " sending it to the printer.", " ", "The final switch is for use with AutoPrint mode and Screen Dumps", " ", "/CHARACTER-SET:", " Specifies the character set used by the printer which may be different", " from both the character set used by the host and by the local computer.", " The default value is CP437.", " ", "SHOW PRINTER displays your current printer settings.", #else #ifdef UNIX "Syntax: SET PRINTER [ { |command, filename } ]", " Specifies the command (such as \"|lpr\") or filename to be used by the", " PRINT command. If a filename is given, each PRINT command appends to the", " given file. If the SET PRINTER argument contains spaces, it must be", " enclosed in braces, e.g. \"set printer {| lpr -Plaser}\". If the argument", " is omitted the default value is restored. SHOW PRINTER lists the current", " printer. See HELP PRINT for further info.", #else "Sorry, SET PRINTER not available yet.", #endif /* UNIX */ #endif /* PRINTSWI */ ""}; #ifdef OS2 #ifdef BPRINT static char *hxybprtr[] = { "Syntax: SET BPRINTER [ portname speed [ parity [ flow-control ] ] ]", " (Obsolete, replaced by SET PRINTER /BIDIRECTIONAL.)", ""}; #endif /* BPRINT */ #endif /* OS2 */ static char *hxyexit[] = { "Syntax: SET EXIT HANGUP { ON, OFF }", " When ON (which is the default), C-Kermit executes an implicit HANGUP and", " CLOSE command on the communications device or connection when it exits.", " When OFF, Kermit skips this sequence.", " ", "Syntax: SET EXIT MESSAGE { ON, OFF, STDERR }", " Allows the text (if any) from an EXIT command (see HELP EXIT) to be", " supressed (OFF), printed normally (ON, the default), or sent to STDERR.", " ", "Syntax: SET EXIT ON-DISCONNECT { ON, OFF }", " When ON, C-Kermit EXITs automatically when a network connection", " is terminated either by the host or by issuing a HANGUP command.", " ", "Syntax: SET EXIT STATUS number", #ifdef NOSPL " Set C-Kermit's program return code to the given number.", #else " Set C-Kermit's program return code to the given number, which can be a", " constant, variable, function result, or arithmetic expression.", #endif /* NOSPL */ " ", "Syntax: SET EXIT WARNING { ON, OFF, ALWAYS }", " When EXIT WARNING is ON, issue a warning message and ask for confirmation", " before EXITing if a connection to another computer might still be open.", " When EXIT WARNING is ALWAYS, confirmation is always requested. When OFF", " it is never requested. The default is ON.", "" }; #ifndef NOSPL static char *hxxpau[] = { "Syntax: PAUSE [ { number-of-seconds, hh:mm:ss } ]", "Example: PAUSE 3 or PAUSE 14:52:30", " Do nothing for the specified number of seconds or until the given time of", " day in 24-hour hh:mm:ss notation. If the time of day is earlier than the", " current time, it is assumed to be tomorrow. If no argument given, one", " second is used. The pause can be interrupted by typing any character on", " the keyboard unless SLEEP CANCELLATION is OFF. If interrupted, PAUSE", " fails, otherwise it succeeds. Synonym: SLEEP.", "" }; static char *hxxmsl[] = { "Syntax: MSLEEP [ number ]", "Example: MSLEEP 500", " Do nothing for the specified number of milliseconds; if no number given,", " 100 milliseconds.","" }; #endif /* NOSPL */ #ifndef NOPUSH extern int nopush; static char *hxxshe[] = { "Syntax: !, @, RUN, PUSH, or SPAWN, optionally followed by a command.", " Gives the command to the local operating system's command processor, and", " displays the results on the screen. If the command is omitted, enters the", " system's command line interpreter or shell; exit from it (the command for", " this is usually EXIT or QUIT or LOGOUT) to return to Kermit.", "" }; #endif /* NOPUSH */ #ifndef NOXMIT static char *hxxxmit[] = { "Syntax: TRANSMIT [ switches ] filename", " Sends the contents of a file, without any error checking or correction,", " to the computer on the other end of your SET LINE or SET HOST connection", " (or if C-Kermit is in remote mode, displays it on the screen). The", " filename is the name of a single file (no wildcards) to be sent or, if", " the /PIPE switch is included, the name of a command whose output is to be", " sent.", " ", " The file is sent according to your current FILE TYPE setting (BINARY or", " TEXT), which you can override with a /BINARY or /TEXT switch without", " changing the global setting. In text mode, it is sent a line at a time,", " with carriage return at the end of each line (as if you were typing it at", " your keyboard), and C-Kermit waits for a linefeed to echo before sending", " the next line; use /NOWAIT to eliminate the feedback requirement. In", " binary mode, it is sent a character at a time, with no feedback required.", " ", " Normally the transmitted material is echoed to your screen. Use SET", " TRANSMIT ECHO OFF or the /NOECHO switch to suppress echoing. Note that", " TRANSMIT /NOECHO /NOWAIT /BINARY is a special case, that more or less", " blasts the file out at full speed.", " ", #ifndef NOCSETS " Character sets are translated according to your current FILE and TERMINAL", " CHARACTER-SET settings when TRANSMIT is in text mode. Include /TRANSPARENT" , " to disable character-set translation in text mode (/TRANSPARENT implies", " /TEXT).", " ", #endif /* NOCSETS */ " There can be no guarantee that the other computer will receive the file", " correctly and completely. Before you start the TRANSMIT command, you", " must put the other computer in data collection mode, for example by", " starting a text editor. TRANSMIT may be interrupted by Ctrl-C. Synonym:", " XMIT. See HELP SET TRANSMIT for further information.", "" }; #endif /* NOXMIT */ #ifndef NOCSETS static char *hxxxla[] = { "Syntax: CONVERT file1 cs1 cs2 [ file2 ]", "Synonym: TRANSLATE", " Converts file1 from the character set cs1 into the character set cs2", " and stores the result in file2. The character sets can be any of", " C-Kermit's file character sets. If file2 is omitted, the translation", " is displayed on the screen. An appropriate intermediate character-set", " is chosen automatically, if necessary. Synonym: XLATE. Example:", " ", " CONVERT lasagna.txt latin1 utf8 lasagna-utf8.txt", " ", " Multiple files can be translated if file2 is a directory or device name,", " rather than a filename, or if file2 is omitted.", "" }; #endif /* NOCSETS */ #ifndef NOSPL static char *hxxwai[] = { "Syntax: WAIT { number-of-seconds, hh:mm:ss } [ ]", " ", "Examples:", " wait 5 cd cts", " wait 23:59:59 cd", " ", " Waits up to the given number of seconds or the given time of day for the", " specified item or event, which can be FILE, the name(s) of one or more", " modem signals, or nothing. If nothing is specified, WAIT acts like SLEEP.", " If one or more modem signal names are given, Kermit waits for the specified" , " modem signals to appear on the serial communication device.", " Sets FAILURE if the signals do not appear in the given time or interrupted", " from the keyboard during the waiting period.", " ", "Signals:", " cd = Carrier Detect;", " dsr = Dataset Ready;", " cts = Clear To Send;", " ri = Ring Indicate.", " ", "If you want Kermit to wait for a file event, then the syntax is:", " ", " WAIT ", " ", " Nesting is possible with {}()[]<> but not with quotes or apostrophes.", " ", "Returns integer:", " Number of words in source string.", " ", "Also see:", " HELP FUNCTION WORD", "" }; /* D O H F U N C -- Give help for a function */ int #ifdef CK_ANSIC dohfunc( int xx ) #else dohfunc(xx) int xx; #endif /* CK_ANSIC */ { /* int x; */ if (xx == -3) { return(hmsga(hmxxfunc)); } if (xx == FN_WORD) /* Long help message */ return(hmsga(hmfword)); printf("\n"); switch (xx) { case FN_IND: /* Index (of string 1 in string 2) */ case FN_RIX: /* Rindex (index from right) */ printf("\\f%sindex(s1,s2,n1,n2)\n\ s1 = string to look for.\n\ s2 = string to look in.\n\ n1 = optional 1-based starting position, default = 1.\n\ n2 = optional desired occurrence number, default = 1.\n", xx == FN_RIX ? "r" : "" ); printf("Returns integer:\n\ 1-based position of %smost occurrence of s1 in s2, ignoring the %smost\n\ (n1-1) characters in s2; returns 0 if s1 not found in s2.\n", xx == FN_IND ? "left" : "right", xx == FN_IND ? "left" : "right" ); break; case FN_COUNT: /* Count occurrences of s1 in s2 */ printf("\\fcount(s1,s2,n1)\n\ s1 = string or character to look for.\n\ s2 = string to look in.\n\ n1 = optional 1-based starting position, default = 1.\n"); printf("Returns integer:\n\ Number of occurrences of s1 in s2, 0 or more.\n"); break; case FN_SEARCH: /* Search for pattern */ case FN_RSEARCH: /* Search for pattern from right */ printf("\\f%ssearch(s1,s2,n1,n2)\n\ s1 = pattern to look for.\n\ s2 = string to look in.\n\ n1 = optional 1-based offset, default = 1.\n\ n2 = optional desired occurrence of match, default = 1.\n", xx == FN_RSEARCH ? "r" : "" ); printf("Returns integer:\n\ 1-based position of %smost match for s1 in s2, ignoring the %smost\n\ (n1-1) characters in s2; returns 0 if no match.\n", xx == FN_SEARCH ? "left" : "right", xx == FN_SEARCH ? "left" : "right" ); printf( " s1 is a \"floating pattern\"; see HELP PATTERNS for details.\n"); break; case FN_LEN: /* Length (of string) */ printf("\\flength(s1)\n\ s1 = string.\n"); printf("Returns integer:\n\ Length of string s1.\n"); break; case FN_LIT: /* Literal (don't expand the string) */ printf("\\fliteral(s1)\n\ s1 = string.\n"); printf("Returns string:\n\ s1 literally without evaluation.\n"); break; case FN_LOW: /* Lower (convert to lowercase) */ printf("\\flower(s1)\n\ s1 = string.\n"); printf("Returns string:\n\ s1 with uppercase letters converted to lowercase.\n"); break; case FN_MAX: /* Max (maximum) */ printf("\\fmaximum(n1,n2)\n\ n1 = integer.\n\ n2 = integer.\n"); printf("Returns integer:\n\ The greater of n1 and n2.\n"); break; case FN_MIN: /* Min (minimum) */ printf("\\fminimum(n1,n2)\n\ n1 = integer.\n\ n2 = integer.\n"); printf("Returns integer:\n\ The lesser of n1 and n2.\n"); break; case FN_MOD: /* Mod (modulus) */ printf("\\fmodulus(n1,n2)\n\ n1 = integer.\n\ n2 = integer.\n"); printf("Returns integer:\n\ The remainder after dividing n1 by n2.\n"); break; case FN_EVA: /* Eval (evaluate arith expression) */ printf("\\fevaluate(e)\n\ e = arithmetic expression in ordinary algebraic notation.\n"); printf("Returns integer:\n\ The result of evaluating the expression.\n"); break; case FN_SUB: /* Substr (substring) */ printf("\\fsubstring(s1,n1,n2)\n\ s1 = string.\n\ n1 = integer, 1-based starting position, default = 1.\n\ n2 = integer, length, default = length(s1) - n1 + 1.\n"); printf("Returns string:\n\ Substring of s1 starting at n1, length n2.\n"); break; case FN_UPP: /* Upper (convert to uppercase) */ printf("\\fupper(s1)\n\ s1 = string.\n"); printf("Returns string:\n\ s1 with lowercase letters converted to uppercase.\n"); break; case FN_REV: /* Reverse (a string) */ printf("\\freverse(s1)\n\ s1 = string.\n"); printf("Returns string:\n\ s1 with its characters in reverse order.\n"); break; case FN_REP: /* Repeat (a string) */ printf("\\frepeat(s1,n1)\n\ s1 = string.\n\ n1 = integer.\n"); printf("Returns string:\n\ s1 repeated n1 times.\n"); break; case FN_EXE: /* Execute (a macro) */ printf("\\fexecute(m1,a1,a2,a3,...)\n\ m1 = macro name.\n\ a1 = argument 1.\n\ a2 = argument 2, etc\n"); printf("Returns string:\n\ The return value of the macro (HELP RETURN for further info).\n"); break; case FN_LPA: /* LPAD (left pad) */ case FN_RPA: /* RPAD (right pad) */ printf("\\f%cpad(s1,n1,c1)\n\ s1 = string.\n\ n1 = integer.\n\ c1 = character, default = space.\n", xx == FN_LPA ? 'l' : 'r'); printf("Returns string:\n\ s1 %s-padded with character c1 to length n1.\n", xx == FN_LPA ? "left" : "right"); break; case FN_DEF: /* Definition of a macro, unexpanded */ printf("\\fdefinition(m1)\n\ m1 = macro name.\n"); printf("Returns string:\n\ Literal definition of macro m1.\n"); break; case FN_CON: /* Contents of a variable, ditto */ printf("\\fcontents(v1)\n\ v1 = variable name such as \\%%a.\n"); printf("Returns string:\n\ Literal definition of variable v1, evaluated one level only.\n"); break; case FN_FIL: /* Next file */ printf("\\fnextfile()\n"); printf("Returns string:\n\ Name of next file from list created by most recent \\f[r]files() or\n\ \\f[r]dir()invocation, or an empty string if there are no more files in\n\ the list.\n"); break; case FN_FC: /* File count */ printf("\\ffiles(f1[,&a]) - File list.\n\ f1 = file specification, possibly containing wildcards.\n\ &a = optional name of array to assign file list to.\n"); printf("Returns integer:\n\ The number of regular files that match f1. Use with \\fnextfile().\n"); break; case FN_CHR: /* Character (like BASIC CHR$()) */ printf("\\fcharacter(n1)\n\ n1 = integer.\n"); printf("Returns character:\n\ The character whose numeric code is n1.\n"); break; case FN_RIG: /* Right (like BASIC RIGHT$()) */ printf("\\fright(s1,n1)\n\ s1 = string.\n\ n1 = integer, default = length(s1).\n"); printf("Returns string:\n\ The rightmost n1 characters of string s1.\n"); break; case FN_LEF: /* Left (like BASIC LEFT$()) */ printf("\\fleft(s1,n1)\n\ s1 = string.\n\ n1 = integer, default = length(s1).\n"); printf("Returns string:\n\ The leftmost n1 characters of string s1.\n"); break; case FN_COD: /* Code value of character */ printf("\\fcode(s1)\n\ c1 = character.\n"); printf("Returns integer:\n\ The numeric code of the first character in string s1, or 0 if s1 empty.\n"); break; case FN_RPL: /* Replace */ printf("\\freplace(s1,s2,[s3[,n1[,n2]]])\n\ s1 = original string.\n\ s2 = match string.\n\ s3 = replacement string (may be empty).\n\ n1 = occurrence (if omitted or 0 does all occurrences).\n"); #ifdef RPLWORDMODE printf(" n2 = word mode \ (0 = ignore context; 1 = only if target is delimited).\n"); #endif /* RPLWORDMODE */ printf("Returns string:\n\ s1 with occurrence number n1 of s2 replaced by s3.\n\ If n1 = 0 or omitted, all occurrences are replaced.\n\ If n1 < 0, occurrences are counted from the right.\n"); break; case FN_FD: /* File date */ printf("\\fdate(f1)\n\ f1 = filename.\n"); #ifdef VMS printf("Returns string:\n\ Creation date of file f1, format: yyyymmdd hh:mm:ss.\n"); #else printf("Returns string:\n\ Modification date of file f1, format: yyyymmdd hh:mm:ss.\n"); #endif /* VMS */ break; case FN_FS: /* File size */ printf("\\fsize(f1)\n\ f1 = filename.\n"); printf("Returns integer:\n\ Size of file f1.\n"); break; case FN_VER: /* Verify */ printf("\\fverify(s1,s2,n1)\n\ s1 = string of characters to look for.\n\ s2 = string to look in.\n\ n1 = starting position in s2.\n"); printf("Returns integer:\n\ 1-based position of first character in s2 that is not also in s1,\n\ or -1 if s1 is empty, or 0 if all characters in s2 are also in s1.\n"); break; case FN_IPA: /* Find and return IP address */ printf("\\fipaddress(s1,n1)\n\ s1 = string.\n\ n1 = 1-based integer starting position, default = 1.\n"); printf("Returns string:\n\ First IP address in s1, scanning from left starting at position n1.\n"); break; case FN_HEX: /* Hexify */ printf("\\fhexify(s1)\n\ s1 = string.\n"); printf("Returns string:\n\ The hexadecimal representation of s1. Also see \\fn2hex().\n"); break; case FN_UNH: /* Unhexify */ printf("\\funhexify(h1)\n\ h1 = Hexadecimal string.\n"); printf("Returns string:\n\ The result of unhexifying s1, or nothing if s1 is not a hex string.\n"); break; case FN_UNTAB: /* Untabify */ printf("\\funtabify(s1)\n\ s1 = string.\n"); printf("Returns string:\n\ The result of converting tabs in s1 to spaces assuming tab stops every\n\ 8 spaces.\n"); break; case FN_BRK: /* Break */ case FN_SPN: /* Span */ printf("\\f%s(s1,s2,n1)\n\ s1 = string to look in.\n\ s2 = string of characters to look for.\n\ n1 = 1-based integer starting position, default = 1.\n", xx == FN_BRK ? "break" : "span" ); printf("Returns string:\n\ s1 up to the first occurrence of any character%salso in s2,\n\ scanning from the left starting at position n1.\n", xx == FN_SPN ? " not " : " "); break; case FN_TRM: /* Trim */ case FN_LTR: /* Left-Trim */ printf("\\f%s(s1,s2)\n\ s1 = string to look in.\n\ s2 = string of characters to look for, default = blanks and tabs.\n", xx == FN_TRM ? "trim" : "ltrim"); printf("Returns string:\n\ s1 with all characters that are also in s2 trimmed from the %s.\n.", xx == FN_TRM ? "right" : "left"); break; case FN_CAP: /* Capitalize */ printf("\\fcapitalize(s1)\n\ s1 = string.\n"); printf("Returns string:\n\ s1 with its first letter converted to uppercase and the remaining\n\ letters to lowercase.\n"); printf("Synonym: \\fcaps(s1)\n"); break; case FN_TOD: /* Time-of-day-to-secs-since-midnite */ printf("\\ftod2secs(s1)\n\ s1 = time-of-day string, hh:mm:ss, 24-hour format.\n"); printf("Returns number:\n\ Seconds since midnight.\n"); break; case FN_FFN: /* Full file name */ printf("\\fpathname(f1)\n\ f1 = filename, possibly wild.\n"); printf("Returns string:\n\ Full pathname of f1.\n"); break; case FN_CHK: /* Checksum of text */ printf("\\fchecksum(s1)\n\ s1 = string.\n"); printf("Returns integer:\n\ 16-bit checksum of string s1.\n"); break; case FN_CRC: /* CRC-16 of text */ printf("\\fcrc16(s1)\n\ s1 = string.\n"); printf("Returns integer:\n\ 16-bit cyclic redundancy check of string s1.\n"); break; case FN_BSN: /* Basename of file */ printf("\\fbasename(f1)\n\ f1 = filename, possibly wild.\n"); printf("Returns string:\n\ Filename f1 stripped of all device and directory information.\n"); break; case FN_CMD: /* Output of a command (cooked) */ printf("\\fcommand(s1)\n\ s1 = string\n"); printf("Returns string:\n\ Output of system command s1, if any, with final line terminator stripped.\n" ); break; case FN_RAW: /* Output of a command (raw) */ printf("\\frawcommand(s1)\n\ s1 = string\n"); printf("Returns string:\n\ Output of system command s1, if any.\n"); break; case FN_STX: /* Strip from right */ printf("\\fstripx(s1,c1)\n\ s1 = string to look in.\n\ c1 = character to look for, default = \".\".\n"); printf("Returns string:\n\ s1 up to the rightmost occurrence of character c1.\n" ); break; case FN_STL: /* Strip from left */ printf("\\flop(s1[,c1[,n1]])\n\ s1 = string to look in.\n\ c1 = character to look for, default = \".\".\n\ n1 = occurrence of c1, default = 1.\n"); printf("Returns string:\n\ The part of s1 after the n1th leftmost occurrence of character c1.\n" ); break; case FN_LOPX: /* Strip from right */ printf("\\flopx(s1,c1)\n\ s1 = string to look in.\n\ c1 = character to look for, default = \".\".\n\ n1 = occurrence of c1, default = 1.\n"); printf("Returns string:\n\ The part of s1 after the n1th rightmost occurrence of character c1.\n" ); break; case FN_STN: /* Strip n chars */ printf("\\fstripn(s1,n1)\n\ s1 = string to look in.\n\ n1 = integer, default = 0.\n"); printf("Returns string:\n\ s1 with n1 characters removed from the right.\n" ); break; case FN_STB: /* Strip enclosing brackets */ printf("\\fstripb(s1[,c1[,c2]])\n\ s1 = original string.\n\ c1 = optional first character\n"); printf("\ c2 = optional final character.\n"); printf("Returns string:\n\ s1 with the indicated enclosing characters removed. If c1 and c2 not\n\ specified, any matching brackets, braces, parentheses, or quotes are\n"); printf("\ assumed. If c1 is given but not c2, the appropriate c2 is assumed.\n\ if both c1 and c2 are given, they are used as-is.\n" ); printf( "Alternative format:\n\ Include a grouping mask number in place of c1 and omit c2 to specify more\n\ than one possibility at once; see \\fword() for details.\n" ); break; #ifdef OS2 case FN_SCRN_CX: /* Screen Cursor X Pos */ printf("\\fscrncurx()\n"); printf("Returns integer:\n\ The 0-based X coordinate (column) of the Terminal screen cursor.\n"); break; case FN_SCRN_CY: /* Screen Cursor Y Pos */ printf("\\fscrncury()\n"); printf("Returns integer:\n\ The 0-based Y coordinate (row) of the Terminal screen cursor.\n"); break; case FN_SCRN_STR: /* Screen String */ printf("\\fscrnstr(ny,nx,n1)\n\ ny = integer.\n\ nx = integer.\n\ n1 = integer.\n"); printf("Returns string:\n\ The string at Terminal-screen coordinates (nx,ny), length n1,\n\ blanks included. Coordinates start at 0. Default values are\n\ 0 for ny and nx, and line width for n1.\n"); break; #endif /* OS2 */ case FN_2HEX: /* Num to hex */ printf("\\fn2hex(n1) - Number to hex\n n1 = integer.\n"); printf("Returns string:\n The hexadecimal representation of n1.\n"); break; case FN_2OCT: /* Num to hex */ printf("\\fn2octal(n1) - Number to octal\n n1 = integer.\n"); printf("Returns string:\n The octal representation of n1.\n"); break; #ifdef RECURSIVE case FN_DIR: /* Recursive directory count */ printf("\\fdirectories(f1,&a) - Directory list.\n\ f1 = directory specification, possibly containing wildcards.\n\ &a = optional name of array to assign directory list to.\n"); printf("Returns integer:\n\ The number of directories that match f1; use with \\fnextfile().\n"); break; case FN_RFIL: /* Recursive file count */ printf("\\frfiles(f1[,&a]) - Recursive file list.\n\ f1 = file specification, possibly containing wildcards.\n\ &a = optional name of array to assign file list to.\n"); printf("Returns integer:\n\ The number of files whose names match f1 in the current or given\n\ directory tree; use with \\fnextfile().\n"); break; case FN_RDIR: /* Recursive directory count */ printf("\\frdirectories(f1) - Recursive directory list.\n\ f1 = directory specification, possibly containing wildcards.\n\ &a = optional name of array to assign directory list to.\n"); printf("Returns integer:\n\ The number of directories that match f1 in the current or given directory\n\ tree. Use with \\fnextfile().\n"); break; #endif /* RECURSIVE */ case FN_DNAM: /* Directory part of a filename */ printf("\\fdirname(f) - Directory part of a filename.\n\ f = a file specification.\n"); printf("Returns directory name:\n\ The full name of the directory that the file is in, or if the file is a\n\ directory, its full name.\n"); break; #ifndef NORANDOM case FN_RAND: /* Random number */ printf("\\frandom(n) - Random number.\n\ n = a positive integer.\n"); printf("Returns integer:\n\ A random number between 0 and n-1.\n"); break; #endif /* NORANDOM */ case FN_SPLIT: /* Split */ #ifdef COMMENT printf("\\fsplit(s1,&a,s2,s3,n2,n3) - \ Assign string words to an array.\n\ s1 = source string\n &a = array designator\n s2 = optional break set.\n"); printf(" s3 = optional include set.\n"); printf(" n2 = optional grouping mask.\n"); printf(" n3 = optional separator flag.\n"); printf(" s2, s3, n2, n3 are as in \\fword().\n"); printf( " All arguments are optional; if \\&a[] already exists, it is recycled;\n\ if array not specified, the count is returned but no array is created.\n"); printf("Returns integer:\n\ Number of words in source string.\n"); #else hmsga(hfsplit); #endif /* COMMENT */ break; case FN_DTIM: /* CVTDATE */ printf("\\fcvtdate([date-time][,n1]) - Date/time conversion.\n"); printf(" Converts date and/or time to standard format.\n"); printf(" If no date/time given, returns current date/time.\n"); printf(" [date-time], if given, is free-format date and/or time.\n"); printf(" HELP DATE for info about date-time formats.\n"); printf("Returns string:\n\ Standard-format date and time: yyyymmdd hh:mm:ss (numeric)\n"); printf(" If n1 is given:\n\ n1 = 1: yyyy-mmm-dd hh:mm:ss (mmm = English 3-letter month abbreviation)\n\ n1 = 2: dd-mmm-yyyy hh:mm:ss (ditto)\n\ n1 = 3: yyyymmddhhmmss (all numeric)\n\ n1 = 4: Day Mon dd hh:mm:ss yyyy (asctime)\n\ n1 = 5: yyyy:mm:dd:hh:mm:ss (all numeric with all fields delimited)\n\ n1 = 6: dd month-spelled-out yyyy hh:mm:ss\n\ Other: yyyymmdd hh:mm:dd\n\ If n1 is negative (-1 to -6), the result is date only."); break; case FN_JDATE: /* DOY */ printf("\\fdoy([date-time]) - Day of Year.\n"); printf(" Converts date and/or time to day-of-year (DOY) format.\n"); printf(" If no date/time given, returns current date.\n"); printf(" [date-time], if given, is free-format date and/or time.\n"); printf(" HELP DATE for info about date-time formats.\n"); printf("Returns numeric string:\n\ DOY: yyyyddd, where ddd is 1-based day number in year.\n"); break; case FN_PNCVT: printf("\\fdialconvert(phone-number) - Convert phone number.\n"); printf(" Converts the given phone number for dialing according\n"); printf( " to the prevailing dialing rules -- country code, area code, etc.\n"); printf("Returns string:\n\ The dial string that would be used if the same phone number had been\n\ given to the DIAL command.\n" ); break; case FN_DATEJ: /* DOY2DATE */ printf("\\fdoy2date([doy[ time]]) - Day of Year to Date.\n"); printf(" Converts yyyymmm to yyyymmdd\n"); printf(" If time included, it is converted to 24-hour format."); printf( "Returns standard date or date-time string yyyymmdd hh:mm:ss\n"); break; case FN_MJD: printf("\\fmjd([[date][ time]]) - Modified Julian Date (MJD).\n"); printf( " Converts date and/or time to MJD, the number of days since 17 Nov 1858.\n"); printf(" HELP DATE for info about date-time formats.\n"); printf("Returns: integer.\n"); break; case FN_MJD2: printf("\\fmjd2date(mjd) - Modified Julian Date (MJD) to Date.\n"); printf(" Converts MJD to standard-format date.\n"); printf("Returns: yyyymmdd.\n"); break; case FN_DAY: printf("\\fday([[date][ time]]) - Day of Week.\n"); printf("Returns day of week of given date as Mon, Tue, etc.\n"); printf("HELP DATE for info about date-time formats.\n"); printf("Also see HELP FUNCTION DAYNAME.\n"); break; case FN_NDAY: printf("\\fnday([[date][ time]]) - Numeric Day of Week.\n"); printf( "Returns numeric day of week of given date, 0=Sun, 1=Mon, ..., 6=Sat.\n"); printf("HELP DATE for info about date-time formats.\n"); break; case FN_TIME: printf("\\ftime([[date][ time]]) - Time.\n"); printf( "Returns time portion of given date and/or time in hh:mm:ss format.\n"); printf("If no argument given, returns current time.\n"); printf("HELP DATE for info about date-time formats.\n"); break; case FN_NTIM: printf("\\fntime([[date][ time]]) - Numeric Time.\n"); printf( "Returns time portion of given date and/or time as seconds since midnight.\n"); printf("If no argument given, returns current time.\n"); printf("HELP DATE for info about date-time formats.\n"); break; case FN_N2TIM: printf("\\fn2time(seconds) - Numeric Time to Time.\n"); printf( "Returns the given number of seconds in hh:mm:ss format.\n"); break; case FN_PERM: printf("\\fpermissions(file) - Permissions of File.\n"); printf( #ifdef UNIX "Returns permissions of given file as they would be shown by \"ls -l\".\n" #else #ifdef VMS "Returns permissions of given file as they would be shown by \"dir /prot\".\n" #else "Returns the permissions of the given file.\n" #endif /* VMS */ #endif /* UNIX */ ); break; case FN_ALOOK: printf("\\farraylook(pattern,&a) - Lookup pattern in array.\n\ pattern = String or pattern\n"); printf(" &a = array designator, can include range specifier.\n"); printf( "Returns number:\n\ The index of the first matching array element or -1 if none.\n"); printf("More info:\n\ HELP PATTERN for pattern syntax.\n HELP ARRAY for arrays.\n"); break; case FN_TLOOK: printf("\\ftablelook(keyword,&a,[c]) \ - Lookup keyword in keyword table.\n"); printf(" keyword = keyword to look up (can be abbreviated).\n"); printf(" &a = array designator, can include range specifier.\n"); printf(" This array must be in alphabetical order.\n"); printf(" c = Optional field delimiter, colon(:) by default.\n"); printf( "Returns number:\n\ 1 or greater, index of array element that uniquely matches given keyword;\n" ); printf( "or -2 if keyword was ambiguous, or -1 if keyword empty or not found.\n" ); printf("Also see:\n\ HELP FUNC ARRAYLOOK for a similar function.\n HELP ARRAY for arrays.\n"); break; case FN_ABS: /* Absolute */ printf("\\fabsolute(n1)\n\ n1 = integer.\n"); printf("Returns integer:\n\ The absolute (unsigned) value of n1.\n"); break; #ifdef FNFLOAT case FN_FPABS: printf("\\ffpabsolute(f1,d)\n\ f1 = floating-point number or integer.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ The absolute (unsigned) value of f1 to d decimal places.\n"); break; case FN_FPADD: printf("\\ffpadd(f1,f2,d)\n\ f1,f2 = floating-point numbers or integers.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ The sum of f1 and f2 to d decimal places.\n"); break; case FN_FPSUB: printf("\\ffpsubtract(f1,f2,d)\n\ f1,f2 = floating-point numbers or integers.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ f1 minus f2 to d decimal places.\n"); break; case FN_FPMUL: printf("\\ffpmultiply(f1,f2,d)\n\ f1,f2 = floating-point numbers or integers.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ The product of f1 and f2 to d decimal places.\n"); break; case FN_FPDIV: printf("\\ffpdivide(f1,f2,d)\n\ f1,f2 = floating-point numbers or integers.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ f1 divided by f2 to d decimal places.\n"); break; case FN_FPMAX: printf("\\ffpmaximum(f1,f2,d)\n\ f1,f2 = floating-point numbers or integers.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ The maximum of f1 and f2 to d decimal places.\n"); break; case FN_FPMIN: printf("\\ffpminimum(f1,f2,d)\n\ f1,f2 = floating-point numbers or integers.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ The minimum of f1 and f2 to d decimal places.\n"); break; case FN_FPMOD: printf("\\ffpmodulus(f1,f2,d)\n\ f1,f2 = floating-point numbers or integers.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ The modulus of f1 and f2 to d decimal places.\n"); break; case FN_FPPOW: printf("\\ffpraise(f1,f2,d)\n\ f1,f2 = floating-point numbers or integers.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ f1 raised to the power f2, to d decimal places.\n"); break; case FN_FPCOS: printf("\\ffpcosine(f1,d)\n\ f1 = floating-point number or integer.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ The cosine of angle f1 (in radians) to d decimal places.\n"); break; case FN_FPSIN: printf("\\ffpsine(f1,d)\n\ f1 = floating-point number or integer.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ The sine of angle f1 (in radians) to d decimal places.\n"); break; case FN_FPTAN: printf("\\ffptangent(f1,d)\n\ f1 = floating-point number or integer.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ The tangent of angle f1 (in radians) to d decimal places.\n"); break; case FN_FPEXP: printf("\\ffpexp(f1,d)\n\ f1 = floating-point number or integer.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ e (the base of natural logarithms) raised to the f1 power,\n\ to d decimal places.\n"); break; case FN_FPINT: printf("\\ffpint(f1)\n\ f1 = floating-point number or integer.\n"); printf("Returns integer:\n\ The integer part of f1.\n"); break; case FN_FPLOG: printf("\\ffplog10(f1,d)\n\ f1 = floating-point number or integer.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ The logarithm, base 10, of f1 to d decimal places.\n"); break; case FN_FPLN: printf("\\ffplogn(f1,d)\n\ f1 = floating-point number or integer.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ The natural logarithm of f1 to d decimal places.\n"); break; case FN_FPROU: printf("\\ffpround(f1,d)\n\ f1 = floating-point number or integer.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ f1 rounded to d decimal places.\n"); break; case FN_FPSQR: printf("\\ffpsqrt(f1,d)\n\ f1 = floating-point number or integer.\n\ d = integer.\n"); printf("Returns floating-point number:\n\ The square root of f1 to d decimal places.\n"); break; #endif /* FNFLOAT */ #ifdef CKCHANNELIO case FN_FEOF: printf("\\f_eof(n1)\n\ n1 = channel number.\n"); printf("Returns number:\n\ 1 if channel n1 at end of file, 0 otherwise.\n"); break; case FN_FPOS: printf("\\f_pos(n1)\n\ n1 = channel number.\n"); printf("Returns number:\n\ Read/write pointer of channel n1 as byte number.\n"); break; case FN_NLINE: printf("\\f_line(n1)\n\ n1 = channel number.\n"); printf("Returns number:\n\ Read/write pointer of channel n1 as line number.\n"); break; case FN_FILNO: printf("\\f_handle(n1)\n\ n1 = channel number.\n"); printf("Returns number:\n\ File %s of open file on channel n1.\n", #ifdef OS2 "handle" #else "descriptor" #endif /* OS2 */ ); break; case FN_FSTAT: printf("\\f_status(n1)\n\ n1 = channel number.\n"); printf("Returns number:\n\ Sum of open modes of channel n1: 1 = read; 2 = write; 4 = append, or:\n\ 0 if not open.\n"); break; case FN_FGCHAR: printf("\\f_getchar(n1)\n\ n1 = channel number.\n"); printf(" Reads a character from channel n1 and returns it.\n"); break; case FN_FGLINE: printf("\\f_getline(n1)\n\ n1 = channel number.\n"); printf(" Reads a line from channel n1 and returns it.\n"); break; case FN_FGBLK: printf("\\f_getblock(n1,n2)\n\ n1 = channel number, n2 = size\n"); printf( " Reads a block of n2 characters from channel n1 and returns it.\n"); break; case FN_FPCHAR: printf("\\f_putchar(n1,c)\n\ n1 = channel number, c = character\n"); printf(" Writes a character to channel n1.\n\ Returns number:\n\ 1 if successful, otherwise a negative error code.\n"); break; case FN_FPLINE: printf("\\f_putline(n1,s1)\n\ n1 = channel number, s1 = string\n"); printf( " Writes the string s1 to channel n1 and adds a line terminator.\n\ Returns number:\n"); printf(" How many characters written if successful;\n\ Otherwise a negative error code.\n" ); break; case FN_FPBLK: printf("\\f_putblock(n1,s1)\n\ n1 = channel number, s1 = string\n"); printf( " Writes the string s1 to channel n1.\n\ Returns number:\n"); printf(" How many characters written if successful;\n\ Otherwise a negative error code.\n" ); break; case FN_FERMSG: printf("\\f_errmsg([n1])\n\ n1 = numeric error code, \\v(f_error) by default.\n"); printf(" Returns the associated error message string.\n"); break; #endif /* CKCHANNELIO */ case FN_AADUMP: printf("\\faaconvert(name,&a[,&b])\n\ name = name of associative array, &a and &b = names of regular arrays.\n"); printf( " Converts the given associative array into two regular arrays, &a and &b,\n\ containing the indices and values, respectively:\n"); printf("Returns number:\n\ How many elements were converted.\n"); break; #ifdef CK_KERBEROS case FN_KRB_TK: printf("\\fkrbtickets(n)\n\ n = Kerberos version number (4 or 5).\n\ Returns string:\n\ The number of active Kerberos 4 or 5 tickets.\n\ Resets the ticket list used by \\fkrbnextticket(n).\n"); break; case FN_KRB_NX: printf("\\fkrbnextticket(n)\n\ n = Kerberos version number (4 or 5).\n\ Returns string:\n\ The next ticket in the Kerberos 4 or 5 ticket list that was set up by\n\ the most recent invocation of \\fkrbtickets(n).\n"); break; case FN_KRB_IV: printf("\\fkrbisvalid(n,name)\n\ n = Kerberos version number (4 or 5).\n\ name = a ticket name as returned by \\fkrbnextticket(n).\n\ Returns number:\n\ 1 if the ticket is valid, 0 if not valid.\n\ A ticket is valid if all the following conditions are true:\n\n"); printf("\n\ (i) it exists in the current cache file;\n\ (ii) it is not expired;\n\ (iii) it is not marked invalid (K5 only);\n\ (iv) it was issued from the current IP address\n"); printf("\n This value can be used in an IF statement, e.g.:\n\n"); printf(" if \\fkrbisvalid(4,krbtgt.FOO.BAR.EDU@FOO.BAR.EDU) ...\n"); break; case FN_KRB_TT: printf("\\fkrbtimeleft(n,name)\n\ n = Kerberos version number (4 or 5).\n\ name = a ticket name as returned by \\fkrbnextticket(n).\n\ Returns string:\n\ The number of seconds remaining in the ticket's lifetime.\n"); break; case FN_KRB_FG: printf("\\fkrbflags(n,name)\n\ n = Kerberos version number (4 or 5).\n\ name = a ticket name as returned by \\fkrbnextticket(n).\n\ Returns string:\n"); printf( " The flags string as reported with AUTH K5 LIST /FLAGS. This string can\n\ be searched for a particular flag using the \\findex() function when\n\ SET CASE is ON (for case sensitive searches). Flag strings are only\n\ available for K5 tickets.\n"); break; #endif /* CK_KERBEROS */ case FN_PATTERN: printf("\\fpattern(s)\n\ s = string\n\ Returns string: s with any variables, etc, evaluated in the normal manner.\n" ); printf("\ For use with INPUT, MINPUT, and REINPUT to declare that a search target is\n\ a pattern rather than a literal string.\n"); break; case FN_HEX2N: printf("\\fhex2n(s)\n\ s = hexadecimal number\n\ Returns decimal equivalent.\n"); break; case FN_HEX2IP: printf("\\fhex2ip(s)\n\ s = 8-digit hexadecimal number\n\ Returns the equivalent decimal dotted IP address.\n"); break; case FN_IP2HEX: printf("\\fip2hex(s)\n\ s = decimal dotted IP address\n\ Returns the equivalent 8-digit hexadecimal number.\n"); break; case FN_OCT2N: printf("\\foct2n(s)\n\ s = octal number\n\ Returns decimal equivalent.\n"); break; case FN_TOB64: printf("\\b64encode(s)\n\ s = string containing no NUL bytes\n\ Returns Base-64 encoding of string.\n"); break; case FN_FMB64: printf("\\b64decode(s)\n\ s = string in Base-64 notation\n\ Returns the decoded string or an error code if s not valid.\n"); break; case FN_RADIX: printf("\\fradix(s,n1,n2)\n\ s = number in radix n1\n\ Returns the number's representation in radix n2.\n"); break; case FN_JOIN: printf("\\fjoin(&a[,s[,n1[,n2]]])\n\ &a = array designator, can include range specifier.\n\ s = optional separator.\n"); printf("\ n1 = nonzero to put grouping around elements that contain spaces;\n\ see \\fword() grouping mask for values of n.\n"); printf("\ n2 = 0 or omitted to put spaces between elements; nonzero to omit them.\n"); printf("\ Returns the (selected) elements of the array joined to together,\n\ separated by the separator.\n"); printf("\n\ If s is CSV (literally), that means the array is to be transformed into a\n\ comma-separated list. No other arguments are needed. If s is TSV, then\n\ a tab-separated list is created.\n"); break; case FN_SUBST: printf("\\fsubstitute(s1,s2,s3)\n\ s1 = Source string.\n\ s2 = List of characters to be translated.\n\ s3 = List of characters to translate them to.\n"); printf( " Returns: s1, with each character that is in s2 replaced by the\n\ corresponding character in s3. s2 and s3 can contain ASCII ranges,\n\ like [a-z]. Any characters in s2 that don't have corresponding\n\ characters in s3 (after range expansion) are removed from the result.\n\ This function works only with single-byte character-sets\n"); break; #ifndef NOSEXP case FN_SEXP: printf("\\fsexpression(s1)\n\ s1 = S-Expression.\n"); printf(" Returns: The result of evaluating s1.\n"); break; #endif /* NOSEXP */ case FN_CMDSTK: printf("\\fcmdstack(n1,n2)\n\ n1 = Command-stack level, 0 to \\v(cmdlevel), default \\v(cmdlevel).\n\ n2 = Function code, 0 or 1.\n"); printf("Returns:\n"); printf(" n2 = 0: name of object at stack level n1\n\ n2 = 1: type of object at stack level n1:\n\ 0 = interactive prompt\n\ 1 = command file\n\ 2 = macro\n" ); break; #ifdef CKFLOAT case FN_DIFDATE: printf("\\fdiffdates(d1,d2)\n\ d1 = free-format date and/or time (default = NOW).\n\ d2 = ditto.\n"); printf("Returns:\n"); printf(" Difference expressed as delta time:\n"); printf(" Negative if d2 is later than d1, otherwise positive.\n"); break; #endif /* CKFLOAT */ case FN_CMPDATE: printf("\\fcmpdates(d1,d2)\n\ d1 = free-format date and/or time (default = NOW).\n\ d2 = ditto.\n"); printf("Returns:\n"); printf(" 0 if d1 is equal to d2;\n\ 1 if d1 is later than d2;\n\ -1 if d1 is earlier than d2.\n"); break; case FN_TOGMT: printf("\\futcdate(d1)\n\ d1 = free-format date and/or time (default = NOW).\n"); printf("Returns:\n"); printf(" Date-time converted to UTC (GMT) yyyymmdd hh:mm:ss.\n"); break; #ifdef TCPSOCKET case FN_HSTADD: printf("\\faddr2name(s)\n\ s = numeric IP address.\n"); printf("Returns:\n"); printf(" Corresponding IP hostname if found, otherwise null.\n"); break; case FN_HSTNAM: printf("\\fname2addr(s)\n\ s = IP host name.\n"); printf("Returns:\n"); printf(" Corresponding numeric IP address if found, else null.\n"); break; #endif /* TCPSOCKET */ case FN_DELSEC: printf("\\fdelta2secs(dt)\n\ dt = Delta time, e.g. +3d14:27:52.\n"); printf("Returns:\n"); printf(" The corresponding number of seconds.\n"); break; case FN_PC_DU: printf("\\fdos2unixpath(p)\n\ p = string, DOS pathname.\n"); printf("Returns:\n"); printf(" The argument converted to a Unix pathname.\n"); break; case FN_PC_UD: printf("\\funix2dospath(p)\n\ p = string, Unix pathname.\n"); printf("Returns:\n"); printf(" The argument converted to a DOS pathname.\n"); break; #ifdef FN_ERRMSG case FN_ERRMSG: printf("\\ferrstring(n)\n\ n = platform-dependent numeric error code.\n"); printf("Returns:\n"); printf(" The corresponding error string.\n"); break; #endif /* FN_ERRMSG */ case FN_KWVAL: printf("\\fkeywordvalue(s1[,s2])\n\ s1 = string of the form \"name=value\"\n\ s2 = one more separator characters (default separator is \"=\")\n"); printf(" Assigns the value, if any, to the named macro and sets\n"); printf(" the \\v(lastkeywordvalue) to the macro name.\n"); printf(" If no value is given, the macro is undefined.\n"); printf("Returns:\n"); printf(" -1 on error\n"); printf(" 0 if no keyword or value were found\n"); printf(" 1 if a keyword was found but no value\n"); printf(" 2 if a keyword and a value were found\n"); printf("Synonym: \\kwvalue(s1[,s2])\n"); break; #ifdef COMMENT case FN_SLEEP: printf("\\fsleep(n)\n\ n = number of seconds\n"); printf(" Pauses for the given number of seconds.\n"); printf("Returns: the empty string.\n"); break; case FN_MSLEEP: printf("\\fmsleep(n)\n\ n = number of milliseconds\n"); printf(" Pauses for the given number of milliseconds.\n"); printf("Returns: the empty string.\n"); break; #endif /* COMMENT */ #ifdef NT case FN_SNAME: printf("\\fshortpathname(s)\n\ s = file or directory name string\n"); printf(" Returns the short path form of the given input.\n"); break; case FN_LNAME: printf("\\flongpathname(s)\n\ s = file or directory name string\n"); printf(" Returns the long path form of the given input.\n"); break; #else case FN_SNAME: printf("\\fshortpathname(s)\n\ Synonym for \fpathname()\n"); break; case FN_LNAME: printf("\\flongpathname(s)\n\ Synonym for \fpathname()\n"); break; #endif /* NT */ case FN_EMAIL: printf("\\femailaddress(s)\n\ s = From: or Sender: header from an RFC2822-format email message\n"); printf(" Extracts and returns the email address.\n"); break; case FN_PICTURE: printf("\\fpictureinfo(s[,&a])\n\ s = File specification of an image file in JPG or GIF format.\n\ &a = Optional array name.\n\n"); printf("Returns integer:\n\ 0 if file not found or not recognized;\n\ 1 if orientation is landscape;\n\ 2 if orientation is portrait;\n\ 3 if the image is square.\n"); printf("\n\ If an array name is included, and if the function's return value is\n\ greater than 0, element 1 of the array is filled in with the image\n\ width in pixels, element 2 the image height, and element 3 is the image's\n\ 'date taken' (if present) in 'yyyy:mm:dd hh:mm:ss' format; for example\n\ 2013:05:17 21:14:12.\n"); break; case FN_PID: printf("\\fgetpidinfo(n1)\n\ n1 = Numeric process ID\n"); printf("Returns integer:\n\ -1 on failure to get information;\n\ 1 if n1 is the ID of an active process;\n\ 0 if the process does not exist.\n"); break; case FN_FUNC: printf("\\ffunction(s1)\n\ s1 = name of function.\n"); printf("Returns integer:\n\ 1 if s1 is the name of an available built-in function;\n\ 0 otherwise.\n"); break; case FN_RECURSE: printf("\\frecurse(s1)\n\ s1 = name of \\&x or \\&x[] type variable\n"); printf("Returns the result of evaluating the variable recursively.\n"); break; case FN_SQUEEZE: printf("\\fsqueeze(s)\n\ s = string\n\ Returns string with leading and trailing whitespace removed, Tabs\n\ converted to Spaces, and multiple spaces converted to single spaces.\n"); break; #ifndef NOCSETS case FN_XLATE: printf("\\fcvtcset(s,cset1,cset2)\n\ s = string\n\ Returns string converted from character set cset1 to cset2, where cset1\n\ and cset2 are names of File Character-Sets \ ('set file char ?' for a list).\n"); break; #endif /* NOCSETS */ case FN_UNPCT: printf("\\fdecodehex(s1[,s2])\n\ s1, s2 = strings\n\ Decodes a string s1 that contains prefixed hex bytes. s2 is the prefix;\n\ the default is %%%%. You can specify any other prefix one or two bytes\n\ long. If the prefix contains letters (such as 0x), case is ingored.\n\ Returns string s1 with hex escapes replaced by the bytes they \ represent.\n"); break; case FN_STRINGT: printf("\\fstringtype(s)\n\ s = string\n\ Returns a string representing the type of its string argument s1:\n\ 7BIT, 8BIT, UTF8, TEXT, or BINARY. TEXT means some kind of text\n\ other than 7BIT, 8BIT, or UTF8 (this probably will never appear).\n"); break; case FN_STRCMP: /* fdc 12 November 2022 */ hmsga(hmfstrcmp); /* Literal string was too long */ break; case FN_FILEINF: /* fdc 12 November 2022 */ hmsga(hmffileinfo); /* Literal string was too long */ break; case FN_FILECMP: printf("\\ffilecompare(s1,s2)\n\ s1 = name of first file\n\ s1 = name of second file\n\ Returns a number:\n\ 0: The two files have identical contents and lengths;\n\ 1: The two files have different content or lengths;\n\ -1: Error opening or reading either file.\n"); break; case FN_DAYNAME: /* fdc 12 November 2022 */ hmsga(hmfdayname); /* Literal string was too long */ break; case FN_MONNAME: /* fdc 12 November 2022 */ hmsga(hmfmonname); /* Literal string was too long */ break; default: printf("Sorry, help not available for \"%s\"\n",cmdbuf); } printf("\n"); return(0); } #endif /* NOSPL */ #ifdef OS2 #ifndef NOKVERBS /* D O H K V E R B -- Give help for a Kverb */ int dohkverb(xx) int xx; { int x,i,found,button,event; if (xx == -3) { printf("\n Type SHOW KVERBS to see a list of available Kverbs.\n" ); printf( " Type HELP KVERB to see the current definition of a given Kverb.\n\n" ); return(-9); } if (xx < 0) return(xx); if ((x = cmcfm()) < 0) return(x); switch ( xx ) { /* DEC VT keyboard key definitions */ case K_COMPOSE : /* Compose key */ printf("\\Kcompose Compose an accented character\n"); break; case K_C_UNI16 : /* UCS2 key */ printf("\\Kucs2 Enter a Unicode character\n"); break; /* DEC arrow keys */ case K_UPARR : /* DEC Up Arrow key */ printf("\\Kuparr Transmit Terminal Up Arrow sequence\n"); break; case K_DNARR : /* DEC Down Arrow key */ printf("\\Kdnarr Transmit Terminal Down Arrow sequence\n"); break; case K_RTARR : /* DEC Right Arrow key */ printf("\\Krtarr Transmit Terminal Right Arrow sequence\n"); break; case K_LFARR : /* DEC Left Arrow key */ printf("\\Klfarr Transmit Terminal Left Arrow sequence\n"); break; case K_PF1 : /* DEC PF1 key */ printf("\\Kpf1,\\Kgold Transmit DEC PF1 sequence\n"); break; case K_PF2 : /* DEC PF2 key */ printf("\\Kpf2 Transmit DEC PF2 sequence\n"); break; case K_PF3 : /* DEC PF3 key */ printf("\\Kpf3 Transmit DEC PF3 sequence\n"); break; case K_PF4 : /* DEC PF4 key */ printf("\\Kpf4 Transmit DEC PF4 sequence\n"); break; case K_KP0 : /* DEC Keypad 0 */ printf("\\Kkp0 Transmit DEC Keypad-0 sequence\n"); break; case K_KP1 : /* DEC Keypad 1 */ printf("\\Kkp1 Transmit DEC Keypad-1 sequence\n"); break; case K_KP2 : /* etc ... through 9 */ printf("\\Kkp2 Transmit DEC Keypad-2 sequence\n"); break; case K_KP3 : printf("\\Kkp3 Transmit DEC Keypad-3 sequence\n"); break; case K_KP4 : printf("\\Kkp4 Transmit DEC Keypad-4 sequence\n"); break; case K_KP5 : printf("\\Kkp5 Transmit DEC Keypad-5 sequence\n"); break; case K_KP6 : printf("\\Kkp6 Transmit DEC Keypad-6 sequence\n"); break; case K_KP7 : printf("\\Kkp7 Transmit DEC Keypad-7 sequence\n"); break; case K_KP8 : printf("\\Kkp8 Transmit DEC Keypad-8 sequence\n"); break; case K_KP9 : printf("\\Kkp9 Transmit DEC Keypad-9 sequence\n"); break; case K_KPCOMA : /* DEC keypad comma */ printf("\\Kkpcoma Transmit DEC Keypad-Comma sequence\n"); break; case K_KPMINUS : /* DEC keypad minus */ printf("\\Kkpminus Transmit DEC Keypad-Minus sequence\n"); break; case K_KPDOT : /* DEC keypad period */ printf("\\Kkpdot Transmit DEC Keypad-Period sequence\n"); break; case K_KPENTER : /* DEC keypad enter */ printf("\\Kkpenter Transmit DEC Keypad-Enter sequence\n"); break; /* DEC Top-Rank F keys */ case K_DECF1 : /* DEC F1 key */ printf("\\Kdecf1 Transmit DEC F1 sequence for PC keyboard\n"); break; case K_DECF2 : /* DEC F2 key */ printf("\\Kdecf2 Transmit DEC F2 sequence for PC keyboard\n"); break; case K_DECF3 : /* DEC F3 key */ printf("\\Kdecf3 Transmit DEC F3 sequence for PC keyboard\n"); break; case K_DECF4 : /* DEC F4 key */ printf("\\Kdecf4 Transmit DEC F4 sequence for PC keyboard\n"); break; case K_DECF5 : /* DEC F5 key */ printf("\\Kdecf5 Transmit DEC F5 sequence for PC keyboard\n"); break; case K_DECHOME: /* DEC HOME key */ printf("\\Kdechome Transmit DEC HOME sequence for PC keyboard\n"); break; case K_DECF6 : /* DEC F6 key */ printf("\\Kdecf6 Transmit DEC F6 sequence\n"); break; case K_DECF7 : /* etc, through F20 */ printf("\\Kdecf7 Transmit DEC F7 sequence\n"); break; case K_DECF8 : printf("\\Kdecf8 Transmit DEC F8 sequence\n"); break; case K_DECF9 : printf("\\Kdecf9 Transmit DEC F9 sequence\n"); break; case K_DECF10 : printf("\\Kdecf10 Transmit DEC F10 sequence\n"); break; case K_DECF11 : printf("\\Kdecf11 Transmit DEC F11 sequence\n"); break; case K_DECF12 : printf("\\Kdecf12 Transmit DEC F12 sequence\n"); break; case K_DECF13 : printf("\\Kdecf13 Transmit DEC F13 sequence\n"); break; case K_DECF14 : printf("\\Kdecf14 Transmit DEC F14 sequence\n"); break; case K_DECHELP : /* DEC Help key */ printf("\\Kdecf15,\\Kdechelp Transmit DEC HELP sequence\n"); break; case K_DECDO : /* DEC Do key */ printf("\\Kdecf16,\\Kdecdo Transmit DEC DO sequence\n"); break; case K_DECF17 : printf("\\Kdecf17 Transmit DEC F17 sequence\n"); break; case K_DECF18 : printf("\\Kdecf18 Transmit DEC F18 sequence\n"); break; case K_DECF19 : printf("\\Kdecf19 Transmit DEC F19 sequence\n"); break; case K_DECF20 : printf("\\Kdecf20 Transmit DEC F20 sequence\n"); break; /* DEC editing keys */ case K_DECFIND : /* DEC Find key */ printf("\\Kdecfind Transmit DEC FIND sequence\n"); break; case K_DECINSERT : /* DEC Insert key */ printf("\\Kdecinsert Transmit DEC INSERT HERE sequence\n"); break; case K_DECREMOVE : /* DEC Remove key */ printf("\\Kdecremove Transmit DEC REMOVE sequence\n"); break; case K_DECSELECT : /* DEC Select key */ printf("\\Kdecselect Transmit DEC SELECT sequence\n"); break; case K_DECPREV : /* DEC Previous Screen key */ printf("\\Kdecprev Transmit DEC PREV SCREEN sequence\n"); break; case K_DECNEXT : /* DEC Next Screen key */ printf("\\Kdecnext Transmit DEC NEXT SCREEN sequence\n"); break; /* DEC User-Defined Keys */ case K_UDKF1 : /* F1 - F5 are XTERM extensions */ printf("\\Kudkf1 Transmit XTERM F1 User Defined Key sequence\n"); break; case K_UDKF2 : printf("\\Kudkf2 Transmit XTERM F2 User Defined Key sequence\n"); break; case K_UDKF3 : printf("\\Kudkf3 Transmit XTERM F3 User Defined Key sequence\n"); break; case K_UDKF4 : printf("\\Kudkf4 Transmit XTERM F4 User Defined Key sequence\n"); break; case K_UDKF5 : printf("\\Kudkf5 Transmit XTERM F5 User Defined Key sequence\n"); break; case K_UDKF6 : /* DEC User Defined Key F6 */ printf("\\Kudkf6 Transmit DEC F6 User Defined Key sequence\n"); break; case K_UDKF7 : /* DEC User Defined Key F7 */ printf("\\Kudkf7 Transmit DEC F7 User Defined Key sequence\n"); break; case K_UDKF8 : /* etc ... through F20 */ printf("\\Kudkf8 Transmit DEC F8 User Defined Key sequence\n"); break; case K_UDKF9 : printf("\\Kudkf9 Transmit DEC F9 User Defined Key sequence\n"); break; case K_UDKF10 : printf("\\Kudkf10 Transmit DEC F10 User Defined Key sequence\n"); break; case K_UDKF11 : printf("\\Kudkf11 Transmit DEC F11 User Defined Key sequence\n"); break; case K_UDKF12 : printf("\\Kudkf12 Transmit DEC F12 User Defined Key sequence\n"); break; case K_UDKF13 : printf("\\Kudkf13 Transmit DEC F13 User Defined Key sequence\n"); break; case K_UDKF14 : printf("\\Kudkf14 Transmit DEC F14 User Defined Key sequence\n"); break; case K_UDKHELP : printf( "\\Kudkhelp,\\Kudkf15 Transmit DEC HELP User Defined Key sequence\n"); break; case K_UDKDO : printf( "\\Kudkdo,\\Kudkf16 Transmit DEC DO User Defined Key sequence\n"); break; case K_UDKF17 : printf("\\Kudkf17 Transmit DEC F17 User Defined Key sequence\n"); break; case K_UDKF18 : printf("\\Kudkf18 Transmit DEC F18 User Defined Key sequence\n"); break; case K_UDKF19 : printf("\\Kudkf19 Transmit DEC F19 User Defined Key sequence\n"); break; case K_UDKF20 : printf("\\Kudkf20 Transmit DEC F20 User Defined Key sequence\n"); break; /* Emacs Keys */ case K_EMACS_OVER: printf( "\\Kemacs_overwrite Transmit EMACS Overwrite toggle command sequence\n"); break; /* Kermit screen-scrolling keys */ case K_DNONE : /* Screen rollback: down one line */ printf("\\Kdnone Screen rollback: down one line\n"); break; case K_DNSCN : /* Screen rollback: down one screen */ printf("\\Kdnscn Screen rollback: down one screen\n"); break; case K_DNHSCN : /* Screen rollback: down half a screen */ printf("\\Kdnhscn Screen rollback: down half of one screen\n"); break; case K_UPONE : /* Screen rollback: Up one line */ printf("\\Kupone Screen rollback: up one line\n"); break; case K_UPSCN : /* Screen rollback: Up one screen */ printf("\\Kupscn Screen rollback: up one screen\n"); break; case K_UPHSCN : /* Screen rollback: Up half a screen */ printf("\\Kuphscn Screen rollback: up half of one screen\n"); break; case K_ENDSCN : /* Screen rollback: latest screen */ printf("\\Kendscn Screen rollback: latest screen\n"); break; case K_HOMSCN : /* Screen rollback: oldest screen */ printf("\\Khomscn Screen rollback: oldest screen\n"); break; case K_GO_BOOK : /* Scroll to bookmark */ printf("\\Kgobook Screen rollback: go to bookmark\n"); break; case K_GOTO : /* Scroll to line number */ printf("\\Kgoto Screen rollback: go to line number\n"); break; case K_LFONE : /* Horizontal Scroll: Left one cell */ printf("\\Klfone Horizontal Scroll: Left one column\n"); break; case K_LFPAGE : /* Horizontal Scroll: Left one page */ printf("\\Klfpage Horizontal Scroll: Left eight columns\n"); break; case K_LFALL : printf("\\Klfall Horizontal Scroll: Left to margin\n"); break; case K_RTONE : /* Horizontal Scroll: Right one cell */ printf("\\Krtone Horizontal Scroll: Right one column\n"); break; case K_RTPAGE : /* Horizontal Scroll: Right one page */ printf("\\Krtpage Horizontal Scroll: Right eight columns\n"); break; case K_RTALL : printf("\\Krtall Horizontal Scroll: Right to margin\n"); break; /* Keyboard language switching verbs */ case K_KB_ENG : /* English keyboard mode */ printf("\\Kkbenglish Switch to Normal (English) keyboard mode\n"); break; case K_KB_HEB : /* Hebrew keyboard mode */ printf("\\Kkbhebrew Switch to Hebrew keyboard mode\n"); break; case K_KB_RUS : /* Russian keyboard mode */ printf("\\Kkbrussian Switch to Russian keyboard mode\n"); break; case K_KB_EMA : /* Emacs keyboard mode */ printf("\\Kkbemacs Switch to EMACS keyboard mode\n"); break; case K_KB_WP : /* Word Perfect 5.1 mode */ printf("\\Kkbwp Switch to Word Perfect 5.1 keyboard mode\n"); break; /* Mark Mode actions */ case K_MARK_START : /* Enter Mark Mode/Start marking */ printf("\\Kmarkstart Mark Mode: Enter mode or Start marking\n"); break; case K_MARK_CANCEL : /* Exit Mark Mode - Do Nothing */ printf("\\Kmarkcancel Mark Mode: Cancel mode\n"); break; case K_MARK_COPYCLIP: /* Exit Mark Mode - Copy data to clipboard */ printf("\\Kmarkcopyclip Mark Mode: Copy marked text to clipboard\n"); break; case K_MARK_COPYHOST: /* Exit Mark Mode - Copy data to host */ printf("\\Kmarkcopyhost Mark Mode: Copy marked text to host\n"); break; case K_MARK_SELECT : /* Exit Mark Mode - Select */ printf( "\\Kmarkselect Mark Mode: Place marked text into \\v(select)\n"); break; case K_BACKSRCH : /* Search Backwards for text */ printf("\\Kbacksearch Search: Begin backward search for text\n"); break; case K_FWDSRCH : /* Search Forwards for text */ printf("\\Kfwdsearch Search: Begin forward search for text\n"); break; case K_BACKNEXT : /* Search Backwards for next instance of text */ printf( "\\Kbacknext Search: Find next instance of text backwards\n"); break; case K_FWDNEXT : /* Search Forwards for next instance of text */ printf("\\Kfwdnext Search: Find next instance of text forwards\n"); break; /* Miscellaneous Kermit actions */ case K_EXIT : /* Return to command parser */ printf("\\Kexit Toggle between COMMAND and CONNECT modes\n"); break; case K_BREAK : /* Send a BREAK */ printf("\\Kbreak Transmit BREAK signal to host\n"); break; case K_RESET : /* Reset emulator */ printf("\\Kreset Reset Terminal Emulator to user defaults\n"); break; case K_DOS : /* Push to DOS (i.e. OS/2) */ printf("\\Kdos,\\Kos2 Push to Command Shell\n"); break; case K_HANGUP : /* Hang up the connection */ printf("\\Khangup Hangup the active connection\n"); break; case K_DUMP : /* Dump/Print current screen */ printf( "\\Kdump Dump/copy current screen to SET PRINTER device/file\n"); break; case K_LBREAK : /* Send a Long BREAK */ printf("\\Klbreak Transmit LONG BREAK signal to host\n"); break; case K_NULL : /* Send a NUL */ printf("\\Knull Transmit NULL ('\0') character to host\n"); break; case K_HELP : /* Pop-up help */ printf("\\Khelp Raise Pop-Up help display\n"); break; case K_HOLDSCRN : /* Hold screen */ printf("\\Kholdscrn Pause data input during CONNECT mode\n"); break; case K_IGNORE : /* Ignore this key, don't even beep */ printf("\\Kignore Ignore key\n"); break; case K_LOGOFF : /* Turn off session logging */ printf("\\Klogoff Turn off session logging (see \\Ksession)\n"); break; case K_LOGON : /* Turn on session logging */ printf("\\Klogon Turn on session logging (see \\Ksession)\n"); break; case K_SESSION: printf( "\\Ksession Toggle on/off session logging to 'session.log'\n"); break; case K_AUTODOWN: printf("\\Kautodown Toggle on/off terminal autodownload.\n"); break; case K_BYTESIZE: printf( "\\Kbytesize Toggle terminal bytesize between 7 and 8 bits.\n"); break; #ifdef COMMENT case MODELINE: case K_NETHOLD : /* Put network connection on hold */ case K_NEXTSESS : /* Toggle to next network session */ #endif /* COMMENT */ case K_CURSOR_URL: printf( "\\Kurl Treat text under cursor position as a URL\n"); break; case K_STATUS : /* Show status */ printf( "\\Kstatus Toggle statusline (None, Indicator, Host Writeable)\n"); break; case K_TERMTYPE : /* Toggle term type: text/graphics */ printf("\\Ktermtype Toggle Terminal Type\n"); break; case K_PRTCTRL : /* Print Controller mode */ printf("\\Kprtctrl Toggle Ctrl-Print (transparent) mode\n"); break; case K_PRINTFF : /* Print formfeed */ printf("\\Kprintff Output Form Feed to SET PRINTER device\n"); break; case K_FLIPSCN : /* Flip screen */ printf("\\Kflipscn Reverse foreground and background colors\n"); break; case K_DEBUG : /* Toggle debugging */ printf("\\Kdebug Toggle Terminal Debug mode\n"); break; case K_TN_SAK : /* TELNET Secure Access Key */ printf("\\Ktn_sak TELNET: IBM Secure Access Key\n"); printf(" Used to request a Trusted Shell with AIX\n"); break; case K_TN_AO : /* TELNET Cancel Output */ printf("\\Ktn_ao TELNET: Transmit Cancel-Output request\n"); break; case K_TN_AYT : /* TELNET Are You There */ printf("\\Ktn_ayt TELNET: Transmit Are You There? request\n"); break; case K_TN_EC : /* TELNET Erase Character */ printf("\\Ktn_ec TELNET: Transmit Erase Character request\n"); break; case K_TN_EL : /* TELNET Erase Line */ printf("\\Ktn_el TELNET: Transmit Erase Line request\n"); break; case K_TN_GA : /* TELNET Go Ahead */ printf("\\Ktn_ga TELNET: Transmit Go Ahead request\n"); break; case K_TN_IP : /* TELNET Interrupt Process */ printf("\\Ktn_ip TELNET: Transmit Interrupt Process request\n"); break; case K_TN_LOGOUT : /* TELNET Logout */ printf("\\Ktn_logout TELNET: Transmit Do Logout Option\n"); break; case K_TN_NAWS : /* TELNET NAWS */ printf( "\\Ktn_naws TELNET: Transmit Window Size if NAWS is active\n"); break; case K_PASTE : /* Paste data from clipboard */ printf("\\Kpaste Paste data from clipboard to host\n"); break; case K_CLRSCRN : /* Clear Terminal Screen */ printf("\\Kclearscreen Clear the Terminal screen\n"); break; case K_PRTAUTO : /* Print Auto mode */ printf("\\Kprtauto Toggle Auto-Print mode\n"); break; case K_PRTCOPY : /* Print Copy mode */ printf("\\Kprtcopy Toggle Copy-Print mode\n"); break; case K_ANSWERBACK : /* Transmit Answerback String */ printf("\\Kanswerback Transmit answerback string to host\n"); break; case K_SET_BOOK : /* Set Bookmark */ printf("\\Ksetbook Set bookmark\n"); break; case K_QUIT : /* Quit Kermit */ printf("\\Kquit Hangup connection and quit kermit\n"); break; case K_KEYCLICK : /* Toggle Keyclick */ printf("\\Kkeyclick Toggle Keyclick mode\n"); break; case K_LOGDEBUG : /* Toggle Debug Log File */ printf("\\Kdebuglog Toggle Debug Logging to File\n"); break; case K_FNKEYS : /* Show Function Key Labels */ printf("\\Kfnkeys Display Function Key Labels\n"); break; #ifdef OS2MOUSE /* Mouse only Kverbs */ case K_MOUSE_CURPOS : printf("\\Kmousecurpos Mouse: Move host cursor to position\n"); break; case K_MOUSE_MARK : printf( "\\Kmousemark Mouse: Mark text for selection (drag event only)\n"); break; case K_MOUSE_URL : printf("\\Kmouseurl Mouse: Start browser with selected URL\n"); break; #endif /* OS2MOUSE */ /* ANSI Function Key definitions */ case K_ANSIF01 : printf("\\Kansif01 Transmit SCOANSI/AT386: F1 \n"); break; case K_ANSIF02 : printf("\\Kansif02 Transmit SCOANSI/AT386: F2 \n"); break; case K_ANSIF03 : printf("\\Kansif03 Transmit SCOANSI/AT386: F3 \n"); break; case K_ANSIF04 : printf("\\Kansif04 Transmit SCOANSI/AT386: F4 \n"); break; case K_ANSIF05 : printf("\\Kansif05 Transmit SCOANSI/AT386: F5 \n"); break; case K_ANSIF06 : printf("\\Kansif06 Transmit SCOANSI/AT386: F6 \n"); break; case K_ANSIF07 : printf("\\Kansif07 Transmit SCOANSI/AT386: F7 \n"); break; case K_ANSIF08 : printf("\\Kansif08 Transmit SCOANSI/AT386: F8 \n"); break; case K_ANSIF09 : printf("\\Kansif09 Transmit SCOANSI/AT386: F9 \n"); break; case K_ANSIF10 : printf("\\Kansif10 Transmit SCOANSI/AT386: F10\n"); break; case K_ANSIF11 : printf("\\Kansif11 Transmit SCOANSI/AT386: F11\n"); break; case K_ANSIF12 : printf("\\Kansif12 Transmit SCOANSI/AT386: F12\n"); break; case K_ANSIF13 : printf("\\Kansif13 Transmit SCOANSI/AT386: Shift-F1 \n"); break; case K_ANSIF14 : printf("\\Kansif14 Transmit SCOANSI/AT386: Shift-F2 \n"); break; case K_ANSIF15 : printf("\\Kansif15 Transmit SCOANSI/AT386: Shift-F3 \n"); break; case K_ANSIF16 : printf("\\Kansif16 Transmit SCOANSI/AT386: Shift-F4 \n"); break; case K_ANSIF17 : printf("\\Kansif17 Transmit SCOANSI/AT386: Shift-F5 \n"); break; case K_ANSIF18 : printf("\\Kansif18 Transmit SCOANSI/AT386: Shift-F6 \n"); break; case K_ANSIF19 : printf("\\Kansif19 Transmit SCOANSI/AT386: Shift-F7 \n"); break; case K_ANSIF20 : printf("\\Kansif20 Transmit SCOANSI/AT386: Shift-F8 \n"); break; case K_ANSIF21 : printf("\\Kansif21 Transmit SCOANSI/AT386: Shift-F9 \n"); break; case K_ANSIF22 : printf("\\Kansif22 Transmit SCOANSI/AT386: Shift-F10\n"); break; case K_ANSIF23 : printf("\\Kansif23 Transmit SCOANSI/AT386: Shift-F11\n"); break; case K_ANSIF24 : printf("\\Kansif24 Transmit SCOANSI/AT386: Shift-F12\n"); break; case K_ANSIF25 : printf("\\Kansif25 Transmit SCOANSI/AT386: Ctrl-F1 \n"); break; case K_ANSIF26 : printf("\\Kansif26 Transmit SCOANSI/AT386: Ctrl-F2 \n"); break; case K_ANSIF27 : printf("\\Kansif27 Transmit SCOANSI/AT386: Ctrl-F3 \n"); break; case K_ANSIF28 : printf("\\Kansif28 Transmit SCOANSI/AT386: Ctrl-F4 \n"); break; case K_ANSIF29 : printf("\\Kansif29 Transmit SCOANSI/AT386: Ctrl-F5 \n"); break; case K_ANSIF30 : printf("\\Kansif30 Transmit SCOANSI/AT386: Ctrl-F6 \n"); break; case K_ANSIF31 : printf("\\Kansif31 Transmit SCOANSI/AT386: Ctrl-F7 \n"); break; case K_ANSIF32 : printf("\\Kansif32 Transmit SCOANSI/AT386: Ctrl-F8 \n"); break; case K_ANSIF33 : printf("\\Kansif33 Transmit SCOANSI/AT386: Ctrl-F9 \n"); break; case K_ANSIF34 : printf("\\Kansif34 Transmit SCOANSI/AT386: Ctrl-F10\n"); break; case K_ANSIF35 : printf("\\Kansif35 Transmit SCOANSI/AT386: Ctrl-F11\n"); break; case K_ANSIF36 : printf("\\Kansif36 Transmit SCOANSI/AT386: Ctrl-F12\n"); break; case K_ANSIF37 : printf("\\Kansif37 Transmit SCOANSI/AT386: Ctrl-Shift-F1 \n"); break; case K_ANSIF38 : printf("\\Kansif38 Transmit SCOANSI/AT386: Ctrl-Shift-F2 \n"); break; case K_ANSIF39 : printf("\\Kansif39 Transmit SCOANSI/AT386: Ctrl-Shift-F3 \n"); break; case K_ANSIF40 : printf("\\Kansif40 Transmit SCOANSI/AT386: Ctrl-Shift-F4 \n"); break; case K_ANSIF41 : printf("\\Kansif41 Transmit SCOANSI/AT386: Ctrl-Shift-F5 \n"); break; case K_ANSIF42 : printf("\\Kansif42 Transmit SCOANSI/AT386: Ctrl-Shift-F6 \n"); break; case K_ANSIF43 : printf("\\Kansif43 Transmit SCOANSI/AT386: Ctrl-Shift-F7 \n"); break; case K_ANSIF44 : printf("\\Kansif44 Transmit SCOANSI/AT386: Ctrl-Shift-F8 \n"); break; case K_ANSIF45 : printf("\\Kansif45 Transmit SCOANSI/AT386: Ctrl-Shift-F9 \n"); break; case K_ANSIF46 : printf("\\Kansif46 Transmit SCOANSI/AT386: Ctrl-Shift-F10\n"); break; case K_ANSIF47 : printf("\\Kansif47 Transmit SCOANSI/AT386: Ctrl-Shift-F11\n"); break; case K_ANSIF48 : printf("\\Kansif48 Transmit SCOANSI/AT386: Ctrl-Shift-F12\n"); break; case K_ANSIF49 : printf("\\Kansif49 Transmit SCOANSI/AT386: Home\n"); break; case K_ANSIF50 : printf("\\Kansif50 Transmit SCOANSI/AT386: Up Arrow\n"); break; case K_ANSIF51 : printf("\\Kansif51 Transmit SCOANSI/AT386: PgUp\n"); break; case K_ANSIF52 : printf("\\Kansif52 Transmit SCOANSI/AT386: Ctrl-Shift-Subtract\n"); break; case K_ANSIF53 : printf("\\Kansif53 Transmit SCOANSI/AT386: Left Arrow\n"); break; case K_ANSIF54 : printf("\\Kansif54 Transmit SCOANSI/AT386: Clear\n"); break; case K_ANSIF55 : printf("\\Kansif55 Transmit SCOANSI/AT386: Right Arrow\n"); break; case K_ANSIF56 : printf("\\Kansif56 Transmit SCOANSI/AT386: Shift-Add\n"); break; case K_ANSIF57 : printf("\\Kansif57 Transmit SCOANSI/AT386: End\n"); break; case K_ANSIF58 : printf("\\Kansif58 Transmit SCOANSI/AT386: Down Arrow\n"); break; case K_ANSIF59 : printf("\\Kansif59 Transmit SCOANSI/AT386: PgDn\n"); break; case K_ANSIF60 : printf("\\Kansif60 Transmit SCOANSI/AT386: Insert\n"); break; case K_ANSIF61 : printf("\\Kansif61 Transmit SCOANSI/AT386: (not named)\n"); break; /* WYSE Function Keys (unshifted) */ case K_WYF01 : printf("\\Kwyf01 Transmit WYSE 30/50/60/160: F1\n"); break; case K_WYF02 : printf("\\Kwyf02 Transmit WYSE 30/50/60/160: F2\n"); break; case K_WYF03 : printf("\\Kwyf03 Transmit WYSE 30/50/60/160: F3\n"); break; case K_WYF04 : printf("\\Kwyf04 Transmit WYSE 30/50/60/160: F4\n"); break; case K_WYF05 : printf("\\Kwyf05 Transmit WYSE 30/50/60/160: F5\n"); break; case K_WYF06 : printf("\\Kwyf06 Transmit WYSE 30/50/60/160: F6\n"); break; case K_WYF07 : printf("\\Kwyf07 Transmit WYSE 30/50/60/160: F7\n"); break; case K_WYF08 : printf("\\Kwyf08 Transmit WYSE 30/50/60/160: F8\n"); break; case K_WYF09 : printf("\\Kwyf09 Transmit WYSE 30/50/60/160: F9\n"); break; case K_WYF10 : printf("\\Kwyf10 Transmit WYSE 30/50/60/160: F10\n"); break; case K_WYF11 : printf("\\Kwyf11 Transmit WYSE 30/50/60/160: F11\n"); break; case K_WYF12 : printf("\\Kwyf12 Transmit WYSE 30/50/60/160: F12\n"); break; case K_WYF13 : printf("\\Kwyf13 Transmit WYSE 30/50/60/160: F13\n"); break; case K_WYF14 : printf("\\Kwyf14 Transmit WYSE 30/50/60/160: F14\n"); break; case K_WYF15 : printf("\\Kwyf15 Transmit WYSE 30/50/60/160: F15\n"); break; case K_WYF16 : printf("\\Kwyf16 Transmit WYSE 30/50/60/160: F16\n"); break; case K_WYF17 : printf("\\Kwyf17 Transmit WYSE 30/50/60/160: F17\n"); break; case K_WYF18 : printf("\\Kwyf18 Transmit WYSE 30/50/60/160: F18\n"); break; case K_WYF19 : printf("\\Kwyf19 Transmit WYSE 30/50/60/160: F19\n"); break; case K_WYF20 : printf("\\Kwyf20 Transmit WYSE 30/50/60/160: F20\n"); break; /* WYSE Function Keys (shifted) */ case K_WYSF01 : printf("\\Kwysf01 Transmit WYSE 30/50/60/160: Shift-F1\n"); break; case K_WYSF02 : printf("\\Kwysf02 Transmit WYSE 30/50/60/160: Shift-F2\n"); break; case K_WYSF03 : printf("\\Kwysf03 Transmit WYSE 30/50/60/160: Shift-F3\n"); break; case K_WYSF04 : printf("\\Kwysf04 Transmit WYSE 30/50/60/160: Shift-F4\n"); break; case K_WYSF05 : printf("\\Kwysf05 Transmit WYSE 30/50/60/160: Shift-F5\n"); break; case K_WYSF06 : printf("\\Kwysf06 Transmit WYSE 30/50/60/160: Shift-F6\n"); break; case K_WYSF07 : printf("\\Kwysf07 Transmit WYSE 30/50/60/160: Shift-F7\n"); break; case K_WYSF08 : printf("\\Kwysf08 Transmit WYSE 30/50/60/160: Shift-F8\n"); break; case K_WYSF09 : printf("\\Kwysf09 Transmit WYSE 30/50/60/160: Shift-F9\n"); break; case K_WYSF10 : printf("\\Kwysf10 Transmit WYSE 30/50/60/160: Shift-F10\n"); break; case K_WYSF11 : printf("\\Kwysf11 Transmit WYSE 30/50/60/160: Shift-F11\n"); break; case K_WYSF12 : printf("\\Kwysf12 Transmit WYSE 30/50/60/160: Shift-F12\n"); break; case K_WYSF13 : printf("\\Kwysf13 Transmit WYSE 30/50/60/160: Shift-F13\n"); break; case K_WYSF14 : printf("\\Kwysf14 Transmit WYSE 30/50/60/160: Shift-F14\n"); break; case K_WYSF15 : printf("\\Kwysf15 Transmit WYSE 30/50/60/160: Shift-F15\n"); break; case K_WYSF16 : printf("\\Kwysf16 Transmit WYSE 30/50/60/160: Shift-F16\n"); break; case K_WYSF17 : printf("\\Kwysf17 Transmit WYSE 30/50/60/160: Shift-F17\n"); break; case K_WYSF18 : printf("\\Kwysf18 Transmit WYSE 30/50/60/160: Shift-F18\n"); break; case K_WYSF19 : printf("\\Kwysf19 Transmit WYSE 30/50/60/160: Shift-F19\n"); break; case K_WYSF20 : printf("\\Kwysf20 Transmit WYSE 30/50/60/160: Shift-F20\n"); break; /* WYSE Edit and Special Keys */ case K_WYBS : printf("\\Kwybs Transmit WYSE 30/50/60/160: Backspace\n"); break; case K_WYCLRLN : printf("\\Kwyclrln Transmit WYSE 30/50/60/160: Clear Line\n"); break; case K_WYSCLRLN : printf("\\Kwysclrln Transmit WYSE 30/50/60/160: Shift-Clear Line\n"); break; case K_WYCLRPG : printf("\\Kwyclrpg Transmit WYSE 30/50/60/160: Clear Page\n"); break; case K_WYSCLRPG : printf("\\Kwysclrpg Transmit WYSE 30/50/60/160: Shift-Clear Page\n"); break; case K_WYDELCHAR : printf("\\Kwydelchar Transmit WYSE 30/50/60/160: Delete Char\n"); break; case K_WYDELLN : printf("\\Kwydelln Transmit WYSE 30/50/60/160: Delete Line\n"); break; case K_WYENTER : printf("\\Kwyenter Transmit WYSE 30/50/60/160: Enter\n"); break; case K_WYESC : printf("\\Kwyesc Transmit WYSE 30/50/60/160: Esc\n"); break; case K_WYHOME : printf("\\Kwyhome Transmit WYSE 30/50/60/160: Home\n"); break; case K_WYSHOME : printf("\\Kwyshome Transmit WYSE 30/50/60/160: Shift-Home\n"); break; case K_WYINSERT : printf("\\Kwyinsert Transmit WYSE 30/50/60/160: Insert\n"); break; case K_WYINSCHAR : printf("\\Kwyinschar Transmit WYSE 30/50/60/160: Insert Char\n"); break; case K_WYINSLN : printf("\\Kwyinsln Transmit WYSE 30/50/60/160: Insert Line\n"); break; case K_WYPGNEXT : printf("\\Kwypgnext Transmit WYSE 30/50/60/160: Page Next\n"); break; case K_WYPGPREV : printf("\\Kwypgprev Transmit WYSE 30/50/60/160: Page Previous\n"); break; case K_WYREPLACE : printf("\\Kwyreplace Transmit WYSE 30/50/60/160: Replace \n"); break; case K_WYRETURN : printf("\\Kwyreturn Transmit WYSE 30/50/60/160: Return \n"); break; case K_WYTAB : printf("\\Kwytab Transmit WYSE 30/50/60/160: Tab \n"); break; case K_WYSTAB : printf("\\Kwystab Transmit WYSE 30/50/60/160: Shift-Tab \n"); break; case K_WYPRTSCN : printf("\\Kwyprtscn Transmit WYSE 30/50/60/160: Print Screen \n"); break; case K_WYSESC : printf("\\Kwysesc Transmit WYSE 30/50/60/160: Shift-Esc \n"); break; case K_WYSBS : printf("\\Kwysbs Transmit WYSE 30/50/60/160: Shift-Backspace\n"); break; case K_WYSENTER : printf("\\Kwysenter Transmit WYSE 30/50/60/160: Shift-Enter\n"); break; case K_WYSRETURN : printf("\\Kwysreturn Transmit WYSE 30/50/60/160: Shift-Return\n"); break; case K_WYUPARR : printf("\\Kwyuparr Transmit WYSE 30/50/60/160: Up Arrow\n"); break; case K_WYDNARR : printf("\\Kwydnarr Transmit WYSE 30/50/60/160: Down Arrow\n"); break; case K_WYLFARR : printf("\\Kwylfarr Transmit WYSE 30/50/60/160: Left Arrow\n"); break; case K_WYRTARR : printf("\\Kwyrtarr Transmit WYSE 30/50/60/160: Right Arrow\n"); break; case K_WYSUPARR : printf("\\Kwysuparr Transmit WYSE 30/50/60/160: Shift-Up Arrow\n"); break; case K_WYSDNARR : printf("\\Kwysdnarr Transmit WYSE 30/50/60/160: Shift-Down Arrow\n"); break; case K_WYSLFARR : printf("\\Kwyslfarr Transmit WYSE 30/50/60/160: Shift-Left Arrow\n"); break; case K_WYSRTARR : printf("\\Kwysrtarr Transmit WYSE 30/50/60/160: Shift-Right Arrow\n"); break; case K_WYSEND: printf("\\Kwysend Transmit WYSE 30/50/60/160: Send\n"); break; case K_WYSSEND: printf("\\Kwyssend Transmit WYSE 30/50/60/160: Shift-Send\n"); break; /* Data General Function Keys (unshifted) */ case K_DGF01 : printf("\\Kdgf01 Transmit Data General: F1 \n"); break; case K_DGF02 : printf("\\Kdgf01 Transmit Data General: F2 \n"); break; case K_DGF03 : printf("\\Kdgf01 Transmit Data General: F3 \n"); break; case K_DGF04 : printf("\\Kdgf01 Transmit Data General: F4 \n"); break; case K_DGF05 : printf("\\Kdgf01 Transmit Data General: F5 \n"); break; case K_DGF06 : printf("\\Kdgf01 Transmit Data General: F6 \n"); break; case K_DGF07 : printf("\\Kdgf01 Transmit Data General: F7 \n"); break; case K_DGF08 : printf("\\Kdgf01 Transmit Data General: F8 \n"); break; case K_DGF09 : printf("\\Kdgf01 Transmit Data General: F9 \n"); break; case K_DGF10 : printf("\\Kdgf01 Transmit Data General: F10 \n"); break; case K_DGF11 : printf("\\Kdgf01 Transmit Data General: F11 \n"); break; case K_DGF12 : printf("\\Kdgf01 Transmit Data General: F12 \n"); break; case K_DGF13 : printf("\\Kdgf01 Transmit Data General: F13 \n"); break; case K_DGF14 : printf("\\Kdgf01 Transmit Data General: F14 \n"); break; case K_DGF15 : printf("\\Kdgf01 Transmit Data General: F15 \n"); break; /* Data General Function Keys (shifted) */ case K_DGSF01 : printf( "\\Kdgsf01 Transmit Data General: Shift-F1 \n"); break; case K_DGSF02 : printf( "\\Kdgsf02 Transmit Data General: Shift-F2 \n"); break; case K_DGSF03 : printf( "\\Kdgsf03 Transmit Data General: Shift-F3 \n"); break; case K_DGSF04 : printf( "\\Kdgsf04 Transmit Data General: Shift-F4 \n"); break; case K_DGSF05 : printf( "\\Kdgsf05 Transmit Data General: Shift-F5 \n"); break; case K_DGSF06 : printf( "\\Kdgsf06 Transmit Data General: Shift-F6 \n"); break; case K_DGSF07 : printf( "\\Kdgsf07 Transmit Data General: Shift-F7 \n"); break; case K_DGSF08 : printf( "\\Kdgsf08 Transmit Data General: Shift-F8 \n"); break; case K_DGSF09 : printf( "\\Kdgsf09 Transmit Data General: Shift-F9 \n"); break; case K_DGSF10 : printf( "\\Kdgsf10 Transmit Data General: Shift-F10 \n"); break; case K_DGSF11 : printf( "\\Kdgsf11 Transmit Data General: Shift-F11 \n"); break; case K_DGSF12 : printf( "\\Kdgsf12 Transmit Data General: Shift-F12 \n"); break; case K_DGSF13 : printf( "\\Kdgsf13 Transmit Data General: Shift-F13 \n"); break; case K_DGSF14 : printf( "\\Kdgsf14 Transmit Data General: Shift-F14 \n"); break; case K_DGSF15 : printf( "\\Kdgsf15 Transmit Data General: Shift-F15 \n"); break; /* Data General Function Keys (control) */ case K_DGCF01 : printf( "\\Kdgcf01 Transmit Data General: Ctrl-F1 \n"); break; case K_DGCF02 : printf( "\\Kdgcf02 Transmit Data General: Ctrl-F2 \n"); break; case K_DGCF03 : printf( "\\Kdgcf03 Transmit Data General: Ctrl-F3 \n"); break; case K_DGCF04 : printf( "\\Kdgcf04 Transmit Data General: Ctrl-F4 \n"); break; case K_DGCF05 : printf( "\\Kdgcf05 Transmit Data General: Ctrl-F5 \n"); break; case K_DGCF06 : printf( "\\Kdgcf06 Transmit Data General: Ctrl-F6 \n"); break; case K_DGCF07 : printf( "\\Kdgcf07 Transmit Data General: Ctrl-F7 \n"); break; case K_DGCF08 : printf( "\\Kdgcf08 Transmit Data General: Ctrl-F8 \n"); break; case K_DGCF09 : printf( "\\Kdgcf09 Transmit Data General: Ctrl-F9 \n"); break; case K_DGCF10 : printf( "\\Kdgcf10 Transmit Data General: Ctrl-F10 \n"); break; case K_DGCF11 : printf( "\\Kdgcf11 Transmit Data General: Ctrl-F11 \n"); break; case K_DGCF12 : printf( "\\Kdgcf12 Transmit Data General: Ctrl-F12 \n"); break; case K_DGCF13 : printf( "\\Kdgcf13 Transmit Data General: Ctrl-F13 \n"); break; case K_DGCF14 : printf( "\\Kdgcf14 Transmit Data General: Ctrl-F14 \n"); break; case K_DGCF15 : printf( "\\Kdgcf15 Transmit Data General: Ctrl-F15 \n"); break; /* Data General Function Keys (control shifted) */ case K_DGCSF01 : printf( "\\Kdgcsf01 Transmit Data General: Ctrl-Shift-F1 \n"); break; case K_DGCSF02 : printf( "\\Kdgcsf02 Transmit Data General: Ctrl-Shift-F2 \n"); break; case K_DGCSF03 : printf( "\\Kdgcsf03 Transmit Data General: Ctrl-Shift-F3 \n"); break; case K_DGCSF04 : printf( "\\Kdgcsf04 Transmit Data General: Ctrl-Shift-F4 \n"); break; case K_DGCSF05 : printf( "\\Kdgcsf05 Transmit Data General: Ctrl-Shift-F5 \n"); break; case K_DGCSF06 : printf( "\\Kdgcsf06 Transmit Data General: Ctrl-Shift-F6 \n"); break; case K_DGCSF07 : printf( "\\Kdgcsf07 Transmit Data General: Ctrl-Shift-F7 \n"); break; case K_DGCSF08 : printf( "\\Kdgcsf08 Transmit Data General: Ctrl-Shift-F8 \n"); break; case K_DGCSF09 : printf( "\\Kdgcsf09 Transmit Data General: Ctrl-Shift-F9 \n"); break; case K_DGCSF10 : printf( "\\Kdgcsf10 Transmit Data General: Ctrl-Shift-F10 \n"); break; case K_DGCSF11 : printf( "\\Kdgcsf11 Transmit Data General: Ctrl-Shift-F11 \n"); break; case K_DGCSF12 : printf( "\\Kdgcsf12 Transmit Data General: Ctrl-Shift-F12 \n"); break; case K_DGCSF13 : printf( "\\Kdgcsf13 Transmit Data General: Ctrl-Shift-F13 \n"); break; case K_DGCSF14 : printf( "\\Kdgcsf14 Transmit Data General: Ctrl-Shift-F14 \n"); break; case K_DGCSF15 : printf( "\\Kdgcsf15 Transmit Data General: Ctrl-Shift-F15 \n"); break; case K_DGUPARR : printf("\\Kdguparr Transmit Data General: Up Arrow \n"); break; case K_DGDNARR : printf("\\Kdgdnarr Transmit Data General: Down Arrow \n"); break; case K_DGLFARR : printf("\\Kdglfarr Transmit Data General: Left Arrow \n"); break; case K_DGRTARR : printf("\\Kdgrtarr Transmit Data General: Right Arrow \n"); break; case K_DGSUPARR : printf("\\Kdgsuparr Transmit Data General: Shift-Up Arrow \n"); break; case K_DGSDNARR : printf("\\Kdgsdnarr Transmit Data General: Shift-Down Arrow \n"); break; case K_DGSLFARR : printf("\\Kdgslfarr Transmit Data General: Shift-Left Arrow \n"); break; case K_DGSRTARR : printf("\\Kdgsrtarr Transmit Data General: Shift-Right Arrow \n"); break; case K_DGERASEPAGE : printf("\\Kdgerasepage Transmit Data General: Erase Page \n"); break; case K_DGC1 : printf("\\Kdgc1 Transmit Data General: C1 \n"); break; case K_DGC2 : printf("\\Kdgc2 Transmit Data General: C2 \n"); break; case K_DGERASEEOL : printf("\\Kdgeraseeol Transmit Data General: Erase EOL \n"); break; case K_DGC3 : printf("\\Kdgc3 Transmit Data General: C3 \n"); break; case K_DGC4 : printf("\\Kdgc4 Transmit Data General: C4 \n"); break; case K_DGCMDPRINT : printf("\\Kdgcmdprint Transmit Data General: Command Print \n"); break; case K_DGHOME : printf("\\Kdghome Transmit Data General: Home \n"); break; case K_DGSERASEPAGE : printf("\\Kdgserasepage Transmit Data General: Erase Page \n"); break; case K_DGSC1 : printf("\\Kdgsc1 Transmit Data General: Shift-C1 \n"); break; case K_DGSC2 : printf("\\Kdgsc2 Transmit Data General: Shift-C2 \n"); break; case K_DGSERASEEOL : printf("\\Kdgseraseeol Transmit Data General: Shift-Erase EOL \n"); break; case K_DGSC3 : printf("\\Kdgsc3 Transmit Data General: Shift-C3 \n"); break; case K_DGSC4 : printf("\\Kdgsc4 Transmit Data General: Shift-C4 \n"); break; case K_DGSCMDPRINT : printf("\\Kdgscmdprint Transmit Data General: Shift-Command Print\n"); break; case K_DGBS : printf("\\Kdgbs Transmit Data General: Backspace \n"); break; case K_DGSHOME : printf("\\Kdgshome Transmit Data General: Shift-Home \n"); break; /* Televideo Function Keys (unshifted) */ case K_TVIF01 : printf("\\Ktvif01 Transmit Televideo: F1 \n"); break; case K_TVIF02 : printf("\\Ktvif02 Transmit Televideo: F2 \n"); break; case K_TVIF03 : printf("\\Ktvif03 Transmit Televideo: F3 \n"); break; case K_TVIF04 : printf("\\Ktvif04 Transmit Televideo: F4 \n"); break; case K_TVIF05 : printf("\\Ktvif05 Transmit Televideo: F5 \n"); break; case K_TVIF06 : printf("\\Ktvif06 Transmit Televideo: F6 \n"); break; case K_TVIF07 : printf("\\Ktvif07 Transmit Televideo: F7 \n"); break; case K_TVIF08 : printf("\\Ktvif08 Transmit Televideo: F8 \n"); break; case K_TVIF09 : printf("\\Ktvif09 Transmit Televideo: F9 \n"); break; case K_TVIF10 : printf("\\Ktvif10 Transmit Televideo: F10 \n"); break; case K_TVIF11 : printf("\\Ktvif11 Transmit Televideo: F11 \n"); break; case K_TVIF12 : printf("\\Ktvif12 Transmit Televideo: F12 \n"); break; case K_TVIF13 : printf("\\Ktvif13 Transmit Televideo: F13 \n"); break; case K_TVIF14 : printf("\\Ktvif14 Transmit Televideo: F14 \n"); break; case K_TVIF15 : printf("\\Ktvif15 Transmit Televideo: F15 \n"); break; case K_TVIF16 : printf("\\Ktvif16 Transmit Televideo: F16 \n"); break; /* Televideo Function Keys (shifted) */ case K_TVISF01 : printf("\\Ktvisf01 Transmit Televideo: Shift-F1 \n"); break; case K_TVISF02 : printf("\\Ktvisf02 Transmit Televideo: Shift-F2 \n"); break; case K_TVISF03 : printf("\\Ktvisf03 Transmit Televideo: Shift-F3 \n"); break; case K_TVISF04 : printf("\\Ktvisf04 Transmit Televideo: Shift-F4 \n"); break; case K_TVISF05 : printf("\\Ktvisf05 Transmit Televideo: Shift-F5 \n"); break; case K_TVISF06 : printf("\\Ktvisf06 Transmit Televideo: Shift-F6 \n"); break; case K_TVISF07 : printf("\\Ktvisf07 Transmit Televideo: Shift-F7 \n"); break; case K_TVISF08 : printf("\\Ktvisf08 Transmit Televideo: Shift-F8 \n"); break; case K_TVISF09 : printf("\\Ktvisf09 Transmit Televideo: Shift-F9 \n"); break; case K_TVISF10 : printf("\\Ktvisf10 Transmit Televideo: Shift-F10\n"); break; case K_TVISF11 : printf("\\Ktvisf11 Transmit Televideo: Shift-F11\n"); break; case K_TVISF12 : printf("\\Ktvisf12 Transmit Televideo: Shift-F12\n"); break; case K_TVISF13 : printf("\\Ktvisf13 Transmit Televideo: Shift-F13\n"); break; case K_TVISF14 : printf("\\Ktvisf14 Transmit Televideo: Shift-F14\n"); break; case K_TVISF15 : printf("\\Ktvisf15 Transmit Televideo: Shift-F15\n"); break; case K_TVISF16 : printf("\\Ktvisf16 Transmit Televideo: Shift-F16\n"); break; /* Televideo Edit and Special Keys */ case K_TVIBS : printf("\\Ktvibs Transmit Televideo: Backspace \n"); break; case K_TVICLRLN : printf("\\Ktviclrln Transmit Televideo: Clear Line \n"); break; case K_TVISCLRLN : printf("\\Ktvisclrln Transmit Televideo: Shift-Clear Line\n"); break; case K_TVICLRPG : printf("\\Ktviclrpg Transmit Televideo: Clear Page \n"); break; case K_TVISCLRPG : printf("\\Ktvisclrpg Transmit Televideo: Shift-Clear Page\n"); break; case K_TVIDELCHAR : printf("\\Ktvidelchar Transmit Televideo: Delete Char \n"); break; case K_TVIDELLN : printf("\\Ktvidelln Transmit Televideo: Delete Line \n"); break; case K_TVIENTER : printf("\\Ktvienter Transmit Televideo: Enter \n"); break; case K_TVIESC : printf("\\Ktviesc Transmit Televideo: Esc \n"); break; case K_TVIHOME : printf("\\Ktvihome Transmit Televideo: Home \n"); break; case K_TVISHOME : printf("\\Ktvishome Transmit Televideo: Shift-Home \n"); break; case K_TVIINSERT : printf("\\Ktviinsert Transmit Televideo: Insert \n"); break; case K_TVIINSCHAR : printf("\\Ktviinschar Transmit Televideo: Insert Char \n"); break; case K_TVIINSLN : printf("\\Ktviinsln Transmit Televideo: Insert Line \n"); break; case K_TVIPGNEXT : printf("\\Ktvipgnext Transmit Televideo: Page Next \n"); break; case K_TVIPGPREV : printf("\\Ktvipgprev Transmit Televideo: Page Previous \n"); break; case K_TVIREPLACE : printf("\\Ktvireplace Transmit Televideo: Replace \n"); break; case K_TVIRETURN : printf("\\Ktvireturn Transmit Televideo: Return \n"); break; case K_TVITAB : printf("\\Ktvitab Transmit Televideo: Tab \n"); break; case K_TVISTAB : printf("\\Ktvistab Transmit Televideo: Shift-Tab \n"); break; case K_TVIPRTSCN : printf("\\Ktviprtscn Transmit Televideo: Print Screen \n"); break; case K_TVISESC : printf("\\Ktvisesc Transmit Televideo: Shift-Esc \n"); break; case K_TVISBS : printf("\\Ktvisbs Transmit Televideo: Shift-Backspace \n"); break; case K_TVISENTER : printf("\\Ktvisenter Transmit Televideo: Shift-Enter \n"); break; case K_TVISRETURN : printf("\\Ktvisreturn Transmit Televideo: Shift-Return \n"); break; case K_TVIUPARR : printf("\\Ktviuparr Transmit Televideo: Up Arrow \n"); break; case K_TVIDNARR : printf("\\Ktvidnarr Transmit Televideo: Down Arrow \n"); break; case K_TVILFARR : printf("\\Ktvilfarr Transmit Televideo: Left Arrow \n"); break; case K_TVIRTARR : printf("\\Ktvirtarr Transmit Televideo: Right Arrow \n"); break; case K_TVISUPARR : printf("\\Ktvisuparr Transmit Televideo: Shift-Up Arrow \n"); break; case K_TVISDNARR : printf("\\Ktvisdnarr Transmit Televideo: Shift-Down Arrow\n"); break; case K_TVISLFARR : printf("\\Ktvislfarr Transmit Televideo: Shift-Left Arrow\n"); break; case K_TVISRTARR : printf("\\Ktvisrtarr Transmit Televideo: Shift-Right Arrow\n"); break; case K_TVISEND: printf("\\Ktvisend Transmit Televideo: Send\n"); break; case K_TVISSEND: printf("\\Ktvissend Transmit Televideo: Shift-Send\n"); break; /* HP Function and Edit keys */ case K_HPF01 : printf("\\Khpf01 Transmit Hewlett-Packard: F1 \n"); break; case K_HPF02 : printf("\\Khpf02 Transmit Hewlett-Packard: F2 \n"); break; case K_HPF03 : printf("\\Khpf03 Transmit Hewlett-Packard: F3 \n"); break; case K_HPF04 : printf("\\Khpf04 Transmit Hewlett-Packard: F4 \n"); break; case K_HPF05 : printf("\\Khpf05 Transmit Hewlett-Packard: F5 \n"); break; case K_HPF06 : printf("\\Khpf06 Transmit Hewlett-Packard: F6 \n"); break; case K_HPF07 : printf("\\Khpf07 Transmit Hewlett-Packard: F7 \n"); break; case K_HPF08 : printf("\\Khpf08 Transmit Hewlett-Packard: F8 \n"); break; case K_HPF09 : printf("\\Khpf09 Transmit Hewlett-Packard: F9 \n"); break; case K_HPF10 : printf("\\Khpf10 Transmit Hewlett-Packard: F10 \n"); break; case K_HPF11 : printf("\\Khpf11 Transmit Hewlett-Packard: F11 \n"); break; case K_HPF12 : printf("\\Khpf12 Transmit Hewlett-Packard: F12 \n"); break; case K_HPF13 : printf("\\Khpf13 Transmit Hewlett-Packard: F13 \n"); break; case K_HPF14 : printf("\\Khpf14 Transmit Hewlett-Packard: F14 \n"); break; case K_HPF15 : printf("\\Khpf15 Transmit Hewlett-Packard: F15 \n"); break; case K_HPF16 : printf("\\Khpf16 Transmit Hewlett-Packard: F16 \n"); break; case K_HPRETURN : printf("\\Khpreturn Transmit Hewlett-Packard: Return\n"); break; case K_HPENTER : printf("\\Khpenter Transmit Hewlett-Packard: Enter (keypad)\n"); break; case K_HPBACKTAB : printf("\\Khpbacktab Transmit Hewlett-Packard: Back Tab\n"); break; /* Siemens Nixdorf International 97801-5xx kverbs */ case K_SNI_DOUBLE_0 : printf("\\Ksni_00 Transmit SNI-97801-5xx: Double-Zero\n"); break; case K_SNI_C_DOUBLE_0 : printf( "\\Ksni_c_00 Transmit SNI-97801-5xx: Ctrl-Double-Zero\n"); break; case K_SNI_C_CE : printf("\\Ksni_c_ce Transmit SNI-97801-5xx: Ctrl-CE\n"); break; case K_SNI_C_COMPOSE : printf("\\Ksni_c_compose Transmit SNI-97801-5xx: Ctrl-Compose\n"); break; case K_SNI_C_DELETE_CHAR : printf( "\\Ksni_c_del_char Transmit SNI-97801-5xx: Ctrl-Delete Char\n"); break; case K_SNI_C_DELETE_LINE : printf( "\\Ksni_c_del_line Transmit SNI-97801-5xx: Ctrl-Delete Line\n"); break; case K_SNI_C_DELETE_WORD : printf( "\\Ksni_c_del_word Transmit SNI-97801-5xx: Ctrl-Delete Word\n"); break; case K_SNI_C_CURSOR_DOWN : printf( "\\Ksni_c_dnarr Transmit SNI-97801-5xx: Ctrl-Cursor Down\n"); break; case K_SNI_C_ENDMARKE : printf("\\Ksni_c_endmarke Transmit SNI-97801-5xx: Ctrl-End Marke\n"); break; case K_SNI_C_F01 : printf("\\Ksni_c_f01 Transmit SNI-97801-5xx: Ctrl-F1\n"); break; case K_SNI_C_F02 : printf("\\Ksni_c_f02 Transmit SNI-97801-5xx: Ctrl-F2\n"); break; case K_SNI_C_F03 : printf("\\Ksni_c_f03 Transmit SNI-97801-5xx: Ctrl-F3\n"); break; case K_SNI_C_F04 : printf("\\Ksni_c_f04 Transmit SNI-97801-5xx: Ctrl-F4\n"); break; case K_SNI_C_F05 : printf("\\Ksni_c_f05 Transmit SNI-97801-5xx: Ctrl-F5\n"); break; case K_SNI_C_F06 : printf("\\Ksni_c_f06 Transmit SNI-97801-5xx: Ctrl-F6\n"); break; case K_SNI_C_F07 : printf("\\Ksni_c_f07 Transmit SNI-97801-5xx: Ctrl-F7\n"); break; case K_SNI_C_F08 : printf("\\Ksni_c_f08 Transmit SNI-97801-5xx: Ctrl-F8\n"); break; case K_SNI_C_F09 : printf("\\Ksni_c_f09 Transmit SNI-97801-5xx: Ctrl-F9\n"); break; case K_SNI_C_F10 : printf("\\Ksni_c_f10 Transmit SNI-97801-5xx: Ctrl-F10\n"); break; case K_SNI_C_F11 : printf("\\Ksni_c_f11 Transmit SNI-97801-5xx: Ctrl-F11\n"); break; case K_SNI_C_F12 : printf("\\Ksni_c_f12 Transmit SNI-97801-5xx: Ctrl-F12\n"); break; case K_SNI_C_F13 : printf("\\Ksni_c_f13 Transmit SNI-97801-5xx: Ctrl-F13\n"); break; case K_SNI_C_F14 : printf("\\Ksni_c_f14 Transmit SNI-97801-5xx: Ctrl-F14\n"); break; case K_SNI_C_F15 : printf("\\Ksni_c_f15 Transmit SNI-97801-5xx: Ctrl-F15\n"); break; case K_SNI_C_F16 : printf("\\Ksni_c_f16 Transmit SNI-97801-5xx: Ctrl-F16\n"); break; case K_SNI_C_F17 : printf("\\Ksni_c_f17 Transmit SNI-97801-5xx: Ctrl-F17\n"); break; case K_SNI_C_F18 : printf("\\Ksni_c_f18 Transmit SNI-97801-5xx: Ctrl-F18\n"); break; case K_SNI_C_USER1 : printf( "\\Ksni_c_user1 Transmit SNI-97801-5xx: Ctrl-Key below F18\n"); break; case K_SNI_C_F19 : printf("\\Ksni_c_f19 Transmit SNI-97801-5xx: Ctrl-F19\n"); break; case K_SNI_C_USER2 : printf( "\\Ksni_c_user2 Transmit SNI-97801-5xx: Ctrl-Key below F19\n"); break; case K_SNI_C_F20 : printf("\\Ksni_c_f20 Transmit SNI-97801-5xx: Ctrl-F20\n"); break; case K_SNI_C_USER3 : printf( "\\Ksni_c_user3 Transmit SNI-97801-5xx: Ctrl-Key below F20\n"); break; case K_SNI_C_F21 : printf("\\Ksni_c_f21 Transmit SNI-97801-5xx: Ctrl-F21\n"); break; case K_SNI_C_USER4 : printf( "\\Ksni_c_user4 Transmit SNI-97801-5xx: Ctrl-Key below F21\n"); break; case K_SNI_C_F22 : printf("\\Ksni_c_f22 Transmit SNI-97801-5xx: Ctrl-F22\n"); break; case K_SNI_C_USER5 : printf( "\\Ksni_c_user5 Transmit SNI-97801-5xx: Ctrl-Key below F22\n"); break; case K_SNI_C_HELP : printf("\\Ksni_c_help Transmit SNI-97801-5xx: Ctrl-Help\n"); break; case K_SNI_C_HOME : printf("\\Ksni_c_home Transmit SNI-97801-5xx: Ctrl-Home\n"); break; case K_SNI_C_INSERT_CHAR : printf( "\\Ksni_c_ins_char Transmit SNI-97801-5xx: Ctrl-Insert Char\n"); break; case K_SNI_C_INSERT_LINE : printf( "\\Ksni_c_ins_line Transmit SNI-97801-5xx: Ctrl-Insert Line\n"); break; case K_SNI_C_INSERT_WORD : printf( "\\Ksni_c_ins_word Transmit SNI-97801-5xx: Ctrl-Insert Word\n"); break; case K_SNI_C_LEFT_TAB : printf("\\Ksni_c_left_tab Transmit SNI-97801-5xx: Ctrl-Left Tab\n"); break; case K_SNI_C_CURSOR_LEFT : printf( "\\Ksni_c_lfarr Transmit SNI-97801-5xx: Ctrl-Cursor Left\n"); break; case K_SNI_C_MODE : printf("\\Ksni_c_mode Transmit SNI-97801-5xx: Ctrl-Mode\n"); break; case K_SNI_C_PAGE : printf("\\Ksni_c_page Transmit SNI-97801-5xx: Ctrl-Page\n"); break; case K_SNI_C_PRINT : printf("\\Ksni_c_print Transmit SNI-97801-5xx: Ctrl-Print\n"); break; case K_SNI_C_CURSOR_RIGHT: printf( "\\Ksni_c_rtarr Transmit SNI-97801-5xx: Ctrl-Cursor Right\n"); break; case K_SNI_C_SCROLL_DOWN : printf( "\\Ksni_c_scroll_dn Transmit SNI-97801-5xx: Ctrl-Scroll Down\n"); break; case K_SNI_C_SCROLL_UP : printf("\\Ksni_c_scroll_up Transmit SNI-97801-5xx: Ctrl-Scroll Up\n"); break; case K_SNI_C_START : printf("\\Ksni_c_start Transmit SNI-97801-5xx: Ctrl-Start\n"); break; case K_SNI_C_CURSOR_UP : printf("\\Ksni_c_uparr Transmit SNI-97801-5xx: Ctrl-Cursor Up\n"); break; case K_SNI_C_TAB : printf("\\Ksni_c_tab Transmit SNI-97801-5xx: Ctrl-Tab\n"); break; case K_SNI_CE : printf("\\Ksni_ce Transmit SNI-97801-5xx: CE\n"); break; case K_SNI_CH_CODE: printf("\\Ksni_ch_code Toggle SNI-97801-5xx: CH.CODE function.\n"); break; case K_SNI_COMPOSE : printf("\\Ksni_compose Transmit SNI-97801-5xx: Compose\n"); break; case K_SNI_DELETE_CHAR : printf("\\Ksni_del_char Transmit SNI-97801-5xx: Delete Char\n"); break; case K_SNI_DELETE_LINE : printf("\\Ksni_del_line Transmit SNI-97801-5xx: Delete Line\n"); break; case K_SNI_DELETE_WORD : printf("\\Ksni_del_word Transmit SNI-97801-5xx: Delete Word\n"); break; case K_SNI_CURSOR_DOWN : printf("\\Ksni_dnarr Transmit SNI-97801-5xx: Cursor Down\n"); break; case K_SNI_ENDMARKE : printf("\\Ksni_endmarke Transmit SNI-97801-5xx: End Marke\n"); break; case K_SNI_F01 : printf("\\Ksni_f01 Transmit SNI-97801-5xx: F1\n"); break; case K_SNI_F02 : printf("\\Ksni_f02 Transmit SNI-97801-5xx: F2\n"); break; case K_SNI_F03 : printf("\\Ksni_f03 Transmit SNI-97801-5xx: F3\n"); break; case K_SNI_F04 : printf("\\Ksni_f04 Transmit SNI-97801-5xx: F4\n"); break; case K_SNI_F05 : printf("\\Ksni_f05 Transmit SNI-97801-5xx: F5\n"); break; case K_SNI_F06 : printf("\\Ksni_f06 Transmit SNI-97801-5xx: F6\n"); break; case K_SNI_F07 : printf("\\Ksni_f07 Transmit SNI-97801-5xx: F7\n"); break; case K_SNI_F08 : printf("\\Ksni_f08 Transmit SNI-97801-5xx: F8\n"); break; case K_SNI_F09 : printf("\\Ksni_f09 Transmit SNI-97801-5xx: F9\n"); break; case K_SNI_F10 : printf("\\Ksni_f10 Transmit SNI-97801-5xx: F10\n"); break; case K_SNI_F11 : printf("\\Ksni_f11 Transmit SNI-97801-5xx: F11\n"); break; case K_SNI_F12 : printf("\\Ksni_f12 Transmit SNI-97801-5xx: F12\n"); break; case K_SNI_F13 : printf("\\Ksni_f13 Transmit SNI-97801-5xx: F13\n"); break; case K_SNI_F14 : printf("\\Ksni_f14 Transmit SNI-97801-5xx: F14\n"); break; case K_SNI_F15 : printf("\\Ksni_f15 Transmit SNI-97801-5xx: F15\n"); break; case K_SNI_F16 : printf("\\Ksni_f16 Transmit SNI-97801-5xx: F16\n"); break; case K_SNI_F17 : printf("\\Ksni_f17 Transmit SNI-97801-5xx: F17\n"); break; case K_SNI_F18 : printf("\\Ksni_f18 Transmit SNI-97801-5xx: F18\n"); break; case K_SNI_USER1 : printf("\\Ksni_user1 Transmit SNI-97801-5xx: Key below F18\n"); break; case K_SNI_F19 : printf("\\Ksni_f19 Transmit SNI-97801-5xx: F19\n"); break; case K_SNI_USER2 : printf("\\Ksni_user2 Transmit SNI-97801-5xx: Key below F19\n"); break; case K_SNI_F20 : printf("\\Ksni_f20 Transmit SNI-97801-5xx: F20\n"); break; case K_SNI_USER3 : printf("\\Ksni_user3 Transmit SNI-97801-5xx: Key below F20\n"); break; case K_SNI_F21 : printf("\\Ksni_f21 Transmit SNI-97801-5xx: F21\n"); break; case K_SNI_USER4 : printf("\\Ksni_user4 Transmit SNI-97801-5xx: Key below F21\n"); break; case K_SNI_F22 : printf("\\Ksni_f22 Transmit SNI-97801-5xx: F22\n"); break; case K_SNI_USER5 : printf("\\Ksni_user5 Transmit SNI-97801-5xx: Key below F22\n"); break; case K_SNI_HELP : printf("\\Ksni_help Transmit SNI-97801-5xx: Help\n"); break; case K_SNI_HOME : printf("\\Ksni_home Transmit SNI-97801-5xx: Home\n"); break; case K_SNI_INSERT_CHAR : printf("\\Ksni_ins_char Transmit SNI-97801-5xx: Insert Char\n"); break; case K_SNI_INSERT_LINE : printf("\\Ksni_ins_line Transmit SNI-97801-5xx: Insert Line\n"); break; case K_SNI_INSERT_WORD : printf("\\Ksni_ins_word Transmit SNI-97801-5xx: Insert Word\n"); break; case K_SNI_LEFT_TAB : printf("\\Ksni_left_tab Transmit SNI-97801-5xx: Left Tab\n"); break; case K_SNI_CURSOR_LEFT : printf("\\Ksni_lfarr Transmit SNI-97801-5xx: Cursor Left\n"); break; case K_SNI_MODE : printf("\\Ksni_mode Transmit SNI-97801-5xx: Mode\n"); break; case K_SNI_PAGE : printf("\\Ksni_page Transmit SNI-97801-5xx: Page\n"); break; case K_SNI_PRINT : printf("\\Ksni_print Transmit SNI-97801-5xx: Print\n"); break; case K_SNI_CURSOR_RIGHT : printf("\\Ksni_rtarr Transmit SNI-97801-5xx: Cursor Right\n"); break; case K_SNI_S_DOUBLE_0 : printf( "\\Ksni_s_00 Transmit SNI-97801-5xx: Shift-Double-Zero\n"); break; case K_SNI_S_CE : printf("\\Ksni_s_ce Transmit SNI-97801-5xx: Shift-CE\n"); break; case K_SNI_S_COMPOSE : printf("\\Ksni_s_compose Transmit SNI-97801-5xx: Shift-Compose\n"); break; case K_SNI_S_DELETE_CHAR : printf( "\\Ksni_s_del_char Transmit SNI-97801-5xx: Shift-Delete Char\n"); break; case K_SNI_S_DELETE_LINE : printf( "\\Ksni_s_del_line Transmit SNI-97801-5xx: Shift-Delete Line\n"); break; case K_SNI_S_DELETE_WORD : printf( "\\Ksni_s_del_word Transmit SNI-97801-5xx: Shift-Delete Word\n"); break; case K_SNI_S_CURSOR_DOWN : printf( "\\Ksni_s_dnarr Transmit SNI-97801-5xx: Shift-Cursor Down\n"); break; case K_SNI_S_ENDMARKE : printf("\\Ksni_s_endmarke Transmit SNI-97801-5xx: Shift-End Marke\n"); break; case K_SNI_S_F01 : printf("\\Ksni_s_f01 Transmit SNI-97801-5xx: Shift-F1\n"); break; case K_SNI_S_F02 : printf("\\Ksni_s_f02 Transmit SNI-97801-5xx: Shift-F2\n"); break; case K_SNI_S_F03 : printf("\\Ksni_s_f03 Transmit SNI-97801-5xx: Shift-F3\n"); break; case K_SNI_S_F04 : printf("\\Ksni_s_f04 Transmit SNI-97801-5xx: Shift-F4\n"); break; case K_SNI_S_F05 : printf("\\Ksni_s_f05 Transmit SNI-97801-5xx: Shift-F5\n"); break; case K_SNI_S_F06 : printf("\\Ksni_s_f06 Transmit SNI-97801-5xx: Shift-F6\n"); break; case K_SNI_S_F07 : printf("\\Ksni_s_f07 Transmit SNI-97801-5xx: Shift-F7\n"); break; case K_SNI_S_F08 : printf("\\Ksni_s_f08 Transmit SNI-97801-5xx: Shift-F8\n"); break; case K_SNI_S_F09 : printf("\\Ksni_s_f09 Transmit SNI-97801-5xx: Shift-F9\n"); break; case K_SNI_S_F10 : printf("\\Ksni_s_f10 Transmit SNI-97801-5xx: Shift-F10\n"); break; case K_SNI_S_F11 : printf("\\Ksni_s_f11 Transmit SNI-97801-5xx: Shift-F11\n"); break; case K_SNI_S_F12 : printf("\\Ksni_s_f12 Transmit SNI-97801-5xx: Shift-F12\n"); break; case K_SNI_S_F13 : printf("\\Ksni_s_f13 Transmit SNI-97801-5xx: Shift-F13\n"); break; case K_SNI_S_F14 : printf("\\Ksni_s_f14 Transmit SNI-97801-5xx: Shift-F14\n"); break; case K_SNI_S_F15 : printf("\\Ksni_s_f15 Transmit SNI-97801-5xx: Shift-F15\n"); break; case K_SNI_S_F16 : printf("\\Ksni_s_f16 Transmit SNI-97801-5xx: Shift-F16\n"); break; case K_SNI_S_F17 : printf("\\Ksni_s_f17 Transmit SNI-97801-5xx: Shift-F17\n"); break; case K_SNI_S_F18 : printf("\\Ksni_s_f18 Transmit SNI-97801-5xx: Shift-F18\n"); break; case K_SNI_S_USER1 : printf( "\\Ksni_s_user1 Transmit SNI-97801-5xx: Shift-Key below F18\n"); break; case K_SNI_S_F19 : printf("\\Ksni_s_f19 Transmit SNI-97801-5xx: Shift-F19\n"); break; case K_SNI_S_USER2 : printf( "\\Ksni_s_user2 Transmit SNI-97801-5xx: Shift-Key below F19\n"); break; case K_SNI_S_F20 : printf("\\Ksni_s_f20 Transmit SNI-97801-5xx: Shift-F20\n"); break; case K_SNI_S_USER3 : printf( "\\Ksni_s_user3 Transmit SNI-97801-5xx: Shift-Key below F20\n"); break; case K_SNI_S_F21 : printf("\\Ksni_s_f21 Transmit SNI-97801-5xx: Shift-F21\n"); break; case K_SNI_S_USER4 : printf( "\\Ksni_s_user4 Transmit SNI-97801-5xx: Shift-Key below F21\n"); break; case K_SNI_S_F22 : printf("\\Ksni_s_f22 Transmit SNI-97801-5xx: Shift-F22\n"); break; case K_SNI_S_USER5 : printf( "\\Ksni_s_user5 Transmit SNI-97801-5xx: Shift-Key below F22\n"); break; case K_SNI_S_HELP : printf("\\Ksni_s_help Transmit SNI-97801-5xx: Shift-Help\n"); break; case K_SNI_S_HOME : printf("\\Ksni_s_home Transmit SNI-97801-5xx: Shift-Home\n"); break; case K_SNI_S_INSERT_CHAR : printf( "\\Ksni_s_ins_char Transmit SNI-97801-5xx: Shift-Insert Char\n"); break; case K_SNI_S_INSERT_LINE : printf( "\\Ksni_s_ins_line Transmit SNI-97801-5xx: Shift-Insert Line\n"); break; case K_SNI_S_INSERT_WORD : printf( "\\Ksni_s_ins_word Transmit SNI-97801-5xx: Shift-Insert Word\n"); break; case K_SNI_S_LEFT_TAB : printf("\\Ksni_s_left_tab Transmit SNI-97801-5xx: Shift-Left Tab\n"); break; case K_SNI_S_CURSOR_LEFT : printf( "\\Ksni_s_lfarr Transmit SNI-97801-5xx: Shift-Cursor Left\n"); break; case K_SNI_S_MODE : printf("\\Ksni_s_mode Transmit SNI-97801-5xx: Shift-Mode\n"); break; case K_SNI_S_PAGE : printf("\\Ksni_s_page Transmit SNI-97801-5xx: Shift-Page\n"); break; case K_SNI_S_PRINT : printf("\\Ksni_s_print Transmit SNI-97801-5xx: Shift-Print\n"); break; case K_SNI_S_CURSOR_RIGHT: printf( "\\Ksni_s_rtarr Transmit SNI-97801-5xx: Shift-Cursor Right\n"); break; case K_SNI_S_SCROLL_DOWN : printf( "\\Ksni_s_scroll_dn Transmit SNI-97801-5xx: Shift-Scroll Down\n"); break; case K_SNI_S_SCROLL_UP : printf("\\Ksni_s_scroll_up Transmit SNI-97801-5xx: Shift-Scroll Up\n"); break; case K_SNI_S_START : printf("\\Ksni_s_start Transmit SNI-97801-5xx: Shift-Start\n"); break; case K_SNI_S_CURSOR_UP : printf("\\Ksni_s_uparr Transmit SNI-97801-5xx: Shift-Cursor Up\n"); break; case K_SNI_S_TAB : printf("\\Ksni_s_tab Transmit SNI-97801-5xx: Shift-Tab\n"); break; case K_SNI_SCROLL_DOWN : printf("\\Ksni_scroll_dn Transmit SNI-97801-5xx: Scroll Down\n"); break; case K_SNI_SCROLL_UP : printf("\\Ksni_scroll_up Transmit SNI-97801-5xx: Scroll Up\n"); break; case K_SNI_START : printf("\\Ksni_start Transmit SNI-97801-5xx: Start\n"); break; case K_SNI_TAB : printf("\\Ksni_tab Transmit SNI-97801-5xx: Tab\n"); break; case K_SNI_CURSOR_UP : printf("\\Ksni_uparr Transmit SNI-97801-5xx: Cursor Up\n"); break; case K_BA80_ATTR: printf("\\Kba80_attr Transmit BA80: Attr\n"); break; case K_BA80_C_KEY: printf("\\Kba80_c_key Transmit BA80: C\n"); break; case K_BA80_CLEAR: printf("\\Kba80_clear Transmit BA80: Clear\n"); break; case K_BA80_CMD: printf("\\Kba80_cmd Transmit BA80: Cmd\n"); break; case K_BA80_COPY: printf("\\Kba80_copy Transmit BA80: Copy\n"); break; case K_BA80_DEL: printf("\\Kba80_del Transmit BA80: Delete\n"); break; case K_BA80_DEL_B: printf("\\Kba80_del_b Transmit BA80: Delete B\n"); break; case K_BA80_DO: printf("\\Kba80_do Transmit BA80: Do\n"); break; case K_BA80_END: printf("\\Kba80_end Transmit BA80: End\n"); break; case K_BA80_ENV: printf("\\Kba80_env Transmit BA80: Env\n"); break; case K_BA80_EOP: printf("\\Kba80_eop Transmit BA80: EOP\n"); break; case K_BA80_ERASE: printf("\\Kba80_erase Transmit BA80: Erase\n"); break; case K_BA80_FMT: printf("\\Kba80_fmt Transmit BA80: Format\n"); break; case K_BA80_HELP: printf("\\Kba80_help Transmit BA80: Help\n"); break; case K_BA80_HOME: printf("\\Kba80_home Transmit BA80: Home\n"); break; case K_BA80_INS: printf("\\Kba80_ins Transmit BA80: Insert\n"); break; case K_BA80_INS_B: printf("\\Kba80_ins_b Transmit BA80: Insert B\n"); break; case K_BA80_MARK: printf("\\Kba80_mark Transmit BA80: Mark\n"); break; case K_BA80_MOVE: printf("\\Kba80_move Transmit BA80: Move\n"); break; case K_BA80_PA01: printf("\\Kba80_pa01 Transmit BA80: PA1\n"); break; case K_BA80_PA02: printf("\\Kba80_pa02 Transmit BA80: PA2\n"); break; case K_BA80_PA03: printf("\\Kba80_pa03 Transmit BA80: PA3\n"); break; case K_BA80_PA04: printf("\\Kba80_pa04 Transmit BA80: PA4\n"); break; case K_BA80_PA05: printf("\\Kba80_pa05 Transmit BA80: PA5\n"); break; case K_BA80_PA06: printf("\\Kba80_pa06 Transmit BA80: PA6\n"); break; case K_BA80_PA07: printf("\\Kba80_pa07 Transmit BA80: PA7\n"); break; case K_BA80_PA08: printf("\\Kba80_pa08 Transmit BA80: PA8\n"); break; case K_BA80_PA09: printf("\\Kba80_pa09 Transmit BA80: PA9\n"); break; case K_BA80_PA10: printf("\\Kba80_pa10 Transmit BA80: PA10\n"); break; case K_BA80_PA11: printf("\\Kba80_pa11 Transmit BA80: PA11\n"); break; case K_BA80_PA12: printf("\\Kba80_pa12 Transmit BA80: PA12\n"); break; case K_BA80_PA13: printf("\\Kba80_pa13 Transmit BA80: PA13\n"); break; case K_BA80_PA14: printf("\\Kba80_pa14 Transmit BA80: PA14\n"); break; case K_BA80_PA15: printf("\\Kba80_pa15 Transmit BA80: PA15\n"); break; case K_BA80_PA16: printf("\\Kba80_pa16 Transmit BA80: PA16\n"); break; case K_BA80_PA17: printf("\\Kba80_pa17 Transmit BA80: PA17\n"); break; case K_BA80_PA18: printf("\\Kba80_pa18 Transmit BA80: PA18\n"); break; case K_BA80_PA19: printf("\\Kba80_pa19 Transmit BA80: PA19\n"); break; case K_BA80_PA20: printf("\\Kba80_pa20 Transmit BA80: PA20\n"); break; case K_BA80_PA21: printf("\\Kba80_pa21 Transmit BA80: PA21\n"); break; case K_BA80_PA22: printf("\\Kba80_pa22 Transmit BA80: PA22\n"); break; case K_BA80_PA23: printf("\\Kba80_pa23 Transmit BA80: PA23\n"); break; case K_BA80_PA24: printf("\\Kba80_pa24 Transmit BA80: PA24\n"); break; case K_BA80_PGDN: printf("\\Kba80_pgdn Transmit BA80: Page Down\n"); break; case K_BA80_PGUP: printf("\\Kba80_pgup Transmit BA80: Page Up\n"); break; case K_BA80_PICK: printf("\\Kba80_pick Transmit BA80: Pick\n"); break; case K_BA80_PRINT: printf("\\Kba80_print Transmit BA80: Print\n"); break; case K_BA80_PUT: printf("\\Kba80_put Transmit BA80: Put\n"); break; case K_BA80_REFRESH: printf("\\Kba80_refresh Transmit BA80: Refresh \n"); break; case K_BA80_RESET: printf("\\Kba80_reset Transmit BA80: Reset\n"); break; case K_BA80_RUBOUT: printf("\\Kba80_rubout Transmit BA80: Rubout\n"); break; case K_BA80_SAVE: printf("\\Kba80_save Transmit BA80: Save\n"); break; case K_BA80_SOFTKEY1: printf("\\Kba80_softkey1 Transmit BA80: Softkey 1\n"); break; case K_BA80_SOFTKEY2: printf("\\Kba80_softkey2 Transmit BA80: Softkey 2\n"); break; case K_BA80_SOFTKEY3: printf("\\Kba80_softkey3 Transmit BA80: Softkey 3\n"); break; case K_BA80_SOFTKEY4: printf("\\Kba80_softkey4 Transmit BA80: Softkey 4\n"); break; case K_BA80_SOFTKEY5: printf("\\Kba80_softkey5 Transmit BA80: Softkey 5\n"); break; case K_BA80_SOFTKEY6: printf("\\Kba80_softkey6 Transmit BA80: Softkey 6\n"); break; case K_BA80_SOFTKEY7: printf("\\Kba80_softkey7 Transmit BA80: Softkey 7\n"); break; case K_BA80_SOFTKEY8: printf("\\Kba80_softkey8 Transmit BA80: Softkey 8\n"); break; case K_BA80_SOFTKEY9: printf("\\Kba80_softkey9 Transmit BA80: Softkey 9\n"); break; case K_BA80_UNDO: printf("\\Kba80_undo Transmit BA80: Undo\n"); break; case K_I31_F01: printf("\\Ki31_f01 Transmit IBM 31xx: F1\n"); break; case K_I31_F02: printf("\\Ki31_f02 Transmit IBM 31xx: F2\n"); break; case K_I31_F03: printf("\\Ki31_f03 Transmit IBM 31xx: F3\n"); break; case K_I31_F04: printf("\\Ki31_f04 Transmit IBM 31xx: F4\n"); break; case K_I31_F05: printf("\\Ki31_f05 Transmit IBM 31xx: F5\n"); break; case K_I31_F06: printf("\\Ki31_f06 Transmit IBM 31xx: F6\n"); break; case K_I31_F07: printf("\\Ki31_f07 Transmit IBM 31xx: F7\n"); break; case K_I31_F08: printf("\\Ki31_f08 Transmit IBM 31xx: F8\n"); break; case K_I31_F09: printf("\\Ki31_f09 Transmit IBM 31xx: F9\n"); break; case K_I31_F10: printf("\\Ki31_f10 Transmit IBM 31xx: F10\n"); break; case K_I31_F11: printf("\\Ki31_f11 Transmit IBM 31xx: F11\n"); break; case K_I31_F12: printf("\\Ki31_f12 Transmit IBM 31xx: F12\n"); break; case K_I31_F13: printf("\\Ki31_f13 Transmit IBM 31xx: F13\n"); break; case K_I31_F14: printf("\\Ki31_f14 Transmit IBM 31xx: F14\n"); break; case K_I31_F15: printf("\\Ki31_f15 Transmit IBM 31xx: F15\n"); break; case K_I31_F16: printf("\\Ki31_f16 Transmit IBM 31xx: F16\n"); break; case K_I31_F17: printf("\\Ki31_f17 Transmit IBM 31xx: F17\n"); break; case K_I31_F18: printf("\\Ki31_f18 Transmit IBM 31xx: F18\n"); break; case K_I31_F19: printf("\\Ki31_f19 Transmit IBM 31xx: F19\n"); break; case K_I31_F20: printf("\\Ki31_f20 Transmit IBM 31xx: F20\n"); break; case K_I31_F21: printf("\\Ki31_f21 Transmit IBM 31xx: F21\n"); break; case K_I31_F22: printf("\\Ki31_f22 Transmit IBM 31xx: F22\n"); break; case K_I31_F23: printf("\\Ki31_f23 Transmit IBM 31xx: F23\n"); break; case K_I31_F24: printf("\\Ki31_f24 Transmit IBM 31xx: F24\n"); break; case K_I31_F25: printf("\\Ki31_f25 Transmit IBM 31xx: F25\n"); break; case K_I31_F26: printf("\\Ki31_f26 Transmit IBM 31xx: F26\n"); break; case K_I31_F27: printf("\\Ki31_f27 Transmit IBM 31xx: F27\n"); break; case K_I31_F28: printf("\\Ki31_f28 Transmit IBM 31xx: F28\n"); break; case K_I31_F29: printf("\\Ki31_f29 Transmit IBM 31xx: F29\n"); break; case K_I31_F30: printf("\\Ki31_f30 Transmit IBM 31xx: F30\n"); break; case K_I31_F31: printf("\\Ki31_f31 Transmit IBM 31xx: F31\n"); break; case K_I31_F32: printf("\\Ki31_f32 Transmit IBM 31xx: F32\n"); break; case K_I31_F33: printf("\\Ki31_f33 Transmit IBM 31xx: F33\n"); break; case K_I31_F34: printf("\\Ki31_f34 Transmit IBM 31xx: F34\n"); break; case K_I31_F35: printf("\\Ki31_f35 Transmit IBM 31xx: F35\n"); break; case K_I31_F36: printf("\\Ki31_f36 Transmit IBM 31xx: F36\n"); break; case K_I31_PA1: printf("\\Ki31_pa1 Transmit IBM 31xx: PA1\n"); break; case K_I31_PA2: printf("\\Ki31_pa2 Transmit IBM 31xx: PA2\n"); break; case K_I31_PA3: printf("\\Ki31_pa3 Transmit IBM 31xx: PA3\n"); break; case K_I31_RESET: printf("\\Ki31_reset Transmit IBM 31xx: Reset\n"); break; case K_I31_JUMP: printf("\\Ki31_jump Transmit IBM 31xx: Jump\n"); break; case K_I31_CLEAR: printf("\\Ki31_clear Transmit IBM 31xx: Clear\n"); break; case K_I31_ERASE_EOF: printf("\\Ki31_erase_eof Transmit IBM 31xx: Erase to End of Field\n"); break; case K_I31_ERASE_EOP: printf("\\Ki31_eop Transmit IBM 31xx: Erase to End of Page\n"); break; case K_I31_ERASE_INP: printf("\\Ki31_inp Transmit IBM 31xx: Erase Input Operation\n"); break; case K_I31_INSERT_CHAR: printf("\\Ki31_ins_char Transmit IBM 31xx: Insert Character\n"); break; case K_I31_INSERT_SPACE: printf("\\Ki31_ins_space Transmit IBM 31xx: Insert Space\n"); break; case K_I31_DELETE: printf("\\Ki31_delete Transmit IBM 31xx: Delete Character\n"); break; case K_I31_INS_LN: printf("\\Ki31_ins_line Transmit IBM 31xx: Insert Line\n"); break; case K_I31_DEL_LN: printf("\\Ki31_del_ln Transmit IBM 31xx: Delete Line\n"); break; case K_I31_PRINT_LINE: printf("\\Ki31_prt_line Transmit IBM 31xx: Print Line\n"); break; case K_I31_PRINT_MSG: printf("\\Ki31_prt_msg Transmit IBM 31xx: Print Message\n"); break; case K_I31_PRINT_SHIFT: printf("\\Ki31_prt_shift Transmit IBM 31xx: Print Shift\n"); break; case K_I31_CANCEL: printf("\\Ki31_cancel Transmit IBM 31xx: Cancel\n"); break; case K_I31_SEND_LINE: printf("\\Ki31_send_line Transmit IBM 31xx: Send Line\n"); break; case K_I31_SEND_MSG: printf("\\Ki31_send_msg Transmit IBM 31xx: Send Message\n"); break; case K_I31_SEND_PAGE: printf("\\Ki31_send_page Transmit IBM 31xx: Send Page\n"); break; case K_I31_HOME: printf("\\Ki31_home Transmit IBM 31xx: Home\n"); break; case K_I31_BACK_TAB: printf("\\Ki31_back_tab Transmit IBM 31xx: Back Tab\n"); break; case K_SUN_STOP: printf("\\Ksunstop Transmit SUN Console: Stop\n"); break; case K_SUN_AGAIN: printf("\\Ksunagain Transmit SUN Console: Again\n"); break; case K_SUN_PROPS: printf("\\Ksunprops Transmit SUN Console: Props\n"); break; case K_SUN_UNDO: printf("\\Ksunundo Transmit SUN Console: Undo\n"); break; case K_SUN_FRONT: printf("\\Ksunfront Transmit SUN Console: Front\n"); break; case K_SUN_COPY: printf("\\Ksuncopy Transmit SUN Console: Copy\n"); break; case K_SUN_OPEN: printf("\\Ksunopen Transmit SUN Console: Open\n"); break; case K_SUN_PASTE: printf("\\Ksunpaste Transmit SUN Console: Paste\n"); break; case K_SUN_FIND: printf("\\Ksunfind Transmit SUN Console: Find\n"); break; case K_SUN_CUT: printf("\\Ksuncut Transmit SUN Console: Cut\n"); break; case K_SUN_HELP: printf("\\Ksunhelp Transmit SUN Console: Help\n"); break; default: printf("No additional help available for this kverb\n"); } printf("\n"); /* This is not the proper way to do it since it doesn't show */ /* all emulations, nor does it show the special modes, but it */ /* is better than nothing. */ printf("Current bindings:\n"); found = 0; for (i = 256; i < KMSIZE ; i++) { con_event evt = mapkey(i); if (evt.type != kverb) continue; if ((evt.kverb.id & ~F_KVERB) == xx) { found = 1; printf(" \\%-4d - %s\n",i,keyname(i)); } } #ifdef OS2MOUSE for ( button = 0 ; button < MMBUTTONMAX ; button++ ) for ( event = 0 ; event < MMEVENTSIZE ; event++ ) if ( mousemap[button][event].type == kverb ) { if ( (mousemap[button][event].kverb.id & ~F_KVERB) == xx ) { found = 1; printf(" Mouse - %s\n",mousename(button,event)); } } #endif /* OS2MOUSE */ if ( !found ) { printf(" (none)\n"); } return(0); } #endif /* NOKVERBS */ #endif /* OS2 */ #ifndef NOXFER /* D O H R M T -- Give help about REMOTE command */ static char *hrset[] = { "Syntax: REMOTE SET parameter value", "Example: REMOTE SET FILE TYPE BINARY", " Asks the Kermit server to set the named parameter to the given value.", " Equivalent to typing the corresponding SET command directly to the other", " Kermit if it were in interactive mode.", "" }; int #ifdef CK_ANSIC dohrmt( int xx ) #else dohrmt(xx) int xx; #endif /* CK_ANSIC */ { int x; if (xx == -3) return(hmsga(hmhrmt)); if (xx < 0) return(xx); if ((x = cmcfm()) < 0) return(x); switch (xx) { case XZCPY: return(hmsg("Syntax: REMOTE COPY source destination\n\ Asks the Kermit server to copy the source file to destination.\n\ Synonym: RCOPY.")); case XZCWD: #ifdef NEWFTP return(hmsg("Syntax: REMOTE CD [ name ]\n\ Asks the Kermit or FTP server to change its working directory or device.\n\ If the device or directory name is omitted, restore the default.\n\ Synonym: RCD.")); #else return(hmsg("Syntax: REMOTE CD [ name ]\n\ Asks the Kermit server to change its working directory or device.\n\ If the device or directory name is omitted, restore the default.\n\ Synonym: RCD.")); #endif /* NEWFTP */ case XZDEL: #ifdef NEWFTP return(hmsg("Syntax: REMOTE DELETE filespec\n\ Asks the Kermit or FTP server to delete the named file(s).\n\ Synonym: RDEL.")); #else return(hmsg("Syntax: REMOTE DELETE filespec\n\ Asks the Kermit server to delete the named file(s).\n\ Synonym: RDEL.")); #endif /* NEWFTP */ case XZMKD: #ifdef NEWFTP return(hmsg("Syntax: REMOTE MKDIR directory-name\n\ Asks the Kermit or FTP server to create the named directory.\n\ Synonym: RMKDIR.")); #else return(hmsg("Syntax: REMOTE MKDIR directory-name\n\ Asks the Kermit server to create the named directory.\n\ Synonym: RMKDIR.")); #endif /* NEWFTP */ case XZRMD: #ifdef NEWFTP return(hmsg("Syntax: REMOTE RMDIR directory-name\n\ Asks the Kermit or FTP server to remove the named directory.\n\ Synonym: RRMDIR.")); #else return(hmsg("Syntax: REMOTE RMDIR directory-name\n\ Asks the Kermit server to remove the named directory.\n\ Synonym: RRMDIR.")); #endif /* NEWFTP */ case XZDIR: #ifdef NEWFTP return(hmsg("Syntax: REMOTE DIRECTORY [ filespec ]\n\ Asks the Kermit or FTP server to provide a directory listing of the named\n\ file(s) or if no file specification is given, of all files in its current\n\ directory. Synonym: RDIR.")); #else return(hmsg("Syntax: REMOTE DIRECTORY [ filespec ]\n\ Asks the Kermit server to provide a directory listing of the named\n\ file(s) or if no file specification is given, of all files in its current\n\ directory. Synonym: RDIR.")); #endif /* NEWFTP */ case XZHLP: #ifdef NEWFTP return(hmsg("Syntax: REMOTE HELP\n\ Asks the Kermit or FTP server to list the services it provides.\n\ Synonym: RHELP.")); #else return(hmsg("Syntax: REMOTE HELP\n\ Asks the Kermit server to list the services it provides.\n\ Synonym: RHELP.")); #endif /* NEWFTP */ case XZHOS: return(hmsg("Syntax: REMOTE HOST command\n\ Sends a command to the other computer in its own command language\n\ through the Kermit server that is running on that host. Synonym: RHOST.")); #ifndef NOFRILLS case XZKER: return(hmsg("Syntax: REMOTE KERMIT command\n\ Sends a command to the remote Kermit server in its own command language.\n\ Synonym: RKERMIT.")); case XZLGI: return(hmsg("Syntax: REMOTE LOGIN user password [ account ]\n\ Logs in to a remote Kermit server that requires you login. Note: RLOGIN\n\ is NOT a synonym for REMOTE LOGIN.")); case XZLGO: return(hmsg("Syntax: REMOTE LOGOUT\n\ Logs out from a remote Kermit server to which you have previously logged in." )); case XZMSG: return(hmsg("Syntax: REMOTE MESSAGE text\n\ Sends a short text message to the remote Kermit server.")); case XZPRI: return(hmsg("Syntax: REMOTE PRINT filespec [ options ]\n\ Sends the specified file(s) to the remote Kermit and ask it to have the\n\ file printed on the remote system's printer, using any specified options.\n\ Synonym: RPRINT.")); #endif /* NOFRILLS */ case XZREN: #ifdef NEWFTP return(hmsg("Syntax: REMOTE RENAME filespec newname\n\ Asks the Kermit or FTP server to rename the file. Synonym: RRENAME.")); #else return(hmsg("Syntax: REMOTE RENAME filespec newname\n\ Asks the Kermit server to rename the file. Synonym: RRENAME.")); #endif /* NEWFTP */ case XZSET: return(hmsga(hrset)); case XZSPA: return(hmsg("Syntax: REMOTE SPACE [ name ]\n\ Asks the Kermit server to tell you about its disk space on the current\n\ disk or directory, or in the one that you name. Synonym: RSPACE.")); #ifndef NOFRILLS case XZTYP: #ifdef NEWFTP return(hmsg("Syntax: REMOTE TYPE file\n\ Asks the Kermit or FTP server to send the named file to your screen.\n\ Synonym: RTYPE.")); #else return(hmsg("Syntax: REMOTE TYPE file\n\ Asks the Kermit server to send the named file(s) to your screen.\n\ Synonym: RTYPE.")); #endif /* NEWFTP */ case XZWHO: return(hmsg("Syntax: REMOTE WHO [ name ]\n\ Asks the Kermit server to list who's logged in, or to give information\n\ about the named user. Synonym: RWHO.")); #endif /* NOFRILLS */ #ifndef NOSPL case XZQUE: return(hmsg( "Syntax: [ REMOTE ] QUERY { KERMIT, SYSTEM, USER } variable-name\n\ Asks the Kermit server to send the value of the named variable of the\n\ given type, and make it available in the \\v(query) variable. When the\n\ type is KERMIT functions may also be specified as if they were variables.")); case XZASG: return(hmsg( "Syntax: REMOTE ASSIGN variable-name [ value ]\n\ Assigns the given value to the named global variable on the server.\n\ Synonyms: RASG, RASSIGN.")); #endif /* NOSPL */ case XZPWD: return(hmsg( #ifdef NEWFTP "Syntax: REMOTE PWD\n\ Asks the Kermit server to display its current working directory.\n\ Synonym: RPWD.")); #else "Syntax: REMOTE PWD\n\ Asks the Kermit or FTP server to display its current working directory.\n\ Synonym: RPWD.")); #endif /* NEWFTP */ case XZXIT: #ifdef NEWFTP return(hmsg("Syntax: REMOTE EXIT\n\ Asks the Kermit server to exit (without disconnecting), or closes an FTP\n\ connection. Synonym: REXIT, and (for FTP only) BYE, FTP BYE.")); #else return(hmsg("Syntax: REMOTE EXIT\n\ Asks the Kermit server to exit. Synonym: REXIT.")); #endif /* NEWFTP */ case XZSTA: return(hmsg("Syntax: REMOTE STATUS\n\ Asks the remote Kermit server for information about itself. Typically\n\ this would include the name and version of Kermit program,the underlying\n\ hardware/architecture, operating system, current directory, and the\n\ details of the most recent file transfer (if any).")); case XZCDU: #ifdef NEWFTP return(hmsg("Syntax: REMOTE CDUP\n\ Asks the Kermit or FTP server to change its working directory to\n\ the directory above it. Synonym: RCDUP.")); #else return(hmsg("Syntax: REMOTE CDUP\n\ Asks the Kermit server to change its working directory to the directory\n\ above it. Synonym: RCDUP.")); #endif /* NEWFTP */ default: if ((x = cmcfm()) < 0) return(x); printf("?Sorry, no help available - \"%s\"\n",cmdbuf); return(-9); } } #endif /* NOXFER */ #endif /* NOHELP */ #endif /* NOICP */ ckuus3.c000664 045065 024037 00001631543 14767403766 012605 0ustar00fdckermit000000 000000 #include "ckcsym.h" /* Symbol definitions */ /* C K U U S 3 -- "User Interface" for C-Kermit, part 3 */ /* Authors: Frank da Cruz , The Kermit Project, New York City Jeffrey E Altman Secure Endpoints Inc., New York City David Goodwin, New Zealand Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Update: Fri Dec 2 07:26:48 2022 (changes for XYZMODEM internal) Update: Wed Apr 12 15:40:01 2023 (ansified 19 function definitions) Update: Sat May 6 13:01:37 2023 (explicit declaration of initproto) Update: Sun May 14 07:38:14 2023 (HPUX10-specific adjustment) */ /* SET command (but much material has been split off into ckuus7.c). */ /* Kermit-specific includes. Definitions here supersede those from system include files. */ #include "ckcdeb.h" /* Debugging & compiler things */ #include "ckcasc.h" /* ASCII character symbols */ #include "ckcker.h" /* Kermit application definitions */ #include "ckcxla.h" /* Character set translation */ #include "ckcnet.h" /* Network symbols */ char pwbuf[PWBUFL+1] = { NUL, NUL }; int pwflg = 0; int pwcrypt = 0; #ifndef NOICP #ifdef CK_AUTHENTICATION #include "ckuath.h" #endif /* CK_AUTHENTICATION */ #ifdef CK_SSL #include "ck_ssl.h" #endif /* CK_SSL */ #include "ckuusr.h" /* User interface symbols */ #ifdef OS2 #include "ckcuni.h" #ifdef SSHBUILTIN #include "ckossh.h" #endif /* SSHBUILTIN */ #ifdef CK_NETBIOS #include #ifdef COMMENT /* Would you believe */ #undef COMMENT /* defines this ? */ #endif /* COMMENT */ #include "ckonbi.h" extern UCHAR NetBiosAdapter; #endif /* CK_NETBIOS */ #include "ckocon.h" #include "ckokey.h" #ifndef NOTERM extern unsigned char colorcmd; /* Command-screen colors */ extern struct keytab ttyclrtab[]; extern int nclrs; extern int tt_cols[], tt_rows[], tt_szchng[], tt_status[]; #endif /* NOTERM */ _PROTOTYP(int setprty, (void)); extern char startupdir[], exedir[]; extern int tt_modechg; int settitle(); /* ckuus7.c */ int setdialer(); /* ckuus7.c */ void os2debugoff(); /* ckoco3.c */ int msktock(int); /* ckokey.c */ int popup_readpass(int,char*,char*,char*,int,int); /* ckocon.c */ int popup_readtext(int,char*,char*,char*,int,int); /* ckocon.c */ #ifdef NETDLL int netdll_load(char *); /* ckonet.c */ #endif /* NETDLL */ #ifndef NOLOCAL int setmsk(); /* ckuus7.c */ #endif /* NOLOCAL */ #ifdef NT #include #include "ckoreg.h" #ifdef CK_TAPI #include #include "ckntap.h" /* Microsoft TAPI */ #endif /* CK_TAPI */ #ifdef KUI int get_gui_window_pos_y(); /* cknwin.c */ int get_gui_window_pos_x(); /* cknwin.c */ int get_gui_resize_mode(); /* cknwin.c */ #endif /* KUI */ int setwin95(); /* ckuus7.c */ Win32EnumPrt(struct keytab**,struct keytab**,int*,int*); /* cknprt.c */ #endif /* NT */ #endif /* OS2 */ #ifndef OS2 extern char * exedir; #endif /* OS2 */ #ifdef CK_RECALL extern int cm_retry; #endif /* CK_RECALL */ #ifdef NEWFTP extern int ftpisopen(); #endif /* NEWFTP */ extern int cmdint; extern int srvidl; #ifdef CKFLOAT extern CKFLOAT floatval; /* (see isfloat()) */ #endif /* CKFLOAT */ #ifndef NOPUSH #ifndef NOFRILLS #ifdef VMS char editor[CKMAXPATH + 1] = "edit"; #else char editor[CKMAXPATH + 1] = { NUL, NUL }; #endif /* VMS */ char editopts[128] = { NUL, NUL }; char editfile[CKMAXPATH + 1] = { NUL, NUL }; #ifdef BROWSER char browser[CKMAXPATH + 1] = { NUL, NUL }; char browsopts[128] = { NUL, NUL }; char browsurl[4096] = { NUL, NUL }; #endif /* BROWSER */ #endif /* NOFRILLS */ #endif /* NOPUSH */ #ifndef NOFRILLS #ifndef NORENAME _PROTOTYP(int setrename, (void)); #endif /* NORENAME */ #endif /* NOFRILLS */ /* Variables */ int exitmsg = 1; int cmd_quoting = 1; int cmd_err = 1; extern int hints, xcmdsrc; #ifdef CK_KERBEROS char * k4pwprompt = NULL; /* Kerberos 4 password prompt */ char * k4prprompt = NULL; /* Kerberos 4 principal prompt */ char * k5pwprompt = NULL; /* Kerberos 5 password prompt */ char * k5prprompt = NULL; /* Kerberos 5 principal prompt */ #endif /* CK_KERBEROS */ #ifdef CK_SRP char * srppwprompt = NULL; #endif /* CK_SRP */ extern char * ckprompt, * ikprompt; /* Default prompt */ extern xx_strp xxstring; extern char * cdmsgfile[], * cdmsgstr; extern int local, server, success, dest, sleepcan, inserver, flow, autoflow, binary, parity, escape, what, turn, duplex, backgrd, hwparity, stopbits, turnch, mdmtyp, network, quiet, nettype, carrier, debses, debtim, cdtimo, nlangs, bgset, pflag, msgflg, cmdmsk, xsuspend, techo, pacing, xitwarn, xitsta, outesc, cmd_cols, cmd_rows, ckxech, xaskmore, haveline, didsetlin, isguest, mdmsav, clearrq, saveask, debmsg; extern int reliable, setreliable, matchdot, matchfifo, dir_dots; #ifndef NOSERVER extern int en_pri; #endif /* NOSERVER */ #ifdef IKSDCONF extern int iksdcf; #endif /* IKSDCONF */ #ifdef TCPSOCKET extern int tn_exit; #endif /* TCPSOCKET */ #ifdef TNCODE char * tn_pr_uid = NULL; #endif /* TNCODE */ extern int exitonclose; #ifndef NOKVERBS extern int nkverbs; extern struct keytab kverbs[]; #endif /* NOKVERBS */ extern int ttnproto; /* Network protocol */ extern char *ccntab[]; /* Names of control chars */ #ifdef CK_APC extern int apcactive, apcstatus; #endif /* CK_APC */ #ifndef NOSCRIPT extern int secho; /* Whether SCRIPT cmd should echo */ #endif /* NOSCRIPT */ #ifdef DCMDBUF extern char *atmbuf, *atxbuf; #else extern char atmbuf[], atxbuf[]; #endif /* DCMDBUF */ extern int cmflgs; extern char psave[]; extern char uidbuf[]; extern int sl_uid_saved; int DeleteStartupFile = 0; extern int cmdlvl; /* Overall command level */ #ifndef NOSPL _PROTOTYP( static int parsdir, (int) ); char prmbuf[PWBUFL+1] = { NUL, NUL }; int fndiags = 1; /* Function diagnostics on/off */ int fnerror = 1; /* Function error treatment */ #ifdef DCMDBUF extern int *count, *takerr, *merror, *inpcas; #else extern int count[], takerr[], merror[], inpcas[]; #endif /* DCMDBUF */ extern int mecho; /* Macro echo */ extern long ck_alarm; extern char alrm_date[], alrm_time[]; #else extern int takerr[]; #endif /* NOSPL */ extern int x_ifnum; extern int bigsbsiz, bigrbsiz; /* Packet buffers */ extern long speed; /* Terminal speed */ extern char ttname[]; /* Communication device name */ extern char myhost[] ; extern char inidir[]; /* Ini File directory */ #ifndef NOSETKEY extern KEY *keymap; /* Character map for SET KEY (1:1) */ extern MACRO *macrotab; /* Macro map for SET KEY (1:string) */ #endif /* NOSETKEY */ #ifdef OS2 int wideresult; /* For wide OS/2 scan codes/cmnum() */ #endif /* OS2 */ #ifndef NOLOCAL #ifdef OS2 extern int tt_scrsize[]; /* Scrollback buffer Sizes */ #endif /* OS2 */ #endif /* NOLOCAL */ /* Printer settings */ extern char * printername; /* NULL if printer not redirected */ extern int printpipe; extern int noprinter; #ifdef PRINTSWI int printtimo = 0; char * printterm = NULL; char * printsep = NULL; int printertype = 0; #ifdef BPRINT int printbidi = 0; /* SET BPRINTER (bidirectional) */ long pportspeed = 0L; /* Bidirection printer port speed, */ int pportparity = 0; /* parity, */ int pportflow = FLO_KEEP; /* and flow control */ #endif /* BPRINT */ #ifdef OS2 extern int txt2ps; /* Text2PS conversion? */ extern int ps_width, ps_length; /* Text2PS dimensions */ #endif /* OS2 */ #endif /* PRINTSWI */ #ifdef OS2 extern int tcp_avail; /* Nonzero if TCP/IP is available */ #ifdef DECNET extern int dnet_avail; /* Ditto for DECnet */ #endif /* DECNET */ #ifdef SUPERLAT extern int slat_avail; #endif /* SUPERLAT */ #endif /* OS2 */ static struct keytab logintab[] = { { "password", LOGI_PSW, CM_INV }, { "prompt", LOGI_PRM, CM_INV }, { "userid", LOGI_UID, 0 } }; #ifndef NOCSETS /* system-independent character sets, defined in ckcxla.[ch] */ extern struct csinfo tcsinfo[]; extern struct langinfo langs[]; /* Other character-set related variables */ extern int tcharset, tslevel, language; #endif /* NOCSETS */ /* File-transfer variable declarations */ #ifndef NOXFER #ifdef CK_AUTODL extern int cmdadl; #endif /* CK_AUTODL */ #ifndef NOSERVER extern int ngetpath; extern char * getpath[]; #endif /* NOSERVER */ extern struct ck_p ptab[]; extern CHAR sstate; /* Protocol start state */ extern CHAR myctlq; /* Control-character prefix */ extern CHAR myrptq; /* Repeat-count prefix */ extern int protocol, size, spsiz, spmax, urpsiz, srvtim, srvcdmsg, slostart, srvdis, xfermode, ckdelay, keep, maxtry, unkcs, bctr, bctf, ebqflg, swcapr, wslotr, lscapr, lscapu, spsizr, rptena, rptmin, docrc, xfrcan, xfrchr, xfrnum, xfrbel, xfrint, srvping, g_xfermode, xfrxla; #ifdef PIPESEND extern int usepipes; #endif /* PIPESEND */ #ifdef CKXXCHAR /* DOUBLE / IGNORE char table */ extern int dblflag, ignflag, dblchar; extern short dblt[]; #endif /* CKXXCHAR */ #ifdef CK_SPEED extern short ctlp[]; /* Control-prefix table */ extern int prefixing; static struct keytab pfxtab[] = { "all", PX_ALL, 0, "cautious", PX_CAU, 0, "minimal", PX_WIL, 0, "none", PX_NON, 0 }; #endif /* CK_SPEED */ #endif /* NOXFER */ /* Declarations from cmd package */ #ifdef DCMDBUF extern char *cmdbuf; /* Command buffer */ extern char *line; extern char *tmpbuf; #else extern char cmdbuf[]; /* Command buffer */ extern char line[]; /* Character buffer for anything */ extern char tmpbuf[]; #endif /* DCMDBUF */ /* From main ckuser module... */ extern char *tp, *lp; /* Temporary buffer */ extern int tlevel; /* Take Command file level */ #ifndef NOLOCAL extern int sessft; /* Session-log file type */ extern int slogts; /* Session-log timestamps on/off */ extern int slognul; /* Lines null-terminated */ #endif /* NOLOCAL */ char * tempdir = NULL; /* Temporary directory */ #ifdef VMS int vms_msgs = 1; /* SET MESSAGES */ extern int batch; #endif /* VMS */ /* Keyword tables for SET commands */ #ifdef CK_SPEED struct keytab ctltab[] = { "prefixed", 1, 0, /* Note, the values are important. */ "unprefixed", 0, 0 }; #endif /* CK_SPEED */ static struct keytab oldnew[] = { "new", 0, 0, "old", 1, 0 }; #define MCH_FIFO 1 #define MCH_DOTF 2 struct keytab matchtab[] = { { "dotfile", MCH_DOTF, 0 }, { "fifo", MCH_FIFO, 0 } }; int nmatchtab = (sizeof(matchtab) / sizeof(struct keytab)); #ifndef NOSPL static struct keytab functab[] = { "diagnostics", FUNC_DI, 0, "error", FUNC_ER, 0 }; static int nfunctab = (sizeof(functab) / sizeof(struct keytab)); struct keytab outptab[] = { /* SET OUTPUT parameters */ "pacing", 0, 0, /* only one so far... */ "special-escapes", 1, 0 }; int noutptab = (sizeof(outptab) / sizeof(struct keytab)); /* How many */ #endif /* NOSPL */ struct keytab chktab[] = { /* Block check types */ "1", 1, 0, /* 1 = 6-bit checksum */ "2", 2, 0, /* 2 = 12-bit checksum */ "3", 3, 0, /* 3 = 16-bit CRC */ "4", 4, 0, /* Same as B */ "5", 5, 0, /* Same as F */ "blank-free-2", 4, CM_INV, /* B = 12-bit checksum, no blanks */ "force-3", 5, CM_INV /* F = Force CRC on ALL packets */ }; static int nchkt = (sizeof(chktab) / sizeof(struct keytab)); struct keytab rpttab[] = { /* SET REPEAT */ "counts", 0, 0, /* On or Off */ #ifdef COMMENT "minimum", 1, 0, /* Threshhold */ #endif /* COMMENT */ "prefix", 2, 0 /* Repeat-prefix character value */ }; #ifndef NOLOCAL /* For SET [ MODEM ] CARRIER, and also for SET DIAL CONNECT */ struct keytab crrtab[] = { "automatic", CAR_AUT, 0, /* 2 */ "off", CAR_OFF, 0, /* 0 */ "on", CAR_ON, 0 /* 1 */ }; int ncrr = 3; #endif /* NOLOCAL */ struct keytab ooatab[] = { /* On/Off/Auto table */ "automatic", SET_AUTO, 0, /* 2 */ "off", SET_OFF, 0, /* 0 */ "on", SET_ON, 0 /* 1 */ }; struct keytab ooetab[] = { /* On/Off/Stderr table 2010/03/12 */ "off", SET_OFF, 0, /* for SET DEBUG MESSAGES */ "on", SET_ON, 0, /* 2013-03-13 and SET EXIT MESSAGE */ "s", 2, CM_ABR|CM_INV, "st", 2, CM_ABR|CM_INV, "std", 2, CM_ABR|CM_INV, "stderr", 2, 0, "stdout", SET_ON, CM_INV }; static int nooetab = (sizeof(ooetab) / sizeof(struct keytab)); struct keytab ooktab[] = { /* On/Off/Ask table */ "ask", 2, 0, /* 2 */ "off", SET_OFF, 0, /* 0 */ "on", SET_ON, 0 /* 1 */ }; struct keytab qvtab[] = { /* Quiet/Verbose table */ "quiet", 1, 0, "verbose", 0, 0 }; int nqvt = 2; /* For SET DEBUG */ #define DEB_OFF 0 #define DEB_ON 1 #define DEB_SES 2 #define DEB_TIM 3 #define DEB_LEN 4 #define DEB_MSG 5 struct keytab dbgtab[] = { "linelength", DEB_LEN, CM_INV, "m", DEB_MSG, CM_ABR|CM_INV, "message", DEB_MSG, 0, "msg", DEB_MSG, CM_INV, "off", DEB_OFF, 0, "on", DEB_ON, 0, "session", DEB_SES, 0, "timestamps", DEB_TIM, 0 }; int ndbg = (sizeof(dbgtab) / sizeof(struct keytab)); #ifndef NOLOCAL /* Transmission speeds */ #ifdef TTSPDLIST /* Speed table constructed at runtime . . . */ struct keytab * spdtab = NULL; int nspd = 0; #else /* Note, the values are encoded in cps rather than bps because 19200 and higher are too big for some ints. All but 75bps 134.5bps are multiples of ten. Result of lookup in this table must be multiplied by 10 to get actual speed in bps. If this number is 70, it must be changed to 75. If it is 888, this means 75/1200 split speed. The values are generic, rather than specific to UNIX. We can't use B75, B1200, B9600, etc, because non-UNIX versions of C-Kermit will not necessarily have these symbols defined. The BPS_xxx symbols are Kermit-specific, and are defined in ckcdeb.h or on the CC command line. Like all other keytabs, this one must be in "alphabetical" order, rather than numeric order. */ struct keytab spdtab[] = { "0", 0, CM_INV, "110", 11, 0, #ifdef BPS_115K "115200",11520, 0, #endif /* BPS_115K */ "1200", 120, 0, #ifdef BPS_134 "134.5", 134, 0, #endif /* BPS_134 */ #ifdef BPS_14K "14400", 1440, 0, #endif /* BPS_14K */ #ifdef BPS_150 "150", 15, 0, #endif /* BPS_150 */ #ifdef BPS_1500K "1500000", 150000, 0, #endif /* BPS_115K */ #ifdef BPS_1800 "1800", 180, 0, #endif /* BPS_150 */ #ifdef BPS_19K "19200", 1920, 0, #endif /* BPS_19K */ #ifdef BPS_200 "200", 20, 0, #endif /* BPS_200 */ #ifdef BPS_230K "230400", 23040, 0, #endif /* BPS_230K */ "2400", 240, 0, #ifdef BPS_28K "28800", 2880, 0, #endif /* BPS_28K */ "300", 30, 0, #ifdef BPS_3600 "3600", 360, 0, #endif /* BPS_3600 */ #ifdef BPS_38K "38400", 3840, 0, #endif /* BPS_38K */ #ifdef BPS_460K "460800", 46080, 0, /* Need 32 bits for this... */ #endif /* BPS_460K */ "4800", 480, 0, #ifdef BPS_50 "50", 5, 0, #endif /* BPS_50 */ #ifdef BPS_57K "57600", 5760, 0, #endif /* BPS_57K */ "600", 60, 0, #ifdef BPS_7200 "7200", 720, 0, #endif /* BPS_7200 */ #ifdef BPS_75 "75", 7, 0, #endif /* BPS_75 */ #ifdef BPS_7512 "75/1200",888, 0, /* Code "888" for split speed */ #endif /* BPS_7512 */ #ifdef BPS_76K "76800", 7680, 0, #endif /* BPS_76K */ #ifdef BPS_921K "921600", 92160,0, /* Need 32 bits for this... */ #endif /* BPS_921K */ "9600", 960, 0 }; int nspd = (sizeof(spdtab) / sizeof(struct keytab)); /* How many speeds */ #endif /* TTSPDLIST */ #ifdef TN_COMPORT struct keytab tnspdtab[] = { /* RFC 2217 TELNET COMPORT Option */ "115200", 11520, 0, /* (add any other defined speeds) */ "1200", 120, 0, "14400", 1440, 0, "19200", 1920, 0, "230400", 23040, 0, "2400", 240, 0, "28800", 2880, 0, "300", 30, 0, "38400", 3840, 0, "460800", 46080, 0, "4800", 480, 0, "57600", 5760, 0, "600", 60, 0, "9600", 960, 0 }; int ntnspd = (sizeof(tnspdtab) / sizeof(struct keytab)); /* How many speeds */ #endif /* TN_COMPORT */ #endif /* NOLOCAL */ #ifndef NOCSETS extern struct keytab lngtab[]; /* Languages for SET LANGUAGE */ extern int nlng; #endif /* NOCSETS */ #ifndef NOLOCAL /* Duplex keyword table */ struct keytab dpxtab[] = { "full", 0, 0, "half", 1, 0 }; #endif /* NOLOCAL */ /* Flow Control */ struct keytab cxtypesw[] = { #ifdef DECNET "/decnet", CXT_DECNET, 0, #endif /* DECNET */ "/direct-serial", CXT_DIRECT, 0, #ifdef DECNET "/lat", CXT_LAT, 0, #else #ifdef SUPERLAT "/lat", CXT_LAT, 0, #endif /* SUPERLAT */ #endif /* DECNET */ "/modem", CXT_MODEM, 0, #ifdef NPIPE "/named-pipe", CXT_NPIPE, 0, #endif /* NPIPE */ #ifdef NETBIOS "/netbios", CXT_NETBIOS, 0, #endif /* NETBIOS */ "/remote", CXT_REMOTE, 0, #ifdef TCPSOCKET "/tcpip", CXT_TCPIP, 0, #endif /* TCPSOCKET */ #ifdef ANYX25 "/x.25", CXT_X25, 0, #endif /* ANYX25 */ "", 0, 0 }; int ncxtypesw = (sizeof(cxtypesw) / sizeof(struct keytab)); #ifdef TN_COMPORT struct keytab tnflotab[] = { /* SET FLOW-CONTROL keyword table */ "dtr/cd", FLO_DTRC, 0, /* for RFC 2217 Telnet COMPORT */ "dtr/cts", FLO_DTRT, 0, "keep", FLO_KEEP, 0, "none", FLO_NONE, 0, "rts/cts", FLO_RTSC, 0, "xon/xoff", FLO_XONX, 0 }; int ntnflo = (sizeof(tnflotab) / sizeof(struct keytab)); #endif /* TN_COMPORT */ struct keytab flotab[] = { /* SET FLOW-CONTROL keyword table */ "automatic", FLO_AUTO, CM_INV, /* Not needed any more */ #ifdef CK_DTRCD "dtr/cd", FLO_DTRC, 0, #endif /* CK_DTRCD */ #ifdef CK_DTRCTS "dtr/cts", FLO_DTRT, 0, #endif /* CK_DTRCTS */ "keep", FLO_KEEP, 0, "none", FLO_NONE, 0, #ifdef CK_RTSCTS "rts/cts", FLO_RTSC, 0, #endif /* CK_RTSCTS */ #ifndef Plan9 "xon/xoff", FLO_XONX, 0, #endif /* Plan9 */ "", 0, 0 }; int nflo = (sizeof(flotab) / sizeof(struct keytab)) - 1; /* Handshake characters */ struct keytab hshtab[] = { "bell", 007, 0, "code", 998, 0, "cr", 015, 0, "esc", 033, 0, "lf", 012, 0, "none", 999, 0, /* (can't use negative numbers) */ "xoff", 023, 0, "xon", 021, 0 }; int nhsh = (sizeof(hshtab) / sizeof(struct keytab)); #ifndef NOLOCAL static struct keytab sfttab[] = { /* File types for SET SESSION-LOG */ "ascii", XYFT_T, CM_INV, "binary", XYFT_B, 0, "debug", XYFT_D, 0, "null-padded-lines", 998, 0, "text", XYFT_T, 0, "timestamped-text", 999, 0 }; static int nsfttab = (sizeof(sfttab) / sizeof(struct keytab)); #endif /* NOLOCAL */ #ifndef NODIAL #ifdef NETCONN /* Networks directory depends */ int nnetdir = 0; /* on DIAL code -- fix later... */ char *netdir[MAXDDIR+2]; #endif /* NETCONN */ _PROTOTYP( static int setdial, (int) ); _PROTOTYP( static int setdcd, (void) ); _PROTOTYP( static int cklogin, (void) ); #ifndef MINIDIAL #ifdef OLDTBCODE extern int tbmodel; /* Telebit model ID */ #endif /* OLDTBCODE */ #endif /* MINIDIAL */ extern MDMINF *modemp[]; /* Pointers to modem info structs */ extern struct keytab mdmtab[]; /* Modem types (in module ckudia.c) */ extern int nmdm; /* Number of them */ _PROTOTYP(static int dialstr,(char **, char *)); extern int dialhng, dialtmo, dialksp, dialdpy, dialmhu, dialec, dialdc; extern int dialrtr, dialint, dialudt, dialsrt, dialrstr, mdmwaitd; extern int mdmspd, dialfc, dialmth, dialesc, dialfld, dialidt, dialpace; extern int mdmspk, mdmvol, dialtest; int dialcvt = 2; /* DIAL CONVERT-DIRECTORY */ int dialcnf = 0; /* DIAL CONFIRMATION */ int dialcon = 2; /* DIAL CONNECT */ int dialcq = 0; /* DIAL CONNECT AUTO quiet/verbose */ extern long dialmax, dialcapas; int usermdm = 0; extern int ndialdir; extern char *dialini, *dialmstr, *dialmprmt, *dialdir[], *dialcmd, *dialnpr, *dialdcon, *dialdcoff, *dialecon, *dialecoff, *dialhcmd, *dialx3, *dialhwfc, *dialswfc, *dialnofc, *dialtone, *dialpulse, *dialname, *diallac; extern char *diallcc, *dialixp, *dialixs, *dialldp, *diallds, *dialtfp, *dialpxi, *dialpxo, *dialsfx, *dialaaon, *dialaaoff; extern char *diallcp, *diallcs, *dialini2, *dialmac; extern char *dialspoff, *dialspon, *dialvol1, *dialvol2, *dialvol3; char *dialtocc[MAXTPCC] = { NULL, NULL }; int ndialtocc = 0; char *dialpucc[MAXTPCC] = { NULL, NULL }; int ndialpucc = 0; char *dialtfc[MAXTOLLFREE] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; int ntollfree = 0; char *dialpxx[MAXPBXEXCH] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; int ndialpxx = 0; char *diallcac[MAXLOCALAC] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; int nlocalac = 0; static struct keytab drstrtab[] = { "international", 5, 0, "local", 2, 0, "long-distance", 4, 0, "none", 6, 0 }; static struct keytab dcnvtab[] = { "ask", 2, 0, "off", 0, 0, "on", 1, 0 }; struct keytab setmdm[] = { "capabilities", XYDCAP, 0, "carrier-watch", XYDMCD, 0, "command", XYDSTR, 0, "compression", XYDDC, CM_INV, "data-compression", XYDDC, 0, "dial-command", XYDDIA, 0, "error-correction", XYDEC, 0, "escape-character", XYDESC, 0, "flow-control", XYDFC, 0, "hangup-method", XYDMHU, 0, #ifndef NOXFER "kermit-spoof", XYDKSP, 0, #endif /* NOXFER */ "maximum-speed", XYDMAX, 0, "name", XYDNAM, 0, "speaker", XYDSPK, 0, "speed-matching", XYDSPD, 0, "type", XYDTYP, 0, "volume", XYDVOL, 0 }; int nsetmdm = (sizeof(setmdm) / sizeof(struct keytab)); struct keytab voltab[] = { "high", 3, 0, "low", 1, 0, "medium", 2, 0 }; struct keytab mdmcap[] = { "at-commands", CKD_AT, 0, "compression", CKD_DC, 0, "dc", CKD_DC, CM_INV, "ec", CKD_EC, CM_INV, "error-correction", CKD_EC, 0, "hardware-flow", CKD_HW, 0, "hwfc", CKD_HW, CM_INV, "itu", CKD_V25, CM_INV, "kermit-spoof", CKD_KS, 0, "ks", CKD_KS, CM_INV, "sb", CKD_SB, CM_INV, "software-flow", CKD_SW, 0, "speed-buffering", CKD_SB, 0, "swfc", CKD_SW, CM_INV, "tb", CKD_TB, CM_INV, "telebit", CKD_TB, 0, "v25bis-commands", CKD_V25, 0 }; int nmdmcap = (sizeof(mdmcap) / sizeof(struct keytab)); #ifdef COMMENT /* SET ANSWER not implemented yet */ static struct keytab answertab[] = { { "caller-id", XYA_CID, 0 }; { "rings", XYA_RNG, 0 }; { "", 0, 0 } }; static int nanswertab = (sizeof(answertab) / sizeof(struct keytab)) - 1; #endif /* COMMENT */ struct keytab dialtab[] = { /* SET DIAL table */ "area-code", XYDLAC, 0, /* Also still includes items */ "compression", XYDDC, CM_INV, /* that were moved to SET MODEM, */ "confirmation", XYDCNF, 0, /* but they are CM_INVisible... */ "connect", XYDCON, 0, "convert-directory",XYDCVT, 0, "country-code", XYDLCC, 0, "dial-command", XYDDIA, CM_INV, "directory", XYDDIR, 0, "display", XYDDPY, 0, "escape-character", XYDESC, CM_INV, "error-correction", XYDEC, CM_INV, "flow-control", XYDFC, CM_INV, "force-long-distance", XYDFLD, 0, "hangup", XYDHUP, 0, "ignore-dialtone", XYDIDT, 0, "interval", XYDINT, 0, "in", XYDINI, CM_INV|CM_ABR, "init-string", XYDINI, CM_INV, "intl-prefix", XYDIXP, 0, "intl-suffix", XYDIXS, 0, #ifndef NOXFER "kermit-spoof", XYDKSP, CM_INV, #endif /* NOXFER */ "lc-area-codes", XYDLLAC, 0, "lc-prefix", XYDLCP, 0, "lc-suffix", XYDLCS, 0, "ld-prefix", XYDLDP, 0, "ld-suffix", XYDLDS, 0, "local-area-code", XYDLAC, CM_INV, "local-prefix", XYDLCP, CM_INV, "local-suffix", XYDLCS, CM_INV, "m", XYDMTH, CM_INV|CM_ABR, #ifndef NOSPL "macro", XYDMAC, 0, /* 195 */ #endif /* NOSPL */ #ifdef MDMHUP "me", XYDMTH, CM_INV|CM_ABR, #endif /* MDMHUP */ "method", XYDMTH, 0, "mnp-enable", XYDMNP, CM_INV, /* obsolete but still accepted */ #ifdef MDMHUP "modem-hangup", XYDMHU, CM_INV, #endif /* MDMHUP */ "pacing", XYDPAC, 0, "pbx-exchange", XYDPXX, 0, "pbx-inside-prefix",XYDPXI, 0, "pbx-outside-prefix",XYDPXO, 0, "prefix", XYDNPR, 0, "pulse-countries", XYDPUCC, 0, "restrict", XYDRSTR, 0, "retries", XYDRTM, 0, "sort", XYDSRT, 0, "speed-matching", XYDSPD, CM_INV, "string", XYDSTR, CM_INV, "suffix", XYDSFX, 0, "test", XYDTEST, 0, "timeout", XYDTMO, 0, "tf-area-code", XYDTFC, CM_INV, "tf-prefix", XYDTFP, CM_INV, "toll-free-area-code",XYDTFC,0, "toll-free-prefix", XYDTFP, 0, "tone-countries", XYDTOCC, 0 }; int ndial = (sizeof(dialtab) / sizeof(struct keytab)); #ifdef MDMHUP struct keytab mdmhang[] = { "dtr", 0, 0, "modem-command", 1, 0, "rs232-signal", 0, 0, "v24-signal", 0, CM_INV }; #endif /* MDMHUP */ static struct keytab mdmcmd[] = { "autoanswer", XYDS_AN, 0, /* autoanswer */ "compression", XYDS_DC, 0, /* data compression */ "dial-mode-prompt", XYDS_MP, 0, /* dial mode prompt */ "dial-mode-string", XYDS_MS, 0, /* dial mode string */ "error-correction", XYDS_EC, 0, /* error correction */ "hangup-command", XYDS_HU, 0, /* hangup command */ "hardware-flow", XYDS_HW, 0, /* hwfc */ "ignore-dialtone", XYDS_ID, 0, /* ignore dialtone */ "init-string", XYDS_IN, 0, /* init string */ "no-flow-control", XYDS_NF, 0, /* no flow control */ "predial-init", XYDS_I2, 0, /* last-minute setup commands */ "pulse", XYDS_DP, 0, /* pulse */ "software-flow", XYDS_SW, 0, /* swfc */ "speaker", XYDS_SP, 0, /* Speaker */ "tone", XYDS_DT, 0, /* tone */ "volume", XYDS_VO, 0 /* Volume */ }; static int nmdmcmd = (sizeof(mdmcmd) / sizeof(struct keytab)); struct keytab dial_fc[] = { "auto", FLO_AUTO, 0, "none", FLO_NONE, 0, "rts/cts", FLO_RTSC, 0, "xon/xoff", FLO_XONX, 0 }; struct keytab dial_m[] = { /* DIAL METHOD */ "auto", XYDM_A, 0, "default", XYDM_D, 0, "pulse", XYDM_P, 0, "tone", XYDM_T, 0 }; int ndial_m = (sizeof(dial_m)/sizeof(struct keytab)); #endif /* NODIAL */ #ifdef CK_TAPI struct keytab tapitab[] = { /* Top-Level Microsoft TAPI */ "configure-line", XYTAPI_CFG, 0, "dialing-properties", XYTAPI_DIAL, 0 }; int ntapitab = (sizeof(tapitab)/sizeof(struct keytab)); struct keytab settapitab[] = { /* SET Microsoft TAPI */ "inactivity-timeout", XYTAPI_INA, 0, "line", XYTAPI_LIN, 0, "location", XYTAPI_LOC, 0, "manual-dialing", XYTAPI_MAN, 0, "modem-dialing", XYTAPI_PASS, 0, "modem-lights", XYTAPI_LGHT, 0, "phone-number-conversions", XYTAPI_CON, 0, "port", XYTAPI_LIN, CM_INV, "post-dial-terminal", XYTAPI_PST, 0, "pre-dial-terminal", XYTAPI_PRE, 0, "use-windows-configuration", XYTAPI_USE, 0, "wait-for-credit-card-tone", XYTAPI_BNG, 0 }; int nsettapitab = (sizeof(settapitab)/sizeof(struct keytab)); struct keytab * tapiloctab = NULL; /* Microsoft TAPI Locations */ int ntapiloc = 0; extern struct keytab * tapilinetab; /* Microsoft TAPI Line Devices */ extern int ntapiline; extern int tttapi; /* TAPI in use */ extern int tapipass; /* TAPI Passthrough mode */ extern int tapiconv; /* TAPI Conversion mode */ extern int tapilights; extern int tapipreterm; extern int tapipostterm; extern int tapimanual; extern int tapiinactivity; extern int tapibong; extern int tapiusecfg; #endif /* CK_TAPI */ #ifdef VMS extern int vms_text; static struct keytab vmstftab[] = { /* SET VMS_TEXT */ { "stream_lf", VMSTFS, 0 }, { "variable", VMSTFV, 0 } }; int nvmstftab = (sizeof(vmstftab) / sizeof(struct keytab)); #endif /* VMS */ #ifndef NOPUSH extern int nopush; extern int wildena; #ifdef UNIX struct keytab wildtab[] = { /* SET WILDCARD-EXPANSION */ #ifdef UNIX "kermit", WILD_KER, 0, /* By Kermit */ #endif /* UNIX */ "off", WILD_OFF, 0, /* Disabled */ "on", WILD_ON, 0, /* Enabled */ #ifdef UNIX "shell", WILD_SHE, 0, /* By Shell */ #endif /* UNIX */ "", 0, 0 }; int nwild = (sizeof(wildtab) / sizeof(struct keytab)) - 1; struct keytab wdottab[] = { /* cont'd */ "/match-dot-files", 1, 0, "/no-match-dot-files", 0, 0 }; extern int wildxpand; #endif /* UNIX */ #endif /* NOPUSH */ #ifdef NETCONN extern struct keytab netcmd[], netkey[]; extern int nnets, nnetkey; #ifdef TCPSOCKET extern struct keytab tcpopt[]; extern int ntcpopt; #endif /* TCPSOCKET */ #ifdef NPIPE char pipename[PIPENAML+1] = { NUL, NUL }; #endif /* NPIPE */ #ifdef CK_NETBIOS extern unsigned char NetBiosName[]; #endif /* CK_NETBIOS */ #endif /* NETCONN */ #ifdef ANYX25 struct keytab x25tab[] = { "call-user-data", XYUDAT, 0, "closed-user-group", XYCLOS, 0, "reverse-charge", XYREVC, 0 }; int nx25 = (sizeof(x25tab) / sizeof(struct keytab)); #ifndef IBMX25 struct keytab padx3tab[] = { "break-action", PAD_BREAK_ACTION, 0, "break-character", PAD_BREAK_CHARACTER, 0, "character-delete", PAD_CHAR_DELETE_CHAR, 0, "cr-padding", PAD_PADDING_AFTER_CR, 0, "discard-output", PAD_SUPPRESSION_OF_DATA, 0, "echo", PAD_ECHO, 0, "editing", PAD_EDITING, 0, "escape", PAD_ESCAPE, 0, "forward", PAD_DATA_FORWARD_CHAR, 0, "lf-padding", PAD_PADDING_AFTER_LF, 0, "lf-insert", PAD_LF_AFTER_CR, 0, "line-delete", PAD_BUFFER_DELETE_CHAR, 0, "line-display", PAD_BUFFER_DISPLAY_CHAR, 0, "line-fold", PAD_LINE_FOLDING, 0, "pad-flow-control", PAD_FLOW_CONTROL_BY_PAD, 0, "service-signals", PAD_SUPPRESSION_OF_SIGNALS, 0, "timeout", PAD_DATA_FORWARD_TIMEOUT, 0, /* Speed is read-only */ "transmission-rate", PAD_LINE_SPEED, 0, "user-flow-control", PAD_FLOW_CONTROL_BY_USER, 0 }; int npadx3 = (sizeof(padx3tab) / sizeof(struct keytab)); #endif /* IBMX25 */ #endif /* ANYX25 */ #ifdef TLOG static struct keytab vbtab[] = { "brief", 0, 0, #ifdef OS2ORUNIX "ftp", 2, 0, #else #ifdef VMS "ftp", 2, 0, #endif /* def VMS */ #endif /* OS2ORUNIX */ "verbose", 1, 0 }; int nvb = (sizeof(vbtab) / sizeof(struct keytab)); #endif /* TLOG */ #ifdef CKSYSLOG static struct keytab syslogtab[] = { "all", SYSLG_CX, 0, "commands", SYSLG_CM, 0, "connection", SYSLG_AC, 0, "debug", SYSLG_DB, 0, "dial", SYSLG_DI, 0, "file-access", SYSLG_FA, 0, "file-create", SYSLG_FC, 0, "login", SYSLG_LI, 0, "none", SYSLG_NO, 0, "protocol", SYSLG_PR, 0 }; int nsyslog = (sizeof(syslogtab) / sizeof(struct keytab)); #endif /* CKSYSLOG */ /* Parity keyword table */ struct keytab partbl[] = { "even", 'e', 0, #ifdef HWPARITY "hardware",'H', 0, #endif /* HWPARITY */ "mark", 'm', 0, "none", 0 , 0, "odd", 'o', 0, "space", 's', 0 }; int npar = (sizeof(partbl) / sizeof(struct keytab)); #ifdef HWPARITY struct keytab hwpartbl[] = { /* Add mark and space if needed and possible */ "even", 'e', 0, #ifdef OS2 "mark", 'm', 0, #endif /* OS2 */ "odd", 'o', 0, #ifdef OS2 "space", 's', 0, #endif /* OS2 */ "", 0, 0 }; int nhwpar = (sizeof(hwpartbl) / sizeof(struct keytab)) - 1; #endif /* HWPARITY */ /* On/Off table */ struct keytab onoff[] = { "off", 0, 0, "on", 1, 0 }; #define XYCD_M 0 /* CD MESSAGE */ #define XYCD_P 1 /* CD PATH */ #define XYCD_H 2 /* CD HOME */ struct keytab cdtab[] = { "home", XYCD_H, 0, "message", XYCD_M, 0, "path", XYCD_P, 0 }; int ncdtab = (sizeof(cdtab) / sizeof(struct keytab)); struct keytab cdmsg[] = { "file", 2, 0, "off", 0, 0, "on", 1, 0 }; int ncdmsg = (sizeof(cdmsg) / sizeof(struct keytab)); static struct keytab xittab[] = { /* SET EXIT */ "hangup", 3, 0, /* ...HANGUP */ "message", 4, 0, /* ...MESSAGE */ "on-disconnect", 2, 0, /* ...ON-DISCONNECT */ "status", 0, 0, /* ...STATUS */ "warning", 1, 0 /* ...WARNING */ }; int nexit = (sizeof(xittab) / sizeof(struct keytab)); struct keytab xitwtab[] = { /* SET EXIT WARNING */ "always", 2, 0, /* even when not connected */ "off", 0, 0, /* no warning */ "on", 1, 0 /* when connected */ }; int nexitw = (sizeof(xitwtab) / sizeof(struct keytab)); struct keytab rltab[] = { "local", 1, 0, /* ECHO values */ "off", 0, CM_INV, "on", 1, CM_INV, "remote", 0, 0 }; int nrlt = (sizeof(rltab) / sizeof(struct keytab)); /* Incomplete File Disposition table */ struct keytab ifdtab[] = { "discard", SET_OFF, 0, "keep", SET_ON, 0 }; struct keytab ifdatab[] = { "auto", SET_AUTO, 0, "discard", SET_OFF, 0, "keep", SET_ON, 0 }; char * ifdnam[] = { "discard", "keep", "auto" }; /* SET TAKE parameters table */ static struct keytab taktab[] = { "echo", 0, 0, "error", 1, 0, "off", 2, CM_INV, /* For compatibility */ "on", 3, CM_INV /* with MS-DOS Kermit... */ }; #ifndef NOSPL #ifdef COMMENT /* not used */ static struct keytab suftab[] = { /* (what to do with) STARTUP-FILE */ "delete", 1, 0, "keep", 0, 0 }; #endif /* COMMENT */ /* SET MACRO parameters table */ static struct keytab smactab[] = { "echo", 0, 0, "error", 1, 0 }; #endif /* NOSPL */ #ifndef NOSCRIPT static struct keytab scrtab[] = { "echo", 0, 0 }; #endif /* NOSCRIPT */ /* SET COMMAND table */ /* SET COMMAND items... */ #define SCMD_BSZ 0 /* BYTESIZE */ #define SCMD_RCL 1 /* RECALL */ #define SCMD_RTR 2 /* RETRY */ #define SCMD_QUO 3 /* QUOTING */ #define SCMD_COL 4 /* COLOR */ #define SCMD_HIG 5 /* HEIGHT */ #define SCMD_WID 6 /* WIDTH */ #define SCMD_CUR 7 /* CURSOR-POSITION */ #define SCMD_SCR 8 /* SCROLLBACK */ #define SCMD_MOR 9 /* MORE-PROMPTING */ #define SCMD_INT 10 /* INTERRUPTION */ #define SCMD_ADL 11 /* AUTODOWNLOAD */ #define SCMD_STA 12 /* STATUSLINE */ #define SCMD_DBQ 13 /* DOUBLEQUOTING */ #define SCMD_CBR 14 /* CBREAK */ #define SCMD_BFL 15 /* BUFFER-SIZE (not used) */ #define SCMD_ERR 16 /* ERROR */ #define SCMD_VAR 17 /* VARIABLE-EVALUATION */ static struct keytab scmdtab[] = { #ifdef CK_AUTODL "autodownload", SCMD_ADL, 0, #endif /* CK_AUTODL */ #ifdef COMMENT /* To implement this requires that we change CMDBL and ATMBL from compile-time symbols to runtime variables. Not a big deal, but not trivial either. */ "buffer-size", SCMD_BFL, 0, #endif /* COMMENT */ "bytesize", SCMD_BSZ, 0, "cbreak", SCMD_CBR, CM_INV, #ifdef OS2 "color", SCMD_COL, 0, "cursor-position", SCMD_CUR, 0, #endif /* OS2 */ #ifdef DOUBLEQUOTING "doublequoting", SCMD_DBQ, 0, #endif /* DOUBLEQUOTING */ "error-display", SCMD_ERR, 0, "height", SCMD_HIG, 0, "interruption", SCMD_INT, 0, "more-prompting", SCMD_MOR, 0, "quoting", SCMD_QUO, 0, #ifdef CK_RECALL "recall-buffer-size", SCMD_RCL, 0, #endif /* CK_RECALL */ #ifdef CK_RECALL "retry", SCMD_RTR, 0, #endif /* CK_RECALL */ #ifdef OS2 #ifdef ONETERMUPD "scrollback", SCMD_SCR, 0, "statusline", SCMD_STA, 0, #endif /* ONETERMUPD */ #endif /* OS2 */ "variable-evaluation", SCMD_VAR,0, "width", SCMD_WID, 0 }; static int nbytt = (sizeof(scmdtab) / sizeof(struct keytab)); #ifndef NOSERVER /* Server parameters table */ static struct keytab srvtab[] = { "cd-message", XYSERC, 0, "display", XYSERD, 0, "get-path", XYSERP, 0, "idle-timeout", XYSERI, 0, "keepalive", XYSERK, 0, "login", XYSERL, 0, "timeout", XYSERT, 0 }; static int nsrvt = (sizeof(srvtab) / sizeof(struct keytab)); #endif /* NOSERVER */ static struct keytab sleeptab[] = { /* SET SLEEP table */ "cancellation", 0, 0 }; static struct keytab tstab[] = { /* SET TRANSFER/XFER table */ "bell", XYX_BEL, 0, #ifdef XFRCAN "cancellation", XYX_CAN, 0, #endif /* XFRCAN */ #ifndef NOCSETS "character-set", XYX_CSE, 0, #endif /* NOCSETS */ #ifndef NOSPL "crc-calculation", XYX_CRC, 0, #endif /* NOSPL */ "display", XYX_DIS, 0, "interruption", XYX_INT, 0, "locking-shift", XYX_LSH, 0, "message", XYX_MSG, 0, "mode", XYX_MOD, 0, "msg", XYX_MSG, CM_INV, #ifdef PIPESEND "pipes", XYX_PIP, 0, #endif /* PIPESEND */ #ifdef CK_XYZ "protocol", XYX_PRO, 0, #endif /* CK_XYZ */ "report", XYX_RPT, 0, "slow-start", XYX_SLO, 0, #ifndef NOCSETS "translation", XYX_XLA, 0, #else "translation", XYX_XLA, CM_INV, #endif /* NOCSETS */ "xlation", XYX_XLA, CM_INV, "", 0, 0 }; static int nts = (sizeof(tstab) / sizeof(struct keytab)) - 1; static struct keytab rtstab[] = { /* REMOTE SET TRANSFER/XFER table */ #ifndef NOCSETS "character-set", XYX_CSE, 0, #endif /* NOCSETS */ "mode", XYX_MOD, 0 }; static int nrts = (sizeof(rtstab) / sizeof(struct keytab)); struct keytab xfrmtab[] = { /* TRANSFER MODE table */ "automatic", XMODE_A, 0, "manual", XMODE_M, 0 }; #ifdef LOCUS extern int locus, autolocus; static struct keytab locustab[] = { #ifdef KUI { "ask", 3, 0 }, /* Presently implemented in GUI only */ #endif /* KUI */ { "auto", 2, 0 }, { "local", 1, 0 }, { "remote", 0, 0 } }; static int nlocustab = (sizeof(locustab) / sizeof(struct keytab)); #endif /* LOCUS */ #ifndef NOCSETS /* SET TRANSFER CHARACTER-SET table */ extern struct keytab tcstab[]; extern int ntcs; #endif /* NOCSETS */ /* SET TRANSFER LOCKING-SHIFT table */ struct keytab lstab[] = { "forced", 2, 0, "off", 0, 0, "on", 1, 0 }; int nls = (sizeof(lstab) / sizeof(struct keytab)); /* SET TELNET tables */ #ifdef TNCODE extern int tn_nlm, tn_b_nlm, tn_b_meu, tn_b_ume, tn_b_xfer, tn_sb_bug; extern int tn_no_encrypt_xfer, tn_auth_krb5_des_bug; extern int tn_wait_flg, tn_duplex, tn_delay_sb, tn_sfu; extern int sl_tn_saved; extern int tn_infinite; extern int tn_rem_echo; extern int tn_deb; extern int tn_auth_how; extern int tn_auth_enc; #ifdef CK_FORWARD_X extern char * tn_fwdx_xauthority; #endif /* CK_FORWARD_X */ #ifdef CK_AUTHENTICATION static struct keytab setauth[] = { #ifdef CK_KERBEROS "k4", AUTH_KRB4, CM_INV, "k5", AUTH_KRB5, CM_INV, "kerberos4", AUTH_KRB4, 0, "kerberos5", AUTH_KRB5, 0, "kerberos_iv",AUTH_KRB4, CM_INV, "kerberos_v", AUTH_KRB5, CM_INV, "krb4", AUTH_KRB4, CM_INV, "krb5", AUTH_KRB5, CM_INV, #endif /* CK_KERBEROS */ #ifdef CK_SRP "srp", AUTH_SRP, 0, #endif /* CK_SRP */ #ifdef CK_SSL "ssl", AUTH_SSL, 0, "tls", AUTH_TLS, 0, #endif /* CK_SSL */ "", 0, 0 }; static int nsetauth = sizeof(setauth)/sizeof(struct keytab) - 1; #ifdef CK_KERBEROS extern char * krb5_d_principal; /* Default principal */ extern char * krb5_d_instance; extern char * krb5_d_realm; /* Default realm */ extern char * krb5_d_cc; /* Default credentials cache */ extern char * krb5_d_srv; /* Default service name */ extern int krb5_d_lifetime; /* Default lifetime */ extern int krb5_d_forwardable; extern int krb5_d_proxiable; extern int krb5_d_renewable; extern int krb5_autoget; extern int krb5_autodel; extern int krb5_d_getk4; extern int krb5_checkaddrs; /* Check TGT Addrs */ extern int krb5_d_no_addresses; extern char * krb5_d_addrs[]; extern char * k5_keytab; /* Keytab file */ extern struct krb4_init_data krb4_init; extern char * krb4_d_principal; /* Default principal */ extern char * krb4_d_realm; /* Default realm */ extern char * krb4_d_srv; /* Default service name */ extern int krb4_d_lifetime; /* Default lifetime */ extern int krb4_d_preauth; extern char * krb4_d_instance; extern int krb4_autoget; extern int krb4_autodel; extern int krb4_checkaddrs; /* Check TGT Addrs */ extern char * k4_keytab; /* Keytab file */ #ifdef KRB4 extern int k4debug; #endif /* KRB4 */ static struct keytab krbver[] = { "4", 4, 0, "5", 5, 0, "iv", 4, CM_INV, "v", 5, CM_INV }; static int nkrbver = sizeof(krbver)/sizeof(struct keytab); static struct keytab kdestab[] = { "never", KRB_DEL_NO, 0, "no", KRB_DEL_NO, CM_INV, "on-close", KRB_DEL_CL, 0, "on-exit", KRB_DEL_EX, 0 }; static int nkdestab = sizeof(kdestab)/sizeof(struct keytab); static struct keytab k4tab[] = { "autodel", XYKRBDEL, CM_INV, "autodestroy", XYKRBDEL, 0, "autoget", XYKRBGET, 0, "check-address", XYKRBADR, 0, "debug", XYKRBDBG, CM_INV, "instance", XYKRBINS, 0, "keytab", XYKRBKTB, 0, "lifetime", XYKRBLIF, 0, "preauth", XYKRBPRE, 0, "principal", XYKRBPR, 0, "prompt", XYKRBPRM, 0, "realm", XYKRBRL, 0, "service-name", XYKRBSRV, 0 }; static int nk4tab = sizeof(k4tab)/sizeof(struct keytab); static struct keytab k5tab[] = { "addresses", XYKRBADD, 0, "autodelete", XYKRBDEL, CM_INV, "autodestroy", XYKRBDEL, 0, "autoget", XYKRBGET, 0, "cc", XYKRBCC, CM_INV, "check-address", XYKRBADR, 0, "credentials-cache", XYKRBCC, 0, "forwardable", XYKRBFWD, 0, "get-k4-tgt", XYKRBK5K4,0, "instance", XYKRBINS, 0, "keytab", XYKRBKTB, 0, "lifetime", XYKRBLIF, 0, "no-addresses", XYKRBNAD, 0, "principal", XYKRBPR, 0, "prompt", XYKRBPRM, 0, "proxiable", XYKRBPRX, 0, "realm", XYKRBRL, 0, "renewable", XYKRBRNW, 0, "service-name", XYKRBSRV, 0 }; static int nk5tab = sizeof(k5tab)/sizeof(struct keytab); #define KRB_PW_PRM 1 #define KRB_PR_PRM 2 static struct keytab krbprmtab[] = { "password", KRB_PW_PRM, 0, "principal", KRB_PR_PRM, 0 }; #endif /* CK_KERBEROS */ #ifdef CK_SRP static struct keytab srptab[] = { "prompt", XYSRPPRM, 0 }; static int nsrptab = sizeof(srptab)/sizeof(struct keytab); #define SRP_PW_PRM 1 static struct keytab srpprmtab[] = { "password", SRP_PW_PRM, 0 }; #endif /* CK_SRP */ #ifdef CK_SSL static struct keytab ssltab[] = { "certs-ok", XYSSLCOK, CM_INV, "cipher-list", XYSSLCL, 0, "crl-dir", XYSSLCRLD, 0, "crl-file", XYSSLCRL, 0, "debug", XYSSLDBG, 0, "dh-key-file", XYSSLDKFL, CM_INV, "dh-param-file", XYSSLDPFL, 0, "dsa-cert-chain-file", XYSSLDCCF, 0, "dsa-cert-file", XYSSLDCFL, 0, "dsa-key-file", XYSSLDKFL, 0, "dummy", XYSSLDUM, CM_INV, "only", XYSSLON, CM_INV, "random-file", XYSSLRND, 0, "rsa-cert-chain-file", XYSSLRCCF, 0, "rsa-cert-file", XYSSLRCFL, 0, "rsa-key-file", XYSSLRKFL, 0, "verbose", XYSSLVRB, 0, "verify", XYSSLVRF, 0, "verify-dir", XYSSLVRFD, 0, "verify-file", XYSSLVRFF, 0 }; static int nssltab = sizeof(ssltab)/sizeof(struct keytab); static struct keytab sslvertab[] = { "fail-if-no-peer-cert", SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0, "no", SSL_VERIFY_NONE, 0, "none", SSL_VERIFY_NONE, CM_INV, "off", SSL_VERIFY_NONE, CM_INV, "on", SSL_VERIFY_PEER, CM_INV, "peer-cert", SSL_VERIFY_PEER, 0 }; static int nsslvertab = sizeof(sslvertab)/sizeof(struct keytab); #endif /* CK_SSL */ #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION int cx_type = CX_AUTO; extern int sl_cx_type; #endif /* CK_ENCRYPTION */ extern char *tcp_address; #ifndef NOHTTP extern char * tcp_http_proxy; extern char * tcp_http_proxy_user; extern char * tcp_http_proxy_pwd; extern char * tcp_http_proxy_agent; #endif /* NOHTTP */ #ifdef NT #ifdef CK_SOCKS extern char *tcp_socks_svr; extern char *tcp_socks_user; #ifdef CK_SOCKS_NS extern char *tcp_socks_ns; #endif /* CK_SOCKS_NS */ #endif /* CK_SOCKS */ #endif /* NT */ #define UPW_USER 1 #define UPW_PASS 2 #define UPW_AGENT 3 static struct keytab userpass[] = { { "/agent", UPW_AGENT, CM_ARG }, { "/password", UPW_PASS, CM_ARG }, { "/user", UPW_USER, CM_ARG }, }; static int nuserpass = sizeof(userpass)/sizeof(struct keytab); static struct keytab tnnegtab[] = { /* TELNET NEGOTIATION table */ "accepted", TN_NG_AC, 0, "refused", TN_NG_RF, 0, "req", TN_NG_RQ, CM_INV|CM_ABR, "requ", TN_NG_RQ, CM_INV|CM_ABR, "reque", TN_NG_RQ, CM_INV|CM_ABR, "reques", TN_NG_RQ, CM_INV|CM_ABR, "request", TN_NG_RQ, CM_INV|CM_ABR, "requeste", TN_NG_RQ, CM_INV|CM_ABR, "requested", TN_NG_RQ, 0, "required", TN_NG_MU, 0 }; static int ntnnegtab = sizeof(tnnegtab)/sizeof(struct keytab); #ifdef CK_ENCRYPTION static struct keytab typkwd[] = { "/type", 0, CM_ARG }; static struct keytab tnenctab[] = { /* TELNET ENCRYPTION table */ "accepted", TN_NG_AC, CM_INV, "refused", TN_NG_RF, CM_INV, "req", TN_NG_RQ, CM_INV|CM_ABR, "requ", TN_NG_RQ, CM_INV|CM_ABR, "reque", TN_NG_RQ, CM_INV|CM_ABR, "reques", TN_NG_RQ, CM_INV|CM_ABR, "request", TN_NG_RQ, CM_INV|CM_ABR, "requeste", TN_NG_RQ, CM_INV|CM_ABR, "requested", TN_NG_RQ, CM_INV, "required", TN_NG_MU, CM_INV, "start", TN_EN_START, CM_INV, "stop", TN_EN_STOP, CM_INV, "type", TN_EN_TYP, 0 }; static int ntnenc = sizeof(tnenctab)/sizeof(struct keytab) ; #endif /* CK_ENCRYPTION */ #ifdef CK_FORWARD_X static struct keytab tnfwdxtab[] = { /* TELNET FORWARD-X table */ "no-encryption", 1, CM_INV, "xauthority-file", 0, 0 }; static int ntnfwdx = sizeof(tnfwdxtab)/sizeof(struct keytab) ; #endif /* CK_FORWARD_X */ static struct keytab tnbugtab[] = { /* TELNET BUG table */ "auth-krb5-des", 4, 0, "binary-me-means-u-too", 0, 0, "binary-u-means-me-too", 1, 0, "infinite-loop-check", 2, 0, "sb-implies-will-do", 3, 0 }; #ifdef CK_ENVIRONMENT static struct keytab tnenvtab[] = { /* TELNET ENVIRONMENT table */ "acct", TN_ENV_ACCT, 0, "display", TN_ENV_DISP, 0, "job", TN_ENV_JOB, 0, "location", TN_ENV_LOC, 0, "off", TN_ENV_OFF, CM_INV, "on", TN_ENV_ON, CM_INV, "printer", TN_ENV_PRNT, 0, "systemtype",TN_ENV_SYS, 0, "user", TN_ENV_USR, 0, "uservar", TN_ENV_UVAR, 0, "", 0, 0 }; static int ntnenv = sizeof(tnenvtab)/sizeof(struct keytab) - 1; #endif /* CK_ENVIRONMENT */ #ifdef CK_AUTHENTICATION static struct keytab tnauthtab[] = { /* TELNET AUTHENTICATION table */ "accepted", TN_NG_AC, CM_INV, "encrypt-flag", TN_AU_ENC, 0, "forwarding", TN_AU_FWD, 0, "how-flag", TN_AU_HOW, 0, "refused", TN_NG_RF, CM_INV, "req", TN_NG_RQ, CM_INV|CM_ABR, "requ", TN_NG_RQ, CM_INV|CM_ABR, "reque", TN_NG_RQ, CM_INV|CM_ABR, "reques", TN_NG_RQ, CM_INV|CM_ABR, "request", TN_NG_RQ, CM_INV|CM_ABR, "requeste", TN_NG_RQ, CM_INV|CM_ABR, "requested", TN_NG_RQ, CM_INV, "required", TN_NG_MU, CM_INV, "type", TN_AU_TYP, 0 }; static int ntnauth = sizeof(tnauthtab)/sizeof(struct keytab) ; struct keytab autyptab[] = { /* TELNET AUTHENTICATION TYPE table */ "automatic", AUTH_AUTO, 0, #ifdef CK_KERBEROS "k4", AUTH_KRB4, CM_INV, "k5", AUTH_KRB5, CM_INV, "kerberos4", AUTH_KRB4, 0, "kerberos5", AUTH_KRB5, 0, "kerberos_iv",AUTH_KRB4, CM_INV, "kerberos_v", AUTH_KRB5, CM_INV, "krb4", AUTH_KRB4, CM_INV, "krb5", AUTH_KRB5, CM_INV, #endif /* CK_KERBEROS */ "none", AUTH_NONE, 0, #ifdef NT "ntlm", AUTH_NTLM, 0, #endif /* NT */ #ifdef CK_SRP "srp", AUTH_SRP, 0, #endif /* CK_SRP */ #ifdef CK_SSL "ssl", AUTH_SSL, 0, #endif /* CK_SSL */ "", 0, 0 }; int nautyp = sizeof(autyptab)/sizeof(struct keytab) - 1; struct keytab auhowtab[] = { /* TELNET AUTHENTICATION HOW table */ "any", TN_AUTH_HOW_ANY, 0, "mutual", TN_AUTH_HOW_MUTUAL, 0, "one-way", TN_AUTH_HOW_ONE_WAY, 0, "", 0, 0 }; int nauhow = sizeof(auhowtab)/sizeof(struct keytab) - 1; struct keytab auenctab[] = { /* TELNET AUTHENTICATION ENCRYPT table */ "any", TN_AUTH_ENC_ANY, 0, "none", TN_AUTH_ENC_NONE, 0, "telopt", TN_AUTH_ENC_TELOPT, 0, #ifdef CK_SSL "tls", TN_AUTH_ENC_TLS, 0, #endif /* CK_SSL */ "", 0, 0 }; int nauenc = sizeof(auenctab)/sizeof(struct keytab) - 1; #endif /* CK_AUTHENTICATION */ #define TN_NL_BIN 3 #define TN_NL_NVT 4 static struct keytab tn_nlmtab[] = { /* TELNET NEWLINE-MODE table */ "binary-mode", TN_NL_BIN, 0, /* Binary mode */ "nvt", TN_NL_NVT, 0, /* NVT mode */ "off", TNL_CRNUL, CM_INV, /* CR-NUL (TELNET spec) */ "on", TNL_CRLF, CM_INV, /* CR-LF (TELNET spec) */ "raw", TNL_CR, CM_INV /* CR only (out of spec) */ }; static int ntn_nlm = (sizeof(tn_nlmtab) / sizeof(struct keytab)); static struct keytab tnlmtab[] = { /* TELNET NEWLINE-MODE table */ "cr", TNL_CR, CM_INV, /* CR only (out of spec) */ "cr-lf", TNL_CRLF, CM_INV, /* CR-LF (TELNET spec) */ "cr-nul", TNL_CRNUL, CM_INV, /* CR-NUL (TELNET spec) */ "lf", TNL_LF, CM_INV, /* LF instead of CR-LF */ "off", TNL_CRNUL, 0, /* CR-NUL (TELNET spec) */ "on", TNL_CRLF, 0, /* CR-LF (TELNET spec) */ "raw", TNL_CR, 0 /* CR only (out of spec) */ }; static int ntnlm = (sizeof(tnlmtab) / sizeof(struct keytab)); struct keytab tntab[] = { #ifdef CK_AUTHENTICATION "authentication", CK_TN_AU, 0, #endif /* CK_AUTHENTICATION */ "b", CK_TN_BM, CM_INV|CM_ABR, "bi", CK_TN_BM, CM_INV|CM_ABR, "bin", CK_TN_BM, CM_INV|CM_ABR, "bina", CK_TN_BM, CM_INV|CM_ABR, "binar", CK_TN_BM, CM_INV|CM_ABR, "binary", CK_TN_BM, CM_INV|CM_ABR, "binary-", CK_TN_BM, CM_INV|CM_ABR, "binary-mode", CK_TN_BM, CM_INV, "binary-transfer-mode", CK_TN_XF, 0, "binary-xfer-mode", CK_TN_XF, CM_INV, "bug", CK_TN_BUG, 0, "debug", CK_TN_DB, 0, "delay-sb", CK_TN_DL, 0, "echo", CK_TN_EC, 0, #ifdef CK_ENCRYPTION "encryption", CK_TN_ENC, 0, #endif /* CK_ENCRYPTION */ #ifdef CK_ENVIRONMENT "environment", CK_TN_ENV, 0, #endif /* CK_ENVIRONMENT */ #ifdef CK_FORWARD_X "forward-x", CK_TN_FX, 0, #endif /* CK_FORWARD_X */ #ifdef IKS_OPTION "kermit", CK_TN_IKS, CM_INV, #endif /* IKS_OPTION */ #ifdef CK_SNDLOC "location", CK_TN_LOC, 0, #endif /* CK_SNDLOC */ #ifdef CK_NAWS "naws", CK_TN_NAWS, CM_INV, #endif /* CK_NAWS */ "newline-mode", CK_TN_NL, 0, "no-encrypt-during-xfer", CK_TN_NE, CM_INV, "prompt-for-userid",CK_TN_PUID,0, "remote-echo", CK_TN_RE, 0, #ifdef CK_SSL "start-tls", CK_TN_TLS, CM_INV, #endif /* CK_SSL */ #ifdef NT "sfu-compatibility", CK_TN_SFU, 0, #else "sfu-compatibility", CK_TN_SFU, CM_INV, #endif /* NT */ "terminal-type", CK_TN_TT, 0, "wait-for-negotiations", CK_TN_WAIT, 0, #ifdef CK_ENVIRONMENT "xdisplay-location",CK_TN_XD, CM_INV, #endif /* CK_ENVIRONMENT */ "", 0, 0 }; int ntn = (sizeof(tntab) / sizeof(struct keytab)) - 1; struct keytab tnopttab[] = { #ifdef CK_AUTHENTICATION "authentication", CK_TN_AU, 0, #else "authentication", CK_TN_AU, CM_INV, #endif /* CK_AUTHENTICATION */ "binary-mode", CK_TN_BM, 0, #ifdef TN_COMPORT "c", CK_TN_CPC, CM_INV|CM_ABR, "co", CK_TN_CPC, CM_INV|CM_ABR, "com", CK_TN_CPC, CM_INV|CM_ABR, "com-port-control",CK_TN_CPC, 0, "comport-control", CK_TN_CPC, CM_INV, #else /* TN_COMPORT */ "com-port-control",CK_TN_CPC, CM_INV, "comport-control", CK_TN_CPC, CM_INV, #endif /* TN_COMPORT */ "echo", CK_TN_EC, 0, #ifdef CK_ENCRYPTION "encryption", CK_TN_ENC, 0, #else "encryption", CK_TN_ENC, CM_INV, #endif /* CK_ENCRYPTION */ #ifdef CK_FORWARD_X "forward-x", CK_TN_FX, 0, #else /* CK_FORWARD_X */ "forward-x", CK_TN_FX, CM_INV, #endif /* CK_FORWARD_X */ "ibm-sak", CK_TN_SAK, CM_INV, #ifdef IKS_OPTION "kermit", CK_TN_IKS, 0, #else "kermit", CK_TN_IKS, CM_INV, #endif /* IKS_OPTION */ "lflow", CK_TN_FLW, CM_INV, "logout", CK_TN_LOG, 0, #ifdef CK_NAWS "naws", CK_TN_NAWS, 0, #else "naws", CK_TN_NAWS, CM_INV, #endif /* CK_NAWS */ #ifdef CK_ENVIRONMENT "new-environment", CK_TN_ENV, 0, #else "new-environment", CK_TN_ENV, CM_INV, #endif /* CK_ENVIRONMENT */ "pragma-heartbeat",CK_TN_PHR, CM_INV, "pragma-logon", CK_TN_PLG, CM_INV, "pragma-sspi", CK_TN_PSP, CM_INV, "sak", CK_TN_SAK, CM_INV, #ifdef CK_SNDLOC "send-location", CK_TN_LOC, 0, #else "send-location", CK_TN_LOC, CM_INV, #endif /* CK_SNDLOC */ "sga", CK_TN_SGA, CM_INV|CM_ABR, #ifdef CK_SSL "start-tls", CK_TN_TLS, 0, #else "start-tls", CK_TN_TLS, CM_INV, #endif /* CK_SSL */ "suppress-go-aheads", CK_TN_SGA, 0, "terminal-type", CK_TN_TT, 0, "ttype", CK_TN_TT, CM_INV|CM_ABR, #ifdef CK_ENVIRONMENT "xdisplay-location", CK_TN_XD, 0, #else "xdisplay-location", CK_TN_XD, CM_INV, #endif /* CK_ENVIRONMENT */ "", 0, 0 }; int ntnopt = (sizeof(tnopttab) / sizeof(struct keytab)) - 1; struct keytab tnoptsw[] = { "/client", CK_TN_CLIENT, 0, "/server", CK_TN_SERVER, 0 }; int ntnoptsw = (sizeof(tnoptsw) / sizeof(struct keytab)); #endif /* TNCODE */ struct keytab ftrtab[] = { /* Feature table */ #ifndef NOCSETS /* 0 = we have it, 1 = we don't */ "character-sets", 0, 0, #else "character-sets", 1, 0, #endif /* NOCSETS */ #ifndef NOCYRIL "cyrillic", 0, 0, #else "cyrillic", 1, 0, #endif /* NOCYRIL */ #ifndef NOLOGDIAL "cx-log", 0, 0, #else "cx-log", 1, 0, #endif /* NOLOGDIAL */ #ifndef NODEBUG "debug", 0, 0, #else "debug", 1, 0, #endif /* NODEBUG */ #ifndef NODIAL "dial", 0, 0, #else "dial", 1, 0, #endif /* NODIAL */ #ifdef DYNAMIC "dynamic-memory", 0, 0, #else "dynamic-memory", 1, 0, #endif /* DYNAMIC */ #ifndef NOXFER "file-transfer", 0, 0, #else "file-transfer", 1, 0, #endif /* NOXFER */ #ifdef XXFWD "forward", 0, 0, #else "forward", 1, 0, #endif /* XXFWD */ #ifdef NEWFTP "ftp", 0, 0, #else "ftp", 1, 0, #endif /* NEWFTP */ #ifdef CK_CURSES "fullscreen-display", 0, 0, #else "fullscreen-display", 1, 0, #endif /* CK_CURSES */ #ifdef GREEK "greek", 0, 0, #else "greek", 1, 0, #endif /* GREEK */ #ifdef HEBREW "hebrew", 0, 0, #else "hebrew", 1, 0, #endif /* HEBREW */ #ifndef NOHELP "help", 0, 0, #else "help", 1, 0, #endif /* NOHELP */ #ifndef NOIKSD "iksd", 0, 0, #else "iksd", 1, 0, #endif /* NOIKSD */ #ifndef NOSPL "if-command", 0, 0, #else "if-command", 1, 0, #endif /* NOSPL */ #ifndef NOJC #ifdef UNIX "job-control", 0, 0, #else "job-control", 1, 0, #endif /* UNIX */ #else "job-control", 1, 0, #endif /* NOJC */ #ifdef KANJI "kanji", 0, 0, #else "kanji", 1, 0, #endif /* KANJI */ #ifndef NOXFER "kermit", 0, 0, #else "kermit", 1, 0, #endif /* NOXFER */ #ifdef CK_KERBEROS "kerberos", 0, 0, #else "kerberos", 1, 0, #endif /* CK_KERBEROS */ #ifndef NOCSETS "latin1", 0, 0, #else "latin1", 1, 0, #endif /* NOCSETS */ #ifdef LATIN2 "latin2", 0, 0, #else "latin2", 1, 0, #endif /* LATIN2 */ #ifdef CKLEARN "learned-scripts", 0, 0, #else "learned-scripts", 1, 0, #endif /* CKLEARN */ #ifdef HAVE_LOCALE "locale", 0, 0, #else "locale", 1, 0, #endif /* HAVE_LOCALE */ #ifndef NOLOCAL "making-connections", 0, 0, #else "making-connections", 1, 0, #endif /* NOLOCAL */ #ifdef NETCONN "network", 0, 0, #else "network", 1, 0, #endif /* NETCONN */ #ifdef NT #ifdef CK_AUTHENTICATION "ntlm", 1, 0, #else /* CK_AUTHENTICATION */ "ntlm", 0, 0, #endif /* CK_AUTHENTICATION */ #else /* NT */ "ntlm", 0, 0, #endif /* NT */ #ifdef PIPESEND "pipes", 0, 0, #else #ifdef NETCMD "pipes", 0, 0, #endif /* NETCMD */ #endif /* PIPESEND */ #ifndef PIPESEND #ifndef NETCMD "pipes", 1, 0, #endif /* PIPESEND */ #endif /* NETCMD */ #ifdef NETPTY "pty", 0, 0, #else "pty", 1, 0, #endif /* NETPTY */ #ifndef NOPUSH "push", 0, 0, #else "push", 1, 0, #endif /* PUSH */ #ifdef CK_REDIR "redirect", 0, 0, #else "redirect", 1, 0, #endif /* CK_REDIR */ #ifdef CK_RTSCTS "rts/cts", 0, 0, #else "rts/cts", 1, 0, #endif /* RTS/CTS */ #ifndef NOSCRIPT "script-command", 0, 0, #else "script-command", 1, 0, #endif /* NOSCRIPT */ #ifndef NOSERVER "server-mode", 0, 0, #else "server-mode", 1, 0, #endif /* NOSERVER */ #ifndef NOSEXP "sexpression", 0, 0, #else "sexpression", 1, 0, #endif /* NOSEXP */ #ifdef SFTP_BUILTIN "sftp", 1, 0, #else "sftp", 0, 0, #endif /* SFTP_BUILTIN */ #ifndef NOSHOW "show-command", 0, 0, #else "show-command", 1, 0, #endif /* NOSHOW */ #ifdef CK_SRP "srp", 0, 0, #else "srp", 1, 0, #endif /* CK_SRP */ #ifdef SSHBUILTIN "ssh", 0, 0, #else /* SSHBUILTIN */ "ssh", 1, 0, #endif /* SSHBUILTIN */ #ifdef CK_SSL "ssl/tls", 0, 0, #else "ssl/tls", 1, 0, #endif /* CK_SSL */ #ifndef NOXMIT "transmit", 0, 0, #else "transmit", 1, 0, #endif /* NOXMIT */ #ifdef UNICODE "unicode", 0, 0, #else "unicode", 1, 0, #endif /* UNICODE */ #ifdef CK_XYZ "xyzmodem", 0, 0, #else "xyzmodem", 1, 0, #endif /* CK_XYZ */ "", 0, 0 }; int nftr = (sizeof(ftrtab) / sizeof(struct keytab)) - 1; struct keytab desttab[] = { /* SET DESTINATION */ #ifdef CALIBRATE "calibrate", DEST_N, CM_INV, #endif /* CALIBRATE */ "disk", DEST_D, 0, #ifdef CALIBRATE "nowhere", DEST_N, 0, #endif /* CALIBRATE */ "printer", DEST_P, 0, "screen", DEST_S, 0 }; int ndests = (sizeof(desttab) / sizeof(struct keytab)); #ifndef NOSPL /* Used only with script programming items... */ #ifndef NOSERVER /* This is just to avoid some */ #define CK_PARSDIR /* "statement not reached" */ #else /* complaints... */ #ifndef NODIAL #define CK_PARSDIR #endif /* NODIAL */ #endif /* NOSERVER */ /* cx == 0 means dial directory cx == 1 means network directory cx == 2 means a directory path list */ static int #ifdef CK_ANSIC parsdir( int cx ) #else parsdir(cx) int cx; #endif /* CK_ANSIC */ { int i, x, y, dd; /* Workers */ int nxdir; char *s; char ** xdir; char *pp[MAXGETPATH]; /* Temporary name pointers */ #ifdef ZFNQFP struct zfnfp * fnp; #ifdef OS2 char * env; char dirpath[4096]; #else /* OS2 */ char dirpath[1024]; /* For fully qualified filenames */ #endif /* OS2 */ #endif /* ZFNQFP */ int max = 0; /* Maximum number of things to parse */ char c; #ifndef NODIAL if (cx == 0) { /* Dialing */ nxdir = ndialdir; xdir = dialdir; max = MAXDDIR; } else #ifdef NETCONN if (cx == 1) { /* Network */ nxdir = nnetdir; xdir = netdir; max = MAXDDIR; } else #endif /* NETCONN */ #endif /* NODIAL */ #ifndef NOSERVER if (cx == 2) { /* GET path */ nxdir = ngetpath; xdir = getpath; max = MAXGETPATH; } else /* Called with invalid function code */ #endif /* NOSERVER */ return(-2); for (i = 0; i < MAXGETPATH; i++) /* Init these. */ pp[i] = NULL; #ifdef CK_PARSDIR dd = 0; /* Temporary name counter */ while (1) { if (cx != 2) { /* Dialing or Network Directory */ #ifdef OS2 int len; char * appdata0 = NULL, * appdata1 = NULL; #ifdef NT env = getenv("K95PHONES"); makestr(&appdata0,GetAppData(0)); makestr(&appdata1,GetAppData(1)); #else /* NT */ env = getenv("K2PHONES"); #endif /* NT */ if (!env) env = getenv("K95PHONES"); if (!env) env = ""; dirpath[0] = '\0'; len = strlen(env) + 2*strlen(startupdir) + 2*strlen(inidir) + (appdata0?2*strlen(appdata0):0) + (appdata1?2*strlen(appdata1):0) + 2*strlen(zhome()) + 2*strlen(exedir) + 8*strlen("PHONES/") + 12; if (len < 4096) /* SAFE */ sprintf(dirpath, "%s%s%s;%s%s;%s%s%s%s%s%s%s%s%s;%s%s;%s;%s%s", /* Semicolon-separated path list */ env, (env[0] && env[strlen(env)-1] == ';') ? "" : ";", startupdir, startupdir, "PHONES/", appdata1 ? appdata1 : "", appdata1 ? "Kermit 95;" : "", appdata1 ? appdata1 : "", appdata1 ? "Kermit 95/PHONES/;" : "", appdata0 ? appdata0 : "", appdata0 ? "Kermit 95;" : "", appdata0 ? appdata0 : "", appdata0 ? "Kermit 95/PHONES/;" : "", inidir, inidir, "PHONES/", zhome(), zhome(), "PHONES/", exedir, exedir, "PHONES/" ); #ifdef NT makestr(&appdata0,NULL); makestr(&appdata1,NULL); #endif /* NT */ #else #ifdef UNIX y = 1024; s = dirpath; zzstring("\\v(home)",&s,&y); #endif /* UNIX */ #endif /* OS2 */ y = cmifip( "Names of one or more directory files, separated by spaces", "",&s,&x,0, #ifdef OS2ORUNIX dirpath, #else NULL, #endif /* OS2ORUNIX */ xxstring ); } else { /* List of directory names */ x = 0; y = cmdir("Directory name","",&s,xxstring); } if (y < 0) { if (y == -3) { /* EOL or user typed */ if ((y = cmcfm()) < 0) return(y); for (i = 0; i < max; i++) { /* Clear these */ if (i < nxdir && xdir[i]) { free(xdir[i]); } xdir[i] = (i < dd) ? pp[i] : NULL; } #ifndef NODIAL if (cx == 0) ndialdir = dd; #ifdef NETCONN if (cx == 1) nnetdir = dd; #endif /* NETCONN */ #endif /* NODIAL */ #ifndef NOSERVER if (cx == 2) ngetpath = dd; #endif /* NOSERVER */ return(success = 1); } else { /* Parse error */ for (i = 0; i < dd; i++) { /* Free temp storage */ if (pp[i]) free(pp[i]); /* but don't change */ pp[i] = NULL; /* anything else */ } return(y); } } if (x) { printf("?Wildcards not allowed\n"); return(-9); } #ifdef CK_TMPDIR if (cx == 2 && !isdir(s)) { printf("?Not a directory - %s\n", s); return(-9); } #endif /* CK_TMPDIR */ #ifdef ZFNQFP if (cx < 2) { if (!isabsolute(s)) { /* If not relative get full path */ if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) { if (fnp->fpath) if ((int) strlen(fnp->fpath) > 0) s = fnp->fpath; } } } #endif /* ZFNQFP */ c = NUL; x = strlen(s); if (x > 0) /* Get last char */ c = s[x-1]; debug(F000,"parsdir s",s,c); if ((pp[dd] = malloc(strlen(s)+2)) == NULL) { printf("?Internal error - malloc\n"); for (i = 0; i < dd; i++) { /* Free temp storage */ if (pp[i]) free(pp[i]); pp[i] = NULL; } return(-9); } else { /* Have storage for name */ strcpy(pp[dd],s); /* Copy string into new storage */ debug(F111,"parsdir pp[dd] 1",pp[dd],dd); #ifndef NOXFER if (cx == 2) { /* If we are parsing directories */ char dirsep[2]; extern int myindex; /* Append directory separator if */ extern struct sysdata sysidlist[]; /* it is missing... */ debug(F101,"parsdir myindex","",myindex); if (myindex > -1) if (sysidlist[myindex].sid_unixlike) if (c != sysidlist[myindex].sid_dirsep) { dirsep[0] = sysidlist[myindex].sid_dirsep; dirsep[1] = NUL; strcat(pp[dd], (char *) dirsep); /* safe */ } } #endif /* NOXFER */ debug(F111,"parsdir pp[dd] 2",pp[dd],dd); if (++dd > max) { printf("?Too many directories - %d max\n", max); for (i = 0; i < dd; i++) { /* Free temp storage */ if (pp[i]) free(pp[i]); pp[i] = NULL; } } } } #endif /* CK_PARSDIR */ } #endif /* NOSPL */ #ifndef NOSERVER static int cklogin() { int x; char * s; char username[LOGINLEN+1]; char password[LOGINLEN+1]; char account[LOGINLEN+1]; extern char * x_user, * x_passwd, * x_acct; extern int x_login, x_logged; username[0] = NUL; password[0] = NUL; account[0] = NUL; x = cmfld("username", "", &s, xxstring); if (x != -3) { if (x < 0) return(x); if ((int)strlen(s) > LOGINLEN) { printf("\"%s\" - too long, %d max\n", s, LOGINLEN); return(-9); } ckstrncpy(username,s,LOGINLEN+1); x = cmfld("password", "", &s, xxstring); if (x != -3) { if (x < 0) return(x); if ((int)strlen(s) > LOGINLEN) { printf("\"%s\" - too long, %d max\n", s, LOGINLEN); return(-9); } ckstrncpy(password,s,LOGINLEN+1); x = cmfld("account", "", &s, xxstring); if (x != -3) { if (x < 0) return(x); if ((int)strlen(s) > LOGINLEN) { printf("\"%s\" - too long, %d max\n", s, LOGINLEN); return(-9); } ckstrncpy(account,s,LOGINLEN+1); if ((x = cmcfm()) < 0) return(x); } } } makestr(&x_user,username); makestr(&x_passwd,password); makestr(&x_acct,account); x_login = (x_user) ? 1 : 0; x_logged = 0; return(1); } #endif /* NOSERVER */ #ifndef NOLOCAL static int setdcd() { int x, y, z = 0; if ((y = cmkey(crrtab,ncrr,"","automatic",xxstring)) < 0) return(y); if (y == CAR_ON) { x = cmnum("Carrier wait timeout, seconds","0",10,&z,xxstring); if (x < 0) return(x); } if ((x = cmcfm()) < 0) return(x); carrier = ttscarr(y); cdtimo = z; return(1); } #endif /* NOLOCAL */ extern struct keytab yesno[]; extern int nyesno; /* g e t y e s n o */ static struct keytab q0yesno[] = { /* Yes/No/Quit keyword table */ "no", 0, 0, "ok", 1, 0, "yes", 1, 0 }; static int nq0yesno = (sizeof(q0yesno) / sizeof(struct keytab)); static struct keytab q1yesno[] = { /* Yes/No/Quit keyword table */ "no", 0, 0, "ok", 1, 0, "quit", 2, 0, "yes", 1, 0 }; static int nq1yesno = (sizeof(q1yesno) / sizeof(struct keytab)); static struct keytab q2yesno[] = { /* Yes/No/Quit keyword table */ "go", 3, 0, "no", 0, 0, "ok", 1, 0, "yes", 1, 0 }; static int nq2yesno = (sizeof(q2yesno) / sizeof(struct keytab)); static struct keytab q3yesno[] = { /* Yes/No/Quit keyword table */ "go", 3, 0, "no", 0, 0, "ok", 1, 0, "quit", 2, 0, "yes", 1, 0 }; static int nq3yesno = (sizeof(q3yesno) / sizeof(struct keytab)); /* Ask question, get yes/no answer */ int #ifdef CK_ANSIC getyesno( char * msg, int flags ) #else getyesno(msg, flags) char * msg; int flags; #endif /* CK_ANSIC */ { #ifdef CK_RECALL extern int on_recall; /* around Password prompting */ #endif /* CK_RECALL */ int y, z; #ifndef NOLOCAL #ifdef OS2 extern BYTE vmode; extern int win95_popup, startflags; int vmode_sav = vmode; #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef CK_APC if ( apcactive != APC_INACTIVE && (apcstatus & APC_NOINP) ) { return(success = 0); } #endif /* CK_APC */ #ifndef NOLOCAL #ifdef OS2 #ifdef COMMENT if (win95_popup && !(startflags & 96) #ifdef IKSD && !inserver #endif /* IKSD */ ) return(popup_readyesno(vmode,NULL,msg,flags)); #endif /* COMMENT */ if (vmode == VTERM) { vmode = VCMD; VscrnIsDirty(VTERM); VscrnIsDirty(VCMD); } #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef VMS /* In VMS, whenever a TAKE file or macro is active, we restore the original console modes so Ctrl-C/Ctrl-Y can work. But here we go interactive again, so we have to temporarily put them back. */ if (!xcmdsrc) concb((char)escape); #endif /* VMS */ #ifdef CK_RECALL on_recall = 0; #endif /* CK_RECALL */ cmsavp(psave,PROMPTL); /* Save old prompt */ cmsetp(msg); /* Make new prompt */ z = 0; /* Initialize answer to No. */ cmini(ckxech); /* Initialize parser. */ do { prompt(NULL); /* Issue prompt. */ switch (flags) { case 0: y = cmkey(q0yesno,nq0yesno,"","",NULL); break; case 1: y = cmkey(q1yesno,nq1yesno,"","",NULL); break; case 2: y = cmkey(q2yesno,nq2yesno,"","",NULL); break; default: y = cmkey(q3yesno,nq3yesno,"","",NULL); } if (y < 0) { if (y == -4) { /* EOF */ z = y; break; } else if (y == -3) /* No answer? */ printf(" Please respond; type '?' to see valid answers.\n"); cmini(ckxech); } else { z = y; /* Save answer */ y = cmcfm(); /* Get confirmation */ } } while (y < 0); /* Continue till done */ cmsetp(psave); /* Restore real prompt */ #ifdef VMS if (cmdlvl > 0) /* In VMS and not at top level, */ conres(); /* restore console again. */ #endif /* VMS */ #ifndef NOLOCAL #ifdef OS2 if (vmode != vmode_sav) { vmode = VTERM; VscrnIsDirty(VCMD); VscrnIsDirty(VTERM); } #endif /* OS2 */ #endif /* NOLOCAL */ return(z); } #ifdef KUI extern HWND hwndConsole; _PROTOTYP(int gui_txt_dialog,(char *,char *,int,char *,int,char *,int)); _PROTOTYP(int gui_mtxt_dialog,(char *,int,struct txtbox [])); _PROTOTYP(int gui_position,(int, int)); _PROTOTYP(int gui_resize_mode,(int)); _PROTOTYP(int gui_win_run_mode,(int)); _PROTOTYP(int gui_file_dialog,(char *,char *, int, char *, char *, int)); extern int gui_dialog; #endif /* KUI */ /* u q _ o k -- User Query, get Yes/No or OK Cancel */ /* Call with: preface: Explanatory text to print, or NULL. prompt: Prompt. mask: Bitmask for legal responses: 1 = OK or Yes; 2 = No or Cancel. help: Help text (array of strings or NULL) [not used by parser]. dflt: Default response (1 or 2) [not used by parser]. Returns: -1: Invalid argument(s). 0: User said No or Cancel. 1 User said Yes or OK. Notes: preface and prompt should not include final line terminator but may include embedded ones. Help text is in case GUI dialog needs a Help button; final element of help-string array is "". dflt is used by GUI to highlight the default response button. */ int #ifdef CK_ANSIC uq_ok(char * preface, char * prompt, int mask,char ** help, int dflt) #else /* CK_ANSIC */ uq_ok(preface,prompt,mask,help,dflt) char * preface, * prompt, ** help; int mask, dflt; #endif /* CK_ANSIC */ /* uq_ok */ { #ifdef KUI int rc, len; char * text=NULL; #endif /* KUI */ if (!prompt) return(-1); if ((mask & 3) == 1) { /* OK (GUI only) */ #ifdef KUI if ( gui_dialog ) { /* This one is for popup help, alerts, etc */ if (preface) { len = strlen(preface) + strlen(prompt) + 4; text = (char *)malloc(len); ckmakmsg(text,len,preface,"\n",prompt,NULL); } rc = MessageBox(hwndConsole, text ? text : prompt, prompt, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL); #ifndef CKT_NT35_OR_31 ShowWindowAsync(hwndConsole,SW_SHOWNORMAL); #else ShowWindow(hwndConsole, SW_SHOWNORMAL); #endif /* CKT_NT35_OR_31 */ SetForegroundWindow(hwndConsole); if (text) free(text); if (!rc) return(-1); else return(1); } else #endif /* KUI */ { if (preface) /* Just display the text, if any */ printf("%s\n",preface); if (prompt) printf("%s\n",prompt); return(1); } } else if ((mask & 3) == 3) { /* Yes/No or OK/Cancel */ #ifdef KUI if ( gui_dialog ) { if (preface) { len = strlen(preface) + strlen(prompt) + 4; text = (char *)malloc(len); ckmakmsg(text,len,preface,"\n",prompt,NULL); } rc = MessageBox(hwndConsole, text ? text : prompt, prompt, MB_YESNO | MB_ICONINFORMATION | MB_TASKMODAL | (dflt == 2 ? MB_DEFBUTTON2 : MB_DEFBUTTON1)); #ifndef CKT_NT35_OR_31 ShowWindowAsync(hwndConsole,SW_SHOWNORMAL); #else ShowWindow(hwndConsole,SW_SHOWNORMAL); #endif /* CKT_NT35_OR_31 */ SetForegroundWindow(hwndConsole); if (text) free(text); if (!rc) return(-1); else if (rc == IDNO || rc == IDCANCEL) return(0); else return(1); } else #endif /* KUI */ { if (preface) printf("%s\n",preface); return(getyesno(prompt,0)); } } else { printf("?Internal error: uq_ok()\n"); return(-1); } } /* u q _ t x t -- User Query, get single text response */ /* Call with: preface: Explanatory text to print, or NULL. prompt: Prompt. echo: 0 = don't echo; 1 = echo; 2 = echo with asterisks. help: Help text (array of strings or NULL) [not used by parser]. buf: Pointer to result buffer. buflen: Length of result buffer. dflt: Default response text or NULL [not used by parser]. timer: Optional Timeout Returns: 0: User said No or Cancel. 1 User said Yes or OK. Notes: preface, prompt, and help as for uq_ok(). */ int #ifdef CK_ANSIC uq_txt(char * preface, char * prompt, int echo, char ** help, char * buf, int buflen, char *dflt, int timer) #else /* CK_ANSIC */ uq_txt(preface,prompt,echo,help,buf,buflen,dflt,timer) char * preface, * prompt, ** help, * buf, * dflt; int buflen, echo, timer; #endif /* CK_ANSIC */ { #ifndef NOLOCAL #ifdef OS2 extern BYTE vmode; extern int startflags; extern int win95_popup; #endif /* OS2 */ #endif /* NOLOCAL */ if (buflen < 1 || !buf) return(0); #ifdef KUI if ( gui_dialog ) { int rc = gui_txt_dialog(preface,prompt,echo,buf,buflen,dflt,timer); if ( rc > -1 ) { return(rc); } /* Otherwise, the dialog could not be created. Fallback to text mode */ } #endif /* KUI */ #ifndef NOLOCAL #ifdef OS2 if (win95_popup && !(startflags & 96) #ifdef IKSD && !inserver #endif /* IKSD */ ) { debok = 0; /* Don't log */ if (echo == 1) popup_readtext(vmode,preface,prompt,buf,buflen,0); else popup_readpass(vmode,preface,prompt,buf,buflen,0); debok = 1; return(1); } #endif /* OS2 */ #endif /* NOLOCAL */ if (preface) printf("%s\n",preface); if (echo == 1) readtext(prompt,buf,buflen); else readpass(prompt,buf,buflen); return(1); /* (no buttons in parser) */ } /* u q _ m t x t -- User Query, get multiple text responses */ /* Call with: preface: Explanatory text to print, or NULL. help: Help text (array of strings or NULL) [not used by parser]. n: Number of responses wanted. field: Array of struct txtbox, one element per field, see ckuusr.h. Returns: 0: User said No or Cancel. 1 User said Yes or OK. Notes: preface and help as for uq_ok(). */ int #ifdef CK_ANSIC uq_mtxt(char * preface,char **help, int n, struct txtbox field[]) #else /* CK_ANSIC */ uq_mtxt(preface,help,n,field) char * preface; char ** help; int n; struct txtbox field[]; #endif /* CK_ANSIC */ { #ifndef NOLOCAL #ifdef OS2 extern BYTE vmode; extern int startflags; extern int win95_popup; #endif /* OS2 */ #endif /* NOLOCAL */ int i; if (n < 1 || !field) return(0); #ifdef KUI if ( gui_dialog ) { int rc = gui_mtxt_dialog(preface, n, field); if ( rc > -1 ) { return(rc); } /* Otherwise, the dialog could not be created. Fallback to text mode */ } #endif /* KUI */ #ifndef NOLOCAL #ifdef OS2 if (win95_popup && !(startflags & 96) #ifdef IKSD && !inserver #endif /* IKSD */ ) { debok = 0; /* Don't log */ for (i = 0; i < n; i++) { if (field[i].t_echo == 1) popup_readtext(vmode,preface,field[i].t_lbl,field[i].t_buf,field[i].t_len,0); else popup_readpass(vmode,preface,field[i].t_lbl,field[i].t_buf,field[i].t_len,0); } debok = 1; return(1); } #endif /* OS2 */ #endif /* NOLOCAL */ if (preface) printf("%s\n",preface); for (i = 0; i < n; i++) { if (field[i].t_echo == 1) readtext(field[i].t_lbl,field[i].t_buf,field[i].t_len); else readpass(field[i].t_lbl,field[i].t_buf,field[i].t_len); } return(1); } /* u q _ f i l e -- User Query, get file or directory name */ /* Call with: preface: Explanatory text to print, or NULL. prompt: Prompt string. fc: Function code: 1 = input (existing) file 2 = existing directory 3 = create new output file 4 = output file allowing append access 5 = same as 3, but don't label the GUI save button "Download" help: Help text (array of strings or NULL) [not used by parser]. dflt: Default response. result: Pointer to result buffer. rlength: Length of result buffer. Returns: -1: Invalid argument, result too long, or other error. 0: User Canceled. 1: OK, with file/pathname copied to result buffer. 2: Like 1, but for output file that is to be appended to. Notes: 1. preface and prompt should not include final line terminator but may include embedded ones. Help text is in case GUI dialog needs a Help button; final element of help-string array is "". 2. The default might be a filename, a directory name, a relative pathname, or an absolute pathname. This routine must convert it into into a fully qualified (absolute) pathname so the user knows exactly where the file is to be found or stored. In addition, the Windows version of this routine must separate the directory part from the name part, so it can display the given directory in the file dialog, and put name in the filename box to be edited, replaced, or accepted. 3. When called with FC 4, the Windows version should include "New" and "Append" buttons in the dialog. so the user can say whether the file should overwrite any file of the same name, or be appended to it. */ int #ifdef CK_ANSIC uq_file(char * preface, char * fprompt, int fc, char ** help, char * dflt, char * result, int rlength) #else /* CK_ANSIC */ uq_file(preface,fprompt,fc,help,dflt,result,rlength) char * preface, * fprompt, ** help, * dflt, * result; int fc, rlength; #endif /* CK_ANSIC */ /* uq_file */ { int rc = -1, x, y, z; char * s, * p, * fullpath; char filebuf[CKMAXPATH+1]; #ifdef CK_RECALL extern int on_recall; #endif /* CK_RECALL */ #ifdef KUI if ( gui_dialog ) { rc = gui_file_dialog(preface,fprompt,fc,dflt,result,rlength); return rc; } #endif /* KUI */ if (fc == 5) fc = 3; #ifdef CK_RECALL on_recall = 0; #endif /* CK_RECALL */ if (preface) /* If prefatory text given... */ printf("%s\n",preface); /* display it. */ cmsavp(psave,PROMPTL); /* Save old prompt */ /* We get the full pathname of the proposed output file just so */ /* we can show it to the user but we don't use it ourselves. */ p = NULL; /* Build new prompt */ if (!dflt) dflt = ""; if (*dflt) /* Have default filename */ zfnqfp(dflt,CKMAXPATH+1,filebuf); /* Get full path */ else ckmakmsg(filebuf,CKMAXPATH+1,zgtdir(),"newfile",NULL,NULL); fullpath = filebuf; x = strlen(fullpath); /* If no prompt given, build one that shows the proposed full pathname. */ if (!fprompt) fprompt = ""; if (!*fprompt) fprompt = x ? " Filename" : " Filename: "; y = strlen(fprompt); if (x > 0) { /* Have default pathname? */ p = (char *)malloc(x + y + 7); /* Get temp storage */ if (p) { /* Build prompt */ ckmakmsg(p,x+y+7,fprompt," [",fullpath,"]: "); fprompt = p; } } cmsetp(fprompt); /* Make new prompt */ if (p) free(p); /* Free temp storage */ cmini(ckxech); /* Initialize parser. */ x = -1; do { prompt(NULL); /* Issue prompt. */ switch (fc) { /* Parse depends on function code */ case 1: /* Input file */ x = cmifi("Name of existing file",dflt,&s,&y,xxstring); rc = 1; break; case 2: /* Directory */ x = cmdir("Directory name",dflt,&s,xxstring); rc = 1; break; case 3: /* New output file */ /* Fall thru... */ case 4: /* Output file - Append allowed */ x = cmofi("Output file specification",dflt,&s,xxstring); rc = (fc == 4) ? 1 : 2; break; default: /* Bad function code */ goto x_uq_file; } if (x < 0) { /* Parse error */ filebuf[0] = NUL; if (x == -4) { /* EOF */ break; } else if (x == -3) /* No answer? */ printf(fc == 2 ? " Please enter a directory name.\n" : " Please enter a filename.\n" ); cmini(ckxech); } else { z = strlen(s); if (z > rlength || ckstrncpy(filebuf,brstrip(s),CKMAXPATH+1) < z) { printf("?Name too long\n"); x = -9; } else x = cmcfm(); /* Get confirmation */ } if (fc == 1 && x > -1 && y > 0) { printf("?Wildcards not allowed\n"); x = -9; } } while (x < 0); /* Continue till done */ x_uq_file: if (x < 0) rc = -1; cmsetp(psave); /* Restore real prompt */ if (rc > 0) ckstrncpy(result,filebuf,rlength); return(rc); } #ifdef CK_PERMS #ifdef UNIX _PROTOTYP( int zsetperm, (char *, int)); /* CHMOD command for UNIX only */ #define CHM_DIR 0 #define CHM_DOT 1 #define CHM_FIL 2 #define CHM_LIS 3 #define CHM_NOL 4 #define CHM_QUI 5 #define CHM_REC 6 #define CHM_VRB 7 #define CHM_PAG 8 #define CHM_NOP 9 #define CHM_TYP 10 #define CHM_SIM 11 static struct keytab uchmodsw[] = { "/directories", CHM_DIR, 0, "/dotfiles", CHM_DOT, 0, "/files", CHM_FIL, 0, "/list", CHM_LIS, 0, "/nolist", CHM_NOL, 0, "/nopage", CHM_NOP, 0, "/page", CHM_PAG, 0, "/quiet", CHM_QUI, CM_INV, "/recursive", CHM_REC, 0, "/simulate", CHM_SIM, 0, "/type", CHM_TYP, CM_ARG, "/verbose", CHM_VRB, CM_INV, }; static int nchmodsw = (sizeof(uchmodsw) / sizeof(struct keytab)); int douchmod() { extern int recursive, nscanfile, diractive; #ifdef CK_TTGWSIZ extern int tt_rows, tt_cols; int n = 0; #endif /* CK_TTGWSIZ */ int i, files = 1, t1 = 1, t2 = 0, x, y, z, verbose = 0, rc = 1, paging; int xmode = -1, fs = 0, getval = 0, simulate = 0, wild = 0; char c, * s; struct FDB sw, nu; if (xaskmore < 0) { #ifdef CK_TTGWSIZ xaskmore = 1; #else xaskmore = 0; #endif /* CK_TTGWSIZ */ } paging = xaskmore; cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Octal file permission code, or switch", "", /* default */ "", /* addtl string data */ nchmodsw, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ uchmodsw, /* Keyword table */ &nu /* Pointer to next FDB */ ); cmfdbi(&nu, _CMNUM, /* Number */ "", /* Help message */ "", /* Default */ "", /* N/A */ 8, /* Radix = 8 */ 0, /* N/A */ xxstring, /* Processing function */ NULL, /* N/A */ NULL /* Next */ ); while (1) { if ((x = cmfdb(&sw)) < 0) { if (x == -3) { x = -9; printf("?Filename required\n"); } return(x); } if (cmresult.fcode != _CMKEY) break; c = cmgbrk(); getval = (c == ':' || c == '='); if (getval && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } switch (cmresult.nresult) { case CHM_DIR: t1 = 1; t2 = 1; break; case CHM_DOT: matchdot = 1; break; case CHM_FIL: t1 = 0; t2 = 0; break; case CHM_LIS: case CHM_VRB: verbose = 1; break; case CHM_NOL: case CHM_QUI: verbose = 0; break; case CHM_REC: recursive = 1; break; case CHM_PAG: verbose = 1; paging = 1; break; case CHM_NOP: paging = 0; break; case CHM_SIM: simulate = 1; break; case CHM_TYP: { extern struct keytab txtbin[]; if ((x = cmkey(txtbin,3,"","",xxstring)) < 0) return(x); if (x == 2) { /* ALL */ xmode = -1; } else { /* TEXT or BINARY only */ xmode = x; fs = 1; } break; } } } z = cmresult.nresult; x = cmifi2("File specification","",&s,&wild,t1,NULL,xxstring,t2); if (x < 0) { if (x == -3) { printf("?A file specification is required\n"); return(-9); } else return(x); } ckstrncpy(tmpbuf,s,TMPBUFSIZ); s = tmpbuf; if ((x = cmcfm()) < 0) return(x); #ifdef ZXREWIND if (wild) files = zxrewind(); #else if (wild) files = nzxpand(s,0); #endif /* ZXREWIND */ if (paging > -1) xaskmore = paging; #ifdef CK_TTGWSIZ if (verbose && paging) { #ifdef OS2 ttgcwsz(); #else /* OS2 */ if (ttgwsiz() > 0) { if (tt_rows > 0 && tt_cols > 0) { cmd_rows = tt_rows; cmd_cols = tt_cols; } } #endif /* OS2 */ } #endif /* CK_TTGWSIZ */ for (i = 0; i < files; i++) { if (files == 1 && wild == 0) { /* For "chmod 777 ." */ ckstrncpy(line,s,LINBUFSIZ); } else { x = znext(line); if (x < 1) { if (i == 0) { printf("?No files match - \"%s\"\n",line); return(-9); } return(1); } } if (fs) { #ifdef VMSORUNIX /* If /TYPE:TEXT or BINARY given, skip directories and links */ /* since they are neither text nor binary. */ extern int zgfs_dir, zgfs_link; zgetfs(line); if (zgfs_dir || zgfs_link) continue; #else if (zchki(line) < 0) continue; #endif /* VMSORUNIX */ /* Regular file, scan it */ switch (scanfile(line,&y,nscanfile)) { case FT_BIN: if (xmode != 1) continue; break; case FT_TEXT: case FT_7BIT: case FT_8BIT: #ifdef UNICODE case FT_UTF8: case FT_UCS2: #endif /* UNICODE */ if (xmode != 0) continue; } } if (simulate) { #ifdef UNIX extern int zchkod; /* Unidentified Flying */ int xx = zchkod; /* API Extension... */ zchkod = 1; #endif /* UNIX */ if (zchko(line) < 0) printf("%s - Access denied\n",line); else printf("%s - OK\n",line); #ifdef UNIX zchkod = xx; #endif /* UNIX */ } else { if (zsetperm(line,z) < 1) { if (verbose || files < 2) { printf("%s: %s\n",line,ck_errstr()); } rc = 0; } else if (verbose) { printf("%s %s\n",ziperm(line),line); } } #ifdef CK_TTGWSIZ if (verbose && paging) { /* Pause at end of screen */ if (cmd_rows > 0 && cmd_cols > 0) { if (++n > cmd_rows - 3) { if (!askmore()) break; else n = 0; } } } #endif /* CK_TTGWSIZ */ } return(success = rc); } #endif /* UNIX */ #endif /* CK_PERMS */ #ifndef NOSPL /* S-Expressions */ #ifndef NOSEXP struct keytab sexptab[] = { "depth-limit", 1, 0, "echo-result", 0, 0, "truncate-all-results", 2 }; static int sexpmaxdep = 1000; /* Maximum depth */ #define xxfloat(s,x) \ ((isdigit(*s)||(*s=='-')||(*s=='+')||(*s=='.')||(*s=='\040'))?isfloat(s,x):0) #define SX_ADD 1 /* Symbols for built-in operators */ #define SX_SUB 2 #define SX_MUL 3 #define SX_DIV 4 #define SX_POW 5 #define SX_SET 6 #define SX_MOD 7 #define SX_EVA 8 #define SX_EXP 9 #define SX_AEQ 10 #define SX_ALT 11 #define SX_AGT 12 #define SX_ALE 13 #define SX_AGE 14 #define SX_MIN 15 #define SX_MAX 16 #define SX_SQR 17 #define SX_FLR 18 #define SX_CEI 19 #define SX_TRU 20 #define SX_ABS 21 #define SX_ROU 22 #define SX_LET 23 #define SX_LGN 24 #define SX_LGX 25 #define SX_FLO 26 #define SX_IFC 27 #define SX_NOT 28 #define SX_NEQ 29 #define SX_AND 30 #define SX_LOR 31 #define SX_SIN 32 #define SX_COS 33 #define SX_TAN 34 #define SX_BWA 35 #define SX_BWO 36 #define SX_BWX 37 #define SX_BWN 38 #define SX_XOR 39 #define SX_INC 40 #define SX_DEC 41 #define SX_QUO 42 #define SX_STR 43 #define SX_ECH 44 #define SX_UNQ 45 /* Operator flags */ #define SXF_PRE 256 /* Predicate */ #define SXF_ONE 512 /* Requires one arg */ #define SXF_TWO 1024 /* Requires two args or more */ #define SXF_FLO 2048 /* Coerce to floating-point */ /* Built-in constants */ #define SXC_NIL 1 /* NIL */ #define SXC_PI 2 /* PI */ #define SXC_T 3 /* T */ /* This is an xlookup() table and so need not be in "alhabetical" order. Therefore entries are arranged to minimize search for most common operators. */ static struct keytab sexpops[] = { /* Built-in operators */ "setq", SX_SET, 0, /* Global assignment */ "+", SX_ADD, 0, /* Simple arithmetic */ "-", SX_SUB, 0, "*", SX_MUL, 0, "/", SX_DIV, SXF_TWO, "^", SX_POW, SXF_TWO, "if", SX_IFC, SXF_TWO, /* IF */ "let", SX_LET, 0, /* Local assignment */ "not", SX_NOT, SXF_ONE, /* NOT */ "mod", SX_MOD, SXF_TWO, /* Modulus */ "<", SX_ALT, SXF_PRE, /* Comparisons */ ">", SX_AGT, SXF_PRE, "<=", SX_ALE, SXF_PRE, "=", SX_AEQ, SXF_PRE, ">=", SX_AGE, SXF_PRE, "!=", SX_NEQ, SXF_PRE, "++", SX_INC, SXF_ONE|SXF_TWO, /* Increment */ "--", SX_DEC, SXF_ONE|SXF_TWO, /* Decrement */ "**", SX_POW, SXF_TWO, /* Common synonyms */ "==", SX_AEQ, SXF_PRE, "!", SX_NOT, SXF_ONE, ".", SX_EVA, 0, "and", SX_AND, 0, /* Logical operators */ "or", SX_LOR, 0, "xor", SX_XOR, SXF_TWO, "max", SX_MAX, SXF_ONE|SXF_TWO, /* Max and min */ "min", SX_MIN, SXF_ONE|SXF_TWO, "%", SX_MOD, SXF_TWO, /* More synonyms */ "||", SX_LOR, 0, "&&", SX_AND, 0, "quote", SX_QUO, SXF_ONE, /* String operators */ "string", SX_STR, SXF_ONE, "unquote", SX_UNQ, SXF_ONE, "eval", SX_EVA, 0, /* Assorted commands */ "abs", SX_ABS, SXF_ONE, "truncate",SX_TRU, SXF_ONE|SXF_FLO, "round", SX_ROU, SXF_ONE|SXF_TWO|SXF_FLO, "ceiling", SX_CEI, SXF_ONE|SXF_FLO, "floor", SX_FLR, SXF_ONE|SXF_FLO, "float", SX_FLO, SXF_ONE|SXF_FLO, "echo", SX_ECH, 0, #ifdef FNFLOAT "sqrt", SX_SQR, SXF_ONE|SXF_FLO, /* Floating point functions */ "exp", SX_EXP, SXF_ONE|SXF_FLO, "sin", SX_SIN, SXF_ONE|SXF_FLO, "cos", SX_COS, SXF_ONE|SXF_FLO, "tan", SX_TAN, SXF_ONE|SXF_FLO, "log", SX_LGN, SXF_ONE|SXF_FLO, "log10", SX_LGX, SXF_ONE|SXF_FLO, #endif /* FNFLOAT */ "#", SX_BWX, SXF_TWO, /* Bitwise operators */ "&", SX_BWA, 0, "|", SX_BWO, 0, "~", SX_BWN, SXF_ONE, "", 0, 0 /* (end) */ }; static int nsexpops = (sizeof(sexpops) / sizeof(struct keytab)) - 1; static struct keytab sexpconsts[] = { /* Built-in constants */ "nil", SXC_NIL, 0, /* NIL (false) */ "pi", SXC_PI, 0, /* Pi (3.1415926...) */ "t", SXC_T, 0, /* T (true) */ "", 0, 0 }; static int nsexpconsts = (sizeof(sexpconsts) / sizeof(struct keytab)) - 1; int sexprc = 0; /* S-Expression error flag */ int sexppv = -1; /* Predicate value */ static int sexptrunc = 0; /* Flag to force all results to int */ #define SXMLEN 64 /* Macro arg list initial length */ #include /* Floating-point functions */ #include "ckcfnp.h" /* Prototypes (must be last) */ #ifndef CK_ANSIC #ifdef HPUX /* HP C 76.3 on HP-UX 10 is a curious mixture of K&R (pre-ANSI) and ANSI C. Even though pre-ANSI C doesn't have prototypes, if this prototype is not present a warning is issued in dosexp() below. */ _PROTOTYP( char * fpformat, (CKFLOAT, int, int) ); #endif /* HPUX */ #endif /* CK_ANSIC */ extern char math_pi[]; /* Value of Pi */ extern int sexpecho; /* SET SEXPRESSION ECHO value */ extern char * sexpval; /* Last top-level S-Expression value */ extern char * lastsexp; /* Last S-Expression */ int sexprmax = 0; /* Longest result (for stats) */ int sexpdmax = 0; /* Max depth reached (for stats) */ int sexpdep = 0; /* dosexp() recursion depth */ static int * sxrlen = NULL; /* Result stack string sizes */ static char ** sxresult = NULL; /* Result stack */ /* s h o s e x p -- Show S-Expression info */ VOID shosexp() { printf("\n"); printf(" sexpression echo-result: %s\n",showooa(sexpecho)); printf(" sexpression depth-limit: %d\n",sexpmaxdep); printf("\n"); printf(" maximum depth reached: %d\n",sexpdmax); printf(" longest result returned: %d\n",sexprmax); printf("\n"); printf(" truncate all results: %s\n",showoff(sexptrunc)); printf("\n"); printf(" last sexpression: %s\n",lastsexp ? lastsexp : "(none)"); printf(" last value: %s\n",sexpval ? sexpval : "(none)"); printf("\n"); } static char * #ifdef CK_ANSIC sexpdebug( char * s ) #else sexpdebug(s) char * s; #endif /* CK_ANSIC */ { /* For debugging -- includes recursion depth in each debug entry */ static char buf[64]; ckmakmsg(buf,64,"dosexp[",ckitoa(sexpdep),"] ",s); return((char *)buf); } /* d o s e x p -- S-Expression Reader */ /* Returns value as string (empty, numeric, or non-numeric) */ static char sxroundbuf[32]; /* For ROUND result */ char * #ifdef CK_ANSIC dosexp( char *s ) /* s = S-Expression */ #else dosexp(s) char *s; #endif /* CK_ANSIC */ { extern struct mtab *mactab; /* Macro table */ extern int maclvl, nmac; extern char *mrval[]; extern int makestrlen; /* (see makestr()) */ struct stringarray * q = NULL; /* cksplit() return type */ char * p[SEXPMAX+1], ** p2; /* List items (must be on stack) */ char * line = NULL; /* For building macro argument list */ int nosplit = 0; int linelen = 0; int linepos = 0; int quote = 0; /* LISP quote flag */ char * s2; /* Workers */ int kw, kwflags, mx = 0, x = 0; int not = 0, truncate = 0, builtin = 0; int fpflag = 0, quit = 0, macro = 0; CK_OFF_T result = 0, i, j, k, n = 0; CKFLOAT fpj, fpresult = 0.0; /* Floating-point results */ int pflag = 0; /* Have predicate */ int presult = 0; /* Predicate result */ int mustfree = 0; /* If we malloc'd we must free */ sexppv = -1; /* Predicate value */ s2 = ""; /* Default return value */ debug(F111,sexpdebug("entry 1"),s,sexprc); if (++sexpdep > sexpmaxdep) { /* Keep track of depth */ printf("?S-Expression depth limit exceeded: %d\n",sexpmaxdep); sexprc++; debug(F111,sexpdebug("max depth exceeded"),s,sexprc); } if (sexpdep > sexpdmax) /* For stats */ sexpdmax = sexpdep; if (sexprc) /* Error, quit all levels */ goto xdosexp; /* Always goto common exit point */ debug(F111,sexpdebug("entry 2"),s,sexprc); if (!s) s = ""; /* Null or empty arg */ while (*s == SP) s++; /* Strip leading spaces */ if (!*s) /* so empty result */ goto xdosexp; /* Allocate result stack upon first use, or after it has been resized with SET SEXP DEPTH-LIMIT. */ if (!sxresult) { sxresult = (char **)malloc(sexpmaxdep * sizeof(char *)); if (!sxresult) { printf("?Memory allocation failure - \"%s\"\n", s); sexprc++; goto xdosexp; } sxrlen = (int *)malloc(sexpmaxdep * sizeof(int)); if (!sxrlen) { printf("?Memory allocation failure - \"%s\"\n", s); sexprc++; goto xdosexp; } for (i = 0; i < sexpmaxdep; i++) { sxresult[i] = NULL; /* Result pointers */ sxrlen[i] = 0; /* Buffer sizes */ } } s2 = s; /* s2 is the result pointer */ k = 0; /* Length accumulator */ if (s[0] == '(') { /* Starts with open paren? */ while (*s2++) k++; /* Get length */ if (s[k-1] == ')') { /* Strip outer parens if any */ s[k-1] = NUL; s++; k -= 2; while (*s == SP) { /* Strip leading spaces from result */ s++; k--; } while (k > 0 && s[k-1] == SP) { /* And trailing spaces. */ s[k-1] = NUL; k--; } } if (!*s) { /* If nothing remains */ s2 = ""; /* return empty result. */ goto xdosexp; } } /* Break result up into "words" (an SEXP counts as a word) */ for (i = 0; i < SEXPMAX+1; i++ ) { /* Clear the operands */ p[i] = NULL; } if (!*(s+1) || !*(s+2)) { /* No need to call cksplit() */ n = 1; /* if it's one or two chars. */ p[1] = s; /* No need to malloc this either. */ nosplit = 1; debug(F101,sexpdebug("nosplit"),"",n); if (s[0] == '(') { /* () empty */ s2 = ""; goto xdosexp; } } else { nosplit = 0; q = cksplit(1,SEXPMAX,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",8,39,0,0); if (!q) goto xdosexp; n = q->a_size; /* Number of items */ debug(F101,sexpdebug("split"),"",n); if (n < 0 || n > SEXPMAX) { /* Check for too many */ printf("?Too many operands: max = %d\n",SEXPMAX); sexprc++; goto xdosexp; } if (n == 0) /* None, result is NULL, done. */ goto xdosexp; if (n == 1 && s[0] == '(') { /* One but it's another SEXP */ s2 = dosexp(s); goto xdosexp; } if (n == 1 && s[0] == '\047') { /* One but it's a string constant */ int x = (int) strlen(s); s2 = s; if (s2[1] == '(' && s2[x-1] == ')') { /* '(string) */ s2[x-1] = NUL; s2 += 2; } goto xdosexp; } /* More than one */ p2 = q->a_head; /* Point to result array. */ for (i = 1; i <= n; i++) { /* We must copy it because */ p[i] = NULL; /* recursive calls to dosexp() */ if (p2[i]) /* write over the same array */ makestr(&(p[i]),p2[i]); } if (s[0] == '(') { /* Operator is an S-Expression */ s2 = dosexp(p[1]); /* Replace it by its value */ if (s2[0] == '\047') { /* LISP string literal */ int x = (int) strlen(s2); if (s2[1] == '(' && s2[x-1] == ')') { /* '(string) */ s2[x-1] = NUL; s2 += 2; printf("XXX s2.2=[%s]\n",s2); } } makestr(&(p[1]),s2); } mustfree++; /* Remember to free it */ } debug(F110,sexpdebug("head"),p[1],0); if (n == 1 && p[1]) { if (*(p[1]) == '\047') { /* Apostrophe = LISP quote character */ s2 = p[1]; goto xdosexp; } } /* This section sidesteps xlookup() of the most common operators. It's not necessary but it speeds up SEXP-heavy loops by about 10%. */ kwflags = 0; if (n > 0) { /* Look up the operator */ s2 = p[1]; /* Prelookup optimization... */ if (!s2) s2 = ""; if (!*s2) goto xdosexp; kw = 0; x = 0; if (isdigit(*s2)) { /* Digit */ x = -2; } else if (isalpha(*s2) && !*(s2+1)) { /* Single letter */ x = -1; } else if (*s2 == 's' || *s2 == 'S') { /* SETQ */ s2++; if (*s2 == 'e' || *s2 == 'E') { s2++; if (*s2 == 't' || *s2 == 'T') { s2++; if (*s2 == 'q' || *s2 == 'Q') { if (!*(s2+1)) { x = SX_SET; kwflags = 0; builtin = 1; } } } } } if (!x) { if (!*(s2+1)) { /* Common single-character ops */ if (*s2 == '+') { x = SX_ADD; kwflags = 0; builtin = 1; } else if (*s2 == '-') { x = SX_SUB; kwflags = 0; builtin = 1; } else if (*s2 == '*') { x = SX_MUL; kwflags = 0; builtin = 1; } else if (*s2 == '/') { x = SX_DIV; kwflags = SXF_TWO; builtin = 1; } } if (!x) { /* None of the above, look it up */ x = xlookup(sexpops,p[1],nsexpops,&kw); if (x > 0) { kwflags = sexpops[kw].flgs; builtin = 1; } } } } /* If none of the above, check built-in constants */ if (x == -1) { x = xlookup(sexpconsts,p[1],nsexpconsts,&kw); if (x > 0) { switch (x) { case SXC_NIL: s2 = ""; goto xdosexp; case SXC_PI: s2 = math_pi; goto xdosexp; case SXC_T: s2 = "1"; goto xdosexp; } } } if (n == 1) { /* Not an expression */ if (builtin) { /* Built-in operand? */ switch (x) { /* Operators with default values */ case SX_EVA: s2 = ""; goto xdosexp; case SX_MUL: /* (*) */ s2 = sexpval ? sexpval : "1"; goto xdosexp; case SX_AND: /* (AND) */ case SX_BWA: /* Bitwise (&) */ result++; case SX_LOR: /* (OR) */ case SX_BWO: /* Bitwise (|) */ case SX_ADD: /* (+) */ case SX_SUB: /* (-) */ s2 = result ? "1" : "0"; goto xdosexp; } } else { /* Not a built-in operand */ char * p1; p1 = p[1]; while (*p1 == SP) p1++; if (!isalpha(*p1)) { if (xxfloat(p1,0) > 0) { /* Is it a number? */ s2 = p1; while (*s2 == '+') s2++; } else if (*p1 == '(') { /* An S-Expression? */ #ifdef COMMENT s2 = dosexp(s2); #else s2 = dosexp(p1); #endif /* COMMENT */ } goto xdosexp; } else if (x < 1) { /* Is it a variable? */ j = mxlook(mactab,p[1],nmac); /* Look it up */ debug(F111,sexpdebug("n==1 mxlook"),p[1],j); s2 = (j > -1) ? mactab[j].mval : ""; if (!s2) s2 = ""; if (xxfloat(s2,0) > 0) /* Macro value is a number */ goto xdosexp; if (j > -1) { /* It's a macro */ mx = j; x = j; /* whose definition is not numeric */ if (*s2 == '(') { /* Is it an S-Expression? */ /* We have to allocate memory on the stack */ /* to call ourselves recursively on it */ /* otherwise we'll wipe out the macro definition */ char * s3 = NULL; /* int k = 0; */ s3 = s2; while (*s3++) k++; s3 = (char *)malloc(k + 4); if (s3) { strcpy(s3,s2); /* SAFE */ s2 = dosexp(s3); /* Evaluate it */ free(s3); } else { printf("?Memory allocation failure - \"%s\"\n",s2); sexprc++; } goto xdosexp; } if (*s2 == '\047') { s2++; #ifdef COMMENT /* Dumps core if petty optimization was taken */ makestr(&(p[1]),s2); #else if (!nosplit && p[1]) free(p[1]); p[1] = (char *)malloc((int)strlen(s2) + 1); #endif /* COMMENT */ s2 = p[1]; if (!s2) s2 = ""; if (*s2 == '(') { if (s2[makestrlen-1] == ')') { s2[makestrlen-1] = NUL; s2++; } } debug(F110,sexpdebug("'A"),s2,0); goto xdosexp; } macro++; /* Not an S-Expression */ } else { printf("?Not defined - \"%s\"\n", p[1]); sexprc++; goto xdosexp; } } } } else if (x < 1 && !macro) { /* n > 1 and not a built-in operator */ x = mxlook(mactab,p[1],nmac); /* See if it's a macro */ debug(F111,sexpdebug("n!=1 mxlook"),p[1],x); if (x < 0) { printf("?Invalid operand - \"%s\"\n",p[1]); sexprc++; s2 = NULL; /* Bad operator, no result */ goto xdosexp; } mx = x; macro++; } if (builtin) { /* Built-in operator... */ if (kwflags) { int flgs; if ((flgs = (kwflags & (SXF_ONE|SXF_TWO)))) { switch (flgs) { case (SXF_ONE|SXF_TWO): if (n < 2) { printf("?Too few operands - \"%s\"\n",s); sexprc++; goto xdosexp; } break; case SXF_TWO: if (n < 3) { printf("?Too few operands - \"%s\"\n",s); sexprc++; goto xdosexp; } break; case SXF_ONE: if (n != 2) { printf("?Too %s operands - \"%s\"\n", (n > 2) ? "many" : "few", s); sexprc++; goto xdosexp; } } } if (kwflags & SXF_PRE) { /* Predicate? */ if (n < 2) { printf("?Too few operands - \"%s\"\n",s); sexprc++; goto xdosexp; } pflag = 1; presult = 1; } if (kwflags & SXF_FLO) /* Operator requires floating point */ fpflag++; /* Force it */ if (x == SX_ROU) { /* ROUND can have 1 or 2 arguments */ if (n < 2 || n > 3) { printf("?Too %s operands - \"%s\"\n", (n > 3) ? "many" : "few", s); sexprc++; goto xdosexp; } } if (x == SX_ROU) { /* But they are not "cumulative" like other SEXP args */ /* So this case is handled specially */ char buf1[32], buf2[32]; float r; char * s0, * s1; char * q0, * q1; s0 = p[2]; if (!s0) s0 = ""; if (!*s0) s0 = "0"; q0 = dosexp(s0); ckstrncpy(buf1,q0,32); q0 = buf1; s1 = p[3]; if (!s1) s1 = ""; if (!*s1) s1 = "0"; q1 = dosexp(s1); if (!q1) q1 = ""; if (!*q1) q1 = "0"; ckstrncpy(buf2,q1,32); q1 = buf2; r = ckround(atof(q0),(int)(atof(q1)),sxroundbuf,31); s2 = sxroundbuf; sexprc = 0; goto xdosexp; } } if (x == SX_SET || x == SX_LET || /* Assignment is special */ x == SX_INC || x == SX_DEC) { int rc; char c, * m, * s3; if (n == 1) { s2 = ""; goto xdosexp; } s2 = NULL; for (i = 1; i < n; i += 2) { /* Loop thru operand pairs */ rc = 0; s3 = p[i+1]; c = *s3; debug(F110,sexpdebug("target p"),s3,0); /* Make sure target doesn't have multiple words */ while (*s3) { if (*s3 < '!') { rc = 1; break; }; s3++; } s3 = p[i+1]; if (rc) { /* If it does it must have been */ char * s4; /* an SEXP so evaluate it */ s3 = dosexp(s3); s4 = s3; rc = 0; while (*s4) { if (*s4 < '!') { rc = 1; break; }; s4++; } if (rc == 0) makestr(&(p[i+1]),s3); } /* And that it's not a number, etc. */ if (rc > 0 || isdigit(c) || c == '(') { printf("?Invalid assignment - \"%s\"\n",s); sexprc++; goto xdosexp; } else if (isalpha(c)) { rc = xlookup(sexpconsts,s3,nsexpconsts,NULL); if (rc > 0) { printf("?Assignment to constant - \"%s\"\n",s); sexprc++; goto xdosexp; } } /* If ++ or --, get current value of variable */ if (x == SX_INC || x == SX_DEC) { int ok = 1; char buf[32]; if (c == CMDQ) { /* A backslash variable */ int n = 32; char * s = buf; buf[0] = NUL; if (zzstring(s3,&s,&n) < 0 || !buf[0]) ok = 0; s2 = buf; } else { /* A macro */ if ((k = mxlook(mactab,s3,nmac)) < 0) ok = 0; else s2 = mactab[k].mval; } if (!ok) { printf("?Not defined - \"%s\"\n",p[i+1]); sexprc++; goto xdosexp; } if (!s2) s2 = ""; k = xxfloat(s2,0); if (k < 1) { printf("?Not numeric - \"%s\"\n",p[i+1]); sexprc++; goto xdosexp; } while (*s2 == '+') s2++; result = ckatofs(s2); fpresult = floatval; if (k > 1 || fpresult != result) fpflag++; } if (n < i+2) { /* Variable with no value */ s2 = ""; if (x == SX_SET || x == SX_LET) { delmac(p[i+1],1); /* Delete the variable */ break; } else { s2 = "1"; } } else { /* Variable with value */ k = xxfloat(p[i+2],0); /* Is it a number? */ if (k > 0) { s2 = p[i+2]; while (*s2 == '+') s2++; } else { s2 = dosexp(p[i+2]); /* Have value, evaluate it */ if (sexprc) goto xdosexp; if (!s2) s2 = ""; if (!*s2 && (x == SX_INC || x == SX_DEC)) continue; } } if (x == SX_INC || x == SX_DEC) { k = xxfloat(s2,0); if (k < 1) { printf("?Not numeric - \"%s\"\n",s2); sexprc++; goto xdosexp; } while (*s2 == '+') s2++; j = ckatofs(s2); if (k > 1) { fpj = floatval; fpflag++; } else { fpj = (CKFLOAT)j; } if (x == SX_INC) { result += j; fpresult += fpj; } else if (x == SX_DEC) { result -= j; fpresult -= fpj; } #ifdef FNFLOAT /* This gets a "Types incompatible in conditional expression" warning in HP-UX 10 with the pre-ANSI HP C 76.3 compiler if there is no prototype for fpformat... even though pre-ANSI C does not have prototypes! This prototype has been added above just after '#include "ckcfnp.h"' within #ifdef HPUX10..#endif. */ if (result != fpresult) fpflag++; #endif /* FNFLOAT */ s2 = (fpflag && !sexptrunc) ? fpformat(fpresult,0,0) : ckfstoa(result); } if (x == SX_LET && cmdlvl > 0) /* LET makes var local */ addlocal(p[i+1]); if ((rc = addmac(p[i+1],s2)) < 0) { /* Add the value */ switch (rc) { case -3: m = "Array not declared"; break; case -2: m = "Subscript out of range"; break; case -4: m = "Out of memory"; break; default: m = "Error creating variable"; } printf("?%s - \"%s\"\n",m,s); sexprc++; goto xdosexp; } if (s2) result = ckatofs(s2); } goto xdosexp; } else if (x == SX_IFC) { /* Conditional expression */ int bool_result = 0; if (n > 4) { printf("?Too many operands: IF - \"%s\"\n",s); sexprc++; goto xdosexp; } s2 = dosexp(p[2]); if (sexprc) goto xdosexp; if (s2) { j = ckatofs(s2); if (xxfloat(s2,0) == 2) { fpflag++; fpresult = (CKFLOAT)result; fpj = floatval; } else { fpj = atof(s2); } bool_result = ((fpj != 0.0) ? 1 : 0); } if (!bool_result && n < 4) { s2 = NULL; } else { s2 = dosexp(bool_result ? p[3] : p[4]); if (sexprc) goto xdosexp; j = s2 ? ckatofs(s2) : 0; if (xxfloat(s2,0) == 2) { fpflag++; fpresult = (CKFLOAT)result; fpj = floatval; } else { fpj = s2 ? atof(s2) : 0.0; } fpresult = fpj; result = j; } goto xdosexp; } else if (x == SX_QUO) { int xx; xx = strlen(p[2]); p[3] = (char *)malloc(xx+4); s2 = p[3]; ckmakmsg(p[3],xx+4,"'(",p[2],")",NULL); n++; goto xdosexp; } else if (x == SX_UNQ) { /* UNQUOTE */ int k, xx = 0; s2 = p[2]; if (!s2) s2 = ""; xx = strlen(s2); if (xx == 0) /* Null or empty arg */ goto xdosexp; /* Case 0 - number */ if (isfloat(s2,0)) goto xdosexp; /* Case 2 - S-expression that evaluates to a quoted string */ if (s2[0] == '(' && s2[xx-1] == ')') { s2 = dosexp(s2); } else if (s2[0] != '\047') { /* Case 3 - Variable */ if ((k = mxlook(mactab,p[2],nmac)) >= 0) { s2 = mactab[k].mval; } else { s2 = ""; } } /* If result is a quoted string, unquote it */ xx = strlen(s2); if (s2[0] == '\047' && s2[1] == '(' && s2[xx-1] == ')') { s2[xx-1] = NUL; s2 += 2; } goto xdosexp; } else if (x == SX_STR) { int xx; s2 = dosexp(p[2]); if (sexprc) goto xdosexp; xx = strlen(s2); p[3] = (char *)malloc(xx+4); ckmakmsg(p[3],xx+4,"'(",s2,")",NULL); s2 = p[3]; n++; goto xdosexp; } } /* Arithmetic operator or macro - Loop thru operands */ quit = 0; /* Short-circuit flag. */ if (macro && n > 1) { /* If operator is a macro */ if (!line) { /* allocate local buffer for */ line = (char *)malloc(SXMLEN); /* the evaluated argument list. */ if (!line) { printf("?Memory allocation failure - \"%s\"\n",p[1]); sexprc++; goto xdosexp; } linelen = SXMLEN; /* debug(F101,"dosexp macro arg buffer","",linelen); */ } linepos = 0; line[linepos] = NUL; } for (i = 1; ((i < n) && !sexprc && !quit); i++) { /* Loop thru operands */ quote = 0; s2 = p[i+1]; /* Get operand */ if (!s2) s2 = ""; #ifdef COMMENT if (*s2 == '\047') { /* Is it quoted? */ debug(F110,sexpdebug("'B"),s2,0); s2++; /* Space past the quote */ quote++; if (*s2 == '(') { /* Quoted S-Expression? */ char c4, * s4 = s2+1; /* Strip outer parens */ while ((c4 = *s4++)) { if (c4 == ')' && !*s4) { s2++; *(s4-1) = NUL; break; } } } debug(F110,sexpdebug("'C"),s2,0); } else { /* Not quoted */ s2 = dosexp(p[i+1]); /* evaluate it */ if (sexprc) goto xdosexp; if (!s2) s2 = ""; if (!macro && x == SX_EVA) continue; } #else if (*s2 != '\047') { /* Not quoted */ if (x == SX_ECH && (k = mxlook(mactab,s2,nmac)) > -1) { s2 = mactab[k].mval; } else { s2 = dosexp(s2); /* No, evaluate it */ } if (sexprc && x != SX_ECH) goto xdosexp; if (!s2) s2 = ""; if (!macro && x == SX_EVA) continue; if (x == SX_ECH) { /* ECHO */ printf("%s ",s2); if (i == n-1) printf("\n"); continue; } } if (*s2 == '\047') { /* Is result quoted? */ debug(F110,sexpdebug("'B"),s2,0); s2++; /* Space past the quote */ quote++; if (*s2 == '(') { /* Quoted S-Expression? */ char c4, * s4 = s2+1; /* Strip outer parens */ while ((c4 = *s4++)) { if (c4 == ')' && !*s4) { s2++; *(s4-1) = NUL; break; } } } debug(F110,sexpdebug("'C"),s2,0); if (x == SX_ECH) { /* ECHO */ printf("%s ",s2); if (i == n-1) printf("\n"); continue; } } #endif /* COMMENT */ if (macro) { debug(F111,sexpdebug("macro arg"),s2,i); if (!*s2) quote++; if (!quote) { register char c4, * s4 = s2; while ((c4 = *s4++)) if (c4 == SP) { quote++; break; } } if (quote) line[linepos++] = '{'; while ((line[linepos++] = *s2++)) { if (linepos > linelen - 3) { char * tmp = NULL; line[linepos] = NUL; linelen += SXMLEN; tmp = (char *) malloc(linelen); if (!tmp) { printf("?Memory re-allocation failure - \"%s...\"\n", line); sexprc++; goto xdosexp; } strcpy(tmp,line); free(line); line = tmp; } } linepos--; /* Back up over NUL */ if (quote) line[linepos++] = '}'; /* End quote group */ line[linepos++] = SP; /* add a space */ line[linepos] = NUL; /* and a NUL */ continue; } if (!quote) { /* Built-in operator... */ s2 = dosexp(s2); if (sexprc) goto xdosexp; if (!s2) s2 = ""; } if (x == SX_EVA) continue; if (!*s2) { /* An empty value is not a legal number */ /* but it is a legal truth value */ if (x != SX_AND && x != SX_LOR && x != SX_NOT) { printf("?Not Numeric - \"%s\"\n",p[i+1]); sexprc++; goto xdosexp; } j = 0; fpj = 0.0; } else { j = ckatofs(s2); /* Switch to floating-point upon encountering any f.p. arg */ /* OR... if integer is too big */ if (!fpflag) if (xxfloat(s2,0) == 2) fpflag++; fpj = atof(s2); } if (i == 1) { /* Initial result is first operand */ result = (n == 2 && x == SX_SUB) ? 0-j : j; fpresult = (n == 2 && x == SX_SUB) ? -fpj : fpj; if ((x == SX_AND && result == 0) || /* Short circuit */ (x == SX_LOR && result != 0)) quit++; if (!(kwflags & SXF_ONE)) /* Command w/single arg */ continue; } if (x == SX_MOD || x == SX_DIV) { if (!result) fpflag++; if (!fpj) { printf("?Divide by zero - \"%s\"\n",cmdbuf); sexprc++; goto xdosexp; } } switch (x) { /* Accumulate result */ case SX_EVA: /* EVAL */ result = j; fpresult = fpj; break; case SX_ADD: /* + */ result += j; fpresult += fpj; #ifdef FNFLOAT if (result != fpresult) fpflag++; #endif /* FNFLOAT */ break; case SX_SUB: /* - */ result -= j; fpresult -= fpj; #ifdef FNFLOAT if (result != fpresult) fpflag++; #endif /* FNFLOAT */ break; case SX_MUL: /* * */ result *= j; fpresult *= fpj; #ifdef FNFLOAT if (result != fpresult) fpflag++; #endif /* FNFLOAT */ break; case SX_AND: /* AND */ result = result && j; if (!result) quit++; fpresult = fpresult && fpj; break; case SX_LOR: /* OR */ result = result || j; if (!result) quit++; fpresult = fpresult || fpj; break; case SX_MOD: /* Modulus */ result = result % j; #ifdef FNFLOAT fpresult = (CKFLOAT)fmod(fpresult,fpj); if (result != fpresult) fpflag++; #else fpresult = result; #endif /* FNFLOAT */ break; case SX_DIV: /* / */ if (j) { result /= j; fpresult /= fpj; #ifdef FNFLOAT if (result != fpresult) fpflag++; #endif /* FNFLOAT */ } else { fpresult /= fpj; result = fpj; #ifdef FNFLOAT fpflag++; #endif /* FNFLOAT */ } break; case SX_AEQ: /* Test for equality */ if (fpflag) { if (fpresult != fpj) presult = 0; } else { if (result != j) presult = 0; } break; case SX_NEQ: /* Test for ineqality */ if (fpflag) { if (fpresult == fpj) presult = 0; } else { if (result == j) presult = 0; } break; case SX_ALE: /* Arithmetic less-equal */ if (fpflag) { if (fpj < fpresult) presult = 0; fpresult = fpj; } else { if (j < result) presult = 0; result = j; } break; case SX_ALT: /* Arithmetic less-than */ if (fpflag) { if (fpj <= fpresult) presult = 0; fpresult = fpj; } else { if (j <= result) presult = 0; result = j; } break; case SX_AGT: /* Arithmetic greater-than */ if (fpflag) { if (fpj >= fpresult) presult = 0; fpresult = fpj; } else { if (j >= result) presult = 0; result = j; } break; case SX_AGE: /* Arithmetic greater-equal */ if (fpflag) { if (fpj > fpresult) presult = 0; fpresult = fpj; } else { if (j > result) presult = 0; result = j; } break; case SX_POW: /* Raise to power */ #ifdef FNFLOAT { double dummy; if (!fpj) { fpresult = 1.0; } else if ((!fpresult && fpj <= 0.0)) { printf("?Divide by zero - \"%s\"\n",cmdbuf); sexprc++; goto xdosexp; } else if (fpresult < 0.0 && modf(fpj,&dummy)) { printf("?Domain error - \"%s\"\n",cmdbuf); sexprc++; goto xdosexp; } else { fpresult = (CKFLOAT)pow(fpresult,fpj); } } #endif /* FNFLOAT */ if (j == 0) { result = 1; } else { CK_OFF_T z, sign = 0; if (j < 0) { if (result == 0) { printf("?Divide by zero - \"%s\"\n",cmdbuf); sexprc++; goto xdosexp; } j = 0 - j; sign++; } z = result; while (--j > 0) result *= z; if (sign) result = 1 / result; } #ifdef FNFLOAT if (result != fpresult) fpflag++; #endif /* FNFLOAT */ break; #ifdef FNFLOAT case SX_EXP: /* e to the given power */ fpresult = (CKFLOAT) exp(fpj); break; case SX_LGN: /* Natural log */ case SX_LGX: /* Log base 10 */ case SX_SQR: /* Square root */ if (fpj < 0.0) { printf("?Argument out of range - \"%s\"\n",cmdbuf); sexprc++; goto xdosexp; } if (x == SX_SQR) fpresult = (CKFLOAT) sqrt(fpj); else if (x == SX_LGN) fpresult = (CKFLOAT) log(fpj); else fpresult = (CKFLOAT) log10(fpj); break; case SX_SIN: /* sine */ fpresult = (CKFLOAT) sin(fpj); break; case SX_COS: /* cosine */ fpresult = (CKFLOAT) cos(fpj); break; case SX_TAN: /* tangent */ fpresult = (CKFLOAT) tan(fpj); break; #endif /* FNFLOAT */ case SX_CEI: /* Ceiling */ if (j != fpj) if (fpj > 0.0) fpj += 1.0; fpresult = fpj; fpflag = 1; truncate = 1; break; case SX_FLR: /* Floor */ if (j != fpj) if (fpj < 0.0) fpj -= 1.0; fpresult = fpj; fpflag = 1; truncate = 1; break; case SX_TRU: /* Truncate */ fpresult = fpj; fpflag = 1; truncate = 1; break; case SX_ABS: /* Absolute value */ result = (j < 0) ? 0 - j : j; #ifdef FNFLOAT fpresult = (fpj < 0.0) ? 0.0 - fpj : fpj; if (result != fpresult) fpflag++; #endif /* FNFLOAT */ break; case SX_MAX: /* Max */ if (j != fpj) fpflag++; if (fpflag) { if (fpj > fpresult) fpresult = fpj; } else if (j > result) result = j; break; case SX_MIN: /* Min */ if (j != fpj) fpflag++; if (fpflag) { if (fpj < fpresult) fpresult = fpj; } else if (j < result) result = j; break; case SX_FLO: /* Float */ fpflag++; fpresult = result; fpj = j; break; case SX_NOT: /* NOT (reverse truth value) */ fpflag = 0; not++; break; case SX_BWA: /* Bitwise AND */ fpflag = 0; result &= j; break; case SX_BWO: /* Bitwise OR */ fpflag = 0; result |= j; break; case SX_BWX: /* Bitwise XOR */ case SX_XOR: /* Logical XOR */ if (n > 3) { printf("?Too many operands - \"%s\"\n",s); sexprc++; goto xdosexp; } fpflag = 0; if (x == SX_BWX) { result ^= j; } else { result = (result && !j) || (!result && j); if (result) result = 1; } break; case SX_BWN: /* Bitwise Not */ fpflag = 0; result = ~result; break; default: printf("BAD OP [%s]\n",p[1]); sexprc++; } } if (!pflag) /* Not a predicate */ sexppv = -1; /* So unset this */ /* domacro: */ if (macro) { /* User-defined macro */ extern int fsexpflag; /* (see fneval():ckuus4.c) */ int lookagain = 0; /* Maybe the macro table changed */ if (mactab[mx].kwd) { /* Check and see */ if (ckstrcmp(mactab[mx].kwd,p[1],-1,0)) lookagain++; } else lookagain++; if (lookagain) { /* The table changed */ mx = mxlook(mactab,p[1],nmac); /* Get the macro's new index */ debug(F111,sexpdebug("macro moved"),p[1],mx); if (mx < 0) { /* Yikes! */ printf("?Macro disappeared! - \"%s\"\n",p[1]); sexprc++; goto xdosexp; } } debug(F111,sexpdebug("macro mx"),mactab[mx].kwd,mx); if (fsexpflag) { /* If embedded in a function call */ if (cmpush() > -1) { /* get a new copy of the parsing */ extern int ifc; /* environment, */ int k, ifcsav = ifc; /* save the IF state */ dodo(mx,line,0); /* Set up the macro */ k = parser(1); /* Call the parser to execute it */ cmpop(); /* Pop back to previous level */ ifc = ifcsav; /* restore IF state */ if (k == 0) /* If no error */ s2 = mrval[maclvl+1]; /* get return value, if any */ if (!s2) s2 = ""; debug(F110,sexpdebug("macro return"),s2,0); } else { printf("?Resources exhausted - \"%s\"\n",s); sexprc++; } } else { /* Not embedded in a function call */ dodo(mx,line,0); /* As above but without cmpush/pop() */ k = parser(1); if (k == 0) s2 = mrval[maclvl+1]; if (!s2) s2 = ""; } } else if (pflag) { /* Predicate */ if (not) presult = presult ? 0 : 1; sexppv = presult; /* So set predicate value (0 or 1) */ s2 = presult ? "1" : "0"; } else if (fpflag && !sexptrunc) { /* Result is floating-point */ if (not) fpresult = fpresult ? 0.0 : 1.0; s2 = fpformat(fpresult,0,0); } else if (x != SX_EVA) { if (not) result = result ? 0 : 1; s2 = ckfstoa(result); } /* Common exit point. Always come here to exit. */ xdosexp: if (!s2) s2 = ""; debug(F111,"xdosexp s2",s2,sexprc); if (x == SX_ECH) s2 = ""; debug(F111,"xdosexp s2 ECHO",s2,sexprc); if (!sexprc /* && *s2 */) { /* Have a result */ char * sx; /* Note -- do this even if result empty */ char * q2 = s2; int xx = 0; if (*s2) { while (*q2++) xx++; /* Get length */ if (xx > sexprmax) /* (stats) */ sexprmax = xx; } else xx = 0; if (xx > sxrlen[sexpdep] || !sxresult[sexpdep]) { int k; k = xx + xx / 4; if (k < 32) k = 32; if (sxresult[sexpdep]) free(sxresult[sexpdep]); if ((sxresult[sexpdep] = (char *)malloc(k))) { sxrlen[sexpdep] = k; } else { printf("?Memory allocation failure - \"%s\"\n",s2); sexprc++; } } sx = sxresult[sexpdep]; /* Point to result buffer */ while ((*sx++ = *s2++)) ; /* copy result. */ if (fpflag && truncate) { /* Floating point + truncate */ sx = sxresult[sexpdep]; /* at decimal point */ for (i = xx - 1; i >= 0; i--) { if (sx[i] == '.') { sx[i] = NUL; if (i == 0) { /* If nothing left */ sx[0] = '0'; /* put a zero. */ sx[1] = NUL; } } } } } /*xxdosexp:*/ if (line) /* If macro arg buffer allocated */ free(line); /* free it. */ if (mustfree) { /* And free local copy of split list */ for (i = 1; i <= n; i++) { if (p[i]) free(p[i]); } } debug(F111,sexpdebug("exit"),sxresult[sexpdep],sexprc); s = sxresult[sexpdep--]; if (!s) s = ""; return(s); } #endif /* NOSEXP */ #endif /* NOSPL */ int /* CHECK command */ dochk() { int x, y; if ((y = cmkey(ftrtab,nftr,"","",xxstring)) < 0) return(y); ckstrncpy(line,atmbuf,LINBUFSIZ); if ((y = cmcfm()) < 0) return(y); #ifdef HAVE_LOCALE if (!ckstrcmp(line,"locale",(int)strlen(line),0)) { extern int nolocale; int ok = 0; ok = (nolocale ? 0 : 1); if (msgflg) printf(" locale%s available\n", ok ? "" : " not"); else if (nolocale && !backgrd) printf(" CHECK: locale not available\n"); return(success = ok); } #endif /* HAVE_LOCALE */ #ifndef NOPUSH if (!ckstrcmp(line,"push",(int)strlen(line),0)) { if (msgflg) /* If at top level... */ printf(" push%s available\n", nopush ? " not" : ""); else if (nopush && !backgrd) printf(" CHECK: push not available\n"); return(success = 1 - nopush); } #endif /* NOPUSH */ #ifdef PIPESEND if (!ckstrcmp(line,"pipes",(int)strlen(line),0)) { if (msgflg) /* If at top level... */ printf(" pipes%s available\n", (nopush || protocol != PROTO_K) ? " not" : ""); else if ((nopush || protocol != PROTO_K) && !backgrd) printf(" CHECK: pipes not available\n"); return(success = 1 - nopush); } #endif /* PIPESEND */ y = lookup(ftrtab,line,nftr,&x); /* Look it up */ debug(F111,"dochk",ftrtab[x].kwd,y); if (msgflg) /* If at top level... */ printf(" %s%s available\n", ftrtab[x].kwd, y ? " not" : ""); else if (y && !backgrd) printf(" CHECK: %s not available\n", ftrtab[x].kwd); return(success = 1 - y); } #ifndef NOLOCAL #ifdef CKLOGDIAL /* Connection log and elapsed-time reporting */ extern char cxlogbuf[]; /* Log record buffer */ extern char diafil[]; /* Log file name */ extern int dialog, cx_active; /* Flags */ static long cx_prev = 0L; /* Elapsed time of previous session */ #endif /* CKLOGDIAL */ #endif /* NOLOCAL */ VOID dologend() { /* Write record to connection log */ #ifdef LOCUS extern int locus, autolocus; #endif /* LOCUS */ #ifndef NOLOCAL #ifdef CKLOGDIAL long d1, d2, t1, t2; char buf[32], * p; #endif /* CKLOGDIAL */ #endif /* NOLOCAL */ #ifdef LOCUS if (autolocus) { #ifdef NEWFTP debug(F101,"dologend ftpisconnected","",ftpisconnected()); setlocus(ftpisconnected() ? 0 : 1, 1); #else setlocus(1,1); #endif /* NEWFTP */ } #endif /* LOCUS */ #ifndef NOLOCAL #ifdef CKLOGDIAL debug(F101,"dologend dialog","",dialog); debug(F101,"dologend cxlogbuf[0]","",cxlogbuf[0]); #ifdef CKSYSLOG debug(F101,"dologend ckxlogging","",ckxlogging); #endif /* CKSYSLOG */ if (!cx_active || !cxlogbuf[0]) /* No active record */ return; cx_active = 0; /* Record is not active */ debug(F111,"dologend cxlogbuf 1",cxlogbuf,cx_active); d1 = mjd((char *)cxlogbuf); /* Get start date of this session */ ckstrncpy(buf,ckdate(),31); /* Get current date */ d2 = mjd(buf); /* Convert them to mjds */ p = cxlogbuf; /* Get start time */ p[11] = NUL; p[14] = NUL; /* Convert to seconds */ t1 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15); p[11] = ':'; p[14] = ':'; p = buf; /* Get end time */ p[11] = NUL; p[14] = NUL; t2 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15); t2 = ((d2 - d1) * 86400L) + (t2 - t1); /* Compute elapsed time */ debug(F101,"dologend t2","",t2); if (t2 > -1L) { cx_prev = t2; p = hhmmss(t2); debug(F110,"dologend hhmmss",p,0); ckstrncat(cxlogbuf,"E=",CXLOGBUFL); /* Append to log record */ ckstrncat(cxlogbuf,p,CXLOGBUFL); debug(F110,"dologend cxlogbuf 2",cxlogbuf,0); } else cx_prev = 0L; debug(F101,"dologend cx_prev","",cx_prev); if (dialog) { /* If logging */ int x; x = diaopn(diafil,1,1); /* Open log in append mode */ debug(F101,"dologend diaopn","",x); x = zsoutl(ZDIFIL,cxlogbuf); /* Write the record */ debug(F101,"dologend zsoutl","",x); x = zclose(ZDIFIL); /* Close the log */ debug(F101,"dologend zclose","",x); } #ifdef CKSYSLOG debug(F101,"dologend ckxlogging","",ckxlogging); if (ckxlogging) { int x; x = ckindex("T=DIAL",cxlogbuf,0,0,1); debug(F111,"dologend ckxsyslog",cxlogbuf,ckxsyslog); debug(F111,"dologend ckindex","T=DIAL",x); if (x > 0) { if (ckxsyslog >= SYSLG_DI) { debug(F110,"dologend syslog",cxlogbuf+18,0); cksyslog(SYSLG_DI,1,"CONNECTION",(char *)(cxlogbuf+18),""); } else if (ckxsyslog >= SYSLG_AC) { debug(F110,"dologend syslog",cxlogbuf+18,0); cksyslog(SYSLG_AC,1,"CONNECTION",(char *)(cxlogbuf+18),""); } } } #endif /* CKSYSLOG */ #endif /* CKLOGDIAL */ #endif /* NOLOCAL */ } #ifndef NOLOCAL #ifdef CKLOGDIAL /* D O L O G S H O W -- Show session/connection info */ /* Call with fc == 1 to show, fc == 0 to only calculate. */ /* Returns session elapsed time in seconds. */ /* If no session active, returns elapsed time of previous session, if any, */ /* otherwise 0 */ long #ifdef CK_ANSIC dologshow( int fc ) /* SHOW (current) CONNECTION */ #else dologshow(fc) int fc; #endif /* CK_ANSIC */ { long d1, d2, t1, t2 = 0, prev; char c, buf1[32], buf2[32], * info[32], * p, * s; char * xlogbuf, xbuf[CXLOGBUFL+1]; int i, x = 0, z, ftp = 0, active = 0; #ifdef NEWFTP extern char ftplogbuf[]; extern long ftplogprev; extern int ftplogactive; if (fc & W_FTP) { fc &= 63; ftp = 1; xlogbuf = ftplogbuf; prev = ftplogprev; active = ftplogactive; } else { #endif /* NEWFTP */ ftp = 0; xlogbuf = cxlogbuf; prev = cx_prev; active = cx_active; #ifdef NEWFTP } #endif /* NEWFTP */ debug(F101,"dologshow local","",local); debug(F101,"dologshow ftp","",ftp); debug(F111,"dologshow active",xlogbuf,active); if (!xlogbuf[0]) { if (fc) { if (didsetlin || ftp) printf(" %s: No record.\n", ftp ? "FTP" : "Kermit"); else printf(" %s: No connection.\n", ftp ? "FTP" : "Kermit"); } return(prev); } #ifdef NEWFTP if (ftp) { z = ftpisconnected() ? 1 : -1; } else { #endif /* NEWFTP */ if (local) { /* See if we have an open connection */ z = ttchk(); debug(F101,"dologshow ttchk","",z); z = (z > -1) ? 1 : -2; } else { z = active ? 1 : -2; } #ifdef NEWFTP } #endif /* NEWFTP */ if (z < 0L) { if (!fc) return(prev); else t2 = prev; } /* Note: NOT ckstrncpy! */ strncpy(buf1,xlogbuf,17); /* Copy of just the timestamp */ buf1[17] = NUL; /* Terminate it */ ckstrncpy(xbuf,xlogbuf+18,CXLOGBUFL); /* Copy that can be poked */ debug(F111,"dologshow prev",xbuf,prev); xwords(xbuf,31,info,1); /* Break up into fields */ d1 = mjd(buf1); /* Convert start time to MJD */ ckstrncpy(buf2,ckdate(),31); /* Current date */ d2 = mjd(buf2); /* Convert to MJD */ p = buf1; /* Point to start time */ p[11] = NUL; p[14] = NUL; /* Convert to seconds */ t1 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15); p[11] = ':'; p[14] = ':'; p = buf2; /* Ditto for current time */ p[11] = NUL; p[14] = NUL; if (z > -1L) { t2 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15); t2 = ((d2 - d1) * 86400L) + (t2 - t1); /* Elapsed time so far */ } if (fc) { p = NULL; if (t2 > -1L) /* Convert seconds to hh:mm:ss */ p = hhmmss(t2); if (z > -1) s = "Active"; else if (z == -2) s = "Closed"; else s = "Unknown"; printf("\n"); /* Show results */ printf(" Status: %s\n",s); printf(" Opened: %s\n",buf1); printf(" User: %s\n",info[1] ? info[1] : ""); printf(" PID: %s\n",info[2] ? info[2] : ""); for (i = 3; info[i]; i++) { c = info[i][0]; s = (info[i]) ? info[i]+2 : ""; switch (c) { case 'T': printf(" Type: %s\n", s); break; case 'N': printf(" To: %s\n", s); break; case 'P': printf(" Port: %s\n", s); break; case 'H': printf(" From: %s\n", s); break; case 'D': printf(" Device: %s\n", s); break; case 'O': printf(" Origin: %s\n", s); break; case 'E': break; default: printf(" %s\n",info[i] ? info[i] : ""); } } if (z < 0L) printf(" Elapsed time: %s\n", hhmmss(t2)); else printf(" Elapsed time: %s\n", p ? p : "(unknown)"); x = 0; #ifdef NETCONN #ifdef SSHBUILTIN if ( IS_SSH() ) x++; #endif /* SSHBUILTIN */ #ifdef CK_ENCRYPTION if (ck_tn_encrypting() && ck_tn_decrypting()) x++; #endif /* CK_ENCRYPTION */ #ifdef CK_SSL if (tls_active_flag || ssl_active_flag) x++; #endif /* CK_SSL */ #ifdef RLOGCODE #ifdef CK_KERBEROS #ifdef CK_ENCRYPTION if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN) x++; #endif /* CK_ENCRYPTION */ #endif /* CK_KERBEROS */ #endif /* RLOGCODE */ #endif /* NETCONN */ if (z > 0) printf(" Encrypted: %s\n", x ? "Yes" : "No"); printf(" Log: %s\n", dialog ? diafil : "(none)"); printf("\n"); } return(t2 > -1L ? t2 : 0L); } VOID dologline() { char * p; int n, m = 0; dologend(); /* Previous session not closed out? */ cx_active = 1; /* Record is active */ cx_prev = 0L; p = ckdate(); /* Get timestamp */ n = ckstrncpy(cxlogbuf,p,CXLOGBUFL-1); /* Start record off with it */ if (!uidbuf[0]) { debug(F100,"dologline uidbuf empty","",0); #ifdef UNIX /* Who has whoami()... */ ckstrncpy(uidbuf,(char *)whoami(),UIDBUFLEN); #else #ifdef STRATUS ckstrncpy(uidbuf,(char *)whoami(),UIDBUFLEN); #else ckstrncpy(uidbuf,"UNKNOWN",UIDBUFLEN); #endif /* STRATUS */ #endif /* UNIX */ } m = strlen(uidbuf) + strlen(myhost) + strlen(ttname) + 32; if (n+m < CXLOGBUFL-1) { /* Add serial device info */ p = cxlogbuf+n; sprintf(p," %s %s T=SERIAL H=%s D=%s ", /* SAFE */ uidbuf, ckgetpid(), myhost, ttname ); } else ckstrncpy(cxlogbuf,"LOGLINE BUFFER OVERFLOW",CXLOGBUFL); debug(F110,"dologline",cxlogbuf,0); } #ifdef NETCONN VOID dolognet() { char * p, * s = "NET", * uu = uidbuf; char * port = ""; int n, m, tcp = 0; char * h = NULL; dologend(); /* Previous session not closed out? */ cx_prev = 0L; cx_active = 1; /* Record is active */ p = ckdate(); n = ckstrncpy(cxlogbuf,p,CXLOGBUFL); #ifdef TCPSOCKET if (nettype == NET_TCPB || nettype == NET_TCPA) { tcp++; s = "TCP"; } else if (nettype == NET_SSH) { s = "SSH"; tcp++; } #endif /* TCPSOCKET */ #ifdef ANYX25 if (nettype == NET_SX25 || nettype == NET_VX25 || nettype == NET_IX25) s = "X25"; #endif /* ANYX25 */ #ifdef DECNET if (nettype == NET_DEC) s = "DECNET"; #endif /* DECNET */ #ifdef SUPERLAT if (nettype == NET_SLAT) s = "SUPERLAT"; #endif /* SUPERLAT */ #ifdef CK_NETBIOS if (nettype == NET_BIOS) s = "NETBIOS"; #endif /* CK_NETBIOS */ if (!uu[0]) { debug(F100,"dolognet uidbuf empty","",0); #ifdef OS2ORUNIX /* Who has whoami()... */ uu = (char *)whoami(); #else #ifdef STRATUS uu = (char *)whoami(); #else uu = "UNKNOWN"; #endif /* STRATUS */ #endif /* UNIX */ } #ifdef TCPSOCKET if (tcp) { int k; makestr(&h,myhost); if ((k = ckindex(":",h,0,0,0)) > 0) { h[k-1] = NUL; port = &h[k]; } else { int svcnum = gettcpport(); if (svcnum > 0) port = ckitoa(svcnum); else port = "unk"; } } #endif /* TCPSOCKET */ m = strlen(uu) + strlen(myhost) + strlen(ttname) + strlen(s) + 32; if (n+m < CXLOGBUFL-1) { /* SAFE */ p = cxlogbuf+n; sprintf(p," %s %s T=%s N=%s H=%s P=%s ", uu, ckgetpid(), s, ttname, myhost, port ); } else ckstrncpy(cxlogbuf,"LOGNET BUFFER OVERFLOW",CXLOGBUFL); debug(F110,"dolognet cxlogbuf",cxlogbuf,0); if (h) makestr(&h,NULL); } #endif /* NETCONN */ #endif /* CKLOGDIAL */ #ifndef NODIAL /* Parse a DIAL-related string, stripping enclosing braces, if any. */ static int #ifdef CK_ANSIC dialstr( char **p, char *msg ) #else dialstr(p,msg) char **p; char *msg; #endif /* CK_ANSIC */ { int x; char *s; if ((x = cmtxt(msg, "", &s, xxstring)) < 0) return(x); s = brstrip(s); /* Strip braces around. */ debug(F110,"dialstr",s,0); makestr(p,*s?s:NULL); return(success = 1); } VOID #ifdef CK_ANSIC initmdm( int x ) #else initmdm(x) int x; #endif /* CK_ANSIC */ { MDMINF * p; int m; mdmtyp = x; /* Set global modem type */ debug(F101,"initmdm mdmtyp","",mdmtyp); debug(F101,"initmdm usermdm","",usermdm); if (x < 1) return; m = usermdm ? usermdm : mdmtyp; p = modemp[m]; /* Point to modem info struct, and */ /* debug(F101,"initmdm p","",p); */ if (p) { dialec = p->capas & CKD_EC; /* set DIAL ERROR-CORRECTION, */ dialdc = p->capas & CKD_DC; /* DIAL DATA-COMPRESSION, and */ mdmspd = p->capas & CKD_SB ? 0 : 1; /* DIAL SPEED-MATCHING from it. */ dialfc = FLO_AUTO; /* Modem's local flow control.. */ dialmax = p->max_speed; dialcapas = p->capas; dialesc = p->esc_char; } else if (mdmtyp > 0) { printf("WARNING: modem info for \"%s\" not filled in yet\n", gmdmtyp() ); } /* Reset or set the SET DIAL STRING items ... */ #ifdef DEBUG if (deblog) { debug(F110,"initmdm dialini",dialini,0); debug(F110,"initmdm dialmstr ",dialmstr,0); debug(F110,"initmdm dialmprmt",dialmprmt,0); debug(F110,"initmdm dialcmd",dialcmd,0); debug(F110,"initmdm dialdcon",dialdcon,0); debug(F110,"initmdm dialdcoff",dialdcoff,0); debug(F110,"initmdm dialecon",dialecon,0); debug(F110,"initmdm dialecoff",dialecoff,0); debug(F110,"initmdm dialhcmd",dialhcmd,0); debug(F110,"initmdm dialhwfc",dialhwfc,0); debug(F110,"initmdm dialswfc",dialswfc,0); debug(F110,"initmdm dialnofc",dialnofc,0); debug(F110,"initmdm dialtone",dialtone,0); debug(F110,"initmdm dialpulse",dialpulse,0); debug(F110,"initmdm dialname",dialname,0); debug(F110,"initmdm dialaaon",dialaaon,0); debug(F110,"initmdm dialaaoff",dialaaoff,0); debug(F110,"initmdm dialx3",dialx3,0); debug(F110,"initmdm dialspon",dialspon,0); debug(F110,"initmdm dialspoff",dialspoff,0); debug(F110,"initmdm dialvol1",dialvol1,0); debug(F110,"initmdm dialvol2",dialvol2,0); debug(F110,"initmdm dialvol3",dialvol3,0); debug(F110,"initmdm dialini2",dialini2,0); } #endif /* DEBUG */ if (usermdm && p) { /* USER-DEFINED: copy info from specified template */ makestr(&dialini ,p->wake_str); makestr(&dialmstr ,p->dmode_str); makestr(&dialmprmt,p->dmode_prompt); makestr(&dialcmd ,p->dial_str); makestr(&dialdcon ,p->dc_on_str); makestr(&dialdcoff,p->dc_off_str); makestr(&dialecon ,p->ec_on_str); makestr(&dialecoff,p->ec_off_str); makestr(&dialhcmd ,p->hup_str); makestr(&dialhwfc ,p->hwfc_str); makestr(&dialswfc ,p->swfc_str); makestr(&dialnofc ,p->nofc_str); makestr(&dialtone ,p->tone); makestr(&dialpulse,p->pulse); makestr(&dialname ,"This space available (use SET MODEM NAME)"); makestr(&dialaaon ,p->aa_on_str); makestr(&dialaaoff,p->aa_off_str); makestr(&dialx3 ,p->ignoredt); makestr(&dialspon ,p->sp_on_str); makestr(&dialspoff,p->sp_off_str); makestr(&dialvol1 ,p->vol1_str); makestr(&dialvol2 ,p->vol2_str); makestr(&dialvol3 ,p->vol3_str); makestr(&dialini2 ,p->ini2); } else { /* Not user-defined, so wipe out overrides */ if (dialini) makestr(&dialini,NULL); /* Init-string */ if (dialmstr) makestr(&dialmstr,NULL); /* Dial-mode-str */ if (dialmprmt) makestr(&dialmprmt,NULL); /* Dial-mode-pro */ if (dialcmd) makestr(&dialcmd,NULL); /* Dial-command */ if (dialdcon) makestr(&dialdcon,NULL); /* DC ON command */ if (dialdcoff) makestr(&dialdcoff,NULL); /* DC OFF command */ if (dialecon) makestr(&dialecon,NULL); /* EC ON command */ if (dialecoff) makestr(&dialecoff,NULL); /* EC OFF command */ if (dialhcmd) makestr(&dialhcmd,NULL); /* Hangup command */ if (dialhwfc) makestr(&dialhwfc,NULL); /* Flow control... */ if (dialswfc) makestr(&dialswfc,NULL); /* */ if (dialnofc) makestr(&dialnofc,NULL); /* */ if (dialtone) makestr(&dialtone,NULL); /* Dialing method */ if (dialpulse) makestr(&dialpulse,NULL); /* */ if (dialname) makestr(&dialname,NULL); /* Modem name */ if (dialaaon) makestr(&dialaaon,NULL); /* Autoanswer On */ if (dialaaoff) makestr(&dialaaoff,NULL); /* Autoanswer Off */ if (dialx3) makestr(&dialx3,NULL); /* Ignore dialtone */ if (dialspon) makestr(&dialspon,NULL); /* Speaker On */ if (dialspoff) makestr(&dialspoff,NULL); /* Speaker Off */ if (dialvol1) makestr(&dialvol1,NULL); /* Low volume */ if (dialvol2) makestr(&dialvol2,NULL); /* Medium volume */ if (dialvol3) makestr(&dialvol3,NULL); /* High volume */ if (dialini2) makestr(&dialini2,NULL); /* Init string 2 */ } if (autoflow) /* Maybe change flow control */ setflow(); #ifndef MINIDIAL #ifdef OLDTBCODE tbmodel = 0; /* If it's a Telebit, we don't know the model yet */ #endif /* OLDTBCODE */ #endif /* MINIDIAL */ } #ifdef COMMENT /* Not implemented yet */ int setanswer() { int x, y; extern int ans_cid, ans_ring; if ((x = cmkey(answertab,nanswertab,"","",xxstring)) < 0) return(x); switch (x) { case XYA_CID: return(seton(&ans_cid)); case XYA_RNG: y = cmnum("How many rings before answering","1",10,&x,xxstring); y = setnum(&ans_rings,x,y,254); return(y); } } #endif /* COMMENT */ int setmodem() { /* SET MODEM */ int x, y, z; long zz; struct FDB k1, k2; extern int mdmset; cmfdbi(&k1,_CMKEY, "Modem parameter","","",nsetmdm, 0, xxstring, setmdm, &k2); cmfdbi(&k2,_CMKEY,"","","",nmdm,0,xxstring,mdmtab,NULL); x = cmfdb(&k1); if (x < 0) { /* Error */ if (x == -2 || x == -9) printf("?No keywords match: \"%s\"\n",atmbuf); return(x); } y = cmresult.nresult; /* Keyword value */ if (cmresult.fdbaddr == &k2) { /* Modem-type keyword table */ if ((x = cmcfm()) < 0) return(x); usermdm = 0; initmdm(cmresult.nresult); /* Set the modem type. */ return(success = 1); /* Done */ } switch (cmresult.nresult) { /* SET MODEM keyword table. */ #ifdef MDMHUP case XYDMHU: /* DIAL MODEM-HANGUP */ if ((y = cmkey(mdmhang,4,"how to hang up modem", "modem-command", xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); dialmhu = y; #ifdef COMMENT /* Nope, I fixed it (2001 11 08) */ #ifdef CK_SCOV5 if (dialmhu == 0 && !quiet) { printf( "\n WARNING: RS-232 signal sampling and manipulation do not work\n" ); printf( " in the standard SCO OSR5 serial i/o drivers. SET MODEM HANGUP-METHOD\n" ); printf( " MODEM-COMMAND is recommended for OSR5.\n\n" ); } #endif /* CK_SCOV5 */ #endif /* COMMENT */ return(success = 1); #endif /* MDMHUP */ case XYDCAP: zz = 0L; y = 0; while (y != -3) { if ((y = cmkey(mdmcap,nmdmcap, "capability of modem", "", xxstring)) < 0) { if (y == -3) break; else return(y); } zz |= y; } if ((x = cmcfm()) < 0) return(x); dialcapas = zz; debug(F101,"setmodem autoflow","",autoflow); debug(F101,"setmodem flow 1","",flow); if (autoflow) /* Maybe change flow control */ setflow(); debug(F101,"setmodem flow 2","",flow); mdmspd = zz & CKD_SB ? 0 : 1; /* Set MODEM SPEED-MATCHING from it. */ return(success = 1); case XYDMAX: #ifdef TN_COMPORT if (network && istncomport()) x = cmkey(tnspdtab,ntnspd,line,"",xxstring); else #endif /* TN_COMPORT */ x = cmkey(spdtab,nspd,line,"",xxstring); if (x < 0) { if (x == -3) printf("?value required\n"); return(x); } if ((y = cmcfm()) < 0) return(y); dialmax = (long) x * 10L; if (dialmax == 70) dialmax = 75; return(success = 1); case XYDSTR: /* These moved from SET DIAL */ case XYDDC: case XYDEC: case XYDESC: case XYDFC: case XYDKSP: case XYDSPD: case XYDDIA: return(setdial(x)); case XYDTYP: if ((y = cmkey(mdmtab,nmdm,"modem type","none", xxstring)) < 0) return(y); if (y == dialudt) { /* User-defined modem type */ if ((x = cmkey(mdmtab,nmdm,"based on existing modem type", "unknown", xxstring)) < 0) return(x); } if ((z = cmcfm()) < 0) return(z); usermdm = 0; usermdm = (y == dialudt) ? x : 0; initmdm(y); mdmset = (mdmtyp > 0); return(success = 1); case XYDNAM: return(dialstr(&dialname,"Descriptive name for modem")); case XYDMCD: /* SET MODEM CARRIER-WATCH */ return(setdcd()); case XYDSPK: /* SET MODEM SPEAKER */ return(seton(&mdmspk)); case XYDVOL: /* SET MODEM VOLUME */ if ((x = cmkey(voltab,3,"","medium",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); mdmvol = x; return(success = 1); default: printf("Unexpected SET MODEM parameter\n"); return(-9); } } static int /* Set DIAL command options */ #ifdef CK_ANSIC setdial( int y ) #else setdial(y) int y; #endif /* CK_ANSIC */ { int x = 0, z = 0; char *s = NULL; if (y < 0) if ((y = cmkey(dialtab,ndial,"","",xxstring)) < 0) return(y); switch (y) { case XYDHUP: /* DIAL HANGUP */ return(seton(&dialhng)); case XYDINI: /* DIAL INIT-STRING */ return(dialstr(&dialini,"Modem initialization string")); case XYDNPR: /* DIAL PREFIX */ return(dialstr(&dialnpr,"Telephone number prefix")); case XYDDIA: /* DIAL DIAL-COMMAND */ x = cmtxt("Dialing command for modem,\n\ include \"%s\" to stand for phone number,\n\ for example, \"set dial dial-command ATDT%s\\13\"", "", &s, xxstring); if (x < 0 && x != -3) /* Handle parse errors */ return(x); s = brstrip(s); /* Strip braces or quotes */ y = x = strlen(s); /* Get length of text */ if (y > 0) { /* If there is any text (left), */ for (x = 0; x < y; x++) { /* make sure they included "%s" */ if (s[x] != '%') continue; if (s[x+1] == 's') break; } if (x == y) { printf( "?Dial-command must contain \"%cs\" for phone number.\n",'%'); return(-9); } } if (dialcmd) { /* Free any previous string. */ free(dialcmd); dialcmd = (char *) 0; } if (y > 0) { dialcmd = malloc(y + 1); /* Allocate space for it */ if (dialcmd) strcpy(dialcmd,s); /* and make a safe copy. */ } return(success = 1); #ifndef NOXFER case XYDKSP: /* DIAL KERMIT-SPOOF */ return(seton(&dialksp)); #endif /* NOXFER */ case XYDTMO: /* DIAL TIMEOUT */ y = cmnum("Seconds to wait for call completion","0",10,&x,xxstring); if (y < 0) return(y); y = cmnum("Kermit/modem timeout differential","10",10,&z,xxstring); if (y < 0) return(y); if ((y = cmcfm()) < 0) return(y); dialtmo = x; mdmwaitd = z; case XYDESC: /* DIAL ESCAPE-CHARACTER */ y = cmnum("ASCII value of character to escape back to modem", "43",10,&x,xxstring); y = setnum(&dialesc,x,y,128); if (y > -1 && dialesc < 0) /* No escape character */ dialmhu = 0; /* So no hangup by modem command */ return(y); case XYDDPY: /* DIAL DISPLAY */ return(seton(&dialdpy)); case XYDSPD: /* DIAL SPEED-MATCHING */ /* used to be speed-changing */ if ((y = seton(&mdmspd)) < 0) return(y); #ifdef COMMENT mdmspd = 1 - mdmspd; /* so here we reverse the meaning */ #endif /* COMMENT */ return(success = 1); case XYDMNP: /* DIAL MNP-ENABLE */ case XYDEC: /* DIAL ERROR-CORRECTION */ x = seton(&dialec); if (x > 0) if (!dialec) dialdc = 0; /* OFF also turns off compression */ return(x); case XYDDC: /* DIAL COMPRESSION */ x = seton(&dialdc); if (x > 0) if (dialdc) dialec = 1; /* ON also turns on error correction */ return(x); #ifdef MDMHUP case XYDMHU: /* DIAL MODEM-HANGUP */ return(seton(&dialmhu)); #endif /* MDMHUP */ #ifndef NOSPL case XYDDIR: /* DIAL DIRECTORY (zero or more) */ return(parsdir(0)); /* 0 means DIAL */ #endif /* NOSPL */ case XYDSTR: /* DIAL STRING */ if ((y = cmkey(mdmcmd,nmdmcmd,"","",xxstring)) < 0) return(y); switch (y) { case XYDS_AN: /* Autoanswer ON/OFF */ case XYDS_DC: /* Data compression ON/OFF */ case XYDS_EC: /* Error correction ON/OFF */ if ((x = cmkey(onoff,2,"","on",xxstring)) < 0) return(x); sprintf(tmpbuf,"Modem's command to %sable %s", /* SAFE */ x ? "en" : "dis", (y == XYDS_DC) ? "compression" : ((y == XYDS_EC) ? "error-correction" : "autoanswer") ); if (x) { if (y == XYDS_DC) return(dialstr(&dialdcon,tmpbuf)); else if (y == XYDS_EC) return(dialstr(&dialecon,tmpbuf)); else return(dialstr(&dialaaon,tmpbuf)); } else { if (y == XYDS_DC) return(dialstr(&dialdcoff,tmpbuf)); else if (y == XYDS_EC) return(dialstr(&dialecoff,tmpbuf)); else return(dialstr(&dialaaoff,tmpbuf)); } case XYDS_HU: /* hangup command */ return(dialstr(&dialhcmd,"Modem's hangup command")); case XYDS_HW: /* hwfc */ return(dialstr(&dialhwfc, "Modem's command to enable hardware flow control")); case XYDS_IN: /* init */ return(dialstr(&dialini,"Modem's initialization string")); case XYDS_NF: /* no flow control */ return(dialstr(&dialnofc, "Modem's command to disable local flow control")); case XYDS_PX: /* prefix */ return(dialstr(&dialnpr,"Telephone number prefix for dialing")); case XYDS_SW: /* swfc */ return(dialstr(&dialswfc, "Modem's command to enable local software flow control")); case XYDS_DT: /* tone dialing */ return(dialstr(&dialtone, "Command to configure modem for tone dialing")); case XYDS_DP: /* pulse dialing */ return(dialstr(&dialpulse, "Command to configure modem for pulse dialing")); case XYDS_MS: /* dial mode string */ return(dialstr(&dialmstr, "Command to enter dial mode")); case XYDS_MP: /* dial mode prompt */ return(dialstr(&dialmprmt, "Modem response upon entering dial mode")); case XYDS_SP: /* SPEAKER OFF */ if ((x = cmkey(onoff,2,"","on",xxstring)) < 0) return(x); if (x) return(dialstr(&dialspon,"Command to turn modem speaker on")); else return(dialstr(&dialspoff,"Command to turn modem speaker off")); case XYDS_VO: /* VOLUME LOW */ if ((x = cmkey(voltab,3,"","medium",xxstring)) < 0) return(x); switch (x) { case 0: case 1: return(dialstr(&dialvol1, "Command for low modem speaker volume")); case 2: return(dialstr(&dialvol2, "Command for medium modem speaker volume")); case 3: return(dialstr(&dialvol3, "Command for high modem speaker volume")); default: return(-2); } case XYDS_ID: /* IGNORE-DIALTONE */ return(dialstr(&dialx3, "Command to tell modem to ignore dialtone")); case XYDS_I2: /* PREDIAL-INIT */ return(dialstr(&dialini2, "Command to send to modem just prior to dialing")); default: printf("?Unexpected SET DIAL STRING parameter\n"); } case XYDFC: /* DIAL FLOW-CONTROL */ if ((y = cmkey(dial_fc,4,"","auto",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); dialfc = y; return(success = 1); case XYDMTH: { /* DIAL METHOD */ extern int dialmauto; if ((y = cmkey(dial_m,ndial_m,"","default",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); if (y == XYDM_A) { /* AUTO */ dialmauto = 1; /* local country code, if known. */ dialmth = XYDM_D; } else { dialmauto = 0; /* use the method specified */ dialmth = y; } return(success = 1); } case XYDRTM: y = cmnum("Number of times to try dialing a number", "1",10,&x,xxstring); z = setnum(&dialrtr,x,y,-1); if (z > -1 && dialrtr < 0) { printf("?Sorry, negative dial retries not valid: %d\n",dialrtr); return(-9); } return(z); case XYDINT: y = cmnum("Seconds to wait between redial attempts", "30",10,&x,xxstring); z = setnum(&dialint,x,y,-1); if (z > -1 && dialint < 0) { printf("?Sorry, negative dial interval not valid: %d\n",dialint); return(-9); } return(z); case XYDLAC: /* DIAL AREA-CODE */ if ((x = dialstr(&diallac,"Area code you are calling from")) < 0) return(x); if (diallac) { if (!rdigits(diallac)) { printf("?Sorry, area code must be numeric\n"); if (*diallac == '(') printf("(please omit the parentheses)\n"); if (*diallac == '/') printf("(no slashes, please)\n"); if (diallac) free(diallac); diallac = NULL; return(-9); } } return(x); case XYDCNF: /* CONFIRMATION */ return(success = seton(&dialcnf)); case XYDCVT: /* CONVERT-DIRECTORY */ if ((y = cmkey(dcnvtab,3,"","ask",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); dialcvt = y; return(success = 1); case XYDLCC: /* DIAL COUNTRY-CODE */ x = dialstr(&diallcc,"Country code you are calling from"); if (x < 1) return(x); if (diallcc) { if (!rdigits(diallcc)) { printf("?Sorry, country code must be numeric\n"); if (*diallcc == '+') printf("(please omit the plus sign)\n"); if (diallcc) free(diallcc); diallcc = NULL; return(-9); } if (!strcmp(diallcc,"1")) { /* Set defaults for USA and Canada */ if (!dialldp) /* Long-distance prefix */ makestr(&dialldp,"1"); if (!dialixp) /* International dialing prefix */ makestr(&dialixp,"011"); if (ntollfree == 0) { /* Toll-free area codes */ if ((dialtfc[0] = malloc(4))) { strcpy(dialtfc[0],"800"); /* 1970-something */ ntollfree++; if ((dialtfc[1] = malloc(4))) { strcpy(dialtfc[1],"888"); /* 1996 */ ntollfree++; if ((dialtfc[2] = malloc(4))) { strcpy(dialtfc[2],"877"); /* 5 April 1998 */ ntollfree++; if ((dialtfc[3] = malloc(4))) { strcpy(dialtfc[3],"866"); /* 2000? */ ntollfree++; } } } } } if (!dialtfp) /* Toll-free dialing prefix */ makestr(&dialtfp,"1"); #ifdef COMMENT /* The time for this is past */ } else if (!strcmp(diallcc,"358") && ((int) strcmp(zzndate(),"19961011") > 0) ) { /* Finland */ if (!dialldp) /* Long-distance prefix */ makestr(&dialldp,"9"); if (!dialixp) /* International dialing prefix */ makestr(&dialixp,"990"); #endif /* COMMENT */ } else { /* Everywhere else ... */ if (!dialldp) { if ((dialldp = malloc(4))) strcpy(dialldp,"0"); } if (!dialixp) { if ((dialixp = malloc(4))) strcpy(dialixp,"00"); } } if (!strcmp(diallcc,"33")) /* France */ dialfld = 1; /* Long-distance dialing is forced */ } return(success = 1); case XYDIXP: /* DIAL INTL-PREFIX */ return(dialstr(&dialixp,"International dialing prefix")); case XYDIXS: /* DIAL INTL-SUFFIX */ return(dialstr(&dialixs,"International dialing suffix")); case XYDLDP: /* DIAL LD-PREFIX */ return(dialstr(&dialldp,"Long-distance dialing prefix")); case XYDLDS: /* DIAL LD-SUFFIX */ return(dialstr(&diallds,"Long-distance dialing suffix")); case XYDLCP: /* DIAL LC-PREFIX */ return(dialstr(&diallcp,"Local dialing prefix")); case XYDLCS: /* DIAL LC-SUFFIX */ return(dialstr(&diallcs,"Local dialing suffix")); #ifdef COMMENT case XYDPXX: /* DIAL PBX-EXCHANGE */ return(dialstr(&dialpxx,"Exchange of PBX you are calling from")); #endif /* COMMENT */ case XYDPXI: { /* DIAL PBX-INTERNAL-PREFIX */ #ifdef COMMENT return(dialstr(&dialpxi, "Internal-call prefix of PBX you are calling from")); #else int x; if ((x = cmtxt("Internal-call prefix of PBX you are calling from", "",&s,NULL)) < 0) /* Don't evaluate */ return(x); #ifndef NOSPL if (*s) { char c, * p = tmpbuf; if (*s == '\\') { c = *(s+1); if (isupper(c)) c = tolower(c); if (c != 'f' && ckstrcmp(s,"\\v(d$px)",8,0) && ckstrcmp(s,"\\v(d$pxx)",9,0) && ckstrcmp(s,"\\v(d$p)",7,0)) { x = TMPBUFSIZ; zzstring(s,&p,&x); s = tmpbuf; } } } #endif /* NOSPL */ makestr(&dialpxi,s); return(1); } #endif /* COMMENT */ case XYDPXO: /* DIAL PBX-OUTSIDE-PREFIX */ return(dialstr(&dialpxo, "Outside-line prefix of PBX you are calling from")); case XYDSFX: /* DIAL INTL-SUFFIX */ return(dialstr(&dialsfx," Telephone number suffix for dialing")); case XYDSRT: /* DIAL SORT */ return(success = seton(&dialsrt)); case XYDPXX: /* DIAL PBX-EXCHANGE */ case XYDTFC: { /* DIAL TOLL-FREE-AREA-CODE */ int n, i; /* (zero or more of them...) */ char * p[MAXTOLLFREE]; /* Temporary pointers */ char * m; for (n = 0; n < MAXTOLLFREE; n++) { if (n == 0) { m = (y == XYDTFC) ? "Toll-free area code(s) in the country you are calling from" : "Exchange(s) of PBX you are calling from"; } else { m = (y == XYDTFC) ? "Another toll-free area code" : "Another PBX exchange"; } if ((x = cmfld(m,"",&s,xxstring)) < 0) break; if (s) { int k; k = (int) strlen(s); if (k > 0) { if ((p[n] = malloc(k + 1))) strcpy(p[n], s); /* safe */ } else break; } else break; } if (x == -3) { /* Command was successful */ int m; m = (y == XYDTFC) ? ntollfree : ndialpxx; if ((x = cmcfm()) < 0) return(x); x = 1; for (i = 0; i < m; i++) { /* Remove old list, if any */ if (y == XYDTFC) makestr(&(dialtfc[i]),NULL); else makestr(&(dialpxx[i]),NULL); } if (y == XYDTFC) ntollfree = n; /* New count */ else ndialpxx = n; for (i = 0; i < n; i++) { /* New list */ if (y == XYDTFC) makestr(&(dialtfc[i]),p[i]); else makestr(&(dialpxx[i]),p[i]); } x = 1; } for (i = 0; i < n; i++) if (p[i]) free(p[i]); return(x); } case XYDTFP: /* TOLL-FREE-PREFIX */ return(dialstr(&dialtfp, " Long-distance prefix for toll-free dialing")); case XYDCON: /* CONNECT */ z = -1; if ((y = cmkey(crrtab,ncrr,"","auto",xxstring)) < 0) return(y); if (y != CAR_OFF) /* AUTO or ON? */ if ((z = cmkey(qvtab,nqvt,"","verbose",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); if (z > -1) dialcq = z; dialcon = y; return(success = 1); case XYDRSTR: /* RESTRICT */ if ((y = cmkey(drstrtab,4,"","none",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); dialrstr = y; return(success = 1); case XYDLLAC: { /* Local area-code list */ int n, i; /* (zero or more of them...) */ char * p[MAXLOCALAC]; /* Temporary pointers */ for (n = 0; n < MAXLOCALAC; n++) { if ((x = cmfld( "Area code to which calls from your area are local", "",&s,xxstring)) < 0) break; if (s) { int k; k = (int) strlen(s); if (k > 0) { if ((p[n] = malloc(k + 1))) strcpy(p[n], s); /* safe */ } else break; } else break; } if (x == -3) { /* Command was successful */ if ((x = cmcfm()) < 0) return(x); for (i = 0; i < nlocalac; i++) /* Remove old list, if any */ if (diallcac[i]) { free(diallcac[i]); diallcac[i] = NULL; } nlocalac = n; /* New count */ for (i = 0; i < nlocalac; i++) /* New list */ diallcac[i] = p[i]; return(success = 1); } else { /* Parse error, undo everything */ for (i = 0; i < n; i++) if (p[i]) free(p[i]); return(x); } } case XYDFLD: return(success = seton(&dialfld)); case XYDIDT: /* DIAL IGNORE-DIALTONE */ return(seton(&dialidt)); case XYDPAC: y = cmnum( "Milliseconds to pause between each character sent to dialer", "",10,&x,xxstring); return(setnum(&dialpace,x,y,9999)); #ifndef NOSPL case XYDMAC: if ((x = cmfld("Name of macro to execute just prior to dialing", "",&s,xxstring)) < 0) { if (x == -3) s = NULL; else return(x); } if (s) { if (!*s) { s = NULL; } else { ckstrncpy(line,s,LINBUFSIZ); s = line; } } if ((x = cmcfm()) < 0) return(x); makestr(&dialmac,s); return(success = 1); #endif /* NOSPL */ case XYDPUCC: /* Pulse country codes */ case XYDTOCC: { /* Tone country codes */ int n, i; char * p[MAXTPCC]; char * m; for (n = 0; n < MAXTPCC; n++) { if (n == 0) { m = (y == XYDPUCC) ? "Country code where Pulse dialing is required" : "Country code where Tone dialing is available"; } else m = "Another country code"; if ((x = cmfld(m,"",&s,xxstring)) < 0) break; if (s) { int k; k = (int) strlen(s); if (k > 0) { if ((p[n] = malloc(k + 1))) strcpy(p[n], s); /* safe */ } else break; } else break; } if (x == -3) { /* Command was successful */ int m; m = (y == XYDPUCC) ? ndialpucc : ndialtocc; if ((x = cmcfm()) < 0) return(x); x = 1; for (i = 0; i < m; i++) { /* Remove old list, if any */ if (y == XYDPUCC) makestr(&(dialpucc[i]),NULL); else makestr(&(dialtocc[i]),NULL); } if (y == XYDPUCC) { ndialpucc = n; /* New count */ } else { ndialtocc = n; } for (i = 0; i < n; i++) { /* New list */ if (y == XYDPUCC) { makestr(&(dialpucc[i]),p[i]); } else { makestr(&(dialtocc[i]),p[i]); } } x = 1; } for (i = 0; i < n; i++) if (p[i]) free(p[i]); return(x); } case XYDTEST: return(seton(&dialtest)); default: printf("?Unexpected SET DIAL parameter\n"); return(-9); } } #ifndef NOSHOW int /* SHOW MODEM */ shomodem() { MDMINF * p; int x, n, mdm; char c; long zz; #ifdef IKSD if (inserver) { printf("Sorry, command disabled\r\n"); return(success = 0); } #endif /* IKSD */ shmdmlin(); printf("\n"); mdm = (mdmtyp > 0) ? mdmtyp : mdmsav; p = (mdm > 0) ? modemp[mdm] : NULL; if (p) { printf(" %s\n\n", dialname ? dialname : p->name); printf(" Modem capabilities: "); zz = dialcapas ? dialcapas : p->capas; if (!zz) { printf(" (none)"); } else { if (zz & CKD_AT) printf(" AT"); if (zz & CKD_V25) printf(" ITU"); if (zz & CKD_SB) printf(" SB"); if (zz & CKD_EC) printf(" EC"); if (zz & CKD_DC) printf(" DC"); if (zz & CKD_HW) printf(" HWFC"); if (zz & CKD_SW) printf(" SWFC"); if (zz & CKD_KS) printf(" KS"); if (zz & CKD_TB) printf(" TB"); } printf("\n Modem carrier-watch: "); if (carrier == CAR_OFF) printf("off\n"); else if (carrier == CAR_ON) printf("on\n"); else if (carrier == CAR_AUT) printf("auto\n"); else printf("unknown\n"); printf(" Modem maximum-speed: "); zz = (dialmax > 0L) ? dialmax : p->max_speed; if (zz > 0) printf("%ld bps\n", zz); else printf("(unknown)\n"); printf(" Modem error-correction: %s\n", dialec ? "on" : "off"); printf(" Modem compression: %s\n", dialdc ? "on" : "off"); printf(" Modem speed-matching: %s", mdmspd ? "on" : "off"); printf(" (interface speed %s)\n", mdmspd ? "changes" : "is locked"); printf(" Modem flow-control: "); if (dialfc == FLO_NONE) printf("none\n"); else if (dialfc == FLO_XONX) printf("xon/xoff\n"); else if (dialfc == FLO_RTSC) printf("rts/cts\n"); else if (dialfc == FLO_AUTO) printf("auto\n"); printf(" Modem hangup-method: %s\n", dialmhu ? "modem-command" : "rs232-signal" ); printf(" Modem speaker: %s\n", showoff(mdmspk)); printf(" Modem volume: %s\n", (mdmvol == 2) ? "medium" : ((mdmvol <= 1) ? "low" : "high")); printf(" Modem kermit-spoof: %s\n", dialksp ? "on" : "off"); c = (char) (x = (dialesc ? dialesc : p->esc_char)); printf(" Modem escape-character: %d", x); if (isprint(c)) printf(" (= \"%c\")",c); printf( "\n\nMODEM COMMANDs (* = set automatically by SET MODEM TYPE):\n\n"); debug(F110,"show dialini",dialini,0); printf(" %c Init-string: ", dialini ? ' ' : '*' ); shods(dialini ? dialini : p->wake_str); printf(" %c Dial-mode-string: ", dialmstr ? ' ' : '*' ); shods(dialmstr ? dialmstr : p->dmode_str); n = local ? 19 : 20; if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Dial-mode-prompt: ", dialmprmt ? ' ' : '*' ); shods(dialmprmt ? dialmprmt : p->dmode_prompt); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Dial-command: ", dialcmd ? ' ' : '*' ); shods(dialcmd ? dialcmd : p->dial_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Compression on: ", dialdcon ? ' ' : '*' ); if (!dialdcon) debug(F110,"dialdcon","(null)",0); else debug(F110,"dialdcon",dialdcon,0); shods(dialdcon ? dialdcon : p->dc_on_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Compression off: ", dialdcoff ? ' ' : '*' ); shods(dialdcoff ? dialdcoff : p->dc_off_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Error-correction on: ", dialecon ? ' ' : '*' ); shods(dialecon ? dialecon : p->ec_on_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Error-correction off: ", dialecoff ? ' ' : '*' ); shods(dialecoff ? dialecoff : p->ec_off_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Autoanswer on: ", dialaaon ? ' ' : '*' ); shods(dialaaon ? dialaaon : p->aa_on_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Autoanswer off: ", dialaaoff ? ' ' : '*' ); shods(dialaaoff ? dialaaoff : p->aa_off_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Speaker on: ", dialspon ? ' ' : '*' ); shods(dialspon ? dialspon : p->sp_on_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Speaker off: ", dialspoff ? ' ' : '*' ); shods(dialspoff ? dialspoff : p->sp_off_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Volume low: ", dialvol1 ? ' ' : '*' ); shods(dialvol1 ? dialvol1 : p->vol1_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Volume medium: ", dialvol2 ? ' ' : '*' ); shods(dialvol2 ? dialvol2 : p->vol2_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Volume high: ", dialvol3 ? ' ' : '*' ); shods(dialvol3 ? dialvol3 : p->vol3_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Hangup-command: ", dialhcmd ? ' ' : '*' ); shods(dialhcmd ? dialhcmd : p->hup_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Hardware-flow: ", dialhwfc ? ' ' : '*' ); shods(dialhwfc ? dialhwfc : p->hwfc_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Software-flow: ", dialswfc ? ' ' : '*' ); shods(dialswfc ? dialswfc : p->swfc_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c No-flow-control: ", dialnofc ? ' ' : '*' ); shods(dialnofc ? dialnofc : p->nofc_str); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Pulse: ", dialpulse ? ' ' : '*'); shods(dialpulse ? dialpulse : p->pulse); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Tone: ", dialtone ? ' ' : '*'); shods(dialtone ? dialtone : p->tone); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Ignore-dialtone: ", dialx3 ? ' ' : '*'); shods(dialx3 ? dialx3 : p->ignoredt); if (++n > cmd_rows - 3) {if (!askmore()) { return(0);} else {n = 0;}} printf(" %c Predial-init: ", dialini2 ? ' ' : '*'); shods(dialini2 ? dialini2 : p->ini2); if (++n > cmd_rows - 4) { if (!askmore()) { return(0);} else {n = 0;}} printf("\n For more info: SHOW DIAL and SHOW COMMUNICATIONS\n"); } else if (mdm > 0) { printf("Modem info for \"%s\" not filled in yet\n", gmdmtyp()); } else printf( " No modem selected, so DIAL and most SET MODEM commands have no effect.\n\ Use SET MODEM TYPE to select a modem.\n"); return(success = 1); } #endif /* NOSHOW */ #endif /* NODIAL */ #ifdef CK_TAPI int /* TAPI action commands */ dotapi() { int x,y; char *s; if (!TAPIAvail) { printf("\nTAPI is unavailable on this system.\n"); return(-9); } if ((y = cmkey(tapitab,ntapitab,"MS TAPI command","",xxstring)) < 0) return(y); switch (y) { case XYTAPI_CFG: { /* TAPI CONFIGURE-LINE */ extern struct keytab * tapilinetab; extern struct keytab * _tapilinetab; extern int ntapiline; extern int LineDeviceId; int lineID=LineDeviceId; if (TAPIAvail) cktapiBuildLineTable(&tapilinetab, &_tapilinetab, &ntapiline); if (tapilinetab && _tapilinetab && ntapiline > 0) { int i=0, j = 9999, k = -1; if ( LineDeviceId == -1 ) { /* Find out what the lowest numbered TAPI device is */ /* and use it as the default. */ for (i = 0; i < ntapiline; i++ ) { if (tapilinetab[i].kwval < j) { k = i; } } } else { /* Find the LineDeviceId in the table and use that entry */ for (i = 0; i < ntapiline; i++ ) { if (tapilinetab[i].kwval == LineDeviceId) { k = i; break; } } } if (k >= 0) s = _tapilinetab[k].kwd; else s = ""; if ((y = cmkey(_tapilinetab,ntapiline, "TAPI device name",s,xxstring)) < 0) return(y); lineID = y; } if ((x = cmcfm()) < 0) return(x); #ifdef IKSD if (inserver) { printf("Sorry, command disabled\r\n"); return(success = 0); } #endif /* ISKD */ cktapiConfigureLine(lineID); break; } case XYTAPI_DIAL: /* TAPI DIALING-PROPERTIES */ if ((x = cmcfm()) < 0) return(x); #ifdef IKSD if (inserver) { printf("Sorry, command disabled\r\n"); return(success = 0); } #endif /* ISKD */ cktapiDialingProp(); break; } return(success = 1); } static int /* SET TAPI command options */ settapi() { int x, y; char *s; if (!TAPIAvail) { printf("\nTAPI is unavailable on this system.\n"); return(-9); } if ((y = cmkey(settapitab,nsettapitab,"MS TAPI option","",xxstring)) < 0) return(y); switch (y) { case XYTAPI_USE: return (success = seton(&tapiusecfg)); case XYTAPI_LGHT: return (success = seton(&tapilights)); case XYTAPI_PRE: return (success = seton(&tapipreterm)); case XYTAPI_PST: return (success = seton(&tapipostterm)); case XYTAPI_INA: y = cmnum("seconds of inactivity before auto-disconnect", "0",10,&x,xxstring); return(setnum(&tapiinactivity,x,y,65535)); case XYTAPI_BNG: y = cmnum("seconds to wait for credit card tone", "8",10,&x,xxstring); return(setnum(&tapibong,x,y,90)); case XYTAPI_MAN: return (success = seton(&tapimanual)); case XYTAPI_CON: /* TAPI CONVERSIONS */ return (success = setonaut(&tapiconv)); case XYTAPI_LIN: /* TAPI LINE */ x = setlin(XYTAPI_LIN,1,0); if (x > -1) didsetlin++; return(x); case XYTAPI_PASS: { /* TAPI PASSTHROUGH */ #ifdef NODIAL printf("\n?Modem-dialing not supported\n"); return(-9); #else /* NODIAL */ /* Passthrough became Modem-dialing which is an antonym */ success = seton(&tapipass); tapipass = !tapipass; return (success); #endif /* NODIAL */ } case XYTAPI_LOC: { /* TAPI LOCATION */ extern char tapiloc[]; extern int tapilocid; int k = -1; cktapiBuildLocationTable(&tapiloctab, &ntapiloc); if (!tapiloctab || !ntapiloc) { printf("\nNo TAPI Locations are configured for this system\n"); return(-9); } if (tapilocid == -1) tapilocid = cktapiGetCurrentLocationID(); /* Find the current tapiloc entry */ /* and use it as the default. */ for (k = 0; k < ntapiloc; k++) { if (tapiloctab[k].kwval == tapilocid) break; } if (k >= 0 && k < ntapiloc) s = tapiloctab[k].kwd; else s = ""; if ((y = cmkey(tapiloctab,ntapiloc, "TAPI location",s,xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); #ifdef IKSD if (inserver) { printf("Sorry, command disabled\r\n"); return(success = 0); } #endif /* IKSD */ cktapiFetchLocationInfoByID( y ); #ifndef NODIAL CopyTapiLocationInfoToKermitDialCmd(); #endif /* NODIAL */ } break; } return(success=1); } #endif /* CK_TAPI */ #endif /* NOLOCAL */ #ifndef NOSPL /* Method for evaluating \%x and \&x[] variables */ static struct keytab varevaltab[] = { { "recursive", 1, 0 }, { "simple", 0, 0 } }; static int nvarevaltab = (sizeof(varevaltab) / sizeof(struct keytab)); int setvareval() { int x = 0, y = 0; extern int vareval; #ifdef DCMDBUF extern int * xvarev; #else extern int xvarev[]; #endif /* DCMDBUF */ if ((x = cmkey(varevaltab, nvarevaltab, "Method for evaluating \\%x and \\&x[] variables", "", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); xvarev[cmdlvl] = x; vareval = x; return(success = 1); } #ifdef CK_ANSIC /* SET ALARM */ int setalarm(long xx) #else int setalarm(xx) long xx; #endif /* CK_ANSIC */ /* setalarm */ { #ifdef COMMENT int yyyy, mm, dd, x; char *s; long zz; char buf[6]; #endif /* COMMENT */ long sec, jd; char xbuf[20], * p; debug(F101,"setalarm xx","",xx); ck_alarm = 0L; /* 0 = no alarm (in case of error) */ if (xx < 0L) { printf("%ld - illegal value, must be 0 or positive\n", xx); return(-9); } if (xx == 0L) { /* CLEAR ALARM */ alrm_date[0] = NUL; alrm_time[0] = NUL; return(1); } #ifdef COMMENT x = 8; /* Get current date */ s = alrm_date; if (zzstring("\\v(ndate)",&s,&x) < 0) { printf("Internal date error, sorry.\n"); alrm_date[0] = SP; return(-9); } x = 5; /* Get current time */ s = alrm_time; if (zzstring("\\v(ntime)",&s,&x) < 0) { printf("Internal time error, sorry.\n"); alrm_time[0] = SP; return(-9); } sprintf(buf,"%05ld",atol(alrm_time)); /* SAFE (20) */ ckstrncpy(alrm_time,buf,8); debug(F110,"SET ALARM date (1)",alrm_date,0); debug(F110,"SET ALARM time (1)",alrm_time,0); if ((zz = atol(alrm_time) + xx) < 0L) { printf("Internal time conversion error, sorry.\n"); return(-9); } if (zz >= 86400L) { /* Alarm crosses midnight */ char d[10]; /* Local date buffer */ int lastday; /* Last day of this month */ ckstrncpy(d,alrm_date,8); /* We'll have to change the date */ x = (zz / 86400L); /* How many days after today */ dd = atoi((char *)(d+6)); /* Parse yyyymmdd */ d[6] = NUL; /* into yyyy, mm, dd ... */ mm = atoi((char *)(d+4)); d[4] = NUL; yyyy = atoi((char *)d); /* How many days in this month */ lastday = mdays[mm]; if (mm == 2 && yyyy % 4 == 0) /* Works thru 2099 AD... */ lastday++; if (dd + x > lastday) { /* Dumb loop */ int y; x -= (mdays[mm] - dd); /* Deduct rest of this month's days */ /* There's a more elegant way to do this... */ while (1) { mm++; /* Next month */ if (mm > 12) { /* Wrap around */ mm = 1; /* Jan, next year */ yyyy++; } y = mdays[mm]; /* Days in new month */ if (mm == 2 && yyyy % 4 == 0) /* Feb in leap year */ y++; /* Works until 2100 AD */ if (x - y < 1) break; x -= y; } dd = x; /* Day of alarm month */ } else dd += x; sprintf(alrm_date,"%04d%02d%02d",yyyy,mm,dd); /* SAFE (24) */ zz = zz % 86400L; } sprintf(alrm_time,"%ld",zz); /* SAFE (24) */ debug(F110,"SET ALARM date (2)",alrm_date,0); debug(F110,"SET ALARM time (2)",alrm_time,0); ck_alarm = xx; #else /* Jul 1998 */ ckstrncpy(xbuf,ckcvtdate("",1),20); /* Get current date and time */ p = xbuf; ckstrncpy(alrm_date,xbuf,10); alrm_date[8] = NUL; sec = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15); debug(F110,"SET ALARM date (1)",alrm_date,0); debug(F101,"SET ALARM time (1)","",sec); if ((sec += xx) < 0L) { printf("Internal time conversion error, sorry.\n"); return(-9); } if (sec >= 86400L) { /* Alarm crosses midnight */ long days; days = sec / 86400L; jd = mjd(p) + days; /* Get modified Julian date */ ckstrncpy(alrm_date,mjd2date(jd),10); sec %= 86400L; } sprintf(alrm_time,"%05ld",sec); /* SAFE (24) */ debug(F110,"SET ALARM date (2)",alrm_date,0); debug(F110,"SET ALARM time (2)",alrm_time,0); ck_alarm = 1; /* Alarm is set */ #endif /* COMMENT */ return(success = 1); } #endif /* NOSPL */ #ifndef NOSETKEY int dosetkey() { /* SET KEY */ int x, y; int flag = 0; int kc; /* Key code */ char *s; /* Key binding */ #ifndef NOKVERBS char *p; /* Worker */ #endif /* NOKVERBS */ #ifdef OS2 extern int os2gks; extern int mskkeys; extern int initvik; #endif /* OS2 */ x_ifnum = 1; y = cmnum("numeric key code, or the word CLEAR,","",10,&kc,xxstring); x_ifnum = 0; if (y < 0) { debug(F111,"SET KEY",atmbuf,y); if (y == -2) { /* Not a valid number */ if ((y = strlen(atmbuf)) < 0) /* Check for SET KEY CLEAR */ return(-2); if (ckstrcmp(atmbuf,"clear",y,0)) return(-2); if ((x = cmcfm()) < 0) return(x); for (y = 0; y < KMSIZE; y++) { keymap[y] = (KEY) y; macrotab[y] = NULL; } #ifdef OS2 keymapinit(); /* Special OS/2 initializations */ initvik = 1; /* Update the VIK table */ #endif /* OS2 */ return(1); } else if (y == -3) { /* SET KEY */ printf(" Press key to be defined: "); /* Prompt for a keystroke */ #ifdef UNIX #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ #endif /* UNIX */ conbin((char)escape); /* Put terminal in binary mode */ #ifdef OS2 os2gks = 0; /* Turn off Kverb preprocessing */ #endif /* OS2 */ kc = congks(0); /* Get character or scan code */ #ifdef OS2 os2gks = 1; /* Turn on Kverb preprocessing */ #endif /* OS2 */ concb((char)escape); /* Restore terminal to cbreak mode */ if (kc < 0) { /* Check for error */ printf("?Error reading key\n"); return(0); } #ifdef OS2 shokeycode(kc,-1); /* Show current definition */ #else shokeycode(kc); /* Show current definition */ #endif /* OS2 */ flag = 1; /* Remember it's a multiline command */ } else /* Error */ return(y); } /* Normal SET KEY command... */ #ifdef OS2 if (mskkeys) kc = msktock(kc); #endif /* OS2 */ if (kc < 0 || kc >= KMSIZE) { printf("?key code must be between 0 and %d\n", KMSIZE - 1); return(-9); } if (kc == escape) { printf("Sorry, %d is the CONNECT-mode escape character\n",kc); return(-9); } #ifdef OS2 wideresult = -1; #endif /* OS2 */ if (flag) { cmsavp(psave,PROMPTL); cmsetp(" Enter new definition: "); cmini(ckxech); cmflgs = 0; prompt(NULL); } def_again: if (flag) cmres(); if ((y = cmtxt("key definition,\n\ or Ctrl-C to cancel this command,\n\ or Enter to restore default definition", "",&s,NULL)) < 0) { if (flag) /* Handle parse errors */ goto def_again; else return(y); } s = brstrip(s); #ifndef NOKVERBS p = s; /* Save this place */ #endif /* NOKVERBS */ /* If the definition included any \Kverbs, quote the backslash so the \Kverb will still be in the definition when the key is pressed. We don't do this in zzstring(), because \Kverbs are valid only in this context and nowhere else. We use this code active for all versions that support SET KEY, even if they don't support \Kverbs, because otherwise \K would behave differently for different versions. */ for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */ if ((x > 0) && (s[x] == 'K' || s[x] == 'k') ) { /* Have K */ if ((x == 1 && s[x-1] == CMDQ) || (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) { line[y++] = CMDQ; /* Make it \\K */ } if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) { line[y-1] = CMDQ; /* Have \{K */ line[y++] = '{'; /* Make it \\{K */ } } line[y] = s[x]; } line[y++] = NUL; /* Terminate */ s = line + y + 1; /* Point to after it */ x = LINBUFSIZ - (int) strlen(line) - 1; /* Calculate remaining space */ if ((x < (LINBUFSIZ / 2)) || (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */ printf("?Key definition too long\n"); if (flag) cmsetp(psave); return(-9); } s = line + y + 1; /* Point to result. */ #ifndef NOKVERBS /* Special case: see if the definition starts with a \Kverb. If it does, point to it with p, otherwise set p to NULL. */ p = s; if (*p++ == CMDQ) { if (*p == '{') p++; p = (*p == 'k' || *p == 'K') ? p + 1 : NULL; } #endif /* NOKVERBS */ if (macrotab[kc]) { /* Possibly free old macro from key. */ free((char *)macrotab[kc]); macrotab[kc] = NULL; } switch (strlen(s)) { /* Action depends on length */ case 0: /* Reset to default binding */ keymap[kc] = (KEY) kc; break; case 1: /* Single character */ keymap[kc] = (CHAR) *s; break; default: /* Character string */ #ifndef NOKVERBS if (p) { y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */ debug(F101,"set key kverb lookup",0,y); /* exact match required */ if (y > -1) { keymap[kc] = F_KVERB | y; break; } } #endif /* NOKVERBS */ keymap[kc] = (KEY) kc; macrotab[kc] = (MACRO) malloc(strlen(s)+1); if (macrotab[kc]) strcpy((char *) macrotab[kc], s); /* safe */ break; } if (flag) cmsetp(psave); #ifdef OS2 initvik = 1; /* Update VIK table */ #endif /* OS2 */ return(1); } #endif /* NOSETKEY */ #ifdef STOPBITS struct keytab stoptbl[] = { { "1", 1, 0 }, { "2", 2, 0 } }; #endif /* STOPBITS */ static struct keytab sertbl[] = { { "7E1", 0, 0 }, { "7E2", 1, 0 }, { "7M1", 2, 0 }, { "7M2", 3, 0 }, { "7O1", 4, 0 }, { "7O2", 5, 0 }, { "7S1", 6, 0 }, { "7S2", 7, 0 }, #ifdef HWPARITY { "8E1", 9, 0 }, { "8E2", 10, 0 }, #endif /* HWPARITY */ { "8N1", 8, 0 }, #ifdef HWPARITY { "8N2", 11, 0 }, { "8O1", 12, 0 }, { "8O2", 13, 0 }, #endif /* HWPARITY */ { "", 0, 0 } }; static int nsertbl = (sizeof(sertbl) / sizeof(struct keytab)) - 1; static char * sernam[] = { /* Keep this in sync with sertbl[] */ "7E1", "7E2", "7M1", "7M2", "7O1", "7O2", "7S1", "7S2", "8N1", "8E1", "8E2", "8N2", "8O1", "8O2" }; static struct keytab optstab[] = { /* SET OPTIONS table */ #ifndef NOFRILLS { "delete", XXDEL, 0}, /* DELETE */ #endif /* NOFRILLS */ { "directory", XXDIR, 0}, /* DIRECTORY */ #ifdef CKPURGE { "purge", XXPURGE, 0}, /* PURGE */ #endif /* CKPURGE */ { "type", XXTYP, 0}, /* TYPE */ { "", 0, 0} }; static int noptstab = (sizeof(optstab) / sizeof(struct keytab)) - 1; #ifndef NOXFER /* PROTOCOL SELECTION. Kermit is always available. If CK_XYZ is defined at compile time, then the others become selections also. In OS/2 and Windows, they are integrated and the various SET commands (e.g. "set file type") affect them as they would Kermit. In other OS's (UNIX, VMS, etc), they are external protocols which are run via Kermit's REDIRECT mechanism. All we do is collect and verify the filenames and pass them along to the external protocol. */ struct keytab protos[] = { #ifdef CK_XYZ "g", PROTO_G, CM_INV, #endif /* CK_XYZ */ "kermit", PROTO_K, 0, #ifdef CK_XYZ "other", PROTO_O, 0, "x", PROTO_X, CM_INV|CM_ABR, "xmodem", PROTO_X, 0, "xmodem-crc", PROTO_XC, 0, "y", PROTO_Y, CM_INV|CM_ABR, "ymodem", PROTO_Y, 0, "ymodem-g", PROTO_G, 0, "zmodem", PROTO_Z, 0 #endif /* CK_XYZ */ }; int nprotos = (sizeof(protos) / sizeof(struct keytab)); #ifndef XYZ_INTERNAL #ifndef NOPUSH #define EXP_HANDLER 1 #define EXP_STDERR 2 #define EXP_TIMO 3 static struct keytab extprotab[] = { { "handler", EXP_HANDLER, 0 }, { "redirect-stderr", EXP_STDERR, 0 }, { "timeout", EXP_TIMO, 0 } }; static int nxtprotab = (sizeof(extprotab) / sizeof(struct keytab)); #endif /* NOPUSH */ #endif /* XYZ_INTERNAL */ #define XPCMDLEN 71 _PROTOTYP(static int protofield, (char *, char *, char *)); _PROTOTYP(static int setproto, (void)); static int #ifdef CK_ANSIC protofield(char * current, char * help, char * px ) #else protofield(current, help, px) char * current, * help, * px; #endif /* CK_ANSIC */ { char *s, tmpbuf[XPCMDLEN+1]; int x; if (current) /* Put braces around default */ ckmakmsg(tmpbuf,TMPBUFSIZ,"{",current,"}",NULL); else tmpbuf[0] = NUL; if ((x = cmfld(help, (char *)tmpbuf, &s, xxstring)) < 0) return(x); if ((int)strlen(s) > XPCMDLEN) { printf("?Sorry - maximum length is %d\n", XPCMDLEN); return(-9); } else if (*s) { strcpy(px,s); /* safe */ } else { px = NULL; } return(x); } static int setproto() { /* Select a file transfer protocol */ /* char * s = NULL; */ int x = 0, y; char s1[XPCMDLEN+1], s2[XPCMDLEN+1], s3[XPCMDLEN+1]; char s4[XPCMDLEN+1], s5[XPCMDLEN+1], s6[XPCMDLEN+1], s7[XPCMDLEN+1]; char * p1 = s1, * p2 = s2, *p3 = s3; char * p4 = s4, * p5 = s5, *p6 = s6, *p7 = s7; /* initproto() is prototyped in ckcfnp.h but for some reason when doing a -DNOSPL build we get "warning: implicit declaration of function 'initproto'", referring to an invocation of it in this routine. This extern statement silences the warning. - fdc 6 May 2023 */ #ifdef CK_ANSIC extern VOID initproto( int,char *,char *,char *,char *,char *,char *,char * ); #endif /* CK_ANSIC */ #ifdef XYZ_INTERNAL extern int p_avail; #else #ifndef CK_REDIR x = 1; #endif /* CK_REDIR */ #endif /* XYZ_INTERNAL */ s1[0] = NUL; s2[0] = NUL; s3[0] = NUL; s4[0] = NUL; s5[0] = NUL; s6[0] = NUL; if ((y = cmkey(protos,nprotos,"","kermit",xxstring)) < 0) return(y); if (x && y != PROTO_K) { printf( "?Sorry, REDIRECT capability required for external protocols.\n"); return(-9); } if ((x = protofield(ptab[y].h_b_init, "Optional command to send to host prior to uploading in binary mode", p1)) < 0) { if (x == -3) { /* DavidG 2022-11-29: If the protocol is internal and P is not * available, bail. Otherwise, the user is able to set the protocol * to xmodem (which won't work) and receives an error if they try * to change it back to kermit. * * I have no idea *why* we don't just jump to protoexit in this case * like all the others which is why the existing behaviour is being * left as-is for now. * */ #ifdef XYZ_INTERNAL if (!p_avail) { bleep(BP_WARN); printf("\n?X,Y, and Zmodem are unavailable\n"); return(success = 0); } #endif /* XYZ_INTERNAL */ protocol = y; /* Set protocol but don't change */ return(1); /* anything else */ } else return(x); } if ((x = protofield(ptab[y].h_t_init, "Optional command to send to host prior to uploading in text mode", p2)) < 0) { if (x == -3) goto protoexit; else return(x); } if (y == PROTO_K) { if ((x = protofield(ptab[y].h_x_init, "Optional command to send to host to start Kermit server", p3)) < 0) { if (x == -3) goto protoexit; else return(x); } } #ifndef XYZ_INTERNAL /* If XYZMODEM are external... */ if (y != PROTO_K) { if ((x = protofield(ptab[y].p_b_scmd, "External command to SEND in BINARY mode with this protocol", p4)) < 0) { if (x == -3) goto protoexit; else return(x); } if ((x = protofield(ptab[y].p_t_scmd, "External command to SEND in TEXT mode with this protocol", p5)) < 0) { if (x == -3) goto protoexit; else return(x); } if ((x = protofield(ptab[y].p_b_rcmd, "External command to RECEIVE in BINARY mode with this protocol", p6)) < 0) { if (x == -3) goto protoexit; else return(x); } if ((x = protofield(ptab[y].p_t_rcmd, "External command to RECEIVE in TEXT mode with this protocol", p7)) < 0) { if (x == -3) goto protoexit; else return(x); } } #endif /* XYZ_INTERNAL */ if ((x = cmcfm()) < 0) /* Confirm the command */ return(x); protoexit: /* Common exit from this routine */ #ifdef XYZ_INTERNAL if (!p_avail) { bleep(BP_WARN); printf("\n?X,Y, and Zmodem are unavailable\n"); return(success = 0); } #endif /* XYZ_INTERNAL */ p1 = brstrip(p1); p2 = brstrip(p2); p3 = brstrip(p3); p4 = brstrip(p4); p5 = brstrip(p5); p6 = brstrip(p6); p7 = brstrip(p7); initproto(y,p1,p2,p3,p4,p5,p6,p7); return(success = 1); } #ifndef NOPUSH #ifndef XYZ_INTERNAL #define DEF_EXP_TIMO 12 /* Default timeout for external protocol (seconds) */ int exp_handler = 0; /* These are exported */ int exp_timo = DEF_EXP_TIMO; int exp_stderr = SET_AUTO; VOID shoextern() { /* Invoked by SHOW PROTOCOL */ printf("\n External-protocol handler: %s\n", exp_handler ? (exp_handler == 1 ? "pty" : "system") : "automatic"); #ifdef COMMENT printf(" External-protocol redirect-stderr: %s\n", showooa(exp_stderr)); #endif /* COMMENT */ printf(" External-protocol timeout: %d (sec)\n", exp_timo); } static struct keytab setexternhandler[] = { { "automatic", 0, 0 }, { "pty", 1, 0 }, { "system", 2, 0 } }; int setextern() { /* SET EXTERNAL-PROTOCOL */ int x, y; if ((x = cmkey(extprotab,nxtprotab,"","",xxstring)) < 0) return(x); switch (x) { case EXP_HANDLER: if ((x = cmkey(setexternhandler,3,"","automatic",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); exp_handler = x; break; #ifdef COMMENT case EXP_STDERR: if ((x = cmkey(ooatab,3,"","automatic",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); exp_stderr = x; break; #endif /* COMMENT */ case EXP_TIMO: y = cmnum("Inactivity timeout, seconds,",ckitoa(DEF_EXP_TIMO), 10,&x,xxstring); return(setnum(&exp_timo,x,y,-1)); } return(success = 1); } #endif /* XYZ_INTERNAL */ #endif /* NOPUSH */ int setdest() { int x, y; if ((y = cmkey(desttab,ndests,"","disk",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); dest = y; return(1); } #endif /* NOXFER */ #ifdef DECNET struct keytab dnettab[] = { #ifndef OS2ONLY "cterm", NP_CTERM, 0, #endif /* OS2ONLY */ "lat", NP_LAT, 0 }; int ndnet = (sizeof(dnettab) / sizeof(struct keytab)); #endif /* DECNET */ /* S E T P R I N T E R -- SET PRINTER command */ #ifdef PRINTSWI static struct keytab prntab[] = { /* SET PRINTER switches */ "/bidirectional", PRN_BID, 0, #ifdef OS2 "/character-set", PRN_CS, CM_ARG, #endif /* OS2 */ "/command", PRN_PIP, CM_ARG, "/dos-device", PRN_DOS, CM_ARG, "/end-of-job-string",PRN_TRM, CM_ARG, "/file", PRN_FIL, CM_ARG, #ifdef BPRINT "/flow-control", PRN_FLO, CM_ARG, #endif /* BPRINT */ "/job-header-file", PRN_SEP, CM_ARG, #ifdef OS2 "/length", PRN_LEN, CM_ARG, #endif /* OS2 */ "/none", PRN_NON, 0, #ifdef OS2 "/nopostscript", PRN_RAW, 0, "/nops", PRN_RAW, CM_INV, #endif /* OS2 */ "/output-only", PRN_OUT, 0, #ifdef BPRINT "/parity", PRN_PAR, CM_ARG, #endif /* BPRINT */ "/pipe", PRN_PIP, CM_ARG|CM_INV, #ifdef OS2 "/postscript", PRN_PS, 0, "/ps", PRN_PS, CM_INV, #endif /* OS2 */ "/separator", PRN_SEP, CM_ARG|CM_INV, #ifdef BPRINT "/speed", PRN_SPD, CM_ARG, #endif /* BPRINT */ "/timeout", PRN_TMO, CM_ARG, "/terminator", PRN_TRM, CM_ARG|CM_INV, #ifdef OS2 #ifdef NT "/w", PRN_WIN, CM_ARG|CM_ABR|CM_INV, "/wi", PRN_WIN, CM_ARG|CM_ABR|CM_INV, #endif /* NT */ "/width", PRN_WID, CM_ARG, #endif /* OS2 */ #ifdef NT "/windows-queue", PRN_WIN, CM_ARG, #endif /* NT */ "", 0, 0 }; int nprnswi = (sizeof(prntab) / sizeof(struct keytab)) - 1; #endif /* PRINTSWI */ static int #ifdef CK_ANSIC setprinter( int xx ) #else setprinter(xx) int xx; #endif /* CK_ANSIC */ { int x, y; char * s; char * defname = NULL; #ifdef OS2 extern int prncs; #endif /* OS2 */ #ifdef BPRINT long portspeed = 0L; int portparity = 0; int portflow = 0; #endif /* BPRINT */ #ifdef PRINTSWI int c, i, n, wild; /* Workers */ int getval = 0; /* Whether to get switch value */ struct stringint pv[PRN_MAX+1]; /* Temporary array for switch values */ struct FDB sw, of, cm; /* FDBs for each parse function */ int haveque = 0; int typeset = 0; #endif /* PRINTSWI */ #ifdef NT struct keytab * printtab = NULL, * _printtab = NULL; int nprint = 0, printdef=0; #endif /* NT */ #ifdef OS2 defname = "PRN"; /* default */ #else #ifdef VMS defname = "LPT:"; #else #ifdef UNIX defname = "|lpr"; #endif /* UNIX */ #endif /* VMS */ #endif /* OS2 */ #ifdef PRINTSWI #ifdef NT haveque = Win32EnumPrt(&printtab,&_printtab,&nprint,&printdef); haveque = haveque && nprint; #endif /* NT */ for (i = 0; i <= PRN_MAX; i++) { /* Initialize switch values */ pv[i].sval = NULL; /* to null pointers */ pv[i].ival = -1; /* and -1 int values */ pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */ } if (xx == XYBDCP) { /* SET BPRINTER == /BIDIRECTIONAL */ pv[PRN_BID].ival = 1; pv[PRN_OUT].ival = 0; } /* Initialize defaults based upon current printer settings */ if (printername) { defname = printername; switch (printertype) { case PRT_WIN: pv[PRN_WIN].ival = 1; break; case PRT_DOS: pv[PRN_DOS].ival = 1; break; case PRT_PIP: pv[PRN_PIP].ival = 1; break; case PRT_FIL: pv[PRN_FIL].ival = 1; break; case PRT_NON: pv[PRN_NON].ival = 1; break; } } #ifdef BPRINT /* only set the BIDI flag if we are bidi */ if (printbidi) pv[PRN_BID].ival = 1; /* serial port parameters may be set for non-bidi devices */ pv[PRN_SPD].ival = pportspeed / 10L; pv[PRN_PAR].ival = pportparity; pv[PRN_FLO].ival = pportflow; #endif /* BPRINT */ if (printtimo) pv[PRN_TMO].ival = printtimo; if (printterm) { pv[PRN_TRM].ival = 1; makestr(&pv[PRN_TRM].sval,printterm); } if (printsep) { pv[PRN_SEP].ival = 1; makestr(&pv[PRN_SEP].sval,printsep); } if (txt2ps) { pv[PRN_PS].ival = 1; pv[PRN_WID].ival = ps_width; pv[PRN_LEN].ival = ps_length; } else { pv[PRN_RAW].ival = 1; } /* Set up chained parse functions... */ cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nprnswi, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ prntab, /* Keyword table */ &cm /* Pointer to next FDB */ ); cmfdbi(&cm, /* Second fdb for confirmation */ _CMCFM, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, NULL, &of ); cmfdbi(&of, /* Third FDB for printer name */ _CMOFI, /* fcode */ "Printer or file name", /* hlpmsg */ defname, /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ NULL, /* Nothing */ NULL ); while (1) { /* Parse 0 or more switches */ x = cmfdb(&sw); /* Parse switch or other thing */ debug(F101,"setprinter cmfdb","",x); if (x < 0) /* Error */ goto xsetprn; /* or reparse needed */ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */ break; if (cmresult.fdbaddr != &sw) /* Advanced usage :-) */ break; c = cmgbrk(); /* Get break character */ getval = (c == ':' || c == '='); /* to see how they ended the switch */ n = cmresult.nresult; /* Numeric result = switch value */ debug(F101,"setprinter switch","",n); switch (n) { /* Process the switch */ case PRN_PS: /* Text to Postscript */ pv[PRN_PS].ival = 1; pv[PRN_BID].ival = 0; pv[PRN_OUT].ival = 1; pv[PRN_RAW].ival = 0; break; case PRN_RAW: /* Non-Postscript */ pv[PRN_PS].ival = 0; pv[PRN_RAW].ival = 1; break; case PRN_BID: /* Bidirectional */ pv[PRN_BID].ival = 1; pv[PRN_OUT].ival = 0; pv[PRN_PS].ival = 0; pv[PRN_RAW].ival = 1; break; case PRN_OUT: /* Output-only */ pv[PRN_OUT].ival = 1; pv[PRN_BID].ival = 0; pv[PRN_PS].ival = 0; pv[PRN_RAW].ival = 1; break; case PRN_NON: /* NONE */ typeset++; pv[n].ival = 1; pv[PRN_SPD].ival = 0; pv[PRN_PAR].ival = 0; pv[PRN_FLO].ival = FLO_KEEP; break; #ifdef UNIX case PRN_WIN: #endif /* UNIX */ case PRN_DOS: /* DOS printer name */ case PRN_FIL: /* Or filename */ case PRN_PIP: typeset++; if (pv[n].sval) free(pv[n].sval); pv[n].sval = NULL; pv[PRN_NON].ival = 0; /* Zero any previous selections */ pv[PRN_WIN].ival = 0; pv[PRN_DOS].ival = 0; pv[PRN_FIL].ival = 0; pv[PRN_PIP].ival = 0; pv[n].ival = 1; /* Flag this one */ if (!getval) break; /* No value wanted */ if (n == PRN_FIL) { /* File, check accessibility */ int wild = 0; if ((x = cmiofi("Filename","kermit.prn",&s,&wild,xxstring))< 0) if (x == -9) { if (zchko(s) < 0) { printf("Can't create \"%s\"\n",s); return(x); } } else goto xsetprn; if (iswild(s)) { printf("?A single file please\n"); return(-9); } pv[PRN_SPD].ival = 0; pv[PRN_PAR].ival = 0; pv[PRN_FLO].ival = FLO_KEEP; } else if ((x = cmfld(n == PRN_DOS ? /* Value wanted - parse it */ "DOS printer device name" : /* Help message */ (n == PRN_PIP ? "Program name" : "Filename"), n == PRN_DOS ? "PRN" : /* Default */ "", &s, xxstring )) < 0) goto xsetprn; s = brstrip(s); /* Strip enclosing braces */ while (*s == SP) /* Strip leading blanks */ s++; if (n == PRN_PIP) { /* If /PIPE: */ if (*s == '|') { /* strip any extraneous pipe sign */ s++; while (*s == SP) s++; } pv[PRN_SPD].ival = 0; pv[PRN_PAR].ival = 0; pv[PRN_FLO].ival = FLO_KEEP; } if ((y = strlen(s)) > 0) /* Anything left? */ if (pv[n].sval = (char *) malloc(y+1)) /* Yes, keep it */ strcpy(pv[n].sval,s); /* safe */ break; #ifdef NT case PRN_WIN: /* Windows queue name */ typeset++; if (pv[n].sval) free(pv[n].sval); pv[n].sval = NULL; pv[PRN_NON].ival = 0; pv[PRN_DOS].ival = 0; pv[PRN_FIL].ival = 0; pv[n].ival = 1; pv[PRN_SPD].ival = 0; pv[PRN_PAR].ival = 0; pv[PRN_FLO].ival = FLO_KEEP; if (!getval || !haveque) break; if ((x = cmkey(_printtab,nprint,"Print queue name", _printtab[printdef].kwd,xxstring)) < 0) { if (x != -2) goto xsetprn; if (pv[PRN_WIN].sval) free(pv[PRN_WIN].sval); s = atmbuf; if ((y = strlen(s)) > 0) if (pv[n].sval = (char *)malloc(y+1)) strcpy(pv[n].sval,s); /* safe */ } else { if (pv[PRN_WIN].sval) free(pv[PRN_WIN].sval); for (i = 0; i < nprint; i++) { if (x == printtab[i].kwval) { s = printtab[i].kwd; break; } } if ((y = strlen(s)) > 0) if (pv[n].sval = (char *)malloc(y+1)) strcpy(pv[n].sval,s); /* safe */ } break; #endif /* NT */ case PRN_SEP: /* /JOB-HEADER (separator) */ if (pv[n].sval) free(pv[n].sval); pv[n].sval = NULL; pv[n].ival = 1; if (!getval) break; if ((x = cmifi("Filename","",&s,&y,xxstring)) < 0) goto xsetprn; if (y) { printf("?Wildcards not allowed\n"); x = -9; goto xsetprn; } if ((y = strlen(s)) > 0) if (pv[n].sval = (char *) malloc(y+1)) strcpy(pv[n].sval,s); /* safe */ break; case PRN_TMO: /* /TIMEOUT:number */ pv[n].ival = 0; if (!getval) break; if ((x = cmnum("Seconds","0",10,&y,xxstring)) < 0) goto xsetprn; if (y > 999) { printf("?Sorry - 999 is the maximum\n"); x = -9; goto xsetprn; } else pv[n].ival = y; break; case PRN_TRM: /* /END-OF-JOB:string */ if (pv[n].sval) free(pv[n].sval); pv[n].sval = NULL; pv[n].ival = 1; if (!getval) break; if ((x = cmfld("String (enclose in braces if it contains spaces)", "",&s,xxstring)) < 0) goto xsetprn; s = brstrip(s); if ((y = strlen(s)) > 0) if (pv[n].sval = (char *) malloc(y+1)) strcpy(pv[n].sval,s); /* safe */ break; #ifdef BPRINT case PRN_FLO: if (!getval) break; if ((x = cmkey(flotab,nflo, "Serial printer-port flow control", "rts/cts",xxstring)) < 0) goto xsetprn; pv[n].ival = x; break; #ifndef NOLOCAL case PRN_SPD: if (!getval) break; /* TN_COMPORT here too? */ if ((x = cmkey(spdtab, /* Speed (no default) */ nspd, "Serial printer-port interface speed", "9600", xxstring) ) < 0) goto xsetprn; pv[n].ival = x; break; #endif /* NOLOCAL */ case PRN_PAR: pv[n].ival = 0; if (!getval) break; if ((x = cmkey(partbl,npar,"Serial printer-port parity", "none",xxstring)) < 0) goto xsetprn; pv[n].ival = x; break; #endif /* BPRINT */ #ifdef OS2 case PRN_LEN: if (!getval) break; if ((x = cmnum("PS page length", "66",10,&y,xxstring)) < 0) goto xsetprn; pv[n].ival = y; break; case PRN_WID: if (!getval) break; if ((x = cmnum("PS page width", "80",10,&y,xxstring)) < 0) goto xsetprn; pv[n].ival = y; break; case PRN_CS: pv[n].ival = 0; if (!getval) break; if ((y = cmkey( #ifdef CKOUNI txrtab,ntxrtab, #else /* CKOUNI */ ttcstab,ntermc, #endif /* CKOUNI */ "auto-print/printscreen character-set", "cp437",xxstring)) < 0) goto xsetprn; pv[n].ival = y; break; #endif /* OS2 */ default: printf("?Unexpected switch value - %d\n",cmresult.nresult); x = -9; goto xsetprn; } } line[0] = NUL; /* Initialize printer name value */ switch (cmresult.fcode) { /* How did we get here? */ case _CMOFI: /* They typed a filename */ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Name */ wild = cmresult.nresult; /* Wild flag */ if (!typeset) { /* A printer name without a type */ pv[PRN_NON].ival = 0; /* is supposed to be treated as */ pv[PRN_WIN].ival = 0; /* a DOS or Pipe printer. We */ pv[PRN_FIL].ival = 0; /* clear all the flags and let */ pv[PRN_PIP].ival = 0; /* the code below dope out the */ pv[PRN_DOS].ival = 0; /* type. */ } #ifdef NT else if (pv[PRN_WIN].ival && lookup(_printtab,line,nprint,&y)) { /* invalid Window Queue name */ printf("?invalid Windows Printer Queue name: \"%s\"\r\n",line); x = -9; goto xsetprn; } #endif /* NT */ if ((x = cmcfm()) < 0) /* Confirm the command */ goto xsetprn; break; case _CMCFM: /* They entered the command */ if (pv[PRN_DOS].ival > 0) ckstrncpy(line,pv[PRN_DOS].sval ? pv[PRN_DOS].sval : "",LINBUFSIZ); else if (pv[PRN_WIN].ival > 0) ckstrncpy(line,pv[PRN_WIN].sval ? pv[PRN_WIN].sval : "",LINBUFSIZ); else if (pv[PRN_FIL].ival > 0) ckstrncpy(line,pv[PRN_FIL].sval ? pv[PRN_FIL].sval : "",LINBUFSIZ); else if (pv[PRN_PIP].ival > 0) ckstrncpy(line,pv[PRN_PIP].sval ? pv[PRN_PIP].sval : "",LINBUFSIZ); break; default: /* By mistake */ printf("?Unexpected function code: %d\n",cmresult.fcode); x = -9; goto xsetprn; } #else /* No PRINTSWI */ if ((x = cmofi("Printer or file name",defname,&s,xxstring)) < 0) return(x); if (x > 1) { printf("?Directory names not allowed\n"); return(-9); } while (*s == SP || *s == HT) s++; /* Trim leading whitespace */ ckstrncpy(line,s,LINBUFSIZ); /* Make a temporary safe copy */ if ((x = cmcfm()) < 0) return(x); /* Confirm the command */ #endif /* PRINTSWI */ #ifdef IKSD if (inserver && (isguest #ifndef NOSERVER || !ENABLED(en_pri) #endif /* NOSERVER */ )) { printf("Sorry, printing disabled\r\n"); return(success = 0); } #endif /* ISKD */ #ifdef PRINTSWI #ifdef BPRINT if (printbidi) { /* If bidi printing active */ #ifndef UNIX bprtstop(); /* Stop it before proceeding */ #endif /* UNIX */ printbidi = 0; } if (pv[PRN_SPD].ival > 0) { portspeed = (long) pv[PRN_SPD].ival * 10L; if (portspeed == 70L) portspeed = 75L; } if (pv[PRN_PAR].ival > 0) portparity = pv[PRN_PAR].ival; if (pv[PRN_FLO].ival > 0) portflow = pv[PRN_FLO].ival; #endif /* BPRINT */ #endif /* PRINTSWI */ s = line; /* Printer name, if given */ #ifdef OS2ORUNIX #ifdef PRINTSWI if (pv[PRN_PIP].ival > 0) { /* /PIPE was given? */ printpipe = 1; noprinter = 0; if (*s == '|') { /* It might still have a pipe sign */ s++; /* if name give later */ while (*s == SP) /* so remove it and spaces */ s++; } } else #endif /* PRINTSWI */ if (*s == '|') { /* Or pipe implied by name? */ s++; /* Point past pipe sign */ while (*s == SP) /* Gobble whitespace */ s++; if (*s) { printpipe = 1; noprinter = 0; } } else { printpipe = 0; } #ifdef PRINTSWI #ifdef BPRINT if (printpipe && pv[PRN_BID].ival > 0) { printf("?Sorry, pipes not allowed for bidirectional printer\n"); return(-9); } #endif /* BPRINT */ #endif /* PRINTSWI */ #endif /* OS2ORUNIX */ #ifdef OS2 if ( pv[PRN_CS].ival > 0 ) prncs = pv[PRN_CS].ival; if ( pv[PRN_PS].ival > 0 ) { txt2ps = 1; ps_width = pv[PRN_WID].ival <= 0 ? 80 : pv[PRN_WID].ival; ps_length = pv[PRN_LEN].ival <= 0 ? 66 : pv[PRN_LEN].ival; } #endif /* OS2 */ y = strlen(s); /* Length of name of new print file */ if (y > 0 #ifdef OS2 && ((y != 3) || (ckstrcmp(s,"PRN",3,0) != 0)) #endif /* OS2 */ ) { if (printername) { /* Had a print file before? */ free(printername); /* Remove its name */ printername = NULL; } printername = (char *) malloc(y + 1); /* Allocate space for it */ if (!printername) { printf("?Memory allocation failure\n"); return(-9); } strcpy(printername,s); /* (safe) Copy new name to new space */ debug(F110,"printername",printername,0); } #ifdef PRINTSWI /* Set printer type from switches that were given explicitly */ if (pv[PRN_NON].ival > 0) { /* No printer */ printertype = PRT_NON; noprinter = 1; printpipe = 0; } else if (pv[PRN_FIL].ival > 0) { /* File */ printertype = PRT_FIL; noprinter = 0; printpipe = 0; } else if (pv[PRN_PIP].ival > 0) { /* Pipe */ printertype = PRT_PIP; noprinter = 0; printpipe = 1; } else if (pv[PRN_WIN].ival > 0) { /* Windows print queue */ printertype = PRT_WIN; noprinter = 0; printpipe = 0; } else if (pv[PRN_DOS].ival > 0) { /* DOS device */ printertype = PRT_DOS; noprinter = 0; printpipe = 0; } else if (line[0]) { /* Name given without switches */ noprinter = 0; printertype = printpipe ? PRT_PIP : PRT_DOS; #ifdef NT /* was the command SET PRINTER windows-queue ? */ y = lookup(_printtab,line,nprint,&x); if (y >= 0) { printertype = PRT_WIN; if (pv[PRN_WIN].sval) free(pv[PRN_WIN].sval); if (printername) { /* Had a print file before? */ free(printername); /* Remove its name */ printername = NULL; } pv[PRN_WIN].sval = NULL; pv[PRN_WIN].ival = 1; s = printtab[x].kwd; /* Get full new name */ if ((y = strlen(s)) > 0) { makestr(&pv[PRN_WIN].sval,s); makestr(&printername,s); if (!printername) { printf("?Memory allocation failure\n"); return(-9); } debug(F110,"printername",printername,0); } } else if ( y == -2 ) { /* Ambiguous Print Queue Name */ printf("?Ambiguous printer name provided.\n"); return(-9); } #endif /* NT */ } #ifdef BPRINT /* Port parameters may be set for non-bidi mode */ pportspeed = portspeed; /* Set parameters */ pportparity = portparity; pportflow = portflow; if (pv[PRN_BID].ival > 0) { /* Bidirectional */ #ifdef UNIX printbidi = 1; /* (just to test parsing...) */ #else printbidi = bprtstart(); /* Start bidirectional printer */ #endif /* UNIX */ return(success = printbidi); } else printbidi = 0; /* Not BPRINTER, unset flag */ #endif /* BPRINT */ if (pv[PRN_TMO].ival > -1) { /* Take care of timeout */ printtimo = pv[PRN_TMO].ival; } if (pv[PRN_TRM].ival > 0) { /* Termination string */ if (printterm) { free(printterm); printterm = NULL; } if (pv[PRN_TRM].sval) makestr(&printterm,pv[PRN_TRM].sval); } if (pv[PRN_SEP].ival > 0) { /* and separator file */ if (printsep) { free(printsep); printsep = NULL; } if (pv[PRN_SEP].sval) makestr(&printsep,pv[PRN_SEP].sval); } #endif /* PRINTSWI */ #ifdef UNIXOROSK if (!printpipe #ifdef PRINTSWI && !noprinter #endif /* PRINTSWI */ ) { /* File - check access */ if (zchko(s) < 0) { printf("?Access denied - %s\n",s); x = -9; goto xsetprn; } } #endif /* UNIXOROSK */ x = 1; /* Return code */ xsetprn: /* Common exit */ #ifdef PRINTSWI for (i = 0; i <= PRN_MAX; i++) { /* Free malloc'd memory */ if (pv[i].sval) free(pv[i].sval); } #endif /* PRINTSWI */ success = (x > 0) ? 1 : 0; return(x); } #ifdef ANYSSH /* The SET SSH command */ #define SSH_CMD 1 /* SET SSH COMMAND */ #ifdef SSHBUILTIN /* Built-in SET SSH options */ #define SSH_ADD 2 /* Add */ #define SSH_AFW 3 /* Agent-forwarding */ #define SSH_CHI 4 /* Check Host IP */ #define SSH_XFW 5 /* X11-forwarding */ #define SSH_DYF 6 /* Dynamic forwarding */ #define SSH_GWP 7 /* Gatewa portgs */ #define SSH_GSS 8 /* GSSAPI */ #define SSH_KBD 9 /* KBD Interactive Devices */ #define SSH_K4 10 /* Kerberos 4 */ #define SSH_K5 11 /* Kerberos 5 */ #define SSH_SHK 12 /* Strict Host Key Check */ #define SSH_V1 13 /* SSH V1 */ #define SSH_V2 14 /* SSH V2 */ #define SSH_PRP 15 /* Privd port */ #define SSH_CMP 16 /* Compression */ #define SSH_XAL 17 /* X Auth Location */ #define SSH_SHH 18 /* Quiet */ #define SSH_VER 19 /* Version */ #define SSH_VRB 20 /* Verbosity level */ #define SSH_IDF 21 /* Identity File */ #define SSH_CFG 22 /* Use OpenSSH Config */ #define SSH_HBT 23 /* Heartbeat Interval */ #define SSH_PXC 24 /* Proxy Command */ #define SSH_DIR 25 /* SSH Directory */ #define SSH_AGL 26 /* SSH Agent Location */ #endif /* SSHBUILTIN */ static struct keytab sshtab[] = { /* SET SSH command table */ #ifdef SSHBUILTIN { "agent-forwarding", SSH_AFW, 0 }, /* SSH_FEAT_AGENT_FWD */ { "agent-location", SSH_AGL, 0 }, /* SSH_FEAT_AGENT_LOC */ { "check-host-ip", SSH_CHI, 0 }, { "compression", SSH_CMP, 0 }, { "directory", SSH_DIR, 0 }, { "dynamic-forwarding", SSH_DYF, 0 }, /* SSH_FEAT_PORT_FWD */ { "gateway-ports", SSH_GWP, 0 }, /* SSH_FEAT_PORT_FWD */ { "gssapi", SSH_GSS, 0 }, /* SSH_FEAT_ADV_GSSAPI */ { "heartbeat-interval", SSH_HBT, 0 }, { "identity-file", SSH_IDF, 0 }, #ifdef COMMENT { "kbd-interactive-devices", SSH_KBD, 0 }, #endif /* COMMENT */ { "k4", SSH_K4, CM_INV }, /* SSH_FEAT_ADV_KERBEROS4 */ { "k5", SSH_K5, CM_INV }, /* SSH_FEAT_ADV_KERBEROS5 */ { "kerberos4", SSH_K4, 0 }, /* SSH_FEAT_ADV_KERBEROS4 */ { "kerberos5", SSH_K5, 0 }, /* SSH_FEAT_ADV_KERBEROS5 */ { "krb4", SSH_K4, CM_INV }, /* SSH_FEAT_ADV_KERBEROS4 */ { "krb5", SSH_K5, CM_INV }, /* SSH_FEAT_ADV_KERBEROS5 */ { "privileged-port", SSH_PRP, 0 }, /* SSH_FEAT_FROM_PRIV_PRT */ { "proxy-command", SSH_PXC, 0 }, /* SSH_FEAT_PROXY_CMD */ { "quiet", SSH_SHH, 0 }, { "strict-host-key-check", SSH_SHK, 0 }, { "use-openssh-config", SSH_CFG, 0 }, /* SSH_FEAT_OPENSSH_CONF */ { "v1", SSH_V1, 0 }, /* SSH_FEAT_SSH_V1 */ { "v2", SSH_V2, 0 }, { "verbose", SSH_VRB, 0 }, { "version", SSH_VER, 0 }, /* SSH_FEAT_SSH_V1 */ { "x11-forwarding", SSH_XFW, 0 }, /* SSH_FEAT_X11_FWD */ { "xauth-location", SSH_XAL, 0 }, /* SSH_FEAT_X11_XAUTH */ #else #ifdef SSHCMD { "command", SSH_CMD, 0 }, #endif /* SSHCMD */ #endif /* SSHBUILTIN */ { "", 0, 0 } }; static int nsshtab = (sizeof(sshtab) / sizeof(struct keytab)) - 1; #ifdef SSHBUILTIN static struct keytab sshver[] = { /* SET SSH VERSION command table */ { "1", 1, 0 }, { "2", 2, 0 }, { "automatic", 0, 0 } }; #define SSHF_LCL 1 #define SSHF_RMT 2 static struct keytab addfwd[] = { /* SET SSH ADD command table */ { "local-port-forward", SSHF_LCL, 0 }, { "remote-port-forward", SSHF_RMT, 0 }, { "", 0, 0 } }; static int naddfwd = (sizeof(addfwd) / sizeof(struct keytab)) - 1; #define SSH1_CIF 1 #define SSH1_GNH 2 #define SSH1_UNH 3 #define SSH1_K54 4 #define SSH2_CIF 1 #define SSH2_GNH 2 #define SSH2_UNH 3 #define SSH2_ARK 4 #define SSH2_HKA 5 #define SSH2_MAC 6 #define SSH2_AUT 7 #define SSH2_KEX 8 static struct keytab sshv1tab[] = { /* SET SSH V1 command table */ { "cipher", SSH1_CIF, 0 }, { "global-known-hosts-file", SSH1_GNH, 0 }, { "k5-reuse-k4-messages", SSH1_K54, CM_INV }, { "user-known-hosts-file", SSH1_UNH, 0 }, { "", 0, 0 } }; static int nsshv1tab = (sizeof(sshv1tab) / sizeof(struct keytab)) - 1; static struct keytab sshv2tab[] = { /* SET SSH V2 command table */ { "authentication", SSH2_AUT, 0 }, { "auto-rekey", SSH2_ARK, 0 }, { "ciphers", SSH2_CIF, 0 }, { "global-known-hosts-file", SSH2_GNH, 0 }, { "hostkey-algorithms", SSH2_HKA, 0 }, { "key-exchange-methods", SSH2_KEX, 0 }, { "macs", SSH2_MAC, 0 }, { "user-known-hosts-file", SSH2_UNH, 0 }, { "", 0, 0 } }; static int nsshv2tab = (sizeof(sshv2tab) / sizeof(struct keytab)) - 1; static struct keytab tgtpass[] = { { "tgt-passing", 1, 0, }, { "", 0, 0 } }; static int ntgtpass = (sizeof(tgtpass) / sizeof(struct keytab)) - 1; #define SSH_GSSAPI_DELEGATE 1 #define SSH_GSSAPI_KEYEX 2 static struct keytab gssapitab[] = { { "delegate-credentials", SSH_GSSAPI_DELEGATE, 0, }, { "key-exchange", SSH_GSSAPI_KEYEX, CM_INV, }, { "", 0, 0 } }; static int ngssapitab = (sizeof(gssapitab) / sizeof(struct keytab)) - 1; char * ssh_idf[33] = { /* Identity file list - null terminated */ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL }; char * ssh_tmp[32] = { /* Temp identity file list */ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }; int ssh_idf_n = 0; #endif /* SSHBUILTIN */ #ifdef SFTP_BUILTIN static struct keytab sftptab[] = { { "end-of-line", XY_SFTP_EOL, 0, }, { "remote-character-set", XY_SFTP_RCS, 0, }, { "", 0, 0 } }; static int nsftptab = (sizeof(sftptab) / sizeof(struct keytab)) - 1; #endif /* SFTP_BUILTIN */ VOID shossh() { #ifdef SSHBUILTIN int i, n = 0, ssh_ver; /* ADD askmore()! */ ssh_ver = ssh_get_iparam(SSH_IPARAM_VER); #ifndef SSH_DLL printf("\nSSH is built in (%s):\n\n", ssh_impl_ver()); #else if (!ssh_avail()) { printf("\nNo SSH backend loaded!"); printf("\nUse \"ssh load\" to specify a backend to make SSH commands available"); } else { printf("\nSSH is loaded (%s):\n\n", ssh_impl_ver()); printf(" ssh backend: %s\n",showstring((char*)ssh_dll_name())); printf(" ssh backend version: %s\n",showstring((char*)ssh_dll_ver())); #endif /* SSH_DLL */ printf(" ssh host: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_HST))); printf(" ssh port: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_PRT))); printf(" ssh command: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_CMD))); if (ssh_feature_supported(SSH_FEAT_AGENT_FWD)) { printf(" ssh agent-forwarding: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_AFW))); } printf(" ssh check-host-ip: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_CHKIP))); printf(" ssh compression: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_CMP))); printf(" ssh directory: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_DIR))); if (ssh_feature_supported(SSH_FEAT_DYN_PORT_FWD)) { printf(" ssh dynamic-forwarding: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_DYF))); } if (ssh_feature_supported(SSH_FEAT_PORT_FWD)) { /* This is a combined array of local and remote port forwards in no * particular order, so we've got to iterate through it twice if we * want to output them separately. The array is terminated with an * entry that has its type set to SSH_PORT_FORWARD_NULL. */ const ssh_port_forward_t* fwd = ssh_fwd_get_ports(); if (fwd != NULL) { int i = 0; BOOL no_forwards = TRUE; /* Output local port forwards */ while (fwd->type != SSH_PORT_FORWARD_NULL) { if (fwd->type == SSH_PORT_FORWARD_LOCAL) { no_forwards = FALSE; if (i == 0) { printf(" ssh forward-local-port: %d %s %d\n", fwd->port, fwd->hostname, fwd->host_port); } else { printf(" : %d %s %d\n", fwd->port, fwd->hostname, fwd->host_port); } i++; } fwd++; } if (no_forwards) { printf(" ssh forward-local-port: (none)\n"); } /* Back to the start of the list for the next trip around */ fwd = ssh_fwd_get_ports(); i = 0; no_forwards = TRUE; /* Output remote port forwards */ while (fwd->type != SSH_PORT_FORWARD_NULL) { if (fwd->type == SSH_PORT_FORWARD_REMOTE) { no_forwards = FALSE; if (i == 0) { printf(" ssh forward-remote-port: %d %s %d\n", fwd->port, fwd->hostname, fwd->host_port); } else { printf(" : %d %s %d\n", fwd->port, fwd->hostname, fwd->host_port); } i++; } fwd++; } if (no_forwards) { printf(" ssh forward-remote-port: (none)\n"); } } } if (ssh_feature_supported(SSH_FEAT_DYN_PORT_FWD)) { printf(" ssh gateway-ports: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_GWP))); } if (ssh_feature_supported(SSH_FEAT_GSSAPI_DELEGAT)) { printf(" ssh gssapi delegate-credentials: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_GSD))); } if (ssh_feature_supported(SSH_FEAT_GSSAPI_KEYEX)) { printf(" ssh gssapi key-exchange: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_GKX))); } printf(" ssh identity-file: %d\n",ssh_idf_n); for (i = 0; i < ssh_idf_n; i++) printf(" %2d. %s\n",i+1,showstring(ssh_idf[i])); printf(" ssh heartbeat interval: %d\n",ssh_get_iparam(SSH_IPARAM_HBT)); if (ssh_feature_supported(SSH_FEAT_ADV_KERBEROS4)) { printf(" ssh k4 tgt-passing: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_K4TGT))); } if (ssh_feature_supported(SSH_FEAT_ADV_KERBEROS5)) { printf(" ssh k5 tgt-passing: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_K5TGT))); } if (ssh_feature_supported(SSH_FEAT_FROM_PRIV_PRT)) { printf(" ssh privileged-port: %s\n",showooa(ssh_get_iparam(SSH_IPARAM_PRP))); } if (ssh_feature_supported(SSH_FEAT_PROXY_CMD)) { printf(" ssh proxy command: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_PXC))); } printf(" ssh quiet: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_SHH))); printf(" ssh strict-host-key-check: %d\n",ssh_get_iparam(SSH_IPARAM_SHK)); if (ssh_feature_supported(SSH_FEAT_OPENSSH_CONF)) { printf(" ssh use-openssh-config: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_CFG))); } printf(" ssh verbose: %d\n",ssh_get_iparam(SSH_IPARAM_VRB)); if (ssh_feature_supported(SSH_FEAT_SSH_V1)) { printf(" ssh version: %s\n", ssh_ver ? ckitoa(ssh_ver) : "automatic" ); } if (ssh_feature_supported(SSH_FEAT_X11_FWD)) { extern char tn_env_disp[64]; /* ckctel.c */ printf(" ssh x11-forwarding: %s\n",showooa(ssh_get_iparam(SSH_IPARAM_XFW))); printf(" ssh x11-forwarding display: %s\n",showstring(tn_env_disp)); /* TODO: Show the display - tn_env_disp */ if (ssh_feature_supported(SSH_FEAT_X11_XAUTH)) { printf(" ssh xauth-location: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_XAL))); } } if (ssh_feature_supported(SSH_FEAT_SSH_V1)) { printf("\n"); printf(" ssh v1 cipher: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_1_CIF))); printf(" ssh v1 global-known-hosts-file: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_1_GNH))); printf(" ssh v1 user-known-hosts-file: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_1_UNH))); } printf("\n"); printf(" ssh v2 authentication: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_2_AUTH))); if (ssh_feature_supported(SSH_FEAT_REKEY_AUTO)) { printf(" ssh v2 auto-rekey: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_2_ARK))); } printf(" ssh v2 ciphers: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_2_CIF))); printf(" ssh v2 command-as-subsystem: %s\n",showoff(ssh_get_iparam(SSH_IPARAM_CAS))); printf(" ssh v2 global-known-hosts-file: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_2_GNH))); printf(" ssh v2 hostkey-algorithms: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_2_HKA))); printf(" ssh v2 key-exchange-methods: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_2_KEX))); printf(" ssh v2 mac: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_2_MAC))); printf(" ssh v2 user-known-hosts-file: %s\n",showstring((char*)ssh_get_sparam(SSH_SPARAM_2_UNH))); #ifdef SSH_DLL } #endif /* SSH_DLL */ #else #ifdef SSHCMD extern char * sshcmd, * defsshcmd; char * s; s = sshcmd ? sshcmd : defsshcmd; printf("\n SSH is external.\n\n"); printf(" ssh command: %s\n",showstring(s)); #endif /* SSHCMD */ #endif /* SSHBUILTIN */ printf("\n"); } #ifdef SSHBUILTIN static int set_ssh_iparam_on(int param) { int value; int success = seton(&value); if (!success) return success; return ssh_set_iparam(param, value); } #endif static int dosetssh() { #ifdef SSHCMD extern char * sshcmd; #endif /* SSHCMD */ #ifdef SSHBUILTIN #ifndef SSHTEST extern int sl_ssh_xfw_saved, sl_ssh_ver_saved; #endif /* SSHTEST */ #endif /* SSHBUILTIN */ int cx, x, y, z; char * s; #ifdef SSHBUILTIN #ifdef SSH_DLL if (!ssh_avail()) { printf("\nNo SSH backend DLL loaded. SSH commands unavailable. Use the SSH LOAD command\n"); printf("to load a compatible SSH backend if you have one.\n"); return (-9); } #endif /* SSH_DLL */ /* Hide any "set ssh" commands not supported by the currently loaded SSH * backend */ for (z = 0; z < nsshtab; z++) { if ((sshtab[z].kwval == SSH_V1 || sshtab[z].kwval == SSH_VER) && !ssh_feature_supported(SSH_FEAT_SSH_V1)) { /* * "set ssh v1" and "set ssh version" commands. */ sshtab[z].flgs = CM_INV; } else if ((sshtab[z].kwval == SSH_XFW && !ssh_feature_supported(SSH_FEAT_X11_FWD)) || (sshtab[z].flgs == SSH_XAL && !ssh_feature_supported(SSH_FEAT_X11_XAUTH))) { /* * "set ssh x11-forwarding" and "set ssh xauth-location" commands. */ sshtab[z].flgs = CM_INV; } else if ((sshtab[z].kwval == SSH_DYF || sshtab[z].kwval == SSH_GWP) && !ssh_feature_supported(SSH_FEAT_DYN_PORT_FWD)) { /* Dynamic Port Forwarding * "set ssh dynamic-forwarding" * "set ssh gateway-ports" */ sshtab[z].flgs = CM_INV; } else if (sshtab[z].kwval == SSH_K4 && !ssh_feature_supported(SSH_FEAT_ADV_KERBEROS4)) { /* * "set ssh kerberos4" commands. */ sshtab[z].flgs = CM_INV; } else if (sshtab[z].kwval == SSH_K5 && !ssh_feature_supported(SSH_FEAT_ADV_KERBEROS5)) { /* * "set ssh kerberos5" commands. */ sshtab[z].flgs = CM_INV; } else if (sshtab[z].kwval == SSH_PXC && !ssh_feature_supported(SSH_FEAT_PROXY_CMD)) { /* * "set ssh command" commands. */ sshtab[z].flgs = CM_INV; } else if (sshtab[z].kwval == SSH_CFG && !ssh_feature_supported(SSH_FEAT_OPENSSH_CONF)) { /* * "set ssh use-openssh-config" commands. */ sshtab[z].flgs = CM_INV; } else if (sshtab[z].kwval == SSH_PRP && !ssh_feature_supported(SSH_FEAT_FROM_PRIV_PRT)) { /* * "set ssh use-openssh-config" commands. */ sshtab[z].flgs = CM_INV; } else if (sshtab[z].kwval == SSH_AFW && !ssh_feature_supported(SSH_FEAT_AGENT_FWD)) { /* * "set ssh agent-forwarding" command. */ sshtab[z].flgs = CM_INV; } else if (sshtab[z].kwval == SSH_AGL && !ssh_feature_supported(SSH_FEAT_AGENT_LOC)) { /* * "set ssh agent-location" command. */ sshtab[z].flgs = CM_INV; } else if (sshtab[z].kwval == SSH_GSS && !ssh_feature_supported(SSH_FEAT_GSSAPI_DELEGAT) && !ssh_feature_supported(SSH_FEAT_GSSAPI_KEYEX)) { /* * "set ssh gssapi" commands - if none of them are enabled, * hide "set ssh gssapi" too. */ sshtab[z].flgs = CM_INV; } } /* Hide any "set ssh v2" commands not supported by the currently loaded SSH * backend */ for (z = 0; z < nsshv2tab; z++) { if (sshv2tab[z].kwval == SSH2_ARK && !ssh_feature_supported(SSH_FEAT_REKEY_AUTO)) { /* * "set ssh v2 auto-rekey" */ sshv2tab[z].flgs = CM_INV; } } /* Hide any "set ssh gssapi" commands not supported by the currently loaded SSH * backend */ for (z = 0; z < ngssapitab; z++) { if (gssapitab[z].kwval == SSH_GSSAPI_DELEGATE && !ssh_feature_supported(SSH_FEAT_GSSAPI_DELEGAT)) { /* * "set ssh gssapi delegate-credentials" */ gssapitab[z].flgs = CM_INV; } else if (gssapitab[z].kwval == SSH_GSSAPI_KEYEX && !ssh_feature_supported(SSH_FEAT_GSSAPI_KEYEX)) { /* The always hidden command: * "set ssh gssapi key-exchange" */ gssapitab[z].flgs = CM_INV; } } #endif /* SSHBUILTIN */ if ((cx = cmkey(sshtab,nsshtab,"","command", xxstring)) < 0) return(cx); switch (cx) { #ifdef SSHCMD case SSH_CMD: /* Command */ if ((x = cmtxt("Command to start ssh","ssh -e none", &s,xxstring)) < 0) return(x); makestr(&sshcmd,s); return(success = 1); #endif /* SSHCMD */ #ifdef SSHBUILTIN case SSH_AFW: /* Agent-forwarding */ if (!ssh_feature_supported(SSH_FEAT_AGENT_FWD)) { printf("\r\nAgent forwarding is not supported by the current SSH " "backend\r\n"); return(-9); } return(success = set_ssh_iparam_on(SSH_IPARAM_AFW)); case SSH_AGL: if (!ssh_feature_supported(SSH_FEAT_AGENT_LOC)) { printf("\r\nSetting of agent location is not supported by the " "current SSH backend\r\n"); return(-9); } if ((x = cmifi("Socket Name","",&s,&z,xxstring)) < 0) { return(x); } ssh_set_sparam(SSH_SPARAM_AGENTLOC, s); return(1); case SSH_CHI: /* Check Host IP */ return(success = set_ssh_iparam_on(SSH_IPARAM_CHKIP)); break; case SSH_CMP: /* Compression */ return(success = set_ssh_iparam_on(SSH_IPARAM_CMP)); case SSH_DIR: if ((x = cmdir("SSH Directory","",&s,xxstring)) < 0) { if (x != -3) return(x); } else { ckstrncpy(line,s,LINBUFSIZ); if (zfnqfp(line,TMPBUFSIZ,tmpbuf)) ckstrncpy(line,tmpbuf,LINBUFSIZ); } s = (x == -3) ? NULL : line; if ((x = cmcfm()) < 0) return(x); ssh_set_sparam(SSH_SPARAM_DIR, s); return(1); case SSH_DYF: /* Dynamic Forwarding */ if (!ssh_feature_supported(SSH_FEAT_DYN_PORT_FWD)) { printf("\r\nDynamic port forwarding is not supported by the current SSH backend\r\n"); return(-9); } return(success = set_ssh_iparam_on(SSH_IPARAM_DYF)); case SSH_GWP: /* Gateway ports */ if (!ssh_feature_supported(SSH_FEAT_DYN_PORT_FWD)) { printf("\r\nPort forwarding is not supported by the current SSH backend\r\n"); return(-9); } return(success = set_ssh_iparam_on(SSH_IPARAM_GWP)); case SSH_GSS: /* GSSAPI */ if ((y = cmkey(gssapitab,ngssapitab,"","", xxstring)) < 0) return(y); switch (y) { case SSH_GSSAPI_DELEGATE: /* Delegate credentials */ if (!ssh_feature_supported(SSH_FEAT_GSSAPI_DELEGAT)) { printf("\r\nDelegating GSSAPI credentials is not supported by the current SSH backend\r\n"); return(-9); } return(success = set_ssh_iparam_on(SSH_IPARAM_GSD)); case SSH_GSSAPI_KEYEX: /* key-exchange */ if (!ssh_feature_supported(SSH_FEAT_GSSAPI_KEYEX)) { printf("\r\nConfiguration of GSSAPI Key Exchange is not supported by the current SSH backend\r\n"); return(-9); } return(success = set_ssh_iparam_on(SSH_IPARAM_GKX)); } if ((x = cmcfm()) < 0) return(x); return(success = 0); #ifdef COMMENT case SSH_KBD: /* Kbd Interactive Devices */ if ((x = cmcfm()) < 0) return(x); /* TO BE FILLED IN */ return(-2); #endif /* COMMENT */ case SSH_K4: /* Kerberos IV */ case SSH_K5: /* Kerberos V */ if (cx == SSH_K4 && !ssh_feature_supported(SSH_FEAT_X11_FWD)) { printf("\r\nNo Kerberos 4 settings are supported by the current SSH backend\r\n"); return(-9); } else if (cx == SSH_K5 && !ssh_feature_supported(SSH_FEAT_X11_FWD)) { printf("\r\nNo Kerberos 5 settings are supported by the current SSH backend\r\n"); return(-9); } if ((y = cmkey(tgtpass,1,"","tgt-passing", xxstring)) < 0) return(y); switch (y) { case 1: return(success = (cx == SSH_K4) ? set_ssh_iparam_on(SSH_IPARAM_K4TGT) : set_ssh_iparam_on(SSH_IPARAM_K5TGT)); } if ((x = cmcfm()) < 0) return(x); return(success = 0); case SSH_PRP: /* Privd port */ if (!ssh_feature_supported(SSH_FEAT_FROM_PRIV_PRT)) { printf("\r\nConnecting from a privileged port not supported by the " "current SSH backend\r\n"); return(-9); } return(success = set_ssh_iparam_on(SSH_IPARAM_PRP)); case SSH_SHH: /* Quiet */ return(success = set_ssh_iparam_on(SSH_IPARAM_SHH)); case SSH_SHK: /* Strict Host Key Check */ if ((y = cmkey(ooktab,3,"","", xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); success = ssh_set_iparam(SSH_IPARAM_SHK, y); return(success); case SSH_HBT: x = cmnum("Heartbeat interval, seconds","0",10,&z,xxstring); if (x < 0) return(x); if ((x = cmcfm()) < 0) return(x); success = ssh_set_iparam(SSH_IPARAM_HBT, z); return(success ); case SSH_V1: /* SSH V1 */ if (!ssh_feature_supported(SSH_FEAT_SSH_V1)) { printf("\r\nSSH V1 is not supported by the current SSH backend\r\n"); return(-9); } if ((y = cmkey(sshv1tab,nsshv1tab,"","", xxstring)) < 0) return(y); switch (y) { case SSH1_K54: return(success = set_ssh_iparam_on(SSH_IPARAM_K5_IS_K4)); case SSH1_CIF: { /* Not a list */ struct keytab *ssh1ciphers; int nssh1ciphers; ktab_ret ktr; ktr = ssh_get_keytab(SSH_KTAB_V1_CIPHERS); if (ktr.rc != 0) { printf("\r\nFailed to get options from the SSH backend\r\n"); return(-9); } ssh1ciphers = ktr.ktab; nssh1ciphers = ktr.ktab_len; if ((y = cmkey(ssh1ciphers,nssh1ciphers,"","", xxstring)) < 0) if (y != -3) return(y); if ((x = cmcfm()) < 0) return(x); if (y == -3) { ssh_set_sparam(SSH_SPARAM_1_CIF, NULL); } else { for (x = 0; x < nssh1ciphers; x++) if (ssh1ciphers[x].kwval == y) break; ssh_set_sparam(SSH_SPARAM_1_CIF, ssh1ciphers[x].kwd); } return(1); } case SSH1_GNH: case SSH1_UNH: if ((x = cmifi("Filename","",&s,&z,xxstring)) < 0) { if (x != -3) return(x); } else { ckstrncpy(line,s,LINBUFSIZ); if (zfnqfp(line,TMPBUFSIZ,tmpbuf)) ckstrncpy(line,tmpbuf,LINBUFSIZ); } s = (x == -3) ? NULL : line; if ((x = cmcfm()) < 0) return(x); switch (y) { case SSH1_GNH: ssh_set_sparam(SSH_SPARAM_1_GNH, s); break; case SSH1_UNH: ssh_set_sparam(SSH_SPARAM_1_UNH, s); break; } return(1); } case SSH_V2: /* SSH V2 */ if ((y = cmkey(sshv2tab,nsshv2tab,"","", xxstring)) < 0) return(y); switch (y) { case SSH2_ARK: if (!ssh_feature_supported(SSH_FEAT_REKEY_AUTO)) { printf("\r\nConfiguring automatic re-key is not supported by the " "current SSH backend\r\n"); return(-9); } return(success = set_ssh_iparam_on(SSH_IPARAM_2_ARK)); case SSH2_AUT: { /* Authentication */ #define TMPCNT 12 int i, j, tmp[TMPCNT]; struct keytab *ssh2aut; int nssh2aut; ktab_ret ktr; ktr = ssh_get_keytab(SSH_KTAB_V2_AUT); if (ktr.rc != 0) { printf("\r\nFailed to get options from the SSH backend\r\n"); return(-9); } ssh2aut = ktr.ktab; nssh2aut = ktr.ktab_len; for (i = 0; i < TMPCNT; i++) tmp[i] = 0; for (i = 0; i < TMPCNT; i++) { if ((y = cmkey(ssh2aut,nssh2aut, "Authentication method","",xxstring)) < 0) { if (y == -3) break; return(y); } for (j = 0; j < i; j++) { if (tmp[j] == y) { printf("\r\n?Choice has already been used.\r\n"); return(-9); } } tmp[i] = y; } if ((z = cmcfm()) < 0) return(z); if (i > 0) { char* ssh2_auth = NULL; int len = 0; for (j = 0; j < i; j++) { for (x = 0; x < nssh2aut; x++) if (ssh2aut[x].kwval == tmp[j] && !ssh2aut[x].flgs) break; len += strlen(ssh2aut[x].kwd) + 1; } ssh2_auth = malloc(len); ssh2_auth[0] = '\0'; for (j = 0; j < i; j++) { for (x = 0; x < nssh2aut; x++) if (ssh2aut[x].kwval == tmp[j] && !ssh2aut[x].flgs) break; ckstrncat(ssh2_auth,ssh2aut[x].kwd,len); if (j < i - 1) ckstrncat(ssh2_auth,",",len); } ssh_set_sparam(SSH_SPARAM_2_AUTH, ssh2_auth); free(ssh2_auth); } return(success = 1); #undef TMPCNT } case SSH2_CIF: { #define TMPCNT 12 int i, j, tmp[TMPCNT]; struct keytab *ssh2ciphers; int nssh2ciphers; ktab_ret ktr; ktr = ssh_get_keytab(SSH_KTAB_V2_CIPHERS); if (ktr.rc != 0) { printf("\r\nFailed to get options from the SSH backend\r\n"); return(-9); } ssh2ciphers = ktr.ktab; nssh2ciphers = ktr.ktab_len; for (i = 0; i < TMPCNT; i++) tmp[i] = 0; for (i = 0; i < TMPCNT; i++) { if ((y = cmkey(ssh2ciphers,nssh2ciphers, "","", xxstring)) < 0) { if (y == -3) break; return(y); } for (j = 0; j < i; j++) { if (tmp[j] == y) { printf("\r\n?Choice has already been used.\r\n"); return(-9); } } tmp[i] = y; } if ((z = cmcfm()) < 0) return(z); if (i > 0) { char* ssh2_cif = NULL; int len = 0; for (j=0; j < i; j++) { for (x = 0; x < nssh2ciphers; x++) if (ssh2ciphers[x].kwval == tmp[j] && !ssh2ciphers[x].flgs) break; len += strlen(ssh2ciphers[x].kwd) + 1; } ssh2_cif = malloc(len); ssh2_cif[0] = '\0'; for (j = 0; j < i; j++) { for (x = 0; x < nssh2ciphers; x++) { if (ssh2ciphers[x].kwval == tmp[j] && !ssh2ciphers[x].flgs) { break; } } ckstrncat(ssh2_cif,ssh2ciphers[x].kwd,len); if (j < i - 1) { ckstrncat(ssh2_cif,",",len); } } ssh_set_sparam(SSH_SPARAM_2_CIF, ssh2_cif); free(ssh2_cif); } return(success = 1); #undef TMPCNT } case SSH2_MAC: { #define TMPCNT 12 int i, j, tmp[TMPCNT]; struct keytab *ssh2macs; int nssh2macs; ktab_ret ktr; ktr = ssh_get_keytab(SSH_KTAB_V2_MACS); if (ktr.rc != 0) { printf("\r\nFailed to get options from the SSH backend\r\n"); return(-9); } ssh2macs = ktr.ktab; nssh2macs = ktr.ktab_len; for (i = 0; i < TMPCNT; i++) tmp[i] = 0; for (i = 0; i < TMPCNT; i++) { if ((y = cmkey(ssh2macs,nssh2macs,"","", xxstring)) < 0) { if (y == -3) break; return(y); } for (j = 0; j < i; j++) { if (tmp[j] == y) { printf("\r\n?Choice has already been used.\r\n"); return(-9); } } tmp[i] = y; } if ((z = cmcfm()) < 0) return(z); if (i > 0) { char* ssh2_mac = NULL; int len = 0; for (j = 0; j < i; j++) { for (x = 0; x < nssh2macs; x++) if (ssh2macs[x].kwval == tmp[j] && !ssh2macs[x].flgs) break; len += strlen(ssh2macs[x].kwd) + 1; } ssh2_mac = malloc(len); ssh2_mac[0] = '\0'; for (j=0; j < i; j++) { for (x = 0; x < nssh2macs; x++) if (ssh2macs[x].kwval == tmp[j] && !ssh2macs[x].flgs) break; ckstrncat(ssh2_mac,ssh2macs[x].kwd,len); if (j < i - 1) ckstrncat(ssh2_mac,",",len); } ssh_set_sparam(SSH_SPARAM_2_MAC, ssh2_mac); free(ssh2_mac); } return(success = 1); #undef TMPCNT } case SSH2_HKA: { #define TMPCNT 12 int i, j, tmp[TMPCNT]; struct keytab *hkatab; int nhkatab; ktab_ret ktr; ktr = ssh_get_keytab(SSH_KTAB_HKA); if (ktr.rc != 0) { printf("\r\nFailed to get options from the SSH backend\r\n"); return(-9); } hkatab = ktr.ktab; nhkatab = ktr.ktab_len; for (i = 0; i < TMPCNT; i++) tmp[i] = 0; for (i = 0; i < TMPCNT; i++) { if ((y = cmkey(hkatab,nhkatab, "","", xxstring)) < 0) { if (y == -3) break; return(y); } for (j = 0; j < i; j++) { if (tmp[j] == y) { printf("\r\n?Choice has already been used.\r\n"); return(-9); } } tmp[i] = y; } if ((z = cmcfm()) < 0) return(z); if (i > 0) { char* ssh2_hka = NULL; int len = 0; for (j=0; j < i; j++) { for (x = 0; x < nhkatab; x++) if (hkatab[x].kwval == tmp[j] && !hkatab[x].flgs) break; len += strlen(hkatab[x].kwd) + 1; } ssh2_hka = malloc(len); ssh2_hka[0] = '\0'; for (j = 0; j < i; j++) { for (x = 0; x < nhkatab; x++) if (hkatab[x].kwval == tmp[j] && !hkatab[x].flgs) break; ckstrncat(ssh2_hka,hkatab[x].kwd,len); if (j < i - 1) ckstrncat(ssh2_hka,",",len); } ssh_set_sparam(SSH_SPARAM_2_HKA, ssh2_hka); free(ssh2_hka); } return(success = 1); #undef TMPCNT } case SSH2_KEX: { #define TMPCNT 24 int i, j, tmp[TMPCNT]; struct keytab *sshkextab; int nsshkextab; ktab_ret ktr; ktr = ssh_get_keytab(SSH_KTAB_KEX); if (ktr.rc != 0) { printf("\r\nFailed to get options from the SSH backend\r\n"); return(-9); } sshkextab = ktr.ktab; nsshkextab = ktr.ktab_len; for (i = 0; i < TMPCNT; i++) tmp[i] = 0; for (i = 0; i < TMPCNT; i++) { if ((y = cmkey(sshkextab,nsshkextab, "","", xxstring)) < 0) { if (y == -3) break; return(y); } for (j = 0; j < i; j++) { if (tmp[j] == y) { printf("\r\n?Choice has already been used.\r\n"); return(-9); } } tmp[i] = y; } if ((z = cmcfm()) < 0) return(z); if (i > 0) { char* ssh2_kex = NULL; int len = 0; for (j=0; j < i; j++) { for (x = 0; x < nsshkextab; x++) if (sshkextab[x].kwval == tmp[j] && !sshkextab[x].flgs) break; len += strlen(sshkextab[x].kwd) + 1; } ssh2_kex = malloc(len); ssh2_kex[0] = '\0'; for (j = 0; j < i; j++) { for (x = 0; x < nsshkextab; x++) if (sshkextab[x].kwval == tmp[j] && !sshkextab[x].flgs) break; ckstrncat(ssh2_kex,sshkextab[x].kwd,len); if (j < i - 1) ckstrncat(ssh2_kex,",",len); } ssh_set_sparam(SSH_SPARAM_2_KEX, ssh2_kex); free(ssh2_kex); } return(success = 1); #undef TMPCNT } case SSH2_GNH: case SSH2_UNH: if ((x = cmifi("Filename","",&s,&z,xxstring)) < 0) { if (x != -3) return(x); } else { ckstrncpy(line,s,LINBUFSIZ); if (zfnqfp(line,TMPBUFSIZ,tmpbuf)) ckstrncpy(line,tmpbuf,LINBUFSIZ); } s = (x == -3) ? NULL : line; if ((x = cmcfm()) < 0) return(x); switch (y) { case SSH2_GNH: ssh_set_sparam(SSH_SPARAM_2_GNH, s); break; case SSH2_UNH: ssh_set_sparam(SSH_SPARAM_2_UNH, s); break; default: return(success = 0); } return(success = 1); } case SSH_VRB: { /* Verbosity level */ int val; y = cmnum("SSH verbosity level, 0-7","2",10,&x,xxstring); success = setnum(&val,x,y,7); return(success = ssh_set_iparam(SSH_IPARAM_VRB, val)); } case SSH_VER: /* Version */ if (!ssh_feature_supported(SSH_FEAT_SSH_V1)) { printf("\r\nSSH V1 is not supported by the current SSH backend\r\n"); return(-9); } if ((y = cmkey(sshver,3,"","auto", xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); ssh_set_iparam(SSH_IPARAM_VER, y); /* 0 == AUTO */ #ifndef SSHTEST sl_ssh_ver_saved = 0; #endif /* SSHTEST */ return(success = 1); case SSH_IDF: { /* Identity file */ int i, n; for (i = 0; i < 32; i++) { if ((x = cmifi("Filename","",&s,&y,xxstring)) < 0) { if (x == -3) break; return(x); } if (!zfnqfp(s,LINBUFSIZ,line)) ckstrncpy(line,s,LINBUFSIZ); makestr(&ssh_tmp[i],line); } n = i; if ((x = cmcfm()) < 0) { for (i = 0; i < n; i++) makestr(&(ssh_tmp[i]),NULL); return(x); } for (i = 0; i < 32; i++) { makestr(&(ssh_idf[i]),NULL); if (i < n) { ssh_idf[i] = ssh_tmp[i]; ssh_tmp[i] = NULL; } else { makestr(&(ssh_tmp[i]),NULL); } } ssh_idf_n = n; if (ssh_set_identity_files((const char **)ssh_idf) < 0) { printf("\r\nCommand not supported by the current SSH backend\r\n"); return(0); } return(success = 1); } case SSH_XFW: /* X11-forwarding */ if (!ssh_feature_supported(SSH_FEAT_X11_FWD)) { printf("\r\nX11 forwarding is not supported by the current SSH backend\r\n"); return(-9); } success = set_ssh_iparam_on(SSH_IPARAM_XFW); #ifndef SSHTEST if (success) sl_ssh_xfw_saved = 0; #endif /* SSHTEST */ return(success); case SSH_XAL: /* SSH Xauth Location */ if (!ssh_feature_supported(SSH_FEAT_X11_FWD)) { printf("\r\nX11 forwarding is not supported by the current SSH backend\r\n"); return(-9); } if ((x = cmifi("Path to executable", "",&s,&y,xxstring)) < 0) { if (x != -3) return(x); } else { ckstrncpy(line,s,LINBUFSIZ); if (zfnqfp(line,TMPBUFSIZ,tmpbuf)) ckstrncpy(line,tmpbuf,LINBUFSIZ); } s = (x == -3) ? NULL : line; if ((x = cmcfm()) < 0) return(x); ssh_set_sparam(SSH_SPARAM_XAL, s); return(success = 1); case SSH_PXC: /* SSH Proxy Command */ if (!ssh_feature_supported(SSH_FEAT_PROXY_CMD)) { printf("\r\nSSH proxy command feature not supported by the current SSH backend\r\n"); return(-9); } if ((y = cmtxt("Command","",&s,xxstring)) < 0) return(y); ssh_set_sparam(SSH_SPARAM_PXC, s); return(success = 1); case SSH_CFG: /* Use OpenSSH Config */ if (!ssh_feature_supported(SSH_FEAT_OPENSSH_CONF)) { printf("\r\nOpenSSH configuration not supported by the current SSH backend\r\n"); return(-9); } return(success = set_ssh_iparam_on(SSH_IPARAM_CFG)); #endif /* SSHBUILTIN */ default: return(-2); } } #endif /* ANYSSH */ #ifdef SFTP_BUILTIN static int dosetsftp() { int cx, x, y, z; char * s; if ((cx = cmkey(sftptab,nsftptab,"","", xxstring)) < 0) return(cx); switch (cx) { case XY_SFTP_EOL: case XY_SFTP_RCS: default: return(-2); } } #endif /* SFTP_BUILTIN */ #ifdef KUI #include "ikui.h" extern ULONG RGBTable[16]; #ifdef CK_ANSIC /* Prototypes for static functions - fdc 30 November 2022 */ static char * sexpdebug( char * ); static int setdial ( int ); static int dialstr( char **, char * ); static int parsdir( int ); static int protofield( char *, char *, char * ); static int setprinter( int ); #endif /* CK_ANSIC */ #define GUI_RGB 1 #define GUI_WIN 2 #define GUI_FON 3 #define GUI_DIA 4 #define GUI_STB 5 #define GUI_TLB 6 #define GUI_MNB 7 #define GUI_CLS 8 #define GUIB_OFF 0 #define GUIB_ON 1 #define GUIB_DIS 2 #define GUIB_VIS 3 #define GUIW_POS 1 #define GUIW_RES 2 #define GUIW_RUN 3 #define GUIWR_NON 0 #define GUIWR_FON 1 #define GUIWR_DIM 2 #define GUIWN_RES 1 #define GUIWN_MIN 2 #define GUIWN_MAX 3 static struct keytab guitab[] = { { "close", GUI_CLS, 0 }, { "dialogs", GUI_DIA, 0 }, { "font", GUI_FON, 0 }, { "menubar", GUI_MNB, 0 }, { "rgbcolor", GUI_RGB, 0 }, { "statusbar", GUI_STB, 0 }, #ifndef NOTOOLBAR { "toolbar", GUI_TLB, 0 }, #endif { "window", GUI_WIN, 0 }, { "", 0, 0} }; static int nguitab = (sizeof(guitab) / sizeof(struct keytab)); static struct keytab guibartab[] = { { "disabled", GUIB_DIS, 0 }, { "off", GUIB_OFF, CM_INV}, { "on", GUIB_ON, CM_INV}, { "visible", GUIB_VIS, 0 }, { "", 0, 0} }; static int nguibartab = (sizeof(guibartab) / sizeof(struct keytab)); static struct keytab guiwtab[] = { { "position", GUIW_POS, 0 }, { "resize-mode", GUIW_RES, 0 }, { "run-mode", GUIW_RUN, 0 }, { "", 0, 0} }; static int nguiwtab = (sizeof(guiwtab) / sizeof(struct keytab)); static struct keytab guiwrtab[] = { { "change-dimensions", GUIWR_DIM, 0 }, { "none", GUIWR_NON, 0 }, { "scale-font", GUIWR_FON, 0 }, { "", 0, 0} }; static int nguiwrtab = (sizeof(guiwrtab) / sizeof(struct keytab)); static struct keytab guiwntab[] = { { "maximize", GUIWN_MAX, 0 }, { "minimize", GUIWN_MIN, 0 }, { "restore", GUIWN_RES, 0 }, { "", 0, 0} }; static int nguiwntab = (sizeof(guiwntab) / sizeof(struct keytab)); static struct keytab rgbtab[] = { { "black", 0, 0 }, { "blue", 1, 0 }, { "brown", 6, 0 }, { "cyan", 3, 0 }, { "darkgray", 8, 0 }, { "dgray", 8, CM_INV }, { "green", 2, 0 }, { "lblue", 9, CM_INV }, { "lcyan", 11, CM_INV }, { "lgreen", 10, CM_INV }, { "lgray", 7, CM_INV }, { "lightblue", 9, 0 }, { "lightcyan", 11, 0 }, { "lightgreen", 10, 0 }, { "lightgray", 7, 0 }, { "lightmagenta", 13, 0 }, { "lightred", 12, 0 }, { "lmagenta", 13, CM_INV }, { "lred", 12, CM_INV }, { "magenta", 5, 0 }, { "red", 4, 0 }, { "white", 15, 0 }, { "yellow", 14, 0 }, }; int nrgb = (sizeof(rgbtab) / sizeof(struct keytab)); VOID shogui() { extern int gui_dialog; extern HWND getHwndKUI(); unsigned char cmdsav = colorcmd; int i, red, green, blue, lines=0; char * s; printf("GUI paramters:\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" Dialogs: %s\n",showoff(gui_dialog)); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" Position: %d,%d\n",get_gui_window_pos_x(), get_gui_window_pos_y()); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" Resolution: %d x %d\n",GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" Run-mode: %s\n",IsIconic(getHwndKUI()) ? "minimized" : IsZoomed(getHwndKUI()) ? "maximized" : "restored"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } switch ( get_gui_resize_mode() ) { case GUIWR_NON: s = "none"; break; case GUIWR_FON: s = "scales font"; break; case GUIWR_DIM: s= "changes dimensions"; break; } printf(" Resize-mode: %s\n",s); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf("\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf("RGB Color Table:\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" Color Red Green Blue\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" ------------------------------------------\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } for (i = 0; i < nrgb; i++) { if (!rgbtab[i].flgs) { blue = (RGBTable[rgbtab[i].kwval] & 0x00FF0000)>>16; green = (RGBTable[rgbtab[i].kwval] & 0x0000FF00)>>8; red = (RGBTable[rgbtab[i].kwval] & 0x000000FF); printf(" %-18s %3d %3d %3d ",rgbtab[i].kwd,red,green,blue); colorcmd = rgbtab[i].kwval << 4; printf("********"); colorcmd = cmdsav; printf("\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } } } printf("\n"); } int setrgb() { int cx, red = 0, blue = 0, green = 0, z, x; if ((cx = cmkey(rgbtab,nrgb,"","",xxstring)) < 0) return(cx); if ((z = cmnum("Red value, 0-255","",10,&red,xxstring)) < 0) return(z); if ((z = cmnum("Green value, 0-255","",10,&green,xxstring)) < 0) return(z); if ((z = cmnum("Blue value, 0-255","",10,&blue,xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); if (cx > 15 || red > 255 || blue > 255 || green > 255) return(-2); RGBTable[cx] = (unsigned)(((unsigned)blue << 16) | (unsigned)((unsigned)green << 8) | (unsigned)red); return(success = 1); } /* Set GUI window position: XY coordinates of upper left corner, expressed as pixel numbers in the current screen resolution. (0,0) means put ourselves in the upper left corner. Can we check for out of bounds? */ int setguiwin() { int cx, x, y, z; if ((cx = cmkey(guiwtab,nguiwtab,"","",xxstring)) < 0) return(cx); switch (cx) { case GUIW_POS: if ((z = cmnum("X coordinate (pixel number)","",10,&x,xxstring)) < 0) return(z); if ((z = cmnum("Y coordinate (pixel number)","",10,&y,xxstring)) < 0) return(z); if ((z = cmcfm()) < 0) return(z); if (x < 0 || y < 0) { printf("?Coordinates must be 0 or greater\n"); return(-9); } gui_position(x,y); return(success = 1); case GUIW_RES: if ((x = cmkey(guiwrtab,nguiwrtab,"","",xxstring)) < 0) return(x); if ((z = cmcfm()) < 0) return(z); gui_resize_mode(x); return(success = 1); case GUIW_RUN: if ((x = cmkey(guiwntab,nguiwntab,"","",xxstring)) < 0) return(x); if ((z = cmcfm()) < 0) return(z); gui_win_run_mode(x); return(success = 1); default: return(-2); } } int setguifont() { /* Assumes that CKFLOAT is defined! */ extern struct keytab * term_font; extern struct keytab * _term_font; extern int tt_font, tt_font_size, ntermfont; int x, z; char *s; if (ntermfont == 0) BuildFontTable(&term_font, &_term_font, &ntermfont); if (!(term_font && _term_font && ntermfont > 0)) { printf("?Internal error: Failure to enumerate fonts\n"); return(-9); } if ((x = cmkey(_term_font,ntermfont,"","",xxstring)) < 0) return(x); if ((z = cmfld("Height of font in points","12",&s,xxstring)) < 0) return(z); if (isfloat(s,0) < 1) { /* (sets floatval) */ printf("?Integer or floating-point number required\n"); return(-9); } if (floatval < 0.5) { printf("?Positive number required\n"); return(-9); } if ((z = cmcfm()) < 0) return(z); tt_font = x; /* Font index */ tt_font_size = (int)(floatval * 2); /* Font size in half points */ KuiSetProperty(KUI_TERM_FONT, (intptr_t)tt_font, (intptr_t)tt_font_size); return(success = 1); } VOID setguidialog(x) int x; { extern int gui_dialog; gui_dialog = x; KuiSetProperty(KUI_GUI_DIALOGS, (intptr_t)x, 0L); } int setguimenubar() { int cx, x, rc; if ((cx = cmkey(guibartab,nguibartab,"","",xxstring)) < 0) { return(cx); } switch (cx) { case GUIB_ON: if ((x = cmcfm()) < 0) return(x); /* Does nothing: Once disabled it stays disabled (its a lock-down * feature) */ return(1); break; case GUIB_OFF: case GUIB_DIS: { if ((x = cmcfm()) < 0) return(x); /* Disable the menubar */ KuiSetProperty(KUI_GUI_MENUBAR, (intptr_t)0, 0L); return(0); } break; case GUIB_VIS: { /* Show or hide the menubar */ rc = seton(&x); if (rc >= 0) { KuiSetProperty(KUI_GUI_MENUBAR_VIS, (intptr_t)x, 0L); } return(rc); } break; } return(0); } int setguitoolbar() { int cx, x, rc; if ((cx = cmkey(guibartab,nguibartab,"","",xxstring)) < 0) { return(cx); } switch (cx) { case GUIB_ON: if ((x = cmcfm()) < 0) return(x); /* Does nothing: Once disabled it stays disabled (its a lock-down * feature) */ return(1); break; case GUIB_OFF: case GUIB_DIS: { if ((x = cmcfm()) < 0) return(x); /* Disable the toolbar */ KuiSetProperty(KUI_GUI_TOOLBAR, (intptr_t)0, 0L); return(0); } break; case GUIB_VIS: { /* Show or hide the toolbar */ rc = seton(&x); if (rc >= 0) { KuiSetProperty(KUI_GUI_TOOLBAR_VIS, (intptr_t)x, 0L); } return(rc); } break; } return(0); } int setguistatusbar() { int x, rc; rc = seton(&x); if (rc >= 0) KuiSetProperty(KUI_GUI_STATBAR_VIS, (intptr_t)x, 0L); return(rc); } VOID setguiclose(x) int x; { KuiSetProperty(KUI_GUI_CLOSE, (intptr_t)x, 0L); } int setgui() { int cx, x, rc; if ((cx = cmkey(guitab,nguitab,"","",xxstring)) < 0) return(cx); switch (cx) { case GUI_DIA: rc = seton(&x); if (rc >= 0) setguidialog(x); return(rc); case GUI_FON: return(setguifont()); case GUI_RGB: return(setrgb()); case GUI_WIN: return(setguiwin()); case GUI_TLB: return(setguitoolbar()); case GUI_STB: return (setguistatusbar()); case GUI_MNB: return (setguimenubar()); case GUI_CLS: rc = seton(&x); if (rc >= 0) setguiclose(x); return(rc); default: return(-2); } } #endif /* KUI */ VOID #ifdef CK_ANSIC setexitwarn( int x ) #else setexitwarn(x) int x; #endif /* CK_ANSIC */ { xitwarn = x; #ifdef KUI KuiSetProperty(KUI_EXIT_WARNING, (intptr_t)x, 0L); #endif /* KUI */ } #ifndef NOLOCAL VOID #ifdef CK_ANSIC setdebses( int x ) #else setdebses(x) int x; #endif /* CK_ANSIC */ { #ifdef OS2 if ((debses != 0) && (x == 0)) /* It was on and we turned it off? */ os2debugoff(); /* Fix OS/2 coloration */ #endif /* OS2 */ debses = x; #ifdef KUI KuiSetProperty(KUI_TERM_DEBUG,x,0); #endif /* KUI */ } #endif /* NOLOCAL */ /* D O P R M -- Set a parameter. */ /* Returns: -2: illegal input -1: reparse needed 0: success */ int #ifdef CK_ANSIC doprm(int xx, int rmsflg) #else doprm(xx,rmsflg) int xx, rmsflg; #endif /* CK_ANSIC */ { int i = 0, x = 0, y = 0, z = 0; long zz = 0L; char *s = NULL; #ifndef NOSETKEY #ifdef OS2 if (xx == XYMSK) return(setmsk()); #endif /* OS2 */ #endif /* NOSETKEY */ if (xx == XYFLAG) { /* SET FLAG */ extern int ooflag; return(success = seton(&ooflag)); } if (xx == XYPRTR /* SET PRINTER (or BPRINTER) */ #ifdef BPRINT || xx == XYBDCP #endif /* BPRINT */ ) return(setprinter(xx)); switch (xx) { #ifdef ANYX25 /* SET X25 ... */ case XYX25: return(setx25()); #ifndef IBMX25 case XYPAD: /* SET PAD ... */ return(setpadp()); #endif /* IBMX25 */ #endif /* ANYX25 */ #ifndef NOXFER case XYEOL: /* These have all been moved to set send/receive... */ case XYLEN: /* Let the user know what to do. */ case XYMARK: case XYNPAD: case XYPADC: case XYTIMO: printf("...Use SET SEND or SET RECEIVE instead.\n"); printf("Type HELP SET SEND or HELP SET RECEIVE for more info.\n"); return(success = 0); case XYATTR: /* File Attribute packets */ return(setat(rmsflg)); case XYIFD: /* Incomplete file disposition */ if ((y = cmkey(ifdatab,3,"","auto",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); if (rmsflg) { sstate = setgen('S', "310", y == 0 ? "0" : (y == 1 ? "1" : "2"), "" ); return((int) sstate); } else { keep = y; return(success = 1); } #endif /* NOXFER */ case XYMATCH: /* [ REMOTE ] SET MATCH... */ #ifndef NOXFER if ((z = cmkey(matchtab,nmatchtab,"","",xxstring)) < 0) return(z); if (rmsflg) { if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); switch (z) { case MCH_DOTF: return(sstate = setgen('S',"330", y == 0 ? "0" : "1", "")); case MCH_FIFO: return(sstate = setgen('S',"331", y == 0 ? "0" : "1", "")); default: return(-2); } } #endif /* NOXFER */ switch (z) { case MCH_FIFO: return(success = seton(&matchfifo)); case MCH_DOTF: x = seton(&matchdot); if (x < 0) return(x); dir_dots = -1; return(success = x); default: return(-2); } #ifndef NOSPL case XYINPU: /* SET INPUT */ return(setinp()); #endif /* NOSPL */ #ifdef NETCONN #ifndef NONETDIR case XYNET: { /* SET NETWORK */ struct FDB k1, k2; cmfdbi(&k1,_CMKEY,"","","",nnetkey, 0, xxstring, netkey, &k2); cmfdbi(&k2,_CMKEY,"","","",nnets, 0, xxstring, netcmd, NULL); #ifdef OS2 /* Hide network-type keywords for networks not installed */ for (z = 0; z < nnets; z++) { if (netcmd[z].kwval == NET_TCPB && tcp_avail == 0) netcmd[z].flgs = CM_INV; #ifdef DECNET if (netcmd[z].kwval == NET_DEC && dnet_avail == 0) netcmd[z].flgs = CM_INV; #endif /* DECNET */ #ifdef CK_NETBIOS else if (netcmd[z].kwval == NET_BIOS && netbiosAvail == 0) netcmd[z].flgs = CM_INV; #endif /* CK_NETBIOS */ #ifdef SUPERLAT else if (netcmd[z].kwval == NET_SLAT && slat_avail == 0) netcmd[z].flgs = CM_INV; #endif /* SUPERLAT */ #if SSH_DLL else if (netcmd[z].kwval == NET_SSH && !ck_ssh_is_installed()) netcmd[z].flgs = CM_INV; #endif /* SSH_DLL */ } if (tcp_avail) /* Default network type */ ckstrncpy(tmpbuf,"tcp/ip",TMPBUFSIZ); #ifdef SSHBUILTIN else if ( ck_ssh_is_installed() ) ckstrncpy(tmpbuf,"ssh",TMPBUFSIZ); #endif /* SSHBUILTIN */ #ifdef DECNET else if (dnet_avail) ckstrncpy(tmpbuf,"decnet",TMPBUFSIZ); #endif /* DECNET */ #ifdef SUPERLAT else if (slat_avail) ckstrncpy(tmpbuf,"superlat",TMPBUFSIZ); #endif /* SUPERLAT */ #ifdef CK_NETBIOS else if (netbiosAvail) ckstrncpy(tmpbuf,"netbios",TMPBUFSIZ); #endif /* CK_NETBIOS */ else ckstrncpy(tmpbuf,"named-pipe",TMPBUFSIZ); #else /* OS2 */ #ifdef TCPSOCKET ckstrncpy(tmpbuf,"tcp/ip",TMPBUFSIZ); #else #ifdef ANYX25 ckstrncpy(tmpbuf,"x.25",TMPBUFSIZ); #else ckstrncpy(tmpbuf,"",TMPBUFSIZ); #endif /* ANYX25 */ #endif /* TCPSOCKET */ #endif /* OS2 */ x = cmfdb(&k1); if (x < 0) { /* Error */ if (x == -2 || x == -9) printf("?No keywords match: \"%s\"\n",atmbuf); return(x); } z = cmresult.nresult; /* Keyword value */ if (cmresult.fdbaddr == &k1) { /* Which table? */ #ifndef NOSPL #ifndef NODIAL if (z == XYNET_D) return(parsdir(1)); #endif /* NODIAL */ #endif /* NOSPL */ if ((z = cmkey(netcmd,nnets,"",tmpbuf,xxstring)) < 0) return(z); } #ifdef NETCMD if (z == NET_CMD && nopush) { printf("\n?Sorry, access to external commands is disabled\n"); return(-9); } #endif /* NETCMD */ #ifndef NOPUSH #ifdef NETPTY if (z == NET_PTY && nopush) { printf("\n?Sorry, access to external commands is disabled\n"); return(-9); } #endif /* NETPTY */ #endif /* NOPUSH */ #ifdef SSH_DLL if (z == NET_SSH && !ssh_avail()) { printf("\n?Sorry, no SSH backend DLL loaded; SSH commands are disabled. Use the SSH LOAD\n" "command to load a compatible SSH backend if you have one.\n"); return(-9); } #endif #ifdef OS2 if (z == NET_TCPB && tcp_avail == 0) { printf( "\n?Sorry, either TCP/IP is not available on this system or\n\ necessary DLLs did not load. Use SHOW NETWORK to check network status.\n"); return(-9); #ifdef CK_NETBIOS } else if (z == NET_BIOS && netbiosAvail == 0) { printf("\n?Sorry, NETBIOS is not available on this system.\n") ; return(-9); #endif /* CK_NETBIOS */ #ifdef DECNET } else if (z == NET_DEC && dnet_avail == 0) { printf("\n?Sorry, DECnet is not available on this system.\n") ; return(-9); #endif /* DECNET */ #ifdef SUPERLAT } else if (z == NET_SLAT && slat_avail == 0) { printf("\n?Sorry, SuperLAT is not available on this system.\n") ; return(-9); #endif /* SUPERLAT */ } #endif /* OS2 */ #ifdef NPIPEORBIOS if (z == NET_PIPE || /* Named pipe -- also get pipename */ z == NET_BIOS) { /* NETBIOS -- also get local name */ char *defnam; #ifdef CK_NETBIOS char tmpnbnam[NETBIOS_NAME_LEN+1]; #endif /* CK_NETBIOS */ /* Construct default name */ if (z == NET_PIPE) { /* Named pipe */ defnam = "kermit"; /* Default name is always "kermit" */ } #ifdef CK_NETBIOS else { /* NetBIOS */ if (NetBiosName[0] != SP) { /* If there is already a name, */ char *p = NULL; int n; /* use it as the default. */ ckstrncpy(tmpnbnam,NetBiosName,NETBIOS_NAME_LEN+1); /* convert trailing spaces to NULs */ p = &tmpnbnam[NETBIOS_NAME_LEN-1]; while (*p == SP) { *p = NUL; p--; } defnam = tmpnbnam; } else if (*myhost) /* Otherwise use this PC's host name */ defnam = (char *) myhost; else /* Otherwise use "kermit" */ defnam = "kermit"; } #endif /* CK_NETBIOS */ if ((y = cmtxt((z == NET_PIPE) ? "name of named-pipe" : "local NETBIOS name", defnam, &s, xxstring)) < 0) return(y); #ifdef NPIPE pipename[0] = NUL; #endif /* NPIPE */ if ((y = (int) strlen(s)) < 1) { printf("?You must also specify a %s name\n", (z == NET_PIPE) ? "pipe" : "local NETBIOS" ); return(-9); } #ifdef CK_NETBIOS if (z == NET_BIOS) { if (!netbiosAvail) { printf("?NETBIOS is not available on this system.\n") ; return(-9); } if (y - NETBIOS_NAME_LEN > 0) { printf("?NETBIOS name too long, %ld maximum\n", NETBIOS_NAME_LEN); return(-9); } else if ( !strcmp(s,tmpnbnam) ) { nettype = z; /* Returning to old connection... */ return(success = 1); /* Done */ } else if (strcmp(" ",NetBiosName)) { printf("?NETBIOS name already assigned to \"%s\"\n", NetBiosName); return(-9); } else { NCB ncb; APIRET rc; ckstrncpy(NetBiosName,s,16); for (x = y; x < NETBIOS_NAME_LEN; x++) NetBiosName[x] = SP; NetBiosName[NETBIOS_NAME_LEN] = NUL; printf("Checking \"%s\" as a unique NetBIOS name...\n", NetBiosName); rc = NCBAddName( NetbeuiAPI, &ncb, NetBiosAdapter, NetBiosName ); if (rc) { printf( "?Sorry, \"%s\" is already in use by another NetBIOS node.\n", NetBiosName); for (x = 0; x < NETBIOS_NAME_LEN; x++) NetBiosName[x] = SP; return(-9); } } } #endif /* CK_NETBIOS */ #ifdef NPIPE if (z == NET_PIPE) ckstrncpy(pipename,s,PIPENAML); #endif /* NPIPE */ } else #endif /* NPIPEORBIOS */ #ifdef DECNET if (z == NET_DEC) { /* Determine if we are using LAT or CTERM */ if ((y = cmkey(dnettab, ndnet,"DECNET protocol","lat",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); ttnproto = y; } else #endif /* DECNET */ #ifdef NETDLL if (z == NET_DLL) { /* Find out which DLL they are using */ char dllname[256]=""; char * p=NULL; if ((x = cmifi("Dynamic load library", "",&p,&y,xxstring)) < 0) { if (x == -3) { printf("?Name of DLL required\n"); return(-9); } return(x); } ckstrncpy(dllname,p,256); if ((x = cmcfm()) < 0) return(x); if (netdll_load(dllname) < 0) /* Try to load the dll */ return(success = 0); else { nettype = z; return(success = 1); } } else #endif /* NETDLL */ if ((x = cmcfm()) < 0) return(x); nettype = z; if ( #ifdef DECNET (nettype != NET_DEC) && #endif /* DECNET */ #ifdef NPIPE (nettype != NET_PIPE) && #endif /* NPIPE */ #ifdef CK_NETBIOS (nettype != NET_BIOS) && #endif /* CK_NETBIOS */ #ifdef NETFILE (nettype != NET_FILE) && #endif /* NETFILE */ #ifdef NETCMD (nettype != NET_CMD) && #endif /* NETCMD */ #ifdef NETPTY (nettype != NET_PTY) && #endif /* NETPTY */ #ifdef NETDLL (nettype != NET_DLL) && #endif /* NETDLL */ #ifdef SUPERLAT (nettype != NET_SLAT) && #endif /* SUPERLAT */ (nettype != NET_SX25) && (nettype != NET_VX25) && #ifdef IBMX25 (nettype != NET_IX25) && #endif /* IBMX25 */ #ifdef SSHBUILTIN (nettype != NET_SSH) && #endif /* SSHBUILTIN */ (nettype != NET_TCPB)) { printf("?Network type not supported\n"); return(success = 0); } else { return(success = 1); } } #endif /* NONETDIR */ #ifndef NOTCPOPTS #ifdef TCPSOCKET case XYTCP: { #ifdef OS2 extern CK_TTYFD_T ttyfd; #else /* OS2 */ extern int ttyfd; #endif if ((z = cmkey(tcpopt,ntcpopt,"TCP option","nodelay",xxstring)) < 0) return(z); switch (z) { #ifndef NOHTTP case XYTCP_HTTP_PROXY: { struct FDB sw, tx; int n, x; char ubuf[LOGINLEN+1], pbuf[LOGINLEN+1], abuf[256]; ubuf[0] = pbuf[0] = abuf[0] = 0; cmfdbi(&sw, /* First FDB - switches */ _CMKEY, /* fcode */ "HTTP proxy server host[:port] or switch", "", /* default */ "", /* addtl string data */ nuserpass, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ userpass, /* Keyword table */ &tx /* Pointer to next FDB */ ); cmfdbi(&tx, _CMTXT, /* fcode */ "HTTP proxy server host[:port]", "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); while (1) { if ((x = cmfdb(&sw)) < 0) { if (x == -3) { x = -9; printf("?Hostname required\n"); } return(x); } if (cmresult.fcode != _CMKEY) break; n = cmresult.nresult; switch (n) { case UPW_USER: case UPW_PASS: case UPW_AGENT: if ((x = cmfld((n == UPW_USER) ? "Username" : ((n == UPW_PASS) ? "Password" : "Agent"), "", &s, xxstring)) < 0) { if (x != -3) return(x); } ckstrncpy((n == UPW_USER) ? ubuf : ((n == UPW_PASS) ? pbuf : abuf), s, (n == UPW_AGENT) ? 256 : (LOGINLEN+1)); } } if (cmresult.fcode != _CMTXT) return(-2); s = cmresult.sresult; if (s) if (!*s) s = NULL; #ifdef IKSDCONF if (iksdcf) return(success = 0); #endif /* IKSDCONF */ makestr(&tcp_http_proxy_user,ubuf[0]?ubuf:NULL); makestr(&tcp_http_proxy_pwd,pbuf[0]?pbuf:NULL); makestr(&tcp_http_proxy_agent,abuf[0]?abuf:NULL); makestr(&tcp_http_proxy,s); memset(pbuf,0,sizeof(pbuf)); return(success = 1); } #endif /* NOHTTP */ /* It would have been easy to combine XYTCP_SOCKS_SVR with the previous one except for the #ifdefs... */ #ifdef NT #ifdef CK_SOCKS case XYTCP_SOCKS_SVR: { char ubuf[LOGINLEN+1], pbuf[LOGINLEN+1]; char * p = getenv("SOCKS_SERVER"); struct FDB sw, tx; int n, x; if (!p) p = ""; cmfdbi(&sw, /* First FDB - switches */ _CMKEY, /* fcode */ "SOCKS server host[:port] or switch", "", /* default */ "", /* addtl string data */ nuserpass, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ userpass, /* Keyword table */ &tx /* Pointer to next FDB */ ); cmfdbi(&tx, _CMTXT, /* fcode */ "SOCKS server host[:port]", p, /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); while (1) { if ((x = cmfdb(&sw)) < 0) { if (x == -3) { x = -9; printf("?Hostname required\n"); } return(x); } if (cmresult.fcode != _CMKEY) break; n = cmresult.nresult; switch (n) { case UPW_USER: case UPW_PASS: if ((x = cmfld((n == UPW_USER) ? "Username" : "Password", "", &s, xxstring)) < 0) { if (x != -3) return(x); } ckstrncpy((n == UPW_USER) ? ubuf : pbuf, s, LOGINLEN+1); } } if (cmresult.fcode != _CMTXT) return(-2); s = cmresult.sresult; if (s) if (!*s) s = NULL; #ifdef IKSDCONF if (iksdcf) return(success = 0); #endif /* IKSDCONF */ makestr(&tcp_socks_user,ubuf); memset(pbuf,0,sizeof(pbuf)); makestr(&tcp_socks_svr,s); return(success = 1); } #ifdef CK_SOCKS_NS case XYTCP_SOCKS_NS: { char * p = getenv("SOCKS_NS"); if (!p) p = ""; if ((y = cmtxt("hostname or IP of SOCKS Name Server",p, &s,xxstring)) < 0) return(y); #ifdef IKSDCONF if (iksdcf) return(success = 0); #endif /* IKSDCONF */ if (tcp_socks_ns) { free(tcp_socks_ns); /* Free any previous storage */ tcp_socks_ns = NULL; } if (s == NULL || *s == NUL) { /* If none given */ tcp_socks_ns = NULL; /* remove the override string */ return(success = 1); } else if ((tcp_socks_ns = malloc(strlen(s)+1))) { strcpy(tcp_socks_ns,s); return(success = 1); } else return(success = 0); } #endif /* CK_SOCKS_NS */ #endif /* CK_SOCKS */ #endif /* NT */ case XYTCP_ADDRESS: if ((y = cmtxt("preferred IP Address for TCP connections","", &s,xxstring)) < 0) return(y); #ifdef IKSDCONF if (iksdcf) return(success = 0); #endif /* IKSDCONF */ if (tcp_address) { free(tcp_address); /* Free any previous storage */ tcp_address = NULL; } if (s == NULL || *s == NUL) { /* If none given */ tcp_address = NULL; /* remove the override string */ return(success = 1); } else if ((tcp_address = malloc(strlen(s)+1))) { strcpy(tcp_address,s); return(success = 1); } else return(success = 0); #ifdef SO_KEEPALIVE case XYTCP_KEEPALIVE: if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); #ifdef IKSDCONF if (iksdcf) return(success = 0); #endif /* IKSDCONF */ #ifdef SSHBUILTIN if (network && nettype == NET_SSH && ssh_get_socket() != -1) success = keepalive(ssh_get_socket(),z); else #endif /* SSHBUILTIN */ success = keepalive(ttyfd,z); return(success); #endif /* SO_KEEPALIVE */ #ifdef SO_DONTROUTE case XYTCP_DONTROUTE: if ((z = cmkey(onoff,2,"","off",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); #ifdef IKSDCONF if (iksdcf) return(success = 0); #endif /* IKSDCONF */ #ifdef SSHBUILTIN if (network && nettype == NET_SSH && ssh_get_socket() != -1) success = dontroute(ssh_get_socket(),z); else #endif /* SSHBUILTIN */ success = dontroute(ttyfd,z); return(success); #endif /* SO_DONTROUTE */ #ifdef TCP_NODELAY case XYTCP_NODELAY: if ((z = cmkey(onoff,2,"","off",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); #ifdef IKSDCONF if (iksdcf) return(success = 0); #endif /* IKSDCONF */ #ifdef SSHBUILTIN if (network && nettype == NET_SSH && ssh_get_socket() != -1) success = no_delay(ssh_get_socket(),z); else #endif /* SSHBUILTIN */ success = no_delay(ttyfd,z); return(success); case XYTCP_NAGLE: /* The inverse of NODELAY */ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); #ifdef IKSDCONF if (iksdcf) return(success = 0); #endif /* IKSDCONF */ #ifdef SSHBUILTIN if (network && nettype == NET_SSH && ssh_get_socket() != -1) success = no_delay(ssh_get_socket(),z); else #endif /* SSHBUILTIN */ success = no_delay(ttyfd,!z); return(success); #endif /* TCP_NODELAY */ #ifdef SO_LINGER case XYTCP_LINGER: if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z); if (z) { /* if on, we need a timeout value */ if ((x = cmnum("Linger timeout in 10th of a millisecond", "0",10,&y,xxstring)) < 0) return(x); } else y = 0; if ((x = cmcfm()) < 0) return(x); #ifdef IKSDCONF if (iksdcf) return(success = 0); #endif /* IKSDCONF */ #ifdef SSHBUILTIN if (network && nettype == NET_SSH && ssh_get_socket() != -1) success = ck_linger(ssh_get_socket(),z,y); else #endif /* SSHBUILTIN */ success = ck_linger(ttyfd,z,y); return(success); #endif /* SO_LINGER */ #ifdef SO_SNDBUF case XYTCP_SENDBUF: x = cmnum("Send buffer size, bytes","8192",10,&z,xxstring); if (x < 0) return(x); if ((x = cmcfm()) < 0) return(x); #ifdef IKSDCONF if (iksdcf) return(success = 0); #endif /* IKSDCONF */ #ifdef SSHBUILTIN if (network && nettype == NET_SSH && ssh_get_socket() != -1) success = sendbuf(ssh_get_socket(),z); else #endif /* SSHBUILTIN */ success = sendbuf(ttyfd,z); return(success); #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF case XYTCP_RECVBUF: x = cmnum("Receive buffer size, bytes","8192",10,&z,xxstring); if (x < 0) return(x); if ((x = cmcfm()) < 0) return(x); #ifdef IKSDCONF if (iksdcf) return(success = 0); #endif /* IKSDCONF */ /* Note: The following is not 16-bit safe */ #ifndef QNX16 if (x > 52248) { printf("?Warning: receive buffers larger than 52248 bytes\n"); printf(" may not be understood by all hosts. Performance\n"); printf(" may suffer.\n"); return(-9); } #endif /* QNX16 */ #ifdef SSHBUILTIN if (network && nettype == NET_SSH && ssh_get_socket() != -1) success = recvbuf(ssh_get_socket(),z); else #endif /* SSHBUILTIN */ success = recvbuf(ttyfd,z); return(success); #endif /* SO_RCVBUF */ #ifdef VMS #ifdef DEC_TCPIP case XYTCP_UCX: { /* UCX 2.0 port swabbing bug */ extern int ucx_port_bug; return(success = seton(&ucx_port_bug)); } #endif /* DEC_TCPIP */ #endif /* VMS */ case XYTCP_RDNS: { extern int tcp_rdns; return(success = setonaut(&tcp_rdns)); } #ifdef CK_DNS_SRV case XYTCP_DNS_SRV: { extern int tcp_dns_srv; return(success = seton(&tcp_dns_srv)); } #endif /* CK_DNS_SRV */ default: return(0); } } #endif /* TCPSOCKET */ #endif /* NOTCPOPTS */ #endif /* NETCONN */ } switch (xx) { #ifndef NOLOCAL #ifdef NETCONN case XYHOST: { /* SET HOST */ z = ttnproto; /* Save protocol in case of failure */ #ifdef DECNET if (nettype != NET_DEC) #endif /* DECNET */ ttnproto = NP_NONE; if ((y = setlin(XYHOST,1,0)) <= 0) { /* Sets success to 1 */ debug(F101,"SET HOST fail mdmtyp","",mdmtyp); ttnproto = z; /* Failed, restore protocol */ success = 0; } didsetlin++; debug(F101,"SET HOST OK mdmtyp","",mdmtyp); debug(F101,"SET HOST reliable","",reliable); return(y); } #endif /* NETCONN */ case XYLINE: /* SET LINE (= SET PORT) */ debug(F101,"setlin flow 1","",flow); x = setlin(xx,1,0); if (x > -1) didsetlin++; debug(F101,"SET LINE setlin","",x); debug(F101,"SET LINE flow","",flow); debug(F101,"SET LINE local","",local); debug(F101,"SET LINE reliable","",reliable); return(x); #endif /* NOLOCAL */ #ifndef NOSETKEY case XYKEY: /* SET KEY */ return(dosetkey()); #endif /* NOSETKEY */ #ifndef NOCSETS case XYLANG: /* Language */ if ((y = cmkey(lngtab,nlng,"","none",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); /* Look up language and get associated character sets */ for (i = 0; (i < nlangs) && (langs[i].id != y); i++) ; if (i >= nlangs) { printf("?internal error, sorry\n"); return(success = 0); } /* */ language = i; /* All good, set the language, */ return(success = 1); #endif /* NOCSETS */ #ifndef MAC case XYBACK: /* BACKGROUND */ if ((z = cmkey(onoff,2,"","",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); #ifdef COMMENT bgset = z; /* 0 = off (foreground) */ #ifdef VMS /* 1 = on (background) */ if (batch && bgset == 0) /* To enable echoing of commands */ ckxech = 1; /* in VMS batch logs */ #endif /* VMS */ #else /* COMMENT */ if (z) { /* 1 = Background */ bgset = 1; backgrd = 1; #ifdef VMS batch = 1; #endif /* VMS */ } else { /* 0 = Foreground */ bgset = 0; backgrd = 0; #ifdef VMS batch = 0; #endif /* VMS */ } #endif /* COMMENT */ success = 1; bgchk(); return(success); #endif /* MAC */ case XYQUIE: { /* QUIET */ #ifdef DCMDBUF extern int * xquiet; #else extern int xquiet[]; #endif /* DCMDBUF */ x = seton(&quiet); if (x < 0) return(x); xquiet[cmdlvl] = quiet; return(success = x); } #ifndef NOXFER case XYBUF: { /* BUFFERS */ #ifdef DYNAMIC int sb, rb; if ((y = cmnum("Send buffer size","",10,&sb,xxstring)) < 0) { if (y == -3) printf("?Buffer size required\n"); return(y); } if (sb < 0) { if (*atmbuf == '-') printf("?Negative numbers can't be used here\n"); else printf("?Integer overflow, use a smaller number please\n"); return(-9); } else if (sb < 80) { printf("?Too small\n"); return(-9); } if ((y=cmnum("Receive buffer size",ckitoa(sb),10,&rb,xxstring)) < 0) return(y); if (rb < 0) { if (*atmbuf == '-') printf("?Negative numbers can't be used here\n"); else printf("?Integer overflow, use a smaller number please\n"); return(-9); } else if (rb < 80) { printf("?Too small\n"); return(-9); } if ((y = cmcfm()) < 0) return(y); if ((y = inibufs(sb,rb)) < 0) return(y); y = adjpkl(urpsiz,wslotr,bigrbsiz); /* Maybe adjust packet sizes */ if (y != urpsiz) urpsiz = y; y = adjpkl(spsiz,wslotr,bigsbsiz); if (y != spsiz) spsiz = spmax = spsizr = y; return(success = 1); #else printf("?Sorry, not available\n"); return(success = 0); #endif /* DYNAMIC */ } case XYCHKT: /* BLOCK-CHECK */ if ((x = cmkey(chktab,nchkt,"","3",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); if (x == 5) { bctf = 1; #ifdef COMMENT printf("?5 - Not implemented yet\n"); return(success = 0); #endif /* COMMENT */ } bctr = x; /* Set local too even if REMOTE SET */ if (rmsflg) { if (x == 4) { tmpbuf[0] = 'B'; tmpbuf[1] = '\0'; } else ckstrncpy(tmpbuf,ckitoa(x),TMPBUFSIZ); sstate = setgen('S', "400", tmpbuf, ""); return((int) sstate); } else { return(success = 1); } #endif /* NOXFER */ #ifndef NOLOCAL #ifndef MAC /* The Mac has no RS-232 */ case XYCARR: /* CARRIER-WATCH */ return(setdcd()); #endif /* MAC */ #endif /* NOLOCAL */ } #ifdef TNCODE switch (xx) { /* Avoid long switch statements... */ case XYTELOP: { int c; /* Workers */ int getval = 0; /* Whether to get switch value */ int tnserver = 0; /* Client by default */ int opt = -1; /* Telnet Option */ struct FDB sw, op; /* FDBs for each parse function */ #ifdef CK_AUTHENTICATION extern int sl_topt_a_s_saved; extern int sl_topt_a_c_saved; extern int sl_topt_e_s_saved; extern int sl_topt_e_c_saved; #endif /* CK_AUTHENTICATION */ #ifdef IKSD if (inserver) /* Server by default when IKSD */ tnserver = 1; #endif /* IKSD */ /* Set up chained parse functions... */ cmfdbi(&op, /* First fdb - telopts*/ _CMKEY, /* fcode */ "/client, /server or", /* hlpmsg */ "", /* default */ "", /* addtl string data */ ntnopt, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, tnopttab, &sw ); cmfdbi(&sw, /* Second FDB - command switches */ _CMKEY, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ ntnoptsw, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ tnoptsw, /* Keyword table */ NULL /* Pointer to next FDB */ ); while (opt < 0) { /* Parse 0 or more switches */ x = cmfdb(&op); /* Parse switch or other thing */ debug(F101,"XYTELOP cmfdb","",x); if (x < 0) /* Error */ return(x); /* or reparse needed */ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */ break; c = cmgbrk(); /* Get break character */ getval = (c == ':' || c == '='); /* see how switch ended */ if (getval && !(cmresult.kflags & CM_ARG)) { printf("?This switch does not take arguments\n"); return(-9); } z = cmresult.nresult; /* Numeric result = switch value */ debug(F101,"XYTELOP switch","",z); switch (z) { /* Process the switch */ case CK_TN_CLIENT: tnserver = 0; break; case CK_TN_SERVER: tnserver = 1; break; case CK_TN_EC: opt = TELOPT_ECHO; break; case CK_TN_TT: opt = TELOPT_TTYPE; break; case CK_TN_BM: opt = TELOPT_BINARY; break; case CK_TN_ENV: opt = TELOPT_NEWENVIRON; break; case CK_TN_LOC: opt = TELOPT_SNDLOC; break; case CK_TN_AU: opt = TELOPT_AUTHENTICATION; break; case CK_TN_FX: opt = TELOPT_FORWARD_X; break; case CK_TN_ENC: opt = TELOPT_ENCRYPTION; break; case CK_TN_IKS: opt = TELOPT_KERMIT; break; case CK_TN_TLS: opt = TELOPT_START_TLS; break; case CK_TN_XD: opt = TELOPT_XDISPLOC; break; case CK_TN_NAWS: opt = TELOPT_NAWS; break; case CK_TN_SGA: opt = TELOPT_SGA; break; case CK_TN_PHR: opt = TELOPT_PRAGMA_HEARTBEAT; break; case CK_TN_PSP: opt = TELOPT_SSPI_LOGON; break; case CK_TN_PLG: opt = TELOPT_PRAGMA_LOGON; break; case CK_TN_SAK: opt = TELOPT_IBM_SAK; break; case CK_TN_CPC: opt = TELOPT_COMPORT; break; case CK_TN_LOG: opt = TELOPT_LOGOUT; break; case CK_TN_FLW: opt = TELOPT_LFLOW; break; default: printf("?Unexpected value - %d\n",z); return(-9); } #ifdef COMMENT if (cmresult.fdbaddr == &op) break; #endif /* COMMENT */ } switch (opt) { case TELOPT_ECHO: /* Options only the Server WILL */ case TELOPT_FORWARD_X: case TELOPT_SEND_URL: case TELOPT_IBM_SAK: case TELOPT_LOGOUT: if ((x = cmkey(tnnegtab, ntnnegtab, "desired server state", TELOPT_MODE(tnserver?TELOPT_DEF_S_ME_MODE(opt):TELOPT_DEF_C_U_MODE(opt)), xxstring) ) < 0) return(x); if ((z = cmcfm()) < 0) return(z); if (tnserver) { TELOPT_DEF_S_ME_MODE(opt) = x; TELOPT_ME_MODE(opt) = x; } else { TELOPT_DEF_C_U_MODE(opt) = x; TELOPT_U_MODE(opt) = x; } break; case TELOPT_TTYPE: /* Options only the Client WILL */ case TELOPT_NEWENVIRON: case TELOPT_SNDLOC: case TELOPT_AUTHENTICATION: case TELOPT_START_TLS: case TELOPT_XDISPLOC: case TELOPT_NAWS: case TELOPT_LFLOW: case TELOPT_COMPORT: if ((x = cmkey(tnnegtab, ntnnegtab, "desired client state", TELOPT_MODE(!tnserver?TELOPT_DEF_S_U_MODE(opt):TELOPT_DEF_C_ME_MODE(opt)), xxstring) ) < 0) return(x); if ((z = cmcfm()) < 0) return(z); if (tnserver) { TELOPT_DEF_S_U_MODE(opt) = x; TELOPT_U_MODE(opt) = x; #ifdef CK_AUTHENTICATION if (opt == TELOPT_AUTHENTICATION) sl_topt_a_s_saved = 0; #endif /* CK_AUTHENTICATION */ } else { TELOPT_DEF_C_ME_MODE(opt) = x; TELOPT_ME_MODE(opt) = x; #ifdef CK_AUTHENTICATION if (opt == TELOPT_AUTHENTICATION) sl_topt_a_c_saved = 0; #endif /* CK_AUTHENTICATION */ } break; default: if ((x = cmkey(tnnegtab, ntnnegtab, tnserver ? "desired server state" : "desired client state", TELOPT_MODE(tnserver?TELOPT_DEF_S_ME_MODE(opt):TELOPT_DEF_C_ME_MODE(opt)), xxstring ) ) < 0) return(x); if ((y = cmkey(tnnegtab, ntnnegtab, !tnserver ? "desired server state" : "desired client state", TELOPT_MODE(!tnserver?TELOPT_DEF_S_U_MODE(opt):TELOPT_DEF_C_U_MODE(opt)), xxstring ) ) < 0) return(y); if ((z = cmcfm()) < 0) return(z); if (tnserver) { TELOPT_DEF_S_ME_MODE(opt) = x; TELOPT_ME_MODE(opt) = x; TELOPT_DEF_S_U_MODE(opt) = y; TELOPT_U_MODE(opt) = y; #ifdef CK_ENCRYPTION if (opt == TELOPT_ENCRYPTION) sl_topt_e_s_saved = 0; #endif /* CK_ENCRYPTION */ } else { TELOPT_DEF_C_ME_MODE(opt) = x; TELOPT_ME_MODE(opt) = x; TELOPT_DEF_C_U_MODE(opt) = y; TELOPT_U_MODE(opt) = y; #ifdef CK_ENCRYPTION if (opt == TELOPT_ENCRYPTION) sl_topt_e_c_saved = 0; #endif /* CK_ENCRYPTION */ } } return(success = 1); } case XYTEL: /* TELNET */ if ((z = cmkey(tntab,ntn,"parameter for TELNET negotiations", "", xxstring)) < 0) return(z); switch (z) { case CK_TN_EC: /* ECHO */ if ((x = cmkey(rltab,nrlt, "initial TELNET echoing state", "local",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); tn_duplex = x; return(success = 1); case CK_TN_RE: /* REMOTE-ECHO */ return(success = seton(&tn_rem_echo)); case CK_TN_DB: /* DEBUG */ return(success = seton(&tn_deb)); case CK_TN_TT: /* TERMINAL TYPE */ if ((y = cmtxt("terminal type for TELNET connections","", &s,xxstring)) < 0) return(y); if (tn_term) { free(tn_term); /* Free any previous storage */ tn_term = NULL; } if (s == NULL || *s == NUL) { /* If none given */ tn_term = NULL; /* remove the override string */ return(success = 1); } else if ((tn_term = malloc(strlen(s)+1))) { strcpy(tn_term,s); return(success = 1); } else return(success = 0); #ifdef CK_FORWARD_X case CK_TN_FX: /* FORWARD-X */ if ((x=cmkey(tnfwdxtab,ntnfwdx,"","xauthority-file",xxstring)) < 0) return(x); switch (x) { case 0: { /* Xauthority-File */ x = cmifi("Full path of .Xauthority file","",&s,&y,xxstring); if (x < 0 && x != -3) return(x); makestr(&tn_fwdx_xauthority,s); return(success = 1); } case 1: { /* No-Encryption */ extern int fwdx_no_encrypt; return(success = seton(&fwdx_no_encrypt)); } } return(success = 0); #endif /* CK_FORWARD_X */ case CK_TN_NL: /* TELNET NEWLINE-MODE */ if ((x = cmkey(tn_nlmtab,ntn_nlm,"","nvt",xxstring)) < 0) return(x); if (x == TN_NL_BIN) { if ((x = cmkey(tnlmtab,ntnlm,"","raw",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); tn_b_nlm = x; return(success = 1); } else if (x == TN_NL_NVT) { if ((x = cmkey(tnlmtab,ntnlm,"","on",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); tn_nlm = x; return(success = 1); } else { if ((y = cmcfm()) < 0) return(y); tn_nlm = x; return(success = 1); } case CK_TN_XF: /* BINARY-TRANSFER-MODE */ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); tn_b_xfer = z; return(success = 1); case CK_TN_NE: /* NO-ENCRYPT-DURING-XFER */ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); #ifdef CK_APC /* Don't let this be set remotely */ if (apcactive == APC_LOCAL || (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))) return(success = 0); #endif /* CK_APC */ tn_no_encrypt_xfer = z; return(success = 1); case CK_TN_BM: /* BINARY-MODE */ if ((x = cmkey(tnnegtab,ntnnegtab,"","refused",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); TELOPT_DEF_S_ME_MODE(TELOPT_BINARY) = x; TELOPT_DEF_S_U_MODE(TELOPT_BINARY) = x; TELOPT_DEF_C_ME_MODE(TELOPT_BINARY) = x; TELOPT_DEF_C_U_MODE(TELOPT_BINARY) = x; return(success = 1); #ifdef IKS_OPTION case CK_TN_IKS: /* KERMIT */ if ((x = cmkey(tnnegtab,ntnnegtab,"DO","accept",xxstring)) < 0) return(x); if ((y = cmkey(tnnegtab,ntnnegtab,"WILL","accept",xxstring)) < 0) return(y); if ((z = cmcfm()) < 0) return(z); TELOPT_DEF_S_ME_MODE(TELOPT_KERMIT) = y; TELOPT_DEF_S_U_MODE(TELOPT_KERMIT) = x; TELOPT_DEF_C_ME_MODE(TELOPT_KERMIT) = y; TELOPT_DEF_C_U_MODE(TELOPT_KERMIT) = x; return(success = 1); #endif /* IKS_OPTION */ #ifdef CK_SSL case CK_TN_TLS: /* START_TLS */ if ((x = cmkey(tnnegtab,ntnnegtab,"me","accept",xxstring)) < 0) return(x); if ((y = cmkey(tnnegtab,ntnnegtab,"u","accept",xxstring)) < 0) return(y); if ((z = cmcfm()) < 0) return(z); TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = x; TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = y; TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = x; TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = y; return(success = 1); #endif /* CK_SSL */ #ifdef CK_NAWS case CK_TN_NAWS: /* NAWS */ if ((x = cmkey(tnnegtab,ntnnegtab,"me","accept",xxstring)) < 0) return(x); if ((y = cmkey(tnnegtab,ntnnegtab,"u","accept",xxstring)) < 0) return(y); if ((z = cmcfm()) < 0) return(z); TELOPT_DEF_S_ME_MODE(TELOPT_NAWS) = x; TELOPT_DEF_S_U_MODE(TELOPT_NAWS) = y; TELOPT_DEF_C_ME_MODE(TELOPT_NAWS) = x; TELOPT_DEF_C_U_MODE(TELOPT_NAWS) = y; return(success = 1); #endif /* CK_NAWS */ #ifdef CK_AUTHENTICATION case CK_TN_AU: /* AUTHENTICATION */ if ((x = cmkey(tnauthtab,ntnauth,"","",xxstring)) < 0) return(x); if (x == TN_AU_FWD) { extern int forward_flag; return(success = seton(&forward_flag)); } else if (x == TN_AU_TYP) { extern int auth_type_user[]; extern int sl_auth_type_user[]; extern int sl_auth_saved; int i, j, atypes[AUTHTYPLSTSZ]; for (i = 0; i < AUTHTYPLSTSZ; i++) { if ((y = cmkey(autyptab,nautyp,"", i == 0 ? "automatic" : "" , xxstring)) < 0) { if (y == -3) break; return(y); } if (i > 0 && (y == AUTHTYPE_AUTO || y == AUTHTYPE_NULL)) { printf( "\r\n?Choice may only be used in first position.\r\n"); return(-9); } for (j = 0; j < i; j++) { if (atypes[j] == y) { printf("\r\n?Choice has already been used.\r\n"); return(-9); } } atypes[i] = y; if (y == AUTHTYPE_NULL || y == AUTHTYPE_AUTO) { i++; break; } } if (i < AUTHTYPLSTSZ) atypes[i] = AUTHTYPE_NULL; if ((z = cmcfm()) < 0) return(z); sl_auth_saved = 0; for (i = 0; i < AUTHTYPLSTSZ; i++) { auth_type_user[i] = atypes[i]; sl_auth_type_user[i] = 0; } } else if (x == TN_AU_HOW) { if ((y = cmkey(auhowtab,nauhow,"","any",xxstring)) < 0) return(y); if ((z = cmcfm()) < 0) return(z); tn_auth_how = y; } else if (x == TN_AU_ENC) { if ((y = cmkey(auenctab,nauenc,"","encrypt",xxstring)) < 0) return(y); if ((z = cmcfm()) < 0) return(z); tn_auth_enc = y; } else { if ((y = cmcfm()) < 0) return(y); TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = x; TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = x; } return(success = 1); #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION case CK_TN_ENC: { /* ENCRYPTION */ int c, tmp = -1; int getval = 0; static struct keytab * tnetbl = NULL; static int ntnetbl = 0; if ((y = cmkey(tnenctab,ntnenc,"","",xxstring)) < 0) return(y); switch (y) { case TN_EN_TYP: x = ck_get_crypt_table(&tnetbl,&ntnetbl); debug(F101,"ck_get_crypt_table x","",x); debug(F101,"ck_get_crypt_table n","",ntnetbl); if (x < 1 || !tnetbl || ntnetbl < 1) /* Didn't get it */ x = 0; if (!x) { printf("?Oops, types not loaded\n"); return(-9); } if ((x = cmkey(tnetbl,ntnetbl,"type of encryption", "automatic",xxstring)) < 0) return(x); if ((z = cmcfm()) < 0) return(z); cx_type = x; sl_cx_type = 0; break; case TN_EN_START: if ((z = cmcfm()) < 0) return(z); #ifdef CK_APC /* Don't let this be set remotely */ if (apcactive == APC_LOCAL || apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)) return(success = 0); #endif /* CK_APC */ ck_tn_enc_start(); /* fdc 2021-12-17 */ break; case TN_EN_STOP: if ((z = cmcfm()) < 0) return(z); #ifdef CK_APC /* Don't let this be set remotely */ if (apcactive == APC_LOCAL || apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)) return(success = 0); #endif /* CK_APC */ ck_tn_enc_stop(); /* fdc 2021-12-17 */ break; default: if ((z = cmcfm()) < 0) return(z); TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = y; TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = y; TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = y; TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = y; } return(success = 1); } #endif /* CK_ENCRYPTION */ case CK_TN_BUG: /* BUG */ if ((x = cmkey(tnbugtab,4,"", "binary-me-means-u-too",xxstring)) < 0) return(x); if ((z = cmkey(onoff,2,"","off",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); switch (x) { case 0: tn_b_meu = z; break; case 1: tn_b_ume = z; break; case 2: tn_infinite = z; break; case 3: tn_sb_bug = z; break; case 4: tn_auth_krb5_des_bug = z; break; } return(success = 1); #ifdef CK_ENVIRONMENT case CK_TN_XD: /* XDISPLOC */ if ((x = cmkey(tnnegtab,ntnnegtab,"me","accept",xxstring)) < 0) return(x); if ((y = cmkey(tnnegtab,ntnnegtab,"u","accept",xxstring)) < 0) return(y); if ((z = cmcfm()) < 0) return(z); TELOPT_DEF_S_ME_MODE(TELOPT_XDISPLOC) = x; TELOPT_DEF_S_U_MODE(TELOPT_XDISPLOC) = y; TELOPT_DEF_C_ME_MODE(TELOPT_XDISPLOC) = x; TELOPT_DEF_C_U_MODE(TELOPT_XDISPLOC) = y; return(success = 1); case CK_TN_ENV: { char * msg = "value of telnet environment variable"; extern int tn_env_flg; extern char tn_env_acct[], tn_env_disp[], tn_env_job[], tn_env_prnt[], tn_env_sys[]; extern char * tn_loc; if ((x = cmkey(tnenvtab,ntnenv,"","",xxstring)) < 0) return(x); if (x == TN_ENV_UVAR) { /* User variables */ char * uvar=NULL; char * uval=NULL; char * env; extern char * tn_env_uservar[8][2]; /* Get the user variable name */ if ((x = cmfld("Name of Environment Variable","",&s, xxstring)) < 0) return(x); makestr(&uvar,s); env = getenv(uvar); if (!env) env = ""; if ((x = cmtxt("Value of Environment Variable",env, &s,xxstring)) < 0) return(x); if (*s) makestr(&uval,s); /* Now that we have the variable and perhaps a value */ /* there are three possibilities: (1) new variable */ /* and associated value; (2) variable already exists */ /* but we have a new value; (3) variable already */ /* exists but no new value therefore the user wants */ /* to clear variable. */ /* Try to find an existing variable */ for (x = 0; x < 8; x++) { if (!ckstrcmp(tn_env_uservar[x][0],uvar,-1,0)) { if (uval) { free(tn_env_uservar[x][1]); tn_env_uservar[x][1] = uval; free(uvar); return(success = 1); } else { free(tn_env_uservar[x][0]); tn_env_uservar[x][0] = NULL; free(tn_env_uservar[x][1]); tn_env_uservar[x][1] = NULL; free(uvar); return(success = 1); } } } /* Couldn't find one; look for empty location to insert */ for (x = 0; x < 8; x++) { if (!tn_env_uservar[x][0]) { tn_env_uservar[x][0] = uvar; tn_env_uservar[x][1] = uval; return(success = 1); } } printf("?Sorry, no space for variable.\n"); return(success = 0); } if (x == TN_ENV_OFF || x == TN_ENV_ON) { if ((y = cmcfm()) < 0) return(y); #ifdef IKSD if (inserver) { printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ tn_env_flg = x == TN_ENV_OFF ? 0 : 1; return(success = 1); } /* Not ON/OFF - Get the value */ z = cmdgquo(); cmdsquo(0); if ((y = cmtxt(msg, "", &s, xxstring)) < 0) { cmdsquo(z); return(y); } cmdsquo(z); #ifdef IKSD if (inserver) return(success = 0); #endif /* IKSD */ if ((int)strlen(s) > 63) { printf("Sorry, too long\n"); return(-9); } switch (x) { case TN_ENV_USR: ckstrncpy(uidbuf,s,UIDBUFLEN); sl_uid_saved = 0; break; case TN_ENV_ACCT: ckstrncpy(tn_env_acct,s,64); break; case TN_ENV_DISP: ckstrncpy(tn_env_disp,s,64); break; case TN_ENV_JOB: ckstrncpy(tn_env_job,s,64); break; case TN_ENV_PRNT: ckstrncpy(tn_env_prnt,s,64); break; case TN_ENV_SYS: ckstrncpy(tn_env_sys,s,64); break; case TN_ENV_LOC: if (!*s) s = NULL; makestr(&tn_loc,s); break; case TN_ENV_UVAR: printf("\n?Not yet implemented\n"); break; } return(success = 1); } #endif /* CK_ENVIRONMENT */ #ifdef CK_SNDLOC case CK_TN_LOC: { /* LOCATION */ extern char * tn_loc; if ((y = cmtxt("Location string","",&s,xxstring)) < 0) return(y); if (!*s) s = NULL; makestr(&tn_loc,s); return(success = 1); } #endif /* CK_SNDLOC */ case CK_TN_SFU: /* Microsoft SFU compatibility */ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); tn_sfu = z; return(success = 1); break; case CK_TN_WAIT: /* WAIT-FOR-NEGOTIATIONS */ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); #ifdef IKSD if (inserver && #ifdef IKSDCONF iksdcf #else 1 #endif /* IKSDCONF */ ) { printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ tn_wait_flg = z; sl_tn_saved = 0; return(success = 1); case CK_TN_DL: /* DELAY SUBNEGOTIATIONS */ if ((z = cmkey(onoff,2,"","on",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); #ifdef IKSD if (inserver && #ifdef IKSDCONF iksdcf #else 1 #endif /* IKSDCONF */ ) { printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ tn_delay_sb = z; return(success = 1); case CK_TN_PUID: { /* PROMPT-FOR-USERID */ int i,len; if ((y = cmtxt("Prompt string","",&s,xxstring)) < 0) return(y); s = brstrip(s); /* we must check to make sure there are no % fields */ len = strlen(s); for (i = 0; i < len; i++) { if (s[i] == '%') { if (s[i+1] != '%') { printf("%% fields are not used in this command.\n"); return(-9); } i++; } } makestr(&tn_pr_uid,s); return(success = 1); } default: return(-2); } } #endif /* TNCODE */ switch (xx) { #ifndef NOSPL case XYCOUN: /* SET COUNT */ x = cmnum("Positive number","0",10,&z,xxstring); if (x < 0) return(x); if ((x = cmcfm()) < 0) return(x); if (z < 0) { printf("?A positive number, please\n"); return(0); } debug(F101,"XYCOUN: z","",z); return(success = setnum(&count[cmdlvl],z,0,10000)); #endif /* NOSPL */ #ifndef NOSPL case XYCASE: return(success = seton(&inpcas[cmdlvl])); #endif /* NOSPL */ case XYCMD: /* COMMAND ... */ if ((y = cmkey(scmdtab,nbytt,"","",xxstring)) < 0) return(y); switch (y) { case SCMD_CBR: if ((y = cmcfm()) < 0) return(y); concb((char)escape); return(success = 1); case SCMD_BSZ: if ((y = cmnum("bytesize for command characters, 7 or 8","7",10,&x, xxstring)) < 0) return(y); if (x != 7 && x != 8) { printf("\n?The choices are 7 and 8\n"); return(success = 0); } if ((y = cmcfm()) < 0) return(y); if (x == 7) cmdmsk = 0177; else if (x == 8) cmdmsk = 0377; return(success = 1); #ifdef CK_RECALL case SCMD_RCL: if ((y = cmnum("maximum number of commands in recall buffer","10", 10,&x,xxstring)) < 0) return(y); if ((y = cmcfm()) < 0) return(y); return(success = cmrini(x)); #endif /* CK_RECALL */ #ifdef CK_RECALL case SCMD_RTR: return(success = seton(&cm_retry)); #endif /* CK_RECALL */ case SCMD_MOR: /* More-prompting */ success = seton(&xaskmore); if (success) saveask = xaskmore; return(success); case SCMD_QUO: if ((x = seton(&y)) < 0) return(x); cmdsquo(y); /* Do it the right way */ cmd_quoting = y; /* Also keep a global copy */ /* Set string-processing function */ #ifdef datageneral xxstring = y ? zzstring : (xx_strp) NULL; #else #ifdef CK_ANSIC xxstring = y ? zzstring : (xx_strp) NULL; #else xxstring = y ? zzstring : (xx_strp) NULL; #endif /* CK_ANSIC */ #endif /* datageneral */ return(success = 1); #ifdef OS2 #ifndef NOLOCAL case SCMD_COL: { /* Command-screen colors */ int fg, bg; fg = cmkey(ttyclrtab, nclrs, "foreground color and then background color", "white", xxstring); if (fg < 0) return(fg); if ((bg = cmkey(ttyclrtab,nclrs, "background color","black",xxstring)) < 0) return(bg); if ((y = cmcfm()) < 0) return(y); colorcmd = fg | bg << 4; return(success = 1); } case SCMD_SCR: /* Command Scrollback size */ if ((y = cmnum("COMMAND scrollback buffer size, lines","512",10,&x, xxstring)) < 0) return(y); /* The max number of lines is the RAM */ /* we can actually dedicate to a */ /* scrollback buffer given the maximum */ /* process memory space of 512MB */ if (x < 256 || x > 2000000L) { printf("\n?The size must be between 256 and 2,000,000.\n"); return(success = 0); } if ((y = cmcfm()) < 0) return(y); tt_scrsize[VCMD] = x; VscrnInit( VCMD ); return(success = 1); case SCMD_WID: { if ((y = cmnum("Number of columns in display window", "80",10,&x,xxstring)) < 0) return(y); if ((y = cmcfm()) < 0) return(y); os2_setcmdwidth(x); return(success = 1); } case SCMD_HIG: if ((y = cmnum("Number of rows in display window", "24",10,&x,xxstring)) < 0) return(y); if ((y = cmcfm()) < 0) return(y); os2_setcmdheight(x); return(success = 1); case SCMD_STA: { extern int marginbot; if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); if (y != tt_status[VCMD]) { /* Might need to fixup the margins */ tt_status[VCMD] = y; if (y) { tt_szchng[VCMD] = 2; tt_rows[VCMD]--; cmd_rows--; VscrnInit(VCMD); /* Height set here */ printf("\n"); } else { tt_szchng[VCMD] = 1; tt_rows[VCMD]++; cmd_rows++; VscrnInit(VCMD); /* Height set here */ } } return(success = 1); } case SCMD_CUR: { int row, col; position * ppos; ppos = VscrnGetCurPos(VCMD); #ifdef NT #define itoa _itoa #endif /* NT */ itoa(ppos->y+1, tmpbuf, 10); if ((y = cmnum("row (1-based)",tmpbuf,10,&row,xxstring)) < 0) return(y); itoa(ppos->x+1, tmpbuf, 10); if ((y = cmnum("col (1-based)",tmpbuf,10,&col,xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); lgotoxy( VCMD, col, row ) ; VscrnIsDirty( VCMD ); return(success=1); } #endif /* NOLOCAL */ #else case SCMD_WID: y = cmnum("Command screen width, characters","80",10,&x,xxstring); return(setnum(&cmd_cols,x,y,1024)); case SCMD_HIG: y = cmnum("Command screen height, rows","24",10,&x,xxstring); return(setnum(&cmd_rows,x,y,1024)); #endif /* OS2 */ case SCMD_INT: return(seton(&cmdint)); #ifdef CK_AUTODL case SCMD_ADL: return(seton(&cmdadl)); #endif /* CK_AUTODL */ #ifdef DOUBLEQUOTING case SCMD_DBQ: { extern int dblquo; return(seton(&dblquo)); } #endif /* DOUBLEQUOTING */ case SCMD_ERR: y = cmnum("Error message verbosity level, 0-3","1",10,&x,xxstring); return(setnum(&cmd_err,x,y,3)); #ifndef NOSPL case SCMD_VAR: return(setvareval()); #endif /* NOSPL */ default: return(-2); } } switch (xx) { case XYDFLT: /* SET DEFAULT = CD */ return(success = docd(XXCWD)); case XYDEBU: /* SET DEBUG { on, off, session } */ if ((y = cmkey(dbgtab,ndbg,"","",xxstring)) < 0) return(y); if (y == DEB_TIM) #ifdef COMMENT return(seton(&debtim) < 0 ? x : (success = 1)); #else /* why this change? */ return(success = seton(&debtim)); #endif /* COMMENT */ #ifdef IKSD if (inserver && isguest) { printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ switch (y) { case DEB_LEN: y = cmnum("Max length for debug log strings","",10,&x,xxstring); if ((z = setnum(&debxlen,x,y,-1)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); return(success = 1); case DEB_OFF: if ((x = cmcfm()) < 0) return(x); #ifndef NOLOCAL setdebses(0); #endif /* NOLOCAL */ #ifdef DEBUG if (deblog) doclslog(LOGD); #endif /* DEBUG */ return(success = 1); case DEB_ON: if ((x = cmcfm()) < 0) return(x); #ifdef DEBUG deblog = debopn("debug.log", 0); return(success = deblog ? 1 : 0); #else printf("?Sorry, debug log feature not enabled\n"); return(success = 0); #endif /* DEBUG */ case DEB_SES: if ((x = cmcfm()) < 0) return(x); #ifndef NOLOCAL setdebses(1); #endif /* NOLOCAL */ return(success = 1); case DEB_MSG: /* Debug messages 2010/03/12 */ if ((y = cmkey(ooetab,nooetab,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); debmsg = y; return(1); } break; #ifndef NOXFER case XYDELA: /* SET DELAY */ y = cmnum("Number of seconds before starting to send", "5",10,&x,xxstring); if (x < 0) x = 0; return(success = setnum(&ckdelay,x,y,999)); #endif /* NOXFER */ default: break; } switch (xx) { #ifdef CK_TAPI case XYTAPI: return(settapi()); #endif /* CK_TAPI */ #ifndef NODIAL case XYDIAL: /* SET MODEM or SET DIAL */ return(setdial(-1)); case XYMODM: return(setmodem()); #ifdef COMMENT /* not implemented yet */ case XYANSWER: /* SET ANSWER */ return(setanswer()); #endif /* COMMENT */ #endif /* NODIAL */ #ifndef NOLOCAL case XYDUPL: /* SET DUPLEX */ if ((y = cmkey(dpxtab,2,"","full",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); duplex = y; return(success = 1); case XYLCLE: /* LOCAL-ECHO (= DUPLEX) */ return(success = seton(&duplex)); case XYESC: /* SET ESCAPE */ return(success = setcc(ckitoa(DFESC),&escape)); #endif /* NOLOCAL */ case XYEXIT: /* SET EXIT */ if ((z = cmkey(xittab,nexit,"","",xxstring)) < 0) return(z); switch (z) { case 0: /* STATUS */ y = cmnum("EXIT status code","",10,&x,xxstring); return(success = setnum(&xitsta,x,y,-1)); case 1: /* WARNING */ if ((z = cmkey(xitwtab,nexitw,"","",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); setexitwarn(z); return(success = 1); case 2: success = seton(&exitonclose); #ifdef TCPSOCKET if (success) tn_exit = exitonclose; #endif /* TCPSOCKET */ return(success); case 3: { extern int exithangup; return((success = seton(&exithangup))); } case 4: { /* MESSAGE 2013-03-13 */ if ((z = cmkey(ooetab,nooetab,"","on",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); exitmsg = z; return(success = 1); } default: return(-2); } /* End of SET EXIT switch() */ default: break; } switch (xx) { case XYFILE: /* SET FILE */ return(setfil(rmsflg)); case XYFLOW: { /* FLOW-CONTROL */ extern int cxflow[]; struct FDB k1, k2; int tncomport = 0; char * m; #ifdef TN_COMPORT if (network && istncomport()) tncomport = 1; #endif /* TN_COMPORT */ if (tncomport) { m = "Flow control type, one of the following:\n\ dtr/cd dtr/cts keep none rts/cts xon/xoff\n\ or connection type"; } else { /* All this is because chained FDB's don't give chained help yet */ m = #ifdef Plan9 #ifdef CK_RTSCTS "Flow control type, one of the following:\n\ keep none rts/cts\n\ or connection type", #else "Flow control type, one of the following:\n\ keep none\n\ or connection type"; #endif /* CK_RTSCTS */ #else #ifdef CK_RTSCTS #ifdef CK_DTRCD #ifdef CK_DTRCTS "Flow control type, one of the following:\n\ dtr/cd dtr/cts keep none rts/cts xon/xoff\n\ or connection type"; #else /* CK_DTRCTS */ "Flow control type, one of the following:\n\ dtr/cd keep none rts/cts xon/xoff\n\ or connection type"; #endif /* CK_DTRCTS */ #else /* CK_DTRCD */ #ifdef CK_DTRCTS "Flow control type, one of the following:\n\ dtr/cts keep none rts/cts xon/xoff\n\ or connection type"; #else /* CK_DTRCTS */ "Flow control type, one of the following:\n\ keep none rts/cts xon/xoff\n\ or connection type"; #endif /* CK_DTRCTS */ #endif /* CK_DTRCD */ #else "Flow control type, one of the following:\n\ keep none xon/xoff\n\ or connection type"; #endif /* CK_RTSCTS */ #endif /* Plan9 */ } cmfdbi(&k1,_CMKEY,m,"","",ncxtypesw, 4, xxstring, cxtypesw, &k2); cmfdbi(&k2, _CMKEY, "", "", "", #ifdef TN_COMPORT (tncomport ? ntnflo : nflo), #else nflo, #endif /* TN_COMPORT */ 0, xxstring, #ifdef TN_COMPORT (tncomport ? tnflotab : flotab), #else flotab, #endif /* TN_COMPORT */ NULL ); x = cmfdb(&k1); if (x < 0) { /* Error */ if (x == -2 || x == -9) printf("?No keywords or switches match: \"%s\"\n",atmbuf); return(x); } z = cmresult.nresult; /* Keyword value */ if (cmresult.fdbaddr == &k2) { /* Flow-control type keyword table */ if ((x = cmcfm()) < 0) /* Set it immediately */ return(x); flow = z; debug(F101,"set flow","",flow); #ifdef CK_SPEED if (flow == FLO_XONX) /* Xon/Xoff forces prefixing */ ctlp[XON] = ctlp[XOFF] = ctlp[XON+128] = ctlp[XOFF+128] = 1; #endif /* CK_SPEED */ autoflow = (flow == FLO_AUTO); return(success = 1); /* Done */ } debug(F101,"set flow /blah 1","",z); /* SET FLOW /for-what */ if ((y = cmkey(flotab,nflo,"Flow control type","none",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); debug(F101,"set flow /blah 2","",y); if (y == FLO_AUTO) { printf( "?Sorry, \"automatic\" can not be assigned to a connection type.\n"); return(-9); } else if (z >= 0 && z <= CXT_MAX) cxflow[z] = y; debug(F101,"set flow","",flow); debug(F101,"set flow autoflow","",autoflow); return(success = 1); } case XYHAND: /* HANDSHAKE */ if ((y = cmkey(hshtab,nhsh,"","none",xxstring)) < 0) return(y); if (y == 998) { if ((x = cmnum("ASCII value","",10,&y,xxstring)) < 0) return(x); if ((y < 1) || ((y > 31) && (y != 127))) { printf("?Character must be in ASCII control range\n"); return(-9); } } if ((x = cmcfm()) < 0) return(x); turn = (y > 0127) ? 0 : 1; turnch = y; return(success = 1); #ifndef NOSPL case XYMACR: /* SET MACRO */ if ((y = cmkey(smactab,2,"","",xxstring)) < 0) return(y); switch (y) { case 0: return(success = seton(&mecho)); case 1: return(success = seton(&merror[cmdlvl])); default: return(-2); } #endif /* NOSPL */ case XYMSGS: #ifdef VMS if ((z = cmkey(onoff,2,"","",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); vms_msgs = z; printf("Sorry, SET MESSAGES not implemented yet\n"); return(success = 0); #endif /* VMS */ default: break; } switch (xx) { case XYPARI: /* PARITY */ if ((y = cmkey(partbl,npar,"","none",xxstring)) < 0) return(y); /* If parity not none, then we also want 8th-bit prefixing */ #ifdef HWPARITY if (y == 'H') { /* Hardware */ if ((x = cmkey(hwpartbl,nhwpar,"","even",xxstring)) < 0) return(x); } #endif /* HWPARITY */ if ((z = cmcfm()) < 0) return(z); #ifdef HWPARITY if (y == 'H') { /* 8 data bits plus hardware parity */ parity = 0; #ifndef NOXFER ebqflg = 0; #endif /* NOXFER */ hwparity = x; } else { /* 7 data bits + software parity */ hwparity = 0; #endif /* HWPARITY */ parity = y; #ifndef NOXFER ebqflg = (parity) ? 1 : 0; #endif /* NOXFER */ #ifdef HWPARITY } #endif /* HWPARITY */ #ifdef TN_COMPORT if (network && istncomport()) tnsettings(parity, 0); #endif /* TN_COMPORT */ return(success = 1); #ifndef NOFRILLS case XYPROM: /* SET PROMPT */ /* Note: xxstring not invoked here. Instead, it is invoked every time the prompt is issued. This allows the prompt string to contain variables that can change, like \v(dir), \v(time), etc. */ ckmakmsg(line, /* Default might have trailing space */ LINBUFSIZ, "{", inserver ? ikprompt : ckprompt, "}", NULL ); if ((x = cmtxt("Program's command prompt",line,&s,NULL)) < 0) return(x); s = brstrip(s); /* Remove enclosing braces, if any */ cmsetp(s); /* Set the prompt */ return(success = 1); #endif /* NOFRILLS */ #ifndef NOXFER case XYRETR: /* RETRY: per-packet retry limit */ y = cmnum("Maximum retries per packet","10",10,&x,xxstring); if (x < 0) x = 0; if ((x = setnum(&maxtry,x,y,999)) < 0) return(x); #ifdef COMMENT if (maxtry <= wslotr) { printf("?Retry limit must be greater than window size\n"); return(success = 0); } #endif /* COMMENT */ if (rmsflg) { sstate = setgen('S', "403", ckitoa(maxtry), ""); return((int) sstate); } else return(success = x); #endif /* NOXFER */ #ifndef NOSERVER case XYSERV: /* SET SERVER items */ if ((y = cmkey(srvtab,nsrvt,"","",xxstring)) < 0) return(y); switch (y) { case XYSERI: if ((y = cmnum("Number of seconds, or 0 for no idle timeout", "0",10,&x,xxstring)) < 0) return(y); if (x < 0) x = 0; if ((y = cmcfm()) < 0) return(y); #ifndef OS2 srvtim = 0; #endif /* OS2 */ srvidl = x; return(success = 1); case XYSERT: if ((y = cmnum("Interval for server NAKs, 0 = none", ckitoa(DSRVTIM), 10,&x, xxstring)) < 0) return(y); if (x < 0) { printf( "\n?Specify a positive number, or 0 for no server NAKs\n"); return(0); } if ((y = cmcfm()) < 0) return(y); if (rmsflg) { sstate = setgen('S', "404", ckitoa(x), ""); return((int) sstate); } else { #ifndef OS2 srvidl = 0; #endif /* OS2 */ srvtim = x; /* Set the server timeout variable */ return(success = 1); } case XYSERD: /* SERVER DISPLAY */ return(success = seton(&srvdis)); /* ON or OFF... */ #ifndef NOSPL case XYSERP: /* SERVER GET-PATH */ return(parsdir(2)); #endif /* NOSPL */ case XYSERL: /* SERVER LOGIN */ return(cklogin()); case XYSERC: /* SERVER CD-MESSAGE */ x = rmsflg ? cmkey(onoff,2,"","",xxstring) : cmkey(cdmsg,3,"","",xxstring); if (x < 0) return(x); if (x == 2) { /* CD-MESSAGE FILE */ if ((x = cmtxt("Name of file","",&s,NULL)) < 0) return(x); if (!*s) { s = NULL; srvcdmsg = 0; } makestr(&cdmsgstr,s); makelist(cdmsgstr,cdmsgfile,8); return(success = 1); } if ((y = cmcfm()) < 0) /* CD-MESSAGE ON/OFF */ return(y); if (rmsflg) { sstate = setgen('S', "420", x ? "1" : "0", ""); return((int) sstate); } else { if (x > 0) srvcdmsg |= 1; else srvcdmsg &= 2; return(success = 1); } case XYSERK: /* SERVER KEEPALIVE */ return(success = seton(&srvping)); /* ON or OFF... */ default: return(-2); } #endif /* NOSERVER */ } switch (xx) { #ifdef UNIX #ifndef NOJC case XYSUSP: /* SET SUSPEND */ seton(&xsuspend); /* on or off... */ return(success = 1); #endif /* NOJC */ #endif /* UNIX */ case XYTAKE: /* SET TAKE */ if ((y = cmkey(taktab,4,"","",xxstring)) < 0) return(y); switch (y) { case 0: return(success = seton(&techo)); #ifndef NOSPL case 1: return(success = seton(&takerr[cmdlvl])); #else case 1: return(success = seton(&takerr[tlevel])); #endif /* NOSPL */ case 2: techo = 0; return(success = 1); /* For compatibility with */ case 3: techo = 1; return(success = 1); /* MS-DOS Kermit */ default: return(-2); } #ifndef NOSCRIPT case XYSCRI: /* SET SCRIPT */ if ((y = cmkey(scrtab,1,"","echo",xxstring)) < 0) return(y); switch (y) { case 0: return(success = seton(&secho)); default: return(-2); } #endif /* NOSCRIPT */ default: break; } #ifndef NOLOCAL switch (xx) { case XYTERM: /* SET TERMINAL */ x = settrm(); success = (x > 0) ? 1 : 0; return(x); #ifdef NT case XYWIN95: /* SET WIN95 workarounds */ x = setwin95(); success = (x > 0 ? 1 : 0); return(x); #endif /* NT */ #ifdef OS2 case XYDLR: /* SET DIALER workarounds */ x = setdialer(); success = (x > 0 ? 1 : 0); return(x); case XYTITLE: /* SET TITLE of window */ x = settitle(); success = (x > 0 ? 1 : 0); return(x); #endif /* OS2 */ #ifdef OS2MOUSE case XYMOUSE: /* SET MOUSE */ return(success = setmou()); #endif /* OS2MOUSE */ case XYBELL: /* SET BELL */ return(success = setbell()); #ifdef OS2 case XYPRTY: return(success = setprty() ); #endif /* OS2 */ default: break; } #endif /* NOLOCAL */ switch (xx) { /* SET SEND/RECEIVE protocol parameters. */ #ifndef NOXFER case XYRECV: case XYSEND: return(setsr(xx,rmsflg)); #endif /* NOXFER */ #ifndef NOLOCAL case XYSESS: /* SESSION-LOG */ if ((x = cmkey(sfttab,nsfttab,"type of file", #ifdef OS2 "binary", #else /* OS2 */ "text", #endif /* OS2 */ xxstring ) ) < 0) return(x); if ((y = cmcfm()) < 0) return(y); if (x == 999) { /* TIMESTAMPED-TEXT */ sessft = XYFT_T; /* Implies text */ slogts = 1; /* and timestamps */ } else if (x == 998) { /* NULL-PADDED-LINES */ slognul = 1; /* adds NUL after ^J */ } else { /* A regular type */ sessft = x; /* The type */ slogts = 0; /* No timestampes */ } return(success = 1); case XYSPEE: /* SET SPEED */ lp = line; if (local && !network) { ckmakmsg(lp, LINBUFSIZ, "Transmission rate for ", ttname, " (bps)", NULL ); } else { ckstrncpy(lp, "Serial-port speed (bps)", LINBUFSIZ ); } zz = -1L; #ifdef TN_COMPORT if (network && istncomport()) x = cmkey(tnspdtab,ntnspd,line,"",xxstring); else #endif /* TN_COMPORT */ #ifdef NOSORTSPEEDS x = cmkey(spdtab,nspd,line,"",xxstring); #else /* Negative number of table entries means its a numeric table */ x = cmkey(spdtab,-nspd,line,"",xxstring); #endif /* NOSORTSPEEDS */ if (x < 0) { if (x == -3) printf("?value required\n"); #ifdef USETCSETSPEED /* SCO Unixware 7 only */ /* In this case, any number can be tried */ /* There's a parse error message but the request still goes thru */ if (rdigits(atmbuf)) zz = atol(atmbuf); else #endif /* USETCSETSPEED */ return(x); } if ((y = cmcfm()) < 0) return(y); #ifdef IKSD if (inserver) { printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ if (!local) { printf("?SET SPEED has no effect without prior SET LINE\n"); return(success = 0); } else if (network #ifdef TN_COMPORT && !istncomport() #endif /* TN_COMPORT */ ) { printf("\n?Speed cannot be set for network connections\n"); return(success = 0); } /* Note: This way of handling speeds is not 16-bit safe for speeds greater than 230400. The argument to ttsspd() should have been a long. */ #ifdef USETCSETSPEED /* SCO Unixware 7 only */ if (zz > -1L) x = zz / 10L; #endif /* USETCSETSPEED */ zz = (long) x * 10L; if (zz == 130L) zz = 134L; if (zz == 70L) zz = 75L; /* (see spdtab[] definition) */ if (ttsspd(x) < 0) { /* Call ttsspd with cps, not bps! */ printf("?Unsupported line speed - %ld\n",zz); return(success = 0); } else { #ifdef CK_TAPI if (!tttapi || tapipass) speed = ttgspd(); /* Read it back */ else speed = zz; #else /* CK_TAPI */ speed = ttgspd(); /* Read it back */ #endif /* CK_TAPI */ if (speed != zz) { /* Call ttsspd with cps, not bps! */ printf("?SET SPEED fails, speed is %ld\n",speed); return(success = 0); } if (pflag && !xcmdsrc) { if (speed == 8880) printf("%s, 75/1200 bps\n",ttname); else if (speed == 134) printf("%s, 134.5 bps\n",ttname); else printf("%s, %ld bps\n",ttname,speed); } return(success = 1); } #endif /* NOLOCAL */ #ifndef NOXFER case XYXFER: /* SET TRANSFER */ if ((y = cmkey(rmsflg ? rtstab : tstab, /* (or REMOTE SET TRANSFER) */ rmsflg ? nrts : nts, "","character-set",xxstring)) < 0) return(y); switch (y) { #ifdef XFRCAN case XYX_CAN: /* CANCELLATION */ if ((z = cmkey(onoff,2,"","",xxstring)) < 0) return(z); if (z == 0) { /* OFF */ if ((y = cmcfm()) < 0) return(y); xfrcan = 0; } else { if ((y = cmnum("ASCII code for cancellation character", "3",10,&x, xxstring)) < 0) return(y); if (x > 31 && x != 127) { printf("Cancel character must be 0-31 or 127\n"); return(-9); } if ((y = cmnum("How many required to cause cancellation", "2",10,&z, xxstring)) < 0) return(y); if (z < 2) { printf("Number must be 2 or greater\n"); return(-9); } if ((y = cmcfm()) < 0) return(y); xfrcan = 1; /* CANCELLATION ON */ xfrchr = x; /* Using this character */ xfrnum = z; /* Needing this many of them */ } return(success = 1); #endif /* XFRCAN */ #ifndef NOCSETS case XYX_CSE: /* CHARACTER-SET */ if ((y = cmkey(tcstab,ntcs,"","transparent",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); if (rmsflg) { sstate = setgen('S', "405", tcsinfo[y].designator, ""); return((int) sstate); } else { extern int s_cset, fcharset, axcset[], tcs_save; tslevel = (y == TC_TRANSP) ? 0 : 1; /* transfer syntax level */ xfrxla = tslevel; tcharset = y; /* transfer character set */ /* SEND CHARACTER-SET AUTO */ if (tslevel > 0 && s_cset == XMODE_A) if (y > -1 && y <= MAXTCSETS) if (axcset[y] > -1 && axcset[y] > MAXFCSETS) fcharset = axcset[y]; /* Auto-pick file charset */ setxlatype(tcharset,fcharset); /* Translation type */ tcs_save = -1; return(success = 1); } #endif /* NOCSETS */ case XYX_LSH: /* LOCKING-SHIFT */ if ((y = cmkey(lstab,nls,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); lscapr = (y == 1) ? 1 : 0; /* ON: requested = 1 */ lscapu = (y == 2) ? 2 : 0; /* FORCED: used = 1 */ return(success = 1); /* #ifdef CK_XYZ */ case XYX_PRO: /* Protocol */ #ifndef OS2 if (inserver) { printf("?Sorry, only Kermit protocol is available\n"); return(-9); } #endif /* OS2 */ return(setproto()); /* #endif */ /* CK_XYZ */ case XYX_MOD: /* Mode */ if ((y = cmkey(xfrmtab,2,"","automatic",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); if (rmsflg) { sstate = setgen('S', "410", y == XMODE_A ? "0" : "1", ""); return((int)sstate); } g_xfermode = y; xfermode = y; #ifdef NEWFTP if (ftpisopen()) { /* If an FTP connection is open */ extern int ftp_xfermode; /* change its transfer mode too */ ftp_xfermode = xfermode; } #endif /* NEWFTP */ return(success = 1); #ifndef NOLOCAL case XYX_DIS: /* Display */ return(doxdis(1)); /* 1 == Kermit */ #endif /* NOLOCAL */ case XYX_SLO: /* Slow-start */ return(seton(&slostart)); #ifndef NOSPL case XYX_CRC: /* CRC */ return(seton(&docrc)); #endif /* NOSPL */ case XYX_BEL: /* Bell */ return(seton(&xfrbel)); #ifdef PIPESEND case XYX_PIP: /* Pipes */ #ifndef NOPUSH if (nopush) { #endif /* NOPUSH */ printf("Sorry, access to pipes is disabled\n"); return(-9); #ifndef NOPUSH } else #endif /* NOPUSH */ return(seton(&usepipes)); #endif /* PIPESEND */ case XYX_INT: /* Interruption */ return(seton(&xfrint)); case XYX_XLA: return(seton(&xfrxla)); /* Translation */ case XYX_MSG: { extern char * xfrmsg; if ((x = cmtxt("Prompt string","",&s,xxstring)) < 0) return(x); if (!*s) s = NULL; makestr(&xfrmsg,s); return(success = 1); } case XYX_RPT: { extern int whereflg; return(seton(&whereflg)); } default: return(-2); } #endif /* NOXFER */ } switch (xx) { #ifndef NOXMIT case XYXMIT: /* SET TRANSMIT */ return(setxmit()); #endif /* NOXMIT */ #ifndef NOXFER #ifndef NOCSETS case XYUNCS: /* UNKNOWN-CHARACTER-SET */ if ((y = cmkey(ifdtab,2,"","discard",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); unkcs = y; return(success = 1); #endif /* NOCSETS */ #endif /* NOXFER */ #ifdef VMS case XYVMSTF: /* VMS_TEXT */ if ((y = cmkey(vmstftab,nvmstftab,"VMS text-file format", "",xxstring)) < 0) return(y); vms_text = y; /* Set new text-file format value. */ return(y); #endif /* VMS */ #ifndef NOPUSH #ifdef UNIX case XYWILD: /* WILDCARD-EXPANSION */ if ((y = cmkey(wildtab,nwild, "Wildcard expansion option","on",xxstring)) < 0) return(y); if ((z = cmkey(wdottab, 2, "whether to match filenames that start with \".\"", "/no-match-dot-files", xxstring) ) < 0) return(z); if ((x = cmcfm()) < 0) return(x); if (nopush) { if (y > 0) { printf("Shell expansion is disabled\n"); return(success = 0); } } switch (y) { case WILD_ON: wildena = 1; break; case WILD_OFF: wildena = 0; break; case WILD_KER: wildxpand = 0; /* These are the previous */ break; /* hardwired values */ case WILD_SHE: wildxpand = 1; break; } matchdot = z; return(success = 1); #endif /* UNIX */ #endif /* NOPUSH */ #ifndef NOXFER case XYWIND: /* WINDOW-SLOTS */ if (protocol == PROTO_K) { y = cmnum("Window size for Kermit protocol, 1 to 32", "1", 10, &x, xxstring); y = setnum(&z,x,y,MAXWS); /* == 32 */ } #ifdef CK_XYZ else if (protocol == PROTO_Z) { y = cmnum("Window size for ZMODEM protocol, 0 to 65535", "0", 10, &x, xxstring); y = setnum(&z,x,y,65535); } #endif /* CK_XYZ */ else { y = cmnum("Window size for current protocol", "", 10, &x, xxstring); y = setnum(&z,x,y,65472); /* Doesn't matter - we won't use it */ } if (y < 0) return(y); if (protocol == PROTO_K) { if (z < 1) z = 1; } #ifdef CK_XYZ else if (protocol == PROTO_Z) { /* Zmodem windowing is closer to Kermit packet length */ /* than Kermit window size. If Window size is zero */ /* an end of frame and CRC is sent only at the end of */ /* the file (default). Otherwise, an End of Frame */ /* and CRC are sent after Window Size number of bytes */ if (z < 0) /* Disable windowing */ z = 0; } else { printf("?SET WINDOW does not apply to %s protocol\n", ptab[protocol].p_name ); } #endif /* CK_XYZ */ #ifdef COMMENT /* This is taken care of automatically now in protocol negotiation */ if (maxtry < z) { printf("?Window slots must be less than retry limit\n"); return(success = 0); } #endif /* COMMENT */ if (protocol == PROTO_K && rmsflg) { /* Set remote window size */ wslotr = z; /* Set local window size too */ ptab[protocol].winsize = wslotr; sstate = setgen('S', "406", ckitoa(z), ""); return((int) sstate); } wslotr = z; /* Set requested window size here */ ptab[protocol].winsize = wslotr; /* and in protocol-specific table */ if (protocol == PROTO_K) { /* And for Kermit only... */ swcapr = (wslotr > 1) ? 1 : 0; /* set window bit in capas word */ if (wslotr > 1) { /* Window size > 1? */ /* Maybe adjust packet size */ y = adjpkl(urpsiz,wslotr,bigrbsiz); if (y != urpsiz) { /* Did it change? */ urpsiz = y; if (msgflg) printf( " Adjusting receive packet-length to %d for %d window slots\n", urpsiz, wslotr ); } } } return(success = 1); #endif /* NOXFER */ } switch (xx) { #ifndef NOSPL case XYOUTP: /* OUTPUT command parameters */ if ((y = cmkey(outptab,noutptab,"OUTPUT command parameter","pacing", xxstring)) < 0) return(y); switch(y) { /* Which parameter */ case OUT_PAC: /* PACING */ y = cmnum("Milliseconds to pause between each OUTPUT character", "100", 10,&x,xxstring); y = setnum(&z,x,y,16383); /* Verify and get confirmation */ if (y < 0) return(y); if (z < 0) z = 0; /* (save some space) */ pacing = z; return(success = 1); case OUT_ESC: /* Special-escapes */ return(seton(&outesc)); default: /* (shouldn't happen) */ return(-2); } #endif /* NOSPL */ #ifdef CK_SPEED case XYQCTL: { short *p; int zz; if ((z = cmkey(ctltab,2, "control-character prefixing option","" ,xxstring)) < 0) return(z); /* Make space for a temporary copy of the prefixing table */ p = (short *)malloc(256 * sizeof(short)); if (!p) { printf("?Internal error - malloc failure\n"); return(-9); } for (i = 0; i < 256; i++) p[i] = ctlp[i]; /* Copy current table */ switch (z) { case 0: /* UNPREFIXED control character */ case 1: /* PREFIXED control character */ while (1) { /* Collect a list of numbers */ #ifndef NOSPL x_ifnum = 1; /* Turn off complaints from eval() */ #endif /* NOSPL */ if ((x = cmnum((z == 0) ? "\n Numeric ASCII value of control character that needs NO prefix,\n\ or the word \"all\", or carriage return to complete the list" : "\n Numeric ASCII value of control character that MUST BE prefixed,\n\ or the word \"all\", or carriage return to complete the list", "",10,&y,xxstring )) < 0) { #ifndef NOSPL x_ifnum = 0; #endif /* NOSPL */ if (x == -3) { if ((x = cmcfm()) < 0) return(x); break; } if (x == -2) { if (p) { free((char *)p); p = NULL; } debug(F110,"SET CONTROL atmbuf",atmbuf,0); if (!ckstrcmp(atmbuf,"all",3,0) || /* "ALL" */ !ckstrcmp(atmbuf,"al",2,0) || !ckstrcmp(atmbuf,"a",1,0)) { if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); prefixing = z ? PX_ALL : PX_NON; setprefix(prefixing); return(success = 1); } else { /* Not number, not ALL */ printf( "?Please specify a number or the word ALL\n"); return(-9); } } else { if (p) free((char *)p); return(x); } } #ifndef NOSPL x_ifnum = 0; #endif /* NOSPL */ #ifdef UNPREFIXZERO zz = 0; #else #ifndef OS2 zz = 1 - z; #else zz = 0; /* Allow 0 (but only for Zmodem) */ #endif /* OS2 */ #endif /* UNPREFIXZERO */ /* printf("x = %d, y = %d, z = %d, zz = %d\n", x,y,z,zz); */ if ((y > 31 && y < 127) || /* A specific numeric value */ (y > 159 && y < 255) || /* Check that it is a valid */ (y < zz) || /* control code. */ (y > 255)) { printf("?Values allowed are: %d-31, 127-159, 255\n",zz); if (p) free((char *)p); return(-9); } x = y & 127; /* Get 7-bit value */ if (z == 0) { /* If they are saying it is safe... */ /* If flow control is Xon/Xoff */ if (((flow == FLO_XONX) && /* XON & XOFF chars not safe. */ (x == XON || x == XOFF)) ) { if (msgflg) printf( "Sorry, not while Xon/Xoff is in effect.\n"); if (p) free((char *)p); return(-9); } #ifdef TNCODE else if (network && IS_TELNET() && (y == CK_CR || (unsigned) y == (unsigned) 255)) { if (msgflg) printf("Sorry, not on a TELNET connection.\n"); if (p) free((char *)p); return(-9); } #endif /* TNCODE */ } p[y] = (char) z; /* All OK, set flag */ } /* End of while loop */ /* Get here only if they have made no mistakes. Copy temporary table back to permanent one, then free temporary table and return successfully. */ for (i = 0; i < 256; i++) ctlp[i] = p[i]; if (p) free((char *)p); if (z > 0) clearrq = 0; /* 199 (see SET PREFIXING) */ return(success = 1); default: return(-2); } } #endif /* CK_SPEED */ } switch (xx) { #ifndef NOXFER case XYREPT: if ((y = cmkey(rpttab,2, "repeat-count compression parameter","",xxstring)) < 0) return(y); switch(y) { case 0: return(success = seton(&rptena)); /* REPEAT COUNTS = ON, OFF */ case 1: /* REPEAT MININUM number */ printf("(not implemented yet, nothing happens)\n"); return(-9); case 2: /* REPEAT PREFIX char */ if ((x = cmnum("ASCII value","",10,&z,xxstring)) < 0) return(x); if ((x = cmcfm()) < 0) return(x); if ((z > 32 && z < 63) || (z > 95 && z < 127)) { if (y == 1) rptmin = (CHAR) z; else myrptq = (CHAR) z; return(success = 1); } else { printf("?Illegal value for prefix character\n"); return(-9); } } #endif /* NOXFER */ #ifndef NOSPL case XYALRM: { #ifndef COMMENT int yy; long zz; zz = -1L; yy = x_ifnum; x_ifnum = 1; /* Turn off internal complaints */ y = cmnum("Seconds from now, or time of day as hh:mm:ss", "0" ,10, &x, xxstring); x_ifnum = yy; if (y < 0) { if (y == -2) { /* Invalid number or expression */ zz = tod2sec(atmbuf); /* Convert to secs since midnight */ if (zz < 0L) { printf("?Number, expression, or time of day required\n"); return(-9); } else { char now[32]; /* Current time */ char *p; long tnow; p = now; ztime(&p); tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17); if (zz < tnow) /* User's time before now */ zz += 86400L; /* So make it tomorrow */ zz -= tnow; /* Seconds from now. */ } } else return(y); } if (x < 0) { printf("?Alarm time is in the past.\n"); return(-9); } if ((y = cmcfm()) < 0) return(y); if (zz > -1L) { /* Time of day given? */ x = zz; if (zz != (long) x) { printf( "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n" ); return(-9); } } return(setalarm((long)x)); } #else /* This is to allow long values where int and long are not the same, e.g. on 16-bit systems. But something is wrong with it. */ if ((y = cmtxt("seconds from now", "0", &s, xxstring)) < 0) return(y); if (rdigits(s)) { return(setalarm(atol(s))); } else { printf("%s - not a number\n",s); return(-9); } #endif /* COMMENT */ #endif /* NOSPL */ #ifndef NOXFER case XYPROTO: return(setproto()); #endif /* NOXFER */ /* C-Kermit unprefixes control characters automatically on network connections if CLEAR-CHANNEL is ON, which it is by default. But not all network connections are transparent to all control characters. For example, the DEC-20, even when you TELNET to it, is sensitive to Ctrl-O and Ctrl-T. If you tell C-Kermit to SET CONTROL PREFIX 15 and/or 20, it doesn't help because CLEAR-CHANNEL is still in effect. If the user goes to the trouble to set up some prefixing, then Kermit should do what the user said. In C-Kermit 7.1 Alpha.03 we change the code to set clearrq to 0 if the user gives a SET PREFIXING or SET CONTROL PREFIX command. */ #ifdef CK_SPEED case XYPREFIX: { #ifdef COMMENT extern int clearrq; #endif /* COMMENT */ if ((z = cmkey(pfxtab, 4, "control-character prefixing option", "", xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); clearrq = 0; /* 199 */ setprefix(z); #ifdef COMMENT if (hints && (z == PX_ALL || z == PX_CAU) && clearrq) { printf("Hint: Use SET CLEAR-CHANNEL OFF to disable negotiation of\n"); printf(" SET PREFIXING NONE during file transfers on reliable\n"); printf(" connections.\n"); } #endif /* COMMENT */ return(success = 1); } #endif /* CK_SPEED */ #ifndef NOSPL case XYLOGIN: if ((z = cmkey(logintab, 3, "value for login script","userid", xxstring)) < 0) return(z); x = cmdgquo(); if (z == LOGI_PSW) cmdsquo(0); if ((y = cmtxt("text","",&s, (z == LOGI_PSW) ? NULL : xxstring)) < 0) { cmdsquo(x); return(y); } cmdsquo(x); #ifdef IKSD if (inserver) return(success = 0); #endif /* IKSD */ s = brstrip(s); if ((int)strlen(s) > 63) { printf("Sorry, too long\n"); return(-9); } switch(z) { case LOGI_UID: ckstrncpy(uidbuf,s,UIDBUFLEN); sl_uid_saved = 0; break; case LOGI_PSW: ckstrncpy(pwbuf,s,PWBUFL); if (pwbuf[0]) { pwflg = 1; #ifdef OS2 pwcrypt = 1; #else /* OS2 */ pwcrypt = 0; #endif /* OS2 */ } break; case LOGI_PRM: ckstrncpy(prmbuf,s,PWBUFL); } return(success = 1); #endif /* NOSPL */ } switch (xx) { case XYSTARTUP: if ((y = cmkey(ifdtab,2,"","discard",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); DeleteStartupFile = (y != 0) ? 0 : 1; return(success = 1); case XYTMPDIR: x = cmdir("Name of temporary directory","",&s,xxstring); if (x == -3) s = ""; else if (x < 0) return(x); ckstrncpy(tmpbuf,s,TMPBUFSIZ); if ((x = cmcfm()) < 0) return(x); #ifdef UNIX if (tmpbuf[0]) { extern int zchkod; char tmpname[CKMAXPATH+1]; char * p = tmpname; int x; zchkod = 1; /* Hack for asking zchko() if */ x = zchko(tmpbuf); /* a directory is writeable */ zchkod = 0; if (x < 0) printf("WARNING: %s does not appear to be writable\n",tmpbuf); zfnqfp(tmpbuf,CKMAXPATH,p); /* Get and store full pathname */ makestr(&tempdir,tmpname); } #else /* No API for getting full pathname in other OS's */ makestr(&tempdir,tmpbuf); #endif /* UNIX */ return(tempdir ? 1 : 0); #ifndef NOXFER case XYDEST: /* DESTINATION */ return(setdest()); #endif /* NOXFER */ #ifndef NOPUSH #ifndef NOFRILLS /* Editor, Browser, and FTP Client */ case XYEDIT: /* EDITOR */ #ifdef IKSD if (inserver) { printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ #ifdef CK_APC /* Don't let this be set remotely */ if (apcactive == APC_LOCAL || (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))) return(success = 0); #endif /* CK_APC */ #ifdef OS2ORUNIX { char *p = getenv("PATH"); char *e; e = editor[0] ? (char *) editor : getenv("EDITOR"); if (!e) e = ""; if (p) x = cmifip("Name of preferred editor",e,&s,&y,0,p,xxstring); else x = cmifi("Full path of preferred editor",e,&s,&y,xxstring); if (x < 0 && x != -3) return(x); } #else #ifdef VMS if ((y = cmtxt("DCL command for editing", "edit", &s, NULL)) < 0) { if (x != -3) return(x); } #else if ((x = cmifi("Full path of preferred editor","",&s,&y,xxstring))<0) { if (x != -3) return(x); } #endif /* VMS */ #endif /* OS2ORUNIX */ #ifdef VMS ckstrncpy(editor,s,CKMAXPATH); editopts[0] = NUL; #else if (y != 0) { printf("?A single file please\n"); return(-2); } ckstrncpy(line,s,LINBUFSIZ); if ((x = cmtxt("editor command-line options","",&s,NULL)) < 0) return(x); ckstrncpy(tmpbuf,s,TMPBUFSIZ); if ((z = cmcfm()) < 0) return(z); if (line[0]) { zfnqfp(line,CKMAXPATH,editor); ckstrncpy(editopts,tmpbuf,128); } else { editor[0] = NUL; editopts[0] = NUL; } #endif /* VMS */ return(success = 1); #ifndef NOFTP #ifndef SYSFTP #ifdef TCPSOCKET case XYFTPX: return(dosetftp()); /* SET FTP */ #endif /* TCPSOCKET */ #endif /* SYSFTP */ #endif /* NOFTP */ #ifdef BROWSER #ifndef NOFTP #ifdef SYSFTP case XYFTP: /* SET FTP-CLIENT */ #endif /* SYSFTP */ #endif /* NOFTP */ case XYBROWSE: /* SET BROWSER */ { char *p = getenv("PATH"); char *app = (char *) browser, *opts = (char *) browsopts; #ifndef NOFTP #ifdef SYSFTP extern char ftpapp[], ftpopts[]; if (xx == XYFTP) { app = (char *)ftpapp; opts = (char *)ftpopts; } #endif /* SYSFTP */ #endif /* NOFTP */ #ifdef IKSD if (inserver) { printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ #ifdef CK_APC /* Don't let this be set remotely */ if (apcactive == APC_LOCAL || (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))) return(success = 0); #endif /* CK_APC */ #ifdef OS2ORUNIX if (p) x = cmifip(xx == XYBROWSE ? "Name of preferred browser" : "Name of preferred ftp client", #ifdef OS2 xx == XYFTP ? "ftp.exe" : "" #else xx == XYFTP ? "ftp" : "" #endif /* OS2 */ ,&s,&y,0,p,xxstring ); else x = cmifi(xx == XYBROWSE ? "Full path of preferred browser" : "Full path of preferred ftp client", "",&s,&y,xxstring ); if (x < 0 && x != -3) return(x); #else #ifdef VMS if ((x = cmtxt("DCL command to start your preferred Web browser", "", &s, NULL)) < 0) { if (x != -3) return(x); } #else if ((x = cmifi("Full path of preferred browser","",&s,&y,xxstring) ) < 0) { if (x != -3) return(x); } #endif /* VMS */ #endif /* OS2ORUNIX */ #ifdef VMS ckstrncpy(app,s,CKMAXPATH); *opts = NUL; #else if (y != 0) { printf("?A single file please\n"); return(-2); } ckstrncpy(line,s,LINBUFSIZ); if ((x = cmtxt(xx == XYBROWSE ? "browser command-line options" : "ftp client command-line options", "",&s,NULL) ) < 0) return(x); ckstrncpy(tmpbuf,s,TMPBUFSIZ); if ((z = cmcfm()) < 0) return(z); if (line[0]) { zfnqfp(line,CKMAXPATH,app); ckstrncpy(opts, tmpbuf, 128); } else { *app = NUL; *opts = NUL; } #endif /* VMS */ return(success = 1); } #endif /* BROWSER */ #endif /* NOFRILLS */ #endif /* NOPUSH */ #ifdef CK_CTRLZ case XYEOF: { /* SET EOF */ extern int eofmethod; extern struct keytab eoftab[]; if ((x = cmkey(eoftab,3,"end-of-file detection method","", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); eofmethod = x; return(success = 1); } #endif /* CK_CTRLZ */ case XYRELY: { /* SET RELIABLE */ if ((x = cmkey(ooatab,3,"","automatic",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); reliable = x; setreliable = (x != SET_AUTO); debug(F101,"SET RELIABLE reliable","",reliable); return(success = 1); } #ifdef STREAMING case XYSTREAM: { /* SET STREAMING */ extern int streamrq; if ((x = cmkey(ooatab,3,"","automatic",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); streamrq = x; return(success = 1); } #endif /* STREAMING */ #ifdef CKSYSLOG case XYSYSL: { if ((x = cmkey(syslogtab,nsyslog,"","",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); #ifdef IKSD if (inserver && #ifdef IKSDCONF iksdcf #else 1 #endif /* IKSDCONF */ ) { printf("?Sorry, command disabled.\n"); return(success = 0); } #endif /* IKSD */ #ifdef CK_APC /* Don't let this be set remotely */ if (apcactive == APC_LOCAL || (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))) return(success = 0); #endif /* CK_APC */ ckxsyslog = x; return(success = 1); } #endif /* CKSYSLOG */ #ifdef TLOG case XYTLOG: { /* SET TRANSACTION-LOG */ extern int tlogsep; if ((x = cmkey(vbtab,nvb,"","verbose",xxstring)) < 0) return(x); if (x == 0) { if ((y = cmtxt("field separator",",",&s,NULL)) < 0) return(y); s = brstrip(s); if (*s) { if (s[1]) { printf("?A single character, please.\n"); return(-9); } else if ((*s >= '0' && *s <= '9') || (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z')) { printf("?A non-alphanumeric character, please.\n"); return(-9); } else tlogsep = *s; } } else { if ((y = cmcfm()) < 0) return(y); } #ifdef IKSD if (inserver && isguest) { printf("?Sorry, command disabled.\n"); return(success = 0); } #endif /* IKSD */ #ifdef CK_APC /* Don't let this be set remotely */ if (apcactive == APC_LOCAL || (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))) return(success = 0); #endif /* CK_APC */ tlogfmt = x; return(success = 1); } #endif /* TLOG */ case XYCLEAR: { /* SET CLEARCHANNEL */ if ((x = cmkey(ooatab,3,"","automatic",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); clearrq = x; return(success = 1); } #ifdef CK_AUTHENTICATION case XYAUTH: { /* SET AUTHENTICATION */ #ifdef CK_KERBEROS int kv = 0; extern struct krb_op_data krb_op; #endif /* CK_KERBEROS */ if ((x = cmkey(setauth,nsetauth,"authentication type","",xxstring)) < 0) return(x); switch (x) { #ifdef CK_KERBEROS case AUTH_KRB4: kv = 4; break; /* Don't assume values are same */ case AUTH_KRB5: kv = 5; break; #endif /* CK_KERBEROS */ #ifdef CK_SRP case AUTH_SRP: break; #endif /* CK_SRP */ #ifdef CK_SSL case AUTH_SSL: case AUTH_TLS: break; #endif /* CK_SSL */ default: printf("?Authorization type not supported yet - \"%s\"\n", atmbuf); return(-9); } #ifdef IKSD if (inserver && #ifdef IKSDCONF iksdcf #else 1 #endif /* IKSDCONF */ ) { if ((y = cmcfm()) < 0) return(y); printf("?Sorry, command disabled.\n"); return(success = 0); } #endif /* IKSD */ #ifdef CK_APC /* Don't let this be set remotely */ if (apcactive == APC_LOCAL || apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)) { if ((y = cmcfm()) < 0) return(y); return(success = 0); } #endif /* CK_APC */ switch(x) { #ifdef CK_KERBEROS case AUTH_KRB4: case AUTH_KRB5: { if ((x = cmkey(kv == 4 ? k4tab : k5tab, kv == 4 ? nk4tab : nk5tab, "Kerberos parameter","",xxstring)) < 0) { return(x); } s = ""; switch (x) { #ifdef KRB4 case XYKRBDBG: if (kv == 4) { if ((y = seton(&k4debug)) < 0) return(y); #ifdef NT ck_krb4_debug(k4debug); #endif /* NT */ } else { return(-9); } break; #endif /* KRB4 */ case XYKRBLIF: if ((y = cmnum("TGT lifetime","600",10,&z,xxstring)) < 0) return(y); break; case XYKRBPRE: if (kv == 4) { if ((y = seton(&krb4_d_preauth)) < 0) return(y); } else { return(-9); } break; case XYKRBINS: if ((y = cmtxt("Instance name","",&s,xxstring)) < 0) return(y); break; case XYKRBFWD: if (kv == 5) { if ((y = seton(&krb5_d_forwardable)) < 0) return(y); } else { return(-9); } break; case XYKRBPRX: if (kv == 5) { if ((y = seton(&krb5_d_proxiable)) < 0) return(y); } else { return(-9); } break; case XYKRBRNW: if ((y = cmnum("TGT renewable lifetime", "0",10,&z,xxstring)) < 0) return(y); break; case XYKRBADR: if (kv == 5) { if ((y = seton(&krb5_checkaddrs)) < 0) return(y); } else { if ((y = seton(&krb4_checkaddrs)) < 0) return(y); } break; case XYKRBNAD: if (kv == 5) { if ((y = seton(&krb5_d_no_addresses)) < 0) return(y); } break; case XYKRBADD: if (kv == 5) { char * tmpaddrs[KRB5_NUM_OF_ADDRS]; for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) tmpaddrs[i] = NULL; if ((y = cmfld("List of IP addresses","",&s,xxstring)) < 0) return(y); makelist(s,tmpaddrs,KRB5_NUM_OF_ADDRS); if ((y = cmcfm()) < 0) { for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) { if (tmpaddrs[i] != NULL) free(tmpaddrs[i]); } return(y); } for (i = 0; i < KRB5_NUM_OF_ADDRS && tmpaddrs[i]; i++) { if (inet_addr(tmpaddrs[i]) == 0xffffffff) { printf("invalid ip address: %s\n", tmpaddrs[i]); for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) { if (tmpaddrs[i] != NULL) free(tmpaddrs[i]); } return(-9); } } for (i = 0; i < KRB5_NUM_OF_ADDRS && krb5_d_addrs[i]; i++) { if (krb5_d_addrs[i]) free(krb5_d_addrs[i]); krb5_d_addrs[i] = NULL; } for (i = 0; i < KRB5_NUM_OF_ADDRS && tmpaddrs[i]; i++) { krb5_d_addrs[i] = tmpaddrs[i]; tmpaddrs[i] = NULL; } krb5_d_addrs[i] = NULL; return(success = 1); } break; case XYKRBGET: if (kv == 5) { if ((y = seton(&krb5_autoget)) < 0) return(y); } else { if ((y = seton(&krb4_autoget)) < 0) return(y); } break; case XYKRBDEL: if ((z = cmkey(kdestab,nkdestab, "Auto Destroy Tickets", "never",xxstring)) < 0) return(z); break; case XYKRBPR: if ((y = cmtxt("User ID",uidbuf,&s,xxstring)) < 0) return(y); break; case XYKRBRL: if ((y = cmtxt("Name of realm","",&s,xxstring)) < 0) return(y); break; case XYKRBKTB: y = cmifi("Filename","",&s,&z,xxstring); if (y != -3) { if (y < 0) return(y); if (z) { printf("?Wildcards not allowed\n"); return(-9); } } break; case XYKRBCC: if ((y = cmofi("Filename","",&s,xxstring)) < 0) return(y); break; case XYKRBSRV: if ((y = cmtxt("Name of service to use in ticket", (kv == 4 ? "rcmd" : "host"), &s, xxstring )) < 0) return(y); break; case XYKRBK5K4: if (kv == 5) { if ((y = seton(&krb5_d_getk4)) < 0) return(y); } else { return(-9); } break; case XYKRBPRM: /* Prompt */ if ((z = cmkey(krbprmtab,2,"","",xxstring)) < 0) return(z); if ((y = cmtxt((z == KRB_PW_PRM) ? "Text of prompt;\nmay contain \"%s\" to be replaced by principal name" : "Text of prompt", "", &s, xxstring ) ) < 0) return(y); break; } ckstrncpy(line,s,LINBUFSIZ); s = line; if ((y = cmcfm()) < 0) return(y); #ifdef IKSD if (inserver && #ifdef IKSDCONF iksdcf #else /* IKSDCONF */ 1 #endif /* IKSDCONF */ ) return(success = 0); #endif /* IKSD */ switch (x) { /* Copy value to right place */ case XYKRBLIF: /* Lifetime */ if (kv == 4) krb4_d_lifetime = z; else krb5_d_lifetime = z; break; case XYKRBRNW: if (kv == 5) krb5_d_renewable = z; break; case XYKRBPR: /* Principal */ s = brstrip(s); /* Strip braces around. */ if (kv == 4) makestr(&krb4_d_principal,s); else makestr(&krb5_d_principal,s); break; case XYKRBINS: /* Instance */ if (kv == 4) makestr(&krb4_d_instance,s); else makestr(&krb5_d_instance,s); break; case XYKRBRL: /* Realm */ if (kv == 4) makestr(&krb4_d_realm,s); else makestr(&krb5_d_realm,s); break; case XYKRBKTB: /* Key Table */ if (kv == 4) makestr(&k4_keytab,s); else makestr(&k5_keytab,s); break; case XYKRBCC: /* Credentials cache */ makestr(&krb5_d_cc,s); break; case XYKRBSRV: /* Service Name */ if (kv == 4) makestr(&krb4_d_srv,s); else makestr(&krb5_d_srv,s); break; case XYKRBDEL: if (kv == 5) krb5_autodel = z; else krb4_autodel = z; break; case XYKRBPRM: /* Prompt */ s = brstrip(s); switch (z) { case KRB_PW_PRM: { /* Password */ /* Check that there are no more than */ /* two % fields and % must followed by 's'. */ int i,n,len; len = strlen(s); for (i = 0, n = 0; i < len; i++) { if (s[i] == '%') { if (s[i+1] != '%') { if (s[i+1] != 's') { printf( "Only %%s fields are permitted.\n" ); return(-9); } if (++n > 2) { printf( "Only two %%s fields are permitted.\n"); return(-9); } } i++; } } if (kv == 5) makestr(&k5pwprompt,s); else makestr(&k4pwprompt,s); break; } case KRB_PR_PRM: { /* Principal */ /* Check to make sure there are no % fields */ int i,len; len = strlen(s); for (i = 0; i < len; i++) { if (s[i] == '%') { if (s[i+1] != '%') { printf( "%% fields are not used in this command.\n"); return(-9); } i++; } } if (kv == 5) makestr(&k5prprompt,s); else makestr(&k4prprompt,s); break; } } } break; } #endif /* CK_KERBEROS */ #ifdef CK_SRP case AUTH_SRP: { if ((x = cmkey(srptab, nsrptab, "SRP parameter","",xxstring)) < 0) { return(x); } s = ""; switch (x) { case XYSRPPRM: /* Prompt */ if ((z = cmkey(srpprmtab,1,"","",xxstring)) < 0) return(z); if ((y = cmtxt( "Text of prompt;\nmay contain one \"%s\" to be replaced by the username", "", &s, xxstring ) ) < 0) return(y); break; } ckstrncpy(line,s,LINBUFSIZ); s = line; if ((y = cmcfm()) < 0) return(y); switch (x) { /* Copy value to right place */ case XYSRPPRM: /* Prompt */ s = brstrip(s); switch (z) { case SRP_PW_PRM: { /* Password */ /* Check %s fields */ int i,n,len; len = strlen(s); for (i = 0, n = 0; i < len; i++) { if (s[i] == '%') { if (s[i+1] != '%') { if (s[i+1] != 's') { printf( "Only %%s fields are permitted.\n"); return(-9); } if (++n > 1) { printf( "Only one %%s field is permitted.\n"); return(-9); } } i++; } } makestr(&srppwprompt,s); break; } } } break; } #endif /* CK_SRP */ #ifdef CK_SSL case AUTH_SSL: case AUTH_TLS: { if ((z = cmkey(ssltab, nssltab, (x == AUTH_SSL ? "SSL parameter" : "TLS parameter"), "",xxstring)) < 0) return(z); s = ""; switch (z) { case XYSSLRCFL: /* SSL/TLS RSA Certs file */ case XYSSLRCCF: /* SSL/TLS RSA Certs Chain file */ case XYSSLRKFL: /* SSL/TLS RSA Key File */ case XYSSLDCFL: /* SSL/TLS DSA Certs file */ case XYSSLDCCF: /* SSL/TLS DSA Certs Chain file */ case XYSSLDKFL: /* SSL/TLS DH Key File */ case XYSSLDPFL: /* SSL/TLS DH Param File */ case XYSSLCRL: /* SSL/TLS CRL File */ case XYSSLVRFF: /* SSL/TLS Verify File */ case XYSSLRND: /* SSL/TLS Random File */ y = cmifi("Filename","",&s,&x,xxstring); if (y != -3) { if (y < 0) return(y); if (x) { printf("?Wildcards not allowed\n"); return(-9); } } ckstrncpy(line,s,LINBUFSIZ); s = line; s = brstrip(s); if ((y = cmcfm()) < 0) return(y); switch (z) { case XYSSLRCFL: /* SSL/TLS RSA Certs file */ if (!s[0] && ssl_rsa_cert_file) { free(ssl_rsa_cert_file); ssl_rsa_cert_file = NULL; } else if (s[0]) { makestr(&ssl_rsa_cert_file,s); if (!ssl_rsa_key_file) makestr(&ssl_rsa_key_file,s); } break; case XYSSLRCCF: /* SSL/TLS RSA Certs Chain file */ if (!s[0] && ssl_rsa_cert_chain_file) { free(ssl_rsa_cert_chain_file); ssl_rsa_cert_chain_file = NULL; } else if (s[0]) { makestr(&ssl_rsa_cert_chain_file,s); } break; case XYSSLRKFL: /* SSL/TLS RSA Key File */ if (!s[0] && ssl_rsa_key_file) { free(ssl_rsa_key_file); ssl_rsa_key_file = NULL; } else if (s[0]) { makestr(&ssl_rsa_key_file,s); } break; case XYSSLDCFL: /* SSL/TLS DSA Certs file */ if (!s[0] && ssl_dsa_cert_file) { free(ssl_dsa_cert_file); ssl_dsa_cert_file = NULL; } else if (s[0]) { makestr(&ssl_dsa_cert_file,s); if (!ssl_dh_key_file) makestr(&ssl_dh_key_file,s); } break; case XYSSLDCCF: /* SSL/TLS DSA Certs Chain file */ if (!s[0] && ssl_dsa_cert_chain_file) { free(ssl_dsa_cert_chain_file); ssl_dsa_cert_chain_file = NULL; } else if (s[0]) { makestr(&ssl_dsa_cert_chain_file,s); } break; case XYSSLDKFL: /* SSL/TLS DH Key File */ if (!s[0] && ssl_dh_key_file) { free(ssl_dh_key_file); ssl_dh_key_file = NULL; } else if (s[0]) { makestr(&ssl_dh_key_file,s); } break; case XYSSLDPFL: /* SSL/TLS DH Param File */ if (!s[0] && ssl_dh_param_file) { free(ssl_dh_param_file); ssl_dh_param_file = NULL; } else if (s[0]) { makestr(&ssl_dh_param_file,s); } break; case XYSSLCRL: /* SSL/TLS CRL File */ if (!s[0] && ssl_crl_file) { free(ssl_crl_file); ssl_crl_file = NULL; } else if (s[0]) { makestr(&ssl_crl_file,s); } break; case XYSSLVRFF: /* SSL/TLS Verify File */ if (!s[0] && ssl_verify_file) { free(ssl_verify_file); ssl_verify_file = NULL; } else if (s[0]) { makestr(&ssl_verify_file,s); } break; case XYSSLRND: /* SSL/TLS Random File */ if (!s[0] && ssl_rnd_file) { free(ssl_rnd_file); ssl_rnd_file = NULL; } else if (s[0]) { makestr(&ssl_rnd_file,s); } break; } break; case XYSSLCRLD: case XYSSLVRFD: { char * d = NULL; if (z == XYSSLVRFD) d= getenv("SSL_CERT_DIR"); if (d == NULL) d = ""; if ((y = cmdir("Directory",d,&s,xxstring)) < 0) if (y != -3) return(y); ckstrncpy(line,s,LINBUFSIZ); s = line; s = brstrip(s); if ((y = cmcfm()) < 0) return(y); switch(z) { case XYSSLCRLD: if (!s[0] && ssl_crl_dir) { free(ssl_crl_dir); ssl_crl_dir = NULL; } else if (s[0]) { makestr(&ssl_crl_dir,s); } break; case XYSSLVRFD: if (!s[0] && ssl_verify_dir) { free(ssl_verify_dir); ssl_verify_dir = NULL; } else if (s[0]) { makestr(&ssl_verify_dir,s); } break; } break; } case XYSSLCOK: /* SSL/TLS Certs-Ok flag */ if ((y = seton(&ssl_certsok_flag)) < 0) return(y); break; case XYSSLDBG: /* SSL/TLS Debug flag */ if ((y = seton(&ssl_debug_flag)) < 0) return(y); break; case XYSSLON: /* SSL/TLS Only flag */ switch (x) { case AUTH_SSL: if ((y = seton(&ssl_only_flag)) < 0) return(y); break; case AUTH_TLS: if ((y = seton(&tls_only_flag)) < 0) return(y); break; } break; case XYSSLVRB: /* SSL/TLS Verbose flag */ if ((y = seton(&ssl_verbose_flag)) < 0) return(y); break; case XYSSLVRF: /* SSL/TLS Verify flag */ if ((x = cmkey(sslvertab, nsslvertab, "SSL/TLS verify mode", "peer-cert",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); ssl_verify_flag = x; break; case XYSSLDUM: if ((y = seton(&ssl_dummy_flag)) < 0) return(y); break; case XYSSLCL: { /* SSL/TLS Cipher List */ #ifdef COMMENT /* This code is used to generate a colon delimited */ /* list of the ciphers currently in use to be used */ /* as the default for cmtxt(). However, a better */ /* default is simply the magic keyword "ALL". */ CHAR def[1024] = ""; if (ssl_con != NULL) { CHAR * p = NULL, *q = def; int i, len; for (i = 0; ; i++) { p = (CHAR *) SSL_get_cipher_list(ssl_con,i); if (p == NULL) break; len = strlen(p); if (q+len+1 >= def+1024) break; if (i != 0) *q++ = ':'; strcpy(q,p); q += len; } } #endif /* COMMENT */ char * p = getenv("SSL_CIPHER"); if (!p) p = "ALL"; if ((y = cmtxt( "Colon-delimited list of ciphers or ALL (case-sensitive)", p, &s, xxstring ) ) < 0) return(y); makestr(&ssl_cipher_list,s); if (ssl_con == NULL) { SSL_library_init(); ssl_ctx = (SSL_CTX *) /* Changed in 9.0.305 Alpha.03 from NetBSD 'rhialto' */ /* from: SSL_CTX_new((SSL_METHOD *)TLSv1_method()); to:...*/ SSL_CTX_new((SSL_METHOD *)SSLv23_method()); if (ssl_ctx != NULL) ssl_con= (SSL *) SSL_new(ssl_ctx); } if (ssl_con) { SSL_set_cipher_list(ssl_con,ssl_cipher_list); } break; } } break; } #endif /* CK_SSL */ default: break; } return(success = 1); } #endif /* CK_AUTHENTICATION */ #ifndef NOSPL case XYFUNC: if ((x = cmkey(functab,nfunctab,"","diagnostics",xxstring)) < 0) return(x); switch (x) { case FUNC_DI: return(seton(&fndiags)); case FUNC_ER: return(seton(&fnerror)); default: return(-2); } #endif /* NOSPL */ case XYSLEEP: /* SET SLEEP / PAUSE */ if ((x = cmkey(sleeptab,1,"","cancellation",xxstring)) < 0) return(x); return(seton(&sleepcan)); case XYCD: /* SET CD */ if ((x = cmkey(cdtab,ncdtab,"","",xxstring)) < 0) return(x); switch (x) { case XYCD_H: { /* SET CD HOME */ extern char * myhome; if ((y = cmdir("Directory name",zhome(),&s,xxstring)) < 0) return(y); makestr(&myhome,s); return(success = 1); } case XYCD_M: /* SET CD MESSAGE */ if ((x = cmkey(cdmsg,ncdmsg,"","",xxstring)) < 0) return(x); if (x == 2) { /* CD MESSAGE FILE */ if ((x = cmtxt("Name of file","",&s,NULL)) < 0) return(x); if (!*s) { s = NULL; #ifndef NOXFER srvcdmsg = 0; #endif /* NOXFER */ } makestr(&cdmsgstr,s); makelist(cdmsgstr,cdmsgfile,8); return(success = 1); } if ((y = cmcfm()) < 0) return(y); /* CD-MESSAGE ON/OFF */ #ifndef NOXFER if (x > 0) srvcdmsg |= 2; else srvcdmsg &= 1; #endif /* NOXFER */ return(success = 1); case XYCD_P: { /* SET CD PATH */ extern char * ckcdpath; if ((x = cmtxt("CD PATH string","",&s,xxstring)) < 0) return(x); makestr(&ckcdpath,s); return(success = 1); } } #ifndef NOLOCAL #ifdef STOPBITS case XYSTOP: /* STOP-BITS */ if ((x = cmkey(stoptbl,2,"Stop bits for serial device","", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); if (x > 0 && x < 3) { stopbits = x; #ifdef TN_COMPORT if (network && istncomport()) { tnsettings(-1, x); return(success = 1); } #endif /* TN_COMPORT */ #ifdef HWPARITY return(success = 1); #else /* HWPARITY */ return(-2); #endif /* HWPARITY */ } else return(-2); #endif /* STOPBITS */ case XYDISC: { extern int clsondisc; return(seton(&clsondisc)); } case XYSERIAL: { /* char c; */ extern int cmask; if ((x = cmkey(sertbl,nsertbl, "Serial device character size, parity, and stop bits", "8N1", xxstring)) < 0) return(x); ckstrncpy(line,atmbuf,LINBUFSIZ); /* Associated keyword string */ s = line; if ((y = cmcfm()) < 0) return(y); ckstrncpy(line,sernam[x],LINBUFSIZ); s = line; if (s[0] != '8' && s[0] != '7') /* Char size */ return(-2); else z = s[0] - '0'; if (isupper(s[1])) /* Parity */ s[1] = tolower(s[1]); if (s[2] != '1' && s[2] != '2') /* Stop bits */ return(-2); else stopbits = s[2] - '0'; if (z == 8) { /* 8 bits + parity (or not) */ parity = 0; /* Set parity */ hwparity = (s[1] == 'n') ? 0 : s[1]; setcmask(8); /* Also set TERM BYTESIZE to 8 */ } else { /* 7 bits plus parity */ parity = (s[1] == 'n') ? 0 : s[1]; hwparity = 0; setcmask(7); /* Also set TERM BYTESIZE to 7 */ } #ifdef TN_COMPORT if (network && !istncomport()) tnsettings(parity, stopbits); #endif /* TN_COMPORT */ return(success = 1); /* from SET SERIAL */ } case XYOPTS: { /* SET OPTIONS */ extern int setdiropts(); extern int settypopts(); #ifdef CKPURGE extern int setpurgopts(); #endif /* CKPURGE */ if ((x = cmkey(optstab,noptstab,"for command","", xxstring)) < 0) return(x); switch (x) { #ifndef NOFRILLS case XXDEL: return(setdelopts()); #endif /* NOFRILLS */ case XXDIR: return(setdiropts()); case XXTYP: return(settypopts()); #ifdef CKPURGE case XXPURGE: return(setpurgopts()); #endif /* CKPURGE */ default: return(-2); } } #endif /* NOLOCAL */ #ifndef NOXFER case XYQ8FLG: { extern int q8flag; return(seton(&q8flag)); } case XYTIMER: { extern int asktimer; y = cmnum("Time limit for ASK command, seconds","0",10,&x,xxstring); #ifdef QNX16 return(setnum(&asktimer,x,y,32767)); #else return(setnum(&asktimer,x,y,86400)); #endif /* QNX16 */ } case XYFACKB: { extern int fackbug; return(seton(&fackbug)); } #endif /* NOXFER */ case XYHINTS: return(seton(&hints)); #ifndef NOSPL case XYEVAL: { extern int oldeval; if ((x = cmkey(oldnew,2,"","", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); oldeval = x; return(success = 1); } #endif /* NOSPL */ #ifndef NOXFER case XYFACKP: { extern int fackpath; return(seton(&fackpath)); } #endif /* NOXFER */ case XYQNXPL: { extern int qnxportlock; return(seton(&qnxportlock)); } #ifndef NOCMDL #ifdef IKSD case XYIKS: { int setiks(); return(setiks()); } #endif /* IKSD */ #endif /* NOCMDL */ #ifdef CKROOT case XYROOT: return(dochroot()); #endif /* CKROOT */ #ifndef NOSPL #ifndef NOSEXP case XYSEXP: { if ((x = cmkey(sexptab,3,"","", xxstring)) < 0) return(x); switch (x) { case 0: if ((x = cmkey(ooatab,3,"","automatic", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); sexpecho = x; break; case 1: { int i, xx; xx = sexpmaxdep; if ((y = cmnum("Maximum recursion depth", "1000",10,&x,xxstring)) < 0) return(y); z = setnum(&sexpmaxdep,x,y,-1); if (z < 0) return(z); if (sxresult) { /* Free old stack if allocated */ for (i = 0; i < xx; i++) if (sxresult[i]) free(sxresult[i]); free((char *)sxresult); if (sxrlen) free((char *)sxrlen); sxresult = NULL; sxrlen = NULL; } break; } case 2: return(seton(&sexptrunc)); } return(success = 1); } #endif /* NOSEXPL */ #endif /* NOSPL */ #ifdef NEWFTP case XYGPR: { extern struct keytab gprtab[]; extern int ftpget; if ((x = cmkey(gprtab,3,"","kermit", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); ftpget = x; return(success = 1); } #endif /* NEWFTP */ #ifdef ANYSSH case XYSSH: return(dosetssh()); #endif /* ANYSHH */ #ifdef SFTP_BUILTIN case XYSFTP: return(dosetsftp()); #endif /* SFTP_BUILTIN */ #ifdef LOCUS case XYLOCUS: if ((x = cmkey(locustab,nlocustab,"", #ifdef KUI "ask" #else "auto" #endif /* KUI */ ,xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); if (x == 2 || x == 3) { /* AUTO or ASK */ setautolocus(x - 1); /* Two forms of automatic locusing */ /* setlocus(1,0); */ /* we're not changing the locus here */ } else { /* LOCAL or REMOTE */ setautolocus(0); /* No automatic Locus changing */ setlocus(x,0); /* Set Locus as requested */ } return(success = 1); #endif /* LOCUS */ #ifdef KUI case XYGUI: return(setgui()); #endif /* KUI */ #ifndef NOFRILLS #ifndef NORENAME case XY_REN: /* SET RENAME */ return(setrename()); #endif /* NORENAME */ #endif /* NOFRILLS */ #ifndef NOPUSH #ifdef CK_REDIR #ifndef NOXFER #ifndef XYZ_INTERNAL case XYEXTRN: /* SET EXTERNAL-PROTOCOL */ return(setextern()); #endif /* XYZ_INTERNAL */ #endif /* NOXFER */ #endif /* CK_REDIR */ #endif /* NOPUSH */ #ifndef NOSPL case XYVAREV: /* SET VARIABLE-EVALUATION */ return(setvareval()); #endif /* NOSPL */ #ifdef HAVE_LOCALE case XYLOCALE: if ((x = cmtxt("Locale string","C",&s,xxstring)) < 0) return(x); setlocale(LC_ALL, ""); setlocale(LC_ALL, s); if (!setlocale(LC_ALL,NULL)) { printf("Warning: setlocale(%s) error: %s\n", s, ck_errstr()); } #ifdef COMMENT if (!setlocale(LC_COLLATE, s)) {perror("COLLATE");return(success=0);} if (!setlocale(LC_CTYPE, s)) {perror("CTYPE");return(success=0);} if (!setlocale(LC_MESSAGES, s)) {perror("MESSAGES");return(success=0);} if (!setlocale(LC_MONETARY, s)) {perror("MONETARY");return(success=0);} if (!setlocale(LC_NUMERIC, s)) {perror("NUMERIC");return(success=0);} if (!setlocale(LC_TIME, s)) {perror("TIME");return(success=0);} #endif /* COMMENT */ return(success=1); #endif /* HAVE_LOCALE */ default: if ((x = cmcfm()) < 0) return(x); printf("Not implemented - %s\n",cmdbuf); return(success = 0); } } /* H U P O K -- Is Hangup OK? Issues a warning and gets OK from user depending on whether a connection seems to be open and what the SET EXIT WARNING setting is. Returns: 0 if not OK to hang up or exit (i.e. user said No); nonzero if OK. Argument x is used to differentiate the EXIT command from SET LINE / HOST. */ int #ifdef CK_ANSIC hupok( int x ) /* Returns 1 if OK, 0 if not OK */ #else hupok(x) int x; #endif /* CK_ANSIC */ { int y, z = 1; extern int exithangup; #ifdef VMS extern int batch; if (batch) /* No warnings in batch */ return(1); #else #ifdef UNIX if (backgrd) /* No warnings in background */ return(1); #endif /* UNIX */ #endif /* VMS */ #ifndef K95G debug(F101,"hupok local","",local); if (!local) /* No warnings in remote mode */ return(1); #endif /* K95G */ if (x == 0 && exithangup == 0) /* EXIT and EXIT HANGUP is OFF */ return(1); debug(F101,"hupok x","",x); debug(F101,"hupok xitwarn","",xitwarn); debug(F101,"hupok network","",network); debug(F101,"hupok haveline","",haveline); if ((local && xitwarn) || /* Is a connection open? */ (!x && xitwarn == 2)) { /* Or Always give warning on EXIT */ int needwarn = 0; char warning[256]; if (network) { if (ttchk() >= 0) needwarn = 1; /* A connection seems to be open but it can't possibly be */ if (!haveline) needwarn = 0; if (needwarn) { if (strcmp(ttname,"*")) ckmakmsg(warning,256, " A network connection to ",ttname, " might still be active.\n",NULL); else ckstrncpy(warning, " An incoming network connection might still be active.\n", 256); } } else { /* Serial connection */ if (carrier == CAR_OFF) /* SET CARRIER OFF */ needwarn = 0; /* so we don't care about carrier. */ else if ((y = ttgmdm()) >= 0) /* else, get modem signals */ needwarn = (y & BM_DCD); /* Check for carrier */ else /* If we can't get modem signals... */ needwarn = (ttchk() >= 0); /* A connection seems to be open but it can't possibly be */ if (!haveline || !exithangup) needwarn = 0; if (needwarn) ckmakmsg(warning,256, " A serial connection might still be active on ", ttname,".\n",NULL); } /* If a warning was issued, get user's permission to EXIT. */ if (needwarn || (!x && xitwarn == 2 #ifndef K95G && local #endif /* K95G */ )) { if ( !needwarn ) ckstrncpy(warning, "No active connections", 256); #ifdef COMMENT printf("%s",warning); z = getyesno(x ? "OK to close? " : "OK to exit? ",0); debug(F101,"hupok getyesno","",z); if (z < -3) z = 0; #else z = uq_ok(warning, x ? "OK to close? " : "OK to exit? ", 3, NULL, 0 ); debug(F101,"hupok uq_ok","",z); if (z < 0) z = 0; #endif /* COMMENT */ } } return(z); } #ifndef NOSHOW VOID shoctl() { /* SHOW CONTROL-PREFIXING */ #ifdef CK_SPEED int i; #ifdef OS2 #ifndef UNPREFIXZERO int zero; #endif /* UNPREFIXZERO */ #endif /* OS2 */ printf( "\ncontrol quote = %d, applied to (0 = unprefixed, 1 = prefixed):\n\n", myctlq); #ifdef OS2 #ifndef UNPREFIXZERO zero = ctlp[0]; if (protocol == PROTO_K) /* Zero can't be unprefixed */ ctlp[0] = 1; /* for Kermit */ #endif /* UNPREFIXZERO */ #endif /* OS2 */ for (i = 0; i < 16; i++) { printf(" %3d: %d %3d: %d ",i,ctlp[i], i+16, ctlp[i+16]); if (i == 15) printf(" 127: %d",ctlp[127]); else printf(" "); printf(" %3d: %d %3d: %d ",i+128,ctlp[i+128], i+144, ctlp[i+144]); if (i == 15) printf(" 255: %d",ctlp[255]); printf("\n"); } printf("\n"); #ifndef UNPREFIXZERO #ifdef OS2 ctlp[0] = zero; #endif /* OS2 */ #endif /* UNPREFIXZERO */ #endif /* CK_SPEED */ } #ifndef NOXFER VOID shodbl() { /* SHOW DOUBLE/IGNORE */ #ifdef CKXXCHAR int i, n = 0; printf("\nSET SEND DOUBLE characters:\n"); for (i = 0; i < 255; i++) { if (dblt[i] & 2) { n++; printf(" %d", i); } } if (n == 0) printf(" (none)"); n = 0; printf("\nSET RECEIVE IGNORE characters:\n"); for (i = 0; i < 255; i++) { if (dblt[i] & 1) { n++; printf(" %d", i); } } if (n == 0) printf(" (none)"); printf("\n\n"); #endif /* CKXXCHAR */ } #endif /* NOXFER */ #endif /* NOSHOW */ #ifndef NOPUSH #ifdef CK_REXX /* Rexx command. Note, this is not OS/2-specific, because Rexx also runs on other systems where C-Kermit also runs, like the Amiga. */ #define REXBUFL 100 /* Change this if neccessary */ char rexxbuf[REXBUFL] = { '\0' }; /* Rexx's return value (string) */ int dorexx() { int x, y; char *rexxcmd; if ((x = cmtxt("Rexx command","",&rexxcmd,xxstring)) < 0) return(x); /* No REXX command? Don't try to run the REXX command (doing so causes * Regina REXX to crash) */ if (strlen(rexxcmd) == 0) return(success = 0); #ifdef IKSD if (inserver) { printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ #ifdef CK_APC /* Don't let this be set remotely */ if (apcactive == APC_LOCAL || apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)) return(success = 0); #endif /* CK_APC */ ckstrncpy(line,rexxcmd,LINBUFSIZ); rexxcmd = line; #ifdef OS2 return(os2rexx(rexxcmd,rexxbuf,REXBUFL)); #else /* !OS2 */ printf("Sorry, nothing happens.\n"); return(success = 0); #endif /* OS2 */ } #endif /* CK_REXX */ #endif /* NOPUSH */ #else /* NOICP */ VOID dologend() { /* Dummy write record to connection log */ } #endif /* NOICP */ ckuus4.c000664 045065 024037 00002013152 14767410117 012561 0ustar00fdckermit000000 000000 #include "ckcsym.h" /* C K U U S 4 -- "User Interface" for C-Kermit, part 4 */ /* Authors: Frank da Cruz , The Kermit Project, New York City Jeffrey E Altman Secure Endpoints Inc., New York City Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Last update: Tue May 2 19:09:58 2023 */ /* File ckuus4.c -- Functions moved from other ckuus*.c modules to even out their sizes. */ #include "ckcdeb.h" #include "ckcasc.h" #include "ckcker.h" #include "ckcnet.h" /* Network symbols */ #include "ckuusr.h" #include "ckuver.h" #include "ckcxla.h" /* Character sets */ #ifdef HAVE_LOCALE #include #endif /* HAVE_LOCALE */ #ifdef CK_AUTHENTICATION #include "ckuath.h" #endif /* CK_AUTHENTICATION */ #ifdef CK_SSL #include "ck_ssl.h" #endif /* CK_SSL */ #ifdef VMS #include /* For \v(errno) */ extern char * ckvmserrstr(unsigned long); #ifndef OLD_VMS #include /* Not for VAX C 2.4 */ #else #include #endif /* OLD_VMS */ _PROTOTYP(int vmsttyfd, (void) ); #endif /* VMS */ /* This section is only for Kermit 95 for MS Windows and IBM OS/2 */ #ifdef OS2 #ifndef NT #define INCL_NOPM #define INCL_VIO /* Needed for ckocon.h */ #include #undef COMMENT #else #include #ifdef CK_TAPI #include #include "ckntap.h" #endif /* CK_TAPI */ #define APIRET ULONG #endif /* NT */ #include "ckocon.h" #include "ckodir.h" /* [jt] 2013/11/21 - for MAXPATHLEN */ #include "ckoetc.h" int StartedFromDialer = 0; HWND hwndDialer = 0; LONG KermitDialerID = 0; #ifdef NT BOOL dialerIsCKCM = 0; #endif /* NT */ #ifdef putchar #undef putchar #endif /* putchar */ #define putchar(x) conoc(x) #ifdef CK_PID #include #endif /* CK_PID */ #include "ckoreg.h" #include "ckoetc.h" #ifdef NT DWORD ckGetLongPathName(LPCSTR,LPSTR,DWORD); /* ckofio.c */ #endif /* NT */ #ifdef SSHBUILTIN #include "ckossh.h" #endif /* SSHBUILTIN */ #endif /* OS2 */ #ifdef KUI int get_gui_window_pos_y(); int get_gui_window_pos_x(); extern struct keytab * term_font; extern int ntermfont, tt_font, tt_font_size; #endif /* KUI */ extern xx_strp xxstring; #ifdef DEC_TCPIP #include #include #include #endif /* DEC_TCPIP */ #ifndef NOICP extern char *tfnam[]; extern int tlevel; #endif /* NOICP */ #ifdef FNFLOAT #include /* Floating-point functions */ #endif /* FNFLOAT */ int fp_rounding = 0; /* Nonzero if printf("%f") rounds */ int fp_digits = 0; /* Digits of floating point precision */ extern int quiet, network, xitsta, escape, nopush, xferstat, exitonclose, tn_exit, ttnproto, autodl, flow, byteorder, what, lastxfer; extern int filepeek, nscanfile, makestrlen; extern char * k_info_dir; #ifndef MAC #ifndef AMIGA extern int ttyfd; #endif /* MAC */ #endif /* AMIGA */ #ifdef TNCODE extern int tn_nlm, tn_b_nlm, tn_b_xfer, tn_sb_bug; extern int tn_rem_echo; extern int tn_b_meu, tn_b_ume, tn_auth_krb5_des_bug; #endif /* TNCODE */ static char * lastkwval = NULL; char * xferfile = NULL; int xferlog = 0; extern int local, xargc, stayflg, rcflag, bgset, backgrd, cfilef, inserver, srvcdmsg, success; #ifdef VMS extern int batch; #endif /* VMS */ extern char cmdfil[], *versio, *ckxsys, **xargv; extern char lasttakeline[]; #ifdef DEBUG extern char debfil[]; /* Debug log file name */ extern int debtim; #endif /* DEBUG */ extern int noinit; #ifdef OS2 extern int usageparm; /* Set if we're only going to show usage info and exit */ #endif /* OS2 */ static char ndatbuf[10]; char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; char * zzndate() { /* Returns today's date as yyyymmdd */ char * p = NULL; int x; /* WARNING - This will fail if asctime() returns non-English month names */ ztime(&p); /* Get "asctime" string */ if (p == NULL || *p == NUL) return(""); for (x = 20; x < 24; x++) /* yyyy */ ndatbuf[x - 20] = p[x]; ndatbuf[6] = (char) ((p[8] == ' ') ? '0' : p[8]); ndatbuf[7] = p[9]; /* dd */ for (x = 0; x < 12; x++) /* mm */ if (!strncmp(p+4,months[x],3)) break; if (x == 12) { ndatbuf[4] = ndatbuf[5] = '?'; } else { x++; ndatbuf[4] = (char) ((x < 10) ? '0' : '1'); ndatbuf[5] = (char) ((x % 10) + 48); } ndatbuf[8] = NUL; debug(F110,"zzndate return",ndatbuf,0); return((char *)ndatbuf); } #ifdef DCMDBUF extern struct cmdptr *cmdstk; extern char *line, *tmpbuf; #else extern struct cmdptr cmdstk[]; extern char line[], tmpbuf[]; #endif /* DCMDBUF */ #ifdef OS2 extern char exedir[]; #else extern char * exedir; #endif /* OS2 */ extern int nettype; #ifndef NOICP /* Most of this file... */ #ifdef CKLOGDIAL extern char diafil[]; #endif /* CKLOGDIAL */ #ifndef AMIGA #ifndef MAC #include #endif /* MAC */ #endif /* AMIGA */ #ifdef SV68 /* July 2006 believe it or not */ #ifndef SEEK_CUR #include #endif /* SEEK_CUR */ #endif /* SV68 */ #ifdef SCO32 /* June 2011 believe it or not... */ #ifdef XENIX #ifndef SEEK_CUR #include #endif /* SEEK_CUR */ #endif /* XENIX */ #endif /* SCO32 */ #include "ckcfnp.h" /* Prototypes (must be last) */ #ifdef STRATUS /* Stratus Computer, Inc. VOS */ #ifdef putchar #undef putchar #endif /* putchar */ #define putchar(x) conoc(x) #ifdef getchar #undef getchar #endif /* getchar */ #define getchar(x) coninc(0) #endif /* STRATUS */ #ifdef ANYX25 extern int revcall, closgr, cudata; int x25ver; extern char udata[]; #ifndef IBMX25 extern int npadx3; extern CHAR padparms[]; extern struct keytab padx3tab[]; #endif /* !IBMX25 */ #ifdef IBMX25 /* global variables only available for IBM X.25 - possibly interesting for * other implementations */ extern x25addr_t local_nua; extern x25addr_t remote_nua; #endif /* IBMX25 */ #endif /* ANYX25 */ #ifdef NETCONN #ifndef NODIAL extern int nnetdir; extern char *netdir[]; #endif /* NODIAL */ extern char ipaddr[]; #ifdef CK_NETBIOS extern unsigned short netbiosAvail; extern unsigned long NetbeuiAPI; extern unsigned char NetBiosName[]; extern unsigned char NetBiosAdapter; extern unsigned char NetBiosLSN; #endif /* CK_NETBIOS */ #ifdef TCPSOCKET extern char myipaddr[]; extern int tcp_rdns; #ifdef CK_DNS_SRV extern int tcp_dns_srv; #endif /* CK_DNS_SRV */ extern char * tcp_address; #ifndef NOHTTP extern char * tcp_http_proxy; #endif /* NOHTTP */ #ifdef NT #ifdef CK_SOCKS extern char * tcp_socks_svr; #ifdef CK_SOCKS_NS extern char * tcp_socks_ns; #endif /* CK_SOCKS_NS */ #endif /* CK_SOCKS */ #endif /* NT */ #ifndef NOTCPOPTS #ifdef SOL_SOCKET #ifdef SO_LINGER extern int tcp_linger; extern int tcp_linger_tmo; #endif /* SO_LINGER */ #ifdef SO_DONTROUTE extern int tcp_dontroute; #endif /* SO_DONTROUTE */ #ifdef TCP_NODELAY extern int tcp_nodelay; #endif /* TCP_NODELAY */ #ifdef SO_SNDBUF extern int tcp_sendbuf; #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF extern int tcp_recvbuf; #endif /* SO_RCVBUF */ #ifdef SO_KEEPALIVE extern int tcp_keepalive; #endif /* SO_KEEPALIVE */ #endif /* SOL_SOCKET */ #endif /* NOTCPOPTS */ #endif /* TCPSOCKET */ #endif /* NETCONN */ #ifdef CK_ANSIC /* static function prototypes - fdc 30 November 2022 */ static VOID evalerr( char * ); static char * fneval( char *, char*[], int, char * ); static char * dokwval( char *, char * ); static char * findinpath( char * ); static char * getip( char * ); static char * jpgdate( FILE * ); static char * pathval( int ); static int ckcindex( char, char * ); #endif /* CK_ANSI */ extern char * floname[]; #ifndef NOSPL extern int vareval; /* Variable evaluation method */ extern int fndiags; /* Function diagnostics on/off */ extern int divbyzero; int itsapattern = 0; int isinbuflen = 0; int isjoin = 0; #ifdef CK_APC extern int apcactive; /* Nonzero = APC command was rec'd */ extern int apcstatus; /* Are APC commands being processed? */ #ifdef DCMDBUF extern char *apcbuf; /* APC command buffer */ #else extern char apcbuf[]; #endif /* DCMDBUF */ #endif /* CK_APC */ extern char evalbuf[]; /* EVALUATE result */ extern char uidbuf[], pwbuf[], prmbuf[]; _PROTOTYP( static char * fneval, (char *, char * [], int, char * ) ); _PROTOTYP( static VOID myflsh, (void) ); _PROTOTYP( static char * getip, (char *) ); _PROTOTYP( int delta2sec, (char *, long *) ); #ifdef NEWFTP _PROTOTYP( char * ftp_cpl_mode, (void) ); _PROTOTYP( char * ftp_dpl_mode, (void) ); _PROTOTYP( char * ftp_authtype, (void) ); #endif /* NEWFTP */ #ifndef NOHTTP _PROTOTYP( char * http_host, (void) ); _PROTOTYP( int http_isconnected, (void) ); _PROTOTYP( char * http_security, (void) ); #endif /* NOHTTP */ #ifndef NOSEXP _PROTOTYP( char * dosexp, (char *) ); int fsexpflag = 0; #endif /* NOSEXP */ static char hexdigits[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; extern char * tempdir; #ifdef CK_REXX extern char rexxbuf[]; #endif /* CK_REXX */ extern int tfline[]; /* This is referenced from other modules so can't be static */ char *wkdays[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; #endif /* NOSPL */ #ifdef OS2 extern char startupdir[], inidir[]; #else #ifdef VMSORUNIX extern char startupdir[]; #endif /* VMSORUNIX */ #endif /* OS2 */ #ifdef OS2 _PROTOTYP (int os2getcp, (void) ); #ifdef TCPSOCKET extern char tcpname[]; #endif /* TCPSOCKET */ extern int tcp_avail; #ifdef DECNET extern int dnet_avail; #endif /* DECNET */ #ifdef SUPERLAT extern int slat_avail; #endif /* SUPERLAT */ #ifndef NOTERM extern int tt_type, max_tt; extern struct tt_info_rec tt_info[]; #endif /* NOTERM */ extern int tt_rows[], tt_cols[]; #else /* OS2 */ extern int tt_rows, tt_cols; #endif /* OS2 */ #ifdef CK_TAPI extern int tttapi; extern int tapipass; extern struct keytab * tapilinetab; extern struct keytab * _tapilinetab; extern int ntapiline; #endif /* CK_TAPI */ extern struct keytab colxtab[]; extern int ncolx; extern char ttname[], *zinptr, *kermrc; extern char inidir[]; extern int activecmd, remonly, cmd_rows, cmd_cols, parity, seslog, sessft, sosi, hwparity, tsecs, xargs, zincnt, tlevel, insilence, cmdmsk, timint, timef, inbufsize, dialog, binary, carrier, cdtimo, cmask, duplex, fmask, inecho, nmac, turnch, turn, kbchar; #ifndef NOXFER extern CHAR eol, mypadc, mystch, padch, seol, stchr, * epktmsg, feol; extern char *cksysid; extern struct ck_p ptab[]; extern int protocol, prefixing, xfrbel, xfrcan, xfrint, xfrchr, xfrnum, pktpaus, lscapr, lscapu, xfermode, dest, slostart, maxrps, maxsps, maxtry, mypadn, npad, pkttim, bigrbsiz, bigsbsiz, keep, atcapr, autopar, bctr, bctu, crunched, ckdelay, ebq, ebqflg, pktlog, retrans, rpackets, rptflg, rptq, rtimo, spackets, spsiz, spsizf, spsizr, timeouts, fncact, fncnv, urpsiz, wmax, wslotn, wslotr, fdispla, spmax, fnrpath, fnspath; extern long crc16; #endif /* NOXFER */ #ifdef OS2 extern int zxpn; extern int viewonly; #endif /* OS2 */ #ifndef NOXFER #ifdef GFTIMER extern CKFLOAT fptsecs, fpxfsecs; #endif /* GFTIMER */ extern long xfsecs, tfcps; #ifdef CK_TMPDIR extern char *dldir; #endif /* CK_TMPDIR */ #endif /* NOXFER */ #ifdef RECURSIVE extern int recursive; #endif /* RECURSIVE */ #ifdef VMS extern int frecl; #endif /* VMS */ extern CK_OFF_T ffc, tfc, tlci, tlco; extern long filcnt, rptn, speed, ccu, ccp, vernum, xvernum; #ifndef NOSPL extern char fspec[], myhost[]; #endif /* NOSPL */ extern char *tfnam[]; /* Command file names */ extern char pktfil[], /* Packet log file name */ #ifdef TLOG trafil[], /* Transaction log file name */ #endif /* TLOG */ sesfil[]; /* Session log file name */ #ifndef NOXMIT /* TRANSMIT command variables */ extern char xmitbuf[]; extern int xmitf, xmitl, xmitx, xmits, xmitw, xmitt; #endif /* NOXMIT */ extern int cmdlvl; #ifndef NOSPL /* Script programming language items */ extern char **a_ptr[]; /* Arrays */ extern int a_dim[]; static char * inpmatch = NULL; #ifdef CKFLOAT char * inpscale = NULL; #endif /* CKFLOAT */ extern char * inpbuf, inchar[]; /* Buffers for INPUT and REINPUT */ extern char *inpbp; /* And pointer to same */ static char *r3 = (char *)0; extern int incount; /* INPUT character count */ extern int m_found; /* MINPUT result */ extern int maclvl; /* Macro invocation level */ extern struct mtab *mactab; /* Macro table */ extern char *mrval[]; extern int macargc[], topargc; #ifdef COMMENT extern char *m_line[]; extern char *topline; #endif /* COMMENT */ extern char *m_arg[MACLEVEL][10]; /* You have to put in the dimensions */ extern char *g_var[GVARS+1]; /* for external 2-dimensional arrays. */ #ifdef DCMDBUF extern int *count, *inpcas; #else extern int count[], inpcas[]; #endif /* DCMDBUF */ #endif /* NOSPL */ #ifdef UNIX extern int haslock; /* For UUCP locks */ extern char flfnam[]; #ifndef USETTYLOCK extern char lock2[]; #endif /* USETTYLOCK */ #endif /* UNIX */ extern int mdmtyp, mdmsav; #ifndef NODIAL /* DIAL-related variables */ extern char modemmsg[]; extern MDMINF *modemp[]; /* Pointers to modem info structs */ extern int nmdm, dialhng, dialtmo, dialksp, dialdpy, dialsrt, dialsta; extern int dialrtr, dialint, dialrstr, dialcon, dialcq, dialfld; extern int mdmspd, dialec, dialdc, dialmth, dialmauto, dialesc; extern char *dialnum, *dialini, *dialdir[], *dialcmd, *dialnpr, *dialdcon, *dialdcoff, *dialecon, *dialecoff, *dialhcmd, *diallac, *dialhwfc, *dialswfc, *dialnofc, *dialpulse, *dialtone, *dialname, *dialaaon, *dialaaoff, *dialmac; extern char *diallcc, *dialixp, *dialixs, *dialldp, *diallds, *dialpxi, *dialpxo, *dialsfx, *dialtfp; extern char *diallcp, *diallcs; extern int ntollfree, ndialpxx, nlocalac; extern char *dialtfc[], *diallcac[], *dialpxx[], *matchpxx; extern int ndialpucc, ndialtocc; extern char *dialtocc[], *dialpucc[]; extern int ndialdir, dialcnf, dialcvt, dialidt, dialpace; extern long dialmax, dialcapas; extern struct keytab mdmtab[]; #ifdef BIGBUFOK #define ARGBUFSIZ 8191 #else #define ARGBUFSIZ 1023 #endif /* BIGBUFOK */ #ifdef BIGBUFOK extern char * dialmsg[]; #endif /* BIGBUFOK */ #endif /* NODIAL */ #ifndef NOCSETS /* Translation stuff */ extern int nfilc; extern struct keytab fcstab[]; extern int fcharset, tcharset, tslevel, language, nlng, tcsr, tcsl; extern int dcset7, dcset8; extern struct keytab lngtab[]; extern struct csinfo fcsinfo[], tcsinfo[]; extern struct langinfo langs[]; #ifdef CK_ANSIC extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */ extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */ #else extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */ extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */ #endif /* CK_ANSIC */ #ifdef UNICODE extern int ucsbom, ucsorder; #endif /* UNICODE */ #endif /* NOCSETS */ #ifndef NOSPL /* Built-in variable names, maximum length VNAML (20 characters) */ struct keytab vartab[] = { { "_line", VN_TFLN, CM_INV}, /* 192 */ { "apcactive", VN_APC, CM_INV}, /* 192 */ #ifdef NT { "appdata", VN_APPDATA, 0}, /* 201 */ #endif /* NT */ { "argc", VN_ARGC, 0}, { "args", VN_ARGS, 0}, { "authname", VN_AUTHN, 0}, /* 196 */ { "authstate", VN_AUTHS, 0}, /* 195 */ { "authtype", VN_AUTHT, 0}, /* 195 */ { "bits", VN_BITS, 0}, /* 212 */ { "blockcheck",VN_BLK, 0}, /* 195 */ #ifdef BROWSER { "browser", VN_BROWSR,0}, /* 193 */ { "browsopts", VN_BROPT, 0}, /* 193 */ { "browsurl", VN_URL, 0}, /* 193 */ { "buildid", VN_BUILD, 0}, /* 199 */ #endif /* BROWSER */ { "byteorder", VN_BYTE, 0}, /* 195 */ #ifndef NOCSETS { "charset", VN_CSET, 0}, /* 192 */ #endif /* NOCSETS */ { "cmdbufsize",VN_CMDBL, 0}, /* 195 */ { "cmdfile", VN_CMDF, 0}, { "cmdlevel", VN_CMDL, 0}, { "cmdsource", VN_CMDS, 0}, { "cols", VN_COLS, 0}, /* 190 */ #ifdef NT { "common", VN_COMMON, 0}, /* 201 */ #endif /* NT */ { "connection",VN_CONN, 0}, /* 190 */ { "count", VN_COUN, 0}, #ifndef NOXFER { "cps", VN_CPS, 0}, /* 190 */ #endif /* NOXFER */ { "cpu", VN_CPU, 0}, #ifndef NOXFER { "crc16", VN_CRC16, 0}, /* 192 */ { "ctty", VN_TTYNAM,0}, /* 196 */ #endif /* NOXFER */ #ifndef NOLOGDIAL #ifndef NOLOCAL { "cx_time", VN_CXTIME,0}, /* 195 */ { "cx_status", VN_CX_STA,0}, /* 199 */ #endif /* NOLOCAL */ #endif /* NOLOGDIAL */ #ifndef NODIAL { "d$ac", VN_D_AC, 0}, /* 192 */ { "d$cc", VN_D_CC, 0}, /* 192 */ { "d$ip", VN_D_IP, 0}, /* 192 */ { "d$lc", VN_D_LCP, 0}, /* 193 */ { "d$lcp", VN_D_LCP, CM_INV}, /* 193 */ { "d$lp", VN_D_LP, 0}, /* 192 */ { "d$px", VN_D_PXX, 0}, /* 195 */ { "d$pxx", VN_D_PXX, CM_INV}, /* 195 */ #endif /* NODIAL */ { "date", VN_DATE, 0}, { "day", VN_DAY, 0}, #ifdef NT { "desktop", VN_DESKTOP, 0}, /* 201 */ #endif /* NT */ #ifndef NODIAL { "dialcount", VN_DRTR, 0}, /* 195 */ { "dialmessage",VN_DMSG, 0}, /* 212 */ { "dialnumber",VN_DNUM, 0}, /* 192 */ { "dialresult",VN_MDMSG, 0}, /* 192 */ { "dialstatus",VN_DIAL, 0}, /* 190 */ { "dialsuffix",VN_PDSFX, 0}, /* 193 */ { "dialtype", VN_DTYPE, 0}, /* 193 */ #endif /* NODIAL */ { "directory", VN_DIRE, 0}, #ifndef NODIAL { "dm_hf", VN_DM_HF, 0}, /* 199 */ { "dm_lp", VN_DM_LP, 0}, /* 195 */ { "dm_sp", VN_DM_SP, 0}, /* 195 */ { "dm_pd", VN_DM_PD, 0}, /* 195 */ { "dm_td", VN_DM_TD, 0}, /* 195 */ { "dm_wa", VN_DM_WA, 0}, /* 195 */ { "dm_wb", VN_DM_WB, 0}, /* 199 */ { "dm_wd", VN_DM_WD, 0}, /* 195 */ { "dm_rc", VN_DM_RC, 0}, /* 195 */ #endif /* NODIAL */ #ifndef NOXFER { "download", VN_DLDIR, 0}, /* 192 */ #endif /* NOXFER */ { "editor", VN_EDITOR,0}, { "editfile", VN_EDFILE,0}, { "editopts", VN_EDOPT, 0}, { "errno", VN_ERRNO, 0}, /* 192 */ { "errstring", VN_ERSTR, 0}, /* 192 */ { "escape", VN_ESC, 0}, /* 193 */ { "evaluate", VN_EVAL, 0}, /* 190 */ #ifdef HAVE_VN_EXEDIR { "exedir", VN_EXEDIR,0}, /* 192 */ #endif /* def HAVE_VN_EXEDIR */ { "exitstatus",VN_EXIT, 0}, #ifdef CKCHANNELIO { "f_count", VN_FCOU, 0}, /* 195 */ { "f_error", VN_FERR, 0}, /* 195 */ { "f_max", VN_FMAX, 0}, /* 195 */ { "fileerror", VN_FERR, CM_INV}, /* 195 */ { "filemax", VN_FERR, CM_INV}, /* 195 */ #endif /* CKCHANNELIO */ { "filename", VN_FNAM, 0}, /* 193 */ { "filenumber",VN_FNUM, 0}, /* 193 */ { "filespec", VN_FILE, 0}, { "fsize", VN_FFC, 0}, /* 190 */ #ifdef GFTIMER { "ftime", VN_FTIME, 0}, /* 199 */ #else { "ftime", VN_NTIM, CM_INV}, #endif /* GFTIMER */ #ifndef NOFTP #ifndef SYSFTP { "ftp_code", VN_FTP_C, 0}, /* 199 */ { "ftp_cpl", VN_FTP_B, 0}, /* 199 */ { "ftp_connected", VN_FTP_X, 0}, /* 199 */ { "ftp_dpl", VN_FTP_D, 0}, /* 199 */ { "ftp_getputremote", VN_FTP_G, 0}, /* 199 */ { "ftp_host", VN_FTP_H, 0}, /* 199 */ { "ftp_loggedin", VN_FTP_L, 0}, /* 199 */ { "ftp_message", VN_FTP_M, 0}, /* 199 */ { "ftp_msg", VN_FTP_M, CM_INV}, /* 199 */ { "ftp_security", VN_FTP_Z, 0}, /* 199 */ { "ftp_server", VN_FTP_S, 0}, /* 199 */ #endif /* SYSFTP */ #endif /* NOFTP */ { "ftype", VN_MODE, 0}, /* 190 */ { "fullversion", VN_FULLVER, 0}, /* 400 */ #ifdef KUI { "gui_fontname", VN_GUI_FNM, 0}, /* 205 */ { "gui_fontsize", VN_GUI_FSZ, 0}, /* 205 */ { "gui_runmode", VN_GUI_RUN, 0}, /* 205 */ { "gui_xpos", VN_GUI_XP, 0}, /* 205 */ { "gui_xres", VN_GUI_XR, 0}, /* 205 */ { "gui_ypos", VN_GUI_YP, 0}, /* 205 */ { "gui_yres", VN_GUI_YR, 0}, /* 205 */ #endif /* KUI */ { "herald", VN_HERALD, 0}, { "home", VN_HOME, 0}, { "host", VN_HOST, 0}, { "hour", VN_HOUR, 0}, /* 200 */ #ifndef NOHTTP { "http_code", VN_HTTP_C, 0}, /* 199 */ { "http_connected", VN_HTTP_N, 0}, /* 199 */ { "http_host", VN_HTTP_H, 0}, /* 199 */ { "http_message", VN_HTTP_M, 0}, /* 199 */ { "http_security", VN_HTTP_S, 0}, /* 199 */ #endif /* NOHTTP */ { "hwparity", VN_HWPAR, 0}, /* 195 */ { "input", VN_IBUF, 0}, { "inchar", VN_ICHR, 0}, { "incount", VN_ICNT, 0}, { "inidir", VN_INI, 0}, /* 192 */ { "inmatch", VN_MATCH, 0}, /* 196 */ { "inmessage", VN_INPMSG,0}, /* 212 */ { "inscale", VN_ISCALE,0}, /* 210 */ { "instatus", VN_ISTAT, 0}, /* 192 */ { "intime", VN_INTIME,0}, /* 193 */ { "inwait", VN_INTMO, 0}, /* 195 */ { "ip", VN_IPADDR, CM_ABR|CM_INV}, { "ipaddress", VN_IPADDR,0}, /* 192 */ { "iprompt", VN_PROMPT,0}, /* 199 */ { "kbchar", VN_KBCHAR,0}, /* 196 */ #ifndef NOLOCAL #ifdef OS2 { "keyboard", VN_KEYB, 0}, #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef CK_KERBEROS { "krb4errmsg", VN_K4EMSG,0}, { "krb4errno", VN_K4ENO, 0}, { "krb4principal", VN_K4PRN, 0}, { "krb4realm", VN_K4RLM, 0}, { "krb4service", VN_K4SRV, 0}, { "krb5cc", VN_K5CC, 0}, { "krb5errmsg", VN_K5EMSG,0}, { "krb5errno", VN_K5ENO, 0}, { "krb5principal", VN_K5PRN, 0}, { "krb5realm", VN_K5RLM, 0}, { "krb5service", VN_K5SRV, 0}, #endif /* CK_KERBEROS */ { "lastcommand", VN_PREVCMD, 0}, /* 299 */ #ifndef NOLASTFILE { "lastfilespec", VN_LASTFIL, 0}, /* 212 */ #endif /* NOLASTFILE */ { "lastkeywordvalue", VN_LASTKWV, 0}, /* 212 */ { "lastkwvalue", VN_LASTKWV, CM_ABR|CM_INV}, /* 212 */ { "line", VN_LINE, 0}, { "local", VN_LCL, 0}, #ifdef UNIX { "lockdir", VN_LCKDIR,0}, /* 195 */ { "lockpid", VN_LCKPID,0}, /* 195 */ #endif /* UNIX */ { "log_connection", VN_LOG_CON, 0}, /* 206 */ { "log_debug", VN_LOG_DEB, 0}, /* 206 */ { "log_packet", VN_LOG_PKT, 0}, /* 206 */ { "log_session", VN_LOG_SES, 0}, /* 206 */ { "log_transaction", VN_LOG_TRA, 0},/* 206 */ { "maclevel", VN_MACLVL,0}, /* 195 */ { "macro", VN_MAC, 0}, #ifdef FNFLOAT { "math_e", VN_MA_E, 0}, /* 195 */ { "math_pi", VN_MA_PI, 0}, /* 195 */ { "math_precision", VN_MA_PR, 0}, /* 195 */ #endif /* FNFLOAT */ { "minput", VN_MINP, 0}, /* 192 */ { "model", VN_MODL, 0}, /* 193 */ { "modem", VN_MDM, 0}, { "month", VN_MONTH, 0}, /* 304 */ #ifndef NOLOCAL #ifdef OS2 { "mousecurx", VN_MOU_X, 0}, /* K95 1.1.14 */ { "mousecury", VN_MOU_Y, 0}, /* K95 1.1.14 */ #endif /* OS2 */ #endif /* NOLOCAL */ #ifndef NODIAL { "m_aa_off", VN_M_AAX, 0}, /* all 192... */ { "m_aa_on", VN_M_AAO, 0}, { "m_dc_off", VN_M_DCX, 0}, { "m_dc_on", VN_M_DCO, 0}, { "m_dial", VN_M_DCM, 0}, { "m_ec_off", VN_M_ECX, 0}, { "m_ec_on", VN_M_ECO, 0}, { "m_fc_hw", VN_M_HWF, 0}, { "m_fc_no", VN_M_NFC, 0}, { "m_fc_sw", VN_M_SWF, 0}, { "m_hup", VN_M_HUP, 0}, { "m_init", VN_M_INI, 0}, { "m_name", VN_M_NAM, 0}, /* 195 */ { "m_pulse", VN_M_PDM, 0}, { "m_sig_cd", VN_MS_CD, 0}, /* 195 */ { "m_sig_cts", VN_MS_CTS,0}, /* 195 */ { "m_sig_dsr", VN_MS_DSR,0}, /* 195 */ { "m_sig_dtr", VN_MS_DTR,0}, /* 195 */ { "m_sig_ri", VN_MS_RI, 0}, /* 195 */ { "m_sig_rts", VN_MS_RTS,0}, /* 195 */ { "m_tone", VN_M_TDM, 0}, #endif /* NODIAL */ { "name", VN_NAME, 0}, { "ndate", VN_NDAT, 0}, { "nday", VN_NDAY, 0}, { "newline", VN_NEWL, 0}, { "nmonth", VN_NMONTH,0}, /* 304 */ { "ntime", VN_NTIM, 0}, { "osname", VN_OSNAM, 0}, /* 193 */ { "osrelease", VN_OSREL, 0}, /* 193 */ { "osversion", VN_OSVER, 0}, /* 193 */ #ifndef NOXFER { "packetlen", VN_RPSIZ, 0}, /* 192 */ #endif /* NOXFER */ { "parity", VN_PRTY, 0}, /* 190 */ { "password", VN_PWD, CM_INV}, /* 192 */ #ifdef NT { "personal", VN_PERSONAL, 0}, /* 201 */ #endif /* NT */ #ifdef PEXITSTAT { "pexitstat", VN_PEXIT, 0}, /* 193 */ #endif /* PEXITSTAT */ #ifdef CK_PID { "pid", VN_PID, 0}, /* 193 */ #endif /* CK_PID */ { "platform", VN_SYSV, 0}, { "printer", VN_PRINT, 0}, /* 193 */ { "program", VN_PROG, 0}, { "prompt", VN_PRM, CM_INV}, /* 192 */ #ifndef NOXFER { "protocol", VN_PROTO, 0}, /* 192 */ { "p_8bit", VN_P_8BIT,0}, /* 193 */ { "p_ctl", VN_P_CTL, 0}, /* 193 */ { "p_rpt", VN_P_RPT, 0}, /* 193 */ { "query", VN_QUE, 0}, /* 190 */ #endif /* NOXFER */ { "remoteip", VN_HOSTIP,0}, /* 212 */ { "return", VN_RET, 0}, #ifdef CK_REXX { "rexx", VN_REXX, 0}, /* 190 */ #endif /* CK_REXX */ #ifdef TN_COMPORT { "rfc2217_signature", VN_TNC_SIG, 0}, /* 201 */ { "rfc2717_signature", VN_TNC_SIG, CM_INV}, /* 202 */ #endif /* TN_COMPORT */ { "rows", VN_ROWS, 0}, /* 190 */ #ifndef NOSEXP { "sdepth", VN_LSEXP,0}, /* 199 */ #endif /* NOSEXP */ { "secure", VN_SECURE, 0}, /* 199 */ #ifndef NOLOCAL #ifdef OS2 { "select", VN_SELCT, 0}, /* 192 */ #endif /* OS2 */ #endif /* NOLOCAL */ { "sendlist", VN_SNDL, 0}, { "serial", VN_SERIAL,0}, /* 195 */ { "setlinemsg",VN_SLMSG, 0}, /* 195 */ #ifndef NOSEXP { "sexpression",VN_SEXP, 0}, /* 199 */ #endif /* NOSEXP */ { "speed", VN_SPEE, 0}, #ifdef OS2 { "space", VN_SPA, 0}, { "startup", VN_STAR, 0}, /* 190 */ #else #ifdef UNIX { "startup", VN_STAR, 0}, /* 193 */ #else #ifdef VMS { "startup", VN_STAR, 0}, /* 193 */ #endif /* VMS */ #endif /* UNIX */ #endif /* OS2 */ { "status", VN_SUCC, 0}, #ifndef NOSEXP { "svalue", VN_VSEXP, 0}, /* 199 */ #endif /* NOSEXP */ #ifndef NOXFER { "sysid", VN_SYSI, 0}, #endif /* NOXFER */ { "system", VN_SYST, 0}, { "terminal", VN_TTYP, 0}, #ifdef OS2 #ifndef NOKVERBS { "termkey", VN_TRMK, CM_INV}, /* 192 */ #endif /* NOKVERBS */ #endif /* OS2 */ { "test", VN_TEST, 0}, /* 193 */ { "textdir", VN_TXTDIR,0}, /* 195 */ #ifndef NOXFER { "tfsize", VN_TFC, 0}, { "tftime", VN_TFTIM, 0}, /* 195 */ #endif /* NOXFER */ { "time", VN_TIME, 0}, { "timestamp", VN_NOW, 0}, /* 200 */ { "tmpdir", VN_TEMP, 0}, /* 192 */ #ifdef CK_TRIGGER { "trigger", VN_TRIG, 0}, /* 193 */ #endif /* CK_TRIGGER */ #ifdef CK_TTYFD { "ttyfd", VN_TTYF, 0}, #endif /* CK_TTYFD */ { "ty_ln", VN_TY_LN, 0}, /* 195 */ { "ty_lc", VN_TY_LC, 0}, /* 195 */ { "ty_lm", VN_TY_LM, 0}, /* 195 */ #ifdef BROWSER { "url", VN_URL, CM_INV}, /* 193 */ #endif /* BROWSER */ { "userid", VN_UID, 0}, /* 192 */ { "vareval", VN_VAREVAL, 0}, /* 212 */ { "version", VN_VERS, 0}, #ifndef NOXFER { "window", VN_WINDO, 0}, /* 192 */ #endif /* NOXFER */ #ifdef IBMX25 { "x25local_nua", VN_X25LA, 0}, /* 193 */ { "x25remote_nua", VN_X25RA, 0}, /* 193 */ #endif /* IBMX25 */ #ifdef CK_SSL { "x509_issuer", VN_X509_I, 0}, { "x509_subject", VN_X509_S, 0}, #endif /* CK_SSL */ #ifndef NOXFER { "xferstatus",VN_XFSTAT,0}, /* 193 */ { "xfermsg", VN_XFMSG, 0}, /* 193 */ { "xfer_badpackets", VN_XF_BC, 0}, /* 195 */ { "xfer_timeouts", VN_XF_TM, 0}, /* 195 */ { "xfer_retransmits",VN_XF_RX, 0}, /* 195 */ #endif /* NOXFER */ { "xprogram", VN_XPROG, 0}, /* 193 */ { "xversion", VN_XVNUM, 0}, /* 192 */ { "year", VN_YEAR, 0} /* 304 */ }; int nvars = (sizeof(vartab) / sizeof(struct keytab)); #endif /* NOSPL */ #ifndef NOSPL struct keytab fnctab[] = { /* Function names */ #ifdef OS2 { ".oox", FN_OOX, CM_INV}, /* ... */ #endif /* OS2 */ #ifdef CKCHANNELIO { "_eof", FN_FEOF, 0}, { "_errmsg", FN_FERMSG, 0}, { "_getblock", FN_FGBLK, 0}, { "_getchar", FN_FGCHAR, 0}, { "_getline", FN_FGLINE, 0}, { "_handle", FN_FILNO, 0}, { "_line", FN_NLINE, 0}, { "_pos", FN_FPOS, 0}, { "_putblock", FN_FPBLK, 0}, { "_putchar", FN_FPCHAR, 0}, { "_putline", FN_FPLINE, 0}, { "_status", FN_FSTAT, 0}, #endif /* CKCHANNELIO */ { "aaconvert", FN_AADUMP, 0}, /* Associative Array conversion */ { "absolute", FN_ABS, 0}, /* Absolute value */ #ifdef TCPSOCKET { "addr2name", FN_HSTADD,CM_INV}, /* IP Address to Hostname */ { "addrtoname", FN_HSTADD,CM_INV}, /* IP Address to Hostname */ #endif /* TCPSOCKET */ { "arraylook", FN_ALOOK,0}, /* Array lookup */ { "b64decode", FN_FMB64,0}, /* Base-64 conversion */ { "b64encode", FN_TOB64,0}, /* ... */ { "basename", FN_BSN, 0}, /* Basename */ { "break", FN_BRK, 0}, /* Break (as in Snobol) */ { "ca", FN_CAP, CM_INV|CM_ABR}, /* Abbreviation for capitablize */ { "cap", FN_CAP, CM_INV|CM_ABR}, /* Abbreviation for capitablize */ { "capitalize", FN_CAP, 0}, /* First Letter -> uppercase */ { "caps", FN_CAP, CM_INV}, /* ditto */ { "character", FN_CHR, 0}, /* Character from code */ { "checksum", FN_CHK, 0}, /* Checksum */ { "cmdstack", FN_CMDSTK,0}, /* Command stack */ { "cmpdates", FN_CMPDATE,0}, /* Compare dates */ { "code", FN_COD, 0}, /* Code from character */ #ifndef NOPUSH { "command", FN_CMD, 0}, /* Output from a command */ #endif /* NOPUSH */ { "contents", FN_CON, 0}, /* Definition (contents) of variable */ { "count", FN_COUNT, 0}, /* Occurrences of string in string */ { "crc16", FN_CRC, 0}, /* CRC-16 */ #ifdef OS2 { "crypt", FN_CRY, CM_INV}, #endif /* OS2 */ { "cvtcset", FN_XLATE, 0}, /* Convert character set */ { "cvtdate", FN_DTIM, 0}, /* Convert free date/time to std */ #ifdef ZFCDAT { "date", FN_FD, 0}, /* File modification/creation date */ #endif /* ZFCDAT */ { "day", FN_DAY, 0}, /* Day of week */ { "dayname", FN_DAYNAME,0}, /* Name of day of week */ { "dayofyear", FN_JDATE, 0}, /* Date to Day of Year */ { "decodehex", FN_UNPCT, 0}, /* Decode string with hex escapes */ { "definition", FN_DEF, 0}, /* Return definition of given macro */ { "delta2secs", FN_DELSEC, 0}, /* Delta time to seconds */ { "deltatosecs", FN_DELSEC, CM_INV}, /* Delta time to seconds */ #ifndef NODIAL { "dialconvert",FN_PNCVT,0}, /* Convert portable phone number */ #endif /* NODIAL */ { "diffdates", FN_DIFDATE,0}, /* Difference of two date-times */ { "dimension", FN_DIM, 0}, /* Dimension of array */ { "dir", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */ { "dire", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */ { "direc", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */ { "direct", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */ { "directo", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */ { "director", FN_DIR, CM_INV|CM_ABR}, /* Abbreviation for direct.. */ { "directories",FN_DIR, 0}, /* List of directories */ { "directory", FN_DIR, CM_INV}, /* List of directories */ { "dirname", FN_DNAM, 0}, /* Directory part of filename */ { "dos2unixpath",FN_PC_DU, CM_INV}, /* DOS to UNIX path */ { "dostounixpath",FN_PC_DU, 0}, /* DOS to UNIX path */ { "doy", FN_JDATE,CM_INV}, /* Date to Day of Year */ { "doy2date", FN_DATEJ,0}, /* Day of Year to date */ { "doytodate", FN_DATEJ,CM_INV}, /* Day of Year to date */ { "emailaddress",FN_EMAIL, 0}, /* Email address */ #ifdef FN_ERRMSG { "errstring", FN_ERRMSG,0}, /* Error code to message */ #endif /* FN_ERRMSG */ { "evaluate", FN_EVA, 0}, /* Evaluate given arith expression */ { "execute", FN_EXE, 0}, /* Execute given macro */ { "filecompare",FN_FILECMP, 0}, /* File compare */ { "fileinfo", FN_FILEINF, 0}, /* File information */ { "files", FN_FC, 0}, /* File count */ #ifdef FNFLOAT { "fpabsolute", FN_FPABS, 0}, /* Floating-point absolute value */ { "fpadd", FN_FPADD, 0}, /* FP add */ { "fpcosine", FN_FPCOS, 0}, /* FP cosine */ { "fpdivide", FN_FPDIV, 0}, /* FP divide */ { "fpexp", FN_FPEXP, 0}, /* FP e to the x */ { "fpint", FN_FPINT, 0}, /* FP to integer */ { "fplog10", FN_FPLOG, 0}, /* FP base-10 logarithm */ { "fplogn", FN_FPLN, 0}, /* FP natural logarithm */ { "fpmaximum", FN_FPMAX, 0}, /* FP maxinum */ { "fpminimum", FN_FPMIN, 0}, /* FP mininum */ { "fpmodulus", FN_FPMOD, 0}, /* FP modulus */ { "fpmultiply", FN_FPMUL, 0}, /* FP multiply */ { "fpraise", FN_FPPOW, 0}, /* FP raise to a power */ { "fpround", FN_FPROU, 0}, /* FP round */ { "fpsine", FN_FPSIN, 0}, /* FP sine */ { "fpsqrt", FN_FPSQR, 0}, /* FP square root */ { "fpsubtract", FN_FPSUB, 0}, /* FP subtract */ { "fptangent", FN_FPTAN, 0}, /* FP tangent */ #endif /* FNFLOAT */ { "function", FN_FUNC, 0 }, /* Test for existence of a function */ { "getpidinfo", FN_PID, CM_INV }, /* Get PID info (synonym for pidnfo) */ { "hex2ip", FN_HEX2IP,0}, /* Hex to IP address */ { "hextoip", FN_HEX2IP,CM_INV}, /* Hex to IP address */ { "hex2n", FN_HEX2N, CM_INV}, /* Hex to decimal number */ { "hexify", FN_HEX, 0}, /* Hexify (string) */ { "index", FN_IND, 0}, /* Index (string search) */ { "ip2hex", FN_IP2HEX,0}, /* IP address to hex */ { "iptohex", FN_IP2HEX,CM_INV}, /* IP address to hex */ { "ipaddress", FN_IPA, 0}, /* Find and return IP address */ { "jdate", FN_JDATE, CM_INV}, /* Date to Day of Year */ { "join", FN_JOIN, 0}, /* Join array elements */ { "keywordvalue", FN_KWVAL, 0}, /* Keyword=Value */ #ifdef CK_KERBEROS { "krbflags", FN_KRB_FG, 0}, /* Kerberos functions */ { "krbisvalid", FN_KRB_IV, 0}, { "krbnextticket", FN_KRB_NX, 0}, { "krbtickets", FN_KRB_TK, 0}, { "krbtimeleft", FN_KRB_TT, 0}, #endif /* CK_KERBEROS */ { "kwvalue", FN_KWVAL, CM_INV}, /* Keyword=Value */ { "left", FN_LEF, 0}, /* Leftmost n characters of string */ { "length", FN_LEN, 0}, /* Return length of argument */ { "literal", FN_LIT, 0}, /* Return argument literally */ #ifdef NT { "longpathname",FN_LNAME,0}, /* GetLongPathName() */ #else { "longpathname",FN_FFN,CM_INV}, #endif /* NT */ { "lop", FN_STL, 0}, /* Lop */ { "lopx", FN_LOPX, 0}, /* Lopx */ { "lower", FN_LOW, 0}, /* Return lowercased argument */ { "lpad", FN_LPA, 0}, /* Return left-padded argument */ { "ltrim", FN_LTR, 0}, /* Left-Trim */ { "maximum", FN_MAX, 0}, /* Return maximum of two arguments */ { "minimum", FN_MIN, 0}, /* Return minimum of two arguments */ { "mjd", FN_MJD, 0}, /* Date to Modified Julian Date */ { "mjd2date", FN_MJD2, CM_INV}, /* MJD to Date */ { "mjdtodate", FN_MJD2, 0}, /* MJD to Date */ { "modulus", FN_MOD, 0}, /* Return modulus of two arguments */ { "monthname", FN_MONNAME,0}, /* Name of month of year */ #ifdef COMMENT { "msleep", FN_MSLEEP,0}, /* Sleep for n milliseconds */ #endif /* COMMENT */ { "n2hex", FN_2HEX, CM_INV}, /* Number to hex */ { "n2octal", FN_2OCT, CM_INV}, /* Number to octal */ { "n2time", FN_N2TIM,0}, /* Number to hh:mm:ss */ #ifdef TCPSOCKET { "name2addr", FN_HSTNAM,CM_INV}, /* Hostname to IP Address */ #endif /* TCPSOCKET */ { "nday", FN_NDAY, 0}, /* Numeric day of week */ { "nextfile", FN_FIL, 0}, /* Next file in list */ { "ntime", FN_NTIM, 0}, /* Time to seconds since midnight */ { "ntohex", FN_2HEX, CM_INV}, /* Number to hex */ { "ntooctal", FN_2OCT, CM_INV}, /* Number to octal */ { "ntotime", FN_N2TIM,CM_INV}, /* Number to hh:mm:ss */ { "oct2n", FN_OCT2N,CM_INV}, /* Octal to decimal number */ { "octton", FN_OCT2N,CM_INV}, /* Octal to decimal number */ { "pathname", FN_FFN, 0}, /* Full file name */ { "pattern", FN_PATTERN, 0}, /* Pattern (for INPUT) */ #ifdef CK_PERMS { "permissions",FN_PERM, 0}, /* Permissions of file */ #else { "permissions",FN_PERM, CM_INV}, /* Permissions of file */ #endif /* CK_PERMS */ #ifdef SEEK_CUR { "pictureinfo",FN_PICTURE, 0 }, /* Picture orientation/dimensions */ #endif /* SEEK_CUR */ { "pidinfo", FN_PID, 0 }, /* Get PID info */ { "radix", FN_RADIX, 0 }, /* Radix conversion */ #ifndef NORANDOM { "random", FN_RAND, 0}, /* Random number */ #endif /* NORANDOM */ #ifndef NOPUSH { "rawcommand", FN_RAW, 0}, /* Output from a command (raw) */ #endif /* NOPUSH */ #ifdef RECURSIVE { "rdirectories", FN_RDIR, 0}, /* Recursive directory list */ #endif /* RECURSIVE */ { "recurse", FN_RECURSE, 0}, /* Recursive variable evaluation */ #ifdef RECURSIVE { "rfiles", FN_RFIL, 0}, /* Recursive file list */ #endif /* RECURSIVE */ { "rep", FN_REP, CM_INV|CM_ABR}, { "repeat", FN_REP, 0}, /* Repeat argument given # of times */ { "replace", FN_RPL, 0}, /* Replace characters in string */ { "reverse", FN_REV, 0}, /* Reverse the argument string */ { "right", FN_RIG, 0}, /* Rightmost n characters of string */ { "rindex", FN_RIX, 0}, /* Right index */ { "rpad", FN_RPA, 0}, /* Right-pad the argument */ { "rsearch", FN_RSEARCH, 0}, /* R-L Search for pattern in string */ #ifdef OS2 { "scrncurx", FN_SCRN_CX, 0}, /* Screen Cursor X Pos */ { "scrncury", FN_SCRN_CY, 0}, /* Screen Cursor Y Pos */ { "scrnstr", FN_SCRN_STR, 0}, /* Screen String */ #endif /* OS2 */ { "search", FN_SEARCH, 0}, /* L-R Search for pattern in string */ #ifndef NOSEXP { "sexpression",FN_SEXP, 0}, /* S-Expression */ #endif /* NOSEXP */ #ifdef NT { "shortpathname",FN_SNAME,0}, /* GetShortPathName() */ #else { "shortpathname",FN_FFN,CM_INV}, #endif /* NT */ { "size", FN_FS, 0}, /* File size */ #ifdef COMMENT { "sleep", FN_SLEEP,0}, /* Sleep for n seconds */ #endif /* COMMENT */ { "span", FN_SPN, 0}, /* Span - like Snobol */ { "split", FN_SPLIT,0}, /* Split string into words */ { "squeeze", FN_SQUEEZE,0}, /* Squeeze whitespace in string */ { "strcmp", FN_STRCMP,0}, /* String comparison */ { "stringtype", FN_STRINGT,0}, /* String type (7-bit, 8-bit, UTF-8) */ { "stripb", FN_STB, 0}, /* Strip enclosing braces/brackets */ { "stripn", FN_STN, 0}, /* Strip n chars */ { "stripx", FN_STX, 0}, /* Strip suffix */ { "su", FN_SUB, CM_INV|CM_ABR}, { "sub", FN_SUB, CM_INV|CM_ABR}, { "subs", FN_SUB, CM_INV|CM_ABR}, { "subst", FN_SUB, CM_INV|CM_ABR}, { "substitute", FN_SUBST,0}, /* Substitute chars */ { "substring", FN_SUB, 0}, /* Extract substring from argument */ { "tablelook", FN_TLOOK,0}, /* Table lookup */ { "time", FN_TIME, 0}, /* Free-format time to hh:mm:ss */ { "tod2secs", FN_NTIM, CM_INV}, /* Time-of-day-to-secs-since-midnite */ { "todtosecs", FN_NTIM, CM_INV}, /* Time-of-day-to-secs-since-midnite */ { "trim", FN_TRM, 0}, /* Trim */ { "unhexify", FN_UNH, 0}, /* Unhexify */ { "unix2dospath",FN_PC_UD, CM_INV}, /* UNIX to DOS path */ { "unixtodospath",FN_PC_UD, 0}, /* UNIX to DOS path */ { "untabify", FN_UNTAB,0}, /* Untabify */ { "upper", FN_UPP, 0}, /* Return uppercased argument */ { "utcdate", FN_TOGMT,0}, /* Date-time to UTC (GMT) */ { "verify", FN_VER, 0}, /* Verify */ { "word", FN_WORD, 0}, /* Extract a word */ { "", 0, 0} }; int nfuncs = (sizeof(fnctab) / sizeof(struct keytab)) - 1; #endif /* NOSPL */ #ifndef NOSPL /* Buffer for expansion of */ #ifdef BIGBUFOK /* built-in variables. */ #define VVBUFL 1024 #else #define VVBUFL 256 #endif /* BIGBUFOK */ char vvbuf[VVBUFL+1]; #endif /* NOSPL */ struct keytab disptb[] = { /* Log file disposition */ { "append", 1, 0}, { "new", 0, 0} }; #ifdef CKFLOAT /* I N I T F L O A T -- Deduce floating-point precision by inspection */ #ifdef COMMENT /* For looking at internal floating-point representations */ static char fp_xbuf[128]; static char * tohex(s, n) CHAR * s; int n; { int x; char * p = fp_xbuf; while (n-- > 0) { x = (*s >> 4) & 0x0f; *p++ = hexdigits[x]; x = *s++ & 0x0f; *p++ = hexdigits[x]; } *p = NUL; return((char *)fp_xbuf); } #endif /* COMMENT */ char math_pi[] = "3.1415926535897932384626433832795"; char math_e[] = "2.7182818284590452353602874713527"; VOID initfloat() { char * buf = NULL; int i, x, y; /* We malloc a big temporary buffer for sprintf() to minimize likelihood of (and damage from) sprintf buffer overflows. In any case, the only way this could happen would be if sprintf() itself had bugs, since the format descriptor says to cut it off at 250 decimal places. */ if ((buf = (char *)malloc(4096))) { sprintf(buf,"%0.250f",(10.0 / 3.0)); for (i = 2; i < 250 && buf[i] == '3'; i++) ; x = i - 1; debug(F111,"initfloat 10.0/3.0",buf,x); sprintf(buf,"%0.250f",(4.0 / 9.0)); for (i = 2; i < 250 && buf[i] == '4'; i++) ; y = i - 1; debug(F111,"initfloat 4.0/9.0",buf,y); fp_digits = (x < y) ? x : y; if (fp_digits < sizeof(math_pi) - 1) { math_pi[fp_digits+1] = NUL; math_e[fp_digits+1] = NUL; } sprintf(buf,"%0.6f",(7.0 / 9.0)); if (buf[7] == '8') fp_rounding = 1; debug(F111,"initfloat 7.0/9.0",buf,fp_rounding); debug(F101,"initfloat precision","",fp_digits); free(buf); } } #endif /* CKFLOAT */ /* P R E S C A N -- A quick look through the command-line options for items that must be handled before the initialization file is executed. */ #ifdef NT extern int StartedFromDialer; #endif /* NT */ #ifdef OS2 extern int k95stdio; unsigned long startflags = 0L; #endif /* OS2 */ static char * #ifdef CK_ANSIC findinpath( char * arg ) #else findinpath(arg) char * arg; #endif /* CK_ANSIC */ { #ifdef OS2 char * scriptenv, * keymapenv; int len; #endif /* OS2 */ #ifdef DCMDBUF extern char * cmdbuf; #else extern char cmdbuf[]; #endif /* DCMDBUF */ char takepath[4096]; char * s; int x; #ifndef OS2 #ifndef NOSPL int z; #endif /* NOSPL */ #endif /* !OS2 */ /* Set up search path... */ #ifdef OS2 char * appdata0 = NULL, *appdata1 = NULL; #ifdef NT scriptenv = getenv("K95SCRIPTS"); keymapenv = getenv("K95KEYMAPS"); makestr(&appdata0,GetAppData(0)); makestr(&appdata1,GetAppData(1)); #else /* NT */ scriptenv = getenv("K2SCRIPTS"); keymapenv = getenv("K2KEYMAPS"); #endif /* NT */ if (!scriptenv) scriptenv = getenv("CK_SCRIPTS"); if (!scriptenv) scriptenv = ""; if (!keymapenv) keymapenv = getenv("CK_KEYMAPS"); if (!keymapenv) keymapenv = ""; debug(F110,"startupdir",startupdir,0); debug(F110,"common appdata directory",appdata1,0); debug(F110,"appdata directory",appdata0,0); debug(F110,"inidir",inidir,0); debug(F110,"home",zhome(),0); debug(F110,"exedir",exedir,0); len = strlen(scriptenv) + strlen(keymapenv) + 3*strlen(startupdir) + 3*strlen(inidir) + 3*strlen(zhome()) + 3*strlen(exedir) + (appdata0 ? 3*strlen(appdata0) : 0) + (appdata1 ? 3*strlen(appdata1) : 0) + 6*strlen("SCRIPTS/") + 6*strlen("KEYMAPS/") + 16; if (len >= 4096) { /* SAFE (length is checked) */ takepath[0] = '\0'; debug(F111,"findinpath error - path length too long","len",len); } else sprintf(takepath, /* semicolon-separated path list */ "%s%s%s%s%s;%s%s;%s%s;%s%s%s%s%s%s%s%s%s%s%s%s%s;%s%s;%s%s;%s;%s%s;%s%s", scriptenv, (scriptenv[0] && scriptenv[strlen(scriptenv)-1]==';')?"":";", keymapenv, (keymapenv[0] && keymapenv[strlen(keymapenv)-1]==';')?"":";", startupdir, startupdir, "SCRIPTS/", startupdir, "KEYMAPS/", appdata1 ? appdata1 : "", appdata1 ? "Kermit 95;" : "", appdata1 ? appdata1 : "", appdata1 ? "Kermit 95/SCRIPTS/;" : "", appdata1 ? appdata1 : "", appdata1 ? "Kermit 95/KEYMAPS/;" : "", appdata0 ? appdata0 : "", appdata0 ? "Kermit 95;" : "", appdata0 ? appdata0 : "", appdata0 ? "Kermit 95/SCRIPTS/;" : "", appdata0 ? appdata0 : "", appdata0 ? "Kermit 95/KEYMAPS/;" : "", inidir, inidir, "SCRIPTS/", inidir, "KEYMAPS/", zhome(), zhome(), "SCRIPTS/", zhome(), "KEYMAPS/", exedir, exedir, "SCRIPTS/", exedir, "KEYMAPS/" ); debug(F110,"findinpath takepath",takepath,0); #ifdef NT makestr(&appdata0,NULL); makestr(&appdata1,NULL); #endif /* NT */ #else /* not OS2 */ #ifndef NOSPL z = 1024; /* Look in home directory */ s = takepath; zzstring("\\v(home)",&s,&z); #else takepath[0] = '\0'; #endif /* NOSPL */ #endif /* OS2 */ /* All the logic for searching the take path is in the command parser. So even though we aren't parsing commands, we initialize and call the parser from here, with the purported filename stuffed into the command buffer, followed by some carriage returns to make the parser return. If the file is not found, or otherwise not accessible, the parser prints an appropriate message, and then we just exit. */ cmdini(); /* Allocate command buffers etc */ cmini(0); /* Initialize them */ /* Stuff filename into command buf with braces in case of spaces */ ckmakmsg(cmdbuf,CMDBL,"{",arg,"}",NULL); debug(F110,"findinpath cmdbuf",cmdbuf,0); ckstrncat(cmdbuf,"\r\r",CMDBL); /* And some carriage returns */ if (cmifip("","",&s,&x,0,takepath,xxstring) < 0) return(NULL); cmres(); return(s); } static int tr_int; /* Flag if TRANSMIT interrupted */ #ifndef MAC SIGTYP #ifdef CK_ANSIC trtrap(int foo) /* TRANSMIT interrupt trap */ #else trtrap(foo) int foo; /* TRANSMIT interrupt trap */ #endif /* CK_ANSIC */ /* trtrap */ { #ifdef __EMX__ signal(SIGINT, SIG_ACK); #endif tr_int = 1; /* (Need arg for ANSI C) */ SIGRETURN; } #endif /* MAC */ #endif /* NOICP */ #ifdef UNIX VOID getexedir() { extern char * xarg0; long xx; /* Unix provides no standard service for this. We look in argv[0], and if we're lucky there's a full pathname. If not we do a PATH search. */ if (ckstrchr(xarg0,'/')) { /* Global copy of argv[0] */ int i, k; char * p = NULL; if ((k = ckstrncpy(tmpbuf,xarg0,TMPBUFSIZ-2)) > 0) { p = tmpbuf; /* Convert to fully qualified pathname */ if (tmpbuf[0]) if (tmpbuf[0] != '/') { line[0] = NUL; zfnqfp(tmpbuf,LINBUFSIZ-2,(char *)line); if (line[0]) p = line; } xx = zchki(p); if (xx > -1) { /* Is the result an existing file? */ k = strlen(p); for (i = k-1; i > 0; i--) { /* Yes, strip name part */ if (p[i] == '/') { if (i < k-1) p[i+1] = NUL; break; } } } makestr(&exedir,p); /* Save the result */ } } if (!exedir && xarg0) { /* Not found? */ char * p; p = getenv("PATH"); /* Search the PATH */ if (p) { /* If there is one... */ char * q, * PATH = NULL; int k; makestr(&PATH,p); /* Pokeable copy of PATH string */ if (PATH) { /* If malloc succeeded... */ p = PATH; while (p && *p) { /* Loop through segments */ q = ckstrchr(p,':'); /* End of this segment */ if (q == p) { /* Null PATH segment */ p++; /* Skip over colon */ continue; } if (q) /* If not at end of PATH string */ *q++ = NUL; /* zero out the colon */ if ((k = ckstrncpy(tmpbuf,p,TMPBUFSIZ)) > 0) { if (tmpbuf[k-1] != '/') { /* Copy this PATH segment */ tmpbuf[k++] = '/'; /* Append '/' if needed */ tmpbuf[k] = NUL; } /* Append the argv[0] value */ if (ckstrncpy(&tmpbuf[k],xarg0,TMPBUFSIZ) > 0) { if (zchki(tmpbuf) > -1) { /* File exists? */ tmpbuf[k] = NUL; /* Yes, we're done */ zfnqfp(tmpbuf,LINBUFSIZ,(char *)line); makestr(&exedir,line); break; } } else break; } else break; p = q; /* Not found, go to next segment */ } /* while */ free(PATH); /* Free PATH copy */ } } if (!exedir) { /* Still nothing? */ if (zchki(xarg0) > -1) { /* Maybe it's in the current dir */ zfnqfp(zgtdir(),LINBUFSIZ,(char *)line); makestr(&exedir,line); } } } if (!exedir) { /* Still nothing? */ makestr(&exedir,"/"); /* Fake it with with root. */ } } #endif /* UNIX */ int arg_x = 0; static int x_prescan = 0; /* The argument y once meant something but I can't imagine what so now it's ignored. (Prior to 22 Aug 98, prescan() was called twice by main(), and the arg differentiated the two calls. But this caused all sorts of problems & confusion, so I commented out the second call. This issue might need to be revisited.) */ VOID #ifdef CK_ANSIC prescan( int dummy ) /* Arg is ignored. */ #else prescan(dummy) int dummy; #endif /* CK_ANSIC */ { extern int howcalled; int yargc; char **yargv; char x; char *yp, *yy; #ifdef DEBUG int debcount = 0; #endif /* DEBUG */ if (x_prescan) /* Only run once */ return; x_prescan = 1; yargc = xargc; /* Make copy of arg vector */ yargv = xargv; #ifndef NOICP #ifdef DCMDBUF if (!kermrc) if (!(kermrc = (char *) malloc(KERMRCL+1))) fatal("prescan: no memory for kermrc"); #endif /* DCMDBUF */ ckstrncpy(kermrc,KERMRC,KERMRCL); /* Default init file name */ #endif /* NOICP */ #ifdef OS2 yp = getenv("K95STARTFLAGS"); if (yp) { startflags = atoi(yp); } #endif /* OS2 */ #ifdef IKSD if (howcalled == I_AM_IKSD) /* Internet Kermit Service daemon */ inserver = 1; /* (See inserver section of ckcmai) */ #endif /* IKSD */ /* Command line options for Kermit */ #ifndef NOCMDL if (yargc > 1 && *yargv[1] != '-' && (yargv[1][0] != '=') #ifdef KERBANG && (yargv[1][0] != '+') #endif /* KERBANG */ #ifdef IKSD && (howcalled != I_AM_IKSD) #endif /* IKSD */ ) { /* Filename as 1st argument */ #ifndef NOICP char *s; #endif /* NOICP */ #ifndef NOURL extern int haveurl; extern struct urldata g_url; if (urlparse(yargv[1],&g_url)) { if (!ckstrcmp(g_url.svc,"ftp",-1,0) || !ckstrcmp(g_url.svc,"ftps",-1,0)) { haveurl = 1; howcalled = I_AM_FTP; } else if (!ckstrcmp(g_url.svc,"telnet",-1,0) || !ckstrcmp(g_url.svc,"telnets",-1,0)) { haveurl = 1; howcalled = I_AM_TELNET; } else if (!ckstrcmp(g_url.svc,"ssh",-1,0)) { haveurl = 1; howcalled = I_AM_SSH; } else if (!ckstrcmp(g_url.svc,"iksd",-1,0) || !ckstrcmp(g_url.svc,"kermit",-1,0)) { haveurl = 1; howcalled = I_AM_KERMIT; } else if (!ckstrcmp(g_url.svc,"http",-1,0) || !ckstrcmp(g_url.svc,"https",-1,0)) { haveurl = 1; howcalled = I_AM_HTTP; } if (haveurl) { while (--yargc > 0) { /* Go through command-line args */ yargv++; /* looking for -Y and -d */ yp = *yargv+1; if (**yargv == '-') { x = *(*yargv+1); while (x) { switch (x) { #ifndef NOICP case '+': case '-': if (doxarg(yargv,1) < 0) { fatal("Extended argument error"); } yp = ""; break; #endif /* NOICP */ case 'Y': noinit++; break; case 'q': quiet = 1; break; case 'h': noinit = 1; #ifdef OS2 startflags |= 2; /* No network DLLs */ startflags |= 4; /* No TAPI DLLs */ startflags |= 8; /* No Security DLLs */ startflags |= 16; /* No Zmodem DLLs */ startflags |= 32; /* Stdin */ startflags |= 64; /* Stdout */ usageparm = 1; /* Showing usage and exiting */ #endif /* OS2 */ break; case 'd': /* = SET DEBUG ON */ #ifdef DEBUG if (debcount++ > 0) debtim = 1; if (!deblog) deblog = debopn("debug.log",0); #endif /* DEBUG */ break; #ifdef OS2 case 'W': if (*(yp+1)) fatal("invalid argument bundling after -W"); yargv++, yargc--; if (yargc < 1) fatal("Window handle missing"); #ifdef _WIN64 hwndDialer = (HWND) _atoi64(*yargv); #else /* _WIN64 */ hwndDialer = (HWND) atol(*yargv); #endif /* _WIN64 */ StartedFromDialer = 1; yargv++, yargc--; KermitDialerID = atol(*yargv) ; break; case '#': /* K95 initialization options */ if (*(yp+1)) { fatal("invalid argument bundling"); } yargv++, yargc--; if (yargc < 1) fatal("-# argument missing"); startflags |= atol(*yargv); break; #endif /* OS2 */ } if (!yp) break; x = *++yp; } } } return; } } /* after this point non-Kermit personalities must return */ switch (howcalled) { case I_AM_KERMIT: case I_AM_IKSD: case I_AM_SSHSUB: break; default: return; } #endif /* NOURL */ #ifndef NOICP /* If it is not a URL that we recognize, try to treat it as a file */ if (!isabsolute(yargv[1])) /* If not absolute */ s = findinpath(yargv[1]); /* Look in PATH */ else s = yargv[1]; if (!s) doexit(BAD_EXIT,xitsta); zfnqfp(s,CKMAXPATH,cmdfil); /* In case of CD in file */ yargc -= 1; /* Skip past the filename */ yargv += 1; /* Otherwise we'll get an error */ #endif /* NOICP */ } #ifndef NOCMDL #ifdef NEWFTP if (howcalled == I_AM_FTP) { /* Kermit's FTP client personality */ while (--yargc > 0) { /* Go through command-line args */ yargv++; /* looking for -Y and -d */ yp = *yargv+1; if (**yargv == '-') { x = *(*yargv+1); while (x) { switch (x) { #ifndef NOICP case '+': case '-': if (doxarg(yargv,1) < 0) { fatal("Extended argument error"); } yp = ""; break; #endif /* NOICP */ case 'Y': noinit++; break; case 'q': quiet = 1; break; case 'h': noinit = 1; #ifdef OS2 startflags |= 2; /* No network DLLs */ startflags |= 4; /* No TAPI DLLs */ startflags |= 8; /* No Security DLLs */ startflags |= 16; /* No Zmodem DLLs */ startflags |= 32; /* Stdin */ startflags |= 64; /* Stdout */ usageparm = 1; /* Showing usage and exiting */ #endif /* OS2 */ break; case 'd': /* = SET DEBUG ON */ #ifdef DEBUG if (debcount++ > 0) debtim = 1; if (!deblog) deblog = debopn("debug.log",0); #endif /* DEBUG */ break; #ifdef OS2 case 'W': if (*(yp+1)) fatal("invalid argument bundling after -W"); yargv++, yargc--; if (yargc < 1) fatal("Window handle missing"); #ifdef _WIN64 hwndDialer = (HWND) _atoi64(*yargv); #else /* _WIN64 */ hwndDialer = (HWND) atol(*yargv); #endif /* _WIN64 */ StartedFromDialer = 1; yargv++, yargc--; KermitDialerID = atol(*yargv) ; break; case '#': /* K95 initialization options */ if (*(yp+1)) { fatal("invalid argument bundling"); } yargv++, yargc--; if (yargc < 1) fatal("-# argument missing"); startflags |= atol(*yargv); break; #endif /* OS2 */ } if (!yp) break; x = *++yp; } } } return; } #endif /* NEWFTP */ #endif /* NOCMDL */ while (--yargc > 0) { /* Go through command-line args */ yargv++; yp = *yargv+1; /* Pointer for bundled args */ if (**yargv == '=') /* Same rules as cmdlin()... */ return; debug(F110,"prescan *yargv",*yargv,0); #ifndef NOICP #ifdef KERBANG yy = *yargv; if (!strcmp(yy,"+") || (*yy == '+' && *(yy+1) < (char)33)) { char * s; yargv++; noinit = 1; if (!*yargv) return; cfilef = 1; s = findinpath(*yargv); if (s) { zfnqfp(s,CKMAXPATH,cmdfil); return; } else doexit(BAD_EXIT,xitsta); } #endif /* KERBANG */ #endif /* NOICP */ if (!strcmp(*yargv,"--")) /* getopt() conformance */ return; #ifdef VMS else if (**yargv == '/') continue; #endif /* VMS */ else if (**yargv == '-') { /* Got an option (begins with dash) */ x = *(*yargv+1); /* Get option letter */ while (x) { /* Allow for bundled options */ debug(F000,"prescan arg","",x); switch (x) { #ifndef NOICP case '+': case '-': if (doxarg(yargv,1) < 0) { fatal("Extended argument error"); } #ifndef COMMENT /* Jeff 28 Apr 2003 */ yp = NULL; /* (not "") */ #else yargv++, yargc--; yp = *yargv; #endif /* COMMENT */ break; #endif /* NOICP */ case '7': /* Undocumented... */ sstelnet = 1; /* (because it doesn't work) */ break; #ifdef IKSD case 'A': { char * p; inserver = 1; /* Flag that we are doing this */ srvcdmsg = 2; /* Preset this */ /* See inserver section of ckcmai.c for more settings */ #ifdef OS2 if (*(yp+1)) { fatal("invalid argument bundling after -A"); } #ifdef NT /* Support for Pragma Systems Telnet/Terminal Servers */ p = getenv("PRAGMASYS_INETD_SOCK"); if (p && atoi(p) != 0) { ttname[0] = '$'; ckstrncpy(&ttname[1],p,TTNAMLEN-1); break; } #endif /* NT */ yargv++, yargc--; if (yargc < 1 || **yargv == '-') { fatal("-A argument missing"); } else { ttname[0] = '$'; ckstrncpy(&ttname[1],*yargv,TTNAMLEN-1); } #endif /* OS2 */ break; } #endif /* IKSD */ #ifdef OS2 case 'W': if (*(yp+1)) fatal("invalid argument bundling after -W"); yargv++, yargc--; if (yargc < 1) fatal("Window handle missing"); #ifdef COMMENT if (dummy) { yargv++, yargc--; break; } else { #endif /* COMMENT */ #ifdef _WIN64 hwndDialer = (HWND) _atoi64(*yargv); #else /* _WIN64 */ hwndDialer = (HWND) atol(*yargv); #endif /* _WIN64 */ StartedFromDialer = 1; yargv++, yargc--; KermitDialerID = atol(*yargv) ; #ifdef COMMENT } #endif /* COMMENT */ break; case '#': /* K95 initialization options */ if (*(yp+1)) { fatal("invalid argument bundling"); } yargv++, yargc--; if (yargc < 1) fatal("-# argument missing"); startflags |= atol(*yargv); break; #endif /* OS2 */ #ifndef NOSPL case 'M': /* My User Name */ if (*(yp+1)) { fatal("invalid argument bundling"); } yargv++, yargc--; if ((yargc < 1) || (**yargv == '-')) { fatal("missing username"); } if ((int)strlen(*yargv) > UIDBUFLEN) { fatal("username too long"); } #ifdef COMMENT /* This can't work. uidbuf is overwritten in sysinit() which has yet to be called. This cannot be set in prescan(). */ #ifdef IKSD if (!inserver) #endif /* IKSD */ ckstrncpy(uidbuf,*yargv,UIDBUFLEN); #endif /* COMMENT */ break; #endif /* NOSPL */ case 'R': /* Remote-only advisory */ #ifdef CK_IFRO remonly = 1; #endif /* CK_IFRO */ break; case 'S': /* STAY */ stayflg = 1; break; case 'h': noinit = 1; #ifdef OS2 startflags |= 2; /* No network DLLs */ startflags |= 4; /* No TAPI DLLs */ startflags |= 8; /* No Security DLLs */ startflags |= 16; /* No Zmodem DLLs */ startflags |= 32; /* Stdin */ startflags |= 64; /* Stdout */ usageparm = 1; /* Showing usage and exiting */ #endif /* OS2 */ break; #ifndef NOICP case 'Y': /* No init file */ noinit = 1; break; #endif /* NOICP */ case 'q': quiet = 1; break; case 'd': /* = SET DEBUG ON */ #ifdef DEBUG if (debcount++ > 0) debtim = 1; if (!deblog) deblog = debopn("debug.log",0); #endif /* DEBUG */ break; case 'x': /* Server */ arg_x = 1; /* Note in advance */ break; #ifndef NOICP case 'y': /* Alternative init file */ noinit = 0; yargv++, yargc--; if (yargc < 1) fatal("missing name in -y"); /* Replace init file name */ ckstrncpy(kermrc,*yargv,KERMRCL); rcflag = 1; /* Flag that this has been done */ debug(F111,"prescan kermrc",kermrc,rcflag); break; #endif /* NOICP */ case 'z': /* = SET BACKGROUND OFF */ bgset = 0; backgrd = 0; #ifdef VMS batch = 0; #endif /* VMS */ break; case 'B': /* Force background (batch) */ bgset = 1; backgrd = 1; #ifdef VMS batch = 1; #endif /* VMS */ break; #ifdef CK_NETBIOS case 'N': { int n ; yargv++, yargc--; #ifdef COMMENT if (y) break; #endif /* COMMENT */ if (strlen(*yargv) != 1 || (*yargv)[0] == 'X') { NetBiosAdapter = -1; } else { n = atoi(*yargv); if (n >= 0 && n <= 9) NetBiosAdapter = n; else NetBiosAdapter = -1; } } break; #endif /* CK_NETBIOS */ default: break; } if (!yp) break; x = *++yp; /* See if options are bundled */ } } } #endif /* NOCMDL */ } /* G E T T C S -- Get Transfer (Intermediate) Character Set */ /* Given two file character sets, this routine picks out the appropriate "transfer" character set to use for translating between them. The transfer character set number is returned. At present this routine is somewhat overloaded. It's fine for file transfer because it does not assume the Kermit partner understands UTF8. However, for terminal emulation it *should* use UTF8 as the intermediate character set whenever possible so as not to lose characters it might have been able to display; for example on a terminal connection from the Linux console (UTF8) to a BBS that uses CP437 box-drawing characters. This is handled in the CONNECT command code in ckucns.c, which avoids calling this routine if the character-set on either end is UTF8. Translation between different Kanji character sets is not yet supported. */ int #ifdef CK_ANSIC gettcs( int cs1, int cs2 ) #else gettcs(cs1,cs2) int cs1, cs2; #endif /* CK_ANSIC */ { #ifdef NOCSETS /* No character-set support */ return(0); /* so no translation */ #else int tcs = TC_TRANSP; #ifdef KANJI /* Kanji not supported yet */ if (fcsinfo[cs1].alphabet == AL_JAPAN || fcsinfo[cs2].alphabet == AL_JAPAN ) tcs = TC_TRANSP; else #endif /* KANJI */ #ifdef CYRILLIC /* I can't remember why we don't test both sets here, but I think there must have been a reason... */ if (fcsinfo[cs2].alphabet == AL_CYRIL) tcs = TC_CYRILL; else #endif /* CYRILLIC */ #ifdef HEBREW if (fcsinfo[cs1].alphabet == AL_HEBREW || fcsinfo[cs2].alphabet == AL_HEBREW ) tcs = TC_HEBREW; else #endif /* HEBREW */ #ifdef GREEK if (fcsinfo[cs1].alphabet == AL_GREEK || fcsinfo[cs2].alphabet == AL_GREEK ) tcs = TC_GREEK; else #endif /* GREEK */ /* Roman sets ... */ #ifdef LATIN2 /* East European */ if (cs1 == FC_2LATIN || cs2 == FC_2LATIN || /* Latin-2 */ cs1 == FC_CP852 || cs2 == FC_CP852 || /* CP852 */ cs1 == FC_CP1250 || cs2 == FC_CP1250 || /* Windows Latin-2 */ cs1 == FC_MAZOVIA || cs2 == FC_MAZOVIA) /* Polish Mazovia */ tcs = TC_2LATIN; else #endif /* LATIN2 */ /* West European Euro-aware */ if (cs1 == FC_CP858 || cs1 == FC_9LATIN || cs2 == FC_CP858 || cs2 == FC_9LATIN) tcs = TC_9LATIN; else /* Traditional West European */ tcs = TC_1LATIN; return(tcs); #endif /* NOCSETS */ } #ifndef NOLOCAL /* D O C O N E C T -- Do the connect command */ /* q = 0 means issue normal informational message about how to get back, etc. q != 0 means to skip the message. */ int #ifdef CK_ANSIC doconect( int q, int async ) #else doconect(q,async) int q, async; #endif /* CK_ANSIC */ { int x; /* Return code */ #ifdef CK_AUTODL extern CHAR ksbuf[]; #endif /* CK_AUTODL */ #ifndef NOKVERBS /* Keyboard macro material */ extern int keymac, keymacx; #endif /* NOKVERBS */ extern int justone, adl_err; int qsave; /* For remembering "quiet" value */ #ifdef OS2 extern int term_io; int term_io_save; #ifdef KUI extern int kui_async; #endif /* KUI */ #endif /* OS2 */ int is_tn = 0; #ifdef IKSD if (inserver) { if (!quiet) printf("?Sorry, IKSD cannot CONNECT.\r\n"); return(success = 0); } #endif /* IKSD */ is_tn = #ifdef TNCODE (local && network && IS_TELNET()) || (!local && sstelnet) #else 0 #endif /* TNCODE */ ; /* Saving, changing, and restoring the global "quiet" variable around calls to conect() to control whether the verbose CONNECT message is printed is obviously less elegant than passing a parameter to conect(), but we do it this way to avoid the need to change all of the ck?con.c modules. NOTE: it is important to restore the value immediately upon return in case there is an autodownload or APC. */ qsave = quiet; /* Save it */ if (!quiet && q > -1) quiet = q; /* Use argument temporarily */ conres(); /* Put console back to normal */ debug(F101,"doconect justone 1","",justone); #ifdef CK_AUTODL ksbuf[0] = NUL; /* Autodownload packet buffer */ #endif /* CK_AUTODL */ #ifdef IKS_OPTION if (is_tn && TELOPT_U(TELOPT_KERMIT) && ttchk() >= 0 #ifdef OS2 && !viewonly #endif /* OS2 */ ) { /* If the remote side is in a state of IKS START-SERVER */ /* we request that the state be changed. We will detect */ /* a failure to adhere to the request when we call ttinc() */ if (!iks_wait(KERMIT_REQ_STOP,0) && !tcp_incoming) { if (!quiet) { printf("\r\nEnter Client/Server Mode... Use:\r\n\r\n"); printf( " REMOTE LOGIN to log in to the server if necessary.\r\n"); printf(" SEND and GET for file transfer.\r\n"); printf(" REMOTE commands for file management.\r\n"); printf(" FINISH to terminate Client/Server mode.\r\n"); printf(" BYE to terminate and close connection.\r\n"); printf(" REMOTE HELP for additional information.\r\n\r\n"); } quiet = qsave; return(0); /* Failure */ } } /* Let our peer know our state. */ #ifdef CK_AUTODL if (is_tn && TELOPT_ME(TELOPT_KERMIT) #ifdef OS2 && !viewonly #endif /* OS2 */ ) { if (autodl && !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) { tn_siks(KERMIT_START); /* Send Kermit-Server Start */ } else if (!autodl && TELOPT_SB(TELOPT_KERMIT).kermit.me_start) { tn_siks(KERMIT_STOP); } } #else /* CK_AUTODL */ if (is_tn && TELOPT_ME(TELOPT_KERMIT) && TELOPT_SB(TELOPT_KERMIT).kermit.me_start) tn_siks(KERMIT_STOP); #endif /* CK_AUTODL */ #endif /* IKS_OPTION */ debug(F101,"doconect flow","",flow); #ifdef OS2 debug(F101,"doconect async","",async); #ifdef KUI if (kui_async) async = 1;; #endif /* KUI */ x = conect(async); /* Connect the first time */ #else /* OS2 */ x = conect(); #endif /* OS2 */ debok = 1; #ifdef IKS_OPTION if (TELOPT_U(TELOPT_KERMIT) && TELOPT_SB(TELOPT_KERMIT).kermit.u_start && !tcp_incoming && !quiet && ttchk() >= 0 ) { printf("\r\nEnter Client/Server Mode... Use:\r\n\r\n"); printf( " REMOTE LOGIN to log in to the server if necessary.\r\n"); printf(" SEND and GET for file transfer.\r\n"); printf(" REMOTE commands for file management.\r\n"); printf(" FINISH to terminate Client/Server mode.\r\n"); printf(" BYE to terminate and close connection.\r\n"); printf(" REMOTE HELP for additional information.\r\n\r\n"); } #endif /* IKS_OPTION */ quiet = qsave; /* Restore "quiet" value */ debug(F101,"doconect justone 2","",justone); #ifdef NETCONN if (network && tn_exit && ttchk() < 0) doexit(GOOD_EXIT,xitsta); /* Exit with good status */ #endif /* NETCONN */ #ifdef OS2ORUNIX /* Exit on disconnect if the port is not open or carrier detect */ if (exitonclose && (ttchk() < 0)) doexit(GOOD_EXIT,xitsta); #endif /* OS2ORUNIX */ #ifdef CKCONINTB4CB /* The order makes a difference in HP-UX 8.00. */ /* The other order makes it think it's in the background when it */ /* returns from CONNECT (Apr 1999). */ setint(); concb((char)escape); /* Restore console for commands */ #else /* This is how it has always been so better leave it */ /* this way for all non-HP-UX-8.00 builds. */ concb((char)escape); /* Restore console for commands */ setint(); #endif /* CKCONINTB4CB */ #ifdef OS2 if (!async) { term_io_save = term_io; /* Disable I/O by emulator */ term_io = 0; #endif /* OS2 */ #ifdef CK_APC /* If an APC command was received during CONNECT mode, we define it now as a macro, execute the macro, and then return to CONNECT mode. We do this in a WHILE loop in case additional APCs come during subsequent CONNECT sessions. */ debug(F101,"doconect apcactive","",apcactive); debug(F101,"doconect success","",success); while (x > 0 && (apcactive == APC_LOCAL || (apcactive == APC_REMOTE && apcstatus != APC_OFF))) { debug(F101,"doconect justone 3","",justone); if (mlook(mactab,"_apc_commands",nmac) == -1) { debug(F110,"doconect about to execute APC",apcbuf,0); domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC); delmac("_apc_commands",1); #ifdef DEBUG } else { debug(F100,"doconect APC in progress","",0); #endif /* DEBUG */ } debug(F101,"doconect apcactive after domac","",apcactive); if (!apcactive) { /* In case CLEAR APC was in APC */ debug(F101,"doconect quit APC loop: apcactive","",apcactive); break; } /* Also don't reconnect if autodownload failed - very confusing! */ /* Let them view the local screen to see what happened. - fdc */ /* This should be conditional. If someone is relying on the */ /* connect mode autodownload for the kermit server to use with */ /* a remotely executed script we should be able to return to */ /* connect mode on the failure. What we really need to do is */ /* report the status of the transfer and then return to CONNECT. */ /* In unix this would simply be a printf(), but in K95 it could */ /* use a popup dialog to report the status. - Jeff */ #ifndef NOXFER debug(F101,"doconect xferstat","",xferstat); if (apcactive == APC_LOCAL && !xferstat && adl_err != 0) { debug(F101,"doconect quit APC loop: xferstat","",xferstat); apcactive = APC_INACTIVE; break; } #endif /* NOXFER */ #ifdef OS2 msleep(250); #endif /* OS2 */ debug(F101,"doconect justone 4","",justone); qsave = quiet; /* Do this again... */ if (!quiet && q > -1) quiet = q; #ifdef CK_AUTODL ksbuf[0] = NUL; #endif /* CK_AUTODL */ #ifdef IKS_OPTION #ifdef CK_AUTODL if (is_tn && TELOPT_ME(TELOPT_KERMIT) && !TELOPT_SB(TELOPT_KERMIT).kermit.me_start && autodl #ifdef CK_APC && !apcactive #endif /* CK_APC */ #ifdef OS2 && !viewonly #endif /* OS2 */ ) { tn_siks(KERMIT_START); /* Send Kermit-Server Start */ } #endif /* CK_AUTODL */ #endif /* IKS_OPTION */ #ifndef OS2 x = conect(); /* Re-CONNECT. */ #else /* OS2 */ x = conect(0); term_io = term_io_save; #endif /* OS2 */ debok = 1; quiet = qsave; debug(F101,"doconect justone 5","",justone); #ifdef NETCONN if (network && ttchk() < 0) { if (tn_exit || exitonclose) doexit(GOOD_EXIT,xitsta); else break; } #endif /* NETCONN */ #ifdef OS2ORUNIX /* If connection dropped */ if (ttchk() < 0) { concb((char)escape); /* Restore console. */ if (exitonclose) doexit(GOOD_EXIT,xitsta); else break; } #endif /* OS2ORUNIX */ } /* Loop back for more. */ #endif /* CK_APC */ #ifndef NOKVERBS if ((keymac > 0) && (keymacx > -1)) { /* Executing a keyboard macro? */ /* Set up the macro and return */ /* Do not clear the keymac flag */ #ifdef OS2 term_io = term_io_save; #endif /* OS2 */ return(dodo(keymacx,NULL,CF_KMAC|cmdstk[cmdlvl].ccflgs)); } #endif /* NOKVERBS */ #ifdef OS2 term_io = term_io_save; } /* if (!async) */ #endif /* OS2 */ #ifdef CKCONINTB4CB /* The order makes a difference in HP-UX 8.00. */ /* The other order makes it think it's in the background when it */ /* returns from CONNECT (Apr 1999). */ setint(); concb((char)escape); /* Restore console for commands */ #else /* This is how it has always been so better leave it */ /* this way for all non-HP-UX-8.00 builds. */ concb((char)escape); /* Restore console for commands */ setint(); #endif /* CKCONINTB4CB */ #ifdef OS2 if (!async) #endif /* OS2 */ what = W_COMMAND; /* Back in command mode. */ return(x); /* Done. */ } #endif /* NOLOCAL */ #ifdef NOICP char * homepath() { return(zhome()); } #else #ifdef COMMENT /* It seemed that this was needed for OS/2, in which \v(cmdfile) and other file-oriented variables or functions can return filenames containing backslashes, which are subsequently interpreted as quotes rather than directory separators (e.g. see commented section for VN_CMDF below). But the problem can't be cured at this level. Example: type \v(cmdfile) Without doubling, the filename is parsed correctly, but then when passed to UNIX 'cat' through the shell, the backslash is removed, and then cat can't open the file. With doubling, the filename is not parsed correctly and the TYPE command fails immediately with a "file not found" error. */ /* Utility routine to double all backslashes in a string. s1 is pointer to source string, s2 is pointer to destination string, n is length of destination string, both NUL-terminated. Returns 0 if OK, -1 if not OK (destination string too short). */ int dblbs(s1,s2,n) char *s1, *s2; int n; { int i = 0; while (*s1) { if (*s1 == '\\') { if (++i > n) return(-1); *s2++ = '\\'; } if (++i > n) return(-1); *s2++ = *s1++; } *s2 = NUL; return(0); } #endif /* COMMENT */ char * gmdmtyp() { /* Get modem type */ #ifndef NODIAL int i, x; debug(F111,"gmdmtyp","mdmtyp",mdmtyp); debug(F111,"gmdmtyp","mdmsav",mdmsav); x = mdmtyp; if (x < 0) /* In case of network dialing */ x = mdmsav; if (x < 1) return("none"); else for (i = 0; i < nmdm; i++) if ((mdmtab[i].kwval == x) && (mdmtab[i].flgs == 0)) return(mdmtab[i].kwd); #endif /* NODIAL */ return("none"); } #ifndef NOXMIT #ifndef NOLOCAL /* T R A N S M I T -- Raw upload */ /* Obey current line, duplex, parity, flow, text/binary settings. */ /* Returns 0 upon apparent success, 1 on obvious failure. */ /*** Things to add: . Make both text and binary mode obey set file bytesize. . Maybe allow user to specify terminators other than CR? . Maybe allow user to specify prompts other than single characters? . Make STATISTICS also work for TRANSMIT. . If TRANSMIT is done without echo, make some kind of (optional) display. . Make the same optimization for binary-mode transmit that was done for text-mode (in the no-echo / no-prompt / no-pause case). ***/ /* T R A N S M I T -- Raw upload */ /* s is the filename, t is the turnaround (prompt) character */ /* Maximum number of characters to buffer. Must be less than LINBUFSIZ */ #ifdef OS2 #define XMBUFS 4096 /* For compatibility with XYZmodem */ #else /* OS2 */ #define XMBUFS 1024 #endif /* OS2 */ #ifdef TNCODE #ifndef IAC #define IAC 255 #endif /* IAC */ #endif /* TNCODE */ #define OUTXBUFSIZ 15 static CHAR inxbuf[OUTXBUFSIZ+1]; /* Host-to-screen expansion buffer */ static int inxcount = 0; /* and count */ static CHAR outxbuf[OUTXBUFSIZ+1]; /* Keyboard-to-host expansion buf */ static int outxcount = 0; /* and count */ /* T R A N S M I T -- Unguarded non-protocol file transmission */ /* Call with: char * s: Name of file to transmit. char t: Turnaround char for text-mode transmission (normally LF). int xlate: nonzero = charset translation for text-mode xfer, 0 = skip. int binary: nonzero = transmit in binary mode, 0 = in text mode. */ #define XBBUFSIZ 508 /* For binary blasting */ static CHAR xbbuf[XBBUFSIZ+4]; int #ifdef CK_ANSIC transmit(char * s, char t, int xlate, int binary, int xxecho) #else transmit(s,t,xlate,binary,xxecho) char *s; char t; int xlate, binary, xxecho; #endif /* CK_ANSIC */ /* transmit */ { #ifdef MAC extern char sstate; int count = 100; #else int count = 0; #ifdef OS2 #ifdef NT SIGTYP (* oldsig)(int); /* For saving old interrupt trap. */ #else /* NT */ SIGTYP (* volatile oldsig)(int); #endif /* NT */ #else /* OS2 */ SIGTYP (* oldsig)(); #endif /* OS2 */ #endif /* MAC */ int eof = 0; /* End of File flag */ int eol = 0; /* End of Line flag */ int rc = 1; /* Return code. 0=fail, 1=succeed. */ int myflow; /* Local copy of global flow... */ int is_tn = 0; /* Do Telnet negotiations */ int xbufsiz = XMBUFS; /* Size of TRANSMIT buffer */ int x, y, c, i; /* Int workers... */ int control = 0; /* Echo loop control */ long nbytes = 0; /* File byte count */ long zz; /* Long worker */ char *p; /* Char * worker */ #ifdef PIPESEND extern int pipesend; #endif /* PIPESEND */ #ifndef NOCSETS int tcs = TC_TRANSP; /* Intermediate (xfer) char set */ int langsv = L_USASCII; /* Save current language */ int unicode = 0; int tcssize = 0; #ifdef CK_ANSIC /* ANSI C prototypes... */ CHAR (*sxo)(CHAR); CHAR (*rxo)(CHAR); CHAR (*sxi)(CHAR); CHAR (*rxi)(CHAR); #else /* Not ANSI C... */ CHAR (*sxo)(); CHAR (*rxo)(); CHAR (*sxi)(); CHAR (*rxi)(); #endif /* CK_ANSIC */ #ifdef UNICODE union ck_short uc; int bomorder = 0; #ifdef CK_ANSIC extern int (*xl_ufc[MAXFCSETS+1])(USHORT); /* Unicode to FCS */ extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */ extern int (*xuf)(USHORT); extern USHORT (*xfu)(CHAR); #else extern int (*xl_ufc[MAXFCSETS+1])(); extern USHORT (*xl_fcu[MAXFCSETS+1])(); extern int (*xuf)(); extern USHORT (*xfu)(); #endif /* CK_ANSIC */ #endif /* UNICODE */ #endif /* NOCSETS */ debug(F101,"xmit t","",t); debug(F101,"xmit xlate","",xlate); debug(F101,"xmit binary","",binary); #ifdef PIPESEND if (pipesend) { if (nopush) return(-2); if (zxcmd(ZIFILE,s) < 1) { printf("?Can't start command: %s\n",s); return(0); } } else #endif /* PIPESEND */ if (zopeni(ZIFILE,s) == 0) { /* Open the file to be transmitted */ printf("?Can't open file %s\n",s); return(0); } x = -1; /* Open the communication channel */ if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) { /* (no harm if already open) */ printf("Can't open device %s\n",ttname); return(0); } zz = x ? speed : -1L; if (binary) { /* Binary file transmission */ myflow = (flow == FLO_XONX) ? FLO_NONE : flow; if (ttvt(zz,myflow) < 0) { /* So no Xon/Xoff! */ printf("Can't condition line\n"); return(0); } } else { if (ttpkt(zz,flow,parity) < 0) { /* Put the line in "packet mode" */ printf("Can't condition line\n"); /* so Xon/Xoff will work, etc. */ return(0); } } is_tn = #ifdef TNCODE (local && network && IS_TELNET()) || (!local && sstelnet) #else 0 #endif /* TNCODE */ ; #ifndef NOCSETS /* Set up character set translations */ tcs = 0; /* "Transfer" or "Other" charset */ sxo = rxo = NULL; /* Initialize byte-to-byte functions */ sxi = rxi = NULL; unicode = 0; /* Assume Unicode won't be involved */ if (!binary && xlate) { /* Set up charset translations */ /* In the SENDING direction, we are converting from the local file's character-set (fcharset) to the remote terminal charset (tcsr). In the RECEIVING direction (echoing) we are converting from the remote end of the terminal charset (tcsr) to its local end (tcsl), which is not necessarily the same as the file character-set. Especially when the file character set is UCS-2, which is not a valid terminal character set. The various combinations are represented in this table: FCS = File Character Set RCS = Remote Terminal Character Set CCS = Console (Local Terminal) Character Set 8 4 2 1 FCS FCS RCS CCS UCS UTF UTF UTF 0 0 0 0 = 0 = No translation 0 0 0 1 = 1 = FCS -> RCS, Echo RCS -> UTF 0 0 1 0 = 2 = FCS -> UTF, Echo UTF -> CCS 0 0 1 1 = 3 = FCS -> UTF, Echo no translation 0 1 0 0 = 4 = UTF -> RCS, Echo RCS -> CCS 0 1 0 1 = 5 = UTF -> RCS, Echo RCS -> UTF 0 1 1 0 = 6 = UTF -> UTF, Echo UTF -> CCS 0 1 1 1 = 7 = No translation 1 0 0 0 = 8 = UCS -> RCS, Echo RCS -> CCS 1 0 0 1 = 9 = UCS -> RCS, Echo RCS -> UTF 1 0 1 0 = 10 = UCS -> UTF, Echo UTF -> CCS 1 0 1 1 = 11 = UCS -> UTF, Echo no translation */ #ifdef UNICODE xfu = NULL; /* Unicode translation functions */ xuf = NULL; bomorder = ucsorder; /* UCS-2 byte order */ if (fcharset == FC_UCS2) /* File charset is UCS-2 */ unicode |= 8; else if (fcharset == FC_UTF8) /* File charset is UTF-8 */ unicode |= 4; if (tcsr == FC_UTF8) /* Remote term charset is UTF-8 */ unicode |= 2; if (tcsl == FC_UTF8) /* Local term charset is UTF-8 */ unicode |= 1; #endif /* UNICODE */ /* When Unicode not involved -- TCS is the intermediate (xfer) set, and: sxo = File-to-Intermediate charset function rxo = Intermediate-to-Remote-Terminal charset function sxi = Remote-Terminal-to-Intermediate rxi = Intermediate-to-Local-Terminal */ tcs = gettcs(tcsr,fcharset); /* Get intermediate set. */ sxo = xls[tcs][fcharset]; /* translation function */ rxo = xlr[tcs][tcsr]; /* pointers for output functions */ sxi = xls[tcs][tcsr]; /* and for input functions. */ rxi = xlr[tcs][tcsl]; /* At this point we have unicode nonzero if Unicode is involved in the conversion, and to 0 if it is not. The following is to prevent use of zmstuff() and zdstuff() by translation functions (stuffing works with file i/o, not with communication i/o). */ langsv = language; /* Save current SET LANGUAGE */ language = L_USASCII; /* No language-specific translations */ } #endif /* NOCSETS */ i = 0; /* Beginning of buffer. */ #ifndef MAC #ifndef AMIGA oldsig = signal(SIGINT, trtrap); /* Save current interrupt trap. */ #endif /* AMIGA */ #endif /* MAC */ tr_int = 0; /* Have not been interrupted (yet). */ rc = 1; /* Return code presumed good. */ #ifdef VMS conres(); #endif /* VMS */ #ifndef NOCSETS debug(F101,"XMIT unicode","",unicode); #ifdef UNICODE debug(F101,"XMIT bomorder","",bomorder); #endif /* UNICODE */ #endif /* NOCSETS */ c = 0; /* Initial condition */ while (c > -1 && !eof) { /* Loop for all characters in file */ eol = 0; #ifdef MAC /* * It is expensive to run the miniparser so don't do it for * every character. */ if (--count < 0) { count = 100; miniparser(1); if (sstate == 'a') { sstate = '\0'; goto xmitfail; } } #else /* Not MAC */ if (tr_int) { /* Interrupted? */ printf("^C...\n"); /* Print message */ goto xmitfail; } #endif /* MAC */ c = zminchar(); /* Get a file character */ #ifdef COMMENT /* too much */ #ifdef DEBUG if (deblog) { if (c < 0) debug(F101,"XMIT zminchar","",c); else debug(F000,"XMIT zminchar","",c); } #endif /* DEBUG */ #endif /* COMMENT */ if (c < -1) { /* Other error */ printf("?TRANSMIT file read error: %s\n",ck_errstr()); goto xmitfail; } else if (c > -1) { nbytes++; c &= fmask; /* Apply SET FILE BYTESIZE mask */ } else if (c == -1) { eof = 1; debug(F101,"XMIT eof","",eof); } if (binary) { /* Binary... */ if (c == -1) { /* If EOF */ rc = 1; /* Success */ eof = 1; goto xmitexit; /* Done */ } if (!xmitw && !xxecho) { /* Special "blast" mode */ if (count == XBBUFSIZ) { /* File input buffer full... */ while (count > 0) { errno = 0; y = ttol(xbbuf,count); if (y < 0) { /* try to send it. */ printf("?TRANSMIT output error: %s\n", ck_errstr()); debug(F111,"XMIT binary ttol error", ck_errstr(),errno); rc = 0; break; } if (y < 0) break; count -= y; } count = 0; } xbbuf[count++] = c; #ifdef TNCODE if (c == IAC && is_tn) /* Telnet IAC */ xbbuf[count++] = IAC; /* must be doubled */ #endif /* TNCODE */ continue; } if (ttoc(dopar((char) c)) < 0) { /* else just send the char */ printf("?Can't transmit character\n"); goto xmitfail; } #ifdef TNCODE if (c == IAC && is_tn) /* Quote Telnet IAC */ ttoc((char)IAC); #endif /* TNCODE */ if (xmitw) /* Pause if requested */ msleep(xmitw); if (xxecho) { /* SET TRANSMIT ECHO ON? */ if (duplex) { /* Yes, for half duplex */ #ifndef NOLOCAL #ifdef OS2 /* Echo to emulator */ scriptwrtbuf((USHORT)(c & cmdmsk)); #endif /* OS2 */ #endif /* NOLOCAL */ if (conoc((char)(c & cmdmsk)) < 0) /* echo locally. */ goto xmitfail; } else { /* For full duplex, */ int i, n; /* display whatever is there. */ n = ttchk(); /* See how many chars are waiting */ if (n < 0) { /* Connection dropped? */ printf("?Connection lost\n"); goto xmitfail; } for (i = 0; i < n; i++) { /* Read and echo that many. */ x = ttinc(xmitt); /* Timed read just in case. */ if (x > -1) { /* If no timeout */ if (parity) x &= 0x7f; /* display the char, */ #ifndef NOLOCAL #ifdef OS2 /* Echo to emulator */ scriptwrtbuf((USHORT)x); #endif /* OS2 */ #endif /* NOLOCAL */ if (conoc((char)(x & cmdmsk)) < 0) { printf("?Output error\n"); goto xmitfail; } } else if (x == -2) { printf("Connection closed.\n"); ttclos(1); goto xmitfail; } else if (x == -3) { printf( "Session Limit exceeded - closing connection.\n" ); ttclos(1); goto xmitfail; } else { printf("?Communications error\n"); goto xmitfail; } } } } else ttflui(); /* Not echoing, just flush input. */ } else { /* Text mode, line at a time. */ #ifdef UNICODE if (fcharset == FC_UCS2 && xlate) { /* Special for UCS-2 */ char xbuf[8]; x = 1 - (nbytes & 1); /* Odd or even byte */ if (x == 0) /* Note: 1 = the 1st, 0 = 2nd, etc */ uc.x_short = 0; if (bomorder) /* Little Endian */ x = 1 - x; /* Save byte in appropriate half */ debug(F101,"XMIT UCS2 x","",x); uc.x_char[x] = (CHAR) (c & 0xff); if (nbytes & 1) /* First byte, go back for next */ continue; if (nbytes == 2) { /* UCS-2 Byte Order Mark */ if (uc.x_short == (USHORT) 0xfeff) { debug(F100,"XMIT UCS2 BOM FEFF","",bomorder); continue; } else if (uc.x_short == (USHORT) 0xfffe) { bomorder = 1 - bomorder; debug(F100,"XMIT UCS2 BOM FFFE (swap)","",bomorder); continue; } } sprintf(xbuf,"%04X",uc.x_short); /* SAFE */ debug(F111,"XMIT UCS2",xbuf,uc.x_short); if (nbytes & 1) /* Special eol test for UCS-2 */ if (uc.x_short == '\n') eol = 1; #ifdef COMMENT if (uc.x_short == 0x2028 || uc.x_short == 0x2029) eol = 1; #endif /* COMMENT */ } else #endif /* UNICODE */ if (c == '\n') { /* Normal eol test otherwise */ eol = 1; } if (eol) { /* End of line? */ int stuff = -1; debug(F101,"XMIT eol length","",i); if (i == 0) { /* Blank line? */ if (xmitf) /* Yes, insert fill if asked. */ line[i++] = dopar((char) xmitf); } if (i == 0 || ((char) line[i-1]) != ((char) dopar(CK_CR))) line[i++] = dopar(CK_CR); /* Terminate it with CR */ if (xmitl) { stuff = LF; #ifdef TNCODE } else if (is_tn && (tn_nlm != TNL_CR)) { /* TELNET NEWLINE ON/OFF/RAW */ stuff = (tn_nlm == TNL_CRLF) ? LF : NUL; #endif /* TNCODE */ } if (stuff > -1) line[i++] = dopar((char)stuff); line[i] = NUL; debug(F111,"XMIT eol line",line,i); } else if (c != -1) { /* Not a newline, regular character */ int k, x; outxbuf[0] = c; /* In case of no translation */ outxcount = 1; /* Assume result is one byte */ #ifndef NOCSETS switch (unicode) { case 0: /* No Unicode involved */ case 1: if (xlate) { /* If not /TRANSPARENT */ /* Local-to-intermediate */ if (sxo) c = (*sxo)((char)c); /* Intermediate-to-remote */ if (rxo) c = (*rxo)((char)c); outxbuf[0] = c; } break; #ifdef UNICODE case 2: /* Local byte to UTF-8 */ case 3: xfu = xl_fcu[fcharset]; tcssize = fcsinfo[fcharset].size; outxcount = b_to_u((CHAR)c,outxbuf,OUTXBUFSIZ,tcssize); break; case 4: /* Local UTF-8 to remote byte */ case 5: xuf = xl_ufc[tcsr]; x = u_to_b((CHAR)c); /* Convert to byte */ if (x == -1) { /* If more input bytes needed */ continue; /* go back and get them */ } else if (x == -2) { /* LS or PS (shouldn't happen) */ outxbuf[0] = CK_CR; } else if (x == -9) { /* UTF-8 error */ outxbuf[0] = '?'; /* Insert error char */ outxbuf[1] = u_to_b2(); /* Insert next char */ outxcount = 2; } else { outxbuf[0] = /* Otherwise store result */ (unsigned)(x & 0xff); } break; case 6: /* UTF-8 to UTF-8 */ case 7: break; case 8: /* UCS-2 to byte */ case 9: xuf = xl_ufc[tcsr]; outxbuf[0] = (*xuf)(uc.x_short); break; case 10: case 11: { /* UCS-2 to UTF-8 */ int j; CHAR * buf = NULL; x = ucs2_to_utf8(uc.x_short,&buf); if (x < 0) { outxbuf[0] = 0xff; /* (= U+FFFD) */ outxbuf[1] = 0xbd; x = 2; } for (j = 0; j < x; j++) outxbuf[j] = buf[j]; outxcount = x; break; } #endif /* UNICODE */ } #endif /* NOCSETS */ outxbuf[outxcount] = NUL; debug(F111,"XMIT outxbuf",outxbuf,outxcount); /* Now the input character (1 or more bytes) is translated into the output expansion buffer (1 or more bytes); outxcount = number of bytes to add to the TRANSMIT line buffer, which we do here, taking care of parity, SI/SO processing, and quoting Telnet IACs. */ for (k = 0; k < outxcount; k++) { c = outxbuf[k]; if (xmits && parity && (c & 0200)) { /* If shifting */ line[i++] = dopar(SO); /* needs to be done, */ line[i++] = dopar((char)c); /* do it here, */ line[i++] = dopar(SI); /* crudely. */ } else { line[i++] = dopar((char)c); #ifdef TNCODE if (c == (CHAR)IAC && is_tn) line[i++] = (CHAR)IAC; #endif /* TNCODE */ } } } /* Send characters if buffer full, or at end of line, or at end of file. (End of line only if echoing, waiting for a prompt, or pausing.) */ debug(F000,"XMIT c",ckitoa(i),c); if (i >= xbufsiz || eof || (eol && (xxecho || xmitw || t))) { p = line; line[i] = '\0'; debug(F111,"transmit buf",p,i); if (ttol((CHAR *)p,i) < 0) { /* try to send it. */ printf("?TRANSMIT output error: %s\n",ck_errstr()); rc = 0; break; } i = 0; /* Reset buffer pointer. */ /* Now we handle the echo. If the user wants to see it, or if we have to wait for the turnaround character, t. If the echo is being displayed, and terminal character-set translation is required, we do it here. */ if (duplex && xxecho) { /* If local echo, echo it */ if (parity || cmdmsk == 0x7f) { /* Strip hi bits */ char *ss = line; /* if necessary */ while (*ss) { *ss &= 0x7f; ss++; } } #ifndef NOLOCAL #ifdef OS2 { /* Echo to emulator */ char *ss = p; while (*ss) { scriptwrtbuf((USHORT)*ss); ss++; } } #endif /* OS2 */ #endif /* NOLOCAL */ if (conoll(p) < 0) goto xmitfail; } if (xmitw) /* Sleep TRANSMIT PAUSE interval */ msleep(xmitw); control = 0; /* Readback loop control */ if (t != 0 && eol) /* TRANSMIT PROMPT given and at EOL */ control |= 1; if (xxecho && !duplex) /* Echo desired and is remote */ control |= 2; if (control) { /* Do this if reading back the echo */ int n; x = 0; while (1) { if (control & 1) { /* Termination criterion */ if (x == t) /* for turnaround */ break; } else if (control & 2) { /* And for echoing */ if ((n = ttchk()) < 1) break; } if ((x = ttinc(xmitt)) < 0) { /* Read with timeout */ switch (x) { case -2: printf("Connection closed.\n"); ttclos(1); goto xmitfail; case -3: printf( "Session Limit exceeded - closing connection.\n" ); ttclos(1); /* full thru... */ goto xmitfail; default: printf("?Timeout\n"); goto xmitfail; } } if (x > -1 && (control & 2)) { /* Echo any echoes */ if (parity) x &= 0x7f; c = x; #ifndef NOLOCAL #ifdef OS2 scriptwrtbuf((USHORT)x); #endif /* OS2 */ #endif /* NOLOCAL */ inxbuf[0] = c; inxcount = 1; #ifndef NOCSETS switch (unicode & 3) { /* Remote bits */ case 0: if (xlate) { if (sxi) c = (*sxi)((CHAR)c); if (rxi) c = (*rxi)((CHAR)c); inxbuf[0] = c; } break; #ifdef UNICODE case 1: /* Remote Byte to local UTF-8 */ xfu = xl_fcu[tcsr]; tcssize = fcsinfo[tcsr].size; inxcount = b_to_u((CHAR)c, inxbuf, OUTXBUFSIZ, tcssize ); break; case 2: /* Remote UTF-8 to local Byte */ xuf = xl_ufc[tcsl]; x = u_to_b((CHAR)c); if (x < 0) continue; inxbuf[0] = (unsigned)(x & 0xff); break; case 3: /* UTF-8 to UTF-8 */ break; #endif /* UNICODE */ } #endif /* NOCSETS */ inxbuf[inxcount] = NUL; if (conxo(inxcount,(char *)inxbuf) < 0) goto xmitfail; } } } else /* Not echoing */ ttflui(); /* Just flush input buffer */ } /* End of buffer-dumping block */ } /* End of text mode */ if (eof) { rc = 1; goto xmitexit; } } /* End of character-reading loop */ xmitfail: /* Failure exit point */ rc = 0; xmitexit: /* General exit point */ if (rc > 0) { if (binary && !xmitw && !xxecho) { /* "blasting"? */ while (count > 0) { /* Partial buffer still to go? */ errno = 0; y = ttol(xbbuf,count); if (y < 0) { printf("?TRANSMIT output error: %s\n", ck_errstr()); debug(F111,"XMIT binary eof ttol error", ck_errstr(),errno); rc = 0; break; } count -= y; } } else if (!binary && *xmitbuf) { /* Anything to send at EOF? */ p = xmitbuf; /* Yes, point to string. */ while (*p) /* Send it. */ ttoc(dopar(*p++)); /* Don't worry about echo here. */ } } #ifndef AMIGA #ifndef MAC signal(SIGINT,oldsig); /* Put old signal action back. */ #endif /* MAC */ #endif /* AMIGA */ #ifdef VMS concb(escape); /* Put terminal back, */ #endif /* VMS */ zclose(ZIFILE); /* Close file, */ #ifndef NOCSETS language = langsv; /* restore language, */ #endif /* NOCSETS */ ttres(); /* and terminal modes, */ return(rc); /* and return successfully. */ } #endif /* NOLOCAL */ #endif /* NOXMIT */ #ifndef NOCSETS _PROTOTYP( CHAR (*sxx), (CHAR) ); /* Local translation function */ _PROTOTYP( CHAR (*rxx), (CHAR) ); /* Local translation function */ _PROTOTYP( CHAR zl1as, (CHAR) ); /* Latin-1 to ascii */ _PROTOTYP( CHAR xl1as, (CHAR) ); /* ditto */ /* X L A T E -- Translate a local file from one character set to another */ /* Translates input file (fin) from character set csin to character set csout and puts the result in the output file (fout). The two character sets are file character sets from fcstab. */ int #ifdef CK_ANSIC xlate( char *fin, char *fout, int csin, int csout ) #else xlate(fin, fout, csin, csout) char *fin, *fout; int csin, csout; #endif /* CK_ANSIC */ { #ifndef MAC #ifdef OS2 extern int k95stdout; extern int wherex[], wherey[]; extern unsigned char colorcmd; #ifdef NT SIGTYP (* oldsig)(int); /* For saving old interrupt trap. */ #else /* NT */ SIGTYP (* volatile oldsig)(int); /* For saving old interrupt trap. */ #endif /* NT */ #else /* OS2 */ SIGTYP (* oldsig)(); #endif /* OS2 */ #endif /* MAC */ #ifdef CK_ANSIC int (*fn)(char); /* Output function pointer */ #else int (*fn)(); #endif /* CK_ANSIC */ extern int xlatype; int filecode; /* Code for output file */ int scrnflg = 0; int z = 1; /* Return code. */ int x, c; /* Workers */ #ifndef UNICODE int tcs; #else #ifdef COMMENT int c2; #endif /* COMMENT */ #endif /* UNICODE */ ffc = 0L; if (zopeni(ZIFILE,fin) == 0) { /* Open the file to be translated */ #ifdef COMMENT /* An error message was already printed by zopeni() */ printf("?Can't open input file %s\n",fin); #endif /* COMMENT */ return(0); } #ifdef MAC /* If user specified no output file, it goes to the screen. For the Mac, this must be done a special way (result goes to a new window); the Mac doesn't have a "controlling terminal" device name. */ filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZOFILE; #else #ifdef VMS filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZMFILE; #else #ifdef OS2 filecode = (!stricmp(fout,"con") || !stricmp(fout,"con:")) ? ZCTERM : ZMFILE; if ((filecode == ZCTERM) && !k95stdout && !inserver) csout = FC_UCS2; #else /* OS2 */ filecode = ZOFILE; #endif /* OS2 */ #endif /* VMS */ #endif /* MAC */ if (zopeno(filecode,fout,NULL,NULL) == 0) { /* And the output file */ printf("?Can't open output file %s\n",fout); return(0); } #ifndef AMIGA #ifndef MAC oldsig = signal(SIGINT, trtrap); /* Save current interrupt trap. */ #endif /* MAC */ #endif /* AMIGA */ scrnflg = (filecode == ZCTERM); /* Set output function */ if (scrnflg) fn = NULL; else if (filecode == ZMFILE) fn = putmfil; else fn = putfil; tr_int = 0; /* Have not been interrupted (yet). */ z = 1; /* Return code presumed good. */ if (!scrnflg && !quiet) printf(" %s (%s) => %s (%s)\n", /* Say what we're doing. */ fin, fcsinfo[csin].keyword, fout,fcsinfo[csout].keyword ); #ifndef UNICODE /* Non-Unicode picks the "most appropriate" transfer character set as the intermediate set, which results in loss of any characters that the source and target sets have in common, but are lacking from the intermediate set. */ #ifdef KANJI /* Special handling for Japanese... */ if (fcsinfo[csin].alphabet == AL_JAPAN || fcsinfo[csout].alphabet == AL_JAPAN) { USHORT eu; int c, x, y; xpnbyte(-1,0,0,NULL); /* Reset output machine */ xlatype = XLA_JAPAN; while ((c = xgnbyte(FC_JEUC,csin,NULL)) > -1) { /* Get an EUC byte */ if (tr_int) { /* Interrupted? */ printf("^C...\n"); /* Print message */ z = 0; break; } /* Send EUC byte to output machine */ if ((x = xpnbyte(c,TC_JEUC,csout,fn)) < 0) { z = -1; break; } } goto xxlate; } #endif /* KANJI */ /* Regular bytewise conversion... */ tcs = gettcs(csin,csout); /* Get intermediate set. */ if (csin == csout) { /* Input and output sets the same? */ sxx = rxx = NULL; /* If so, no translation. */ } else { /* Otherwise, set up */ if (tcs < 0 || tcs > MAXTCSETS || csin < 0 || csin > MAXFCSETS || csout < 0 || csout > MAXFCSETS) { debug(F100,"XLATE csets out of range","",0); sxx = rxx = NULL; } else { sxx = xls[tcs][csin]; /* translation function */ rxx = xlr[tcs][csout]; /* pointers. */ if (rxx == zl1as) rxx = xl1as; } } while ((c = zminchar()) != -1) { /* Loop for all characters in file */ if (tr_int) { /* Interrupted? */ printf("^C...\n"); /* Print message */ z = 0; break; } if (sxx) c = (*sxx)((CHAR)c); /* From fcs1 to tcs */ if (rxx) c = (*rxx)((CHAR)c); /* from tcs to fcs2 */ if (zchout(filecode,(char)c) < 0) { /* Output xlated character */ z = -1; break; } } goto xxlate; /* Done. */ #else /* UNICODE */ /* Use Unicode as the intermediate character set. It's simple and gives little or no loss, but the overhead is a bit higher. */ initxlate(csin,csout); /* Set up translation functions */ if (xlatype == XLA_NONE) { while ((c = zminchar()) != -1) { /* Loop for all characters in file */ if (tr_int) { /* Interrupted? */ printf("^C...\n"); /* Print message */ z = 0; break; } if (zchout(filecode,(char)c) < 0) { /* Output xlated character */ z = -1; break; } } goto xxlate; /* Done. */ } #ifndef NOLOCAL #ifdef OS2 if (csout == FC_UCS2 && /* we're translating to UCS-2 */ filecode == ZCTERM && /* for the real screen... */ !k95stdout && !inserver ) { union { USHORT ucs2; UCHAR bytes[2]; } output; while (1) { /* In this case we go two-by-two. */ if ((c = xgnbyte(FC_UCS2,csin,NULL)) < 0) break; output.bytes[0] = c; if ((c = xgnbyte(FC_UCS2,csin,NULL)) < 0) break; output.bytes[1] = c; if (tr_int) { /* Interrupted? */ printf("^C...\n"); /* Print message */ z = 0; break; } VscrnWrtUCS2StrAtt(VCMD, &output.ucs2, 1, wherey[VCMD], wherex[VCMD], &colorcmd ); } } else #endif /* OS2 */ #endif /* NOLOCAL */ /* General case: Get next byte translated from fcs to UCS-2 */ #ifdef COMMENT while ((c = xgnbyte(FC_UCS2,csin,NULL)) > -1 && (c2 = xgnbyte(FC_UCS2,csin,NULL)) > -1) { extern int fileorder; if (tr_int) { /* Interrupted? */ printf("^C...\n"); /* Print message */ z = 0; break; } debug(F001,"XLATE c","",c); debug(F001,"XLATE c2","",c2); /* And then send UCS-2 byte to translate-and-output machine */ if ((x = xpnbyte(fileorder?c2:c,TC_UCS2,csout,fn)) < 0) { z = -1; break; } if ((x = xpnbyte(fileorder?c:c2,TC_UCS2,csout,fn)) < 0) { z = -1; break; } } #else while ((c = xgnbyte(FC_UCS2,csin,NULL)) > -1) { if (tr_int) { /* Interrupted? */ printf("^C...\n"); /* Print message */ z = 0; break; } if ((x = xpnbyte(c,TC_UCS2,csout,fn)) < 0) { z = -1; break; } } #endif /* COMMENT */ #endif /* UNICODE */ xxlate: /* Common exit point */ #ifndef AMIGA #ifndef MAC signal(SIGINT,oldsig); /* Put old signal action back. */ #endif /* MAC */ #endif /* AMIGA */ tr_int = 0; if (z < 0) { if (z == -1) printf("?File output error: %s\n",ck_errstr()); z = 0; } zclose(ZIFILE); /* Close files */ zclose(filecode); /* ... */ return(success = z); /* and return status. */ } int doxlate() { #ifdef OS2ONLY extern int tt_font; #endif /* OS2ONLY */ #ifdef UNIX extern char ** mtchs; /* zxpand() file list */ #endif /* UNIX */ int x, y, incs, outcs, multiple = 0, wild = 0, fc = 0, len = 0; int ofisdir = 0; char * s, * tocs = ""; if ((x = cmifi("File(s) to translate","",&s,&wild,xxstring)) < 0) { if (x == -3) { printf("?Name of an existing file\n"); return(-9); } else return(x); } ckstrncpy(line,s,LINBUFSIZ); /* Save copy of string just parsed. */ if ((incs = cmkey(fcstab,nfilc,"from character-set","",xxstring)) < 0) return(incs); #ifdef OS2 if (ck_isunicode()) tocs = "ucs2"; else #endif /* OS2 */ tocs = getdcset(); if ((outcs = cmkey(fcstab,nfilc,"to character-set",tocs,xxstring)) < 0) return(outcs); if ((x = cmofi("output file",CTTNAM,&s,xxstring)) < 0) return(x); if (x > 1) ofisdir = 1; len = ckstrncpy(tmpbuf,s,TMPBUFSIZ); if ((y = cmcfm()) < 0) return(y); /* Confirm the command */ if (len < 1) return(-2); if (ofisdir) multiple = 2; else if (wild) { if (isdir(tmpbuf)) multiple = 2; else if (!strcmp(tmpbuf,CTTNAM)) multiple = 1; #ifdef OS2 else if (!stricmp(tmpbuf,"con") || !stricmp(tmpbuf,"con:")) multiple = 1; #else #ifdef UNIXOROSK else if (!strncmp(tmpbuf,"/dev/",4)) multiple = 1; #endif /* UNIXOROSK */ #endif /* OS2 */ if (!multiple) { printf("?A single file please\n"); return(-9); } } if (!multiple) { /* Just one file */ return(success = xlate(line,tmpbuf,incs,outcs)); } else { /* Translate multiple files */ char dirbuf[CKMAXPATH+4]; int k; #ifndef ZXREWIND int flags = ZX_FILONLY; #endif /* ZXREWIND */ if (multiple == 2) { /* Target is a directory */ k = ckstrncpy(dirbuf,tmpbuf,CKMAXPATH+1) - 1; if (k < 0) return(-2); #ifdef OS2ORUNIX if (dirbuf[k] != '/') { dirbuf[k+1] = '/'; dirbuf[k+2] = NUL; } #else #ifdef OSK if (dirbuf[k] != '/') { dirbuf[k+1] = '/'; dirbuf[k+2] = NUL; } #else #ifdef VMS if (ckmatch("*.DIR;1",s,0,0)) k = cvtdir(tmpbuf,dirbuf,TMPBUFSIZ); if (dirbuf[k] != ']' && dirbuf[k] != '>' && dirbuf[k] != ':') return(-2); #else #ifdef datageneral if (dirbuf[k] != ':') { dirbuf[k+1] = ':'; dirbuf[k+2] = NUL; } #else #ifdef STRATUS if (dirbuf[k] != '>') { dirbuf[k+1] = '>'; dirbuf[k+2] = NUL; } #endif /* STRATUS */ #endif /* datageneral */ #endif /* VMS */ #endif /* OSK */ #endif /* OS2ORUNIX */ } #ifdef ZXREWIND fc = zxrewind(); /* Rewind the file list */ #else if (matchdot) flags |= ZX_MATCHDOT; fc = nzxpand(line,flags); #endif /* ZXREWIND */ if (fc < 1) { printf("?Wildcard expansion error\n"); return(-9); } #ifdef UNIX sh_sort(mtchs,NULL,fc,0,0,filecase); /* Sort the file list */ #endif /* UNIX */ while (1) { /* Loop through the files */ znext(line); if (!line[0]) break; if (multiple == 2) ckmakmsg(tmpbuf,TMPBUFSIZ,dirbuf,line,NULL,NULL); if (xlate(line,tmpbuf,incs,outcs) < 1) return(success = 0); } } return(success = 1); } #endif /* NOCSETS */ /* Returns path of user's actual home directory (or, if specified, SET CD HOME directory), properly terminated to allow filenames or sub-paths to be appended. */ static char hompthbuf[CKMAXPATH+1] = { NUL, NUL }; /* Home directory path */ char * homepath() { #ifdef UNIXOROSK int x; #endif /* UNIXOROSK */ extern char hompthbuf[]; extern char * myhome; char * h; /* myhome = SET CD HOME; zhome() uses API to get home directory */ h = myhome ? myhome : zhome(); hompthbuf[0] = NUL; /* Ensure it is terminated with appropriate directory or device separator. */ #ifdef UNIXOROSK x = ckstrncpy(hompthbuf,h,CKMAXPATH+1); if (x <= 0) { hompthbuf[0] = '/'; hompthbuf[1] = NUL; } else if (x < CKMAXPATH - 2 && hompthbuf[x-1] != '/') { hompthbuf[x] = '/'; hompthbuf[x+1] = NUL; } return(hompthbuf); #else #ifdef STRATUS if (strlen(h) < CKMAXPATH) sprintf(hompthbuf,"%s>",h); /* SAFE */ return(hompthbuf); #else return(h); #endif /* STRATUS */ #endif /* UNIXOROSK */ } /* D O L O G -- Do the log command */ int #ifdef CK_ANSIC dolog( int x ) #else dolog(x) int x; #endif /* CK_ANSIC */ { int y, disp; char *s = NULL, * p = NULL, * q = NULL; extern int isguest; #ifdef ZFNQFP struct zfnfp * fnp; #endif /* ZFNQFP */ if (isguest) { printf("?Anonymous log creation not allowed\n"); return(-9); } switch (x) { /* Which log... */ #ifdef DEBUG case LOGD: q = "debug.log"; y = cmofi("Name of debugging log file",q,&s,xxstring); break; #endif /* DEBUG */ case LOGP: q = "packet.log"; y = cmofi("Name of packet log file",q,&s,xxstring); break; #ifndef NOLOCAL case LOGS: q = "session.log"; y = cmofi("Name of session log file",q,&s,xxstring); break; #endif /* NOLOCAL */ #ifdef TLOG case LOGT: q = "transact.log"; y = cmofi("Name of transaction log file",q,&s,xxstring); break; #endif /* TLOG */ #ifdef CKLOGDIAL case LOGM: { int m, n; char mypath[CKMAXPATH+1]; q = CXLOGFILE; m = ckstrncpy(mypath,homepath(),CKMAXPATH); n = strlen(CXLOGFILE); if (m + n < CKMAXPATH) ckstrncat(mypath,CXLOGFILE,CKMAXPATH); else ckstrncpy(mypath,CXLOGFILE,CKMAXPATH); y = cmofi("Name of connection log file",mypath,&s,xxstring); break; } #endif /* CKLOGDIAL */ default: printf("\n?Unknown log designator - %d\n",x); return(-2); } if (y < 0) return(y); if (y == 2) { /* If they gave a directory name */ int k; char * ds = "/"; k = strlen(s); if (k > 0 && s[k-1] == '/') ds = ""; ckmakmsg(tmpbuf,TMPBUFSIZ,s,ds,q,NULL); s = tmpbuf; } #ifdef ZFNQFP #ifdef OS2ORUNIX if (*s != '|') /* Allow for pipes */ #else #ifdef OSK if (*s != '|') #endif /* OSK */ #endif /* OS2ORUNIX */ if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) { if (fnp->fpath) if ((int) strlen(fnp->fpath) > 0) s = fnp->fpath; } /* else if error keep original string */ #endif /* ZFNQFP */ ckstrncpy(line,s,LINBUFSIZ); s = line; #ifdef MAC y = 0; #else p = "new"; #ifdef TLOG if ((x == LOGT && tlogfmt == 2) || x == LOGM) p = "append"; #endif /* TLOG */ if ((y = cmkey(disptb,2,"Disposition",p,xxstring)) < 0) return(y); #endif /* MAC */ disp = y; if ((y = cmcfm()) < 0) return(y); switch (x) { #ifdef DEBUG case LOGD: return(deblog = debopn(s,disp)); #endif /* DEBUG */ #ifndef NOXFER case LOGP: return(pktlog = pktopn(s,disp)); #endif /* NOXFER */ #ifndef NOLOCAL case LOGS: setseslog(sesopn(s,disp)); return(seslog); #endif /* NOLOCAL */ #ifdef TLOG case LOGT: return(tralog = traopn(s,disp)); #endif /* TLOG */ #ifdef CKLOGDIAL case LOGM: return(dialog = diaopn(s,disp,0)); #endif /* CKLOGDIAL */ default: return(-2); } } #ifndef NOXFER int #ifdef CK_ANSIC pktopn( char *s, int disp ) #else pktopn(s,disp) char *s; int disp; #endif /* CK_ANSIC */ { static struct filinfo xx; if (!s) s = ""; if (!*s) return(0); debug(F111,"pktopn",s,disp); zclose(ZPFILE); #ifdef OS2ORUNIX if (s[0] == '|') { /* Pipe */ char * p = s + 1; debug(F110,"pktopn p",p,0); while (*p) { if (*p != ' ') break; else p++; } debug(F110,"pktopn pipe",p,0); pktlog = zxcmd(ZPFILE,p); debug(F101,"pktopn seslog","",seslog); } else { /* File */ #endif /* OS2ORUNIX */ if (disp) { xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0; xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = ""; xx.lblopts = 0; pktlog = zopeno(ZPFILE,s,NULL,&xx); } else pktlog = zopeno(ZPFILE,s,NULL,NULL); if (!pktlog && !quiet) printf("?%s - %s\n",s,ck_errstr()); #ifdef OS2ORUNIX } #endif /* OS2ORUNIX */ if (pktlog > 0) ckstrncpy(pktfil,s,CKMAXPATH+1); else *pktfil = '\0'; return(pktlog); } #endif /* NOXFER */ int #ifdef CK_ANSIC traopn( char *s, int disp ) #else traopn(s,disp) char *s; int disp; #endif /* CK_ANSIC */ { #ifdef TLOG static struct filinfo xx; if (!s) s = ""; if (!*s) return(0); debug(F111,"traopn",s,disp); debug(F101,"traopn tlogfmt","",tlogfmt); zclose(ZTFILE); #ifdef OS2ORUNIX if (tlogfmt == 2) { /* FTP format is special... */ VOID doiklog(); if (!disp) /* Append? */ if (zchki(s) > -1) /* No - does file exist? */ (VOID) zdelet(s); /* Yes - delete it. */ xferlog = 1; ckstrncpy(trafil,s,CKMAXPATH); makestr(&xferfile,s); doiklog(); return(1); } if (s[0] == '|') { /* Pipe */ char * p = s + 1; debug(F110,"traopn p",p,0); while (*p) { if (*p != ' ') break; else p++; } debug(F110,"traopn pipe",p,0); tralog = zxcmd(ZTFILE,p); debug(F101,"traopn tralog","",tralog); } #endif /* OS2ORUNIX */ if (s[0] != '|') { /* File */ if (disp) { xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0; xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = ""; xx.lblopts = 0; tralog = zopeno(ZTFILE,s,NULL,&xx); } else tralog = zopeno(ZTFILE,s,NULL,NULL); } if (!tralog && !quiet) printf("?%s - %s\n",s,ck_errstr()); if (tralog > 0 && tlogfmt > 0) { ckstrncpy(trafil,s,CKMAXPATH); tlog(F110,"Transaction Log:",versio,0L); #ifndef MAC tlog(F100,ckxsys,"",0L); #endif /* MAC */ ztime(&s); tlog(F100,s,"",0L); } else *trafil = '\0'; return(tralog); #else return(0); #endif /* TLOG */ } #ifndef NOLOCAL int #ifdef CK_ANSIC sesopn( char * s, int disp ) #else sesopn(s,disp) char * s; int disp; #endif /* CK_ANSIC */ { static struct filinfo xx; extern int tsstate; tsstate = 0; /* Session log timestamp state */ if (!s) s = ""; if (!*s) return(0); debug(F111,"sesopn",s,disp); zclose(ZSFILE); #ifdef OS2ORUNIX if (s[0] == '|') { /* Pipe */ char * p = s + 1; debug(F110,"sesopn p",p,0); while (*p) { if (*p != ' ') break; else p++; } debug(F110,"sesopn pipe",p,0); setseslog(zxcmd(ZSFILE,p)); debug(F101,"sesopn seslog","",seslog); } else { /* File */ #endif /* OS2ORUNIX */ if (disp) { xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0; xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = ""; xx.lblopts = 0; setseslog(zopeno(ZSFILE,s,NULL,&xx)); } else setseslog(zopeno(ZSFILE,s,NULL,NULL)); if (!seslog && !quiet) printf("?%s - %s\n",s,ck_errstr()); #ifdef OS2ORUNIX } #endif /* OS2ORUNIX */ if (seslog > 0) ckstrncpy(sesfil,s,CKMAXPATH+1); else *sesfil = '\0'; return(seslog); } #endif /* NOLOCAL */ #endif /* NOICP */ int #ifdef CK_ANSIC debopn( char *s, int disp ) #else debopn(s,disp) char *s; int disp; #endif /* CK_ANSIC */ { #ifdef DEBUG #ifdef CK_UTSNAME extern char unm_mch[], unm_nam[], unm_rel[], unm_ver[], unm_mod[]; #endif /* CK_UTSNAME */ #ifdef OS2 extern char ckxsystem[]; #endif /* OS2 */ char *tp; static struct filinfo xx; if (!s) s = ""; if (!*s) return(0); zclose(ZDFILE); #ifdef OS2ORUNIX if (s[0] == '|') { /* Pipe */ char * p = s + 1; debug(F110,"debopn p",p,0); while (*p) { if (*p != ' ') break; else p++; } debug(F110,"debopn pipe",p,0); deblog = zxcmd(ZDFILE,p); debug(F101,"debopn deblog","",deblog); } else { /* File */ #endif /* OS2ORUNIX */ if (disp) { xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0; xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = ""; xx.lblopts = 0; deblog = zopeno(ZDFILE,s,NULL,&xx); } else deblog = zopeno(ZDFILE,s,NULL,NULL); if (!deblog && !quiet) printf("?%s - %s\n",s,ck_errstr()); #ifdef OS2ORUNIX } #endif /* OS2ORUNIX */ if (deblog > 0) { ckstrncpy(debfil,s,CKMAXPATH+1); debug(F110,"Debug Log ",versio,0); #ifndef MAC #ifdef OS2 debug(F110,ckxsys,ckxsystem,0); #else /* OS2 */ debug(F100,ckxsys,"",0); #endif /* OS2 */ #endif /* MAC */ #ifdef CK_UTSNAME if (unm_mch[0]) { debug(F110,"uname machine",unm_mch,0); if (unm_mod[0]) debug(F110,"uname model ",unm_mod,0); debug(F110,"uname sysname",unm_nam,0); debug(F110,"uname release",unm_rel,0); debug(F110,"uname version",unm_ver,0); } #ifdef KTARGET { char * s; /* Makefile target */ s = KTARGET; if (!s) s = ""; if (!*s) s = "(unknown)"; debug(F110,"build target",s,0); } #endif /* KTARGET */ deblog = 0; ztime(&tp); deblog = 1; debug(F100,tp,"",0); #endif /* UTSNAME */ debug(F101,"byteorder","",byteorder); #ifndef NOICP #ifndef NOLOCAL if (local) { debug(F110,"Active connection: ",ttname,0); if (!network) { debug(F101,"Speed","",speed); if (hwparity) debug(F110,"Parity[hardware]",parnam((char)hwparity),0); else debug(F110,"Parity",parnam((char)parity),0); deblog = 0; debug(F110,"Modem",gmdmtyp(),0); deblog = 1; } } else { debug(F110,"Active connection: ","none",0); } #endif /* NOLOCAL */ #endif /* NOICP */ } else *debfil = '\0'; return(deblog); #else return(0); #endif /* MAC */ } #ifndef NOICP /* C K D A T E -- Returns current date/time in standard format */ static char nowbuf[18]; char * ckdate() { extern struct keytab cmonths[]; int x; char * t; /* Substitute today's date */ char dbuf[32]; ztime(&t); /* 012345678901234567890123 */ /* Sat Jul 4 12:16:43 1998 */ ckstrncpy(dbuf,t,32); t = dbuf; debug(F110,"ckdate dbuf",dbuf,0); nowbuf[0] = t[20]; nowbuf[1] = t[21]; nowbuf[2] = t[22]; nowbuf[3] = t[23]; nowbuf[4] = NUL; debug(F110,"ckdate nowbuf",nowbuf,0); t[7] = NUL; if ((x = lookup(cmonths,t+4,12,NULL)) < 0) { debug(F110,"ckdate bad month",t,0); return(""); } sprintf(nowbuf+4,"%02d",x); /* SAFE */ nowbuf[6] = (t[8] == SP) ? '0' : t[8]; nowbuf[7] = t[9]; nowbuf[8] = ' '; nowbuf[9] = NUL; debug(F110,"ckdate nowbuf",nowbuf,0); for (x = 11; x < 19; x++) nowbuf[x-2] = t[x]; nowbuf[17] = NUL; debug(F110,"ckdate nowbuf",nowbuf,0); return((char *)nowbuf); } #ifdef CKLOGDIAL /* fc = 0 for initial open, meaning open, then close immediately. fc > 0 for subsequent opens, meaning open for use, leave open. */ int #ifdef CK_ANSIC diaopn( char *s, int disp, int fc ) #else diaopn(s,disp,fc) char *s; int disp, fc; #endif /* CK_ANSIC */ { static struct filinfo xx; if (!s) s = ""; if (!*s) return(0); debug(F110,"diaopn log",s,0); debug(F101,"diaopn fc",s,fc); debug(F101,"diaopn disp 1",s,disp); if (fc) disp = 1; /* Force append if open for use */ debug(F101,"diaopn disp 2",s,disp); zclose(ZDIFIL); /* In case a log was already open */ #ifdef OS2ORUNIX if (s[0] == '|') { /* Pipe */ char * p = s + 1; debug(F110,"diaopn p",p,0); while (*p) { if (*p != ' ') break; else p++; } debug(F110,"diaopn pipe",p,0); dialog = zxcmd(ZDIFIL,p); debug(F101,"diaopn dialog","",dialog); } else { /* File */ #endif /* OS2ORUNIX */ if (disp) { xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0; xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = ""; xx.lblopts = 0; dialog = zopeno(ZDIFIL,s,NULL,&xx); } else dialog = zopeno(ZDIFIL,s,NULL,NULL); if (!dialog) printf("?%s - %s\n",s,ck_errstr()); #ifdef OS2ORUNIX } #endif /* OS2ORUNIX */ if (dialog > 0) ckstrncpy(diafil,s,CKMAXPATH+1); else *diafil = '\0'; if (fc == 0) /* Initial open */ zclose(ZDIFIL); /* close it */ return(dialog); } #endif /* CKLOGDIAL */ #ifndef NOSHOW /* SHOW command routines */ char * #ifdef CK_ANSIC shoxm( void ) #else shoxm() #endif /* CK_ANSIC */ { char * s; switch (binary) { case XYFT_T: s = "text"; break; #ifdef VMS case XYFT_B: s = "binary fixed"; break; case XYFT_I: s = "image"; break; case XYFT_L: s = "labeled"; break; case XYFT_U: s = "binary undef"; break; #else #ifdef MAC case XYFT_B: s = "binary"; break; case XYFT_M: s = "macbinary"; break; #else case XYFT_B: s = "binary"; break; #ifdef CK_LABELED case XYFT_L: s = "labeled"; break; #endif /* CK_LABELED */ #endif /* MAC */ #endif /* VMS */ default: s = "unknown"; break; } return(s); } #ifndef NOXFER VOID /* SHOW TRANSFER */ shoxfer() { extern int docrc, usepipes, xfrxla, whereflg; extern char * xfrmsg; printf("\n"); printf(" Transfer Bell: %s\n",showoff(xfrbel)); printf(" Transfer Interruption: %s\n",showoff(xfrint)); printf(" Transfer Cancellation: %s\n",showoff(xfrcan)); #ifndef NOCSETS printf(" Transfer Translation: %s\n",showoff(xfrxla)); printf(" Transfer Character-set: "); if (tcharset == TC_TRANSP) printf("Transparent\n"); else printf("%s\n",tcsinfo[tcharset].keyword); #endif /* NOCSETS */ printf(" Transfer CRC-calculation: %s\n",showoff(docrc)); printf(" Transfer Display: "); switch (fdispla) { case XYFD_N: printf("%s\n","none"); break; case XYFD_R: printf("%s\n","serial"); break; case XYFD_C: printf("%s\n","fullscreen"); break; case XYFD_S: printf("%s\n","crt"); break; case XYFD_B: printf("%s\n","brief"); break; case XYFD_G: printf("%s\n","gui"); break; } printf(" Transfer Message: %s\n", xfrmsg ? xfrmsg : "(none)"); printf(" Transfer Locking-shift: "); if (lscapu == 2) { printf("forced"); } else { printf("%s", (lscapr ? "enabled" : "disabled")); if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used"); } printf("\n Transfer Mode: %s\n", xfermode == XMODE_A ? "automatic" : "manual" ); printf(" Transfer Pipes: %s\n", showoff(usepipes)); printf(" Transfer Protocol: %s\n",ptab[protocol].p_name); printf(" Transfer Report: %s\n",showoff(whereflg)); printf(" Transfer Slow-start: %s\n",showoff(slostart)); printf("\n"); } #endif /* NOXFER */ VOID shoflow() { int i, x; extern int cxflow[], cxtype, ncxname, nfloname, autoflow; extern char * cxname[]; printf("\nConnection type: %s\n",cxname[cxtype]); if (autoflow) { printf("Current flow-control: %s\n", floname[cxflow[cxtype]]); printf("Switches automatically: yes\n"); } else { printf("Current flow-control: %s\n", floname[flow]); printf("Switches automatically: no\n"); } printf("\nDefaults by connection type:\n"); debug(F111,"shoflow cxtype",cxname[cxtype],cxtype); debug(F101,"shoflow flow","",flow); for (i = 0; i < ncxname; i++) { #ifdef NOLOCAL if (i > 0) break; #endif /* NOLOCAL */ #ifndef NETCONN if (i > 2) break; #endif /* NETCONN */ #ifndef DECNET if (i == CXT_DECNET) continue; #endif /* DECNET */ #ifndef DECNET #ifndef SUPERLAT if (i == CXT_LAT) continue; #endif /* SUPERLAT */ #endif /* DECNET */ #ifndef CK_NETBIOS if (i == CXT_NETBIOS) continue; #endif /* CK_NETBIOS */ #ifndef NPIPE if (i == CXT_NPIPE) continue; #endif /* NPIPE */ #ifndef NETCMD if (i == CXT_PIPE) continue; #endif /* NETCMD */ #ifndef ANYX25 if (i == CXT_X25) continue; #endif /* ANYX25 */ x = cxflow[i]; debug(F101,"shoflow x","",x); if (x < nfloname) printf(" %-14s: %s\n",cxname[i],floname[x]); else printf(" %-14s: (%d)\n",cxname[i],x); } printf("\n"); } #ifndef NOLOCAL #ifdef ANYX25 int shox25(n) int n; { if (nettype == NET_SX25) { printf("SunLink X.25 V%d.%d",x25ver / 10,x25ver % 10); if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,"); printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" Reverse charge call %s", revcall ? "selected" : "not selected"); printf (", Closed user group "); if (closgr > -1) printf ("%d",closgr); else printf ("not selected"); printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" Call user data %s.\n", cudata ? udata : "not selected"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} } else if (nettype == NET_VX25) { if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,"); printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" Reverse charge call %s", revcall ? "selected" : "not selected"); printf (", Closed user group [unsupported]"); if (closgr > -1) printf ("%d",closgr); else printf ("not selected"); printf (","); printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" Call user data %s.\n", cudata ? udata : "not selected"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} } else if (nettype == NET_IX25) { printf("AIX NPI X.25\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf("\n Reverse charge call %s", revcall ? "selected" : "not selected"); printf (", Closed user group [unsupported]"); if (closgr > -1) printf ("%d",closgr); else printf ("not selected"); printf (","); printf("\n Call user data %s.\n", cudata ? udata : "not selected"); } return(n); } #ifndef IBMX25 int shopad(n) int n; { int i; printf("\nX.3 PAD Parameters:\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} for (i = 0; i < npadx3; i++) { printf(" [%d] %s %d\n",padx3tab[i].kwval,padx3tab[i].kwd, padparms[padx3tab[i].kwval]); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} } return(n); } #endif /* IBMX25 */ #endif /* ANYX25 */ VOID shoparc() { extern int reliable, stopbits, clsondisc; char *s; long zz; #ifdef NEWFTP if (ftpisconnected()) { shoftp(1); printf("\n"); } #endif /* NEWFTP */ printf("Communications Parameters:\n"); if (network #ifdef IKSD || inserver #endif /* IKSD */ ) { printf(" Network Host: %s%s",ttname, (reliable == SET_ON || (reliable == SET_AUTO && !local) #ifdef TN_COMPORT && !istncomport() #endif /* TN_COMPORT */ #ifdef IKSD || inserver #endif /* IKSD */ ) ? " (reliable)" : ""); #ifdef TN_COMPORT if (istncomport()) { int modemstate; char * oflow, * iflow = "", * parity, * stopsize, * signature; int baud = tnc_get_baud(); switch (tnc_get_oflow()) { case TNC_CTL_OFLOW_NONE: oflow = "none"; break; case TNC_CTL_OFLOW_XON_XOFF: oflow = "xon/xoff"; break; case TNC_CTL_OFLOW_RTS_CTS: oflow = "rts/cts"; break; case TNC_CTL_OFLOW_DCD: oflow = "dcd"; break; case TNC_CTL_OFLOW_DSR: oflow = "dsr"; break; default: oflow = "(unknown)"; } switch (tnc_get_iflow()) { case TNC_CTL_IFLOW_NONE: iflow = "none"; break; case TNC_CTL_IFLOW_XON_XOFF: iflow = "xon/xoff"; break; case TNC_CTL_IFLOW_RTS_CTS: iflow = "rts/cts"; break; case TNC_CTL_IFLOW_DTR: break; default: iflow = oflow; } switch (tnc_get_parity()) { case TNC_PAR_NONE: parity = "none"; break; case TNC_PAR_ODD: parity = "odd"; break; case TNC_PAR_EVEN: parity = "even"; break; case TNC_PAR_MARK: parity = "mark"; break; case TNC_PAR_SPACE: parity = "space"; break; default: parity = "(unknown)"; } switch (tnc_get_stopsize()) { case TNC_SB_1: stopsize = "1"; break; case TNC_SB_1_5: stopsize = "1.5"; break; case TNC_SB_2: stopsize = "2"; break; default: stopsize = "(unknown)"; } signature = (char *)tnc_get_signature(); printf("\n Signature : %s\n",signature?signature:""); if (baud <= 0) printf(" Speed : (unknown)\n"); else printf(" Speed : %d\n", baud); printf(" Outbound Flow Control: %s\n", oflow); printf(" Inbound Flow Control : %s\n", iflow); printf(" Parity : %s\n", parity); printf(" Data Size : %d\n", tnc_get_datasize()); printf(" Stop Bits : %s\n", stopsize); printf(" DTR Signal : %d\n", tnc_get_dtr_state()); printf(" RTS Signal : %d\n", tnc_get_rts_state()); printf(" Modem State:\n"); modemstate = tnc_get_ms(); if (modemstate & TNC_MS_EDGE_RING) printf(" Trailing Edge Ring Detector On\n"); else printf(" Trailing Edge Ring Detector Off\n"); if (modemstate & TNC_MS_CTS_SIG) printf(" CTS Signal On\n"); else printf(" CTS Signal Off\n"); if (modemstate & TNC_MS_DSR_SIG) printf(" DSR Signal On\n"); else printf(" DSR Signal Off\n"); if (modemstate & TNC_MS_RI_SIG) printf(" Ring Indicator On\n"); else printf(" Ring Indicator Off\n"); if (modemstate & TNC_MS_RLSD_SIG) printf(" RLSD (CD) Signal On\n"); else printf(" RLSD (CD) Signal Off\n"); printf("\n"); } #endif /* TN_COMPORT */ } else { printf(" %s: %s%s, speed: ", #ifdef OS2 "Port", #else "Line", #endif /* OS2 */ ttname, #ifdef CK_TTYFD (local && #ifdef VMS vmsttyfd() < 0 #else ttyfd == -1 #endif /* VMS */ ) ? " (closed)" : (reliable == SET_ON ? " (reliable)" : "") #else "" #endif /* CK_TTYFD */ ); if ( #ifdef CK_TTYFD #ifdef VMS vmsttyfd() < 0 #else ttyfd == -1 #endif /* VMS */ || #endif /* CK_TTYFD */ (zz = ttgspd()) < 0) { printf("unknown"); } else { if (speed == 8880) printf("75/1200"); else if (speed == 134) printf("134.5"); else printf("%ld",zz); } } if (network #ifdef IKSD || inserver #endif /* IKSD */ ) printf("\n Mode: "); else printf(", mode: "); if (local) printf("local"); else printf("remote"); if (network == 0 #ifdef IKSD && !inserver #endif/* IKSD */ ) { #ifdef CK_TAPI if (tttapi && !tapipass ) printf(", modem: %s","TAPI"); else #endif /* CK_TAPI */ printf(", modem: %s",gmdmtyp()); } else { #ifdef NETCONN if (nettype == NET_TCPA) printf(", TCP/IP"); if (nettype == NET_TCPB) printf(", TCP/IP"); if (nettype == NET_DEC) { if (ttnproto == NP_LAT) printf(", DECnet LAT"); else if ( ttnproto == NP_CTERM ) printf(", DECnet CTERM"); else printf(", DECnet"); } if (nettype == NET_SLAT) printf(", Meridian Technologies' SuperLAT"); #ifdef NETFILE if (nettype == NET_FILE) printf(", local file"); #endif /* NETFILE */ #ifdef NETCMD if (nettype == NET_CMD) printf(", pipe"); #endif /* NETCMD */ #ifdef NETPTY if (nettype == NET_PTY) printf(", pseudoterminal"); #endif /* NETPTY */ #ifdef NETDLL if (nettype == NET_DLL) printf(", dynamic load library"); #endif /* NETDLL */ if (nettype == NET_PIPE) printf(", Named Pipes"); #ifdef SSHBUILTIN if (nettype == NET_SSH) printf(", Secure Shell protocol (SECURE)"); #endif /* SSHBUILTIN */ #ifdef ANYX25 if (shox25(0) < 0) return; #endif /* ANYX25 */ if (IS_TELNET()) { printf(", telnet protocol"); if (0 #ifdef CK_ENCRYPTION || ck_tn_encrypting() && ck_tn_decrypting() #endif /* CK_ENCRYPTION */ #ifdef CK_SSL || tls_active_flag || ssl_active_flag #endif /* CK_SSL */ ) printf(" (SECURE)"); } #ifdef RLOGCODE else if (ttnproto == NP_RLOGIN || ttnproto == NP_K4LOGIN || ttnproto == NP_K5LOGIN) printf(", rlogin protocol"); else if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN) printf(", rlogin protocol (SECURE)"); #endif /* RLOGCODE */ #ifdef CK_KERBEROS #ifdef KRB5 else if (ttnproto == NP_K5U2U) printf(", Kerberos 5 User to User protocol (SECURE)"); #endif /* KRB5 */ #endif /* CK_KERBEROS */ #endif /* NETCONN */ } printf("\n"); if (hwparity && local && !network) s = parnam((char)hwparity); else s = parnam((char)parity); printf(" Parity: %s%s",hwparity ? "hardware " : "", s); #ifndef NOLOCAL if (local && !network) { int sb; char c; c = s[0]; if (islower(c)) c = toupper(c); sb = stopbits; if (sb < 1) { sb = (speed > 0 && speed <= 110L) ? 2 : 1; printf(", stop-bits: (default)"); } else { printf(", stop-bits: %d",sb); } if (hwparity) printf(" (8%c%d)",c,sb); else if (parity) printf(" (7%c%d)",c,sb); else printf(" (8N%d)",sb); printf("\n D"); } else printf(", d"); #endif /* NOLOCAL */ printf("uplex: %s, ", duplex ? "half" : "full"); debug(F101,"shoparp flow","",flow); printf("flow: %s", floname[flow]); printf(", handshake: "); if (turn) printf("%d\n",turnch); else printf("none\n"); #ifdef COMMENT if (local && !network) { /* SET CARRIER-WATCH */ #endif /* COMMENT */ if (carrier == CAR_OFF) s = "off"; else if (carrier == CAR_ON) s = "on"; else if (carrier == CAR_AUT) s = "auto"; else s = "unknown"; printf(" Carrier-watch: %s", s); if (carrier == CAR_ON) { if (cdtimo) printf(", timeout: %d sec", cdtimo); else printf(", timeout: none"); } #ifdef COMMENT } #endif /* COMMENT */ printf(", close-on-disconnect: %s\n",showoff(clsondisc)); #ifdef UNIX /* UUCP lockfile, UNIX only */ if (local) { #ifndef NOUUCP if (!network && haslock && *flfnam) printf(" Lockfile: %s",flfnam); #ifndef USETTYLOCK if (!network && haslock && lock2[0]) printf("\n Secondary lockfile: %s",lock2); #endif /* USETTYLOCK */ #else #ifdef QNX { extern int qnxportlock, qnxopencount(); if (local) printf(" Qnx-port-lock: %s, Open count: %d", showoff(qnxportlock), qnxopencount() ); else printf(" Qnx-port-lock: %s", showoff(qnxportlock)); } #endif /* QNX */ #endif /* NOUUCP */ printf("\n"); } else { char * s; s = ttglckdir(); if (!s) s = ""; printf(" Lockfile directory: %s\n", *s ? s : "(none)"); } #endif /* UNIX */ #ifndef MACOSX if (!local) { printf(" Typical port device name: %s\n",ttgtpn()); } #endif /* MACOSX */ if (local) { int i; i = parity ? 7 : 8; if (i == 8) i = (cmask == 0177) ? 7 : 8; printf(" Terminal bytesize: %d,",i); printf(" escape character: %d (^%c)\n",escape,ctl(escape)); } } int #ifdef CK_ANSIC shotcp( int n ) #else shotcp(n) int n; #endif /* CK_ANSIC */ { #ifdef TCPSOCKET if (nettype == NET_TCPA || nettype == NET_TCPB) { printf("SET TCP parameters:\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" Reverse DNS lookup: %s\n", showooa(tcp_rdns)); if (++n > cmd_rows - 3) { if (!askmore()) {return(0);} else {n = 0;}} #ifdef CK_DNS_SRV printf(" DNS Service Records lookup: %s\n", showooa(tcp_dns_srv)); if (++n > cmd_rows - 3) { if (!askmore()) {return(0);} else {n = 0;}} #endif /* CK_DNS_SRV */ #ifndef NOTCPOPTS #ifdef SOL_SOCKET #ifdef SO_KEEPALIVE printf(" Keepalive: %s\n", showoff(tcp_keepalive)); if (++n > cmd_rows - 3) { if (!askmore()) {return(0);} else {n = 0;}} #endif /* SO_KEEPALIVE */ #ifdef SO_LINGER printf(" Linger: %s", tcp_linger ? "on, " : "off\n" ); if (tcp_linger) { if (tcp_linger_tmo) printf("%d x 10 milliseconds\n",tcp_linger_tmo); else printf("no timeout\n"); } if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* SO_LINGER */ #ifdef SO_DONTROUTE printf(" DontRoute: %s\n", tcp_dontroute ? "on" : "off" ); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* SO_DONTROUTE */ #ifdef TCP_NODELAY printf(" Nodelay: %s\n", showoff(tcp_nodelay)); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* TCP_NODELAY */ #ifdef SO_SNDBUF if (tcp_sendbuf <= 0) printf(" Send buffer: (default size)\n"); else printf(" Send buffer: %d bytes\n", tcp_sendbuf); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF if (tcp_recvbuf <= 0) printf(" Receive buffer: (default size)\n"); else printf(" Receive buffer: %d bytes\n", tcp_recvbuf); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* SO_RCVBUF */ #endif /* SOL_SOCKET */ #endif /* NOTCPOPTS */ printf(" address: %s\n",tcp_address ? tcp_address : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} #ifndef NOHTTP printf(" http-proxy: %s\n",tcp_http_proxy ? tcp_http_proxy : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} #endif /* NOHTTP */ #ifdef NT #ifdef CK_SOCKS printf(" socks-server: %s\n",tcp_socks_svr ? tcp_socks_svr : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} #ifdef CK_SOCKS_NS printf(" socks-name-server: %s\n", tcp_socks_ns ? tcp_socks_ns : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} #endif /* CK_SOCKS_NS */ #endif /* CK_SOCKS */ #endif /* NT */ } #endif /* TCPSOCKET */ return(n); } #ifdef TNCODE int #ifdef CK_ANSIC shotopt( int n ) #else shotopt(n) int n; #endif /* CK_ANSIC */ { int opt; printf("%-21s %12s %12s %12s %12s\n\n", "Telnet Option","Me (client)","U (client)", "Me (server)","U (server)"); n += 2; if (n > cmd_rows - 3) { if (!askmore()) {return(-1);} else {n = 0;}} for ( opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) { switch (opt) { case TELOPT_AUTHENTICATION: case TELOPT_ENCRYPTION: case TELOPT_TTYPE: case TELOPT_NAWS: case TELOPT_BINARY: case TELOPT_NEWENVIRON: case TELOPT_SNDLOC: case TELOPT_XDISPLOC: case TELOPT_SGA: case TELOPT_ECHO: case TELOPT_KERMIT: case TELOPT_START_TLS: case TELOPT_FORWARD_X: case TELOPT_COMPORT: break; default: continue; } printf("%03d %-17s ", opt, TELOPT(opt) ); printf("%12s %12s ", TELOPT_MODE(TELOPT_DEF_C_ME_MODE(opt)), TELOPT_MODE(TELOPT_DEF_C_U_MODE(opt)) ); printf("%12s %12s\n", TELOPT_MODE(TELOPT_DEF_S_ME_MODE(opt)), TELOPT_MODE(TELOPT_DEF_S_U_MODE(opt)) ); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} if (sstelnet) printf("%21s %12s %12s %12s %12s\n", "", "", "", (TELOPT_ME(opt)?"WILL":"WONT"), (TELOPT_U(opt)?"DO":"DONT") ); else printf("%21s %12s %12s %12s %12s\n", "", (TELOPT_ME(opt)?"WILL":"WONT"), (TELOPT_U(opt)?"DO":"DONT"), "", "" ); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} } return(n); } int #ifdef CK_ANSIC shotel( int n ) #else shotel(n) int n; #endif /* CK_ANSIC */ { extern int tn_duplex; #ifdef CK_ENVIRONMENT extern int tn_env_flg; extern char tn_env_acct[]; extern char tn_env_job[]; extern char tn_env_prnt[]; extern char tn_env_sys[]; extern char * tn_env_uservar[8][2]; int x; #endif /* CK_ENVIRONMENT */ #ifdef CK_SNDLOC extern char * tn_loc; #endif /* CK_SNDLOC */ printf("SET TELNET parameters:\n echo: %s\n NVT newline-mode: ", tn_duplex ? "local" : "remote"); switch (tn_nlm) { case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break; case TNL_CRLF: printf("%s\n","on (cr-lf)"); break; case TNL_CR: printf("%s\n","raw (cr)"); break; case TNL_LF: printf("%s\n","(lf)"); break; } if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} #ifdef CK_AUTHENTICATION { int type = ck_tn_authenticated(); printf(" authentication: "); switch (sstelnet ? TELOPT_U_MODE(TELOPT_AUTHENTICATION) : TELOPT_ME_MODE(TELOPT_AUTHENTICATION) ) { case TN_NG_AC: printf( "accepted " ); break; case TN_NG_RF: printf( "refused " ); break; case TN_NG_RQ: printf( "requested"); break; case TN_NG_MU: printf( "required "); break; } #ifdef CK_SSL if ((ssl_active_flag || tls_active_flag) && ck_tn_auth_valid() == AUTH_VALID && (!TELOPT_U(TELOPT_AUTHENTICATION) || type == AUTHTYPE_NULL || type == AUTHTYPE_AUTO)) printf(" in use: X.509 certificate\n"); else #endif /* CK_SSL */ printf(" in use: %s\n",AUTHTYPE_NAME(type)); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} if (forward_flag) printf(" credentials forwarding requested %s\n", forwarded_tickets ? "and completed" : "but not completed"); else printf(" credentials forwarding disabled\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} } #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION { int i,x; int e_type = ck_tn_encrypting(); int d_type = ck_tn_decrypting(); char * e_str = NULL, * d_str = NULL; static struct keytab * tnetbl = NULL; static int ntnetbl = 0; x = ck_get_crypt_table(&tnetbl,&ntnetbl); for (i = 0; i < ntnetbl; i++) { if (e_type == tnetbl[i].kwval) e_str = tnetbl[i].kwd; if (d_type == tnetbl[i].kwval) d_str = tnetbl[i].kwd; } printf(" encryption: "); switch (TELOPT_ME_MODE(TELOPT_ENCRYPTION)) { /* This should be changed to report both ME and U modes */ case TN_NG_AC: printf( "accepted " ); break; case TN_NG_RF: printf( "refused " ); break; case TN_NG_RQ: printf( "requested"); break; case TN_NG_MU: printf( "required "); break; } printf(" in use: "); switch ((e_type ? 1 : 0) | (d_type ? 2 : 0)) { case 0: printf("plain text in both directions"); break; case 1: printf("%s output, plain text input",e_str); break; case 2: printf("plain text output, %s input",d_str); break; case 3: printf("%s output, %s input",e_str,d_str); break; } printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} } #endif /* CK_ENCRYPTION */ #ifdef IKS_OPTION printf(" kermit: "); switch (TELOPT_U_MODE(TELOPT_KERMIT)) { case TN_NG_AC: printf( "u, accepted; " ); break; case TN_NG_RF: printf( "u, refused; " ); break; case TN_NG_RQ: printf( "u, requested; "); break; case TN_NG_MU: printf( "u, required; "); break; } switch (TELOPT_ME_MODE(TELOPT_KERMIT)) { case TN_NG_AC: printf( "me, accepted; " ); break; case TN_NG_RF: printf( "me, refused; " ); break; case TN_NG_RQ: printf( "me, requested; "); break; case TN_NG_MU: printf( "me, required; "); break; } if (TELOPT_U(TELOPT_KERMIT)) printf(" u, %s", TELOPT_SB(TELOPT_KERMIT).kermit.u_start ? "started" : "stopped" ); else printf(" u, n/a"); if (TELOPT_ME(TELOPT_KERMIT)) printf(" me, %s;", TELOPT_SB(TELOPT_KERMIT).kermit.me_start ? "started" : "stopped" ); else printf(" me, n/a;"); printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} #endif /* IKS_OPTION */ printf(" BINARY newline-mode: "); switch (tn_b_nlm) { case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break; case TNL_CRLF: printf("%s\n","on (cr-lf)"); break; case TNL_CR: printf("%s\n","raw (cr)"); break; case TNL_LF: printf("%s\n","(lf)"); break; } if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" binary-mode: "); switch (TELOPT_U_MODE(TELOPT_BINARY)) { case TN_NG_AC: printf( "u, accepted; " ); break; case TN_NG_RF: printf( "u, refused; " ); break; case TN_NG_RQ: printf( "u, requested; "); break; case TN_NG_MU: printf( "u, required; "); break; } switch (TELOPT_ME_MODE(TELOPT_BINARY)) { case TN_NG_AC: printf( "me, accepted; " ); break ; case TN_NG_RF: printf( "me, refused; " ); break; case TN_NG_RQ: printf( "me, requested; "); break; case TN_NG_MU: printf( "me, required; "); break; } printf("u, %s; me, %s\n", TELOPT_U(TELOPT_BINARY) ? "BINARY" : "NVT", TELOPT_ME(TELOPT_BINARY) ? "BINARY" : "NVT" ); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" binary-transfer-mode: %s\n",showoff(tn_b_xfer)); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" bug binary-me-means-u-too: %s\n",showoff(tn_b_meu)); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" bug binary-u-means-me-too: %s\n",showoff(tn_b_ume)); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" bug sb-implies-will-do: %s\n",showoff(tn_sb_bug)); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" bug auth-krb5-des: %s\n",showoff(tn_auth_krb5_des_bug)); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" terminal-type: "); if (tn_term) { printf("%s\n",tn_term); } else { char *p; #ifdef OS2 p = (tt_type >= 0 && tt_type <= max_tt) ? tt_info[tt_type].x_name : "UNKNOWN"; #else p = getenv("TERM"); #endif /* OS2 */ if (p) printf("none (%s will be used)\n",p); else printf("none\n"); } if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} #ifdef CK_ENVIRONMENT printf(" environment: %s\n", showoff(tn_env_flg)); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" ACCOUNT: %s\n",tn_env_acct); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" DISPLAY: %s\n",(char *)tn_get_display() ? (char *)tn_get_display() : ""); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" JOB : %s\n",tn_env_job); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" PRINTER: %s\n",tn_env_prnt); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} #ifndef NOSPL printf(" USER : %s\n",uidbuf); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} #endif /* NOSPL */ printf(" SYSTEM : %s\n",tn_env_sys); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} for (x = 0; x < 8; x++) { if (tn_env_uservar[x][0] && tn_env_uservar[x][1]) { printf(" %-7s: %s\n",tn_env_uservar[x][0], tn_env_uservar[x][1]); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} } } #endif /* CK_ENVIRONMENT */ #ifdef CK_SNDLOC printf(" LOCATION: %s\n", tn_loc ? tn_loc : ""); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} #endif /* CK_SNDLOC */ #ifdef CK_FORWARD_X printf(" .Xauthority-file: %s\n", (char *)XauFileName() ? (char *)XauFileName() : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} #endif /* CK_FORWARD_X */ return(n); } #endif /* TNCODE */ #ifdef CK_NETBIOS static int shonb(n) int n; { printf("NETBIOS parameters:\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" API : %s\n", NetbeuiAPI ? "NETAPI.DLL - IBM Extended Services or Novell Netware Requester" : "ACSNETB.DLL - IBM Network Transport Services/2" ) ; if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" Local Name: [%s]\n", NetBiosName); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} printf(" Adapter : %d\n", NetBiosAdapter); if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} if (NetBiosLSN > 0xFF) { printf(" Session : %d\n", NetBiosLSN); } else { printf(" Session : none active\n"); } if (++n > cmd_rows - 3) { if (!askmore()) { return(-1);} else {n = 0;}} return(n); } #endif /* CK_NETBIOS */ #ifndef NONET int shonet() { #ifndef NETCONN printf("\nNo networks are supported in this version of C-Kermit\n"); #else #ifdef NOLOCAL printf("\nNo networks are supported in this version of C-Kermit\n"); #else /* rest of this routine */ int n = 4; #ifndef NODIAL if (nnetdir <= 1) { printf("\nNetwork directory: %s\n",netdir[0] ? netdir[0] : "(none)"); n++; } else { int i; printf("\nNetwork directories:\n"); for (i = 0; i < nnetdir; i++) { printf("%2d. %s\n",i,netdir[i]); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } } #endif /* NODIAL */ #ifdef SSHCMD { extern char * sshcmd; printf("SSH COMMAND: %s\n",sshcmd ? sshcmd : "ssh -e none"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } #endif /* SSHCMD */ #ifdef OS2 printf("\nNetwork availability:\n"); #else printf("\nSupported networks:\n"); #endif /* OS2 */ if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #ifdef VMS #ifdef TCPWARE printf(" Process Software Corporation TCPware for OpenVMS"); #else #ifdef MULTINET printf(" TGV MultiNet TCP/IP"); #else #ifdef WINTCP printf(" WOLLONGONG WIN/TCP"); #else #ifdef DEC_TCPIP { static $DESCRIPTOR(tcp_desc,"_TCP0:"); int status; long devclass; static int itmcod = DVI$_DEVCLASS; #ifdef COMMENT status = LIB$GETDVI(&itmcod, 0, &tcp_desc, &devclass); #else /* Martin Zinser 9/96 */ status = lib$getdvi(&itmcod, 0, &tcp_desc, &devclass); #endif /* COMMENT */ if ((status & 1) && (devclass == DC$_SCOM)) printf(" Process Software Corporation TCPware for OpenVMS"); else #ifdef UCX50 printf(" DEC TCP/IP Services for (Open)VMS 5.0"); #else printf(" DEC TCP/IP Services for (Open)VMS"); #endif /* UCX50 */ } #else #ifdef CMU_TCPIP printf(" CMU-OpenVMS/IP"); #else printf(" None"); #endif /* CMU_TCPIP */ #endif /* DEC_TCPIP */ #endif /* WINTCP */ #endif /* MULTINET */ #endif /* TCPWARE */ if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #ifdef TNCODE printf(", TELNET protocol\n\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } n = shotel(n); if (n < 0) return(0); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* TNCODE */ printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf("\n"); n = shotcp(++n); if (n < 0) return(0); #else /* Not VMS */ #ifdef SUNX25 printf(" SunLink X.25\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* SUNX25 */ #ifdef STRATUSX25 printf(" Stratus VOS X.25\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* STRATUSX25 */ #ifdef IBMX25 printf(" IBM AIX X.25\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* IBMX25 */ #ifdef HPX25 printf(" HP-UX X.25\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* HPX25 */ #ifdef SSHBUILTIN if (ck_ssh_is_installed()) printf(" SSH V2 protocol\n"); #endif /* SSHBUILTIN */ #ifdef DECNET #ifdef OS2 #ifdef NT if (dnet_avail) printf(" DECnet, LAT and CTERM protocols\n"); else printf(" DECnet, LAT and CTERM protocols - not available\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #else /* NT */ if (dnet_avail) printf(" DECnet, LAT protocol\n"); else printf(" DECnet, LAT protocol - not available\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* NT */ #else printf(" DECnet\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* OS2 */ #endif /* DECNET */ #ifdef NPIPE printf(" Named Pipes\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* NPIPE */ #ifdef CK_NETBIOS if (netbiosAvail) printf(" NETBIOS\n"); else printf(" NETBIOS - not available\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* CK_NETBIOS */ #ifdef SUPERLAT if (slat_avail) printf(" SuperLAT\n"); else printf(" SuperLAT - not available\n") ; if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* SUPERLAT */ #ifdef TCPSOCKET if ( #ifdef OS2 tcp_avail #else 1 #endif /* OS2 */ ) { char ipaddr[16]; if (getlocalipaddrs(ipaddr,16,0) < 0) { #ifdef OS2ONLY printf(" TCP/IP via %s\n", tcpname); #else printf(" TCP/IP\n"); #endif /* OS2ONLY */ if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } else { int i = 1; #ifdef OS2ONLY printf(" TCP/IP [%16s] via %s\n", ipaddr, tcpname); #else printf(" TCP/IP [%16s]\n",ipaddr); #endif /* OS2ONLY */ if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } while (getlocalipaddrs(ipaddr,16,i++) >= 0) { printf(" [%16s]\n",ipaddr); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } } if (nettype == NET_TCPB) { printf("\n"); n = shotcp(++n); if (n < 0) return(0); #ifdef TNCODE printf("\n"); n = shotel(++n); if (n < 0) return(0); #endif /* TNCODE */ if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } #ifdef OS2 } else { printf(" TCP/IP - not available%s\n",tcpname[0] ? tcpname : "" ); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* OS2 */ } #endif /* TCPSOCKET */ #ifdef CK_NETBIOS if (netbiosAvail && nettype == NET_BIOS) { printf("\n") ; if ((n = shonb(++n)) < 0) return(0); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } #endif /* CK_NETBIOS */ #endif /* VMS */ printf("\nActive network connection:\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } if (network) { printf(" Host: %s",ttname); if ((nettype == NET_TCPA || nettype == NET_TCPB) && *ipaddr) printf(" [%s]",ipaddr); } else printf(" Host: none"); printf(", via: "); if (nettype == NET_TCPA || nettype == NET_TCPB) printf("tcp/ip\n"); else if (nettype == NET_SX25) printf("SunLink X.25\n"); else if (nettype == NET_VX25) printf("Stratus VOS X.25\n"); else if (nettype == NET_IX25) printf("IBM AIX X.25\n"); else if (nettype == NET_HX25) printf("HP-UX X.25\n"); else if (nettype == NET_DEC) { if ( ttnproto == NP_LAT ) printf("DECnet LAT\n"); else if ( ttnproto == NP_CTERM ) printf("DECnet CTERM\n"); else printf("DECnet\n"); } else if (nettype == NET_PIPE) printf("Named Pipes\n"); else if (nettype == NET_BIOS) printf("NetBIOS\n"); else if (nettype == NET_SLAT) printf("SuperLAT\n"); #ifdef NETFILE else if ( nettype == NET_FILE ) printf("local file\n"); #endif /* NETFILE */ #ifdef NETCMD else if ( nettype == NET_CMD ) printf("pipe\n"); #endif /* NETCMD */ #ifdef NETPTY else if ( nettype == NET_PTY ) printf("pseudoterminal\n"); #endif /* NETPTY */ #ifdef NETDLL else if ( nettype == NET_DLL ) printf("dynamic link library\n"); #endif /* NETDLL */ if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #ifdef ANYX25 if ((nettype == NET_SX25) || (nettype == NET_VX25) || (nettype == NET_IX25)) if ((n = shox25(n)) < 0) return(0); #endif /* ANYX25 */ #ifdef SSHBUILTIN if (nettype == NET_SSH) { printf("Secure Shell protocol\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } #endif /* SSHBUILTIN */ if (nettype == NET_TCPA || nettype == NET_TCPB) { #ifdef RLOGCODE if (ttnproto == NP_RLOGIN) { printf(" LOGIN (rlogin) protocol\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } #ifdef CK_KERBEROS else if (ttnproto == NP_K4LOGIN) { printf(" Kerberos 4 LOGIN (klogin) protocol\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } else if (ttnproto == NP_EK4LOGIN) { printf(" Encrypted Kerberos 4 LOGIN (eklogin) protocol\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } else if (ttnproto == NP_K5LOGIN) { printf(" Kerberos 5 LOGIN (klogin) protocol\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } else if (ttnproto == NP_EK5LOGIN) { printf(" Encrypted Kerberos 5 LOGIN (eklogin) protocol\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } #endif /* CK_KERBEROS */ #endif /* RLOGCODE */ #ifdef CK_KERBEROS if (ttnproto == NP_K5U2U) { printf(" Kerberos 5 User to User protocol\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } #endif /* CK_KERBEROS */ #ifdef TNCODE if (IS_TELNET()) { printf(" TELNET protocol\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Echoing is currently %s\n",duplex ? "local" : "remote"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } #endif /* TNCODE */ if (ttnproto == NP_TCPRAW) { printf(" Raw TCP socket\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } } printf("\n"); #endif /* NOLOCAL */ #endif /* NETCONN */ return(0); } #endif /* NONET */ #ifndef NODIAL VOID shodial() { if (mdmtyp >= 0 || local != 0) doshodial(); } VOID #ifdef CK_ANSIC shods( char *s ) /* Show a dial-related string */ #else shods(s) char *s; #endif /* CK_ANSIC */ { char c; if (s == NULL || !(*s)) { /* Empty? */ printf("(none)\n"); } else { /* Not empty. */ while ((c = *s++)) /* Can contain controls */ if (c == '\\') /* a backslash */ printf("\\\\"); else if (c > 31 && c < 127) { putchar(c); } else printf("\\{%d}",c); printf("\n"); } } int doshodial() { int i, n = 2; printf(" Dial status: %d", dialsta); #ifdef BIGBUFOK if (dialsta > 90) printf(" = Unknown error"); else if (dialsta < 0) printf(" = (none)"); else if (dialsta < 35 && dialmsg[dialsta]) printf(" = %s", dialmsg[dialsta]); #endif /* BIGBUFOK */ n++; if (ndialdir <= 1) { printf("\n Dial directory: %s\n",dialdir[0] ? dialdir[0] : "(none)"); } else { int i; printf("\n Dial directories:\n"); for (i = 0; i < ndialdir; i++) printf("%2d. %s\n",i+1,dialdir[i]); n += ndialdir; } printf(" Dial method: "); if (dialmauto) printf("auto "); else if (dialmth == XYDM_D) printf("default"); else if (dialmth == XYDM_P) printf("pulse "); else if (dialmth == XYDM_T) printf("tone "); printf(" Dial sort: %s\n",dialsrt ? "on" : "off"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Dial hangup: %s Dial display: %s\n", dialhng ? "on " : "off", dialdpy ? "on" : "off"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } if (dialrtr > 0) { printf(" Dial retries: %-12d Dial interval: %d\n", dialrtr, dialint); } else { printf(" Dial retries: (auto) Dial interval: %d\n", dialint); } if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Dial timeout: "); #ifdef CK_TAPI if (tttapi && !tapipass) printf("(tapi)"); else #endif /* CK_TAPI */ if (dialtmo > 0) printf("%4d sec", dialtmo); else printf("0 (auto)"); printf(" Redial number: %s\n",dialnum ? dialnum : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Dial confirmation: %s Dial convert-directory: %s\n", dialcnf ? "on " : "off", dialcvt ? ((dialcvt == 1) ? "on" : "ask") : "off"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Dial ignore-dialtone: %s", dialidt ? "on " : "off"); printf(" Dial pacing: %d\n",dialpace); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial prefix: %s\n", dialnpr ? dialnpr : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial suffix: %s\n", dialsfx ? dialsfx : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial country-code: %-12s", diallcc ? diallcc : "(none)"); printf("Dial connect: %s", dialcon ? ((dialcon == 1) ? "on" : "auto") : "off"); if (dialcon != CAR_OFF) printf(" %s", dialcq ? "quiet" : "verbose"); printf( "\n Dial area-code: %-12s", diallac ? diallac : "(none)"); n++; if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf("Dial restrict: "); if (dialrstr == 5) printf("international\n"); else if (dialrstr == 4) printf("long-distance\n"); else if (dialrstr == 2) printf("local\n"); else if (dialrstr == 6) printf("none\n"); else printf("?\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Dial lc-area-codes: "); if (nlocalac == 0) printf("(none)"); else for (i = 0; i < nlocalac; i++) printf("%s ", diallcac[i]); printf( "\n Dial lc-prefix: %s\n", diallcp ? diallcp : "(none)"); n++; if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial lc-suffix: %s\n", diallcs ? diallcs : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial ld-prefix: %s\n", dialldp ? dialldp : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial ld-suffix: %s\n", diallds ? diallds : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial force-long-distance %s\n", showoff(dialfld)); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial intl-prefix: %s\n", dialixp ? dialixp : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial intl-suffix: %s\n", dialixs ? dialixs : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial toll-free-area-code: "); if (ntollfree == 0) printf("(none)"); else for (i = 0; i < ntollfree; i++) printf("%s ", dialtfc[i]); printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial pulse-countries: "); if (ndialpucc == 0) printf("(none)"); else for (i = 0; i < ndialpucc; i++) printf("%s ", dialpucc[i]); printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial tone-countries: "); if (ndialtocc == 0) printf("(none)"); else for (i = 0; i < ndialtocc; i++) printf("%s ", dialtocc[i]); printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial toll-free-prefix: %s\n", dialtfp ? dialtfp : (dialldp ? dialldp : "(none)") ); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Dial pbx-exchange: "); if (ndialpxx == 0) printf("(none)"); else for (i = 0; i < ndialpxx; i++) printf("%s ", dialpxx[i]); printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial pbx-inside-prefix: %s\n", dialpxi ? dialpxi : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial pbx-outside-prefix: %s\n", dialpxo ? dialpxo : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf( " Dial macro: %s\n", dialmac ? dialmac : "(none)"); return(0); } #endif /* NODIAL */ #endif /* NOLOCAL */ /* Show File Parameters */ static char * #ifdef CK_ANSIC pathval( int x ) #else pathval(x) int x; #endif /* CK_ANSIC */ { switch (x) { case PATH_OFF: return("off"); case PATH_ABS: return("absolute"); case PATH_REL: return("relative"); case PATH_AUTO: return("auto"); default: return("unknown"); } } VOID shofil() { char *s; int i = 0, n = 1; extern char * ifdnam[]; extern int wildena; #ifdef UNIX extern int wildxpand; #endif /* UNIX */ extern char * snd_move, * snd_rename, * rcv_move, * rcv_rename; #ifdef PATTERNS extern int patterns; #endif /* PATTERNS */ extern char * rfspec, * sfspec; #ifdef UNIX extern int zobufsize, zofbuffer, zofblock; #endif /* UNIX */ #ifdef CK_CTRLZ extern int eofmethod; #endif /* CK_CTRLZ */ printf("\n"); #ifdef VMS printf(" File record-Length: %5d\n",frecl); n++; #endif /* VMS */ #ifndef NOXFER printf(" Transfer mode: %s\n", xfermode == XMODE_A ? "automatic" : "manual" ); n++; #ifdef PATTERNS printf(" File patterns: %s", showooa(patterns)); if (xfermode == XMODE_M && patterns) printf(" (but disabled by TRANSFER-MODE MANUAL)"); else if (patterns) printf(" (SHOW PATTERNS for list)"); printf("\n"); n++; #endif /* PATTERNS */ if (filepeek) printf(" File scan: on %d\n", nscanfile); else printf(" File scan: off\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} if (xfermode == XMODE_A) printf(" Default file type: %s\n",shoxm()); else printf(" File type: %s\n",shoxm()); n++; if (fncnv == XYFN_L) s = "literal"; else if (fncnv == XYFN_C) s = "converted"; else s = "(unknown)"; printf(" File names: %s\n",s); n++; printf(" Send pathnames: %s\n", pathval(fnspath)); n++; printf(" Receive pathnames: %s\n", pathval(fnrpath)); n++; #ifdef UNIXOROSK printf(" Match dot files: %s\n", matchdot ? "yes" : "no"); n++; #ifdef UNIX printf(" Wildcard-expansion: %s (%s)\n", showoff(wildena), wildxpand ? "shell" : "kermit"); n++; #endif /* UNIX */ #endif /* UNIXOROSK */ printf(" File collision: "); for (i = 0; i < ncolx; i++) if (colxtab[i].kwval == fncact) break; printf("%s\n", (i == ncolx) ? "unknown" : colxtab[i].kwd); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf(" File destination: %s\n", (dest == DEST_D) ? "disk" : ((dest == DEST_S) ? "screen" : ((dest == DEST_N) ? "nowhere" : "printer")) ); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} s = (keep >= 0 && keep <= 2) ? ifdnam[keep] : "keep"; printf(" File incomplete: %s\n",s); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf(" File bytesize: %d\n",(fmask == 0177) ? 7 : 8); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} #ifndef NOCSETS printf(" File character-set: %s\n",fcsinfo[fcharset].keyword); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf(" File default 7-bit: %s\n",fcsinfo[dcset7].keyword); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf(" File default 8-bit: %s\n",fcsinfo[dcset8].keyword); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} #ifdef UNICODE printf(" File UCS bom: %s\n",showoff(ucsbom)); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf(" File UCS byte-order: %s-endian\n", ucsorder ? "little" : "big"); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf(" Computer byteorder: %s-endian\n", byteorder ? "little" : "big"); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} #endif /* UNICODE */ #endif /* NOCSETS */ printf(" File end-of-line: "); i = feol; switch (feol) { case XYFA_C: printf("%s\n","cr"); break; case XYFA_L: printf("%s\n","lf"); break; case XYFA_2: printf("%s\n","crlf"); break; default: printf("%d\n",i); } if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} #endif /* NOXFER */ #ifdef CK_CTRLZ printf(" File eof: %s\n", eofmethod ? "ctrl-z" : "length"); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} #endif /* CK_CTRLZ */ #ifndef NOXFER #ifdef CK_TMPDIR printf(" File download-directory: %s\n", dldir ? dldir : "(your current directory)"); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} #ifdef COMMENT i = 256; s = line; zzstring("\\v(tmpdir)",&s,&i); printf(" Temporary directory: %s\n", line); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} #endif /* COMMENT */ #endif /* CK_TMPDIR */ #ifdef VMS { extern int vmssversions, vmsrversions; printf(" Send version-numbers: %s\n",showoff(vmssversions)); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf(" Receive version-numbers: %s\n",showoff(vmsrversions)); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} } #endif /* VMS */ printf(" Send move-to: %s\n", snd_move ? snd_move : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf(" Send rename-to: %s\n", snd_rename ? snd_rename : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf(" Receive move-to: %s\n", rcv_move ? rcv_move : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf(" Receive rename-to: %s\n", rcv_rename ? rcv_rename : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} #endif /* NOXFER */ #ifdef KERMRC printf(" Initialization file: %s\n", noinit ? "(none)" : #ifdef CK_SYSINI CK_SYSINI #else kermrc #endif /* CK_SYSINI */ ); #endif /* KERMRC */ if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} if (k_info_dir) { printf(" Kermit doc files: %s\n", k_info_dir); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} } #ifdef CKROOT s = zgetroot(); printf(" Root set: %s\n", s ? s : "(none)"); #endif /* CKROOT */ #ifdef UNIX printf(" Disk output buffer: %d (writes are %s, %s)\n", zobufsize, zofbuffer ? "buffered" : "unbuffered", zofblock ? "blocking" : "nonblocking" ); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} #ifdef DYNAMIC printf(" Stringspace: %d\n", zsetfil(0,2)); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf(" Listsize: %d\n", zsetfil(0,4)); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} #endif /* DYNAMIC */ #endif /* UNIX */ #ifdef CKMAXNAM printf(" Longest filename: %d\n", CKMAXNAM); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} #endif /* def CKMAXNAM */ #ifdef CKMAXPATH printf(" Longest pathname: %d\n", CKMAXPATH); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} #endif /* def CKMAXPATH */ printf(" Last file sent: %s\n", sfspec ? sfspec : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf(" Last file received: %s\n", rfspec ? rfspec : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf("\n Also see:\n"); n++; if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf(" SHOW PROTOCOL, SHOW XFER"); #ifdef CK_LABELED printf(", SHOW LABELED"); #endif /* CK_LABELED */ #ifdef PATTERNS printf(", SHOW PATTERNS"); #endif /* PATTERNS */ #ifdef STREAMING printf(", SHOW STREAMING"); #endif /* STREAMING */ #ifndef NOCSETS printf(", SHOW CHARACTER-SETS"); #endif /* NOCSETS */ printf("\n\n"); } #ifndef NOXFER VOID shoparp() { /* Protocol */ extern int docrc, skipbup; char *s; #ifdef CK_TIMERS extern int rttflg; #endif /* CK_TIMERS */ printf("Protocol: %s\n",ptab[protocol].p_name); if (protocol == PROTO_K) { printf("\nProtocol Parameters: Send Receive"); if (timef) printf("\n Timeout (used=%2d):%7d*%8d ", timint, rtimo, pkttim); else printf("\n Timeout (used=%2d):%7d%9d ", timint, rtimo, pkttim); #ifdef XFRCAN printf(" Cancellation: %s",showoff(xfrcan)); if (xfrcan) printf(" %d %d", xfrchr, xfrnum); #endif /* XFRCAN */ printf("\n Padding: %11d%9d", npad, mypadn); if (bctr == 4) printf(" Block Check: blank-free-2\n"); else printf(" Block Check: %6d\n",bctr); printf( " Pad Character:%11d%9d", padch, mypadc); printf(" Delay: %6d\n",ckdelay); printf( " Pause: %11d%9d", pktpaus, pktpaus); printf(" Attributes: %s\n",showoff(atcapr)); printf( " Packet Start: %11d%9d", mystch, stchr); printf(" Max Retries: %6d%s\n", maxtry, (maxtry == 0) ? " (unlimited)" : "" ); printf( " Packet End: %11d%9d", seol, eol); if (ebqflg) printf(" 8th-Bit Prefix: '%c'",ebq); else printf(" 8th-Bit Prefix: ('%c' but not used)",ebq); printf( "\n Packet Length:%11d ", spmax); printf("%8d ", urpsiz); if (rptflg) printf(" Repeat Prefix: '%c'",rptq); else printf(" Repeat Prefix: ('%c' but not used)",rptq); printf( "\n Maximum Length: %9d%9d", maxsps, maxrps); printf(" Window Size:%7d set, %d used\n",wslotr,wmax); printf( " Buffer Size: %11d%9d", bigsbsiz, bigrbsiz); printf(" Locking-Shift: "); if (lscapu == 2) { printf("forced"); } else { printf("%s", (lscapr ? "enabled" : "disabled")); if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used"); } printf("\n\n"); if (!(s = ptab[protocol].h_b_init)) s = ""; printf(" Auto-upload command (binary): "); if (*s) { shostrdef((CHAR *)s); printf("\n"); } else { printf("(none)\n"); } if (!(s = ptab[protocol].h_t_init)) s = ""; printf(" Auto-upload command (text): "); if (*s) { shostrdef((CHAR *)s); printf("\n"); } else { printf("(none)\n"); } if (!(s = ptab[protocol].h_x_init)) s = ""; printf(" Auto-server command: "); if (*s) { shostrdef((CHAR *)s); printf("\n"); } else { printf("(none)\n"); } tmpbuf[0] = NUL; #ifdef CK_TIMERS if (rttflg) { extern int mintime, maxtime; sprintf(tmpbuf," Packet timeouts: dynamic %d:%d", /* SAFE */ mintime, maxtime); } else { sprintf(tmpbuf," Packet timeouts: fixed"); /* SAFE */ } #endif /* CK_TIMERS */ if (tmpbuf[0]) printf("%-31s",tmpbuf); printf("Send backup: %s\n",showoff(!skipbup)); printf(" Transfer mode: %s", xfermode == XMODE_A ? "automatic " : "manual " ); printf(" Transfer slow-start: %s, crc: %s\n", showoff(slostart), showoff(docrc) ); #ifdef PIPESEND { extern int usepipes; printf(" Transfer pipes: %s ",usepipes ? "on " : "off"); } #endif /* PIPESEND */ #ifndef NOCSETS printf(" Transfer character-set: "); if (tcharset == TC_TRANSP) printf("transparent\n"); else printf("%s\n", tcsinfo[tcharset].keyword ); #endif /* NOCSETS */ #ifdef PIPESEND { extern char * sndfilter, * rcvfilter; printf(" Send filter: %s\n", sndfilter ? sndfilter : "(none)"); printf(" Receive filter: %s\n", rcvfilter ? rcvfilter : "(none)"); } #endif /* PIPESEND */ printf("\nAlso see:\n"); printf(" SHOW FILE, SHOW XFER"); #ifdef CK_LABELED printf(", SHOW LABELED"); #endif /* CK_LABELED */ #ifdef PATTERNS printf(", SHOW PATTERNS"); #endif /* PATTERNS */ #ifdef STREAMING printf(", SHOW STREAMING"); #endif /* STREAMING */ #ifndef NOCSETS printf(", SHOW CHARACTER-SETS"); #endif /* NOCSETS */ } #ifdef CK_XYZ #ifdef XYZ_INTERNAL if (protocol != PROTO_K) { int i; int x; printf(" File type: %s\n", binary ? "binary" : "text"); if (protocol == PROTO_Z) { /* Zmodem */ printf(" Window size: "); if (ptab[protocol].winsize < 1) printf("none\n"); else printf("%d\n",wslotr); #ifdef COMMENT printf(" Packet (frame) length: "); if (ptab[protocol].spktlen < 0) printf("none\n"); else printf("%d\n",spmax); #endif /* COMMENT */ } else { if (ptab[protocol].spktlen >= 1000) printf(" 1K packets\n"); else printf(" 128-byte packets\n"); } printf(" Pathname stripping when sending: %s\n", showoff(ptab[protocol].fnsp) ); printf(" Pathname stripping when receiving: %s\n", showoff(ptab[protocol].fnrp) ); printf(" Filename collision action: "); for (i = 0; i < ncolx; i++) if (colxtab[i].kwval == fncact) break; printf("%-12s", (i == ncolx) ? "unknown" : colxtab[i].kwd); printf("\n Escape control characters: "); x = ptab[protocol].prefix; if (x == PX_ALL) printf("all\n"); else if (x == PX_CAU || x==PX_WIL) printf("minimal\n"); else printf("none\n"); if (!(s = ptab[protocol].h_b_init)) s = ""; printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)"); if (!(s = ptab[protocol].h_t_init)) s = ""; printf(" Autoreceive command (text): %s\n", *s ? s : "(none)"); } #else #ifndef NOPUSH if (protocol != PROTO_K) { _PROTOTYP( VOID shoextern, (void) ); printf("\nExecuted by external commands:\n\n"); s = ptab[protocol].p_b_scmd; if (!s) s = ""; printf(" SEND command (binary): %s\n", *s ? s : "(none)"); s = ptab[protocol].p_t_scmd; if (!s) s = ""; printf(" SEND command (text): %s\n", *s ? s : "(none)"); s = ptab[protocol].p_b_rcmd; if (!s) s = ""; printf(" RECEIVE command (binary): %s\n", *s ? s : "(none)"); s = ptab[protocol].p_t_rcmd; if (!s) s = ""; printf(" RECEIVE command (text): %s\n", *s ? s : "(none)"); s = ptab[protocol].h_b_init; if (!s) s = ""; printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)"); s = ptab[protocol].h_t_init; if (!s) s = ""; printf(" Autoreceive command (text): %s\n", *s ? s : "(none)"); (VOID) shoextern(); } #endif /* NOPUSH */ #endif /* XYZ_INTERNAL */ #endif /* CK_XYZ */ } #endif /* NOXFER */ #ifndef NOCSETS /* Character-set items */ extern int s_cset, r_cset, axcset[], afcset[]; extern struct keytab xfrmtab[]; VOID shoparl() { #ifdef COMMENT int i; /* Misleading... */ printf("\nAvailable Languages:\n"); for (i = 0; i < MAXLANG; i++) { printf(" %s\n",langs[i].description); } #else printf("\nLanguage-specific translation rules: %s\n", language == L_USASCII ? "none" : langs[language].description); shocharset(); printf("\n\n"); #endif /* COMMENT */ } VOID shocharset() { int x; #ifdef COMMENT char * s = "Unknown"; extern int xlatype; #endif /* COMMENT */ #ifndef NOXFER extern int xfrxla; #endif /* NOXFER */ debug(F101,"SHOW FILE CHAR","",fcharset); printf("\n"); #ifndef NOXFER printf(" Transfer Translation: %s\n", showoff(xfrxla)); if (!xfrxla) { printf( " Because transfer translation is off, the following are ignored:\n\n"); } #endif /* NOXFER */ printf(" File Character-Set: %s (%s), ", fcsinfo[fcharset].keyword, fcsinfo[fcharset].name ); if ((x = fcsinfo[fcharset].size) == 128) printf("7-bit"); else if (x == 256) printf("8-bit"); else printf("multibyte"); printf("\n"); printf(" File Scan: %s\n",showoff(filepeek)); printf(" Default 7bit-Character-Set: %s\n",fcsinfo[dcset7].keyword); printf(" Default 8bit-Character-Set: %s\n",fcsinfo[dcset8].keyword); printf(" Transfer Character-Set"); #ifdef COMMENT if (tslevel == TS_L2) printf(": (international)"); else #endif /* COMMENT */ if (tcharset == TC_TRANSP) printf(": Transparent"); else printf(": %s (%s)",tcsinfo[tcharset].keyword, tcsinfo[tcharset].name); printf("\n"); #ifdef COMMENT switch (xlatype) { case XLA_NONE: s = "None"; break; case XLA_BYTE: s = "Byte"; break; case XLA_JAPAN: s = "Japanese"; break; case XLA_UNICODE: s = "Unicode"; break; } printf("\n Translation type: %s\n",s); #endif /* COMMENT */ printf(" SEND character-set-selection: %s\n",xfrmtab[s_cset].kwd); printf(" RECEIVE character-set-selection: %s\n",xfrmtab[r_cset].kwd); if (s_cset == XMODE_A || r_cset == XMODE_A) printf( " (Use SHOW ASSOCIATIONS to list automatic character-set selections.)\n" ); } VOID showassoc() { int i, k, n = 4; char * s; printf("\nFor incoming files:\n\n"); printf("Transfer Character-Set File Character-Set\n"); for (i = 1; i <= MAXTCSETS; i++) { k = axcset[i]; if (k < 0 || k > MAXFCSETS) s = "(none)"; else s = fcsinfo[k].keyword; if (!s) s = ""; if (!*s) s = "(none)"; printf(" %-25s%s\n",tcsinfo[i].keyword,s); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} } printf("\nFor outbound files:\n\n"); n += 2; if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} printf("File Character-Set Transfer Character-Set\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} for (i = 0; i <= MAXFCSETS; i++) { k = afcset[i]; if (k < 0 || k > MAXTCSETS) s = "(none)"; else s = tcsinfo[k].keyword; if (!s) s = ""; if (!*s) s = "(none)"; printf(" %-25s%s\n",fcsinfo[i].keyword,s); if (++n > cmd_rows - 3) { if (!askmore()) { return;} else {n = 0;}} } } #endif /* NOCSETS */ VOID shopar() { printf("Show what? (Type \"show ?\" for a list of possibilities.)\n"); } #endif /* NOSHOW */ #ifndef NOXFER /* D O S T A T -- Display file transfer statistics. */ int #ifdef CK_ANSIC dostat( int brief ) #else dostat(brief) int brief; #endif /* CK_ANSIC */ { extern long filrej, peakcps; extern int lastspmax, streamed, cleared, streamok; extern char whoareu[]; int n = 0, ftp = 0; extern int docrc, interrupted, fatalio; ftp = lastxfer & W_FTP; #ifdef CK_TTGWSIZ #ifdef OS2 if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0) ttgwsiz(); #else /* OS2 */ if (ttgwsiz() > 0) { if (tt_rows > 0 && tt_cols > 0) { cmd_rows = tt_rows; cmd_cols = tt_cols; } } #endif /* OS2 */ #endif /* CK_TTGWSIZ */ debug(F101,"dostat xferstat","",xferstat); if (xferstat < 0) { printf(" No file transfers yet.\n"); return(1); } n = 0; if (brief) { printf("\n"); n++; }; printf(" protocol : %s\n", ftp ? "ftp" : ptab[protocol].p_name); n++; printf(" status : "); if (xferstat) printf("SUCCESS\n"); else if (interrupted) printf("FAILURE (interrupted)\n"); else if (fatalio) printf("FAILURE (i/o error)\n"); else printf("FAILURE\n"); #ifndef XYZ_INTERNAL if (!ftp && protocol != PROTO_K) { printf("\n external protocol statistics not available\n"); return(1); } #endif /* XYZ_INTERNAL */ n++; if (!ftp) { if (xferstat > 0) { /* Transfer OK - show CRC */ if (docrc) printf(" crc-16 of file(s) : %ld\n", crc16); else printf(" crc-16 of file(s) : (disabled)\n"); n++; } if ((xferstat == 0) && *epktmsg) { /* Transfer failed */ printf(" reason : %s\n", epktmsg); n++; } } if (!brief) { #ifdef NEWFTP if (ftp) { extern char ftp_srvtyp[]; printf(" remote system type : %s\n",ftp_srvtyp); } else #endif /* NEWFTP */ if (whoareu[0]) { printf(" remote system type : %s\n", getsysid((char *)whoareu)); n++; } printf(" files transferred : %ld\n",filcnt - filrej); if (!ftp) printf(" files not transferred : %ld\n",filrej); printf(" characters last file : %s\n",ckfstoa(ffc)); printf(" total file characters : %s\n",ckfstoa(tfc)); n += ftp ? 3 : 4; if (!ftp) { printf(" communication line in : %s\n",ckfstoa(tlci)); printf(" communication line out : %s\n",ckfstoa(tlco)); printf(" packets sent : %d\n", spackets); printf(" packets received : %d\n", rpackets); n += 4; } } if (ftp) goto dotimes; printf(" damaged packets rec'd : %d\n", crunched); printf(" timeouts : %d\n", timeouts); printf(" retransmissions : %d\n", retrans); n += 3; if (!brief) { if (filcnt > 0) { printf(" parity : %s",parnam((char)parity)); n++; if (autopar) { printf(" (detected automatically)"); n++; } printf( "\n control characters : %ld prefixed, %ld unprefixed\n", ccp, ccu); n++; printf(" 8th bit prefixing : "); n++; if (ebqflg) printf("yes [%c]\n",ebq); else printf("no\n"); n++; printf(" locking shifts : %s\n", lscapu ? "yes" : "no"); n++; } } if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; } if (streamed > 0) printf(" window slots used : (streaming)\n"); else printf(" window slots used : %d of %d\n", wmax, wslotr); if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; } printf(" reliable: : %s%s\n", streamok ? "" : "not ", "negotiated"); if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; } printf(" clearchannel: : %s%s\n", cleared ? "" : "not ", "negotiated"); if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; } if (!brief) { printf(" packet length : %d (send), %d (receive)\n", lastspmax, urpsiz); if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; } printf(" compression : "); if (rptflg) printf("yes [%c] (%ld)\n",(char) rptq,rptn); else printf("no\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; } if (bctu == 4) printf(" block check type used : blank-free-2\n"); else printf(" block check type used : %d\n",bctu); if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; } } dotimes: #ifdef GFTIMER #ifdef COMMENT printf(" elapsed time : %0.3f sec, %s\n", fptsecs,hhmmss(tsecs)); #endif /* COMMENT */ printf(" elapsed time : %s (%0.3f sec)\n", hhmmss((long)(fptsecs + 0.5)),fptsecs); #else #ifdef COMMENT printf(" elapsed time : %s (%d sec)\n",hhmmss(tsecs),tsecs); #endif /* COMMENT */ printf(" elapsed time : %d sec, %s\n",tsecs,hhmmss(tsecs)); #endif /* GFTIMER */ if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; } if (!ftp && local && !network && !brief) { if (speed <= 0L) speed = ttgspd(); if (speed > 0L) { if (speed == 8880) printf(" transmission rate : 75/1200 bps\n"); else printf(" transmission rate : %ld bps\n",speed); if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; } } } if (!ftp && local && !network && /* Only makes sense for */ mdmtyp == 0 && /* direct serial connections */ speed > 99L && /* when we really know the speed */ speed != 8880L ) { int eff; eff = (((tfcps * 100L) / (speed / 100L)) + 5L) / 10L; printf(" effective data rate : %ld cps (%d%%)\n",tfcps,eff); } else printf(" effective data rate : %ld cps\n", tfcps); if (!ftp && peakcps > 0L && peakcps > tfcps) printf(" peak data rate : %ld cps\n", peakcps); if (brief) printf("\nUse STATISTICS /VERBOSE for greater detail.\n\n"); return(1); } #endif /* NOXFER */ #ifndef NOSPL /* The INPUT command */ /* NOTE: An INPUT timeout of 0 means to perform a nonblocking read of the material that has already arrived and is waiting to be read, and perform matches against it, without doing any further reads. It should succeed or fail instantaneously. */ /* Output buffering for "doinput" */ #ifdef pdp11 #define MAXBURST 16 /* Maximum size of input burst */ #else #define MAXBURST 1024 #endif /* pdp11 */ #ifdef OSK static CHAR *conbuf; /* Buffer to hold output for console */ #else static CHAR conbuf[MAXBURST]; /* Buffer to hold output for console */ #endif /* OSK */ static int concnt = 0; /* Number of characters buffered */ #ifdef OSK static CHAR *sesbuf; /* Buffer to hold output for session log */ #else static CHAR sesbuf[MAXBURST]; /* Buffer to hold output for session log */ #endif /* OSK */ static int sescnt = 0; /* Number of characters buffered */ extern int debses; /* TERMINAL DEBUG ON/OFF */ static VOID /* Flush INPUT echoing */ myflsh() { /* and session log output. */ if (concnt > 0) { if (debses) { /* Terminal debugging? */ int i; for (i = 0; i < concnt; i++) conol(dbchr(conbuf[i])); } else conxo(concnt, (char *) conbuf); concnt = 0; } if (sescnt > 0) { logstr((char *) sesbuf, sescnt); sescnt = 0; } } /* Execute the INPUT and MINPUT commands */ int instatus = -1; long inetime = -1L; int inwait = 0; int nowrap = 0; /* For returning the input sequence that matched */ #ifdef BIGBUFOK #define MATCHBUFSIZ 8191 #else #define MATCHBUFSIZ 1023 #endif /* BIGBUFOK */ static char * matchbuf = NULL; static int matchindex = 0; static int burst = 0; /* Chars remaining in input burst */ /* timo = How long to wait: < 0 = Wait forever 0 = Don't wait at all - material must already have arrived > 0 = Wait this many seconds ms = Array of strings to wait for. mp = Array of flags. If mp[i] == 0, ms[i] is literal, else it's a pattern. flags = bit mask INPSW_NOM = /NOMATCH = 1 INPSW_CLR = /CLEAR = 2 INPSW_NOW = /NOWRAP = 4 INPSW_COU = /COUNT = 8 count = /COUNT: value if a /COUNT switch was given. Returns: 0 on failure, 1 on success. */ #ifndef ES_NORMAL #define ES_NORMAL 0 #endif /* ES_NORMAL */ extern int inesc[], oldesc[]; int #ifdef CK_ANSIC doinput(int timo, char *ms[], int mp[], int flags, int count ) #else doinput(timo,ms,mp,flags,count) int timo; char *ms[]; int mp[]; int flags; int count; #endif /* CK_ANSIC */ { extern int inintr; #ifdef CK_AUTODL extern int inautodl; #endif /* CK_AUTODL */ int x, y, i, t, rt, icn, anychar = 0, mi[MINPMAX]; #ifdef GFTIMER CKFLOAT fpt = 0.0; #endif /* GFTIMER */ int savecount = 0; int nomatch = 0; int clearfirst = 0; int lastchar = 0; int waiting = 0; int imask = 0; char *xp, *s; CHAR c; #ifndef NOLOCAL #ifdef OS2 extern int term_io; int term_io_save; #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef TNCODE static int cr = 0; #endif /* TNCODE */ int is_tn = 0; int noescseq = 0; /* Filter escape sequences */ #ifdef SSHBUILTIN const char* ssh_cmd; #endif debug(F101,"input count","",count); debug(F101,"input flags","",flags); /* CK_BURST enables the INPUT speedup code, which depends on ttchk() returning accurate information. If INPUT fails with this code enabled, change the above "#define" to "#undef". */ #define CK_BURST /***** CHANGE THIS TO A SET INPUT PARAMETER *****/ noescseq = (sessft == XYFT_T); /* Filter escape sequences */ imask = cmask; if (parity) imask = 0x7f; inwait = timo; /* For \v(inwait) */ /* Options from command switches */ nowrap = flags & INPSW_NOW; /* 4 = /NOWRAP */ nomatch = flags & INPSW_NOM; /* 1 = /NOMATCH */ clearfirst = flags & INPSW_CLR; /* 2 = /CLEAR */ savecount = count; makestr(&inpmatch,NULL); if (!matchbuf) { matchbuf = malloc(MATCHBUFSIZ+1); matchbuf[0] = NUL; } matchindex = 0; /* If last time through we returned because of /NOWRAP and buffer full */ /* now we have to clear the buffer to make room for another load. */ if (nowrap && instatus == INP_BF) clearfirst = 1; if (clearfirst) { /* INPUT /CLEAR */ int i; myflsh(); /* Flush screen and log buffers */ for (i = 0; i < inbufsize; i++) inpbuf[i] = NUL; inpbp = inpbuf; } is_tn = #ifdef TNCODE (local && network && IS_TELNET()) || (!local && sstelnet) #else 0 #endif /* TNCODE */ ; #ifdef CK_SSL if (is_tn) if (ssl_raw_flag || tls_raw_flag) is_tn = 0; #endif /* CK_SSL */ instatus = INP_IE; /* 3 = internal error */ kbchar = 0; #ifdef OSK if (conbuf == NULL) { if ((conbuf = (CHAR *)malloc(MAXBURST*2)) == NULL) { return(0); } sesbuf = conbuf + MAXBURST; } #endif /* OSK */ #ifndef NOLOCAL if (local) { /* In local mode... */ if ((waiting = ttchk()) < 0) { /* check that connection is open */ if (!quiet) { if ((!network #ifdef TN_COMPORT || istncomport() #endif /* TN_COMPORT */ ) && carrier != CAR_OFF) printf("?Carrier detect failure on %s.\n", ttname); else printf("?Connection %s %s is not open.\n", network ? "to" : "on", ttname ); } instatus = INP_IO; return(0); } debug(F101,"doinput waiting","",waiting); y = ttvt(speed,flow); /* Put line in "ttvt" mode */ if (y < 0) { printf("?INPUT initialization error\n"); instatus = INP_IO; return(0); /* Watch out for failure. */ } } #endif /* NOLOCAL */ #ifdef SSHBUILTIN ssh_cmd = ssh_get_sparam(SSH_SPARAM_CMD); if ( network && nettype == NET_SSH && ssh_get_iparam(SSH_IPARAM_CAS) && ssh_cmd && !(strcmp(ssh_cmd,"kermit") && strcmp(ssh_cmd,"sftp"))) { if (!quiet) printf("?SSH Subsystem active: %s\n", ssh_cmd); instatus = INP_IKS; return(0); } #endif /* SSHBUILTIN */ debug(F111,"doinput ms[0]",ms[0],waiting); if (!ms[0] || isemptystring(ms[0])) { /* No search string was given nor */ if (count < 2) /* a /COUNT: switch so we just */ anychar = 1; /* wait for the first character */ } if (nomatch) anychar = 0; /* Don't match anything */ if (!anychar && waiting == 0 && timo == 0) return(0); #ifndef NODEBUG if (deblog) { char xbuf[100]; debug(F101,"doinput anychar","",anychar); debug(F101,"doinput timo","",timo); debug(F101,"doinput echo","",inecho); #ifdef CK_BURST debug(F101,"doinput burst","",burst); #endif /* CK_BURST */ y = -1; while (ms[++y]) { sprintf(xbuf,"doinput string %2d",y); /* SAFE (24) */ debug(F111,xbuf,ms[y],mp[y]); } } #endif /* NODEBUG */ #ifdef IKS_OPTION if (is_tn) { /* If the remote side is in a state of IKS START-SERVER */ /* we request that the state be changed. We will detect */ /* a failure to adhere to the request when we call ttinc() */ if (TELOPT_U(TELOPT_KERMIT) && TELOPT_SB(TELOPT_KERMIT).kermit.u_start) iks_wait(KERMIT_REQ_STOP,0); /* Send Request-Stop */ #ifdef CK_AUTODL /* If we are processing packets during INPUT and we have not */ /* sent a START message, do so now. */ if (inautodl && TELOPT_ME(TELOPT_KERMIT) && !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) { tn_siks(KERMIT_START); /* Send Kermit-Server Start */ } #endif /* CK_AUTODL */ } #endif /* IKS_OPTION */ x = 0; /* Return code, assume failure */ instatus = INP_TO; /* Status, assume timeout */ for (y = 0; y < MINPMAX; y++) /* Initialize... */ mi[y] = 0; /* ..string pattern match position */ if (!inpcas[cmdlvl]) { /* INPUT CASE = IGNORE? */ y = -1; while ((xp = ms[++y])) { /* Convert each target to lowercase */ while (*xp) { if (isupper(*xp)) *xp = (char) tolower(*xp); xp++; } } } rtimer(); /* Reset timer. */ #ifdef GFTIMER rftimer(); /* Floating-point timer too. */ #endif /* GFTIMER */ inetime = -1L; /* Initialize elapsed time. */ t = 0; /* Time now is 0. */ m_found = 0; /* Default to timed-out */ incount = 0; /* Character counter */ rt = (timo == 0) ? 0 : 1; /* Character-read timeout interval */ #ifndef NOLOCAL #ifdef OS2 term_io_save = term_io; /* Disable I/O by emulator */ term_io = 0; #endif /* OS2 */ #endif /* NOLOCAL */ while (1) { /* Character-getting loop */ #ifdef CK_APC /* Check to see if there is an Autodown or other APC command */ if (apcactive == APC_LOCAL || (apcactive == APC_REMOTE && apcstatus != APC_OFF)) { if (mlook(mactab,"_apc_commands",nmac) == -1) { debug(F110,"doinput about to execute APC",apcbuf,0); domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC); delmac("_apc_commands",1); apcactive = APC_INACTIVE; #ifdef DEBUG } else { debug(F100,"doinput APC in progress","",0); #endif /* DEBUG */ } } #endif /* CK_APC */ if (timo == 0 && waiting < 1) { /* Special exit criterion */ instatus = INP_TO; /* for timeout == 0 */ break; } if (local) { /* One case for local */ y = ttinc(rt); /* Get character from comm device */ debug(F101,"doinput ttinc(rt) returns","",y); if (y < -1) { /* Connection failed. */ instatus = INP_IO; /* Status = i/o error */ #ifndef NOLOCAL #ifdef OS2 term_io = term_io_save; #endif /* OS2 */ #endif /* NOLOCAL */ switch (y) { case -2: /* Connection lost */ if (local && !network && carrier != CAR_OFF) { dologend(); printf("Connection closed.\n"); ttclos(1); } break; case -3: dologend(); printf("Session Limit exceeded - closing connection.\n"); ttclos(1); default: break; } debug(F111,"doinput Connection failed","returning 0",y); return(0); } if (inintr) { debug(F111,"doinput","inintr",inintr); if ((icn = conchk()) > 0) { /* Interrupted from keyboard? */ debug(F101,"input interrupted from keyboard","",icn); kbchar = coninc(0); if (kbchar >= 0) { while (--icn > 0) { debug(F110,"doinput","absorbing",0); coninc(0); /* Yes, absorb what was typed. */ } instatus = INP_UI; /* Fail and remember why. */ break; } } } } else { /* Another for remote */ y = coninc(rt); debug(F101,"doinput coninc(rt) returns","",y); } if (y > -1) { /* A character arrived */ debug(F111,"doinput","a character arrived",y); if (timo == 0) waiting--; #ifndef OS2 #define TN_NOLO #endif /* OS2 */ #ifdef NOLOCAL #define TN_NOLO #endif /* NOLOCAL */ #ifdef TN_NOLO debug(F100,"doinput TN_NOLO","",0); #ifdef TNCODE /* Check for telnet protocol negotiation */ if (is_tn) { switch (y & 0xff) { case IAC: cr = 0; myflsh(); /* Break from input burst for tn_doop() */ #ifdef CK_BURST burst = 0; #endif /* CK_BURST */ waiting -= 2; /* (not necessarily...) */ switch (tn_doop((CHAR)(y & 0xff),duplex,ttinc)) { case 2: duplex = 0; continue; case 1: duplex = 1; continue; #ifdef IKS_OPTION case 4: if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start && !tcp_incoming) { instatus = INP_IKS; printf( " Internet Kermit Service in SERVER mode.\n Please use REMOTE commands.\n" ); break; } continue; #endif /* IKS_OPTION */ case 6: /* TELNET DO LOGOUT received */ continue; case 7: case 3: /* A quoted IAC */ break; default: continue; } case CK_CR: cr = 1; break; case NUL: if (!TELOPT_U(TELOPT_BINARY) && cr) { cr = 0; continue; } cr = 0; break; default: cr = 0; } /* I'm echoing remote chars */ if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo) ttoc((char)y); } #endif /* TNCODE */ #ifdef CK_AUTODL /* Check for file transfer packets */ if (inautodl) autodown(y); #endif /* CK_AUTODL */ #else /* TN_NOLO */ debug(F100,"doinput !TN_NOLO","",0); #ifdef TNCODE /* Check for telnet protocol negotiation */ if (is_tn) { int tx; switch (y & 0xff) { case IAC: myflsh(); /* Break from input burst for tn_doop() */ #ifdef CK_BURST burst = 0; #endif /* CK_BURST */ #ifdef IKS_OPTION tx = scriptwrtbuf((USHORT)y); if (tx == 4) { if (TELOPT_U(TELOPT_KERMIT) && TELOPT_SB(TELOPT_KERMIT).kermit.u_start && !tcp_incoming ) { instatus = INP_IKS; printf( " Internet Kermit Service in SERVER mode.\n Please use REMOTE commands.\n" ); break; } } else if (tx == 6) { /* TELNET DO LOGOUT received */ } #else /* IKS_OPTION */ /* Handles Telnet negotiations */ tx = scriptwrtbuf((USHORT)y); if (tx == 6) { /* TELNET DO LOGOUT received */ } #endif /* IKS_OPTION */ waiting -= 2; /* (not necessarily...) */ cr = 0; continue; /* and autodownload check */ case CK_CR: cr = 1; tx = scriptwrtbuf((USHORT)y); if (tx == 6) { /* TELNET DO LOGOUT received */ } break; case NUL: cr = 0; if (!TELOPT_U(TELOPT_BINARY) && cr) continue; tx = scriptwrtbuf((USHORT)y); if (tx == 6) { /* TELNET DO LOGOUT received */ } break; default: cr = 0; tx = scriptwrtbuf((USHORT)y); if (tx == 6) { /* TELNET DO LOGOUT received */ } } /* I'm echoing remote chars */ if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo) ttoc((CHAR)y); } else #endif /* TNCODE */ /* Handles terminal emulation responses */ scriptwrtbuf((USHORT)y); #endif /* TN_NOLO */ /* Real input character to be checked */ #ifdef CK_BURST burst--; /* One less character waiting */ debug(F101,"doinput burst","",burst); #endif /* CK_BURST */ c = (CHAR) (imask & (CHAR) y); /* Mask off any parity */ inchar[0] = c; /* Remember character for \v(inchar) */ #ifdef COMMENT #ifdef CK_BURST /* Update "lastchar" time only once during input burst */ if (burst <= 0) #endif /* CK_BURST */ #endif /* COMMENT */ lastchar = gtimer(); /* Remember when it came */ if (c == '\0') { /* NUL, we can't use it */ if (anychar) { /* Except if any character will do? */ x = 1; /* Yes, done. */ instatus = INP_OK; incount = 1; /* This must be the first and only. */ break; } else goto refill; /* Otherwise continue INPUTting */ } *inpbp++ = c; /* Store char in circular buffer */ incount++; /* Count it for \v(incount) */ if (flags & INPSW_COU) { /* INPUT /COUNT */ if (--count < 1) { x = 1; instatus = INP_OK; incount = savecount; break; } } if (matchbuf) { if (matchindex < MATCHBUFSIZ) { matchbuf[matchindex++] = c; matchbuf[matchindex] = NUL; } } #ifdef MAC { extern char *ttermw; /* fake pointer cast */ if (inecho) { outchar(ttermw, c); /* echo to terminal window */ /* this might be too much overhead to do here ? */ updatecommand(ttermw); } } #else /* Not MAC */ if (inecho) { /* Buffer console output */ conbuf[concnt++] = c; } #endif /* MAC */ #ifndef OS2 if (seslog) { int dummy = 0, skip = 0; #ifndef NOLOCAL if (noescseq) { dummy = chkaes(c,0); if (inesc[0] != ES_NORMAL || oldesc[0] != ES_NORMAL) skip = 1; } #endif /* NOLOCAL */ #ifdef UNIXOROSK if (sessft == XYFT_T) { #ifdef UNIX if (c == '\r') #else #ifdef OSK if (c == '\012') #endif /* OSK */ #endif /* UNIX */ skip = 1; } #endif /* UNIXOROSK */ if (!skip) sesbuf[sescnt++] = c; /* Buffer session log output */ } #endif /* OS2 */ if (anychar) { /* Any character will do? */ x = 1; instatus = INP_OK; break; } if (!inpcas[cmdlvl]) { /* Ignore alphabetic case? */ if (isupper(c)) /* Yes, convert input char to lower */ c = (CHAR) tolower(c); } debug(F000,"doinput char","",c); /* Here is the matching section */ y = -1; /* Loop thru search strings */ while (!nomatch && (s = ms[++y])) { /* ...as many as we have. */ if (mp[y]) { /* Pattern match? */ #ifdef COMMENT int j; /* This is gross but it works... */ /* We could just as easily have prepended '*' to the */ /* pattern and skipped the loop, except then we would */ /* not have any way to identify the matching string. */ for (j = 0; j < matchindex; j++) { if (ckmatch(s,&matchbuf[j],1,1)) { matchindex = j; instatus = INP_OK; x = 1; break; } } if (x > 0) break; #else /* July 2001 - ckmatch() returns match position. */ /* It works and it's not gross. */ /* (4 = floating pattern) */ x = ckmatch(s,matchbuf,inpcas[cmdlvl],1+4); if (x > 0) { matchindex = x - 1; instatus = INP_OK; x = 1; break; } #endif /* COMMENT */ continue; } /* Literal match. */ i = mi[y]; /* Match-position in search string. */ debug(F000,"compare char","",(CHAR)s[i]); if (c == (CHAR) s[i]) { /* Check for match */ i++; /* Got one, go to next character */ } else { /* Don't have a match */ int j; for (j = i; i > 0; ) { /* Back up in search string */ i--; /* (Do this here to prevent compiler foulup) */ /* j is the length of the substring that matched */ if (c == (CHAR) s[i]) { if (!strncmp(s,&s[j-i],i)) { i++; /* c actually matches -- cfk */ break; } } } } if ((CHAR) s[i] == (CHAR) '\0') { /* Matched to end? */ ckstrncpy(matchbuf,ms[y],MATCHBUFSIZ); matchindex = 0; instatus = INP_OK; /* Yes, */ x = 1; break; /* done. */ } mi[y] = i; /* No, remember match-position */ } if (x == 1) { /* Set \v(minput) result */ instatus = INP_OK; m_found = y + 1; break; } if (inpbp >= inpbuf + inbufsize) { /* Reached end of buffer? */ if (nowrap) { /* If /NOWRAP...*/ instatus = INP_BF; /* ...return indicating buffer full. */ *inpbp = NUL; goto xinput; } *inpbp = NUL; /* Make it null-terminated */ inpbp = inpbuf; /* Yes. */ } } #ifdef CK_BURST else if (y <= -1 && burst > 0) { debug(F111,"doinput (y<=-1&&burst>0)","burst",burst); /* A timeout occurred so there can't */ burst = 0; /* be data waiting; must check timo */ } refill: if (burst <= 0) { /* No buffered chars remaining... */ myflsh(); /* Flush buffered output */ if (local) { /* Get size of next input burst */ burst = ttchk(); if (burst < 0) { /* ttchk() says connection is closed */ instatus = INP_IO; /* Status = i/o error */ #ifndef NOLOCAL #ifdef OS2 term_io = term_io_save; #endif /* OS2 */ #endif /* NOLOCAL */ if ((!network #ifdef TN_COMPORT || istncomport() #endif /* TN_COMPORT */ ) && carrier != CAR_OFF) { /* The test is written this way because the Microsoft compiler * is producing bad code if written: * * if (network && (!istncomport() || carrier == CAR_OFF) ) */ break; } else { printf("Fatal error - disconnected.\n"); ttclos(1); break; } } if (inintr) { if ((icn = conchk()) > 0) { /* Interrupt from keyboard? */ kbchar = coninc(0); debug(F101,"input interrupted from keyboard","",icn); while (--icn > 0) coninc(0); /* Yes, absorb chars. */ break; /* And fail. */ } } } else { burst = conchk(); } debug(F101,"doinput burst","",burst); /* Prevent overflow of "conbuf" and "sesbuf" */ if (burst > MAXBURST) burst = MAXBURST; /* Did not match, timer exceeded? */ t = gtimer(); debug(F111,"doinput gtimer","burst",t); debug(F101,"doinput timo","",timo); if ((t >= timo) && (timo > 0)) break; else if (insilence > 0 && (t - lastchar) > insilence) break; } else { debug(F111,"doinput (burst > 0)","burst",burst); } #else /* CK_BURST */ refill: myflsh(); /* Flush buffered output */ /* Did not match, timer exceeded? */ t = gtimer(); debug(F111,"doinput gtimer","no burst",t); debug(F101,"doinput timo","",timo); if ((t >= timo) && (timo > -1)) break; else if (insilence > 0 && (t - lastchar) > insilence) break; #endif /* CK_BURST */ } /* Still have time left, continue. */ xinput: myflsh(); /* Flush buffered output */ if (instatus == INP_BF) { /* Buffer full and /NOWAIT */ x = 0; /* Must not succeed */ } else { /* Buffer full and /NOWAIT */ if (nomatch) x = 1; /* Succeed if nomatch and timed out */ if (x > 0 && !nomatch) instatus = 0; } #ifndef NOLOCAL #ifdef OS2 term_io = term_io_save; #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef COMMENT #ifdef IKS_OPTION #ifdef CK_AUTODL if (is_tn && TELOPT_ME(TELOPT_KERMIT) && inautodl) { tn_siks(KERMIT_STOP); /* Send Kermit-Server Stop */ } #endif /* CK_AUTODL */ #endif /* IKS_OPTION */ #endif /* COMMENT */ #ifdef GFTIMER fpt = gftimer(); /* Get elapsed time */ /* If a long is 32 bits, it would take about 50 days for this to overflow. */ inetime = (int)(fpt * (CKFLOAT)1000.0); #else inetime = (int)(gtimer() * 1000); #endif /* GFTIMER */ if (x > 0) makestr(&inpmatch,&matchbuf[matchindex]); /* \v(inmatch) */ return(x); /* Return the return code. */ } #endif /* NOSPL */ #ifndef NOSPL /* REINPUT Command */ /* Note, the timeout parameter is required, but ignored. Syntax is compatible with MS-DOS Kermit except timeout can't be omitted. This function only looks at the characters already received and does not read any new characters from the connection. */ int #ifdef CK_ANSIC doreinp( int timo, char *s, int pat ) #else doreinp(timo,s,pat) int timo; char *s; int pat; #endif /* CK_ANSIC */ { int x, y, i; char *xx, *xp, *xq = (char *)0; CHAR c; if (!s) s = ""; debug(F101,"doreinput pat","",pat); y = (int)strlen(s); debug(F111,"doreinput search",s,y); if (y > inbufsize) { /* If search string longer than */ debug(F101,"doreinput inbufsize","",inbufsize); return(0); /* input buffer, fail. */ } makestr(&inpmatch,NULL); if (!matchbuf) matchbuf = malloc(MATCHBUFSIZ+1); matchindex = 0; x = 0; /* Return code, assume failure */ i = 0; /* String pattern match position */ if (!inpcas[cmdlvl]) { /* INPUT CASE = IGNORE? */ xp = malloc(y+2); /* Make a separate copy of the */ if (!xp) { /* search string. */ printf("?malloc error 6\n"); return(x); } else xq = xp; /* Keep pointer to beginning. */ while (*s) { /* Yes, convert to lowercase */ *xp = *s; if (isupper(*xp)) *xp = (char) tolower(*xp); xp++; s++; } *xp = NUL; /* Terminate it! */ s = xq; /* Move search pointer to it. */ } xx = *inpbp ? inpbp : inpbuf; /* Current INPUT buffer pointer */ do { c = *xx++; /* Get next character */ if (!c) break; if (xx >= inpbuf + inbufsize) /* Wrap around if necessary */ xx = inpbuf; if (!inpcas[cmdlvl]) { /* Ignore alphabetic case? */ if (isupper(c)) c = (CHAR) tolower(c); /* Yes */ } if (pat) { int j; if (matchbuf) { if (matchindex < MATCHBUFSIZ) { matchbuf[matchindex++] = c; matchbuf[matchindex] = NUL; } for (j = 0; j < matchindex; j++) { /* Gross but effective */ if (ckmatch(s,&matchbuf[j],1,1)) { debug(F101,"GOT IT","",j); matchindex = j; x = 1; break; } } } if (x > 0) break; continue; } debug(F000,"doreinp char","",c); debug(F000,"compare char","",(CHAR) s[i]); if (((char) c) == ((char) s[i])) { /* Check for match */ i++; /* Got one, go to next character */ } else { /* Don't have a match */ int j; for (j = i; i > 0; ) { /* [jrs] search backwards for it */ i--; if (((char) c) == ((char) s[i])) { if (!strncmp(s,&s[j-i],i)) { i++; break; } } } } /* [jrs] or return to zero from -1 */ if (s[i] == '\0') { /* Matched all the way to end? */ ckstrncpy(matchbuf,s,MATCHBUFSIZ); matchindex = 0; x = 1; /* Yes, */ break; /* done. */ } } while (xx != inpbp && x < 1); /* Until back where we started. */ if (!inpcas[cmdlvl]) if (xq) free(xq); /* Free this if it was malloc'd. */ makestr(&inpmatch,&matchbuf[matchindex]); /* \v(inmatch) */ return(x); /* Return search result. */ } /* X X S T R I N G -- Interpret strings containing backslash escapes */ /* Z Z S T R I N G -- (new name...) */ /* Copies result to new string. strips enclosing braces or doublequotes. interprets backslash escapes. returns 0 on success, nonzero on failure. tries to be compatible with MS-DOS Kermit. Syntax of input string: string = chars | "chars" | {chars} chars = (c*e*)* where c = any printable character, ascii 32-126 and e = a backslash escape and * means 0 or more repetitions of preceding quantity backslash escape = \operand operand = {number} | number | fname(operand) | v(name) | $(name) | m(name) number = [r]n[n[n]]], i.e. an optional radix code followed by 1-3 digits radix code is oO (octal), xX (hex), dD or none (decimal) (see xxesc()). */ #ifndef NOFRILLS int #ifdef CK_ANSIC yystring( char *s, char **s2 ) #else yystring(s,s2) char *s; char **s2; #endif /* CK_ANSIC */ { int x; static char *new; new = *s2; if (!s || !new) return(-1); /* Watch out for null pointers. */ if ((x = (int)strlen(s)) == 0) { /* Recursion done. */ *new = '\0'; return(0); } x--; /* Otherwise, call self */ *new++ = s[x]; /* to reverse rest of string. */ s[x] = 0; return(yystring(s,&new)); } #endif /* NOFRILLS */ static char ipabuf[16] = { NUL }; /* IP address buffer */ static char * #ifdef CK_ANSIC getip( char *s ) #else getip(s) char *s; #endif /* CK_ANSIC */ { char c=NUL; /* Workers... */ int i=0, p=0, d=0; int state = 0; /* State of 2-state FSA */ while ((c = *s++)) { switch(state) { case 0: /* Find first digit */ i = 0; /* Output buffer index */ ipabuf[i] = NUL; /* Initialize output buffer */ p = 0; /* Period counter */ d = 0; /* Digit counter */ if (isdigit(c)) { /* Have first digit */ d = 1; /* Count it */ ipabuf[i++] = c; /* Copy it */ state = 1; /* Change state */ } break; case 1: /* In numeric field */ if (isdigit(c)) { /* Have digit */ if (++d > 3) /* Too many */ state = 0; /* Start over */ else /* Not too many */ ipabuf[i++] = c; /* Keep it */ } else if (c == '.' && p < 3) { /* Have a period */ p++; /* Count it */ if (d == 0) /* Not preceded by a digit */ state = 0; /* Start over */ else /* OK */ ipabuf[i++] = c; /* Keep it */ d = 0; /* Reset digit counter */ } else if (p == 3 && d > 0) { /* Not part of address */ ipabuf[i] = NUL; /* If we have full IP address */ return((char *)ipabuf); /* Return it */ } else { /* Otherwise */ state = 0; /* Start over */ ipabuf[0] = NUL; /* (in case no more chars left) */ } } } /* Fall thru at end of string */ ipabuf[i] = NUL; /* Maybe we have one */ return((p == 3 && d > 0) ? (char *)ipabuf : ""); } #endif /* NOSPL */ /* Date Routines */ /* Z J D A T E -- Convert yyyymmdd date to Day of Year */ static int jdays[12] = { 0,31,59,90,120,151,181,212,243,273,304,334 }; static int ldays[12] = { 0,31,60,91,121,152,182,213,244,274,305,335 }; static char zjdbuf[12] = { NUL, NUL }; /* Deinde, ne in posterum a XII kalendas aprilis aequinoctium recedat, statuimus bissextum quarto quoque anno (uti mos est) continuari debere, praeterquam in centesimis annis; qui, quamvis bissextiles antea semper fuerint, qualem etiam esse volumus annum MDC, post eum tamen qui deinceps consequentur centesimi non omnes bissextiles sint, sed in quadringentis quibusque annis primi quique tres centesimi sine bissexto transigantur, quartus vero quisque centesimus bissextilis sit, ita ut annus MDCC, MDCCC, MDCCCC bissextiles non sint. Anno vero MM, more consueto dies bissextus intercaletur, februario dies XXIX continente, idemque ordo intermittendi intercalandique bissextum diem in quadringentis quibusque annis perpetuo conservetur. - Gregorius XIII, Anno Domini MDLXXXII. */ char * #ifdef CK_ANSIC zjdate( char * date ) /* date = yyyymmdd */ #else zjdate(date) char * date; #endif /* CK_ANSIC */ { char year[5]; char month[3]; char day[3]; int d, m, x, y; int leapday, j; char * time = NULL; if (!date) date = ""; /* Validate arg */ x = strlen(date); if (x < 1) return("0"); if (x < 8) return("-1"); for (x = 0; x < 8; x++) if (!isdigit(date[x])) return("-1"); if (date[8]) if (date[9]) time = date + 9; year[0] = date[0]; /* Isolate year */ year[1] = date[1]; year[2] = date[2]; year[3] = date[3]; year[4] = '\0'; month[0] = date[4]; /* Month */ month[1] = date[5]; month[2] = '\0';; day[0] = date[6]; /* And day */ day[1] = date[7]; day[2] = '\0'; leapday = 0; /* Assume no leap day */ y = atoi(year); m = atoi(month); d = atoi(day); if (m > 2) { /* No Leap day before March */ if (y % 4 == 0) { /* If year is divisible by 4 */ leapday = 1; /* It's a Leap year */ if (y % 100 == 0) { /* Except if divisible by 100 */ if (y % 400 != 0) /* but not by 400 */ leapday = 0; } } } j = jdays[m - 1] + d + leapday; /* Day of year */ if (time) sprintf(zjdbuf,"%04d%03d %s",y,j,time); /* SAFE */ else sprintf(zjdbuf,"%04d%03d",y,j); /* SAFE */ return((char *)zjdbuf); } static char jzdbuf[32]; /* J Z D A T E -- Convert Day of Year to yyyyddmm date */ char * #ifdef CK_ANSIC jzdate( char * date ) /* date = yyyyddd */ #else jzdate(date) char * date; #endif /* CK_ANSIC */ { char year[5]; /* with optional time */ char day[4]; char * time = NULL, * p; int d, m, x, y; int leapday, j; int * zz; if (!date) date = ""; /* Validate arg */ x = strlen(date); debug(F111,"jzdate len",date,x); if (x < 1) return("0"); if (x < 7) return("-1"); if (x > 8) time = date + 8; for (x = 0; x < 7; x++) if (!isdigit(date[x])) return("-1"); year[0] = date[0]; /* Isolate year */ year[1] = date[1]; year[2] = date[2]; year[3] = date[3]; year[4] = '\0'; debug(F110,"jzdate year",year,0); day[0] = date[4]; /* And day */ day[1] = date[5]; day[2] = date[6]; day[3] = '\0'; debug(F110,"jzdate day",day,0); j = atoi(day); if (j > 366) return("-1"); leapday = 0; /* Assume no leap day */ y = atoi(year); if (y % 4 == 0) { /* If year is divisible by 4 */ leapday = 1; /* It's a Leap year */ if (y % 100 == 0) { /* Except if divisible by 100 */ if (y % 400 != 0) /* but not by 400 */ leapday = 0; } } debug(F101,"jzdate leapday","",leapday); zz = leapday ? ldays : jdays; for (x = 0; x < 11; x++) if (j > zz[x] && j <= zz[x+1]) break; m = x + 1; debug(F101,"jzdate m","",m); d = j - zz[x]; debug(F101,"jzdate d","",d); if (time) sprintf(jzdbuf,"%04d%02d%02d %s",y,m,d,time); /* SAFE */ else sprintf(jzdbuf,"%04d%02d%02d",y,m,d); /* SAFE */ debug(F101,"jzdate jzdbuf",jzdbuf,0); p = ckcvtdate((char *)jzdbuf, 0); /* Convert to standard form */ ckstrncpy(jzdbuf,p,32); if (!time) jzdbuf[8] = NUL; /* Remove time if not wanted */ return((char *)jzdbuf); } /* M J D -- Modified Julian Date */ /* Call with: Standard-format date-time string: yyyymmdd[ hh:mm:ss]. The time, if any, is ignored. Returns: -1L on error, otherwise: The number of days since 17 Nov 1858 as a whole number: 16 Nov 1858 = -1, 17 Nov 1858 = 0, 18 Nov 1858 = 1, 19 Nov 1858 = 2, ... The Modified Julian Date is defined by the International Astronomical Union as the true Julian date minus 2400000.5 days. The true Julian date is the number days since since noon of 1 January 4713 BCE of the Julian proleptic calendar. Conversions between calendar dates and Julian dates, however, assume Gregorian dating. The day of the week is MJD mod 7: 0=We, 1=Th, 2=Fr, 3=Sa, 4=Su, 5=Mo, 6=Tu. */ long #ifdef CK_ANSIC mjd( char * date ) #else mjd(date) char * date; #endif /* CK_ANSIC */ { char year[5]; char month[3]; char day[3]; int x, a, d, m, y; long z; if (!date) date = ""; /* Validate arg */ x = strlen(date); if (x < 1) return(0L); if (x < 8) return(-1L); for (x = 0; x < 8; x++) if (!isdigit(date[x])) return(-1L); year[0] = date[0]; /* Isolate year */ year[1] = date[1]; year[2] = date[2]; year[3] = date[3]; year[4] = '\0'; month[0] = date[4]; /* Month */ month[1] = date[5]; month[2] = '\0';; m = atoi(month); day[0] = date[6]; /* And day */ day[1] = date[7]; day[2] = '\0'; d = atoi(day); a = (14-m)/12; /* Calculate true Julian date */ y = atoi(year) + 4800 - a; m = m + 12 * a - 3; z = d + (long)(306*m+5)/10 + (long)(y*365) + y/4 - y/100 + y/400 - 32045L; z -= 2400001L; /* Convert JD to MJD */ return(z); } static char mjd2dbuf[32]; /* M J D 2 D A T E -- Converts MJD to yyyymmdd */ char * #ifdef CK_ANSIC mjd2date(long mjd) #else mjd2date(mjd) long mjd; #endif /* CK_ANSIC */ /* mjd2date */ { long jd, l, n; int d, m, y; jd = (long)(mjd + 2400001L); l = jd + 68569; n = 4 * l / 146097L; l = l - (146097 * n + 3) / 4; y = 4000 * (l + 1) / 1461001L; l = l - 1461 * y / 4 + 31; m = 80 * l / 2447; d = l - 2447 * m / 80; l = m / 11; m = m + 2 - 12 * l; y = 100 * (n - 49) + y + l; sprintf(mjd2dbuf,"%04d%02d%02d",y,m,d); /* SAFE */ return((char *)mjd2dbuf); } #ifndef NOSPL #ifndef OS2 static char ** flist = (char **) NULL; /* File list for \fnextfile() */ static int flistn = 0; /* Number of items in file list */ #endif /* OS2 */ /* The function return-value buffer must be global, since fneval() returns a pointer to it. fneval() is called only by zzstring(), which always copies the result out of this buffer to somewhere else, so it's OK to have only one buffer for this in most cases. However, since function calls can be nested -- e.g. functions whose arguments are functions, or recursive functions, at some point we should convert this to an array of buffers, indexed by function depth (which might or might not be the same as the "depth" variable). Also, since function results are potentially quite big, we'd need to allocate and deallocate dynamically as we descend and ascend function depth. Left for a future release... */ char fnval[FNVALL+2]; /* Function return value */ static int fndepth = 0; /* (we don't actually use this yet) */ int fnsuccess = 1; extern int fnerror; /* f p f o r m a t -- Floating-point number nicely formatted. */ /* Returns results from a circular 1K buffer. Don't count on too many results remaining available at once; it could be anywhere from 5 to maybe 100, depending on the sizes of the results. */ #ifdef CKFLOAT #define FPFMTSIZ 1024 static char fpfmtbuf[FPFMTSIZ] = { NUL, NUL }; static int fpfbufpos = 0; /* (why was this char before?) */ char * #ifdef CK_ANSIC fpformat( CKFLOAT fpresult, int places, int round ) #else fpformat(fpresult,places,round) CKFLOAT fpresult; int places, round; #endif /* CK_ANSIC */ { char fbuf[16]; /* For creating printf format */ int nines = 0, sign = 0, x, y, i, j, size = 0; char * buf; CKFLOAT ftmp; x = places ? places : (fp_digits ? fp_digits : 6); debug(F101,"fpformat fpresult","",fpresult); debug(F101,"fpformat places","",places); debug(F101,"fpformat fpfbufpos 1","",fpfbufpos); ftmp = fpresult; if (ftmp < 0.0) ftmp = 0.0 - fpresult; #ifdef FNFLOAT if (!fp_rounding && /* If printf doesn't round, */ (places > 0 || /* round result to decimal places. */ (places == 0 && round))) fpresult += (0.5 / pow(10.0,(CKFLOAT)places)); y = (ftmp == 0.0) ? 1 : (int)log10(ftmp); size = y + x + 3; /* Estimated length of result */ if (fpresult < 0.0) size++; #else size = 200; /* No way to estimate, be generous */ #endif /* FNFLOAT */ debug(F101,"fpformat size","",size); if (fpfbufpos > (FPFMTSIZ - size)) /* Wrap around if necessary */ fpfbufpos = 0; debug(F101,"fpformat fpfbufpos 1","",fpfbufpos); buf = &fpfmtbuf[fpfbufpos]; if (places > 0) { /* If places specified */ /* use specified places to write given number of digits */ sprintf(fbuf,"%%0.%df",places); /* SAFE */ sprintf(buf,fbuf,fpresult); /* SAFE */ } else { /* Otherwise... */ /* Go for max precision */ sprintf(fbuf,"%%0.%df",fp_digits); /* SAFE */ sprintf(buf,fbuf,fpresult); /* SAFE */ } if (buf[0] == '-') sign = 1; debug(F111,"fpresult 1 errno",buf,errno); /* Check for over/underflow */ debug(F111,"fpresult 1 fpfbufpos",buf,fpfbufpos); /* Give requested decimal places */ for (i = sign; i < FPFMTSIZ && buf[i]; i++) { if (buf[i] == '.') /* First find the decimal point */ break; else if (i > fp_digits + sign - 1) /* replacing garbage */ buf[i] = '0'; /* digits with 0... */ } if (buf[i] == '.') { /* Have decimal point */ int gotend = 0; /* places < 0 so truncate fraction */ if (places < 0 || (places == 0 && round)) { buf[i] = NUL; } else if (places > 0) { /* d > 0 so this many decimal places */ i++; /* First digit after decimal */ for (j = 0; j < places; j++) { /* Truncate after d decimal */ if (!buf[j+i]) /* places or extend to d */ gotend = 1; /* decimal places. */ if (gotend || j+i+sign > fp_digits) buf[j+i] = '0'; } buf[j+i] = NUL; } else { /* places == 0 so Do The Right Thing */ for (j = (int)strlen(buf) - 1; j > i+1; j--) { if ((j - sign) > fp_digits) buf[j] = '0'; if (buf[j] == '0') buf[j] = NUL; /* Strip useless trailing 0's. */ else break; } } } fpfmtbuf[FPFMTSIZ-1] = NUL; j = strlen(buf); sign = 0; for (i = j-1; i >= 0; i--) { if (buf[i] == '9') nines++; else break; } /* Do something about xx.xx99999999... */ if (nines > 5) { if (isdigit(buf[i]) && i < FPFMTSIZ - 2) { buf[i] = buf[i] + 1; buf[i+1] = '0'; buf[i+2] = '\0'; } } if (!strncmp(buf,"-0.0",FPFMTSIZ)) ckstrncpy(buf,"0.0",FPFMTSIZ); fpfbufpos += (int)strlen(buf) + 1; return((char *)buf); } #endif /* CKFLOAT */ static VOID #ifdef CK_ANSIC evalerr( char * fn ) #else evalerr(fn) char * fn; #endif /* CK_ANSIC */ { if (fndiags) { if (divbyzero) ckmakmsg(fnval,FNVALL,"",NULL); else ckmakmsg(fnval,FNVALL,"",NULL); } } static int #ifdef CK_ANSIC ckcindex(char c, char *s) #else ckcindex(c,s) char c, *s; #endif /* CK_ANSIC */ { int rc; if (!c || !s) return(0); for (rc = 0; s[rc]; rc++) { if (c == s[rc]) return(rc+1); } return(0); } static char * #ifdef CK_ANSIC dokwval( char * s, char * sep ) #else dokwval(s,sep) char * s, * sep; #endif /* CK_ANSIC */ { char c = '\0', * p, * kw = NULL, * vp = NULL; char * rc = "0"; /* Return code */ int x = 0; if (!s) return(rc); if (!*s) return(rc); debug(F110,"kwval arg",s,0); debug(F110,"kwval sep",sep,0); p = (char *)malloc((int)strlen(s)+1); if (!p) goto xdokwval; strcpy(p,s); /* SAFE */ s = p; while (*s < '!' && *s > '\0') /* Get first nonblank */ s++; if (!*s) goto xdokwval; if (ckcindex(*s,sep)) /* Separator but no keyword */ goto xdokwval; kw = s; /* Keyword */ while (*s > ' ') { if (ckcindex(*s,sep)) { /* keyword=... */ c = *s; break; } s++; } if (*kw) rc = "1"; /* Have keyword, promote return code */ *s++ = NUL; /* Terminate keyword */ while (*s < '!' && *s > '\0') /* Skip blanks */ s++; if (!c && ckcindex(*s,sep)) { c = *s++; /* Have separator */ while (*s < '!' && *s > '\0') /* Skip blanks */ s++; } if (c) { vp = s; if (*vp) rc = "2"; /* Have value, another promotion */ #ifdef COMMENT while (*s > ' ') /* Skip to end */ s++; *s = NUL; /* Terminate value */ #endif /* COMMENT */ } debug(F110,"kwval c",ckctoa(c),0); debug(F110,"kwval keyword",kw,0); debug(F110,"kwval value",vp,0); makestr(&lastkwval,kw); vp = brstrip(vp); debug(F110,"kwval value",vp,0); x = addmac(kw,vp); debug(F111,"kwval addmac",kw,x); xdokwval: if (p) free(p); return((x < 0) ? "-1" : rc); } static int #ifdef CK_ANSIC isaarray( char * s ) /* Is s an associative array element */ #else isaarray(s) char * s; #endif /* CK_ANSIC */ { int state = 0; CHAR c; if (!s) return(0); while ((c = *s++)) { if (!isprint(c)) { return(0); } else if (c == '<') { if (state != 0) return(0); state = 1; } else if (c == '>') { return((state != 1 || *s) ? 0 : 1); } } return(0); } /* J P G D A T E -- Get "date taken" from JPG file Exif data */ /* This routine doesn't follow the Exif spec, it just hunts for date-time strings in the first 8K of the JPG and keeps the earliest one. Call with file pointer, returns Exif date-time string "yyyy:mm:dd hh:mm:ss" or an empty string if none found. */ #define JPGYEAR 1 #define JPGMONTH 2 #define JPGDAY 3 #define JPGHOUR 4 #define JPGMIN 5 #define JPGSEC 6 #define JPGDATEBUF 8192 /* Should be more than enough bytes to find date */ static char * #ifdef CK_ANSIC jpgdate( FILE * fp ) #else jpgdate(fp) FILE * fp; #endif /* CK_ANSIC */ { static char datebuf[20]; char tmpbuf[20]; CHAR buf[JPGDATEBUF+1]; CHAR * p; CHAR * z; CHAR c; int i; int k = 0; int n = 0; int count = 0; int state = 0; if (fp == NULL) return(""); rewind(fp); for (i = 0; i < 20; i++) { datebuf[i] = NUL; tmpbuf[i] = NUL; } datebuf[0] = NUL; tmpbuf[0] = NUL; count = fread(buf,1,JPGDATEBUF,fp); /* Read a buffer */ if (count == EOF || count == 0) { return(""); } p = (CHAR *) buf; z = p + JPGDATEBUF; while (p < z) { c = *p++; n++; if (c != ' ' && c != ':' && !isdigit(c)) { state = 0; k = 0; continue; } switch (state) { case 0: if (c == '1' && *p == '9') state = JPGYEAR; else if (c == '2' && *p == '0') state = JPGYEAR; if (state == JPGYEAR) { k = 0; tmpbuf[k++] = c; } continue; case JPGYEAR: if (c == ':' && k == 4) { tmpbuf[k++] = c; state = JPGMONTH; continue; } if (k > 3 || !isdigit(c)) state = k = 0; else tmpbuf[k++] = c; continue; case JPGMONTH: if (c == ':' && k == 7) { tmpbuf[k++] = c; state = JPGDAY; continue; } if (k > 6 || !isdigit(c)) state = k = 0; else tmpbuf[k++] = c; continue; case JPGDAY: if (c == ' ' && k == 10) { tmpbuf[k++] = c; state = JPGHOUR; continue; } if (k > 9 || !isdigit(c)) state = k = 0; else tmpbuf[k++] = c; continue; case JPGHOUR: if (c == ':' && k == 13) { tmpbuf[k++] = c; state = JPGMIN; continue; } if (k > 12 || !isdigit(c)) state = k = 0; else tmpbuf[k++] = c; continue; case JPGMIN: if (c == ':' && k == 16) { tmpbuf[k++] = c; state = JPGSEC; continue; } if (k > 15 || !isdigit(c)) state = k = 0; else tmpbuf[k++] = c; continue; case JPGSEC: if (!isdigit(c) || !isdigit(*p)) { state = k = 0; continue; } tmpbuf[k++] = c; tmpbuf[k++] = *p; tmpbuf[k] = NUL; } if (!datebuf[0]) { /* First date */ strncpy(datebuf,tmpbuf,19); } else if (strncmp(tmpbuf,datebuf,19) < 0) { /* Earlier date */ strncpy(datebuf,tmpbuf,19); } } return((char *) datebuf); } int /* Is character alphnumeric? */ #ifdef CK_ANSIC cisalphanum(CHAR ch) /* i.e. a letter, digit, @, $, or _ */ #else cisalphanum(ch) CHAR ch; /* i.e. a letter, digit, @, $, or _ */ #endif /* CK_ANSIC */ { /* All 8-bit characters are counted as alphanumeric */ int c; c = (int)ch; /* Avoid C-language character syntax */ if (c == 36) return(1); /* '$' is alphanumeric */ if (c == 95) return(1); /* '_' is alphanumeric */ if (c < 48) return(0); /* Space, punctuation, math */ if (c > 57 && c < 64) return(0); /* Between '9' and '@' */ if (c > 90 && c < 97) return(0); /* Between 'Z' and 'a' */ if (c > 122 && c < 127) return(0); /* Between 'z' and DEL */ return(1); } int /* Is character non-alphanumeric */ #ifdef CK_ANSIC cnonalphanum( CHAR ch ) /* i.e. not letter, digit, [$@_] */ #else cnonalphanum(ch) CHAR ch; #endif /* CK_ANSIC */ { int c; c = (int)ch; /* Avoid C-language character syntax */ if (c == 36) return(0); /* '$' is alphanumeric */ if (c == 95) return(0); /* '_' is alphanumeric */ if (c < 48) return(1); /* Space, punctuation, math */ if (c > 57 && c < 64) return(1); /* Between '9' and '@' */ if (c > 90 && c < 97) return(1); /* Between 'Z' and 'a' */ if (c > 122 && c < 127) return(1); /* Between 'z' and DEL */ return(0); } /* Tell if a string contains only alphanumeric characters */ int #ifdef CK_ANSIC isalphanum( char *s ) #else isalphanum(s) char *s; #endif /* CK_ANSIC */ { CHAR c; while ((c = (int)(*s++))) { if (!cisalphanum(c)) return(0); } return(1); } /* Tell if a string contains only non-alphanumeric characters */ int #ifdef CK_ANSIC nonalphanum( char *s ) #else nonalphanum(s) char *s; #endif /* CK_ANSIC */ { CHAR c; while ((c = (int)(*s++))) { if (!cnonalphanum(c)) return(0); } return(1); } static char * /* Evaluate builtin functions */ #ifdef CK_ANSIC fneval( char *fn, char *argp[], int argn, char * xp ) #else fneval(fn,argp,argn,xp) char *fn, *argp[]; int argn; char * xp; #endif /* CK_ANSIC */ { int i=0, j=0, k=0, len1=0, len2=0, len3=0, n=0, t=0, x=0, y=0; int cx, failed = 0; /* Return code, 0 = ok */ long z = 0L; char *bp[FNARGS + 1]; /* Pointers to malloc'd strings */ char c = NUL; char *p = NULL, *s = NULL; char *val1 = NULL, *val2 = NULL; /* Pointers to numeric string values */ #ifdef RECURSIVE int rsave = recursive; #endif /* RECURSIVE */ #ifdef OS2 int zsave = zxpn; #endif /* OS2 */ if (!fn) fn = ""; /* Protect against null pointers */ if (!*fn) return(""); for (i = 0; i < FNARGS; i++) /* Initialize argument pointers */ bp[i] = NULL; /* IMPORTANT: Note that argn is not an accurate count of the number of arguments. We can't really tell if an argument is null until after we execute the code below. So argn is really the maximum number of arguments we might have. Argn should always be at least 1, even if the function is called with empty parentheses (but don't count on it). */ debug(F111,"fneval",fn,argn); debug(F110,"fneval",argp[0],0); if (argn > FNARGS) /* Discard excess arguments */ argn = FNARGS; fndepth++; debug(F101,"fneval fndepth","",fndepth); p = fnval; fnval[0] = NUL; y = lookup(fnctab,fn,nfuncs,&x); /* Look up the function name */ cx = y; /* Because y is too generic... */ if (cx < 0) { /* Not found */ failed = 1; if (fndiags) { /* FUNCTION DIAGNOSTIC ON */ int x; x = strlen(fn); /* The following sprintf's are safe */ switch (cx) { case -1: if (x + 32 < FNVALL) sprintf(fnval,"",fn); else sprintf(fnval,""); break; case -2: if (x + 26 < FNVALL) sprintf(fnval,"",fn); else sprintf(fnval,""); break; case -3: sprintf(fnval,""); break; default: if (x + 26 < FNVALL) sprintf(fnval,"",fn); else sprintf(fnval,""); break; } } goto fnend; /* Always leave via common exit */ } fn = fnctab[x].kwd; /* Full name of function */ if (argn < 0) { failed = 1; p = fnval; if (fndiags) sprintf(fnval,"",fn); goto fnend; } if (cx == FN_LIT) { /* literal(arg1) */ debug(F010,"flit",xp,0); p = xp ? xp : ""; /* Return a pointer to arg itself */ goto fnend; } #ifdef DEBUG if (deblog) { int j; for (j = 0; j < argn; j++) debug(F111,"fneval arg",argp[j],j); } #endif /* DEBUG */ for (j = argn-1; j >= 0; j--) { /* Uncount empty trailing args */ if (!argp[j]) argn--; else if (!*(argp[j])) argn--; else break; } debug(F111,"fneval argn",fn,argn); /* \fliteral() and \fcontents() are special functions that do not evaluate their arguments, and are treated specially here. After these come the functions whose arguments are evaluated in the normal way. */ #ifdef COMMENT /* (moved up) */ if (cx == FN_LIT) { /* literal(arg1) */ debug(F110,"flit",xp,0); p = xp ? xp : ""; /* Return a pointer to arg itself */ goto fnend; } #endif /* COMMENT */ if (cx == FN_CON) { /* Contents of variable, unexpanded. */ char c; int subscript = 0; if (!(p = argp[0]) || !*p) { failed = 1; p = fnval; if (fndiags) sprintf(fnval,""); goto fnend; } p = brstrip(p); if (*p == CMDQ) p++; if ((c = *p) == '%') { /* Scalar variable. */ c = *++p; /* Get ID character. */ p = ""; /* Assume definition is empty */ if (!c) { /* Double paranoia */ failed = 1; p = fnval; if (fndiags) sprintf(fnval,""); goto fnend; } if (c >= '0' && c <= '9') { /* Digit for macro arg */ if (maclvl < 0) /* Digit variables are global */ p = g_var[c]; /* if no macro is active */ else /* otherwise */ p = m_arg[maclvl][c - '0']; /* they're on the stack */ } else if (c == '*') { #ifdef COMMENT p = (maclvl > -1) ? m_line[maclvl] : topline; if (!p) p = ""; #else int nx = FNVALL; char * sx = fnval; p = fnval; #ifdef COMMENT if (cmdsrc() == 0 && topline) p = topline; else #endif /* COMMENT */ if (zzstring("\\fjoin(&_[],{ },1)",&sx,&nx) < 0) { failed = 1; p = fnval; if (fndiags) sprintf(fnval,""); debug(F110,"zzstring fcontents(\\%*)",p,0); } #endif /* COMMENT */ } else { if (isupper(c)) c -= ('a'-'A'); p = g_var[c]; /* Letter for global variable */ } if (!p) p = ""; goto fnend; } else if (c == '&') { /* Array reference. */ int vbi, d; if (arraynam(p,&vbi,&d) < 0) { /* Get name and subscript */ failed = 1; p = fnval; if (fndiags) sprintf(fnval,""); goto fnend; } subscript = chkarray(vbi,d); /* Check the array */ if (subscript >= 0) { /* Array is declared? */ vbi -= ARRAYBASE; /* Convert name to index */ if (a_dim[vbi] >= d) { /* If subscript in range */ char **ap; ap = a_ptr[vbi]; /* get data pointer */ if (ap) { /* and if there is one */ p = ap[d]; /* return it */ goto fnend; } } } else { /* Array not declared or element */ fnval[0] = NUL; /* out of range - return null string */ p = fnval; /* fdc 2010-12-30 */ goto fnend; } } else { failed = 1; p = fnval; if (fndiags) sprintf(fnval,""); goto fnend; } } p = fnval; /* Default result pointer */ fnval[0] = NUL; /* Default result = empty string */ for (i = 0; i < argn; i++) { /* Loop to expand each argument */ n = MAXARGLEN; /* Allow plenty of space */ bp[i] = s = malloc(n+1); /* Allocate space for this argument */ if (bp[i] == NULL) { /* Handle failure to get space */ failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } p = argp[i] ? argp[i] : ""; /* Point to this argument */ /* Trim leading and trailing spaces from the original argument, before evaluation. This code new to edit 184. Fixed in edit 199 to trim blanks BEFORE stripping braces. */ { int x, j; x = strlen(p); j = x - 1; /* Trim trailing whitespace */ while (j > 0 && (*(p + j) == SP || *(p + j) == HT)) *(p + j--) = NUL; while (*p == SP || *p == HT) /* Strip leading whitespace */ p++; x = strlen(p); if (*p == '{' && *(p+x-1) == '}') { /* NOW strip braces */ p[x-1] = NUL; p++; x -= 2; } } /* Now evaluate the argument */ debug(F111,"fneval calling zzstring",p,n); t = zzstring(p,&s,&n); /* Expand arg into new space */ debug(F101,"fneval zzstring","",t); debug(F101,"fneval zzstring","",n); if (t < 0) { debug(F101,"fneval zzstring fails, arg","",i); failed = 1; if (fndiags) { if (n == 0) ckmakmsg(fnval,FNVALL, "",NULL); else ckmakmsg(fnval,FNVALL, "",NULL); } goto fnend; } debug(F111,"fneval arg",bp[i],i); } #ifdef DEBUG if (deblog) { int j; debug(F110,"fneval",fn,0); for (j = 0; j < argn; j++) { debug(F111,"fneval arg post eval",argp[j],j); debug(F111,"fneval evaluated arg",bp[j],j); } } #endif /* DEBUG */ { /* Adjust argn for empty trailing arguments. */ /* For example when an arg is a variable name but the */ /* variable has no value. July 2006. */ int j, old; char *p; old = argn; for (j = argn - 1; j >= 0; j--) { p = bp[j]; if (!p) argn--; else if (!*p) argn--; else break; } #ifdef DEBUG if (argn != old) debug(F101,"fneval adjusted argn","",argn); #endif /* DEBUG */ } /* From this point on, bp[0..argn-1] are not NULL and all must be freed before returning. BUT NOTE: if no arguments were given, bp[0] *is* NULL. */ if (argn < 1) { /* Catch required args missing */ switch (cx) { case FN_DEF: case FN_EVA: case FN_EXE: case FN_CHR: /* case FN_COD: */ case FN_MAX: case FN_MIN: case FN_MOD: case FN_FD: case FN_FS: case FN_TOD: case FN_FFN: case FN_BSN: case FN_RAW: case FN_CMD: case FN_2HEX: case FN_2OCT: case FN_DNAM: #ifdef FN_ERRMSG case FN_ERRMSG: #endif /* FN_ERRMSG */ #ifdef CK_KERBEROS case FN_KRB_TK: case FN_KRB_NX: case FN_KRB_IV: case FN_KRB_TT: case FN_KRB_FG: #endif /* CK_KERBEROS */ case FN_MJD2: case FN_N2TIM: case FN_DIM: case FN_DATEJ: case FN_PNCVT: case FN_PERM: case FN_ALOOK: case FN_TLOOK: case FN_ABS: case FN_AADUMP: case FN_JOIN: #ifdef CKFLOAT case FN_FPABS: case FN_FPEXP: case FN_FPLOG: case FN_FPLN: case FN_FPMOD: case FN_FPSQR: case FN_FPADD: case FN_FPDIV: case FN_FPMUL: case FN_FPPOW: case FN_FPSUB: case FN_FPINT: case FN_FPROU: case FN_FPSIN: case FN_FPCOS: case FN_FPTAN: #endif /* CKFLOAT */ #ifdef TCPSOCKET case FN_HSTADD: case FN_HSTNAM: #endif /* TCPSOCKET */ case FN_DELSEC: #ifdef COMMENT case FN_KWVAL: case FN_SLEEP: case FN_MSLEEP: #endif /* COMMENT */ #ifdef NT case FN_SNAME: case FN_LNAME: #endif /* NT */ case FN_FILEINF: case FN_FILECMP: failed = 1; p = fnval; if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } } p = fnval; /* Reset these again. */ fnval[0] = NUL; switch (cx) { /* Do function on expanded args. */ #ifdef TCPSOCKET case FN_HSTADD: p = ckaddr2name(bp[0]); goto fnend; case FN_HSTNAM: p = ckname2addr(bp[0]); goto fnend; #endif /* TCPSOCKET */ case FN_DEF: /* \fdefinition(arg1) */ k = isaarray(bp[0]) ? mxxlook(mactab,bp[0],nmac) : mxlook(mactab,bp[0],nmac); p = (k > -1) ? mactab[k].mval : ""; goto fnend; case FN_EVA: /* \fevaluate(arg1) */ p = *(bp[0]) ? evalx(bp[0]) : ""; if (!*p && fndiags) { failed = 1; p = fnval; evalerr(fn); } goto fnend; case FN_EXE: /* \fexecute(arg1) */ j = (int)strlen(s = bp[0]); /* Length of macro invocation */ p = ""; /* Initialize return value to null */ if (j) { /* If there is a macro to execute */ while (*s == SP) s++,j--; /* strip leading spaces */ p = s; /* remember beginning of macro name */ for (i = 0; i < j; i++) { /* find end of macro name */ if (*s == SP) break; s++; } if (*s == SP) { /* if there was a space after */ *s++ = NUL; /* terminate the macro name */ while (*s == SP) s++; /* skip past any extra spaces */ } else s = ""; /* maybe there are no arguments */ if (p && *p) { k = mlook(mactab,p,nmac); /* Look up the macro name */ debug(F111,"fexec mlook",p,k); } else k = -1; if (k < 0) { char * p2 = p; failed = 1; p = fnval; if (fndiags) ckmakxmsg(fnval,FNVALL, "", NULL,NULL,NULL,NULL,NULL,NULL,NULL); goto fnend; } /* This is just a WEE bit dangerous because we are copying up to 9 arguments into the space reserved for one. It won't overrun the buffer, but if there are lots of long arguments we might lose some. The other problem is that if the macro has more than 3 arguments, the 4th through last are all concatenated onto the third. (The workaround is to use spaces rather than commas to separate them.) Leaving it like this to avoid having to allocate tons more buffers. */ if (argn > 1) { /* Commas used instead of spaces */ int i; char *p = bp[0]; /* Reuse this space */ *p = NUL; /* Make into dodo() arg list */ for (i = 1; i < argn; i++) { ckstrncat(p,bp[i],MAXARGLEN); ckstrncat(p," ",MAXARGLEN); } s = bp[0]; /* Point to new list */ } p = ""; /* Initialize return value */ if (k >= 0) { /* If macro found in table */ /* Go set it up (like DO cmd) */ if ((j = dodo(k,s,cmdstk[cmdlvl].ccflgs)) > 0) { if (cmpush() > -1) { /* Push command parser state */ extern int ifc; int ifcsav = ifc; /* Push IF condition on stack */ k = parser(1); /* Call parser to execute the macro */ cmpop(); /* Pop command parser */ ifc = ifcsav; /* Restore IF condition */ if (k == 0) { /* No errors, ignore action cmds. */ p = mrval[maclvl+1]; /* If OK, set return value. */ if (p == NULL) p = ""; } } else { /* Can't push any more */ debug(F100,"zzstring fneval fexec failure","",0); printf("\n?\\fexec() too deeply nested\n"); while (cmpop() > -1) ; p = ""; } } } } debug(F110,"zzstring fneval fexecute final p",p,0); goto fnend; #ifdef RECURSIVE case FN_RDIR: /* \frdir..() - Recursive dir count */ case FN_RFIL: /* \frfiles() - Recursive file count */ /* recursive = 2; */ /* fall thru... */ #endif /* RECURSIVE */ case FN_FC: /* \ffiles() - File count. */ case FN_DIR: { /* \ffdir.() - Directory count. */ char abuf[16], *s; char ** ap = NULL; int x, xflags = 0; if (matchdot) xflags |= ZX_MATCHDOT; if (cx == FN_RDIR || cx == FN_RFIL) { xflags |= ZX_RECURSE; #ifdef CKSYMLINK /* Recursive - don't follow symlinks */ xflags |= ZX_NOLINKS; #endif /* CKSYMLINK */ } failed = 0; if (argn < 1) { p = "0"; goto fnend; } if (cx == FN_DIR || cx == FN_RDIR) { /* Only list directories */ debug(F100,"FN_DIR or FN_RDIR","",0); xflags |= ZX_DIRONLY; #ifdef OS2 zxpn = 1; /* Use the alternate list */ #endif /* OS2 */ } else { /* List only files */ debug(F100,"Not FN_DIR or FN_RDIR","",0); xflags |= ZX_FILONLY; #ifdef OS2 zxpn = 1; /* Use the alternate list */ #endif /* OS2 */ } if (*(bp[0])) { k = nzxpand(bp[0],xflags); if (k < 0) k = 0; sprintf(fnval,"%d",k); /* SAFE */ p = fnval; } else p = "0"; if (argn > 1) { /* Assign list to array */ fnval[0] = NUL; /* Initial return value */ ckstrncpy(abuf,bp[1],16); /* Get array reference */ s = abuf; if (*s == CMDQ) s++; failed = 1; /* Assume it's bad */ p = fnval; /* Point to result */ if (fndiags) /* Default is this error message */ ckmakmsg(fnval,FNVALL, "",NULL); if (s[0] != '&') /* "Address" of array */ goto fnend; if (s[2]) if (s[2] != '[' || s[3] != ']') goto fnend; if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */ s[1] += 32; if ((x = dclarray(s[1],k)) < 0) /* File list plus count */ goto fnend; failed = 0; /* Unset failure flag */ ap = a_ptr[x]; /* Point to array we just declared */ sprintf(fnval,"%d",k); /* SAFE */ } #ifdef OS2 if (ap) { /* We are making an array */ int i; char tmp[16]; ap[0] = NULL; /* Containing number of files */ makestr(&(ap[0]),ckitoa(k)); ckstrncpy(tmp,fnval,16); /* Save return value */ for (i = 1; i <= k; i++) { /* Fill it */ ap[i] = NULL; znext(fnval); /* Next filename */ if (!*fnval) /* No more, done */ break; /* In case a premature end */ makestr(&(ap[i]),fnval); } #ifdef ZXREWIND k = zxrewind(); /* Reset the file expansion */ #else k = nzxpand(bp[0],xflags); #endif /* ZXREWIND */ ckstrncpy(fnval,tmp,FNVALL); /* Restore return value */ } #else /* OS2 */ { /* Make copies of the list */ int i; char tmp[16]; if (flist) { /* Free old file list, if any */ for (i = 0; flist[i]; i++) { /* and each string */ free(flist[i]); flist[i] = NULL; } free((char *)flist); } ckstrncpy(tmp,fnval,16); /* Save our return value */ flist = (char **) malloc((k+1) * sizeof(char *)); /* New array */ if (flist) { for (i = 0; i <= k; i++) { /* Fill it */ flist[i] = NULL; znext(fnval); /* Next filename */ if (!*fnval) /* No more, done */ break; makestr(&(flist[i]),fnval); } if (ap) { /* If array pointer given */ ap[0] = NULL; makestr(&(ap[0]),ckitoa(k)); for (i = 0; i < k; i++) { /* Copy file list to array */ ap[i+1] = NULL; makestr(&(ap[i+1]),flist[i]); } } } ckstrncpy(fnval,tmp,FNVALL); /* Restore return value */ flistn = 0; /* Reset global list pointer */ } #endif /* OS2 */ #ifdef RECURSIVE recursive = rsave; #endif /* RECURSIVE */ #ifdef OS2 zxpn = zsave; #endif /* OS2 */ } goto fnend; case FN_FIL: /* \fnextfile() - Next file in list. */ p = fnval; /* (no args) */ *p = NUL; #ifdef OS2 zxpn = 1; /* OS/2 - use the alternate list */ znext(p); /* Call system-dependent function */ zxpn = zsave; /* Restore original list */ #else if (flist) /* Others, use our own list. */ if (flist[flistn]) p = flist[flistn++]; #endif /* OS2 */ goto fnend; } /* Break up big switch... */ switch (cx) { case FN_IND: /* \findex(s1,s2,start,occurrence) */ case FN_RIX: /* \frindex(s1,s2,start,occurrence) */ case FN_SEARCH: /* \fsearch(pat,string,start,occ) */ case FN_RSEARCH: /* \frsearch(pat,string,start,occ) */ case FN_COUNT: { /* \fcount(s1,s2,start) */ int i = 0, right = 0, search = 0, count = 0; int desired = 1; right = (cx == FN_RIX || cx == FN_RSEARCH); search = (cx == FN_SEARCH || cx == FN_RSEARCH); count = (cx == FN_COUNT); p = "0"; if (argn > 1) { /* Only works if we have 2 or 3 args */ int start = 0; char * pat = NULL; len1 = (int)strlen(pat = bp[0]); /* length of string to look for */ len2 = (int)strlen(s = bp[1]); /* length of string to look in */ if (len1 < 1 || len2 < 1) /* Watch out for empty strings */ goto fnend; start = right ? -1 : 0; /* Default starting position */ if (argn > 2) { val1 = *(bp[2]) ? evalx(bp[2]) : "1"; if (argn > 3) { /* Occurrence */ val2 = *(bp[3]) ? evalx(bp[3]) : "1"; if (chknum(val2)) desired = atoi(val2); if (desired * len1 > len2) goto fnend; } if (chknum(val1)) { int t; t = atoi(val1); if (!search) { /* Index or Rindex */ j = len2 - len1; /* Length difference */ t--; /* Convert position to 0-based */ if (t < 0) t = 0; start = t; if (!right && start < 0) start = 0; } else { /* Search or Rsearch */ int x; if (t < 0) t = 0; if (right) { /* Right to left */ if (t > len2) t = len2; start = len2 - t - 1; if (start < 0) goto fnend; x = len2 - t; s[x] = NUL; } else { /* Left to right */ start = t - 1; if (start < 0) start = 0; if (start >= len2) goto fnend; } } } else { failed = 1; evalerr(fn); p = fnval; goto fnend; } } if (count) { /* \fcount() */ int j; for (i = 0; start < len2; i++) { j = ckindex(pat,bp[1],start,0,inpcas[cmdlvl]); if (j == 0) break; start = j; } } else if (search) { /* \fsearch() or \frsearch() */ if (right && pat[0] == '^') { right = 0; start = 0; } if (right) { /* From right */ int k, j = 1; if (start < 0) start = len2 - 1; i = 0; while (start >= 0 && j <= desired) { for (i = start; (i >= 0) && !(k = ckmatch(pat,s+i,inpcas[cmdlvl],1+4)); i--) ; if (k < 1) { /* No match */ i = 0; break; } if (j == desired) { /* The match we want? */ i += k; /* Yes, return string index */ break; } j++; /* No, count this match */ s[i] = NUL; /* null it out */ start = i-1; /* move left and look again */ } } else { /* From left */ int j; i = 0; for (j = 1; j <= desired && start < len2; j++) { i = ckmatch(pat,&s[start],inpcas[cmdlvl],1+4); if (i == 0 || j == desired) break; start += i + 1; } if (j == desired && i != 0) i += start; else i = 0; } } else { /* index or rindex */ int j = 0; i = 0; for (j = 1; j <= desired && start < len2; j++) { i = ckindex(pat,bp[1],start,right,inpcas[cmdlvl]); if (i == 0 || j == desired) break; start = (right) ? len2 - i + 1 : i; } if (j != desired) i = 0; } sprintf(fnval,"%d",i); /* SAFE */ p = fnval; } goto fnend; } case FN_RPL: /* \freplace(s1,s2,s3) */ /* s = bp[0] = source string (len1) bp[1] = match string (len2) bp[2] = replacement string (len3) bp[3] = which occurrence (default = all); bp[4] = context sensitive ("word mode") 20171005 fnval = p = destination (result) string */ if (argn < 1) /* Nothing */ goto fnend; if (argn < 2) { /* Need at least two args */ ckstrncpy(p,bp[0],FNVALL); } else { int occur = 0, xx = 0, context = 0, j2; int left = 0, right = 0, ok = 0; len1 = (int)strlen(bp[0]); /* length of string to look in */ len2 = (int)strlen(bp[1]); /* length of string to look for */ len3 = (argn < 3) ? 0 : (int)strlen(bp[2]); /* Len of replacemnt */ j = len1 - len2 + 1; /* source - match + 1 */ j2 = j; if (argn > 3) { if (chknum(bp[3])) { occur = atoi(bp[3]); } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } } /* Context-sensitive "word mode" replace, new for C-Kermit 9.0.304 Dev.23, October 2017. Can be removed by defining NORPLWORDMODE. */ #ifdef RPLWORDMODE if (argn > 4) { if (chknum(bp[4])) { context = atoi(bp[4]); } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } } #endif /* RPLWORDMODE */ /* If args out of whack... */ if (j < 1 || len1 == 0 || len2 == 0) { ckstrncpy(p,bp[0],FNVALL); /* just return original string */ p[FNVALL] = NUL; } else { ragain: s = bp[0]; /* Point to beginning of source string */ xx = 0; /* Match counter */ while (*s) { /* For each character in it...*/ /* Compare current segment with target string */ if (!ckstrcmp(bp[1],s,len2,inpcas[cmdlvl])) { ok = 1; /* Assume OK to replace */ #ifdef RPLWORDMODE if (context) { /* New 2017-10-05 */ CHAR c; left = 0; right = 0; ok = 0; /* Mustcheck context before replacing */ if (!strncmp(bp[1],"...",len2)) { /* Special case for ellipsis */ if (s > bp[0]) { /* Can't begin a line */ c = *(s-1); /* Check preceding char */ if (c != 32 && c != '.') left = 1; } c = *(s+len2); /* Check following char */ if (c != '.' && (c == SP || c == '\0')) right = 1; } else if (isalphanum(bp[1])) { /* Target string is alphanumeric... */ if (s == bp[0]) { /* At beginning of string */ left = 1; /* So left boundary ok */ } else { /* Otherwise */ c = *(s-1); /* Check preceding char */ if (cnonalphanum(c)) /* If not alphamum */ left = 2; /* left boundary ok */ } c = *(s+len2); /* Check following character */ if (c == '\0') /* If end of string */ right = 1; /* Right boundary OK */ else if (cnonalphanum(c)) right = 2; /* Right boundary OK */ } else if (nonalphanum(bp[1])) { /* Target is non-salphanumeric */ if (s == bp[0]) { /* At beginning of line */ left = 1; /* Left OK */ } else { /* Otherwise */ c = *(s-1); /* Check preceding char */ if (cisalphanum(c) || c == SP) left = 2; /* Left OK */ } c = *(s+len2); /* Check char after target */ if (c == '\0') { /* At end of string */ right = 1; /* Right OK */ } else { /* Otherwise */ if (cisalphanum(c) || c <= SP) right = 2; /* Right ok */ } } /* If none of the above nothing is replaced */ if (left && right) { /* Match accepted */ ok = 1; /* OK to replace */ xx++; /* Count this match */ } } else #endif /* RPLWORDMODE */ xx++; /* Straight replace - count every match */ if (ok && (occur == 0 || occur == xx)) { if (len3) { ckstrncpy(p,bp[2],FNVALL); p += len3; } s += len2; /* and skip past it. */ } else { /* matched but not selected */ *p++ = *s++; /* Just copy this character */ } } else { /* Didn't match */ *p++ = *s++; /* just copy this character */ } } *p = NUL; while ((*p++ = *s++)); /* Append the rest */ if (occur < 0) { /* cheap... */ occur = xx + occur + 1; xx = 0; p = fnval; j = j2; if (occur > 0) goto ragain; } } } p = fnval; goto fnend; case FN_CHR: /* \fcharacter(arg1) */ val1 = *(bp[0]) ? evalx(bp[0]) : ""; if (chknum(val1)) { /* Must be numeric */ i = atoi(val1); if (i >= 0 && i < 256) { /* Must be an 8-bit value */ p = fnval; *p++ = (char) i; *p = NUL; p = fnval; } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); } } else { failed = 1; evalerr(fn); } goto fnend; case FN_COD: /* \fcode(string) */ /* returns decimal character value of first char in string. or 0 if string empty or no string given. */ p = "0"; if (!bp[0]) goto fnend; /* No argument given */ if ((int)strlen(bp[0]) < 1) /* Empty argument */ goto fnend; i = (int) bp[0][0]; debug(F111,"FN_CODE",bp[0],i); p = fnval; sprintf(p,"%d",(i & 0xff)); /* SAFE */ debug(F111,"FN_CODE fnval",fnval,i); goto fnend; case FN_LEN: /* \flength(arg1) */ if (argn > 0) { p = fnval; sprintf(p,"%d",(int)strlen(bp[0])); /* SAFE */ } else p = "0"; goto fnend; case FN_LOW: /* \flower(arg1) */ s = bp[0] ? bp[0] : ""; p = fnval; while (*s) { if (isupper(*s)) *p = (char) tolower(*s); else *p = *s; p++; s++; } *p = NUL; p = fnval; goto fnend; case FN_MAX: /* \fmax(arg1,arg2) */ case FN_MIN: /* \fmin(arg1,arg2) */ case FN_MOD: /* \fmod(arg1,arg2) */ val1 = *(bp[0]) ? evalx(bp[0]) : ""; #ifdef COMMENT /* No longer necessary because evalx() no longer overwrites its */ /* result every time it's called (2000/09/23). */ free(bp[0]); bp[0] = NULL; #endif /* COMMENT */ if (argn > 1) { #ifdef COMMENT /* Ditto... */ bp[0] = malloc((int)strlen(val1)+1); if (bp[0]) strcpy(bp[0],val1); /* safe */ val1 = bp[0]; #endif /* COMMENT */ val2 = *(bp[1]) ? evalx(bp[1]) : ""; if (chknum(val1) && chknum(val2)) { i = atoi(val1); j = atoi(val2); switch (y) { case FN_MAX: if (j < i) j = i; break; case FN_MIN: if (j > i) j = i; break; case FN_MOD: if (j == 0) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); else fnval[0] = NUL; goto fnend; } else j = i % j; } p = fnval; sprintf(p,"%d",j); /* SAFE */ } else { failed = 1; evalerr(fn); } } else p = val1; goto fnend; } /* Break up big switch... */ switch (y) { case FN_SUB: /* \fsubstr(arg1,arg2,arg3) */ case FN_RIG: /* \fright(arg1,arg2) */ case FN_LEF: /* \fleft(arg1,arg2) */ if (argn < 1) goto fnend; val1 = ""; if (argn > 1) if (*(bp[1])) val1 = evalx(bp[1]); #ifdef COMMENT if (bp[1]) free(bp[1]); /* Have to copy this */ bp[1] = malloc((int)strlen(val1)+1); if (!bp[1]) { failed = 1; if (fndiags) { p = fnval; ckmakmsg(fnval,FNVALL, "",NULL); } goto fnend; } strcpy(bp[1],val1); /* safe */ val1 = bp[1]; #endif /* COMMENT */ val2 = ""; if (argn > 2) if (*(bp[2])) val2 = evalx(bp[2]); if ( ((argn > 1) && (int)strlen(val1) && !rdigits(val1)) || ((cx == FN_SUB) && ((argn > 2) && (int)strlen(val2) && !rdigits(val2))) ) { failed = 1; evalerr(fn); } else { int lx; p = fnval; /* pointer to result */ lx = strlen(bp[0]); /* length of arg1 */ if (cx == FN_SUB) { /* substring */ k = (argn > 2) ? atoi(val2) : MAXARGLEN; /* length */ j = (argn > 1) ? atoi(val1) : 1; /* start pos for substr */ } else if (cx == FN_LEF) { /* left */ k = (argn > 1) ? atoi(val1) : lx; j = 1; } else { /* right */ k = (argn > 1) ? atoi(val1) : lx; /* length */ j = lx - k + 1; /* start pos for right */ if (j < 1) j = 1; } if (k > 0 && j <= lx) { /* if start pos in range */ s = bp[0]+j-1; /* point to source string */ for (i = 0; (i < k) && (*p++ = *s++); i++) ; /* copy */ } *p = NUL; /* terminate the result */ p = fnval; /* and point to it. */ } goto fnend; case FN_UPP: /* \fupper(arg1) */ s = bp[0] ? bp[0] : ""; p = fnval; while (*s) { if (islower(*s)) *p = (char) toupper(*s); else *p = *s; p++; s++; } *p = NUL; p = fnval; goto fnend; case FN_REP: /* \frepeat(text,number) */ if (argn < 1) goto fnend; val1 = "1"; if (argn > 1) if (*(bp[1])) val1 = evalx(bp[1]); if (chknum(val1)) { /* Repeat count */ n = atoi(val1); debug(F111,"SUNDAY frepeat n",val1,n); if (n > 0) { /* Make n copies */ p = fnval; *p = '\0'; k = (int)strlen(bp[0]); /* Make sure string has some length */ debug(F111,"SUNDAY frepeat k","",k); debug(F111,"SUNDAY frepeat FNVALL","",FNVALL); if (k * n >= FNVALL) { /* But not too much... */ failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); else fnval[0] = NUL; p = fnval; goto fnend; } if (k > 0) { /* If there is something to copy */ for (i = 0; i < n; i++) { /* Copy loop */ s = bp[0]; for (j = 0; j < k; j++) { if ((p - fnval) >= FNVALL) break; /* shouldn't happen... */ else *p++ = *s++; } } *p = NUL; } } } else { failed = 1; evalerr(fn); } p = fnval; goto fnend; #ifndef NOFRILLS case FN_REV: /* \freverse() */ if (argn < 1) goto fnend; yystring(bp[0],&p); goto fnend; #endif /* NOFRILLS */ case FN_RPA: /* \frpad() and \flpad() */ case FN_LPA: if (argn < 1) goto fnend; val1 = ""; if (argn > 1) if (*(bp[1])) val1 = evalx(bp[1]); if (argn == 1) { /* If a number wasn't given */ p = fnval; /* just return the original string */ ckstrncpy(p,bp[0],FNVALL); } else if (argn > 1 && !*val1) { failed = 1; evalerr(fn); } else /* if (chknum(val1)) */ { /* Repeat count */ char pc; n = atoi(val1); if (n >= 0) { p = fnval; k = (int)strlen(bp[0]); /* Length of string to be padded */ if (k >= n) { /* It's already long enough */ ckstrncpy(p,bp[0],FNVALL); } else { if (n + k <= FNVALL) { pc = (char) ((argn < 3) ? SP : *bp[2]); if (!pc) pc = SP; if (cx == FN_RPA) { /* RPAD */ strncpy(p,bp[0],k); /* (leave it like this) */ p[k] = NUL; p += k; for (i = k; i < n; i++) *p++ = pc; } else { /* LPAD */ n -= k; for (i = 0; i < n; i++) *p++ = pc; strncpy(p,bp[0],k); /* (leave it like this) */ p[k] = NUL; p += k; } } *p = NUL; } } } p = fnval; goto fnend; #ifdef ZFCDAT case FN_FD: /* \fdate(filename) */ p = fnval; s = zfcdat(bp[0]); if (!s) s = ""; if (!*s) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } ckstrncpy(fnval,s,FNVALL); #endif /* ZFCDAT */ goto fnend; } /* Break up big switch... */ switch (y) { case FN_FS: { /* \fsize(filename) */ CK_OFF_T z; p = fnval; z = zchki(bp[0]); if (z < (CK_OFF_T)0) { failed = 1; if (fndiags) { if (z == (CK_OFF_T)-1) ckmakmsg(fnval,FNVALL, "",NULL); else if (z == (CK_OFF_T)-2) ckmakmsg(fnval,FNVALL, "",NULL); else if (z == (CK_OFF_T)-3) ckmakmsg(fnval,FNVALL, "",NULL); else ckmakmsg(fnval,FNVALL, "",NULL); } goto fnend; } ckstrncpy(fnval,ckfstoa(z),FNVALL); goto fnend; } case FN_VER: /* \fverify() */ p = "-1"; if (argn == 1) /* No second arg */ goto fnend; else if (!bp[1]) /* Or second arg null */ goto fnend; else if (!*(bp[1])) /* or empty. */ goto fnend; p = "0"; if (argn > 1) { /* Only works if we have 2 or 3 args */ int start; char *s2, ch1, ch2; start = 0; if (argn > 2) { /* Starting position specified */ val1 = *(bp[2]) ? evalx(bp[2]) : "0"; if (chknum(val1)) { start = atoi(val1) /* - 1 */; if (start < 0) start = 0; if (start > (int)strlen(bp[1])) goto verfin; } else { failed = 1; evalerr(fn); goto fnend; } } i = start; p = "0"; for (s = bp[1] + start; *s; s++,i++) { ch1 = *s; if (!inpcas[cmdlvl]) if (islower(ch1)) ch1 = toupper(ch1); j = 0; for (s2 = bp[0]; *s2; s2++) { ch2 = *s2; if (!inpcas[cmdlvl]) if (islower(ch2)) ch2 = toupper(ch2); if (ch1 == ch2) { j = 1; break; } } if (j == 0) { sprintf(fnval,"%d",i+1); /* SAFE */ p = fnval; break; } } } verfin: goto fnend; case FN_IPA: /* Find and return IP address */ if (argn > 0) { /* in argument string. */ int start = 0; if (argn > 1) { /* Starting position specified */ if (chknum(bp[1])) { start = atoi(bp[1]) - 1; if (start < 0) start = 0; } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } } p = getip(bp[0]+start); } else p = ""; goto fnend; #ifdef OS2 case FN_CRY: p = ""; if (argn > 0) { p = fnval; ckstrncpy(p,bp[0],FNVALL); ck_encrypt(p); } goto fnend; case FN_OOX: p = ""; if (argn > 0) p = ck_oox(bp[0], (argn > 1) ? bp[1] : ""); goto fnend; #endif /* OS2 */ case FN_HEX: /* \fhexify(arg1) */ if (argn < 1) goto fnend; if ((int)strlen(bp[0]) < (FNVALL / 2)) { s = bp[0]; p = fnval; while (*s) { x = (*s >> 4) & 0x0f; *p++ = hexdigits[x]; x = *s++ & 0x0f; *p++ = hexdigits[x]; } *p = NUL; p = fnval; } goto fnend; case FN_UNTAB: /* \funtab(arg1) */ if (argn < 1) goto fnend; if ((int)strlen(bp[0]) < (FNVALL * 2)) { s = bp[0]; p = fnval; if (untabify(bp[0],p,FNVALL) < 0) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); } goto fnend; } case FN_UNH: { /* \funhex(arg1) */ int c[2], i; if (argn < 1) goto fnend; if ((int)strlen(bp[0]) < (FNVALL * 2)) { s = bp[0]; p = fnval; while (*s) { for (i = 0; i < 2; i++) { c[i] = *s++; if (!c[i]) { p = ""; goto unhexfin; } if (islower(c[i])) c[i] = toupper(c[i]); if (c[i] >= '0' && c[i] <= '9') { c[i] -= 0x30; } else if (c[i] >= 'A' && c[i] <= 'F') { c[i] -= 0x37; } else { failed = 1; if (fndiags) ckmakmsg(fnval, FNVALL, "", NULL ); goto fnend; } } *p++ = ((c[0] << 4) & 0xf0) | (c[1] & 0x0f); } *p = NUL; p = fnval; } unhexfin: goto fnend; } case FN_BRK: { /* \fbreak() */ char * c; /* Characters to break on */ char c2, s2; int start = 0; int done = 0; if (argn < 1) goto fnend; if (argn > 2) { s = bp[2] ? bp[2] : "0"; if (chknum(s)) { start = atoi(s); if (start < 0) start = 0; if (start > (int)strlen(bp[0])) goto brkfin; } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } } s = bp[0] + start; /* Source pointer */ while (*s && !done) { s2 = *s; if (!inpcas[cmdlvl] && islower(s2)) s2 = toupper(s2); c = bp[1] ? bp[1] : ""; /* Character to break on */ while (*c) { c2 = *c; if (!inpcas[cmdlvl] && islower(c2)) c2 = toupper(c2); if (c2 == s2) { done = 1; break; } c++; } if (done) break; *p++ = *s++; } *p = NUL; /* terminate the result */ p = fnval; /* and point to it. */ brkfin: goto fnend; } case FN_SPN: { /* \fspan() */ char *q; char c1, c2; int start = 0; if (argn < 1) goto fnend; if (argn > 2) { /* Starting position */ s = bp[2] ? bp[2] : "0"; if (chknum(s)) { start = atoi(s); if (start < 0) start = 0; } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } } s = bp[0] + start; /* Source pointer */ if (argn > 1 && (int)strlen(bp[1]) > 0 && start <= (int)strlen(bp[0])) { while (*s) { /* Loop thru source string */ q = bp[1]; /* Span string */ c1 = *s; if (!inpcas[cmdlvl]) if (islower(c1)) c1 = toupper(c1); x = 0; while ((c2 = *q++)) { if (!inpcas[cmdlvl]) if (islower(c2)) c2 = toupper(c2); if (c1 == c2) { x = 1; break; } } if (!x) break; *p++ = *s++; } *p = NUL; /* Terminate and return the result */ p = fnval; } goto fnend; } } /* Break up big switch... */ switch (y) { case FN_TRM: /* \ftrim(s1[,s2]) */ case FN_LTR: /* \fltrim(s1[,s2]) */ if (argn < 1) goto fnend; if ((len1 = (int)strlen(bp[0])) > 0) { if (len1 > FNVALL) len1 = FNVALL; s = " \t\r\n"; if (argn > 1) /* Trim list given */ s = bp[1]; len2 = (int)strlen(s); if (len2 < 1) { /* or not... */ s = " \t\r\n"; /* Default is to trim whitespace */ len2 = 2; } if (cx == FN_TRM) { /* Trim from right */ char * q, p2, q2; ckstrncpy(fnval,bp[0],FNVALL); /* Copy string to output */ p = fnval + len1 - 1; /* Point to last character */ while (p >= (char *)fnval) { /* Go backwards */ q = s; /* Point to trim list */ p2 = *p; if (!inpcas[cmdlvl]) if (islower(p2)) p2 = toupper(p2); while (*q) { /* Is this char in trim list? */ q2 = *q; if (!inpcas[cmdlvl]) if (islower(q2)) q2 = toupper(q2); if (p2 == q2) { /* Yes, null it out */ *p = NUL; break; } q++; } if (!*q) /* Trim list exhausted */ break; /* So we're done. */ p--; /* Else keep trimming */ } } else { /* Trim from left */ char * q, p2, q2; p = bp[0]; /* Source */ while (*p) { p2 = *p; if (!inpcas[cmdlvl]) if (islower(p2)) p2 = toupper(p2); q = s; while (*q) { /* Is this char in trim list? */ q2 = *q; if (!inpcas[cmdlvl]) if (islower(q2)) q2 = toupper(q2); if (p2 == q2) { /* Yes, point past it */ p++; /* and try next source character */ break; } q++; /* No, try next trim character */ } if (!*q) /* Trim list exhausted */ break; /* So we're done. */ } ckstrncpy(fnval,p,FNVALL); } p = fnval; } else p = ""; goto fnend; case FN_CAP: /* \fcapitalize(arg1) */ if (argn < 1) goto fnend; s = bp[0]; p = fnval; x = 0; while ((c = *s++)) { if (isalpha(c)) { if (x == 0) { x = 1; if (islower(c)) c = toupper(c); } else if (isupper(c)) c = tolower(c); } *p++ = c; } *p = NUL; p = fnval; goto fnend; #ifdef COMMENT case FN_TOD: /* Time of day to secs since midnite */ sprintf(fnval,"%ld",tod2sec(bp[0])); /* SAFE */ goto fnend; #endif /* COMMENT */ case FN_FFN: /* Full pathname of file */ zfnqfp(bp[0],FNVALL,p); if (!p) p = ""; goto fnend; case FN_CHK: { /* \fchecksum() */ long chk = 0; p = (argn > 0) ? bp[0] : ""; while (*p) chk += *p++; sprintf(fnval,"%lu",chk); /* SAFE */ p = fnval; goto fnend; } #ifndef NOXFER case FN_CRC: /* \fcrc16() */ if (argn > 0) sprintf(fnval,"%u", /* SAFE */ chk3((CHAR *)bp[0],(int)strlen(bp[0]))); else p = "0"; goto fnend; #endif /* NOXFER */ case FN_BSN: /* \fbasename() */ zstrip(bp[0],&p); goto fnend; #ifndef NOLOCAL #ifdef OS2 case FN_SCRN_CX: /* \fscrncurx() */ p = fnval; sprintf(p,"%d",(int)VscrnGetCurPos(VTERM)->x); /* SAFE */ goto fnend; case FN_SCRN_CY: /* \fscrncury() */ p = fnval; sprintf(p,"%d",(int)VscrnGetCurPos(VTERM)->y); /* SAFE */ goto fnend; case FN_SCRN_STR: { /* \fscrnstr() */ videoline * line = NULL; viocell * cells = NULL; int row = 0, col = 0, len = 0; /* NOTE: On Unicode systems, the screen contents are stored in */ /* in Unicode. Therefore, we should really be performing a */ /* conversion to the local character set. */ /* 6/18/2000 - added the translation to lcs */ if (bp[0] == NULL || bp[0][0] == '\0') { row = 0; } else { if (chknum(bp[0])) { row = atoi(bp[0]); if (row < 0) row = 0; } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } } line = VscrnGetLineFromTop( VTERM, (USHORT) row ); if (line != NULL) { if (bp[1] == NULL || bp[1][0] == '\0') col = 0; else { if (chknum(bp[0])) { col = atoi(bp[1]); if (col < 0 || col >= line->width) col = 0; } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } } if (bp[2] == NULL || bp[2][0] == '\0') { len = line->width - (col+1); } else { if (!chknum(bp[2])) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } len = atoi(bp[2]); if (len < 0 || len > line->width) len = line->width; } cells = line->cells; for (i = 0; i < len; i++) { int pos = i + col; if (pos < line->width) { if (ck_isunicode()) fnval[i] = (CHAR) utolxlat(cells[pos].c); else fnval[i] = (CHAR) (cells[pos].c & 0xFF); if (fnval[i] == 0) fnval[i] = SP; } else fnval[i] = SP; } fnval[i] = '\0'; } else { fnval[0] = '\0'; } p = fnval; goto fnend; } #endif /* OS2 */ #endif /* NOLOCAL */ #ifndef NOPUSH case FN_RAW: /* \frawcommand() */ case FN_CMD: { /* \fcommand() */ int x, c, n = FNVALL; x = 0; /* Completion flag */ /* ZIFILE can be safely used because we can't possibly be transferring a file while executing this function. */ if (!nopush && zxcmd(ZIFILE,bp[0]) > 0) { /* Open the command */ while (n-- > -1) { /* Read from it */ if ((c = zminchar()) < 0) { x = 1; /* EOF - set completion flag */ if (cx == FN_CMD) { /* If not "rawcommand" */ p--; /* remove trailing newlines */ while (*p == CK_CR || *p == LF) p--; p++; } *p = NUL; /* Terminate the string */ break; } else /* Command still running */ *p++ = c; /* Copy the bytes */ } zclose(ZIFILE); /* Close the command */ } /* Return null string if command's output was too long. */ p = fnval; if (!x) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); } goto fnend; } #endif /* NOPUSH */ } /* Break up big switch... */ switch (y) { case FN_STX: /* \fstripx(string,c) */ if (!(s = bp[0])) /* Make sure there is a string */ goto fnend; c = '.'; /* Character to strip from */ if (argn > 1) if (*bp[1]) c = *bp[1]; n = ckstrncpy(fnval,bp[0],FNVALL); while (--n >= 0) { if (fnval[n] == c) { fnval[n] = NUL; break; } } p = fnval; goto fnend; case FN_STL: /* \flop(string,c) */ case FN_LOPX: { /* \flopx(string,c) */ int n = 1; if (!(s = bp[0])) /* Make sure there is a string */ goto fnend; c = '.'; /* Character to strip to */ if (argn > 1) if (*bp[1]) c = *bp[1]; if (argn > 2) if (*bp[2]) { #ifndef NOFLOAT n = 0; if (isfloat(bp[2],0)) { n = (int)floatval; if (n < 0) n = 0; } else #endif /* NOFLOAT */ n = atoi(bp[2]); } x = 0; if (cx == FN_LOPX) { /* Lopx (from right) */ if (n == 0) goto fnend; s += strlen(s) - 1; /* We already know it's > 0 */ while (s-- >= bp[0]) { if (*s == c) { n--; if (n == 0) { s++; x = 1; break; } } } if (!x) s = ""; } else { /* Lop (from left) */ if (n == 0) { p = bp[0]; goto fnend; } while (*s++) { if (*(s-1) == c) { if (--n == 0) { x = 1; break; } } } if (!x) s = bp[0]; } ckstrncpy(fnval,s,FNVALL); p = fnval; goto fnend; } case FN_STN: /* \fstripn(string,n) */ if (argn < 1) /* Remove n chars from right */ goto fnend; val1 = "0"; if (argn > 1) if (*(bp[1])) val1 = evalx(bp[1]); if (!chknum(val1)) { failed = 1; evalerr(fn); goto fnend; } n = atoi(val1); if (n < 0) n = 0; k = (int)strlen(s = bp[0]) - n; if (k < 0) k = 0; p = fnval; while (k-- > 0) *p++ = *s++; *p = NUL; p = fnval; goto fnend; case FN_STB: { /* \fstripb(string,c) */ char c2 = NUL; int i, k = 0; char * gr_opn = "\"{'([<"; /* Group open brackets */ char * gr_cls = "\"}')]>"; /* Group close brackets */ p = fnval; *p = NUL; if (!(s = bp[0])) /* Make sure there is a string */ goto fnend; if ((x = strlen(s)) < 1) goto fnend; c = NUL; /* Brace/bracket kind */ if (argn > 1) { if (*bp[1]) { if (chknum(bp[1])) { k = atoi(bp[1]); if (k < 0) k = 63; for (i = 0; i < 6; i++) { if (k & (1< 2) if (*bp[2]) c2 = *bp[2]; if (*s == c) { if (!c2) { switch (c) { case '(': c2 = ')'; break; case '[': c2 = ']'; break; case '{': c2 = '}'; break; case '<': c2 = '>'; break; case '"': c2 = '"'; break; case 39: c2 = 39; break; case 96: c2 = 39; break; default: if (argn == 2) { c2 = c; } else { strncpy(fnval,s,x); /* Leave it like this */ fnval[x] = NUL; goto fnend; } } } if (s[x-1] == c2) { strncpy(fnval,s+1,x-2); /* Leave it like this */ fnval[x-2] = NUL; goto fnend; } } strncpy(fnval,s,x); fnval[x] = NUL; goto fnend; } case FN_2HEX: /* Number to hex */ case FN_2OCT: /* Number to octal */ val1 = evalx(bp[0]); if (!*val1) { failed = 1; evalerr(fn); goto fnend; } sprintf(fnval, cx == FN_2HEX ? "%lx" : "%lo", atol(val1)); /* SAFE */ if (cx == FN_2HEX && (int)(strlen(fnval)&1)) sprintf(fnval,"0%lx",atol(val1)); /* SAFE */ p = fnval; goto fnend; case FN_DNAM: { /* Directory part of file name */ char *s; zfnqfp(bp[0],FNVALL,p); /* Get full name */ if (!isdir(p)) { /* Is it already a directory? */ zstrip(p,&s); /* No get basename */ if (*s) { x = ckindex(s,p,0,0,0); /* Pos of latter in former */ if (x > 0) p[x-1] = NUL; } } if (!p) p = ""; goto fnend; } #ifndef NORANDOM case FN_RAND: /* Random number */ #ifdef CK_SSL if (RAND_bytes((unsigned char *)&k,sizeof(k)) < 0) #endif /* CK_SSL */ k = rand(); x = 0; if (argn > 0) { if (!chknum(bp[0])) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } x = atoi(bp[0]); } #ifdef COMMENT sprintf(fnval,"%d", (x > 0 && k > 0) || (x < 0 && k < 0) ? k % x : (x == 0 ? 0 : (0 - (k % (-x))))); #else debug(F111,"rand",ckitoa(x),k); #ifdef SUNOS4 /* This is really strange but on SunOS, if we are requesting random numbers */ /* between 0 and 4 or less, they always come out in sequence: 0 1 2 3 0 1 2 */ /* Shifting the result of rand() in this case gives a more random result. */ if (x < 5) k = k >> 5; #endif /* SUNOS4 */ if ((x > 0 && k > 0) || (x < 0 && k < 0)) x = k % x; else if (x == 0) x = 0; else x = 0 - (k % (-x)); debug(F101,"rand x","",x); sprintf(fnval,"%d", x); /* SAFE */ #endif /* COMMENT */ p = fnval; goto fnend; #endif /* NORANDOM */ } /* Break up big switch... */ switch (y) { case FN_SPLIT: /* \fsplit(s1,a,s2,s3,mask) */ case FN_WORD: { /* \fword(s1,n,s2,s3,mask) */ int wordnum = 0; int splitting = 0; int x; int array = 0; int grouping = 0; int nocollapse = 0; char * sep = ""; char * notsep = ""; char * bp0 = NULL; char * bp1 = NULL; char abuf[16]; struct stringarray * q = NULL; splitting = (cx == FN_SPLIT); /* Our job */ debug(F101,"FN_SPLIT splitting","",splitting); fnval[0] = splitting ? '0' : NUL; /* Initial return value */ fnval[1] = NUL; p = fnval; bp0 = bp[0]; /* Source string */ if (!bp0) bp0 = ""; debug(F111,"fsplit bp[0]",bp0,argn); if (argn < 1 || !*bp0) /* If none, return default value */ goto fnend; bp1 = bp[1]; /* Function-dependent arg */ if (!bp1) bp1 = ""; /* (array or number) */ debug(F110,"fsplit bp[1]",bp1,0); if (bp[5]) { if (!chknum(bp[5])) { failed = 1; ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } x = atoi(bp[5]); nocollapse = x; } if (!splitting) { /* \fword(): n = desired word number */ val1 = "1"; /* Default is first word */ if (argn > 1) /* Word number supplied */ if (*bp1) val1 = evalx(bp1); if (!chknum(val1)) { failed = 1; ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } n = atoi(val1); } else if (argn > 1 && *bp1) { /* \fsplit(): n = word count */ ckstrncpy(abuf,bp1,16); /* Get array reference */ debug(F110,"fsplit abuf 1",abuf,0); failed = 1; /* Assume it's bad */ if (fndiags) /* Default is this error message */ ckmakmsg(fnval,FNVALL, "",NULL); if (abuf[0] != '&') /* "Address" of array */ goto fnend; /* It's bad */ if (abuf[2]) { /* Check for brackets */ if (abuf[2] != '[' || abuf[3] != ']') { goto fnend; /* Bad */ } } debug(F110,"fsplit abuf 2",abuf,0); if (abuf[1] > 64 && abuf[1] < 91) /* Convert upper to lower */ abuf[1] += 32; if (abuf[1] < 97 || abuf[1] > 122) { /* Check for a-z */ goto fnend; } debug(F110,"fsplit abuf 3",abuf,0); array = 1; fnval[0] = NUL; /* No error, erase message */ failed = 0; /* Unset failure flag */ n = 0; /* Initialize word counter */ } if (argn > 2) /* Have break set? */ sep = bp[2]; debug(F111,"fsplit sep",sep,argn); if (argn > 3) /* Have include set? */ notsep = bp[3]; debug(F111,"fsplit notsep",notsep,argn); if (argn > 4) { /* Have grouping set? */ char * bp4 = bp[4]; debug(F111,"fsplit bp4",bp4,argn); if (!bp4) bp4 = "0"; if (!*bp4) bp4 = "0"; if (chknum(bp4)) { grouping = atoi(bp4); if (grouping == -1) grouping = 127; } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } } /* Args parsed, now do the work */ debug(F111,"fsplit bp0",bp0,n); q = cksplit(splitting,n,bp0,sep,notsep,grouping,0,nocollapse,0); wordnum = q ? q->a_size : -1; /* Check result */ if (wordnum < 0) { failed = 1; /* Failure */ if (fndiags) ckmakmsg(fnval,FNVALL, (wordnum == -1) ? "", NULL ); goto fnend; } if (splitting) { /* \fsplit() result */ ckstrncpy(fnval,ckitoa(wordnum),FNVALL); if (array) { /* Array was not declared. */ int i; if ((x = dclarray(abuf[1],wordnum)) < 0) { /* Declare it. */ failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } for (i = 1; i <= wordnum; i++) { /* Copy results */ makestr(&(a_ptr[x][i]),q->a_head[i]); } a_ptr[x][0] = NULL; /* Array is 1-based */ makestr(&(a_ptr[x][0]),fnval); /* Element = size */ } } else { /* \fword() result */ char * s; s = q->a_head[1]; if (!s) s = ""; ckstrncpy(fnval,s,FNVALL); } goto fnend; /* Done */ } } /* Break up big switch... */ switch (y) { #ifdef CK_KERBEROS case FN_KRB_TK: /* Kerberos tickets */ case FN_KRB_NX: /* Kerberos next ticket */ case FN_KRB_IV: /* Kerberos ticket is valid */ case FN_KRB_FG: /* Kerberos Ticket flags */ case FN_KRB_TT: { /* Kerberos ticket time */ int kv = 0; /* Kerberos version */ int n = 0; char * s = NULL; if (rdigits(bp[0])) { kv = atoi(bp[0]); } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } if (kv != 4 && kv != 5) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } if ((cx == FN_KRB_IV || cx == FN_KRB_TT || cx == FN_KRB_FG) && argn < 2) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } switch (y) { case FN_KRB_TK: /* Number of Kerberos tickets */ #ifdef CK_AUTHENTICATION switch (kv) { case 4: n = ck_krb4_get_tkts(); sprintf(fnval, "%d", (n >= 0) ? n : 0); /* SAFE */ goto fnend; case 5: { extern char * krb5_d_cc; n = ck_krb5_get_tkts(krb5_d_cc); sprintf(fnval, "%d", (n >= 0) ? n : 0); /* SAFE */ goto fnend; } } #else sprintf(fnval,"%d",0); /* SAFE */ #endif /* CK_AUTHENTICATION */ goto fnend; case FN_KRB_NX: /* Kerberos next ticket */ #ifdef CK_AUTHENTICATION switch (kv) { case 4: s = ck_krb4_get_next_tkt(); ckstrncpy(fnval, s ? s : "",FNVALL); goto fnend; case 5: s = ck_krb5_get_next_tkt(); ckstrncpy(fnval, s ? s : "",FNVALL); goto fnend; } #else sprintf(fnval,"k%d next-ticket-string",kv); /* SAFE */ #endif /* CK_AUTHENTICATION */ goto fnend; case FN_KRB_IV: /* Kerberos ticket is valid */ #ifdef CK_AUTHENTICATION /* Return 1 if valid, 0 if not */ switch (kv) { case 4: n = ck_krb4_tkt_isvalid(bp[1]); sprintf(fnval, "%d", n > 0 ? 1 : 0); /* SAVE */ goto fnend; case 5: { extern char * krb5_d_cc; n = ck_krb5_tkt_isvalid(krb5_d_cc,bp[1]); sprintf(fnval,"%d", n > 0 ? 1 : 0); /* SAFE */ goto fnend; } } #else sprintf(fnval,"%d",0); /* SAFE */ #endif /* CK_AUTHENTICATION */ goto fnend; case FN_KRB_TT: /* Kerberos ticket time */ #ifdef CK_AUTHENTICATION switch (kv) { case 4: n = ck_krb4_tkt_time(bp[1]); sprintf(fnval,"%d", n >= 0 ? n : 0); /* SAFE */ goto fnend; case 5: { extern char * krb5_d_cc; n = ck_krb5_tkt_time(krb5_d_cc,bp[1]); sprintf(fnval,"%d", n >= 0 ? n : 0); /* SAFE */ goto fnend; } } #else ckstrncpy(fnval,"600",FNVALL); /* Some time */ #endif /* CK_AUTHENTICATION */ goto fnend; case FN_KRB_FG: /* Kerberos ticket flags */ #ifdef CK_AUTHENTICATION switch (kv) { case 4: fnval[0] = '\0'; goto fnend; case 5: { extern char * krb5_d_cc; ckstrncpy(fnval,ck_krb5_tkt_flags(krb5_d_cc,bp[1]),FNVALL); goto fnend; } } #else fnval[0] = '\0'; #endif /* CK_AUTHENTICATION */ goto fnend; } p = fnval; goto fnend; } #endif /* CK_KERBEROS */ #ifdef FN_ERRMSG case FN_ERRMSG: if (rdigits(bp[0])) { k = atoi(bp[0]); } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } #ifdef VMS ckstrncpy(fnval,ckvmserrstr(k),FNVALL); #else x = errno; errno = k; ckstrncpy(fnval,ck_errstr(),FNVALL); errno = x; #endif /* VMS */ p = fnval; goto fnend; #endif /* FN_ERRMSG */ case FN_DIM: { int max; char abuf[16], *s; fnval[0] = NUL; /* Initial return value */ ckstrncpy(abuf,bp[0],16); /* Get array reference */ s = abuf; if (*s == CMDQ) s++; failed = 1; /* Assume it's bad */ p = fnval; /* Point to result */ if (fndiags) /* Default is this error message */ ckmakmsg(fnval,FNVALL,"",NULL); if (s[0] != '&') { /* "Address" of array */ goto fnend; } if (s[2]) { if (s[2] != '[' || s[3] != ']') { goto fnend; } } if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */ s[1] += 32; if (s[1] < 95 || s[1] > 122) { /* Check for a-z */ goto fnend; /* Bad */ } if ((max = chkarray(s[1],1)) < 1) /* (second arg was 1) */ max = 0; failed = 0; /* Unset failure flag */ sprintf(fnval,"%d",max); /* SAFE */ goto fnend; } case FN_FILEINF: { /* File information */ #ifdef UNIX /* from zgetfs in ckufio.c */ extern int zgfs_dir, zgfs_link; extern char linkname[]; char * tx; /* For tilde expansion */ #endif /* UNIX */ char abuf[16], *s; char ** ap = NULL; char workbuf[CKMAXPATH]; int attrs = 9; /* Number of attributes defined */ int k = 0; /* current attribute index */ int i,j,n; int m; /* For scanfile() */ int dir = -1; /* 1 = arg is a directory file */ CK_OFF_T z; /* For file size */ #ifdef UNIX CK_OFF_T z2; /* Also for file size */ #endif /* UNIX */ workbuf[0] = NUL; workbuf[1] = NUL; if (argn < 2) { /* An array designator is required */ if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } #ifdef UNIX if (*(bp[0]) == '~') { /* Expand any tildes in filenames. */ tx = tilde_expand(bp[0]); /* We recycle bp[0] */ if (tx) if (*tx) { /* this way so they will be freed */ free(bp[0]); /* automatically later. */ bp[0] = NULL; makestr(&(bp[0]),tx); } } #endif /* UNIX */ j = ckstrncpy(workbuf,bp[0],CKMAXPATH); /* Strip any trailing '/' */ if (workbuf[j-1] == '/') { workbuf[j-1] = NUL; makestr(&(bp[0]),workbuf); } z = zchki(bp[0]); /* Check accessibility */ if (z == -1L || z == -3L) { /* Access denied or whatever */ p = "0"; goto fnend; /* Note: z > 0 is the file size but only of regular files */ /* Thus the zgetfs call just below */ } #ifdef UNIX if ((z2 = zgetfs(bp[0])) > 0) { /* Get size and some attributes */ z = z2; /* Have size */ dir = zgfs_dir; /* File is/isn't a directory */ } #endif /* UNIX */ if (dir < 0) /* Check if file is a a directory */ dir = isdir(bp[0]); /* if previous clause didn't already */ fnval[0] = NUL; /* Initial return value */ ckstrncpy(abuf,bp[1],16); /* Get array reference */ s = abuf; if (*s == CMDQ) s++; failed = 1; /* Assume it's bad */ p = fnval; /* Point to result */ if (fndiags) /* Default is this error message */ ckmakmsg(fnval,FNVALL, "",NULL); if (s[0] != '&') /* "Address" of array */ goto fnend; if (s[2]) if (s[2] != '[' || s[3] != ']') goto fnend; if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */ s[1] += 32; if ((x = dclarray(s[1],attrs)) < 0) /* One element per attribute */ goto fnend; failed = 0; /* Unset failure flag */ ap = a_ptr[x]; /* Point to array we just declared */ sprintf(fnval,"%d",k); /* SAFE */ /* Element 1 = filename */ s = bp[0]; /* Argument (might include path) */ n = strlen(s); for (i = n; i > 0; i--) { /* Get filename without path */ if (ISDIRSEP(s[i-1])) { /* Platform independent way */ s += i; break; } } a_ptr[x][1] = NULL; /* Filename */ makestr(&(a_ptr[x][1]),s); /* Element 2 - Full pathname */ s = workbuf; zfnqfp(bp[0],FNVALL,s); n = strlen(s); for (i = n; i > 0; i--) { /* Get filename without path */ if (ISDIRSEP(s[i-1])) { /* Platform independent way */ s[i] = NUL; break; } } a_ptr[x][2] = NULL; makestr(&(a_ptr[x][2]),s); /* Element 3 - Modification date-time */ s = zfcdat(bp[0]); a_ptr[x][3] = NULL; makestr(&(a_ptr[x][3]),s); /* Element 4 - Permissions string */ #ifdef UNIX if (zgfs_link) s = "lrwxrwxrwx"; else #endif /* UNIX */ /* [jt] 2013/11/21: * K-95 doesn't have ziperm. However, I have not read through this * code thoroughly, and this needs to be double checked to see if there are * any side effects of commenting this out. */ #ifdef CK_PERMS s = ziperm(bp[0]); a_ptr[x][4] = NULL; makestr(&(a_ptr[x][4]),s); ckstrncpy(workbuf,s,32); /* Save for later */ #endif /* CK_PERMS */ /* Element 5 - Permissions numeric code */ s = zgperm(bp[0]); a_ptr[x][5] = NULL; makestr(&(a_ptr[x][5]),s); /* Element 6 - Size in bytes */ #ifdef UNIX /* [fdc] 2021-09-14 only Unix has file links */ s = zgfs_link ? ckitoa((int)strlen((char *)linkname)) : ckfstoa(z); #else s = ckfstoa(z); #endif /* UNIX */ a_ptr[x][6] = NULL; makestr(&(a_ptr[x][6]),s); /* Element 7 - File type */ j = 0; if (dir) j = 3; #ifdef UNIX else if (zgfs_link) j = 4; else if (ckindex("x",(char *)workbuf,0,0,1)) j = 2; else if (workbuf[1] != '-') j = 1; #else #ifdef VMS else if (ckindex("E",(char *)workbuf,0,0,1)) j = 2; else j = 1; #endif /* VMS */ #endif /* UNIX */ a_ptr[x][7] = NULL; switch (j) { case 0: s = "unknown"; break; case 1: s = "regular"; break; case 2: s = "executable"; break; case 3: s = "directory"; break; case 4: s = "link"; break; default: s = "unknown"; } makestr(&(a_ptr[x][7]),s); k = 7; /* Element 8 - Name of linked-to file (if link) */ a_ptr[x][8] = NULL; #ifdef UNIX if (zgfs_link) { makestr(&(a_ptr[x][8]),(char *)linkname); k++; } #endif /* UNIX */ /* Element 9 - File scan result */ if (j == 1 || j == 2) { /* Regular file */ m = scanfile(bp[0],NULL,nscanfile); if (m > -1) { if (k < 8) k = 8; /* Insert empty element for link */ makestr(&(a_ptr[x][8]),""); k++; switch (m) { case FT_7BIT: s = "text:7bit"; break; case FT_UTF8: s = "text:utf8"; break; case FT_UCS2: s = "text:ucs2"; break; case FT_8BIT: s = "text:8bit"; break; case FT_TEXT: s = "text:unknown"; break; case FT_BIN: s = "binary"; break; default: s = "unknown"; } a_ptr[x][9] = NULL; makestr(&(a_ptr[x][9]),s); } } /* If adding another change attrs declaration to match */ /* Element 0 = array size */ p = ckitoa(k); /* Number of elements */ a_ptr[x][0] = NULL; /* Put number of elements in [0] */ makestr(&(a_ptr[x][0]),p); debug(F101,"FILEINF","",attrs); goto fnend; } case FN_FILECMP: { /* File comparison */ FILE *fp1 = NULL; FILE *fp2 = NULL; char * s1 = NULL, * s2 = NULL; #ifdef UNIX char * tx; /* For tilde expansion */ #endif /* UNIX */ int c1, c2; int eof1 = 0, eof2 = 0; failed = 1; /* Assume files differ */ p[0] = '1'; /* Default return value = differ */ p[1] = NUL; if (argn != 2) { /* Need two args */ if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } s1 = bp[0]; s2 = bp[1]; #ifdef UNIX if (*s1 == '~') { /* Expand any tildes in filenames. */ tx = tilde_expand(bp[0]); /* We recycle bp[0] and bp[1] */ if (tx) if (*tx) { /* this way so they will be freed */ free(bp[0]); /* automatically later. */ bp[0] = NULL; makestr(&(bp[0]),tx); } s1 = bp[0]; } if (*s2 == '~') { tx = tilde_expand(bp[1]); if (tx) if (*tx) { free(bp[1]); bp[1] = NULL; makestr(&(bp[1]),tx); } s2 = bp[1]; } #endif /* UNIX */ fp1 = fopen(s1, "r"); /* Open it first file*/ fp2 = fopen(s2, "r"); /* Open it first file*/ failed = 0; /* No failure from here down */ if (fp1 == NULL || fp2 == NULL) { /* Open failure */ p[0] = '-'; p[1] = '1'; p[2] = NUL; /* Return -1 */ if (fp1) fclose(fp1); if (fp1) fclose(fp2); goto fnend; } while (1) { if (!eof1) { c1 = getc(fp1); if (c1 == (unsigned int)EOF) { eof1++; fclose(fp1); } } if (!eof2) { c2 = getc(fp2); if (c2 == (unsigned int)EOF) { eof2++; fclose(fp2); } } if (eof1 && eof2) { p[0] = '0'; /* Success */ p[1] = NUL; failed = 0; goto fnend; } if (eof1 || eof2 || (c1 != c2)) { if (!eof1) fclose(fp1); if (!eof2) fclose(fp2); goto fnend; } } } } /* Break up big switch... */ switch (y) { case FN_JDATE: if (argn < 1) /* Check number of args */ p = ckdate(); /* None, get today's date-time */ else /* Some */ p = bp[0]; /* Use first */ p = ckcvtdate(p,0); /* Convert to standard form */ ckstrncpy(fnval,zjdate(p),FNVALL); /* Convert to Julian */ p = fnval; /* Point to result */ failed = 0; if (*p == '-') { failed = 1; if (fndiags) /* Default is this error message */ ckmakmsg(fnval,FNVALL,"",NULL); } goto fnend; case FN_DATEJ: ckstrncpy(fnval,jzdate(bp[0]),FNVALL); /* Convert to yyyy */ p = fnval; /* Point to result */ failed = 0; if (*p == '-') { failed = 1; if (fndiags) /* Default is this error message */ ckmakmsg(fnval,FNVALL,"",NULL); } goto fnend; case FN_DTIM: /* \fcvtdate() */ case FN_TIME: /* Free-format time to hh:mm:ss */ case FN_NTIM: /* Time to sec since midnight */ s = (argn > 0) ? bp[0] : ""; if (!s) s = ""; if (!*s) p = ckdate(); /* None, get today's date */ else /* Some */ p = bp[0]; /* Use first */ { char * s; s = p; while (*s) { /* Strip leading spaces/ctrls */ if (*s < 32) { *s = NUL; break; } s++; } /* do { if (*s < '!') *s = NUL; break; } while (*s++); */ } p = ckcvtdate(p,2); /* Convert to standard form */ if (*p == '<') { failed = 1; if (fndiags) /* Default is this error message */ ckmakmsg(fnval,FNVALL, "",NULL); p = fnval; goto fnend; } if (argn > 1) { /* Format code */ s = evalx(bp[1]); if (!s) s = ""; if (!*s) s = "0"; if (!chknum(s)) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); p = fnval; goto fnend; } x = atoi(s); /* if (x) */ p = shuffledate(p,x); } if (cx == FN_TIME) { p += 9; } else if (cx == FN_NTIM) { long sec = 0L; p[11] = NUL; p[14] = NUL; sec = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15); sprintf(fnval,"%ld",sec); /* SAFE */ p = fnval; } goto fnend; case FN_MJD: /* Modified Julian Date */ if (argn < 1) /* Check number of args */ p = zzndate(); /* None, get today's date-time */ else /* Some */ p = bp[0]; /* Use first */ p = ckcvtdate(p,0); /* Convert to standard form */ if (*p == '-') { failed = 1; if (fndiags) /* Default is this error message */ ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } /* Convert to modified Julian date */ sprintf(fnval,"%ld",mjd(p)); /* SAFE */ p = fnval; /* Point to result */ goto fnend; case FN_MJD2: { long k = 0L; int n = 0; p = evalx(bp[0]); if (*p == '-') { p++; n = 1; } if (!rdigits(p)) { failed = 1; evalerr(fn); p = fnval; goto fnend; } else { k = atol(p); if (n) k = -k; } ckstrncpy(fnval,mjd2date(k),FNVALL); /* Convert to Date */ p = fnval; /* Point to result */ failed = 0; goto fnend; } #ifndef NODIAL case FN_PNCVT: { /* Convert phone number */ failed = 0; p = pncvt(bp[0]); if (!p) p = ""; if (!*p) { failed = 1; if (fndiags) /* Default is this error message */ ckmakmsg(fnval,FNVALL, "",NULL); } goto fnend; } #endif /* NODIAL */ case FN_DAY: case FN_NDAY: if (argn < 1) /* Check number of args */ p = zzndate(); /* None, get today's date-time */ else /* Some */ p = bp[0]; /* Use first */ p = ckcvtdate(p,0); /* Convert to standard form */ if (*p == '-') { failed = 1; if (fndiags) /* Default is this error message */ ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } failed = 0; z = mjd(p); /* Convert to modified Julian date */ z = z % 7L; if (z < 0) { z = 0 - z; k = 6 - ((int)z + 3) % 7; } else { k = ((int)z + 3) % 7; /* Day of week */ } p = fnval; /* Point to result */ if (cx == FN_NDAY) sprintf(fnval,"%d",k); /* SAFE */ else ckstrncpy(fnval,wkdays[k],FNVALL); goto fnend; case FN_N2TIM: { /* Sec since midnight to hh:mm:ss */ long k = 0L; int n = 0, hh, mm, ss; char * s = bp[0]; if (argn < 1) /* If no arg substitute 0 */ s = "0"; p = evalx(s); /* Evaluate expression silently */ if (*p == '-') { /* Check result for minus sign */ p++; n = 1; } if (!rdigits(p)) { /* Check for numeric */ failed = 1; ckmakmsg(fnval,FNVALL, "",NULL); p = fnval; goto fnend; } else { k = atol(p); if (n) k = -k; } if (k < 0) { /* Check for negative */ failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); p = fnval; goto fnend; } hh = k / 3600L; /* Have positive number */ mm = (k % 3600L) / 60L; /* break it down... */ ss = ((k % 3600L) % 60L); sprintf(fnval,"%02d:%02d:%02d",hh,mm,ss); /* SAFE */ p = fnval; failed = 0; goto fnend; } case FN_PERM: { /* File permissions */ p = fnval; z = zchki(bp[0]); if (z < 0) { failed = 1; if (fndiags) { if (z == -1) ckmakmsg(fnval,FNVALL, "",NULL); else if (z == -2) ckmakmsg(fnval,FNVALL, "",NULL); else if (z == -3) ckmakmsg(fnval,FNVALL, "",NULL); else ckmakmsg(fnval,FNVALL, "",NULL); } goto fnend; } #ifdef CK_PERMS ckstrncpy(fnval,ziperm(bp[0]),FNVALL); #else ckstrncpy(fnval,"(unknown)",FNVALL); #endif /* CK_PERMS */ goto fnend; } case FN_TLOOK: /* tablelook() */ case FN_ALOOK: { /* arraylook() */ int i, x, hi, lo, max, cmdlen; char abuf[16], *s, *pat; char kwbuf[256]; char delim = ':'; failed = 1; /* Assume failure */ ckstrncpy(fnval,"-1",FNVALL); pat = bp[0]; /* Point to search pattern */ if (!pat) pat = ""; /* Watch out for NULL pointer */ cmdlen = strlen(pat); /* Get pattern length */ if (argn < 2 /* || cmdlen < 1 */ ) { /* Need two args */ if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } ckstrncpy(abuf,bp[1],16); /* Get array reference */ if (argn > 2) delim = *(bp[2]); s = abuf; if ((x = arraybounds(s,&lo,&hi)) < 0) { /* Get index and bounds */ if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } p = fnval; /* Point to result */ max = a_dim[x]; /* Size of array */ if (lo < 0) lo = 0; /* Use given range if any */ if (lo > max) lo = max; if (hi < 0) hi = max; if (hi > max) hi = max; failed = 0; /* Unset failure flag */ if (max < 1) goto fnend; kwbuf[255] = NUL; for (i = lo; i <= hi; i++) { if (!a_ptr[x][i]) continue; if (cx == FN_ALOOK) { if (ckmatch(pat,a_ptr[x][i],inpcas[cmdlvl],1+4)) { sprintf(fnval,"%d",i); /* SAFE */ goto fnend; } } else if (cx == FN_TLOOK) { char * aa; int j = 0, v = 0, len; if (i == hi) break; aa = a_ptr[x][i]; /* Point to this array element */ if (!aa) aa = ""; while (j < 254 && *aa) { /* Isolate keyword */ if (*aa == delim) break; kwbuf[j++] = *aa++; } kwbuf[j] = NUL; len = j; v = 0; if ((len == cmdlen && !ckstrcmp(kwbuf,pat,len,0)) || ((v = !ckstrcmp(kwbuf,pat,cmdlen,0)) && ckstrcmp(a_ptr[x][i+1],pat,cmdlen,0))) { sprintf(fnval,"%d",i); /* SAFE */ goto fnend; } if (v) { /* Ambiguous */ ckstrncpy(fnval,"-2",FNVALL); goto fnend; } } } if (cx == FN_TLOOK) { /* tablelook() last element */ ckstrncpy(fnval,"-1",FNVALL); if (!ckstrcmp(a_ptr[x][hi],pat,cmdlen,0)) sprintf(fnval,"%d",hi); /* SAFE */ } goto fnend; } case FN_TOB64: /* Base-64 conversion */ case FN_FMB64: p = fnval; *p = NUL; if (argn < 1) goto fnend; if (cx == FN_TOB64) { x = b8tob64(bp[0],-1,fnval,FNVALL); } else { x = strlen(bp[0]); if (x % 4) { /* length must be multiple of 4 */ failed = 1; ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } b64tob8(NULL,0,NULL,0); /* Reset */ x = b64tob8(bp[0],-1,fnval,FNVALL); b64tob8(NULL,0,NULL,0); /* Reset again */ } if (x < 0) { failed = 1; if (fndiags) { char * m = "INTERNAL_ERROR"; switch (x) { case -1: m = "ARG_TOO_LONG"; break; case -2: m = "ARG_OUT_OF_RANGE"; break; } if (ckmakmsg(fnval,FNVALL," 0) ckstrncat(fnval,"()>",FNVALL); } } goto fnend; case FN_ABS: { char * s; s = bp[0]; if (*s == '-' || *s == '+') s++; if (!rdigits(s)) { if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } ckstrncpy(fnval,s,FNVALL); goto fnend; } case FN_AADUMP: { char abuf[16], *s = NULL, **ap = NULL, **vp = NULL; char pattern[VNAML]; int slen, i, j, k, first = -1; p = fnval; if (argn < 2) { if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } debug(F101,"aaconvert argn","",argn); s = bp[0]; slen = strlen(s); /* Count elements so we can create the array */ ckmakmsg(pattern,VNAML,s,"<*>",NULL,NULL); for (k = 0, i = 0; i < nmac; i++) { if (ckmatch(pattern,mactab[i].kwd,0,1)) { if (first < 0) /* Remember location of first match */ first = i; k++; } } debug(F101,"aaconvert matches","",k); debug(F101,"aaconvert first","",first); fnval[0] = NUL; /* Initial return value */ ckstrncpy(abuf,bp[1],16); /* Get array reference */ s = abuf; if (*s == CMDQ) s++; p = fnval; /* Point to result */ if (fndiags) /* Default is this error message */ ckmakmsg(fnval,FNVALL,"",NULL); if (s[0] != '&') /* Address of array */ goto fnend; if (s[2]) if (s[2] != '[' || s[3] != ']') goto fnend; if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */ s[1] += 32; if ((x = dclarray(s[1],k)) < 0) /* Declare array to size */ goto fnend; ap = a_ptr[x]; /* Point to array we just declared */ /* debug(F111,"aaconvert array 1",abuf,ap); */ abuf[0] = NUL; if (argn > 2) { ckstrncpy(abuf,bp[2],16); /* Get value array reference */ s = abuf; if (*s == CMDQ) s++; if (s[0] != '&') /* Address of array */ goto fnend; if (s[2]) if (s[2] != '[' || s[3] != ']') goto fnend; if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */ s[1] += 32; if ((x = dclarray(s[1],k)) < 0) goto fnend; vp = a_ptr[x]; /* Point to array we just declared */ } /* debug(F111,"aaconvert array 2",abuf,vp); */ makestr(&ap[0],ckitoa(k)); if (vp) makestr(&vp[0],ckitoa(k)); if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); /* Copy macro index & value to the arrays and then remove the */ /* macro, so the 'first' pointer keeps indicating the next one. */ /* We could combine the initial counting loop with this one but */ /* then it would be harder to create the array and anyway this */ /* function is plenty fast as it is. */ for (i = 1; i <= k; ) { if (!ckmatch(pattern,mactab[first].kwd,0,1)) { debug(F111,"aaconvert oddball",mactab[first].kwd,first); first++; continue; } ckstrncpy(tmpbuf,mactab[first].kwd,TMPBUFSIZ); /* Macro name */ s = tmpbuf; /* Make writeable copy */ s += slen; /* Isolate "index" */ j = strlen(s) - 1; if (*s != '<' || *(s+j) != '>') { /* Check syntax */ /* This shouldn't happen */ debug(F111,"aaconvert ERROR",mactab[first].kwd,first); goto fnend; } *(s+j) = NUL; /* Remove final '>' */ debug(F111,"aaconvert",s+1,i); makestr(&(ap[i]),s+1); /* Set first array to index */ if (vp) makestr(&(vp[i]),mactab[first].mval); /* 2nd to value */ if (xdelmac(first) < 0) goto fnend; i++; } sprintf(fnval,"%d",k); /* SAFE */ p = fnval; /* Return size of array */ debug(F110,"aaconvert return",p,0); failed = 0; /* Unset failure flag */ goto fnend; } } /* End of switch() */ #ifdef FNFLOAT /* Floating-point functions. To be included only if FNFLOAT is defined, which should happen only if CKFLOAT is also defined, and if the math library is linked in. Even then, we might have float-vs-double confusion as well as confusion about what the final "%f" format effector is supposed to reference (32 bits, 64 bits, etc). Expect trouble if CKFLOAT does not match the data type of math library functions or args. */ if (cx == FN_FPABS || /* Floating-point functions */ cx == FN_FPADD || cx == FN_FPDIV || cx == FN_FPEXP || cx == FN_FPLOG || cx == FN_FPLN || cx == FN_FPMOD || cx == FN_FPMAX || cx == FN_FPMIN || cx == FN_FPMUL || cx == FN_FPPOW || cx == FN_FPSQR || cx == FN_FPINT || cx == FN_FPSUB || cx == FN_FPROU || cx == FN_FPSIN || cx == FN_FPCOS || cx == FN_FPTAN) { CKFLOAT farg[2], fpresult = 0.0; char fpbuf[64], * bp0; double dummy; /* int sign = 0; */ int i, places = 0; int argcount = 1; #ifdef COMMENT int j; #endif failed = 1; p = fnval; bp0 = bp[0]; if (!bp0) bp0 = "0"; else if (!*bp0) bp0 = "0"; if (!isfloat(bp0,0)) { k = mxlook(mactab,bp0,nmac); bp0 = (k > -1) ? mactab[k].mval : NULL; if (bp0) { if (!isfloat(bp0,0)) { if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } } } if (cx == FN_FPINT) { /* Float to int */ failed = 0; ckstrncpy(fnval,bp0,FNVALL); for (i = 0; fnval[i]; i++) { if (fnval[i] == '.') { fnval[i] = NUL; break; } } goto fnend; } switch (y) { /* These need 2 args */ case FN_FPADD: case FN_FPDIV: case FN_FPMOD: case FN_FPMAX: case FN_FPMIN: case FN_FPMUL: case FN_FPPOW: case FN_FPSUB: argcount = 2; } /* Missing arguments are supplied as 0.0 */ debug(F111,fn,"argcount",argcount); for (i = 0; i < argcount; i++) { /* Get floating-point args */ #ifdef DEBUG if (deblog) { ckmakmsg(fpbuf, 64, "bp[", ckitoa(i), bp[i] ? bp[i] : "(null)", "]" ); debug(F100,fpbuf,"",0); } #endif /* DEBUG */ if (!bp[i]) { farg[i] = 0.0; } else if (!*(bp[i])) { farg[i] = 0.0; } else if (!isfloat(bp[i],0)) { char * tmp; k = mxlook(mactab,bp[i],nmac); tmp = (k > -1) ? mactab[k].mval : NULL; if (tmp) { if (!isfloat(tmp,0)) { if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } } } farg[i] = floatval; #ifdef DEBUG if (deblog) { sprintf(fpbuf,"farg[%d]=%f",i,farg[i]); /* SAFE */ debug(F100,fpbuf,"",0); } #endif /* DEBUG */ } if (bp[argcount]) { /* Get decimal places */ char * s; s = bp[argcount]; if (!s) s = ""; if (!*s) s = "0"; s = evalx(s); if (!s) s = ""; if (!*s) { evalerr(fn); goto fnend; } places = atoi(s); } errno = 0; failed = 0; switch (y) { /* Now do the requested function */ case FN_FPABS: /* Floating-point absolute value */ #ifndef COMMENT fpresult = fabs(farg[0]); #else if (farg[0] < 0.0) fpresult = 0.0 - farg[0]; #endif /* COMMENT */ break; case FN_FPADD: /* FP add */ fpresult = farg[0] + farg[1]; break; case FN_FPDIV: /* FP divide */ case FN_FPMOD: /* FP modulus */ if (!farg[1]) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); } else fpresult = (cx == FN_FPDIV) ? (farg[0] / farg[1]) : fmod(farg[0],farg[1]); break; case FN_FPEXP: /* FP e to the x */ fpresult = (CKFLOAT) exp(farg[0]); break; case FN_FPLOG: /* FP base-10 logarithm */ case FN_FPLN: /* FP natural logarithm */ if (farg[0] < 0.0) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); } else fpresult = (cx == FN_FPLOG) ? log10(farg[0]) : log(farg[0]); break; case FN_FPMUL: /* FP multiply */ fpresult = farg[0] * farg[1]; break; case FN_FPPOW: /* FP raise to a power */ fpresult = modf(farg[1],&dummy); if ((!farg[0] && farg[1] <= 0.0) || (farg[0] < 0.0 && fpresult)) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); } else fpresult = pow(farg[0],farg[1]); break; case FN_FPSQR: /* FP square root */ if (farg[0] < 0.0) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); } else fpresult = sqrt(farg[0]); break; case FN_FPSUB: /* FP subtract */ fpresult = farg[0] - farg[1]; break; case FN_FPROU: /* FP round */ fpresult = farg[0]; break; case FN_FPSIN: /* FP sine */ fpresult = (CKFLOAT) sin(farg[0]); break; case FN_FPCOS: /* FP cosine */ fpresult = (CKFLOAT) cos(farg[0]); break; case FN_FPTAN: /* FP tangent */ fpresult = (CKFLOAT) tan(farg[0]); break; case FN_FPMAX: fpresult = (farg[0] > farg[1]) ? farg[0] : farg[1]; break; case FN_FPMIN: fpresult = (farg[0] < farg[1]) ? farg[0] : farg[1]; break; } /* Get here with fpresult = function result */ if (errno) { /* If range or domain error */ failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); } if (failed) /* and/or any other kind of error, */ goto fnend; /* fail. */ #ifndef COMMENT /* Call routine containing code that was formerly inline */ ckstrncpy(fnval,fpformat(fpresult,places,cx == FN_FPROU),FNVALL); #else { char fbuf[16]; /* For creating printf format */ if (!fp_rounding && /* If printf doesn't round, */ (places > 0 || /* round result to decimal places. */ (places == 0 && cx == FN_FPROU))) fpresult += (0.5 / pow(10.0,(CKFLOAT)places)); if (places > 0) { /* If places specified */ /* use specified places to write given number of digits */ sprintf(fbuf,"%%0.%df",places); /* SAFE */ sprintf(fnval,fbuf,fpresult); /* SAFE */ } else { /* Otherwise... */ #ifdef COMMENT /* Here we want to print exactly fp_digits significant digits, no matter which side of the decimal point they are on. That is, we want want the default format to show the maximum number of non-garbage digits, AND we want the last such digit to be rounded. Of course there is no way to do that, since the digit after the last non-garbage digit is, well, garbage. So the following clever ruse does no good. */ int sign = 0, m = 0; sprintf(fnval,"%f",fpresult); if (fnval[0] == '-') sign = 1; for (i = sign; i < FNVALL; i++) { if (isdigit(fnval[i])) m++; else break; } if (m > 1) { int d = fp_digits - m; if (d < 1) d = 1; sprintf(fbuf,"%%%d.%df",fp_digits+sign+1,d); } else { sprintf(fbuf,"%%0.%df",fp_digits); } sprintf(fnval,fbuf,fpresult); #else /* Go for max precision */ sprintf(fbuf,"%%0.%df",fp_digits); /* SAFE */ sprintf(fnval,fbuf,fpresult); /* SAFE */ #endif /* COMMENT */ } if (fnval[0] == '-') sign = 1; } debug(F111,"fpresult 1",fnval,errno); /* Check for over/underflow */ for (i = sign; fnval[i]; i++) { /* Give requested decimal places */ if (fnval[i] == '.') /* First find the decimal point */ break; else if (i > fp_digits + sign - 1) /* replacing garbage */ fnval[i] = '0'; /* digits with 0... */ } if (fnval[i] == '.') { /* Have decimal point */ int gotend = 0; /* d < 0 so truncate fraction */ if (places < 0 || (places == 0 && cx == FN_FPROU)) { fnval[i] = NUL; } else if (places > 0) { /* d > 0 so this many decimal places */ i++; /* First digit after decimal */ for (j = 0; j < places; j++) { /* Truncate after d decimal */ if (!fnval[j+i]) /* places or extend to d */ gotend = 1; /* decimal places. */ if (gotend || j+i+sign > fp_digits) fnval[j+i] = '0'; } fnval[j+i] = NUL; } else { /* d == 0 so Do The Right Thing */ for (j = (int)strlen(fnval) - 1; j > i+1; j--) { if ((j - sign) > fp_digits) fnval[j] = '0'; if (fnval[j] == '0') fnval[j] = NUL; /* Strip useless trailing 0's. */ else break; } } } #endif /* COMMENT */ debug(F111,"fpresult 2",fnval,errno); goto fnend; } #endif /* FNFLOAT */ #ifdef CKCHANNELIO if (cx == FN_FSTAT || /* File functions */ cx == FN_FPOS || cx == FN_FEOF || cx == FN_FGCHAR || cx == FN_FGLINE || cx == FN_FGBLK || cx == FN_FPCHAR || cx == FN_FPLINE || cx == FN_FPBLK || cx == FN_NLINE || cx == FN_FERMSG || cx == FN_FILNO) { int x = 0, t = 0, channel; long z; extern int z_maxchan; failed = 1; /* Assume failure */ p = fnval; /* until we validate args */ if (cx == FN_FERMSG) { extern int z_error; if (argn < 1) { x = z_error; } else if (chknum(bp[0])) { x = atoi(bp[0]); } else if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); failed = 0; ckstrncpy(fnval,ckferror(x),FNVALL); goto fnend; } if (argn < 1) { /* All file functions need channel */ if (cx == FN_FSTAT) { /* Except f_status(), e.g. when */ fnval[0] = '0'; /* called with a variable that */ fnval[1] = NUL; /* hasn't been defined yet. */ failed = 0; } else { if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); } goto fnend; } if (rdigits(bp[0])) { /* Channel must be numeric */ channel = atoi(bp[0]); } else { /* Fail if it isn't */ if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } if (channel < 0 || channel > z_maxchan) { /* Check channel range */ if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } x = z_getmode(channel); /* Find out about the channel */ failed = 0; /* Assume success from here down */ if (cx == FN_FSTAT) { /* Status / modes of channel */ if (x > -1) x &= FM_RWB; /* Mask out irrelevant bits */ else /* In this case not open is OK */ x = 0; /* 0 if not open, 1-7 if open */ sprintf(fnval,"%d",x); /* SAFE */ goto fnend; } else if (x < 1) { /* Not \f_status() so must be open */ failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } switch (y) { /* Do the requested function */ case FN_FPOS: /* Get position */ z = z_getpos(channel); /* FIX THIS */ sprintf(fnval,"%ld",z); /* SAFE */ goto fnend; case FN_NLINE: /* Get line number */ z = z_getline(channel); /* FIX THIS */ sprintf(fnval,"%ld",z); /* SAFE */ goto fnend; case FN_FEOF: /* Check EOF */ t = 0; if (x & FM_EOF) t = 1; sprintf(fnval,"%d",t); /* SAFE */ goto fnend; case FN_FILNO: /* Get file handle */ x = z_getfnum(channel); sprintf(fnval,"%d",x); /* SAFE */ goto fnend; case FN_FPBLK: /* Read or write block */ case FN_FGBLK: if (argn < 2) { if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } if (rdigits(bp[1])) { t = atoi(bp[1]); } else { if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } case FN_FGCHAR: /* Read or write character or line */ case FN_FPCHAR: case FN_FGLINE: case FN_FPLINE: fnval[0] = NUL; switch (y) { case FN_FGCHAR: t = z_in(channel,fnval,FNVALL,1,1); break; case FN_FGLINE: t = z_in(channel,fnval,FNVALL,FNVALL-1,0); break; case FN_FGBLK: if (t >= FNVALL) t = FNVALL - 1; t = z_in(channel,fnval,FNVALL,t,1); break; case FN_FPCHAR: t = z_out(channel,bp[1],1,1); break; case FN_FPLINE: t = z_out(channel,bp[1],-1,0); break; case FN_FPBLK: t = z_out(channel,bp[1],-1,1); break; } if (t < 0) { /* Handle read/write error */ failed = 1; if (fndiags && t != FX_EOF) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } if (cx == FN_FGCHAR) /* Null terminate char */ fnval[1] = NUL; /* Write (put) functions return numeric status code */ if (cx == FN_FPCHAR || cx == FN_FPLINE || cx == FN_FPBLK) sprintf(fnval,"%d",t); /* SAFE */ goto fnend; } } #endif /* CKCHANNELIO */ if (cx == FN_SQUEEZE) { /* String function \fsqueeze() */ /* Squeeze out whitespace */ /* Add options later for whether to trim leading and trailing blanks */ /* and what to do about control characters, 8-bit whitespace, etc */ int started = 0; /* Flag for first non-whitespace */ int n = 0; /* Blank/Tab counter */ s = bp[0] ? bp[0] : ""; p = fnval; /* Result buffer */ while (*s) { /* While there is input */ if (!started && (*s == ' ' || *s == '\011')) { s++; /* Skip past leading whitespace */ continue; } started++; /* Leading whitespace was skipped */ if (*s != ' ' && *s != '\011') { /* Have a nonspace char */ n = 0; /* reset space counter */ *p++ = *s++; /* copy char to destination */ continue; } if (n++ > 0) { /* Have blank or tab */ s++; /* don't copy more than one */ continue; } *p++ = ' '; /* Deposit one space */ s++; /* and go to next source char */ } if (*(p-1) == ' ') p--; /* Remove trailing space */ *p = NUL; /* Terminate string */ p = fnval; /* point to beginning */ goto fnend; /* Done. */ } if (cx == FN_PATTERN) { /* \fpattern() for INPUT */ itsapattern = 1; if (argn > 0) { p = fnval; ckstrncpy(fnval,bp[0],FNVALL); } else p = ""; goto fnend; } if (cx == FN_HEX2N || cx == FN_OCT2N) { /* \fhex2n(), \foct2n() */ p = "0"; if (argn < 1) goto fnend; p = ckradix(bp[0], ((cx == FN_HEX2N) ? 16 : 8), 10); if (!p) { if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } failed = 0; ckstrncpy(fnval,p,FNVALL); p = fnval; goto fnend; } if (cx == FN_HEX2IP) { int c[2], ip[4], i, k; p = "0"; if (argn < 1) goto fnend; s = bp[0]; if ((int)strlen(s) != 8) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } p = fnval; for (k = 0; k < 8; k += 2) { for (i = 0; i < 2; i++) { c[i] = *s++; if (islower(c[i])) c[i] = toupper(c[i]); if (c[i] >= '0' && c[i] <= '9') { c[i] -= 0x30; } else if (c[i] >= 'A' && c[i] <= 'F') { c[i] -= 0x37; } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } ip[k/2] = c[0] << 4 | c[1]; } sprintf(p,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]); /* SAFE */ } goto fnend; } if (cx == FN_IP2HEX) { int ip[4], i; char * q; p = "00000000"; if (argn < 1) goto fnend; s = bp[0]; p = fnval; for (i = 0; i < 3; i++) { q = ckstrchr(s,'.'); if (q) { *q++ = NUL; ip[i] = atoi(s); s = q; } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } } ip[3] = atoi(s); sprintf(p,"%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]); /* SAFE */ goto fnend; } if (cx == FN_RADIX) { failed = 1; p = fnval; if (argn < 3) { if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } if (!rdigits(bp[1]) || !rdigits(bp[2])) { if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } p = ckradix(bp[0],atoi(bp[1]),atoi(bp[2])); if (!p) { if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } failed = 0; ckstrncpy(fnval,p,FNVALL); p = fnval; goto fnend; } if (cx == FN_JOIN) { int i, x, y, z, flag, flag2, hi, lo, max, seplen, grouping = 0; char abuf[16], c, *s, *q, *sep = NULL; char * gr_opn = "\"{'([<"; /* Group open brackets */ char * gr_cls = "\"}')]>"; /* Group close brackets */ char lb[2], rb[2]; /* Selected left and right brackets */ int csv = 0, tsv = 0; /* Function flags */ char specialchar = 0; /* Field char that triggers grouping */ char *s2 = NULL; /* Address of malloc'd storage */ failed = 1; /* Assume failure */ fnval[0] = NUL; debug(F101,"FNJOIN ARGN","",argn); ckstrncpy(abuf,bp[0],16); /* Get array reference */ s = abuf; if ((x = arraybounds(s,&lo,&hi)) < 0) { /* Get index and bounds */ if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } p = fnval; /* Point to result */ max = a_dim[x]; /* Size of array */ if (lo < 0) lo = 1; /* Use given range if any */ if (lo > max) lo = max; #ifdef COMMENT hi = max; #else /* This is a workaround for the problem in which the dimension of the \&_[] array (but not its contents) grows upon entry to a SWITCH block. But this code prevents the dimension from growing. Go figure. */ if (hi < 0) { /* Bounds not given */ if (x) /* Regular array */ hi = max; else /* Argument vector array */ for (hi = max; hi >= lo; hi--) { /* ignore any trailing */ if (!a_ptr[x][hi]) continue; /* empty elements */ if (!*(a_ptr[x][hi])) continue; break; } } #endif /* COMMENT */ if (hi > max) hi = max; failed = 0; /* Unset failure flag */ if (max < 1) goto fnend; sep = " "; /* Separator */ lb[0] = NUL; /* Group start char (as string) */ rb[0] = NUL; lb[1] = NUL; /* Group end char as string */ rb[1] = NUL; if (argn > 1) { if (bp[1]) if (*bp[1]) { /* If arg1 given and not empty */ if (!strcmp(bp[1],"CSV")) { /* Special "CSV" symbolic arg */ csv++; /* Make a comma separated list */ sep = ","; /* Comma */ specialchar = *sep; /* Separator is special character */ grouping = 1; /* Group with doublequotes */ lb[0] = '"'; /* and here */ rb[0] = '"'; /* they are */ } else if (!strcmp(bp[1],"TSV")) { /* "TSV" symbolic arg */ tsv++; /* Make a Tab separated list */ sep = "\011"; /* Tab */ specialchar = *sep; grouping = 0; /* No grouping */ } else /* Normal case */ sep = bp[1]; /* use the separator char specified */ } } if (argn > 2 && !csv && !tsv) { /* Grouping? */ char * bp2 = bp[2]; if (!bp2) bp2 = "0"; if (!*bp2) bp2 = "0"; if (chknum(bp2)) { grouping = atoi(bp2); if (grouping < 0 || grouping > 63) grouping = 1; } else { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } if (grouping) { /* Take lowest-order one */ int j, k; /* and set the others to 0 */ for (k = 0; k < 6; k++) { j = 1 << k; if (grouping & j) { lb[0] = gr_opn[k]; rb[0] = gr_cls[k]; break; } } } } if (!csv && !tsv) { /* Normal case, not CSV or TSV */ specialchar = SP; /* Special character is space */ if (argn > 3) /* Nonzero 4th arg for no separator */ if (chknum(bp[3])) if (atoi(bp[3]) > 0) sep = NULL; if (!sep) { sep = ""; seplen = 0; } else seplen = strlen(sep); } for (i = lo; i <= hi; i++) { /* Loop thru selected array elements */ s = a_ptr[x][i]; /* Get next element */ if (!s) s = ""; flag = 0; /* Flag to indicate grouping needed */ flag2 = 0; /* Flag for internal doublequotes */ if (grouping) { /* Does this element need quoting? */ q = s; /* Look for special character */ while ((c = *q++)) { /* If found */ if (c == specialchar) /* grouping is required */ flag++; if (csv && (c == '"')) /* Character that needs doubling */ flag2++; /* in comma-separated list */ if (flag && !csv) /* Exit early if no more to do */ break; } } y = strlen(s); /* Get length of this element */ if ((y > 0) && csv && !flag) { /* CSV item needs grouping */ if (s[0] == SP || s[y-1] == SP || /* if it has leading */ s[0] == HT || s[y-1] == HT) /* or trailing whitespace */ flag++; /* then it needs grouping */ } if (flag || flag2) { /* String needs grouping or quoting */ char *ss = s; q = (char *)malloc(y + flag2 + 3); /* Make new buffer */ if (q) { s2 = q; /* and this is what to free */ if (flag) /* If grouping */ *q++ = lb[0]; /* put opening group quote */ while (*ss) { /* Loop through string */ if (flag2 && (*ss == '"')) /* If CSV and this a '"' */ *q++ = *ss; /* double it. */ *q++ = *ss++; /* Copy the character */ } if (flag) /* If grouping */ *q++ = rb[0]; /* add closing group quote */ *q = NUL; /* terminate the result. */ s = s2; y = strlen(s); } } z = 0; /* Number of chars copied */ flag = 0; /* flag is now buffer-overrun flag */ if (y > 0) /* If this string is not empty */ z = ckstrncat(fnval,s,FNVALL); /* copy it. */ if (s2) free(s2); /* Free temp storage */ if (z < y) /* Now check for buffer overrun. */ flag++; if (!flag && *sep && i < hi) { /* If buffer still has room */ z = ckstrncat(fnval,sep,FNVALL); /* copy delimiter */ if (z < seplen) flag++; } if (flag) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } } isjoin = 1; goto fnend; } if (cx == FN_SUBST) { /* \fsubstitute() */ CHAR c, * s, * r, * tp[2], buf1[256], buf2[256], buf3[256]; int len, i, j, state = 0, lo = 0, hi = 0; failed = 0; p = fnval; /* Result pointer */ *p = NUL; if (!bp[0]) /* No target, no result*/ goto fnend; len = strlen(bp[0]); /* Length of source */ if (len == 0) goto fnend; if (len > FNVALL) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } if (!bp[1]) { ckstrncpy(bp[0],fnval,FNVALL); goto fnend; } tp[0] = buf1; /* For s2-s3 interpretation loop */ tp[1] = buf2; for (i = 0; i < 256; i++) { /* Initialize working buffers */ buf1[i] = 0; /* s2 expansion buffer */ buf2[i] = 0; /* s3 expansion buffer */ buf3[i] = i; /* Translation table */ } for (i = 0; i < 2; i++) { /* Interpret s2 and s3 */ s = (CHAR *)bp[i+1]; /* Arg pointer */ if (!s) s = (CHAR *)""; r = tp[i]; /* To construct interpreted arg */ j = 0; /* Output buf pointer */ state = 0; /* Initial state */ while ((c = *s++)) { /* Loop thru arg chars */ if (j > 255) /* Output buf full */ break; switch (state) { case 0: /* Normal state */ switch (c) { case '\\': /* Have quote */ state = 1; break; case '[': /* Have range starter */ state = 2; break; default: /* Anything else */ r[j++] = c; break; } continue; case 1: /* Quoted char */ r[j++] = c; state = 0; continue; case 2: /* Range bottom */ lo = c; state++; continue; case 3: /* Range separater */ if (c != '-') { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } state++; continue; case 4: /* Range top */ hi = c; state++; continue; case 5: /* Range end */ if (c != ']') { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } for (k = lo; k <= hi && j < 255; k++) /* Fill in */ r[j++] = k; lo = 0; hi = 0; /* Reset */ state = 0; continue; } } } for (i = 0; i < 256 && buf1[i]; i++) { /* Create translation table */ k = (unsigned)buf1[i]; buf3[k] = buf2[i]; } s = (CHAR *)bp[0]; /* Point to source string */ for (i = 0; i < len; i++) { /* Translation loop */ k = (unsigned)s[i]; /* Get next char */ if (!buf3[k]) /* Remove this char */ continue; *p++ = buf3[k]; /* Substitute this char */ } *p = NUL; p = fnval; goto fnend; } #ifndef NOSEXP if (cx == FN_SEXP) { /* \fsexpression(arg1) */ char * p2; fsexpflag++; p = (argn > 0) ? dosexp(bp[0]) : ""; fsexpflag--; p2 = fnval; while ((*p2++ = *p++)) ; p = fnval; goto fnend; } #endif /* NOSEXP */ if (cx == FN_CMDSTK) { /* \fcmdstack(n1,n2) */ int i, j, k; char * s; if (bp[0]) val1 = *(bp[0]) ? evalx(bp[0]) : ckitoa(cmdlvl); else val1 = ckitoa(cmdlvl); #ifdef COMMENT free(bp[0]); /* (evalx() always uses same buffer) */ bp[0] = NULL; /* (not any more!) */ #endif /* COMMENT */ failed = 1; if (argn > 1) { #ifdef COMMENT makestr(&(bp[0]),val1); val1 = bp[0]; #endif /* COMMENT */ val2 = *(bp[1]) ? evalx(bp[1]) : "0"; if (!(chknum(val1) && chknum(val2))) { if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } } else { val1 = ckitoa(cmdlvl); val2 = "0"; } i = atoi(val1); /* Level */ j = atoi(val2); /* Flags */ if (i < 0 || i > cmdlvl) { if (fndiags) ckmakmsg(fnval,FNVALL, "",NULL); goto fnend; } failed = 0; p = fnval; k = cmdstk[i].src; /* What (prompt, file, macro) */ if (j) { ckstrncpy(fnval,ckitoa(k),FNVALL); goto fnend; } switch (k) { case CMD_KB: ckstrncpy(fnval,"(prompt)",FNVALL); break; case CMD_TF: s = tfnam[cmdstk[i].lvl]; if (!zfnqfp(s,FNVALL,fnval)) ckstrncpy(fnval,s,FNVALL); break; case CMD_MD: ckstrncpy(fnval,m_arg[cmdstk[i].lvl][0],FNVALL); break; } goto fnend; } #ifdef CKFLOAT if (cx == FN_DIFDATE) { /* \fdiffdates(d1,d2) */ char * d1, * d2; d1 = bp[0] ? bp[0] : ckdate(); d2 = bp[1] ? bp[1] : ckdate(); p = (char *)cmdiffdate(d1,d2); if (!p) { failed = 1; if (fndiags) { ckmakmsg(fnval,FNVALL,"",NULL); p = fnval; } } goto fnend; } #endif /* CKFLOAT */ if (cx == FN_CMPDATE) { /* \fcmddates(d1,d2) */ int x = 0; char d1[18], d2[18], * dp; failed = 0; d1[0] = NUL; d2[0] = NUL; p = fnval; dp = cmcvtdate(bp[0],1); if (dp) { ckstrncpy(d1,dp,18); if ((dp = cmcvtdate(bp[1],1))) { ckstrncpy(d2,dp,18); x = 1; } } if (x == 0) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); } else { x = strcmp(d1,d2); if (x > 0) x = 1; else if (x < 0) x = -1; sprintf(fnval,"%d",x); } goto fnend; } if (cx == FN_TOGMT) { /* \futcdate(d1) */ char * dp; char datebuf[32]; char d2[32]; p = fnval; failed = 1; if ((dp = cmcvtdate(bp[0],1))) { /* The given date */ ckstrncpy(datebuf,dp,18); ckstrncpy(d2,dp,18); /* local time */ ckstrncat(datebuf,"Z",19); /* Same time GMT */ if ((dp = cmcvtdate(datebuf,1))) /* converted to local time */ ckstrncpy(datebuf,dp,18); if ((p = (char *)cmdiffdate(d2,datebuf))) { /* Get offset */ ckstrncat(d2,p,32); /* Append offset to local time */ if ((dp = cmcvtdate(d2,1))) { failed = 0; ckstrncpy(fnval,dp,FNVALL); p = fnval; } } } if (failed && fndiags) ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } if (cx == FN_DELSEC) { /* \fdelta2secs(delta-time) */ long secs; p = fnval; if ((x = delta2sec(bp[0],&secs)) < 0) { failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL, (x == -1) ? "", NULL ); goto fnend; } sprintf(p,"%ld",secs); goto fnend; } if (cx == FN_PC_DU) { char c, * s = bp[0]; if (!s) s = ""; p = fnval; while ((c = *s++)) { if (c == ':') { if (*s != '\\') *p++ = '/'; } else if (c == '\\') { *p++ = '/'; } else { *p++ = c; } } *p = NUL; p = fnval; goto fnend; } if (cx == FN_PC_UD) { /* Unix to DOS path */ char c, * s = bp[0]; if (!s) s = ""; if (*s == '~') { /* Skip leading tilde */ s++; if (*s == '/') s++; } p = fnval; while ((c = *s++)) *p ++ = (c == '/') ? '\\' : c; *p = NUL; p = fnval; goto fnend; } if (cx == FN_KWVAL) { /* Keyword=Value */ p = dokwval(bp[0],bp[1]?bp[1]:"="); goto fnend; } #ifdef COMMENT /* Cute idea but doesn't work */ if (cx == FN_SLEEP || cx == FN_MSLEEP) { p = ""; if (chknum(bp[0])) { x = atoi(bp[0]); } else { failed = 1; if (fndiags) { ckmakmsg(fnval,FNVALL, "",NULL); p = fnval; } goto fnend; } if (cx == FN_SLEEP) x *= 1000; msleep(x); goto fnend; } #endif /* COMMENT */ #ifdef NT if (cx == FN_SNAME) { ckGetShortPathName(bp[0],fnval,FNVALL); goto fnend; } if (cx == FN_LNAME) { ckGetLongPathName(bp[0],fnval,FNVALL); goto fnend; } #endif /* NT */ /* \femailaddress(): Picks the email address out of an RFC 2822 From: or Sender: header. Added 26 Nov 2005. Handles all common, and some uncommon, cases but doesn't totally bother about nested comments. Needed this for fetching email from a POP server and then constructing the BSD "From " line. Works with or without the "From: " or "Sender: " tag. */ if (cx == FN_EMAIL) { char * s = bp[0], * s2, * s3, * ap = ""; int k; #ifdef COMMENT char c; int quote = 0, state = 0, infield = 0 , pc = 0; /* For nested comments */ #endif /* COMMENT */ if (!s) s = ""; if (!*s) goto xemail; if (ckindex("From: ",s,0,0,0) == 1) s += 5; if (ckindex("Sender: ",s,0,0,0) == 1) s += 7; k = strlen(s); /* Strip junk from end */ if (k < 1) goto xemail; k--; while (k >= 0 && s[k] == CK_CR || s[k] == LF) s[k--] = NUL; while (k >= 0 && s[k] == SP || s[k] == HT) s[k--] = NUL; if (k == 0) goto xemail; #ifndef COMMENT /* Simple method if not 100% foolproof */ k = 0; for (s2 = s; *s2; s2++) { /* Find at-sign */ if (*s2 == '@') { k++; /* If more than one use rightmost */ s3 = s2; } } if (k < 1) /* No at-sign */ goto xemail; for (ap = s3-1; ap >= s; ap--) { /* Back up to beginning of address */ if (isspace(*ap) || *ap == '<') { ap++; break; } if (ap == s) break; } for (s2 = s3+1; *s2; s2++) { /* Find end of address */ if (isspace(*s2) || *s2 == '>') break; } *s2-- = NUL; if (*ap == '[' && *s2 == ']') { /* Handle [blah@blah.blah] */ ap++; *s2 = NUL; } if (!ckstrcmp(ap,"mailto:",7,0)) /* Handle mailto: URLs */ ap += 7; #else /* Too complicated and error-prone */ k = 0; for (s2 = s; *s2; s2++) { /* Strip leading whitespace */ if (*s2 == SP || *s2 == HT) { k = 1; break; } } if (!k) { /* Simple address */ ap = s; goto xemail; } do { /* Not simple, have to extract it */ if (quote) { quote = 0; continue; } else if (*s == '\\') { quote = 1; continue; } switch (state) { case 0: if (!infield && *s == '"') { /* Quoted string */ infield = 1; c = '"'; state = 1; } else if (!infield && *s == '(') { /* Comment in parens */ pc++; infield = 1; c = ')'; if (*ap) *s = NUL; state = 1; } else if (!infield && *s == '<') { /* Address */ infield = 1; c = '>'; ap = s+1; state = 2; } else if (infield && (*s == SP || *s == HT)) { infield = 0; } else { /* One or more bare words */ infield = 1; /* Could be an address */ if (!*ap) ap = s; /* Could be comments */ } continue; case 1: /* In Quoted string or Comment */ if (infield && *s == c) { /* Look for end */ infield = 0; *s++ = NUL; while (*s == SP || *s == HT) s++; if (!*ap) ap = s; state = 0; } continue; case 2: /* In address */ if (infield && *s == c) { /* Looking for end */ infield = 0; *s = NUL; break; } } } while (*s++); xemail: if (*ap) { while (*ap == SP || *ap == HT) ap++; } k = strlen(ap) - 1; while (k >= 0 && (ap[k] == SP || ap[k] == HT)) ap[k--] = NUL; if (*ap) { failed = 0; if (*ap == '<') { k = strlen(ap); if (*(ap+k-1) == '>') { ap[k-1] = NUL; ap++; } } } else failed = 1; /* Here we might also want check against "*@*.*" */ #endif /* COMMENt */ xemail: ckstrncpy(fnval,ap,FNVALL); goto fnend; } #ifdef SEEK_CUR /* \fpictureinfo(): Get dimensions of GIF or JPG image - fdc June 2006. NOTE: The height and width of a JPG image do not necessarily indicate an image's actual orientation. This is given by the Exif Orientation tag (0x0122). But locating it in a JPG file without having a full-blown Exif parser is probably not possible. */ if (cx == FN_PICTURE) { FILE *fp = NULL; int c, x, w = 0, h = 0, eof = 0; unsigned int j, k; unsigned char buf[1024]; char abuf[16], * p, * s; char ** ap = NULL; #ifdef UNIX char * tx; #endif /* UNIX */ p = fnval; /* Point to result */ failed = 1; /* Assume failure */ s = bp[0]; #ifdef UNIX if (*s == '~') { tx = tilde_expand(bp[0]); if (tx) if (*tx) { free(bp[0]); bp[0] = NULL; makestr(&(bp[0]),tx); } s = bp[0]; } #endif /* UNIX */ if (argn > 1) { int xi; ckstrncpy(abuf,bp[1],16); /* Get array reference */ s = abuf; if (*s == CMDQ) s++; if (fndiags) /* Default is this error message */ ckmakmsg(fnval,FNVALL, "",NULL); if (s[0] != '&') /* "Address" of array */ goto fnend; if (s[2]) if (s[2] != '[' || s[3] != ']') goto fnend; if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */ s[1] += 32; if ((xi = dclarray(s[1],3)) < 0) /* three elements */ goto fnend; ap = a_ptr[xi]; /* Point to array we just declared */ } s = bp[0]; /* Filename */ failed = 0; /* From here on we don't fail */ p[0] = '0'; /* Default return value */ p[1] = NUL; /* Tail anchor removed 2013-10-15 -fdc */ if (!ckmatch("*.{jpg,jpeg,gif}",s,0,1)) /* Appropriate name? */ goto fnend; /* No, fail */ fp = fopen(s, "r"); /* Open it */ if (fp == NULL) { /* Can't, fail */ p[0] = '-'; p[1] = '1'; p[2] = NUL; /* Return -1 */ goto fnend; } k = strlen(s); if (!ckstrcmp(&s[k-4],".gif",4,0)) { /* GIF file */ if (fread(buf,1,10,fp) != 10) { fclose(fp); goto fnend; } /* Check signature */ if (ckstrcmp((char *)buf,"GIF87a",6,0) && ckstrcmp((char *)buf,"GIF89a",6,0)) { fclose(fp); goto fnend; } w = buf[6] + 256 * buf[7]; h = buf[8] + 256 * buf[9]; goto picend; } else if (!ckstrcmp(&s[k-4],".jpg",4,0) || /* JPEG file */ !ckstrcmp(&s[k-5],".jpeg",5,0)) { /* (according to name) */ if (fread(buf,1,2,fp) != 2) { /* Read 1st bytes */ fclose(fp); goto fnend; } if (buf[0] != 0xff || buf[1] != 0xd8) { /* Check signature */ fclose(fp); /* Should be FFD8 */ goto fnend; } eof = 0; while (!eof) { /* Loop for each marker */ while (!eof) { /* Find next marker */ c = getc(fp); if (c == (unsigned int)EOF) { eof++; break; } if (c == 0xff) { buf[0] = c; c = getc(fp); if (c == (unsigned int)EOF) { eof++; break; } buf[1] = c; if (c == 0xd9) /* FFD9 means End of Image */ eof++; if (c >= 0xc0 && c <= 0xfe) break; } } if (eof) break; x = buf[1]; if (x == 0xc0 || x == 0xc1 || x == 0xc2 || x == 0xc3 || x == 0xc9 || x == 0xca || x == 0xcb) { if (fread(buf,1,7,fp) != 7) { fclose(fp); goto fnend; } h = buf[3] * 256 + buf[4]; w = buf[5] * 256 + buf[6]; goto picend; } else { /* Not a desired field */ if (feof(fp)) { eof++; break; } if (fread(buf,1,2,fp) != 2) { /* Length of this field */ fclose(fp); goto fnend; } j = 256 * buf[0] + buf[1] - 2; /* Skip next field */ if (CKFSEEK(fp,(CK_OFF_T)j,SEEK_CUR) != 0) { fclose(fp); goto fnend; } } } } picend: if (ap) { char * s; makestr(&(ap[0]),"2"); makestr(&(ap[1]),ckitoa(w)); makestr(&(ap[2]),ckitoa(h)); s = jpgdate(fp); debug(F110,"jpgdate",s,0); if (s) if (*s) makestr(&(ap[3]),s); } fclose(fp); if (w > 0 && h > 0) { if (w > h) p[0] = '1'; /* Landscape */ else if (h > w) p[0] = '2'; /* Portrait */ else p[0] = '3'; /* Square - 2013-10-05 */ } goto fnend; } #endif /* SEEK_CUR */ if (cx == FN_PID) { int x = -1; if (chknum(bp[0])) { /* Need numeric argument */ int pid; pid = atoi(bp[0]); /* Convert to int */ #ifdef UNIX if (kill(pid,0) < 0) { /* Test it */ if (errno == #ifdef ESRCH ESRCH /* No such process */ #else 3 #endif /* ESRCH */ ) x = 0; } else /* Process exists */ x = 1; #endif /* UNIX */ } sprintf(fnval,"%d",x); /* SAFE */ goto fnend; } if (cx == FN_FUNC) { char * s = bp[0]; p = "0"; debug(F111,"ffunc",s,argn); if (argn > 0) { int x, y; for (p = s; *p; p++) { /* Chop off trailing parens if any */ if (*p == '(') { *p = NUL; break; } } /* Chop off leading "\\f" or "\f" or "f" */ p = s; if (*p == CMDQ) /* Allow for \\f... */ p++; if (*p == CMDQ && (*(p+1) == 'f' || *(p+1) == 'F')) { /* or \f */ p += 2; } else if (*p == 'f' || *p == 'F') { /* or just f */ p++; } y = lookup(fnctab,p,nfuncs,&x); /* Look up the result */ debug(F111,"ffunc",p,y); p = (y > -1) ? "1" : "0"; } goto fnend; } if (cx == FN_RECURSE) { int n; char * s; fnval[0] = NUL; /* Default result is empty string */ s = bp[0]; /* Check for null argument */ if (!s) s = ""; /* or empty argument */ if (!*s) goto fnend; /* in which case return empty string */ n = FNVALL; /* Not empty, max size for result */ s = fnval; /* Location of result */ { /* Force VARIABLE-EVALUATION SIMPLE RECURSIVE */ /* NOTE: This is vulnerable to SIGINT and whatnot... */ int tmp = vareval; /* Save VARIABLE-EVALUATION setting */ vareval = 1; /* Force it to RECURSIVE */ zzstring(bp[0],&s,&n); /* Expand arg into result space */ vareval = tmp; /* Restore VARIABLE-EVALUATION */ } goto fnend; } if (cx == FN_XLATE) { /* f_cvtcset() */ #ifdef NOFRILLS ckstrncpy(fnval,bp[0],FNVALL); #else #ifndef NOUNICODE _PROTOTYP( char * cvtstring, (char *, int, int) ); char * string, * cset1, * cset2; int id1, id2; #endif /* NOUNICODE */ fnval[0] = NUL; #ifdef NOUNICODE ckstrncpy(fnval,bp[0],FNVALL); #else string = bp[0] ? bp[0] : ""; /* String to convert */ if (!*string) goto fnend; /* It's empty */ cset1 = bp[1] ? bp[1] : "ascii"; /* Current charset of string */ cset2 = bp[2] ? bp[2] : "ascii"; /* Charset to convert to */ id1 = lookup(fcstab,cset1,nfilc,NULL); /* Lookup 'from' set */ if (id1 < 0) { failed = 1; ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } id2 = lookup(fcstab,cset2,nfilc,NULL); /* Lookup 'to' set */ if (id2 < 0) { failed = 1; ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } string = cvtstring(string,id1,id2); ckstrncpy(fnval,string,FNVALL); #endif /* NOUNICODE */ #endif /* NOFRILLS */ goto fnend; } /* Decode strings containing hex escapes */ if (cx == FN_UNPCT) { /* \fdecodehex() */ char *s1; char *prefix; /* Can be 1 or 2 chars */ char buf[3]; int n = 0, k; p = fnval; *p = NUL; if (argn < 1) goto fnend; /* Empty string */ s1 = bp[0] ? bp[0] : ""; /* Original string */ prefix = bp[1] ? bp[1] : "%%"; /* Hex byte prefix */ n = (int)strlen(prefix); /* Length of prefix */ if (n < 1 || n > 2) { /* must be 1 or 2 */ ckmakmsg(fnval,FNVALL, "",NULL); goto xunpct; } while (*s1) { if (!ckstrcmp(s1,prefix,n,0)) { /* Case-independent */ if (!*(s1+n)) { ckmakmsg(fnval,FNVALL, "",NULL); goto xunpct; } buf[0] = *(s1+n); /* First hex character */ buf[1] = *(s1+n+1); /* Second hex character */ buf[2] = NUL; if ((k = ckhexbytetoint((char *)buf)) > -1) { *p++ = (char) k; /* Deposit decoded result */ s1 += 2+n; /* and advance the source pointer */ } else { /* Fail on conversion error */ ckmakmsg(fnval,FNVALL, "",NULL); goto xunpct; } } else { /* Not a hex escape sequence */ *p++ = *s1++; /* Just copy the character */ } } *p = NUL; /* Terminate the result string */ failed = 0; /* Say we didn't fail */ p = fnval; /* Set up result pointer */ goto fnend; /* and finish */ xunpct: /* Error exit */ p = fnval; failed = 1; goto fnend; } /* Check a string for encoding family */ if (cx == FN_STRINGT) { /* \fstringtype() */ p = "UNK"; switch (scanstring(bp[0])) { case FT_7BIT: p = "7BIT"; break; case FT_8BIT: p = "8BIT"; break; case FT_UTF8: p = "UTF8"; break; case FT_UCS2: p = "UCS2"; break; case FT_TEXT: p = "TEXT"; break; case FT_BIN: p = "BINARY"; break; } ckstrncpy(fnval,p,FNVALL); p = fnval; goto fnend; } /* String compare s1, s2, [ case ], [ start ] , [ len ] */ if (cx == FN_STRCMP) { int docase = 0; /* Case matters or not */ int start = 0; /* Start of substring */ int len = -1; /* Length of substring to compare */ int x; char * s1, * s2; /* workers */ p = "0"; /* Return value */ if (argn == 0) { /* Two null strings are equal */ ckstrncpy(fnval,p,FNVALL); p = fnval; goto fnend; } if (argn == 1) { /* Non-null string > null string */ p = "1"; ckstrncpy(fnval,p,FNVALL); p = fnval; goto fnend; } if (argn > 2) { s = *(bp[2]) ? evalx(bp[2]) : "0"; /* 0 = caseless */ if (chknum(s)) docase = atoi(s); if (argn > 3) { s = *(bp[3]) ? evalx(bp[3]) : "1"; /* start is 1-based */ if (chknum(s)) start = atoi(s); if (argn > 4) { s = *(bp[4]) ? evalx(bp[4]) : "-1"; /* -1 = whole thing */ if (chknum(s)) len = atoi(s); } } } if (start > 0) start--; /* start is 0-based internally */ s1 = bp[0]; /* Get length of first arg */ x = (int)strlen(s1); if (x > start) /* Point to start position of s1 */ s1 += start; else s1 = ""; s2 = bp[1]; /* Get length of second arg */ x = (int)strlen(s2); if (x > start) /* Point to start position of s2 */ s2 += start; else s2 = ""; x = ckstrcmp(s,s2,len,docase); p = ckitoa(x); ckstrncpy(fnval,p,FNVALL); p = fnval; goto fnend; } #ifdef HAVE_LOCALE /* \fdayname() - Returns locale-dependent day name string - 2013/07/23 */ if (cx == FN_DAYNAME) { _PROTOTYP( char * locale_dayname, (int, int) ); char *s1, *s2; char buf[3]; int fc = 0, day = 999; s1 = bp[0]; s2 = bp[1]; p = fnval; *p = NUL; if (!s1) s1 = ""; if (!*s1) { s1 = ckdate(); } else if (rdigits(s1) && (int)strlen(s1) < 8) { day = atoi(s1); if (day == 0) day = 7; /* In case \v(nday) used as arg */ if (day < 1 || day > 7) { ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } day--; /* Adjust to zero-based */ } else if (!(s1 = cmcvtdate(s1,1))) { ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } if (!s2) s2 = ""; /* Parse function code */ if (!*s2) { fc = 0; } else if (rdigits(s2)) { fc = atoi(s2); } else { failed = 1; ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } if (day > 6) { /* Day number was not given */ day = (mjd(s1) % 7) + 2; /* Get day number */ if (day > 6) day -= 7; /* Adjust to 0=Sunday */ } s1 = locale_dayname(day,fc); /* Get locale-based day name */ if (!s1) { failed = 1; ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } ckstrncpy(fnval,s1,FNVALL); goto fnend; } /* \fmonthname() - Returns locale-dependent month name string 2013/07/24 */ if (cx == FN_MONNAME) { _PROTOTYP( char * locale_monthname, (int, int) ); char *s1, *s2; char buf[3]; int fc = 0, month = 999; s1 = bp[0]; s2 = bp[1]; p = fnval; *p = NUL; if (!s1) s1 = ""; if (!*s1) { s1 = ckdate(); } else if (rdigits(s1) && (int)strlen(s1) < 8) { month = atoi(s1); if (month == 0) month = 12; if (month < 1 || month > 12) { ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } month--; /* Adjust to zero-based */ } else if (!(s1 = cmcvtdate(s1,1))) { ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } if (month > 12) { char mn[3]; mn[0] = s1[4]; mn[1] = s1[5]; mn[2] = NUL; month = atoi((char *)mn) - 1; } if (!s2) s2 = ""; /* Parse function code */ if (!*s2) { fc = 0; } else if (rdigits(s2)) { fc = atoi(s2); } else { failed = 1; ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } s1 = locale_monthname(month,fc); /* Get locale-based month name */ if (!s1) { failed = 1; ckmakmsg(fnval,FNVALL,"",NULL); goto fnend; } ckstrncpy(fnval,s1,FNVALL); goto fnend; } #endif /* HAVE_LOCALE */ /* Note: when adding new functions remember to update dohfunc in ckuus2.c. */ failed = 1; if (fndiags) ckmakmsg(fnval,FNVALL,"",NULL); fnend: /* Free temporary storage for aguments */ for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]); fndepth--; if (failed) { /* Handle failure */ debug(F111,"fnend",fnval,errno); if (!p) p = ""; if (p[0]) { /* In case this wasn't caught above... */ k = strlen(p); if (p[0] != '<' && p[k-1] != '>') { ckmakmsg(fnval,FNVALL,"",NULL); p = fnval; } } else { ckmakmsg(fnval,FNVALL,"",NULL); p = fnval; } if (fnerror) /* SET FUNCTION ERROR ON */ fnsuccess = 0; /* Make command fail (see ckuus5.c) */ debug(F111,"fneval failed",p,fnsuccess); if (fndiags) /* SET FUNCTION DIAGNOSTICS ON */ printf("?%s\n",p); /* Print error message now. */ else return(""); /* Return nothing. */ } return(p); } #endif /* NOSPL */ static char ckpidbuf[32] = "????"; #ifdef VMS _PROTOTYP(long zgpid,(void)); #endif /* VMS */ char * ckgetpid() { /* Return pid as string */ #ifdef CK_PID #ifdef OS2 #ifndef __WATCOMC__ #define getpid _getpid #endif /* __WATCOMC__ */ unsigned long zz; #else long zz; #endif /* OS2 */ #ifdef VMS zz = zgpid(); #else zz = getpid(); #endif /* VMS */ sprintf(ckpidbuf,"%ld",zz); /* SAFE */ #endif /* CK_PID */ return((char *)ckpidbuf); } #ifndef NOSPL #define EMBUFLEN 128 /* Error message buffer length */ static char embuf[EMBUFLEN+1]; char * /* Evaluate builtin variable */ #ifdef CK_ANSIC nvlook( char *s ) #else nvlook(s) char *s; #endif /* CK_ANSIC */ { int x, y, cx; long z; char *p; #ifndef NODIAL MDMINF * m; #endif /* NODIAL */ #ifndef NOKVERBS /* Keyboard macro material */ extern int keymac, keymacx; #endif /* NOKVERBS */ #ifdef CK_LOGIN extern int isguest; #endif /* CK_LOGIN */ if (!s) s = ""; x = strlen(s); if (fndiags) { /* FUNCTION DIAGNOSTIC ON */ if (x + 32 < EMBUFLEN) sprintf(embuf,"",s); /* SAFE */ else sprintf(embuf,""); /* SAFE */ } else /* FUNCTION DIAGNOSTIC OFF */ embuf[0] = NUL; x = VVBUFL; p = vvbuf; if (zzstring(s,&p,&x) < 0) { /* e.g. for \v(\%a) */ y = -1; } else { s = vvbuf; y = lookup(vartab,s,nvars,&x); } cx = y; /* y is too generic */ #ifndef NODIAL m = (mdmtyp > 0) ? modemp[mdmtyp] : NULL; /* For \v(m_xxx) variables */ #endif /* NODIAL */ debug(F101,"nvlook y","",y); switch (y) { case VN_ARGC: /* ARGC */ sprintf(vvbuf,"%d",maclvl < 0 ? topargc : macargc[maclvl]); /* SAFE */ return(vvbuf); case VN_ARGS: /* ARGS */ sprintf(vvbuf,"%d",xargs); /* SAFE */ return(vvbuf); case VN_COUN: /* COUNT */ sprintf(vvbuf,"%d",count[cmdlvl]); /* SAFE */ return(vvbuf); case VN_DATE: /* DATE */ ztime(&p); /* Get "asctime" string */ if (p == NULL || *p == NUL) return(NULL); vvbuf[0] = p[8]; /* dd */ vvbuf[1] = p[9]; vvbuf[2] = SP; vvbuf[3] = p[4]; /* mmm */ vvbuf[4] = p[5]; vvbuf[5] = p[6]; vvbuf[6] = SP; for (x = 20; x < 24; x++) /* yyyy */ vvbuf[x - 13] = p[x]; vvbuf[11] = NUL; return(vvbuf); case VN_NDAT: /* Numeric date */ ckstrncpy(vvbuf,zzndate(),VVBUFL); return(vvbuf); case VN_DIRE: /* DIRECTORY */ s = zgtdir(); /* Get current directory */ if (!s) #ifdef UNIXOROSK s = "./"; #else #ifdef VMS s = "[]"; #else s = ""; #endif /* VMS */ #endif /* UNIXOROSK */ ckstrncpy(vvbuf,s,VVBUFL); s = vvbuf; #ifdef UNIXOROSK x = strlen(s); if (x < VVBUFL - 1) { if (s[x-1] != '/') { s[x] = '/'; s[x+1] = NUL; } } #endif /* UNIXOROSK */ return(s); case VN_FILE: /* filespec */ return(fspec); case VN_HOST: /* host name */ if (*myhost) { /* If known */ return(myhost); /* return it. */ } else { /* Otherwise */ ckstrncpy(vvbuf,"unknown",VVBUFL); /* just say "unknown" */ return(vvbuf); } case VN_SYST: /* System type */ #ifdef UNIX ckstrncpy(vvbuf,"UNIX",VVBUFL); #else #ifdef VMS ckstrncpy(vvbuf,"VMS",VVBUFL); #else #ifdef OSK ckstrncpy(vvbuf,"OS9/68K",VVBUFL); #else #ifdef AMIGA ckstrncpy(vvbuf,"Amiga",VVBUFL); #else #ifdef MAC ckstrncpy(vvbuf,"Macintosh",VVBUFL); #else #ifdef OS2 #ifdef NT ckstrncpy(vvbuf,"WIN32",VVBUFL) ; #else /* NT */ ckstrncpy(vvbuf,"OS/2",VVBUFL); #endif /* NT */ #else #ifdef datageneral ckstrncpy(vvbuf,"AOS/VS",VVBUFL); #else #ifdef GEMDOS ckstrncpy(vvbuf,"Atari_ST",VVBUFL); #else #ifdef STRATUS ckstrncpy(vvbuf,"Stratus_VOS",VVBUFL); #else ckstrncpy(vvbuf,"unknown",VVBUFL); #endif /* STRATUS */ #endif /* GEMDOS */ #endif /* datageneral */ #endif /* OS2 */ #endif /* MAC */ #endif /* AMIGA */ #endif /* OSK */ #endif /* VMS */ #endif /* UNIX */ return(vvbuf); case VN_SYSV: /* System herald */ #ifdef IKSD #ifdef CK_LOGIN if (inserver && isguest) return(""); #endif /* CK_LOGIN */ #endif /* IKSD */ for (x = y = 0; x < VVBUFL; x++) { if (ckxsys[x] == SP && y == 0) continue; vvbuf[y++] = (char) ((ckxsys[x] == SP) ? '_' : ckxsys[x]); } vvbuf[y] = NUL; return(vvbuf); } /* Break up long switch statements... */ switch(y) { case VN_TIME: /* TIME. Assumes that ztime returns */ ztime(&p); /* "Thu Feb 8 12:00:00 1990" */ if (p == NULL || *p == NUL) /* like asctime()! */ return(""); for (x = 11; x < 19; x++) /* copy hh:mm:ss */ vvbuf[x - 11] = p[x]; /* to vvbuf */ vvbuf[8] = NUL; /* terminate */ return(vvbuf); /* and return it */ case VN_NTIM: /* Numeric time */ ztime(&p); /* "Thu Feb 8 12:00:00 1990" */ if (p == NULL || *p == NUL) /* like asctime()! */ return(NULL); z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17); sprintf(vvbuf,"%ld",z); /* SAFE */ return(vvbuf); #ifdef CK_TTYFD case VN_TTYF: /* TTY file descriptor */ sprintf(vvbuf,"%d", /* SAFE */ #ifdef VMS vmsttyfd() #else ttyfd #endif /* VMS */ ); return(vvbuf); #endif /* CK_TTYFD */ case VN_VERS: /* Numeric Kermit version number */ sprintf(vvbuf,"%ld",vernum); /* SAFE */ return(vvbuf); case VN_XVNUM: /* Product-specific version number */ sprintf(vvbuf,"%ld",xvernum); /* SAFE */ return(vvbuf); case VN_FULLVER: /* Full version number (edit 400) */ { extern char *ck_s_ver, *ck_s_edit, *ck_s_test, *ck_s_tver; if (x > strlen(ck_s_test)) { sprintf(vvbuf,"%s.%s %s.%s", ck_s_ver, ck_s_edit, ck_s_test, ck_s_tver); /* SAFE */ } else { sprintf(vvbuf,"%s.%s", ck_s_ver, ck_s_edit); /* SAFE */ } return(vvbuf); } case VN_HOME: /* Home directory */ return(homepath()); case VN_IBUF: /* INPUT buffer */ return((char *)inpbuf); case VN_ICHR: /* INPUT character */ inchar[1] = NUL; return((char *)inchar); case VN_ICNT: /* INPUT character count */ sprintf(vvbuf,"%d",incount); /* SAFE */ return(vvbuf); case VN_SPEE: { /* Transmission SPEED */ long t; t = ttgspd(); if (t < 0L) sprintf(vvbuf,"unknown"); /* SAFE */ else sprintf(vvbuf,"%ld",t); /* SAFE */ return(vvbuf); } case VN_SUCC: /* SUCCESS flag */ /* Note inverted sense */ sprintf(vvbuf,"%d",(success == 0) ? 1 : 0); /* SAFE */ return(vvbuf); case VN_LINE: { /* LINE */ #ifdef DEBUG if (deblog) { debug(F111,"\\v(line) local",ttname,local); debug(F111,"\\v(line) inserver","",inserver); #ifdef TNCODE debug(F111,"\\v(line) tcp_incoming","",tcp_incoming); #endif /* TNCODE */ #ifdef CK_TAPI debug(F111,"\\v(line) tttapi","",tttapi); #endif /* CK_TAPI */ } #endif /* DEBUG */ #ifdef CK_TAPI if (tttapi) { /* If I have made a TAPI connection */ int i; /* return the TAPI device name */ for (i = 0; i < ntapiline; i++) { if (!strcmp(ttname,tapilinetab[i].kwd)) { p = _tapilinetab[i].kwd; return(p); } } } #endif /* CK_TAPI */ #ifndef NOXFER if (inserver /* If I am a TCP server */ #ifdef TNCODE || tcp_incoming #endif /* TNCODE */ ) #ifdef TCPSOCKET p = ckgetpeer(); /* return peer name */ else #endif /* TCPSOCKET */ #endif /* NOXFER */ if (local) /* Otherwise if in local mode */ p = (char *) ttname; /* return SET LINE / SET HOST name */ else /* Otherwise */ p = ""; /* return empty string */ if (!p) /* In case ckgetpeer() returns */ p = ""; /* null pointer... */ debug(F110,"\\v(line) p",p,0); if (!*p) p = (char *) ttname; return(p); } case VN_PROG: /* Program name */ return("C-Kermit"); } /* Break up long switch statements... */ switch(y) { case VN_RET: /* Value of most recent RETURN */ debug(F111,"\\v(return)",mrval[maclvl+1],maclvl+1); p = mrval[maclvl+1]; if (p == NULL) p = ""; return(p); case VN_FFC: /* Size of most recent file */ sprintf(vvbuf, "%s", ckfstoa(ffc)); /* SAFE */ return(vvbuf); case VN_TFC: /* Size of most recent file group */ sprintf(vvbuf, "%s", ckfstoa(tfc)); /* SAFE */ return(vvbuf); case VN_CPU: /* CPU type */ #ifdef IKSD #ifdef CK_LOGIN if (inserver && isguest) return(""); #endif /* CK_LOGIN */ #endif /* IKSD */ #ifdef OS2 { char * getcpu(void) ; return getcpu(); } #else /* OS2 */ #ifdef CKCPU return(CKCPU); /* Traditionally, compile-time value */ #else #ifdef CK_UTSNAME { /* But if none, try runtime value */ extern char unm_mch[]; return((char *)unm_mch); } #else p = getenv("HOSTTYPE"); /* 20091116 */ if (p) if (*p) return(p); return("unknown"); #endif /* CK_UTSNAME */ #endif /* CKCPU */ #endif /* OS2 */ case VN_CMDL: /* Command level */ sprintf(vvbuf, "%d", cmdlvl); /* SAFE */ return(vvbuf); case VN_DAY: /* Current day of the week */ ztime(&p); /* three-letter abbreviation */ if (p != NULL && *p != NUL) /* ztime() succeeded. */ ckstrncpy(vvbuf,p,4); else vvbuf[0] = NUL; /* ztime() failed. */ return(vvbuf); /* Return what we got. */ case VN_NDAY: { /* Numeric day of week */ long k; z = mjd(zzndate()); /* Get modified Julian date */ k = (((int)(z % 7L)) + 3) % 7; /* Get day number */ sprintf(vvbuf,"%ld",k); /* SAFE */ return(vvbuf); case VN_MONTH: ztime(&p); /* three-letter abbreviation */ if (p != NULL && *p != NUL) /* ztime() succeeded. */ ckstrncpy(vvbuf,p+4,5); else vvbuf[0] = NUL; /* ztime() failed. */ return(vvbuf); /* Return what we got. */ case VN_NMONTH: { /* Numeric month (1-12) */ int x; ztime(&p); /* asctime three-letter abbreviation */ for (x = 0; x < 12; x++) if (!strncmp(p+4,months[x],3)) break; if (x == 12) { vvbuf[0] = '?'; vvbuf[1] = '?'; } else { x++; vvbuf[0] = (char) ((x < 10) ? '0' : '1'); vvbuf[1] = (char) ((x % 10) + 48); } vvbuf[2] = NUL; return(vvbuf); /* Return what we got. */ } case VN_YEAR: /* Current year */ ztime(&p); if (p != NULL && *p != NUL) /* ztime() succeeded. */ ckstrncpy(vvbuf,p+20,5); else vvbuf[0] = NUL; /* ztime() failed. */ return(vvbuf); /* Return what we got. */ } case VN_LCL: /* Local (vs remote) mode */ ckstrncpy(vvbuf, local ? "1" : "0",VVBUFL); return(vvbuf); case VN_CMDS: /* Command source */ if (cmdstk[cmdlvl].src == CMD_KB) ckstrncpy(vvbuf,"prompt",VVBUFL); else if (cmdstk[cmdlvl].src == CMD_MD) ckstrncpy(vvbuf,"macro",VVBUFL); else if (cmdstk[cmdlvl].src == CMD_TF) ckstrncpy(vvbuf,"file",VVBUFL); else ckstrncpy(vvbuf,"unknown",VVBUFL); return(vvbuf); case VN_CMDF: /* Current command file name */ /* printf("ENTERING VN_CMDF; tlevel=%d...\n",tlevel); */ #ifdef COMMENT /* (see comments above) */ if (tfnam[tlevel]) { /* (near dblbs declaration) */ dblbs(tfnam[tlevel],vvbuf,VVBUFL); return(vvbuf); } else return(""); #else if (tlevel < 0) { return(""); } else { /* printf("FN_CMDF tlevel:cmdfile:%d:[%s]\n",tlevel,tfnam[tlevel]); */ return(tfnam[tlevel] ? tfnam[tlevel] : ""); } #endif /* COMMENT */ case VN_MAC: /* Current macro name */ return((maclvl > -1) ? m_arg[maclvl][0] : ""); case VN_EXIT: sprintf(vvbuf,"%d",xitsta); /* SAFE */ return(vvbuf); } /* Break up long switch statements... */ switch(y) { case VN_PRTY: { /* Parity */ char *ss; switch (parity) { case 0: ss = "none"; break; case 'e': ss = "even"; break; case 'm': ss = "mark"; break; case 'o': ss = "odd"; break; case 's': ss = "space"; break; default: ss = "unknown"; break; } ckstrncpy(vvbuf,ss,VVBUFL); return(vvbuf); } case VN_DIAL: sprintf(vvbuf,"%d", /* SAFE */ #ifndef NODIAL dialsta #else -1 #endif /* NODIAL */ ); return(vvbuf); #ifndef NODIAL case VN_DMSG: #ifdef BIGBUFOK ckstrncpy(vvbuf, ((dialsta < 0) ? "(none)" : dialmsg[dialsta]), VVBUFL); /* Safe if src == NULL.. mdw 20140213 */ #endif /* BIGBUFOK */ return((char *)vvbuf); #endif /* NODIAL */ #ifdef OS2 case VN_KEYB: ckstrncpy(vvbuf,conkbg(),VVBUFL); return(vvbuf); case VN_SELCT: { #ifndef NOLOCAL const char * selection = GetSelection(); return( (char *) (selection ? selection : "" )) ; #else return(""); #endif /* NOLOCAL */ } #endif /* OS2 */ #ifndef NOXFER case VN_CPS: sprintf(vvbuf,"%ld",tfcps); /* SAFE */ return(vvbuf); #endif /* NOXFER */ case VN_MODE: /* File transfer mode */ switch (binary) { case XYFT_T: ckstrncpy(vvbuf,"text",VVBUFL); break; case XYFT_B: case XYFT_U: ckstrncpy(vvbuf,"binary",VVBUFL); break; case XYFT_I: ckstrncpy(vvbuf,"image",VVBUFL); break; case XYFT_L: ckstrncpy(vvbuf,"labeled",VVBUFL); break; case XYFT_M: ckstrncpy(vvbuf,"macbinary",VVBUFL); break; default: ckstrncpy(vvbuf,"unknown",VVBUFL); } return(vvbuf); #ifdef CK_REXX case VN_REXX: return(rexxbuf); #endif /* CK_REXX */ case VN_NEWL: /* System newline char or sequence */ #ifdef UNIX ckstrncpy(vvbuf,"\n",VVBUFL); #else #ifdef datageneral ckstrncpy(vvbuf,"\n",VVBUFL); #else #ifdef OSK ckstrncpy(vvbuf,"\15",VVBUFL); /* Remember, these are octal... */ #else #ifdef MAC ckstrncpy(vvbuf,"\15",VVBUFL); #else #ifdef OS2 ckstrncpy(vvbuf,"\15\12",VVBUFL); #else #ifdef STRATUS ckstrncpy(vvbuf,"\n",VVBUFL); #else #ifdef VMS ckstrncpy(vvbuf,"\15\12",VVBUFL); #else #ifdef AMIGA ckstrncpy(vvbuf,"\n",VVBUFL); #else #ifdef GEMDOS ckstrncpy(vvbuf,"\n",VVBUFL); #else ckstrncpy(vvbuf,"\n",VVBUFL); #endif /* GEMDOS */ #endif /* AMIGA */ #endif /* VMS */ #endif /* STRATUS */ #endif /* OS2 */ #endif /* MAC */ #endif /* OSK */ #endif /* datageneral */ #endif /* UNIX */ return(vvbuf); case VN_ROWS: /* ROWS */ case VN_COLS: /* COLS */ ckstrncpy(vvbuf,(cx == VN_ROWS) ? "24" : "80",VVBUFL); /* Default */ #ifdef CK_TTGWSIZ #ifdef OS2 if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0) ttgwsiz(); sprintf(vvbuf,"%d", /* SAFE */ (cx == VN_ROWS) ? tt_rows[VTERM] : tt_cols[VTERM]); #else /* OS2 */ if (ttgwsiz() > 0) /* Get window size */ if (tt_cols > 0 && tt_rows > 0) /* sets tt_rows, tt_cols */ sprintf(vvbuf,"%d", /* SAFE */ (cx == VN_ROWS) ? tt_rows : tt_cols); #endif /* OS2 */ #endif /* CK_TTGWSIZ */ return(vvbuf); case VN_TTYP: #ifdef NOTERM ckstrncpy(vvbuf,"unknown",VVBUFL); #else #ifdef OS2 sprintf(vvbuf, "%s", /* SAFE */ (tt_type >= 0 && tt_type <= max_tt) ? tt_info[tt_type].x_name : "unknown" ); #else #ifdef MAC ckstrncpy(vvbuf,"vt320",VVBUFL); #else p = getenv("TERM"); ckstrncpy(vvbuf,p ? p : "unknown",VVBUFL+1); #endif /* MAC */ #endif /* OS2 */ #endif /* NOTERM */ return(vvbuf); case VN_MINP: /* MINPUT */ sprintf(vvbuf, "%d", m_found); /* SAFE */ return(vvbuf); } /* Break up long switch statements... */ switch(y) { case VN_CONN: /* CONNECTION */ if (!local) { ckstrncpy(vvbuf,"remote",VVBUFL); } else { if (!network) ckstrncpy(vvbuf,"serial",VVBUFL); #ifdef TCPSOCKET else if (nettype == NET_TCPB || nettype == NET_TCPA) { if (ttnproto == NP_TELNET) ckstrncpy(vvbuf,"tcp/ip_telnet",VVBUFL); #ifdef CK_SSL else if (ttnproto == NP_SSL || ttnproto == NP_SSL_RAW) ckstrncpy(vvbuf,"tcp/ip_ssl",VVBUFL); else if (ttnproto == NP_TLS || ttnproto == NP_SSL_RAW) ckstrncpy(vvbuf,"tcp/ip_tls",VVBUFL); #endif /* CK_SSL */ else ckstrncpy(vvbuf,"tcp/ip",VVBUFL); } #endif /* TCPSOCKET */ #ifdef SSHBUILTIN else if (nettype == NET_SSH) ckstrncpy(vvbuf,"tcp/ip_ssh",VVBUFL); #endif /* SSHBUILTIN */ #ifdef ANYX25 else if (nettype == NET_SX25 || nettype == NET_VX25 || nettype == NET_IX25 ) ckstrncpy(vvbuf,"x.25",VVBUFL); #endif /* ANYX25 */ #ifdef DECNET else if (nettype == NET_DEC) { if (ttnproto == NP_LAT) ckstrncpy(vvbuf,"decnet_lat",VVBUFL); else if ( ttnproto == NP_CTERM ) ckstrncpy(vvbuf,"decnet_cterm",VVBUFL); else ckstrncpy(vvbuf,"decnet",VVBUFL); } #endif /* DECNET */ #ifdef SUPERLAT else if (nettype == NET_SLAT) ckstrncpy(vvbuf,"superlat",VVBUFL); #endif /* SUPERLAT */ #ifdef NETFILE else if (nettype == NET_FILE) ckstrncpy(vvbuf,"local_file",VVBUFL); #endif /* NETFILE */ #ifdef NETCMD else if (nettype == NET_CMD) ckstrncpy(vvbuf,"pipe",VVBUFL); #endif /* NETCMD */ #ifdef NETPTY else if (nettype == NET_PTY) ckstrncpy(vvbuf,"pseudoterminal",VVBUFL); #endif /* NETPTY */ #ifdef NETDLL else if (nettype == NET_DLL) ckstrncpy(vvbuf,"dynamic_link_library",VVBUFL); #endif /* NETDLL */ #ifdef NPIPE else if (nettype == NET_PIPE) ckstrncpy(vvbuf,"named_pipe",VVBUFL); #endif /* NPIPE */ #ifdef CK_NETBIOS else if (nettype == NET_BIOS) ckstrncpy(vvbuf,"netbios",VVBUFL); #endif /* CK_NETBIOS */ else ckstrncpy(vvbuf,"unknown",VVBUFL); } return(vvbuf); #ifndef NOXFER case VN_SYSI: /* System ID, Kermit code */ return((char *)cksysid); #endif /* NOXFER */ #ifdef OS2 case VN_SPA: { CK_OFF_T space = zdskspace(0); if (space > 0 && space < 1024) sprintf(vvbuf,"-1"); else sprintf(vvbuf,"%lu",space); /* SAFE */ return(vvbuf); } #endif /* OS2 */ #ifndef NOXFER case VN_QUE: { extern char querybuf[]; return(querybuf); } #endif /* NOXFER */ #ifndef NOCSETS case VN_CSET: #ifdef OS2 sprintf(vvbuf,"cp%d",os2getcp()); /* SAFE */ #else ckstrncpy(vvbuf,fcsinfo[fcharset].keyword,VVBUFL+1); #endif /* OS2 */ return(vvbuf); #endif /* NOCSETS */ #ifdef OS2 case VN_EXEDIR: return(exedir); case VN_STAR: return(startupdir); #else case VN_EXEDIR: return(exedir ? exedir : ""); #ifdef VMSORUNIX case VN_STAR: return(startupdir); #endif /* VMSORUNIX */ #endif /* OS2 */ case VN_INI: return(inidir); case VN_MDM: return(gmdmtyp()); case VN_EVAL: return(evalbuf); #ifndef NODIAL case VN_D_CC: /* DIAL COUNTRY-CODE */ return(diallcc ? diallcc : ""); case VN_D_AC: /* DIAL AREA-CODE */ return(diallac ? diallac : ""); case VN_D_IP: /* DIAL INTERNATIONAL-PREFIX */ return(dialixp ? dialixp : ""); case VN_D_LP: /* DIAL LD-PREFIX */ return(dialldp ? dialldp : ""); case VN_D_LCP: /* DIAL LOCAL-PREFIX */ return(diallcp ? diallcp : ""); case VN_D_PXX: /* DIAL PBX-EXCHANGE that matched */ return(matchpxx ? matchpxx : ""); #else case VN_D_CC: /* DIAL COUNTRY-CODE */ case VN_D_AC: /* DIAL AREA-CODE */ case VN_D_IP: /* DIAL INTERNATIONAL-PREFIX */ case VN_D_LP: /* DIAL LD-PREFIX */ case VN_D_LCP: /* DIAL LOCAL-PREFIX */ case VN_D_PXX: /* DIAL PBX-EXCHANGE */ return(""); #endif /* NODIAL */ case VN_UID: #ifdef UNIX { #ifdef IKSD if (inserver) return((char *)uidbuf); else #endif /* IKSD */ if (uidbuf[0]) return((char *)uidbuf); else return(whoami()); } #else return((char *)uidbuf); #endif /* UNIX */ } /* Break up long switch statements... */ switch(y) { case VN_PWD: #ifdef OS2 if (activecmd == XXOUT || activecmd == XXLNOUT) { ckstrncpy(vvbuf,pwbuf,VVBUFL); ck_encrypt((char *)vvbuf); return((char *)vvbuf); } else #endif /* OS2 */ return((char *)pwbuf); case VN_PRM: return((char *)prmbuf); case VN_PROTO: #ifdef NOXFER return("none"); #else #ifdef CK_XYZ return(ptab[protocol].p_name); #else return("kermit"); #endif /* CK_XYZ */ #endif /* NOXFER */ #ifndef NOXFER #ifdef CK_TMPDIR case VN_DLDIR: return(dldir ? dldir : ""); #endif /* CK_TMPDIR */ #endif /* NOXFER */ #ifndef NODIAL case VN_M_INI: /* Modem init string */ return(dialini ? dialini : (m ? m->wake_str : "")); case VN_M_DCM: /* Modem dial command */ return(dialcmd ? dialcmd : (m ? m->dial_str : "")); case VN_M_DCO: /* Modem data compression on */ return(dialdcon ? dialdcon : (m ? m->dc_on_str : "")); case VN_M_DCX: /* Modem data compression off */ return(dialdcoff ? dialdcoff : (m ? m->dc_off_str : "")); case VN_M_ECO: /* Modem error correction on */ return(dialecon ? dialecon : (m ? m->ec_on_str : "")); case VN_M_ECX: /* Modem error correction off */ return(dialecoff ? dialecoff : (m ? m->ec_off_str : "")); case VN_M_AAO: /* Modem autoanswer on */ return(dialaaon ? dialaaon : (m ? m->aa_on_str : "")); case VN_M_AAX: /* Modem autoanswer off */ return(dialaaoff ? dialaaoff : (m ? m->aa_off_str : "")); case VN_M_HUP: /* Modem hangup command */ return(dialhcmd ? dialhcmd : (m ? m->hup_str : "")); case VN_M_HWF: /* Modem hardware flow command */ return(dialhwfc ? dialhwfc : (m ? m->hwfc_str : "")); case VN_M_SWF: /* Modem software flow command */ return(dialswfc ? dialswfc : (m ? m->swfc_str : "")); case VN_M_NFC: /* Modem no flow-control command */ return(dialnofc ? dialnofc : (m ? m->nofc_str : "")); case VN_M_PDM: /* Modem pulse dialing mode */ return(dialpulse ? dialpulse : (m ? m->pulse : "")); case VN_M_TDM: /* Modem tone dialing mode */ return(dialtone ? dialtone : (m ? m->tone : "")); case VN_M_NAM: /* Modem full name */ return(dialname ? dialname : (m ? m->name : "")); #else case VN_M_INI: /* Modem init string */ case VN_M_DCM: /* Modem dial command */ case VN_M_DCO: /* Modem data compression on */ case VN_M_DCX: /* Modem data compression off */ case VN_M_ECO: /* Modem error correction on */ case VN_M_ECX: /* Modem error correction off */ case VN_M_AAO: /* Modem autoanswer on */ case VN_M_AAX: /* Modem autoanswer off */ case VN_M_HUP: /* Modem hangup command */ case VN_M_HWF: /* Modem hardware flow command */ case VN_M_SWF: /* Modem software flow command */ case VN_M_NFC: /* Modem no flow-control command */ case VN_M_PDM: /* Modem pulse dialing mode */ case VN_M_TDM: /* Modem tone dialing mode */ case VN_M_NAM: return(""); #endif /* NODIAL */ case VN_ISTAT: /* INPUT status */ sprintf(vvbuf, "%d", instatus); /* SAFE */ return(vvbuf); case VN_TEMP: /* Temporary directory */ if (tempdir) { /* This is where SET TEMP-DIRECTORY */ p = tempdir; /* puts it -- just use what's here */ ckstrncpy(vvbuf,tempdir,VVBUFL); } else { char c; /* If tempdir was empty, we have to figure out what the temp directory should be here and then put the result where we should have found it in the first place. This is done by checking environment variables (or logical names in VMS, same thing from the API point of view), and if that fails using platform-specific conventions, like the /tmp directory in Unix. */ #ifdef OS2 #ifdef NT p = getenv("K95TMP"); #else p = getenv("K2TMP"); #endif /* NT */ if ( !p ) #endif /* OS2 */ p = getenv("CK_TMP"); if (!p) p = getenv("TMPDIR"); if (!p) p = getenv("TEMP"); if (!p) p = getenv("TMP"); #ifdef OS2ORUNIX if (p) { int len = strlen(p); if (p[len-1] != '/' #ifdef OS2 && p[len-1] != '\\' #endif /* OS2 */ ) { ckstrncpy(vvbuf,p,VVBUFL); if (vvbuf[0]) ckstrncat(vvbuf,"/",CKMAXPATH); p = vvbuf; } } #endif /* OS2ORUNIX */ if (!p) { #ifdef UNIX /* Systems that have a standard */ p = "/tmp/"; /* temporary directory... */ #else #ifdef datageneral p = ":TMP:"; #else p = ""; #endif /* datageneral */ #endif /* UNIX */ ckstrncpy(vvbuf,p,VVBUFL); p = vvbuf; } /* If the result does not end with a directory separator, tack on the appropriate one. This way scripts can be written in a platform-independent way, without having to hardwire a particlar OS's directory separator; e.g. \v(tmpfile)foo.bar instead of \v(tmpfile)/foo.bar, which would not be portable to (say) VMS. In a better world the following code would be in the platform-specific modules, ck?fio.c, but it's too late to go back and redo them all. Note: Windows and OS/2 use backslash (\) as the directory separate in the user interface, but accept slash(/) in their APIs. */ while (*p) { /* For Windows and OS/2 */ #ifdef OS2 /* flip the backslash */ if (*p == '\\') *p = '/'; #endif /* OS2 */ p++; } p = vvbuf; #ifndef VMS c = #ifdef MAC ':' #else #ifdef datageneral ':' #else #ifdef STRATUS '>' #else '/' #endif /* STRATUS */ #endif /* datageneral */ #endif /* MAC */ ; if (p > vvbuf) { /* Directory termination character */ if (*(p-1) != c) { /* Add it to the end of the */ *p++ = c; /* string if it was not already */ *p = NUL; /* there */ } } /* But if the result is just the one character, e.g. '/' in Unix, erase it because that's the root directory and obviously can't be used for temporary files. */ if (vvbuf[0] == c && vvbuf[1] == NUL) { vvbuf[0] = NUL; } #endif /* Not VMS */ } makestr(&tempdir,p); /* Save result where we can find it next time */ return(vvbuf); } /* Break up long switch statements... */ switch(y) { case VN_ERRNO: /* Error number */ #ifdef VMS { extern int vms_lasterr; sprintf(vvbuf, "%d", vms_lasterr); /* SAFE */ } #else sprintf(vvbuf, "%d", errno); /* SAFE */ #endif /* VMS */ return(vvbuf); case VN_ERSTR: /* Error string */ ckstrncpy(vvbuf,ck_errstr(),VVBUFL); return(vvbuf); #ifndef NOXFER case VN_RPSIZ: /* RECEIVE packet-length */ sprintf(vvbuf,"%d",urpsiz); /* SAFE */ return(vvbuf); case VN_WINDO: /* WINDOW slots */ sprintf(vvbuf,"%d",wslotr); /* SAFE */ return(vvbuf); #endif /* NOXFER */ case VN_TFLN: /* TAKE-file line number */ if (tlevel > -1) { sprintf(vvbuf, "%d", tfline[tlevel]); /* SAFE */ return(vvbuf); } else return("0"); case VN_MDMSG: /* DIALRESULT */ #ifndef NODIAL return((char *)modemmsg); #else return(""); #endif /* NODIAL */ case VN_DNUM: /* DIALNUMBER */ #ifndef NODIAL return(dialnum ? (char *) dialnum : ""); #else return(""); #endif /* NODIAL */ case VN_APC: sprintf(vvbuf, "%d", /* SAFE */ #ifdef CK_APC apcactive #else 0 #endif /* CK_APC */ ); return((char *)vvbuf); #ifdef OS2 #ifndef NOKVERBS case VN_TRMK: sprintf(vvbuf, "%d", keymac); /* SAFE */ return((char *)vvbuf); #endif /* NOKVERBS */ #endif /* OS2 */ case VN_IPADDR: #ifdef TCPSOCKET #ifndef OSK /* This dumps core on OS-9 for some reason, but only if executed */ /* before we have made a TCP connection. This is obviously not */ /* the ideal fix. */ if (!myipaddr[0]) getlocalipaddr(); #endif /* OSK */ #endif /* TCPSOCKET */ ckstrncpy(vvbuf, #ifdef TCPSOCKET (char *)myipaddr, #else "", #endif /* TCPSOCKET */ VVBUFL); return((char *)vvbuf); #ifndef NOXFER case VN_CRC16: /* CRC-16 of most recent transfer */ sprintf(vvbuf,"%ld",crc16); /* SAFE */ return(vvbuf); #endif /* NOXFER */ #ifdef CK_PID case VN_PID: #ifdef IKSD #ifdef CK_LOGIN if (inserver && isguest) return(""); #endif /* CK_LOGIN */ #endif /* IKSD */ return(ckgetpid()); #endif /* CK_PID */ #ifndef NOXFER case VN_FNAM: { /* \v(filename) */ extern char filnam[], ofn1[], *sfspec, *rrfspec; char * tmp; switch (what) { /* File transfer is in progress */ #ifdef NEWFTP case (W_FTP|W_RECV): case (W_FTP|W_SEND): return((char *)filnam); #endif /* NEWFTP */ case W_RECV: case W_REMO: return((char *)ofn1); default: /* Most recent file transferred */ if (filnam[0]) { /* (if any) */ return((char *)filnam); } else if (lastxfer & W_SEND && sfspec) { if (fnspath == PATH_OFF) zstrip(sfspec,&tmp); else tmp = sfspec; return(tmp); } else if (lastxfer & W_RECV && rrfspec) { if (fnrpath == PATH_OFF) zstrip(rrfspec,&tmp); else tmp = rrfspec; return(tmp); } else return(""); } } case VN_FNUM: /* \v(filenum) */ sprintf(vvbuf,"%ld",filcnt); /* SAFE */ return((char *)vvbuf); #endif /* NOXFER */ #ifdef PEXITSTAT case VN_PEXIT: { extern int pexitstat; sprintf(vvbuf,"%d",pexitstat); /* SAFE */ return((char *)vvbuf); } #endif /* PEXITSTAT */ #ifndef NOXFER case VN_P_8BIT: vvbuf[0] = parity ? ebq : NUL; vvbuf[1] = NUL; return((char *)vvbuf); case VN_P_CTL: { extern CHAR myctlq; vvbuf[0] = myctlq; vvbuf[1] = NUL; return((char *)vvbuf); } case VN_P_RPT: { extern int rptena; vvbuf[0] = rptena ? rptq : NUL; vvbuf[1] = NUL; return((char *)vvbuf); } #endif /* NOXFER */ } /* Break up long switch statements... */ switch(y) { case VN_XPROG: #ifdef OS2 #ifdef NT #ifdef KUI return("K-95G"); #else return("K-95"); #endif /* KUI */ #else return("K/2"); #endif /* NT */ #else return("C-Kermit"); #endif /* OS2 */ case VN_EDITOR: #ifdef NOFRILLS return(""); #else #ifdef NOPUSH return(""); #else { extern char editor[]; char *ss; if (!editor[0]) { ss = getenv("EDITOR"); if (ss) { ckstrncpy(editor,ss,CKMAXPATH); } } debug(F110,"\\v(editor)",editor,0); return(editor[0] ? (char *)editor : ""); } #endif /* NOPUSH */ #endif /* NOFRILLS */ case VN_EDOPT: #ifdef NOFRILLS return(""); #else #ifdef NOPUSH return(""); #else { extern char editopts[]; return(editopts[0] ? (char *)editopts : ""); } #endif /* NOPUSH */ #endif /* NOFRILLS */ case VN_EDFILE: #ifdef NOFRILLS return(""); #else #ifdef NOPUSH return(""); #else { extern char editfile[]; return(editfile[0] ? (char *)editfile : ""); } #endif /* NOPUSH */ #endif /* NOFRILLS */ #ifdef BROWSER case VN_BROWSR: { extern char browser[]; if (!browser[0]) { s = getenv("BROWSER"); if (s) ckstrncpy(browser,s,CKMAXPATH); } return(browser[0] ? (char *)browser : ""); } case VN_BROPT: { extern char browsopts[]; return(browsopts[0] ? (char *)browsopts : ""); } case VN_URL: { extern char browsurl[]; return(browsurl[0] ? (char *)browsurl : ""); } #endif /* BROWSER */ case VN_HERALD: { extern char myherald[]; sprintf(vvbuf,"%s",myherald); } return((char *)vvbuf); case VN_TEST: { /* test */ extern char * ck_s_test, * ck_s_tver; if (!ck_s_test) ck_s_test = ""; if (!ck_s_tver) ck_s_tver = ""; if (*ck_s_test) { ckstrncpy(vvbuf,ck_s_test,VVBUFL); if (*ck_s_tver) { ckstrncat(vvbuf,".",VVBUFL); ckstrncat(vvbuf,ck_s_tver,VVBUFL); } } else ckstrncpy(vvbuf,"0",VVBUFL); return((char *)vvbuf); } #ifndef NOXFER case VN_XFSTAT: /* xferstatus */ x = xferstat; /* Like success */ if (x > -1) x = (x == 0) ? 1 : 0; /* External value is reversed */ sprintf(vvbuf,"%d",x); /* SAFE */ return((char *)vvbuf); case VN_XFMSG: /* xfermsg */ return((char *)epktmsg); #ifndef NOMSEND case VN_SNDL: { /* sendlist */ extern int filesinlist; sprintf(vvbuf,"%d",filesinlist); /* SAFE */ return((char *)vvbuf); } #endif /* NOMSEND */ #endif /* NOXFER */ #ifdef CK_TRIGGER case VN_TRIG: { extern char * triggerval; return(triggerval ? triggerval : ""); } #endif /* CK_TRIGGER */ #ifdef OS2MOUSE #ifdef OS2 case VN_MOU_X: { extern int MouseCurX; sprintf(vvbuf,"%d",MouseCurX); /* SAFE */ return((char *)vvbuf); } case VN_MOU_Y: { extern int MouseCurY; sprintf(vvbuf,"%d",MouseCurY); /* SAFE */ return((char *)vvbuf); } #endif /* OS2 */ #endif /* OS2MOUSE */ case VN_PRINT: { extern int printpipe; extern char * printername; #ifdef PRINTSWI extern int noprinter; if (noprinter) return(""); #endif /* PRINTSWI */ ckmakmsg(vvbuf,VVBUFL, printpipe ? "|" : "", printername ? printername : #ifdef OS2 "PRN", #else "(default)", #endif /* OS2 */ NULL, NULL ); return((char *)vvbuf); } } /* Break up long switch statements... */ switch(y) { case VN_ESC: /* Escape character */ sprintf(vvbuf,"%d",escape); /* SAFE */ return((char *)vvbuf); case VN_INTIME: sprintf(vvbuf,"%ld",inetime); /* SAFE */ return((char *)vvbuf); case VN_INTMO: sprintf(vvbuf,"%d",inwait); /* SAFE */ return((char *)vvbuf); case VN_SECURE: if (0 #ifdef SSHBUILTIN || IS_SSH() #endif /* SSHBUILTIN */ #ifdef CK_ENCRYPTION || ck_tn_encrypting() && ck_tn_decrypting() #endif /* CK_ENCRYPTION */ #ifdef CK_SSL || tls_active_flag || ssl_active_flag #endif /* CK_SSL */ ) return("1"); else return("0"); case VN_AUTHN: #ifdef CK_AUTHENTICATION { extern char szUserNameAuthenticated[]; return((char *)szUserNameAuthenticated); } #else /* CK_AUTHENTICATION */ return((char *)""); #endif /* CK_AUTHENTICATION */ case VN_AUTHS: #ifdef CK_AUTHENTICATION switch (ck_tn_auth_valid()) { case AUTH_UNKNOWN: return((char *)"unknown"); case AUTH_OTHER: return((char *)"other"); case AUTH_USER: return((char *)"user"); case AUTH_VALID: return((char *)"valid"); case AUTH_REJECT: default: return((char *)"rejected"); } #else /* CK_AUTHENTICATION */ return((char *)"rejected"); #endif /* CK_AUTHENTICATION */ case VN_AUTHT: #ifdef CK_AUTHENTICATION #ifdef CK_SSL if ((ssl_active_flag || tls_active_flag) && ck_tn_auth_valid() == AUTH_VALID && (sstelnet ? (!TELOPT_U(TELOPT_AUTHENTICATION)) : (!TELOPT_ME(TELOPT_AUTHENTICATION))) || ck_tn_authenticated() == AUTHTYPE_NULL || ck_tn_authenticated() == AUTHTYPE_AUTO) return("X_509_CERTIFICATE"); else #endif /* CK_SSL */ return(AUTHTYPE_NAME(ck_tn_authenticated())); #else /* CK_AUTHENTICATION */ return((char *)"NULL"); #endif /* CK_AUTHENTICATION */ #ifdef CK_KERBEROS case VN_K4PRN: { extern char * krb4_d_principal; if (krb4_d_principal) ckstrncpy(vvbuf,krb4_d_principal,VVBUFL+1); else *vvbuf = NUL; return((char *)vvbuf); } case VN_K5PRN: { extern char * krb5_d_principal; if (krb5_d_principal) ckstrncpy(vvbuf,krb5_d_principal,VVBUFL+1); else *vvbuf = NUL; return((char *)vvbuf); } case VN_K4RLM: { extern char * krb4_d_realm; if (krb4_d_realm) { ckstrncpy(vvbuf,krb4_d_realm,VVBUFL+1); } else { char * s = ck_krb4_getrealm(); ckstrncpy(vvbuf,s ? s : "",VVBUFL+1); } return((char *)vvbuf); } case VN_K4SRV: { extern char * krb4_d_srv; if (krb4_d_srv) ckstrncpy(vvbuf,krb4_d_srv,VVBUFL+1); else ckstrncpy(vvbuf,"rcmd",VVBUFL); return((char *)vvbuf); } case VN_K5RLM: { extern char * krb5_d_realm; extern char * krb5_d_cc; if (krb5_d_realm) { ckstrncpy(vvbuf,krb5_d_realm,VVBUFL+1); } else { char * s = ck_krb5_getrealm(krb5_d_cc); ckstrncpy(vvbuf,s,VVBUFL+1); } return((char *)vvbuf); } case VN_K5CC: { extern char * krb5_d_cc; if (krb5_d_cc) ckstrncpy(vvbuf,krb5_d_cc,VVBUFL+1); else ckstrncpy(vvbuf,ck_krb5_get_cc_name(),VVBUFL+1); return((char *)vvbuf); } case VN_K5SRV: { extern char * krb5_d_srv; if (krb5_d_srv) ckstrncpy(vvbuf,krb5_d_srv,VVBUFL+1); else ckstrncpy(vvbuf,"host",VVBUFL); return((char *)vvbuf); } case VN_K4ENO: { extern int krb4_errno; sprintf(vvbuf,"%d",krb4_errno); /* SAFE */ return((char *)vvbuf); } case VN_K5ENO: { extern int krb5_errno; sprintf(vvbuf,"%d",krb5_errno); /* SAFE */ return((char *)vvbuf); } case VN_K4EMSG: { extern char * krb4_errmsg; ckstrncpy(vvbuf,krb4_errmsg?krb4_errmsg:"",VVBUFL+1); return((char *)vvbuf); } case VN_K5EMSG: { extern char * krb5_errmsg; ckstrncpy(vvbuf,krb5_errmsg,VVBUFL+1); return((char *)vvbuf); } #endif /* CK_KERBEROS */ #ifdef CK_SSL case VN_X509_S: if (ssl_active_flag) ckstrncpy(vvbuf,ssl_get_subject_name(ssl_con),VVBUFL+1); else if (tls_active_flag) ckstrncpy(vvbuf,ssl_get_subject_name(tls_con),VVBUFL+1); else ckstrncpy(vvbuf,"",VVBUFL+1); return((char *)vvbuf); case VN_X509_I: if (ssl_active_flag) ckstrncpy(vvbuf,ssl_get_issuer_name(ssl_con),VVBUFL+1); else if (tls_active_flag) ckstrncpy(vvbuf,ssl_get_issuer_name(tls_con),VVBUFL+1); else ckstrncpy(vvbuf,"",VVBUFL+1); return((char *)vvbuf); #endif /* CK_SSL */ case VN_OSNAM: #ifdef IKSD #ifdef CK_LOGIN if (inserver && isguest) return(""); #endif /* CK_LOGIN */ #endif /* IKSD */ #ifdef CK_UTSNAME { extern char unm_nam[]; return((char *)unm_nam); } #else for (x = y = 0; x < VVBUFL; x++) { if (ckxsys[x] == SP && cx == 0) continue; vvbuf[y++] = (char) ((ckxsys[x] == SP) ? '_' : ckxsys[x]); } vvbuf[y] = NUL; return(vvbuf); #endif /* CK_UTSNAME */ case VN_OSVER: { #ifdef CK_UTSNAME extern char unm_ver[]; #ifdef IKSD #ifdef CK_LOGIN if (inserver && isguest) return(""); #endif /* CK_LOGIN */ #endif /* IKSD */ return((char *)unm_ver); #else return(""); #endif /* CK_UTSNAME */ } case VN_OSREL: { #ifdef CK_UTSNAME extern char unm_rel[]; #ifdef IKSD #ifdef CK_LOGIN if (inserver && isguest) return(""); #endif /* CK_LOGIN */ #endif /* IKSD */ return((char *)unm_rel); #else return(""); #endif /* CK_UTSNAME */ } } /* Break up long switch statements... */ switch(y) { case VN_NAME: { extern char * myname; return(myname); } case VN_MODL: { #ifdef CK_UTSNAME extern char unm_mod[], unm_mch[]; #ifdef OSF32 int y = VVBUFL - 1; char * s = unm_mod; #endif /* OSF32 */ #endif /* CK_UTSNAME */ #ifdef IKSD #ifdef CK_LOGIN if (inserver && isguest) return(""); #endif /* CK_LOGIN */ #endif /* IKSD */ #ifdef COMMENT /* was HPUX */ if (!unm_mod[0] && !nopush) zzstring("\\fcommand(model)",&s,&y); /* Another possibility would be: "\\fcommand(ksh -c 'whence model 1>&- && model || uname -m')" But that would depend on having ksh. */ #else #ifdef OSF32 /* Digital UNIX 3.2 and higher... */ /* Note: Ultrix has /etc/sizer, but it is not publicly executable. */ /* sizer -c outputs 'cpu:"DECxxxx"' */ if (!unm_mod[0]) { char * p; int flag = 0; zzstring("\\fcommand(/usr/sbin/sizer -c)",&s,&y); debug(F110,"DU model",unm_mod,0); s = unm_mod; p = unm_mod; while (*p) { /* Extract the part in quotes */ if (*p == '"') { if (flag) break; flag = 1; p++; continue; } if (flag) *s++ = *p; p++; } *s = NUL; } #endif /* OSF32 */ #endif /* COMMENT */ #ifdef CK_UTSNAME if (unm_mod[0]) return((char *)unm_mod); else return((char *)unm_mch); #else return(""); #endif /* CK_UTSNAME */ } #ifdef IBMX25 /* X.25 variables (local and remote address) */ case VN_X25LA: if (!local_nua[0] && !x25local_nua(local_nua)) *vvbuf = NULL; else ckstrncpy(vvbuf,local_nua,VVBUFL+1); return((char *)vvbuf); case VN_X25RA: if (!remote_nua[0]) *vvbuf = NULL; else ckstrncpy(vvbuf,remote_nua,VVBUFL+1); return((char *)vvbuf); #endif /* IBMX25 */ #ifndef NODIAL case VN_PDSFX: { extern char pdsfx[]; return((char *)pdsfx); } case VN_DTYPE: { extern int dialtype; sprintf(vvbuf,"%d",dialtype); /* SAFE */ return((char *)vvbuf); } #endif /* NODIAL */ #ifdef UNIX case VN_LCKPID: { extern char lockpid[]; return((char *)lockpid); } #endif /* UNIX */ #ifndef NOXFER case VN_BLK: sprintf(vvbuf,"%d",bctr); /* SAFE */ return((char *)vvbuf); case VN_TFTIM: sprintf(vvbuf, /* SAFE */ #ifdef GFTIMER "%ld", (long)(fptsecs + 0.5) #else "%d", tsecs #endif /* GFTIMER */ ); return((char *)vvbuf); #endif /* NOXFER */ case VN_HWPAR: case VN_SERIAL: { int sb; char c, * ss; extern int stopbits; vvbuf[0] = NUL; if (hwparity && local && !network) ss = parnam((char)hwparity); else ss = parnam((char)parity); if (cx == VN_HWPAR) { ckstrncpy(vvbuf,ss,VVBUFL); return((char *)vvbuf); } c = ss[0]; if (islower(c)) c = toupper(c); sb = stopbits; if (sb < 1) sb = (speed > 0 && speed <= 110L) ? 2 : 1; if (hwparity) sprintf(vvbuf," 8%c%d",c,sb); /* SAFE */ else if (parity) sprintf(vvbuf," 7%c%d",c,sb); /* SAFE */ else sprintf(vvbuf," 8N%d",sb); /* SAFE */ return((char *)vvbuf); } #ifdef UNIX case VN_LCKDIR: { #ifndef NOUUCP extern char * uucplockdir; ckstrncpy(vvbuf,uucplockdir,VVBUFL); x = strlen(vvbuf); if (x > 0) { if (vvbuf[x-1] != '/') { vvbuf[x] = '/'; vvbuf[x+1] = NUL; } } #else vvbuf[0] = NUL; #endif /* NOUUCP */ return((char *)vvbuf); } #endif /* UNIX */ } /* Break up long switch statements... */ switch(y) { #ifndef NODIAL case VN_DM_LP: case VN_DM_SP: case VN_DM_PD: case VN_DM_TD: case VN_DM_WA: case VN_DM_WD: case VN_DM_HF: case VN_DM_WB: case VN_DM_RC: { ckstrncpy(vvbuf,getdm(y),VVBUFL); return((char *)vvbuf); } #endif /* NODIAL */ case VN_TY_LN: case VN_TY_LC: { extern int typ_lines; sprintf(vvbuf,"%d",typ_lines); /* SAFE */ return((char *)vvbuf); } case VN_TY_LM: { extern int typ_mtchs; sprintf(vvbuf,"%d",typ_mtchs); /* SAFE */ return((char *)vvbuf); } case VN_MACLVL: sprintf(vvbuf,"%d",maclvl); /* SAFE */ return((char *)vvbuf); } /* Break up long switch statements... */ switch(y) { #ifndef NOLASTFILE case VN_LASTFIL: { extern char * lastfile; return(lastfile ? lastfile : ""); } #endif /* NOLASTFILE */ #ifndef NOXFER case VN_XF_BC: sprintf(vvbuf,"%d",crunched); /* SAFE */ return((char *)vvbuf); case VN_XF_TM: sprintf(vvbuf,"%d",timeouts); /* SAFE */ return((char *)vvbuf); case VN_XF_RX: sprintf(vvbuf,"%d",retrans); /* SAFE */ return((char *)vvbuf); #endif /* NOXFER */ case VN_MS_CD: /* Modem signals */ case VN_MS_CTS: case VN_MS_DSR: case VN_MS_DTR: case VN_MS_RI: case VN_MS_RTS: { int x, z = -1; x = ttgmdm(); /* Try to get them */ if (x > -1) { switch (y) { case VN_MS_CD: z = (x & BM_DCD) ? 1 : 0; break; case VN_MS_DSR: z = (x & BM_DSR) ? 1 : 0; break; case VN_MS_CTS: z = (x & BM_CTS) ? 1 : 0; break; #ifdef MAC case VN_MS_DTR: z = (x & BM_DTR) ? 1 : 0; break; #else #ifndef STRATUS case VN_MS_RI: z = (x & BM_RNG) ? 1 : 0; break; #ifndef NT case VN_MS_DTR: z = (x & BM_DTR) ? 1 : 0; break; case VN_MS_RTS: z = (x & BM_RTS) ? 1 : 0; break; #endif /* NT */ #endif /* STRATUS */ #endif /* MAC */ } } sprintf(vvbuf,"%d",z); /* SAFE */ return((char *)vvbuf); } case VN_MATCH: /* INPUT MATCH */ return(inpmatch ? inpmatch : ""); #ifdef CKFLOAT case VN_ISCALE: /* INPUT SCALE-FACTOR */ return(inpscale ? inpscale : "1.0"); #endif /* CKFLOAT */ case VN_SLMSG: { /* SET LINE / HOST message */ extern char * slmsg; vvbuf[0] = NUL; if (slmsg) ckstrncpy(vvbuf,slmsg,VVBUFL); return(vvbuf); } case VN_TXTDIR: /* TEXTDIR */ return(k_info_dir ? k_info_dir : ""); #ifdef FNFLOAT case VN_MA_PI: return(math_pi); case VN_MA_E: return(math_e); case VN_MA_PR: sprintf(vvbuf,"%d",fp_digits); /* SAFE */ return(vvbuf); #endif /* FNFLOAT */ case VN_CMDBL: sprintf(vvbuf,"%d",CMDBL); /* SAFE */ return(vvbuf); #ifdef CKCHANNELIO case VN_FERR: { extern int z_error; sprintf(vvbuf,"%d",z_error); /* SAFE */ return(vvbuf); } case VN_FMAX: { extern int z_maxchan; sprintf(vvbuf,"%d",z_maxchan); /* SAFE */ return(vvbuf); } case VN_FCOU: { extern int z_filcount; sprintf(vvbuf,"%d",z_filcount); /* SAFE */ return(vvbuf); } #endif /* CKCHANNELIO */ #ifndef NODIAL case VN_DRTR: { extern int dialcount; sprintf(vvbuf,"%d",dialcount); /* SAFE */ return(vvbuf); } #endif /* NODIAL */ #ifndef NOLOGDIAL #ifndef NOLOCAL case VN_CXTIME: sprintf(vvbuf,"%ld",dologshow(0)); /* SAFE */ return(vvbuf); #endif /* NOLOCAL */ #endif /* NOLOGDIAL */ case VN_BYTE: sprintf(vvbuf,"%d",byteorder); /* SAFE */ return(vvbuf); case VN_KBCHAR: vvbuf[0] = NUL; vvbuf[1] = NUL; if (kbchar > 0) vvbuf[0] = (kbchar & 0xff); return(vvbuf); case VN_TTYNAM: { #ifdef HAVECTTNAM extern char cttnam[]; return((char *)cttnam); #else return(CTTNAM); #endif /* HAVECTTNAM */ } case VN_PROMPT: return(cmgetp()); case VN_BUILD: { extern char * buildid; return(buildid); } #ifndef NOSEXP case VN_SEXP: { extern char * lastsexp; return(lastsexp ? lastsexp : ""); } case VN_VSEXP: { extern char * sexpval; return(sexpval ? sexpval : ""); } case VN_LSEXP: { extern int sexpdep; ckstrncpy(vvbuf,ckitoa(sexpdep),VVBUFL); return(vvbuf); } #endif /* NOSEXP */ #ifdef GFTIMER case VN_FTIME: { CKFLOAT f; ztime(&p); if (p == NULL || *p == NUL) return(NULL); z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17); f = (CKFLOAT)z + ((CKFLOAT)ztusec) / 1000000.0; sprintf(vvbuf,"%f",f); /* SAFE */ return(vvbuf); } #endif /* GFTIMER */ #ifndef NOHTTP case VN_HTTP_C: { /* HTTP Code */ extern int http_code; return(ckitoa(http_code)); } case VN_HTTP_N: /* HTTP Connected */ return( http_isconnected() ? "1" : "0"); case VN_HTTP_H: /* HTTP Host */ return( (char *)http_host() ); case VN_HTTP_M: { /* HTTP Message */ extern char http_reply_str[]; return((char *)http_reply_str); } case VN_HTTP_S: /* HTTP Security */ return((char *)http_security()); #endif /* NOHTTP */ #ifdef NEWFTP case VN_FTP_B: return((char *)ftp_cpl_mode()); case VN_FTP_D: return((char *)ftp_dpl_mode()); case VN_FTP_Z: return((char *)ftp_authtype()); case VN_FTP_C: { extern int ftpcode; return(ckitoa(ftpcode)); } case VN_FTP_M: { extern char ftp_reply_str[]; if (isdigit(ftp_reply_str[0]) && isdigit(ftp_reply_str[1]) && isdigit(ftp_reply_str[2]) && ftp_reply_str[3] == ' ') return(&ftp_reply_str[4]); else return(ftp_reply_str); } case VN_FTP_S: { extern char ftp_srvtyp[]; return((char *)ftp_srvtyp); } case VN_FTP_H: { extern char * ftp_host; return(ftp_host ? ftp_host : ""); } case VN_FTP_X: { /* FTP Connected */ return(ftpisconnected() ? "1" : "0"); } case VN_FTP_L: { /* FTP Logged in */ return(ftpisloggedin() ? "1" : "0"); } case VN_FTP_G: { /* FTP GET-PUT-REMOTE */ extern int ftpget; char * s = ""; switch (ftpget) { case 0: s = "kermit"; break; case 1: s = "ftp"; break; case 2: s = "auto"; break; } return(s); } #endif /* NEWFTP */ #ifndef NOLOCAL case VN_CX_STA: { /* CONNECT status */ extern int cx_status; return(ckitoa(cx_status)); } #endif /* NOLOCAL */ case VN_NOW: /* Timestamp */ return(ckcvtdate(p,0)); case VN_HOUR: /* Hour of the day */ ztime(&p); /* "Thu Feb 8 12:00:00 1990" */ if (!p) p = ""; if (!*p) return(p); vvbuf[0] = p[11]; vvbuf[1] = p[12]; vvbuf[2] = NUL; return(vvbuf); /* and return it */ case VN_BITS: /* Bits (16, 32, 64) */ if (sizeof(long) > 4) return(ckitoa(8*sizeof(long))); else return(ckitoa(8*sizeof(int))); case VN_LASTKWV: /* 212 */ return(lastkwval ? lastkwval : ""); case VN_HOSTIP: { /* 212 */ #ifdef TCPSOCKET extern char hostipaddr[]; return((char *)hostipaddr); #else return(""); #endif /* TCPSOCKET */ } case VN_INPMSG: switch (instatus) { case INP_OK: return("SUCCESS"); case INP_TO: return("Timed out"); case INP_UI: return("Keyboard interrupt"); case INP_IE: return("Internal error"); case INP_IO: return("I/O error or connection lost"); case INP_IKS: return("INPUT disabled"); case INP_BF: return("Buffer filled and /NOWRAP set"); default: return("Unknown"); } case VN_VAREVAL: /* 212 */ return(vareval ? "recursive" : "simple"); case VN_LOG_CON: /* \v(...) for log files */ #ifdef CKLOGDIAL return(diafil); #else return(""); #endif case VN_LOG_PKT: #ifndef NOXFER return(pktfil); #else return(""); #endif case VN_LOG_SES: #ifndef NOLOCAL return(sesfil); #else return(""); #endif case VN_LOG_TRA: #ifdef TLOG return(trafil); #else return(""); #endif case VN_LOG_DEB: #ifdef DEBUG return(debfil); #else return(""); #endif case VN_PREVCMD: { extern char * prevcmd; return(prevcmd ? prevcmd : ""); } } #ifndef NODIAL switch (y) { /* Caller ID values */ extern char * callid_date, * callid_time, * callid_name, * callid_nmbr, * callid_mesg; case VN_CI_DA: return(callid_date ? callid_date : ""); case VN_CI_TI: return(callid_time ? callid_time : ""); case VN_CI_NA: return(callid_name ? callid_name : ""); case VN_CI_NU: return(callid_nmbr ? callid_nmbr : ""); case VN_CI_ME: return(callid_mesg ? callid_mesg : ""); } /* End of variable-name switches */ #endif /* NODIAL */ #ifdef NT switch (y) { case VN_PERSONAL: p = GetPersonal(); if (p) { ckGetShortPathName(p,vvbuf,VVBUFL); return(vvbuf); } return(""); case VN_DESKTOP: p = GetDesktop(); if (p) { ckGetShortPathName(p,vvbuf,VVBUFL); return(vvbuf); } return(""); case VN_COMMON: p = GetAppData(1); if (p) { ckmakmsg(vvbuf,VVBUFL,p,"Kermit 95/",NULL,NULL); ckGetShortPathName(vvbuf,vvbuf,VVBUFL); return(vvbuf); } return(""); case VN_APPDATA: p = GetAppData(0); if (p) { ckmakmsg(vvbuf,VVBUFL,p,"Kermit 95/",NULL,NULL); ckGetShortPathName(vvbuf,vvbuf,VVBUFL); return(vvbuf); } return(""); } #endif /* NT */ #ifdef TN_COMPORT switch (y) { case VN_TNC_SIG: { p = (char *) tnc_get_signature(); ckstrncpy(vvbuf,p ? p : "",VVBUFL); return(vvbuf); } } #endif /* TN_COMPORT */ #ifdef KUI switch (y) { case VN_GUI_RUN: { extern HWND getHwndKUI(); if ( IsIconic(getHwndKUI()) ) return("minimized"); if ( IsZoomed(getHwndKUI()) ) return("maximized"); return("restored"); } case VN_GUI_XP: sprintf(vvbuf,"%d",get_gui_window_pos_x()); /* SAFE */ return(vvbuf); case VN_GUI_YP: sprintf(vvbuf,"%d",get_gui_window_pos_y()); /* SAFE */ return(vvbuf); case VN_GUI_XR: sprintf(vvbuf,"%d",GetSystemMetrics(SM_CXSCREEN)); /* SAFE */ return(vvbuf); case VN_GUI_YR: sprintf(vvbuf,"%d",GetSystemMetrics(SM_CYSCREEN)); /* SAFE */ return(vvbuf); case VN_GUI_FNM: if ( ntermfont > 0 ) { int i; for (i = 0; i < ntermfont; i++) { if (tt_font == term_font[i].kwval) { ckstrncpy(vvbuf,term_font[i].kwd,VVBUFL); return(vvbuf); } } } return("(unknown)"); case VN_GUI_FSZ: ckstrncpy(vvbuf,ckitoa(tt_font_size/2),VVBUFL); if ( tt_font_size % 2 ) ckstrncat(vvbuf,".5",VVBUFL); return(vvbuf); } #endif /* KUI */ fnsuccess = 0; if (fnerror) { fnsuccess = 0; } if (fndiags) { if (!embuf[0]) ckstrncpy(embuf,"",EMBUFLEN); printf("?%s\n",embuf); return((char *)embuf); } else return(""); } #endif /* NOSPL */ /* warning, this won't work for VMS */ char * #ifdef CK_ANSIC getbasename( char *s ) #else getbasename(s) char *s; #endif /* CK_ANSIC */ { int n, i; if (!s) s = ""; if (!*s) return(""); n = (int)strlen(s); for (i = n-2; i >= 0; i--) { if (ISDIRSEP(s[i])) return(s+i+1); } return(s); } /* X X S T R I N G -- Expand variables and backslash codes. int xxtstring(s,&s2,&n); Expands \ escapes via recursive descent. Argument s is a pointer to string to expand (source). Argument s2 is the address of where to put result (destination). Argument n is the length of the destination string buffer. Returns -1 on failure, 0 on success, with destination string null-terminated and s2 pointing to the terminating null, so that subsequent characters can be added. Failure reasons include destination buffer is filled up. */ #define XXDEPLIM 100 /* Recursion depth limit */ /* In Windows the stack is limited to 256K so big character arrays like vnambuf can't be on the stack in recursive functions like zzstring(). But that's no reason use malloc() in Unix or VMS, which don't have this kind of restriction. */ #ifdef DVNAMBUF /* Dynamic vnambuf[] */ #undef DVNAMBUF /* Clean slate */ #endif /* DVNAMBUF */ #ifndef NOSPL /* Only if SPL included */ #ifdef OS2 /* Only for K95 */ #define DVNAMBUF #endif /* OS2 */ #endif /* NOSPL */ int #ifdef CK_ANSIC zzstring( char *s, char **s2, int *n ) #else zzstring(s,s2,n) char *s; char **s2; int *n; #endif /* CK_ANSIC */ { int x, /* Current character */ xx, /* Worker */ y, /* Worker */ pp, /* Paren level */ kp, /* Brace level */ argn, /* Function argument counter */ n2, /* Local copy of n */ d, /* Array dimension */ vbi, /* Variable id (integer form) */ argl, /* String argument length */ nx, /* Save original length */ quoting = 0; /* 299 */ char vb, /* Variable id (char form) */ *vp, /* Pointer to variable definition */ *new, /* Local pointer to target string */ #ifdef COMMENT *old, /* Save original target pointer */ #endif /* COMMENT */ *p, /* Worker */ *q, /* Worker */ *s3; /* Worker */ int x3; /* Worker */ char *r = (char *)0; /* For holding function args */ char *r2 = (char *)0; char *r3p; #ifndef NOSPL #ifdef DVNAMBUF char * vnambuf = NULL; /* Buffer for variable/function name */ #else /* DVNAMBUF */ char vnambuf[VNAML]; /* Buffer for variable/function name */ #endif /* DVNAMBUF */ char *argp[FNARGS]; /* Pointers to function args */ #endif /* NOSPL */ static int depth = 0; /* Call depth, avoid overflow */ n2 = *n; /* Make local copies of args */ nx = n2; #ifdef COMMENT /* This is always 32K in BIGBUFOK builds */ if (depth == 0) debug(F101,"zzstring top-level n","",n2); #endif /* COMMENT */ new = *s2; /* for one less level of indirection */ #ifndef NOSPL itsapattern = 0; /* For \fpattern() */ isjoin = 0; /* For \fjoin() */ #endif /* NOSPL */ depth++; /* Sink to a new depth */ if (depth > XXDEPLIM) { /* Too deep? */ (VOID) newerrmsg("Definition is circular or too deep"); debug(F111,"zzstring","Definition is circular or too deep",XXDEPLIM); depth = 0; *new = NUL; return(-1); } if (!s || !new) { /* Watch out for null pointers */ debug(F101,"zzstring fail 2","",depth); if (new) *new = NUL; depth = 0; return(-1); } s3 = s; argl = 0; while (*s3++) argl++; /* Get length of source string */ debug(F010,"zzstring entry",s,0); if (argl == 0) { /* Empty string */ debug(F111,"zzstring empty arg",s,argl); depth = 0; *new = NUL; return(0); } if (argl < 0) { /* Watch out for garbage */ debug(F101,"zzstring fail 3","",depth); *new = NUL; depth = 0; return(-1); } #ifdef DVNAMBUF debug(F100,"vnambuf malloc...","",0); vnambuf = malloc(VNAML); if (vnambuf == NULL) { printf("?Out of memory"); return(-1); } debug(F100,"vnambuf malloc ok","",0); #endif /* DVNAMBUF */ while ((x = *s)) { /* Loop for all characters */ if (x != CMDQ) { /* Is it the command-quote char? */ *new++ = *s++; /* No, normal char, just copy */ if (--n2 < 0) { /* and count it, careful of overflow */ debug(F101,"zzstring overflow 1","",depth); depth = 0; #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); } continue; } /* We have the command-quote character. */ x = *(s+1); /* Get the following character. */ if (isupper(x)) x = tolower(x); switch (x) { /* Act according to variable type */ #ifndef NOSPL case 0: /* It's a lone backslash */ *new++ = *s++; if (--n2 < 0) { debug(F101,"zzstring overflow 2","",0); #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); } break; case '%': /* Variable */ s += 2; /* Get the letter or digit */ vb = *s++; /* and move source pointer past it */ vp = NULL; /* Assume definition is empty */ if (vb >= '0' && vb <= '9') { /* Digit for macro arg */ if (maclvl < 0) /* Digit variables are global */ vp = g_var[vb]; /* if no macro is active */ else /* otherwise */ vp = m_arg[maclvl][vb - '0']; /* they're on the stack */ } else if (vb == '*') { /* Macro args string */ #ifdef COMMENT /* This doesn't take changes into account */ vp = (maclvl >= 0) ? m_line[maclvl] : topline; if (!vp) vp = ""; #else char * ss = new; if (zzstring("\\fjoin(&_[],,1)",&new,&n2) < 0) { #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); } debug(F110,"zzstring \\%*",ss,0); break; #endif /* COMMENT */ } else { if (isupper(vb)) vb += ('a'-'A'); vp = g_var[vb]; /* Letter for global variable */ } if (!vp) vp = ""; #ifdef COMMENT if (vp) { /* If definition not empty */ #endif /* COMMENT */ if (vareval) { debug(F010,"zzstring %n vp",vp,0); /* call self to evaluate it */ if (zzstring(vp,&new,&n2) < 0) { debug(F101,"zzstring fail 6","",depth); #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); /* Pass along failure */ } } else { while ((*new++ = *vp++)) /* copy it to output string. */ if (--n2 < 0) { if (q) free(q); debug(F101,"zzstring overflow 4.5","",depth); #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); } new--; /* Back up over terminating null */ n2++; /* to allow for further deposits. */ } #ifdef COMMENT } else { debug(F110,"zzstring %n vp","(NULL)",0); n2 = nx; *new = NUL; } #endif /* COMMENT */ break; case '&': /* An array reference */ x = arraynam(s,&vbi,&d); /* Get name and subscript */ debug(F111,"zzstring arraynam",s,x); if (x < 0) { debug(F101,"zzstring fail 7","",depth); #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); } pp = 0; /* Bracket counter */ while (*s) { /* Advance source pointer... */ if (*s == '[') pp++; if (*s == ']' && --pp == 0) break; s++; } if (*s == ']') s++; /* ...past the closing bracket. */ xx = chkarray(vbi,d); /* Array is declared? */ debug(F101,"zzstring chkarray","",x); if (xx > -1) { #ifdef COMMENT char * s1 = NULL; #endif /* COMMENT */ vbi -= ARRAYBASE; /* Convert name to index */ if (a_dim[vbi] >= d) { /* If subscript in range */ char **ap; ap = a_ptr[vbi]; /* get data pointer */ if (ap) { /* and if there is one */ if (ap[d]) { /* If definition not empty */ debug(F111,"zzstring ap[d]",ap[d],d); if (vareval) { if (zzstring(ap[d],&new,&n2) < 0) { debug(F101,"zzstring fail 8","",depth); #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); /* Pass along failure */ } } else { vp = ap[d]; while ((*new++ = *vp++)) /* copy to result */ if (--n2 < 0) { if (q) free(q); debug(F101, "zzstring overflow 8.5","",depth); #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); } new--; /* Back up over terminating null */ n2++; /* to allow for further deposits. */ } } } else { n2 = nx; } } } break; case 'f': /* A builtin function */ q = vnambuf; /* Copy the name */ y = 0; /* into a separate buffer */ s += 2; /* point past 'F' */ while (y++ < VNAML) { if (*s == '(') { s++; break; } /* Look for open paren */ if ((*q = *s) == NUL) break; /* or end of string */ s++; q++; } *q = NUL; /* Terminate function name */ if (y >= VNAML) { /* Handle pathological case */ while (*s && (*s != '(')) /* of very long string entered */ s++; /* as function name. */ if (*s == ')') s++; /* Skip past it. */ } r = r2 = malloc(argl+2); /* And make a place to copy args */ /* debug(F101,"zzstring r2","",r2); */ if (!r2) { /* Watch out for malloc failure */ debug(F101,"zzstring fail 9","",depth); *new = NUL; depth = 0; #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); } if (r3) free(r3); /* And another to copy literal arg string */ r3 = malloc(argl+2); /* debug(F101,"zzstring r3","",r3); */ if (!r3) { debug(F101,"zzstring fail 10","",depth); depth = 0; *new = NUL; if (r2) free(r2); #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); } else r3p = r3; argn = 0; /* Argument counter */ argp[argn++] = r; /* Point to first argument */ y = 0; /* Completion flag */ pp = 1; /* Paren level (already have one). */ kp = 0; while (1) { /* Copy each argument, char by char. */ *r3p++ = *s; /* This is a literal copy for \flit */ if (!*s) break; if (*s == '{') { /* Left brace */ kp++; } if (*s == '}') { /* Right brace */ kp--; } if (*s == '(' && kp <= 0) { /* Open paren not in brace */ pp++; /* Count it */ } *r = *s; /* Now copy resulting byte */ if (!*r) /* If NUL, done. */ break; if (*r == ')' && kp <= 0) { /* Closing paren, count it. */ if (--pp == 0) { /* Final one? */ *r = NUL; /* Make it a terminating null */ *(r3p - 1) = NUL; s++; /* Point past it in source string */ y = 1; /* Flag we've got all the args */ break; /* Done with while loop */ } } if (*r == ',' && kp <= 0) { /* Comma */ if (pp == 1) { /* If not within ()'s, */ if (argn >= FNARGS) { /* Too many args */ s++; r++; /* Keep collecting flit() string */ continue; } *r = NUL; /* New arg, skip past comma */ argp[argn++] = r+1; /* In range, point to new arg */ } /* Otherwise just skip past */ } s++; r++; /* Advance pointers */ } if (!y) /* If we didn't find closing paren */ argn = -1; #ifdef DEBUG if (deblog) { char buf[24]; debug(F111,"zzstring function name",vnambuf,y); debug(F010,"zzstring function r3",r3,0); for (y = 0; y < argn; y++) { sprintf(buf,"arg %2d ",y); debug(F010,buf,argp[y],0); } } #endif /* DEBUG */ { /* In case the function name itself is constructed */ char buf[64]; char * p = buf; int n = 64; if (zzstring(vnambuf,&p,&n) > -1) ckstrncpy(vnambuf,buf,64); } vp = fneval(vnambuf,argp,argn,r3); /* Evaluate the function. */ if (vp) { /* If definition not empty */ while ((*new++ = *vp++)) { /* copy it to output string */ if (--n2 < 0) { /* watch out for overflow */ debug(F101,"zzstring fail 12","",depth); if (r2) { free(r2); r2 = NULL; } if (r3) { free(r3); r3 = NULL; } #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); } } new--; /* Back up over terminating null */ n2++; /* to allow for further deposits. */ } if (r2) { free(r2); r2 = NULL; } if (r3) { free(r3); r3 = NULL; } break; case 'q': /* 299 String to be take literally */ quoting = 1; /* 299 */ case '$': /* An environment variable */ case 'v': /* Or a named builtin variable. */ case 'm': /* Or a macro /long variable */ case 's': /* 196 Macro substring */ case ':': /* 196 \-variable substring */ pp = 0; p = s+2; /* $/V/M must be followed by (name) */ if (*p != '(') { /* as in \$(HOME) or \V(count) */ *new++ = *s++; /* If not, just copy it */ if (--n2 < 0) { debug(F101,"zzstring overflow 3","",depth); #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); } break; } pp++; p++; /* Point to 1st char of name */ q = vnambuf; /* Copy the name */ y = 0; /* into a separate buffer */ debug(F110,">>>> \\q(ARG)",p,0); while (y++ < VNAML) { /* Watch out for name too long */ if (*p == '(') { /* Parens can be nested... */ if (*(p-1) != CMDQ) /* 299 */ pp++; } else if (*p == ')') { /* Name properly terminated with ')' */ if (*(p-1) != CMDQ) /* 299 */ pp--; if (pp == 0) { p++; /* Move source pointer past ')' */ break; } } if ((*q = *p) == NUL) /* String ends before ')' */ break; p++; q++; /* Advance pointers */ } *q = NUL; /* Terminate the variable name */ if (y >= VNAML) { /* Handle pathological case */ while (*p && (*p != ')')) /* of very long string entered */ p++; /* as variable name. */ if (*p == ')') p++; /* Skip ahead to the end of it. */ } /* At this point vnambuf contains the macro name from inside the parens */ s = p; /* Adjust global source pointer */ s3 = vnambuf; x3 = 0; while (*s3++) x3++; /* Length needed */ /* The following is in case the macro name itself contains variables */ p = malloc(x3 + 1); /* Make temporary space */ if (p && !quoting) { /* If we got the space */ vp = vnambuf; /* Point to original */ strcpy(p,vp); /* (safe) Make a copy of it */ y = VNAML; /* Length of name buffer */ zzstring(p,&vp,&y); /* Evaluate the copy */ free(p); /* Free the temporary space */ p = NULL; } /* At this point vnambuf contains the fully evaluated macro name */ debug(F110,"zzstring macro name",vnambuf,0); q = NULL; if (x == 'q') { /* 299 Quoting this string */ vp = vnambuf; /* 299 */ debug(F110,">>> VP",vp,0); } else if (x == '$') { /* Look up its value */ vp = getenv(vnambuf); /* This way for environment variable */ } else if (x == 'm' || x == 's' || x == ':') { /* Macro / substr */ int k, x1 = -1, x2 = -1; char c = NUL; k = strlen(vnambuf); /* \s(name[n:m]) -- Compact substring notation */ if ((x == 's' || x == ':') && (k > 1)) { /* Substring wanted */ int bprc; if (vnambuf[k-1] == ']') { int i; for (i = 0; i < k-1; i++) { if (vnambuf[i] == '[') { bprc = boundspair(vnambuf,":_.",&x1,&x2,&c); debug(F111,"zzstring boundspair",vnambuf,bprc); debug(F000,"zzstring boundspair c","",c); if (bprc > -1) { vnambuf[i] = NUL; if (x1 < 1) x1 = 1; x1--; /* Adjust to 0-base */ } break; } } } } if (x == ':') { /* Variable type (s or :) */ vp = vnambuf; } else { /* Regular macro or associative array*/ y = isaarray(vnambuf) ? mxxlook(mactab,vnambuf,nmac) : /* Assoc Array */ mxlook(mactab,vnambuf,nmac); /* Macro */ if (y > -1) { /* Got definition */ vp = mactab[y].mval; } else { vp = NULL; } } debug(F111,"zzstring vp",vp,(vp==NULL)?0:strlen(vp)); if (vp) { if ((x == 's' || x == ':') && (k > 1)) { /* Compact substring notation */ if (x2 == 0) { /* Length */ vp = NULL; } else if (x1 > -1) { /* Start */ k = strlen(vp); debug(F101,">>> k","",k); /* If it's off the end, result is empty */ if (x1 > k) { vp = NULL; } else if (k > 0) { /* Stay in bounds */ if (c == '_' && x2 > k) /* startpos_endpos */ x2 = k; if (c == ':' && x1 + x2 > k) /* start:length */ x2 = -1; debug(F101,">>> x2","",x2); debug(F000,">>> c","",c); if ((q = malloc(k+1))) { strcpy(q,vp); /* safe */ if (c == '.') { q[x1+1] = NUL; debug(F000,"XXX. q",q,c); } if (c == ':') { /* start:length */ if ((x2 > -1) && ((x1 + x2) <= k)) { q[x1+x2] = NUL; } debug(F000,"XXX: q",q,c); } else if (c == '_') { /* start_endpos */ if (x1 >= x2) { q[x1 = 0] = NUL; } else if (x2 < k && x2 > -1) { q[x2] = NUL; } debug(F000,"XXX_ q",q,c); } vp = q+x1; } else vp = NULL; } else vp = NULL; } debug(F110,"XXX vnambuf",vnambuf,0); debug(F000,"XXX c","",c); debug(F101,"XXX x1","",x1); debug(F101,"XXX x2","",x2); debug(F110,"XXX result",vp,0); #ifdef DEBUG if (deblog) { if (!vp) { } else { k = strlen(vp); } } #endif /* DEBUG */ } } } else { /* or */ vp = nvlook(vnambuf); /* this way for builtin variable */ } if (vp) { /* If definition not empty */ while ((*new++ = *vp++)) /* copy it to output string. */ if (--n2 < 0) { if (q) free(q); debug(F101,"zzstring overflow 4","",depth); #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); } new--; /* Back up over terminating null */ n2++; /* to allow for further deposits. */ } if (q) { free(q); q = NULL; } break; #endif /* NOSPL */ /* Handle \nnn even if NOSPL. */ #ifndef NOICP #ifndef NOKVERBS case 'K': case 'k': { extern struct keytab kverbs[]; extern int nkverbs; #define K_BUFLEN 30 char kbuf[K_BUFLEN + 1]; /* Key verb name buffer */ int x, y, z, brace = 0; s += 2; /* We assume that the verb name is {braced}, or it extends to the end of the string, s, or it ends with a space, control character, or backslash. */ p = kbuf; /* Copy verb name into local buffer */ x = 0; if (*s == '{') { s++; brace++; } while ((x++ < K_BUFLEN) && (*s > SP) && (*s != CMDQ)) { if (brace && *s == '}') { s++; break; } *p++ = *s++; } brace = 0; *p = NUL; /* Terminate. */ p = kbuf; /* Point back to beginning */ debug(F110,"zzstring kverb",p,0); y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */ debug(F101,"zzstring lookup",0,y); if (y > -1) { dokverb(VCMD,y); #ifndef NOSPL } else { /* Is it a macro? */ y = mxlook(mactab,p,nmac); if (y > -1) { debug(F111,"zzstring mxlook",p,y); if ((z = dodo(y,NULL,cmdstk[cmdlvl].ccflgs)) > 0) { if (cmpush() > -1) { /* Push command parser state */ extern int ifc; int ifcsav = ifc; /* Push IF condition on stack */ y = parser(1); /* New parser to execute macro */ cmpop(); /* Pop command parser */ ifc = ifcsav; /* Restore IF condition */ if (y == 0) { /* No errors, ignore actions */ p = mrval[maclvl+1]; /* If OK set return val */ if (p == NULL) p = ""; } } else { /* Can't push any more */ debug(F101,"zzstring pushed too deep","",depth); printf( "\n?Internal error: zzstring stack overflow\n" ); while (cmpop() > -1); p = ""; } } } #endif /* NOSPL */ } break; } #endif /* NOKVERBS */ #endif /* NOICP */ default: /* Maybe it's a backslash code */ y = xxesc(&s); /* Go interpret it */ if (y < 0) { /* Upon failure */ *new++ = (char) x; /* Just quote the next character */ s += 2; /* Move past the pair */ n2 -= 2; if (n2 < 0) { debug(F101,"zzstring overflow 5","",depth); #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); } continue; /* and go back for more */ } else { *new++ = (char) y; /* else deposit interpreted value */ if (--n2 < 0) { debug(F101,"zzstring overflow 6","",depth); #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(-1); } } } } *new = NUL; /* Terminate the new string */ depth--; /* Adjust stack depth gauge */ *s2 = new; /* Copy results back into */ *n = n2; /* the argument addresses */ debug(F111,"zzstring ok s2 n2",*s2,n2); #ifdef DVNAMBUF if (vnambuf) free(vnambuf); #endif /* DVNAMBUF */ return(0); /* and return. */ } #endif /* NOICP */ ckuus5.c000664 045065 024037 00001445531 14767410161 012572 0ustar00fdckermit000000 000000 #include "ckcsym.h" int xcmdsrc = 0; #ifdef NOICP int cmdsrc() { return(0); } #endif /* NOICP */ /* C K U U S 5 -- "User Interface" for C-Kermit, part 5 */ /* Authors: Frank da Cruz , The Kermit Project, New York City Jeffrey E Altman Secure Endpoints Inc., New York City Update: Jun 24 2023 (David Goodwin) Update: Oct 10-11 2022 (fdc and sms) Update: Dec 02 2022 (David Goodwin - SHOW MOUSE) Update: Dec 13 2022 (David Goodwin - missing break + K95 arrow keys) Update: Apr 14 2023 (ANSI function declarations and prototypes) Update: May 16 2023 (Jeff Johnson fix for iksd.conf diagnostic) Update: May 16 2023 (Jeff Johnson fix for \v(startup) vs \v(exedir)) Update: Jun 25 2023 (Added Clang support to SHOW FEATURES - fdc) Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ /* Includes */ #include "ckcdeb.h" #include "ckcasc.h" #include "ckcker.h" #include "ckuusr.h" #ifdef DCMDBUF char *line; /* Character buffer for anything */ char *tmpbuf; #else char line[LINBUFSIZ+1]; char tmpbuf[TMPBUFSIZ+1]; /* Temporary buffer */ #endif /* DCMDBUF */ char lasttakeline[TMPBUFSIZ+1]; /* Last TAKE-file line */ int noherald = 0; /* Whether to print the program herald on startup */ #ifndef NOICP #include "ckcnet.h" #ifndef NOCSETS #include "ckcxla.h" #endif /* NOCSETS */ #ifdef MAC #include "ckmasm.h" #endif /* MAC */ #ifdef CK_SSL #include "ck_ssl.h" #endif /* CK_SSL */ extern char * ck_cryear; /* (ckcmai.c) Latest C-Kermit copyright year */ #ifdef OS2 #include "ckoetc.h" #ifndef NT #define INCL_NOPM #define INCL_VIO /* Needed for ckocon.h */ #include #undef COMMENT #else /* NT */ #include #ifdef CK_TAPI #define TAPI_CURRENT_VERSION 0x00010004 #include #include #include "ckntap.h" #endif /* CK_TAPI */ #define APIRET ULONG extern int DialerHandle; extern int StartedFromDialer; #endif /* NT */ #include "ckocon.h" #include "ckokey.h" #ifdef CRYPT_DLL /* For ck_crypt_dll_version */ #include "ckoath.h" #endif /* CRYPT_DLL */ #ifdef KUI #include "ikui.h" #endif /* KUI */ #ifdef putchar #undef putchar #endif /* putchar */ #define putchar(x) conoc(x) extern int cursor_save ; extern bool cursorena[] ; int cktomsk(int); /* ckokey.c */ #ifdef KUI void shogui(); /* ckuus3.c */ #endif /* KUI */ #endif /* OS2 */ /* 2010-03-09 SMS. VAX C V3.1-051 needs for off_t. */ #ifdef VMS #include #endif /* def VMS */ #include "ckcfnp.h" /* Prototypes (must be last) */ #ifdef CK_ANSIC /* prototypes for static functions - fdc 30 November 2022 */ static char * cmddisplay( char *, int ); static char * vardef( char *, int *, int *, int * ); static int isaa( char * ); static int iseom( char * ); static int traceval( char *, char * ); #endif /* CK_ANSIC */ /* For formatted screens, "more?" prompting, etc. */ #ifdef FT18 #define isxdigit(c) isdigit(c) #endif /* FT18 */ #ifdef STRATUS /* Stratus Computer, Inc. VOS */ #ifdef putchar #undef putchar #endif /* putchar */ #define putchar(x) conoc(x) #ifdef getchar #undef getchar #endif /* getchar */ #define getchar(x) coninc(0) #endif /* STRATUS */ /* External variables */ extern int carrier, cdtimo, local, quiet, backgrd, bgset, sosi, xsuspend, binary, escape, xargs, flow, cmdmsk, duplex, ckxech, seslog, what, inserver, diractive, tlevel, cwdf, nfuncs, msgflg, remappd, hints, mdmtyp, zincnt, cmask, rcflag, success, xitsta, pflag, tnlm, tn_nlm, xitwarn, debses, xaskmore, parity, saveask, wasclosed, whyclosed, cdactive, rcdactive, keepallchars, cmd_err; #ifdef LOCUS extern int locus, autolocus; #endif /* LOCUS */ #ifdef VMS extern int vms_text; /* SET VMS_TEXT */ #endif /* VMS */ #ifndef NOMSEND extern int addlist; #endif /* NOMSEND */ #ifdef CK_SPEED extern int prefixing; #endif /* CK_SPEED */ extern int g_matchdot; #ifdef RECURSIVE extern int recursive; #endif /* RECURSIVE */ extern int xfiletype; #ifdef IKSDCONF extern char * iksdconf; extern int iksdcf; #endif /* IKSDCONF */ #ifdef CK_RECALL extern int on_recall; #endif /* CK_RECALL */ extern int ngetpath, exitonclose; extern char * getpath[]; extern CHAR * epktmsg; extern char * snd_move; extern char * snd_rename; extern char * rcv_move; extern char * rcv_rename; extern char * g_snd_move; extern char * g_snd_rename; extern char * g_rcv_move; extern char * g_rcv_rename; extern char * nm[]; #ifdef CK_UTSNAME extern char unm_mch[]; extern char unm_mod[]; extern char unm_nam[]; extern char unm_rel[]; extern char unm_ver[]; #endif /* CK_UTSNAME */ #ifndef NOPUSH #ifndef NOFRILLS extern char editor[]; extern char editfile[]; extern char editopts[]; #ifdef BROWSER extern char browser[]; extern char browsopts[]; extern char browsurl[]; #endif /* BROWSER */ #endif /* NOFRILLS */ #endif /* NOPUSH */ #ifndef NOFRILLS #ifndef NORENAME _PROTOTYP(VOID shorename, (void)); #endif /* NORENAME */ #endif /* NOFRILLS */ #ifndef NOSERVER extern char * x_user, * x_passwd, * x_acct; #endif /* NOSERVER */ #ifdef CKLOGDIAL extern int dialog; extern char diafil[]; #endif /* CKLOGDIAL */ #ifdef CKROOT extern int ckrooterr; #endif /* CKROOT */ #ifndef NOSPL extern int cfilef, xxdot, vareval; extern char cmdfil[]; struct localvar * localhead[CMDSTKL]; struct localvar * localtail = NULL; struct localvar * localnext = NULL; _PROTOTYP( VOID shosexp, (void) ); _PROTOTYP( static VOID shoinput, (void) ); _PROTOTYP( static char gettok, (void) ); _PROTOTYP( static VOID factor, (void) ); _PROTOTYP( static VOID term, (void) ); _PROTOTYP( static VOID termp, (void) ); _PROTOTYP( static VOID exprp, (void) ); _PROTOTYP( static VOID expr, (void) ); _PROTOTYP( static VOID simple, (void) ); _PROTOTYP( static VOID simpler, (void) ); _PROTOTYP( static VOID simplest, (void) ); _PROTOTYP( static CK_OFF_T xparse, (void) ); #endif /* NOSPL */ #ifndef NOSHOW _PROTOTYP( int sho_iks, (void) ); #endif /* NOSHOW */ #ifdef MAC char * ckprompt = "Mac-Kermit>"; /* Default prompt for Macintosh */ char * ikprompt = "IKSD>"; #else /* Not MAC */ #ifdef NOSPL #ifdef OS2 char * ckprompt = "K-95> "; /* Default prompt for Win32 */ char * ikprompt = "IKSD> "; #else char * ckprompt = "C-Kermit>"; char * ikprompt = "IKSD>"; #endif /* NT */ #else /* NOSPL */ #ifdef OS2 /* Default prompt for OS/2 and Win32 */ /* fdc 2013-12-06 - C-Kermit 9.0 and later is just "C-Kermit" */ /* dg 2024-07-15 - Back to Kermit 95 on Windows and OS/2 */ #ifdef NT char * ckprompt = "[\\freplace(\\flongpath(\\v(dir)),/,\\\\)] K-95> "; char * ikprompt = "[\\freplace(\\flongpath(\\v(dir)),/,\\\\)] IKSD> "; #else /* NT */ char * ckprompt = "[\\freplace(\\v(dir),/,\\\\)] K-95> "; char * ikprompt = "[\\freplace(\\v(dir),/,\\\\)] IKSD> "; #endif /* NT */ #else /* OS2 */ #ifdef VMS char * ckprompt = "\\v(dir) C-Kermit>"; /* Default prompt VMS */ char * ikprompt = "\\v(dir) IKSD>"; #else #ifdef UNIX /* Note: parens, not brackets, because of ISO646 */ /* Collapse long paths using ~ notation if in home directory tree */ char * ckprompt = "(\\freplace(\\v(dir),\\fpathname(\\v(home)),~/)) C-Kermit>"; char * ikprompt = "(\\freplace(\\v(dir),\\fpathname(\\v(home)),~/)) IKSD>"; #else /* Default prompt for other platforms */ char * ckprompt = "(\\v(dir)) C-Kermit>"; /* Default prompt for others */ char * ikprompt = "(\\v(dir)) IKSD>"; #endif /* UNIX */ #endif /* VMS */ #endif /* NT */ #endif /* NOSPL */ #endif /* MAC */ #ifndef CCHMAXPATH #define CCHMAXPATH 257 #endif /* CCHMAXPATH */ char inidir[CCHMAXPATH] = { NUL, NUL }; /* Directory INI file executed from */ #ifdef TNCODE extern int tn_b_nlm; /* TELNET BINARY newline mode */ #endif /* TNCODE */ #ifndef NOKVERBS extern struct keytab kverbs[]; /* Table of \Kverbs */ extern int nkverbs; /* Number of \Kverbs */ #endif /* NOKVERBS */ #ifndef NOPUSH extern int nopush; #endif /* NOPUSH */ #ifdef CK_RECALL extern int cm_recall; #endif /* CK_RECALL */ extern char *ccntab[]; /* Printer stuff */ extern char *printername; extern int printpipe; #ifdef BPRINT extern int printbidi, pportparity, pportflow; extern long pportspeed; #endif /* BPRINT */ #ifdef OS2 _PROTOTYP (int os2getcp, (void) ); _PROTOTYP (int os2getcplist, (int *, int) ); #ifdef OS2MOUSE extern int tt_mouse; #endif /* OS2MOUSE */ extern int tt_update, tt_updmode, updmode, tt_utf8; #ifndef IKSDONLY extern int tt_status[]; #endif /* IKSDONLY */ #ifdef PCFONTS extern struct keytab term_font[]; #else #ifdef KUI extern struct keytab * term_font; #endif /* KUI */ #endif /* PCFONTS */ extern int ntermfont, tt_font, tt_font_size; extern unsigned char colornormal, colorunderline, colorstatus, colorhelp, colorselect, colorborder, colorgraphic, colordebug, colorreverse, colorcmd, coloritalic; extern int priority; extern struct keytab prtytab[]; extern int nprty; char * cmdmac = NULL; #endif /* OS2 */ #ifdef VMS _PROTOTYP (int zkermini, (char *, int, char *) ); #endif /* VMS */ extern long vernum; extern int inecho, insilence, inbufsize, nvars, inintr; extern char *protv, *fnsv, *cmdv, *userv, *ckxv, *ckzv, *ckzsys, *xlav, *cknetv, *clcmds; #ifdef OS2 extern char *ckyv; #endif /* OS2 */ #ifdef CK_AUTHENTICATION extern char * ckathv; #endif /* CK_AUTHENTICATION */ #ifdef CK_SSL extern char * cksslv; #endif /* CK_SSL */ #ifdef CK_ENCRYPTION #ifndef CRYPT_DLL extern char * ckcrpv; #endif /* CRYPT_DLL */ #endif /* CK_ENCRYPTION */ #ifdef SSHBUILTIN extern char *cksshv; #ifdef SFTP_BUILTIN extern char *cksftpv; #endif /* SFTP_BUILTIN */ #include "ckossh.h" #endif /* SSHBUILTIN */ #ifdef TNCODE extern char *cktelv; #endif /* TNCODE */ #ifndef NOFTP #ifndef SYSFTP extern char * ckftpv; #endif /* SYSFTP */ #endif /* NOFTP */ extern int srvidl; #ifdef OS2 extern char *ckonetv; extern int interm; #ifdef CK_NETBIOS extern char *ckonbiv; #endif /* CK_NETBIOS */ #ifdef OS2MOUSE extern char *ckomouv; #endif /* OS2MOUSE */ #endif /* OS2 */ #ifndef NOLOCAL extern char *connv; #endif /* NOLOCAL */ #ifndef NODIAL extern char *dialv; #endif /* NODIAL */ #ifndef NOSCRIPT extern char *loginv; extern int secho; #endif /* NOSCRIPT */ #ifndef NODIAL extern int nmdm, dirline; extern struct keytab mdmtab[]; #endif /* NODIAL */ extern int network, nettype, ttnproto; #ifdef OS2 #ifndef NOTERM /* SET TERMINAL items... */ extern int tt_type, tt_arrow, tt_keypad, tt_wrap, tt_answer, tt_scrsize[]; extern int tt_bell, tt_roll[], tt_ctstmo, tt_cursor, tt_pacing, tt_type_mode; extern char answerback[]; extern struct tt_info_rec tt_info[]; /* Indexed by terminal type */ extern int max_tt; #endif /* NOTERM */ #endif /* OS2 */ _PROTOTYP( VOID shotrm, (void) ); _PROTOTYP( int shofea, (void) ); #ifdef OS2 extern int tt_rows[], tt_cols[]; #else /* OS2 */ extern int tt_rows, tt_cols; #endif /* OS2 */ extern int cmd_rows, cmd_cols; #ifdef CK_TMPDIR extern int f_tmpdir; /* Directory changed temporarily */ extern char savdir[]; /* Temporary directory */ #endif /* CK_TMPDIR */ #ifndef NOLOCAL extern int tt_crd, tt_lfd, tt_escape; #endif /* NOLOCAL */ #ifndef NOCSETS extern int language, nfilc, tcsr, tcsl, tcs_transp, fcharset; extern struct keytab fcstab[]; extern struct csinfo fcsinfo[]; #ifndef MAC extern struct keytab ttcstab[]; #endif /* MAC */ #endif /* NOCSETS */ extern long speed; #ifndef NOXMIT extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw, xmitt; extern char xmitbuf[]; #endif /* NOXMIT */ extern char **xargv, *versio, *ckxsys, *dftty, *lp; #ifdef DCMDBUF extern char *cmdbuf, *atmbuf; /* Command buffers */ #ifndef NOSPL extern char *savbuf; /* Command buffers */ #endif /* NOSPL */ #else extern char cmdbuf[], atmbuf[]; /* Command buffers */ #ifndef NOSPL extern char savbuf[]; /* Command buffers */ #endif /* NOSPL */ #endif /* DCMDBUF */ extern char toktab[], ttname[], psave[]; extern CHAR sstate, feol; extern int cmflgs, techo, repars, ncmd; extern struct keytab cmdtab[]; #ifndef NOSETKEY KEY *keymap; #ifndef OS2 #define mapkey(x) keymap[x] #endif /* OS2 */ MACRO *macrotab; _PROTOTYP( VOID shostrdef, (CHAR *) ); #endif /* NOSETKEY */ extern int cmdlvl; #ifndef NOSPL extern struct mtab *mactab; extern struct keytab mackey[]; extern struct keytab vartab[], fnctab[], iftab[]; extern int maclvl, nmac, mecho, fndiags, fnerror, fnsuccess, nif; #endif /* NOSPL */ FILE *tfile[MAXTAKE]; /* TAKE file stack */ char *tfnam[MAXTAKE]; /* Name of TAKE file */ int tfline[MAXTAKE]; /* Current line number */ int tfblockstart[MAXTAKE]; /* Current block-start line */ int topcmd = -1; /* cmdtab index of current command */ int havetoken = 0; extern int dblquo; /* Doublequoting enabled */ #ifdef DCMDBUF /* Initialization filespec */ char *kermrc = NULL; #else char kermrcb[KERMRCL]; char *kermrc = kermrcb; #endif /* DCMDBUF */ int cm_retry = 1; /* Command retry enabled */ xx_strp xxstring = zzstring; #ifndef NOXFER extern int displa, bye_active, protocol, pktlog, remfile, rempipe, unkcs, keep, lf_opts, fncnv, pktpaus, autodl, xfrcan, xfrchr, xfrnum, srvtim, srvdis, query, retrans, streamed, reliable, crunched, timeouts, fnrpath, autopath, rpackets, spackets, epktrcvd, srvping; #ifdef CK_AUTODL extern int inautodl, cmdadl; #endif /* CK_AUTODL */ #ifndef NOSERVER extern int en_asg, en_cwd, en_cpy, en_del, en_dir, en_fin, en_bye, en_ret, en_get, en_hos, en_que, en_ren, en_sen, en_set, en_spa, en_typ, en_who, en_mai, en_pri, en_mkd, en_rmd, en_xit, en_ena; #endif /* NOSERVER */ extern int atcapr, atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko, attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso; #ifdef STRATUS extern int atfrmi, atfrmo, atcrei, atcreo, atacti, atacto; #endif /* STRATUS */ #ifdef CK_PERMS extern int atlpri, atlpro, atgpri, atgpro; #endif /* CK_PERMS */ #ifdef CK_LOGIN extern char * anonfile; /* Anonymous login init file */ extern char * anonroot; /* Anonymous file-system root */ extern char * userfile; /* Forbidden user file */ extern int isguest; /* Flag for anonymous user */ #endif /* CK_LOGIN */ #endif /* NOXFER */ #ifdef DCMDBUF int *xquiet = NULL; int *xvarev = NULL; #else int xquiet[CMDSTKL]; int xvarev[CMDSTKL]; #endif /* DCMDBUF */ char * prstring[CMDSTKL]; #ifndef NOSPL extern long ck_alarm; extern char alrm_date[], alrm_time[]; /* Local declarations */ static int nulcmd = 0; /* Flag for next cmd to be ignored */ /* Definitions for predefined macros */ /* First, the single-line macros, installed with addmac()... */ /* IBM-LINEMODE macro */ char *m_ibm = "set parity mark, set dupl half, set handsh xon, set flow none"; /* FATAL macro */ char *m_fat = "if def \\%1 echo \\%1, if not = \\v(local) 0 hangup, stop 1"; #ifdef CK_SPEED #ifdef IRIX65 char *m_fast = "set win 30, set rec pack 4000, set prefix cautious"; #else #ifdef IRIX /* Because of bug in telnet server */ char *m_fast = "set window 30, set rec pack 4000, set send pack 4000,\ set pref cautious"; #else #ifdef pdp11 char *m_fast = "set win 3, set rec pack 1024, set prefix cautious"; #else #ifdef BIGBUFOK char *m_fast = "set win 30, set rec pack 4000, set prefix cautious"; #else char *m_fast = "set win 4, set rec pack 2200, set prefix cautious"; #endif /* BIGBUFOK */ #endif /* IRIX */ #endif /* IRIX65 */ #endif /* pdp11 */ #ifdef pdp11 char *m_cautious = "set win 2, set rec pack 512, set prefixing cautious"; #else char *m_cautious = "set win 4, set rec pack 1000, set prefixing cautious"; #endif /* pdp11 */ char *m_robust = "set win 1, set rec pack 90, set prefixing all, \ set reliable off, set clearchannel off, set send timeout 20 fixed"; #else #ifdef BIGBUFOK #ifdef IRIX65 char *m_fast = "set win 30, set rec pack 4000"; #else #ifdef IRIX char *m_fast = "set win 30, set rec pack 4000, set send pack 4000"; #else char *m_fast = "set win 30, set rec pack 4000"; #endif /* IRIX */ #endif /* IRIX65 */ #else /* Not BIGBUFOK */ char *m_fast = "set win 4, set rec pack 2200"; #endif /* BIGBUFOK */ char *m_cautious = "set win 4, set rec pack 1000"; char *m_robust = "set win 1, set rec pack 90, set reliable off,\ set send timeout 20 fixed"; #endif /* CK_SPEED */ #ifdef VMS char *m_purge = "run purge \\%*"; #endif /* VMS */ #ifdef OS2 char *m_manual = "browse \\v(exedir)docs/manual/index.htm"; #endif /* OS2 */ /* Now the multiline macros, defined with addmmac()... */ /* Kermit's scripting language is so much more powerful than C that it was about a thousand time easier to implement FOR, WHILE, IF, and SWITCH commands as internal Kermit macros. This was done in 1996 for C-Kermit 6.0. The following definitions, down to #ifdef COMMENT, are from C-Kermit 9.0.304 Dev.22, April 2017, where the command parser was changed to not evaluate macro arguments on the DO command line, but to defer evaluation until after the arguments had been separated and counted. This change required subtle modifications to the internal macro templates. IMPORTANT: Internal macros must have names that start with '_', followed by three letters, e.g. _whi for WHILE. The definitions below are just templates for some other code that constructs the actual menu to be executed by filling in the \%x variables. The generated macros have names like _whil2, _whil3, etc, where the trailing number is the execution stack level. The reason for the strict naming convention is so internal macros can be parsed differently than regular ones. See ckuusr.c:isinternalmacro(), which determines the type of macro. */ /* The WHILE macro: \%1 = Loop condition \%2 = Loop body */ char *whil_def[] = { "_assign _whi\\v(cmdlevel) {_getargs,", ":_..inc,\\fcontents(\\%1),\\fcontents(\\%2),goto _..inc,:_..bot,_putargs},", "_define break goto _..bot, _define continue goto _..inc,", "do _whi\\v(cmdlevel),_assign _whi\\v(cmdlevel)", ""}; /* FOR macro for \%i-style loop variables (see dofor()...) \%1 = Loop variable \%2 = Initial value (can be an expression) \%3 = Loop exit value \%4 = Loop increment \%5 = > or < \%6 = Loop body */ char *for_def[] = { "_assign _for\\v(cmdlevel) { _getargs,", "define \\\\\\%1 \\feval(\\%2),:_..top,if \\%5 \\\\\\%1 \\%3 goto _..bot,", "\\fcontents(\\%6),:_..inc,incr \\\\\\%1 \\%4,goto _..top,:_..bot,_putargs},", "define break goto _..bot, define continue goto _..inc,", "do _for\\v(cmdlevel) \\\\%1 \\%2 \\%3 \\%4 { \\%5 },_assign _for\\v(cmdlevel)", ""}; /* FOR macro when the loop variable is itself a macro, with same arguments but slightly different quoting. */ char *foz_def[] = { "_assign _for\\v(cmdlevel) { _getargs,", "def \\%1 \\feval(\\%2),:_..top,if \\%5 \\%1 \\%3 goto _..bot,", "\\fcontents(\\%6),:_..inc,incr \\%1 \\%4,goto _..top,:_..bot,_putargs},", "def break goto _..bot, def continue goto _..inc,", "do _for\\v(cmdlevel) \\%1 \\%2 \\%3 \\%4 { \\%5 },_assign _for\\v(cmdlevel)", ""}; /* SWITCH macro \%1 = Switch variable \%2 = Switch body */ char *sw_def[] = { "_assign _sw_\\v(cmdlevel) {_getargs,", "_forward {\\fcontents(\\%1)},\\fcontents(\\%2),:default,:_..bot,_putargs},_def break goto _..bot,", "do _sw_\\v(cmdlevel),_assign _sw_\\v(cmdlevel)", ""}; /* IF macro /%1 = Commands to execute (IF part and ELSE part if any) */ char *xif_def[] = { "_assign _if_\\v(cmdlevel) {_getargs,\\fcontents(\\%1),_putargs},", "do _if_\\v(cmdlevel),_assign _if\\v(cmdlevel)", ""}; #ifdef COMMENT /* Internal macro definitions for C-Kermit 6.0 through 9.0.302 */ char *for_def[] = { "_assign _for\\v(cmdlevel) { _getargs,", "def \\\\\\%1 \\feval(\\%2),:_..top,if \\%5 \\\\\\%1 \\%3 goto _..bot,", "\\%6,:_..inc,incr \\\\\\%1 \\%4,goto _..top,:_..bot,_putargs},", "def break goto _..bot, def continue goto _..inc,", "do _for\\v(cmdlevel) \\%1 \\%2 \\%3 \\%4 { \\%5 },_assign _for\\v(cmdlevel)", ""}; char *foz_def[] = { "_assign _for\\v(cmdlevel) { _getargs,", "def \\%1 \\feval(\\%2),:_..top,if \\%5 \\%1 \\%3 goto _..bot,", "\\%6,:_..inc,incr \\%1 \\%4,goto _..top,:_..bot,_putargs},", "def break goto _..bot, def continue goto _..inc,", "do _for\\v(cmdlevel) \\%1 \\%2 \\%3 \\%4 { \\%5 },_assign _for\\v(cmdlevel)", ""}; /* SWITCH macro */ char *sw_def[] = { "_assign _sw_\\v(cmdlevel) {_getargs,", "_forward {\\%1},\\%2,:default,:_..bot,_putargs},_def break goto _..bot,", "do _sw_\\v(cmdlevel),_assign _sw_\\v(cmdlevel)", ""}; /* XIF macro */ char *xif_def[] = { "_assign _if\\v(cmdlevel) {_getargs,\\%1,_putargs},", "do _if\\v(cmdlevel),_assign _if\\v(cmdlevel)", ""}; #endif /* COMMENT */ /* Variables declared here for use by other ckuus*.c modules. Space is allocated here to save room in ckuusr.c. */ #ifdef DCMDBUF struct cmdptr *cmdstk; int *ifcmd = NULL, *count = NULL, *iftest = NULL, *intime = NULL, *inpcas = NULL, *takerr = NULL, *merror = NULL; #else struct cmdptr cmdstk[CMDSTKL]; int ifcmd[CMDSTKL], count[CMDSTKL], iftest[CMDSTKL], intime[CMDSTKL], inpcas[CMDSTKL], takerr[CMDSTKL], merror[CMDSTKL]; #endif /* DCMDBUF */ /* Macro stack */ #ifdef COMMENT char *topline = NULL; /* Program invocation arg line */ char *m_line[MACLEVEL] = { NULL, NULL }; /* Stack of macro invocation lines */ #endif /* COMMENT */ char **m_xarg[MACLEVEL]; /* Pointers to arg vector arrays */ int n_xarg[MACLEVEL]; /* Sizes of arg vector arrays */ char *m_arg[MACLEVEL][NARGS]; /* Args of each level */ int macargc[MACLEVEL]; /* Argc of each level */ char *macp[MACLEVEL]; /* Current position in each macro */ char *macx[MACLEVEL]; /* Beginning of each macro def */ char *mrval[MACLEVEL]; /* RETURN value at each level */ int lastcmd[MACLEVEL]; /* Last command at each level */ int topargc = 0; /* Argc at top level */ char **topxarg = NULL; /* Argv at top level */ char *toparg[MAXARGLIST+2]; /* Global Variables */ char *g_var[GVARS+1]; /* Global \%a..z pointers */ extern char varnam[]; /* \%x variable name buffer */ /* Arrays -- Dimension must be 'z' - ARRAYBASE + 1 */ /* Note: a_link[x] < 0 means no link; >= 0 is a link */ char **a_ptr[32]; /* Array pointers, for arrays a-z */ int a_dim[32]; /* Dimensions for each array */ int a_link[32]; /* Link (index of linked-to-array) */ char **aa_ptr[CMDSTKL][32]; /* Array stack for automatic arrays */ int aa_dim[CMDSTKL][32]; /* Dimensions for each array */ /* INPUT command buffers and variables */ char * inpbuf = NULL; /* Buffer for INPUT and REINPUT */ extern char * inpbp; /* Global/static pointer to it */ char inchar[2] = { NUL, NUL }; /* Last character that was INPUT */ int incount = 0; /* INPUT character count */ extern int instatus; /* INPUT status */ static char * i_text[] = { /* INPUT status text */ "success", "timeout", "interrupted", "internal error", "i/o error" }; char lblbuf[LBLSIZ]; /* Buffer for labels */ #else /* NOSPL */ int takerr[MAXTAKE]; #endif /* NOSPL */ static char *prevdir = NULL; int pacing = 0; /* OUTPUT pacing */ char *tp; /* Temporary buffer pointer */ int timelimit = 0, asktimer = 0; /* Timers for time-limited commands */ #ifdef CK_APC /* Application Program Command (APC) */ int apcactive = APC_INACTIVE; int apcstatus = APC_OFF; /* OFF by default everywhere */ #ifdef DCMDBUF char *apcbuf; #else char apcbuf[APCBUFLEN]; #endif /* DCMDBUF */ #endif /* CK_APC */ extern char pktfil[], #ifdef DEBUG debfil[], #endif /* DEBUG */ #ifdef TLOG trafil[], #endif /* TLOG */ sesfil[]; #ifndef NOFRILLS extern int rmailf, rprintf; /* REMOTE MAIL & PRINT items */ extern char optbuf[]; #endif /* NOFRILLS */ extern int noinit; /* Flat to skip init file */ #ifndef NOSPL static struct keytab kcdtab[] = { /* Symbolic directory names */ #ifdef NT { "appdata", VN_APPDATA, 0 }, { "common", VN_COMMON, 0 }, { "desktop", VN_DESKTOP, 0 }, #endif /* NT */ { "download", VN_DLDIR, 0 }, #ifdef OS2ORUNIX { "exedir", VN_EXEDIR, 0 }, #endif /* OS2ORUNIX */ { "home", VN_HOME, 0 }, { "inidir", VN_INI, 0 }, #ifdef UNIX { "lockdir", VN_LCKDIR, 0 }, #endif /* UNIX */ #ifdef NT { "my_documents",VN_PERSONAL, 0 }, { "personal", VN_PERSONAL, CM_INV }, #endif /* NT */ { "startup", VN_STAR, 0 }, { "textdir", VN_TXTDIR, 0 }, { "tmpdir", VN_TEMP, 0 } }; static int nkcdtab = (sizeof(kcdtab) / sizeof(struct keytab)); #endif /* NOSPL */ #ifndef NOSPL _PROTOTYP( VOID freelocal, (int) ); _PROTOTYP( static CK_OFF_T expon, (CK_OFF_T, CK_OFF_T) ); _PROTOTYP( static CK_OFF_T gcd, (CK_OFF_T, CK_OFF_T) ); _PROTOTYP( static CK_OFF_T fact, (CK_OFF_T) ); int /* Initialize macro data structures. */ macini() { /* Allocate mactab and preset the first element. */ int i; if (!(mactab = (struct mtab *) malloc(sizeof(struct mtab) * MAC_MAX))) return(-1); mactab[0].kwd = NULL; mactab[0].mval = NULL; mactab[0].flgs = 0; for (i = 0; i < MACLEVEL; i++) localhead[i] = NULL; return(0); } #endif /* NOSPL */ /* C M D S R C -- Returns current command source */ /* 0 = top level, 1 = file, 2 = macro, -1 = error (shouldn't happen) */ /* As of 19 Aug 2000 this routine is obsolete. The scalar global variable xcmdsrc can be checked instead to save the overhead of a function call. */ int cmdsrc() { #ifdef COMMENT return(xcmdsrc); #else #ifndef NOSPL if (cmdlvl == 0) return(0); else if (cmdstk[cmdlvl].src == CMD_MD) return(2); else if (cmdstk[cmdlvl].src == CMD_TF) return(1); else return(-1); #else if (tlevel < 0) return(0); else return(1); #endif /* NOSPL */ #endif /* COMMENT */ } /* C M D I N I -- Initialize the interactive command parser */ static int cmdinited = 0; /* Command parser initialized */ extern int cmdint; /* Interrupts are allowed */ #ifdef CK_AUTODL int cmdadl = 1; /* Autodownload */ #else int cmdadl = 0; #endif /* CK_AUTODL */ char * k_info_dir = NULL; /* Where to find text files */ #ifdef UNIX static char * txtdir[] = { "/usr/local/doc/", /* Linux, SunOS, ... */ "/usr/share/lib/", /* HP-UX 10.xx... */ "/usr/share/doc/", /* Other possibilities... */ "/usr/local/lib/", /* NOTE: Each of these is tried */ "/usr/local/share/", /* as is, and also with a kermit */ "/usr/local/share/doc/", /* subdirectory. */ "/usr/local/share/lib/", "/opt/kermit/", /* Solaris */ "/opt/kermit/doc/", "/opt/", "/usr/doc/", "/doc/", "" }; #endif /* UNIX */ /* lookup() cache to speed up script execution. This is a static cache. Items are stored in decreasing frequency of reference based on statistics from a range of scripts. This gives better performance than a dynamic cache, which would require a lot more code and also would require system-dependent elements including system calls (e.g. to get subsecond times for entry aging). */ #ifdef USE_LUCACHE /* Set in ckuusr.h */ #define LUCACHE 32 /* Change this to reduce cache size */ int lusize = 0; char * lucmd[LUCACHE]; int luval[LUCACHE]; int luidx[LUCACHE]; struct keytab * lutab[LUCACHE]; #endif /* USE_LUCACHE */ static VOID luinit() { /* Initialize lookup() cache */ int x, y; #ifdef USE_LUCACHE x = lookup(cmdtab,"if",ncmd,&y); lucmd[lusize] = "if"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = cmdtab; if (++lusize > LUCACHE) return; x = lookup(iftab,"not",nif,&y); lucmd[lusize] = "not"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = iftab; if (++lusize > LUCACHE) return; x = lookup(vartab,"cmdlevel",nvars,&y); lucmd[lusize] = "cmdlevel"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = vartab; if (++lusize > LUCACHE) return; x = lookup(cmdtab,"goto",ncmd,&y); lucmd[lusize] = "goto"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = cmdtab; if (++lusize > LUCACHE) return; x = lookup(iftab,">",nif,&y); lucmd[lusize] = ">"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = iftab; if (++lusize > LUCACHE) return; x = lookup(cmdtab,"incr",ncmd,&y); lucmd[lusize] = "incr"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = cmdtab; if (++lusize > LUCACHE) return; x = lookup(cmdtab,"def",ncmd,&y); lucmd[lusize] = "def"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = cmdtab; if (++lusize > LUCACHE) return; x = lookup(cmdtab,"_assign",ncmd,&y); lucmd[lusize] = "_assign"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = cmdtab; if (++lusize > LUCACHE) return; x = lookup(cmdtab,"echo",ncmd,&y); lucmd[lusize] = "echo"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = cmdtab; if (++lusize > LUCACHE) return; x = lookup(fnctab,"eval",nfuncs,&y); lucmd[lusize] = "eval"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = fnctab; if (++lusize > LUCACHE) return; x = lookup(fnctab,"lit",nfuncs,&y); lucmd[lusize] = "lit"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = fnctab; if (++lusize > LUCACHE) return; x = lookup(cmdtab,"do",ncmd,&y); lucmd[lusize] = "do"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = cmdtab; if (++lusize > LUCACHE) return; x = lookup(cmdtab,"_getargs",ncmd,&y); lucmd[lusize] = "_getargs"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = cmdtab; if (++lusize > LUCACHE) return; x = lookup(iftab,"<",nif,&y); lucmd[lusize] = "<"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = iftab; if (++lusize > LUCACHE) return; x = lookup(cmdtab,"_putargs",ncmd,&y); lucmd[lusize] = "_putargs"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = cmdtab; if (++lusize > LUCACHE) return; x = lookup(cmdtab,"asg",ncmd,&y); lucmd[lusize] = "asg"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = cmdtab; if (++lusize > LUCACHE) return; x = lookup(cmdtab,"else",ncmd,&y); lucmd[lusize] = "else"; luval[lusize] = x; luidx[lusize] = y; lutab[lusize] = cmdtab; #endif /* USE_LUCACHE */ } VOID cmdini() { int i = 0, x = 0, y = 0, z = 0, skip = 0; char * p; #ifdef TTSPDLIST long * ss = NULL; extern int nspd; extern struct keytab * spdtab; #endif /* TTSPDLIST */ #ifndef NOSPL /* On stack to allow recursion! */ char vnambuf[VNAML]; /* Buffer for variable names */ #endif /* NOSPL */ if (cmdinited) /* Already initialized */ return; /* Don't do it again */ for (i = 0; i < CMDSTKL; i++) /* Prompt strings for each */ prstring[i] = NULL; /* command level */ #ifndef NOCSETS p = getenv("K_CHARSET"); /* Set default file character set */ if (p) { /* from environment */ x = lookup(fcstab,p,nfilc,&y); if (x > -1) fcharset = x; } #endif /* NOCSETS */ p = getenv("K_INFO_DIRECTORY"); /* Find Kermit info directory */ if (p && *p && strlen(p) <= CKMAXPATH) makestr(&k_info_dir,p); if (!k_info_dir) { p = getenv("K_INFO_DIR"); if (p && *p && strlen(p) <= CKMAXPATH) makestr(&k_info_dir,p); } #ifdef UNIX if (k_info_dir) { /* Look for Kermit docs directory */ if (zchki(k_info_dir) == -2) { char xbuf[CKMAXPATH+32], *s = ""; if (ckrchar(k_info_dir) != '/') s = "/"; ckmakmsg(xbuf,CKMAXPATH+32,k_info_dir,s,"ckubwr.txt",NULL); if (zchki(xbuf) < 0) makestr(&k_info_dir,NULL); } } if (!k_info_dir) { char xbuf[CKMAXPATH+32]; int i; for (i = 0; *(txtdir[i]); i++) { ckmakmsg(xbuf,CKMAXPATH+32,txtdir[i],"ckubwr.txt",NULL,NULL); if (zchki(xbuf) > 0) { makestr(&k_info_dir,txtdir[i]); debug(F110,"k_info_dir 1",k_info_dir,0); break; } ckmakmsg(xbuf,CKMAXPATH+32, txtdir[i],"kermit/","ckubwr.txt",NULL); if (zchki(xbuf) > 0) { ckmakmsg(xbuf,CKMAXPATH+32,txtdir[i],"kermit/",NULL,NULL); makestr(&k_info_dir,xbuf); debug(F110,"k_info_dir 2",k_info_dir,0); break; } ckmakmsg(xbuf,CKMAXPATH+32, txtdir[i],"ckermit/","ckubwr.txt",NULL); if (zchki(xbuf) > 0) { ckmakmsg(xbuf,CKMAXPATH+32,txtdir[i],"ckermit/",NULL,NULL); makestr(&k_info_dir,xbuf); debug(F110,"k_info_dir 3",k_info_dir,0); break; } } if (k_info_dir) { /* Make sure it ends with "/" */ if (ckrchar(k_info_dir) != '/') { char xbuf[CKMAXPATH+32]; ckmakmsg(xbuf,CKMAXPATH+32,k_info_dir,"/",NULL,NULL); makestr(&k_info_dir,xbuf); } } } #else #ifdef OS2 { char xdir[CKMAXPATH+8], *s = ""; extern char startupdir[]; xdir[0] = NUL; if (ckrchar(startupdir) != '/') s = "/"; if (strlen(s) + strlen(startupdir) + 5 < CKMAXPATH + 8 ) ckmakmsg(xdir,CKMAXPATH+8,s,startupdir,"DOC/",NULL); makestr(&k_info_dir,xdir); } #endif /* OS2 */ #endif /* UNIX */ #ifdef TTSPDLIST if (!spdtab && (ss = ttspdlist())) { /* Get speed list if necessary */ int j, k, m = 0, n; /* Create sorted keyword table */ char buf[16]; char * p; if ((spdtab = (struct keytab *) malloc(sizeof(struct keytab) * ss[0]))) { for (i = 1; i <= ss[0]; i++) { /* ss[0] = number of elements */ if (ss[i] < 1L) break; /* Shouldn't happen */ buf[0] = NUL; /* Make string */ sprintf(buf,"%ld",ss[i]); /* SAFE */ if (ss[i] == 8880L) ckstrncpy(buf,"75/1200",sizeof(buf)); if (ss[i] == 134L) ckstrncat(buf,".5",16); n = strlen(buf); if ((n > 0) && (p = (char *)malloc(n+1))) { if (m > 0) { /* Have at least one in list */ for (j = 0; /* Find slot */ j < m && strcmp(buf,spdtab[j].kwd) > 0; j++ ) ; if (j < m) { /* Must insert */ for (k = m-1; k >= j; k--) { /* Move others down */ spdtab[k+1].kwd = spdtab[k].kwd; spdtab[k+1].flgs = spdtab[k].flgs; spdtab[k+1].kwval = spdtab[k].kwval; } } } else /* First one */ j = 0; ckstrncpy(p,buf,n+1); /* Add new speed */ spdtab[j].kwd = p; spdtab[j].flgs = 0; spdtab[j].kwval = (int) ss[i] / 10; m++; /* Count this one */ } } } nspd = m; } #ifndef NOSORTSPEEDS /* In C-Kermit 10.0 the list of serial speeds is potentially much longer than in earlier releases because of the new high-speed UARTs. When the user types "set speed ?" the result is a confusing jumble because it's in "alphabetic" order rather than numeric. This code sorts the list into numeric order so a sensible result is obtained. -fdc 10 October 2022 */ if ( 1 ) { int i = 0; int k = 0; int x = 0; int n = sizeof spdtab + 2; int maxspeedlen = 20; #ifdef COMMENT /* This approach blew up on VMS even though it worked on Ubuntu and NetBSD */ char * speeds[nspd + 2]; struct keytab tmp[nspd + 2]; #else /* Fix by SMS 2022-10-11: Use constant array dimensions; non-constant array dimensions are a C99 feature. */ char **speeds; struct keytab *tmp; speeds = malloc( sizeof( char *)* (nspd + 2)); tmp = malloc( sizeof( struct keytab)* (nspd + 2)); #endif /* COMMENT */ for (i = 0; i < nspd; i++) { /* Allocate string storage */ speeds[i] = malloc(n+2); tmp[i].kwd = malloc(maxspeedlen+2); } for (i = 0; i < nspd; i++) { /* Copy speeds into a sortable array */ ckstrncpy(speeds[i],spdtab[i].kwd,maxspeedlen); } /* Sort the array (sh_sort() doesn't sort structs) */ (void) sh_sort(speeds,NULL,nspd,0,0,2); /* Create new sorted array of structs */ for (i = 0; i < nspd; i++) { /* i = index to sorted speeds */ for (k = 0; k < nspd; k++) { /* k = index to original list */ if (!strcmp(spdtab[k].kwd, speeds[i])) { ckstrncpy(tmp[i].kwd,spdtab[k].kwd,n); tmp[i].flgs = spdtab[k].flgs; tmp[i].kwval = spdtab[k].kwval; break; } } } for (i = 0; i < nspd; i++) { ckstrncpy(spdtab[i].kwd, tmp[i].kwd,n); spdtab[i].flgs = tmp[i].flgs; spdtab[i].kwval = tmp[i].kwval; } free(tmp); free(speeds); } #endif /* NOSORTSPEEDS */ #endif /* TTSPDLIST */ #ifndef NOSPL /* Allocate INPUT command buffer */ if (!inpbuf) { if (!(inpbuf = (char *) malloc(INPBUFSIZ+8))) fatal("cmdini: no memory for INPUT buffer"); } for (x = 0; x < INPBUFSIZ; x++) /* Initialize it */ inpbuf[x] = NUL; inpbp = inpbuf; /* Initialize pointer */ inbufsize = INPBUFSIZ; /* and size. */ #endif /* NOSPL */ #ifdef DCMDBUF if (cmsetup() < 0) fatal("Can't allocate command buffers!"); #ifndef NOSPL /* Allocate command stack allowing command parser to call itself */ if (!(cmdstk = (struct cmdptr *) malloc(sizeof(struct cmdptr)*CMDSTKL))) fatal("cmdini: no memory for cmdstk"); if (!(ifcmd = (int *) malloc(sizeof(int)*CMDSTKL))) fatal("cmdini: no memory for ifcmd"); if (!(count = (int *) malloc(sizeof(int)*CMDSTKL))) fatal("cmdini: no memory for count"); if (!(iftest = (int *) malloc(sizeof(int)*CMDSTKL))) fatal("cmdini: no memory for iftest"); if (!(intime = (int *) malloc(sizeof(int)*CMDSTKL))) fatal("cmdini: no memory for intime"); if (!(inpcas = (int *) malloc(sizeof(int)*CMDSTKL))) fatal("cmdini: no memory for inpcas"); if (!(takerr = (int *) malloc(sizeof(int)*CMDSTKL))) fatal("cmdini: no memory for takerr"); if (!(merror = (int *) malloc(sizeof(int)*CMDSTKL))) fatal("cmdini: no memory for merror"); if (!(xquiet = (int *) malloc(sizeof(int)*CMDSTKL))) fatal("cmdini: no memory for xquiet"); if (!(xvarev = (int *) malloc(sizeof(int)*CMDSTKL))) fatal("cmdini: no memory for xvarev"); if (!kermrc) if (!(kermrc = (char *) malloc(KERMRCL+1))) fatal("cmdini: no memory for kermrc"); #ifdef CK_APC /* Application Program Command buffer */ if (!(apcbuf = malloc(APCBUFLEN + 1))) fatal("cmdini: no memory for apcbuf"); #endif /* CK_APC */ #endif /* NOSPL */ /* line[] and tmpbuf[] are the two string buffers used by the command parser */ if (!(line = malloc(LINBUFSIZ + 1))) fatal("cmdini: no memory for line"); if (!(tmpbuf = malloc(LINBUFSIZ + 1))) fatal("cmdini: no memory for tmpbuf"); #endif /* DCMDBUF */ #ifndef NOSPL #ifdef CK_MINPUT { /* Initialize MINPUT pointers */ int i; extern char *ms[]; for (i = 0; i < MINPMAX; i++) ms[i] = NULL; } #endif /* CK_MINPUT */ if (macini() < 0) /* Allocate macro buffers */ fatal("Can't allocate macro buffers!"); ifcmd[0] = 0; /* Command-level related variables. */ iftest[0] = 0; /* Initialize variables at top level */ count[0] = 0; /* of stack... */ intime[0] = 0; inpcas[0] = 0; takerr[0] = 0; merror[0] = 0; xquiet[0] = quiet; xvarev[0] = vareval; #endif /* NOSPL */ #ifndef NOSPL cmdlvl = 0; /* Initialize the command stack */ xcmdsrc = CMD_KB; cmdstk[cmdlvl].src = CMD_KB; /* Source is console */ cmdstk[cmdlvl].lvl = 0; /* Level is 0 */ cmdstk[cmdlvl].ccflgs = 0; /* No flags */ #endif /* NOSPL */ tlevel = -1; /* Take file level = keyboard */ for (i = 0; i < MAXTAKE; i++) /* Initialize command file names */ tfnam[i] = NULL; cmsetp(ckprompt); /* Set up C-Kermit's prompt */ /* Can't set IKSD prompt here since */ /* we do not yet know if we are IKSD */ #ifndef NOSPL initmac(); /* Initialize macro table */ /* Predefine built-in one-line macros */ addmac("ibm-linemode",m_ibm); /* IBM-LINEMODE */ addmac("fatal",m_fat); /* FATAL macro */ y = addmac("fast",m_fast); /* FAST macro */ addmac("cautious",m_cautious); /* CAUTIOUS macro */ addmac("robust",m_robust); /* ROBUST macro */ #ifdef OS2 addmac("manual",m_manual); /* MANUAL macro */ #endif /* OS2 */ #ifdef VMS addmac("purge",m_purge); /* PURGE macro */ #endif /* VMS */ /* Predefine built-in multiline macros; these are top-level commands that are implemented internally as macros. NOTE: When adding a new one of these, remember to update the END and RETURN commands to account for it, or else END and RETURN from within it won't work right. */ x = addmmac("_forx",for_def); /* FOR macro */ if (x > -1) mactab[x].flgs = CM_INV; x = addmmac("_forz",foz_def); /* Other FOR macro */ if (x > -1) mactab[x].flgs = CM_INV; x = addmmac("_xif",xif_def); /* XIF macro */ if (x > -1) mactab[x].flgs = CM_INV; x = addmmac("_while",whil_def); /* WHILE macro */ if (x > -1) mactab[x].flgs = CM_INV; x = addmmac("_switx",sw_def); /* SWITCH macro */ if (x > -1) mactab[x].flgs = CM_INV; /* Fill in command-line argument vector */ sprintf(vnambuf,"\\&@[%d]",xargs); /* SAFE */ if (inserver) { /* But hidden in IKSD */ y = -1; xargs = 0; } else y = arraynam(vnambuf,&x,&z); /* goes in array \&@[] */ tmpbuf[0] = NUL; if (y > -1) { int j = -1; int yy = 0; dclarray((char)x,z); /* Declare the array */ #ifndef NOTAKEARGS /* Macro argument vector */ sprintf(vnambuf,"\\&_[%d]",z); /* SAFE */ yy = arraynam(vnambuf,&x,&z); /* goes in array \&_[] */ if (yy > -1) /* Name is OK */ dclarray((char)x,z); /* Declare the array */ #endif /* NOTAKEARGS */ skip = 0; for (i = 0; i < xargs; i++) { /* Fill the arrays */ sprintf(vnambuf,"\\&@[%d]",i); /* SAFE */ addmac(vnambuf,xargv[i]); if (cfilef && i == 0) continue; #ifdef KERBANG if (skip) { j = 0; skip = 0; continue; } #endif /* KERBANG */ if (j < 0 && /* Assign items after "=" or "--"*/ (!strcmp(xargv[i],"=") || !strcmp(xargv[i],"--")) ) { j = 0; /* to \%1..\%9 */ #ifdef KERBANG } else if (j < 0 && (!strcmp(xargv[i],"+") || !strncmp(xargv[i],"+ ",2) || !strncmp(xargv[i],"+\t",2)) ) { skip = 1; continue; #endif /* KERBANG */ } else if (j > -1) { j++; if (j <= 9) { vnambuf[0] = '\\'; vnambuf[1] = '%'; vnambuf[2] = (char)(j+'0'); vnambuf[3] = NUL; addmac(vnambuf,xargv[i]); } if (yy > -1) { char c, * p; int flag = 0; p = xargv[i]; makestr(&(toparg[j]),p); while ((c = *p++)) { if (c == SP) { flag++; break; } } if (flag) ckstrncat(tmpbuf,"\"",TMPBUFSIZ); ckstrncat(tmpbuf,xargv[i],TMPBUFSIZ); if (flag) ckstrncat(tmpbuf,"\"",TMPBUFSIZ); ckstrncat(tmpbuf," ",TMPBUFSIZ); } } } if (cfilef) { addmac("\\%0",cmdfil); if (yy > -1) makestr(&(toparg[0]),cmdfil); } else { addmac("\\%0",xargv[0]); if (yy > -1) makestr(&(toparg[0]),xargv[0]); } if (yy > -1) { topargc = (j < 0) ? 1 : j + 1; topxarg = toparg; #ifdef COMMENT /* This needs work */ if (!cfilef) makestr(&topline,tmpbuf); #endif /* COMMENT */ } else { topargc = 0; topxarg = NULL; } a_dim[0] = topargc - 1; a_ptr[0] = topxarg; debug(F111,"a_dim[0]","A",a_dim[0]); } *vnambuf = NUL; #endif /* NOSPL */ luinit(); /* Initialize lookup() cache */ /* Get our home directory now. This needed in lots of places. */ cmdinited = 1; } #ifdef NT _PROTOTYP(char * GetAppData,(int)); #endif /* NT */ VOID doinit() { #ifdef CKROOT extern int ckrooterr; #endif /* CKROOT */ int x = 0, ok = 0; #ifdef OS2 char * ptr = 0; #endif /* OS2 */ if (!cmdinited) cmdini(); #ifdef MAC return; /* Mac Kermit has no init file */ #else /* !MAC */ /* If skipping init file ('-Y' on Kermit command line), return now. */ if (noinit) { kermrc[0] = '\0'; inidir[0] = '\0'; /* But returning from here results in inidir[] never being set to anything. Instead it should be set to wherever the init file *would* have been executed from. So this bit of code should be removed, and then we should sprinkle "if (noinit)" tests throughout the following code until we have set inidir[], and then return without actually taking the init file. */ return; } #ifdef OS2 /* The -y init file must be fully specified or in the current directory. KERMRC is looked for via INIT, DPATH and PATH in that order. Finally, our own executable file path is taken and the .EXE suffix is replaced by .INI and this is tried as the initialization file. */ #ifdef CK_LOGIN debug(F101,"doinit inserver","",inserver); debug(F101,"doinit isguest","",isguest); debug(F110,"doinit anonfile",anonfile,0); if (isguest && anonfile) { ckstrncpy(line, anonfile, LINBUFSIZ+1); } else #endif /* CK_LOGIN */ if (rcflag) { ckstrncpy(line,kermrc,LINBUFSIZ+1); #ifdef CK_LOGIN } else if (inserver) { char * appdata = NULL; #ifdef NT appdata = GetAppData(1); if ( appdata ) { ckmakmsg(line,LINBUFSIZ+1,appdata, "Kermit 95/k95.ini",NULL,NULL); if ( zchki(line) < 0 ) line[0] = '\0'; } if (line[0] == 0) { appdata = GetAppData(0); if ( appdata ) { ckmakmsg(line,LINBUFSIZ+1,appdata, "Kermit 95/k95.ini",NULL,NULL); if ( zchki(line) < 0 ) line[0] = '\0'; } } #endif /* NT */ if (line[0] == 0) { appdata = zhome(); if ( appdata ) { ckmakmsg(line,LINBUFSIZ+1,appdata, #ifdef NT "k95.ini", #else /* NT */ "k2.ini", #endif /* NT */ NULL,NULL); if ( zchki(line) < 0 ) line[0] = '\0'; } } debug(F110,"doinit inserver inifile",line,0); #endif /* CK_LOGIN */ } else { char * env = 0; #ifdef NT env = getenv("K95.KSC"); #else env = getenv("K2.KSC"); #endif /* NT */ if (!env) { #ifdef NT env = getenv("K95.INI"); #else env = getenv("K2.INI"); #endif /* NT */ } if (!env) env = getenv("CKERMIT.INI"); if (!env) env = getenv("CKERMIT_INI"); line[0] = '\0'; debug(F110,"doinit env",env,0); if (env) ckstrncpy(line,env,LINBUFSIZ+1); #ifdef NT if (line[0] == 0) { env = GetAppData(1); if ( env ) { ckmakmsg(line,LINBUFSIZ+1,env,"Kermit 95/k95.ini",NULL,NULL); if ( zchki(line) < 0 ) line[0] = '\0'; } } if (line[0] == 0) { env = GetAppData(0); if ( env ) { ckmakmsg(line,LINBUFSIZ+1,env,"Kermit 95/k95.ini",NULL,NULL); if ( zchki(line) < 0 ) line[0] = '\0'; } } #endif /* NT */ if (line[0] == 0) { env = zhome(); if ( env ) { ckmakmsg(line,LINBUFSIZ+1,env, #ifdef NT "k95.ini", #else /* NT */ "k2.ini", #endif /* NT */ NULL,NULL); if ( zchki(line) < 0 ) line[0] = '\0'; } } if (line[0] == 0) _searchenv(kermrc,"INIT",line); if (line[0] == 0) _searchenv(kermrc,"DPATH",line); if (line[0] == 0) _searchenv(kermrc,"PATH",line); if (line[0] == 0) { char *pgmptr = GetLoadPath(); if (pgmptr && strlen(pgmptr) < LINBUFSIZ-8) { lp = strrchr(pgmptr, '\\'); if (lp) { strncpy(line, pgmptr, lp - pgmptr); #ifdef NT strcpy(line + (lp - pgmptr), "/k95.ini"); #else /* NT */ strcpy(line + (lp - pgmptr), "/k2.ini"); #endif /* NT */ } else { lp = strrchr(pgmptr, '.'); if (lp) { strncpy(line, pgmptr, lp - pgmptr); strcpy(line + (lp - pgmptr), ".ini"); } } } } } #ifdef CKROOT if (!zinroot(line)) { debug(F110,"doinit setroot violation",line,0); return; } #endif /* CKROOT */ debug(F110,"doinit fopen()",line,0); if ((tfile[0] = fopen(line,"r")) != NULL) { ok = 1; tlevel = 0; tfline[tlevel] = 0; tfblockstart[tlevel] = 1; if (tfnam[tlevel] = malloc(strlen(line)+1)) strcpy(tfnam[tlevel],line); /* safe */ #ifndef NOSPL cmdlvl++; xcmdsrc = CMD_TF; cmdstk[cmdlvl].src = CMD_TF; cmdstk[cmdlvl].lvl = tlevel; cmdstk[cmdlvl].ccflgs = 0; ifcmd[cmdlvl] = 0; iftest[cmdlvl] = 0; count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */ intime[cmdlvl] = intime[cmdlvl-1]; inpcas[cmdlvl] = inpcas[cmdlvl-1]; takerr[cmdlvl] = takerr[cmdlvl-1]; merror[cmdlvl] = merror[cmdlvl-1]; xquiet[cmdlvl] = quiet; xvarev[cmdlvl] = vareval; #endif /* NOSPL */ debug(F110,"doinit init file",line,0); } else { debug(F100,"doinit no init file","",0); } ckstrncpy(kermrc,line,KERMRCL); for (ptr = kermrc; *ptr; ptr++) /* Convert backslashes to slashes */ if (*ptr == '\\') *ptr = '/'; #else /* not OS2 */ lp = line; lp[0] = '\0'; debug(F101,"doinit rcflag","",rcflag); #ifdef GEMDOS zkermini(line, rcflag, kermrc); #else #ifdef VMS { int x; x = zkermini(line,LINBUFSIZ,kermrc); debug(F111,"CUSTOM zkermini",line,x); if (x == 0) line[0] = NUL; } #else /* not VMS */ #ifdef CK_LOGIN debug(F101,"doinit isguest","",isguest); if (isguest) ckstrncpy(lp, anonfile ? anonfile : kermrc, LINBUFSIZ); else #endif /* CK_LOGIN */ if (rcflag) { /* If init file name from cmd line */ ckstrncpy(lp,kermrc,LINBUFSIZ); /* use it, */ } else { /* otherwise... */ #ifdef CK_INI_A /* If we've a system-wide init file */ /* And it takes precedence over the user's... */ ckstrncpy(lp,CK_SYSINI,KERMRCL); /* Use it */ if (zchki(lp) < 0) { /* (if it exists...) */ #endif /* CK_INI_A */ char * homdir; char * env = 0; line[0] = NUL; /* Add support for environment variable */ env = getenv("CKERMIT.INI"); if (!env) env = getenv("CKERMIT_INI"); if (env) ckstrncpy(lp,env,KERMRCL); if (lp[0] == 0) { homdir = zhome(); if (homdir) { /* Home directory for init file. */ ckstrncpy(lp,homdir,KERMRCL); #ifdef STRATUS ckstrncat(lp,">",KERMRCL);/* VOS dirsep */ #else if (lp[0] == '/') ckstrncat(lp,"/",KERMRCL); #endif /* STRATUS */ } ckstrncat(lp,kermrc,KERMRCL);/* Append default file name */ } #ifdef CK_INI_A } #endif /* CK_INI_A */ #ifdef CK_INI_B /* System-wide init defined? */ /* But user's ini file takes precedence */ if (zchki(lp) < 0) /* If user doesn't have her own, */ ckstrncpy(lp,CK_SYSINI,KERMRCL); /* use system-wide one. */ #endif /* CK_INI_B */ } #endif /* VMS */ #endif /* GEMDOS */ #ifdef AMIGA reqoff(); /* Disable requestors */ #endif /* AMIGA */ #ifdef USE_CUSTOM /* If no init file was found, execute the customization file */ debug(F111,"CUSTOM 1",line,rcflag); if ((!line[0] || zchki(line) < 0) && !rcflag) { int x; #ifdef OS2 x = ckmakestr(line,LINBUFSIZ,GetAppData(1),"/","K95CUSTOM.INI",NULL); debug(F111,"CUSTOM 2",line,x); if (zchki(line) < 0) { x = ckmakestr(line,LINBUFSIZ,GetAppData(0),"/","K95USER.INI",NULL); debug(F111,"CUSTOM 3",line,x); } #else /* OS2 */ x = ckstrncpy(line,zhome(),LINBUFSIZ); #ifndef VMS /* VMS zhome() returns "SYS$LOGIN:" */ if (line[x-1] != DIRSEP) { line[x++] = DIRSEP; line[x] = NUL; } #endif /* VMS */ x = ckstrncat(line,MYCUSTOM,LINBUFSIZ); debug(F111,"CUSTOM 4",line,x); #endif /* OS2 */ } debug(F110,"CUSTOM 5",line,0); #endif /* USE_CUSTOM */ #ifdef CKROOT if (!zinroot(line)) { debug(F110,"doinit setroot violation",line,0); return; } #endif /* CKROOT */ debug(F110,"doinit ini file is",line,0); if ((tfile[0] = fopen(line,"r")) != NULL) { /* Try to open init file. */ ok = 1; tlevel = 0; tfline[tlevel] = 0; tfblockstart[tlevel] = 1; if ((tfnam[tlevel] = malloc(strlen(line)+1))) strcpy(tfnam[tlevel],line); /* safe */ ckstrncpy(kermrc,line,KERMRCL); #ifndef NOSPL cmdlvl++; ifcmd[cmdlvl] = 0; iftest[cmdlvl] = 0; count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */ intime[cmdlvl] = intime[cmdlvl-1]; inpcas[cmdlvl] = inpcas[cmdlvl-1]; takerr[cmdlvl] = takerr[cmdlvl-1]; merror[cmdlvl] = merror[cmdlvl-1]; xquiet[cmdlvl] = quiet; xvarev[cmdlvl] = vareval; debug(F101,"doinit open ok","",cmdlvl); xcmdsrc = CMD_TF; cmdstk[cmdlvl].src = CMD_TF; cmdstk[cmdlvl].lvl = tlevel; cmdstk[cmdlvl].ccflgs = 0; #endif /* NOSPL */ } else if (rcflag) { /* Print an error message only if a specific file was asked for. */ printf("?%s - %s\n", ck_errstr(), line); } #ifdef datageneral /* If CKERMIT.INI not found in home directory, look in searchlist */ if (/* homdir && */ (tlevel < 0)) { ckstrncpy(lp,kermrc,LINBUFSIZ); if ((tfile[0] = fopen(line,"r")) != NULL) { ok = 1; tlevel = 0; tfline[tlevel] = 0; tfblockstart[tlevel] = 1; if (tfnam[tlevel] = malloc(strlen(line)+1)) strcpy(tfnam[tlevel],line); /* safe */ #ifndef NOSPL cmdlvl++; xcmdsrc = CMD_TF; cmdstk[cmdlvl].src = CMD_TF; cmdstk[cmdlvl].lvl = tlevel; cmdstk[cmdlvl].ccflgs = 0; ifcmd[cmdlvl] = 0; iftest[cmdlvl] = 0; count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */ intime[cmdlvl] = intime[cmdlvl-1]; inpcas[cmdlvl] = inpcas[cmdlvl-1]; takerr[cmdlvl] = takerr[cmdlvl-1]; merror[cmdlvl] = merror[cmdlvl-1]; xquiet[cmdlvl] = quiet; xvarev[cmdlvl] = vareval; #endif /* NOSPL */ } } #endif /* datageneral */ #ifdef AMIGA /* Amiga... */ reqpop(); /* Restore requestors */ #endif /* AMIGA */ #endif /* OS2 */ #endif /* MAC */ /* Assign value to inidir */ if (!ok) { inidir[0] = NUL; } else { ckstrncpy(inidir, kermrc, CCHMAXPATH); x = strlen(inidir); if (x > 0) { int i; for (i = x - 1; i > 0; i-- ) { if (ISDIRSEP(inidir[i])) { inidir[i+1] = NUL; break; } } } #ifdef NT ckGetShortPathName(inidir,inidir,CCHMAXPATH); #endif /* NT */ } } VOID doiksdinit() { #ifdef CK_SSL /* IKSD doesn't request client certs */ ssl_verify_flag = SSL_VERIFY_NONE; #endif /* CK_SSL */ if (!cmdinited) cmdini(); #ifdef IKSDCONF #ifdef OS2 line[0] = '\0'; _searchenv(iksdconf,"INIT",line); if (line[0] == 0) _searchenv(iksdconf,"DPATH",line); if (line[0] == 0) _searchenv(iksdconf,"PATH",line); if (line[0] == 0) { char *pgmptr = GetLoadPath(); if (pgmptr && strlen(pgmptr) < LINBUFSIZ-8) { lp = strrchr(pgmptr, '\\'); if (lp) { strncpy(line, pgmptr, lp - pgmptr); strcpy(line + (lp - pgmptr), "\\"); strcpy(line + (lp - pgmptr + 1), iksdconf); } else { lp = strrchr(pgmptr, '.'); if (lp) { strncpy(line, pgmptr, lp - pgmptr); strcpy(line + (lp - pgmptr), ".ksc"); } } } } debug(F110,"doiksdinit() line",line,0); tfile[0] = fopen(line,"r"); #else /* OS2 */ tfile[0] = fopen(iksdconf,"r"); #endif /* OS2 */ if (tfile[0] != NULL) { tlevel = 0; tfline[tlevel] = 0; tfblockstart[tlevel] = 1; #ifdef OS2 if (tfnam[tlevel] = malloc(strlen(line)+1)) strcpy(tfnam[tlevel],line); #else /* OS2 */ if ((tfnam[tlevel] = malloc(strlen(iksdconf)+1))) strcpy(tfnam[tlevel],iksdconf); #endif /* OS2 */ #ifndef NOSPL cmdlvl++; xcmdsrc = CMD_TF; cmdstk[cmdlvl].src = CMD_TF; cmdstk[cmdlvl].lvl = tlevel; cmdstk[cmdlvl].ccflgs = 0; ifcmd[cmdlvl] = 0; iftest[cmdlvl] = 0; count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */ intime[cmdlvl] = intime[cmdlvl-1]; inpcas[cmdlvl] = inpcas[cmdlvl-1]; takerr[cmdlvl] = takerr[cmdlvl-1]; merror[cmdlvl] = merror[cmdlvl-1]; xquiet[cmdlvl] = quiet; xvarev[cmdlvl] = vareval; #endif /* NOSPL */ debug(F110,"doiksdinit file ok",tfnam[tlevel],0); } else { debug(F110,"doiksdinit open failed",tfnam[tlevel],0); } #endif /* IKSDCONF */ } #ifndef NOSPL /* G E T N C M Get next command from current macro definition. Command is copied into string pointed to by argument s, max length n. Returns: 0 if a string was copied; -1 if there was no string to copy. */ int #ifdef CK_ANSIC getncm( char *s, int n ) #else getncm(s,n) char *s; int n; #endif /* CK_ANSIC */ { int y = 0; /* Character counter */ int quote = 0; int kp = 0; /* Brace up-down counter */ int pp = 0; /* Parenthesis up-down counter */ #ifndef NODQMACRO int dq = 0; /* Doublequote counter */ #endif /* NODQMACRO */ char *s2; /* Copy of destination pointer */ s2 = s; /* Initialize string pointers */ *s = NUL; /* and destination buffer */ /* debug(F010,"getncm entry",macp[maclvl],0); */ for (y = 0; /* Loop for n bytes max */ macp[maclvl] && *macp[maclvl] && y < n; y++, s++, macp[maclvl]++) { *s = *macp[maclvl]; /* Get next char from macro def */ #ifndef COMMENT /* This is to allow quoting of parentheses, commas, etc, in function arguments, but it breaks just about everything else. DON'T REMOVE THIS COMMENT! (Otherwise you'll wind up adding the same code again and breaking everything again.) <-- The preceding warning should be obsolete since the statements below have been fixed, but in case of fire, remove the "n" from the <#>ifndef above. NEW WARNING: code added 12 Apr 2002 to exempt the opening brace in \{nnn} from being treated as a quoted brace. */ if (!quote && *s == CMDQ) { quote = 1; continue; } if (quote) { int notquote = 0; quote = 0; if (*s == '{') { /* Check for \{nnn} (8.0.203) */ char c, * p; p = macp[maclvl] + 1; while ((c = *p++)) { if (isdigit(c)) continue; else if (c == '}') { notquote++; break; } else { break; } } } if (notquote == 0) continue; } #endif /* COMMENT */ /* Allow braces around macro definition to prevent commas from being turned to end-of-lines and also treat any commas within parens as text so that multiple-argument functions won't cause the command to break prematurely. 19 Oct 2001: Similar treatment was added for doublequotes, so define foo { echo "one, two, three" } would work as expected. This doesn't seem to have broken anything but if something comes up later, rebuild with NODQMACRO defined. */ if (*s == '{') kp++; /* Count braces */ if (*s == '}' && kp > 0) kp--; if (*s == '(') pp++; /* Count parentheses. */ if (*s == ')' && pp > 0) pp--; #ifndef NODQMACRO #ifndef COMMENT /* Too many false positives */ /* No, not really -- this is indeed the best we can do */ /* Reverted to this method Sun May 11 18:43:45 2003 */ if (*s == '"') dq = 1 - dq; /* Account for doublequotes */ #else /* Fri Apr 4 13:21:29 2003 */ /* The code below breaks the SWITCH statement */ /* There is no way to make this work -- it would require */ /* building in all the knowledge of command parser. */ if (dblquo && (*s == '"')) { /* Have doublequote */ if (dq == 1) { /* Close quote only if... */ if ((*(macp[maclvl]+1) == SP) || /* followed by space or... */ (!*(macp[maclvl]+1)) || /* at end or ... */ /* Next char is command separator... */ /* Sun May 11 17:24:12 2003 */ (kp < 1 && pp < 1 && (*(macp[maclvl]+1) == ',')) ) dq = 0; /* Close the quote */ } else if (dq == 0) { /* Open quote only if at beginning or preceded by space */ if (s > s2) { if (*(s-1) == SP) dq = 1; } else if (s == s2) { dq = 1; } } } #endif /* COMMENT */ #endif /* NODQMACRO */ if (*s == ',' && pp <= 0 && kp <= 0 #ifndef NODQMACRO && dq == 0 #endif /* NODQMACRO */ ) { macp[maclvl]++; /* Comma not in {} or () */ /* debug(F110,"next cmd",s,0); */ kp = pp = 0; /* so we have the next command */ break; } } /* Reached end. */ #ifdef COMMENT /* DON'T DO THIS - IT BREAKS EVERYTHING */ *s = NUL; #endif /* COMMENT */ if (*s2 == NUL) { /* If nothing was copied, */ /* debug(F100,"getncm eom","",0); */ popclvl(); /* pop command level. */ return(-1); } else { /* otherwise, tack CR onto end */ *s++ = CK_CR; *s = '\0'; /* debug(F110,"getncm OK",s,0); */ if (mecho && pflag) /* If MACRO ECHO ON, echo the cmd */ printf("%s\n",s2); } return(0); } /* D O M A C -- Define and then execute a macro */ int #ifdef CK_ANSIC domac( char *name, char *def, int flags ) #else domac(name, def, flags) char *name, *def; int flags; #endif /* CK_ANSIC */ { int x, m; #ifndef NOLOCAL #ifdef OS2 extern int term_io; int term_io_sav = term_io; term_io = 0; /* Disable Terminal Emulator I/O */ #endif /* OS2 */ #endif /* NOLOCAL */ m = maclvl; /* Current macro stack level */ x = addmac(name, def); /* Define a new macro */ if (x > -1) { /* If successful, */ dodo(x,NULL,flags); /* start it (increments maclvl). */ while (maclvl > m) { /* Keep going till done with it, */ debug(F101,"domac loop maclvl 1","",maclvl); sstate = (CHAR) parser(1); /* parsing & executing each command, */ debug(F101,"domac loop maclvl 2","",maclvl); if (sstate) proto(); /* including protocol commands. */ } debug(F101,"domac loop exit maclvl","",maclvl); } #ifndef NOLOCAL #ifdef OS2 term_io = term_io_sav; #endif /* OS2 */ #endif /* NOLOCAL */ return(success); } #endif /* NOSPL */ /* G E T N C T Get next command from TAKE (command) file. Call with: s Pointer to buffer to read into n Length of buffer f File descriptor of file to read from flag 0 == keep line terminator on and allow continuation 1 == discard line terminator and don't allow continuation Call with flag == 0 to read a command from a TAKE file; Call with flag != 0 to read a line from a dialing or network directory. In both cases, trailing comments and/or trailing whitespace is/are stripped. If flag == 0, continued lines are combined into one line. A continued line is one that ends in hypen, or any line in a "block", which starts with "{" at the end of a line and ends with a matching "}" at the beginning of a subsequent line; blocks may be nested. Returns: 0 if a string was copied, -1 on EOF, -2 on malloc failure -3 if line is not properly terminated -4 if (possibly continued) line is too long. */ static int lpxlen = 0; int #ifdef CK_ANSIC getnct( char *s, int n, FILE *f, int flag ) #else getnct(s,n,f,flag) char *s; int n; FILE *f; int flag; #endif /* CK_ANSIC */ { int i = 0, len = 0, buflen = 0; char c = NUL, cc = NUL, ccl = NUL, ccx = NUL, *s2 = NULL; char *lp = NULL, *lpx = NULL, *lp2 = NULL, *lp3 = NULL, *lastcomma = NULL; char * prev = NULL; int bc = 0; /* Block counter */ int firstread = 1; s2 = s; /* Remember original pointer */ prev = s2; /* Here too */ buflen = n; /* Remember original buffer length */ if (n < 0) return(-2); /* Allocate a line buffer only if we don't have one that's big enough */ debug(F111,"getnct",ckitoa(lpxlen),n); if (lpx && (n > lpxlen)) { /* Have one already */ debug(F101,"getnct new buffer","",lpxlen); free(lpx); /* But it's not big enough */ lpx = NULL; /* Free current one */ lpxlen = 0; } if (!lpx) { /* Get new one */ if (!(lpx = (char *) malloc(n))) { debug(F101,"getnct malloc failure","",0); printf("?Memory allocation failure [getnct:%d]\n",n); return(-2); } lpxlen = n; } lp2 = lpx; #ifdef KLUDGE /* NOTE: No longer used as of 14 Aug 2000 */ lp2++; #endif /* KLUDGE */ while (1) { /* Loop to read lines from file */ debug(F101,"getnct while (1)","",n); if (fgets(lp2,n,f) == NULL) { /* Read a line into lp2 */ debug(F110,"getnct EOF",s2,0); /* EOF */ free(lpx); /* Free temporary storage */ lpx = NULL; *s = NUL; /* Make destination be empty */ return(-1); /* Return failure code */ } if (firstread) { /* Beginning of a block or statement */ tfblockstart[tlevel] = tfline[tlevel]; firstread = 0; } #ifndef NODIAL if (flag) /* Count this line */ dirline++; else #endif /* NODIAL */ tfline[tlevel]++; len = strlen(lp2) - 1; /* Position of line terminator */ if (len == 0 && lp2[0] != '\n') { /* Last line in file has one char */ lp2[++len] = '\n'; /* that is not a newline */ lp2[len] = NUL; } debug(F010,"getnct",lp2,0); if (len < 0) len = 0; if (techo && pflag) { /* If TAKE ECHO ON, */ if (flag) { printf("%3d. %s", #ifndef NODIAL flag ? dirline : #endif /* NODIAL */ tfline[tlevel], lp2 ); } else { printf("%3d. %3d. %s", tfline[tlevel], tfblockstart[tlevel], lp2 ); } } lp3 = lp2; /* Working pointer */ i = len; /* Get first nonwhitespace character */ while (i > 0 && (*lp3 == SP || *lp3 == HT)) { i--; lp3++; } if (i == 0 && bc > 0) /* Blank line in {...} block */ continue; /* Isolate, remove, and check terminator */ c = lp2[len]; /* Value of line terminator */ /* debug(F101,"getnct terminator","",c); */ if (c < LF || c > CK_CR) { /* It's not a terminator */ /* debug(F111,"getnct bad line",lp2,c); */ if (feof(f) && len > 0 && len < n) { /* Kludge Alert... */ if (!quiet) printf("WARNING: Last line of %s lacks terminator\n", s2 == cmdbuf ? "command file" : "directory file"); c = lp2[++len] = '\n'; /* No big deal - supply one. */ } else { /* Something's wrong, fail. */ free(lpx); lpx = NULL; return(-3); } } /* Trim trailing whitespace */ for (i = len - 1; i > -1 && lp2[i] <= SP; i--) /* Trim */ ; /* debug(F101,"getnct i","",i); */ lp2[i+1] = NUL; /* Terminate the string */ /* debug(F110,"getnct lp2",lp2,0); */ lp = lp2; /* Make a working pointer */ /* Remove trailing or full-line comment */ while ((cc = *lp)) { if (cc == ';' || cc == '#') { /* Comment introducer? */ if (lp == lp2) { /* First char on line */ *lp = NUL; break; } else if (*(lp - 1) == SP || *(lp - 1) == HT) { lp--; *lp = NUL; /* Or preceded by whitespace */ break; } } lp++; } if (lp > lp2) lp--; /* Back up over the NUL */ /* Now trim any space that preceded the comment */ while ((*lp == SP || *lp == HT) && lp >= lp2) { *lp = NUL; if (lp <= lp2) break; lp--; } /* debug(F110,"getnct comment trimmed",lp2,0); */ len = strlen(lp2); /* Length after trimming */ if (n - len < 2) { /* Check remaining space */ debug(F111,"getnct command too long",s2,buflen); printf("?Line too long, maximum length: %d.\n",buflen); free(lpx); return(-4); } ccl = (len > 0) ? lp2[len-1] : 0; /* Last character in line */ ccx = (len > 1) ? lp2[len-2] : 0; /* Penultimate char in line */ #ifdef COMMENT /* Line containing only whitespace and ,- */ if ((len > 1) && (lp3 == lp2+len-2) && (ccl == '-') && (ccx == ',')) continue; #endif /* COMMENT */ #ifdef KLUDGE /* If it is a command and it begins with a token (like ! or .) that is not followed by a space, insert a space now; otherwise cmkey() can get mighty confused. */ if (s == s2 && !flag) { char *p = toktab; while (*p) { if (*p == *lp3 && *(p+1) != SP) { debug(F110,"getnct token",p,0); *lp3-- = SP; *lp3 = *p; if (lp3 < lp2) { lp2--; len++; } break; } else p++; } } #endif /* KLUDGE */ lp = lp2; while ((*s++ = *lp++)) /* Copy result to target buffer */ n--; /* accounting for length */ s--; /* Back up over the NUL */ /* Check whether this line is continued */ if (flag) /* No line continuation when flag=1 */ break; /* So break out of read-lines loop */ #ifdef COMMENT debug(F000,"getnct first char","",*lp3); debug(F000,"getnct last char","",ccl); debug(F000,"getnct next-to-last char","",ccx); #endif /* COMMENT */ if (bc > 0 && *lp3 == '}') { /* First char on line is '}' */ bc--; /* Decrement block counter */ } if (bc == 0 && /* Line is continued if bc > 0 */ #ifdef COMMENT /* Not supported as of C-Kermit 6.0 */ ccl != CMDQ && /* or line ends with CMDQ */ #endif /* COMMENT */ ccl != '-' && /* or line ends with dash */ ccl != '{') { /* or line ends with opening brace */ break; /* None of those, we're done. */ } if (ccl == '-' || ccl == '{') /* Continuation character */ if (ccx == CMDQ) /* But it's quoted */ break; /* so ignore it */ if (ccl == '{') { /* Last char on line is '{'? */ bc++; /* Count the block opener. */ } else if (ccl == '-') { /* Explicit continue? */ char c, * ss; int state = 0, nn; s--; /* Yes, back up over terminators */ n++; /* and over continuation character */ nn = n; /* Save current count */ ss = s; /* and pointer */ s--; /* Back up over dash */ n++; while (state < 2 && s >= prev) { /* Check for "{,-" */ n++; c = *s--; if (c <= SP) continue; if (c != ',' && c != '{') break; switch (state) { case 0: /* Looking for comma */ if (c == ',') state = 1; break; case 1: /* Looking for left brace */ if (c == '{') { state = 2; s += 2; *s = NUL; bc++; } break; } } if (state != 2) { s = ss; n = nn; } *s = NUL; } else { /* None of those but (bc > 0) */ lastcomma = s; *s++ = ','; /* and insert a comma */ n--; } #ifdef COMMENT debug(F101,"getnct bc","",bc); debug(F100,"getnct continued","",0); #endif /* COMMENT */ *s = NUL; prev = s; } /* read-lines while loop */ if (lastcomma) *lastcomma = SP; if (!flag) /* Tack line terminator back on */ *s++ = c; *s++ = NUL; /* Terminate the string */ untab(s2); /* Done, convert tabs to spaces */ #ifdef DEBUG if (!flag) { debug(F010,"CMD(F)",s2,0); } #endif /* DEBUG */ { int i = 0; char *s = s2; char prev = '\0'; char c = '\0'; /* Next line from Jeff Johnson, to fix garbled message when iksd.conf has an invalide line that is shorter than a previous line that is valid - 16 May 2023 */ memset(lasttakeline, '\0', sizeof(char)*TMPBUFSIZ+1); while (*s) { /* Save beginning of this command for error messages */ c = *s++; if (c == '\n' || c == '\r') c = SP; if (c == SP && prev == SP) /* Squeeze spaces */ continue; lasttakeline[i++] = c; prev = c; if (i > TMPBUFSIZ-5) { lasttakeline[i++] = '.'; lasttakeline[i++] = '.'; lasttakeline[i++] = '.'; lasttakeline[i++] = NUL; break; } } i = (int)strlen((char *)lasttakeline) - 1; while (i > 0 && lasttakeline[i] == SP) { /* Trim treailing spaces */ lasttakeline[i] = NUL; i--; } } free(lpx); /* Free temporary storage */ return(0); /* Return success */ } VOID shostack() { /* Dump the command stack */ int i; char *p; #ifndef NOSPL for (i = cmdlvl; i > 0; i--) { if (cmdstk[i].src == CMD_TF) { p = tfnam[cmdstk[i].lvl]; if (zfnqfp(p,TMPBUFSIZ,tmpbuf)) p = tmpbuf; printf(" %2d. File : %s (line %d)\n", i, p, tfline[cmdstk[i].lvl] ); } else if (cmdstk[i].src == CMD_MD) { char * m; m = m_arg[cmdstk[i].lvl][0]; /* Name of this macro */ if (i > 0) { /* Special handling for 2-level */ char *s; /* built-in macros... */ s = m_arg[cmdstk[i-1].lvl][0]; /* Name next level up */ if (s && cmdstk[i-1].src == CMD_MD) { if (!strcmp(s,"_forx")) m = "FOR"; else if (!strcmp(s,"_xif")) m = "XIF"; else if (!strcmp(s,"_while")) m = "WHILE"; else if (!strcmp(s,"_switx")) m = "SWITCH"; } } printf(" %2d. Macro : %s\n",i,m); } else if (cmdstk[i].src == CMD_KB) { printf(" %2d. Prompt:\n",i); } else { printf(" %2d. ERROR : Command source unknown\n",i); } } #else for (i = tlevel; i > -1; i--) { p = tfnam[i]; if (zfnqfp(p,TMPBUFSIZ,tmpbuf)) p = tmpbuf; printf(" %2d. File : %s (line %d)\n", i, p, tfline[i] ); } #endif /* NOSPL */ if (i == 0) printf(" %2d. Prompt: (top level)\n",0); } /* For command error messages - avoid dumping out the contents of some */ /* some huge FOR loop if it contains a syntax error. */ static char * #ifdef CK_ANSIC cmddisplay( char * s, int cx ) #else cmddisplay(s, cx) char * s; int cx; #endif /* CK_ANSIC */ { static char buf[80]; if ((int)strlen(s) > 70) { sprintf(buf,"%.64s...",s); /* SAFE */ s = buf; } return(s); } #ifdef COMMENT static VOID cmderr() { if (xcmdsrc > 0) { switch (cmd_err) { /* SET COMMAND ERROR-DISPLAY */ case 0: break; case 1: case 2: if (tlevel > -1) { #ifndef NOSPL if (xcmdsrc == 2) printf( "In macro or block defined in file: %s starting about line %d\n", tfnam[tlevel] ? tfnam[tlevel] : "", tfline[tlevel] ); else #endif /* NOSPL */ printf("File: %s, Line: %d\n", tfnam[tlevel] ? tfnam[tlevel] : "", tfline[tlevel] ); } #ifndef NOSPL if (cmd_err == 2) { if (cmdstk[cmdlvl].src == CMD_MD) { /* Executing a macro? */ int m; m = cmdstk[cmdlvl].lvl; if (mlook(mactab,m_arg[m][0],nmac) >= 0) printf("Macro name: %s\n", m_arg[m][0]); } } #endif /* NOSPL */ break; case 3: printf("Command stack:\n"); shostack(); } } } #endif /* COMMENT */ /* P A R S E R -- Top-level interactive command parser. */ /* Call with: m = 0 for normal behavior: keep parsing and executing commands until an action command is parsed, then return with a Kermit start-state as the value of this function. m = 1 to parse only one command, can also be used to call parser() recursively. m = 2 to read but do not execute one command. In all cases, parser() returns: 0 if no Kermit protocol action required > 0 with a Kermit protocol start-state. < 0 upon error. */ int #ifdef CK_ANSIC parser( int m ) #else parser(m) int m; #endif /* CK_ANSIC */ { int tfcode, xx, yy, zz; /* Workers */ int is_tn = 0; int cdlost = 0; #ifndef NOSPL int inlevel; /* Level we were called at */ extern int askflag, echostars; #endif /* NOSPL */ char *cbp; /* Command buffer pointer */ #ifdef MAC extern char *lfiles; /* Fake extern cast */ #endif /* MAC */ extern int interrupted; #ifndef NOXFER extern int sndcmd, getcmd, fatalio, clearrq; #endif /* NOXFER */ #ifdef AMIGA reqres(); /* Restore AmigaDOS requestors */ #endif /* AMIGA */ #ifdef OS2 if (cursor_save > -1) { /* Restore cursor if it was */ cursorena[VCMD] = cursor_save; /* turned off during file transfer */ cursor_save = -1; } #endif /* OS2 */ #ifdef IKSDB if (ikdbopen) slotstate(what,"COMMAND PROMPT","",""); /* IKSD database */ #endif /* IKSDB */ is_tn = (local && network && IS_TELNET()) || (!local && sstelnet); if (!xcmdsrc) /* If at top (interactive) level ... */ concb((char)escape); /* put console in 'cbreak' mode. */ #ifdef CK_TMPDIR /* If we were cd'd temporarily to another device or directory ... */ if (f_tmpdir) { int x; x = zchdir((char *) savdir); /* ... restore previous directory */ f_tmpdir = 0; /* and remember we did it. */ debug(F111,"parser tmpdir restoring",savdir,x); } #endif /* CK_TMPDIR */ #ifndef NOSPL inlevel = cmdlvl; /* Current macro level */ #ifdef DEBUG if (deblog) { debug(F101,"&parser entry maclvl","",maclvl); debug(F101,"&parser entry inlevel","",inlevel); debug(F101,"&parser entry tlevel","",tlevel); debug(F101,"&parser entry cmdlvl","",cmdlvl); debug(F101,"&parser entry m","",m); } #endif /* DEBUG */ #endif /* NOSPL */ #ifndef NOXFER ftreset(); /* Reset global file settings */ #endif /* NOXFER */ /* sstate becomes nonzero when a command has been parsed that requires some action from the protocol module. Any non-protocol actions, such as local directory listing or terminal emulation, are invoked directly from below. */ sstate = 0; /* Start with no start state. */ #ifndef NOXFER #ifndef NOSPL query = 0; /* QUERY not active */ #endif /* NOSPL */ #ifndef NOHINTS if (!success) { if (local && !network && carrier != CAR_OFF) { int x; /* Serial connection */ x = ttgmdm(); /* with carrier checking */ if (x > -1) { if (!(x & BM_DCD)) { cdlost = 1; fatalio = 1; } } } } #ifdef DEBUG if (deblog) { debug(F101,"parser top what","",what); debug(F101,"parser top interrupted","",interrupted); debug(F101,"parser top cdlost","",cdlost); debug(F101,"parser top sndcmd","",sndcmd); debug(F101,"parser top getcmd","",getcmd); } #endif /* DEBUG */ if (cdlost && !interrupted && (sndcmd || getcmd)) { printf("?Connection broken (carrier signal lost)\n"); } if (sndcmd && protocol == PROTO_K && !success && hints && !interrupted && !fatalio && !xcmdsrc) { int x = 0, n = 0; printf("\n*************************\n"); printf("SEND-class command failed.\n"); printf(" Packets sent: %d\n", spackets); printf(" Retransmissions: %d\n",retrans); printf(" Timeouts: %d\n", timeouts); printf(" Damaged packets: %d\n", crunched); if (epktrcvd) { printf(" Transfer canceled by receiver.\n"); printf(" Receiver's message: \"%s\"\n",(char *)epktmsg); n++; } else { if (epktmsg) if (*epktmsg) { printf(" Fatal Kermit Protocol Error: %s\n",epktmsg); n++; } } if (local && !network && carrier != CAR_OFF) { int xx; /* Serial connection */ xx = ttgmdm(); /* with carrier checking */ if (xx > -1) { if (!(xx & BM_DCD)) cdlost = 1; } } #ifdef UNIX if (errno != 0) #endif /* UNIX */ { printf(" Most recent local OS error: \"%s\"\n",ck_errstr()); n++; } printf( "\nHINTS... If the preceding error message%s not explain the failure:\n", (n > 1) ? "s do" : " does" ); #ifndef NOLOCAL if (local) { if (rpackets == 0) { printf(" . Did you start a Kermit receiver on the far end?\n"); } else { printf( " . Try changing the remote Kermit's FLOW-CONTROL setting.\n"); if (!network && mdmtyp > 0) if ((3 * crunched) > spackets) printf( " . Try placing a new call to get a cleaner connection.\n"); } } else if (rpackets > 0) { if (flow == FLO_NONE) printf(" . Give me a SET FLOW XON/XOFF command and try again.\n"); else printf(" . Give me a SET FLOW NONE command and try again.\n"); } x++; #endif /* NOLOCAL */ if ((3 * timeouts) > spackets) printf(" . Adjust the timeout method (see HELP SET SEND).\n"); if ((3 * retrans) > spackets) printf(" . Increase the retry limit (see HELP SET RETRY).\n"); #ifdef CK_SPEED if (prefixing != PX_ALL && rpackets > 2) { printf(" . Try it again with: SET PREFIXING ALL\n"); x++; } #endif /* CK_SPEED */ #ifdef STREAMING if (streamed) { printf(" . Try it again with: SET STREAMING OFF\n"); x++; } else if (reliable) { printf(" . Try it again with: SET RELIABLE OFF\n"); x++; } #endif /* STREAMING */ #ifdef CK_SPEED if (clearrq > 0 && prefixing == PX_NON) { printf(" . Try it again with: SET CLEAR-CHANNEL OFF\n"); x++; } #endif /* CK_SPEED */ if (!parity) { printf(" . Try it again with: SET PARITY SPACE\n"); x++; } printf(" . %sive a ROBUST command and try again.\n", (x > 0) ? "As a last resort, g" : "G" ); printf("Also:\n"); printf(" . Be sure the source file has read permission.\n"); printf(" . Be sure the target directory has write permission.\n"); /* if the file was 2G or larger make sure other Kermit supports LFs... */ printf(" . Be sure the target disk has sufficient space.\n"); printf("(Use SET HINTS OFF to suppress hints.)\n"); printf("*************************\n\n"); } debug(F101,"topcmd","",topcmd); if (getcmd && protocol == PROTO_K && !success && hints && !interrupted && !fatalio && !xcmdsrc) { #ifdef COMMENT int x = 0; #endif /* COMMENT */ extern int urpsiz, wslotr; printf("\n*************************\n"); printf("RECEIVE- or GET-class command failed.\n"); printf(" Packets received: %d\n", rpackets); printf(" Damaged packets: %d\n", crunched); printf(" Timeouts: %d\n", timeouts); if (rpackets > 0) printf(" Packet length: %d\n", urpsiz); if (epktrcvd) { printf(" Transfer canceled by sender.\n"); printf(" Sender's message: \"%s\"\n",(char *)epktmsg); if (ckindex("not found",(char *)epktmsg,0,0,0) || ckindex("no such",(char *)epktmsg,0,0,0)) { printf(" Did you spell the filename right?\n"); printf(" Is the other Kermit CD'd to the right directory?\n"); } } #ifdef UNIX if (errno != 0) #endif /* UNIX */ { (VOID) ckstrncpy(tmpbuf,ck_errstr(),TMPBUFSIZ); printf(" Most recent local error: \"%s\"\n",tmpbuf); } #ifdef COMMENT printf( "\nHINTS... If the preceding error message%s not explain the failure:\n", epktrcvd ? "s do" : " does" ); #ifndef NOLOCAL if (local) { if (topcmd == XXGET) printf(" . Did you start a Kermit SERVER on the far end?\n"); if (rpackets == 0) { if (topcmd != XXGET) printf(" . Did you start a Kermit SENDer on the far end?\n"); } else { printf( " . Choose a different FLOW-CONTROL setting and try again.\n"); } } else if (topcmd == XXGET) printf(" . Is the other Kermit in (or does it have) SERVER mode?\n"); if (rpackets > 0 && urpsiz > 90) printf(" . Try smaller packets (SET RECEIVE PACKET-LENGTH).\n"); if (rpackets > 0 && wslotr > 1 && !streamed) printf(" . Try a smaller window size (SET WINDOW).\n"); if (!local && rpackets > 0) { if (flow == FLO_NONE) printf(" . Give me a SET FLOW XON/XOFF command and try again.\n"); else printf(" . Give me a SET FLOW NONE command and try again.\n"); } x++; #endif /* NOLOCAL */ #ifdef STREAMING if (streamed) { printf(" . Try it again with: SET STREAMING OFF\n"); x++; } else if (reliable && local) { printf(" . Try it again with: SET RELIABLE OFF\n"); x++; } else #endif /* STREAMING */ if (!parity) { printf(" . Try it again with: SET PARITY SPACE\n"); x++; } printf((x > 0) ? " . As a last resort, give a ROBUST command and try again.\n" : " . Give a ROBUST command and try again.\n" ); #endif /* COMMENT */ printf("Also:\n"); printf(" . Be sure the target directory has write permission.\n"); printf(" . Be sure the target disk has sufficient space.\n"); printf(" . Try telling the %s to SET PREFIXING ALL.\n", topcmd == XXGET ? "server" : "sender" ); printf(" . Try giving a ROBUST command to the %s.\n", topcmd == XXGET ? "server" : "sender" ); printf("(Use SET HINTS OFF to suppress hints.)\n"); printf("*************************\n\n"); } #endif /* NOHINTS */ getcmd = 0; sndcmd = 0; interrupted = 0; #endif /* NOXFER */ while (sstate == 0) { /* Parse cmds until action requested */ debug(F100,"parse top","",0); what = W_COMMAND; /* Now we're parsing commands. */ rcdactive = 0; /* REMOTE CD not active */ keepallchars = 0; /* MINPUT not active */ #ifdef OS2 if (apcactive == APC_INACTIVE) WaitCommandModeSem(-1); #endif /* OS2 */ #ifdef IKS_OPTION if ((local && !xcmdsrc && is_tn && TELOPT_ME(TELOPT_KERMIT) && TELOPT_SB(TELOPT_KERMIT).kermit.me_start) || (!local && !cmdadl && TELOPT_ME(TELOPT_KERMIT) && TELOPT_SB(TELOPT_KERMIT).kermit.me_start) ) { tn_siks(KERMIT_STOP); } #endif /* IKS_OPTION */ #ifndef NOXFER if (autopath) { fnrpath = PATH_AUTO; autopath = 0; } remfile = 0; /* Clear these in case REMOTE */ remappd = 0; /* command was interrupted... */ rempipe = 0; makestr(&snd_move,g_snd_move); /* Restore these */ makestr(&rcv_move,g_rcv_move); makestr(&snd_rename,g_snd_rename); makestr(&rcv_rename,g_rcv_rename); #endif /* NOXFER */ /* Take requested action if there was an error in the previous command */ setint(); debug(F101,"parser tlevel","",tlevel); debug(F101,"parser cmd_rows","",cmd_rows); #ifndef NOLOCAL debug(F101,"parser wasclosed","",wasclosed); if (wasclosed) { /* If connection was just closed */ #ifndef NOSPL int k; k = mlook(mactab,"on_close",nmac); /* Look up "on_close" */ if (k >= 0) { /* If found, */ /* printf("ON_CLOSE CMD LOOP\n"); */ dodo(k,ckitoa(whyclosed),0); /* Set it up */ } #endif /* NOSPL */ whyclosed = WC_REMO; wasclosed = 0; } #endif /* NOLOCAL */ #ifndef NOSPL xxdot = 0; /* Clear this... */ debug(F101,"parser success","",success); if (success == 0) { if (cmdstk[cmdlvl].src == CMD_TF && takerr[cmdlvl]) { printf("Command file terminated by error.\n"); popclvl(); if (cmdlvl == 0) return(0); } if (cmdstk[cmdlvl].src == CMD_MD && merror[cmdlvl]) { printf("Command error: macro terminated.\n"); popclvl(); if (m && (cmdlvl < inlevel)) return((int) sstate); } } nulcmd = (m == 2); debug(F101,"parser nulcmd","",nulcmd); #else if (success == 0 && tlevel > -1 && takerr[tlevel]) { printf("Command file terminated by error.\n"); popclvl(); cmini(ckxech); /* Clear the cmd buffer. */ if (tlevel < 0) /* Just popped out of cmd files? */ return(0); /* End of init file or whatever. */ } #endif /* NOSPL */ #ifdef MAC /* Check for TAKE initiated by menu. */ if ((tlevel == -1) && lfiles) startlfile(); #endif /* MAC */ /* If in TAKE file, check for EOF */ #ifndef NOSPL #ifdef MAC if #else while #endif /* MAC */ ((cmdstk[cmdlvl].src == CMD_TF) /* If end of take file */ && (tlevel > -1) && feof(tfile[tlevel])) { popclvl(); /* pop command level */ cmini(ckxech); /* and clear the cmd buffer. */ if (cmdlvl == 0) { /* Just popped out of all cmd files? */ return(0); /* End of init file or whatever. */ } } #ifdef MAC miniparser(1); if (sstate == 'a') { /* if cmd-. cancel */ debug(F100, "parser: cancel take due to sstate", "", sstate); sstate = '\0'; dostop(); return(0); /* End of init file or whatever. */ } #endif /* MAC */ #else /* NOSPL */ if ((tlevel > -1) && feof(tfile[tlevel])) { /* If end of take */ popclvl(); /* Pop up one level. */ cmini(ckxech); /* and clear the cmd buffer. */ if (tlevel < 0) /* Just popped out of cmd files? */ return(0); /* End of init file or whatever. */ } #endif /* NOSPL */ #ifndef NOSPL debug(F101,"parser cmdlvl","",cmdlvl); debug(F101,"parser cmdsrc","",cmdstk[cmdlvl].src); if (cmdstk[cmdlvl].src == CMD_MD) { /* Executing a macro? */ debug(F100,"parser macro","",0); maclvl = cmdstk[cmdlvl].lvl; /* Get current level */ debug(F101,"parser maclvl","",maclvl); cbp = cmdbuf; /* Copy next cmd to command buffer. */ *cbp = NUL; if (*savbuf) { /* In case then-part of 'if' command */ ckstrncpy(cbp,savbuf,CMDBL); /* was saved, restore it. */ *savbuf = '\0'; } else { /* Else get next cmd from macro def */ if (getncm(cbp,CMDBL) < 0) { #ifdef DEBUG if (deblog) { debug(F101,"parser end of macro m","",m); debug(F101,"parser end of macro cmdlvl","",cmdlvl); debug(F101,"parser end of macro inlevel","",inlevel); } #endif /* DEBUG */ if (m && (cmdlvl < inlevel)) return((int) sstate); else /* if (!m) */ continue; } } debug(F010,"CMD(M)",cmdbuf,0); } else if (cmdstk[cmdlvl].src == CMD_TF) #else if (tlevel > -1) #endif /* NOSPL */ { #ifndef NOSPL debug(F111,"parser savbuf",savbuf,tlevel); if (*savbuf) { /* In case THEN-part of IF command */ ckstrncpy(cmdbuf,savbuf,CMDBL); /* was saved, restore it. */ *savbuf = '\0'; } else #endif /* NOSPL */ /* Get next line from TAKE file */ if ((tfcode = getnct(cmdbuf,CMDBL,tfile[tlevel],0)) < 0) { debug(F111,"parser tfcode",tfile[tlevel],tfcode); if (tfcode < -1) { /* Error */ printf("?Error in TAKE command file: %s\n", (tfcode == -2) ? "Memory allocation failure" : "Line too long or contains NUL characters" ); dostop(); } continue; /* -1 means EOF */ } /* If interactive, get next command from user. */ } else { /* User types it in. */ if (pflag) prompt(xxstring); cmini(ckxech); } /* Now we know where next command is coming from. Parse and execute it. */ repars = 1; /* 1 = command needs parsing */ #ifndef NOXFER displa = 0; /* Assume no file transfer display */ #endif /* NOXFER */ while (repars) { /* Parse this cmd until entered. */ debug(F101,"parser top of while loop","",0); xaskmore = saveask; /* Restore global more-prompting */ diractive = 0; /* DIR command not active */ cdactive = 0; /* CD command not active */ #ifndef NOSPL askflag = 0; /* ASK command not active */ echostars = 0; /* Nor ASKQ */ debok = 1; /* Undisable debugging */ #endif /* NOSPL */ #ifdef RECURSIVE /* In case of "send /recursive ./?" etc */ recursive = 0; /* This is never sticky */ #endif /* RECURSIVE */ xfiletype = -1; /* Reset this between each command */ #ifndef NOMSEND addlist = 0; #endif /* NOMSEND */ #ifdef CK_RECALL on_recall = 1; #endif /* CK_RECALL */ /* This might have been changed by a switch */ if (g_matchdot > -1) { matchdot = g_matchdot; g_matchdot = -1; } cmres(); /* Reset buffer pointers. */ #ifdef OS2 #ifdef COMMENT /* we check to see if a macro is waiting to be executed */ /* if so, we call domac on it */ if (cmdmac) { ckstrncpy(cmdbuf, cmdmac, CMDBL); free(cmdmac); cmdmac = NULL; } #endif /* COMMENT */ #endif /* OS2 */ #ifndef NOXFER bye_active = 0; #endif /* NOXFER */ havetoken = 0; xx = cmkey2(cmdtab,ncmd,"Command","",toktab,xxstring,1); debug(F101,"top-level cmkey2","",xx); if (xx == -5) { yy = chktok(toktab); debug(F101,"top-level cmkey token","",yy); #ifndef COMMENT /* Either way makes absolutely no difference */ debug(F110,"NO UNGWORD",atmbuf,0); /* ungword(); */ #else debug(F110,"TOKEN UNGWORD",atmbuf,0); ungword(); #endif /* COMMENT */ switch (yy) { case '#': xx = XXCOM; break; /* Comment */ case ';': xx = XXCOM; break; /* Comment */ #ifndef NOSPL case '.': xx = XXDEF; xxdot = 1; break; /* Assignment */ case ':': xx = XXLBL; break; /* GOTO label */ #endif /* NOSPL */ #ifndef NOPUSH #ifdef CK_REDIR case '<': #endif /* CK_REDIR */ case '@': case '!': if (nopush) { char *s; int x; if ((x = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(x); success = 0; xx = XXCOM; } else { switch(yy) { #ifdef CK_REDIR case '<': xx = XXFUN; break; /* REDIRECT */ #endif /* CK_REDIR */ case '@': case '!': xx = XXSHE; break; /* Shell escape */ } } break; #endif /* NOPUSH */ #ifdef CK_RECALL case '^': xx = XXREDO; break; #endif /* CK_RECALL */ #ifndef NOSPL case '{': xx = XXMACRO; break; case '(': xx = XXSEXP; break; #endif /* NOSPL */ default: if (!quiet && !cmd_err) { printf("\n?Not a valid command or token - \"%s\"\n", cmddisplay((char *)cmdbuf,xx) ); /* cmderr(); */ newerrmsg(""); } xx = -2; } havetoken = 1; debug(F101,"HAVE TOKEN","",xx); } if (xx > -1) { topcmd = xx; /* Top-level command index */ #ifndef NOSPL if (maclvl > -1) lastcmd[maclvl] = xx; #endif /* NOSPL */ debug(F101,"topcmd","",topcmd); debug(F101,"cmflgs","",cmflgs); } #ifndef NOSPL /* Special handling for IF..ELSE */ debug(F101,"cmdlvl","",cmdlvl); debug(F101,"ifcmd[cmdlvl]","",ifcmd[cmdlvl]); if (ifcmd[cmdlvl]) /* Count stmts after IF */ ifcmd[cmdlvl]++; if (ifcmd[cmdlvl] > 2 && xx != XXELS && xx != XXCOM) ifcmd[cmdlvl] = 0; /* Execute the command and take action based on return code. */ if (nulcmd) { /* Ignoring this command? */ xx = XXCOM; /* Make this command a comment. */ } fnsuccess = 1; /* For catching \function() errors */ #endif /* NOSPL */ debug(F101,"calling docmd()","",xx); zz = docmd(xx); /* Parse rest of command & execute. */ #ifndef NOSPL { /* For \v(lastcommand) */ extern char * prevcmd; /* The exception list kind of a hack but let's try it... */ if (ckstrcmp(cmdbuf,"_getarg",7,0) && ckstrcmp(cmdbuf,"if ",3,0) && ckstrcmp(cmdbuf,"xif ",4,0) && ckstrcmp(cmdbuf,"do _if",6,0) && ckstrcmp(cmdbuf,"_assign _if",11,0)) ckstrncpy(prevcmd,cmdbuf,CMDBL); } #endif /* NOSPL */ #ifndef NOSPL if (fnerror && !fnsuccess) success = 0; #endif /* NOSPL */ debug(F101,"docmd returns","",zz); /* debug(F011,"cmdbuf",cmdbuf,30); */ /* debug(F011,"atmbuf",atmbuf,30); */ #ifdef MAC if (tlevel > -1) { if (sstate == 'a') { /* if cmd-. cancel */ debug(F110, "parser: cancel take, sstate:", "a", 0); sstate = '\0'; dostop(); return(0); /* End of init file or whatever. */ } } #endif /* MAC */ switch (zz) { case -4: /* EOF (e.g. on redirected stdin) */ doexit(GOOD_EXIT,xitsta); /* ...exit successfully */ case -1: /* Reparse needed */ repars = 1; /* Just set reparse flag and... */ continue; #ifdef OS2 case -7: /* They typed a disk letter */ if (!zchdir((char *)cmdbuf)) { perror((char *)cmdbuf); success = 0; } else success = 1; repars = 0; continue; #endif /* OS2 */ /* Changed 2013-12-06 fdc: Previously the failing command was echoed only in the -6 and -9 cases. This made it difficult to know exactly which command had failed when a macro or command file was being executed and the failing command had already issued its own error message and returned -9. Now we include -9 in the caselist for this code, but we echo the failing command only if Kermit is not at top level. So now, even though the error message is imprecise about *where* the failing command was, at least it shows the failing command. */ case -9: /* Bad, error message already done */ case -6: /* Invalid command given w/no args */ case -2: /* Invalid command given w/args */ if (zz == -2 || zz == -6 || (zz == -9 && cmdlvl > 0)) { int x = 0; #ifdef COMMENT char * eol = ""; #endif /* COMMENT */ x = strlen(cmdbuf); /* Avoid blank line */ #ifdef COMMENT if (x > 0) { if (cmdbuf[x-1] != LF) eol = "\n"; printf("?Invalid: %s%s", cmddisplay(cmdbuf,xx),eol ); } else printf("?Invalid\n"); #else if (x > 0) newerrmsg("Syntax error"); #endif /* COMMENT */ } success = 0; debug(F110,"top-level cmkey failed",cmdbuf,0); /* If in background w/ commands coming stdin, terminate */ if (pflag == 0 && tlevel < 0) fatal("Kermit command error in background execution"); /* Command retry feature, edit 190. If we're at interactive prompting level, reprompt the user with as much of the command as didn't fail. */ #ifdef CK_RECALL if (cm_retry && !xcmdsrc) { /* If at top level */ int len; char *p, *s; len = strlen(cmdbuf); /* Length of command buffer */ p = malloc(len + 1); /* Allocate space for copy */ if (p) { /* If we got the space copy */ strcpy(p,cmdbuf); /* the command buffer (SAFE). */ /* Chop off final field, the one that failed. */ s = p + len - 1; /* Point to end */ while (*s == SP && s > p) /* Trim blanks */ s--; while (*s != SP && s > p) /* Trim last field */ s--; if (s > p) /* Keep the space */ s++; /* after last good field */ if (s >= p) /* Cut off remainder */ *s = NUL; cmini(ckxech); /* Reinitialize the parser */ ckstrncpy(cmdbuf,p,CMDBL); /* Copy result back */ free(p); /* Free temporary storage */ p = NULL; prompt(xxstring); /* Reprint the prompt */ printf("%s",cmdbuf); /* Reprint partial command */ repars = 1; /* Force reparse */ continue; } } else #endif /* CK_RECALL */ /* cmderr(); */ newerrmsg(""); cmini(ckxech); /* (fall thru) */ case -3: /* Empty command OK at top level */ repars = 0; /* Don't need to reparse. */ continue; /* Go back and get another command. */ default: /* Command was successful. */ #ifndef NOSPL debug(F101,"parser preparing to continue","",maclvl); #endif /* NOSPL */ debug(F101,"parser success","",success); repars = 0; /* Don't need to reparse. */ continue; /* Go back and get another command. */ } } #ifndef NOSPL debug(F101,"parser breaks out of while loop","",maclvl); if (m && (cmdlvl < inlevel)) return((int) sstate); #endif /* NOSPL */ } /* Got an action command, return start state. */ return((int) sstate); } #ifndef NOSPL /* OUTPUT command. Buffering and pacing added by L.I. Kirby, 5A(189), June 1993. */ #define OBSIZE 80 /* Size of local character buffer */ static int obn; /* Buffer offset (high water mark) */ static char obuf[OBSIZE+1]; /* OUTPUT buffer. */ static char *obp; /* Pointer to output buffer. */ _PROTOTYP( static int oboc, (char) ); _PROTOTYP( static int xxout, (char *, int) ); static int #ifdef CK_ANSIC xxout(char *obuf, int obsize) #else xxout(obuf, obsize) char *obuf; int obsize; #endif /* CK_ANSIC */ /* xxout */ { /* OUTPUT command's output function */ int i, rc; debug(F101,"xxout obsize","",obsize); debug(F101,"xxout pacing","",pacing); debug(F111,"xxout string",obuf,strlen(obuf)); rc = 0; /* Initial return code. */ if (!obuf || (obsize <= 0)) /* Nothing to output. */ goto xxout_x; /* Return successfully */ rc = -1; /* Now assume failure */ if (pacing == 0) { /* Is pacing enabled? */ if ((local ? /* No, write entire string at once */ ttol((CHAR *)obuf, obsize) : /* to communications device */ conxo(obsize, obuf)) /* or to console */ != obsize) goto xxout_x; } else { for (i = 0; i < obsize; i++) { /* Write individual chars */ if ((local ? ttoc(obuf[i]) : conoc(obuf[i])) < 0) goto xxout_x; msleep(pacing); } } if (duplex) { #ifdef OS2 if (inecho && local) { #ifndef NOLOCAL for (i = 0; i < obsize; i++) { /* Write to emulator */ scriptwrtbuf((USHORT)obuf[i]); /* which also logs session */ } #endif /* NOLOCAL */ conxo(obsize,obuf); } else if (seslog) { /* or log session here */ logstr((char *) obuf, obsize); } #else /* OS2 */ if (seslog) { logstr((char *) obuf, obsize); } if (inecho && local) { conxo(obsize,obuf); } #endif /* OS2 */ } rc = 0; /* Success */ xxout_x: obn = 0; /* Reset count */ obp = obuf; /* and pointers */ return(rc); /* return our return code */ } #ifdef COMMENT /* Macros for OUTPUT command execution, to make it go faster. */ #define obfls() ((xxout(obuf,obn)<0)?-1:0) #define oboc(c) ((*obp++=(char)(c)),*obp=0,(((++obn)>=OBSIZE)?obfls():0)) #else /* The macros cause some compilers to generate bad code. */ static int #ifdef CK_ANSIC oboc(char c) #else oboc(c) char c; #endif /* CK_ANSIC */ /* oboc */ { /* OUTPUT command's output function */ *obp++ = c; /* Deposit character */ *obp = NUL; /* Flush buffer if it's now full */ return(((++obn) >= OBSIZE) ? xxout(obuf,obn) : 0); } #endif /* COMMENT */ /* Routines for handling local variables -- also see popclvl(). */ VOID #ifdef CK_ANSIC freelocal( int m ) /* Free local variables */ #else freelocal(m) int m; #endif /* CK_ANSIC */ { struct localvar * v, * tv; /* at macro level m... */ debug(F101,"freelocal level","",m); if (m < 0) return; v = localhead[m]; /* List head for level m */ while (v) { if (v->lv_name) /* Variable name */ free(v->lv_name); if (v->lv_value) /* Value */ free(v->lv_value); tv = v; /* Save pointer to this node */ v = v->lv_next; /* Get next one */ if (tv) /* Free this one */ free((char *)tv); } localhead[m] = (struct localvar *) NULL; /* Done, set list head to NULL */ } #define MAXLOCALVAR 64 /* Return a pointer to the definition of a user-defined variable */ static char * #ifdef CK_ANSIC vardef( char * s, int * isarray, int * x1,int * x2 ) #else vardef(s,isarray,x1,x2) char * s; int * isarray, * x1, * x2; #endif /* CK_ANSIC */ { char * p; char c; *isarray = 0; if (!s) return(NULL); if (!*s) return(NULL); p = s; if (*s == CMDQ) { p++; if (!*p) return(NULL); if ((c = *p) == '%') { /* Scalar variable. */ c = *++p; /* Get ID character. */ p = ""; /* Assume definition is empty */ if (!c) return(NULL); if (c >= '0' && c <= '9') { /* Digit for macro arg */ if (maclvl < 0) /* Digit variables are global */ return(g_var[c]); /* if no macro is active */ else /* otherwise */ return(m_arg[maclvl][c - '0']); /* they're on the stack */ } else if (isalpha(c)) { if (isupper(c)) c -= ('a'-'A'); return(g_var[c]); /* Letter for global variable */ } else return(NULL); } else if (c == '&') { /* Array reference. */ int x, vbi, d; x = arraynam(p,&vbi,&d); /* Get name and subscript */ if (x > -1 || d == -17) { *isarray = 1; *x1 = vbi; *x2 = (d == -17) ? 0 : d; } if (x < 0) return(NULL); if (chkarray(vbi,d) >= 0) { /* Array is declared? */ vbi -= ARRAYBASE; /* Convert name to index */ if (a_dim[vbi] >= d) { /* If subscript in range */ char **ap; ap = a_ptr[vbi]; return((ap) ? ap[d] : NULL); } } } return(NULL); } else { int k; k = mxlook(mactab,s,nmac); return((k > -1) ? mactab[k].mval : NULL); } } int #ifdef CK_ANSIC addlocal( char * p ) #else addlocal(p) char * p; #endif /* CK_ANSIC */ { int x, z, isarray = 0; char * s; struct localvar * v, *prev = (struct localvar *)NULL; extern int tra_asg; int tra_tmp; tra_tmp = tra_asg; s = vardef(p,&isarray,&x,&z); /* Get definition of variable */ if (isarray) { /* Arrays are handled specially */ pusharray(x,z); return(0); } if (!s) s = ""; if ((v = localhead[cmdlvl])) { /* Already have some at this level? */ while (v) { /* Find end of list */ prev = v; v = v->lv_next; } } v = (struct localvar *) malloc(sizeof(struct localvar)); if (!v) { printf("?Failure to allocate storage for local variables"); return(-9); } if (!localhead[cmdlvl]) /* If first, set list head */ localhead[cmdlvl] = v; else /* Otherwise link previous to this */ prev->lv_next = v; prev = v; /* And make this previous */ v->lv_next = (struct localvar *) NULL; /* No next yet */ if (!(v->lv_name = (char *) malloc((int) strlen(p) + 1))) return(-1); strcpy(v->lv_name, p); /* Copy name into new node (SAFE) */ if (*s) { if (!(v->lv_value = (char *) malloc((int) strlen(s) + 1))) return(-1); strcpy(v->lv_value, s); /* Copy value into new node (SAFE) */ } else v->lv_value = NULL; tra_asg = 0; delmac(p,1); /* Delete the original macro */ tra_asg = tra_tmp; return(0); } int #ifdef CK_ANSIC dolocal( void ) /* Do the LOCAL command */ #else dolocal() #endif /* CK_ANSIC */ { int i, x; char * s; char * list[MAXLOCALVAR+2]; /* Up to 64 variables per line */ if ((x = cmtxt("Variable name(s)","",&s,NULL)) < 0) return(x); xwords(s,MAXLOCALVAR,list,0); /* Break up line into "words" */ /* Note: Arrays do not use the localhead list, but have their own stack */ for (i = 1; i < MAXLOCALVAR && list[i]; i++) { /* Go through the list */ if (addlocal(list[i]) < 0) goto localbad; } return(success = 1); localbad: printf("?Failure to allocate storage for local variables"); freelocal(cmdlvl); return(-9); } /* D O O U T P U T -- Returns 0 on failure, 1 on success */ #ifndef NOKVERBS #define K_BUFLEN 30 #define SEND_BUFLEN 255 #define sendbufd(x) { osendbuf[sendndx++] = x;\ if (sendndx == SEND_BUFLEN) {dooutput(s,cx); sendndx = 0;}} #endif /* NOKVERBS */ int outesc = 1; /* Process special OUTPUT escapes */ int #ifdef CK_ANSIC dooutput( char *s, int cx ) #else dooutput(s, cx) char *s; int cx; #endif /* CK_ANSIC */ { #ifdef SSHBUILTIN const char * ssh_cmd; #endif /* SSHBUILTIN */ int x, xx, y, quote; /* Workers */ int is_tn = 0; is_tn = (local && network && IS_TELNET()) || (!local && sstelnet); debug(F111,"dooutput s",s,(int)strlen(s)); if (local) { /* Condition external line */ #ifdef NOLOCAL goto outerr; #else if (ttchk() < 0) { if (!network) { if (carrier != CAR_OFF) { int x; x = ttgmdm(); if ((x > -1) && ((x & BM_DCD) == 0)) { printf( "?Carrier signal required but not present - Try SET CARRIER-WATCH OFF.\n" ); return(0); } } else { printf( "?Problem with serial port or modem or cable - Try SHOW COMMUNICATIONS.\n" ); return(0); } } printf("?Connection %s %s is not open or not functioning.\n", network ? "to" : "on", ttname ); return(0); } if (ttvt(speed,flow) < 0) { printf("?OUTPUT initialization error\n"); return(0); } #endif /* NOLOCAL */ } #ifdef SSHBUILTIN ssh_cmd = ssh_get_sparam(SSH_SPARAM_CMD); if ( network && nettype == NET_SSH && ssh_get_iparam(SSH_IPARAM_CAS) && ssh_cmd && !(strcmp(ssh_cmd,"kermit") && strcmp(ssh_cmd,"sftp"))) { if (!quiet) printf("?SSH Subsystem active: %s\n", ssh_cmd); return(0); } #endif /* SSHBUILTIN */ if (!cmdgquo()) { /* COMMAND QUOTING OFF */ x = strlen(s); /* Just send the string literally */ xx = local ? ttol((CHAR *)s,x) : conxo(x,s); return(success = (xx == x) ? 1 : 0); } quote = 0; /* Initialize backslash (\) quote */ obn = 0; /* Reset count */ obp = obuf; /* and pointers */ outagain: while ((x = *s++)) { /* Loop through the string */ y = 0; /* Error code, 0 = no error. */ debug(F000,"dooutput","",x); if (quote) { /* This character is quoted */ #ifndef NOKVERBS if (x == 'k' || x == 'K') { /* \k or \K */ extern struct keytab kverbs[]; extern int nkverbs; extern char * keydefptr; extern int keymac; extern int keymacx; int x, y, brace = 0; char * p; char kbuf[K_BUFLEN + 1]; /* Key verb name buffer */ char osendbuf[SEND_BUFLEN +1]; int sendndx = 0; if (xxout(obuf,obn) < 0) /* Flush buffer */ goto outerr; debug(F100,"OUTPUT KVERB","",0); /* Send a KVERB */ { /* Have K verb? */ if (!*s) { break; } /* We assume that the verb name is {braced}, or it extends to the end of the string, s, or it ends with a space, control character, or backslash. */ p = kbuf; /* Copy verb name into local buffer */ x = 0; while ((x++ < K_BUFLEN) && (*s > SP) && (*s != CMDQ)) { if (brace && *s == '}') { break; } *p++ = *s++; } if (*s && !brace) /* If we broke because of \, etc, */ s--; /* back up so we get another look. */ brace = 0; *p = NUL; /* Terminate. */ p = kbuf; /* Point back to beginning */ debug(F110,"dooutput kverb",p,0); y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */ debug(F101,"dooutput lookup",0,y); if (y > -1) { if (sendndx) { dooutput(osendbuf,cx); sendndx = 0; } dokverb(VCMD,y); #ifndef NOSPL } else { /* Is it a macro? */ y = mxlook(mactab,p,nmac); if (y > -1) { cmpush(); keymac = 1; /* Flag for key macro active */ keymacx = y; /* Key macro index */ keydefptr = s; /* Where to resume next time */ debug(F111,"dooutput mxlook",keydefptr,y); parser(1); cmpop(); } #endif /* NOSPL */ } } quote = 0; continue; } else #endif /* NOKVERBS */ if (outesc && (x == 'n' || x == 'N')) { /* \n or \N */ if (xxout(obuf,obn) < 0) /* Flush buffer */ goto outerr; debug(F100,"OUTPUT NUL","",0); /* Send a NUL */ if (local) ttoc(NUL); else conoc(NUL); quote = 0; continue; } else if (outesc && (x == 'b' || x == 'B')) { /* \b or \B */ if (xxout(obuf,obn) < 0) /* Flush buffer first */ goto outerr; debug(F100,"OUTPUT BREAK","",0); #ifndef NOLOCAL ttsndb(); /* Send BREAK signal */ #else if (local) ttoc(NUL); else conoc(NUL); #endif /* NOLOCAL */ quote = 0; /* Turn off quote flag */ continue; /* and not the b or B */ #ifdef CK_LBRK } else if (outesc && (x == 'l' || x == 'L')) { /* \l or \L */ if (xxout(obuf,obn) < 0) /* Flush buffer first */ goto outerr; debug(F100,"OUTPUT Long BREAK","",0); #ifndef NOLOCAL ttsndlb(); /* Send Long BREAK signal */ #else if (local) ttoc(NUL); else conoc(NUL); #endif /* NOLOCAL */ quote = 0; /* Turn off quote flag */ continue; /* and not the l or L */ #endif /* CK_LBRK */ } else if (x == CMDQ) { /* Backslash itself */ debug(F100,"OUTPUT CMDQ","",0); xx = oboc(dopar(CMDQ)); /* Output the backslash. */ if (xx < 0) goto outerr; quote = 0; continue; } else { /* if \ not followed by special esc */ /* Note: Atari ST compiler won't allow macro call in "if ()" */ xx = oboc(dopar(CMDQ)); /* Output the backslash. */ if (xx < 0) goto outerr; quote = 0; /* Turn off quote flag */ } } else if (x == CMDQ) { /* This is the quote character */ quote = 1; /* Go back and get next character */ continue; /* which is quoted */ } xx = oboc(dopar((char)x)); /* Output this character */ debug(F111,"dooutput",obuf,obn); if (xx < 0) goto outerr; #ifdef COMMENT if (seslog && duplex) { /* Log the character if log is on */ logchar((char)x); } #endif /* COMMENT */ if (x == '\015') { /* String contains carriage return */ int stuff = -1, stuff2 = -1; if (tnlm) { /* TERMINAL NEWLINE ON */ stuff = LF; /* Stuff LF */ } #ifdef TNCODE /* TELNET NEWLINE ON/OFF/RAW */ if (is_tn) { switch (TELOPT_ME(TELOPT_BINARY) ? /* NVT or BINARY */ tn_b_nlm : tn_nlm ) { case TNL_CR: break; case TNL_CRNUL: stuff2 = stuff; stuff = NUL; break; case TNL_CRLF: stuff2 = stuff; stuff = LF; break; } } #endif /* TNCODE */ if (stuff > -1) { /* Stuffing another character... */ xx = oboc(dopar((CHAR)stuff)); if (xx < 0) goto outerr; #ifdef COMMENT if (seslog && duplex) { /* Log stuffed char if appropriate */ logchar((char)stuff); } #endif /* COMMENT */ } if (stuff2 > -1) { /* Stuffing another character... */ xx = oboc(dopar((CHAR)stuff2)); if (xx < 0) goto outerr; #ifdef COMMENT if (seslog && duplex) { /* Log stuffed char if appropriate */ logchar((char)stuff2); } #endif /* COMMENT */ } if (xxout(obuf,obn) < 0) /* Flushing is required here! */ goto outerr; } } if (cx == XXLNOUT) { s = "\015"; cx = 0; goto outagain; } if (quote == 1) /* String ended with backslash */ xx = oboc(dopar(CMDQ)); if (obn > 0) /* OUTPUT done */ if (xxout(obuf,obn) < 0) /* Flush the buffer if necessary. */ goto outerr; return(1); outerr: /* OUTPUT command error handler */ if (msgflg) printf("?OUTPUT execution error\n"); return(0); /* Remove "local" OUTPUT macro defininitions */ #ifdef COMMENT /* No more macros ... */ #undef oboc #undef obfls #endif /* COMMENT */ } #endif /* NOSPL */ /* Display version herald */ VOID herald() { extern char myherald[]; extern char * cdmsgfile[]; extern int srvcdmsg; int i; #ifndef NOCMDL extern char * bannerfile; debug(F110,"herald bannerfile",bannerfile,0); if (bannerfile) { concb((char)escape); if (dotype(bannerfile,1,0,0,NULL,0,NULL,0,0,NULL,0) > 0) { debug(F111,"herald","srvcdmsg",srvcdmsg); if (srvcdmsg) { for (i = 0; i < 8; i++) { debug(F111,"herald cdmsgfile[i]",cdmsgfile[i],i); if (zchki(cdmsgfile[i]) > -1) { printf("\n"); dotype(cdmsgfile[i], xaskmore,0,0,NULL,0,NULL,0,0,NULL,0); break; } } } return; } } #endif /* NOCMDL */ if (!noherald) { printf("%s\n",myherald); printf(" Copyright (C) 1985, %s,\n", ck_cryear); printf(" Trustees of Columbia University in the City of New York.\n"); printf(" Open Source 3-clause BSD license since 2011.\n"); if (!quiet && !backgrd ) { debug(F111,"herald","srvcdmsg",srvcdmsg); if (srvcdmsg) { for (i = 0; i < 8; i++) { debug(F111,"herald cdmsgfile[i]",cdmsgfile[i],i); if (zchki(cdmsgfile[i]) > -1) { printf("\n"); dotype(cdmsgfile[i], xaskmore,0,0,NULL,0,NULL,0,0,NULL,0); break; } } } printf("Type ? or HELP for help.\n"); } } } /* G F M O D E -- Get File (transfer) Mode */ char * #ifdef CK_ANSIC gfmode( int binary, int upcase ) #else gfmode(binary,upcase) int binary, upcase; #endif /* CK_ANSIC */ { char * s; switch (binary) { case XYFT_T: s = upcase ? "TEXT" : "text"; break; #ifdef VMS case XYFT_B: s = upcase ? "BINARY FIXED" : "binary fixed"; break; case XYFT_I: s = upcase ? "IMAGE" : "image"; break; case XYFT_L: s = upcase ? "LABELED" : "labeled"; break; case XYFT_U: s = upcase ? "BINARY UNDEF" : "binary undef"; break; #else #ifdef MAC case XYFT_B: s = upcase ? "BINARY" : "binary"; break; case XYFT_M: s = upcase ? "MACBINARY" : "macbinary"; break; #else case XYFT_B: s = upcase ? "BINARY" : "binary"; break; #ifdef CK_LABELED case XYFT_L: s = upcase ? "LABELED" : "labeled"; break; #endif /* CK_LABELED */ #endif /* MAC */ #endif /* VMS */ case XYFT_X: s = upcase ? "TENEX" : "tenex"; break; default: s = ""; } return(s); } #ifndef NOSPL static int #ifdef CK_ANSIC isaa( char * s ) /* Is associative array */ #else isaa(s) char * s; #endif /* CK_ANSIC */ { char c; int x; if (!s) s = ""; if (!*s) return(0); s++; while ((c = *s++)) { if (c == '<') { x = strlen(s); return ((*(s+x-1) == '>') ? 1 : 0); } } return(0); } /* M L O O K -- Lookup the macro name in the macro table */ /* Call this way: v = mlook(table,word,n); table - a 'struct mtab' table. word - the target string to look up in the table. n - the number of elements in the table. The keyword table must be arranged in ascending alphabetical order, and all letters must be lowercase. Returns the table index, 0 or greater, if the name was found, or: -3 if nothing to look up (target was null), -2 if ambiguous, -1 if not found. A match is successful if the target matches a keyword exactly, or if the target is a prefix of exactly one keyword. It is ambiguous if the target matches two or more keywords from the table. */ int #ifdef CK_ANSIC mlook( struct mtab table[], char *cmd, int n ) #else mlook(table,cmd,n) struct mtab table[]; char *cmd; int n; #endif /* CK_ANSIC */ { register int i; int v, w, cmdlen = 0; char c = 0, c1, * s; if (!cmd) cmd = ""; for (s = cmd; *s; s++) cmdlen++; /* (instead of strlen) */ debug(F111,"MLOOK",cmd,cmdlen); c1 = *cmd; if (isupper(c1)) c1 = tolower(c1); if (cmdlen < 1) return(-3); /* Not null, look it up */ if (n < 12) { /* Not worth it for small tables */ i = 0; } else { /* Binary search for where to start */ int lo = 0; int hi = n; int count = 0; while (lo+2 < hi && ++count < 12) { i = lo + ((hi - lo) / 2); c = *(table[i].kwd); if (isupper(c)) c = tolower(c); if (c < c1) { lo = i; } else { hi = i; } } i = (c < c1) ? lo+1 : lo; } for ( ; i < n-1; i++) { s = table[i].kwd; if (!s) s = ""; if (!*s) continue; /* Empty table entry */ c = *s; if (isupper(c)) c = tolower(c); if (c1 != c) continue; /* First char doesn't match */ if (!ckstrcmp(s,cmd,-1,0)) /* Have exact match? */ return(i); v = !ckstrcmp(s,cmd,cmdlen,0); w = ckstrcmp(table[i+1].kwd,cmd,cmdlen,0); if (v && w) /* Have abbreviated match? */ return(i); if (v) /* Ambiguous? */ return(-2); if (w > 0) /* Past our alphabetic area? */ return(-1); } /* Last (or only) element */ if (!ckstrcmp(table[n-1].kwd,cmd,cmdlen,0)) return(n-1); return(-1); } /* mxlook is like mlook, but an exact full-length match is required */ int #ifdef CK_ANSIC mxlook(struct mtab table[], char * cmd, int n) #else mxlook(table,cmd,n) char *cmd; struct mtab table[]; int n; #endif /* CK_ANSIC */ { register int i; int w, cmdlen = 0, one = 0; register char c = 0, c1, * s; if (!cmd) cmd = ""; /* Check args */ for (s = cmd; *s; s++) cmdlen++; /* (instead of strlen) */ debug(F111,"MXLOOK",cmd,cmdlen); c1 = *cmd; /* First char of string to look up */ if (isupper(c1)) c1 = tolower(c1); if (!*(cmd+1)) /* Special handling for 1-char names */ one = 1; if (cmdlen < 1) /* Nothing to look up */ return(-3); if (n < 12) { /* Not worth it for small tables */ i = 0; } else { /* Binary search for where to start */ int lo = 0; int hi = n; int count = 0; while (lo+2 < hi && ++count < 12) { i = lo + ((hi - lo) / 2); c = *(table[i].kwd); if (isupper(c)) c = tolower(c); if (c < c1) { lo = i; } else { hi = i; } } i = (c < c1) ? lo+1 : lo; } for ( ; i < n; i++) { /* Look thru table */ s = table[i].kwd; /* This entry */ if (!s) s = ""; if (!*s) continue; /* Empty table entry */ c = *s; if (isupper(c)) c = tolower(c); if (c1 != c) continue; /* First char doesn't match */ if (one) { /* Name is one char long */ if (!*(s+1)) return(i); /* So is table entry */ } #ifdef COMMENT if (((int)strlen(s) == cmdlen) && (!ckstrcmp(s,cmd,cmdlen,0))) return(i); #else w = ckstrcmp(s,cmd,-1,0); if (!w) { debug(F111,"MXLOOK",mactab[i].mval,i); return(i); } if (w > 0) return(-1); #endif /* COMMENT */ } return(-1); } /* mxxlook is like mxlook, but case-sensitive */ int #ifdef CK_ANSIC mxxlook(struct mtab table[], char * cmd, int n) #else mxxlook(table,cmd,n) char *cmd; struct mtab table[]; int n; #endif /* CK_ANSIC */ { int i, cmdlen; if (!cmd) cmd = ""; if (((cmdlen = strlen(cmd)) < 1) || (n < 1)) return(-3); /* debug(F111,"mxxlook target",cmd,n); */ for (i = 0; i < n; i++) { if (((int)strlen(table[i].kwd) == cmdlen) && (!strncmp(table[i].kwd,cmd,cmdlen))) return(i); } return(-1); } static int #ifdef CK_ANSIC traceval( char * nam, char * val ) /* For TRACE command */ #else traceval(nam, val) char * nam, * val; #endif /* CK_ANSIC */ { if (val) printf(">>> %s: \"%s\"\n", nam, val); else printf(">>> %s: (undef)\n", nam); return(0); } #ifdef USE_VARLEN /* Not used */ /* V A R L E N -- Get length of variable's value. Given a variable name, return the length of its definition or 0 if the variable is not defined. If it is defined, set argument s to point to its definition. Otherwise set s to NULL. */ int varlen(nam,s) char *nam; char **s; { /* Length of value of variable */ int x, z; char *p = NULL, c; *s = NULL; if (!nam) return(0); /* Watch out for null pointer */ if (*nam == CMDQ) { nam++; if (*nam == '%') { /* If it's a variable name */ if (!(c = *(nam+1))) return(0); /* Get letter or digit */ p = (char *)0; /* Initialize value pointer */ if (maclvl > -1 && c >= '0' && c <= '9') { /* Digit? */ p = m_arg[maclvl][c - '0']; /* Pointer from macro-arg table */ } else { /* It's a global variable */ if (c < 33 || c > GVARS) return(0); p = g_var[c]; /* Get pointer from global-var table */ } } else if (*nam == '&') { /* An array reference? */ char **q; if (arraynam(nam,&x,&z) < 0) /* If syntax is bad */ return(-1); /* return -1. */ x -= ARRAYBASE; /* Convert name to number. */ if ((q = a_ptr[x]) == NULL) /* If array not declared, */ return(0); /* return -2. */ if (z > a_dim[x]) /* If subscript out of range, */ return(0); /* return -3. */ p = q[z]; } } else { /* Macro */ z = isaa(nam); x = z ? mxxlook(mactab,nam,nmac) : mlook(mactab,nam,nmac); if (x < 0) return(0); p = mactab[x].mval; } if (p) *s = p; else p = ""; return((int)strlen(p)); } #endif /* USE_VARLEN */ /* This routine is for the benefit of those compilers that can't handle long string constants or continued lines within them. Long predefined macros like FOR, WHILE, and XIF have their contents broken up into arrays of string pointers. This routine concatenates them back into a single string again, and then calls the real addmac() routine to enter the definition into the macro table. */ int #ifdef CK_ANSIC addmmac( char *nam, char *s[] ) /* Add a multiline macro definition */ #else addmmac(nam,s) char *nam, *s[]; #endif /* CK_ANSIC */ { int i, x, y; char *p; x = 0; /* Length counter */ for (i = 0; (y = (int)strlen(s[i])) > 0; i++) { /* Add up total length */ debug(F111,"addmmac line",s[i],y); x += y; } debug(F101,"addmmac lines","",i); debug(F101,"addmmac loop exit","",y); debug(F111,"addmmac length",nam,x); if (x < 0) return(-1); p = malloc(x+1); /* Allocate space for all of it. */ if (!p) { printf("?addmmac malloc error: %s\n",nam); debug(F110,"addmmac malloc error",nam,0); return(-1); } *p = '\0'; /* Start off with null string. */ for (i = 0; *s[i]; i++) /* Concatenate them all together. */ ckstrncat(p,s[i],x+1); y = (int)strlen(p); /* Final precaution. */ debug(F111,"addmmac constructed string",p,y); if (y == x) { y = addmac(nam,p); /* Add result to the macro table. */ } else { debug(F100,"addmmac length mismatch","",0); printf("\n!addmmac internal error!\n"); y = -1; } free(p); /* Free the temporary copy. */ return(y); } static char evalmacrobuf[TMPBUFSIZ]; VOID #ifdef CK_ANSIC evalmacroarg( char **p ) #else evalmacroarg(p) char **p; #endif /* CK_ANSIC */ { char * s = evalmacrobuf; int t = TMPBUFSIZ; (VOID) zzstring(*p,&s,&t); *p = evalmacrobuf; } /* Here is the real addmac routine. */ /* Returns -1 on failure, macro table index >= 0 on success. */ int mtchanged = 0; int #ifdef CK_ANSIC addmac( char *nam, char *def ) /* Add a macro to the macro table */ #else addmac(nam,def) char *nam, *def; #endif /* CK_ANSIC */ { int i, x, y, z, namlen, deflen, flag = 0; int replacing = 0, deleting = 0; char * p = NULL, c; #ifdef USE_VARLEN char *s; #endif /* USE_VARLEN */ extern int tra_asg; int tra_tmp; if (!nam) return(-1); if (!*nam) return(-1); #ifdef IKSD if (inserver && #ifdef IKSDCONF iksdcf #else /* IKSDCONF */ 1 #endif /* IKSDCONF */ ) { if (!ckstrcmp("on_exit",nam,-1,0) || !ckstrcmp("on_logout",nam,-1,0)) return(-1); } #endif /* IKSD */ namlen = 0; p = nam; while (*p++) namlen++; /* (instead of strlen) */ tra_tmp = tra_asg; /* trace... */ debug(F111,"addmac nam",nam,namlen); if (!def) { /* Watch out for null pointer */ deflen = 0; debug(F111,"addmac def","(null pointer)",deflen); } else { deflen = 0; p = def; while (*p++) deflen++; /* (instead of strlen) */ debug(F010,"addmac def",def,0); } #ifdef USE_VARLEN /* NOT USED */ /* This does not boost performance much because varlen() does a lot */ x = varlen(nam,&s); if (x > 0 && x >= deflen) { strcpy(s,def); /* NOT USED */ flag = 1; p = s; } #endif /* USE_VARLEN */ if (*nam == CMDQ) nam++; /* Backslash quote? */ if (*nam == '%') { /* Yes, if it's a variable name, */ if (!(c = *(nam + 1))) return(-1); /* Variable name letter or digit */ if (!flag) { tra_asg = 0; delmac(nam,0); /* Delete any old value. */ tra_asg = tra_tmp; } if (deflen < 1) { /* Null definition */ p = NULL; /* Better not malloc or strcpy! */ } else if (!flag) { /* A substantial definition */ p = malloc(deflen + 1); /* Allocate space for it */ if (!p) { printf("?addmac malloc error 2\n"); return(-1); } else strcpy(p,def); /* Copy def into new space (SAFE) */ } /* Now p points to the definition, or is a null pointer */ if (c >= '0' && c <= '9') { /* \%0-9 variable */ if (maclvl < 0) { /* Are we calling or in a macro? */ g_var[c] = p; /* No, it's top level one */ makestr(&(toparg[c - '0']),p); /* Take care \&_[] too */ } else { /* Yes, it's a macro argument */ m_arg[maclvl][c - '0'] = p; /* Assign the value */ makestr(&(m_xarg[maclvl][c - '0']),p); /* And a copy here */ } } else { /* It's a \%a-z variable */ if (c < 33 || (unsigned int)c > GVARS) return(-1); if (isupper(c)) c = (char) tolower(c); g_var[c] = p; /* Put pointer in global-var table */ } if (tra_asg) traceval(nam,p); return(0); } else if (*nam == '&') { /* An array reference? */ char **q = NULL; int rc = 0; if ((y = arraynam(nam,&x,&z)) < 0) /* If syntax is bad */ return(-1); /* return -1. */ if (chkarray(x,z) < 0) /* If array not declared or */ rc = -2; /* subscript out of range, ret -2 */ if (!flag) { tra_asg = 0; delmac(nam,0); /* Delete any old value. */ tra_asg = tra_tmp; } x -= ARRAYBASE; /* Convert name letter to index. */ if (x > 'z' - ARRAYBASE + 1) rc = -1; if (rc != -1) { if ((q = a_ptr[x]) == NULL) /* If array not declared, */ return(-3); /* return -3. */ } if (rc < 0) return(rc); if (!flag) { if (deflen > 0) { if ((p = malloc(deflen+1)) == NULL) { /* Allocate space */ printf("addmac macro error 7: %s\n",nam); return(-4); /* for new def, return -4 on fail. */ } strcpy(p,def); /* Copy def into new space (SAFE). */ } else p = NULL; } q[z] = p; /* Store pointer to it. */ if (x == 0) { /* Arg vector array */ if (z >= 0 && z <= 9) { /* Copy values to corresponding */ if (maclvl < 0) { /* \%1..9 variables. */ makestr(&(toparg[z]),p); } else { makestr(&(m_arg[maclvl][z]),p); } } } if (tra_asg) traceval(nam,p); return(0); /* Done. */ } /* Not a macro argument or a variable, so it's a macro definition */ #ifdef USE_VARLEN if (flag) { if (tra_asg) traceval(nam,p); return(0); } #endif /* USE_VARLEN */ x = isaa(nam) ? /* If it's an associative array */ mxxlook(mactab,nam,nmac) : /* look it up this way */ mxlook(mactab,nam,nmac); /* otherwise this way. */ if (x > -1) { /* If found... */ if (deflen > 0) /* and a new definition was given */ replacing = 1; /* we're replacing */ else /* otherwise */ deleting = 1; /* we're deleting */ } if (deleting) { /* Deleting... */ if (delmac(nam,0) < 0) return(-1); mtchanged++; if (tra_asg) traceval(nam,p); return(0); } else if (deflen < 1) /* New macro with no definition */ return(0); /* Nothing to do. */ if (replacing) { /* Replacing an existing macro */ if (mactab[x].mval) { /* If it currently has a definition, */ free(mactab[x].mval); /* free it. */ mactab[x].mval = NULL; } mtchanged++; y = x; /* Replacement index. */ } else { /* Adding a new macro... */ char c1, c2; /* Use fast lookup to find the */ c1 = *nam; /* alphabetical slot. */ if (isupper(c1)) c1 = (char) tolower(c1); if (nmac < 5) { /* Not worth it for small tables */ y = 0; } else { /* First binary search to find */ int lo = 0; /* where to start */ int hi = nmac; int count = 0; char c = 0; while (lo+2 < hi && ++count < 12) { y = lo + ((hi - lo) / 2); c = *(mactab[y].kwd); if (isupper(c)) c = (char) tolower(c); if (c < c1) { lo = y; } else { hi = y; } } y = (c < c1) ? lo+1 : lo; } /* Now search linearly from starting location */ for ( ; y < MAC_MAX && mactab[y].kwd != NULL; y++) { c2 = *(mactab[y].kwd); if (isupper(c2)) c2 = (char) tolower(c2); if (c1 > c2) continue; if (c1 < c2) break; if (ckstrcmp(nam,mactab[y].kwd,-1,0) <= 0) break; } if (y == MAC_MAX) { /* Macro table is full. */ debug(F101,"addmac table overflow","",y); printf("?Macro table overflow\n"); return(-1); } if (mactab[y].kwd != NULL) { /* Must insert */ for (i = nmac; i > y; i--) { /* Move the rest down one slot */ mactab[i].kwd = mactab[i-1].kwd; mactab[i].mval = mactab[i-1].mval; mactab[i].flgs = mactab[i-1].flgs; } } mtchanged++; p = malloc(namlen + 1); /* Allocate space for name */ if (!p) { printf("?Addmac: Out of memory - \"%s\"\n",nam); return(-1); } strcpy(p,nam); /* Copy name into new space (SAFE) */ mactab[y].kwd = p; /* Add pointer to table */ } if (deflen > 0) { /* If we have a definition */ p = malloc(deflen + 1); /* Get space */ if (p == NULL) { printf("?Space exhausted - \"%s\"\n", nam); if (mactab[y].kwd) { free(mactab[y].kwd); mactab[y].kwd = NULL; } return(-1); } else { strcpy(p,def); /* Copy the definition (SAFE) */ } } else { /* definition is empty */ p = NULL; } mactab[y].mval = p; /* Macro points to definition */ mactab[y].flgs = 0; /* No flags */ if (!replacing) /* If new macro */ nmac++; /* count it */ if (tra_asg) traceval(nam,p); return(y); } int #ifdef CK_ANSIC xdelmac( int x ) /* Delete a macro given its index */ #else xdelmac(x) int x; #endif /* CK_ANSIC */ { int i; extern int tra_asg; if (x < 0) return(x); if (tra_asg) traceval(mactab[x].kwd,NULL); if (mactab[x].kwd) { /* Free the storage for the name */ free(mactab[x].kwd); mactab[x].kwd = NULL; } if (mactab[x].mval) { /* and for the definition */ free(mactab[x].mval); mactab[x].mval = NULL; } for (i = x; i < nmac; i++) { /* Now move up the others. */ mactab[i].kwd = mactab[i+1].kwd; mactab[i].mval = mactab[i+1].mval; mactab[i].flgs = mactab[i+1].flgs; } nmac--; /* One less macro */ mactab[nmac].kwd = NULL; /* Delete last item from table */ mactab[nmac].mval = NULL; mactab[nmac].flgs = 0; mtchanged++; return(0); } int #ifdef CK_ANSIC delmac( char *nam, int exact ) /* Delete the named macro */ #else delmac(nam,exact) char *nam; int exact; #endif /* CK_ANSIC */ { int x, z; char *p, c; extern int tra_asg; if (!nam) return(0); /* Watch out for null pointer */ debug(F110,"delmac nam",nam,0); #ifdef IKSD if ( inserver && #ifdef IKSDCONF iksdcf #else /* IKSDCONF */ 1 #endif /* IKSDCONF */ ) { if (!ckstrcmp("on_exit",nam,-1,0) || !ckstrcmp("on_logout",nam,-1,0)) return(-1); } #endif /* IKSD */ if (*nam == CMDQ) nam++; if (*nam == '%') { /* If it's a variable name */ if (!(c = *(nam+1))) return(0); /* Get variable name letter or digit */ p = (char *)0; /* Initialize value pointer */ if (maclvl < 0 && c >= '0' && c <= '9') { /* Top-level digit? */ p = toparg[c - '0']; if (p) if (p != g_var[c]) { free(p); toparg[c - '0'] = NULL; } p = g_var[c]; g_var[c] = NULL; /* Zero the table entry */ } else if (maclvl > -1 && c >= '0' && c <= '9') { /* Digit? */ p = m_xarg[maclvl][c - '0']; if (p) if (p != g_var[c]) { free(p); m_xarg[maclvl][c - '0'] = NULL; } p = m_arg[maclvl][c - '0']; /* Get pointer from macro-arg table */ m_arg[maclvl][c - '0'] = NULL; /* Zero the table pointer */ } else { /* It's a global variable */ if (c < 33 || (unsigned int)c > GVARS) return(0); p = g_var[c]; /* Get pointer from global-var table */ g_var[c] = NULL; /* Zero the table entry */ } if (p) { debug(F010,"delmac def",p,0); free(p); /* Free the storage */ p = NULL; } else debug(F110,"delmac def","(null pointer)",0); if (tra_asg) traceval(nam,NULL); return(0); } if (*nam == '&') { /* An array reference? */ char **q; if (arraynam(nam,&x,&z) < 0) /* If syntax is bad */ return(-1); /* return -1. */ x -= ARRAYBASE; /* Convert name to number. */ if ((q = a_ptr[x]) == NULL) /* If array not declared, */ return(-2); /* return -2. */ if (z > a_dim[x]) /* If subscript out of range, */ return(-3); /* return -3. */ if (q[z]) { /* If there is an old value, */ debug(F010,"delmac def",q[z],0); if (x != 0) /* Macro arg vector is just a copy */ free(q[z]); /* Others are real so free them */ q[z] = NULL; if (x == 0) { /* Arg vector array */ if (z >= 0 && z <= 9) { /* Copy values to corresponding */ if (maclvl < 0) { /* \%1..9 variables. */ makestr(&(toparg[z]),NULL); } else { makestr(&(m_arg[maclvl][z]),NULL); } } } if (tra_asg) traceval(nam,NULL); } else debug(F010,"delmac def","(null pointer)",0); } /* Not a variable or an array, so it must be a macro. */ z = isaa(nam); debug(F111,"delmac isaa",nam,z); debug(F111,"delmac exact",nam,exact); x = z ? mxxlook(mactab,nam,nmac) : exact ? mxlook(mactab,nam,nmac) : mlook(mactab,nam,nmac); if (x < 0) { debug(F111,"delmac mlook",nam,x); return(x); } return(xdelmac(x)); } VOID initmac() { /* Init macro & variable tables */ int i, j, x; nmac = 0; /* No macros */ for (i = 0; i < MAC_MAX; i++) { /* Initialize the macro table */ mactab[i].kwd = NULL; mactab[i].mval = NULL; mactab[i].flgs = 0; } mtchanged++; x = (MAXARGLIST + 1) * sizeof(char **); for (i = 0; i < MACLEVEL; i++) { /* Init the macro argument tables */ m_xarg[i] = (char **) malloc(x); mrval[i] = NULL; /* Macro return value */ /* Pointer to entire argument vector, level i, for \&_[] array */ for (j = 0; j <= MAXARGLIST; j++) { /* Macro argument list */ if (j < 10) /* For the \%0..\%9 variables */ m_arg[i][j] = NULL; /* Pointer to arg j, level i. */ if (m_xarg[i]) /* For \&_[] - all args. */ m_xarg[i][j] = NULL; } } for (i = 0; i < GVARS; i++) { /* And the global variables table */ g_var[i] = NULL; } /* And the table of arrays */ for (i = 0; i < (int) 'z' - ARRAYBASE + 1; i++) { a_ptr[i] = (char **) NULL; /* Null pointer for each */ a_dim[i] = 0; /* and a dimension of zero */ a_link[i] = -1; for (j = 0; j < CMDSTKL; j++) { aa_ptr[j][i] = (char **) NULL; aa_dim[j][i] = 0; } } } int popclvl() { /* Pop command level, return cmdlvl */ extern int tra_cmd; struct localvar * v; int i, topcmd; debug(F101,"popclvl cmdlvl","",cmdlvl); if (cmdlvl > 0) { if ((v = localhead[cmdlvl])) { /* Did we save any variables? */ while (v) { /* Yes */ if (v->lv_value) /* Copy old ones back */ addmac(v->lv_name,v->lv_value); else delmac(v->lv_name,1); v = v->lv_next; } freelocal(cmdlvl); /* Free local storage */ } /* Automatic arrays do not use the localhead list */ for (i = 0; i < 28; i++) { /* Free any local arrays */ if (aa_ptr[cmdlvl][i]) { /* Does this one exist? */ dclarray((char)(i+ARRAYBASE),-1); /* Destroy global one */ a_ptr[i] = aa_ptr[cmdlvl][i]; a_dim[i] = aa_dim[cmdlvl][i]; aa_ptr[cmdlvl][i] = (char **)NULL; aa_dim[cmdlvl][i] = 0; } else if (aa_dim[cmdlvl][i] == -23) { /* Secret code */ /* A local array declared at this level when there was no array of the same name at any higher level. See comment in pusharray(). */ dclarray((char)(i+ARRAYBASE),-1); a_ptr[i] = (char **)NULL; /* Delete top-level array */ a_dim[i] = 0; /* created by pusharray - Feb 2016 */ aa_ptr[cmdlvl][i] = (char **)NULL; aa_dim[cmdlvl][i] = 0; } /* Otherwise do nothing - it is a local array that was declared */ /* at a level above this one so leave it alone. */ } } if (cmdlvl < 1) { /* If we're already at top level */ cmdlvl = 0; /* just make sure all the */ tlevel = -1; /* stack pointers are set right */ maclvl = -1; /* and return */ } else if (cmdstk[cmdlvl].src == CMD_TF) { /* Reading from TAKE file? */ debug(F101,"popclvl tlevel","",tlevel); if (tlevel > -1) { /* Yes, */ fclose(tfile[tlevel]); /* close it */ if (tra_cmd) printf("[%d] -F: \"%s\"\n",cmdlvl,tfnam[tlevel]); debug(F111,"CMD -F",tfnam[tlevel],cmdlvl); if (tfnam[tlevel]) { /* free storage for name */ free(tfnam[tlevel]); tfnam[tlevel] = NULL; } tlevel--; /* and pop take level */ cmdlvl--; /* and command level */ quiet = xquiet[cmdlvl]; vareval = xvarev[cmdlvl]; } else tlevel = -1; } else if (cmdstk[cmdlvl].src == CMD_MD) { /* In a macro? */ topcmd = lastcmd[maclvl]; debug(F101,"popclvl maclvl","",maclvl); if (maclvl > -1) { /* Yes, */ #ifdef COMMENT int i; char **q; #endif /* COMMENT */ macp[maclvl] = ""; /* set macro pointer to null string */ *cmdbuf = '\0'; /* clear the command buffer */ if ((maclvl > 0) && /* 2 May 1999 */ (m_arg[maclvl-1][0]) && (!strncmp(m_arg[maclvl-1][0],"_xif",4) || !strncmp(m_arg[maclvl-1][0],"_for",4) || !strncmp(m_arg[maclvl-1][0],"_swi",4) || !strncmp(m_arg[maclvl-1][0],"_whi",4)) && mrval[maclvl+1]) { makestr(&(mrval[maclvl-1]),mrval[maclvl+1]); } if (maclvl+1 < MACLEVEL) { if (mrval[maclvl+1]) { /* Free any deeper return values. */ free(mrval[maclvl+1]); mrval[maclvl+1] = NULL; } } if (tra_cmd) printf("[%d] -M: \"%s\"\n",cmdlvl,m_arg[cmdstk[cmdlvl].lvl][0]); debug(F111,"CMD -M",m_arg[cmdstk[cmdlvl].lvl][0],cmdlvl); maclvl--; /* Pop macro level */ cmdlvl--; /* and command level */ debug(F101,"popclvl mac new maclvl","",maclvl); debug(F010,"popclvl mac mrval[maclvl+1]",mrval[maclvl+2],0); quiet = xquiet[cmdlvl]; vareval = xvarev[cmdlvl]; if (maclvl > -1) { a_ptr[0] = m_xarg[maclvl]; a_dim[0] = n_xarg[maclvl] - 1; debug(F111,"a_dim[0]","B",a_dim[0]); } else { a_ptr[0] = topxarg; a_dim[0] = topargc - 1; debug(F111,"a_dim[0]","C",a_dim[0]); } } else { maclvl = -1; } #ifndef NOSEXP debug(F101,"popclvl topcmd","",topcmd); if (topcmd == XXSEXP) { extern char * sexpval; makestr(&(mrval[maclvl+1]),sexpval); } #endif /* NOSEXP */ } else { cmdlvl--; } debug(F101,"popclvl cmdlvl","",cmdlvl); if (prstring[cmdlvl]) { cmsetp(prstring[cmdlvl]); makestr(&(prstring[cmdlvl]),NULL); } #ifndef MAC if (cmdlvl < 1 || xcmdsrc == CMD_KB) { /* If at prompt */ setint(); concb((char)escape); /* Go into cbreak mode */ } #endif /* MAC */ xcmdsrc = cmdstk[cmdlvl].src; debug(F101,"popclvl xcmdsrc","",xcmdsrc); debug(F101,"popclvl tlevel","",tlevel); return(cmdlvl < 1 ? 0 : cmdlvl); /* Return command level */ } #else /* No script programming language */ int popclvl() { /* Just close current take file. */ if (tlevel > -1) { /* if any... */ if (tfnam[tlevel]) { free(tfnam[tlevel]); tfnam[tlevel] = NULL; } fclose(tfile[tlevel--]); } if (tlevel == -1) { /* And if back at top level */ setint(); concb((char)escape); /* and go back into cbreak mode. */ } xcmdsrc = tlevel > -1 ? CMD_TF : 0; return(tlevel + 1); } #endif /* NOSPL */ #ifndef NOSPL static int #ifdef CK_ANSIC iseom( char * m ) /* Test if at end of macro def */ #else iseom(m) char * m; #endif /* CK_ANSIC */ { if (!m) m = ""; debug(F111,"iseom",m,maclvl); while (*m) { /* Anything but Space and Comma means more macro is left */ if ((*m > SP) && (*m != ',')) { debug(F111,"iseom return",m,0); return(0); } m++; } debug(F111,"iseom return",m,1); return(1); /* Nothing left */ } #endif /* NOSPL */ /* Pop all command levels that can be popped */ int prepop() { if (cmdlvl > 0) { /* If command level is > 0 and... */ while ( #ifndef NOSPL ((cmdstk[cmdlvl].src == CMD_TF) && /* Command source is file */ #endif /* NOSPL */ (tlevel > -1) && feof(tfile[tlevel])) /* And at end of file... */ #ifndef NOSPL /* Or command source is macro... */ || ((cmdstk[cmdlvl].src == CMD_MD) && (maclvl > -1) && iseom(macp[maclvl]))) /* and at end of macro, then... */ #endif /* NOSPL */ { popclvl(); /* pop command level. */ } } return(cmdlvl < 1 ? 0 : cmdlvl); /* Return command level */ } /* STOP - get back to C-Kermit prompt, no matter where from. */ int dostop() { extern int cmddep; while (popclvl()) ; /* Pop all macros & take files */ #ifndef NOSPL if (cmddep > -1) /* And all recursive cmd pkg invocations */ while (cmpop() > -1) ; #endif /* NOSPL */ cmini(ckxech); /* Clear the command buffer. */ return(0); } /* Close the given log */ int #ifdef CK_ANSIC doclslog( int x ) #else doclslog(x) int x; #endif /* CK_ANSIC */ { int y; switch (x) { #ifdef DEBUG case LOGD: if (deblog <= 0) { printf("?Debugging log wasn't open\n"); return(0); } debug(F100,"Debug Log Closed","",0L); *debfil = '\0'; deblog = 0; return(zclose(ZDFILE)); #endif /* DEBUG */ #ifndef NOXFER case LOGP: if (pktlog <= 0) { printf("?Packet log wasn't open\n"); return(0); } *pktfil = '\0'; pktlog = 0; return(zclose(ZPFILE)); #endif /* NOXFER */ #ifndef NOLOCAL case LOGS: if (seslog <= 0) { printf("?Session log wasn't open\n"); return(0); } *sesfil = '\0'; setseslog(0); return(zclose(ZSFILE)); #endif /* NOLOCAL */ #ifdef TLOG case LOGT: { #ifdef IKSD extern int iklogopen, xferlog; #endif /* IKSD */ if (tralog <= 0 #ifdef IKSD && !iklogopen #endif /* IKSD */ ) { if (msgflg) printf("?Transaction log wasn't open\n"); return(0); } #ifdef IKSD if (iklogopen && !inserver) { close(xferlog); iklogopen = 0; } #endif /* IKSD */ if (tralog) { tlog(F100,"Transaction Log Closed","",0L); zclose(ZTFILE); } *trafil = '\0'; tralog = 0; return(1); } #endif /* TLOG */ #ifdef CKLOGDIAL case LOGM: if (dialog <= 0) { if (msgflg) printf("?Connection log wasn't open\n"); return(0); } *diafil = '\0'; dialog = 0; return(zclose(ZDIFIL)); #endif /* CKLOGDIAL */ #ifndef NOSPL case LOGW: /* WRITE file */ case LOGR: /* READ file */ y = (x == LOGR) ? ZRFILE : ZWFILE; if (chkfn(y) < 1) /* If no file to close */ return(1); /* succeed silently. */ return(zclose(y)); /* Otherwise, close the file. */ #endif /* NOSPL */ default: printf("\n?Unexpected log designator - %d\n", x); return(0); } } static int slc = 0; /* Screen line count */ char * #ifdef CK_ANSIC showstring( char * s ) #else showstring(s) char * s; #endif /* CK_ANSIC */ { return(s ? s : "(null)"); } char * #ifdef CK_ANSIC showoff( int x ) #else showoff(x) int x; #endif /* CK_ANSIC */ { return(x ? "on" : "off"); } char * #ifdef CK_ANSIC showooa( int x ) #else showooa(x) int x; #endif /* CK_ANSIC */ { switch (x) { case SET_OFF: return("off"); case SET_ON: return("on"); case SET_AUTO: return("automatic"); default: return("(unknown)"); } } #ifdef GEMDOS isxdigit(c) int c; { return(isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); } #endif /* GEMDOS */ #ifndef NOSETKEY #ifdef OS2 static struct keytab shokeytab[] = { /* SHOW KEY modes */ "all", 1, 0, "one", 0, 0 }; static int nshokey = (sizeof(shokeytab) / sizeof(struct keytab)); #define SHKEYDEF TT_MAX+5 struct keytab shokeymtab[] = { "aaa", TT_AAA, CM_INV, /* AnnArbor */ "adm3a", TT_ADM3A, 0, /* LSI ADM-3A */ "adm5", TT_ADM5, 0, /* LSI ADM-5 */ "aixterm", TT_AIXTERM, 0, /* IBM AIXterm */ "annarbor", TT_AAA, 0, /* AnnArbor */ "ansi-bbs", TT_ANSI, 0, /* ANSI.SYS (BBS) */ "at386", TT_AT386, 0, /* Unixware ANSI */ "avatar/0+", TT_ANSI, 0, /* AVATAR/0+ */ "ba80", TT_BA80, 0, /* Nixdorf BA80 */ "be", TT_BEOS, CM_INV|CM_ABR, "beos-ansi", TT_BEOS, CM_INV, /* BeOS ANSI */ "beterm", TT_BEOS, 0, /* BeOS Console */ "d200", TT_DG200, CM_INV|CM_ABR, /* Data General DASHER 200 */ "d210", TT_DG210, CM_INV|CM_ABR, /* Data General DASHER 210 */ "d217", TT_DG217, CM_INV|CM_ABR, /* Data General DASHER 217 */ "default", SHKEYDEF, 0, "dg200", TT_DG200, 0, /* Data General DASHER 200 */ "dg210", TT_DG210, 0, /* Data General DASHER 210 */ "dg217", TT_DG217, 0, /* Data General DASHER 217 */ "emacs", TT_KBM_EMACS, 0, /* Emacs mode */ "h19", TT_H19, CM_INV, /* Heath-19 */ "heath19", TT_H19, 0, /* Heath-19 */ "hebrew", TT_KBM_HEBREW, 0, /* Hebrew mode */ "hft", TT_HFT, 0, /* IBM HFT */ "hp2621a", TT_HP2621, 0, /* HP 2621A */ "hpterm", TT_HPTERM, 0, /* HP TERM */ "hz1500", TT_HZL1500, 0, /* Hazeltine 1500 */ "ibm3151", TT_IBM31, 0, /* IBM 3101-xx,3161 */ "linux", TT_LINUX, 0, /* Linux */ "qansi", TT_QANSI, 0, /* QNX ANSI */ "qnx", TT_QNX, 0, /* QNX */ "russian", TT_KBM_RUSSIAN, 0, /* Russian mode */ "scoansi", TT_SCOANSI, 0, /* SCO ANSI */ "sni-97801", TT_97801, 0, /* Sinix 97801 */ "sun", TT_SUN, 0, /* Sun Console */ #ifdef OS2PM #ifdef COMMENT "tek4014", TT_TEK40, 0, #endif /* COMMENT */ #endif /* OS2PM */ "tty", TT_NONE, 0, "tvi910+", TT_TVI910, 0, "tvi925", TT_TVI925, 0, "tvi950", TT_TVI950, 0, "vc404", TT_VC4404, 0, "vc4404", TT_VC4404, CM_INV, "vip7809", TT_VIP7809, 0, "vt100", TT_VT100, 0, "vt102", TT_VT102, 0, "vt220", TT_VT220, 0, "vt220pc", TT_VT220PC, 0, "vt320", TT_VT320, 0, "vt320pc", TT_VT320PC, 0, "vt52", TT_VT52, 0, "wp", TT_KBM_WP, 0, "wy160", TT_WY160, 0, "wy30", TT_WY30, 0, "wy370", TT_WY370, 0, "wy50", TT_WY50, 0, "wy60", TT_WY60, 0, "wyse30", TT_WY30, CM_INV, "wyse370", TT_WY370, CM_INV, "wyse50", TT_WY50, CM_INV, "wyse60", TT_WY60, CM_INV }; int nshokeym = (sizeof(shokeymtab) / sizeof(struct keytab)); #endif /* OS2 */ VOID #ifdef OS2 shokeycode(c,m) int c, m; #else #ifdef CK_ANSIC shokeycode( int c ) #else shokeycode(c) int c; #endif /* CK_ANSIC */ #endif /* OS2 */ { KEY ch; CHAR *s; #ifdef OS2 int i; con_event km; #else /* OS2 */ int km; #endif /* OS2 */ #ifdef OS2 extern int mskkeys; char * mstr = ""; if (c >= KMSIZE) { bleep(BP_FAIL); return; } #else /* OS2 */ printf(" Key code \\%d => ", c); #endif /* OS2 */ #ifndef OS2 km = mapkey(c); #ifndef NOKVERBS if (IS_KVERB(km)) { /* \Kverb? */ int i, kv; kv = km & ~(F_KVERB); printf("Verb: "); for (i = 0; i < nkverbs; i++) if (kverbs[i].kwval == kv) { printf("\\K%s",kverbs[i].kwd); break; } printf("\n"); } else #endif /* NOKVERBS */ if (IS_CSI(km)) { int xkm = km & 0xFF; if (xkm <= 32 || xkm >= 127) printf("String: \\{27}[\\{%d}\n",xkm); else printf("String: \\{27}[%c\n",xkm); } else if (IS_ESC(km)) { int xkm = km & 0xFF; if (xkm <= 32 || xkm >= 127) printf("String: \\{27}\\{%d}\n",xkm); else printf("String: \\{27}%c\n",xkm); } else if (macrotab[c]) { /* See if there's a macro */ printf("String: "); /* If so, display its definition */ s = macrotab[c]; shostrdef(s); printf("\n"); #ifndef NOKVERBS } else if (km >= 0x100) { /* This means "undefined" */ printf("Undefined\n"); #endif /* NOKVERBS */ } else { /* No macro, show single character */ printf("Character: "); ch = km; if (ch < 32 || ch == 127 #ifdef OS2 || ch > 255 #endif /* OS2 */ #ifndef NEXT #ifndef AUX #ifndef XENIX #ifndef OS2 || (ch > 127 && ch < 160) #endif /* OS2 */ #endif /* XENIX */ #endif /* AUX */ #endif /* NEXT */ ) /* These used to be %d, but gcc 1.93 & later complain about type mismatches. %u is supposed to be totally portable. */ printf("\\%u",(unsigned int) ch); else printf("%c \\%u",(CHAR) (ch & 0xff),(unsigned int) ch); if (ch == (KEY) c) printf(" (self, no translation)\n"); else printf("\n"); } #else /* OS2 */ if (m < 0) { km = mapkey(c); mstr = "default"; } else { km = maptermkey(c,m); for (i = 0; i < nshokeym; i++) { if (m == shokeymtab[i].kwval) { mstr = shokeymtab[i].kwd; break; } } } s = keyname(c); debug(F111,"shokeycode mstr",mstr,m); debug(F111,"shokeycode keyname",s,c); printf(" %sKey code \\%d %s (%s) => ", mskkeys ? "mskermit " : "", mskkeys ? cktomsk(c) : c, s == NULL ? "" : s, mstr); switch (km.type) { #ifndef NOKVERBS case kverb: { int i, kv; kv = km.kverb.id & ~(F_KVERB); printf("Verb: "); for (i = 0; i < nkverbs; i++) { if (kverbs[i].kwval == kv) { printf("\\K%s",kverbs[i].kwd); break; } } printf("\n"); break; } #endif /* NOKVERBS */ case csi: { int xkm = km.csi.key & 0xFF; if (xkm <= 32 || xkm >= 127) printf("String: \\{27}[\\{%d}\n",xkm); else printf("String: \\{27}[%c\n",xkm); break; } case esc: { int xkm = km.esc.key & 0xFF; if (xkm <= 32 || xkm >= 127) printf("String: \\{%d}\\{%d}\n",ISDG200(tt_type)?30:27,xkm); else printf("String: \\{%d}%c\n",ISDG200(tt_type)?30:27,xkm); break; } case macro: { printf("String: "); /* Macro, display its definition */ shostrdef(km.macro.string); printf("\n"); break; } case literal: { printf("Literal string: "); /* Literal, display its definition */ shostrdef(km.literal.string); printf("\n"); break; } case error: { if (c >= 0x100) { printf("Undefined\n"); } else { printf("Character: "); ch = c; if (ch < 32 || ch == 127 || ch > 255 #ifndef NEXT #ifndef AUX #ifndef XENIX #ifndef OS2 || (ch > 127 && ch < 160) #endif /* OS2 */ #endif /* XENIX */ #endif /* AUX */ #endif /* NEXT */ ) /* These used to be %d, but gcc 1.93 & later complain about type mismatches. %u is supposed to be totally portable. */ printf("\\%u",(unsigned int) ch); else printf("%c \\%u",(CHAR) (ch & 0xff),(unsigned int) ch); printf(" (self, no translation)\n"); } break; } case key: { printf("Character: "); ch = km.key.scancode; if (ch < 32 || ch == 127 || ch > 255 #ifndef NEXT #ifndef AUX #ifndef XENIX #ifndef OS2 || (ch > 127 && ch < 160) #else || (ch > 127) #endif /* OS2 */ #endif /* XENIX */ #endif /* AUX */ #endif /* NEXT */ ) /* These used to be %d, but gcc 1.93 & later complain about type mismatches. %u is supposed to be totally portable. */ printf("\\%u",(unsigned int) ch); else printf("%c \\%u",(CHAR) (ch & 0xff),(unsigned int) ch); if (ch == (KEY) c) printf(" (self, no translation)\n"); else printf("\n"); break; } } #endif /* OS2 */ } #endif /* NOSETKEY */ VOID #ifdef CK_ANSIC shostrdef( CHAR * s ) #else shostrdef(s) CHAR * s; #endif /* CK_ANSIC */ { CHAR ch; if (!s) s = (CHAR *)""; while ((ch = *s++)) { if (ch < 32 || ch == 127 || ch == 255 /* Systems whose native character sets have graphic characters in C1... */ #ifndef NEXT /* NeXT */ #ifndef AUX /* Macintosh */ #ifndef XENIX /* IBM PC */ #ifdef OS2 /* It doesn't matter whether the local host can display 8-bit characters; they are not portable among character-sets and fonts. Who knows what would be displayed... */ || (ch > 127) #else /* OS2 */ || (ch > 127 && ch < 160) #endif /* OS2 */ #endif /* XENIX */ #endif /* AUX */ #endif /* NEXT */ ) printf("\\{%d}",ch); /* Display control characters */ else putchar((char) ch); /* in backslash notation */ } } #define xxdiff(v,sys) strncmp(v,sys,strlen(sys)) #ifndef NOSHOW VOID shover() { #ifdef OS2 extern char ckxsystem[]; #endif /* OS2 */ extern char *ck_patch, * cklibv; printf("\nVersions:\n %s\n",versio); printf(" Numeric: %ld\n",vernum); #ifdef OS2 printf(" Operating System: %s\n", ckxsystem); #else /* OS2 */ printf(" Built for: %s\n", ckxsys); #ifdef CK_UTSNAME if (unm_nam[0]) printf(" Running on: %s %s %s %s\n", unm_nam,unm_ver,unm_rel,unm_mch); #endif /* CK_UTSNAME */ printf(" Patches: %s\n", *ck_patch ? ck_patch : "(none)"); #endif /* OS2 */ if (xxdiff(ckxv,ckxsys)) printf(" %s for%s\n",ckxv,ckxsys); else printf(" %s\n",ckxv); if (xxdiff(ckzv,ckzsys)) printf(" %s for%s\n",ckzv,ckzsys); else printf(" %s\n",ckzv); printf(" %s\n",cklibv); printf(" %s\n",protv); printf(" %s\n",fnsv); printf(" %s\n %s\n",cmdv,userv); #ifndef NOCSETS printf(" %s\n",xlav); #endif /* NOCSETS */ #ifndef MAC #ifndef NOLOCAL printf(" %s\n",connv); #ifdef OS2 printf(" %s\n",ckyv); #endif /* OS2 */ #endif /* NOLOCAL */ #endif /* MAC */ #ifndef NODIAL printf(" %s\n",dialv); #endif /* NODIAL */ #ifndef NOSCRIPT printf(" %s\n",loginv); #endif /* NOSCRIPT */ #ifdef NETCONN printf(" %s\n",cknetv); #ifdef OS2 printf(" %s\n",ckonetv); #ifdef CK_NETBIOS printf(" %s\n",ckonbiv); #endif /* CK_NETBIOS */ #endif /* OS2 */ #endif /* NETCONN */ #ifdef TNCODE printf(" %s\n",cktelv); #endif /* TNCODE */ #ifdef SSHBUILTIN printf(" %s\n",cksshv); #ifdef SFTP_BUILTIN printf(" %s\n",cksftpv); #endif /* SFTP_BUILTIN */ #endif /* SSHBUILTIN */ #ifdef OS2 #ifdef OS2MOUSE printf(" %s\n",ckomouv); #endif /* OS2MOUSE */ #endif /* OS2 */ #ifndef NOFTP #ifndef SYSFTP #ifdef NEWFTP printf(" %s\n",ckftpv); #endif /* NEWFTP */ #endif /* SYSFTP */ #endif /* NOFTP */ #ifdef CK_AUTHENTICATION printf(" %s\n",ckathv); #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION #ifdef CRYPT_DLL printf(" %s\n",ck_crypt_dll_version()); #else /* CRYPT_DLL */ printf(" %s\n",ckcrpv); #endif /* CRYPT_DLL */ #endif /* CK_ENCRYPTION */ #ifdef CK_SSL printf(" %s\n",cksslv); #endif /* CK_SSL */ printf("\n"); } #ifdef CK_LABELED VOID sholbl() { #ifdef VMS printf("VMS Labeled File Features:\n"); printf(" acl %s (ACL info %s)\n", showoff(lf_opts & LBL_ACL), lf_opts & LBL_ACL ? "preserved" : "discarded"); printf(" backup-date %s (backup date/time %s)\n", showoff(lf_opts & LBL_BCK), lf_opts & LBL_BCK ? "preserved" : "discarded"); printf(" name %s (original filename %s)\n", showoff(lf_opts & LBL_NAM), lf_opts & LBL_NAM ? "preserved" : "discarded"); printf(" owner %s (original file owner id %s)\n", showoff(lf_opts & LBL_OWN), lf_opts & LBL_OWN ? "preserved" : "discarded"); printf(" path %s (original file's disk:[directory] %s)\n", showoff(lf_opts & LBL_PTH), lf_opts & LBL_PTH ? "preserved" : "discarded"); #else #ifdef OS2 printf("OS/2 Labeled File features (attributes):\n"); printf(" archive: %s\n", showoff(lf_opts & LBL_ARC)); printf(" extended: %s\n", showoff(lf_opts & LBL_EXT)); printf(" hidden: %s\n", showoff(lf_opts & LBL_HID)); printf(" read-only: %s\n", showoff(lf_opts & LBL_RO )); printf(" system: %s\n", showoff(lf_opts & LBL_SYS)); #endif /* OS2 */ #endif /* VMS */ } #endif /* CK_LABELED */ VOID #ifdef CK_ANSIC shotcs( int csl, int csr ) /* Show terminal character set */ #else shotcs(csl,csr) int csl, csr; #endif /* CK_ANSIC */ { #ifndef NOCSETS #ifdef OS2 #ifndef NOTERM extern struct _vtG G[4], *GL, *GR; extern int decnrcm, sni_chcode; extern int tt_utf8, dec_nrc, dec_kbd, dec_lang; extern int prncs; printf(" Terminal character-sets:\n"); if (IS97801(tt_type_mode)) { if (cmask == 0377) printf(" Mode: 8-bit Mode\n"); else printf(" Mode: 7-bit Mode\n"); printf(" CH.CODE is %s\n",sni_chcode?"On":"Off"); } else if (ISVT100(tt_type_mode)) { if (decnrcm) printf(" Mode: 7-bit National Mode\n"); else printf(" Mode: 8-bit Multinational Mode\n"); } if ( ck_isunicode() ) printf(" Local: Unicode display / %s input\n", csl == TX_TRANSP ? "transparent" : csl == TX_UNDEF ? "undefined" : txrinfo[csl]->keywd); else printf(" Local: %s\n", csl == TX_TRANSP ? "transparent" : csl == TX_UNDEF ? "undefined" : txrinfo[csl]->keywd); if ( tt_utf8 ) { printf(" Remote: UTF-8\n"); } else { printf(" Remote: %sG0: %s (%s)\n", GL == &G[0] ? "GL->" : GR == &G[0] ? "GR->" : " ", txrinfo[G[0].designation]->keywd, G[0].designation == TX_TRANSP ? "" : G[0].size == cs94 ? "94 chars" : G[0].size == cs96 ? "96 chars" : "multi-byte"); printf(" %sG1: %s (%s)\n", GL == &G[1] ? "GL->" : GR == &G[1] ? "GR->" : " ", txrinfo[G[1].designation]->keywd, G[1].designation == TX_TRANSP ? "" : G[1].size == cs94 ? "94 chars" : G[1].size == cs96 ? "96 chars" : "multi-byte"); printf(" %sG2: %s (%s)\n", GL == &G[2] ? "GL->" : GR == &G[2] ? "GR->" : " ", txrinfo[G[2].designation]->keywd, G[2].designation == TX_TRANSP ? "" : G[2].size == cs94 ? "94 chars" : G[2].size == cs96 ? "96 chars" : "multi-byte"); printf(" %sG3: %s (%s)\n", GL == &G[3] ? "GL->" : GR == &G[3] ? "GR->" : " ", txrinfo[G[3].designation]->keywd, G[3].designation == TX_TRANSP ? "" : G[3].size == cs94 ? "94 chars" : G[3].size == cs96 ? "96 chars" : "multi-byte"); } printf("\n"); printf(" Keyboard character-sets:\n"); printf(" Multinational: %s\n",txrinfo[dec_kbd]->keywd); printf(" National: %s\n",txrinfo[dec_nrc]->keywd); printf("\n"); printf(" Printer character-set: %s\n",txrinfo[prncs]->keywd); #endif /* NOTERM */ #else /* OS2 */ #ifndef MAC char *s; debug(F101,"TERM LOCAL CSET","",csl); debug(F101,"TERM REMOTE CSET","",csr); printf(" Terminal character-set: "); if (tcs_transp) { /* No translation */ printf("transparent\n"); } else { /* Translation */ printf("%s (remote) %s (local)\n", fcsinfo[csr].keyword,fcsinfo[csl].keyword); if (csr != csl) { switch(gettcs(csr,csl)) { case TC_USASCII: s = "ascii"; break; case TC_1LATIN: s = "latin1-iso"; break; case TC_2LATIN: s = "latin2-iso"; break; case TC_CYRILL: s = "cyrillic-iso"; break; case TC_JEUC: s = "japanese-euc"; break; case TC_HEBREW: s = "hebrew-iso"; break; case TC_GREEK: s = "greek-iso"; break; case TC_9LATIN: s = "latin9-iso"; break; default: s = "transparent"; break; } if (strcmp(s,fcsinfo[csl].keyword) && strcmp(s,fcsinfo[csr].keyword)) printf(" (via %s)\n",s); } } #endif /* MAC */ #endif /* OS2 */ #endif /* NOCSETS */ } #ifndef NOLOCAL #ifdef OS2 extern char htab[]; VOID shotabs() { int i,j,k,n; printf("Tab Stops:\n\n"); for (i = 0, j = 1, k = VscrnGetWidth(VCMD); i < MAXTERMCOL; ) { do { printf("%c",htab[++i]=='T'?'T':'-'); } while (i % k && i < MAXTERMCOL); printf("\n"); for ( ; j <= i; j++) { switch ( j%10 ) { case 1: printf("%c",j == 1 ? '1' : '.'); break; case 2: case 3: case 4: case 5: case 6: case 7: printf("%c",'.'); break; case 8: n = (j+2)/100; if (n) printf("%d",n); else printf("%c",'.'); break; case 9: n = (j+1)%100/10; if (n) printf("%d",n); else if (j>90) printf("0"); else printf("%c",'.'); break; case 0: printf("0"); break; } } printf("\n"); } #ifdef COMMENT for (i = 1; i <= 70; i++) printf("%c",htab[i]=='T'?'T':'-'); printf("\n1.......10........20........30........40........50........60\ ........70\n\n"); for (; i <= 140; i++) printf("%c",htab[i]=='T'?'T':'-'); printf("\n........80........90.......100.......110.......120.......130\ .......140\n\n"); for (; i <= 210; i++) printf("%c",htab[i]=='T'?'T':'-'); printf("\n.......150.......160.......170.......180.......190.......200\ .......210\n\n"); for (; i <= 255; i++) printf("%c",htab[i]=='T'?'T':'-'); printf("\n.......220.......230.......240.......250..255\n"); #endif } #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef OS2MOUSE VOID shomou() { int button, event, id, i; char * name = ""; extern int mouse_reporting_mode; extern BOOL mouse_reporting_override; printf("Mouse settings:\n"); printf(" Button Count: %d\n",mousebuttoncount()); printf(" Active: %s\n",showoff(tt_mouse)); printf(" Reporting: "); if (MOUSE_REPORTING_TEST_FLAG(mouse_reporting_mode, MOUSEREPORTING_DISABLE)) { printf("Disabled"); } else { printf("%s ", mouse_reporting_override ? "Override" : "Enabled"); if (MOUSE_REPORTING_TEST_FLAG(mouse_reporting_mode, MOUSEREPORTING_SGR)) { printf("(SGR)"); } else if (MOUSE_REPORTING_TEST_FLAG(mouse_reporting_mode, MOUSEREPORTING_URXVT)) { printf("(URXVT)"); } else if (MOUSE_REPORTING_TEST_FLAG(mouse_reporting_mode, MOUSEREPORTING_X11)) { printf("(X11)"); } else if (MOUSE_REPORTING_TEST_FLAG(mouse_reporting_mode, MOUSEREPORTING_X10)) { printf("(X10)"); } } printf("\n\n"); for (button = 0; button < MMBUTTONMAX; button++) for (event = 0; event < MMEVENTSIZE; event++) if (mousemap[button][event].type != error) switch (mousemap[button][event].type) { case key: if (isprint(mousemap[button][event].key.scancode)) { printf(" %s = Character: %c \\%d\n", mousename(button,event), mousemap[button][event].key.scancode, mousemap[button][event].key.scancode ); } else { printf(" %s = Character: \\%d\n", mousename(button,event), mousemap[button][event].key.scancode); } break; case kverb: id = mousemap[button][event].kverb.id & ~(F_KVERB); if (id != K_IGNORE) { for (i = 0; i< nkverbs; i++) if (id == kverbs[i].kwval) { name = kverbs[i].kwd; break; } printf(" %s = Kverb: \\K%s\n", mousename(button,event), name ); } break; case macro: printf(" %s = Macro: ", mousename(button,event) ); shostrdef(mousemap[button][event].macro.string); printf("\n"); break; } } #endif /* OS2MOUSE */ #ifndef NOLOCAL VOID shotrm() { char *s; extern char * getiact(); extern int tt_print, adl_err, adl_ask; #ifndef NOTRIGGER extern char * tt_trigger[]; #endif /* NOTRIGGER */ #ifdef CKTIDLE extern char * tt_idlesnd_str; extern int tt_idlesnd_tmo; extern int tt_idlelimit, tt_idleact; #endif /* CKTIDLE */ #ifdef OS2 extern int wy_autopage, autoscroll, sgrcolors, colorreset, user_erasemode, decscnm, decscnm_usr, tt_diff_upd, tt_senddata, wy_blockend, marginbell, marginbellcol, tt_modechg, dgunix; int lines = 0; #ifdef KUI extern CKFLOAT tt_linespacing[]; extern int tt_cursor_blink; #endif /* KUI */ #ifdef PCFONTS int i; char *font; if (IsOS2FullScreen()) { /* Determine the font name */ if (!os2LoadPCFonts()) { for (i = 0; i < ntermfont; i++) { if (tt_font == term_font[i].kwval) { font = term_font[i].kwd; break; } } } else { font = "(DLL not available)"; } } else { font = "(full screen only)"; } #endif /* PCFONTS */ #ifdef KUI char font[64] = "(unknown)"; if ( ntermfont > 0 ) { int i; for (i = 0; i < ntermfont; i++) { if (tt_font == term_font[i].kwval) { ckstrncpy(font,term_font[i].kwd,59); ckstrncat(font," ",64); ckstrncat(font,ckitoa(tt_font_size/2),64); if ( tt_font_size % 2 ) ckstrncat(font,".5",64); break; } } } #endif /* KUI */ printf("Terminal parameters:\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %1d%-12s %13s: %1d%-14s\n", "Bytesize: Command", (cmdmsk == 0377) ? 8 : 7, " bits","Terminal", (cmask == 0377) ? 8 : 7," bits"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %-13s","Type", (tt_type >= 0 && tt_type <= max_tt) ? tt_info[tt_type].x_name : "unknown" ); if (tt_type >= 0 && tt_type <= max_tt) if (strlen(tt_info[tt_type].x_id)) printf(" %13s: %s","ID",tt_info[tt_type].x_id); printf("\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %-13s %13s: %-15s\n","Echo", duplex ? "local" : "remote","Locking-shift",showoff(sosi)); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %-13s %13s: %-15s\n","Newline-mode", showoff(tnlm), "Cr-display",tt_crd ? "crlf" : "normal"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %-13s %13s: %-15s\n","Cursor", #ifdef KUI (tt_cursor == 2) ? (tt_cursor_blink ? "full (*)" : "full (.)") : (tt_cursor == 1) ? (tt_cursor_blink ? "half (*)" : "half (.)") : (tt_cursor_blink ? "underline (*)" : "underline (.)"), #else /* KUI */ (tt_cursor == 2) ? "full" : (tt_cursor == 1) ? "half" : "underline", #endif /* KUI */ #ifdef CK_AUTODL "autodownload",(autodl == TAD_ON && adl_ask == 0) ? (adl_err ? "on, error stop" : "on, error continue") : (autodl == TAD_ON && adl_ask == 1) ? (adl_err ? "ask, error stop" : "ask, error continue") : "off" #else /* CK_AUTODL */ "", "" #endif /* CK_AUTODL */ ); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %-13s %13s: %-15s\n","Arrow-keys", tt_arrow ? "application" : "cursor", "Keypad-mode", tt_keypad ? "application" : "numeric" ); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } /* Just to make sure we are using current info */ updanswerbk(); /* This line doesn't end with '\n' because the answerback string is terminated with a newline */ printf(" %19s: %-13s %13s: %-15s","Answerback", showoff(tt_answer),"response",answerback); switch (tt_bell) { case XYB_NONE: s = "none"; break; case XYB_VIS: s= "visible"; break; case XYB_AUD | XYB_BEEP: s="beep"; break; case XYB_AUD | XYB_SYS: s="system sounds"; break; default: s="(unknown)"; } printf(" %19s: %-13s %13s: %-15s\n","Bell",s, "Wrap",showoff(tt_wrap)); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %-13s %13s: %-15s\n","Autopage",showoff(wy_autopage), "Autoscroll",showoff(autoscroll)); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %-13s %13s: %-15s\n","SGR Colors",showoff(sgrcolors), "ESC[0m color",colorreset?"default-color":"current-color"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %-13s %13s: %-15s\n", "Erase color",user_erasemode?"default-color":"current-color", "Screen mode",decscnm?"reverse":"normal"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %-13d %13s: %-15d\n","Transmit-timeout",tt_ctstmo, "Output-pacing",tt_pacing); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %-13d %13s: %s\n","Idle-timeout",tt_idlelimit, "Idle-action", getiact()); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %-13s %13s: %-15s\n","Send data", showoff(tt_senddata),"End of Block", wy_blockend?"crlf/etx":"us/cr"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } #ifndef NOTRIGGER printf(" %19s: %-13s %13s: %d seconds\n","Auto-exit trigger", tt_trigger[0],"Output pacing",tt_pacing ); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } #endif /* NOTRIGGER */ printf(" %19s: %-13s %13s: %-15d\n","Margin bell", showoff(marginbell),"at column", marginbellcol); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } switch (tt_modechg) { case TVC_DIS: s = "disabled"; break; case TVC_ENA: s = "enabled"; break; case TVC_W95: s = "win95-restricted"; break; default: s = "(unknown)"; } printf(" %19s: %-13s %13s: %-15s\n","DG Unix mode", showoff(dgunix),"Video change", s); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } #ifdef CK_APC if (apcstatus == APC_ON) s = "on"; else if (apcstatus == APC_OFF) s = "off"; else if (apcstatus == APC_ON|APC_UNCH) s = "unchecked"; else if (apcstatus == APC_ON|APC_NOINP) s = "no-input"; else if (apcstatus == APC_ON|APC_UNCH|APC_NOINP) s = "unchecked-no-input"; printf(" %19s: %-13s %13s: %-15s\n", "APC", s, #ifdef PCFONTS "Font (VGA)",font #else /* PCFONTS */ #ifdef KUI "Font",font #else "Font","(not supported)" #endif /* KUI */ #endif /* PCFONTS */ ); #endif /* CK_APC */ if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } #ifdef CK_TTGWSIZ /* Console terminal screen size */ if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0) ttgwsiz(); /* Try to get latest size */ #endif /* CK_TTGWSIZ */ printf(" %19s: %-13d %13s: %-15d\n","Height",tt_rows[VTERM], "Width",tt_cols[VTERM]); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } #ifdef KUI printf(" %19s: %-12f %14s: %-15d\n","Line spacing",tt_linespacing[VTERM], "Display Height",VscrnGetDisplayHeight(VTERM)); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } #endif /* KUI */ printf(" %19s: %-13s %13s: %d lines\n","Roll-mode", tt_roll[VTERM]?"insert":"overwrite","Scrollback", tt_scrsize[VTERM]); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } if (updmode == tt_updmode) if (updmode == TTU_FAST) s = "fast (fast)"; else s = "smooth (smooth)"; else if (updmode == TTU_FAST) s = "fast (smooth)"; else s = "smooth (fast)"; printf(" %19s: %-13s %13s: %d ms\n","Screen-update: mode",s, "interval",tt_update); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %-13s %13s: %-15s\n", "Screen-optimization",showoff(tt_diff_upd), "Status line",showoff(tt_status[VTERM])); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" %19s: %-13s %13s: %-15s\n","Debug", showoff(debses),"Session log", seslog? sesfil : "(none)" ); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } /* Display colors (should become SHOW COLORS) */ { USHORT row; #ifndef ONETERMUPD USHORT col; #endif /* ONETERMUPD */ char * colors[16] = { "black","blue","green","cyan","red","magenta","brown","lgray", "dgray","lblue","lgreen","lcyan","lred","lmagent","yellow","white" }; printf("\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" Color:"); #ifndef ONETERMUPD GetCurPos(&row, &col); WrtCharStrAtt("border", 6, row, 9, &colorborder ); WrtCharStrAtt("debug", 5, row, 17, &colordebug ); WrtCharStrAtt("helptext", 8, row, 25, &colorhelp ); WrtCharStrAtt("reverse", 7, row, 34, &colorreverse ); WrtCharStrAtt("select", 6, row, 42, &colorselect ); WrtCharStrAtt("status", 6, row, 50, &colorstatus ); WrtCharStrAtt("terminal", 8, row, 58, &colornormal ); WrtCharStrAtt("underline", 9, row, 67, &colorunderline ); #endif /* ONETERMUPD */ row = VscrnGetCurPos(VCMD)->y+1; VscrnWrtCharStrAtt(VCMD, "border", 6, row, 9, &colorborder ); VscrnWrtCharStrAtt(VCMD, "debug", 5, row, 17, &colordebug ); VscrnWrtCharStrAtt(VCMD, "helptext", 8, row, 25, &colorhelp ); VscrnWrtCharStrAtt(VCMD, "reverse", 7, row, 34, &colorreverse ); VscrnWrtCharStrAtt(VCMD, "select", 6, row, 42, &colorselect ); VscrnWrtCharStrAtt(VCMD, "status", 6, row, 50, &colorstatus ); VscrnWrtCharStrAtt(VCMD, "terminal", 8, row, 58, &colornormal ); VscrnWrtCharStrAtt(VCMD, "underline", 9, row, 67, &colorunderline ); printf("\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } /* Foreground color names */ printf("%6s: %-8s%-8s%-9s%-8s%-8s%-8s%-9s%-9s\n","fore", "", colors[colordebug&0x0F], colors[colorhelp&0x0F], colors[colorreverse&0x0F], colors[colorselect&0x0F], colors[colorstatus&0x0F], colors[colornormal&0x0F], colors[colorunderline&0x0F]); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } /* Background color names */ printf("%6s: %-8s%-8s%-9s%-8s%-8s%-8s%-9s%-9s\n","back", colors[colorborder], colors[colordebug>>4], colors[colorhelp>>4], colors[colorreverse>>4], colors[colorselect>>4], colors[colorstatus>>4], colors[colornormal>>4], colors[colorunderline>>4] ); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf("\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" Color:"); #ifndef ONETERMUPD GetCurPos(&row, &col); WrtCharStrAtt("graphic", 7, row, 9, &colorgraphic ); WrtCharStrAtt("command", 7, row, 17, &colorcmd ); WrtCharStrAtt("italic", 6, row, 26, &coloritalic ); #endif /* ONETERMUPD */ row = VscrnGetCurPos(VCMD)->y+1; VscrnWrtCharStrAtt(VCMD, "graphic", 7, row, 9, &colorgraphic ); VscrnWrtCharStrAtt(VCMD, "command", 7, row, 17, &colorcmd ); VscrnWrtCharStrAtt(VCMD, "italic", 6, row, 26, &coloritalic ); printf("\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } /* Foreground color names */ printf("%6s: %-8s%-8s%-8s\n","fore", colors[colorgraphic&0x0F], colors[colorcmd&0x0F], colors[coloritalic&0x0F]); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } /* Background color names */ printf("%6s: %-8s%-8s%-8s\n","back", colors[colorgraphic>>4], colors[colorcmd>>4], colors[coloritalic>>4]); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } } printf("\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } { extern int trueblink, truedim, truereverse, trueunderline, trueitalic; printf( " Attribute: \ blink: %-3s dim: %-3s italic: %-3s reverse: %-3s underline: %-3s\n", trueblink?"on":"off", truedim?"on":"off", trueitalic?"on":"off", truereverse?"on":"off", trueunderline?"on":"off"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } } { extern vtattrib WPattrib; printf(" ASCII Protected chars: %s%s%s%s%s%s%s\n", WPattrib.blinking?"blink ":"", WPattrib.italic?"italic ":"", WPattrib.reversed?"reverse ":"", WPattrib.underlined?"underline ":"", WPattrib.bold?"bold ":"", WPattrib.dim?"dim ":"", WPattrib.invisible?"invisible ":""); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } } printf("\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } (VOID) shoesc(escape); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } printf(" See SHOW CHARACTER-SETS for character-set info\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return; else lines = 0; } #else /* OS2 */ /* Beginning of new non-OS2 version */ printf("\n"); printf("Terminal parameters:\n"); printf(" %19s: %1d%-12s %13s: %1d%-14s\n", "Bytesize: Command", (cmdmsk == 0377) ? 8 : 7, " bits","Terminal", (cmask == 0377) ? 8 : 7," bits"); s = getenv("TERM"); #ifdef XPRINT printf(" %19s: %-13s %13s: %-15s\n", "Type", s ? s : "(unknown)", "Print", showoff(tt_print) ); #else printf(" %19s: %-13s\n","Type", s ? s : "(unknown)"); #endif /* XPRINT */ printf(" %19s: %-13s %13s: %-15s\n","Echo", duplex ? "local" : "remote","Locking-shift",showoff(sosi)); printf(" %19s: %-13s %13s: %-15s\n","Newline-mode", showoff(tnlm),"Cr-display",tt_crd ? "crlf" : "normal"); #ifdef CK_APC if (apcstatus == APC_ON) s = "on"; else if (apcstatus == APC_OFF) s = "off"; else if (apcstatus == (APC_ON|APC_UNCH)) s = "unchecked"; else if (apcstatus == (APC_ON|APC_NOINP)) s = "no-input"; else if (apcstatus == (APC_ON|APC_UNCH|APC_NOINP)) s = "unchecked-no-input"; printf(" %19s: %-13s %13s: %-15s\n", "APC", s, #ifdef CK_AUTODL "Autodownload", autodl ? (adl_err ? "on, error stop" : "on, error continue") : "off" #else "","" #endif /* CK_AUTODL */ ); #endif /* CK_APC */ #ifdef CK_TTGWSIZ /* Console terminal screen size */ ttgwsiz(); /* Try to get latest size */ printf(" %19s: %-13d %13s: %-15d\n","Height",tt_rows, "Width", tt_cols); #endif /* CK_TTGWSIZ */ printf(" %19s: %-13s %13s: %-15s\n","Debug", showoff(debses),"Session log", seslog? sesfil : "(none)" ); #ifdef CKTIDLE printf(" %19s: %-13d %13s: %s\n","Idle-timeout",tt_idlelimit, "Idle-action", getiact()); #endif /* CKTIDLE */ printf(" %19s: %-13s ","Lf-display", tt_lfd ? "crlf" : "normal"); #ifdef UNIX #ifndef NOJC printf("%13s: %-15s","Suspend", showoff(xsuspend)); #endif /* NOJC */ #endif /* UNIX */ printf("\n"); #ifndef NOTRIGGER printf(" %19s: %-13s\n","Trigger", tt_trigger[0] ? tt_trigger[0] : "(none)"); #endif /* NOTRIGGER */ printf("\n"); (VOID) shoesc(escape); #ifndef NOCSETS shotcs(tcsl,tcsr); /* Show terminal character sets */ #endif /* NOCSETS */ #endif /* OS2 */ } VOID shmdmlin() { /* Briefly show modem & line */ #ifndef NODIAL #ifndef MINIDIAL #ifdef OLDTBCODE extern int tbmodel; _PROTOTYP( char * gtbmodel, (void) ); #endif /* OLDTBCODE */ #endif /* MINIDIAL */ #endif /* NODIAL */ if (local) #ifdef OS2 printf(" Port: %s, Modem type: ",ttname); #else printf(" Line: %s, Modem type: ",ttname); #endif /* OS2 */ else printf( #ifdef OS2 " Communication device not yet selected with SET PORT\n Modem type: " #else " Communication device not yet selected with SET LINE\n Modem type: " #endif /* OS2 */ ); #ifndef NODIAL printf("%s",gmdmtyp()); #ifndef MINIDIAL #ifdef OLDTBCODE if (tbmodel) printf(" (%s)",gtbmodel()); /* Telebit model info */ #endif /* OLDTBCODE */ #endif /* MINIDIAL */ #else printf("(disabled)"); #endif /* NODIAL */ } #ifdef CK_TAPI void shotapi(int option) { int rc=0,k ; char *s=NULL; LPDEVCFG lpDevCfg = NULL; LPCOMMCONFIG lpCommConfig = NULL; LPMODEMSETTINGS lpModemSettings = NULL; DCB * lpDCB = NULL; extern struct keytab * tapiloctab; /* Microsoft TAPI Locations */ extern int ntapiloc; extern struct keytab * tapilinetab; /* Microsoft TAPI Line Devices */ extern int ntapiline; extern int tttapi; /* TAPI in use */ extern int tapipass; /* TAPI Passthrough mode */ extern int tapiconv; /* TAPI Conversion mode */ extern int tapilights; extern int tapipreterm; extern int tapipostterm; extern int tapimanual; extern int tapiinactivity; extern int tapibong; extern int tapiusecfg; extern char tapiloc[]; extern int tapilocid; extern int TAPIAvail; if (!TAPIAvail) { printf("TAPI Support not enabled\r\n"); return; } switch (option) { case 0: printf("TAPI Settings:\n"); printf(" Line: %s\n", tttapi ? ttname : "(none in use)"); cktapiBuildLocationTable(&tapiloctab, &ntapiloc); if (tapilocid == -1) tapilocid = cktapiGetCurrentLocationID(); /* Find the current tapiloc entry */ /* and use it as the default. */ for (k = 0; k < ntapiloc; k++) { if (tapiloctab[k].kwval == tapilocid) break; } if (k >= 0 && k < ntapiloc) s = tapiloctab[k].kwd; else s = "(unknown)"; printf(" Location: %s\n",s); printf(" Modem-dialing: %s\n",tapipass?"off":"on"); printf(" Phone-number-conversions: %s\n", tapiconv==CK_ON?"on":tapiconv==CK_AUTO?"auto":"off"); printf(" Modem-lights: %s %s\n",tapilights?"on ":"off", tapipass?"(n/a)":""); printf(" Predial-terminal: %s %s\n",tapipreterm?"on ":"off", tapipass?"(n/a)":""); printf(" Postdial-terminal: %s %s\n",tapipostterm?"on ":"off", tapipass?"(n/a)":""); printf(" Manual-dial: %s %s\n",tapimanual?"on ":"off", tapipass?"(n/a)":""); printf(" Inactivity-timeout: %d seconds %s\n",tapiinactivity, tapipass?"(n/a)":""); printf(" Wait-for-bong: %d seconds %s\n",tapibong, tapipass?"(n/a)":""); printf(" Use-windows-configuration: %s %s\n", tapiusecfg?"on ":"off", tapipass?"(n/a)":""); printf("\n"); #ifdef TAPI_BETATEST if (tapipass) { printf("K-95 uses the TAPI Line in an exclusive mode. Other applications\n"); printf("may open the device but may not place calls nor answer calls.\n"); printf("Dialing is performed using the K-95 dialing procedures. SET MODEM\n"); printf("TYPE TAPI after the SET TAPI LINE command to activate the modem\n"); printf("definition associated with the active TAPI LINE device.\n\n"); } else { printf("K-95 uses the TAPI Line in a cooperative mode. Other applications\n"); printf("may open the device, place and answer calls. Dialing is performed\n"); printf("by TAPI. K-95 SET MODEM commands are not used.\n\n"); } if (tapiconv == CK_ON || tapiconv == CK_AUTO && !tapipass) { printf( "Phone numbers are converted from canonical to dialable form by TAPI\n"); printf("using the dialing rules specified in the TAPI Dialing Properties\n"); printf("dialog.\n\n"); } else { printf( "Phone numbers are converted from canonical to dialable form by K-95\n"); printf( "using the dialing rules specified with the SET DIAL commands. TAPI\n"); printf( "Dialing Properties are imported automaticly upon startup and whenever\n"); printf("the TAPI Dialing Properties are altered or when the TAPI Location\n"); printf("is changed.\n\n"); } #endif /* TAPI_BETATEST */ if (tapipass) { printf("Type SHOW MODEM to see MODEM configuration.\n"); if (tapiconv == CK_ON) printf("Type SHOW DIAL to see DIAL-related items.\n"); } else { if (tapiconv == CK_ON || tapiconv == CK_AUTO) printf("Type SHOW DIAL to see DIAL-related items.\n"); } break; case 1: cktapiDisplayTapiLocationInfo(); break; case 2: rc = cktapiGetModemSettings(&lpDevCfg,&lpModemSettings, &lpCommConfig,&lpDCB); if (rc) { cktapiDisplayModemSettings(lpDevCfg,lpModemSettings, lpCommConfig,lpDCB); } else { printf("?Unable to retrieve Modem Settings\n"); } break; case 3: { HANDLE hModem = GetModemHandleFromLine((HLINE)0); if (hModem) DisplayCommProperties(hModem); else printf("?Unable to retrieve a valid Modem Handle\n"); CloseHandle(hModem); break; } } printf("\n"); } #endif /* CK_TAPI */ #endif /* NOLOCAL */ #ifdef PATTERNS static VOID shopat() { extern char * binpatterns[], * txtpatterns[]; extern int patterns, filepeek; char **p, *s; int i, j, k, n, flag, width; #ifdef CK_TTGWSIZ ttgwsiz(); /* Try to get latest size */ #ifdef OS2 width = tt_cols[VCMD]; #else /* OS2 */ width = tt_cols; #endif /* OS2 */ if (width < 1) #endif /* CK_TTGWSIZ */ width = 80; printf("\n"); printf(" Set file type: %s\n",gfmode(binary,1)); printf(" Set file patterns: %s", showooa(patterns)); #ifdef CK_LABELED if (binary == XYFT_L) printf(" (but SET FILE TYPE LABELED overrides)\n"); else #endif /* CK_LABELED */ #ifdef VMS if (binary == XYFT_I) printf(" (but SET FILE TYPE IMAGE overrides)\n"); else #endif /* VMS */ if (filepeek) printf(" (but SET FILE SCAN ON overrides)\n"); else printf("\n"); printf(" Maximum patterns allowed: %d\n", FTPATTERNS); for (k = 0; k < 2; k++) { /* For each kind of patter */ printf("\n"); if (k == 0) { /* binary... */ printf(" File binary-patterns: "); p = binpatterns; } else { /* text... */ printf(" File text-patterns: "); p = txtpatterns; } if (!p[0]) { printf("(none)\n"); } else { printf("\n "); n = 2; for (i = 0; i < FTPATTERNS; i++) { /* For each pattern */ if (!p[i]) /* Done */ break; s = p[i]; /* Look for embedded space */ for (j = 0, flag = 1; *s; s++, j++) /* and also get length */ if (*s == SP) flag = 3; n += j + flag; /* Length of this line */ if (n >= width - 1) { printf("\n "); n = j+2; } printf(flag == 3 ? " {%s}" : " %s", p[i]); } if (n > 2) printf("\n"); } } printf("\n"); } #endif /* PATTERNS */ #ifndef NOSPL static VOID shooutput() { printf(" Output pacing: %d (milliseconds)\n",pacing); printf(" Output special-escapes: %s\n", showoff(outesc)); } static VOID shoinput() { #ifdef CKFLOAT extern char * inpscale; #endif /* CKFLOAT */ #ifdef CK_AUTODL printf(" Input autodownload: %s\n", showoff(inautodl)); #endif /* CK_AUTODL */ printf(" Input cancellation: %s\n", showoff(inintr)); printf(" Input case: %s\n", inpcas[cmdlvl] ? "observe" : "ignore"); printf(" Input buffer-length: %d\n", inbufsize); printf(" Input echo: %s\n", showoff(inecho)); printf(" Input silence: %d (seconds)\n", insilence); #ifdef OS2 printf(" Input terminal: %s\n", showoff(interm)); #endif /* OS2 */ printf(" Input timeout: %s\n", intime[cmdlvl] ? "quit" : "proceed"); #ifdef CKFLOAT printf(" Input scale-factor: %s\n", inpscale ? inpscale : "1.0"); #endif /* CKFLOAT */ if (instatus < 0) printf(" Last INPUT: -1 (INPUT command not yet given)\n"); else printf(" Last INPUT: %d (%s)\n", instatus,i_text[instatus]); } #endif /* NOSPL */ #ifndef NOSPL int showarray() { #ifdef COMMENT char * p, * q, ** ap; int i; #endif /* COMMENT */ char *s; int x = 0, y; int range[2]; if ((y = cmfld("Array name","",&s,NULL)) < 0) if (y != -3) return(y); ckstrncpy(line,s,LINBUFSIZ); s = line; if ((y = cmcfm()) < 0) return(y); if (*s) { char ** ap; if ((x = arraybounds(s,&(range[0]),&(range[1]))) < 0) { printf("?Bad array: %s\n",s); return(-9); } ap = a_ptr[x]; if (!ap) { printf("Array not declared: %s\n", s); return(success = 1); } else { int i, n, max; max = (range[1] > 0) ? range[1] : ((range[0] > 0) ? range[0] : a_dim[x]); if (range[0] < 0) range[0] = 0; if (max > a_dim[x]) max = a_dim[x]; n = 1; printf("\\&%c[]: Dimension = %d",arrayitoa(x),a_dim[x]); if (a_link[x] > -1) printf(" (Link to \\&%c[])",arrayitoa(a_link[x])); printf("\n"); for (i = range[0]; i <= max; i++) { if (ap[i]) { printf("%3d. %s\n",i,ap[i]); if (xaskmore) { if (cmd_cols > 0) { x = strlen(ap[i]) + 5; y = (x % cmd_cols) ? 1 : 0; n += (x / cmd_cols) + y; } else { n++; } if (n > (cmd_rows - 3)) { if (!askmore()) break; else n = 0; } } } } } return(1); } /* All arrays - just show name and dimension */ for (y = 0; y < (int) 'z' - ARRAYBASE + 1; y++) { if (a_ptr[y]) { if (x == 0) printf("Declared arrays:\n"); x = 1; printf(" \\&%c[%d]", (y == 1) ? 64 : y + ARRAYBASE, a_dim[y]); if (a_link[y] > -1) printf(" => \\&%c[]",arrayitoa(a_link[y])); printf("\n"); } if (!x) printf(" No arrays declared\n"); } return(1); } #endif /* NOSPL */ int #ifdef CK_ANSIC doshow( int x ) #else doshow(x) int x; #endif /* CK_ANSIC */ { int y, z, i; long zz; extern int optlines; char *s; #ifdef OS2 extern int os2gks; extern int tt_kb_mode; #endif /* OS2 */ extern int srvcdmsg; extern char * cdmsgstr, * ckcdpath; char fnbuf[100]; #ifndef NOSETKEY if (x == SHKEY) { /* SHOW KEY */ int c; #ifdef OS2 if ((x = cmkey(shokeytab,nshokey,"How many keys should be shown?", "one",xxstring)) < 0) return(x); switch (tt_kb_mode) { case KBM_EM: s = "emacs"; break; case KBM_HE: s = "hebrew"; break; case KBM_RU: s = "russian"; break; case KBM_EN: default: s = "default"; break; } if ((z = cmkey(shokeymtab,nshokeym,"Which definition should be shown?", s,xxstring)) < 0) return(z); if (z == SHKEYDEF) z = -1; #endif /* OS2 */ if ((y = cmcfm()) < 0) return(y); #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ #ifdef MAC printf("Not implemented\n"); return(0); #else /* Not MAC */ #ifdef OS2 if (x) { con_event evt; for (c = 0; c < KMSIZE; c++) { evt = (z < 0) ? mapkey(c) : maptermkey(c,z); if (evt.type != error) { shokeycode(c,z); } } } else { #endif /* OS2 */ printf(" Press key: "); #ifdef UNIX #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ #endif /* UNIX */ conbin((char)escape); /* Put terminal in binary mode */ #ifdef OS2 os2gks = 0; /* Raw scancode processing */ #endif /* OS2 */ c = congks(0); /* Get character or scan code */ #ifdef OS2 os2gks = 1; /* Cooked scancode processing */ #endif /* OS2 */ concb((char)escape); /* Restore terminal to cbreak mode */ if (c < 0) { /* Check for error */ printf("?Error reading key\n"); return(0); } #ifndef OS2 /* Do NOT mask when it can be a raw scan code, perhaps > 255 */ c &= cmdmsk; /* Apply command mask */ #endif /* OS2 */ printf("\n"); #ifdef OS2 shokeycode(c,z); #else /* OS2 */ shokeycode(c); #endif /* OS2 */ #ifdef OS2 } #endif /* OS2 */ return(1); #endif /* MAC */ } #ifndef NOKVERBS if (x == SHKVB) { /* SHOW KVERBS */ if ((y = cmcfm()) < 0) return(y); #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ printf("\nThe following %d keyboard verbs are available:\n\n",nkverbs); kwdhelp(kverbs,nkverbs,"","\\K","",3,0); printf("\n"); return(1); } #ifdef OS2 if (x == SHUDK) { /* SHOW UDKs */ extern void showudk(void); if ((y = cmcfm()) < 0) return(y); #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ showudk(); return(1); } #endif /* OS2 */ #endif /* NOKVERBS */ #endif /* NOSETKEY */ #ifndef NOSPL if (x == SHMAC) { /* SHOW MACRO */ struct FDB kw, fl, cm; int i, k, n = 0, left, flag, confirmed = 0; char * p, *q[64]; for (i = 0; i < nmac; i++) { /* copy the macro table */ mackey[i].kwd = mactab[i].kwd; /* into a regular keyword table */ mackey[i].kwval = i; /* with value = pointer to macro tbl */ mackey[i].flgs = mactab[i].flgs; } p = line; left = LINBUFSIZ; while (!confirmed && n < 64) { cmfdbi(&kw, /* First FDB - macro table */ _CMKEY, /* fcode */ "Macro name", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nmac, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ mackey, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* 2nd FDB - something not in mactab */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, &cm ); cmfdbi(&cm, /* 3rd FDB - Confirmation */ _CMCFM, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, NULL, NULL ); x = cmfdb(&kw); /* Parse something */ if (x < 0) return(x); s = atmbuf; /* What the user typed */ switch (cmresult.fcode) { case _CMKEY: /* If it was a keyword */ y = mlook(mactab,atmbuf,nmac); /* get full name */ if (y > -1) s = mactab[y].kwd; /* (fall thru on purpose...) */ case _CMFLD: k = ckstrncpy(p,s,left) + 1; /* Copy result to list */ left -= k; if (left <= 0) { *p = NUL; break; } q[n++] = p; /* Point to this item */ p += k; /* Move buffer pointer past it */ break; case _CMCFM: /* End of command */ confirmed++; default: break; } } if (n == 0) { printf("Macros:\n"); slc = 1; for (y = 0; y < nmac; y++) if (shomac(mactab[y].kwd,mactab[y].mval) < 0) break; return(1); } slc = 0; for (i = 0; i < n; i++) { flag = 0; s = q[i]; if (!s) s = ""; if (!*s) continue; if (iswild(s)) { /* Pattern match */ for (k = 0, x = 0; x < nmac; x++) { if (ckmatch(s,mactab[x].kwd,0,1)) { shomac(mactab[x].kwd,mactab[x].mval); k++; } } if (!k) x = -1; else continue; } else { /* Exact match */ x = mxlook(mactab,s,nmac); flag = 1; } if (flag && x == -1) x = mlook(mactab,s,nmac); switch (x) { case -3: /* Nothing to look up */ case -1: /* Not found */ printf("%s - (not defined)\n",s); break; case -2: /* Ambiguous, matches more than one */ printf("%s - ambiguous\n",s); break; default: /* Matches one exactly */ shomac(mactab[x].kwd,mactab[x].mval); break; } } return(1); } #endif /* NOSPL */ /* Other SHOW commands only have two fields. Get command confirmation here, then handle with big switch() statement. */ #ifndef NOSPL if (x != SHBUI && x != SHARR) { #endif /* NOSPL */ if (x == SHFUN) { /* For SHOW FUNCTIONS */ int y; if ((y = cmtxt("Match string for function names","",&s,NULL)) < 0) { return(y); } fnbuf[0] = NUL; if (!s) { s = ""; } if (*s) { ckstrncpy(fnbuf,s,100); } } else { y = cmcfm(); if (y < 0) { return(y); } } #ifndef NOSPL } #endif /* NOSPL */ #ifdef COMMENT /* This restriction is too general. */ #ifdef IKSD if (inserver && #ifdef CK_LOGIN isguest #else 0 #endif /* CK_LOGIN */ ) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ #endif /* COMMENT */ switch (x) { #ifdef ANYX25 #ifndef IBMX25 case SHPAD: shopad(0); break; #endif /* IBMX25 */ #endif /* ANYX25 */ case SHNET: #ifdef NOLOCAL printf(" No network support in this version of C-Kermit.\n"); #else #ifndef NETCONN printf(" No network support in this version of C-Kermit.\n"); #else shonet(); #endif /* NETCONN */ #endif /* NOLOCAL */ break; case SHPAR: shopar(); break; #ifndef NOXFER case SHATT: shoatt(); break; #endif /* NOXFER */ #ifndef NOSPL case SHCOU: printf(" %d\n",count[cmdlvl]); break; #endif /* NOSPL */ #ifndef NOSERVER case SHSER: /* Show Server */ i = 0; #ifndef NOFRILLS printf("Function: Status:\n"); i++; printf(" GET %s\n",nm[en_get]); i++; printf(" SEND %s\n",nm[en_sen]); i++; printf(" MAIL %s\n",nm[inserver ? 0 : en_mai]); i++; printf(" PRINT %s\n",nm[inserver ? 0 : en_pri]); i++; #ifndef NOSPL printf(" REMOTE ASSIGN %s\n",nm[en_asg]); i++; #endif /* NOSPL */ printf(" REMOTE CD/CWD %s\n",nm[en_cwd]); i++; #ifdef ZCOPY printf(" REMOTE COPY %s\n",nm[en_cpy]); i++; #endif /* ZCOPY */ printf(" REMOTE DELETE %s\n",nm[en_del]); printf(" REMOTE DIRECTORY %s\n",nm[en_dir]); printf(" REMOTE HOST %s\n",nm[inserver ? 0 : en_hos]); i += 3; #ifndef NOSPL printf(" REMOTE QUERY %s\n",nm[en_que]); i++; #endif /* NOSPL */ printf(" REMOTE MKDIR %s\n",nm[en_mkd]); printf(" REMOTE RMDIR %s\n",nm[en_rmd]); printf(" REMOTE RENAME %s\n",nm[en_ren]); printf(" REMOTE SET %s\n",nm[en_set]); printf(" REMOTE SPACE %s\n",nm[en_spa]); printf(" REMOTE TYPE %s\n",nm[en_typ]); printf(" REMOTE WHO %s\n",nm[inserver ? 0 : en_who]); printf(" BYE %s\n",nm[en_bye]); printf(" FINISH %s\n",nm[en_fin]); printf(" EXIT %s\n",nm[en_xit]); printf(" ENABLE %s\n",nm[en_ena]); i += 11; #endif /* NOFRILLS */ if (i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; } printf("Server timeout: %d\n",srvtim); if (++i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; } printf("Server idle-timeout: %d\n",srvidl); if (++i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; } printf("Server keepalive %s\n", showoff(srvping)); if (++i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; } printf("Server cd-message %s\n", showoff(srvcdmsg)); if (srvcdmsg && cdmsgstr) printf("Server cd-message %s\n", cdmsgstr); if (++i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; } printf("Server display: %s\n", showoff(srvdis)); if (++i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; } printf("Server login: "); if (!x_user) { printf("(none)\n"); } else { printf("\"%s\", \"%s\", \"%s\"\n", x_user, x_passwd ? x_passwd : "", x_acct ? x_acct : "" ); } if (++i > cmd_rows - 3) { if (!askmore()) return(1); else i = 0; } printf("Server get-path: "); if (ngetpath == 0) { printf(" (none)\n"); } else { printf("\n"); i += 3; for (x = 0; x < ngetpath; x++) { if (getpath[x]) printf(" %d. %s\n", x, getpath[x]); if (++i > (cmd_rows - 3)) { /* More than a screenful... */ if (!askmore()) break; else i = 0; } } } break; #endif /* NOSERVER */ case SHSTA: /* Status of last command */ printf(" %s\n", success ? "SUCCESS" : "FAILURE"); return(0); /* Don't change it */ case SHSTK: { /* Stack for MAC debugging */ #ifdef MAC long sp; sp = -1; loadA0 ((char *)&sp); /* set destination address */ SPtoaA0(); /* move SP to destination */ printf("Stack at 0x%x\n", sp); show_queue(); /* more debugging */ break; #else shostack(); #endif /* MAC */ break; } #ifndef NOLOCAL #ifdef OS2 case SHTAB: /* SHOW TABS */ #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ shotabs(); break; #endif /* OS2 */ case SHTER: /* SHOW TERMINAL */ #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ shotrm(); break; #ifdef OS2 case SHVSCRN: /* SHOW Virtual Screen - for debug */ shovscrn(); break; #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef OS2MOUSE case SHMOU: /* SHOW MOUSE */ #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ shomou(); break; #endif /* OS2MOUSE */ #ifndef NOFRILLS case SHVER: shover(); break; #endif /* NOFRILLS */ #ifndef NOSPL case SHBUI: /* Built-in variables */ line[0] = NUL; if ((y = cmtxt("Variable name or pattern","",&s,xxstring)) < 0) return(y); ckstrncpy(line,s,LINBUFSIZ); /* if (line[0]) ckstrncat(line,"*",LINBUFSIZ); */ case SHFUN: /* or built-in functions */ #ifdef CK_TTGWSIZ #ifdef OS2 if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0) ttgwsiz(); #else /* OS2 */ if (ttgwsiz() > 0) { /* Get current screen size */ if (tt_rows > 0 && tt_cols > 0) { cmd_rows = tt_rows; cmd_cols = tt_cols; } } #endif /* OS2 */ #endif /* CK_TTGWSIZ */ if (x == SHFUN) { /* Functions */ printf("\nThe following functions are available:\n\n"); kwdhelp(fnctab,nfuncs,(char *)fnbuf,"\\F","()",3,8); printf("\n"); #ifndef NOHELP printf( "HELP FUNCTION gives the calling conventions of the given function.\n\n" ); #endif /* NOHELP */ break; } else { /* Variables */ int j, flag = 0, havearg = 0; struct stringarray * q = NULL; char ** pp; if (line[0]) { /* Have something to search for */ havearg = 1; /* Maybe a list of things */ q = cksplit(1,0,line,NULL,"_-^$*?[]{}",0,0,0,0); if (!q) break; pp = q->a_head; } i = 0; for (y = 0; y < nvars; y++) { if ((vartab[y].flgs & CM_INV)) continue; if (havearg) { /* If I have something to match */ char * s2; for (flag = 0, j = 1; j <= q->a_size && !flag; j++) { s2 = pp[j] ? pp[j] : ""; #ifdef COMMENT /* This is not needed because it's what the 4 arg does in ckmatch() */ len = strlen(s2); if (len > 0) { if (s2[len-1] != '$') {/* To allow anchors */ ckmakmsg(line,LINBUFSIZ,pp[j],"*",NULL,NULL); s2 = line; } } #endif /* COMMENT */ if (ckmatch(s2,vartab[y].kwd,0,4) > 0) { flag = 1; /* Matches */ break; } } if (!flag) /* Doesn't match */ continue; } s = nvlook(vartab[y].kwd); printf(" \\v(%s) = ",vartab[y].kwd); if (vartab[y].kwval == VN_NEWL) { /* \v(newline) */ while (*s) /* Show control chars symbolically */ printf("\\{%d}",*s++); printf("\n"); } else if (vartab[y].kwval == VN_IBUF || /* \v(input) */ vartab[y].kwval == VN_QUE || /* \v(query) */ #ifdef OS2 vartab[y].kwval == VN_SELCT || /* \v(select) */ #endif /* OS2 */ (vartab[y].kwval >= VN_M_AAA && /* modem ones */ vartab[y].kwval <= VN_M_ZZZ) ) { int r = 12; /* This one can wrap around */ char buf[10]; while (*s) { if (isprint(*s)) { buf[0] = *s; buf[1] = NUL; r++; } else { sprintf(buf,"\\{%d}",*s); /* SAFE */ r += (int) strlen(buf); } if (r >= cmd_cols - 1) { printf("\n"); r = 0; i++; } printf("%s",buf); s++; } printf("\n"); } else printf("%s\n",s); if (++i > (cmd_rows - 3)) { /* More than a screenful... */ if ((y >= nvars - 1) || !askmore()) break; else i = 0; } } } break; case SHVAR: /* Global variables */ x = 0; /* Variable count */ slc = 1; /* Screen line count for "more?" */ for (y = 33; y < GVARS; y++) if (g_var[y]) { if (x++ == 0) printf("Global variables:\n"); sprintf(line," \\%%%c",y); /* SAFE */ if (shomac(line,g_var[y]) < 0) break; } if (!x) printf(" No variables defined\n"); break; case SHARG: { /* Args */ char * s1, * s2; if (maclvl > -1) { printf("Macro arguments at level %d (\\v(argc) = %d):\n", maclvl, macargc[maclvl] ); for (y = 0; y < macargc[maclvl]; y++) { s1 = m_arg[maclvl][y]; if (!s1) s1 = "(NULL)"; s2 = m_xarg[maclvl][y]; if (!s2) s2 = "(NULL)"; #ifdef COMMENT if (y < 10) printf(" \\%%%d = %s\n",y,s1); else printf(" \\&_[%d] = %s\n",y,s2); #else printf(" \\&_[%d] = %s\n",y,s2); #endif /* COMMENT */ } } else { printf("Top-level arguments (\\v(argc) = %d):\n", topargc); for (y = 0; y < topargc; y++) { s1 = g_var[y + '0']; if (!s1) s1 = "(NULL)"; s2 = toparg[y]; if (!s2) s2 = "(NULL)"; if (y < 10 && g_var[y]) printf(" \\%%%d = %s\n",y,s1); if (toparg[y]) printf(" \\&_[%d] = %s\n",y,s2); } } } break; case SHARR: /* Arrays */ return(showarray()); #endif /* NOSPL */ #ifndef NOXFER case SHPRO: /* Protocol parameters */ shoparp(); printf("\n"); break; #endif /* NOXFER */ #ifndef NOLOCAL case SHCOM: /* Communication parameters */ printf("\n"); shoparc(); #ifdef OS2 { int i; char *s = "(unknown)"; for (i = 0; i < nprty; i++) if (prtytab[i].kwval == priority) { s = prtytab[i].kwd; break; } printf(" Priority: %s\n", s ); } #endif /* OS2 */ printf("\n"); #ifdef NETCONN if (!network #ifdef IKSD && !inserver #endif /* IKSD */ ) { #endif /* NETCONN */ shomdm(); printf("\n"); #ifdef NETCONN } #endif /* NETCONN */ #ifndef NODIAL #ifdef IKSD if ( !inserver ) #endif /* IKSD */ { printf("Type SHOW DIAL to see DIAL-related items.\n"); printf("Type SHOW MODEM to see modem-related items.\n"); #ifdef CK_TAPI printf("Type SHOW TAPI to see TAPI-related items.\n"); #endif /* CK_TAPI */ printf("\n"); } #endif /* NODIAL */ break; #endif /* NOLOCAL */ case SHFIL: /* File parameters */ shofil(); /* printf("\n"); */ /* (out o' space) */ break; #ifndef NOCSETS case SHLNG: /* Languages */ shoparl(); break; #endif /* NOCSETS */ #ifndef NOSPL case SHSCR: /* Scripts */ printf(" Command quoting: %s\n", showoff(cmdgquo())); printf(" Take echo: %s\n", showoff(techo)); printf(" Take error: %s\n", showoff(takerr[cmdlvl])); printf(" Macro echo: %s\n", showoff(mecho)); printf(" Macro error: %s\n", showoff(merror[cmdlvl])); printf(" Quiet: %s\n", showoff(quiet)); printf(" Variable evaluation: %s [\\%%x and \\&x[] variables]\n", vareval ? "recursive" : "simple"); printf(" Function diagnostics: %s\n", showoff(fndiags)); printf(" Function error: %s\n", showoff(fnerror)); #ifdef CKLEARN { extern char * learnfile; extern int learning; if (learnfile) { printf(" LEARN file: %s (%s)\n", learnfile, learning ? "ON" : "OFF" ); } else printf(" LEARN file: (none)\n"); } #endif /* CKLEARN */ shoinput(); shooutput(); #ifndef NOSCRIPT printf(" Script echo: %s\n", showoff(secho)); #endif /* NOSCRIPT */ printf(" Command buffer length: %d\n", CMDBL); printf(" Atom buffer length: %d\n", ATMBL); break; #endif /* NOSPL */ #ifndef NOXMIT case SHXMI: printf("\n"); printf(" File type: %s\n", binary ? "binary" : "text"); #ifndef NOCSETS printf(" File character-set: %s\n", fcsinfo[fcharset].keyword); #ifdef OS2 if ( ck_isunicode() ) { printf(" Terminal Character (remote): %s\n", tt_utf8 ? "utf-8" : tcsr == TX_TRANSP ? "transparent" : tcsr == TX_UNDEF ? "undefined" : txrinfo[tcsr]->keywd); printf(" Terminal Character (local): %s\n", tcsl == TX_TRANSP ? "transparent" : tcsl == TX_UNDEF ? "undefined" : txrinfo[tcsl]->keywd); } else { printf(" Terminal Character (remote): %s\n", tt_utf8 ? "utf-8" : tcsr == TX_TRANSP ? "transparent" : tcsr == TX_UNDEF ? "undefined" : txrinfo[tcsr]->keywd); printf(" Terminal Character (local): %s\n", tcsl == TX_TRANSP ? "transparent" : tcsl == TX_UNDEF ? "undefined" : txrinfo[tcsl]->keywd); } #else /* OS2 */ printf(" Terminal character-set (remote): %s\n", fcsinfo[tcsr].keyword); printf(" Terminal character-set (local): %s\n", fcsinfo[tcsl].keyword); #endif /* OS2 */ #endif /* NOCSETS */ printf(" Terminal bytesize: %d\n", (cmask == 0xff) ? 8 : 7); printf(" Terminal echo: %s\n", duplex ? "local" : "remote"); printf(" Transmit EOF: "); if (*xmitbuf == NUL) { printf("(none)\n"); } else { char *p; p = xmitbuf; while (*p) { if (*p < SP) printf("^%c",ctl(*p)); else printf("%c",*p); p++; } printf("\n"); } if (xmitf) printf(" Transmit Fill: %d\n", xmitf); else printf(" Transmit Fill: (none)\n"); printf(" Transmit Linefeed: %s\n",showoff(xmitl)); if (xmitp) printf(" Transmit Prompt: %d (%s)\n", xmitp, chartostr(xmitp) ); else printf(" Transmit Prompt: (none)\n"); printf(" Transmit Echo: %s\n", showoff(xmitx)); printf(" Transmit Locking-Shift: %s\n", showoff(xmits)); printf(" Transmit Pause: %d (millisecond%s)\n", xmitw, (xmitw == 1) ? "" : "s" ); printf(" Transmit Timeout: %d (second%s)\n", xmitt, (xmitt == 1) ? "" : "s" ); printf("\n"); break; #endif /* NOXMIT */ #ifndef NODIAL case SHMOD: /* SHOW MODEM */ #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ shomodem(); /* Show SET MODEM items */ break; #endif /* NODIAL */ #ifndef MAC case SHDFLT: printf("%s\n",zgtdir()); break; #endif /* MAC */ #ifndef NOLOCAL case SHESC: #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ return(shoesc(escape)); #ifndef NODIAL case SHDIA: /* SHOW DIAL */ #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ shmdmlin(); printf(", speed: "); if ((zz = ttgspd()) < 0) { printf("unknown"); } else { if (zz == 8880) printf("75/1200"); else printf("%ld",zz); } if (carrier == CAR_OFF) s = "off"; else if (carrier == CAR_ON) s = "on"; else if (carrier == CAR_AUT) s = "auto"; else s = "unknown"; printf(", carrier: %s", s); if (carrier == CAR_ON) { if (cdtimo) printf(", timeout: %d sec", cdtimo); else printf(", timeout: none"); } printf("\n"); doshodial(); if (local #ifdef NETCONN && !network #endif /* NETCONN */ ) { printf("Type SHOW MODEM to see modem settings.\n"); #ifdef CK_TAPI printf("Type SHOW TAPI to see TAPI-related items\n"); #endif /* CK_TAPI */ printf("Type SHOW COMMUNICATIONS to see modem signals.\n"); } break; #endif /* NODIAL */ #endif /* NOLOCAL */ #ifndef NOXFER #ifdef CK_LABELED case SHLBL: /* Labeled file info */ sholbl(); break; #endif /* CK_LABELED */ #endif /* NOXFER */ case SHCSE: /* Character sets */ #ifdef NOCSETS printf( " Character set translation is not supported in this version of C-Kermit\n"); #else shocharset(); #ifndef NOXFER printf("\n Unknown-Char-Set: %s\n", unkcs ? "Keep" : "Discard"); #endif /* NOXFER */ #ifdef OS2 printf("\n"); #endif /* OS2 */ shotcs(tcsl,tcsr); printf("\n"); #ifdef OS2 /* PC Code Page information */ { char cpbuf[128]; int cplist[16], cps; int activecp; cps = os2getcplist(cplist, sizeof(cplist)); sprintf(cpbuf, /* SAFE */ "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d", cps > 1 ? cplist[1] : 0, cps > 2 ? cplist[2] : 0, cps > 3 ? cplist[3] : 0, cps > 4 ? cplist[4] : 0, cps > 5 ? cplist[5] : 0, cps > 6 ? cplist[6] : 0, cps > 7 ? cplist[7] : 0, cps > 8 ? cplist[8] : 0, cps > 9 ? cplist[9] : 0, cps > 10 ? cplist[10] : 0, cps > 11 ? cplist[11] : 0, cps > 12 ? cplist[12] : 0 ); printf(" Code Pages:\n"); activecp = os2getcp(); if ( activecp ) { printf(" Active: %d\n",activecp); if (!isWin95()) printf(" Available: %s\n",cpbuf); } else printf(" Active: n/a\n"); printf("\n"); } #endif /* OS2 */ #endif /* NOCSETS */ break; case SHFEA: /* Features */ shofea(); break; #ifdef CK_SPEED case SHCTL: /* Control-Prefix table */ shoctl(); break; #endif /* CK_SPEED */ case SHEXI: { extern int exithangup, exitmsg; printf("\n Exit warning %s\n", xitwarn ? (xitwarn == 1 ? "on" : "always") : "off"); printf(" Exit message: %s\n", exitmsg ? (exitmsg == 1 ? "on" : "stderr") : "off"); printf(" Exit on-disconnect: %s\n", showoff(exitonclose)); printf(" Exit hangup: %s\n", showoff(exithangup)); printf(" Current exit status: %d\n\n", xitsta); break; } case SHPRT: { #ifdef PRINTSWI extern int printtimo, printertype, noprinter; extern char * printterm, * printsep; extern int prncs; #ifdef BPRINT extern int printbidi; #endif /* BPRINT */ #endif /* PRINTSWI */ #ifdef IKSD if (inserver && #ifdef CK_LOGIN isguest #else /* CK_LOGIN */ 0 #endif /* CK_LOGIN */ ) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ #ifdef PRINTSWI if (noprinter) { printf("Printer: (none)\n\n"); break; } #endif /* PRINTSWI */ printf("Printer: %s%s\n", printpipe ? "| " : "", printername ? printername : #ifdef OS2 "PRN" #else "(default)" #endif /* OS2 */ ); #ifdef PRINTSWI #ifdef BPRINT if (printbidi) { printf(" /BIDIRECTIONAL\n"); if (pportspeed > 0) printf(" /SPEED:%ld\n",pportspeed); printf(" /PARITY:%s\n",parnam((char)pportparity)); printf(" /FLOW:%s\n", pportflow == FLO_NONE ? "NONE" : (pportflow == FLO_RTSC ? "RTS/CTS" : "XON/XOFF") ); } else printf(" /OUTPUT-ONLY\n"); #endif /* BPRINT */ switch (printertype) { case PRT_NON: printf(" /NONE\n"); break; case PRT_FIL: printf(" /FILE\n"); break; case PRT_PIP: printf(" /PIPE\n"); break; case PRT_DOS: printf(" /DOS-DEVICE\n"); break; case PRT_WIN: printf(" /WINDOWS-QUEUE\n"); break; } printf(" /TIMEOUT:%d\n",printtimo); if (printterm) { printf(" /END-OF-JOB-STRING:"); shostrdef(printterm); printf("\n"); } else printf(" /END-OF-JOB-STRING:(none)\n"); printf(" /JOB-HEADER-FILE:%s\n",printsep ? printsep : "(none)"); printf(" /CHARACTER-SET: %s\n",txrinfo[prncs]->keywd); #endif /* PRINTSWI */ printf("\n"); break; } case SHCMD: { #ifdef DOUBLEQUOTING extern int dblquo; #endif /* DOUBLEQUOTING */ #ifdef CK_AUTODL printf(" Command autodownload: %s\n",showoff(cmdadl)); #else printf(" Command autodownload: (not available)\n"); #endif /* CK_AUTODL */ printf(" Command bytesize: %d bits\n", (cmdmsk == 0377) ? 8 : 7); printf(" Command error-display: %d\n", cmd_err); #ifdef CK_RECALL printf(" Command recall-buffer-size: %d\n",cm_recall); #else printf(" Command recall-buffer not available in this version\n"); #endif /* CK_RECALL */ #ifdef CK_RECALL printf(" Command retry: %s\n",showoff(cm_retry)); #else printf(" Command retry not available in this version\n"); #endif /* CK_RECALL */ printf(" Command interruption: %s\n", showoff(cmdint)); printf(" Command quoting: %s\n", showoff(cmdgquo())); #ifdef DOUBLEQUOTING printf(" Command doublequoting: %s\n", showoff(dblquo)); #endif /* DOUBLEQUOTING */ printf(" Command more-prompting: %s\n", showoff(xaskmore)); printf(" Command height: %d\n", cmd_rows); printf(" Command width: %d\n", cmd_cols); #ifndef IKSDONLY #ifdef OS2 printf(" Command statusline: %s\n",showoff(tt_status[VCMD])); #endif /* OS2 */ #endif /* IKSDONLY */ #ifdef LOCUS printf(" Locus: %s", autolocus ? (autolocus == 2 ? "ask" : "auto") : (locus ? "local" : "remote")); if (autolocus) printf(" (%s)", locus ? "local" : "remote"); printf("\n"); #endif /* LOCUS */ printf(" Hints: %s\n", showoff(hints)); printf(" Quiet: %s\n", showoff(quiet)); printf(" Maximum command length: %d\n", CMDBL); #ifndef NOSPL { char * s; int k; printf(" Maximum number of macros: %d\n", MAC_MAX); printf(" Macros defined: %d\n", nmac); printf(" Maximum macro depth: %d\n", MACLEVEL); printf(" Maximum TAKE depth: %d\n", MAXTAKE); s = "(not defined)"; k = mlook(mactab,"on_unknown_command",nmac); if (k > -1) if (mactab[k].mval) s = mactab[k].mval; printf(" ON_UNKNOWN_COMMAND: %s\n",s); } #endif /* NOSPL */ #ifdef UNIX #ifndef NOJC printf(" Suspend: %s\n", showoff(xsuspend)); #endif /* NOJC */ #endif /* UNIX */ printf(" Access to external commands and programs%s allowed\n", #ifndef NOPUSH !nopush ? "" : #endif /* NOPUSH */ " not"); break; } #ifndef NOSPL case SHALRM: if (ck_alarm) printf("Alarm at %s %s\n",alrm_date,alrm_time); else printf("(no alarm set)\n"); break; #endif /* NOSPL */ #ifdef VMS char *rec_fmt; case SHOVMSTXT: if (vms_text == VMSTFS) { rec_fmt = "Stream_LF"; } else if (vms_text == VMSTFV) { rec_fmt = "Variable"; } else { rec_fmt = "(Unknown?)"; } printf("VMS text-file record format: %s\n", rec_fmt); break; #endif /* VMS */ #ifndef NOMSEND case SHSFL: { extern struct filelist * filehead; if (!filehead) { printf("send-list is empty\n"); } else { struct filelist * flp; char * s; flp = filehead; while (flp) { s = flp->fl_alias; if (!s) s = "(none)"; printf("%s, mode: %s, alias: %s\n", flp->fl_name, gfmode(flp->fl_mode,0), s ); flp = flp->fl_next; } } } break; #endif /* NOMSEND */ #ifdef CKXXCHAR case SHDBL: shodbl(); break; #endif /* CKXXCHAR */ #ifndef NOPUSH #ifndef NOFRILLS case SHEDIT: if (!editor[0]) { s = getenv("EDITOR"); if (s) ckstrncpy(editor,s,CKMAXPATH); } printf("\n editor: %s\n", editor[0] ? editor : "(none)"); if (editor[0]) { printf(" options: %s\n", editopts[0] ? editopts : "(none)"); printf(" file: %s\n", editfile[0] ? editfile : "(none)"); } printf("\n"); break; #ifdef BROWSER case SHBROWSE: if (!browser[0]) { s = getenv("BROWSER"); if (s) ckstrncpy(browser,s,CKMAXPATH); } printf("\n browser: %s\n", browser[0] ? browser : "(none)"); if (browser[0]) { printf(" options: %s\n", browsopts[0] ? browsopts : "(none)"); printf(" url: %s\n", browsurl[0] ? browsurl : "(none)"); } printf("\n"); break; #endif /* BROWSER */ #endif /* NOFRILLS */ #endif /* NOPUSH */ #ifndef NOLOCAL #ifdef CK_TAPI case SHTAPI: /* TAPI options */ #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ shotapi(0); break; case SHTAPI_L: /* TAPI Locations */ #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ shotapi(1); break; case SHTAPI_M: /* TAPI Modem */ #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ shotapi(2); break; case SHTAPI_C: /* TAPI Comm */ #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ shotapi(3); break; #endif /* CK_TAPI */ case SHTCP: /* SHOTCP */ printf("\n"); shotcp(0); printf("\n"); break; #ifdef TNCODE case SHTEL: /* TELNET */ printf("\n"); shotel(0); printf("\n"); break; case SHTOPT: /* TELNET OPTIONS */ printf("\n"); shotopt(0); printf("\n"); break; #endif /* TNCODE */ case SHOTMPDIR: /* TEMPORARY DIRECTORY */ { extern char * tempdir; if (!tempdir) { printf(" (none)\n"); } else if (!*tempdir) { printf(" (none)\n"); } else { printf(" %s\n", tempdir); } break; } #ifdef CK_TRIGGER case SHTRIG: { extern char * tt_trigger[], * triggerval; int i; if (!tt_trigger[0]) { printf(" Triggers: (none)\n"); } else { printf(" Triggers:\n"); for (i = 0; i < TRIGGERS; i++) { if (!tt_trigger[i]) break; printf(" \"%s\"\n",tt_trigger[i]); } printf(" Most recent trigger encountered: "); if (triggerval) printf("\"%s\"\n",triggerval); else printf("(none)\n"); } break; } #endif /* CK_TRIGGER */ #endif /* NOLOCAL */ #ifndef NOSPL case SHINP: shoinput(); break; #endif /* NOSPL */ case SHLOG: { #ifndef MAC #ifdef IKSD if (inserver && #ifdef CK_LOGIN isguest #else /* CK_LOGIN */ 0 #endif /* CK_LOGIN */ ) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ #ifdef DEBUG printf("\n Debug log: %s", deblog ? debfil : "(none)"); { extern int debtim; if (debtim) printf(" (timestamps)"); printf("\n"); } #endif /* DEBUG */ #ifndef NOXFER printf(" Packet log: %s\n", pktlog ? pktfil : "(none)"); #endif /* NOXFER */ #ifndef NOLOCAL printf(" Session log: %s", seslog ? sesfil : "(none)"); { extern int sessft, slogts, slognul; switch (sessft) { case XYFT_T: printf(" (text)"); break; case XYFT_B: printf(" (binary)"); break; case XYFT_D: printf(" (debug)"); break; } if (slogts) printf("(timestamped)"); if (slognul) printf("(null-padded)"); printf("\n"); } #endif /* NOLOCAL */ #ifdef TLOG printf(" Transaction log: %s (%s)\n", (tralog ? (*trafil ? trafil : "(none)") : "(none)"), (tlogfmt ? ((tlogfmt == 2) ? "ftp" : "verbose") : "brief") ); #endif /* TLOG */ #ifdef CKLOGDIAL printf(" Connection log: %s\n", dialog ? diafil : "(none)"); #endif /* CKLOGDIAL */ printf("\n"); #endif /* MAC */ break; } #ifndef NOSPL case SHOUTP: /* OUTPUT */ shooutput(); break; #endif /* NOSPL */ #ifdef PATTERNS case SHOPAT: /* PATTERNS */ shopat(); break; #endif /* PATTERNS */ #ifdef STREAMING case SHOSTR: { /* STREAMING */ extern int streamrq, clearrq, cleared; extern long tfcps; debug(F101,"SHOW RELIABLE reliable","",reliable); printf("\n Reliable: %s\n",showooa(reliable)); printf(" Clearchannel: %s\n",showooa(clearrq)); printf(" Streaming: %s\n\n",showooa(streamrq)); if ((!local && (streamrq == SET_ON)) || (streamrq == SET_AUTO && reliable)) printf(" Streaming will be done if requested.\n"); else if ((streamrq == SET_OFF) || ((streamrq == SET_AUTO) && !reliable)) printf(" Streaming will not be requested and will not be done.\n"); else if ((streamrq == SET_ON) || ((streamrq == SET_AUTO) && reliable)) printf( " Streaming will be requested and will be done if the other Kermit agrees.\n"); printf(" Last transfer: %sstreaming%s, %ld cps.\n", streamed > 0 ? "" : "no ", cleared ? ", clearchannel" : "", tfcps ); printf("\n"); break; } #endif /* STREAMING */ #ifdef ISKD case SHOIKS: return(sho_iks()); break; #endif /* IKSD */ #ifdef CK_AUTHENTICATION case SHOAUTH: return(sho_auth(0)); #endif /* CK_AUTHENTICATION */ #ifndef NOFTP case SHOFTP: { #ifdef IKSD if (inserver) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ #ifdef SYSFTP { extern char ftpapp[], ftpopts[]; printf(" ftp-client: %s\n", ftpapp[0] ? ftpapp : "(none)"); if (ftpapp[0]) printf(" ftp options: %s\n", ftpopts[0] ? ftpopts : "(none)"); } #else #ifdef NEWFTP shoftp(0); #else printf("(No FTP client included in this version of Kermit.)\n"); #endif /* NEWFTP */ #endif /* SYSFTP */ break; } #endif /* NOFTP */ #ifndef NOCMDL case SHXOPT: { #ifdef IKSDB extern int dbenabled; extern char * dbfile, * dbdir; #endif /* IKSDB */ #ifdef CKWTMP extern int ckxwtmp; extern char * wtmpfile; #endif /* CKWTMP */ #ifdef CK_LOGIN extern int ckxanon, xferlog, logintimo; extern char * xferfile; #ifdef UNIX extern int ckxpriv; #endif /* UNIX */ #ifdef CK_PERMS extern int ckxperms; #endif /* CK_PERMS */ #endif /* CK_LOGIN */ extern char * bannerfile, * helpfile; #ifdef IKSD if (inserver && #ifdef CK_LOGIN isguest #else /* CK_LOGIN */ 0 #endif /* CK_LOGIN */ ) { printf("Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ printf("\n"); if (!cmdint) printf(" --nointerrupts\n"); printf(" --bannerfile=%s\n",bannerfile ? bannerfile : "(null)"); printf(" --cdfile:%s\n",cdmsgstr ? cdmsgstr : "(null)"); printf(" --cdmessage:%d\n",srvcdmsg); printf(" --helpfile:%s\n",helpfile); if (inserver) { printf("\n"); break; } #ifdef CKSYSLOG #ifdef SYSLOGLEVEL printf(" --syslog:%d (forced)\n",ckxsyslog); #else printf(" --syslog:%d\n",ckxsyslog); #endif /* SYSLOGLEVEL */ #endif /* CKSYSLOG */ #ifdef CKWTMP printf(" --wtmplog:%d\n",ckxwtmp); printf(" --wtmpfile=%s\n",wtmpfile ? wtmpfile : "(null)"); #endif /* CKWTMP */ #ifdef IKSD #ifdef CK_LOGIN printf(" --anonymous:%d\n",ckxanon); #ifdef UNIX printf(" --privid:%d\n",ckxpriv); #endif /* UNIX */ #ifdef CK_PERMS printf(" --permission:%04o\n",ckxperms); #endif /* CK_PERMS */ printf(" --initfile:%s\n",anonfile ? anonfile : "(null)"); printf(" --userfile:%s\n",userfile ? userfile : "(null)"); printf(" --root:%s\n",anonroot ? anonroot : "(null)"); printf(" --xferlog=%d\n",xferlog); printf(" --xferfile=%s\n",xferfile ? xferfile : "(null)"); printf(" --timeout=%d\n",logintimo); #endif /* CK_LOGIN */ #ifdef IKSDB printf(" --database=%d\n",dbenabled); printf(" --dbfile=%s\n",dbfile ? dbfile : "(null)"); if (dbdir) printf(" (db directory=[%s])\n",dbdir); #endif /* IKSDB */ #ifdef IKSDCONF printf(" IKSD conf=%s\n",iksdconf); #endif /* IKSDCONF */ #endif /* IKSD */ printf("\n"); break; } #endif /* NOCMDL */ case SHCD: { extern char * myhome; s = getenv("CDPATH"); if (!s) s = "(none)"; printf("\n current directory: %s\n", zgtdir()); printf(" previous directory: %s\n", prevdir ? prevdir : "(none)"); printf(" cd home: %s\n", homepath()); printf(" cd path: %s\n", ckcdpath ? ckcdpath : s); printf(" cd message: %s\n", showoff(srvcdmsg & 2)); printf(" server cd-message: %s\n", showoff(srvcdmsg & 1)); printf(" cd message file: %s\n\n",cdmsgstr ? cdmsgstr : "(none)"); break; } #ifndef NOCSETS case SHASSOC: (VOID) showassoc(); break; #endif /* NOCSETS */ #ifdef CKLOGDIAL case SHCONNX: #ifdef NEWFTP if (ftpisconnected()) { extern char cxlogbuf[]; dologshow(W_FTP | 1); if (cxlogbuf[0]) dologshow(1); } else { #endif /* NEWFTP */ dologshow(1); #ifdef NEWFTP } #endif /* NEWFTP */ break; #endif /* CKLOGDIAL */ case SHOPTS: optlines = 0; #ifndef NOFRILLS (VOID) showdelopts(); #endif /* NOFRILLS */ #ifdef DOMYDIR (VOID) showdiropts(); #endif /* DOMYDIR */ #ifdef CKPURGE (VOID) showpurgopts(); #endif /* CKPURGE */ (VOID) showtypopts(); break; #ifndef NOLOCAL case SHOFLO: (VOID) shoflow(); break; #endif /* NOLOCAL */ #ifndef NOXFER case SHOXFER: (VOID) shoxfer(); break; #endif /* NOXFER */ #ifdef CK_RECALL case SHHISTORY: (VOID) cmhistory(); break; #endif /* CK_RECALL */ #ifndef NOSEXP #ifndef NOSPL case SHSEXP: (VOID) shosexp(); break; #endif /* NOSPL */ #endif /* NOSEXP */ #ifdef ANYSSH case SHOSSH: (VOID) shossh(); break; #endif /* ANYSSH */ #ifdef KUI case SHOGUI: (VOID) shogui(); break; #endif /* KUI */ #ifndef NOFRILLS #ifndef NORENAME case SHOREN: (VOID) shorename(); break; #endif /* NORENAME */ #endif /* NOFRILLS */ case SHOLOC: { #ifdef HAVE_LOCALE char *s; extern int nolocale; printf("\n"); printf("Locale %s:\n", nolocale ? "disabled" : "enabled"); #ifdef COMMENT s = setlocale(LC_ALL, NULL); if (!s) s = ""; printf("LC_ALL=%s\n",s); #endif /* COMMENT */ s = setlocale(LC_COLLATE, NULL); if (!s) s = ""; printf(" LC_COLLATE=\"%s\"\n",s); s = setlocale(LC_CTYPE, NULL); if (!s) s = ""; printf(" LC_CTYPE=\"%s\"\n",s); s = setlocale(LC_MONETARY, NULL); if (!s) s = ""; printf(" LC_MONETARY=\"%s\"\n",s); s = setlocale(LC_MESSAGES, NULL); if (!s) s = ""; printf(" LC_MESSAGES=\"%s\"\n",s); s = setlocale(LC_NUMERIC, NULL); if (!s) s = ""; printf(" LC_NUMERIC=\"%s\"\n",s); s = setlocale(LC_TIME, NULL); if (!s) s = ""; printf(" LC_TIME=\"%s\"\n",s); printf(" LANG=\"%s\"\n",getenv("LANG")); printf("\n"); #else printf("\n"); printf(" Locale support is not included in this version of Kermit\n"); printf("\n"); #endif /* HAVE_LOCALE */ break; } default: printf("\nNothing to show...\n"); return(-2); } return(success = 1); } #ifndef NOXFER int shoatt() { printf("Attributes: %s\n", showoff(atcapr)); if (!atcapr) return(0); printf(" Blocksize: %s\n", showoff(atblki)); printf(" Date: %s\n", showoff(atdati)); printf(" Disposition: %s\n", showoff(atdisi)); printf(" Encoding (Character Set): %s\n", showoff(atenci)); printf(" Length: %s\n", showoff(atleni)); printf(" Type (text/binary): %s\n", showoff(attypi)); printf(" System ID: %s\n", showoff(atsidi)); printf(" System Info: %s\n", showoff(atsysi)); #ifdef CK_PERMS printf(" Permissions In: %s\n", showoff(atlpri)); printf(" Permissions Out: %s\n", showoff(atlpro)); #endif /* CK_PERMS */ #ifdef STRATUS printf(" Format: %s\n", showoff(atfrmi)); printf(" Creator: %s\n", showoff(atcrei)); printf(" Account: %s\n", showoff(atacti)); #endif /* STRATUS */ return(0); } #endif /* NOXFER */ #ifndef NOSPL int /* SHOW MACROS */ #ifdef CK_ANSIC shomac( char *s1, char *s2 ) #else shomac(s1, s2) char *s1, *s2; #endif /* CK_ANSIC */ { int x, n, pp; pp = 0; /* Parenthesis counter */ debug(F110,"shomac s1",s1,0); debug(F110,"shomac s2",s2,0); #ifdef IKSD if ( inserver && #ifdef IKSDCONF iksdcf #else /* IKSDCONF */ 1 #endif /* IKSDCONF */ ) { if (!ckstrcmp("on_exit",s1,-1,0) || !ckstrcmp("on_logout",s1,-1,0)) return(0); } #endif /* IKSD */ if (!s1) return(0); else printf("%s = ",s1); /* Print blank line and macro name */ n = (int)strlen(s1) + 4; /* Width of current line */ if (!s2) s2 = "(not defined)"; while ((x = *s2++)) { /* Loop thru definition */ if (x == '(') pp++; /* Treat commas within parens */ if (x == ')') pp--; /* as ordinary text */ if (pp < 0) pp = 0; /* Outside parens, */ if (x == ',' && pp == 0) { /* comma becomes comma-dash-NL. */ putchar(','); putchar('-'); x = '\n'; } if (inserver && (x == '\n')) /* Send CR before LF */ putchar(CK_CR); putchar((CHAR)x); /* Output the character */ if (x == '\n') { /* If it was a newline */ #ifdef UNIX #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ #endif /* UNIX */ putchar(' '); /* Indent the next line 1 space */ while(*s2 == ' ') s2++; /* skip past leading blanks */ n = 2; /* restart the character counter */ slc++; /* and increment the line counter. */ } else if (++n > (cmd_cols - 1)) { /* If line is too wide */ putchar('-'); /* output a dash */ if (inserver) putchar(CK_CR); /* and a carriage return */ putchar(NL); /* and a newline */ #ifdef UNIX #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ #endif /* UNIX */ n = 1; /* and restart the char counter */ slc++; /* and increment the line counter */ } if (n < 3 && slc > (cmd_rows - 3)) { /* If new line and screen full */ if (!askmore()) return(-1); /* ask if they want more. */ n = 1; /* They do, start a new line */ slc = 0; /* and restart line counter */ } } if (inserver) putchar(CK_CR); putchar(NL); /* End of definition */ if (++slc > (cmd_rows - 3)) { if (!askmore()) return(-1); slc = 0; } return(0); } #endif /* NOSPL */ #endif /* NOSHOW */ int x_ifnum = 0; /* Flag for IF NUMERIC active */ #ifndef NOSPL /* Evaluate an arithmetic expression. */ /* Code adapted from ev, by Howie Kaye of Columbia U & others. */ static int xerror = 0; int divbyzero = 0; static char *cp; static CK_OFF_T tokval; static char curtok; static CK_OFF_T expval; #define LONGBITS (8*sizeof (CK_OFF_T)) #define NUMBER 'N' #define N_EOT 'E' /* Replacement for strchr() and index(), neither of which seem to be universal. */ static char * #ifdef CK_ANSIC windex(char * s, char c) #else windex(s,c) char *s, c; #endif /* CK_ANSIC */ /* windex */ { while (*s != NUL && *s != c) s++; if (*s == c) return(s); else return(NULL); } /* g e t t o k Returns the next token. If token is a NUMBER, sets tokval appropriately. */ static char gettok() { char tbuf[80] /* ,*tp */ ; /* Buffer to accumulate number */ while (isspace(*cp)) /* Skip past leading spaces */ cp++; debug(F110,"GETTOK",cp,0); switch (*cp) { case '$': /* ??? */ case '+': /* Add */ case '-': /* Subtract or Negate */ case '@': /* Greatest Common Divisor */ case '*': /* Multiply */ case '/': /* Divide */ case '%': /* Modulus */ case '<': /* Left shift */ case '>': /* Right shift */ case '&': /* And */ case '|': /* Or */ case '#': /* Exclusive Or */ case '~': /* Not */ case '^': /* Exponent */ case '!': /* Factorial */ case '(': /* Parens for grouping */ case ')': return(*cp++); /* operator, just return it */ case '\n': case '\0': return(N_EOT); /* End of line, return that */ } #ifdef COMMENT /* This is the original code, which allows only integer numbers. */ if (isxdigit(*cp)) { /* Digit, must be a number */ int radix = 10; /* Default radix */ for (tp = tbuf; isxdigit(*cp); cp++) *tp++ = (char) (isupper(*cp) ? tolower(*cp) : *cp); *tp = '\0'; /* End number */ switch(isupper(*cp) ? tolower(*cp) : *cp) { /* Examine break char */ case 'h': case 'x': radix = 16; cp++; break; /* if radix signifier... */ case 'o': case 'q': radix = 8; cp++; break; case 't': radix = 2; cp++; break; } for (tp = tbuf, tokval = 0; *tp != '\0'; tp++) { int dig; dig = *tp - '0'; /* Convert number */ if (dig > 10) dig -= 'a'-'0'-10; if (dig >= radix) { if (cmdlvl == 0 && !x_ifnum && !xerror) printf("?Invalid digit '%c' in number\n",*tp); xerror = 1; return(NUMBER); } tokval = radix*tokval + dig; } return(NUMBER); } if (cmdlvl == 0 && !x_ifnum && !xerror) printf("Invalid character '%c' in input\n",*cp); xerror = 1; cp++; return(gettok()); #else /* This code allows non-numbers to be treated as macro names */ { int i, x; char * s, * cp1; cp1 = cp; tp = tbuf; for (i = 0; i < 80; i++) { /* Look ahead to next break character */ /* pretty much anything that is not in the switch() above. */ if (isalpha(*cp) || isdigit(*cp) || *cp == '_' || *cp == ':' || *cp == '.' || *cp == '[' || *cp == ']' || *cp == '{' || *cp == '}' ) tbuf[i] = *cp++; else break; } if (i >= 80) { printf("Too long - \"%s\"\n", cp1); xerror = 1; cp++; return(gettok()); } if (xerror) return(NUMBER); tbuf[i] = NUL; s = tbuf; if (!isdigit(tbuf[0])) { char * s2 = NULL; x = mxlook(mactab,tbuf,nmac); debug(F111,"gettok mxlook",tbuf,x); if (x < 0) { if (cmdlvl == 0 && !x_ifnum && !xerror) printf("Bad number - \"%s\"\n",tbuf); xerror = 1; cp++; return(gettok()); } s2 = mactab[x].mval; if (!s2) s2 = ""; if (*s2) s = s2; } #ifdef CKFLOAT x = isfloat(s,0); #else x = chknum(s); #endif /* CKFLOAT */ if (x > 0) { tokval = ckatofs(s); } else { if (cmdlvl == 0 && !x_ifnum && !xerror) printf("Bad number - \"%s\"\n",tbuf); xerror = 1; cp++; return(gettok()); } return(NUMBER); } #endif /* COMMENT */ } static CK_OFF_T #ifdef CK_ANSIC expon(CK_OFF_T x, CK_OFF_T y) #else expon(x,y) CK_OFF_T x,y; #endif /* CK_ANSIC */ /* expon */ { CK_OFF_T result = 1; int sign = 1; if (y < 0) return(0); if (x < 0) { x = -x; if (y & 1) sign = -1; } while (y != 0) { if (y & 1) result *= x; y >>= 1; if (y != 0) x *= x; } return(result * sign); } /* * factor ::= simple | simple ^ factor * */ static VOID factor() { CK_OFF_T oldval; simple(); if (curtok == '^') { oldval = expval; curtok = gettok(); factor(); expval = expon(oldval,expval); } } /* * termp ::= NULL | {*,/,%,&} factor termp * */ static VOID termp() { while (curtok == '*' || curtok == '/' || curtok == '%' || curtok == '&') { CK_OFF_T oldval; char op; op = curtok; curtok = gettok(); /* skip past operator */ oldval = expval; factor(); switch(op) { case '*': expval = oldval * expval; break; case '/': case '%': if (expval == 0) { if (!x_ifnum) printf("?Divide by zero\n"); xerror = 1; divbyzero = 1; expval = -1; } else expval = (op == '/') ? (oldval / expval) : (oldval % expval); break; case '&': expval = oldval & expval; break; } } } static CK_OFF_T #ifdef CK_ANSIC fact(CK_OFF_T x) #else fact(x) CK_OFF_T x; #endif /* CK_ANSIC */ /* fact */ { /* factorial */ CK_OFF_T result = 1; while (x > 1) result *= x--; return(result); } /* * term ::= factor termp * */ static VOID term() { factor(); termp(); } static CK_OFF_T #ifdef CK_ANSIC gcd(CK_OFF_T x, CK_OFF_T y) #else gcd(x,y) CK_OFF_T x,y; #endif /* CK_ANSIC */ /* gcd */ { /* Greatest Common Divisor */ int nshift = 0; if (x < 0) x = -x; if (y < 0) y = -y; /* validate arguments */ if (x == 0 || y == 0) return(x + y); /* this is bogus */ while (!((x & 1) | (y & 1))) { /* get rid of powers of 2 */ nshift++; x >>= 1; y >>= 1; } while (x != 1 && y != 1 && x != 0 && y != 0) { while (!(x & 1)) x >>= 1; /* eliminate unnecessary */ while (!(y & 1)) y >>= 1; /* powers of 2 */ if (x < y) { /* force x to be larger */ CK_OFF_T t; t = x; x = y; y = t; } x -= y; } if (x == 0 || y == 0) return((x + y) << nshift); /* gcd is non-zero one */ else return((CK_OFF_T) 1 << nshift); /* else gcd is 1 */ } /* * exprp ::= NULL | {+,-,|,...} term exprp * */ static VOID exprp() { while (windex("+-|<>#@",curtok) != NULL) { CK_OFF_T oldval; char op; op = curtok; curtok = gettok(); /* skip past operator */ oldval = expval; term(); switch(op) { case '+' : expval = oldval + expval; break; case '-' : expval = oldval - expval; break; case '|' : expval = oldval | expval; break; case '#' : expval = oldval ^ expval; break; case '@' : expval = gcd(oldval,expval); break; case '<' : expval = oldval << expval; break; case '>' : expval = oldval >> expval; break; } } } /* * expr ::= term exprp * */ static VOID expr() { term(); exprp(); } static CK_OFF_T xparse() { curtok = gettok(); expr(); #ifdef COMMENT if (curtok == '$') { curtok = gettok(); if (curtok != NUMBER) { if (cmdlvl == 0 && !x_ifnum) printf("?Illegal radix\n"); xerror = 1; return(0); } curtok = gettok(); } #endif /* COMMENT */ if (curtok != N_EOT) { if (cmdlvl == 0 && !x_ifnum && !xerror) printf("?Extra characters after expression\n"); xerror = 1; } return(expval); } char * /* Silent front end for evala() */ #ifdef CK_ANSIC evalx( char *s ) #else evalx(s) char *s; #endif /* CK_ANSIC */ { char * p; int t; t = x_ifnum; x_ifnum = 1; p = evala(s); x_ifnum = t; return(p); } char * #ifdef CK_ANSIC evala( char *s ) #else evala(s) char *s; #endif /* CK_ANSIC */ { CK_OFF_T v; /* Numeric value */ if (!s) return(""); xerror = 0; /* Start out with no error */ divbyzero = 0; cp = s; /* Make the argument global */ v = xparse(); /* Parse the string */ return(xerror ? "" : ckfstoa(v)); /* Return empty string on error */ } /* * simplest ::= NUMBER | ( expr ) * */ static VOID simplest() { char * p; p = cp; if (curtok == NUMBER) expval = tokval; else if (curtok == '(') { curtok = gettok(); /* skip over paren */ expr(); if (curtok != ')') { if (cmdlvl == 0 && !x_ifnum && !xerror) printf("?Missing right parenthesis\n"); xerror = 1; } debug(F110,"GETTOK SIMPLEST ()",p,0); } else { if (cmdlvl == 0 && !x_ifnum && !xerror) printf("?Operator unexpected\n"); xerror = 1; } curtok = gettok(); } /* * simpler ::= simplest | simplest ! * */ static VOID simpler() { simplest(); if (curtok == '!') { curtok = gettok(); expval = fact(expval); } } /* * simple ::= {-,~,!} simpler | simpler * */ static VOID simple() { if (curtok == '-' || curtok == '~' || curtok == '!' || curtok == '+') { int op = curtok; curtok = gettok(); /* skip over - sign */ simpler(); /* parse the factor again */ if (op != '+') expval = (op == '-') ? -expval : ((op == '!') ? !expval : ~expval); } else simpler(); } /* D C L A R R A Y -- Declare an array */ /* Call with: char a = single character designator for the array, e.g. "a". int n = size of array. -1 means to undeclare the array. Returns: 0 or greater on success, having created the requested array with with n+1 elements, 0..n. If an array of the same name existed previously, it is destroyed. The new array has all its elements initialized to NULL pointers. When an array is successfully created, the return value is its index (0 = 'a', 1 = 'b', and so on.) -1 on failure (because 'a' out of range or malloc failure). */ int #ifdef CK_ANSIC dclarray(char a, int n) #else dclarray(a,n) char a; int n; #endif /* CK_ANSIC */ /* dclarray */ { char c, **p; int i, n2, rc; if (a > 63 && a < 91) a += 32; /* Convert letters to lowercase */ if (a < ARRAYBASE || a > 122) /* Verify name */ return(-1); if (n < 0) /* Check arg */ return(-1); if (n+1 < 0) /* MAXINT+1 wraps around */ return(-1); c = a; a -= ARRAYBASE; /* Convert name to number */ rc = a; /* Array index will be return code */ if ((p = a_ptr[a]) != NULL) { /* Delete old array of same name */ if (a_link[a] > -1) { /* Is it a link? */ if (n == 0) { /* If we're just deleting it */ a_ptr[a] = (char **) NULL; /* clear all the info. */ a_dim[a] = 0; a_link[a] = -1; return(0); } /* Not deleting */ a = a_link[a]; /* Switch to linked-to array */ } n2 = a_dim[a]; /* Real array */ for (i = 0; i <= n2; i++) { /* First delete its elements */ if (p[i]) { free(p[i]); p[i] = NULL; } } free((char *)a_ptr[a]); /* Then the element list */ if (n == 0) { /* If undeclaring this array... */ for (i = 0; i < 122 - ARRAYBASE; i++) { /* Any linked arrays? */ if (i != a && a_link[i] == a) { /* Find them */ a_ptr[i] = (char **) NULL; /* and remove them */ a_dim[i] = 0; a_link[i] = -1; } } } a_ptr[a] = (char **) NULL; /* Remove pointer to element list */ a_dim[a] = 0; /* Set dimension at zero. */ a_link[a] = -1; /* Unset link word */ } if (n < 0) /* If only undeclaring, */ return(0); /* we're done. */ p = (char **) malloc((n+1) * sizeof(char **)); /* Allocate for new array */ if (p == NULL) return(-1); /* Check */ a_ptr[a] = p; /* Save pointer to member list */ a_dim[a] = n; /* Save dimension */ for (i = 0; i <= n; i++) /* Initialize members to null */ p[i] = NULL; for (i = 0; i < (int) 'z' - ARRAYBASE; i++) { /* Any linked arrays? */ if (i != a && a_link[i] == a) { /* Find and update them */ a_ptr[i] = p; a_dim[i] = n; } } return(rc); } /* X A R R A Y -- Convert array name to array index */ int #ifdef CK_ANSIC xarray( char * s ) #else xarray(s) char * s; #endif /* CK_ANSIC */ { char buf[8]; int x; char c; if (!s) s = ""; debug(F110,"xarray",s,0); if (!*s) return(-1); x = strlen(s); buf[0] = NUL; buf[1] = NUL; buf[2] = s[0]; buf[3] = (x > 0) ? s[1] : NUL; buf[4] = (x > 1) ? s[2] : NUL; buf[5] = (x > 2) ? s[3] : NUL; buf[6] = NUL; debug(F110,"xarray buf[3]",&buf[3],0); s = buf+2; if (*s == '&') { buf[1] = CMDQ; s--; } else if (*s != CMDQ) { buf[0] = CMDQ; buf[1] = '&'; s = buf; } debug(F110,"xarray s",s,0); c = *(s+2); if (isupper(c)) c = tolower(c); if (c == '@') c = 96; x = (int)c - ARRAYBASE; if (*(s+3) == '[') *(s+3) = NUL; if (x < 0) { return(-1); } if (x > ('z' - ARRAYBASE)) { debug(F101,"xarray x out of range","",x); return(-1); } if (*(s+3)) { debug(F110,"xarray syntax",s,0); return(-1); } return(x); } /* boundspair() -- parses blah[n:m] For use with array segment specifiers and compact substring notation. Ignores the "blah" part, gets the values of n and m, which can be numbers, variables, or arithmetic expressions; anything that resolves to a number. Call with: s - string to parse sep - array of permissible bounds separator chars lo - pointer to low-bound result (or -1) hi - pointer to hi-bound result (or -1) zz - pointer to separator char that was encountered (or NUL) Returns: -1 on failure 0 on success */ int #ifdef CK_ANSIC boundspair(char *s, char *sep, int *lo, int *hi, char *zz) #else boundspair(s,sep,lo,hi,zz) char *s, *sep, *zz; int *lo, *hi; #endif /* CK_ANSIC */ { int i, y, range[2], bc = 0; char c = NUL, *s2 = NULL, buf[256], *p, *q, *r, *e[2], *tmp = NULL; debug(F110,"boundspair s",s,0); debug(F110,"boundspair sep",sep,0); *lo = -1; /* Default bounds */ *hi = -1; *zz = 0; /* Default bounds separator */ range[0] = -1; /* It's OK -- get contents */ range[1] = -1; /* of subscript brackets */ if (!s) s = ""; if (!*s) return(-1); makestr(&tmp,s); /* Make a pokeable copy */ p = tmp; q = NULL; r = NULL; for (p = s; *p; p++) { /* Get the two elements */ if (*p == '[') { bc++; /* Bracket counter */ if (bc == 1 && !q) q = p+1; } else if (*p == ']') { bc--; if (bc == 0 && q) *p = NUL; } else if (bc == 1) { /* If within brackers */ s2 = ckstrchr(sep,*p); /* Check for separator */ if (s2) { debug(F000,"boundspair *s2","",*s2); if (c) { debug(F000,"boundspair","Too many separators",*s2); makestr(&tmp,NULL); return(-1); } c = *s2; /* Separator character */ *p = NUL; r = p+1; } } } if (bc == 0 && !q) { /* This allows such constructions as "show array a" */ debug(F110,"boundspair","no brackets",0); makestr(&tmp,NULL); return(0); } if (bc != 0 || !q) { debug(F110,"boundspair","unbalanced or missing brackets",0); makestr(&tmp,NULL); return(-1); } if (!q) q = ""; if (!*q) q = "-1"; if (!r) r = ""; if (!*r) r = "-1"; e[0] = q; e[1] = r; debug(F000,"boundspair c","",c); debug(F110,"boundspair q",q,0); debug(F110,"boundspair r",r,0); for (i = 0; i < 2 && e[i]; i++) { y = 255; /* Expand variables, etc. */ s = buf; zzstring(e[i],&s,&y); s = evalx(buf); /* Evaluate it arithmetically */ if (s) if (*s) ckstrncpy(buf,s,256); if (!chknum(buf)) { /* Did we get a number? */ debug(F110,"boundspair element not numeric",buf,0); makestr(&tmp,NULL); /* No, fail. */ return(-1); } range[i] = atoi(buf); } makestr(&tmp,NULL); /* Free temporary poked string */ *lo = range[0]; /* Return what we got */ *hi = range[1]; *zz = c; debug(F101,"boundspair lo","",*lo); debug(F101,"boundspair hi","",*hi); return(0); } /* A R R A Y B O U N D S -- Parse array segment notation \&a[n:m] */ /* Call with s = array name (like a or &a), plus two pointers to ints. Returns -1 on error, or array index, with the two ints set as follows: \&a[] -1, -1 \&a[3] 3, -1 \&a[3:17] 3, 17 The array need not be declared -- this routine is just for parsing. */ int #ifdef CK_ANSIC arraybounds( char * s, int * lo, int * hi ) #else arraybounds(s,lo,hi) char * s; int * lo, * hi; #endif /* CK_ANSIC */ { int x, y; char zz; *lo = -1; /* Default bounds */ *hi = -1; if (!s) s = ""; /* Defense de null args */ if (!*s) return(-1); x = xarray(s); /* Check basic structure */ debug(F111,"arraybounds xarray",s,x); if (x < 0) /* Not OK, fail. */ return(-1); y = boundspair(s,":",lo,hi,&zz); debug(F111,"arraybounds boundspair",s,y); debug(F101,"arraybounds lo","",*lo); debug(F101,"arraybounds hi","",*hi); if (y < 0) /* Get bounds */ return(-1); return(x); } /* A R R A Y N A M -- Parse an array name */ /* Call with pointer to string that starts with the array reference. String may begin with either \& or just &. On success, Returns letter ID (always lowercase) in argument c, which can also be accent grave (` = 96; '@' is converted to grave); Dimension or subscript in argument n; IMPORTANT: These arguments must be provided by the caller as addresses of ints (not chars), for example: char *s; int x, y; arraynam(s,&x,&y); On failure, returns a negative number, with args n and c set to zero. */ int #ifdef CK_ANSIC arraynam( char *ss, int *c, int *n ) #else arraynam(ss,c,n) char *ss; int *c; int *n; #endif /* CK_ANSIC */ { int i, y, pp, len; char x; char *s, *p, *sx, *vnp; /* On stack to allow for recursive calls... */ char vnbuf[ARRAYREFLEN+1]; /* Entire array reference */ char ssbuf[ARRAYREFLEN+1]; /* Subscript in "plain text" */ char sxbuf[16]; /* Evaluated subscript */ *c = *n = 0; /* Initialize return values */ len = strlen(ss); for (pp = 0,i = 0; i < len; i++) { /* Check length */ if (ss[i] == '[') { pp++; } else if (ss[i] == ']') { if (--pp == 0) break; } } if (i > ARRAYREFLEN) { printf("?Array reference too long - %s\n",ss); return(-9); } ckstrncpy(vnbuf,ss,ARRAYREFLEN); vnp = vnbuf; if (vnbuf[0] == CMDQ && vnbuf[1] == '&') vnp++; if (*vnp != '&') { printf("?Not an array - %s\n",vnbuf); return(-9); } x = *(vnp + 1); /* Fold case of array name */ /* We don't use isupper & tolower here on purpose because these */ /* would produce undesired effects with accented letters. */ if (x > 63 && x < 91) x = *(vnp + 1) = (char) (x + 32); if ((x < ARRAYBASE) || (x > 122) || (*(vnp+2) != '[')) { if (msgflg) { printf("?Invalid format for array name - %s\n",vnbuf); return(-9); } else return(-2); } *c = x; /* Return the array name */ s = vnp+3; /* Get dimension */ p = ssbuf; pp = 1; /* Bracket counter */ for (i = 0; i < ARRAYREFLEN && *s != NUL; i++) { /* Copy up to ] */ if (*s == '[') pp++; if (*s == ']' && --pp == 0) break; *p++ = *s++; } if (*s != ']') { printf("?No closing bracket on array dimension - %s\n",vnbuf); return(-9); } p--; /* Trim whitespace from end */ while (*p == SP || *p == HT) p--; p++; *p = NUL; /* Terminate subscript with null */ p = ssbuf; /* Point to beginning of subscript */ while (*p == SP || *p == HT) /* Trim whitespace from beginning */ p++; sx = sxbuf; /* Where to put expanded subscript */ y = 16; { /* Even if VARIABLE-EVALUATION SIMPLE use RECURSIVE for subscripts */ /* NOTE: This is vulnerable to SIGINT and whatnot... */ int tmp = vareval; /* Save VARIABLE-EVALUATION setting */ vareval = 1; /* Force it to RECURSIVE */ zzstring(p,&sx,&y); /* Convert variables, etc. */ vareval = tmp; /* Restore VARIABLE-EVALUATION */ } sx = sxbuf; while (*sx == SP) sx++; /* debug(F110,"arraynam sx","",sx); */ if (!*sx) { /* Empty brackets... */ *n = -17; /* (Secret code :-) */ return(-2); } p = evala(sx); /* Run it thru \fneval()... */ if (p) if (*p) ckstrncpy(sxbuf,p,16); /* We know it has to be a number. */ if (!chknum(sxbuf)) { /* Make sure it's all digits */ if (msgflg) { printf("?Array dimension or subscript missing or not numeric\n"); return(-9); } else return(-2); } if ((y = atoi(sxbuf)) < 0) { if (cmflgs == 0) printf("\n"); if (msgflg) { printf("?Array dimension or subscript not positive or zero\n"); return(-9); } else return(-2); } *n = y; /* Return the subscript or dimension */ return(0); } /* chkarray returns 0 or greater if array exists, negative otherwise */ int #ifdef CK_ANSIC chkarray( int a, int i ) /* Check if array is declared */ #else chkarray(a,i) int a, i; #endif /* CK_ANSIC */ { int x; /* and if subscript is in range */ if (a == 64) a = 96; /* Convert atsign to grave accent */ x = a - ARRAYBASE; /* Values must be in range 95-122 */ #ifdef COMMENT if (x == 0 && maclvl < 0) /* Macro arg vector but no macro */ return(0); #endif /* COMMENT */ if (x < 0 || x > 'z' - ARRAYBASE) /* Not in range */ return(-2); if (a_ptr[x] == NULL) return(-1); /* Not declared */ if (i > a_dim[x]) return(-2); /* Declared but out of range. */ return(a_dim[x]); /* All ok, return dimension */ } #ifdef COMMENT /* This isn't used. */ char * arrayval(a,i) int a, i; { /* Return value of \&a[i] */ int x; char **p; /* (possibly NULL) */ if (a == 64) a = 96; /* Convert atsign to grave accent */ x = a - ARRAYBASE; /* Values must be in range 95-122 */ if (x < 0 || x > 27) return(NULL); /* Not in range */ if ((x > 0) && (p = a_ptr[x]) == NULL) /* Array not declared */ return(NULL); if (i > a_dim[x]) /* Subscript out of range. */ return(NULL); return(p[i]); /* All ok, return pointer to value. */ } #endif /* COMMENT */ /* pusharray() is called when an array name is included in a LOCAL statement. It moves the pointers from the global definition to the stack, and removes the global definition. Later, if the same array is declared in the local context, it occupies the global definition in the normal way. But when popclvl() is called, it replaces the global definition with the one saved here. The "secret code" is used to indicate to popclv() that it should remove the global array when popping through this level -- otherwise if a local array were declared that had no counterpart at any higher level, it would never be deleted. This allows Algol-like inheritance to work both on the way down and on the way back up. */ int #ifdef CK_ANSIC pusharray( int x, int z ) #else pusharray(x,z) int x, z; #endif /* CK_ANSIC */ { int y; debug(F000,"pusharray x","",x); debug(F101,"pusharray z","",z); y = chkarray(x,z); debug(F101,"pusharray y","",y); x -= ARRAYBASE; /* Convert name letter to index. */ if (x < 0 || x > 27) return(-1); if (y < 0) { aa_ptr[cmdlvl][x] = (char **) NULL; aa_dim[cmdlvl][x] = -23; /* Secret code (see popclvl()) */ } else { aa_ptr[cmdlvl][x] = a_ptr[x]; aa_dim[cmdlvl][x] = y; } a_ptr[x] = (char **) NULL; a_dim[x] = 0; return(0); } /* P A R S E V A R -- Parse a variable name or array reference. */ /* Call with: s = pointer to candidate variable name or array reference. *c = address of integer in which to return variable ID. *i = address of integer in which to return array subscript. Returns: -2: syntax error in variable name or array reference. 1: successful parse of a simple variable, with ID in c. 2: successful parse of an array reference, w/ID in c and subscript in i. */ int #ifdef CK_ANSIC parsevar( char *s, int *c, int *i ) #else parsevar(s,c,i) char *s; int *c, *i; #endif /* CK_ANSIC */ { char *p; int x,y,z; p = s; if (*s == CMDQ) s++; /* Point after backslash */ if (*s != '%' && *s != '&') { /* Make sure it's % or & */ printf("?Not a variable name - %s\n",p); return(-9); } if ((int)strlen(s) < 2) { printf("?Incomplete variable name - %s\n",p); return(-9); } if (*s == '%' && *(s+2) != '\0') { printf("?Only one character after '%%' in variable name, please\n"); return(-9); } if (*s == '&' && *(s+2) != '[') { printf("?Array subscript expected - %s\n",p); return(-9); } if (*s == '%') { /* Simple variable. */ y = *(s+1); /* Get variable ID letter/char */ if (isupper(y)) y -= ('a'-'A'); /* Convert upper to lower case */ *c = y; /* Set the return values. */ *i = -1; /* No array subscript. */ return(1); /* Return 1 = simple variable */ } if (*s == '&') { /* Array reference. */ y = arraynam(s,&x,&z); /* Go parse it. */ debug(F101,"parsevar arraynam","",y); if ((y) < 0) { if (y == -2) return(pusharray(x,z)); if (y != -9) printf("?Invalid array reference - %s\n",p); return(-9); } if (chkarray(x,z) < 0) { /* Check if declared, etc. */ printf("?Array not declared or subscript out of range\n"); return(-9); } *c = x; /* Return array letter */ *i = z; /* and subscript. */ return(2); } return(-2); /* None of the above. */ } #define VALN 32 /* Get the numeric value of a variable */ /* Call with pointer to variable name, pointer to int for return value. Returns: 0 on success with second arg containing the value. -1 on failure (bad variable syntax, variable not defined or not numeric). */ int #ifdef CK_ANSIC varval( char *s, CK_OFF_T *v ) #else varval(s,v) char *s; CK_OFF_T *v; #endif /* CK_ANSIC */ { char valbuf[VALN+1]; /* s is pointer to variable name */ char name[256]; char *p; int y; if (*s != CMDQ) { /* Handle macro names too */ ckmakmsg(name,256,"\\m(",s,")",NULL); s = name; } p = valbuf; /* Expand variable into valbuf. */ y = VALN; if (zzstring(s,&p,&y) < 0) return(-1); p = valbuf; /* Make sure value is numeric */ if (!*p) { /* Be nice -- let an undefined */ valbuf[0] = '0'; /* variable be treated as 0. */ valbuf[1] = NUL; } if (chknum(p)) { /* Convert numeric string to int */ *v = ckatofs(p); /* OK */ } else { /* Not OK */ p = evala(p); /* Maybe it's an expression */ if (!chknum(p)) /* Did it evaluate? */ return(-1); /* No, failure. */ else /* Yes, */ *v = ckatofs(p); /* success */ } return(0); } #define SVALN 2048 /* Like varval() but returns variable value as a string, not a number. Added but not tested or used; it's usually easier to use zzstring(). - fdc 11 December 2022 */ int #ifdef CK_ANSIC varsval( char *s, char **s2 ) #else varsval(s,s2) char *s; char **s2; #endif /* CK_ANSIC */ { char valbuf[SVALN+1]; /* s is pointer to variable name */ char name[256]; char *p; int y; if (*s != CMDQ) { /* Handle macro names too */ ckmakmsg(name,256,"\\m(",s,")",NULL); s = name; } p = valbuf; /* Expand variable into valbuf. */ y = SVALN; if (zzstring(s,&p,&y) < 0) return(-1); *s2 = p; /* success */ return(0); } /* Increment or decrement a variable */ /* Returns -1 on failure, 0 on success */ int #ifdef CK_ANSIC incvar( char *s, CK_OFF_T x, int z ) /* Increment a numeric variable */ #else incvar(s,x,z) char *s; CK_OFF_T x; int z; #endif /* CK_ANSIC */ { CK_OFF_T n; /* s is pointer to variable name */ /* x is amount to increment by */ /* z != 0 means add */ /* z = 0 means subtract */ if (varval(s,&n) < 0) /* Convert numeric string to int */ return(-1); if (z) /* Increment it by the given amount */ n += x; else /* or decrement as requested. */ n -= x; addmac(s,ckfstoa(n)); /* Replace old variable */ return(0); } /* D O D O -- Do a macro */ /* Call with x = macro table index, s = pointer to arguments. Returns 0 on failure, 1 on success. */ int #ifdef CK_ANSIC dodo( int x, char *s, int flags ) #else dodo(x,s,flags) int x; char *s; int flags; #endif /* CK_ANSIC */ { int y; extern int tra_asg, tra_cmd; int tra_tmp; /* For TRACE */ #ifndef NOLOCAL #ifdef OS2 extern int term_io; int term_io_sav = term_io; #endif /* OS2 */ #endif /* NOLOCAL */ if (x < 0) /* It can happen! */ return(-1); tra_tmp = tra_asg; if (++maclvl >= MACLEVEL) { /* Make sure we have storage */ debug(F101,"dodo maclvl too deep","",maclvl); --maclvl; printf("Macros nested too deeply\n"); return(0); } macp[maclvl] = mactab[x].mval; /* Point to the macro body */ macx[maclvl] = mactab[x].mval; /* Remember where the beginning is */ #ifdef COMMENT makestr(&(m_line[maclvl]),s); /* Entire arg string for "\%*" */ #endif /* COMMENT */ cmdlvl++; /* Entering a new command level */ if (cmdlvl >= CMDSTKL) { /* Too many macros + TAKE files? */ debug(F101,"dodo cmdlvl too deep","",cmdlvl); cmdlvl--; printf("?TAKE files and DO commands nested too deeply\n"); return(0); } #ifdef DEBUG if (deblog) { debug(F111,"CMD +M",mactab[x].kwd,cmdlvl); debug(F010,"CMD ->",s,0); } #endif /* DEBUG */ #ifdef VMS conres(); /* So Ctrl-C, etc, will work. */ #endif /* VMS */ #ifndef NOLOCAL #ifdef OS2 term_io = 0; /* Disable terminal emulator I/O */ #endif /* OS2 */ #endif /* NOLOCAL */ ifcmd[cmdlvl] = 0; iftest[cmdlvl] = 0; count[cmdlvl] = count[cmdlvl-1]; /* Inherit COUNT from previous level */ intime[cmdlvl] = intime[cmdlvl-1]; /* Inherit previous INPUT TIMEOUT */ inpcas[cmdlvl] = inpcas[cmdlvl-1]; /* and INPUT CASE */ takerr[cmdlvl] = takerr[cmdlvl-1]; /* and TAKE ERROR */ merror[cmdlvl] = merror[cmdlvl-1]; /* and MACRO ERROR */ xquiet[cmdlvl] = quiet; xvarev[cmdlvl] = vareval; xcmdsrc = CMD_MD; cmdstk[cmdlvl].src = CMD_MD; /* Say we're in a macro */ cmdstk[cmdlvl].lvl = maclvl; /* and remember the macro level */ cmdstk[cmdlvl].ccflgs = flags & ~CF_IMAC; /* Set flags */ /* Initialize return value except in FOR, WHILE, IF, and SWITCH macros */ if (!(flags & CF_IMAC) && mrval[maclvl]) { free(mrval[maclvl]); mrval[maclvl] = NULL; } /* Clear old %0..%9 arguments */ addmac("%0",mactab[x].kwd); /* Define %0 = name of macro */ makestr(&(m_xarg[maclvl][0]),mactab[x].kwd); varnam[0] = '%'; varnam[2] = '\0'; tra_asg = 0; for (y = 1; y < 10; y++) { /* Clear args %1..%9 */ if (m_arg[maclvl][y]) { /* Don't call delmac() unless */ varnam[1] = (char) (y + '0'); /* we have to... */ delmac(varnam,0); } } tra_asg = tra_tmp; /* Break the big "s" string up into macro arguments */ xwords(s,MAXARGLIST,NULL,0); #ifndef NOLOCAL #ifdef OS2 term_io = term_io_sav; #endif /* OS2 */ #endif /* NOLOCAL */ if (tra_cmd) printf("[%d] +M: \"%s\"\n",cmdlvl,mactab[x].kwd); return(1); } /* Insert "literal" quote around each comma-separated command to prevent */ /* its premature expansion. Only do this if object command is surrounded */ /* by braces. */ static char* flit = "\\flit("; int #ifdef CK_ANSIC litcmd( char **src, char **dest, int n ) #else litcmd(src,dest,n) char **src, **dest; int n; #endif /* CK_ANSIC */ { int bc = 0, pp = 0; char c, *s, *lp, *ss; s = *src; lp = *dest; debug(F010,"litcmd",s,0); while (*s == SP) s++; /* Strip extra leading spaces */ if (*s == '{') { /* Starts with brace */ pp = 0; /* Paren counter */ bc = 1; /* Count leading brace */ *lp++ = *s++; /* Copy it */ if (--n < 1) return(-1); /* Check space */ while (*s == SP) s++; /* Strip interior leading spaces */ ss = flit; /* Point to "\flit(" */ while ((*lp++ = *ss++)) /* Copy it */ if (--n < 1) /* and check space */ return(-1); lp--; /* Back up over null */ while (*s) { /* Go thru rest of text */ c = *s; if (c == '{') bc++; /* Count brackets */ if (c == '(') pp++; /* and parens */ if (c == ')') { /* Right parenthesis. */ pp--; /* Count it. */ if (pp < 0) { /* An unbalanced right paren... */ #ifdef COMMENT /* The problem here is that "\{" appears to be a quoted brace and therefore isn't counted; then the "}" matches an earlier opening brace, causing (e.g.) truncation of macros by getncm(). */ if (n < 5) /* Out of space in dest buffer? */ return(-1); /* If so, give up. */ *lp++ = CMDQ; /* Must be quoted to prevent */ *lp++ = '}'; /* premature termination of */ *lp++ = '4'; /* \flit(...) */ *lp++ = '1'; *lp++ = '}'; n -= 5; #else /* Here we rely on the fact the \nnn never takes more than 3 digits */ if (n < 4) /* Out of space in dest buffer? */ return(-1); /* If so, give up. */ *lp++ = CMDQ; /* Must be quoted to prevent */ *lp++ = '0'; /* premature termination of */ *lp++ = '4'; /* \flit(...) */ *lp++ = '1'; n -= 4; #endif /* COMMENT */ pp++; /* Uncount it. */ s++; continue; } } if (c == '}') { /* Closing brace. */ if (--bc == 0) { /* Final one? */ *lp++ = ')'; /* Add closing paren for "\flit()" */ if (--n < 1) return(-1); *lp++ = c; if (--n < 1) return(-1); s++; break; } } *lp++ = c; /* General case */ if (--n < 1) return(-1); s++; } *lp = NUL; } else { /* No brackets around, */ while ((*lp++ = *s++)) /* just copy. */ if (--n < 1) return(-1); lp--; } *src = s; /* Return updated source */ *dest = lp; /* and destination pointers */ if (bc) /* Fail if braces unbalanced */ return(-1); else /* Otherwise succeed. */ return(0); } #endif /* NOSPL */ /* Functions moved here from ckuusr.c to even out the module sizes... */ /* Breaks up string s -- IN PLACE! -- into a list of up to max words. Pointers to each word go into the array list[]. max is the maximum number of words (pointers). If list is NULL, then they are added to the macro table. flag = 0 means the last field is to be one word, like all the other fields, so anything after it is discarded. flag = 1 means the last field extends to the end of the string, even if there are lots of words left, so the last field contains the remainder of the string. */ VOID #ifdef CK_ANSIC xwords( char *s, int max, char *list[], int flag ) #else xwords(s,max,list,flag) char *s; int max; char *list[]; int flag; #endif /* CK_ANSIC */ { char *p; int b, i, k, q, y, z; int macro = 0; if (!list) { debug(F100," xwords list is NULL","",0); macro = 1; } else { debug(F100," xwords LIST is defined","",0); } debug(F100,"xwords ENTRY","",0); #ifndef NOSPL /* debug(F110," xwords macro",(char *)m_xarg[maclvl][0],0); */ debug(F101," xwords maclvl","",maclvl); debug(F101," xwords max","",max); debug(F101," xwords flag","",flag); debug(F110," xwords string",s,0); debug(F101," xwords macro","",macro); #endif /* NOSPL */ p = s; /* Pointer to beginning of string */ q = 0; /* Flag for doublequote removal */ b = 0; /* Flag for outer brace removal */ k = 0; /* Flag for in-word */ y = 0; /* Brace nesting level */ z = 0; /* "Word" counter, 0 thru max */ if (!s) s = ""; /* Nothing to do */ if (!*s) return; if (list) for (i = 0; i <= max; i++) /* Initialize pointers */ list[i] = NULL; if (flag) max--; #ifndef NOSPL /* Macro arguments at this point are a single string... must split it up. As of C-Kermit 9.0.304 Dev.22, 24 April 2017, we use cksplit() for this instead of tons of messy code in xwords() written decades ago to do what cksplit() does better. */ if (macro) { struct stringarray * q = NULL; char **pp = NULL; if (maclvl < 0) { debug(F101," xwords maclvl < 0","",maclvl); newerrmsg("Internal error: maclvl < 0"); } debug(F101," xwords splitting macro arguments.. maclvl","",maclvl); /* Space is the only separator; grouping is with "" or {} */ q = cksplit(1,0,p," ","ALL",1+2,0,0,1); z = q->a_size; /* Number of "words" in string */ if (z <= 0) return; pp = q->a_head; if (pp) { /* In C-Kermit 9.0.304 Dev.22, April 2017, we have to get the macro arguments from the previous macro level (prev). Up to now, the macro arguments were evaluated when the DO command was parsed, before dodo() or xwords() were ever called. Now we're evaluating them after already entering the new macro stack level: evalmacroarg() is just a front end for zzstring(), which is at the heart of all variable-substitution operations. To evaluate a \%1-9 variable, zzstring() looks in the CURRENT macro stack frame. Rather than mess with zzstring(), I set maclvl back before calling evalmacroarg() and restore it immediately afterward. It's the only safe way to do this, Because zzstring() has no way of knowing whether (say) \%1 is on the DO command line or in some other context. */ debug(F101," xwords macro cksplit items","",z); if (z > max) z = max; for (i = 1; i <= z; i++) { /* Loop through macro arguments. */ p = pp[i]; debug(F111," xwords arg i",p,i); maclvl--; /* Get argument from previous level */ evalmacroarg(&p); /* Evaluate it */ maclvl++; /* Use its value on currentlevel */ debug(F111," xwords arg i evaluated",p,i); makestr(&(m_xarg[maclvl][i]),p); if (i < 10) { varnam[1] = (char) (i + '0'); /* Assign last arg */ addmac(varnam,p); debug(F111," xwords arg name",varnam,maclvl); debug(F111," xwords def def ",p,maclvl); } } /* Handle argc and the dimension of the \&_[] arg vector array */ if (maclvl < 0) { /* (How can this be?) */ a_dim[0] = z; /* Array dimension is one less */ topargc = z + 1; /* than \v(argc) */ debug(F111," xwords a_dim[0]","IMPOSSIBLE",a_dim[0]); } else { macargc[maclvl] = z + 1; /* Set \v(argc) variable */ n_xarg[maclvl] = z + 1; /* This is the actual number */ a_ptr[0] = m_xarg[maclvl]; /* Point \&_[] at the args */ a_dim[0] = z; /* And give it this dimension */ debug(F111," xwords a_dim[0]","E",a_dim[0]); } } return; } #endif /* NOSPL */ /* Not macro args, some other kind of list. This whole mess could be a cksplit() call... */ while (1) { /* Go thru word list */ if (!s || (*s == '\0')) { /* No more characters? */ if (k != 0) { /* Was I in a word? */ if (z == max) break; /* Yes, only go up to max. */ z++; /* Count this word. */ list[z] = p; /* Assign pointer. */ debug(F111," xwords list item p z",p,z); } break; /* And get out. */ } if (k == 0 && (*s == SP || *s == HT)) { /* Eat leading blanks */ s++; continue; } else if (q == 0 && *s == '{') { /* An opening brace */ if (k == 0 && y == 0) { /* If leading brace */ p = s+1; /* point past it */ b = 1; /* and flag that we did this */ } k = 1; /* Flag that we're in a word */ y++; /* Count the brace. */ } else if (q == 0 && *s == '}') { /* A closing brace. */ y--; /* Count it. */ if (y <= 0 && b != 0) { /* If it matches the leading brace */ char c; c = *(s+1); if (!c || c == SP || c == HT) { /* at EOL or followed by SP */ *s = SP; /* change it to a space */ b = 0; /* and we're not in braces any more */ } } #ifdef DOUBLEQUOTING /* Opening doublequote */ } else if (k == 0 && b == 0 && *s == '"' && dblquo) { y++; p = s+1; /* point past it */ q = 1; /* and flag that we did this */ k = 1; /* Flag that we're in a word */ /* Closing double quote */ } else if (q > 0 && k > 0 && b == 0 && *s == '"' && dblquo) { char c; c = *(s+1); if (!c || c == SP || c == HT) { /* at EOL or followed by SP */ y--; *s = SP; /* change it to a space */ q = 0; /* and we're not in quotes any more */ } #endif /* DOUBLEQUOTING */ } else if (*s != SP && *s != HT) { /* Nonspace means we're in a word */ if (k == 0) { /* If we weren't in a word before, */ p = s; /* Mark the beginning */ if (flag && z == max) { /* Want last word to be remainder? */ z++; list[z] = p; /* Yes, point to it */ break; /* and quit */ } k = 1; /* Set in-word flag */ } } /* If we're not inside a braced quantity, and we are in a word, and */ /* we have hit whitespace, then we have a word. */ if ((y < 1) && (k != 0) && (*s == SP || *s == HT) && !b) { if (!flag || z < max) /* if we don't want to keep rest */ *s = '\0'; /* terminate the arg with null */ k = 0; /* say we're not in a word any more */ y = 0; /* start braces off clean again */ if (z == max) break; /* Only go up to max. */ z++; /* count this arg */ list[z] = p; p = s+1; } s++; /* Point past this character */ } if ((z == 0) && (y > 1)) { /* Extra closing brace(s) at end */ z++; list[z] = p; } return; } #ifndef NOSPL /* D O S H I F T -- Do the SHIFT Command; shift macro args left by n */ /* Note: at some point let's consolidate m_arg[][] and m_xarg[][]. */ int #ifdef CK_ANSIC doshift( int n ) /* n = shift count */ #else doshift(n) int n; #endif /* CK_ANSIC */ { int i, top, level; char /* *s, *m, */ buf[6]; /* Buffer to build scalar names */ char * sx = tmpbuf; int nx = TMPBUFSIZ; debug(F101,"SHIFT count","",n); debug(F101,"SHIFT topargc","",topargc); if (n < 1) /* Stay in range */ return(n == 0 ? 1 : 0); level = maclvl; top = (level < 0) ? topargc : macargc[level]; if (n >= top) n = top - 1; #ifdef DEBUG if (deblog) { debug(F101,"SHIFT count 2","",n); debug(F101,"SHIFT level","",level); if (level > -1) debug(F101,"SHIFT macargc[level]","",macargc[level]); } #endif /* DEBUG */ buf[0] = '\\'; /* Initialize name template */ buf[1] = '%'; buf[2] = NUL; buf[3] = NUL; for (i = 1; i <= n; i++) { /* Free shifted-over args */ if (level < 0) { makestr(&(toparg[i]),NULL); } else { makestr(&(m_xarg[level][i]),NULL); } if (i < 10) { /* Is this necessary? */ buf[2] = (char)(i+'0'); delmac(buf,0); } } for (i = 1; i <= top-n; i++) { /* Shift remaining args */ if (level < 0) { #ifdef COMMENT toparg[i] = toparg[i+n]; /* Full vector */ #else makestr(&(toparg[i]),toparg[i+n]); /* Full vector */ #endif /* COMMENT */ if (i < 10) /* Scalars... */ makestr(&(g_var[i+'0']),toparg[i+n]); } else { #ifdef COMMENT m_xarg[level][i] = m_xarg[level][i+n]; #else makestr(&(m_xarg[level][i]),m_xarg[level][i+n]); #endif /* COMMENT */ if (i < 10) { buf[2] = (char)(i+'0'); debug(F010,"SHIFT buf",buf,0); addmac(buf,m_xarg[level][i+n]); } } } for (i = top-n; i <= top; i++) { /* Clear n args from the end */ if (level < 0) { #ifdef COMMENT toparg[i] = NULL; #else makestr(&(toparg[i]),NULL); #endif /* COMMENt */ if (i < 10) makestr(&(g_var[i+'0']),NULL); } else { #ifdef COMMENT m_xarg[level][i] = NULL; #else makestr(&(m_xarg[level][i]),NULL); #endif /* COMMENt */ if (i < 10) { buf[2] = (char)(i+'0'); delmac(buf,0); } } } if (level > -1) { /* Macro args */ macargc[level] -= n; /* Adjust count */ n_xarg[maclvl] = macargc[level]; /* Here too */ a_dim[0] = macargc[level] - 1; /* Adjust array dimension */ debug(F111,"a_dim[0]","F",a_dim[0]); zzstring("\\fjoin(&_[],{ },1)",&sx,&nx); /* Handle \%* */ #ifdef COMMENT makestr(&(m_line[level]),tmpbuf); #endif /* COMMENT */ } else { /* Ditto for top level */ topargc -= n; a_dim[0] = topargc - 1; debug(F111,"a_dim[0]","G",a_dim[0]); zzstring("\\fjoin(&_[],{ },1)",&sx,&nx); #ifdef COMMENT makestr(&topline,tmpbuf); #endif /* COMMENT */ } return(1); } #endif /* NOSPL */ int #ifdef CK_ANSIC docd( int cx ) /* Do the CD command */ #else docd(cx) int cx; #endif /* CK_ANSIC */ { int x; extern int server, srvcdmsg, cdactive; extern char * cdmsgfile[], * ckcdpath; char *s, *p; #ifdef MAC char temp[34]; #endif /* MAC */ #ifdef IKSDCONF extern int iksdcf; #endif /* IKSDCONF */ #ifndef NOFRILLS if (cx == XXBACK) { if ((x = cmcfm()) < 0) cwdf = 1; if (prevdir) { s = zgtdir(); if (!zchdir(prevdir)) { cwdf = 0; perror(s); } else { makestr(&prevdir,s); } } return(cwdf); } #endif /* NOFRILLS */ if (cx == XXCDUP) { #ifdef VMS s = "[-]"; #else #ifdef datageneral s = "^"; #else s = ".."; #endif /* datageneral */ #endif /* VMS */ ckstrncpy(line,s,LINBUFSIZ); goto gocd; } #ifndef NOSPL if (cx == XXKCD) { /* Symbolic (Kermit) CD */ char * p; int n, k; x = cmkey(kcdtab,nkcdtab,"Symbolic directory name","home",xxstring); if (x < 0) return(x); x = lookup(kcdtab,atmbuf,nkcdtab,&k); /* Get complete keyword */ if (x < 0) { printf("?Lookup error\n"); /* shouldn't happen */ return(-9); } if ((x = cmcfm()) < 0) return(x); if (k == VN_HOME) { /* HOME: allow SET HOME to override */ ckstrncpy(line,homepath(),LINBUFSIZ); } else { /* Other symbolic name */ /* Convert to variable syntax */ ckmakmsg(tmpbuf,TMPBUFSIZ,"\\v(",kcdtab[k].kwd,")",NULL); p = line; /* Expand the variable */ n = LINBUFSIZ; zzstring(tmpbuf,&p,&n); if (!line[0]) { /* Fail if variable not defined */ printf("?%s - not defined\n",tmpbuf); return(success = 0); } } s = line; /* All OK, go try to CD... */ goto gocd; } #endif /* NOSPL */ cdactive = 1; #ifdef GEMDOS if ((x = cmdir("Name of local directory, or carriage return", homepath(), &s, NULL ) ) < 0 ) return(x); #else #ifdef OS2 if ((x = cmdirp("Name of PC disk and/or directory,\n\ or press the Enter key for the default", homepath(), &s, ckcdpath ? ckcdpath : getenv("CDPATH"), xxstring ) ) < 0 ) return(x); #else #ifdef MAC x = ckstrncpy(temp,homepath(),32); if (x > 0) if (temp[x-1] != ':') { temp[x] = ':'; temp[x+1] = NUL; } if ((x = cmtxt("Name of Macintosh volume and/or folder,\n\ or press the Return key for the desktop on the boot disk", temp,&s, xxstring)) < 0 ) return(x); #else if ((x = cmdirp("Carriage return for home directory,\n\ or name of directory on this computer", #ifdef VMS "SYS$LOGIN", /* With no colon */ #else homepath(), /* In VMS this is "SYS$LOGIN:" */ #endif /* VMS */ &s, ckcdpath ? ckcdpath : getenv("CDPATH"), xxstring )) < 0) return(x); #endif /* MAC */ #endif /* OS2 */ #endif /* GEMDOS */ ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy */ s = line; #ifdef VMS if (ckmatch("*.DIR;1$",s,0,0)) if (cvtdir(s,tmpbuf,TMPBUFSIZ) > 0) s = tmpbuf; #endif /* VMS */ debug(F110,"docd",s,0); #ifndef MAC if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); #endif /* MAC */ gocd: #ifdef datageneral x = strlen(line); /* homdir ends in colon, */ if (x > 1 && line[x-1] == ':') /* and "dir" doesn't like that... */ line[x-1] = NUL; #endif /* datageneral */ #ifdef MAC cwdf = 1; if (!zchdir(s)) { cwdf = 0; if (*s != ':') { /* If it failed, */ char *p; /* supply leading colon */ int len = (int)strlen(s) + 2; p = malloc(len); /* and try again... */ if (p) { strcpy(p,":"); /* safe */ strcat(p,s); /* safe */ if (zchdir(p)) cwdf = 1; free(p); p = NULL; } } } if (!cwdf) perror(s); #else p = zgtdir(); if (!zchdir(s)) { cwdf = 0; #ifdef CKROOT if (ckrooterr) printf("?Off limits: \"%s\"\n",s); else #endif /* CKROOT */ perror(s); } else cwdf = 1; #endif /* MAC */ x = 0; if (cwdf) { makestr(&prevdir,p); debug(F111,"docd","srvcdmsg",srvcdmsg); if (srvcdmsg #ifdef IKSDCONF && !(inserver && !iksdcf) #endif /* IKSDCONF */ ) { int i; for (i = 0; i < 8; i++) { debug(F111,"docd cdmsgfile[i]",cdmsgfile[i],i); if (zchki(cdmsgfile[i]) > -1) { x = 1; dotype(cdmsgfile[i],xaskmore,0,0,NULL,0,NULL,0,0,NULL,0); break; } } } } /* xdocd: */ if (!x && srvcdmsg && !server #ifdef IKSDCONF && !(inserver && !iksdcf) #endif /* IKSDCONF */ && !quiet && !xcmdsrc) printf("%s\n", zgtdir()); return(cwdf); } static int on_ctrlc = 0; VOID fixcmd() { /* Fix command parser after interruption */ #ifndef NOSPL #ifndef NOONCTRLC if (nmac) { /* Any macros defined? */ int k; /* Yes */ char * s = "on_ctrlc"; /* Name of Ctrl-C handling macro */ k = mlook(mactab,s,nmac); /* Look it up. */ if (k >= 0) { /* If found, */ if (on_ctrlc++ == 0) { /* if not already executing, */ if (dodo(k,"",0) > -1) /* set it up, */ parser(1); /* execute it, */ } delmac(s,1); /* and undefine it. */ } } on_ctrlc = 0; #endif /* NOONCTRLC */ #endif /* NOSPL */ dostop(); /* Back to top level (also calls conint()). */ bgchk(); /* Check background status */ if (*psave) { /* If old prompt saved, */ cmsetp(psave); /* restore it. */ *psave = NUL; } success = 0; /* Tell parser last command failed */ } #ifndef NOSHOW /* SHOW FEATURES */ /* Note, presently optlist[] index overflow is not checked. There is plenty of room (less than 360 entries for 1000 slots). When space starts to get tight, check for noptlist >= NOPTLIST every time noptlist is incremented. */ #define NOPTLIST 1024 static int noptlist = 0; static char * optlist[NOPTLIST+1]; static int hpos = 0; int #ifdef CK_ANSIC prtopt( int * lines, char *s ) /* Print an option */ #else prtopt(lines,s) int * lines; char *s; #endif /* CK_ANSIC */ { int y, i; /* Does word wrap. */ if (!s) s = ""; i = *lines; if (!*s) { /* Empty argument */ if (hpos > 0) { /* means to end this line. */ printf("\n"); /* Not needed if already at */ if (++i > (cmd_rows - 3)) { /* beginning of new line. */ if (!askmore()) return(0); else i = 0; } } printf("\n"); /* And then make a blank line */ if (++i > (cmd_rows - 3)) { if (!askmore()) return(0); else i = 0; } hpos = 0; *lines = i; return(1); } y = (int)strlen(s) + 1; hpos += y; debug(F101,"prtopt hpos","",hpos); debug(F101,"prtopt cmd_cols","",cmd_cols); if ( #ifdef OS2 hpos > ((cmd_cols > 40) ? (cmd_cols - 1) : 79) #else /* OS2 */ hpos > ((tt_cols > 40) ? (tt_cols - 1) : 79) #endif /* OS2 */ ) { printf("\n"); if (++i > (cmd_rows - 3)) { if (!askmore()) return(0); else i = 0; } printf(" %s",s); hpos = y; } else printf(" %s",s); *lines = i; return(1); } static VOID initoptlist() { int i; if (noptlist > 0) return; for (i = 0; i < NOPTLIST; i++) optlist[i] = NULL; #ifdef MAC #ifdef MPW makestr(&(optlist[noptlist++]),"MPW"); #endif /* MPW */ #endif /* MAC */ #ifdef MAC #ifdef THINK_C makestr(&(optlist[noptlist++]),"THINK_C"); #endif /* THINK_C */ #endif /* MAC */ #ifdef __386__ makestr(&(optlist[noptlist++]),"__386__"); #endif /* __386__ */ /* Memory models... */ #ifdef __FLAT__ makestr(&(optlist[noptlist++]),"__FLAT__"); #endif /* __FLAT__ */ #ifdef __SMALL__ makestr(&(optlist[noptlist++]),"__SMALL__"); #endif /* __SMALL__ */ #ifdef __MEDIUM__ makestr(&(optlist[noptlist++]),"__MEDIUM__"); #endif /* __MEDIUM__ */ #ifdef __COMPACT__ makestr(&(optlist[noptlist++]),"__COMPACT__"); #endif /* __COMPACT__ */ #ifdef __LARGE__ makestr(&(optlist[noptlist++]),"__LARGE__"); #endif /* __LARGE__ */ #ifdef DEBUG #ifdef IFDEBUG makestr(&(optlist[noptlist++]),"IFDEBUG"); #else makestr(&(optlist[noptlist++]),"DEBUG"); #endif /* IFDEBUG */ #endif /* DEBUG */ #ifdef TLOG makestr(&(optlist[noptlist++]),"TLOG"); #endif /* TLOG */ #ifdef BIGBUFOK makestr(&(optlist[noptlist++]),"BIGBUFOK"); #endif /* BIGBUFOK */ #ifdef INPBUFSIZ sprintf(line,"INPBUFSIZ=%d",INPBUFSIZ); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* INPBUFSIZE */ #ifdef LINBUFSIZ sprintf(line,"LINBUFSIZ=%d",LINBUFSIZ); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* LINBUFSIZE */ #ifdef INBUFSIZE sprintf(line,"INBUFSIZE=%d",INBUFSIZE); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* INBUFSIZE */ #ifdef OBUFSIZE sprintf(line,"OBUFSIZE=%d",OBUFSIZE); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* OBUFSIZE */ #ifdef FD_SETSIZE sprintf(line,"FD_SETSIZE=%d",FD_SETSIZE); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* FD_SETSIZE */ #ifdef XFRCAN makestr(&(optlist[noptlist++]),"XFRCAN"); #endif /* XFRCAN */ #ifdef XPRINT makestr(&(optlist[noptlist++]),"XPRINT"); #endif /* XPRINT */ #ifdef PIPESEND makestr(&(optlist[noptlist++]),"PIPESEND"); #endif /* PIPESEND */ #ifdef C89 makestr(&(optlist[noptlist++]),"C89"); #endif /* C89 */ #ifdef C90 makestr(&(optlist[noptlist++]),"C90"); #endif /* C90 */ #ifdef C99 makestr(&(optlist[noptlist++]),"C99"); #endif /* C99 */ #ifdef CK_SPEED makestr(&(optlist[noptlist++]),"CK_SPEED"); #endif /* CK_SPEED */ #ifdef CK_FAST makestr(&(optlist[noptlist++]),"CK_FAST"); #endif /* CK_FAST */ #ifdef CK_APC makestr(&(optlist[noptlist++]),"CK_APC"); #endif /* CK_APC */ #ifdef CK_AUTODL makestr(&(optlist[noptlist++]),"CK_AUTODL"); #endif /* CK_AUTODL */ #ifdef CK_MKDIR makestr(&(optlist[noptlist++]),"CK_MKDIR"); #endif /* CK_MKDIR */ #ifdef HAVE_GSSAPI makestr(&(optlist[noptlist++]),"HAVE_GSSAPI"); #endif /* HAVE_GSSAPI */ #ifdef HAVE_KRB4 makestr(&(optlist[noptlist++]),"HAVE_KRB4"); #endif /* HAVE_KRB4 */ #ifdef HAVE_KRB5 makestr(&(optlist[noptlist++]),"HAVE_KRB5"); #endif /* HAVE_KRB5 */ #ifdef HAVE_LOCALE makestr(&(optlist[noptlist++]),"HAVE_LOCALE"); #endif /* HAVE_LOCALE */ #ifdef HAVE_SNPRINTF makestr(&(optlist[noptlist++]),"HAVE_SNPRINTF"); #endif /* HAVE_SNPRINTF */ #ifdef NOMKDIR makestr(&(optlist[noptlist++]),"NOMKDIR"); #endif /* NOMKDIR */ #ifdef CK_LABELED makestr(&(optlist[noptlist++]),"CK_LABELED"); #endif /* CK_LABELED */ #ifdef NODIAL makestr(&(optlist[noptlist++]),"NODIAL"); #endif /* NODIAL */ #ifdef MINIDIAL makestr(&(optlist[noptlist++]),"MINIDIAL"); #endif /* MINIDIAL */ #ifdef WHATAMI makestr(&(optlist[noptlist++]),"WHATAMI"); #endif /* WHATAMI */ #ifdef DYNAMIC makestr(&(optlist[noptlist++]),"DYNAMIC"); #endif /* DYNAMIC */ #ifndef NOSPL sprintf(line,"CMDDEP=%d",CMDDEP); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* NOSPL */ #ifdef MAXPATHLEN sprintf(line,"MAXPATHLEN=%d",MAXPATHLEN); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MAXPATHLEN */ #ifdef DEVNAMLEN sprintf(line,"DEVNAMLEN=%d",DEVNAMLEN); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* DEVNAMLEN */ #ifdef NO_PARAM_H makestr(&(optlist[noptlist++]),"NO_PARAM_H"); #endif /* NO_PARAM_H */ #ifdef INCL_PARAM_H makestr(&(optlist[noptlist++]),"INCL_PARAM_H"); #endif /* INCL_PARAM_H */ #ifdef CKMAXPATH sprintf(line,"CKMAXPATH=%d",CKMAXPATH); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* CKMAXPATH */ sprintf(line,"CKMAXOPEN=%d",CKMAXOPEN); /* SAFE */ makestr(&(optlist[noptlist++]),line); #ifndef UNIX /* These aren't actually used... In Unix we get maximum number of open files from sysconf() at runtime. */ sprintf(line,"Z_MAXCHAN=%d",Z_MAXCHAN); /* SAFE */ makestr(&(optlist[noptlist++]),line); #ifdef OPEN_MAX sprintf(line,"OPEN_MAX=%d",OPEN_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* OPEN_MAX */ #ifdef _POSIX_OPEN_MAX sprintf(line,"_POSIX_OPEN_MAX=%d",_POSIX_OPEN_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* _POSIX_OPEN_MAX */ #endif /* UNIX */ #ifdef CKCHANNELIO { extern int z_maxchan; #ifdef UNIX extern int ckmaxfiles; sprintf(line,"ckmaxfiles=%d",ckmaxfiles); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* UNIX */ sprintf(line,"z_maxchan=%d",z_maxchan); /* SAFE */ makestr(&(optlist[noptlist++]),line); } #endif /* CKCHANNELIO */ #ifdef FOPEN_MAX sprintf(line,"FOPEN_MAX=%d",FOPEN_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* FOPEN_MAX */ #ifdef MAXGETPATH sprintf(line,"MAXGETPATH=%d",MAXGETPATH); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MAXGETPATH */ #ifdef CMDBL sprintf(line,"CMDBL=%d",CMDBL); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* CMDBL */ #ifdef VNAML sprintf(line,"VNAML=%d",VNAML); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* VNAML */ #ifdef ARRAYREFLEN sprintf(line,"ARRAYREFLEN=%d",ARRAYREFLEN); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* ARRAYREFLEN */ #ifdef UIDBUFLEN sprintf(line,"UIDBUFLEN=%d",UIDBUFLEN); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* UIDBUFLEN */ #ifdef FORDEPTH sprintf(line,"FORDEPTH=%d",FORDEPTH); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* FORDEPTH */ #ifdef MAXTAKE sprintf(line,"MAXTAKE=%d",MAXTAKE); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MAXTAKE */ #ifdef MACLEVEL sprintf(line,"MACLEVEL=%d",MACLEVEL); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MACLEVEL */ #ifdef MAC_MAX sprintf(line,"MAC_MAX=%d",MAC_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MAC_MAX */ #ifdef _LARGEFILE_SOURCE makestr(&(optlist[noptlist++]),"_LARGEFILE_SOURCE"); #endif /* _LARGEFILE_SOURCE */ #ifdef _FILE_OFFSET_BITS sprintf(line,"_FILE_OFFSET_BITS=%d",_FILE_OFFSET_BITS); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* _FILE_OFFSET_BITS */ #ifdef __USE_FILE_OFFSET64 makestr(&(optlist[noptlist++]),"__USE_FILE_OFFSET64"); #endif /* __USE_FILE_OFFSET64 */ #ifdef __USE_LARGEFILE64 makestr(&(optlist[noptlist++]),"__USE_LARGEFILE64"); #endif /* __USE_LARGEFILE64 */ #ifdef TMPBUFSIZ sprintf(line,"TMPBUFSIZ=%d",TMPBUFSIZ); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* TMPBUFSIZ */ #ifdef LINEBUFSIZ sprintf(line,"LINEBUFSIZ=%d",LINEBUFSIZ); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* LINEBUFSIZ */ #ifdef COMMENT #ifdef CHAR_MAX sprintf(line,"CHAR_MAX=%llx",CHAR_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* CHAR_MAX */ #ifdef UCHAR_MAX sprintf(line,"UCHAR_MAX=%llx",UCHAR_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* UCHAR_MAX */ #ifdef SHRT_MAX sprintf(line,"SHRT_MAX=%llx",SHRT_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* SHRT_MAX */ #ifdef USHRT_MAX sprintf(line,"USHRT_MAX=%llx",USHRT_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* USHRT_MAX */ #ifdef INT_MAX sprintf(line,"INT_MAX=%llx",INT_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* INT_MAX */ #ifdef UINT_MAX sprintf(line,"UINT_MAX=%llx",UINT_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* UINT_MAX */ #ifdef MAX_LONG sprintf(line,"MAX_LONG=%llx",MAX_LONG); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MAX_LONG */ #ifdef LONG_MAX sprintf(line,"LONG_MAX=%llx",LONG_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* LONG_MAX */ #ifdef ULONG_MAX sprintf(line,"ULONG_MAX=%llx",ULONG_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* ULONG_MAX */ #ifdef MAXINT sprintf(line,"MAXINT=%llx",MAXINT); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MAXINT */ #ifdef MAXLONG sprintf(line,"MAXLONG=%llx",MAXLONG); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MAXLONG */ #ifdef NT #ifdef LLONG_MAX sprintf(line,"LLONG_MAX=%I64x",LLONG_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* LLONG_MAX */ #ifdef ULLONG_MAX sprintf(line,"ULLONG_MAX=%I64x",ULLONG_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* ULLONG_MAX */ #ifdef MAXLONGLONG sprintf(line,"MAXLONGLONG=%I64x",MAXLONGLONG); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MAXLONGLONG */ #else #ifdef LLONG_MAX sprintf(line,"LLONG_MAX=%llx",LLONG_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* LLONG_MAX */ #ifdef ULLONG_MAX sprintf(line,"ULLONG_MAX=%llx",ULLONG_MAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* ULLONG_MAX */ #ifdef MAXLONGLONG sprintf(line,"MAXLONGLONG=%llx",MAXLONGLONG); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MAXLONGLONG */ #endif #ifdef _INTEGRAL_MAX_BITS sprintf(line,"_INTEGRAL_MAX_BITS=%d",_INTEGRAL_MAX_BITS); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* _INTEGRAL_MAX_BITS */ #endif /* COMMENT */ #ifdef MINPUTMAX sprintf(line,"MINPUTMAX=%d",MINPUTMAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MINPUTMAX */ #ifdef MAXWLD sprintf(line,"MAXWLD=%d",MAXWLD); /* SAFE */ makestr(&(optlist[noptlist++]),line); #else #ifdef OS2 makestr(&(optlist[noptlist++]),"MAXWLD=unlimited"); #endif /* OS2 */ #endif /* MAXWLD */ #ifdef MSENDMAX sprintf(line,"MSENDMAX=%d",MSENDMAX); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MSENDMAX */ #ifdef MAXDDIR sprintf(line,"MAXDDIR=%d",MAXDDIR); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MAXDDIR */ #ifdef MAXDNUMS sprintf(line,"MAXDNUMS=%d",MAXDNUMS); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* MAXDNUMS */ #ifdef UNIX makestr(&(optlist[noptlist++]),"UNIX"); #endif /* UNIX */ #ifdef VMS makestr(&(optlist[noptlist++]),"VMS"); #ifdef __VMS_VER sprintf(line,"__VMS_VER=%d",__VMS_VER); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* __VMS_VER */ #ifdef VMSV70 makestr(&(optlist[noptlist++]),"VMSV70"); #endif /* VMSV70 */ #ifdef OLD_VMS makestr(&(optlist[noptlist++]),"OLD_VMS"); #endif /* OLD_VMS */ #ifdef vms makestr(&(optlist[noptlist++]),"vms"); #endif /* vms */ #ifdef VMSV60 makestr(&(optlist[noptlist++]),"VMSV60"); #endif /* VMSV60 */ #ifdef VMSV80 makestr(&(optlist[noptlist++]),"VMSV80"); #endif /* VMSV80 */ #ifdef VMSSHARE makestr(&(optlist[noptlist++]),"VMSSHARE"); #endif /* VMSSHARE */ #ifdef NOVMSSHARE makestr(&(optlist[noptlist++]),"NOVMSSHARE"); #endif /* NOVMSSHARE */ #endif /* VMS */ #ifdef NOARROWKEYS sprintf(line,"NOARROWKEYS"); makestr(&(optlist[noptlist++]),line); #endif /* NOARROWKEYS */ #ifdef DOARROWKEYS sprintf(line,"DOARROWKEYS"); makestr(&(optlist[noptlist++]),line); #endif /* DOARROWKEYS */ #ifdef datageneral makestr(&(optlist[noptlist++]),"datageneral"); #endif /* datageneral */ #ifdef apollo makestr(&(optlist[noptlist++]),"apollo"); #endif /* apollo */ #ifdef aegis makestr(&(optlist[noptlist++]),"aegis"); #endif /* aegis */ #ifdef A986 makestr(&(optlist[noptlist++]),"A986"); #endif /* A986 */ #ifdef AMIGA makestr(&(optlist[noptlist++]),"AMIGA"); #endif /* AMIGA */ #ifdef CONVEX9 makestr(&(optlist[noptlist++]),"CONVEX9"); #endif /* CONVEX9 */ #ifdef CONVEX10 makestr(&(optlist[noptlist++]),"CONVEX10"); #endif /* CONVEX9 */ #ifdef MAC makestr(&(optlist[noptlist++]),"MAC"); #endif /* MAC */ #ifdef AUX makestr(&(optlist[noptlist++]),"AUX"); #endif /* AUX */ #ifdef OS2 makestr(&(optlist[noptlist++]),"OS2"); #ifdef NT makestr(&(optlist[noptlist++]),"NT"); #endif /* NT */ #endif /* OS2 */ #ifdef OSK makestr(&(optlist[noptlist++]),"OS9"); #endif /* OSK */ #ifdef MSDOS makestr(&(optlist[noptlist++]),"MSDOS"); #endif /* MSDOS */ #ifdef DIRENT makestr(&(optlist[noptlist++]),"DIRENT"); #endif /* DIRENT */ #ifdef SDIRENT makestr(&(optlist[noptlist++]),"SDIRENT"); #endif /* SDIRENT */ #ifdef NDIR makestr(&(optlist[noptlist++]),"NDIR"); #endif /* NDIR */ #ifdef XNDIR makestr(&(optlist[noptlist++]),"XNDIR"); #endif /* XNDIR */ #ifdef SAVEDUID makestr(&(optlist[noptlist++]),"SAVEDUID"); #endif /* SAVEDUID */ #ifdef RENAME makestr(&(optlist[noptlist++]),"RENAME"); #endif /* RENAME */ #ifdef CK_TMPDIR makestr(&(optlist[noptlist++]),"CK_TMPDIR"); #endif /* CK_TMPDIR */ #ifdef NOCCTRAP makestr(&(optlist[noptlist++]),"NOCCTRAP"); #endif /* NOCCTRAP */ #ifdef NOCOTFMC makestr(&(optlist[noptlist++]),"NOCOTFMC"); #endif /* NOCOTFMC */ #ifdef NOFRILLS makestr(&(optlist[noptlist++]),"NOFRILLS"); #endif /* NOFRILLS */ #ifdef PARSENSE makestr(&(optlist[noptlist++]),"PARSENSE"); #endif /* PARSENSE */ #ifdef TIMEH makestr(&(optlist[noptlist++]),"TIMEH"); #endif /* TIMEH */ #ifdef NOTIMEH makestr(&(optlist[noptlist++]),"TIMEH"); #endif /* NOTIMEH */ #ifdef SYSTIMEH makestr(&(optlist[noptlist++]),"SYSTIMEH"); #endif /* SYSTIMEH */ #ifdef NOSYSTIMEH makestr(&(optlist[noptlist++]),"SYSTIMEH"); #endif /* NOSYSTIMEH */ #ifdef SYSTIMEBH makestr(&(optlist[noptlist++]),"SYSTIMEBH"); #endif /* SYSTIMEBH */ #ifdef NOSYSTIMEBH makestr(&(optlist[noptlist++]),"SYSTIMEBH"); #endif /* NOSYSTIMEBH */ #ifdef UTIMEH makestr(&(optlist[noptlist++]),"UTIMEH"); #endif /* UTIMEH */ #ifdef SYSUTIMEH makestr(&(optlist[noptlist++]),"SYSUTIMEH"); #endif /* SYSUTIMEH */ #ifdef CK_NEED_SIG makestr(&(optlist[noptlist++]),"CK_NEED_SIG"); #endif /* CK_NEED_SIG */ #ifdef CK_TTYFD makestr(&(optlist[noptlist++]),"CK_TTYFD"); #endif /* CK_TTYFD */ #ifdef NETCONN makestr(&(optlist[noptlist++]),"NETCONN"); #endif /* NETCONN */ #ifdef TCPSOCKET makestr(&(optlist[noptlist++]),"TCPSOCKET"); #ifdef NOTCPOPTS makestr(&(optlist[noptlist++]),"NOTCPOPTS"); #endif /* NOTCPOPTS */ #ifdef CK_DNS_SRV makestr(&(optlist[noptlist++]),"CK_DNS_SRV"); #endif /* CK_DNS_SRV */ #ifdef NO_DNS_SRV makestr(&(optlist[noptlist++]),"NO_DNS_SRV"); #endif /* NO_DNS_SRV */ #ifdef CKGHNLHOST makestr(&(optlist[noptlist++]),"CKGHNLHOST"); #endif /* CKGHNLHOST */ #ifdef NOLISTEN makestr(&(optlist[noptlist++]),"NOLISTEN"); #endif /* NOLISTEN */ #ifdef SOL_SOCKET makestr(&(optlist[noptlist++]),"SOL_SOCKET"); #endif /* SOL_SOCKET */ #ifdef SO_OOBINLINE makestr(&(optlist[noptlist++]),"SO_OOBINLINE"); #endif /* SO_OOBINLNE */ #ifdef SO_DONTROUTE makestr(&(optlist[noptlist++]),"SO_DONTROUTE"); #endif /* SO_DONTROUTE */ #ifdef SO_KEEPALIVE makestr(&(optlist[noptlist++]),"SO_KEEPALIVE"); #endif /* SO_KEEPALIVE */ #ifdef SO_LINGER makestr(&(optlist[noptlist++]),"SO_LINGER"); #endif /* SO_LINGER */ #ifdef TCP_NODELAY makestr(&(optlist[noptlist++]),"TCP_NODELAY"); #endif /* TCP_NODELAY */ #ifdef SO_SNDBUF makestr(&(optlist[noptlist++]),"SO_SNDBUF"); #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF makestr(&(optlist[noptlist++]),"SO_RCVBUF"); #endif /* SO_RCVBUF */ #ifdef h_addr makestr(&(optlist[noptlist++]),"h_addr"); #endif /* h_addr */ #ifdef HADDRLIST makestr(&(optlist[noptlist++]),"HADDRLIST"); #endif /* HADDRLIST */ #ifdef CK_SOCKS makestr(&(optlist[noptlist++]),"CK_SOCKS"); #ifdef CK_SOCKS5 makestr(&(optlist[noptlist++]),"CK_SOCKS5"); #endif /* CK_SOCKS5 */ #ifdef CK_SOCKS_NS makestr(&(optlist[noptlist++]),"CK_SOCKS_NS"); #endif /* CK_SOCKS_NS */ #endif /* CK_SOCKS */ #ifdef RLOGCODE makestr(&(optlist[noptlist++]),"RLOGCODE"); #endif /* RLOGCODE */ #ifdef NETCMD makestr(&(optlist[noptlist++]),"NETCMD"); #endif /* NETCMD */ #ifdef NONETCMD makestr(&(optlist[noptlist++]),"NONETCMD"); #endif /* NONETCMD */ #ifdef NETPTY makestr(&(optlist[noptlist++]),"NETPTY"); #endif /* NETPTY */ #ifdef CK_ENVIRONMENT makestr(&(optlist[noptlist++]),"CK_ENVIRONMENT"); #endif /* CK_ENVIRONMENT */ #endif /* TCPSOCKET */ #ifdef TNCODE makestr(&(optlist[noptlist++]),"TNCODE"); #endif /* TNCODE */ #ifdef CK_FORWARD_X makestr(&(optlist[noptlist++]),"CK_FORWARD_X"); #endif /* CK_FORWARD_X */ #ifdef TN_COMPORT makestr(&(optlist[noptlist++]),"TN_COMPORT"); #endif /* TN_COMPORT */ #ifdef MULTINET makestr(&(optlist[noptlist++]),"MULTINET"); #endif /* MULTINET */ #ifdef DEC_TCPIP makestr(&(optlist[noptlist++]),"DEC_TCPIP"); #endif /* DEC_TCPIP */ #ifdef TCPWARE makestr(&(optlist[noptlist++]),"TCPWARE"); #endif /* TCPWARE */ #ifdef UCX50 makestr(&(optlist[noptlist++]),"UCX50"); #endif /* UCX50 */ #ifdef CMU_TCPIP makestr(&(optlist[noptlist++]),"CMU_TCPIP"); #endif /* CMU_TCPIP */ #ifdef TTLEBUF makestr(&(optlist[noptlist++]),"TTLEBUF"); #endif /* TTLEBUF */ #ifdef NETLEBUF makestr(&(optlist[noptlist++]),"NETLEBUF"); #endif /* NETLEBUF */ #ifdef IKS_OPTION makestr(&(optlist[noptlist++]),"IKS_OPTION"); #endif /* IKS_OPTION */ #ifdef IKSDB makestr(&(optlist[noptlist++]),"IKSDB"); #endif /* IKSDB */ #ifdef IKSDCONF makestr(&(optlist[noptlist++]),"IKSDCONF"); #endif /* IKSDCONF */ #ifdef CK_LOGIN makestr(&(optlist[noptlist++]),"CK_LOGIN"); #endif /* CK_LOGIN */ #ifdef CK_PAM makestr(&(optlist[noptlist++]),"CK_PAM"); #endif /* CK_PAM */ #ifdef CK_SHADOW makestr(&(optlist[noptlist++]),"CK_SHADOW"); #endif /* CK_SHADOW */ #ifdef CONGSPD makestr(&(optlist[noptlist++]),"CONGSPD"); #endif /* CONGSPD */ #ifdef SUNX25 makestr(&(optlist[noptlist++]),"SUNX25"); #endif /* SUNX25 */ #ifdef IBMX25 makestr(&(optlist[noptlist++]),"IBMX25"); #endif /* IBMX25 */ #ifdef HPX25 makestr(&(optlist[noptlist++]),"HPX25"); #endif /* HPX25 */ #ifdef DECNET makestr(&(optlist[noptlist++]),"DECNET"); #endif /* DECNET */ #ifdef SUPERLAT makestr(&(optlist[noptlist++]),"SUPERLAT"); #endif /* SUPERLAT */ #ifdef NPIPE makestr(&(optlist[noptlist++]),"NPIPE"); #endif /* NPIPE */ #ifdef CK_NETBIOS makestr(&(optlist[noptlist++]),"CK_NETBIOS"); #endif /* CK_NETBIOS */ #ifdef ATT7300 makestr(&(optlist[noptlist++]),"ATT7300"); #endif /* ATT7300 */ #ifdef ATT6300 makestr(&(optlist[noptlist++]),"ATT6300"); #endif /* ATT6300 */ #ifdef HDBUUCP makestr(&(optlist[noptlist++]),"HDBUUCP"); #endif /* HDBUUCP */ #ifdef USETTYLOCK makestr(&(optlist[noptlist++]),"USETTYLOCK"); #endif /* USETTYLOCK */ #ifdef USE_UU_LOCK makestr(&(optlist[noptlist++]),"USE_UU_LOCK"); #endif /* USE_UU_LOCK */ #ifdef HAVE_LOCKDEV makestr(&(optlist[noptlist++]),"HAVE_LOCKDEV"); #endif /* HAVE_LOCKDEV */ #ifdef HAVE_BAUDBOY makestr(&(optlist[noptlist++]),"HAVE_BAUDBOY"); #endif /* HAVE_BAUDBOY */ #ifdef HAVE_OPENPTY makestr(&(optlist[noptlist++]),"HAVE_OPENPTY"); #endif /* HAVE_OPENPTY */ #ifdef TTPTYCMD makestr(&(optlist[noptlist++]),"TTPTYCMD"); #endif /* TTPTYCMD */ #ifdef NOUUCP makestr(&(optlist[noptlist++]),"NOUUCP"); #endif /* NOUUCP */ #ifdef LONGFN makestr(&(optlist[noptlist++]),"LONGFN"); #endif /* LONGFN */ #ifdef RDCHK makestr(&(optlist[noptlist++]),"RDCHK"); #endif /* RDCHK */ #ifdef SELECT makestr(&(optlist[noptlist++]),"SELECT"); #endif /* SELECT */ #ifdef USLEEP makestr(&(optlist[noptlist++]),"USLEEP"); #endif /* USLEEP */ #ifdef NAP makestr(&(optlist[noptlist++]),"NAP"); #endif /* NAP */ #ifdef NAPHACK makestr(&(optlist[noptlist++]),"NAPHACK"); #endif /* NAPHACK */ #ifdef CK_POLL makestr(&(optlist[noptlist++]),"CK_POLL"); #endif /* CK_POLL */ #ifdef NOIEXTEN makestr(&(optlist[noptlist++]),"NOIEXTEN"); #endif /* NOIEXTEN */ #ifdef EXCELAN makestr(&(optlist[noptlist++]),"EXCELAN"); #endif /* EXCELAN */ #ifdef INTERLAN makestr(&(optlist[noptlist++]),"INTERLAN"); #endif /* INTERLAN */ #ifdef NOFILEH makestr(&(optlist[noptlist++]),"NOFILEH"); #endif /* NOFILEH */ #ifdef NOSYSIOCTLH makestr(&(optlist[noptlist++]),"NOSYSIOCTLH"); #endif /* NOSYSIOCTLH */ #ifdef DCLPOPEN makestr(&(optlist[noptlist++]),"DCLPOPEN"); #endif /* DCLPOPEN */ #ifdef NOSETBUF makestr(&(optlist[noptlist++]),"NOSETBUF"); #endif /* NOWSETBUF */ #ifdef NOWTMP makestr(&(optlist[noptlist++]),"NOWTMP"); #endif /* NOWTMP */ #ifdef NOXFER makestr(&(optlist[noptlist++]),"NOXFER"); #endif /* NOXFER */ #ifdef NOCURSES makestr(&(optlist[noptlist++]),"NOCURSES"); #endif /* NOCURSES */ #ifdef NOSERVER makestr(&(optlist[noptlist++]),"NOSERVER"); #endif /* NOSERVER */ #ifdef NOPATTERNS makestr(&(optlist[noptlist++]),"NOPATTERNS"); #else #ifdef PATTERNS makestr(&(optlist[noptlist++]),"PATTERNS"); #endif /* PATTERNS */ #endif /* NOPATTERNS */ #ifdef NOCKEXEC makestr(&(optlist[noptlist++]),"NOCKEXEC"); #else #ifdef CKEXEC makestr(&(optlist[noptlist++]),"CKEXEC"); #endif /* CKEXEC */ #endif /* NOCKEXEC */ #ifdef NOAUTODL makestr(&(optlist[noptlist++]),"NOAUTODL"); #endif /* NOAUTODL */ #ifdef NOMSEND makestr(&(optlist[noptlist++]),"NOMSEND"); #endif /* NOMSEND */ #ifdef NOFDZERO makestr(&(optlist[noptlist++]),"NOFDZERO"); #endif /* NOFDZERO */ #ifdef NOPOPEN makestr(&(optlist[noptlist++]),"NOPOPEN"); #endif /* NOPOPEN */ #ifdef NOPARTIAL makestr(&(optlist[noptlist++]),"NOPARTIAL"); #endif /* NOPARTIAL */ #ifdef NOKVERBS makestr(&(optlist[noptlist++]),"NOKVERBS"); #endif /* NOKVERBS */ #ifdef NOPRINTFSUBST makestr(&(optlist[noptlist++]),"NOPRINTFSUBST"); #endif /* NOPRINTFSUBST */ #ifdef NOSETREU makestr(&(optlist[noptlist++]),"NOSETREU"); #endif /* NOSETREU */ #ifdef NOSYSLOG makestr(&(optlist[noptlist++]),"NOSYSLOG"); #endif /* NOSYSLOG */ #ifdef LCKDIR makestr(&(optlist[noptlist++]),"LCKDIR"); #endif /* LCKDIR */ #ifdef ACUCNTRL makestr(&(optlist[noptlist++]),"ACUCNTRL"); #endif /* ACUCNTRL */ #ifdef BSD4 makestr(&(optlist[noptlist++]),"BSD4"); #endif /* BSD4 */ #ifdef BSD44 makestr(&(optlist[noptlist++]),"BSD44"); #endif /* BSD44 */ #ifdef BSD41 makestr(&(optlist[noptlist++]),"BSD41"); #endif /* BSD41 */ #ifdef BSD43 makestr(&(optlist[noptlist++]),"BSD43"); #endif /* BSD43 */ #ifdef BSD29 makestr(&(optlist[noptlist++]),"BSD29"); #endif /* BSD29 */ #ifdef BSDI makestr(&(optlist[noptlist++]),"BSDI"); #endif /* BSDI */ #ifdef __bsdi__ makestr(&(optlist[noptlist++]),"__bsdi__"); #endif /* __bsdi__ */ #ifdef __NetBSD__ makestr(&(optlist[noptlist++]),"__NetBSD__"); #endif /* __NetBSD__ */ #ifdef __OpenBSD__ makestr(&(optlist[noptlist++]),"__OpenBSD__"); #endif /* __OpenBSD__ */ #ifdef __FreeBSD__ makestr(&(optlist[noptlist++]),"__FreeBSD__"); #endif /* __FreeBSD__ */ #ifdef FREEBSD4 makestr(&(optlist[noptlist++]),"FREEBSD4"); #endif /* FREEBSD4 */ #ifdef FREEBSD8 makestr(&(optlist[noptlist++]),"FREEBSD8"); #endif /* FREEBSD8 */ #ifdef FREEBSD9 makestr(&(optlist[noptlist++]),"FREEBSD9"); #endif /* FREEBSD9 */ #ifdef __linux__ makestr(&(optlist[noptlist++]),"__linux__"); #endif /* __linux__ */ #ifdef LINUX_HI_SPD makestr(&(optlist[noptlist++]),"LINUX_HI_SPD"); #endif /* LINUX_HI_SPD */ #ifdef LYNXOS makestr(&(optlist[noptlist++]),"LYNXOS"); #endif /* LYNXOS */ #ifdef V7 makestr(&(optlist[noptlist++]),"V7"); #endif /* V7 */ #ifdef AIX370 makestr(&(optlist[noptlist++]),"AIX370"); #endif /* AIX370 */ #ifdef RTAIX makestr(&(optlist[noptlist++]),"RTAIX"); #endif /* RTAIX */ #ifdef HPUX makestr(&(optlist[noptlist++]),"HPUX"); #endif /* HPUX */ #ifdef HPUX9 makestr(&(optlist[noptlist++]),"HPUX9"); #endif /* HPUX9 */ #ifdef HPUX10 makestr(&(optlist[noptlist++]),"HPUX10"); #endif /* HPUX10 */ #ifdef HPUX1000 makestr(&(optlist[noptlist++]),"HPUX1000"); #endif /* HPUX1000 */ #ifdef HPUX1100 makestr(&(optlist[noptlist++]),"HPUX1100"); #endif /* HPUX1100 */ #ifdef HPUXPRE65 makestr(&(optlist[noptlist++]),"HPUXPRE65"); #endif /* HPUXPRE65 */ #ifdef DGUX makestr(&(optlist[noptlist++]),"DGUX"); #endif /* DGUX */ #ifdef DGUX430 makestr(&(optlist[noptlist++]),"DGUX430"); #endif /* DGUX430 */ #ifdef DGUX540 makestr(&(optlist[noptlist++]),"DGUX540"); #endif /* DGUX540 */ #ifdef DGUX543 makestr(&(optlist[noptlist++]),"DGUX543"); #endif /* DGUX543 */ #ifdef DGUX54410 makestr(&(optlist[noptlist++]),"DGUX54410"); #endif /* DGUX54410 */ #ifdef DGUX54411 makestr(&(optlist[noptlist++]),"DGUX54411"); #endif /* DGUX54411 */ #ifdef sony_news makestr(&(optlist[noptlist++]),"sony_news"); #endif /* sony_news */ #ifdef CIE makestr(&(optlist[noptlist++]),"CIE"); #endif /* CIE */ #ifdef XENIX makestr(&(optlist[noptlist++]),"XENIX"); #endif /* XENIX */ #ifdef SCO_XENIX makestr(&(optlist[noptlist++]),"SCO_XENIX"); #endif /* SCO_XENIX */ #ifdef ISIII makestr(&(optlist[noptlist++]),"ISIII"); #endif /* ISIII */ #ifdef I386IX makestr(&(optlist[noptlist++]),"I386IX"); #endif /* I386IX */ #ifdef RTU makestr(&(optlist[noptlist++]),"RTU"); #endif /* RTU */ #ifdef PROVX1 makestr(&(optlist[noptlist++]),"PROVX1"); #endif /* PROVX1 */ #ifdef PYRAMID makestr(&(optlist[noptlist++]),"PYRAMID"); #endif /* PYRAMID */ #ifdef TOWER1 makestr(&(optlist[noptlist++]),"TOWER1"); #endif /* TOWER1 */ #ifdef UTEK makestr(&(optlist[noptlist++]),"UTEK"); #endif /* UTEK */ #ifdef ZILOG makestr(&(optlist[noptlist++]),"ZILOG"); #endif /* ZILOG */ #ifdef TRS16 makestr(&(optlist[noptlist++]),"TRS16"); #endif /* TRS16 */ #ifdef MINIX makestr(&(optlist[noptlist++]),"MINIX"); #endif /* MINIX */ #ifdef MINIX2 makestr(&(optlist[noptlist++]),"MINIX2"); #endif /* MINIX2 */ #ifdef MINIX3 makestr(&(optlist[noptlist++]),"MINIX3"); #endif /* MINIX3 */ #ifdef MINIX315 makestr(&(optlist[noptlist++]),"MINIX315"); #endif /* MINIX315 */ #ifdef MINIX340 makestr(&(optlist[noptlist++]),"MINIX340"); /* 2020-02-01 TIH */ #endif /* MINIX340 */ #ifdef C70 makestr(&(optlist[noptlist++]),"C70"); #endif /* C70 */ #ifdef AIXPS2 makestr(&(optlist[noptlist++]),"AIXPS2"); #endif /* AIXPS2 */ #ifdef AIXRS makestr(&(optlist[noptlist++]),"AIXRS"); #endif /* AIXRS */ #ifdef UTSV makestr(&(optlist[noptlist++]),"UTSV"); #endif /* UTSV */ #ifdef ATTSV makestr(&(optlist[noptlist++]),"ATTSV"); #endif /* ATTSV */ #ifdef SVR3 makestr(&(optlist[noptlist++]),"SVR3"); #endif /* SVR3 */ #ifdef SVR4 makestr(&(optlist[noptlist++]),"SVR4"); #endif /* SVR4 */ #ifdef DELL_SVR4 makestr(&(optlist[noptlist++]),"DELL_SVR4"); #endif /* DELL_SVR4 */ #ifdef ICL_SVR4 makestr(&(optlist[noptlist++]),"ICL_SVR4"); #endif /* ICL_SVR4 */ #ifdef OSF makestr(&(optlist[noptlist++]),"OSF"); #endif /* OSF */ #ifdef OSF1 makestr(&(optlist[noptlist++]),"OSF1"); #endif /* OSF1 */ #ifdef __OSF makestr(&(optlist[noptlist++]),"__OSF"); #endif /* __OSF */ #ifdef __OSF__ makestr(&(optlist[noptlist++]),"__OSF__"); #endif /* __OSF__ */ #ifdef __osf__ makestr(&(optlist[noptlist++]),"__osf__"); #endif /* __osf__ */ #ifdef __OSF1 makestr(&(optlist[noptlist++]),"__OSF1"); #endif /* __OSF1 */ #ifdef __OSF1__ makestr(&(optlist[noptlist++]),"__OSF1__"); #endif /* __OSF1__ */ #ifdef PTX makestr(&(optlist[noptlist++]),"PTX"); #endif /* PTX */ #ifdef POSIX makestr(&(optlist[noptlist++]),"POSIX"); #endif /* POSIX */ #ifdef BSD44ORPOSIX makestr(&(optlist[noptlist++]),"BSD44ORPOSIX"); #endif /* BSD44ORPOSIX */ #ifdef SVORPOSIX makestr(&(optlist[noptlist++]),"SVORPOSIX"); #endif /* SVORPOSIX */ #ifdef SVR4ORPOSIX makestr(&(optlist[noptlist++]),"SVR4ORPOSIX"); #endif /* SVR4ORPOSIX */ #ifdef OS2ORVMS makestr(&(optlist[noptlist++]),"OS2ORVMS"); #endif /* OS2ORVMS */ #ifdef OS2ORWINDOWS makestr(&(optlist[noptlist++]),"OS2ORWINDOWS"); #endif /* OS2ORWINDOWS */ #ifdef OS2ORUNIX makestr(&(optlist[noptlist++]),"OS2ORUNIX"); #endif /* OS2ORUNIX */ #ifdef VMSORUNIX makestr(&(optlist[noptlist++]),"VMSORUNIX"); #endif /* VMSORUNIX */ #ifdef VMS64BIT makestr(&(optlist[noptlist++]),"VMS64BIT"); /* VMS on non-VAX */ #endif /* VMS64BIT */ #ifdef _POSIX_SOURCE makestr(&(optlist[noptlist++]),"_POSIX_SOURCE"); #endif /* _POSIX_SOURCE */ #ifdef _XOPEN_SOURCE makestr(&(optlist[noptlist++]),"_XOPEN_SOURCE"); #endif #ifdef _ALL_SOURCE makestr(&(optlist[noptlist++]),"_ALL_SOURCE"); #endif #ifdef _SVID3 makestr(&(optlist[noptlist++]),"_SVID3"); #endif /* _SVID3 */ #ifdef Plan9 makestr(&(optlist[noptlist++]),"Plan9"); #endif /* Plan9 */ #ifdef SOLARIS makestr(&(optlist[noptlist++]),"SOLARIS"); #ifdef SOLARIS24 makestr(&(optlist[noptlist++]),"SOLARIS24"); #endif /* SOLARIS24 */ #ifdef SOLARIS25 makestr(&(optlist[noptlist++]),"SOLARIS25"); #endif /* SOLARIS25 */ #ifdef SOLARIS26 makestr(&(optlist[noptlist++]),"SOLARIS26"); #endif /* SOLARIS26 */ #ifdef SOLARIS7 makestr(&(optlist[noptlist++]),"SOLARIS7"); #endif /* SOLARIS7 */ #ifdef SOLARIS8 makestr(&(optlist[noptlist++]),"SOLARIS8"); #endif /* SOLARIS8 */ #ifdef SOLARIS9 makestr(&(optlist[noptlist++]),"SOLARIS9"); #endif /* SOLARIS9 */ #ifdef SOLARIS10 makestr(&(optlist[noptlist++]),"SOLARIS10"); #endif /* SOLARIS10 */ #endif /* SOLARIS */ #ifdef SUNOS4 makestr(&(optlist[noptlist++]),"SUNOS4"); #endif /* SUNOS4 */ #ifdef SUN4S5 makestr(&(optlist[noptlist++]),"SUN4S5"); #endif /* SUN4S5 */ #ifdef IRIX makestr(&(optlist[noptlist++]),"IRIX"); #endif /* IRIX */ #ifdef ENCORE makestr(&(optlist[noptlist++]),"ENCORE"); #endif /* ENCORE */ #ifdef ultrix makestr(&(optlist[noptlist++]),"ultrix"); #endif #ifdef sxaE50 makestr(&(optlist[noptlist++]),"sxaE50"); #endif #ifdef mips makestr(&(optlist[noptlist++]),"mips"); #endif #ifdef MIPS makestr(&(optlist[noptlist++]),"MIPS"); #endif #ifdef vax makestr(&(optlist[noptlist++]),"vax"); #endif #ifdef VAX makestr(&(optlist[noptlist++]),"VAX"); #endif #ifdef alpha makestr(&(optlist[noptlist++]),"alpha"); #endif #ifdef ALPHA makestr(&(optlist[noptlist++]),"ALPHA"); #endif #ifdef __ALPHA makestr(&(optlist[noptlist++]),"__ALPHA"); #endif #ifdef __alpha makestr(&(optlist[noptlist++]),"__alpha"); #endif #ifdef __AXP makestr(&(optlist[noptlist++]),"__AXP"); #endif #ifdef AXP makestr(&(optlist[noptlist++]),"AXP"); #endif #ifdef axp makestr(&(optlist[noptlist++]),"axp"); #endif #ifdef __ALPHA__ makestr(&(optlist[noptlist++]),"__ALPHA__"); #endif #ifdef __alpha__ makestr(&(optlist[noptlist++]),"__alpha__"); #endif #ifdef sun makestr(&(optlist[noptlist++]),"sun"); #endif #ifdef sun3 makestr(&(optlist[noptlist++]),"sun3"); #endif #ifdef sun386 makestr(&(optlist[noptlist++]),"sun386"); #endif #ifdef _SUN makestr(&(optlist[noptlist++]),"_SUN"); #endif #ifdef sun4 makestr(&(optlist[noptlist++]),"sun4"); #endif #ifdef sparc makestr(&(optlist[noptlist++]),"sparc"); #endif #ifdef _CRAY makestr(&(optlist[noptlist++]),"_CRAY"); #endif /* _CRAY */ #ifdef NEXT33 makestr(&(optlist[noptlist++]),"NEXT33"); #endif #ifdef NEXT makestr(&(optlist[noptlist++]),"NEXT"); #endif #ifdef NeXT makestr(&(optlist[noptlist++]),"NeXT"); #endif #ifdef MACH makestr(&(optlist[noptlist++]),"MACH"); #endif #ifdef MACOSX makestr(&(optlist[noptlist++]),"MACOSX"); #endif #ifdef MACOSX10 makestr(&(optlist[noptlist++]),"MACOSX10"); #endif #ifdef MACOSX103 makestr(&(optlist[noptlist++]),"MACOSX10e"); #endif #ifdef COMMENT /* not used */ #ifdef MACOSX103 makestr(&(optlist[noptlist++]),"MACOSX103"); #endif #endif /* COMMENT */ #ifdef sgi makestr(&(optlist[noptlist++]),"sgi"); #endif #ifdef M_SYS5 makestr(&(optlist[noptlist++]),"M_SYS5"); #endif #ifdef __SYSTEM_FIVE makestr(&(optlist[noptlist++]),"__SYSTEM_FIVE"); #endif #ifdef sysV makestr(&(optlist[noptlist++]),"sysV"); #endif #ifdef M_XENIX /* SCO Xenix V and UNIX/386 */ makestr(&(optlist[noptlist++]),"M_XENIX"); #endif #ifdef M_UNIX /* SCO UNIX */ makestr(&(optlist[noptlist++]),"M_UNIX"); #endif #ifdef _M_UNIX /* SCO UNIX 3.2v4 = ODT 2.0 */ makestr(&(optlist[noptlist++]),"_M_UNIX"); #endif #ifdef CK_SCOV5 makestr(&(optlist[noptlist++]),"CK_SCOV5"); #endif #ifdef SCO_OSR504 makestr(&(optlist[noptlist++]),"SCO_OSR504"); #endif #ifdef M_IA64 makestr(&(optlist[noptlist++]),"M_IA64"); #endif #ifdef _M_IA64 makestr(&(optlist[noptlist++]),"_M_IA64"); #endif #ifdef ia64 makestr(&(optlist[noptlist++]),"ia64"); #endif #ifdef _ia64 makestr(&(optlist[noptlist++]),"_ia64"); #endif #ifdef _ia64_ makestr(&(optlist[noptlist++]),"_ia64_"); #endif #ifdef __ia64 makestr(&(optlist[noptlist++]),"__ia64"); #endif #ifdef M_I686 makestr(&(optlist[noptlist++]),"M_I686"); #endif #ifdef _M_I686 makestr(&(optlist[noptlist++]),"_M_I686"); #endif #ifdef i686 makestr(&(optlist[noptlist++]),"i686"); #endif #ifdef M_I586 makestr(&(optlist[noptlist++]),"M_I586"); #endif #ifdef _M_I586 makestr(&(optlist[noptlist++]),"_M_I586"); #endif #ifdef i586 makestr(&(optlist[noptlist++]),"i586"); #endif #ifdef M_I486 makestr(&(optlist[noptlist++]),"M_I486"); #endif #ifdef _M_I486 makestr(&(optlist[noptlist++]),"_M_I486"); #endif #ifdef i486 makestr(&(optlist[noptlist++]),"i486"); #endif #ifdef M_I386 makestr(&(optlist[noptlist++]),"M_I386"); #endif #ifdef _M_I386 makestr(&(optlist[noptlist++]),"_M_I386"); #endif #ifdef i386 makestr(&(optlist[noptlist++]),"i386"); #endif #ifdef __i386 makestr(&(optlist[noptlist++]),"__i386"); #endif #ifdef __x86 makestr(&(optlist[noptlist++]),"__x86"); #endif #ifdef __x86_64 makestr(&(optlist[noptlist++]),"__x86_64"); #endif #ifdef __amd64 makestr(&(optlist[noptlist++]),"__amd64"); #endif #ifdef _ILP32 makestr(&(optlist[noptlist++]),"_ILP32"); #endif #ifdef _ILP64 makestr(&(optlist[noptlist++]),"_ILP64"); #endif #ifdef _LP32 makestr(&(optlist[noptlist++]),"_LP32"); #endif #ifdef _LP64 makestr(&(optlist[noptlist++]),"_LP64"); #endif #ifdef __LP32__ makestr(&(optlist[noptlist++]),"__LP32__"); #endif #ifdef __LP64__ makestr(&(optlist[noptlist++]),"__LP64__"); #endif #ifdef _XGP4_2 makestr(&(optlist[noptlist++]),"_XGP4_2"); #endif #ifdef __ppc__ makestr(&(optlist[noptlist++]),"__ppc__"); #endif #ifdef __ppc32__ makestr(&(optlist[noptlist++]),"__ppc32__"); #endif #ifdef __ppc64__ makestr(&(optlist[noptlist++]),"__ppc64__"); #endif #ifdef CK_64BIT makestr(&(optlist[noptlist++]),"CK_64BIT"); #endif #ifdef i286 makestr(&(optlist[noptlist++]),"i286"); #endif #ifdef M_I286 makestr(&(optlist[noptlist++]),"M_I286"); #endif #ifdef __sparc makestr(&(optlist[noptlist++]),"__sparc"); #endif #ifdef __sparcv8 makestr(&(optlist[noptlist++]),"__sparcv8"); #endif #ifdef __sparcv9 makestr(&(optlist[noptlist++]),"__sparcv9"); #endif #ifdef mc68000 makestr(&(optlist[noptlist++]),"mc68000"); #endif #ifdef mc68010 makestr(&(optlist[noptlist++]),"mc68010"); #endif #ifdef mc68020 makestr(&(optlist[noptlist++]),"mc68020"); #endif #ifdef mc68030 makestr(&(optlist[noptlist++]),"mc68030"); #endif #ifdef mc68040 makestr(&(optlist[noptlist++]),"mc68040"); #endif #ifdef M_68000 makestr(&(optlist[noptlist++]),"M_68000"); #endif #ifdef M_68010 makestr(&(optlist[noptlist++]),"M_68010"); #endif #ifdef M_68020 makestr(&(optlist[noptlist++]),"M_68020"); #endif #ifdef M_68030 makestr(&(optlist[noptlist++]),"M_68030"); #endif #ifdef M_68040 makestr(&(optlist[noptlist++]),"M_68040"); #endif #ifdef m68k makestr(&(optlist[noptlist++]),"m68k"); #endif #ifdef m88k makestr(&(optlist[noptlist++]),"m88k"); #endif #ifdef pdp11 makestr(&(optlist[noptlist++]),"pdp11"); #endif #ifdef iAPX makestr(&(optlist[noptlist++]),"iAPX"); #endif #ifdef hpux makestr(&(optlist[noptlist++]),"hpux"); #endif #ifdef __hpux makestr(&(optlist[noptlist++]),"__hpux"); #endif #ifdef __hp9000s800 makestr(&(optlist[noptlist++]),"__hp9000s800"); #endif #ifdef __hp9000s700 makestr(&(optlist[noptlist++]),"__hp9000s700"); #endif #ifdef __hp9000s500 makestr(&(optlist[noptlist++]),"__hp9000s500"); #endif #ifdef __hp9000s300 makestr(&(optlist[noptlist++]),"__hp9000s300"); #endif #ifdef __hp9000s200 makestr(&(optlist[noptlist++]),"__hp9000s200"); #endif #ifdef AIX makestr(&(optlist[noptlist++]),"AIX"); #endif #ifdef _AIXFS makestr(&(optlist[noptlist++]),"_AIXFS"); #endif #ifdef u370 makestr(&(optlist[noptlist++]),"u370"); #endif #ifdef u3b makestr(&(optlist[noptlist++]),"u3b"); #endif #ifdef u3b2 makestr(&(optlist[noptlist++]),"u3b2"); #endif #ifdef multimax makestr(&(optlist[noptlist++]),"multimax"); #endif #ifdef balance makestr(&(optlist[noptlist++]),"balance"); #endif #ifdef ibmrt makestr(&(optlist[noptlist++]),"ibmrt"); #endif #ifdef _IBMRT makestr(&(optlist[noptlist++]),"_IBMRT"); #endif #ifdef ibmrs6000 makestr(&(optlist[noptlist++]),"ibmrs6000"); #endif #ifdef _AIX makestr(&(optlist[noptlist++]),"_AIX"); #endif /* _AIX */ #ifdef _IBMR2 makestr(&(optlist[noptlist++]),"_IBMR2"); #endif #ifdef UNIXWARE makestr(&(optlist[noptlist++]),"UNIXWARE"); #endif #ifdef QNX makestr(&(optlist[noptlist++]),"QNX"); #ifdef __QNX__ makestr(&(optlist[noptlist++]),"__QNX__"); #ifdef __16BIT__ makestr(&(optlist[noptlist++]),"__16BIT__"); #endif #ifdef CK_QNX16 makestr(&(optlist[noptlist++]),"CK_QNX16"); #endif #ifdef __32BIT__ makestr(&(optlist[noptlist++]),"__32BIT__"); #endif #ifdef CK_QNX32 makestr(&(optlist[noptlist++]),"CK_QNX32"); #endif #endif /* __QNX__ */ #endif /* QNX */ #ifdef QNX6 makestr(&(optlist[noptlist++]),"QNX6"); #endif /* QNX6 */ #ifdef NEUTRINO makestr(&(optlist[noptlist++]),"NEUTRINO"); #endif /* NEUTRINO */ #ifdef __STRICT_BSD__ makestr(&(optlist[noptlist++]),"__STRICT_BSD__"); #endif #ifdef __STRICT_ANSI__ makestr(&(optlist[noptlist++]),"__STRICT_ANSI__"); #endif #ifdef _ANSI_C_SOURCE makestr(&(optlist[noptlist++]),"_ANSI_C_SOURCE"); #endif #ifdef __STDC__ makestr(&(optlist[noptlist++]),"__STDC__"); #endif #ifdef cplusplus makestr(&(optlist[noptlist++]),"cplusplus"); #endif #ifdef __DECC makestr(&(optlist[noptlist++]),"__DECC"); #ifdef __DECC_VER sprintf(line,"__DECC_VER=%d",__DECC_VER); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* __DECC_VER */ #endif /* __DECC */ #ifdef __CRTL_VER sprintf(line,"__CRTL_VER=%d",__CRTL_VER); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* __CRTL_VER */ #ifdef __GNUC__ /* gcc in ansi mode */ makestr(&(optlist[noptlist++]),"__GNUC__"); #endif #ifdef GNUC /* gcc in traditional mode */ makestr(&(optlist[noptlist++]),"GNUC"); #endif #ifdef __clang__ makestr(&(optlist[noptlist++]),"clang"); #endif #ifdef __EGCS__ /* egcs in ansi mode */ makestr(&(optlist[noptlist++]),"__EGCS__"); #endif #ifdef __egcs__ /* egcs in ansi mode */ makestr(&(optlist[noptlist++]),"__egcs__"); #endif #ifdef __WATCOMC__ makestr(&(optlist[noptlist++]),"__WATCOMC__"); #endif #ifdef _WIN64 /* 64bit Windows NT */ makestr(&(optlist[noptlist++]),"_WIN64"); #endif #ifdef _MSC_VER sprintf(line,"_MSC_VER=%d",_MSC_VER); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif #ifdef CK_ANSIC makestr(&(optlist[noptlist++]),"CK_ANSIC"); #endif #ifdef CK_ANSILIBS makestr(&(optlist[noptlist++]),"CK_ANSILIBS"); #endif #ifdef CKCONINTB4CB makestr(&(optlist[noptlist++]),"CKCONINTB4CB"); #endif /* CKCONINTB4CB */ #ifdef NOTERMCAP makestr(&(optlist[noptlist++]),"NOTERMCAP"); #endif /* NOTERMCAP */ #ifdef __GLIBC__ makestr(&(optlist[noptlist++]),"__GLIBC__"); #endif #ifdef _SC_JOB_CONTROL makestr(&(optlist[noptlist++]),"_SC_JOB_CONTROL"); #endif #ifdef _POSIX_JOB_CONTROL makestr(&(optlist[noptlist++]),"_POSIX_JOB_CONTROL"); #endif #ifdef SIG_I makestr(&(optlist[noptlist++]),"SIG_I"); #endif /* SIG_I */ #ifdef SIG_V makestr(&(optlist[noptlist++]),"SIG_V"); #endif /* SIG_V */ #ifdef CK_POSIX_SIG makestr(&(optlist[noptlist++]),"CK_POSIX_SIG"); #endif #ifdef SVR3JC makestr(&(optlist[noptlist++]),"SVR3JC"); #endif #ifdef _386BSD makestr(&(optlist[noptlist++]),"_386BSD"); #endif #ifdef _BSD makestr(&(optlist[noptlist++]),"_BSD"); #endif #ifdef USE_MEMCPY makestr(&(optlist[noptlist++]),"USE_MEMCPY"); #endif /* USE_MEMCPY */ #ifdef USE_LSTAT makestr(&(optlist[noptlist++]),"USE_LSTAT"); #endif /* USE_LSTAT */ #ifdef TERMIOX makestr(&(optlist[noptlist++]),"TERMIOX"); #endif /* TERMIOX */ #ifdef STERMIOX makestr(&(optlist[noptlist++]),"STERMIOX"); #endif /* STERMIOX */ #ifdef CK_CURSES makestr(&(optlist[noptlist++]),"CK_CURSES"); #endif /* CK_CURSES */ #ifdef CK_NEWTERM makestr(&(optlist[noptlist++]),"CK_NEWTERM"); #endif /* CK_NEWTERM */ #ifdef CK_WREFRESH makestr(&(optlist[noptlist++]),"CK_WREFRESH"); #endif /* CK_WREFRESH */ #ifdef CK_PCT_BAR makestr(&(optlist[noptlist++]),"CK_PCT_BAR"); #endif /* CK_PCT_BAR */ #ifdef CK_DTRCD makestr(&(optlist[noptlist++]),"CK_DTRCD"); #endif /* CK_DTRCD */ #ifdef CK_DTRCTS makestr(&(optlist[noptlist++]),"CK_DTRCTS"); #endif /* CK_DTRCTS */ #ifdef CK_RTSCTS makestr(&(optlist[noptlist++]),"CK_RTSCTS"); #endif /* CK_RTSCTS */ #ifdef CKT_NT31 makestr(&(optlist[noptlist++]),"CKT_NT31"); #endif /* CKT_NT31 */ #ifdef CKT_NT35 makestr(&(optlist[noptlist++]),"CKT_NT35"); #endif /* CKT_NT35 */ #ifdef POSIX_CRTSCTS makestr(&(optlist[noptlist++]),"POSIX_CRTSCTS"); #endif /* POSIX_CRTSCTS */ #ifdef FIXCRTSCTS makestr(&(optlist[noptlist++]),"FIXCRTSCTS"); #endif /* FIXCRTSCTS */ #ifdef HWPARITY makestr(&(optlist[noptlist++]),"HWPARITY"); #endif /* HWPARITY */ #ifdef CK_SYSINI #ifdef CK_INI_A makestr(&(optlist[noptlist++]),"CK_INI_A"); ckmakmsg(line,LINBUFSIZ,"CK_SYSINI=\"",CK_SYSINI,"\"",NULL); makestr(&(optlist[noptlist++]),line); #else #ifdef CK_INI_B makestr(&(optlist[noptlist++]),"CK_INI_B"); ckmakmsg(line,LINBUFSIZ,"CK_SYSINI=\"",CK_SYSINI,"\"",NULL); makestr(&(optlist[noptlist++]),line); #else makestr(&(optlist[noptlist++]),"CK_SYSINI"); #endif /* CK_INI_B */ #endif /* CK_INI_A */ #endif /* CK_DSYSINI */ #ifdef CK_DSYSINI makestr(&(optlist[noptlist++]),"CK_DSYSINI"); #endif /* CK_DSYSINI */ #ifdef CK_TTGWSIZ makestr(&(optlist[noptlist++]),"CK_TTGWSIZ"); #endif /* CK_TTGWSIZ */ #ifdef CK_NAWS makestr(&(optlist[noptlist++]),"CK_NAWS"); #endif /* CK_NAWS */ #ifdef MDMHUP makestr(&(optlist[noptlist++]),"MDMHUP"); #endif /* MDMHUP */ #ifdef HUP_CLOSE_POSIX makestr(&(optlist[noptlist++]),"HUP_CLOSE_POSIX"); #endif /* HUP_CLOSE_POSIX */ #ifdef NO_HUP_CLOSE_POSIX makestr(&(optlist[noptlist++]),"NO_HUP_CLOSE_POSIX"); #endif /* NO_HUP_CLOSE_POSIX */ #ifdef DCMDBUF makestr(&(optlist[noptlist++]),"DCMDBUF"); #endif /* DCMDBUF */ #ifdef CK_RECALL makestr(&(optlist[noptlist++]),"CK_RECALL"); #endif /* CK_RECALL */ #ifdef BROWSER makestr(&(optlist[noptlist++]),"BROWSER"); #endif /* BROWSER */ #ifdef CLSOPN makestr(&(optlist[noptlist++]),"CLSOPN"); #endif /* CLSOPN */ #ifdef STRATUS makestr(&(optlist[noptlist++]),"STRATUS"); #endif /* STRATUS */ #ifdef __VOS__ makestr(&(optlist[noptlist++]),"__VOS__"); #endif /* __VOS__ */ #ifdef STRATUSX25 makestr(&(optlist[noptlist++]),"STRATUSX25"); #endif /* STRATUSX25 */ #ifdef OS2MOUSE makestr(&(optlist[noptlist++]),"OS2MOUSE"); #endif /* OS2MOUSE */ #ifdef CK_REXX makestr(&(optlist[noptlist++]),"CK_REXX"); #endif /* CK_REXX */ #ifdef CK_TIMERS makestr(&(optlist[noptlist++]),"CK_TIMERS"); #endif /* CK_TIMERS */ #ifdef TTSPDLIST makestr(&(optlist[noptlist++]),"TTSPDLIST"); #endif /* TTSPDLIST */ #ifdef CK_PERMS makestr(&(optlist[noptlist++]),"CK_PERMS"); #endif /* CK_PERMS */ #ifdef CKTUNING makestr(&(optlist[noptlist++]),"CKTUNING"); #endif /* CKTUNING */ #ifdef NEWFTP makestr(&(optlist[noptlist++]),"NEWFTP"); #endif /* NEWFTP */ #ifdef SYSFTP makestr(&(optlist[noptlist++]),"SYSFTP"); #endif /* SYSFTP */ #ifdef NOFTP makestr(&(optlist[noptlist++]),"NOFTP"); #endif /* NOFTP */ #ifdef CKHTTP makestr(&(optlist[noptlist++]),"CKHTTP"); #endif /* CKHTTP */ #ifdef NOHTTP makestr(&(optlist[noptlist++]),"NOHTTP"); #endif /* NOHTTP */ #ifdef NONTLM makestr(&(optlist[noptlist++]),"NONTLM"); #endif #ifdef CKROOT makestr(&(optlist[noptlist++]),"CKROOT"); #endif /* CKROOT */ #ifdef CKREALPATH makestr(&(optlist[noptlist++]),"CKREALPATH"); #endif /* CKREALPATH */ #ifdef STREAMING makestr(&(optlist[noptlist++]),"STREAMING"); #endif /* STREAMING */ #ifdef UNPREFIXZERO makestr(&(optlist[noptlist++]),"UNPREFIXZERO"); #endif /* UNPREFIXZERO */ #ifdef CKREGEX makestr(&(optlist[noptlist++]),"CKREGEX"); #endif /* CKREGEX */ #ifdef ZXREWIND makestr(&(optlist[noptlist++]),"ZXREWIND"); #endif /* ZXREWIND */ #ifdef CKSYSLOG makestr(&(optlist[noptlist++]),"CKSYSLOG"); #endif /* CKSYSLOG */ #ifdef SYSLOGLEVEL sprintf(line,"SYSLOGLEVEL=%d",SYSLOGLEVEL); /* SAFE */ makestr(&(optlist[noptlist++]),line); #endif /* SYSLOGLEVEL */ #ifdef NOSEXP makestr(&(optlist[noptlist++]),"NOSEXP"); #endif /* NOSEXP */ #ifdef CKLEARN makestr(&(optlist[noptlist++]),"CKLEARN"); #else #ifdef NOLOEARN makestr(&(optlist[noptlist++]),"NOLOEARN"); #endif /* NOLOEARN */ #endif /* CKLEARN */ #ifdef BETATEST makestr(&(optlist[noptlist++]),"BETATEST"); #endif /* BETATEST */ #ifdef NOFLOAT makestr(&(optlist[noptlist++]),"NOFLOAT"); #else #ifdef FNFLOAT makestr(&(optlist[noptlist++]),"FNFLOAT"); #endif /* FNFLOAT */ #ifdef CKFLOAT #ifdef GFTIMER makestr(&(optlist[noptlist++]),"GFTIMER"); #endif /* GFTIMER */ #ifdef CKFLOAT_S ckmakmsg(line,LINBUFSIZ,"CKFLOAT=",CKFLOAT_S,NULL,NULL); makestr(&(optlist[noptlist++]),line); #else makestr(&(optlist[noptlist++]),"CKFLOAT"); #endif /* CKFLOAT_S */ #endif /* CKFLOAT */ #endif /* NOFLOAT */ #ifdef COPYINTERPRET makestr(&(optlist[noptlist++]),"COPYINTERPRET"); #endif /* COPYINTERPRET */ #ifdef TYPEINTERPRET makestr(&(optlist[noptlist++]),"TYPEINTERPRET"); #endif /* TYPEINTERPRET */ #ifdef GREPINTERPRET makestr(&(optlist[noptlist++]),"GREPINTERPRET"); #endif /* GREPINTERPRET */ #ifdef TMX_TIME_T makestr(&(optlist[noptlist++])," TMX_TIME_T"); #endif /* TMX_TIME_T */ #ifdef SSH makestr(&(optlist[noptlist++]),"SSH"); #endif /* SSH */ #ifdef NETDLL makestr(&(optlist[noptlist++]),"NETDLL"); #endif /* NETDLL */ #ifdef NETFILE makestr(&(optlist[noptlist++]),"NETFILE"); #endif /* NETFILE */ #ifdef CK_TAPI makestr(&(optlist[noptlist++]),"CK_TAPI"); #endif /* CK_TAPI */ #ifdef CK_SSL makestr(&(optlist[noptlist++]),"CK_SSL"); #ifdef OPENSSL_VERSION_TEXT ckmakmsg(line,LINBUFSIZ, "OPENSSL_VERSION_TEXT=","\"",OPENSSL_VERSION_TEXT,"\""); makestr(&(optlist[noptlist++]),line); #endif /* OPENSSL_VERSION_TEXT */ #endif /* CK_SSL */ #ifdef CK_CONPTY makestr(&(optlist[noptlist++]),"CK_CONPTY"); #endif /* CK_CONPTY */ debug(F101,"initoptlist noptlist","",noptlist); sh_sort(optlist,NULL,noptlist,0,0,0); } int shofea() { int i; int flag = 0; int lines = 1; #ifdef FNFLOAT extern int fp_digits, fp_rounding; #endif /* FNFLOAT */ extern int byteorder; printf("%s\n",versio); if (inserver) return(1); #ifdef COMMENT if (0) { #ifdef UNIX printf("UNIX defined\n"); #else printf("UNIX not defined\n"); #endif #ifdef DOWTMP printf("DOWTMP defined\n"); #else printf("DOWTMP not defined\n"); #endif #ifdef NOWTMP printf("NOWTMP defined\n"); #else printf("NOWTMP not defined\n"); #endif #ifdef CKWTMP printf("Have CKWTMP defined\n"); #else printf("CKWTMP not defined\n"); #endif return(1); } #endif /* COMMENT */ debug(F101,"shofea NOPTLIST","",NOPTLIST); initoptlist(); debug(F101,"shofea noptlist","",noptlist); #ifdef OS2 #ifdef NT #ifdef _M_ALPHA printf("Microsoft Windows Operating Systems for Alpha CPUs.\n"); #else /* _M_ALPHA */ #ifdef _M_PPC printf("Microsoft Windows Operating Systems for PowerPC CPUs.\n"); #else /* _M_PPC */ #ifdef _M_MRX000 printf("Microsoft Windows Operating Systems for MIPS CPUs.\n"); #else /* _M_MRX000 */ #ifdef _M_IX86 printf("Microsoft Windows Operating Systems for 32-bit Intel CPUs.\n"); #else /* _M_IX86 */ #ifdef _M_IA64 printf("Microsoft Windows Operating Systems for Itanium CPUs.\n"); #else /* _M_IA64 */ #ifdef _M_AMD64 printf("Microsoft Windows Operating Systems for x86-64/AMD64 CPUs.\n"); #else /* _M_AMD64 */ #ifdef _M_ARM printf("Microsoft Windows Operating Systems for ARM CPUs.\n"); #else /* _M_ARM */ #ifdef _M_ARM64 printf("Microsoft Windows Operating Systems for 64bit ARM CPUs.\n"); #else /* _M_ARM64 */ UNKNOWN WINDOWS PLATFORM #endif /* _M_ARM64 */ #endif /* _M_ARM */ #endif /* _M_AMD64 */ #endif /* _M_IA64 */ #endif /* _M_IX86 */ #endif /* _M_MRX000 */ #endif /* _M_PPC */ #endif /* _M_ALPHA */ #else /* NT */ #ifdef M_I286 printf("IBM OS/2 16-bit.\n"); #else printf("IBM OS/2 32-bit.\n"); #endif /* M_I286 */ #endif /* NT */ lines++; #endif /* OS2 */ { /* New 11 December 2022 - fdc */ char mebuf[2046]; /* Show Kermit's own pathname and size */ char * s; char * mestring = "\\v(exedir)\\v(name), size: \\fsize(\\v(exedir)\\v(name))"; int mysize = 2046; int x = 0; s = mebuf; x = zzstring(mestring,&s,&mysize); printf("%s\n\n",mebuf); } /* END:NEW */ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf("Major features included:\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } if (sizeof(CK_OFF_T) == 8) { printf(" Large files and large integers (64 bits)\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } } #ifdef NETCONN printf(" Network support (type SHOW NET for further info)\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #ifdef IKS_OPTION printf(" Telnet Kermit Option\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* IKS_OPTION */ #ifdef CK_AUTHENTICATION printf(" Telnet Authentication Option\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #ifdef CK_KERBEROS #ifdef KRB4 #ifdef KRB5 printf(" Kerberos(TM) IV and Kerberos V authentication\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #else /* KRB5 */ printf(" Kerberos(TM) IV authentication\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* KRB5 */ #else /* KRB4 */ #ifdef KRB5 printf(" Kerberos(TM) V authentication\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* KRB5 */ #endif /* KRB4 */ #endif /* CK_KERBEROS */ #ifdef CK_SRP printf(" SRP(TM) (Secure Remote Password) authentication\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_SRP */ #ifdef CK_SSL printf(" Secure Sockets Layer (SSL)\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf(" Transport Layer Security (TLS)\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_SSL */ #ifdef SSHBUILTIN printf(" Secure Shell (SSH) [internal]\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* SSHBUILTIN */ #ifdef SSHCMD printf(" Secure Shell (SSH) [external]\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* SSHCMD */ #ifdef CK_ENCRYPTION printf(" Telnet Encryption Option\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #ifdef CK_DES printf(" Telnet DES Encryption\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_DES */ #ifdef CK_CAST printf(" Telnet CAST Encryption\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_CAST */ #ifdef CK_KERBEROS #ifdef KRB5 #ifdef ALLOW_KRB_3DES_ENCRYPT printf(" Kerberos 3DES/AES Telnet Encryption\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* ALLOW_KRB_3DES_ENCRYPT */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ #endif /* CK_ENCRYPTION */ #endif /* CK_AUTHENTICATION */ #ifdef CK_FORWARD_X printf(" X Windows forwarding\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_FORWARD_X */ #ifdef TN_COMPORT printf(" Telnet Remote Com Port Control Option\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* TN_COMPORT */ #ifdef CK_SOCKS #ifdef CK_SOCKS5 printf(" SOCKS 5\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #else /* CK_SOCKS5 */ printf(" SOCKS 4\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_SOCKS5 */ #endif /* CK_SOCKS */ #ifdef NEWFTP printf(" Built-in FTP client\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* NEWFTP */ #ifdef CKHTTP printf(" Built-in HTTP client\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CKHTTP */ #endif /* NETCONN */ #ifdef CK_RTSCTS printf(" Hardware flow control\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_RTSCTS */ #ifdef CK_XYZ #ifdef XYZ_INTERNAL printf(" Built-in XYZMODEM protocols\n"); #else printf(" External XYZMODEM protocol support\n"); #endif /* XYZ_INTERNAL */ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_XYZ */ #ifndef NOCSETS printf(" Latin-1 (West European) character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #ifdef LATIN2 printf(" Latin-2 (East European) character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* LATIN2 */ #ifdef CYRILLIC printf(" Cyrillic (Russian, Ukrainian, etc) character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CYRILLIC */ #ifdef GREEK printf(" Greek character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* GREEK */ #ifdef HEBREW printf(" Hebrew character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* HEBREW */ #ifdef KANJI printf(" Japanese character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* KANJI */ #ifdef UNICODE printf(" Unicode character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* UNICODE */ #ifdef CKOUNI if (ck_isunicode()) printf(" Unicode support for ISO-2022 Terminal Emulation\n"); else printf(" Unicode translation for Terminal Character-Sets\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CKOUNI */ #endif /* NOCSETS */ #ifdef NETPTY printf(" Pseudoterminal control\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* NETPTY */ #ifdef CK_REDIR printf(" REDIRECT command\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_REDIR */ #ifdef CK_RESEND printf(" RESEND command\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_RESEND */ #ifndef NOXFER #ifdef CK_CURSES printf(" Fullscreen file transfer display\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_CURSES */ #endif /* NOXFER */ #ifdef CK_SPEED printf(" Control-character unprefixing\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_SPEED */ #ifdef STREAMING printf(" Streaming\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* STREAMING */ #ifdef CK_AUTODL printf(" Autodownload\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_AUTODL */ #ifdef OS2MOUSE printf(" Mouse support\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* OS2MOUSE */ #ifdef CK_REXX printf(" REXX script language interface\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_REXX */ #ifdef IKSD #ifdef CK_LOGIN printf(" Internet Kermit Service with user login support\n"); #else /* CK_LOGIN */ printf(" Internet Kermit Service without user login support\n"); #endif /* CK_LOGIN */ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* IKSD */ #ifdef OS2 #ifdef DECNET printf(" DECnet (Pathworks) LAT/CTERM support\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* DECNET */ #endif /* OS2 */ #ifdef NT #ifdef SUPERLAT printf(" SuperLAT/TES32 support\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* SUPERLAT */ #endif /* NT */ printf("\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf("Major optional features not included:\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } if (sizeof(CK_OFF_T) <= 4) { printf(" No large files or large integers\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } } #ifdef NOXFER printf(" No file-transfer protocols\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #else #ifndef CK_CURSES #ifndef MAC printf(" No fullscreen file transfer display\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* MAC */ #endif /* CK_CURSES */ #ifdef NOSERVER printf(" No server mode\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOSERVER */ #ifndef CK_SPEED printf(" No control-character unprefixing\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* CK_SPEED */ #ifndef STREAMING printf(" No streaming\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* STREAMING */ #ifndef CK_AUTODL printf(" No autodownload\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* CK_AUTODL */ #ifndef CK_XYZ printf(" No built-in XYZMODEM protocols\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* CK_XYZ */ #ifdef NOFLOAT printf(" No floating-point arithmetic\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; printf(" No S-Expressions (LISP interpreter)\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #else #ifdef NOSEXP printf(" No S-Expressions (LISP interpreter)\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOSEXP */ #endif /* NOFLOAT */ #ifdef NOTLOG printf(" No transaction log\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOTLOG */ #endif /* NOXFER */ #ifdef NODEBUG printf(" No debugging\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NODEBUG */ #ifdef NOHELP printf(" No built-in help\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOHELP */ #ifdef NOLOCAL printf(" No making connections\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #else #ifndef NETCONN printf(" No network support\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #else /* NETCONN */ #ifndef IKS_OPTION printf(" No Telnet Kermit Option\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* IKS_OPTION */ #endif /* NETCONN */ #ifdef NOSSH printf(" No Secure Shell (SSH)\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* NOSSH */ #ifndef CK_AUTHENTICATION printf(" No Kerberos(TM) authentication\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf(" No SRP(TM) (Secure Remote Password) protocol\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf(" No Secure Sockets Layer (SSL) protocol\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf(" No Transport Layer Security (TLS) protocol\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf(" No encryption\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #else /* CK_AUTHENTICATION */ #ifndef CK_KERBEROS printf(" No Kerberos(TM) authentication\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #else /* CK_KERBEROS */ #ifndef KRB4 printf(" No Kerberos(TM) IV authentication\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* KRB4 */ #ifndef KRB5 printf(" No Kerberos(TM) V authentication\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* KRB5 */ #endif /* CK_KERBEROS */ #ifndef CK_SRP printf(" No SRP(TM) (Secure Remote Password) authentication\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* CK_SRP */ #ifndef CK_SSL printf(" No Secure Sockets Layer (SSL) protocol\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf(" No Transport Layer Security (TLS) protocol\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* CK_SSL */ #ifndef CK_ENCRYPTION printf(" No Telnet Encryption Option\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #else /* CK_ENCRYPTION */ #ifndef OS2 #ifndef CK_DES printf(" No Telnet DES encryption\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* CK_DES */ #ifndef CK_CAST printf(" No Telnet CAST encryption\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* CK_CAST */ #ifdef COMMENT #ifdef CK_KERBEROS #ifdef KRB5 #ifndef ALLOW_KRB_3DES_ENCRYPT printf(" No Kerberos 3DES/AES Telnet Encryption\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* ALLOW_KRB_3DES_ENCRYPT */ #endif /* KRB5 */ #endif /* CK_KERBEROS */ #endif /* COMMENT */ #endif /* OS2 */ #endif /* CK_ENCRYPTION */ #endif /* CK_AUTHENTICATION */ #ifndef CK_FORWARD_X printf(" No X Windows forwarding\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_FORWARD_X */ #ifndef TN_COMPORT printf(" No Telnet Remote Com Port Control Option\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* TN_COMPORT */ #ifndef CK_SOCKS printf(" No SOCKS\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_SOCKS */ #ifndef NEWFTP printf(" No built-in FTP client\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* NEWFTP */ #ifdef NOTELNET printf(" No built-in TELNET client\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* NOTELNET */ #ifdef NORLOGIN printf(" No built-in RLOGIN client\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* NORLOGIN */ #ifdef NOHTTP printf(" No built-in HTTP client\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* NOHTTP */ #ifdef NOARROWKEYS /* OS/2 and Windows always have arrow key support regardless of the NOARROWKEYS * build option */ #ifndef OS2 printf(" No arrow-key support\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* OS2 */ #endif /* NOARROWKEYS */ #ifdef NODIAL printf(" No DIAL command\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #else #ifdef MINIDIAL printf(" Support for most modem types excluded\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* MINIDIAL */ #endif /* NODIAL */ #endif /* NOLOCAL */ #ifndef CK_RTSCTS #ifndef MAC printf(" No hardware flow control\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* MAC */ #endif /* CK_RTSCTS */ #ifdef NOXMIT printf(" No TRANSMIT command\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOXMIT */ #ifdef NOSCRIPT printf(" No SCRIPT command\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOSCRIPT */ #ifdef NOSPL printf(" No script programming features\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOSPL */ #ifdef NOCSETS printf(" No character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #else #ifndef LATIN2 printf(" No Latin-2 character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* LATIN2 */ #ifdef NOGREEK printf(" No Greek character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOGREEK */ #ifdef NOHEBREW printf(" No Hebrew character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOHEBREW */ #ifdef NOUNICODE printf(" No Unicode character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOUNICODE */ #ifdef NOCYRIL printf(" No Cyrillic character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOCYRIL */ #ifndef KANJI printf(" No Kanji character-set translation\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* KANJI */ #endif /* NOCSETS */ #ifdef NOCMDL printf(" No command-line arguments\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOCMDL */ #ifdef NOPUSH printf(" No escape to system\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOPUSH */ #ifdef NOJC #ifdef UNIX printf(" No UNIX job control\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* UNIX */ #endif /* NOJC */ #ifdef NOSETKEY printf(" No SET KEY command\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NOSETKEY */ #ifndef CK_REDIR printf(" No REDIRECT or PIPE command\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* CK_REDIR */ #ifdef WIN32ORUNIX #ifndef NETPTY printf(" No pseudoterminal control\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* NETPTY */ #endif /* WIN32ORUNIX */ #ifndef CK_RESEND printf(" No RESEND command\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* CK_RESEND */ #ifdef OS2 #ifdef __32BIT__ #ifndef OS2MOUSE printf(" No Mouse support\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* __32BIT__ */ #endif /* OS2 */ #endif /* OS2MOUSE */ #ifdef OS2 #ifndef CK_REXX printf(" No REXX script language interface\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* CK_REXX */ #endif /* OS2 */ #ifndef IKSD printf(" No Internet Kermit Service\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* IKSD */ #ifdef OS2 #ifndef DECNET printf(" No DECnet (Pathworks) LAT/CTERM support\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* DECNET */ #endif /* OS2 */ #ifdef NT #ifndef SUPERLAT printf(" No SuperLAT/TES32 support\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } flag = 1; #endif /* SUPERLAT */ #endif /* NT */ if (flag == 0) { printf(" None\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } } printf("\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #ifdef CK_UTSNAME if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf("Host info:\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf(" Machine: %s\n",unm_mch[0] ? unm_mch : "(unknown)"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf(" Model: %s\n",unm_mod[0] ? unm_mod : "(unknown)"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf(" OS: %s\n",unm_nam[0] ? unm_nam : "(unknown)"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf(" OS Release: %s\n",unm_rel[0] ? unm_rel : "(unknown)"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf(" OS Version: %s\n",unm_ver[0] ? unm_ver : "(unknown)"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf("\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* CK_UTSNAME */ /* Print compile-time (-D) options, as well as C preprocessor predefined symbols that might affect us... */ #ifdef KTARGET { char * s; /* Makefile target */ s = KTARGET; if (!s) s = ""; if (!*s) s = "(unknown)"; printf("\n"); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } printf("Target: %s\n", s); if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } } #endif /* KTARGET */ #ifdef __VERSION__ #ifdef __clang__ printf("Compiler version: %s\n", __VERSION__); #else #ifdef __GNUC__ printf("GCC version: %s\n", __VERSION__); #else printf("Compiler version: %s\n", __VERSION__); #endif /* __GNUC__ */ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } #endif /* __clang__ */ #endif /* __VERSION__ */ #ifdef __DATE__ /* GNU and other ANSI */ #ifdef __TIME__ printf("Compiled %s %s, options:\n", __DATE__, __TIME__); #else printf("Compiled %s, options:\n", __DATE__); #endif /* __TIME__ */ #else /* !__DATE__ */ printf("Compiler options:\n"); #endif /* __DATE__ */ if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; } for (i = 0; i < noptlist; i++) /* Print sorted option list */ if (!prtopt(&lines,optlist[i])) return(0); if (!prtopt(&lines,"")) return(0); /* Start a new section */ /* Sizes of data types */ ckmakmsg(line, LINBUFSIZ, "byte order: ", byteorder ? "little" : "big", " endian", NULL ); { /* Whether to use %d or %ld with sizeof is a portability issue, so... */ int size = 0; if (!prtopt(&lines,line)) return(0); if (!prtopt(&lines,"")) return(0); /* Start a new section */ size = (int)sizeof(int); sprintf(line,"sizeofs: int=%d",size); /* SAFE */ if (!prtopt(&lines,line)) return(0); size = (int)sizeof(long); sprintf(line,"long=%d",size); /* SAFE */ if (!prtopt(&lines,line)) return(0); #ifndef OS2 /* Windows doesn't have off_t */ size = (int)sizeof(off_t); sprintf(line,"off_t=%d",size); /* SAFE */ if (!prtopt(&lines,line)) return(0); #endif /* OS2 */ size = (int)sizeof(CK_OFF_T); sprintf(line,"CK_OFF_T=%d",size); /* SAFE */ if (!prtopt(&lines,line)) return(0); #ifdef BIGBUFOK size = (int)sizeof(size_t); sprintf(line,"size_t=%d",size); /* SAFE */ if (!prtopt(&lines,line)) return(0); #endif /* BIGBUFOK */ size = (int)sizeof(short); sprintf(line,"short=%d",size); /* SAFE */ if (!prtopt(&lines,line)) return(0); size = (int)sizeof(char); sprintf(line,"char=%d",size); /* SAFE */ if (!prtopt(&lines,line)) return(0); size = (int)sizeof(char *); sprintf(line,"char*=%d",size); /* SAFE */ if (!prtopt(&lines,line)) return(0); size = (int)sizeof(float); sprintf(line,"float=%d",size); /* SAFE */ if (!prtopt(&lines,line)) return(0); size = (int)sizeof(double); sprintf(line,"double=%d",size); /* SAFE */ if (!prtopt(&lines,line)) return(0); } #ifdef FNFLOAT if (!prtopt(&lines,"")) return(0); /* Start a new section */ if (!prtopt(&lines,"floating-point:")) return(0); sprintf(line,"precision=%d",fp_digits); /* SAFE */ if (!prtopt(&lines,line)) return(0); sprintf(line,"rounding=%d",fp_rounding); /* SAFE */ if (!prtopt(&lines,line)) return(0); #endif /* FNFLOAT */ prtopt(&lines,""); return(0); } #endif /* NOSHOW */ #endif /* NOICP */ ckuus6.c000664 045065 024037 00001565646 14767410206 012605 0ustar00fdckermit000000 000000 #include "ckcsym.h" #include "ckcdeb.h" #ifndef NOICP /* Authors: Frank da Cruz , The Kermit Project, New York City Jeffrey E Altman Secure Endpoints Inc., New York City Copyright (C) 1985, 2024, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Last updates: Tue Mar 26 15:00:12 2024 (fix debug(F110,"GREP tmpstr","",tmpstr);) Mon Aug 22 20:11:01 2022 (for TYPE /INTERPRET) Mon Aug 22 20:11:01 2022 (for TYPE /INTERPRET) Wed Aug 31 15:46:35 2022 (to disable TYPE /INTERPRET in Windows) Tue Sep 20 15:40:49 2022 (for COPY /TOSCREEN and /INTERPRET) Fri Sep 23 16:40:42 2022 (corrections from David Goodwin) Wed Oct 5 14:44:10 2022 (fixed "dir filespec1 filespec2 filespec3.." -fdc) Mon Dec 12 05:41:18 2022 (new GREP options) Sat Mar 18 20:47:32 2023 (fix new GREP options, notably GREP /ARRAY) Wed Apr 12 19:48:13 2023 (function prototypes and declarations) Mon Jul 3 07:10:28 2023 (isatty definition for very old Windows versions) */ /* Includes */ #include "ckcasc.h" #include "ckcker.h" #include "ckuusr.h" #include "ckcxla.h" #include "ckcnet.h" /* Network symbols */ #include #ifndef NOSTAT #ifdef VMS /* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */ #include #else /* def VMS */ #include #endif /* def VMS [else] */ #endif /* NOSTAT */ #ifdef VMS #ifndef TCPSOCKET #include #endif /* TCPSOCKET */ #endif /* VMS */ #ifdef datageneral #define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd) #endif /* datageneral */ #ifdef QNX6 #define readblock kreadblock #endif /* QNX6 */ /* External Kermit Variables, see ckmain.c for description. */ extern xx_strp xxstring; extern int local, xitsta, binary, parity, escape, flow, cmd_rows, turn, turnch, duplex, ckxech, seslog, dfloc, cnflg, tlevel, pflag, msgflg, mdmtyp, zincnt, quiet, repars, techo, network, nzxopts, what, filepeek, recursive; extern int xaskmore, tt_rows, tt_cols, cmd_cols, g_matchdot, diractive, xcmdsrc, nscanfile, reliable, nolinks, cmflgs; #ifdef VMSORUNIX extern int zgfs_dir, zgfs_link; #endif /* VMSORUNIX */ #ifdef CK_IFRO extern int remonly; #endif /* CK_IFRO */ #ifdef OS2 extern int StartedFromDialer ; extern BYTE vmode; extern int k95stdout; #ifndef NT #define INCL_NOPM #define INCL_VIO /* Needed for ckocon.h */ #include #undef COMMENT #else #define APIRET ULONG #include #ifdef CK_TAPI #include #include "ckntap.h" #endif /* CK_TAPI */ #ifndef isatty /* This usually isn't required as oldnames.lib handles it - except in some * very old Windows SDKs where it doesn't - David Goodwin 2 July 2023 */ #define isatty _isatty #endif /* isaatty */ #endif /* NT */ #include "ckocon.h" #include "ckodir.h" /* [jt] 2013/11/21 - for MAXPATHLEN */ int zlink(char *,char *); /* ckofio.c */ int ttgcwsz(); /* ckocon.c */ int popup_readpass(int,char*,char*,char*,int,int); /* ckocon.c */ int popup_readtext(int,char*,char*,char*,int,int); /* ckocon.c */ #ifdef KUI int gui_txt_dialog(char*,char*,int,char*,int,char*,int); /* cknwin.c */ #endif /* KUI */ #endif /* OS2 */ #include "ckcfnp.h" /* Prototypes (must be last) */ extern long vernum, speed; extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv; extern char *dialv, *loginv, *for_def[], *whil_def[], *xif_def[], *sw_def[]; extern char *foz_def[]; extern char *ckxsys, *ckzsys; #ifndef OS2 extern char *DIRCMD; #ifndef UNIX extern char *DELCMD; #endif /* UNIX */ #endif /* OS2 */ extern char ttname[], filnam[]; extern CHAR sstate, feol; extern char *zinptr; #ifdef UNIX extern char ** mtchs; /* zxpand() file list */ #endif /* UNIX */ #ifndef NOXFER extern int oopts, omode, oname, opath; /* O-Packet options */ extern int stdinf, sndsrc, size, rpsiz, urpsiz, fncnv, fnrpath, displa, stdouf, isguest, pktlog, nfils, keep, maxrps, fblksiz, frecl, frecfm, atcapr, atdiso, spsizf, spsiz, spsizr, spmax, wslotr, prefixing, fncact, fnspath, nprotos, g_proto, g_urpsiz, g_spsizf, g_spsiz, g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact, g_fncnv, g_fnspath, g_fnrpath, xfrxla, g_xfrxla; extern char *cmarg, *cmarg2; #ifdef CK_ANSIC /* prototypes for static functions - fdc 30 November 2022 */ static char * xdial( char * ); static int typegetline( int, int, char *, int ); static int callisld( char *, char * ); static int ddcvt( char *, FILE *, int ); static int dncvt(int, int, int, int ); static int renameone(char *, char *,int,int,int,int,int,int,int,int,int,int,int); static int typeline( char *, int, int, FILE * ); static int xxundef( char *, int, int ); #endif /* CK_ANSIC */ #ifndef NOMSEND /* Multiple SEND */ extern char *msfiles[]; #endif /* NOMSEND */ extern char fspec[]; /* Most recent filespec */ extern int fspeclen; #ifdef CK_TMPDIR extern int f_tmpdir; /* Directory changed temporarily */ extern char savdir[]; /* For saving current directory */ #endif /* CK_TMPDIR */ extern struct keytab protos[]; /* File transfer protocols */ extern struct ck_p ptab[NPROTOS]; #endif /* NOXFER */ #ifdef DCMDBUF /* Declarations from cmd package */ extern char *cmdbuf, *atmbuf; /* Command buffers */ #else extern char cmdbuf[], atmbuf[]; /* Command buffers */ #endif /* DCMDBUF */ extern int nopush; #ifdef TYPEINTERPRET extern int type_intrp; /* TYPE /INTERPRET */ #endif /* TYPEINTERPRET */ #ifndef NOSPL int askflag = 0; /* ASK-class command active */ int echostars = 0; /* ASKQ should echo asterisks */ extern char **a_ptr[]; extern int a_dim[]; extern char **m_xarg[]; extern int n_xarg[]; extern struct mtab *mactab; extern int nmac; extern long ck_alarm; extern char alrm_date[], alrm_time[]; extern int x_ifnum; #endif /* NOSPL */ extern int inserver; /* I am IKSD */ extern int backgrd; /* Kermit executing in background */ extern char psave[]; /* For saving & restoring prompt */ extern char *tp; /* Temporary buffer */ int readblock = 4096; /* READ buffer size */ CHAR * readbuf = NULL; /* Pointer to read buffer */ int readsize = 0; /* Number of chars actually read */ int getcmd = 0; /* GET-class command was given */ char chgsourcedir[CKMAXPATH+1] = { 0,0 }; /* Source directory for CHANGE */ char chgdestdir[CKMAXPATH+1] = { 0,0 }; /* Destination directory for CHANGE */ char chgbackupdir[CKMAXPATH+1] = { 0,0 }; /* Backup directory for CHANGE */ extern int zchkod, zchkid; /* C K U U S 6 -- "User Interface" for Unix Kermit (Part 6) */ struct keytab deltab[] = { /* DELETE Command Options */ { "/all", DEL_ALL, CM_INV }, { "/after", DEL_AFT, CM_ARG }, { "/ask", DEL_ASK, 0 }, { "/before", DEL_BEF, CM_ARG }, { "/directories", DEL_DIR, 0 }, { "/dotfiles", DEL_DOT, 0 }, { "/except", DEL_EXC, CM_ARG }, { "/heading", DEL_HDG, 0 }, { "/l", DEL_LIS, CM_INV|CM_ABR }, { "/larger-than", DEL_LAR, CM_ARG }, { "/list", DEL_LIS, 0 }, { "/log", DEL_LIS, CM_INV }, { "/noask", DEL_NAS, 0 }, { "/nodotfiles", DEL_NOD, 0 }, { "/noheading", DEL_NOH, 0 }, { "/nol", DEL_NOL, CM_INV|CM_ABR }, { "/nolist", DEL_NOL, 0 }, { "/nolog", DEL_NOL, CM_INV }, { "/nopage", DEL_NOP, 0 }, { "/not-after", DEL_NAF, CM_ARG }, { "/not-before", DEL_NBF, CM_ARG }, { "/not-since", DEL_NAF, CM_INV|CM_ARG }, { "/page", DEL_PAG, 0 }, { "/quiet", DEL_QUI, CM_INV }, { "/recursive", DEL_REC, 0 }, { "/simulate", DEL_SIM, 0 }, { "/since", DEL_AFT, CM_ARG|CM_INV }, { "/smaller-than", DEL_SMA, CM_ARG }, { "/summary", DEL_SUM, 0 }, { "/tree", DEL_ALL, 0 }, { "/type", DEL_TYP, CM_ARG }, { "/verbose", DEL_VRB, CM_INV } }; int ndeltab = sizeof(deltab)/sizeof(struct keytab); /* /QUIET-/VERBOSE (/LIST-/NOLIST) (/LOG-/NOLOG) table */ struct keytab qvswtab[] = { { "/l", DEL_LIS, CM_INV|CM_ABR }, { "/list", DEL_LIS, 0 }, { "/log", DEL_LIS, CM_INV }, { "/nol", DEL_NOL, CM_INV|CM_ABR }, { "/nolist", DEL_NOL, 0 }, { "/nolog", DEL_NOL, CM_INV }, { "/quiet", DEL_QUI, CM_INV }, { "/verbose", DEL_VRB, CM_INV } }; int nqvswtab = sizeof(qvswtab)/sizeof(struct keytab); static struct keytab renamsw[] = { { "/collision", REN_OVW, CM_ARG }, #ifndef NOUNICODE { "/convert", REN_XLA, CM_ARG }, #endif /* NOUNICODE */ { "/fixspaces", REN_SPA, CM_ARG }, { "/l", DEL_LIS, CM_INV|CM_ABR }, { "/list", DEL_LIS, 0 }, { "/log", DEL_LIS, CM_INV }, { "/lower", REN_LOW, CM_ARG }, { "/nol", DEL_NOL, CM_INV|CM_ABR }, { "/nolist", DEL_NOL, 0 }, { "/nolog", DEL_NOL, CM_INV }, { "/quiet", DEL_QUI, CM_INV }, { "/replace", REN_RPL, CM_ARG }, { "/simulate", DEL_SIM, 0 }, { "/upper", REN_UPP, CM_ARG }, { "/verbose", DEL_VRB, CM_INV } }; static int nrenamsw = sizeof(renamsw)/sizeof(struct keytab); static struct keytab renamset[] = { { "collision", REN_OVW, 0 }, { "list", DEL_LIS, 0 } }; static int nrenamset = sizeof(renamset)/sizeof(struct keytab); /* Args for RENAME /LOWER: and /UPPER: */ static struct keytab r_upper[] = { { "all", 1, 0 }, { "lower", 0, 0 } }; static struct keytab r_lower[] = { { "all", 1, 0 }, { "upper", 0, 0 } }; /* Args for RENAME /COLLISION... */ #define RENX_FAIL 0 #define RENX_OVWR 1 #define RENX_SKIP 2 static struct keytab r_collision[] = { { "fail", RENX_FAIL, 0 }, { "overwrite", RENX_OVWR, 0 }, { "proceed", RENX_SKIP, CM_INV }, { "skip", RENX_SKIP, 0 } }; static int nr_collision = sizeof(r_collision)/sizeof(struct keytab); /* This started out being a clone of the DELETE command parser, but now it has some unique switches of its own with numeric IDs instead of DEL_xxx. Census: 999 swap-bytes 998 append 997 fromb64 996 tob64 995 preserve 994 overwrite 993 toscreen 992 interpret */ struct keytab copytab[] = { { "/append", 998, 0 }, #ifndef NOSPL { "/fromb64", 997, 0 }, #endif /* NOSPL */ #ifdef COPYINTERPRET { "/interpret", 992, 0 }, /* fdc 20 Sep 2022 */ #endif /* COPYINTERPRET */ { "/l", DEL_LIS, CM_INV|CM_ABR }, { "/list", DEL_LIS, 0 }, { "/log", DEL_LIS, CM_INV }, { "/nol", DEL_NOL, CM_INV|CM_ABR }, { "/nolist", DEL_NOL, 0 }, { "/nolog", DEL_NOL, CM_INV }, { "/overwrite", 994, CM_ARG }, #ifndef NOXFER { "/preserve", 995, 0 }, #endif /* NOXFER */ { "/quiet", DEL_QUI, CM_INV }, { "/swap-bytes", 999, 0 }, #ifndef NOSPL { "/tob64", 996, 0 }, #endif /* NOSPL */ { "/toscreen", 993, 0 }, { "/verbose", DEL_VRB, CM_INV } }; int ncopytab = sizeof(copytab)/sizeof(struct keytab); #define OVW_ALWAYS 0 #define OVW_NEVER 1 #define OVW_OLDER 2 #define OVW_NEWER 3 static struct keytab ovwtab[] = { { "always", OVW_ALWAYS, 0 }, { "never", OVW_NEVER, 0 }, { "newer", OVW_NEWER, 0 }, { "older", OVW_OLDER, 0 } }; static int novwtab = 4; #ifndef NOXFER static struct keytab gettab[] = { /* GET options */ { "/as-name", SND_ASN, CM_ARG }, { "/binary", SND_BIN, 0 }, #ifdef CALIBRATE { "/calibrate", SND_CAL, CM_INV }, #endif /* CALIBRATE */ #ifdef PIPESEND { "/command", SND_CMD, CM_PSH }, #endif /* PIPESEND */ { "/delete", SND_DEL, 0 }, { "/except", SND_EXC, CM_ARG }, { "/filenames", SND_NAM, CM_ARG }, #ifdef PIPESEND { "/filter", SND_FLT, CM_ARG|CM_PSH }, #endif /* PIPESEND */ #ifdef VMS { "/image", SND_IMG, 0 }, { "/labeled", SND_LBL, 0 }, #else { "/image", SND_BIN, CM_INV }, #endif /* VMS */ #ifdef CK_TMPDIR { "/move-to", SND_MOV, CM_ARG }, #endif /* CK_TMPDIR */ { "/pathnames", SND_PTH, CM_ARG }, { "/pipes", SND_PIP, CM_ARG|CM_PSH }, { "/quiet", SND_SHH, 0 }, #ifdef CK_RESEND { "/recover", SND_RES, 0 }, #endif /* CK_RESEND */ { "/recursive", SND_REC, 0 }, { "/rename-to", SND_REN, CM_ARG }, #ifdef COMMENT { "/smaller-than", SND_SMA, CM_ARG }, #endif /* COMMENT */ { "/subdirectories", SND_REC, CM_INV }, { "/text", SND_TXT, 0 }, { "/transparent", SND_XPA, 0 } }; #define NGETTAB sizeof(gettab)/sizeof(struct keytab) static int ngettab = NGETTAB; static struct keytab rcvtab[] = { /* RECEIVE options */ { "/as-name", SND_ASN, CM_ARG }, { "/binary", SND_BIN, 0 }, #ifdef CALIBRATE { "/calibrate", SND_CAL, CM_INV }, #endif /* CALIBRATE */ #ifdef PIPESEND { "/command", SND_CMD, CM_PSH }, #endif /* PIPESEND */ { "/except", SND_EXC, CM_ARG }, { "/filenames", SND_NAM, CM_ARG }, #ifdef PIPESEND { "/filter", SND_FLT, CM_ARG|CM_PSH }, #endif /* PIPESEND */ #ifdef VMS { "/image", SND_IMG, 0 }, { "/labeled", SND_LBL, 0 }, #else { "/image", SND_BIN, CM_INV }, #endif /* VMS */ #ifdef CK_TMPDIR { "/move-to", SND_MOV, CM_ARG }, #endif /* CK_TMPDIR */ { "/pathnames", SND_PTH, CM_ARG }, { "/pipes", SND_PIP, CM_ARG|CM_PSH }, #ifdef CK_XYZ { "/protocol", SND_PRO, CM_ARG }, #else { "/protocol", SND_PRO, CM_ARG|CM_INV }, #endif /* CK_XYZ */ { "/quiet", SND_SHH, 0 }, { "/recursive", SND_REC, 0 }, { "/rename-to", SND_REN, CM_ARG }, { "/text", SND_TXT, 0 }, { "/transparent", SND_XPA, 0 } }; #define NRCVTAB sizeof(rcvtab)/sizeof(struct keytab) static int nrcvtab = NRCVTAB; #endif /* NOXFER */ /* WAIT table */ #define WAIT_FIL 997 #define WAIT_MDM 998 struct keytab waittab[] = { { "cd", BM_DCD, CM_INV }, /* (Carrier Detect) */ { "cts", BM_CTS, CM_INV }, /* (Clear To Send) */ { "dsr", BM_DSR, CM_INV }, /* (Data Set Ready) */ { "file", WAIT_FIL, 0 }, /* New category selector keywords */ { "modem-signals", WAIT_MDM, 0 }, /* ... */ { "ri", BM_RNG, CM_INV } /* (Ring Indicator) */ }; int nwaittab = (sizeof(waittab) / sizeof(struct keytab)); /* Modem signal table */ struct keytab mstab[] = { { "cd", BM_DCD, 0 }, /* Carrier Detect */ { "cts", BM_CTS, 0 }, /* Clear To Send */ { "dsr", BM_DSR, 0 }, /* Data Set Ready */ { "ri", BM_RNG, 0 } /* Ring Indicator */ }; int nms = (sizeof(mstab) / sizeof(struct keytab)); #define WF_MOD 1 #define WF_DEL 2 #define WF_CRE 3 struct keytab wfswi[] = { /* WAIT FILE switches */ { "creation", WF_CRE, 0 }, /* Wait for file to be created */ { "deletion", WF_DEL, 0 }, /* Wait for file to be deleted */ { "modification", WF_MOD, 0 } /* Wait for file to be modified */ }; int nwfswi = (sizeof(wfswi) / sizeof(struct keytab)); #ifndef NOSPL struct keytab asgtab[] = { /* Assignment operators for "." */ { "::=", 2, 0 }, /* ASSIGN and EVALUATE */ { ":=", 1, 0 }, /* ASSIGN */ { "=", 0, 0 } /* DEFINE */ }; int nasgtab = (sizeof(asgtab) / sizeof(struct keytab)); struct keytab opntab[] = { #ifndef NOPUSH { "!read", OPN_PI_R, CM_INV }, { "!write", OPN_PI_W, CM_INV }, #endif /* NOPUSH */ { "append", OPN_FI_A, 0 }, { "host", OPN_NET, 0 }, #ifdef OS2 { "line", OPN_SER, CM_INV }, { "port", OPN_SER, 0 }, #else { "line", OPN_SER, 0 }, { "port", OPN_SER, CM_INV }, #endif /* OS2 */ { "read", OPN_FI_R, 0 }, { "write", OPN_FI_W, 0 } }; int nopn = (sizeof(opntab) / sizeof(struct keytab)); /* IF conditions */ #define XXIFCO 0 /* IF COUNT */ #define XXIFER 1 /* IF ERRORLEVEL */ #define XXIFEX 2 /* IF EXIST */ #define XXIFFA 3 /* IF FAILURE */ #define XXIFSU 4 /* IF SUCCESS */ #define XXIFNO 5 /* IF NOT */ #define XXIFDE 6 /* IF DEFINED */ #define XXIFEQ 7 /* IF EQUAL (strings) */ #define XXIFAE 8 /* IF = (numbers) */ #define XXIFLT 9 /* IF < (numbers) */ #define XXIFGT 10 /* IF > (numbers) */ #define XXIFLL 11 /* IF Lexically Less Than (strings) */ #define XXIFLG 12 /* IF Lexically Greater Than (strings) */ #define XXIFEO 13 /* IF EOF (READ file) */ #define XXIFBG 14 /* IF BACKGROUND */ #define XXIFNU 15 /* IF NUMERIC */ #define XXIFFG 16 /* IF FOREGROUND */ #define XXIFDI 17 /* IF DIRECTORY */ #define XXIFNE 18 /* IF NEWER */ #define XXIFRO 19 /* IF REMOTE-ONLY */ #define XXIFAL 20 /* IF ALARM */ #define XXIFSD 21 /* IF STARTED-FROM-DIALER */ #define XXIFTR 22 /* IF TRUE */ #define XXIFNT 23 /* IF FALSE */ #define XXIFTM 24 /* IF TERMINAL-MACRO */ #define XXIFEM 25 /* IF EMULATION */ #define XXIFOP 26 /* IF OPEN */ #define XXIFLE 27 /* IF <= */ #define XXIFGE 28 /* IF >= */ #define XXIFIP 29 /* IF INPATH */ #define XXIFTA 30 /* IF TAPI */ #define XXIFMA 31 /* IF MATCH */ #define XXIFFL 32 /* IF FLAG */ #define XXIFAB 33 /* IF ABSOLUTE */ #define XXIFAV 34 /* IF AVAILABLE */ #define XXIFAT 35 /* IF ASKTIMEOUT */ #define XXIFRD 36 /* IF READABLE */ #define XXIFWR 37 /* IF WRITEABLE */ #define XXIFAN 38 /* IF ... AND ... */ #define XXIFOR 39 /* IF ... OR ... */ #define XXIFLP 40 /* IF left parenthesis */ #define XXIFRP 41 /* IF right parenthesis */ #define XXIFNQ 42 /* IF != (== "NOT =") */ #define XXIFQU 43 /* IF QUIET */ #define XXIFCK 44 /* IF C-KERMIT */ #define XXIFK9 45 /* IF K-95 */ #define XXIFMS 46 /* IF MS-KERMIT */ #define XXIFWI 47 /* IF WILD */ #define XXIFLO 48 /* IF LOCAL */ #define XXIFCM 49 /* IF COMMAND */ #define XXIFFP 50 /* IF FLOAT */ #define XXIFIK 51 /* IF IKS */ #define XXIFKB 52 /* IF KBHIT */ #define XXIFKG 53 /* IF KERBANG */ #define XXIFVE 54 /* IF VERSION */ #define XXIFDC 55 /* IF DECLARED */ #define XXIFGU 56 /* IF GUI */ #define XXIFLN 57 /* IF LINK */ #define XXIFDB 58 /* IF DEBUG */ #define XXIFFU 59 /* IF FUNCTION */ #define XXIFNN 60 /* IF NEQ (lexically not equal) */ #define XXIFLLE 61 /* IF LLE (lexically less than or equal) */ #define XXIFLGE 62 /* IF LLE (lexically less than or equal) */ #define XXIFTXT 63 /* IF TEXT (file) */ #define XXIFBIN 64 /* IF BINARY (file) */ struct keytab iftab[] = { /* IF commands */ { "!", XXIFNO, 0 }, { "!=", XXIFNQ, 0 }, { "&&", XXIFAN, 0 }, { "(", XXIFLP, 0 }, { ")", XXIFRP, 0 }, { "<", XXIFLT, 0 }, { "<=", XXIFLE, 0 }, { "=", XXIFAE, 0 }, { "==", XXIFAE, CM_INV }, { ">", XXIFGT, 0 }, { ">=", XXIFGE, 0 }, { "absolute", XXIFAB, 0 }, { "alarm", XXIFAL, 0 }, { "and", XXIFAN, 0 }, { "asktimeout", XXIFAT, 0 }, { "available", XXIFAV, 0 }, { "background", XXIFBG, 0 }, { "binary", XXIFBIN,0 }, { "c-kermit", XXIFCK, 0 }, { "command", XXIFCM, 0 }, { "count", XXIFCO, 0 }, { "dcl", XXIFDC, CM_INV }, { "debug", XXIFDB, 0 }, { "declared", XXIFDC, 0 }, { "defined", XXIFDE, 0 }, #ifdef CK_TMPDIR { "directory", XXIFDI, 0 }, #endif /* CK_TMPDIR */ { "emulation", XXIFEM, 0 }, #ifdef COMMENT { "eof", XXIFEO, 0 }, #endif /* COMMENT */ { "equal", XXIFEQ, 0 }, { "error", XXIFFA, CM_INV }, { "exist", XXIFEX, 0 }, { "failure", XXIFFA, 0 }, { "false", XXIFNT, 0 }, { "flag", XXIFFL, 0 }, #ifdef CKFLOAT { "float", XXIFFP, 0 }, #endif /* CKFLOAT */ { "foreground", XXIFFG, 0 }, { "function", XXIFFU, 0 }, #ifdef OS2 { "gui", XXIFGU, 0 }, #else { "gui", XXIFGU, CM_INV }, #endif /* OS2 */ #ifdef IKSD { "iksd", XXIFIK, 0 }, #else { "iksd", XXIFIK, CM_INV }, #endif /* IKSD */ { "integer", XXIFNU, CM_INV }, { "k-95", XXIFK9, CM_INV }, { "kbhit", XXIFKB, 0 }, #ifdef UNIX { "kerbang", XXIFKG, 0 }, #else { "kerbang", XXIFKG, CM_INV }, #endif /* UNIX */ { "lge", XXIFLGE,0 }, { "lgt", XXIFLG, 0 }, #ifdef UNIX { "link", XXIFLN, 0 }, #endif /* UNIX */ { "lle", XXIFLLE,0 }, { "llt", XXIFLL, 0 }, { "local", XXIFLO, 0 }, { "match", XXIFMA, 0 }, { "ms-kermit", XXIFMS, CM_INV }, { "neq", XXIFNN, 0 }, #ifdef ZFCDAT { "newer", XXIFNE, 0 }, #endif /* ZFCDAT */ { "not", XXIFNO, 0 }, { "numeric", XXIFNU, 0 }, /* { "ok", XXIFSU, CM_INV }, */ { "open", XXIFOP, 0 }, { "or", XXIFOR, 0 }, { "quiet", XXIFQU, 0 }, { "readable", XXIFRD, 0 }, { "remote-only",XXIFRO, 0 }, { "started-from-dialer",XXIFSD, CM_INV }, { "success", XXIFSU, 0 }, { "tapi", XXIFTA, 0 }, #ifdef OS2 { "terminal-macro", XXIFTM, 0 }, #else { "terminal-macro", XXIFTM, CM_INV }, #endif /* OS2 */ { "text", XXIFTXT,0 }, { "true", XXIFTR, 0 }, { "version", XXIFVE, 0 }, { "wild", XXIFWI, 0 }, { "windows", XXIFK9, 0 }, { "writeable", XXIFWR, 0 }, { "||", XXIFOR, 0 }, { "", 0, 0 } }; int nif = (sizeof(iftab) / sizeof(struct keytab)) - 1; struct keytab iotab[] = { /* Keywords for IF OPEN */ { "!read-file", ZRFILE, CM_INV }, { "!write-file", ZWFILE, CM_INV }, { "append-file", ZWFILE, CM_INV }, { "connection", 8888, 0 }, #ifdef CKLOGDIAL { "cx-log", 7777, 0 }, #endif /* CKLOGDIAL */ { "debug-log", ZDFILE, 0 }, { "error", 9999, 0 }, { "packet-log", ZPFILE, 0 }, { "read-file", ZRFILE, 0 }, { "screen", ZSTDIO, 0 }, { "session-log", ZSFILE, 0 }, { "transaction-log", ZTFILE, 0 }, { "write-file", ZWFILE, 0 } }; int niot = (sizeof(iotab) / sizeof(struct keytab)); #endif /* NOSPL */ /* Variables and prototypes */ _PROTOTYP(static int doymdir,(int)); _PROTOTYP(static int renameone,(char *,char *, int,int,int,int,int,int,int,int,int,int,int)); #ifdef NETCONN extern int nnetdir; /* How many network directories */ #endif /* NETCONN */ #ifdef CK_SECURITY _PROTOTYP(int ck_krb4_is_installed,(void)); _PROTOTYP(int ck_krb5_is_installed,(void)); _PROTOTYP(int ck_ntlm_is_installed,(void)); _PROTOTYP(int ck_srp_is_installed,(void)); _PROTOTYP(int ck_ssleay_is_installed,(void)); _PROTOTYP(int ck_ssh_is_installed,(void)); _PROTOTYP(int ck_crypt_is_installed,(void)); #else #define ck_krb4_is_installed() (0) #define ck_krb5_is_installed() (0) #define ck_ntlm_is_installed() (0) #define ck_srp_is_installed() (0) #define ck_ssleay_is_installed() (0) #define ck_ssh_is_installed() (0) #define ck_crypt_is_installed() (0) #endif /* CK_SECURITY */ #define AV_KRB4 1 #define AV_KRB5 2 #define AV_NTLM 3 #define AV_SRP 4 #define AV_SSL 5 #define AV_CRYPTO 6 #define AV_SSH 7 struct keytab availtab[] = { /* Available authentication types */ { "crypto", AV_CRYPTO, CM_INV }, /* and encryption */ { "encryption", AV_CRYPTO, 0 }, { "k4", AV_KRB4, CM_INV }, { "k5", AV_KRB5, CM_INV }, { "kerberos4", AV_KRB4, 0 }, { "kerberos5", AV_KRB5, 0 }, { "krb4", AV_KRB4, CM_INV }, { "krb5", AV_KRB5, CM_INV }, { "ntlm", AV_NTLM, 0 }, { "srp", AV_SRP, 0 }, { "ssh", AV_SSH, 0 }, { "ssl", AV_SSL, 0 }, { "tls", AV_SSL, 0 }, { "", 0, 0 } }; int availtabn = sizeof(availtab)/sizeof(struct keytab)-1; #ifndef NODIAL _PROTOTYP(static int ddcvt, (char *, FILE *, int) ); #ifdef COMMENT /* New prototype above */ _PROTOTYP(static int dncvt, (int, int, int, int) ); #endif /* COMMENT */ _PROTOTYP(char * getdname, (void) ); static int partial = 0; /* For partial dial */ static char *dscopy = NULL; int dialtype = -1; char *dialnum = (char *)0; /* Remember DIAL number for REDIAL */ int dirline = 0; /* Dial directory line number */ extern char * dialdir[]; /* Dial directory file names */ extern int dialdpy; /* DIAL DISPLAY on/off */ extern int ndialdir; /* How many dial directories */ extern int ntollfree; /* Toll-free call info */ extern int ndialpxx; /* List of PBX exchanges */ extern char *dialtfc[]; char * matchpxx = NULL; /* PBX exchange that matched */ extern int nlocalac; /* Local area-code list */ extern char * diallcac[]; extern int tttapi; #ifdef CK_TAPI extern int tapiconv; /* TAPI Conversions */ extern int tapipass; /* TAPI Passthrough */ #endif /* CK_TAPI */ extern int dialatmo; extern char * dialnpr, * dialsfx; extern char * dialixp, * dialixs, * dialmac; extern char * dialldp, * diallds, * dialtfp; extern char * dialpxi, * dialpxo, * diallac; extern char * diallcp, * diallcs, * diallcc; extern char * dialpxx[]; extern int dialcnf; /* DIAL CONFIRMATION */ int dialfld = 0; /* DIAL FORCE-LONG-DISTANCE */ int dialsrt = 1; /* DIAL SORT ON */ int dialrstr = 6; /* DIAL RESTRICTION */ int dialtest = 0; /* DIAL TEST */ int dialcount = 0; /* \v(dialcount) */ extern int dialsta; /* Dial status */ int dialrtr = -1, /* Dial retries */ dialint = 10; /* Dial retry interval */ extern long dialcapas; /* Modem capabilities */ extern int dialcvt; /* DIAL CONVERT-DIRECTORY */ #endif /* NODIAL */ #ifndef NOSPL #define IFCONDLEN 256 int ifc, /* IF case */ not = 0, /* Flag for IF NOT */ ifargs = 0; /* Count of IF condition words */ char ifcond[IFCONDLEN]; /* IF condition text */ char *ifcp; /* Pointer to IF condition text */ extern int vareval; #ifdef DCMDBUF extern int *ifcmd, *count, *iftest, *intime, *inpcas, *takerr, *merror, *xquiet, *xvarev; #else extern int ifcmd[]; /* Last command was IF */ extern int iftest[]; /* Last IF was true */ extern int count[]; /* For IF COUNT, one for each cmdlvl */ extern int intime[]; /* Ditto for other stackables... */ extern int inpcas[]; extern int takerr[]; extern int merror[]; extern int xquiet[]; extern int xvarev[]; #endif /* DCMDBUF */ #else extern int takerr[]; #endif /* NOSPL */ #ifdef DCMDBUF extern char *line; /* Character buffer for anything */ extern char *tmpbuf; #else extern char line[], tmpbuf[]; #endif /* DCMDBUF */ extern char *lp; /* Pointer to line buffer */ int cwdf = 0; /* CWD has been done */ /* Flags for ENABLE/DISABLE */ extern int en_cwd, en_cpy, en_del, en_dir, en_fin, en_get, en_hos, en_ren, en_sen, en_set, en_spa, en_typ, en_who, en_bye, en_asg, en_que, en_ret, en_mai, en_pri, en_mkd, en_rmd, en_xit, en_ena; extern FILE *tfile[]; /* File pointers for TAKE command */ extern char *tfnam[]; /* Names of TAKE files */ extern int tfline[]; /* TAKE-file line number */ extern int success; /* Command success/failure flag */ extern int cmdlvl; /* Current position in command stack */ #ifndef NOSPL extern int maclvl; /* Macro to execute */ extern char *macx[]; /* Index of current macro */ extern char *mrval[]; /* Macro return value */ extern char *macp[]; /* Pointer to macro */ extern int macargc[]; /* ARGC from macro invocation */ #ifdef COMMENT extern char *m_line[]; #endif /* COMMENT */ extern char *m_arg[MACLEVEL][NARGS]; /* Stack of macro arguments */ extern char *g_var[]; /* Global variables %a, %b, etc */ #ifdef DCMDBUF extern struct cmdptr *cmdstk; /* The command stack itself */ #else extern struct cmdptr cmdstk[]; /* The command stack itself */ #endif /* DCMDBUF */ #endif /* NOSPL */ #define xsystem(s) zsyscmd(s) static int x, y, z = 0; static char *s, *p; #ifdef OS2 _PROTOTYP( int os2settitle, (char *, int) ); #endif /* OS2 */ extern struct keytab yesno[], onoff[], fntab[]; extern int nyesno, nfntab; #ifndef NOSPL /* Do the ASK, ASKQ, GETOK, and READ commands */ int asktimedout = 0; #define ASK_PUP 1 #define ASK_TMO 2 #define ASK_GUI 3 #define ASK_QUI 4 #define ASK_DEF 5 #define ASK_ECH 6 #define GETC_CHK 1 #define GETC_TMO 2 #define GETC_QUI 3 static struct keytab asktab[] = { { "/default", ASK_DEF, CM_ARG }, { "/gui", ASK_GUI, #ifdef KUI 0 #else /* KUI */ CM_INV #endif /* KUI */ }, { "/popup", ASK_PUP, #ifdef OS2 0 #else /* OS2 */ CM_INV #endif /* OS2 */ }, { "/quiet", ASK_QUI, 0 }, { "/timeout", ASK_TMO, CM_ARG }, { "", 0, 0 } }; static int nasktab = sizeof(asktab)/sizeof(struct keytab)-1; static struct keytab askqtab[] = { { "/default", ASK_DEF, CM_ARG }, { "/echo", ASK_ECH, CM_ARG }, { "/gui", ASK_GUI, #ifdef KUI 0 #else /* KUI */ CM_INV #endif /* KUI */ }, { "/noecho", ASK_QUI, CM_INV }, { "/popup", ASK_PUP, #ifdef OS2 0 #else /* OS2 */ CM_INV #endif /* OS2 */ }, { "/quiet", ASK_QUI, 0 }, { "/timeout", ASK_TMO, CM_ARG }, { "", 0, 0 } }; static int naskqtab = sizeof(askqtab)/sizeof(struct keytab)-1; static struct keytab getctab[] = { { "/check", GETC_CHK, 0 }, { "/quiet", GETC_QUI, 0 }, { "/timeout", GETC_TMO, CM_ARG }, { "", 0, 0 } }; static int ngetctab = sizeof(getctab)/sizeof(struct keytab)-1; int #ifdef CK_ANSIC doask( int cx ) #else doask(cx) int cx; #endif /* CK_ANSIC */ { extern int asktimer, timelimit; #ifdef CK_RECALL extern int on_recall; #endif /* CK_RECALL */ int echochar = 0; int popupflg = 0; int guiflg = 0; int nomsg = 0; int mytimer = 0; int peek = 0; #ifdef CK_APC extern int apcactive, apcstatus; #endif /* CK_APC */ char dfbuf[1024]; /* Buffer for default answer */ char * dfanswer = NULL; /* Pointer to it */ char vnambuf[VNAML+1]; /* Buffer for variable names */ char *vnp = NULL; /* Pointer to same */ dfbuf[0] = NUL; vnambuf[0] = NUL; #ifdef CK_APC if ( apcactive != APC_INACTIVE && (apcstatus & APC_NOINP) ) { return(success = 0); } #endif /* CK_APC */ mytimer = asktimer; /* Inherit global ASK timer */ echostars = 0; /* For ASKQ */ if (cx == XXASK || cx == XXASKQ) { struct FDB sw, fl; int getval; char c; if (cx == XXASKQ) /* Don't log ASKQ response */ debok = 0; cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Variable name or switch", "", /* default */ "", /* addtl string data */ ((cx == XXASK) ? nasktab : naskqtab), /* Table size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ ((cx == XXASK) ? asktab : askqtab), /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* Anything that doesn't match */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, NULL, NULL ); while (1) { /* Parse 0 or more switches */ x = cmfdb(&sw); /* Parse something */ if (x < 0) return(x); if (cmresult.fcode != _CMKEY) /* Break out if not a switch */ break; c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } switch (cmresult.nresult) { case ASK_QUI: nomsg = 1; if (cx == XXASKQ) echostars = 0; break; case ASK_PUP: popupflg = 1; break; case ASK_GUI: guiflg = 1; break; case ASK_TMO: { if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0) return(y); if (x < 0) x = 0; mytimer = x; break; } case ASK_ECH: { if ((y = cmfld("Character to echo","*",&s,xxstring)) < 0) return(y); echochar = *s; break; } case ASK_DEF: { if ((y = cmfld("Text to supply if reply is empty", "",&s,xxstring)) < 0) return(y); ckstrncpy(dfbuf,s,1024); dfanswer = dfbuf; break; } default: return(-2); } } /* Have variable name, make copy. */ ckstrncpy(vnambuf,cmresult.sresult,VNAML); vnp = vnambuf; if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++; y = 0; if (*vnp == '%' || *vnp == '&') { if ((y = parsevar(vnp,&x,&z)) < 0) return(y); } } else if (cx == XXGETC) { /* GETC */ struct FDB sw, fl; int getval; char c; cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Variable name or switch", "", /* default */ "", /* addtl string data */ ngetctab, /* Table size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ getctab, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* Anything that doesn't match */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, NULL, NULL ); while (1 && !peek) { /* Parse 0 or more switches */ x = cmfdb(&sw); /* Parse something */ if (x < 0) return(x); if (cmresult.fcode != _CMKEY) /* Break out if not a switch */ break; c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } switch (cmresult.nresult) { case GETC_CHK: /* GETC /CHECK */ peek = 1; break; case GETC_QUI: /* GETC /QUIET */ nomsg = 1; break; case GETC_TMO: { /* GETC /TIMEOUT:sec */ if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0) return(y); if (x < 0) x = 0; mytimer = x; break; } default: return(-2); } } if (peek) { /* GETC /CHECK */ /* This was intended to mean "check how many characters are waiting to be read from standard input". Conchk() was supposed to do that but it doesn't when stdin is redirected. The best I can do is ask isatty(0) whether stdin is a terminal. If not we'll assume it's redirected stdin. Btw, even if stdin really is a terminal conchk() returns 0, even if there is typeahead. - fdc, 21 Apr 2017. */ int itsatty = -1; if ((y = cmcfm()) < 0) /* Get confirmation */ return(y); itsatty = isatty(0); /* Is stdin a tty? */ debug(F101,"GETC peek","",peek); debug(F101,"GETC itsatty","",itsatty); return(success = (itsatty > 0) ? 0 : 1); } /* Regular GETC... Have variable name, make copy. */ ckstrncpy(vnambuf,cmresult.sresult,VNAML); vnp = vnambuf; if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++; y = 0; if (*vnp == '%' || *vnp == '&') { if ((y = parsevar(vnp,&x,&z)) < 0) return(y); } } else if (cx != XXGOK && cx != XXRDBL && !peek) { /* Get variable name */ if ((y = cmfld("Variable name","",&s,NULL)) < 0) { if (y == -3) { printf("?Variable name required\n"); return(-9); } else return(y); } ckstrncpy(vnambuf,s,VNAML); /* Make a copy. */ vnp = vnambuf; if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++; y = 0; if (*vnp == '%' || *vnp == '&') { if ((y = parsevar(vnp,&x,&z)) < 0) return(y); } } if (cx == XXREA || cx == XXRDBL) { /* READ or READBLOCK command */ if ((y = cmcfm()) < 0) /* Get confirmation */ return(y); if (chkfn(ZRFILE) < 1) { /* File open? */ printf("?Read file not open\n"); return(success = 0); } if (!(s = (char *)readbuf)) { /* Where to read into. */ printf("?Oops, no READ buffer!\n"); return(success = 0); } y = zsinl(ZRFILE, s, readblock); /* Read a line. */ debug(F111,"read zsinl",s,y); if (y < 0) { /* On EOF or other error, */ zclose(ZRFILE); /* close the file, */ delmac(vnp,0); /* delete the variable, */ return(success = 0); /* and return failure. */ } else { /* Read was OK. */ readsize = (int) strlen(s); success = (addmac(vnp,s) < 0 ? 0 : 1); /* Define variable */ debug(F111,"read addmac",vnp,success); return(success); /* Return success. */ } } /* ASK, ASKQ, GETOK */ if (cx == XXGOK) { /* GETOK can take switches */ struct FDB sw, fl; int getval; char c; cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Variable name or question prompt", "", /* default */ "", /* addtl string data */ nasktab, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ asktab, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* Anything that doesn't match */ _CMTXT, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, NULL, NULL ); while (1) { /* Parse 0 or more switches */ x = cmfdb(&sw); /* Parse something */ if (x < 0) return(x); if (cmresult.fcode != _CMKEY) /* Break out if not a switch */ break; c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } switch (cmresult.nresult) { case ASK_PUP: popupflg = 1; break; case ASK_GUI: guiflg = 1; break; case ASK_TMO: { if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0) return(y); if (x < 0) x = 0; mytimer = x; break; } case ASK_DEF: { if ((y = cmfld("Text to supply if reply is empty", "",&s,xxstring)) < 0) return(y); ckstrncpy(dfbuf,s,1024); dfanswer = dfbuf; break; } case ASK_QUI: nomsg = 1; break; default: return(-2); } } p = cmresult.sresult; } else if ((y = cmtxt( "Prompt,\n\ enclose in { braces } or \" quotes \" to preserve leading and trailing\n\ spaces, precede question mark with backslash (\\).", "",&p,xxstring)) < 0) return(y); if (!p) p = ""; #ifndef NOLOCAL #ifdef OS2 if (popupflg) { /* Popup requested */ int len = -1; ckstrncpy(tmpbuf,brstrip(p),TMPBUFSIZ); p = tmpbuf; if (cx == XXASK || cx == XXASKQ) { if (cx == XXASK) len = popup_readtext(vmode,NULL,p,line,LINBUFSIZ,mytimer); else len = popup_readpass(vmode,NULL,p,line,LINBUFSIZ,mytimer); asktimedout = ( len < 0 && mytimer ); } else if (cx == XXGOK) { printf("?Sorry, GETOK /POPUP not implemented yet\n"); timelimit = 0; return(-9); } if (len >= 0) { y = addmac(vnp,(char *)line); /* Add it to the macro table. */ } else if ( asktimedout && dfanswer ) { y = addmac(vnp,dfanswer); /* Add it to the macro table. */ asktimedout = 0; len = 0; } timelimit = 0; return(success = ((len >= 0) && (y >= 0)) && !asktimedout); } #ifdef KUI if (guiflg) { /* GUI requested */ int rc, n; char * s1; s1 = tmpbuf; n = TMPBUFSIZ-1; zzstring(brstrip(p),&s1,&n); p = tmpbuf; if (cx == XXASK || cx == XXASKQ) { rc = gui_txt_dialog(NULL,p,(cx == XXASK), line,LINBUFSIZ,dfanswer,mytimer); asktimedout = (rc == -1 && mytimer); if (rc == 1) { y = addmac(vnp,(char *)line); /* Add it to the macro table. */ } else if ( asktimedout && dfanswer ) { y = addmac(vnp,dfanswer); /* Add default to macro table. */ asktimedout = 0; rc = 1; } timelimit = 0; return(success = (rc == 1 && (y >= 0)) && !asktimedout); } else if (cx == XXGOK) { int x; x = lookup(yesno,dfanswer,nyesno,NULL); if (x != 1) x = 2; rc = uq_ok(NULL, p, 3, NULL, x); return(success = (rc == 1)); } } #endif /* KUI */ #endif /* OS2 */ #endif /* NOLOCAL */ concb((char)escape); /* Enter CBREAK mode */ cmsavp(psave,PROMPTL); /* Save old prompt */ cmsetp(brstrip(p)); /* Make new prompt */ reprompt: if (cx == XXASKQ) { /* For ASKQ, */ cmini(0); /* no-echo mode. */ if (echochar) echostars = echochar; } else { /* For others, regular echoing. */ cmini(ckxech); echostars = 0; } askflag = 1; x = -1; /* This means to reparse. */ cmflgs = 0; if (pflag) prompt(xxstring); /* Issue prompt. */ asktimedout = 0; /* Handle timed responses. */ timelimit = mytimer; reparse: cmres(); if (cx == XXGOK) { /* GETOK */ #ifdef CK_RECALL on_recall = 0; #endif /* CK_RECALL */ askflag = 0; /* GETOK uses keyword table */ x = cmkey(yesno,nyesno,"",dfanswer,xxstring); if (x < 0) { /* Parse error */ if (x == -10) { char * ds; ds = dfanswer ? dfanswer : "No"; if (!nomsg) printf("?Timed out, assuming \"%s\"",ds); printf("\n"); asktimedout = 1; x = lookup(yesno,ds,nyesno,NULL); if (x != 1) x = 0; goto gokdone; } else if (x == -3) { /* No answer? */ printf("Please respond Yes or No\n"); /* Make them answer */ cmini(ckxech); goto reprompt; } else if (x == -1) { goto reparse; } else goto reprompt; } if (cmcfm() < 0) /* Get confirmation */ goto reparse; gokdone: askflag = 0; cmsetp(psave); /* Restore prompt */ #ifdef VMS if (cmdlvl > 0) /* In VMS and not at top level, */ conres(); /* restore console again. */ #endif /* VMS */ timelimit = 0; return(x); /* Return success or failure */ } else if (cx == XXGETC /* GETC */ #ifdef OS2 || cx == XXGETK /* or GETKEYCODE */ #endif /* OS2 */ ) { /* GETC */ char tmp[16]; conbin((char)escape); /* Put keyboard in raw mode */ #ifndef NOSETKEY #ifdef OS2 if (cx == XXGETK) { /* GETKEYCODE */ extern int os2gks; int t; t = os2gks; /* Turn off kverb recognition */ os2gks = 0; x = congks(timelimit); /* Read a key event, blocking */ os2gks = t; /* Put back kverb recognition */ } else /* GETC */ #endif /* OS2 */ #endif /* NOSETKEY */ { x = coninc(timelimit); /* Read one character */ debug(F101,"GETC coninc","",x); } concb((char)escape); /* Put keyboard back in cbreak mode */ if (x > -1) { if (xcmdsrc == 0) printf("\r\n"); #ifdef OS2 if (cx == XXGETK) { /* GETKEYCODE */ sprintf(tmp,"%d",x); /* SAFE */ } else { #endif /* OS2 */ tmp[0] = (char) (x & 0xff); tmp[1] = NUL; #ifdef OS2 } #endif /* OS2 */ y = addmac(vnp,tmp); /* Add it to the macro table. */ debug(F111,"getc/getk addmac",vnp,y); } else y = -1; cmsetp(psave); /* Restore old prompt. */ if (x < -1) { asktimedout = 1; if (!quiet && !nomsg) printf("?Timed out"); printf("\n"); } timelimit = 0; return(success = ((y < 0 ? 0 : 1) && (asktimedout == 0))); } else { /* ASK or ASKQ */ #ifdef CK_RECALL on_recall = 0; /* Don't put response in recall buf */ #endif /* CK_RECALL */ askflag = 1; /* ASK[Q] always goes to terminal */ y = cmdgquo(); /* Get current quoting */ cmdsquo(0); /* Turn off quoting */ while (x == -1) { /* Prompt till they answer */ x = cmtxt("Please respond.",dfanswer,&s,NULL); debug(F111,"ASK cmtxt",s,x); cmres(); } cmdsquo(y); /* Restore previous quoting */ if (cx == XXASKQ) /* ASKQ must echo CRLF here */ printf("\r\n"); if (x == -10 && dfanswer) { /* Don't fail on timeout if */ s = dfanswer; /* a default was specified */ asktimedout = 0; /* and don't fail */ x = 0; } if (x < 0) { /* If cmtxt parse error, */ cmsetp(psave); /* restore original prompt */ #ifdef VMS if (cmdlvl > 0) /* In VMS and not at top level, */ conres(); /* restore console again. */ #endif /* VMS */ if (x == -10) { /* Timed out with no response */ if (!nomsg) printf("?Timed out"); printf("\n"); asktimedout = 1; if (dfanswer) /* Supply default answer if any */ s = dfanswer; success = x = 0; /* (was "x = -9;") */ } timelimit = 0; return(x); /* and return cmtxt's error code. */ } if (!s || *s == NUL) { /* If user typed a bare CR, */ cmsetp(psave); /* Restore old prompt, */ delmac(vnp,0); /* delete variable if it exists, */ #ifdef VMS if (cmdlvl > 0) /* In VMS and not at top level, */ conres(); /* restore console again. */ #endif /* VMS */ timelimit = 0; return(success = 1); /* and return. */ } y = addmac(vnp,s); /* Add it to the macro table. */ debug(F111,"ask addmac",vnp,y); cmsetp(psave); /* Restore old prompt. */ #ifdef VMS if (cmdlvl > 0) /* In VMS and not at top level, */ conres(); /* restore console again. */ #endif /* VMS */ timelimit = 0; return(success = (y < 0 ? 0 : 1) && (asktimedout == 0)); } } #endif /* NOSPL */ #ifndef NOSPL int #ifdef CK_ANSIC doincr( int cx ) /* INCREMENT, DECREMENT */ #else doincr(cx) int cx; #endif /* CK_ANSIC */ { char vnambuf[VNAML+1]; /* Buffer for variable names */ int eval = 0; CK_OFF_T x; eval = (cx == XX_DECR || cx == XX_INCR); if ((y = cmfld("Variable name","",&s, eval ? xxstring : NULL)) < 0) { if (y == -3) { printf("?Variable name required\n"); return(-9); } else return(y); } ckstrncpy(vnambuf,s,VNAML); if ((y = cmnumw("by amount","1",10,&x,xxstring)) < 0) return(y); if ((y = cmcfm()) < 0) return(y); z = (cx == XX_INCR || cx == XXINC) ? 1 : 0; /* Increment or decrement? */ if (incvar(vnambuf,x,z) < 0) { printf("?Variable %s not defined or not numeric\n",vnambuf); return(success = 0); } return(success = 1); } /* Used by doundef() */ static int #ifdef CK_ANSIC xxundef( char * s, int verbose, int simulate ) #else xxundef(s,verbose,simulate) char * s; int verbose, simulate; #endif /* CK_ANSIC */ { int rc = 0; if (!s) return(0); if (*s == CMDQ && *(s+1) == '%') { char c = *(s+2), * p = NULL; if (c >= '0' && c <= '9') { if (maclvl < 0) p = g_var[c]; else p = m_arg[maclvl][c - '0']; } else { if (isupper(c)) c += ('a'-'A'); if (c >= 'a' && c <= 'z') p = g_var[c]; } if (!p) return(-1); } if (verbose) printf(" %s ",s); if (simulate) { printf("(SELECTED)\n"); } else if ((x = delmac(s,1)) > -1) { /* Full name required */ rc = 1; if (verbose) printf("(OK)\n"); } else if (verbose) printf("(FAILED)\n"); return(rc); } /* Do the (_)DEFINE, (_)ASSIGN, and UNDEFINE commands */ #define UND_MAT 1 #define UND_VRB 2 #define UND_EXC 3 #define UND_SIM 3 static struct keytab undefswi[] = { { "/list", UND_VRB, 0 }, #ifdef COMMENT { "/except", UND_EXC, CM_ARG }, #endif /* COMMENT */ { "/matching", UND_MAT, 0 }, { "/simulate", UND_SIM, 0 }, { "/verbose", UND_VRB, CM_INV } }; static int nundefswi = sizeof(undefswi) / sizeof(struct keytab); #define UNDEFMAX 64 static char ** undeflist = NULL; int #ifdef CK_ANSIC doundef( int cx ) /* UNDEF, _UNDEF */ #else doundef(cx) int cx; #endif /* CK_ANSIC */ { int i, j, n, rc = 0, arraymsg = 0; int domatch = 0, verbose = 0, errors = 0, simulate = 0, flag = 0; char *vnp, vnbuf[4]; #ifdef COMMENT char *except = NULL; #endif /* COMMENT */ struct FDB sw, fl; int getval; char c; if (!undeflist) { /* Allocate list if necessary */ undeflist = (char **)malloc(UNDEFMAX * sizeof(char *)); if (!undeflist) { printf("?Memory allocation failure\n"); return(-9); } for (i = 0; i < UNDEFMAX; i++) undeflist[i] = NULL; } cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Variable name or switch", "", /* default */ "", /* addtl string data */ nundefswi, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ undefswi, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* Anything that doesn't match */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ (cx == XXUNDEF) ? NULL : xxstring, NULL, NULL ); while (1) { /* Parse 0 or more switches */ x = cmfdb(&sw); /* Parse something */ if (x < 0) return(x); if (cmresult.fcode != _CMKEY) /* Break out if not a switch */ break; c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } switch (cmresult.nresult) { case UND_MAT: domatch = 1; break; case UND_SIM: simulate = 1; /* fall thru on purpose */ case UND_VRB: verbose = 1; break; #ifdef COMMENT case UND_EXC: if (!getval) break; if ((x = cmfld("Pattern","",&s,xxstring)) < 0) { if (x == -3) { printf("?Pattern required\n"); x = -9; } goto xgetx; } makestr(&except,cmresult.sresult); break; #endif /* COMMENT */ default: return(-2); } } n = 0; makestr(&(undeflist[n++]),cmresult.sresult); for (i = 1; i < UNDEFMAX; i++) { x = cmfld("Macro or variable name","",&s, ((cx == XXUNDEF) ? NULL : xxstring) ); if (x == -3) { if ((y = cmcfm()) < 0) return(y); break; } else if (y < 0) { return(y); } makestr(&(undeflist[n++]),s); } /* Now we have a list of n variables or patterns to undefine */ for (i = 0; i < n; i++) { flag = 0; if (!(vnp = undeflist[i])) continue; if (vnp[0] == CMDQ && (vnp[1] == '%' || vnp[1] == '&')) { flag++; vnp++; } if (!domatch) { /* Pattern match not requested */ if (flag) { if ((y = parsevar(vnp,&x,&z)) < 0) { vnp--; if (verbose) printf(" %s...error\n",vnp); continue; } vnp--; } x = xxundef(vnp,verbose,simulate); if (x > -1) { if (!x && !simulate) errors++; rc += x; } continue; } /* Pattern match requested */ if (!flag) { /* It's a macro */ for (j = 0; j < nmac; j++) { if (ckmatch(vnp,mactab[j].kwd,0,1)) { x = xxundef(mactab[j].kwd,verbose,simulate); if (x > -1) { rc += x; if (!x) errors++; } if (!simulate) j--; /* Because mactab shifted up */ } } } else if (vnp[0] == '%') { /* It's a \%x variable */ vnbuf[0] = CMDQ; vnbuf[1] = '%'; vnbuf[3] = NUL; for (j = '0'; j <= 'z'; j++) { /* 0..9 a..z */ vnbuf[2] = j; if (ckmatch(vnp,&vnbuf[1],0,1)) { x = xxundef(vnbuf,verbose,simulate); if (x > -1) { if (!x) errors++; rc += x; } } if (j == '9') j = (int)'a' - 1; /* 9 -> a */ } } else if (vnp[0] == '&') { if (!arraymsg && !quiet) { printf("?UNDEFINE /MATCH can't be used with arrays.\n"); printf("(Type HELP ARRAY to see other methods.)\n"); } arraymsg++; errors++; } } if (verbose) printf("undefined: %d, errors: %d\n",rc,errors); for (i = 0; i < UNDEFMAX; i++) { /* Check them all */ if (undeflist[i]) { /* in case we were interrupted */ free(undeflist[i]); /* previously... */ undeflist[i] = NULL; } } return(success = (errors == 0) ? 1 : 0); } int #ifdef CK_ANSIC dodef( int cx ) #else dodef(cx) int cx; #endif /* CK_ANSIC */ { extern int xxdot; extern char ppvnambuf[]; int doeval = 0; char vnambuf[VNAML+1]; /* Buffer for variable names */ char *vnp; /* Pointer to same */ int k, mydot; mydot = xxdot; /* Copy */ xxdot = 0; /* and reset */ /* In case we got here from a command that begins like ".\%a", cmkey() has already evaluated \%a, but we don't want that, so we retrieve the variable name from a special pre-evaluation buffer in the command module, and we undo the "unget word" that would be done because of the token, because if the variable was defined, it will unget its value rather than its name. */ s = NULL; if (mydot && ppvnambuf[0] == '.' && ppvnambuf[1]) { s = ppvnambuf+1; unungw(); } if (!s) { if (cx == XXDFX || cx == XXASX) /* Evaluate variable name */ y = cmfld("Macro or variable name","",&s,xxstring); else /* Don't evaluate the variable name */ y = cmfld("Macro or variable name","",&s,NULL); if (y < 0) { if (y == -3) { printf("?Variable name required\n"); return(-9); } else return(y); } } k = strlen(s); if (k > VNAML) { printf("?Name too long: \"%s\"\n",s); return(-9); } ckstrncpy(vnambuf,s,VNAML); vnambuf[VNAML] = NUL; vnp = vnambuf; if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++; if (*vnp == '%' || *vnp == '&') { if ((y = parsevar(vnp,&x,&z)) < 0) return(y); #ifdef COMMENT if (cx == XXUNDEF) { /* Undefine */ if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y); delmac(vnp,0); return(success = 1); } #endif /* COMMENT */ debug(F101,"dodef parsevar x","",x); if (mydot) { if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0) return(doeval); if (doeval > 0) /* Type of assignment */ cx = XXASS; } if (y == 1) { /* Simple variable */ if ((y = cmtxt("Definition of variable","",&s,NULL)) < 0) return(y); s = brstrip(s); debug(F110,"xxdef var name",vnp,0); debug(F110,"xxdef var def",s,0); } else if (y == 2) { /* Array element */ if ((y = arraynam(vnp,&x,&z)) < 0) return(y); if (x == 96) { printf("?Argument vector array is read-only\n"); return(-9); } if (chkarray(x,z) < 0) return(-2); if ((y = cmtxt("Definition of array element","",&s,NULL)) < 0) return(y); debug(F110,"xxdef array ref",vnp,0); debug(F110,"xxdef array def",s,0); } } else { /* Macro */ #ifdef COMMENT if (cx == XXUNDEF) { /* Undefine */ if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y); delmac(vnp,0); return(success = 1); } #endif /* COMMENT */ if (mydot) { if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0) return(doeval); if (doeval > 0) cx = XXASS; } if ((y = cmtxt("Definition of macro","",&s,NULL)) < 0) return(y); #ifdef DEBUG if (deblog) { debug(F110,"xxdef macro name",vnp,0); debug(F010,"xxdef macro def",s,0); } #endif /* DEBUG */ s = brstrip(s); } if (*s == NUL) { /* No arg given, undefine */ delmac(vnp,1); /* silently... */ return(success = 1); /* even if it doesn't exist... */ } /* Defining a new macro or variable */ if (cx == XXASS || cx == XXASX) { /* ASSIGN rather than DEFINE? */ int t; t = LINBUFSIZ-1; lp = line; /* If so, expand its value now */ zzstring(s,&lp,&t); s = line; } if (doeval == 2) { /* Arithmetic evaluation wanted too? */ ckstrncpy(line,evala(s),LINBUFSIZ); line[LINBUFSIZ] = NUL; } /* debug(F111,"calling addmac",s,(int)strlen(s)); */ y = addmac(vnp,s); /* Add it to the appropriate table. */ if (y < 0) { printf("?%s failed\n",(cx == XXASS || cx == XXASX) ? "ASSIGN" : "DEFINE"); return(success = 0); } else if (cx == XXASX || cx == XXDFX) /* For _ASG or _DEF, */ return(1); /* don't change success variable */ else return(success = 1); } #endif /* NOSPL */ #ifndef NODIAL /* L U D I A L -- Lookup up dialing directory entry. Call with string to look up and file descriptor of open dialing directory file. On success, returns number of matches found, with numbers stored in an array accessible via getdnum(). */ static char *dn_p[MAXDNUMS + 1]; /* Dial Number pointers */ static char *dn_p2[MAXDNUMS + 1]; /* Converted dial number pointers */ static int dn_x[MAXDNUMS + 1]; /* Type of call */ static int dncount = 0; char * d_name = NULL; /* Dial name pointer */ char * /* Get dial directory entry name */ #ifdef CK_ANSIC getdname( void ) #else getdname() #endif /* CK_ANSIC */ { return(d_name ? d_name : ""); } char * #ifdef CK_ANSIC getdnum( int n ) /* Get dial number n from directory */ #else getdnum(n) int n; #endif /* CK_ANSIC */ { if (n < 0 || n > dncount || n > MAXDNUMS) return(""); else return(dn_p[n]); } char * /* Check area code for spurious leading digit */ #ifdef CK_ANSIC chk_ac( int i, char buf[] ) #else chk_ac(i,buf) int i; char buf[]; #endif /* CK_ANSIC */ { char *p; if (!buf) return(""); p = (char *) buf; /* Country we are calling: */ if (i == 44 || /* UK */ i == 49 || /* Germany */ i == 39 || /* Italy */ i == 31 || /* Netherlands */ i == 351 || /* Portugal */ i == 55 || /* Brazil */ i == 972 || /* Israel */ i == 41 || /* Switzerland */ i == 43 || /* Austria */ i == 42 || /* Czech Republic */ i == 36 || /* Hungary */ i == 30 || /* Greece */ i == 352 || /* Luxembourg */ i == 48 || /* Poland */ i == 27 || /* South Africa */ i == 33 || /* France (as of 1997) */ i == 358 /* Finland (ditto) */ ) { if (buf[0] == '0') p++; } return(p); } /* Call Is Long Distance -- Expand this to cover 10-digit local dialing etc */ /* src = area code of caller dest = area code of callee Returns: 0 if call is local 1 if call is long distance 2 if call is local but area code must be dialed anyway */ static int #ifdef CK_ANSIC callisld( char * src, char * dest ) #else callisld(src, dest) char * src, * dest; #endif /* CK_ANSIC */ { int i; if (dialfld) /* Force long distance? */ return(1); if (!strcmp(src,dest)) { /* Area codes are the same */ for (i = 0; i < nlocalac; i++) /* Is AC in the lc-area-codes list? */ if (!strcmp(src,diallcac[i])) return(2); /* Yes so must be dialed */ return(0); /* No so don't dial it. */ } for (i = 0; i < nlocalac; i++) /* ACs not the same so look in list */ if (!strcmp(dest,diallcac[i])) /* Match */ return(2); /* So local call with area code */ return(1); /* Not local so long-distance */ } char pdsfx[64] = { NUL, NUL }; #ifndef NOSPL static char * #ifdef CK_ANSIC xdial( char *s ) /* Run dial string thru macro */ #else xdial(s) char *s; #endif /* CK_ANSIC */ { int x, m; char * s2; s2 = NULL; makestr(&s2,s); /* Copy the argument */ if (!dialmac) /* Dial macro name given? */ return(NULL); if ((x = mxlook(mactab,dialmac,nmac)) < 0) /* Is the macro defined? */ return(NULL); m = maclvl; x = dodo(x,s2,0); /* Set up the macro */ if (s2) free(s2); if (x > 0) { while (maclvl > m) /* Execute the parser */ parser(1); return(mrval[maclvl+1]); /* Return the result */ } return(NULL); } #endif /* NOSPL */ static int #ifdef CK_ANSIC dncvt(int k, int cx, int prefix, int suffix) /* Dial Number Convert */ #else dncvt(k,cx, prefix, suffix) int k, cx, prefix, suffix; #endif /* CK_ANSIC */ { int i, j, n, what; /* cx is top-level command index */ char *ss; /* prefix - add prefixes? */ char *p, *p2, *pxo; /* suffix - add suffixes? */ char *lac; char *npr; char *sfx; /* char *psfx; */ char ccbuf[128]; int cc; char acbuf[24]; char *acptr; char outbuf[256]; /* First pass for strict (punctuation-based) interpretation. If it fails, we try the looser (length-based) one. */ dialtype = -1; what = 0; /* Type of call */ s = dn_p[k]; /* Number to be converted. */ debug(F111,"dncvt",s,k); if (dn_p2[k]) { free(dn_p2[k]); dn_p2[k] = NULL; } if (!s) { printf("Error - No phone number to convert\n"); return(-1); } if ((int)strlen(s) > 200) { ckstrncpy(outbuf,s,40); printf("?Too long: \"%s...\"\n",outbuf); return(-1); } npr = (prefix && dialnpr) ? dialnpr : ""; sfx = (suffix && dialsfx) ? dialsfx : ""; /* if (partial) psfx = dialsfx ? dialsfx : ""; */ pxo = (prefix && dialpxo) ? dialpxo : ""; lac = diallac ? diallac : ""; /* Local area code */ outbuf[0] = NUL; /* Initialize conversion buffer */ ss = s; /* Remember original string */ if (*s != '+') { /* Literal number */ dn_x[k] = DN_UNK; /* Sort key is "unknown". */ ckmakmsg(outbuf,256, /* Sandwich it between */ pxo,npr,s,sfx /* DIAL PREFIX and SUFFIX */ ); #ifdef CK_TAPI if (tttapi && /* TAPI does its own conversions */ !tapipass && /* if not in passthru mode */ tapiconv == CK_AUTO || /* and TAPI conversions are AUTO */ tapiconv == CK_ON /* OR if TAPI conversions are ON */ ) { char * p = NULL; dialtype = -2; if (!cktapiConvertPhoneNumber(dn_p[k], &p)) return(-1); makestr(&dn_p2[k], p); if (p) free(p); return(0); } else #endif /* CK_TAPI */ makestr(&dn_p2[k], outbuf); /* Not TAPI */ dialtype = what; return(0); /* Done. */ } i = 0; /* Portable number */ s++; /* Tiptoe past the plus sign */ ccbuf[0] = NUL; /* Do country code first */ if (!diallcc) { /* Do we know our own? */ if (cx != XXLOOK) printf("Error - prior SET DIAL COUNTRY-CODE command required\n"); return(-1); } /* Parse the number */ while (1) { /* Get the country code */ while (*s == HT || *s == SP) s++; if (!s) /* Not in standard format */ break; if (*s == '(') { /* Beginning of area code */ s++; /* Skip past parenthesis */ ccbuf[i] = NUL; /* End of country code */ if (!s) { /* Check for end of string */ printf("Error - phone number ends prematurely: \"%s\"\n",ss); return(-1); } break; } else { /* Collect country code */ if (isdigit(*s)) ccbuf[i++] = *s; /* copy this character */ s++; if (!*s || i > 127) /* watch out for memory leak */ break; } } cc = atoi(ccbuf); /* Numeric version of country code */ i = 0; /* Now get area code */ acbuf[0] = NUL; /* Initialize area-code buffer */ acptr = acbuf; /* and pointer. */ while (1) { while (*s == HT || *s == SP) /* Ignore whitespace */ s++; if (!s) /* String finished */ break; if (*s == ')') { /* End of area code */ s++; /* Skip past parenthesis */ acbuf[i] = NUL; /* Terminate area-code buffer */ break; } else { /* Part of area code */ if (isdigit(*s)) /* If it's a digit, */ acbuf[i++] = *s; /* copy this character */ s++; /* Point to next */ if (!*s || i > 23) /* Watch out for overflow */ break; } } /* Here we strip any leading 0 for countries that we know have 0 as a long-distance prefix and do not have any area codes that start with 0 (formerly also ditto for "9" in Finland...) */ i = atoi(ccbuf); acptr = chk_ac(i,acbuf); while (*s == HT || *s == SP) /* Skip whitespace */ s++; /* printf("S=[%s], ACPTR=[%s]\n",s,acptr); */ if (*s && *acptr) { /* Area code was delimited */ while (*s == '-' || *s == '.') /* Skip past gratuitious punctuation */ s++; if (!*s) s--; /* But not to end of string */ if (strcmp(diallcc,ccbuf)) { /* Out of country? */ if (!dialixp) { /* Need intl-prefix */ if (cx != XXLOOK) printf("Error - No international dialing prefix defined\n"); return(-1); } what = dn_x[k] = DN_INTL; p = (prefix && dialixp) ? dialixp : ""; /* Intl-prefix */ p2 = (suffix && dialixs) ? dialixs : ""; /* Intl-suffix */ /* Form the final phone number */ #ifdef COMMENT sprintf(pdsfx,"%s%s",p2,sfx); /* UNSAFE */ sprintf(outbuf, "%s%s%s%s%s%s%s%s", pxo,npr,p,ccbuf,acptr,s,p2,sfx ); #else ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL); ckmakxmsg(outbuf,256,pxo,npr,p,ccbuf,acptr,s,p2,sfx, NULL,NULL,NULL,NULL); #endif /* COMMENT */ } else if ((x = callisld(lac,acptr)) >= 1) { /* In-country LD */ if (!diallac && cx != XXLOOK) { /* Don't know my own area code */ if (cc == 1) printf("WARNING - Prior SET DIAL AREA-CODE needed\n"); } if (x == 2) { /* Local call with area code */ what = dn_x[k] = DN_LOCAL; /* Local-call */ p = (prefix && diallcp) ? diallcp : ""; /* local-prefix */ p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */ } else { what = dn_x[k] = DN_LONG; /* Long-distance */ for (i = 0; i < ntollfree; i++) { /* But toll-free too? */ if (!strcmp(acptr,dialtfc[i])) { what = dn_x[k] = DN_FREE; break; } } if (what == DN_FREE) { /* Toll-free call */ p = (prefix && dialtfp) ? dialtfp : ((prefix && dialldp) ? dialldp : ""); p2 = ""; /* no suffix */ } else { /* normal long distance */ p = (prefix && dialldp) ? dialldp : ""; /* ld-prefix */ p2 = (suffix && diallds) ? diallds : ""; /* ld-suffix */ } } /* Form the number to be dialed */ #ifdef COMMENT sprintf(outbuf,"%s%s%s%s%s%s%s", pxo,npr,p,acptr,s,p2,sfx ); sprintf(pdsfx,"%s%s",p2,sfx); #else ckmakxmsg(outbuf,256, pxo,npr,p,acptr,s,p2,sfx, NULL,NULL,NULL,NULL,NULL); ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL); #endif /* COMMENT */ } else { /* Same country, same area code */ what = dn_x[k] = DN_LOCAL; /* So it's a local call. */ if (!prefix || !(dialpxo || ndialpxx)) { /* Not dialing from PBX */ p = (prefix && diallcp) ? diallcp : ""; /* local-prefix */ p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */ #ifdef COMMENT if (x == 2) sprintf(outbuf,"%s%s%s%s%s%s",npr,p,acptr,s,p2,sfx); else sprintf(outbuf,"%s%s%s%s%s",npr,p,s,p2,sfx); sprintf(pdsfx,"%s%s",p2,sfx); #else if (x == 2) ckmakxmsg(outbuf,256, npr,p,acptr,s,p2,sfx, NULL,NULL,NULL,NULL,NULL,NULL); else ckmakxmsg(outbuf,256, npr,p,s,p2,sfx, NULL,NULL,NULL,NULL,NULL,NULL,NULL); ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL); #endif /* COMMENT */ } else { /* Dialing from a PBX and not TAPI */ if (ndialpxx) { /* Is it internal? */ #ifdef COMMENT i = (int) strlen(dialpxx); j = (int) strlen(s); x = -1; if (j > i) x = ckstrcmp(dialpxx,s,i,0); #else int kx; x = -1; j = (int) strlen(s); for (kx = 0; kx < ndialpxx; kx++) { i = (int) strlen(dialpxx[kx]); if (j > i) if (!(x = ckstrcmp(dialpxx[kx],s,i,0))) break; } #endif /* COMMENT */ if (!x) { char * icp, buf[32]; makestr(&matchpxx,dialpxx[kx]); debug(F111,"dncvt matchpxx",matchpxx,kx); what = dn_x[kx] = DN_INTERN; /* Internal call. */ s += i; /* Internal-call prefix */ icp = dialpxi; #ifndef NOSPL if (icp) { if (*icp == '\\') { char c, *bp; int n; c = *(icp+1); if (isupper(c)) c = tolower(c); if (c == 'v' || c == 'f') { n = 32; bp = buf; zzstring(icp,&bp,&n); icp = buf; } } } #endif /* NOSPL */ p = (prefix && icp) ? icp : ""; #ifdef COMMENT sprintf(outbuf,"%s%s%s%s",npr,p,s,sfx); #else ckmakmsg(outbuf,256,npr,p,s,sfx); #endif /* COMMENT */ } else { /* External local call */ /* local-prefix */ p = (prefix && diallcp) ? diallcp : ""; /* local-suffix */ p2 = (prefix && diallcs) ? diallcs : ""; #ifdef COMMENT if (x == 2) sprintf(outbuf,"%s%s%s%s%s%s%s", dialpxo ? dialpxo : "", npr,p,acptr,s,p2,sfx); else sprintf(outbuf, "%s%s%s%s%s%s", dialpxo ? dialpxo : "", npr,p,s,p2,sfx ); #else if (x == 2) ckmakxmsg(outbuf, 256, dialpxo ? dialpxo : "", npr,p,acptr,s,p2,sfx, NULL,NULL,NULL,NULL,NULL); else ckmakxmsg(outbuf, 256, dialpxo ? dialpxo : "", npr,p,s,p2,sfx, NULL,NULL,NULL,NULL,NULL,NULL); #endif /* COMMENT */ } } } } } else { /* Area code was not delimited */ char xbuf[256]; /* Comparison based only on length */ char ybuf[256]; int x, j; s = ss; for (i = 0; i < 255; i++) { if (!*s) break; while (!isdigit(*s)) { /* Pay attention only to digits */ s++; if (!*s) break; } xbuf[i] = *s++; } xbuf[i] = NUL; x = 1; /* Assume LD */ n = 0; if (!dialfld) { /* If LD not forced */ for (j = 0; j < nlocalac; j++) { /* check local AC list? */ ckmakmsg(ybuf,256,diallcc,diallcac[j],NULL,NULL); n = (int) strlen(ybuf); if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) { x = 2; break; } } if (x == 1) { /* Or exact match with local CC+AC? */ ckmakmsg(ybuf,256,diallcc,lac,NULL,NULL); n = (int) strlen(ybuf); if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) x = 0; } } if (x == 0 || x == 2) { /* Local call */ int xx,kx; /* Begin 1 Dec 2001... */ /* Account for PBX internal calls */ if (ndialpxx) { xx = -1; j = (int) strlen(ybuf); for (kx = 0; kx < ndialpxx; kx++) { i = (int) strlen(dialpxx[kx]); if (j >= i) if (!(xx = ckstrcmp(dialpxx[kx],&xbuf[j],i,0))) break; } } if (!xx) { char * icp, buf[32]; makestr(&matchpxx,dialpxx[kx]); debug(F111,"dncvt matchpxx",matchpxx,kx); what = dn_x[kx] = DN_INTERN; /* Internal call. */ s = xbuf + j + i; icp = dialpxi; /* Internal-call prefix */ #ifndef NOSPL if (icp) { if (*icp == '\\') { char c, *bp; int n; c = *(icp+1); if (isupper(c)) c = tolower(c); if (c == 'v' || c == 'f') { n = 32; bp = buf; zzstring(icp,&bp,&n); icp = buf; } } } #endif /* NOSPL */ p = (prefix && icp) ? icp : ""; ckmakmsg(outbuf,256,npr,p,s,sfx); /* End 1 Dec 2001... */ } else { /* Not PBX internal */ dn_x[k] = DN_LOCAL; p = (prefix && diallcp) ? diallcp : ""; p2 = (suffix && diallcs) ? diallcs : ""; s = (char *) (xbuf + ((x == 0) ? n : (int)strlen(diallcc))); ckmakxmsg(outbuf,256, pxo,npr,p,s,p2,sfx, NULL,NULL,NULL,NULL,NULL,NULL); ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL); } } else { /* Not local */ n = ckstrncpy(ybuf,diallcc,256); if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) { /* Long distance */ dn_x[k] = DN_LONG; p = (prefix && dialldp) ? dialldp : ""; p2 = (suffix && diallds) ? diallds : ""; s = xbuf + n; while (*s == '-' || *s == '.') s++; #ifdef COMMENT sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,s,p2,sfx); sprintf(pdsfx,"%s%s",p2,sfx); #else ckmakxmsg(outbuf,256, pxo,npr,p,s,p2,sfx, NULL,NULL,NULL,NULL,NULL,NULL); ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL); #endif /* COMMENT */ } else { dn_x[k] = DN_INTL; /* International */ if (!dialixp) { if (cx != XXLOOK) { printf( "Error - No international dialing prefix defined\n" ); return(-1); } } p = (prefix && dialixp) ? dialixp : ""; p2 = (suffix && dialixs) ? dialixs : ""; #ifdef COMMENT sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,xbuf,p2,sfx); sprintf(pdsfx,"%s%s",p2,sfx); #else ckmakxmsg(outbuf,256, pxo,npr,p,xbuf,p2,sfx, NULL,NULL,NULL,NULL,NULL,NULL); ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL); #endif /* COMMENT */ } } } #ifdef CK_TAPI if (tttapi && /* TAPI performs the conversions */ !tapipass && tapiconv == CK_AUTO || tapiconv == CK_ON ) { p = NULL; dialtype = -2; if (!cktapiConvertPhoneNumber(dn_p[k],&p)) return(-1); makestr(&dn_p2[k], p); if (p) free(p); return(0); } else { #endif /* CK_TAPI */ makestr(&dn_p2[k], outbuf); #ifdef CK_TAPI } #endif /* CK_TAPI */ dialtype = what; return(0); } static int #ifdef CK_ANSIC ddcvt( char * s, FILE * f, int n ) /* Dial Directory Convert */ #else ddcvt(s, f, n) char * s; FILE * f; int n; #endif /* CK_ANSIC */ { char linebuf[1024], *s2; /* Buffers and pointers */ #ifdef VMS char * temp = NULL; #endif /* VMS */ char *info[8]; /* Pointers to words from entry */ FILE * f2 = NULL; int x, rc; rc = -1; debug(F110,"ddcvt file",s,0); if (!s || !f) /* No filename or file */ return(-1); if (!*s) fclose(f); znewn(s,&s2); /* s2 = address of static buffer */ debug(F110,"ddcvt newname",s2,0); #ifdef VMS /* In VMS, znewn() returns the same file name with a new version number */ makestr(&temp,s); /* Swap - otherwise the new */ s = s2; /* version has the older version */ s2 = temp; /* number... */ debug(F110,"ddcvt after swap s",s,0); debug(F110,"ddcvt after swap s2",s2,0); makestr(&(dialdir[n]),s); /* New file gets new version number */ debug(F110,"ddcvt after makestr s2",s2,0); debug(F111,"ddcvt dialdir[n]",dialdir[n],n); #else if (zrename(s,s2) < 0) { /* Not VMS - rename old file */ perror(s2); /* to new (weird) name. */ goto ddexit; } #endif /* VMS */ debug(F110,"ddcvt s2 (old)",s2,0); if ((f = fopen(s2,"r")) == NULL) { /* Reopen old file with weird name */ debug(F110,"ddcvt s2 open error",ck_errstr(),0); dirline = 0; /* (or in VMS, old version) */ perror(s2); goto ddexit; } debug(F110,"ddcvt fopen(s2) OK",s2,0); debug(F110,"ddcvt s (new)",s,0); if ((f2 = fopen(s,"w")) == NULL) { /* Create new file with old name */ debug(F110,"ddcvt s open error",ck_errstr(),0); perror(s); /* (or in VMS, new version) */ goto ddexit; } debug(F110,"ddcvt fopen(s) OK",s,0); printf("\nSaving old directory as %s.\nConverting %s...",s2,s); fprintf(f2,"; %s - Kermit dialing directory\n", s); fprintf(f2,"%-16s %-20s ; %5s %-6s ; %s\n", "; Name","Number","Speed","Parity","Comment" ); while (1) { linebuf[0] = NUL; /* Read a line */ if (fgets(linebuf,1023,f) == NULL) break; debug(F110,"ddcvt linebuf",linebuf,0); if (!linebuf[0]) { /* Empty line */ fprintf(f2,"\n"); continue; } x = (int) strlen(linebuf); /* Strip line terminator, */ while (x-- > 0) { /* if any. */ if (linebuf[x] <= SP) linebuf[x] = NUL; else break; } xwords(linebuf,5,info,1); /* Parse it the old way */ for (x = 1; x < 6; x++) if (!info[x]) info[x] = ""; fprintf(f2,"%-16s %-20s ; %5s %-6s %s\n", info[1],info[2],info[3],info[4],info[5] ); } printf(" OK\n\n"); rc = 0; /* Success */ ddexit: if (f) fclose(f); if (f2) fclose(f2); #ifdef VMS if (temp) free(temp); #endif /* VMS */ return(rc); } int /* s = name to look up */ #ifdef CK_ANSIC /* cx = index of command */ ludial(char *s, int cx) /* (DIAL, LOOKUP, etc) */ #else ludial(s, cx) char *s; int cx; #endif /* CK_ANSIC */ /* ludial */ { int dd, n1, n2, n3, j, t; /* Workers */ int olddir, newdir, oldentry, newentry; int pass = 0; int oldflg = 0; int ambiguous = 0; /* Flag for lookup was ambiguous */ char *info[7]; /* Pointers to words from entry */ char *pp; /* Pointer to element of array */ FILE * f; char *line; /* File input buffer */ /* #define LUDEBUG */ #ifdef LUDEBUG int zz = 1; #endif /* LUDEBUG */ if (!s || ndialdir < 1) /* Validate arguments */ return(-1); if ((n1 = (int) strlen(s)) < 1) /* Length of string to look up */ return(-1); if (!(line = malloc(1024))) /* Allocate input buffer */ return(-1); #ifdef LUDEBUG if (zz) printf("LUDIAL 1 s[%s], n1=%d\n",s,n1); #endif /* LUDEBUG */ pass = 0; lu_again: f = NULL; /* Dial directory file descriptor */ t = dncount = 0; /* Dial-number match count */ dd = 0; /* Directory counter */ olddir = 0; newdir = 0; /* We need to recognize both old- and new-style directories. But we can't allow old-style and new-style entries in the same directory because there is no way to tell for sure the difference between an old-style entry like this: foo 5551212 9600 and a new-style literal entry like this: foo 555 9600 I.e. is the "9600" a speed, or part of the phone number? */ while (1) { /* We make one pass */ if (!f) { /* Directory not open */ if (dd >= ndialdir) /* No directories left? */ break; /* Done. */ debug(F111,"ludial dialdir[dd]",dialdir[dd],dd); if ((f = fopen(dialdir[dd],"r")) == NULL) { /* Open it */ perror(dialdir[dd]); /* Can't, print message saying why */ if (line) { free(line); line = NULL; } dd++; /* Go on to next one, if any... */ continue; } dirline = 0; /* Directory file line number */ if (dialdpy && !pass) printf("Opening: %s...\n",dialdir[dd]); dd++; if (!oldflg) olddir = 0; newdir = 0; } oldentry = 0; newentry = 0; line[0] = NUL; if (getnct(line,1023,f,1) < 0) { /* Read a line */ if (f) { /* f can be clobbered! */ fclose(f); /* Close the file */ f = NULL; /* Indicate next one needs opening */ oldflg = 0; } continue; } if (!line[0]) /* Empty line */ continue; #ifdef LUDEBUG if (zz) printf("LUDIAL 2 s[%s]\n",s); #endif /* LUDEBUG */ /* Make a copy and parse it the old way */ /* A copy is needed because xwords() pokes NULs into the string */ if ((pp = malloc((int)strlen(line) + 1))) { strcpy(pp,line); /* safe */ xwords(pp,5,info,0); /* Parse it the old way */ #ifdef LUDEBUG if (zz) printf("LUDIAL 3 s[%s]\n",s); #endif /* LUDEBUG */ if (!info[1]) continue; if (*info[1] == ';') { /* If full-line comment, */ newdir = 1; /* (only new directories have them) */ continue; /* keep reading. */ } if (!info[2]) continue; if (*info[2] == '+') newentry = 1; if (info[4]) { if ((*info[4] == '=') || !ckstrcmp(info[4],"none", 4,0) || !ckstrcmp(info[4],"even", 4,0) || !ckstrcmp(info[4],"space",5,0) || !ckstrcmp(info[4],"mark", 4,0) || !ckstrcmp(info[4],"odd", 3,0) ) oldentry = 1; } } if (pp) { free(pp); pp = NULL; } /* Check consistency */ if ((oldentry || olddir) && (newentry || newdir)) { printf( "\nERROR: You seem to have old- and new-format entries mixed in your\n"); printf( "dialing directory. You'll have to edit it by hand to convert it to the\n"); #ifndef NOHELP printf("new format. Type HELP DIAL for further information.\n\n"); #else printf("new format.\n\n"); #endif /* NOHELP */ if (line) { free(line); line = NULL; } return(-1); } if (!olddir && oldentry) { int convert = 0; olddir = 1; if (dialcvt == 2) { /* 2 == ASK */ sprintf(tmpbuf, "WARNING: Old-style dialing directory detected:\n%s", line); convert = uq_ok(tmpbuf, "Shall I convert it for you? ",3,NULL,0); } else convert = dialcvt; if (convert) { debug(F111,"ludial calling ddcvt",dialdir[dd-1],dd); if (ddcvt(dialdir[dd-1],f,dd-1) < 0) { debug(F111,"ludial ddcvt failed",dialdir[dd-1],dd); oldflg = 1; printf( " Sorry, can't convert."); printf( " Will ignore speed and parity fields, continuing...\n\n"); } else { olddir = newdir = 0; debug(F111,"ludial ddcvt ok",dialdir[dd-1],dd); } dd--; f = NULL; continue; } else { if (dialcvt == 2) printf( " OK, will ignore speed and parity fields, continuing...\n\n"); olddir = 1; } } #ifdef LUDEBUG if (zz) printf("LUDIAL XX s[%s], n1=%d\n",s,n1); #endif /* LUDEBUG */ /* Now parse again for real */ if (oldentry) /* Parse it the old way */ xwords(line,5,info,0); else /* Parse it the new way */ xwords(line,2,info,1); #ifdef LUDEBUG if (zz) printf("LUDIAL YY s[%s], n1=%d\n",s,n1); if (zz) printf("%s [%s]\n",info[1],info[2]); #endif /* LUDEBUG */ if (info[1]) { /* First word is entry name */ if ((n3 = (int) strlen(info[1])) < 1) /* Its length */ continue; /* If no first word, keep reading. */ if (n3 < n1) /* Search name is longer */ continue; /* Can't possibly match */ if (ambiguous && n3 != n1) continue; #ifdef LUDEBUG if (zz) printf("MATCHING: [%s] [%s], n1=%d\n",s,info[1],n1); #endif /* LUDEBUG */ if (ckstrcmp(s,info[1],n1,0)) /* Caseless string comparison */ continue; #ifdef LUDEBUG if (zz) printf("MATCH OK: [%s] [%s], n1=%d\n",s,info[1],n1); #endif /* LUDEBUG */ if (!info[2]) /* No phone number given */ continue; if ((n2 = (int) strlen(info[2])) < 1) /* Length of phone number */ continue; /* Ignore empty phone numbers */ /* Got one */ if (!(pp = (char *)malloc(n2 + 1))) { /* Allocate storage for it */ printf("?internal error - ludial malloc 1\n"); if (line) { free(line); line = NULL; } dncount = 0; return(-1); } strcpy(pp,info[2]); /* safe */ if (dncount > MAXDNUMS) { printf("Warning: %d matches found, %d max\n", dncount, MAXDNUMS ); dncount = MAXDNUMS; break; } dn_p[dncount++] = pp; /* Add pointer to array. */ if (dncount == 1) { /* First one... */ if (d_name) free(d_name); if (!(d_name = (char *)malloc(n3 + 1))) { /* Save its name */ printf("?internal error - ludial malloc 2\n"); if (line) { free(line); line = NULL; } dncount = 0; return(-1); } t = n3; /* And its length */ strcpy(d_name,info[1]); /* safe */ } else { /* Second or subsequent one */ #ifdef LUDEBUG if (zz) printf("d_name=[%s],info[1]=%s,t=[%d]\n",d_name,info[1],t); #endif /* LUDEBUG */ if ((int) strlen(info[1]) == t) /* Lengths compare */ if (!ckstrcmp(d_name,info[1],t,0)) /* Caseless compare OK */ continue; /* Name given by user matches entries with different names */ if (ambiguous) /* Been here before */ break; ambiguous = 1; /* Now an exact match is required */ for (j = 0; j < dncount; j++) { /* Clean out previous list */ if (dn_p[j]) { free(dn_p[j]); dn_p[j] = NULL; } } pass++; /* Second pass... */ goto lu_again; /* Do it all over again. */ } } } if (line) free(line); if (dncount == 0 && ambiguous) { printf(" Lookup: \"%s\" - ambiguous%s\n", s, cx == XXLOOK ? "" : " - dialing skipped" ); return(-2); } return(dncount); } char * #ifdef CK_ANSIC pncvt( char *s ) /* Phone number conversion */ #else pncvt(s) char *s; #endif /* CK_ANSIC */ { char *p = NULL; /* (just a wrapper for dncvt() */ char *q = NULL; static char pnbuf[128]; makestr(&p,dn_p[0]); /* Save these in case they are */ makestr(&q,dn_p2[0]); /* being used */ makestr(&dn_p[0],s); /* Copy the argument string to here */ dncvt(0,XXLOOK,1,1); /* Convert it */ if (!dn_p2[0]) /* Put result where can return it */ pnbuf[0] = NUL; else ckstrncpy(pnbuf,dn_p2[0],127); makestr(&dn_p[0],p); /* Restore these */ makestr(&dn_p2[0],q); makestr(&p,NULL); /* Free these */ makestr(&q,NULL); return((char *)pnbuf); } int #ifdef CK_ANSIC dodial( int cx ) /* DIAL or REDIAL */ #else dodial(cx) int cx; #endif /* CK_ANSIC */ { int i = 0, x = 0; /* Workers */ int sparity = -1; /* For saving global parity value */ int previous = 0; int len = 0; int literal = 0; int flowsave; int lufound = 0; /* Did any lookup succeed? */ int prefix = 1; int postfix = 1; int wasalpha = 0; int xredial = 0; int braces = 0; char *p = NULL, *s3 = NULL, * sav = NULL; int j = 0, t = 0, n = 0; int xretries, xlcc; #ifdef COMMENT debug(F101,"dodial cx","",cx); debug(F111,"dodial diallcc",diallcc,diallcc); #endif /* COMMENT */ xretries = dialrtr; /* If retries not set, */ if (diallcc) { /* choose default based on */ xlcc = atoi(diallcc); /* local country code. */ if (xretries < 0) { switch (xlcc) { case 1: xretries = 10; break; /* No restrictions in NANP */ /* Add other country codes here */ /* that are known to have no restrictions on redialing. */ default: xretries = 1; } } } if (cx == XXPDIA) { /* Shortcut... */ cx = XXDIAL; partial = 1; debug(F100,"PDIAL sets partial=1","",0); postfix = 0; /* Do not add postfix */ } else { partial = 0; debug(F100,"DIAL sets partial=0","",0); } previous = dialsta; /* Status of previous call, if any */ if (previous == DIA_PART) { prefix = 0; /* do not add prefix */ } s = NULL; /* Initialize user's dial string */ if (cx == XXRED) { /* REDIAL or... */ if ((y = cmcfm()) < 0) return(y); } else if (cx == XXANSW) { /* ANSWER or ... */ if ((y = cmnum("timeout (seconds)","0",10,&x,xxstring)) < 0) return(y); dialatmo = x; if ((y = cmcfm()) < 0) return(y); } else { /* DIAL or LOOKUP */ if (ndialdir > 0) s3 = "Number to dial or entry from dial directory"; else s3 = "Number to dial"; if ((x = cmtxt(s3, dialnum ? dialnum : "",&s,xxstring)) < 0) return(x); if (s) { len = (int) strlen(s); ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Save literal copy */ #ifdef COMMENT if (len > 1) { /* Strip outer braces if given */ if (*s == '{') { if (s[len-1] == '}') { s[len-1] = NUL; s++; len -= 2; } } } #else s = brstrip(s); /* Strip outer braces or quotes */ #endif /* COMMENT */ } } if (cx != XXLOOK) { /* Not LOOKUP */ #ifdef IKSD if (inserver) { printf("Sorry, dialing is disabled.\r\n"); return(success = 0); } #endif /* IKSD */ #ifdef CK_TAPI if (tttapi && !tapipass) { ; /* Skip the modem test if TAPI */ } else #endif /* CK_TAPI */ if (mdmtyp < 1 && !dialtest) { if (network #ifdef TN_COMPORT && !istncomport() #endif /* TN_COMPORT */ ) printf("Please SET HOST first, and then SET MODEM TYPE\n"); else printf("Sorry, you must SET MODEM TYPE first\n"); dialsta = DIA_NOMO; return(success = 0); } if (!local && !dialtest) { printf("Sorry, you must SET %s or SET HOST first\n", #ifdef OS2 "PORT" #else "LINE" #endif /* OS2 */ ); dialsta = DIA_NOLI; return(success = 0); } if ((!network #ifdef TN_COMPORT || istncomport() #endif /* TN_COMPORT */ ) && !dialtest && #ifdef CK_TAPI !tttapi && #endif /* CK_TAPI */ (speed < 0L) #ifdef UNIX && (strcmp(ttname,"/dev/null")) #else #ifdef OSK && (strcmp(ttname,"/nil")) #endif /* OSK */ #endif /* UNIX */ ) { printf("\nSorry, you must SET SPEED first\n"); dialsta = DIA_NOSP; return(success = 0); } } if (cx != XXANSW) { for (j = 0; j < MAXDNUMS; j++) { /* Initialize dial-number list */ if (!dialnum) { /* First time dialing */ dn_p[j] = NULL; /* initialize all pointers. */ dn_p2[j] = NULL; } else if (dn_p[j]) { /* Not the first time, */ free(dn_p[j]); /* free previous, if any, */ dn_p[j] = NULL; /* then set to NULL. */ if (dn_p2[j]) free(dn_p2[j]); dn_p2[j] = NULL; } else break; /* Already NULL */ } if (len == 0) s = NULL; if (!s) s = dialnum; if (!s) { if (cx == XXLOOK) printf("?Lookup what?\n"); else printf("%s\n", (cx == XXRED) ? "?No DIAL command given yet" : "?You must specify a number to dial" ); return(-9); } /* Now we have the "raw" dial or lookup string and s is not NULL */ makestr(&dscopy,s); /* Put it in a safe place */ s = dscopy; n = 0; debug(F111,"dodial",s,ndialdir); wasalpha = 0; if (isalpha(*s)) { wasalpha = 1; if (ndialdir > 0) { /* Do we have a dialing directory? */ n = ludial(s,cx); /* Look up what the user typed */ if (n == 0) printf(" Lookup: \"%s\" - not found%s\n", s, cx == XXLOOK ? "" : " - dialing as given\n" ); } debug(F101,"dodial",s,n); if (n < 0 && cx != XXLOOK) { /* Error out if they wanted to dial */ if (n == -1) /* -2 means ludial already gave msg */ printf(" Lookup: fatal error - dialing skipped\n"); dialsta = DIA_DIR; return(-9); } if (n > 0) /* A successful lookup */ lufound = 1; } else if (*s == '=') { /* If number starts with = sign */ s++; /* strip it */ literal = 1; /* remember this */ while (*s == SP) s++; /* and then also any leading spaces */ } else if (tmpbuf[0] == '{' && tmpbuf[1] == '{') { makelist(tmpbuf,dn_p,MAXDNUMS); makestr(&dscopy,tmpbuf); s = tmpbuf; for (n = 0; n < MAXDNUMS; n++) /* (have to count how many) */ if (!dn_p[n]) break; braces = 1; } if (cx == XXLOOK && !wasalpha && !braces) { /* We've been told to lookup a number or a quoted name */ char *p; n = 0; p = literal ? s : pncvt(dscopy); if (!p) p = ""; if (*p) { printf("%s => %s\n", dscopy, p); return(success = 1); } else { printf("?Bad phone number\n"); return(success = 0); } } /* Save DIAL or successful LOOKUP string for future DIAL or REDIAL */ /* But don't save pieces of partial dial ... */ debug(F101,"DIAL save dialnum partial","",partial); debug(F101,"DIAL save dialnum previous","",previous); if ((cx == XXDIAL && partial == 0 && previous != DIA_PART) || (cx == XXLOOK && n > 0)) { makestr(&dialnum,dscopy); if (!quiet && dscopy && !dialnum) printf("WARNING - memory allocation failure: redial number\n"); } if (n > 0) { if (!quiet && !backgrd && !braces /* && dialdpy */ ) { if (!strcmp(d_name,s)) printf(" Lookup: \"%s\" - exact match\n",s); else printf(" Lookup: \"%s\" - uniquely matches \"%s\"\n", s, d_name ); } if ((cx == XXLOOK) || ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) { printf(" %d telephone number%sfound for \"%s\"%s\n", n, (n == 1) ? " " : "s ", s, (n > 0) ? ":" : "." ); s3 = getdname(); } for (i = 0; i < n; i++) { /* Convert */ dn_x[i] = -1; if (dncvt(i,cx,prefix,postfix) < 0) { if (cx != XXLOOK) { dialsta = DIA_DIR; return(-9); } } } if (dialsrt && n > 1) { /* Sort into optimal order */ for (i = 0; i < n-1; i++) { for (j = i+1; j < n; j++) { if (dn_x[j] < dn_x[i]) { t = dn_x[j]; dn_x[j] = dn_x[i]; dn_x[i] = t; p = dn_p[j]; dn_p[j] = dn_p[i]; dn_p[i] = p; p = dn_p2[j]; dn_p2[j] = dn_p2[i]; dn_p2[i] = p; } } } } if ((cx == XXLOOK) || ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) { int nn = n; if (cx != XXLOOK) if (n > 12) nn = 12; for (i = 0; i < nn; i++) { printf("%3d. %-12s %-20s => %-20s (%d)\n",i+1, s3, dn_p[i], dn_p2[i] ? dn_p2[i] : "(processing failed)", dn_x[i] ); } if (cx != XXLOOK && n != nn) printf("And %d more...\n", n - nn); } } else if (n == 0) { /* Not found in directory */ makestr(&(dn_p[0]),literal ? s : dscopy); makestr(&d_name,literal ? s : dscopy); dncount = 1; n = 1; if (dncvt(0,cx,prefix,postfix) < 0) { /* In case they typed a */ dialsta = DIA_DIR; /* portable-format number ... */ return(-9); } } #ifndef NONET #ifdef NETCONN /* It's not good that the networks directory depends on NOT-NODIAL.. */ if (cx == XXLOOK && dscopy) { /* Networks here too... */ extern char *nh_p[], *nh_p2[], *n_name; extern char *nh_px[4][MAXDNUMS+1]; n = -1; if (nnetdir > 0) { /* Do we have a network directory? */ dirline = 0; n = lunet(dscopy); /* Look up what the user typed */ } if (n > -1) { int k; if (n > 0) /* A successful lookup */ lufound = 1; if (cx == XXLOOK && n == 0) printf(" Lookup: \"%s\" - not found\n",dscopy); else printf("%s %d network entr%s found for \"%s\"%s\n", cx == XXLOOK ? " Lookup:" : "", n, (n == 1) ? "y" : "ies", dscopy, (n > 0) ? ":" : "." ); for (i = 0; i < n; i++) { printf("%3d. %-12s => %-9s %s", i+1,n_name,nh_p2[i],nh_p[i]); for (k = 0; k < 4; k++) { if (nh_px[k][i]) { printf(" %s",nh_px[k][i]); } else break; } printf("\n"); } } } #endif /* NETCONN */ #endif /* NONET */ if (cx == XXLOOK) return(success = lufound); } /* cx != XXANSW */ #ifdef VMS conres(); /* So Ctrl-C/Y will work */ #endif /* VMS */ /* Some modems do not react well to parity. Also, if we are dialing through a TCP/IP TELNET modem server, parity can be fatally misinterpreted as TELNET negotiations. This should work even if the user interrupts the DIAL command, because the DIAL module has its own interrupt handler. BUT... if, for some reason, a dialing device actually *requires* parity (e.g. CCITT V.25bis says that even parity should be used), this might prevent successful dialing. For that reason, we don't do this for V.25bis modems. */ sparity = parity; /* Save current parity */ if ((dialcapas & CKD_V25) == 0) /* If not V.25bis... */ parity = 0; /* Set parity to NONE */ flowsave = flow; /* These modems use some kind of screwy flow control while in command mode, and do not present CTS as they should. So if RTS/CTS is set (or even if it isn't) disable flow control during dialing. */ #ifndef MINIDIAL if (mdmtyp == n_ATT1910 || mdmtyp == n_ATT1900) { flow = FLO_NONE; /* This is not enough */ #ifdef CK_TTSETFLOW ttsetflow(FLO_NONE); /* Really turn it off */ #endif /* CK_TTSETFLOW */ } #endif /* MINIDIAL */ if (!network #ifdef TN_COMPORT || istncomport() #endif /* TN_COMPORT */ ) { int x; if ((x = ttgmdm()) > -1) { if (!x && msgflg) { printf( "WARNING - No modem signals detected. Is your modem turned on? If not,\n\ use Ctrl-C to interrupt dialing, turn on your modem, then %s.\n", cx == XXANSW ? "ANSWER again" : "REDIAL" ); } if (flow == FLO_RTSC) { if (!(x & BM_CTS)) { if (msgflg) printf( "WARNING - SET FLOW RTS/CTS is in effect but modem's CTS signal is off.\n\ Disabling flow control temporarily %s...\n", cx == XXANSW ? "while waiting for call" : "during dialing" ); flow = FLO_NONE; } } } } if (cx == XXANSW) { /* ANSWER */ success = ckdial("",0,0,1,0); goto dialfin; } /* Edit 192 adds the ability to dial repeatedly. */ i = 0; dialcount = 0; do { if (i > 0) printf("\nDial attempt %d of %d...\n", i+1, xretries); dialcount = i+1; success = 0; /* And the ability to dial alternate numbers. */ /* Loop to dial each in a list of numbers for the same name... */ for (j = 0; j < n && !success; j++) { /* until one answers. */ s = dn_p2[j]; /* Next number in list */ if (dn_x[j] >= dialrstr) { /* Dial restriction */ printf("Restricted: %s, skipping...\n",dn_p[j]); continue; } xredial = (i == 0 && j == 0) ? 0 : 1; if (!s) s = dn_p[j]; #ifndef NOSPL sav = s; p = xdial(s); /* Apply DIAL macro now */ if (p) if (*p) s = p; #endif /* NOSPL */ /* Dial confirmation */ /* NOTE: the uq_xxx() calls allow for a GUI dialog */ if (i == 0 && dialcnf) { char msgbuf[128]; ckmakmsg(msgbuf,128,"Dialing ",s,NULL,NULL); x = uq_ok(msgbuf,"Is this number correct? ",3,NULL,0); if (!x) { #ifndef COMMENT x = uq_txt( /* Allow GUI dialog */ #ifdef OS2 " Please enter the correct number,\r\n or press Enter to skip.", #else " Please enter the correct number,\r\n or press Return to skip.", #endif /* OS2 */ "Corrected phone number: ", 1, NULL, atmbuf, ATMBL, s, DEFAULT_UQ_TIMEOUT ); if (x && atmbuf[0]) { /* They gave a new one */ s = atmbuf; makestr(&(dn_p2[j]), s); } #else /* COMMENT */ #ifdef CK_RECALL extern int on_recall; #endif /* CK_RECALL */ cmsavp(psave,PROMPTL); cmsetp( #ifdef OS2 " Please enter the correct number,\r\n or press Enter to skip: " #else " Please enter the correct number,\r\n or press Return to skip: " #endif /* OS2 */ ); cmini(ckxech); x = -1; if (pflag) prompt(NULL); #ifdef CK_RECALL on_recall = 0; #endif /* CK_RECALL */ y = cmdgquo(); cmdsquo(0); while (x < 0) { x = cmtxt("Corrected phone number","",&s,NULL); cmres(); } if ((int) strlen(s) < 1) { cmsetp(psave); continue; } makestr(&(dn_p2[j]), s); cmdsquo(y); cmsetp(psave); #endif /* COMMENT */ } } if (dialtest) { /* Just testing */ if (i + j == 0) printf("\nTESTING...\n"); #ifndef NOSPL if (dialmac) printf(" Number: \"%s\" => \"%s\"\n",sav,s); else printf(" Number: \"%s\"\n",s); #endif /* NOSPL */ dialsta = DIA_BUSY; success = 0; } else { what |= W_DIALING; success = ckdial(s,i,j,partial ? 3 : 0, xredial); /* Dial it */ what &= ~(W_DIALING); if (!success) { if (dialsta < 8 || /* Break out if unrecoverable error */ dialsta == DIA_INTR || dialsta == DIA_ERR || previous == DIA_PART ) break; } } } if (success) /* Succeeded, leave the outer loop */ break; if (dialsta < 8 || /* Break out if unrecoverable error */ dialsta == DIA_INTR || /* Interrupted */ dialsta == DIA_NODT || /* No dialtone */ dialsta == DIA_NOAC || /* Access forbidden */ dialsta == DIA_BLCK || /* Blacklisted */ dialsta == DIA_DIR || /* Dialing directory error */ dialsta == DIA_ERR || /* Modem command error */ previous == DIA_PART) break; if (++i >= xretries) /* Break out if too many tries */ break; if (!backgrd && !quiet) { if (dialint > 5) printf( "\nWill redial in %d second%s- press any key to redial immediately.\n", dialint, dialint == 1 ? " " : "s " ); printf("Ctrl-C to cancel...\n"); } x = dialint; /* Redial interval */ while (x-- > 0) { if ((y = conchk()) > 0) { /* Did they type something? */ while (y--) coninc(0); /* Yes, absorb it */ break; /* And wake up */ } sleep(1); /* No interrupt, sleep a sec */ } } while (!success); dialfin: if (cx != XXLOOK) { if (!success) { bleep((short) BP_FAIL); } else if (!quiet) { bleep((short) BP_NOTE); } #ifdef OS2 setint(); /* Fix OS/2 interrupts */ #endif /* OS2 */ if (sparity > -1) parity = sparity; /* Restore parity if we saved it */ flow = flowsave; #ifdef OS2 ttres(); /* Restore DIAL device */ #endif /* OS2 */ #ifdef VMS concb((char)escape); /* Restore console */ #endif /* VMS */ #ifdef OS2 { /* Set session title */ char * p, name[72]; /* in window list. */ char * q; if (cx == XXANSW) { q = "Incoming call"; } else { if (d_name) q = d_name; else if (dialnum) q = dialnum; else if (ttname[0]) q = ttname; else q = ""; } p = name; if (success) { strncpy(name,q,48); while (*p) { /* Uppercase it for emphasis. */ if (islower(*p)) *p = toupper(*p); p++; } } else name[0] = NUL ; os2settitle((char *) name, TRUE); } #endif /* OS2 */ } if (cx != XXLOOK) { if (success) { if (reliable == SET_AUTO) { /* It's not a reliable connection. */ reliable = SET_OFF; debug(F101,"dodial reliable","",reliable); } } else { #ifndef NOHINTS extern int hints; if (hints && !quiet && dialsta != 9) { /* 9 == User interrupted */ extern int dialmhu, dialhng, dialdpy; extern char * dialmsg[]; printf("\n*************************\n"); printf("DIAL-class command failed.\n"); printf("Modem type: %s\n", gmdmtyp()); printf("Device: %s\n", ttname); printf("Speed: %ld\n", speed); printf("Dial status: %d",dialsta); if (dialsta < 35 && dialmsg[dialsta]) printf(" [%s]",dialmsg[dialsta]); printf("\n"); if (dialsta == DIA_TIMO || dialsta == DIA_NRDY || (dialsta > 13 && dialsta != DIA_BUSY && dialsta != DIA_NOAN) ) { switch (dialsta) { case DIA_TIMO: printf( " . SET DIAL TIMEOUT to a greater value and try again.\n" ); break; case DIA_NRSP: case DIA_NRDY: case DIA_NOIN: printf( " . Is the modem turned on?\n" ); printf( " . Are you using the right communication port?\n" ); break; case DIA_NODT: printf( " . Is the modem connected to the telephone line?\n" ); } if (mdmtyp == n_GENERIC) { printf( " . Please choose a specific modem type with SET MODEM TYPE and try again.\n" ); printf( " SET MODEM TYPE ? to see the list of known modem types.\n" ); } else { printf( " . Are you sure you have chosen the appropriate modem type?\n" ); } if (speed > 19200L) { printf( " . Maybe the interface speed (%ld) is too fast:\n", speed ); printf( " SET SPEED to a lower speed and try again.\n" ); printf( " SET SPEED ? to see the list of valid speeds.\n" ); } if (dialhng) { if (dialmhu) printf( " . SET MODEM HANGUP-METHOD RS232 and try again.\n" ); else printf( " . SET MODEM HANGUP-METHOD MODEM-COMMAND and try again.\n" ); printf( " . If that doesn't work, try again with SET DIAL HANGUP OFF.\n" ); } else { printf( " . Give a HANGUP or SET DIAL HANGUP ON command and try again.\n" ); } if (!dialdpy) printf( " . Use SET DIAL DISPLAY ON to watch the dialog between Kermit and modem.\n" ); } #ifndef NOSHOW printf( " . SHOW COMMUNICATIONS, SHOW MODEM, SHOW DIAL to see current settings.\n" ); #endif /* NOSHOW */ #ifndef NOHELP printf( " . HELP SET MODEM, HELP SET DIAL, and HELP DIAL for more information.\n" ); #endif /* NOHELP */ printf("(Use SET HINTS OFF to suppress future hints.)\n"); printf("*************************\n\n"); } #endif /* NOHINTS */ } } return(success); } #endif /* NODIAL */ /* D O T Y P E -- Type (display) a file with various options... */ #ifdef BIGBUFOK #define TYPBUFL 16384 #else #define TYPBUFL 256 #endif /* BIGBUFOK */ int typ_lines = 0; /* \v(ty_ln) */ int typ_mtchs = 0; /* \v(ty_lm) */ static int typ_int = 0; /* Flag if TYPE interrupted */ #ifdef UNICODE extern int fcharset, fileorder, byteorder, ucsorder; #define TYPXBUFL TYPBUFL+TYPBUFL+TYPBUFL+4 static char * mp = NULL; static char * mbuf = NULL; static long xn = 0L; static int #ifdef CK_ANSIC storechar(char c) #else storechar(c) char c; #endif /* CK_ANSIC */ { if (!mp) return(-1); if (++xn > TYPXBUFL) return(-1); debug(F111,"storechar xn",ckitoa((int)c),xn); *mp++ = c; return(0); } #endif /* UNICODE */ static FILE * ofp = NULL; /* For /OUTPUT: file */ static int #ifdef CK_ANSIC typeline( char * buf, int len, int outcs, FILE * ofp ) #else typeline(buf,len,outcs,ofp) char * buf; int len, outcs; FILE * ofp; #endif /* CK_ANSIC */ { register int i; debug(F011,"typeline buf",buf,len); /* debug(F101,"typeline outcs","",outcs); */ #ifdef OS2 #ifndef NOLOCAL #ifdef UNICODE /* In K95 only, the buffer is guaranteed to be in UCS-2 if outcs >= 0. */ /* Len is its length in bytes. There is no line terminator. */ /* outcs is the file character-set number (FC_xxx) of the target set */ /* that was requested by the user. */ if (!inserver && !k95stdout) { extern int wherex[], wherey[]; extern unsigned char colorcmd; VscrnWrtUCS2StrAtt( VCMD, (unsigned short *)buf, len/2, wherey[VCMD], wherex[VCMD], &colorcmd); printf("\r\n"); return(0); } #endif /* UNICODE */ #endif /* NOLOCAL */ #endif /* OS2 */ /* In Unix, VMS, etc, the line has already been converted to the desired */ /* character-set, if one was given. OR... on all platforms, including in */ /* K95, we don't know the character set. In either case we dump the line */ /* byte by byte in case it contains NULs (printf() would truncate). */ #ifdef COMMENT for (i = 0; i < len; i++) putchar(buf[i]); #else for (i = 0; i < len; i++) { if (ofp == stdout) { putchar(buf[i]); } else { putc(buf[i],ofp); } } #endif /* COMMENT */ #ifdef IKSD if (inserver) { #ifdef UNICODE if (outcs == FC_UCS2) { if (ofp == stdout) { putchar(NUL); } else { putc(NUL,ofp); } } #endif /* UNICODE */ if (ofp == stdout) { putchar('\r'); } else { putc('\r',ofp); } } #endif /* IKSD */ #ifdef UNICODE if (outcs == FC_UCS2) { if (ofp == stdout) { putchar(NUL); } else { putc(NUL,ofp); } } #endif /* UNICODE */ if (ofp == stdout) { putchar('\n'); } else { putc('\n',ofp); } fflush(stdout); return(0); } static int /* Get translated line */ #ifdef CK_ANSIC typegetline(int incs, int outcs, char * buf, int n ) #else typegetline(incs, outcs, buf, n) int incs, outcs, n; char * buf; #endif /* CK_ANSIC */ { int x = 0, c0, c1, len = 0, count = 0, eof = 0, xlate = 0; #ifdef UNICODE int xxn = -1; int yyn = -9; xn = 0L; #ifdef DEBUG if (deblog && typ_lines == 0) { debug(F101,"typegetline incs","",incs); debug(F101,"typegetline outcs","",outcs); debug(F101,"typegetline feol","",feol); debug(F101,"typegetline byteorder","",byteorder); debug(F101,"typegetline ucsorder ","",ucsorder); debug(F111,"typegetline fileorder","1",fileorder); } #endif /* DEBUG */ if (incs < 0) /* Shouldn't happen */ return(-2); if (outcs == -1) /* Can happen */ outcs = incs; if (incs != outcs || incs == FC_UCS2) { /* See if we should translate */ xlate = 1; if (!mbuf) { /* Allocate buffer if not allocated */ mbuf = (char *)malloc(TYPXBUFL+1); /* yet */ if (!mbuf) { printf("WARNING: Translation buffer allocation failure.\n"); printf("Translation will be skipped...\n"); xlate = 0; } } } if (xlate) { /* Translating... */ mp = mbuf; /* Reset working buffer pointer */ /* Here we call xgnbyte() in a loop, having it return UCS-2 bytes. In K95, we use UCS-2 directly. Elsewhere, we feed the UCS-2 bytes into xpnbyte() to convert them to the desired target character set. But since we are using UCS-2, we have several sources for confusion: (1) xgnbyte() might return in LE or BE byte order, with no explicit indication of what the order is; but (2) xpnbyte() wants BE; but (3) Windows wants LE. */ while (1) { if (typ_int) /* Quit if interrupted */ return(0); c0 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */ debug(F000,"typegetline c0","",c0); if (c0 < 0) { /* EOF */ eof++; break; } c1 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */ debug(F000,"typegetline c1","",c1); if (c1 < 0) { /* EOF */ eof++; break; } #ifdef DEBUG if (deblog && typ_lines == 0) { if (count == 0) /* Check fileorder after BOM */ debug(F111,"typegetline fileorder","2",fileorder); } #endif /* DEBUG */ #ifdef COMMENT /* Now we have the two UCS-2 bytes. Which order are they in? */ if (fileorder > 0) { /* Little Endian */ int t; /* So swap them */ debug(F100,"typegetline swapping","",0); t = c1; c1 = c0; c0 = t; } #endif /* COMMENT */ if (c0 == 0 && c1 == 0x0D) /* Now see if we have EOL */ yyn = xn; if (c0 == 0 && c1 == 0x0A) /* Now see if we have EOL */ xxn = xn; count++; /* Count byte */ /* Give the two bytes to xpnbyte() in BE order */ if ((x = xpnbyte(c0,TC_UCS2,outcs,storechar)) < 0) return(-1); if ((x = xpnbyte(c1,TC_UCS2,outcs,storechar)) < 0) return(-1); if (xxn > -1) { /* Have end of line? */ xn = xxn; if (yyn == xxn - 2) /* Adjust for CRLF */ xn = yyn; break; /* And break out of loop. */ } } mbuf[xn] = NUL; if (xn > n) /* Can truncate here... */ xn = n; memcpy(buf,mbuf,xn); debug(F011,"typegetline xlate",buf,xn); return((eof && (xn == 0)) ? -1 : xn); } #endif /* UNICODE */ #ifdef COMMENT /* We can't use this because, stupidly, zsinl() doesn't return a length. */ /* It could be changed but then we'd have to change all ck?fio.c modules */ x = zsinl(ZIFILE,buf,n); #else /* So instead, we copy zsinl() to here... */ /* But note: This does not necessarily handle UCS-2 alignment properly; */ /* that's what the code in the first section of this routine is for. */ /* But it does tolerate files that contain NULs. */ { int a; char *s; s = buf; a = -1; /* Current character, none yet. */ debug(F101,"typegetline zsinl simulation","",n); while (n--) { /* Up to given length */ #ifdef COMMENT int old = 0; if (feol) /* Previous character */ old = a; #endif /* COMMENT */ if (zchin(ZIFILE,&a) < 0) { /* Read a character from the file */ debug(F101,"typegetline zchin fail","",count); if (count == 0) x = -1; /* EOF or other error */ break; } else count++; if (feol) { /* Single-character line terminator */ if (a == feol) break; } else { /* CRLF line terminator */ #ifdef COMMENT /* Debug log shows that in Windows, is returned as . */ /* Apparently we're not reading the file in binary mode. */ if (a == '\015') /* CR, get next character */ continue; if (old == '\015') { /* Previous character was CR */ if (a == '\012') { /* This one is LF, so we have a line */ break; } else { /* Not LF, deposit CR */ *s++ = '\015'; n--; len++; } } #else if (a == LF) { if (s[len] == CK_CR) { /* This probably won't happen */ s[len] = NUL; s--; len--; } break; } #endif /* COMMENT */ } *s = a; /* Deposit character */ s++; len++; } *s = '\0'; /* Terminate the string */ } #endif /* COMMENT */ #ifdef TYPEINTERPRET #ifndef NT /* (or should this be OS2?) */ dointerpret: if ( type_intrp ) { /* TYPE /INTERPRET (2022-08-22 fdc) */ int zzrc = 0; /* Returncode for zzstring */ int tmplen = TMPBUFSIZ; char * newbuf = tmpbuf; /* New string to create */ zzrc = zzstring(buf, &newbuf, &tmplen); /* Interpret the string */ len = ckstrncpy(buf, tmpbuf, TYPBUFL); /* Replace original string */ } #endif /* NT */ #endif /* TYPEINTERPRET */ return(x < 0 ? -1 : len); } #ifndef MAC SIGTYP #ifdef CK_ANSIC tytrap(int foo) /* TYPE interrupt trap */ #else tytrap(foo) int foo; #endif /* CK_ANSIC */ /* tytrap */ { #ifdef __EMX__ signal(SIGINT, SIG_ACK); #endif debug(F100,"type tytrap SIGINT","",0); typ_int = 1; /* (Need arg for ANSI C) */ SIGRETURN; } #endif /* MAC */ _PROTOTYP(char * cvtstring,(char*,int,int)); int #ifdef CK_ANSIC dotype( char * file, int paging, int first, int head, char * pat, int width, char * prefix, int incs, int outcs, char * outfile, int z ) #else dotype(file, paging, first, head, pat, width, prefix, incs, outcs, outfile, z) char * file, * pat, * prefix; int paging, first, head, width, incs, outcs; char * outfile; int z; #endif /* CK_ANSIC */ { extern CK_OFF_T ffc; char buf[TYPBUFL+2]; char * s = NULL; int rc = 1, lines = 0, ucs2 = 0; char ** tail = NULL; int * tlen = NULL; int tailing = 0, counting = 0; int x, n, i, j, k = 0; int number = 0, save, len, pfxlen = 0, evalpfx = 1; #ifdef UNICODE int ucsbom_sav; extern int ucsbom; #endif /* UNICODE */ #ifdef NT #ifdef KUI int gui = 0; #endif /* KUI */ #endif /* NT */ #ifndef MAC #ifdef OS2 #ifdef NT SIGTYP (* oldsig)(int); /* For saving old interrupt trap. */ #else /* NT */ SIGTYP (* volatile oldsig)(int); #endif /* NT */ #else /* OS2 */ SIGTYP (* oldsig)(); #endif /* OS2 */ #endif /* MAC */ #ifdef KUI if (outfile == (char *)1) { gui = 1; outfile = ""; } #endif /* KUI */ if (!file) file = ""; if (!*file) return(-2); if (ofp != stdout) { /* In case of previous interruption */ if (ofp) fclose(ofp); ofp = stdout; } if (!outfile) outfile = ""; if (outfile[0]) { ofp = fopen(outfile,"w"); /* Open output file */ if (!ofp) { printf("?Can't open output file %s: %s\n",outfile,ck_errstr()); ofp = stdout; return(-9); } } number = z; if (number && prefix) prefix = NULL; #ifdef UNICODE ucsbom_sav = ucsbom; /* We are not creating a file */ ucsbom = 0; /* Do not use BOM bytes */ #endif /* UNICODE */ typ_int = 0; save = binary; /* Save file type */ debug(F101,"dotype incs","",incs); debug(F101,"dotype outcs","",outcs); #ifdef UNICODE debug(F111,"dotype fileorder","A",fileorder); #ifdef OS2 if (!inserver && !k95stdout) outcs = FC_UCS2; #endif /* OS2 */ if (outcs == FC_UCS2) /* Output is UCS-2? */ ucs2 = 1; if (fileorder < 0) fileorder = ucsorder; debug(F111,"dotype fileorder","B",fileorder); #endif /* UNICODE */ #ifdef CK_TTGWSIZ #ifdef OS2 ttgcwsz(); #else /* OS2 */ /* Check whether window size changed */ if (ttgwsiz() > 0) { if (tt_rows > 0 && tt_cols > 0) { cmd_rows = tt_rows; cmd_cols = tt_cols; debug(F101,"dotype cmd_rows","",cmd_rows); debug(F101,"dotype cmd_cols","",cmd_cols); } } #endif /* OS2 */ #endif /* CK_TTGWSIZ */ if (prefix) pfxlen = strlen(prefix); if (paging < 0) { /* Count only, don't print */ counting = 1; prefix = NULL; width = 0; paging = 0; } if (ucs2) /* Crude... */ width *= 2; #ifdef OS2 if (*file) { ckstrncpy(buf, file, TYPBUFL); /* Change / to \. */ p = buf; while (*p) { if (*p == '/') *p = '\\'; p++; } file = buf; } else { rc = 0; goto xdotype; } #endif /* OS2 */ if (zchki(file) == -2) { /* It's a directory */ debug(F111,"dotype zchki failure",file,-2); if (xcmdsrc == 0) { printf("?Not a regular file: \"%s\"\n",file); rc = -9; } else rc = 0; goto xdotype; } /* printf("%s: %d\n","DOTYPE tlevel BEFORE open:",tlevel); */ if (!zopeni(ZIFILE, file)) { /* Not a directory, open it */ debug(F111,"dotype zopeni failure",file,0); if (xcmdsrc == 0) { printf("?Can't open file: \"%s\"\n",file); rc = -9; } else rc = 0; goto xdotype; } /* printf("%s: %d\n","DOTYPE tlevel AFTER open:",tlevel); */ #ifndef AMIGA #ifndef MAC errno = 0; oldsig = signal(SIGINT, tytrap); /* Save current interrupt trap. */ /* debug(F111,"type SIGINT trap set",ckitoa(errno),oldsig); */ #endif /* MAC */ #endif /* AMIGA */ if (paging > -1) /* More-prompting */ xaskmore = paging; binary = 0; if (head < 0) { /* "tail" was requested */ tailing = 1; /* Set flag */ head = 0 - head; /* Get absolute number of lines */ if (!counting) { tail = (char **) malloc(head * sizeof(char *)); /* Allocate list */ if (!tail) { printf("?Memory allocation failure\n"); goto xdotype; } tlen = (int *) malloc(head * sizeof(int)); if (!tlen) { printf("?Memory allocation failure\n"); goto xdotype; } for (i = 0; i < head; i++) { /* Initialize each pointer in list. */ tail[i] = NULL; tlen[i] = 0; } } } typ_lines = 0; typ_mtchs = 0; #ifdef UNICODE if (outcs > -1 && (incs != outcs || incs == FC_UCS2)) { /* Translating? */ ffc = (CK_OFF_T)0; initxlate(incs,outcs); /* Set up translation functions */ } else #endif /* UNICODE */ outcs = -1; /* Means we don't know the charset */ debug(F101,"dotype ffc","",ffc); debug(F101,"dotype outcs 2","",outcs); #ifdef UNICODE debug(F111,"dotype fileorder","C",fileorder); #endif /* UNICODE */ /* Allow the buffer to contain NULs */ for (n = first; (len = typegetline(incs,outcs,buf,TYPBUFL)) > -1; lines++ ) { debug(F111,"dotype line",buf,len); #ifdef TYPEINTERPRET /* 2022-08-31 fdc */ #ifdef NT /* Or should this be OS2? */ if (type_intrp) { /* TYPE /INTERPRET? */ int zzrc = 0, tmplen = 0; /* Return code for zzstring */ char * cvtbuf; /* Pointer to conversion buffer */ char * newbuf = malloc(TYPBUFL+3); /* Buffer for zzstring result */ char * resultbuf; /* The line has been returned to us as UCS-2 but we need to feed it to zzstring() to interpret all the backslash escapes, but zzstring doesn't understand UCS-2. So we have to convert it from UCS2 (outcs) back to incs; feed it to zzstring(), and then convert it back to UCS2 (outcs). */ cvtbuf = cvtstring(buf,outcs,incs); /* UCS2->original cset */ debug(F110,"dotype interpret cvtbuf",cvtbuf,0); zzstring(cvtbuf, &newbuf, &tmplen); /* Evaluate it */ resultbuf = cvtstring(newbuf,incs,outcs); /* Back to UCS2 */ ckstrncpy(buf, resultbuf, TYPBUFL+3); debug(F110,"dotype interpret zzstring result buf",buf,0); free(newbuf); } #endif /* NT */ #endif /* TYPEINTERPRET */ #ifndef MAC /* */ if (typ_int) { /* Interrupted? */ typ_int = 0; debug(F101,"type interrupted line","",lines); printf("^C...\n"); /* Print message */ if (ofp != stdout) { /* Close any output file */ if (ofp) fclose(ofp); ofp = stdout; } goto xxdotype; } #endif /* MAC */ typ_lines++; /* For \v(ty_ln) */ if (pat) /* Matching? */ if (!ckmatch(pat,buf,1,1+4)) /* Line matches pattern? */ continue; /* No, skip it */ typ_mtchs++; if (head > 0 && !tailing && lines == head) /* Handle /HEAD:n */ break; buf[TYPBUFL+1] = NUL; /* Just in case... */ if (prefix) { /* Add specified prefix to each line */ char pbuf[64]; char * pp; pp = prefix; #ifndef NOSPL if (evalpfx) { /* Prefix is a variable? */ int n = 63; /* Maybe - evaluate it and see */ char * p = pbuf; zzstring(prefix,&p,&n); /* If there is no change */ if (!strcmp(prefix,pbuf)) { /* it's not a variable */ evalpfx = 0; /* So don't do this again. */ } else { /* It was a variable */ pp = pbuf; /* So substitute its value */ pfxlen = 63 - n; /* and get its new length */ } } #endif /* NOSPL */ if (len + pfxlen + 2 < TYPBUFL) { /* Shift right to make room for prefix */ memcpy((char *)line+pfxlen,(char *)buf,len); lset((char *)line,pp,pfxlen,SP); debug(F110,"dotype prefix",line,pfxlen); len += pfxlen; memcpy((char *)buf,(char *)line,len); } } else if (number) { /* Line numbers */ int x; sprintf(line,"%4d. ",typ_lines); x = strlen(line); len += x; if (len < LINBUFSIZ) { memcpy((char *)&line[x],(char *)buf,len); memcpy((char *)buf,(char *)line,len); } } if (width > 0 && width <= TYPBUFL) { /* Truncate at given width. */ char * obuf = line; /* But to do that first we must */ int i,k,z; /* expand tabs; assume every 8 cols. */ line[0] = NUL; for (i = 0, k = 0; i < width; k++) { /* Character loop... */ if (!buf[k]) /* No more chars in this line, done. */ break; if (buf[k] != '\t') { /* If it's not a tab */ if (i >= LINBUFSIZ) /* Check for overflow */ break; obuf[i++] = buf[k]; /* and then deposit it. */ obuf[i] = NUL; /* Keep it null-terminated */ continue; } z = 8 - (i % 8); /* It's a tab, expand it. */ if (z == 0) z = 8; for (j = 0; j < z && i < LINBUFSIZ; j++) { #ifdef UNICODE if (ucs2 && !ucsorder) obuf[i++] = NUL; #endif /* UNICODE */ obuf[i++] = ' '; #ifdef UNICODE if (ucs2 && ucsorder) obuf[i++] = NUL; #endif /* UNICODE */ } obuf[i++] = NUL; obuf[i] = NUL; } obuf[width] = NUL; /* Now truncate at given width. */ #ifdef COMMENT /* This doesn't work for UCS-2 because it contains NULs */ ckstrncpy(buf,obuf,TYPBUFL); /* and copy it back (again?) */ #else memcpy((char *)buf,(char *)obuf,i); /* Copy it back */ #endif /* COMMENT */ len = (i > width) ? width : i; /* Spare us another strlen()... */ } if (tailing) { /* If /TAIL:n... */ k = lines % head; /* save this line in circular buffer */ if (!counting) { if (tail[k]) free(tail[k]); tail[k] = malloc(len+2); if (!tail[k]) { printf("?Memory allocation failure\n"); goto xdotype; } memcpy(tail[k],buf,len); tlen[k] = len; continue; } } if (counting) /* If only counting */ continue; /* we're done with this line */ if (paging) { /* Displaying this line... */ int u; u = len; /* Length in BYTES */ if (ucs2) /* If outputting in UCS-2 */ u /= 2; /* convert length to CHARACTERS */ x = (u / cmd_cols) + 1; /* Crudely allow for wrap */ if (cmd_rows > 0 && cmd_cols > 0) n += x; /* This assumes terminal will wrap */ } #ifdef KUI #ifndef NORICHEDIT if ( gui ) { int i; unsigned short * uch = (unsigned short *)buf; for ( i=0; i 0 && ofp == stdout) { /* Pause at end of screen */ if (cmd_rows > 0 && cmd_cols > 0) { if (n > cmd_rows - 3) { if (!askmore()) { goto xdotype; } else { n = 0; } } } } #endif /* CK_TTGWSIZ */ } xdotype: if (counting) { fprintf(ofp, "%s: %d line%s\n",file,typ_lines,typ_lines == 1 ? "" : "s"); if (pat) fprintf(ofp, "%s: %d match%s\n",pat,typ_mtchs,typ_mtchs == 1 ? "" : "es"); goto xxdotype; } if (tailing && tail) { /* Typing tail of file? */ if (lines < head) { /* Yes, show the lines we saved */ k = 0; /* Show all lines */ } else { /* More lines than tail number */ lines = k; /* Last line to show */ k++; /* First line to show */ if (k >= head) k = 0; } n = first; /* Output line counter */ for (i = k ;; i++) { /* Loop thru circular buffer */ #ifndef MAC if (typ_int) { /* Interrupted? */ printf("^C...\n"); /* Print message */ goto xxdotype; } #endif /* MAC */ j = i % head; /* Index of this line */ s = tail[j]; /* Point to line to display */ if (!s) /* (shouldn't happen...) */ break; if (paging) { /* Crudely allow for line wrap */ x = tlen[j]; if (ucs2) x /= 2; x = x / cmd_cols + 1; if (cmd_rows > 0 && cmd_cols > 0) n += x; } typeline(s,tlen[j],outcs,ofp); /* Display this line */ if (paging && ofp == stdout) { /* Pause at end of screen */ if (cmd_rows > 0 && cmd_cols > 0) { if (n > cmd_rows - 3) { if (!askmore()) { break; } else { n = 0; } } } } tail[j] = NULL; free(s); /* Free the line */ if (i % head == lines) /* When to stop */ break; } free((char *)tail); /* Free the list */ tail = NULL; if (tlen) free((char *)tlen); tlen = NULL; } /* Come here when finished or on SIGINT */ xxdotype: #ifndef AMIGA #ifndef MAC signal(SIGINT,oldsig); /* Put old signal action back. */ #endif /* MAC */ #endif /* AMIGA */ if (tailing && tail) { for (i = 0; i < head; i++) { /* Free each line. */ if (tail[i]) free(tail[i]); } free((char *)tail); /* Free list pointer */ if (tlen) free((char *)tlen); } x = zclose(ZIFILE); /* Done, close the input file */ if (ofp != stdout) { /* Close any output file */ if (ofp) fclose(ofp); ofp = stdout; } binary = save; /* Restore text/binary mode */ #ifdef UNICODE ucsbom = ucsbom_sav; /* Restore BOM usage */ #endif /* UNICODE */ #ifdef KUI #ifndef NORICHEDIT if ( gui ) gui_text_popup_wait(-1); /* Wait for user to close the dialog */ #endif /* NORICHEDIT */ #endif /* KUI */ return(rc); } /* GREP command */ #define GREP_CASE 0 /* /CASE */ #define GREP_COUN 1 /* /COUNT */ #define GREP_DOTF 2 /* /DOTFILES */ #define GREP_NAME 3 /* /NAMEONLY */ #define GREP_NOBK 4 /* /NOBACKUP */ #define GREP_NODO 5 /* /NODOTFILES */ #define GREP_NOLI 6 /* /NOLIST */ #define GREP_NOMA 7 /* /INVERT = /NOMATCH */ #define GREP_NOPA 8 /* /NOPAGE */ #define GREP_NUMS 9 /* /LINENUMBERS */ #define GREP_PAGE 10 /* /PAGE */ #define GREP_RECU 11 /* /RECURSIVE */ #define GREP_TYPE 12 /* /TYPE: */ #define GREP_OUTP 13 /* /OUTPUTFILE: */ #define GREP_EXCP 14 /* /EXCEPT: */ #define GREP_ARRA 15 /* /ARRAY: */ #define GREP_DISP 16 /* /DISPLAY: */ #define GREP_VERB 17 /* /VERBATIM */ #define GREP_MACR 18 /* /DEFINE */ static struct keytab greptab[] = { { "/array", GREP_ARRA, CM_ARG }, { "/count", GREP_COUN, CM_ARG }, #ifndef NOSPL { "/define", GREP_MACR, CM_ARG|CM_INV }, #endif /* NOSPL */ { "/display", GREP_DISP, CM_ARG }, { "/dotfiles", GREP_DOTF, 0 }, { "/except", GREP_EXCP, CM_ARG }, { "/linenumbers", GREP_NUMS, 0 }, #ifndef NOSPL { "/macro", GREP_MACR, CM_ARG }, #endif /* NOSPL */ { "/nameonly", GREP_NAME, 0 }, { "/nobackupfiles",GREP_NOBK, 0 }, { "/nocase", GREP_CASE, 0 }, { "/nodotfiles", GREP_NODO, 0 }, { "/nolist", GREP_NOLI, 0 }, { "/nomatch", GREP_NOMA, 0 }, { "/nopage", GREP_NOPA, 0 }, { "/output", GREP_OUTP, CM_ARG }, { "/page", GREP_PAGE, 0 }, { "/quiet", GREP_NOLI, CM_INV }, #ifdef RECURSIVE { "/recursive", GREP_RECU, 0 }, #endif /* RECURSIVE */ { "/show", GREP_DISP, CM_ARG|CM_INV }, { "/type", GREP_TYPE, CM_ARG }, { "/verbatim", GREP_VERB, 0 }, { "", 0, 0 } }; static int ngreptab = sizeof(greptab)/sizeof(struct keytab)-1; #ifndef GREPARRAYSIZE #define GREPARRAYSIZE 1000 #endif /* GREPARRAYSIZE */ static char * grep_except = NULL; int dogrep() { int match, x, y, fc, getval, mc = 0, count = 0, bigcount = 0; int fline = 0, sline = 0, wild = 0, len = 0; int xmode = -1, scan = 0, dispmode = 0, verbatim = 0; char c, name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p, *s, *cv = NULL; FILE * fp = NULL; /* File pointer for result file */ #ifndef NOSPL char array = NUL; char ** ap = NULL; char * arrayname = ""; /* Name of array */ int arraynum = -1; /* Numeric identifier of array */ int arrayslot = 1; /* Array element number */ char macroname[CKMAXPATH+1]; /* Macro name buffer */ char macrodef[CKMAXPATH+1]; /* Macro definition buffer */ #endif /* NOSPL */ char *rp1 = ""; /* Result Part 1 (filename) */ char *rp2 = ""; /* Result Part 2 (line number) */ char *rp3 = ""; /* Result Part 3 (a matching line */ /* gr_noli produces no result listings, arrays, or macros; if simply sets the SUCCESS or FAILURE code of the GREP command. */ int /* Switch values and defaults */ gr_coun = 0, /* Just count the matches */ gr_name = 0, /* Show filename only */ gr_nobk = 0, /* Skip backup files (*.~n~) */ gr_case = 1, /* Honor or ignore alphabetic case */ gr_noma = 0, /* Only show lines that DON'T match */ gr_nums = 0, /* Show line numbers */ gr_excp = 0, /* Files to skip */ gr_noli = 0, /* Don't list results */ gr_page = xaskmore; /* Pause for each screenful */ #ifndef NOSPL int gr_macr = 0; /* Initialize GREP macro flag */ #endif /* NOSPL */ struct FDB sw, fl; #ifndef NOSPL macroname[0] = NUL; /* Initialize macro name buffer */ macrodef[0] = NUL; /* Initialize macro def buffer */ #endif /* NOSPL */ g_matchdot = matchdot; /* Save global matchdot setting */ outfile[0] = NUL; makestr(&grep_except,NULL); if (ofp != stdout) { /* In case of previous interruption */ if (ofp) fclose(ofp); ofp = stdout; } cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "String or pattern to search for, or switch", "", /* default */ "", /* addtl string data */ ngreptab, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ greptab, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* Anything that doesn't match */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, /* processing function */ NULL, NULL ); while (1) { /* Parse 0 or more switches */ x = cmfdb(&sw); /* Parse something */ if (x < 0) return(x); if (cmresult.fcode != _CMKEY) { /* Break out if not a switch */ break; } c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } if ((cmresult.nresult != GREP_COUN) && !getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } switch (cmresult.nresult) { case GREP_COUN: { gr_coun++; if (getval) { if ((x = cmfld("Variable for result","",&s,NULL)) < 0) return(x); makestr(&cv,s); } break; } case GREP_CASE: gr_case=0; break; case GREP_NAME: gr_name++; gr_noli=0; break; case GREP_NOBK: gr_nobk++; break; case GREP_NOLI: gr_noli++; gr_name=0; gr_nums=0; break; case GREP_NOMA: gr_noma++; break; case GREP_NOPA: gr_page=0; break; case GREP_NUMS: gr_nums++; gr_noli=0; break; case GREP_PAGE: gr_page++; gr_noli=0; break; case GREP_NODO: matchdot = 0; break; case GREP_DOTF: matchdot = 1; break; #ifndef NOSPL case GREP_ARRA: { char * s2; if (c != ':' && c != '=') { printf("?Array name required\n"); return(-9); } if ((x = cmfld("Array name (a single letter will do)", "", &s, NULL )) < 0) { if (x == -3) { printf("?Array name required\n"); return(-9); } else return(x); } if (!*s) { printf("?Array name required\n"); return(-9); } s2 = s; if (*s == CMDQ) s++; if (*s == '&') s++; if (!isalpha(*s)) { printf("?Bad array name - \"%s\"\n",s2); return(-9); } array = *s++; if (isupper(array)) array = tolower(array); if (*s && (*s != '[' || *(s+1) != ']')) { printf("?Bad array name - \"%s\"\n",s2); return(-9); } arrayname = s2; debug(F110,"GREP arrayname",arrayname,0); break; } #endif /* NOSPL */ #ifdef RECURSIVE case GREP_RECU: recursive = 1; break; #endif /* RECURSIVE */ #ifndef NOSPL case GREP_MACR: { /* Results become macro definition */ gr_macr = 1; if ((x = cmfld("macro name","",&s,xxstring)) < 0) return(x); ckstrncpy(macroname,s,CKMAXPATH); /* Macro name */ break; } #endif /* NOSPL */ case GREP_TYPE: { extern struct keytab txtbin[]; if ((x = cmkey(txtbin,3,"","",xxstring)) < 0) return(x); if (x == 2) { /* ALL */ xmode = -1; } else { /* TEXT or BINARY only */ xmode = x; scan = 1; } break; } case GREP_OUTP: /* Send output to file */ if ((x = cmofi("File for GREP'd lines","",&s,xxstring)) < 0) return(x); ckstrncpy(outfile,s,CKMAXPATH); break; case GREP_EXCP: /* Exception pattern */ if (getval) { if ((x = cmfld("Exception pattern", "", &s, xxstring )) < 0) return(x); gr_excp++; makestr(&grep_except,s); } case GREP_DISP: /* Display options */ if (getval) { if ((y = cmnum("number: max lines to show", "0",10,&x,xxstring)) < 0) return(y); dispmode = x; /* Number of lines to display */ break; } case GREP_VERB: /* VERBATIM */ cmfdbi(&fl, /* Don't call zzstring */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, /* processing function */ NULL, NULL ); verbatim = 1; break; } } if (outfile[0]) { ofp = fopen(outfile,"w"); /* Open output file */ if (!ofp) { printf("?Can't open output file %s: %s\n",outfile,ck_errstr()); ofp = stdout; return(-9); } gr_page = 0; } s = cmresult.sresult; s = brstrip(s); /* Strip braces from pattern */ if (!*s) { printf("?Pattern required\n"); return(-9); } ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Save pattern */ if ((x = cmifi("File(s) to search","",&s,&wild,xxstring)) < 0) { if (x == -3) { printf("?File specification required\n"); x = -9; } return(x); } s = brstrip(s); /* Strip braces from filename */ #ifndef ZXREWIND ckstrncpy(line,s,LINBUFSIZ); #endif /* ZXREWIND */ if ((y = cmcfm()) < 0) return(y); if (gr_page > -1) xaskmore = gr_page; /* Paging... */ p = tmpbuf; /* Point to pattern */ #ifdef COMMENT /* Now this is done in ckmatch */ if (*p == '^') { /* '^' anchors pattern to beginning */ p++; } else if (*p != '*') { /* Otherwise prepend implied '*' */ tmpbuf[0] = '*'; p = tmpbuf; } x = strlen(p); /* Get length of result */ if (x > 0 && x < TMPBUFSIZ) { /* '$' at end anchors pattern to end */ if (p[x-1] == '$') { p[x-1] = NUL; } else if (p[x-1] != '*') { p[x] = '*'; p[x+1] = NUL; } } #endif /* COMMENT */ debug(F111,"GREP pat",p,x); #ifdef ZXREWIND fc = zxrewind(); /* Rewind the file list */ debug(F101,"GREP ZXREWIND fc (number of files to grep)",NULL,fc); #else { int flags = ZX_FILONLY; /* Expand file list */ if (matchdot) flags |= ZX_MATCHDOT; if (recursive) flags |= ZX_RECURSE; fc = nzxpand(line,flags); /* Number of files that match */ debug(F110,"GREP fc (number of files to grep)",fc,0); } #endif /* ZXREWIND */ #ifndef NOSPL if (array) { int n = GREPARRAYSIZE; /* Size for "grep /array" array */ if ((arraynum = dclarray(array,n)) < 0) { printf("?Array declaration failure\n"); mc = 0; /* Number of lines that match target */ goto xgrep; } ap = a_ptr[arraynum]; /* Pointer to list of elements */ if (ap) { /* Set element 0 to dimension */ makestr(&(ap[0]),"0"); /* which so far is zero */ } else { printf("?Array initialization failure\n"); goto xgrep; } if (fc < 1) { /* No files matched, done. */ mc = 0; /* Match count */ debug(F110,"GREP /array no files match",p,0); goto xgrep; } debug(F101,"GREP /array setup ok size","",n); } #endif /* NOSPL */ #ifdef UNIX sh_sort(mtchs,NULL,fc,0,0,filecase); #endif /* UNIX */ debug(F101,"GREP cmd_rows","",cmd_rows); debug(F101,"GREP cmd_cols","",cmd_cols); debug(F101,"GREP gr_nums","",gr_nums); debug(F101,"GREP gr_nobk","",gr_nobk); debug(F101,"GREP gr_noma","",gr_noma); #ifndef NOSPL debug(F101,"GREP gr_macr","",gr_macr); #endif /* NOSPL */ debug(F101,"GREP gr_name","",gr_name); debug(F101,"GREP gr_coun","",gr_coun); debug(F101,"GREP gr_noli","",gr_noli); debug(F101,"GREP wild","",wild); while (1) { /* Loop for each file */ znext(name); /* Get next file */ if (!name[0]) /* No more, done */ break; if (gr_nobk) /* Skipping backup files? */ if (ckmatch("*.~[1-9]*~",name,1,1)) /* Backup file? */ continue; /* Yes, skip */ if (scan) { /* /TYPE: given? */ switch (scanfile(name,&y,nscanfile)) { /* Yes, scan the file */ case FT_BIN: if (xmode != 1) continue; break; case FT_TEXT: case FT_7BIT: case FT_8BIT: #ifdef UNICODE case FT_UTF8: case FT_UCS2: #endif /* UNICODE */ if (xmode != 0) continue; } } fp = fopen(name,"r"); /* Open */ if (!fp) /* Can't */ continue; /* Skip */ debug(F110,"GREP file open ok",name,0); count = 0; /* Match count, this file */ fline = 0; /* Line count, this file */ while (1) { /* Loop for each line */ if (fgets(line,LINBUFSIZ,fp) == NULL) { /* Get next line */ fclose(fp); fp = NULL; debug(F100,"GREP EOF","",0); break; } fline++; /* Count this line (line # in file) */ line[LINBUFSIZ] = NUL; /* Make sure it's terminated */ debug(F111,"GREP line and number",line,fline); len = (int)strlen(line); /* Get length */ debug(F111,"GREP line length","",len); while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r')) line[--len] = NUL; /* Chop off terminators */ if (verbatim) { /* Match literally */ match = ckindex(p,line,0,0,gr_case); } else { match = ckmatch(p,line,gr_case,1+4); /* Match pattern */ if (match && gr_excp) { if (ckmatch(grep_except,line,gr_case,1+4)) match = 0; } } if (gr_noma) /* Invert match sense if requested */ match = !match; if (match) { /* Have a matching line */ mc++; /* Total match count */ count++; /* Match count this file */ debug(F101,"GREP match count this file","",count); #ifndef NOSPL if (gr_macr) { /* Adding grep lines to macro def */ int len = 0; /* WHAT IS LEN FOR? */ debug(F100,"GREP adding line to macro","",0); len = ckstrncat(macrodef,line,CKMAXPATH); (VOID)ckstrncat(macrodef,"\n",CKMAXPATH); continue; } #endif /* NOSPL */ /* gr_name means just print the name of each file that contains at least one match. */ if (gr_name && count > 0) { /* Show name only */ #ifndef NOSPL if (array) { makestr(&(ap[arrayslot++]),name); } else { #endif /* NOSPL */ fprintf(ofp,"%s\n",name); x++; #ifndef NOSPL } #endif /* NOSPL */ break; /* Only need one per file */ } if (gr_coun || gr_noli) /* Not listing each line */ continue; /* so don't print anything now. */ if (wild) { /* If searching multiple files */ rp1 = name; /* set pointer to filename */ len += (int)strlen(name) + 1; } if (gr_nums) { /* If line numbers wanted */ rp2 = ckitoa(fline); /* set pointer to line number */ } rp3 = line; if (cmd_rows > 0 && cmd_cols > 0) sline += (len / cmd_cols) + 1; #ifndef NOSPL if (array) { char tmpstr[10000]; int tmplen; tmplen = (int)strlen(rp1) + (int)strlen(rp2) + (int)strlen(rp3) + 2; debug(F100,"GREP adding line to array","",0); debug(F101,"GREP tmplen","",tmplen); if (!rp1) rp1 = ""; if (!rp2) rp2 = ""; debug(F110,"GREP rp1",rp1,""); /* filename */ debug(F110,"GREP rp2",rp2,""); /* line number in file */ debug(F110,"GREP rp3",rp3,""); /* the matching line */ if (!(int)strlen(rp3)) /* (shouldn't happen) */ printf("*** EMPTY MATCH STRING ***\n"); /* name:lineno:line */ if ((int)strlen(rp1) && (int)strlen(rp2)) { ckmakxmsg(tmpstr,tmplen,rp1,":",rp2,":",rp3, NULL,NULL,NULL,NULL,NULL,NULL,NULL); /* name:line */ } else if ((int)strlen(rp1)) { ckmakmsg(tmpstr,tmplen,rp1,":",rp3,NULL); /* name:lineno */ } else if ((int)strlen(rp2)) { ckmakmsg(tmpstr,tmplen,rp2,":",rp3,NULL); /* line only */ } else { ckmakmsg(tmpstr,tmplen,rp3,NULL,NULL,NULL); } debug(F110,"GREP tmpstr",tmpstr,""); makestr(&(ap[arrayslot++]),tmpstr); } else { #endif /* NOSPL */ debug(F100,"GREP printing line","",0); if (wild) { if ((int)strlen(rp2)) fprintf(ofp,"%s%s%s%s%s\n", rp1,":",rp2,":",rp3); else fprintf(ofp,"%s%s%s\n", rp1,":",rp3); } else { if ((int)strlen(rp2)) fprintf(ofp,"%s%s%s\n", rp2,":",rp3); else fprintf(ofp,"%s\n",rp3); } if (sline > cmd_rows - 3) { if (!askmore()) { goto xgrep; } else { sline = 0; } } #ifndef NOSPL } #endif /* NOSPL */ debug(F100,"GREP X5","",0); debug(F101,"GREP X5 mc","",mc); debug(F101,"GREP X5 dispmode","",dispmode); if ((dispmode > 0) && (mc >= dispmode)) { goto xgrep; } } } x = 0; if (gr_coun) { /* Show match count only */ fprintf(ofp,"%s:%d\n",name,count); x++; } if (x > 0) { if (++sline > cmd_rows - 3) { if (!askmore()) { goto xgrep; } else { sline = 0; } } } bigcount += count; /* Overall count */ } xgrep: #ifndef NOSPL if (gr_macr) { /* If /macro assign matches to macro */ if (*macrodef) addmac(macroname,macrodef); } /* ...resize array resize... The array was declared has having GREPARRAYSIZE elements. This code resizes it to the actual number of matches found. - fdc, 19 March 2023 */ if (array) { int i; /* For loop variable */ int high = arrayslot - 1; /* To... */ a_dim[arraynum] = high; /* Adjust dimension */ makestr(&(ap[0]),ckitoa(arrayslot)); /* deallocate leftover elements */ for (i = arrayslot + 1; i <= GREPARRAYSIZE; i++ ) makestr(&(a_ptr[x][i]),NULL); /* from original array. */ } if (gr_coun && cv) { /* /COUNT:blah */ addmac(cv,ckitoa(bigcount)); /* set the variable */ makestr(&cv,NULL); /* free this */ } #endif /* NOSPL */ if (fp) fclose(fp); /* close input file if still open */ if (ofp != stdout) { /* Close any output file */ if (ofp) fclose(ofp); ofp = stdout; } return(success = mc ? 1 : 0); } /* Platform-independent DIRECTORY command */ static char ** dirlist = NULL; static int ndirlist = 0; /* This is part of a hack to allow multiple file specifications */ static VOID freedirlist() { if (dirlist) { int i; for (i = 0; i < ndirlist; i++) { if (dirlist[i]) free(dirlist[i]); } free((char *)dirlist); dirlist = NULL; } ndirlist = 0; } static struct keytab dirswtab[] = { /* DIRECTORY command switches */ { "/after", DIR_AFT, CM_ARG }, { "/all", DIR_ALL, 0 }, #ifndef NOSPL { "/array", DIR_ARR, CM_ARG }, #endif /* NOSPL */ { "/ascending", DIR_ASC, 0 }, { "/backup", DIR_BUP, 0 }, { "/before", DIR_BEF, CM_ARG }, { "/brief", DIR_BRF, 0 }, { "/count", DIR_COU, CM_ARG }, { "/descending", DIR_DSC, CM_INV }, { "/directories", DIR_DIR, 0 }, { "/dotfiles", DIR_DOT, 0 }, { "/englishdate", DIR_DAT, 0 }, { "/except", DIR_EXC, CM_ARG }, { "/files", DIR_FIL, 0 }, #ifdef CKSYMLINK { "/followlinks", DIR_LNK, 0 }, #endif /* CKSYMLINK */ { "/heading", DIR_HDG, 0 }, { "/isodate", DIR_ISO, 0 }, { "/larger-than", DIR_LAR, CM_ARG }, { "/message", DIR_MSG, CM_ARG }, { "/nobackupfiles",DIR_NOB, 0 }, { "/nodotfiles", DIR_NOD, 0 }, #ifdef CKSYMLINK { "/nofollowlinks",DIR_NLK, 0 }, #endif /* CKSYMLINK */ { "/noheading", DIR_NOH, 0 }, #ifdef CKSYMLINK { "/nolinks", DIR_NOL, 0 }, #endif /* CKSYMLINK */ { "/nomessage", DIR_NOM, 0 }, #ifdef CK_TTGWSIZ { "/nopage", DIR_NOP, 0 }, #endif /* CK_TTGWSIZ */ #ifdef RECURSIVE { "/norecursive", DIR_NOR, 0 }, #else #ifdef VMS { "/norecursive", DIR_NOR, 0 }, #else #ifdef datageneral { "/norecursive", DIR_NOR, 0 }, #endif /* datageneral */ #endif /* VMS */ #endif /* RECURSIVE */ { "/nosort", DIR_NOS, 0 }, { "/not-after", DIR_NAF, CM_ARG }, { "/not-before", DIR_NBF, CM_ARG }, { "/not-since", DIR_NAF, CM_INV|CM_ARG }, { "/noxfermode", DIR_NOT, 0 }, { "/output", DIR_OUT, CM_ARG }, #ifdef CK_TTGWSIZ { "/page", DIR_PAG, 0 }, #endif /* CK_TTGWSIZ */ #ifdef RECURSIVE { "/recursive", DIR_REC, 0 }, #else #ifdef VMS { "/recursive", DIR_REC, 0 }, #else #ifdef datageneral { "/recursive", DIR_REC, 0 }, #endif /* datageneral */ #endif /* VMS */ #endif /* RECURSIVE */ { "/reverse", DIR_DSC, 0 }, { "/since", DIR_AFT, CM_ARG|CM_INV }, { "/smaller-than",DIR_SMA, CM_ARG }, { "/sort", DIR_SRT, CM_ARG }, { "/summary", DIR_SUM, 0 }, { "/top", DIR_TOP, CM_ARG }, { "/type", DIR_BIN, CM_ARG }, { "/xfermode", DIR_TYP, 0 }, { "/verbose", DIR_VRB, 0 }, { "",0,0 } }; static int ndirswtab = (sizeof(dirswtab) / sizeof(struct keytab)) - 1; static struct keytab dirsort[] = { /* DIRECTORY /SORT: options */ { "date", DIRS_DT, 0 }, { "name", DIRS_NM, 0 }, { "size", DIRS_SZ, 0 } }; static int ndirsort = (sizeof(dirsort) / sizeof(struct keytab)); static struct keytab touchswtab[] = { /* TOUCH command switches */ { "/after", DIR_AFT, CM_ARG }, { "/all", DIR_ALL, 0 }, { "/backup", DIR_BUP, 0 }, { "/before", DIR_BEF, CM_ARG }, { "/count", DIR_COU, CM_ARG }, { "/directories", DIR_DIR, 0 }, { "/dotfiles", DIR_DOT, 0 }, { "/except", DIR_EXC, CM_ARG }, { "/files", DIR_FIL, 0 }, #ifdef CKSYMLINK { "/followlinks", DIR_LNK, 0 }, #endif /* CKSYMLINK */ { "/larger-than", DIR_LAR, CM_ARG }, { "/list", DIR_VRB, 0 }, { "/modtime", DIR_MOD, CM_ARG }, { "/nobackupfiles",DIR_NOB, 0 }, { "/nodotfiles", DIR_NOD, 0 }, #ifdef CKSYMLINK { "/nofollowlinks",DIR_NLK, 0 }, #endif /* CKSYMLINK */ #ifdef CKSYMLINK { "/nolinks", DIR_NOL, 0 }, #endif /* CKSYMLINK */ #ifdef CK_TTGWSIZ #endif /* CK_TTGWSIZ */ #ifdef RECURSIVE { "/norecursive", DIR_NOR, 0 }, #else #ifdef VMS { "/norecursive", DIR_NOR, 0 }, #else #ifdef datageneral { "/norecursive", DIR_NOR, 0 }, #endif /* datageneral */ #endif /* VMS */ #endif /* RECURSIVE */ { "/not-after", DIR_NAF, CM_ARG }, { "/not-before", DIR_NBF, CM_ARG }, { "/not-since", DIR_NAF, CM_INV|CM_ARG }, #ifdef RECURSIVE { "/recursive", DIR_REC, 0 }, #else #ifdef VMS { "/recursive", DIR_REC, 0 }, #else #ifdef datageneral { "/recursive", DIR_REC, 0 }, #endif /* datageneral */ #endif /* VMS */ #endif /* RECURSIVE */ { "/simulate", DIR_SIM, 0 }, { "/since", DIR_AFT, CM_ARG|CM_INV }, { "/smaller-than",DIR_SMA, CM_ARG }, { "/type", DIR_BIN, CM_ARG }, { "/verbose", DIR_VRB, CM_INV }, { "",0,0 } }; static int ntouchswtab = (sizeof(touchswtab) / sizeof(struct keytab)) - 1; static struct keytab changeswtab[] = { /* CHANGE command switches */ { "/after", DIR_AFT, CM_ARG }, { "/backup", DIR_BAK, CM_ARG }, { "/before", DIR_BEF, CM_ARG }, { "/case", 7777, CM_ARG }, { "/count", DIR_COU, CM_ARG }, { "/destination", DIR_DES, CM_ARG }, { "/dotfiles", DIR_DOT, 0 }, { "/except", DIR_EXC, CM_ARG }, { "/larger-than", DIR_LAR, CM_ARG }, { "/list", DIR_VRB, 0 }, { "/modtime", DIR_MOD, CM_ARG }, { "/nodotfiles", DIR_NOD, 0 }, #ifdef RECURSIVE { "/norecursive", DIR_NOR, 0 }, #endif /* RECURSIVE */ { "/not-after", DIR_NAF, CM_ARG }, { "/not-before", DIR_NBF, CM_ARG }, { "/not-since", DIR_NAF, CM_INV|CM_ARG }, #ifdef RECURSIVE { "/recursive", DIR_REC, 0 }, #endif /* RECURSIVE */ { "/simulate", DIR_SIM, 0 }, { "/since", DIR_AFT, CM_ARG|CM_INV }, { "/smaller-than",DIR_SMA, CM_ARG }, { "/verbose", DIR_VRB, CM_INV }, { "",0,0 } }; static int nchangeswtab = (sizeof(changeswtab) / sizeof(struct keytab)) - 1; #define CHMT_U 0 /* CHANGE command modtime options */ #define CHMT_P 1 static struct keytab chmttab[] = { { "preserve", CHMT_P, 0 }, { "update", CHMT_U, 0 } }; static int nchmttab = 2; static int dir_date = -1; /* Option defaults (-1 means none) */ static int dir_page = -1; static int dir_verb = 1; static int dir_msg = -1; #ifdef VMS static int dir_sort = -1; /* Names are already sorted in VMS */ static int dir_rvrs = -1; #else static int dir_sort = 1; /* Sort by default */ static int dir_rvrs = 0; /* Not in reverse */ #endif /* VMS */ static int dir_skey = DIRS_NM; /* By name */ #ifdef RECURSIVE static int dir_recu = -1; #endif /* RECURSIVE */ static int dir_mode = -1; static int dir_show = -1; /* Show all files by default */ int dir_dots = -1; /* Except dot files */ int dir_back = 1; int dir_head = 0; static char * dirmsg = NULL; static int dirmsglen = 0; #ifndef NOSHOW VOID showdiropts() { int x = 0; extern int optlines; prtopt(&optlines,"DIRECTORY"); if (dir_show > 0) { prtopt(&optlines,(dir_show == 1) ? "/FILES" : ((dir_show == 2) ? "/DIRECTORIES" : "/ALL")); x++; } else { prtopt(&optlines,"/ALL"); x++; } if (dir_verb > -1) { prtopt(&optlines,dir_verb ? "/VERBOSE" : "/BRIEF"); x++; } if (dir_page > -1) { prtopt(&optlines,dir_page ? "/PAGE" : "/NOPAGE"); x++; } if (dir_date > -1) { prtopt(&optlines,dir_date ? "/ENGLISHDATE" : "/ISODATE"); x++; } if (dir_dots > -1) { prtopt(&optlines,dir_dots ? "/DOTFILES" : "/NODOTFILES"); x++; } if (dir_back > -1) { prtopt(&optlines,dir_back ? "/BACKUP" : "/NOBACKUP"); x++; } if (dir_head > -1) { prtopt(&optlines,dir_head ? "/HEADING" : "/NOHEADING"); x++; } #ifdef RECURSIVE if (dir_recu > -1) { prtopt(&optlines,dir_recu ? "/RECURSIVE" : "/NORECURSIVE"); x++; } #endif /* RECURSIVE */ if (dir_mode > -1) { prtopt(&optlines,dir_mode ? "/XFERMODE" : "/NOXFERMODE"); x++; } if (dir_sort == 0) { x++; prtopt(&optlines,"/NOSORT "); } else if (dir_sort > 0) { x++; if (dir_skey == DIRS_NM) s = "/SORT:NAME"; else if (dir_skey == DIRS_SZ) s = "/SORT:SIZE"; else if (dir_skey == DIRS_DT) s = "/SORT:DATE"; prtopt(&optlines,s); } if (dir_rvrs > -1) { prtopt(&optlines,dir_rvrs ? "/REVERSE" : "/ASCENDING"); x++; } if (dir_msg > -1) { if (dir_msg == 0) { prtopt(&optlines,"/NOMESSAGE"); } else { ckmakmsg(tmpbuf,TMPBUFSIZ,"/MESSAGE:{",dirmsg,"}",NULL); prtopt(&optlines,tmpbuf); } x++; } if (!x) prtopt(&optlines,"(no options set)"); prtopt(&optlines,""); } #endif /* NOSHOW */ int setdiropts() { /* Set DIRECTORY option defaults */ int xb = -1, xv = -1, xp = -1, xd = -1, xh = -1, xf = -1; int xk = -1, xr = -1, xs = -1, xx = -1, xm = -1, xa = -1, xg = -1; int getval; char c; while (1) { if ((y = cmswi(dirswtab,ndirswtab,"Switch","",xxstring)) < 0) { if (y == -3) break; else return(y); } c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } switch (y) { case DIR_BRF: xv = 0; break; case DIR_VRB: xv = 1; break; case DIR_PAG: xp = 1; break; case DIR_NOP: xp = 0; break; case DIR_ISO: xd = 0; break; case DIR_DAT: xd = 1; break; case DIR_HDG: xh = 1; break; case DIR_NOH: xh = 0; break; case DIR_DOT: xf = 1; break; case DIR_NOD: xf = 0; break; case DIR_ALL: xa = 3; break; case DIR_DIR: xa = 2; break; case DIR_FIL: xa = 1; break; case DIR_SRT: x = DIRS_NM; if (getval) if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0) return(x); xk = x; xs = 1; break; case DIR_NOS: xs = 0; break; case DIR_ASC: xx = 0; break; case DIR_DSC: xx = 1; break; case DIR_REC: xr = 1; break; case DIR_NOR: xr = 0; break; case DIR_TYP: xm = 1; break; case DIR_NOT: xm = 0; break; case DIR_BUP: xb = 1; break; case DIR_NOB: xb = 0; break; case DIR_NOM: xg = 0; break; case DIR_MSG: if (getval) if ((x = cmfld("Message to append to each line", "", &s, xxstring )) < 0) return(x); xg = 1; ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ); break; default: printf("?This option can not be set\n"); return(-9); } } if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); if (xv > -1) dir_verb = xv; /* Confirmed, save defaults */ if (xp > -1) dir_page = xp; if (xd > -1) dir_date = xd; if (xh > -1) dir_head = xh; if (xs > -1) dir_sort = xs; if (xk > -1) dir_skey = xk; if (xx > -1) dir_rvrs = xx; if (xf > -1) dir_dots = xf; if (xa > -1) dir_show = xa; if (xm > -1) dir_mode = xm; if (xb > -1) dir_back = xb; #ifdef RECURSIVE if (xr > -1) dir_recu = xr; #endif /* RECURSIVE */ if (xg > -1) dir_msg = xg; if (xg > 0) makestr(&dirmsg,tmpbuf); return(success = 1); } int #ifdef CK_ANSIC domydir( int cx ) /* Internal DIRECTORY command */ #else domydir(cx) int cx; #endif /* CK_ANSIC */ { extern char *months[], *tempdir; #ifdef VMS _PROTOTYP( char * zrelname, (char *,char *) ); char * cdp = NULL; #endif /* VMS */ struct zattr xxstruct; int chmtopt = CHMT_U; char name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p = NULL, c = NUL; char linebuf[CKMAXPATH+CKMAXPATH+256]; char string1[1024], string2[1024]; /* For CHANGE */ char modtime[100]; char * mstr = NULL, * dstr = NULL, * s2 = NULL, * cv = NULL; CK_OFF_T len = (CK_OFF_T)0, nbytes = (CK_OFF_T)0; CK_OFF_T minsize = (CK_OFF_T)-1, maxsize = (CK_OFF_T)-1; long ndirs = 0, nfiles = 0, nmatches = 0; int verbose = 0, wild = 0, page = 0, n = 0, engdate = 0, summary = 0; int heading = 0, xsort = 0, reverse = 0, sortby = 0, msg = 0; int k, i = 0, x = 0, nx = 0, skey = 0, dlen = 0, itsadir = 0; int show = 3, xfermod = 0, backup = 1, rc = 0, getval = 0; int touch = 0; int change = 0; /* Doing CHANGE command */ int chcase = 0; /* CHANGE case dependence */ int s1len = 0; /* CHANGE string1 length */ int s2len = 0; /* CHANGE string2 length */ int fs = 0; int multiple = 0; int cmifn1 = 1, cmifn2 = 0; int dir_top = 0, dir_cou = 0; #ifdef CKSYMLINK int dontshowlinks = 0; int dontfollowlinks = 0; #endif /* CKSYMLINK */ int arrayindex = -1; int simulate = 0; struct FDB sw, fi, fl; char dbuf[256], xbuf[32]; int reallysort = 0; int changeinplace = 0; int changebackup = 0; int changes = 0; /* Change counter per file */ int totalchanges = 0; /* Change counter all files */ #ifndef NOSPL char array = NUL; char ** ap = NULL; #endif /* NOSPL */ char * dir_aft = NULL, * dir_bef = NULL, * dir_naf = NULL, * dir_nbf = NULL, * dir_exc = NULL; char * xlist[16]; debug(F101,"domydir cx","",cx); chgsourcedir[0] = NUL; /* CHANGE source directory */ chgdestdir[0] = NUL; /* CHANGE destination directory */ chgbackupdir[0] = NUL; /* CHANGE backup directory */ changeinplace = 1; /* CHANGE'ing files in place */ changebackup = 0; /* Backing up CHANGEd files */ changes = 0; totalchanges = 0; g_matchdot = matchdot; /* Save global matchdot setting */ #ifdef COMMENT nolinks = 2; /* (it should already be 2) */ #endif /* COMMENT */ outfile[0] = NUL; /* No output file yet */ modtime[0] = '\0'; /* Initialize TOUCH /MODTIME */ if (ofp != stdout) { /* In case of previous interruption */ if (ofp) fclose(ofp); ofp = stdout; } for (i = 0; i < 16; i++) xlist[i] = NULL; dir_top = 0; name[0] = NUL; freedirlist(); /* In case not freed last time */ page = dir_page > -1 ? dir_page : xaskmore; /* Set option defaults */ engdate = dir_date > -1 ? dir_date : 0; verbose = dir_verb > -1 ? dir_verb : 1; heading = dir_head > -1 ? dir_head : 0; xsort = dir_sort > -1 ? dir_sort : 0; sortby = dir_skey > -1 ? dir_skey : 0; reverse = dir_rvrs > -1 ? dir_rvrs : 0; msg = dir_msg > -1 ? dir_msg : 0; #ifdef UNIXOROSK if (dir_dots > -1) matchdot = dir_dots; #endif /* UNIXOROSK */ xfermod = dir_mode > -1 ? dir_mode : 0; backup = dir_back > -1 ? dir_back : 1; #ifdef RECURSIVE recursive = dir_recu > -1 ? dir_recu : 0; #endif /* RECURSIVE */ show = dir_show > -1 ? dir_show : 3; diractive = 1; /* This is a DIRECTORY command */ switch (cx) { case XXWDIR: /* WDIRECTORY */ debug(F100,"domydir WDIRECTORY","",0); reverse = 1; /* Reverse chronological order */ xsort = 1; sortby = DIRS_DT; break; case XXHDIR: /* HDIRECTORY */ debug(F100,"domydir HDIRECTORY","",0); reverse = 1; /* Reverse order by size */ xsort = 1; sortby = DIRS_SZ; break; case XXTOUC: diractive = 0; /* This is NOT a DIRECTORY command */ touch = 1; verbose = 0; break; case XXCHG: /* CHANGE 2013-04-18 */ diractive = 0; /* This is NOT a DIRECTORY command */ change = 1; verbose = 0; } #ifdef CK_TTGWSIZ #ifdef OS2 ttgcwsz(); /* Screen length for more-prompting */ #else /* OS2 */ /* Check whether window size changed */ if (ttgwsiz() > 0) { if (tt_rows > 0 && tt_cols > 0) { cmd_rows = tt_rows; cmd_cols = tt_cols; } } #endif /* OS2 */ #endif /* CK_TTGWSIZ */ cmifn1 = nolinks | 1; /* 1 = files or directories */ cmifn2 = 0; /* 0 = not directories only */ again: cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Enter or Return to confirm the command, or\n\ file specification, or switch", "", /* default */ "", /* addtl string data */ touch ? ntouchswtab : (change ? nchangeswtab : ndirswtab), 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ touch ? touchswtab : (change ? changeswtab : dirswtab), &fi /* Pointer to next FDB */ ); cmfdbi(&fi, /* 2nd FDB - filespec to match */ _CMIFI, /* fcode */ "File specification", /* hlpmsg */ #ifdef datageneral "+", /* Default filespec is wildcard */ #else /* that matches all files... */ #ifdef VMS "*.*", #else "*", #endif /* VMS */ #endif /* datageneral */ "", /* addtl string data */ cmifn1, cmifn2, /* 1 = only dirs; 0 files or dirs */ xxstring, NULL, &fl ); cmfdbi(&fl, /* Anything that doesn't match */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); while (1) { /* Parse 0 or more switches */ x = cmfdb(&sw); /* Parse something */ debug(F101,"domydir cmfdb","",x); if (x < 0) return(x); if (cmresult.fcode != _CMKEY) /* Break out if not a switch */ break; c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } k = cmresult.nresult; if (!getval && (cmgkwflgs() & CM_ARG) && k != DIR_TOP && k != DIR_COU) { printf("?This switch requires an argument\n"); return(-9); } switch (k) { case DIR_COU: { dir_cou++; if (getval) { if ((x = cmfld("Variable for result","",&s,NULL)) < 0) return(x); makestr(&cv,s); } break; } case DIR_BRF: verbose = 0; break; case DIR_VRB: verbose = 1; break; #ifdef CK_TTGWSIZ case DIR_PAG: page = 1; break; case DIR_NOP: page = 0; break; #endif /* CK_TTGWSIZ */ case DIR_ISO: engdate = 0; break; case DIR_DAT: engdate = 1; break; case DIR_HDG: heading = 1; break; case DIR_NOH: heading = 0; break; #ifdef UNIXOROSK case DIR_DOT: matchdot = 1; break; case DIR_NOD: matchdot = 0; break; #endif /* UNIXOROSK */ case DIR_ALL: show = 3; cmifn1 |= 1; cmifn2 = 0; goto again; case DIR_DIR: show = 2; cmifn1 |= 1; cmifn2 = 1; goto again; case DIR_FIL: show = 1; cmifn1 &= ~(1); cmifn2 = 0; goto again; case DIR_SRT: x = DIRS_NM; if (c == ':' || c == '=') if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0) return(x); xsort = 1; sortby = x; break; case DIR_BUP: backup = 1; fs++; break; case DIR_NOB: backup = 0; fs++; break; case DIR_NOS: xsort = 0; break; case DIR_ASC: reverse = 0; break; case DIR_DSC: reverse = 1; break; #ifdef RECURSIVE case DIR_REC: recursive = 1; diractive = 1; break; case DIR_NOR: recursive = 0; diractive = 0; break; #endif /* RECURSIVE */ case DIR_TYP: xfermod = 1; break; case DIR_NOT: xfermod = 0; break; #ifdef CKSYMLINK case DIR_LNK: /* Follow links */ #ifdef COMMENT /* A command switch shouldn't be setting a global value! */ nolinks = 0; #endif /* COMMENT */ cmifn1 &= ~(2); dontfollowlinks = 0; goto again; case DIR_NLK: /* Don't follow links */ #ifdef COMMENT nolinks = 2; #endif /* COMMENT */ cmifn1 &= ~(2); dontfollowlinks = 1; goto again; case DIR_NOL: /* Don't show links at all */ dontshowlinks = 1; goto again; #endif /* CKSYMLINK */ case DIR_NOM: msg = 0; break; case DIR_MSG: if (c == ':' || c == '=') if ((x = cmfld("Message to append to each line", "", &s, xxstring )) < 0) return(x); msg = 1; ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ); break; case DIR_SMA: case DIR_LAR: { CK_OFF_T y; if (!getval) break; if ((x = cmnumw("File size in bytes","0",10,&y,xxstring)) < 0) return(x); fs++; show = 1; switch (cmresult.nresult) { case DIR_SMA: minsize = y; break; case DIR_LAR: maxsize = y; break; } break; } case DIR_TOP: dir_top = 10; if (!getval) break; if ((x = cmnum("How many lines to show","10",10,&y,xxstring))< 0) return(x); dir_top = y; break; #ifndef NOSPL case DIR_ARR: if (c != ':' && c != '=') { printf("?Array name required\n"); return(-9); } if ((x = cmfld("Array name (a single letter will do)", "", &s, NULL )) < 0) { if (x == -3) { printf("?Array name required\n"); return(-9); } else return(x); } if (!*s) { printf("?Array name required\n"); return(-9); } s2 = s; if (*s == CMDQ) s++; if (*s == '&') s++; if (!isalpha(*s)) { printf("?Bad array name - \"%s\"\n",s2); return(-9); } array = *s++; if (isupper(array)) array = tolower(array); if (*s && (*s != '[' || *(s+1) != ']')) { printf("?Bad array name - \"%s\"\n",s2); return(-9); } break; #endif /* NOSPL */ case DIR_AFT: case DIR_BEF: case DIR_NAF: case DIR_NBF: if (!getval) break; if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) { if (x == -3) { printf("?Date-time required\n"); rc = -9; } else rc = x; goto xdomydir; } fs++; switch (k) { case DIR_AFT: makestr(&dir_aft,s); break; case DIR_BEF: makestr(&dir_bef,s); break; case DIR_NAF: makestr(&dir_naf,s); break; case DIR_NBF: makestr(&dir_nbf,s); break; } break; case DIR_EXC: if (!getval) break; if ((x = cmfld("Pattern","",&s,xxstring)) < 0) { if (x == -3) { printf("?Pattern required\n"); rc = -9; } else rc = x; goto xdomydir; } fs++; makestr(&dir_exc,s); break; case DIR_SUM: summary = 1; break; case DIR_BIN: { extern struct keytab txtbin[]; extern int xfiletype; if (!getval) break; if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0) { rc = x; goto xdomydir; } if (x == 2) { xfiletype = -1; } else { xfiletype = x; fs = 1; } break; } case DIR_OUT: if ((x = cmofi("File for directory listing","",&s,xxstring)) < 0) return(x); ckstrncpy(outfile,s,CKMAXPATH+1); break; case DIR_SIM: /* TOUCH or CHANGE /SIMULATE */ simulate = 1; break; case 7777: /* CASE: (CHANGE only) */ if (change) { if ((x = cmkey(onoff,2,"","on",xxstring)) < 0) return(x); chcase = x; } break; case DIR_MOD: /* TOUCH or CHANGE /MODTIME: */ if (change) { if ((x = cmkey(chmttab,nchmttab,"","update",xxstring)) < 0) return(x); chmtopt = x; break; } if ((x = cmdate("File modification date-time", "now",&s,0,xxstring)) < 0) return(x); ckstrncpy(modtime,brstrip(s),100); break; case DIR_DES: /* CHANGE /DESTINATION:dirname */ case DIR_BAK: /* CHANGE /BACKUP:dirname */ if (change) { int x; char * whatdir = chgdestdir; char * hmsg = "Directory for changed files"; if (k == DIR_BAK) { hmsg = "Directory for backing up original files"; whatdir = chgbackupdir; } x = cmdir(hmsg,"",&s,xxstring); if (x < 0) { if (x == -3) { printf("?Parse error\n"); return(-9); } return(x); } x = isdir(s); /* this is overkill but... */ if (x < 0) { if (x == -3) { printf("?Directory name required\n"); return(-9); } return(x); } ckstrncpy(whatdir,s,CKMAXPATH); if (!isdir(whatdir)) { /* Double overkill */ printf("?%s is not a directory name\n",whatdir); return(-9); } switch (k) { case DIR_DES: /* DESTINATION switch given */ changeinplace = 0; /* Making new files */ break; case DIR_BAK: /* BACKUP switch given */ changebackup = 1; /* Backup up original files */ break; } } break; default: printf("?Sorry, not implemented yet - \"%s\"\n", atmbuf); goto xdomydir; } } ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Safe copy of filespec */ /* ^^^ START MULTIPLE */ while (!touch && !change) { /* Multiple filespecs only for DIR */ x = cmfld("Another filespec or Enter","",&s,xxstring); if (x == -3) break; if (x < 0) return(x); ckstrncat(line,",",LINBUFSIZ); ckstrncat(line,s,LINBUFSIZ); multiple++; } ckmakmsg(tmpbuf,TMPBUFSIZ,"{",line,"}",NULL); ckstrncpy(line,tmpbuf,LINBUFSIZ); cmresult.nresult = 1; cmresult.fcode = _CMIFI; /* ^^^ END MULTIPLE */ ckstrncpy(name,line,CKMAXPATH); if (change) { /* Finish parsing CHANGE command */ debug(F110,"CHANGE source file",line,0); x = cmfld("Text to be changed","",&s,xxstring); if (x < 0) { if (x == -3) { printf("?You must specify the text to be changed\n"); return(-9); } else { return(x); } } s = brstrip(s); s1len = ckstrncpy(string1,s,1024); debug(F110,"CHANGE string1",string1,0); x = cmfld("Text to change it to","",&s2,xxstring); if (x < 0 && x != -3) return(x); s2 = brstrip(s2); s2len = ckstrncpy(string2,s2,1024); debug(F110,"CHANGE string2",string2,0); } if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); /* Command is TOUCH and file doesn't exist. */ if (touch) { /* TOUCH */ s = line; /* fdc - 5 October 2022 */ if ((cmresult.fcode == _CMIFI && zchki(s) == (CK_OFF_T)-1)) { FILE * fp; s = brstrip(s); if (!iswild(s)) { /* Given date-time, if any, else current date-time */ dstr = ckcvtdate(modtime[0] ? modtime : "",0); xxstruct.date.val = dstr; xxstruct.date.len = (int)strlen(xxstruct.date.val); xxstruct.lprotect.len = 0; xxstruct.gprotect.len = 0; #ifdef UNIX if (s[0] == '~') s = tilde_expand(s); #endif /* UNIX */ /* the IF condition was added 2013-04-15 */ if (zchki(s) < 0) { /* If file doesn't already exist... */ fp = fopen(s,"w"); /* Create it */ if (!fp) { printf("?TOUCH %s: %s\n",s,ck_errstr()); rc = -9; goto xdomydir; } fclose(fp); } debug(F110,"TOUCH CREATE NONEXISTENT",s,0); if (zstime(s,&xxstruct,0) < 0) { debug(F110,"TOUCH ZSTIME FAILED",s,0); printf("?TOUCH %s: %s\n",name,ck_errstr()); rc = -9; goto xdomydir; } debug(F110,"TOUCH ZSTIME OK",xxstruct.date.val,0); multiple++; /* Force new directory scan */ } } } else if (cmresult.fcode != _CMIFI) { /* Nothing matched */ /* Note - this never gets executed because after the "begin multiple" hack above, the result is always _CMIFI). */ char * m; if (*s == '/') #ifdef UNIXOROSK m = "does not match switch or name of accessible file"; #else #ifdef OS2 m = "does not match switch or name of accessible file"; #else m = "no switches match"; #endif /* OS2 */ #endif /* UNIXOROSX */ else m = "not found or not accessible"; printf("\"%s\" - %s\n",s,m); rc = -9; goto xdomydir; } #ifdef COMMENT /* This can't be right because it's based on _CMCFM */ wild = cmresult.nresult; /* Wildcard was given? */ debug(F111,"domydir cmifi2",s,wild); #else wild = 0; #endif /* COMMENT */ debug(F111,"domydir cmifi2",s,wild); if (outfile[0]) { /* If an output file was specified */ ofp = fopen(outfile,"w"); /* open it */ if (!ofp) { printf("?Can't open output file %s: %s\n",outfile,ck_errstr()); ofp = stdout; return(-9); } page = 0; } #ifdef OS2 if (!wild) { if (zchki(s) == -2) { /* Found a directory */ p = s + (int)strlen(s) - 1; /* Yes */ if (*p == '\\' || *p == '/') strcat(s, "*"); else if (*p == ':') strcat(s, "./*"); else strcat(s, "/*"); wild = 1; /* Now it's wild */ } } #else if (!wild) if (isdir(s)) { /* Is it a directory? */ p = s + (int)strlen(s) - 1; /* Yes */ #ifdef VMS { /* Convert from FOO.DIR;1 to [x.FOO] if necessary */ char buf[CKMAXPATH+1]; debug(F000,"domydir directory 0",s,*p); if (cvtdir(s,buf,CKMAXPATH) > 0) ckstrncpy(line,buf,LINBUFSIZ); } #endif /* VMS */ debug(F000,"domydir directory 1",s,*p); #ifdef VMS if (*p == ']' || *p == '>' || *p == ':') strcat(s, "*.*"); #else #ifdef datageneral if (*p == ':') strcat(s, "+"); else strcat(s, ":+"); #else #ifdef STRATUS if (*p == '>') strcat(s, "*"); else strcat(s, ">*"); #endif /* STRATUS */ #endif /* datageneral */ #endif /* VMS */ wild = 1; /* Now it's wild */ debug(F000,"domydir directory 2",s,*p); } #endif /* OS2 */ #ifdef ZXREWIND /* cmifi() already called nzxpand so we can just re-use the same list. */ if (!multiple) { x = zxrewind(); /* Rewind the list */ debug(F111,"domydir zxrewind",s,x); } else { #endif /* ZXREWIND */ /* In case we gave multiple filespecs they are now in {a,b,c} list format. Which is a valid wildcard. We pass it to nzxpand() to get back the list of files that match. This is fine for DIRECTORY but it's not fine for TOUCH because we want TOUCH to see those names so it can create the files. So for now at least, if TOUCH is to be used to create files -- as opposed to changing the timestamps of existing files -- it can only do one file at a time. */ if (!touch && !change) s = name; /* fdc - 5 October 2022 */ nzxopts = (show == ZX_DIRONLY) ? ZX_DIRONLY : (show == ZX_FILONLY ? ZX_FILONLY : 0); if (matchdot) nzxopts |= ZX_MATCHDOT; if (recursive) nzxopts |= ZX_RECURSE; x = nzxpand(s,nzxopts); /* Expand file list */ debug(F111,"domydir nzxpand",s,x); debug(F111,"999 domydir nzxpand result",s,x); #ifdef ZXREWIND } #endif /* ZXREWIND */ #ifndef NOSPL if (array) { int n, xx; n = (x < 0) ? 0 : x; if ((xx = dclarray(array,n)) < 0) { printf("?Array declaration failure\n"); rc = -9; goto xdomydir; } arrayindex = xx; ap = a_ptr[xx]; /* Pointer to list of elements */ if (ap) /* Set element 0 to dimension */ makestr(&(ap[0]),"0"); /* which so far is zero */ if (n < 1) { /* No files matched, done. */ rc = 0; goto xdomydir; } } else #endif /* NOSPL */ if (!touch && x < 1) { #ifdef CKROOT extern int ckrooterr; if (ckrooterr) printf("?Off limits: %s\n",s); else #endif /* CKROOT */ if (x == 0 && isdir(s)) printf("?Empty directory - \"%s\"\n", s); else printf("?%s %s match - \"%s\"\n", (x == 0) ? "No" : "Too many", (show == 2) ? "directories" : "files", brstrip(s) ); rc = -9; goto xdomydir; } nx = x; /* Remember how many files */ reallysort = xsort; if (nx < 2) reallysort = 0; /* Skip sorting if none or one */ xsort = 1; /* 2013-12-06 but do everything else */ if (msg) { makestr(&dirmsg,tmpbuf); dirmsglen = strlen(tmpbuf); } #ifdef VMS cdp = zgtdir(); /* Get current directory */ debug(F110,"domydir VMS zgtdir",cdp,0); #endif /* VMS */ if (xsort && verbose) { /* If sorting, allocate space */ if (!(dirlist = (char **) malloc((x + 1) * sizeof(char **)))) { if (!quiet) { printf("* Warning: Failure to allocate memory for sorting.\n"); printf("* Will proceed without sorting...\n"); } xsort = 0; } debug(F101,"domydir sort malloc","",xsort); } /* Display the listing */ #ifndef NOSPL if (array) /* Storing instead of printing */ heading = 0; #endif /* NOSPL */ if (heading) { /* If /HEADING print heading */ zfnqfp(s,TMPBUFSIZ,tmpbuf); fprintf(ofp,"\nDirectory of %s\n\n",tmpbuf); n += 3; } if (page > -1) /* Paging */ xaskmore = page; if (dir_exc) /* Have exception list? */ makelist(dir_exc,xlist,16); /* Yes, convert to array */ if (!verbose && !touch && !change) { /* /BRIEF */ if (outfile[0]) { /* To file */ int k = 0; znext(name); while (name[0]) { /* One line per file */ k++; if (fs) if (fileselect(name, dir_aft,dir_bef,dir_naf,dir_nbf, minsize,maxsize,!backup,16,xlist) < 1) { znext(name); continue; } fprintf(ofp,"%s\n",name); znext(name); } if (heading) fprintf(ofp,"Files: %d\n\n",k); rc = 1; goto xdomydir; } else { rc = xfilhelp(x,"","",n,0,1, dir_aft,dir_bef,dir_naf,dir_nbf, minsize,maxsize,!backup,16,xlist); if (rc < 0) goto xdomydir; if (heading && rc > 0) fprintf(ofp,"Files: %d\n\n",x); /* (Might scroll a line or 2) */ rc = 1; goto xdomydir; } } ndirs = nfiles = 0L; /* Initialize counters */ nbytes = (CK_OFF_T)0; if (change) { /* CHANGE - check for conflicts */ struct zfnfp * fp; char dbuf[CKMAXPATH+1]; char bbuf[CKMAXPATH+1]; fp = zfnqfp(name,TMPBUFSIZ,chgsourcedir); /* Source directory path */ if (fp) { chgsourcedir[fp->fname - fp->fpath] = NUL; debug(F110,"CHANGE source directory",chgsourcedir,0); if (chgdestdir[0]) { debug(F110,"CHANGE destination directory",chgdestdir,0); zfnqfp(chgdestdir,TMPBUFSIZ,dbuf); debug(F110,"CHANGE destination directory",dbuf,0); if (!strcmp(dbuf,chgsourcedir)) { printf( "?Destination and source directories are the same\n"); success = 0; goto xdomydir; } } if (chgbackupdir[0]) { debug(F110,"CHANGE backup directory",chgbackupdir,0); zfnqfp(chgbackupdir,TMPBUFSIZ,bbuf); debug(F110,"CHANGE backup directory",bbuf,0); if (!strcmp(bbuf,chgsourcedir)) { printf("?Backup and source directories are the same\n"); success = 0; goto xdomydir; } } if (chgbackupdir[0] && chgdestdir[0]) { if (!strcmp(bbuf,dbuf)) { printf( "?Backup and destination directories are the same\n"); success = 0; goto xdomydir; } } } } diractive = 1; /* DIRECTORY command is active */ znext(name); /* Get next file */ while (name[0]) { /* Loop for each file */ if (fs) if (fileselect(name, dir_aft,dir_bef,dir_naf,dir_nbf, minsize,maxsize,!backup,16,xlist) < 1) { znext(name); continue; } len = zgetfs(name); /* Get file length */ debug(F111,"domydir loop zgetfs",name,len); #ifdef VMSORUNIX itsadir = zgfs_dir; /* See if it's a directory */ #else itsadir = (len == (CK_OFF_T)-2 || isdir(name)); #endif /* VMSOUNIX */ debug(F111,"domydir itsadir",name,itsadir); changes = 0; if ((itsadir && (show == 1)) || (!itsadir && (show == 2))) { znext(name); continue; } /* Get here when we know we have selected this file */ nmatches++; if (itsadir) { /* Accumulate totals for summary */ ndirs++; } else { nfiles++; nbytes += len; } dstr = NULL; /* File date-time string */ /* BEGIN CHANGE command */ if (cx == XXCHG) { /* Command was CHANGE, not DIRECTORY */ FILE * ifp = NULL; /* Input file pointer */ FILE * ofp = NULL; /* Output (temporary) file pointer */ FILE * bfp = NULL; /* Backup file pointer */ char backupfile[CKMAXPATH+1]; /* Backup file */ char tmpfile[CKMAXPATH]; /* Buffer for filename */ int linebufsiz = 24575; /* Buf size for reading file lines */ char * linebuf = NULL; /* Input file buffer */ char * lbp = NULL; /* and pointer to it */ char * newbuf = NULL; /* Output file buffer */ char * nbp = NULL; /* and pointer */ int bufleft = 0; /* Space left in newbuf */ int j, k, x; /* Workers */ int failed = 0; /* Search string not found */ changes = 0; /* Change counter */ k = 0; x = scanfile(name,NULL,nscanfile) ; debug(F111,"domydir CHANGE scanfile",name,x); switch (x) { /* Is it a text file? */ case FT_7BIT: k++; break; case FT_UTF8: k++; break; case FT_UCS2: k++; break; case FT_8BIT: k++; break; case FT_TEXT: k++; break; } if (!k) { if (verbose) printf("%s: Skipped (not a text file)\n", name); znext(name); continue; } debug(F101,"CHANGE changeinplace","",changeinplace); if (changeinplace) { /* CHANGing in place? */ int x = 0; if (!tempdir) { /* Need a temporary directory */ x++; } else if (!*tempdir) { x++; } /* It might make more sense to fall back on the current directory, or the directory specified in the filespec, because that one has to be writeable or the files could not be changed. */ if (x) { printf( "?Temporary directory not defined, use SET TEMP-DIRECTORY to define one.\n" ); success = 0; goto xdomydir; } ckstrncpy(tmpfile,tempdir,CKMAXPATH); /* Temp directory */ ckstrncat(tmpfile,"__x",CKMAXPATH); /* Temp filespec */ if (simulate) { /* Too much */ /* printf("Would create temp file %s\n",tmpfile); */ } else { ofp = fopen(tmpfile,"w"); /* Open temporary file */ debug(F110,"CHANGE in place tmpfile",tmpfile,0); if (!ofp) { printf("?Can't open temporary file %s: %s\n", tmpfile,ck_errstr()); success = 0; goto xdomydir; } } } else { /* Making a new copy of the file */ char * p = name, * p2 = NULL; debug(F110,"CHANGE chgdestdir",chgdestdir,0); ckstrncpy(tmpfile,chgdestdir,CKMAXPATH); debug(F110,"CHANGE tmpfile",tmpfile,0); while (*p++) { if (ISDIRSEP(*p)) p2 = p; } /* Just the name */ if (!p2) { /* name had no slashes in it */ p2 = name; ckstrncat(tmpfile,STRDIRSEP,CKMAXPATH); } debug(F110,"CHANGE name",p2,0); ckstrncat(tmpfile,p2,CKMAXPATH); debug(F110,"CHANGE final tmpfile",tmpfile,0); if (simulate) { printf("Would create new file %s\n",tmpfile); } else { debug(F110,"CHANGE /dest tmpfile",tmpfile,0); ofp = fopen(tmpfile,"w"); /* Open temporary file */ if (!ofp) { printf("?Can't open destination file %s: %s\n", tmpfile,ck_errstr()); success = 0; goto xdomydir; } } } if (changebackup) { /* Backing up original file? */ char * p = name, * p2 = NULL; ckstrncpy(backupfile,chgbackupdir,CKMAXPATH); debug(F111,"CHANGE backupfile",backupfile,1); while (*p++) { if (ISDIRSEP(*p)) p2 = p; } /* Just the name */ if (!p2) { /* name had no slashes in it */ p2 = name; ckstrncat(backupfile,STRDIRSEP,CKMAXPATH); } debug(F111,"CHANGE backupfile",backupfile,2); ckstrncat(backupfile,p2,CKMAXPATH); debug(F111,"CHANGE backupfile",backupfile,3); if (simulate) { printf("Would back up original file to %s\n", backupfile); } else { bfp = fopen(backupfile,"w"); /* Open temporary file */ if (!bfp) { printf("?Can't open backup file %s: %s\n", backupfile,ck_errstr()); success = 0; goto xdomydir; } } } if ((ifp = fopen(name,"r")) == NULL) { /* Open input file */ printf("?Can't open file %s: %s\n",s,ck_errstr()); fclose(ofp); success = 0; goto xdomydir; } /* Get timestamp of original file */ debug(F101,"CHANGE timestamp changebackup","",changebackup); if (chmtopt == CHMT_P || changebackup) { debug(F110,"CHANGE file timestamp name",name,0); dstr = zfcdat(name); if (!dstr) dstr = ""; if (!*dstr) printf("WARNING: can't get date for %s\n",name); debug(F110,"CHANGE file timestamp dstr",dstr,0); xxstruct.date.val = dstr; /* change file's modtime */ xxstruct.date.len = (int)strlen(xxstruct.date.val); xxstruct.lprotect.len = 0; xxstruct.gprotect.len = 0; } linebuf = (char *) malloc(linebufsiz+1); /* Malloc a line buffer */ if (!linebuf) { printf("?Memory allocation failure\n"); fclose(ofp); fclose(ifp); if (bfp) fclose(bfp); success = 0; goto xdomydir; } newbuf = (char *) malloc(linebufsiz+1); /* Buffer for copy */ if (!newbuf) { free(linebuf); printf("?Memory allocation failure\n"); fclose(ofp); fclose(ifp); if (bfp) fclose(bfp); success = 0; goto xdomydir; } /* Loop through lines of each original file... */ while (fgets(linebuf, linebufsiz, ifp)) { /* Read a line */ if (changebackup && !simulate) { if (fputs(linebuf, bfp) == EOF) { /* Backing up */ printf("?%s: Write failed - %s\n", backupfile,ck_errstr()); failed++; break; } } nbp = newbuf; lbp = linebuf; bufleft = linebufsiz; /* Space left in newbuf */ x = ckindex(string1,lbp,0,0,chcase); if (x == 0) { /* Nothing to replace */ if (!simulate) { if (fputs(lbp, ofp) == EOF) { printf("?%s: Write failed - %s\n", tmpfile,ck_errstr()); failed++; break; } } } else while (1) { /* One or maybe more occurrences */ changes++; /* Count this change */ totalchanges++; /* Increment total changes */ j = x + s2len - 1; /* Size of addition to newbuf */ bufleft -= j; /* Remaining space in newbuf after */ if (bufleft > j) { /* If space enough */ char c; c = lbp[x]; lbp[x] = NUL; /* Terminate for strncpy */ strncpy(nbp,lbp,bufleft); /* Copy this piece */ lbp[x] = c; nbp += (x - 1); /* adjust destination pointer */ strncpy(nbp,string2,bufleft); /* replacement string */ nbp += s2len; /* and adjust destination pointer */ } else { /* Otherwise fail. */ failed++; printf("?%s: Write failed - %s\n",tmpfile,ck_errstr()); break; } lbp += x + s1len - 1; /* Adjust source pointer */ x = ckindex(string1,lbp,0,0,chcase); /* Get next */ if (!x) { /* No more string1's found in this line */ if (!simulate) { /* Write changes */ if (fputs(newbuf, ofp) == EOF) { printf("?%s: Write failed - %s\n", tmpfile,ck_errstr()); failed++; break; } if (*lbp) { /* And write out last chunk if any */ if (fputs(lbp, ofp) == EOF) { printf("?%s: Write failed - %s\n", tmpfile,ck_errstr()); failed++; break; } } } break; } } } fclose(ifp); /* End... close files */ if (!simulate) { if (bfp) fclose(bfp); fclose(ofp); } bfp = ifp = ofp = NULL; free(linebuf); /* and free buffers */ free(newbuf); if (simulate) { /* Simulation run */ if (failed) { printf("Would fail: %s\n",name); } else if (changes) { printf("Would change: %s\n",name); } else if (verbose) { printf("Would not change: %s\n",name); } zdelet(tmpfile); } else if (!failed) { /* Really changing */ char * result = name; if (changes) { /* If changes were made */ if (changeinplace) { /* Changing in place... */ x = zrename(tmpfile,name); /* Replace original file */ if (x < 0) { printf("?Rename temporary file %s to %s failed", tmpfile, name); zdelet(tmpfile); /* delete temporary file */ success = 0; goto xdomydir; } } else { /* Making new file... */ result = tmpfile; } if (chmtopt == CHMT_P) { /* If preserving file dates */ debug(F110,"Setting modtime",result,0); if (zstime(result,&xxstruct,0) < 0) { printf("?Error \ preserving original modtime: %s %s\n", result, ck_errstr() ); rc = -9; goto xdomydir; } } /* Change modtime of backup file unconditionally */ debug(F111,"CHANGE modtime",backupfile,changebackup); if (changebackup) { if (zstime(backupfile,&xxstruct,0) < 0) { printf("?Modtime error on backup file %s: %s\n", backupfile, ck_errstr() ); rc = -9; goto xdomydir; } } if (verbose) printf("Changed %s: %s -> %s\n",result,string1,string2); } else if (changeinplace) { zdelet(tmpfile); /* Delete temporary file */ if (changebackup) zdelet(backupfile); /* and backup */ } } if (znext(name)) /* Get next file */ continue; success = 1; /* If none we're finished */ goto xdomydir; } /* TOUCH command... */ if (cx == XXTOUC) { /* Command was TOUCH, not DIRECTORY */ /* Given date-time, if any, else current date-time */ debug(F110,"TOUCH dstr before",dstr,0); dstr = ckcvtdate(modtime[0] ? modtime : "",0); debug(F110,"TOUCH dstr after",dstr,0); xxstruct.date.val = dstr; xxstruct.date.len = (int)strlen(xxstruct.date.val); xxstruct.lprotect.len = 0; xxstruct.gprotect.len = 0; if (simulate) { printf(" %s (%s)\n",name,dstr); } else { if (zstime(name,&xxstruct,0) < 0) { printf("?TOUCH %s: %s\n",name,ck_errstr()); rc = -9; goto xdomydir; } } if (!verbose || simulate) { /* No listing so just go back */ znext(name); /* and do next file. */ continue; } } if (summary) { /* Summary only, no detail */ znext(name); continue; } /* NOTE: The sprintf's in this routine should be safe. They involve permission strings, date/time strings, and filenames, all of which have known maximum lengths; none of these items is input from users. The destination buffers are large enough to hold maximum sizes for any and all items. NOTE 2: If command was TOUCH, dstr was already set just above. */ if (!dstr) { /* Get file's modification date/time */ dstr = zfcdat(name); debug(F111,"domydir zcfdat",dstr,0); } if (!dstr) dstr = ""; { /* Note that zfcdat() always returns "" or yyyymmdd hh:mm:ss, so any warnings about possible out-of-bounds dstr[] array refs do not apply. This block of code is to stifle the warnings and also allows for any out-of-spec zfcdat() implementations. */ int x; char * p = "00000000 00:00:00"; x = ckstrncpy(xbuf,dstr,32); if (x < 17) ckstrncpy(&xbuf[x],p+x,32-x); dstr = xbuf; } if (engdate) { /* English date requested? */ short month, day, year, hour, minute, seconds; month = (dstr[4]-48)*10 + (dstr[5]-48); mstr = (month > 0 && month <= 12) ? months[month-1] : "xxx"; day = (dstr[6]-48)*10 + (dstr[7]-48); year = (((dstr[0]-48)*10 + (dstr[1]-48))*10 + (dstr[2]-48))*10 + (dstr[3]-48); hour = (dstr[9]-48)*10 + (dstr[10]-48); minute = (dstr[12]-48)*10 + (dstr[13]-48); seconds = (dstr[15]-48)*10 + (dstr[16]-48); sprintf(dbuf, /* SAFE */ "%2d-%s-%4d %02d:%02d:%02d", day,mstr,year,hour,minute,seconds ); dstr = dbuf; } else { /* ISO date */ dbuf[0] = dstr[0]; /* yyyy */ dbuf[1] = dstr[1]; dbuf[2] = dstr[2]; dbuf[3] = dstr[3]; dbuf[4] = '-'; dbuf[5] = dstr[4]; /* mm (numeric) */ dbuf[6] = dstr[5]; dbuf[7] = '-'; dbuf[8] = dstr[6]; /* dd */ dbuf[9] = dstr[7]; strcpy(dbuf+10,dstr+8); /* hh:mm:ss */ dstr = dbuf; } dlen = strlen(dbuf); /* Length of date */ name[CKMAXPATH] = NUL; #ifdef CK_PERMS #ifdef VMSORUNIX p = ziperm(name); /* Get permissions */ debug(F110,"ziperm perms",p,0); #else p = zgperm(name); debug(F110,"zgperm perms",p,0); #endif /* VMSORUNIX */ #else p = NULL; debug(F110,"NULL perms",p,0); #endif /* CK_PERMS */ #ifdef VMS /* Get relative name to save space -- VMS fullnames are long... */ ckstrncpy(name,zrelname(name,cdp),CKMAXPATH); #endif /* VMS */ if (itsadir && len < (CK_OFF_T)0) { /* Directory */ #ifdef VMS sprintf(linebuf,"%-22s%-10s %s %s",p,"",dstr,name); #else if (p) sprintf(linebuf,"%10s%-10s %s %s",p,"",dstr,name); else sprintf(linebuf,"%-10s %s %s", "", dstr, name); #endif /* VMS */ } else { /* Regular file */ #ifdef VMS sprintf(linebuf,"%-22s%10s %s %s", p, ckfstoa(len), dstr, name); #else if (p) sprintf(linebuf,"%10s%10s %s %s", p, ckfstoa(len), dstr, name); else sprintf(linebuf,"%10s %s %s", ckfstoa(len), dstr, name); #endif /* VMS */ } #ifdef UNIX #ifdef CKSYMLINK if (zgfs_link) { /* If it's a symlink */ if (dontshowlinks) { /* If /NOLINKS don't show it */ znext(name); continue; } } if (zgfs_link && !dontfollowlinks) { /* Symlink and following links */ int n, m; /* Show what the link points to */ extern char linkname[]; n = strlen(linebuf); m = strlen(linkname) + n; if (m < CKMAXPATH + 58) strcpy(linebuf+n, " -> "); /* safe (checked) */ if (m + 4 < CKMAXPATH - 58) strcpy(linebuf+n+4, linkname); /* safe (checked) */ } else #endif /* CKSYMLINK */ #endif /* UNIX */ if (xfermod) { /* Show transfer mode */ int x, y; char * s = ""; y = -1; x = scanfile(name,&y,nscanfile); switch (x) { case FT_TEXT: s = " (T)"; break; case FT_7BIT: s = " (T)(7BIT)"; break; case FT_8BIT: s = " (T)(8BIT)"; break; #ifdef UNICODE case FT_UTF8: s = " (T)(UTF8)"; break; case FT_UCS2: s = y ? " (T)(UCS2LE)" : " (T)(UCS2BE)"; break; #endif /* UNICODE */ case FT_BIN: s = " (B)"; break; } if (!*s) { s = binary ? " (B)" : " (T)"; } if (*s) { int n; n = strlen(linebuf); if (n + 4 < CKMAXPATH - 58) strcpy(linebuf+n, s); /* safe (checked) */ } } if (msg && dirmsg) { int n; n = strlen(linebuf); if (n + dirmsglen + 2 < CKMAXPATH) sprintf((char *)(linebuf+n)," %s", dirmsg); /* SAFE */ } if (xsort) { /* Sorting - save line */ i = strlen(linebuf); if ((ndirlist >= nx) || !(dirlist[ndirlist] = (char *)malloc(i+1))) { printf("?Memory allocation error - try /NOSORT\n"); rc = -9; goto xdomydir; } strcpy(dirlist[ndirlist],linebuf); /* safe */ ndirlist++; } znext(name); /* Peek ahead to next file */ if (!xsort) { if (!touch || (touch && verbose)) fprintf(ofp,"%s\n",linebuf); if (page && (name[0] || heading)) { /* If /PAGE */ if (cmd_cols > 0) { int x = strlen(linebuf); int y; y = (x % cmd_cols) ? 1 : 0; n += x / cmd_cols + y; } else { n++; } #ifdef CK_TTGWSIZ if (n > (cmd_rows - 3)) { /* Do more-prompting */ if (!askmore()) { rc = 0; goto xdomydir; } else { n = 0; } } #endif /* CK_TTGWSIZ */ } } } if (xsort) { int namepos; skey = 0; #ifdef VMS namepos = dlen + 35; switch (sortby) { case DIRS_NM: skey = namepos; break; case DIRS_DT: skey = 33; break; case DIRS_SZ: skey = 21; } #else if (p) { namepos = dlen + 24; switch (sortby) { case DIRS_NM: skey = namepos; break; case DIRS_DT: skey = 22; break; case DIRS_SZ: skey = 10; } } else { namepos = dlen + 14; switch (sortby) { case DIRS_NM: skey = namepos; break; case DIRS_DT: skey = 12; break; case DIRS_SZ: skey = 0; } } #endif /* VMS */ if (reallysort) sh_sort(dirlist,NULL,ndirlist,skey,reverse,filecase); if (dir_top > 0 && dir_top < ndirlist) ndirlist = dir_top; for (i = 0; i < ndirlist; i++) { #ifndef NOSPL /* Storing result filenames in an array... */ if (array) { char * name; name = dirlist[i] + namepos; debug(F111,"domydir array",name,nfiles); if (ap) makestr(&(ap[i+1]),name); continue; } #endif /* NOSPL */ /* Printing the result filenames, size, date, etc... */ fprintf(ofp,"%s\n",dirlist[i]); if (page && (i < ndirlist -1 || heading)) { /* If /PAGE */ if (cmd_cols > 0) { int x = strlen(dirlist[i]); int y; y = (x % cmd_cols) ? 1 : 0; n += ((int)strlen(dirlist[i]) / cmd_cols) + y; } else { n++; } #ifdef CK_TTGWSIZ if (n > (cmd_rows - 3)) { /* Do more-prompting */ if (!askmore()) { rc = 0; goto xdomydir; } else { n = 0; } } #endif /* CK_TTGWSIZ */ } } #ifndef NOSPL if (array) { if (ap) makestr(&(ap[0]),ckitoa(ndirlist)); rc = 1; goto xdomydir; } #endif /* NOSPL */ } if (heading || summary) { #ifdef CKFLOAT CKFLOAT gm; #endif /* CKFLOAT */ fprintf(ofp,"\n%ld director%s, %ld file%s, %s byte%s", ndirs, (ndirs == 1) ? "y" : "ies", nfiles, (nfiles == 1) ? "" : "s", ckfstoa(nbytes), (nbytes == 1) ? "" : "s" ); #ifdef CKFLOAT gm = ((CKFLOAT) nbytes ) / 1000000.0; if (gm > 1000.0) fprintf(ofp," (%0.2fGB)",(gm / 1000.0)); else if (gm >= 0.01) fprintf(ofp," (%0.2fMB)",gm); #endif /* CKFLOAD */ fprintf(ofp,"\n\n"); } else if (dir_cou && !cv) { fprintf(ofp,"\n Files: %ld\n\n",nfiles); } xdomydir: #ifndef NOSPL if (dir_cou && cv) { /* /COUNT:var */ int n; n = totalchanges; /* Number of changes for CHANGE */ if (cx != XXCHG) /* Number for files for DIRECTORY */ n = nfiles; addmac(cv,ckitoa(n)); /* set the variable */ makestr(&cv,NULL); /* free this */ } if (ap) { /* If we have a result array */ if (a_dim[arrayindex] > nmatches) /* but it was not filled */ a_dim[arrayindex] = nmatches; /* adjust dimension */ } #endif /* NOSPL */ if (g_matchdot > -1) { matchdot = g_matchdot; /* Restore these... */ g_matchdot = -1; } freedirlist(); if (ofp != stdout) { /* Close any output file */ if (ofp) fclose(ofp); ofp = stdout; } if (rc > 0) success = 1; return(rc); } int #ifdef CK_ANSIC dodir( int cx ) /* Do the DIRECTORY command */ #else dodir(cx) int cx; #endif /* CK_ANSIC */ { #ifdef OS2 return(domydir(cx)); #else /* OS2 */ char *dc , *msg; if (nopush #ifdef DOMYDIR /* Builds that domydir() by default */ || (cx == XXDIR || cx == XXLDIR || cx == XXWDIR || cx == XXHDIR || cx == XXTOUC || cx == XXCHG ) #endif /* DOMYDIR */ ) return(domydir(cx)); /* Built-in directory command */ /* Use the system's directory command. */ msg = (cx == XXLS) ? "Arguments for ls" : "Directory and/or file specification"; if ((x = cmtxt(msg,"",&s,xxstring)) < 0) return(x); ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Copy the filespec */ s = tmpbuf; if ((y = cmcfm()) < 0) return(y); lp = line; if (!(dc = getenv("CK_DIR"))) dc = DIRCMD; ckmakmsg(lp,LINBUFSIZ,dc," ",s,NULL); debug(F110,"DIR",line,0); #ifdef VMS conres(); #endif /* VMS */ x = zshcmd(line); #ifdef VMS concb((char)escape); #endif /* VMS */ return(success = (x < 1) ? 0 : 1); #endif /* OS2 */ } #ifndef NOSERVER #ifndef NOFRILLS /* Do the ENABLE and DISABLE commands */ int #ifdef CK_ANSIC doenable( int y, int x ) #else doenable(y,x) int y, x; #endif /* CK_ANSIC */ { #ifdef CK_LOGIN if (isguest) /* IKSD: Don't let guests */ return(0); /* enable anything that's disabled */ #endif /* CK_LOGIN */ switch (x) { case EN_ALL: en_cwd = en_cpy = en_del = en_dir = en_fin = en_get = y; en_ren = en_sen = en_set = en_spa = en_typ = en_ret = y; if (!inserver) en_who = en_mai = en_pri = y; en_mkd = en_rmd = y; en_xit = y; #ifndef datageneral en_bye = y; #endif /* datageneral */ #ifndef NOPUSH if (!nopush && !inserver) en_hos = y; #endif /* NOPUSH */ #ifndef NOSPL en_asg = en_que = y; #endif /* NOSPL */ break; case EN_BYE: #ifndef datageneral /* In Data General AOS/VS Kermit can't log out its superior process. */ en_bye = y; #endif /* datageneral */ break; case EN_CPY: en_cpy = y; break; case EN_CWD: en_cwd = y; #ifdef IKSD if (inserver && y == 0) { fnrpath = PATH_OFF; fnspath = PATH_OFF; } #endif /* IKSD */ break; case EN_DEL: /* Deleting of files */ en_del = y; break; case EN_DIR: en_dir = y; break; case EN_FIN: en_fin = y; break; case EN_GET: en_get = y; break; #ifndef NOPUSH case EN_HOS: if (!nopush) en_hos = y; break; #endif /* NOPUSH */ case EN_REN: en_ren = y; break; case EN_SEN: en_sen = y; break; case EN_SET: en_set = y; break; case EN_SPA: en_spa = y; break; case EN_TYP: en_typ = y; break; case EN_WHO: en_who = y; break; #ifndef NOSPL case EN_ASG: en_asg = y; break; case EN_QUE: en_que = y; break; #endif /* NOSPL */ case EN_RET: en_del = y; break; case EN_MAI: #ifdef CK_LOGIN if (isguest && y) { printf("?Sorry, not valid for guests\n"); return(-9); } #endif /* CK_LOGIN */ en_mai = y; break; case EN_PRI: #ifdef CK_LOGIN if (isguest && y) { printf("?Sorry, not valid for guests\n"); return(-9); } #endif /* CK_LOGIN */ en_pri = y; break; case EN_MKD: en_mkd = y; break; case EN_RMD: en_rmd = y; break; case EN_XIT: en_xit = y; break; case EN_ENA: if (((y & 1) && !(en_ena & 1)) || ((y & 2) && !(en_ena & 2))) { printf("?Sorry, DISABLE ENABLE can not be undone\n"); return(-9); } else { en_ena = y; break; } default: return(-2); } return(1); } #endif /* NOFRILLS */ #endif /* NOSERVER */ #ifndef NOFRILLS static int del_lis = 0; static int del_dot = 0; static int del_hdg = 0; static int del_pag = -1; static int del_ask = 0; #ifndef NOSHOW VOID showdelopts() { int x = 0; extern int optlines; prtopt(&optlines,""); prtopt(&optlines,"DELETE"); if (del_ask > -1) { prtopt(&optlines, del_ask ? "/ASK" : "/NOASK"); x++; } #ifdef UNIXOROSK if (del_dot > -1) { prtopt(&optlines, del_dot ? "/DOTFILES" : "/NODOTFILES"); x++; } #endif /* UNIXOROSK */ if (del_lis > -1) { prtopt(&optlines, del_lis ? "/LIST" : "/NOLIST"); x++; } if (del_hdg > -1) { prtopt(&optlines, del_hdg ? "/HEADING" : "/NOHEADING"); x++; } #ifndef CK_TTGWSIZ if (del_pag > -1) { prtopt(&optlines, del_pag ? "/PAGE" : "/NOPAGE"); x++; } #endif /* CK_TTGWSIZ */ if (!x) prtopt(&optlines,"(no options set)"); prtopt(&optlines,""); } #endif /* NOSHOW */ int setdelopts() { int x_lis = -1, x_pag = -1, x_dot = -1, x_hdg = -1, x_ask = -1; int getval = 0; char c; while (1) { if ((y = cmswi(deltab,ndeltab,"Switch","",xxstring)) < 0) { if (y == -3) break; else return(y); } c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } switch (y) { case DEL_DOT: x_dot = 1; break; case DEL_NOD: x_dot = 0; break; case DEL_HDG: x_hdg = 1; break; case DEL_LIS: x_lis = 1; break; case DEL_NOL: x_lis = 0; break; #ifndef CK_TTGWSIZ case DEL_PAG: x_pag = 1; break; case DEL_NOP: x_pag = 0; break; #endif /* CK_TTGWSIZ */ case DEL_QUI: x_lis = 0; break; case DEL_VRB: x_lis = 1; break; case DEL_ASK: x_ask = 1; break; case DEL_NAS: x_ask = 0; break; default: printf("?Sorry, this option can not be set\n"); return(-9); } } if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); if (x_pag > -1) del_pag = x_pag; if (x_dot > -1) del_dot = x_dot; if (x_hdg > -1) del_hdg = x_hdg; if (x_lis > -1) del_lis = x_lis; if (x_ask > -1) del_ask = x_ask; return(success = 1); } #ifdef OS2 static char ** xmtchs = NULL; static int xmtchn = 0; #endif /* OS2 */ int dodel() { /* DELETE */ int i, k, x; #ifdef VMS int j; #endif /* VMS */ int fs = 0; /* Need to call fileselect() */ int len = 0; int bad = 0; int getval = 0, asking = 0; int simulate = 0, rc = 0; CK_OFF_T minsize = -1L, maxsize = -1L; int havename = 0, confirmed = 0; int qflag = 0; int summary = 0; int deldirs = 0; int deltree = 0; int itsadir = 0; int argisdir = 0; int xmode = -1, scan = 0, skip = 0; #ifdef COMMENT int pass = 0; #endif /* COMMENT */ char c; char * deldef = ""; char safebuf[CKMAXPATH+1]; struct FDB sw, fi, fl; char * del_aft = NULL, * del_bef = NULL, * del_naf = NULL, * del_nbf = NULL, * del_exc = NULL; int x_lis = 0, /* x_dot = -1, */ x_hdg = 0; char * dxlist[8]; for (i = 0; i < 8; i++) dxlist[i] = NULL; g_matchdot = matchdot; if (del_lis > -1) x_lis = del_lis; if (del_dot > -1) matchdot = del_dot; if (del_hdg > -1) x_hdg = del_hdg; if (del_pag > -1) xaskmore = del_pag; if (del_ask > -1) asking = del_ask; diractive = 1; nolinks = 2; /* By default don't follow links */ cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "File specification;\n or switch", "", /* default */ "", /* addtl string data */ ndeltab, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ deltab, /* Keyword table */ &fi /* Pointer to next FDB */ ); cmfdbi(&fl, /* Anything that doesn't match */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); again: cmfdbi(&fi, /* 2nd FDB - file to delete */ _CMIFI, /* fcode */ "File(s) to delete", /* hlpmsg */ deldef, /* default */ "", /* addtl string data */ nolinks | deldirs, /* 0 = files, 1 = files or dirs */ 0, /* 1 = dirs only */ xxstring, NULL, &fl ); while (!havename && !confirmed) { x = cmfdb(&sw); /* Parse something */ if (x < 0) { /* Error */ if (x == -3) break; if (x == -2 || x == -9) printf("?Does not match switch or filename: \"%s\"\n",atmbuf); return(x); } if (cmresult.fcode != _CMKEY) /* Break out if not a switch */ break; c = cmgbrk(); /* Get break character */ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); rc = -9; goto xdelete; } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); rc = -9; goto xdelete; } switch (k = cmresult.nresult) { case DEL_AFT: case DEL_BEF: case DEL_NAF: case DEL_NBF: if (!getval) break; if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) { if (x == -3) { printf("?Date-time required\n"); x = -9; } else rc = x; goto xdelete; } fs++; deltree = 0; switch (k) { case DEL_AFT: makestr(&del_aft,s); break; case DEL_BEF: makestr(&del_bef,s); break; case DEL_NAF: makestr(&del_naf,s); break; case DEL_NBF: makestr(&del_nbf,s); break; } break; case DEL_DOT: matchdot = 1; break; case DEL_NOD: matchdot = 0; break; case DEL_ALL: fs = 0; #ifdef VMS deldef = "*.*"; /* UNIX, Windows, OS/2 */ #else #ifdef datageneral deldef = "+"; /* AOS/VS */ #else deldef = "*"; /* UNIX, Windows, OS/2, VMS... */ #endif /* datageneral */ #endif /* VMS */ deltree = 1; nolinks = 2; matchdot = 1; recursive = 1; /* Fall through purposely... */ case DEL_DIR: deldirs = 1; goto again; case DEL_EXC: if (!getval) break; if ((x = cmfld("Pattern","",&s,xxstring)) < 0) { if (x == -3) { printf("?Pattern required\n"); x = -9; } else rc = x; goto xdelete; } fs++; deltree = 0; makestr(&del_exc,s); break; case DEL_HDG: x_hdg = 1; break; #ifdef RECURSIVE case DEL_REC: recursive = 1; break; #endif /* RECURSIVE */ case DEL_LIS: x_lis = 1; break; case DEL_SUM: summary = 1; x_lis = 0; x_hdg = 1; break; case DEL_NOL: x_lis = 0; break; #ifndef CK_TTGWSIZ case DEL_PAG: xaskmore = 1; break; case DEL_NOP: xaskmore = 0; break; #endif /* CK_TTGWSIZ */ case DEL_QUI: qflag = 1; x_lis = 0; break; case DEL_VRB: x_lis = 1; break; case DEL_SMA: case DEL_LAR: if (!getval) break; if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0) return(x); fs++; deltree = 0; switch (cmresult.nresult) { case DEL_SMA: minsize = y; break; case DEL_LAR: maxsize = y; break; } break; case DEL_SIM: simulate = 1; x_lis = 1; break; case DEL_ASK: asking = 1; break; case DEL_NAS: asking = 0; break; case DEL_TYP: { extern struct keytab txtbin[]; if (!getval) break; if ((x = cmkey(txtbin,3,"","",xxstring)) < 0) return(x); if (x == 2) { /* ALL */ xmode = -1; } else { /* TEXT or BINARY only */ xmode = x; scan = 1; } break; } default: printf("?Not implemented yet - \"%s\"\n",atmbuf); return(-9); } } if (qflag && (cmresult.fcode == _CMFLD)) { if ((x = cmcfm()) < 0) return(x); else return(success = 0); } if (cmresult.fcode != _CMIFI) { if (*atmbuf) { int x; if (iswild(atmbuf) && nzxpand(atmbuf,nzxopts) == 0) printf("?No files match: %s\n",brstrip(atmbuf)); else if ((x = zchki(atmbuf)) == -1) printf("?File not found: %s\n",brstrip(atmbuf)); else if (x == -2) printf("?Not a regular file: %s\n",atmbuf); else /* printf("?Not a deletable file: %s\n",atmbuf); */ goto tryanyway; } else { printf("?A file specification is required\n"); } return(-9); } tryanyway: ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ); /* Safe copy of filespec */ if (deldirs) { ckstrncpy(safebuf,cmresult.sresult,CKMAXPATH); #ifdef VMSORUNIX len = zgetfs(tmpbuf); /* Is it a directory name? */ argisdir = zgfs_dir; /* Then because of how zxpand() */ if (argisdir && zgfs_link) /* works, we have to add it to */ argisdir = 0; /* the list. */ if (itsadir) len = -2; #else len = zchki(tmpbuf); if (len < 0) argisdir = isdir(tmpbuf); #endif /* VMSORUNIX */ } debug(F110,"DELETE file",tmpbuf,0); if ((x = cmcfm()) < 0) return(x); #ifdef IKSD #ifdef CK_LOGIN if (inserver && isguest) { printf("?Sorry, DELETE unavailable to guests\n"); return(-9); } #endif /* CK_LOGIN */ #endif /* IKSD */ #ifndef OS2ORUNIX if (simulate) { printf("?Sorry, /SIMULATE not implemented on this platform\n"); return(-9); } #endif /* OS2ORUNIX */ #ifdef COMMENT /* (not needed) */ if (!iswild(tmpbuf)) { char *m; errno = 0; x = zchki(tmpbuf); if (x < 0) { switch (x) { case -2: m = "Not a regular file"; break; case -1: m = "File not found or not accessible"; break; default: m = errno ? ck_errstr() : "Can't delete"; } printf("?%s: \"%s\"\n",m,tmpbuf); return(-9); } } #endif /* COMMENT */ makelist(del_exc,dxlist,8); /* tmpbuf[] has the name - now do any needed conversions on it */ #ifdef OS2 { /* Lower level functions change / to \, not good for CMD.EXE. */ char *p = tmpbuf; while (*p) { /* Change them back to \ */ if (*p == '/') *p = '\\'; p++; } } #endif /* OS2 */ #ifdef VMS if (iswild(tmpbuf)) { #ifdef COMMENT /* Does not handle '.' as version separator */ char *p = tmpbuf; x = 0; while (*p) { if (*p == ';') { x = 1; break; } else p++; } if (!x) ckstrncat(tmpbuf,";*",TMPBUFSIZ); #else j = 0; x = 0; /* for end_dot and number of dots */ i = strlen(tmpbuf); if (tmpbuf[i] == ';') { ckstrncat(tmpbuf,"0",TMPBUFSIZ); } else { if (tmpbuf[i--] == '.') j++; for (; i >= 0; i--) { if (tmpbuf[i] == ';' || tmpbuf[i] == ':' || tmpbuf[i] == ']' || tmpbuf[i] == '>') break; else if (tmpbuf[i] == '.') x++; } if (tmpbuf[i] != ';') { /* dot may have been used */ if (j) { /* last char is dot */ if (x) /* second is version separator */ ckstrncat(tmpbuf,"0",TMPBUFSIZ); else /* 'foo.' */ ckstrncat(tmpbuf,";0",TMPBUFSIZ); } else if (x == 1) /* lacking a version separator */ ckstrncat(tmpbuf,";0",TMPBUFSIZ); else if (x == 0) /* x == 2 has a version */ ckstrncat(tmpbuf,".*;0",TMPBUFSIZ); } } #endif /* COMMENT */ } #endif /* VMS */ debug(F110,"dodel tmpbuf",tmpbuf,0); /* Filename */ #ifndef OS2ORUNIX /* No built-in DELETE code... */ /* Construct system command. */ ckmakmsg(line,LINBUFSIZ,DELCMD," ",tmpbuf,NULL); #else #ifdef VMS if (asking) { /* Maybe overwrite in VMS */ if (x_lis) /* if options are needed... */ ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm/log ",tmpbuf,NULL); else ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm ",tmpbuf,NULL); } else if (x_lis) ckmakmsg(line,LINBUFSIZ,DELCMD," /log ",tmpbuf,NULL); conres(); #endif /* VMS */ debug(F110,"dodel line",line,0); #endif /* OS2ORUNIX */ #ifdef MAC success = (zdelet(tmpbuf) == 0); #else /* !MAC ... */ #ifdef OS2ORUNIX { int filespace = 0; int count = 0; int lines = 0; int n = 0; s = tmpbuf; #ifdef CK_TTGWSIZ #ifdef OS2 ttgcwsz(); #else /* OS2 */ /* Check whether window size changed */ if (ttgwsiz() > 0) { if (tt_rows > 0 && tt_cols > 0) { cmd_rows = tt_rows; cmd_cols = tt_cols; } } #endif /* OS2 */ #endif /* CK_TTGWSIZ */ if (x_hdg > 0 && !summary) { printf("Deleting %s...%s\n", s, simulate ? " (SIMULATION)" : ""); n += 2; } #ifdef ZXREWIND z = zxrewind(); /* Rewind file list */ #else if (!deldirs) nzxopts = ZX_FILONLY; if (recursive) nzxopts |= ZX_RECURSE; if (matchdot) nzxopts |= ZX_MATCHDOT; errno = 0; z = nzxpand(s,nzxopts); /* Expand file list */ #endif /* ZXREWIND */ debug(F111,"dodel",s,z); /* If deleting directories, sort in reverse order */ /* so we delete the files first, then the directory. */ #ifdef OS2 /* In K95, we have no mtchs array, nor any control over */ /* the order in which znext() returns filenames, so we */ /* must copy the array and sort it. */ { int i; if (xmtchs) { /* Free previous list in case */ debug(F101,"dodel freeing previous list","",xmtchn); for (i = 0; i < xmtchn; i++) /* it wasn't freed last time. */ if (xmtchs[i]) free(xmtchs[i]); free(xmtchs); } xmtchn = 0; xmtchs = (char **)malloc(z * (sizeof(char **))); /* Make new one */ if (!xmtchs) { printf("?Memory allocation failure\n"); return(-9); } for (i = 0; i < z; i++) { xmtchs[i] = NULL; znext(tmpbuf); if (!*tmpbuf) break; makestr(&(xmtchs[i]),tmpbuf); if (!xmtchs[i]) { printf("?Memory allocation failure\n"); xmtchn = i - 1; rc = -9; goto xdelete; } /* debug(F111,"dodel add",xmtchs[i],i); */ } xmtchn = i; debug(F101,"dodel xmtchn","",xmtchn); sh_sort(xmtchs,NULL,z,0,deldirs,0); } #else #ifdef UNIX sh_sort(mtchs,NULL,z,0,deldirs,filecase); #endif /* UNIX */ #endif /* OS2 */ if (z > 0) { #ifdef OS2 int ix = 0; #endif /* OS2 */ success = 1; if (x_hdg > 0) printf("\n"); while ( #ifdef OS2 ix < xmtchn #else 1 #endif /* OS2 */ ) { /* Loop for all files */ #ifdef OS2 ckstrncpy(tmpbuf,xmtchs[ix++],TMPBUFSIZ); #else znext(tmpbuf); /* Get next file */ #endif /* OS2 */ if (!*tmpbuf) { /* No more */ if (deldirs && recursive && argisdir) { ckstrncpy(tmpbuf,safebuf,TMPBUFSIZ); argisdir = 0; /* (only do this once) */ } else break; } skip = 0; if (!deltree) { if (fs) if (fileselect(tmpbuf, del_aft,del_bef,del_naf,del_nbf, minsize,maxsize,0,8,dxlist) < 1) { skip++; } } if (!skip && scan && itsadir) { skip++; } if (!skip && scan) { switch (scanfile(tmpbuf,&y,nscanfile)) { case FT_BIN: if (xmode != 1) skip++; break; case FT_TEXT: case FT_7BIT: case FT_8BIT: #ifdef UNICODE case FT_UTF8: case FT_UCS2: #endif /* UNICODE */ if (xmode != 0) skip++; } } if (!skip && asking) { int x; ckmakmsg(line,LINBUFSIZ," Delete ",tmpbuf,"? ",NULL); x = getyesno(line,3); switch (x) { case 0: continue; /* no */ case 1: break; /* yes */ case 2: goto xdelete; /* quit */ case 3: asking = 0; break; /* go */ } } #ifdef VMSORUNIX len = zgetfs(tmpbuf); /* Get length and accessibility */ itsadir = zgfs_dir; if (itsadir && zgfs_link) { /* Treat links to directories */ itsadir = 0; /* as regular files */ if (scan) /* But not if /TYPE: was given */ skip++; } if (itsadir) /* (emulate non-Unix code) */ len = -2; #else len = zchki(tmpbuf); /* Get accessibility */ if (len < 0) /* See if it's a directory */ itsadir = isdir(tmpbuf); #endif /* VMSORUNIX */ if (skip) { #ifdef COMMENT /* Too verbose */ if (x_lis > 0) { lines++; printf(" %s (SKIPPED)\n",tmpbuf); #ifdef CK_TTGWSIZ if (++n > cmd_rows - 3) if (!askmore()) { goto xdelete; } else { n = 0; } #endif /* CK_TTGWSIZ */ } #endif /* COMMENT */ continue; } debug(F111,"DELETE len",tmpbuf,len); if (simulate) { filespace += len; count++; if (x_lis > 0) { lines++; printf(" %s (SELECTED)\n",tmpbuf); if (++n > cmd_rows - 3) { int xx; xx = askmore(); if (!xx) goto xdelete; else n = 0; } } } else if (len >= 0 || !itsadir) { /* Regular file */ zdelet(tmpbuf); /* or symlink, etc... */ if (zchki(tmpbuf) < 0) { filespace += len; count++; if (x_lis > 0) { lines++; printf(" %s (OK)\n",tmpbuf); if (++n > cmd_rows - 3) { if (!askmore()) { goto xdelete; } else { n = 0; } } } } else { bad++; success = 0; if (x_lis > 0) { lines++; printf(" %s (FAILED: %s)\n",tmpbuf,ck_errstr()); if (++n > cmd_rows - 3) { if (!askmore()) { goto xdelete; } else { n = 0; } } } } } else if (/* pass > 0 && */ deldirs && itsadir) { /* It's a directory */ if (zrmdir(tmpbuf) > -1) { /* Only works if empty */ count++; if (x_lis > 0) { lines++; printf(" %s (OK)\n",tmpbuf); if (++n > cmd_rows - 3) { if (!askmore()) { goto xdelete; } else { n = 0; } } } } else { success = 0; if (x_lis > 0) { lines++; printf(" %s (FAILED: %s)\n", tmpbuf, ck_errstr()); if (++n > cmd_rows - 3) { if (!askmore()) { goto xdelete; } else { n = 0; } } } } } else if (x_lis > 0) { lines++; if (isdir(tmpbuf)) printf(" %s (FAILED: directory)\n",tmpbuf); else printf(" %s (FAILED: not a regular file)\n",tmpbuf); if (++n > cmd_rows - 3) { if (!askmore()) { goto xdelete; } else { n = 0; } } } } if (x_hdg > 0) { if (lines > 0) printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) { goto xdelete; } else { n = 0; } } printf("%d file%s %sdeleted, %d byte%s %sfreed%s\n", count, count != 1 ? "s" : "", simulate ? "would be " : "", filespace, filespace != 1 ? "s" : "", simulate ? "would be " : "", simulate ? " (maybe)" : "" ); } if (!x_lis && !success && !quiet) { printf("?DELETE failed for %d file%s \ (use DELETE /LIST to see details)\n", bad, bad == 1 ? "" : "s" ); } } else if (x_lis > 0) { if (errno) printf("?%s: %s\n",ck_errstr(), tmpbuf); else printf("?Can't delete: %s\n",tmpbuf); } } #else /* OS2ORUNIX */ #ifndef VMS /* Others - let the system do it. */ xsystem(line); x = nzxpand(tmpbuf,nzxopts); success = (x > 0) ? 0 : 1; if (x_hdg > 0) printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not "); #else if (asking) printf("\n"); x = xsystem(line); /* zshcmd returns 1 for success */ success = (x > 0) ? 1 : 0; if (x_hdg > 0 && !asking) printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not "); concb((char)escape); #endif /* VMS */ #endif /* OS2ORUNIX */ #endif /* MAC */ xdelete: if (g_matchdot > -1) { matchdot = g_matchdot; /* Restore these... */ g_matchdot = -1; } #ifdef OS2 if (xmtchs) { int i; debug(F101,"dodel freeing list","",xmtchn); for (i = 0; i < xmtchn; i++) if (xmtchs[i]) free(xmtchs[i]); free(xmtchs); xmtchs = NULL; xmtchn = 0; } #endif /* OS2 */ debug(F101,"dodel result","",rc); return((rc < 0) ? rc : success); } #endif /* NOFRILLS */ #ifndef NOSPL /* The ELSE command */ _PROTOTYP( VOID pushqcmd, (char *) ); int doelse() { if (!ifcmd[cmdlvl]) { printf("?ELSE doesn't follow IF\n"); return(-2); } #ifdef COMMENT /* Wrong. This prevents IF..ELSE IF...ELSE IF...ELSE IF...ELSE... from working. */ ifcmd[cmdlvl] = 0; #endif /* COMMENT */ if (!iftest[cmdlvl]) { /* If IF was false do ELSE part */ if (maclvl > -1 || tlevel > -1) { /* In macro or command file */ debug(F100,"doelse pushing","",0); #ifndef COMMENT pushcmd(NULL); /* save rest of command. */ #else /* This fixes certain obscure problems */ /* but breaks many other constructions that must work. */ pushqcmd(NULL); #endif /* COMMENT */ } else { /* If interactive, */ cmini(ckxech); /* just start a new command */ printf("\n"); /* (like in MS-DOS Kermit) */ if (pflag) prompt(xxstring); } } else { /* Condition is false */ if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0) return(y); /* Gobble up rest of line */ } return(0); } #endif /* NOSPL */ #ifndef NOSPL int doswitch() { char *lp, *ap; /* Macro argument pointer */ int len = 0, x, y, pp = 0; char brbuf[3]; /* Get variable name */ tmpbuf[0] = NUL; brbuf[0] = '{'; brbuf[1] = '}'; brbuf[2] = NUL; y = cmfld("Variable name","",&s,xxstring); debug(F111,"doswitch cmfld",s,y); if (y < 0) { if (y == -3) /* Because brstrip() writes */ s = brbuf; /* into its argument. */ else return(y); } debug(F110,"doswitch A",s,0); if (!strcmp(s,"(")) { pp++; if ((y = cmfld("Variable name","",&s,xxstring)) < 0) { if (y == -3) s = brbuf; else return(y); debug(F110,"doswitch B",s,0); } } len = ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ); if (tmpbuf[0] == CMDQ) { if (chkvar(s) < 1) { printf("?Variable name required\n"); return(-9); } } if (pp > 0) { /* If open paren given parse closing */ if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0) return(y); if (strcmp(atmbuf,")")) { printf("?Closing parenthesis required\n"); return(-9); } } lp = line; x = ckstrncpy(lp,"_switx ",LINBUFSIZ); /* _switx + space */ lp += x; ap = lp; debug(F010,"SWITCH a",line,0); #ifdef COMMENT x = ckmakmsg(lp,LINBUFSIZ-x,tmpbuf," ",NULL,NULL); /* variable name + SP */ #else { /* variable name + SP */ char * p = tmpbuf; if (len > 0) { if (tmpbuf[0] == '(' && tmpbuf[len-1] == ')') { tmpbuf[len-1] = NUL; p++; } } x = ckmakmsg(lp,LINBUFSIZ-x,"{",brstrip(p),"}"," "); } #endif /* COMMENT */ debug(F010,"SWITCH b",line,0); lp += x; /* Get body */ if ((y = cmtxt("series of cases","",&s,NULL)) < 0) return(y); if ((y = (int)strlen(s)) < 1) return(-2); if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */ ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL); s = tmpbuf; } if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) { printf("?Unbalanced braces\n"); return(0); } debug(F010,"SWITCH c",line,0); x = mlook(mactab,"_switx",nmac); /* Look up SWITCH macro definition */ if (x < 0) { /* Not there? */ addmmac("_switx",sw_def); /* Put it back. */ if ((x = mlook(mactab,"_switx",nmac)) < 0) { /* Look it up again. */ printf("?SWITCH macro definition gone!\n"); /* Shouldn't happen. */ return(success = 0); } } debug(F010,"SWITCH command",line,0); /* Execute the SWITCH macro. */ success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC); debug(F101,"SWITCH status","",success); return(success); } int dofor() { /* The FOR command. */ int i, fx, fy, fz; /* loop variables */ char *ap, *di; /* macro argument pointer */ int pp = 0; /* Paren level */ int mustquote = 0; debug(F100,"dofor entry","",0); for (i = 0; i < 2; i++) { if ((y = cmfld("Variable name","",&s,NULL)) < 0) { if (y == -3) { printf("?Variable name required\n"); return(-9); } else return(y); } if (strcmp(s,"(")) break; pp++; } #ifdef COMMENT if ((y = parsevar(s,&x,&z)) < 0) /* Check variable. */ return(y); #else if (*s == CMDQ) /* If loop variable starts with */ mustquote++; /* backslash, mustquote is > 0. */ #endif /* COMMENT */ debug(F111," dofor loop variable mustquote",s,mustquote); lp = line; /* Build a copy of the command */ ckstrncpy(lp,"_forx ",LINBUFSIZ); lp += (int)strlen(line); /* "_for" macro. */ ap = lp; /* Save pointer to macro args. */ if (*s == CMDQ) s++; /* Skip past backslash if any. */ while ((*lp++ = *s++)) ; /* copy it */ lp--; *lp++ = SP; /* add a space */ if ((y = cmnum("initial value","",10,&fx,xxstring)) < 0) { if (y == -3) return(-2); else return(y); } debug(F101," dofor fx","",fx); s = atmbuf; /* Copy the atom buffer */ if ((int)strlen(s) < 1) goto badfor; /* In edit 192, we change the loop variables to be evaluated at loop entry, not each time through the loop. This was required in order to allow \v(argc) to be used as a loop variable, or in a loop-variable expression. Thus, we can't have FOR loops that modify their own exit conditions by changing the final value or the increment. The problem with \v(argc) was that it is on the macro stack; after entry into the _forx macro, it is at the wrong place. */ sprintf(tmpbuf,"%d",fx); /* (SAFE) Substitute actual value */ s = tmpbuf; while ((*lp++ = *s++)) ; /* (what they actually typed) */ lp--; *lp++ = SP; #ifdef DEBUG *lp = NUL; debug(F110," dofor line A",line,0); #endif /* DEBUG */ if ((y = cmnum("final value","",10,&fy,xxstring)) < 0) { if (y == -3) return(-2); else return(y); } debug(F101," dofor loop exit value","",fy); s = atmbuf; /* Same deal */ if ((int)strlen(s) < 1) goto badfor; sprintf(tmpbuf,"%d",fy); /* SAFE */ s = tmpbuf; while ((*lp++ = *s++)) ; lp--; *lp++ = SP; #ifdef DEBUG *lp = NUL; debug(F110," dofor line B",line,0); #endif /* DEBUG */ x_ifnum = 1; /* Increment or parenthesis */ di = (fx < fy) ? "1" : "-1"; /* Default increment */ debug(F110," dofor default increment",di,0); if ((y = cmnum("increment",di,10,&fz,xxstring)) < 0) { debug(F111," dofor increment parse failed",atmbuf,y); x_ifnum = 0; if (y == -3) { /* Premature termination */ return(-2); } else if (y == -2) { /* Maybe closing paren */ if (!strcmp(atmbuf,")")) { pp--; /* Count it */ s = di; /* supply default interval */ fz = atoi(s); } else /* Not closing paren, invalid */ return(y); } else /* Other error */ return(y); debug(F101," dofor default increment supplied","",fz); } else { /* Number */ x_ifnum = 0; debug(F101," dofor parsed increment ok","",fz); s = atmbuf; /* Use it */ } if ((int)strlen(s) < 1) goto badfor; sprintf(tmpbuf,"%d",fz); /* (SAFE) Same deal */ s = tmpbuf; while ((*lp++ = *s++)) ; lp--; *lp++ = SP; #ifdef DEBUG *lp = NUL; debug(F110," dofor FOR command C",line,0); #endif /* DEBUG */ /* Insert the appropriate comparison operator */ if (fz < 0) *lp++ = '<'; else *lp++ = '>'; *lp++ = SP; #ifdef DEBUG *lp = NUL; debug(F110," dofor FOR command D",line,0); #endif /* DEBUG */ if (pp > 0) { /* If open paren given parse closing */ if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0) return(y); if (strcmp(atmbuf,")")) { printf("?Closing parenthesis required\n"); return(-9); } } if ((y = cmtxt("Command(s) to execute","",&s,NULL)) < 0) return(y); if ((y = (int)strlen(s)) < 1) return(-2); debug(F110," doif FOR body A",s,0); if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */ ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL); s = tmpbuf; } debug(F110," doif FOR body B",s,0); if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) { printf("?Unbalanced braces\n"); return(0); } #ifdef DEBUG *lp = NUL; debug(F110," doif FOR body C",s,0); #endif /* DEBUG */ #ifdef COMMENT /* Too strict */ if (fz == 0) { printf("?Zero increment not allowed\n"); return(0); } #endif /* COMMENT */ /* In C-Kermit 8.0 we allow bare macro names anywhere a numeric-valed variable could appear. But this caused trouble for the FOR loops because the quoting in for_def[] assumed a \%i-style loop variable. We account for this here in the if (mustquote)...else logic by invoking separate FOR macro definitions in the two cases. */ debug(F100," dofor choosing FOR macro definition","",0); if (mustquote) { /* \%i-style loop variable */ debug(F101," dofor choosing _forx because mustquote","",mustquote); x = mlook(mactab,"_forx",nmac); /* Look up FOR macro definition */ if (x < 0) { /* Not there? */ addmmac("_forx",for_def); /* Put it back. */ if ((x = mlook(mactab,"_forx",nmac)) < 0) { /* Look it up again. */ printf("?FOR macro definition gone!\n"); return(success = 0); } debug(F110," dofor loop var is \\%x",for_def[0],0); } } else { /* Loop variable is a macro */ debug(F101," dofor choosing _forz because mustquote","",mustquote); x = mlook(mactab,"_forz",nmac); if (x < 0) { addmmac("_forz",foz_def); if ((x = mlook(mactab,"_forz",nmac)) < 0) { printf("?FOR macro definition gone!\n"); return(success = 0); } } debug(F110," dofor loop var is macro",foz_def[0],0); } debug(F010," dofor final FOR body",line,0); /* Execute the FOR macro. */ debug(F100," dofor done, chaining to dodo()...","",0); return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC)); badfor: printf("?Incomplete FOR command\n"); debug(F100," dofoar parse failure","",0); return(-2); } #endif /* NOSPL */ #ifndef NOSPL /* T O D 2 S E C -- Convert time of day as hh:mm:ss to secs since midnite */ /* Call with a string hh:mm or hh:mm:ss. Returns a 0 to 86400 on success, or a negative number on failure. */ long #ifdef CK_ANSIC tod2sec( char * t ) #else tod2sec(t) char * t; #endif /* CK_ANSIC */ { long t2; long hh = 0L, mm = 0L, ss = 0L; if (!t) t = ""; if (!*t) return(-3L); debug(F110,"tod2sec",t,0); if (isdigit(*t)) /* Get hours from argument */ hh = *t++ - '0'; else return(-1L); if (isdigit(*t)) hh = hh * 10 + *t++ - '0'; #ifdef COMMENT if (hh > 24L) return(-1L); #endif /* COMMENT */ if (*t == ':') t++; else if (!*t) goto xtod2sec; else return(-1L); if (isdigit(*t)) /* Minutes */ mm = *t++ - '0'; else return(-1L); if (isdigit(*t)) mm = mm * 10 + *t++ - '0'; if (mm > 60L) return(-1L); if (*t == ':') t++; else if (!*t) goto xtod2sec; else return(-1L); if (isdigit(*t)) /* Seconds */ ss = *t++ - '0'; else return(-1L); if (isdigit(*t)) ss = ss * 10 + *t++ - '0'; if (ss > 60L) return(-1L); if (*t > 32) /* No trailing junk allowed */ return(-1L); xtod2sec: t2 = hh * 3600L + mm * 60L + ss; /* Seconds since midnight from arg */ debug(F101,"tod2sec t2","",t2); return(t2); } int waitinterval = 1; #ifdef OLDWAIT #undef OLDWAIT #endif /* OLDWAIT */ int kbchar = NUL; int #ifdef CK_ANSIC dopaus( int cx ) #else dopaus(cx) int cx; #endif /* CK_ANSIC */ { long zz; extern int sleepcan; #ifdef OLDWAIT zz = -1L; x_ifnum = 1; /* Turn off internal complaints */ if (cx == XXWAI) y = cmnum("seconds to wait, or time of day hh:mm:ss","1",10,&x,xxstring); else if (cx == XXPAU) y = cmnum("seconds to pause, or time of day hh:mm:ss", "1",10,&x,xxstring); else y = cmnum("milliseconds to sleep, or time of day hh:mm:ss", "100",10,&x,xxstring); x_ifnum = 0; if (y < 0) { if (y == -2) { /* Invalid number or expression */ char *p = tmpbuf; /* Retrieve string from atmbuf */ int n = TMPBUFSIZ; *p = NUL; zzstring(atmbuf,&p,&n); /* Evaluate in case it's a variable */ zz = tod2sec(tmpbuf); /* Convert to secs since midnight */ if (zz < 0L) { printf("?Number, expression, or time of day required\n"); return(-9); } else { char now[32]; /* Current time */ char *p; long tnow; p = now; ztime(&p); tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17); if (zz < tnow) /* User's time before now */ zz += 86400L; /* So make it tomorrow */ zz -= tnow; /* Seconds from now. */ } } else return(y); } if (x < 0) x = 0; switch (cx) { case XXPAU: /* PAUSE */ case XXMSL: /* MSLEEP */ if ((y = cmcfm()) < 0) return(y); break; case XXWAI: /* WAIT */ z = 0; /* Modem signal mask */ while (1) { /* Read zero or more signal names */ y = cmkey(mstab,nms,"modem signal","",xxstring); if (y == -3) break; /* -3 means they typed CR */ if (y < 0) return(y); /* Other negatives are errors */ z |= y; /* OR the bit into the signal mask */ } if ((y = cmcfm()) < 0) return(y); break; default: /* Shouldn't happen */ return(-2); } /* Command is entered, now do it. */ if (zz > -1L) { /* Time of day given? */ x = zz; if (zz != (long) x) { printf( "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n" ); return(-9); } } if (cx == XXMSL) { /* Millisecond sleep */ msleep(zz < 0 ? x : x * 1000); return(success = 1); } if (cx == XXPAU && !sleepcan) { /* SLEEP CANCELLATION is OFF */ sleep(x); return(success = 1); } /* WAIT, or else SLEEP with cancellation allowed... */ do { /* Sleep loop */ int mdmsig; if (sleepcan) { /* Keyboard cancellation allowed? */ if (y = conchk()) { /* Did they type something? */ #ifdef COMMENT while (y--) coninc(0); /* Yes, gobble it all up */ #else /* There is a debate over whether PAUSE should absorb */ /* its cancelling character(s). There are several */ /* reasons why it should gobble at least one character: */ /* (1) MS-DOS Kermit does it */ /* (2) if not, subsequent PAUSE commands will terminate */ /* immediately */ /* (3) if not, subsequent ASK commands will use it as */ /* valid input. If \13, then it will get no input */ /* (4) if not, then the character appears on the command */ /* line after all enclosing macros are complete. */ kbchar = coninc(0); /* Gobble one up */ #endif /* COMMENT */ break; /* And quit PAUSing or WAITing */ } } if (cx == XXWAI) { /* WAIT (z == modem signal mask) */ debug(F101,"WAIT x","",x); if (z > 0) { /* Looking for any modem signals? */ mdmsig = ttgmdm(); /* Yes, get them */ if (mdmsig < 0) /* Failed */ return(success = 0); if ((mdmsig & z) == z) /* Got what we wanted? */ return(success = 1); /* Succeed */ } if (x == 0) /* WAIT 0 and didn't get our signals */ break; } sleep(1); /* No interrupt, sleep one second */ } while (--x > 0); if (cx == XXWAI) /* If WAIT and loop exhausted */ success = (z == 0); /* Fail. */ else /* */ success = (x == 0); /* Set SUCCESS/FAILURE for PAUSE. */ return(success); #else /* New code uses chained FDBs and allows FILE waits... */ char * m = ""; /* Help message */ struct FDB nu, fl; /* Parse function descriptor blocks */ int filewait = 0; int mdmsig = 0, fs = 0; char filedate[32]; kbchar = 0; switch (cx) { case XXWAI: m = "seconds to wait, or time of day hh:mm:ss"; break; case XXPAU: m = "seconds to pause, or time of day hh:mm:ss"; break; case XXMSL: m = "milliseconds to sleep, or time of day hh:mm:ss"; break; } zz = -1L; cmfdbi(&nu, _CMNUM, /* Number */ m, /* Help message */ (cx == XXMSL) ? "100" : "1", /* Default */ "", /* N/A */ 0, /* N/A */ 0, /* N/A */ xxstring, /* Processing function */ NULL, /* N/A */ &fl /* Next */ ); cmfdbi(&fl, /* Time of day */ _CMFLD, /* Field */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, /* processing func */ NULL, /* N/A */ NULL /* No next */ ); x = cmfdb(&nu); /* Parse a number or a field */ if (x < 0) { if (x == -3) x = -2; return(x); } switch (cmresult.fcode) { case _CMNUM: /* Number */ x = cmresult.nresult; break; case _CMFLD: /* Field */ zz = tod2sec(cmresult.sresult); /* Convert to secs since midnight */ if (zz < 0L) { printf("?Number, expression, or time of day required\n"); return(-9); } else { char now[32]; /* Current time */ char *p; long tnow; p = now; ztime(&p); tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17); if (zz < tnow) /* User's time before now */ zz += 86400L; /* So make it tomorrow */ zz -= tnow; /* Seconds from now. */ } } debug(F101,"PAUSE/WAIT/MSLEEP zz","",zz); switch (cx) { case XXPAU: /* PAUSE */ case XXMSL: /* MSLEEP */ if ((y = cmcfm()) < 0) return(y); break; case XXWAI: /* WAIT */ z = 0; /* Modem signal mask */ y = cmkey(waittab,nwaittab,"","",xxstring); if (y < 0) { if (y == -3) { if ((y = cmcfm()) < 0) return(y); break; } else return(y); } if (y == WAIT_FIL) { /* FILE */ int wild = 0; if ((z = cmkey(wfswi,nwfswi,"event","",xxstring)) < 0) return(z); filewait = z; if (filewait == WF_MOD || filewait == WF_DEL) z = cmifi("Filename","",&s,&wild,xxstring); else z = cmfld("Filename","",&s,xxstring); if (z < 0) return(z); if (wild || ((filewait == WF_CRE) && iswild(s))) { printf("?Wildcards not valid here\n"); return(-9); } ckstrncpy(tmpbuf,s,TMPBUFSIZ); if ((z = cmcfm()) < 0) return(z); break; } else if (y != WAIT_MDM) { /* A modem signal */ z |= y; /* OR the bit into the signal mask */ } if (!filewait) { /* Modem signals... */ while (1) { /* Get zero or more signal names */ y = cmkey(mstab,nms,"modem signal","",xxstring); if (y == -3) break; /* -3 means they typed CR */ if (y < 0) return(y); /* Other negatives are errors */ z |= y; /* OR the bit into the signal mask */ } if ((y = cmcfm()) < 0) return(y); break; } default: /* Shouldn't happen */ return(-2); } /* switch (cx) */ /* Command is entered, now do it. */ if (zz > -1L) { /* Time of day given? */ x = zz; if (zz != (long) x) { printf( "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n" ); return(-9); } } if (sleepcan) concb((char)escape); /* Ensure single-char wakeup */ if (cx == XXMSL) { /* Millisecond sleep */ msleep(zz < 0 ? x : x * 1000); return(success = 1); } if (cx == XXPAU && !sleepcan) { /* SLEEP CANCELLATION is OFF */ sleep(x); return(success = 1); } if (filewait) { /* FILE... */ fs = zchki(tmpbuf); /* Check if file exists */ switch (filewait) { case WF_DEL: if (fs == -1) return(success = 1); break; case WF_MOD: if (fs == -1) { printf("?File does not exit: %s\n",tmpbuf); return(-9); } s = zfcdat(tmpbuf); /* Get current modification date */ if (!s) s = ""; if (ckstrncpy(filedate,s,32) != 17) { printf("?Can't get modification time: %s\n",tmpbuf); return(-9); } break; case WF_CRE: if (fs > -1) return(success = 1); break; } } do { /* Polling loop */ if (sleepcan) { /* Keyboard cancellation allowed? */ if ((y = conchk()) > 0) { /* Did they type something? */ kbchar = coninc(0); /* Yes, get first char they typed */ debug(F000,"WAIT kbchar","",kbchar); #ifdef COMMENT while (--y > 0) /* Gobble the rest up */ coninc(0); #endif /* COMMENT */ return(success = 0); /* And quit PAUSing or WAITing */ } } if (filewait == 0) { if (cx == XXWAI) { /* WAIT for modem signals */ if (z != 0) { mdmsig = ttgmdm(); /* Get them. */ debug(F101,"WAIT ttgmdm","",mdmsig); if (mdmsig < 0) /* Failure to get them? */ return(success = 0); /* Fail. */ if ((mdmsig & z) == z) /* Got desired ones? */ return(success = 1); /* Succeed. */ } else if (x == 0) return(success = 0); } } else { /* FILE... */ fs = zchki(tmpbuf); /* Get file status */ if (filewait == WF_MOD) { /* Wait for modification */ if (fs == -1) /* Failure to get status */ return(success = 0); /* so WAIT fails. */ s = zfcdat(tmpbuf); /* Get current modification time */ if (!s) s = ""; /* And compare with the time */ if (strcmp(s,filedate)) /* when the WAIT started */ return(success = 1); } else if (filewait == WF_DEL) { /* Wait for deletion */ if (fs == -1) /* If file doesn't exist, */ return(success = 1); /* succeed. */ } else if (filewait == WF_CRE) { /* Wait for creation */ if (fs != -1) /* If file exists */ return(success = 1); /* succeed. */ } } if (x < 1) /* SLEEP/WAIT/PAUSE 0 */ break; sleep(waitinterval); /* No interrupt, sleep */ x -= waitinterval; /* Deduct sleep time */ } while (x > 0); if (cx == XXWAI) /* WAIT time expired */ success = (z == 0); /* Succeed if no modem signals */ else /* For SLEEP or PAUSE, success */ success = (x == 0); /* depends on whether it was */ return(success); /* interrupted from the keyboard. */ #endif /* OLDWAIT */ } #endif /* NOSPL */ #ifdef OS2ORUNIX _PROTOTYP(int zcmpfn,(char *, char *)); #endif /* OS2ORUNIX */ #ifndef NOFRILLS #ifdef NT int dolink() { /* Parse a file or a directory name */ int x, z, listing = 0, havename = 0, wild = 0, rc = 1; struct FDB sw, fi; cmfdbi(&sw, /* 2nd FDB - optional /PAGE switch */ _CMKEY, /* fcode */ "Filename or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nqvswtab, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ qvswtab, /* Keyword table */ &fi /* Pointer to next FDB */ ); cmfdbi(&fi, /* 1st FDB - file to type */ _CMIFI, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 3, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); while (!havename) { x = cmfdb(&sw); /* Parse something */ if (x < 0) /* Error */ return(x); switch (cmresult.fcode) { case _CMKEY: switch (cmresult.nresult) { case DEL_LIS: case DEL_VRB: listing = 1; break; case DEL_NOL: case DEL_QUI: listing = 0; break; } break; case _CMIFI: s = cmresult.sresult; havename = 1; break; default: return(-2); } } wild = cmresult.nresult; /* Source specification wild? */ ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */ s = line; if (!wild) wild = iswild(line); p = tmpbuf; /* Place for new name */ if ((x = cmofi(wild ? "Target directory" : "New name", "",&s,xxstring)) < 0) { /* Get new name */ if (x == -3) { printf("?%s required\n", wild ? "Target directory" : "New name"); return(-9); } else return(x); } ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */ if ((y = cmcfm()) < 0) return(y); if (!wild) { /* Just one */ if (listing) printf("%s => %s ",line,p); if (zlink(line,p) < 0) { if (listing) printf("(FAILED: %s\n",ck_errstr()); rc = 0; } else { if (listing) printf("(OK)\n"); } return(success = rc); } if (!isdir(p)) { /* Multiple */ printf( /* if target is not a directory */ "?Multiple source files not allowed if target is not a directory.\n"); return(-9); } #ifdef COMMENT else { /* Show full path of target */ char buf[CKMAXPATH]; /* (too much) */ if (zfnqfp(p,CKMAXPATH,buf)) ckstrncpy(tmpbuf,buf,TMPBUFSIZ); } #endif /* COMMENT */ #ifdef VMS conres(); /* Let Ctrl-C work. */ #endif /* VMS */ debug(F110,"dolink line",line,0); #ifdef ZXREWIND z = zxrewind(); /* Rewind file list */ #else z = nzxpand(s,0); /* Expand file list */ #endif /* ZXREWIND */ debug(F111,"dolink p",p,z); #ifdef UNIX if (wild && z > 1) sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */ #endif /* UNIX */ while (z-- > 0) { if (!(z == 0 && !wild)) znext(line); if (!line[0]) break; if (listing) printf("%s => %s ",line,p); if (zlink(line,p) < 0) { if (listing) printf("(FAILED: %s\n",ck_errstr()); rc = 0; } else { if (listing) printf("(OK)\n"); } } #ifdef VMS concb((char)escape); #endif /* VMS */ return(success = rc); } #endif /* NT */ #ifdef ZCOPY int docopy() { int x, listing = 0, nolist = 0, havename = 0, getval; char c; struct FDB sw, fi; int overwrite = OVW_ALWAYS; int targetisdir = 0; int targetlen = 0; int appending = 0; int preserve = 0; int swapping = 0; int fromb64 = 0; int tob64 = 0; int toscreen = 0; int interpret = 0; int wild = 0; int rc = 1; char newname[CKMAXPATH], * nm; nm = newname; cmfdbi(&sw, /* 1st FDB - switches */ _CMKEY, /* fcode */ "Filename or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ ncopytab, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ copytab, /* Keyword table */ &fi /* Pointer to next FDB */ ); cmfdbi(&fi, /* 2nd FDB - file to copy */ _CMIFI, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); while (!havename) { x = cmfdb(&sw); /* Parse something */ if (x < 0) /* Error */ return(x); switch (cmresult.fcode) { case _CMKEY: c = cmgbrk(); /* Get break character */ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); rc = -9; return(rc); } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); rc = -9; return(rc); } switch (cmresult.nresult) { case DEL_LIS: case DEL_VRB: nolist = 0; listing = 1; break; case DEL_NOL: case DEL_QUI: nolist = 1; listing = 0; break; case 999: swapping = 1; break; case 998: appending = 1; break; case 995: preserve = 1; break; case 994: if ((x = cmkey(ovwtab,novwtab, "When to overwrite existing destination file", "",xxstring)) < 0) return(x); overwrite = x; break; #ifndef NOSPL case 997: fromb64 = 1; break; case 996: tob64 = 1; break; #endif /* NOSPL */ #ifdef COPYINTERPRET case 992: interpret = 1; break; #endif /* COPYINTERPRET */ case 993: toscreen = 1; break; } break; case _CMIFI: s = cmresult.sresult; havename = 1; break; default: return(-2); } } wild = cmresult.nresult; ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */ s = line; p = tmpbuf; /* Place for new name */ /* Get destination name */ /* Previously the default in Unix was "." but that was (literally!) self-destructive: it destroyed the source file! - fdc, 20 Sep 2022 */ if (!toscreen) { x = cmofi("destination name and/or directory","",&s,xxstring); if (x < 0) { if (x == -3) { printf("?Name for destination file required\n"); return(-9); } else return(x); } } ckstrncpy(p,s,TMPBUFSIZ); /* Safe copy of destination name */ if ((y = cmcfm()) < 0) return(y); if (appending && swapping) { printf("?Sorry, /APPEND and /SWAP conflict\n"); return(-9); } #ifdef COMMENT /* This unreasonably prevented "COPY /APPEND *.* bigfile" from concatenating a bunch of files into one big file. */ if (appending && wild) { printf("?Sorry, /APPEND can be used only with single files\n"); return(-9); } #endif /* COMMENT */ if (toscreen == 0) { targetisdir = isdir(p); x = strlen(p); if (targetisdir) { #ifdef UNIXOROSK if (p[x-1] != '/') { ckstrncat(p,"/",TMPBUFSIZ); x++; } #else #ifdef OS2 if (p[x-1] != '/') { ckstrncat(p,"/",TMPBUFSIZ); x++; } #else #ifdef STRATUS if (p[x-1] != '>') { ckstrncat(p,">",TMPBUFSIZ); x++; } #else #ifdef datageneral if (p[x-1] != ':') { ckstrncat(p,":",TMPBUFSIZ); x++; } #else if (p[x-1] != '/') { ckstrncat(p,"/",TMPBUFSIZ); x++; } #endif /* datageneral */ #endif /* STRATUS */ #endif /* OS2 */ #endif /* UNIXOROSK */ } targetlen = x; } if (!appending) { /* If /APPEND not given */ if (wild && !targetisdir) { /* No wildcards allowed */ printf( /* if target is not a directory */ "?Multiple source files not allowed if target is not a directory.\n"); return(-9); } } #ifdef VMS conres(); /* Let Ctrl-C work. */ #endif /* VMS */ debug(F110,"docopy line",line,0); debug(F110,"docopy p",p,0); debug(F110,"docopy nm",nm,0); #ifdef ZXREWIND z = zxrewind(); /* Rewind file list */ #else z = nzxpand(s,0); /* Expand file list */ #endif /* ZXREWIND */ #ifdef UNIX if (wild) sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */ #endif /* UNIX */ #ifdef IKSD if (!targetisdir && zchki(p) > -1) { /* Destination file exists? */ if (inserver && (!ENABLED(en_del) #ifdef CK_LOGIN || isguest #endif /* CK_LOGIN */ )) { printf("?Sorry, overwriting existing files is disabled\n"); return(-9); } } #endif /* IKSD */ if (tob64 && fromb64) { /* To and from B64 = no conversion */ tob64 = 0; fromb64 = 0; } debug(F110,"COPY dest",p,0); while (z > 0) { znext(line); if (!line[0]) break; errno = 0; /* Reset errno */ if (targetisdir) { zstrip(line,&nm); ckmakmsg(newname,CKMAXPATH,p,nm,NULL,NULL); nm = newname; } else { nm = p; } if (overwrite) { /* Overwrite checking? */ if (zchki(nm) >= (CK_OFF_T)0) { /* Destination file exists? */ char d1[20], * d2; char * n1, * n2; int i; i = strlen(line); /* Isolate source filename */ for (; i >= 0; i--) { if (ISDIRSEP(line[i])) { n1 = &line[i+1]; break; } } debug(F110,"COPY n1", n1, 0); i = strlen(nm); /* And destination filename */ for (; i >= 0; i--) { if (ISDIRSEP(nm[i])) { n2 = &nm[i+1]; break; } } debug(F110,"COPY n2", n2, 0); if (!strcmp(n1,n2)) { /* Same name? */ if (overwrite == OVW_NEVER) { /* Never overwrite? */ if (listing) /* Skip */ if (listing) printf("%s => %s (SKIPPED)\n",line,nm); continue; } ckstrncpy(d1,zfcdat(line),20); /* Source file timestamp */ d2 = zfcdat(nm); /* Timestamp of dest file */ x = strcmp(d1,d2); /* Compare them */ if (((overwrite == OVW_NEWER) && (x < 0)) || ((overwrite == OVW_OLDER) && (x > 0))) { if (listing) if (listing) printf("%s => %s (SKIPPED)\n",line,nm); continue; } } } } if (listing) printf("%s => %s ",line,nm); /* Straight copy */ if (!swapping && !appending && !fromb64 && !tob64 && !toscreen && !interpret) { debug(F110,"COPY zcopy",line,0); if ((x = zcopy(line,p)) < 0) { /* Let zcopy() do it. */ debug(F111,"COPY not OK",line,x); switch (x) { case -2: if (listing) printf("(FAILED: Not a regular file)\n"); else if (!nolist) printf("?Not a regular file - %s\n",line); rc = 0; break; case -3: if (listing) printf("(FAILED: Not found or not accessible)\n"); else if (!nolist) printf("?Not found or not accessible - %s\n",line); rc = 0; break; case -4: if (listing) printf("(FAILED: Permission denied)\n"); else if (!nolist) printf("?Permission denied - %s\n",line); rc = 0; break; case -5: if (listing) printf("(Source and destination are the same file)\n"); else if (!nolist) printf( "?Source and destination are the same file - %s\n", line ); break; case -6: if (listing) printf("(FAILED: Input/Output error)\n"); else if (!nolist) printf("?Input/Output error - %s\n",line); rc = 0; break; case -7: if (listing) printf("(FAILED: %s - %s)\n",p,ck_errstr()); else if (!nolist) printf("?%s - %s\n",ck_errstr(),p); rc = 0; break; default: if (listing) printf("(FAILED: %s)\n",ck_errstr()); else if (!nolist) printf("?%s\n",ck_errstr()); rc = 0; } } else { /* Regular copy succeeded */ debug(F110,"COPY OK..",newname,0); #ifndef NOXFER if (preserve) { /* Handle /PRESERVE */ char * pstr = ""; /* File permissions string */ struct zattr xx; /* File attribute structure */ extern char * cksysid; initattr(&xx); /* Initialize the struct */ xx.systemid.val = cksysid; /* Set our system ID */ xx.systemid.len = (int)strlen(cksysid); #ifdef CK_PERMS pstr = zgperm(line); /* Get source file's permissions */ #endif /* CK_PERMS */ xx.lprotect.val = pstr; xx.lprotect.len = (int)strlen(pstr); xx.gprotect.len = 0; xx.date.val = zfcdat(line); /* Source file's timestamp */ xx.date.len = (int)strlen(xx.date.val); if (zstime(nm,&xx,0) < 0) { printf("?COPY /PRESERVE %s: %s\n",nm,ck_errstr()); rc = -9; } } #endif /* NOXFER */ if (listing && rc > -1) printf("(OK)\n"); } } else { /* Special options */ int prev, y, x = 0; /* Variables needed for them */ int i, t; char ibuf[100]; char obuf[200]; FILE * in = NULL; FILE * out = NULL; if (toscreen) out = (FILE *)stdout; if ((in = fopen(line,"r")) == NULL) { /* Open input file */ if (listing) printf("(FAILED: %s)\n",ck_errstr()); else if (!nolist) printf("?%s - %s)\n",ck_errstr(),line); rc = 0; continue; } if (toscreen == 0) { if (targetisdir) { /* Target is directory */ char * buf = NULL; /* so append this filename to it */ zstrip(line,&buf); p[targetlen] = NUL; if (buf) ckstrncat(p,buf,TMPBUFSIZ); } #ifdef OS2ORUNIX if (zcmpfn(line,p)) { /* Input and output are same file? */ if (listing) printf("(FAILED: Source and destination identical)\n"); else if (!nolist) printf("?Source and destination identical - %s\n", line); rc = 0; continue; } #endif /* OS2ORUNIX */ } if (toscreen == 0) { if ((out = fopen(p, (appending ? "a" : "w"))) == NULL) { fclose(in); if (listing) printf("(FAILED: %s - %s)\n",p,ck_errstr()); else if (!nolist) printf("?%s - %s\n",p,ck_errstr()); rc = 0; continue; } } #ifndef NOSPL if (tob64) { /* Converting to Base-64 */ debug(F110,"COPY tob64",line,0); while (1) { /* Loop... */ prev = x; if ((x = fread(ibuf,1,54,in)) < 1) { /* EOF */ if (listing) printf("(OK)\n"); break; } if (prev % 3) { if (listing) printf("(FAILED: Phase error at %d)\n",prev); else if (!nolist) printf("?Phase error at %d\n",prev); rc = 0; break; } if (swapping) { if (x & 1) { if (listing) printf("(FAILED: Swap error)\n"); else if (!nolist) printf("?Swap error\n"); rc = 0; break; } for (i = 0; i < x; i+=2) { t = ibuf[i]; ibuf[i] = ibuf[i+1]; ibuf[i+1] = t; } } if ((y = b8tob64(ibuf,x,obuf,180)) < 0) { if (listing) printf("(FAILED: Encoding error)\n"); else if (!nolist) printf("?Encoding error\n"); rc = 0; break; } fprintf(out,"%s\n",obuf); } } else if (fromb64) { /* Converting from Base 64 */ debug(F110,"COPY fromb64",line,0); if (toscreen == 0) { if ((out = fopen(p,appending ? "a" : "w")) == NULL) { fclose(in); if (listing) printf("(FAILED: %s - %s)\n",p,ck_errstr()); else if (!nolist) printf("?%s - %s\n",p,ck_errstr()); rc = 0; continue; } } x = 1; while (x) { x = fread(ibuf,1,80,in); if ((y = b64tob8(ibuf,x,obuf,80)) < 0) { if (listing) printf("(FAILED: Decoding error)\n"); else if (!nolist) printf("?Decoding error\n"); rc = 0; break; } if (swapping) { if (x & 1) { if (listing) printf("(FAILED: Swap error)\n"); else if (!nolist) printf("?Swap error\n"); rc = 0; break; } for (i = 0; i < y; i+=2) { t = obuf[i]; obuf[i] = obuf[i+1]; obuf[i+1] = t; } } if (y > 0) { if (fwrite(obuf,1,y,out) < 1) { if (listing) printf("(FAILED: %s - %s)\n",p,ck_errstr()); else if (!nolist) printf("?%s - %s\n",p,ck_errstr()); rc = 0; break; } } } } else #endif /* NOSPL */ if (swapping) { /* Swapping bytes */ CHAR c[3]; c[2] = NUL; debug(F110,"COPY swapping",line,0); while (1) { x = fread((char *)c,1,2,in); if (x < 1) { if (listing) printf("(OK)\n"); break; } else if (x == 1) { c[1] = c[0]; c[0] = NUL; printf( "(WARNING: Odd byte count)"); if (!listing) printf("\n"); } if (fprintf(out,"%c%c",c[1],c[0]) == EOF) { if (listing) printf("(FAILED: %s - %s)\n",p,ck_errstr()); else if (!nolist) printf("?%s - %s\n",p,ck_errstr()); rc = 0; break; } } } else if (appending) { /* Appending to target file */ char c; debug(F110,"COPY appending",line,0); while (1) { x = fread(&c,1,1,in); if (x < 1) { if (listing) printf("(OK)\n"); break; } if (fwrite(&c,1,1,out) < 1) { if (listing) printf("(FAILED: %s - %s)\n",p,ck_errstr()); else if (!nolist) printf("?%s - %s\n",p,ck_errstr()); rc = 0; break; } } } else if (toscreen || interpret) { /* fdc - 20220920 */ int i; int p = 0; int n = 0; int linebufsize = 2000; char prev = NUL; char *linebuf; linebuf = malloc(linebufsize + 2); /* This is the only portable way I can think of to read a line at a time. getline() isn't portable. It has to be line by line so Kermit backslash escapes aren't broken across lines for COPY /INTERPRET. */ n = 0; while (!feof(in)) { if (fread(&c,1,1,in) < 1) { break; } /* worry about LF vs CRLF... */ if (c == '\013' || c == '\012') { if (p == 0 && c == '\012' && prev == '\013') continue; /* Leftover LF from CRLF */ linebuf[p] = 0; /* Null-terminate the line */ #ifdef COPYINTERPRET /* copy /INTERPRET - fdc 20220920 */ if (interpret) { int zzrc = 0; /* Return code for zzstring */ int tmplen = TMPBUFSIZ; char * newbuf = tmpbuf; /* New string to create */ zzrc = zzstring(linebuf, &newbuf, &tmplen); /* Replace original string */ (void) ckstrncpy(linebuf, tmpbuf, linebufsize); } #endif /* COPYINTERPRET */ n++; if (toscreen) { /* Write this line out to screen */ #ifdef CK_TTGWSIZ if (n > (cmd_rows - 3)) { /* Do more-prompting */ if (!askmore()) { rc = 0; goto xdocopy; } else { n = 0; } } #endif /* CK_TTGWSIZ */ printf("%s\n",linebuf); } else { /* or disk file */ fprintf(out,"%s\n",linebuf); } for (i = 1; i < 100; i++) { /* Clear buffer */ linebuf[i] = NUL; } p = 0; /* Reset buffer pointer */ } else { /* Normal case, accumulate the line */ linebuf[p++] = c; linebuf[p] = NUL; prev = c; if (p > linebufsize) { /* line too long */ rc = -1; break; } } } xdocopy: free(linebuf); } if (!toscreen) if (out) fclose(out); if (in) fclose(in); } #ifdef VMSORUNIX concb((char)escape); #endif /* VMSORUNIX */ } if (rc > -1) success = rc; return(rc); } #endif /* ZCOPY */ #endif /* NOFRILLS */ #ifndef NOCSETS #ifndef NOUNICODE static struct keytab * xfcstab = NULL; /* For RENAME /CONVERT: */ static char cvtbufin[CKMAXPATH+8] = { NUL, NUL }; static char cvtbufout[CKMAXPATH+8] = { NUL, NUL }; static char * pcvtbufin = NULL; static char * pcvtbufout = NULL; static int /* Input function xgnbyte() */ #ifdef CK_ANSIC cvtfnin(void) #else cvtfnin() #endif /* CK_ANSIC */ { CHAR c; c = *pcvtbufin++; return(c ? c : -1); } static int #ifdef CK_ANSIC cvtfnout(char c) /* Output function for xpnbyte() */ #else cvtfnout(c) char c; #endif /* CK_ANSIC */ { if (pcvtbufout - cvtbufout >= CKMAXPATH) return(-1); *pcvtbufout++ = c; *pcvtbufout = NUL; return(1); } /* Convert a string from any charset to any other charset */ char * #ifdef CK_ANSIC cvtstring(char* s,int csin,int csout) #else cvtstring(s,csin,csout) char * s; int csin, csout; #endif { int c; extern CK_OFF_T ffc; ckstrncpy(cvtbufin,s,CKMAXPATH); /* Put it in a public place */ pcvtbufin = cvtbufin; /* with public pointers */ pcvtbufout = cvtbufout; *pcvtbufout = NUL; if (csin == csout) /* If the two sets are the same */ return((char *)cvtbufin); /* don't bother converting */ initxlate(csin,csout); /* Initialize the translator */ while ((c = xgnbyte(FC_UCS2,csin,cvtfnin)) > -1) { /* Loop thru string */ if (xpnbyte(c,TC_UCS2,csout,cvtfnout) < 0) { ffc = (CK_OFF_T)0; return(""); } } /* ffc is touched by xgnbyte() but this is not file transfer */ /* so we have to undo it */ ffc = (CK_OFF_T)0; return((char *)cvtbufout); } #endif /* NOUNICODE */ #endif /* NOCSETS */ #ifndef NORENAME #ifndef NOFRILLS #ifdef ZRENAME /* The RENAME command - expanded and improved in 8.0.212 April 2006 */ static char * ren_sub[4] = { NULL,NULL,NULL,NULL }; /* For RENAME /REPLACE */ int ren_list = 0; /* Default listing action for RENAME */ int ren_coll = RENX_OVWR; /* Default collision action */ int shorename() { char * s; switch (ren_coll) { case RENX_FAIL: s = "fail"; break; case RENX_OVWR: s = "overwrite"; break; case RENX_SKIP: s = "proceed"; break; } printf(" rename collision: %s\n",s); printf(" rename list: %s\n",showoff(ren_list)); return(1); } int setrename() { /* Parse SET RENAME options */ int x, y; if ((x = cmkey(renamset,nrenamset,"","", xxstring)) < 0) return(x); switch (x) { case REN_OVW: /* COLLISION */ if ((x = cmkey(r_collision,nr_collision,"","", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); ren_coll = x; break; case DEL_LIS: /* LIST */ return(seton(&ren_list)); } return(success = 1); } /* Reverse a string - Assumes a single-byte character set */ int #ifdef CK_ANSIC gnirts( char * s1, char * s2, int len ) #else gnirts(s1, s2, len) char * s1, * s2; int len; #endif /* CK_ANSIC */ { int n, m = 0; if (!s1) /* Null source pointer, fail */ return(0); n = (int) strlen(s1); if (n > len-1) /* Source longer than dest, fail */ return(0); s2[n--] = NUL; /* Deposit null byte at end of dest */ for (; n >= 0; n--) { /* Copy the rest backwards */ *s2++ = s1[n]; m++; } return(m); } /* r e n a m e o n e Worker function to rename one file for dorenam() (below). old = name of file or directory to be renamed new = new name (not required for /UPPER, /LOWER, and /REPLACE) replacing = 1 if doing string replacement on the name casing = 1 if converting name to lowercase, 2 if to uppercase all = if doing case conversion on all names, not just monocase ones converting = 1 if converting character sets cset1 = character set to convert from (File Character Set index) cset2 = character set to convert to (ditto, see ck?xla.h) listing = 1 to show results of rename nolist = 1 to be completely silent (don't even print error messages) op = 1 means simulate, 2 means check for collision, 0 means rename size = length of result buffer. collision = action to take if destination file already exists: 0 = fail 1 = overwrite and succeed 2 = skip and succeed Returns: 0: on failure to rename or when a forbidden collision would have occurred. 1: on success (file was renamed or did not need to be renamed). Note: If this code is ever built on any platform that is not Unix, Windows, VMS, or OS/2, this routine might need some adjustment. */ /* Opcodes for op... */ #define REN_OP_SIM 1 /* Simulate */ #define REN_OP_CHK 2 /* Check for collisions */ static int #ifdef CK_ANSIC renameone(char * old, char * new, int replacing, int casing, int all, int converting, int cset1, int cset2, int listing, int nolist, int op, int size, int collision ) #else renameone(old,new, replacing,casing,all,converting,cset1,cset2, listing,nolist,op,size,collision) char * old, * new; int replacing,casing,all,converting,cset1,cset2, listing,nolist,op,size,collision; #endif /* CK_ANSIC */ { char buf[CKMAXPATH]; /* Temporary filename buffer */ char out[CKMAXPATH]; /* Buffer for new name */ char dir[CKMAXPATH]; /* Destination directory */ char pat[CKMAXPATH]; /* Path segment on old filename */ char * destdir; /* Destination directory, if any */ char * srcpath; /* Source path, if any */ int rc = 1, flag = 0, skip = 0; /* Control */ int honorcase = 0, replaced = 0; int anchor = 0; /* 1 = beginning, 2 = end */ int occur = 0; /* Occurrence */ int minus = 0; /* Occurrence is negative */ int allbut = 0; /* Occurrence is "all but" */ int arg2isfile = 0; /* Arg2 ("new") is a filename */ debug(F110,"RENAMEONE old",old,0); debug(F110,"RENAMEONE new",new,0); debug(F110,"RENAMEONE ren_sub[0]",ren_sub[0],0); debug(F110,"RENAMEONE ren_sub[1]",ren_sub[1],0); debug(F110,"RENAMEONE ren_sub[2]",ren_sub[2],0); if (op == REN_OP_SIM && !nolist) /* For convenience */ listing = 1; #ifndef NOSPL honorcase = inpcas[cmdlvl]; /* Inherit SET CASE value */ #else #ifdef UNIX honorcase = 1; #else honorcase = 0; #endif /* UNIX */ #endif /* NOSPL */ if (!old) old = ""; /* In case of bad args */ if (!new) new = ""; if (!*old) return(success = 0); ckstrncpy(out,new,CKMAXPATH); /* So we don't write into */ new = out; /* our argument... */ size = CKMAXPATH; pat[0] = NUL; /* Assume no path in source file.. */ srcpath = pat; { int n; /* If the old name includes a path */ n = (int)strlen(old) - 1; /* put it in a separate place. */ for (; n >= 0; n--) { /* We are renaming the file only. */ if (ISDIRSEP(old[n])) { ckstrncpy(pat,old,CKMAXPATH); pat[n+1] = NUL; old = old+n+1; break; } } } debug(F110,"RENAMEONE old 2",old,0); debug(F110,"RENAMEONE pat 2",pat,0); dir[0] = NUL; /* Assume no destination directory */ destdir = dir; if (*new) { /* If Arg2 given */ if (isdir(new)) { /* If it's a directory */ ckstrncpy(dir,new,CKMAXPATH); /* put it here */ } else { /* otherwise */ arg2isfile++; /* flag that it's a filename */ } } if (!casing && !replacing && !converting) { if (!*new) return(success = 0); if (!arg2isfile) { /* Destination is a directory? */ if (!isdir(old)) { /* and source is not? */ #ifndef VMS int n, x = 0; /* Concatenate them */ if ((n = strlen(new)) > 0) /* so we can check for */ if (ISDIRSEP(new[n-1])) /* collisions. */ x++; ckmakmsg(buf,size,new,x ? "" : "/", old, ""); #else ckmakmsg(buf,size,new, old, NULL, NULL); #endif /* VMS */ debug(F110,"RENAMEONE new new",new,0); new = buf; size = CKMAXPATH; } } } else if (*new) { /* Directory to move file to */ int n, x = 0; /* after changing its name */ if (!isdir(new)) return(success = 0); #ifndef VMS if ((n = strlen(new)) > 0) if (ISDIRSEP(new[n-1])) x++; ckmakmsg(dir,CKMAXPATH,new,x ? "" : "/", "", ""); #else ckstrncpy(dir,new,CKMAXPATH); #endif /* VMS */ } #ifndef NOCSETS #ifndef NOUNICODE if (converting) { new = cvtstring(old,cset1,cset2); } #endif /* NOUNICODE */ #endif /* NOCSETS */ if (replacing) { /* Replacing strings */ int todo = 0; int len0, len1, len2; char c, *p, *s, *bp[3]; bp[0] = old; /* Original name */ bp[1] = ren_sub[0]; /* String to be replaced */ bp[2] = ren_sub[1]; /* What to replace it with */ if (!bp[2]) bp[2] = ""; len0 = (int)strlen(bp[0]); /* length of original filename */ len1 = (int)strlen(bp[1]); /* length of target substring */ len2 = (int)strlen(bp[2]); /* Length of replacement string */ if (ren_sub[2]) { /* Optional options */ p = ren_sub[2]; while ((c = *p++)) { switch (c) { case '^': anchor = 1; occur = 0; minus = 0; allbut = 0; break; case '$': anchor = 2; occur = 0; minus = 0; allbut = 0; break; case 'A': honorcase = 1; minus = 0; allbut = 0; break; case 'a': honorcase = 0; minus = 0; allbut = 0; break; case '-': minus = 1; break; case '~': allbut = 1; break; default: if (isdigit(c)) { occur = c - '0'; if (minus) occur = 0 - occur; anchor = 0; } minus = 0; } } } if (anchor) { /* Anchored replacement... */ y = len0 - len1; if (y > 0) { int x; switch (anchor) { case 1: /* Anchored at beginning */ if (!ckstrcmp(bp[1],bp[0],len1,honorcase)) { x = ckstrncpy(new,bp[2],size); (VOID) ckstrncpy(new+x,bp[0]+len1,size-x); replaced = 1; } break; case 2: /* Anchored at end */ if (!ckstrcmp(bp[1],bp[0]+y,len1,honorcase)) { x = ckstrncpy(new,bp[0],y+1); (VOID) ckstrncpy(new+y,bp[2],size-x); replaced = 1; } break; } } if (!replaced) { ckstrncpy(new,old,size); /* Keep old name */ replaced = 1; } } else { /* Replace all occurrences */ int j, n = 0; /* or a particular occurrence */ int x = 0; char * s0 = NULL, * s1 = NULL, * s2 = NULL; p = new; /* Pointer to new name */ if (occur < 0) { /* nth occurrence from the right */ occur = 0 - occur; s0 = (char *)malloc(len0+1); /* Reverse original string */ if (s0) { (VOID) gnirts(bp[0],s0,len0+1); bp[0] = s0; } else return(0); s1 = (char *)malloc(len1+1); /* Reverse target string */ if (s1) { (VOID) gnirts(bp[1],s1,len1+1); bp[1] = s1; } else return(0); s2 = (char *)malloc(len2+1); /* Reverse replacement string */ if (s2) { (VOID) gnirts(bp[2],s2,len2+1); bp[2] = s2; } else return(0); debug(F111,"RENAMEONE s0",s0,len0); debug(F111,"RENAMEONE s1",s1,len1); debug(F111,"RENAMEONE s2",s2,len2); } s = bp[0]; /* Pointer to old name */ p = new; /* Pointer to new name */ j = len0 - len1 + 1; /* How much to scan */ while (j-- > 0) { /* For each character... */ if (!ckstrcmp(bp[1],s,len1,honorcase)) { /* Match? */ n++; /* Occurrence counter */ todo = (occur == 0) || (!allbut && n == occur) || (allbut && n != occur); if (!todo) { /* Desired occurrence? */ size -= ckstrncpy(p,bp[1],size); /* No... */ p += len1; /* Copy target string */ s += len1; /* instead of replacement string */ continue; } if (len2) { /* If replacement string not empty */ size -= ckstrncpy(p,bp[2],size); /* Copy it */ p += len2; } s += len1; /* Advance source position */ } else { /* No match */ *p++ = *s++; /* just copy this character */ size--; } } while ((*p++ = *s++)); /* Done copy the rest */ replaced = 1; /* Remember we changed the name */ if (s0) { /* Were we doing "all but"? */ debug(F110,"RENAMEONE new1",new,0); x = (int)strlen(new); /* Unreverse the result */ if ((p = (char *)malloc(x+2))) { (VOID) gnirts(new,p,x+2); debug(F110,"RENAMEONE new2",new,0); ckstrncpy(new,p,x+2); free(p); } if (s0) free(s0); /* Free the temporary strings */ if (s1) free(s1); if (s2) free(s2); debug(F110,"RENAMEONE new3",new,0); } } } if (casing) { /* Changing case? */ char c, * t; /* See if mixed case. */ if (!replaced) ckstrncpy(new,old,size); /* Copy old name to new name */ t = new; while ((c = *t++)) { if (islower(c)) flag |= 1; /* Have a lowercase letter */ else if (isupper(c)) flag |= 2; /* Have an uppercase letter */ if (flag == 3) break; /* Have a mixed-case name */ } if (all || flag < 3) { /* Not skipping or not mixed case */ if (casing == 1 && flag != 1) /* Change case to lower */ (VOID) cklower(new); else if (casing == 2 && flag != 2) /* Change case to upper */ (VOID) ckupper(new); } } if (*destdir && !arg2isfile) { /* Moving without renaming */ ckstrncat(srcpath,old,CKMAXPATH); old = srcpath; new = destdir; } else if (*destdir || *srcpath) { /* Were there any pathnames? */ char tmp[CKMAXPATH]; ckmakmsg(tmp,CKMAXPATH,srcpath,old,NULL,NULL); ckstrncpy(old,tmp,CKMAXPATH); if (*destdir) { /* Directory-to-move-to given? */ ckstrncat(destdir,new,CKMAXPATH); new = destdir; } else if (*srcpath && !arg2isfile) { /* Or was there a source path? */ ckstrncat(srcpath,new,CKMAXPATH); new = srcpath; } } skip = 0; /* Can we skip this one? */ #ifdef COMMENT if (casing && !replaced) { skip = (((all == 0) && (flag == 3)) || (flag == casing)) ? 1 : 0; if (!skip && destdir) skip = 0; } #endif /* COMMENT */ if (!skip) { if (!ckstrcmp(old,new,-1,1)) skip = 1; } if (op == 0 && !skip && (collision != RENX_OVWR)) { if (zchki(new) > (CK_OFF_T)-1) { /* New file already exists? */ switch (collision) { /* Yes, take specified action */ case RENX_SKIP: /* Skip this one and proceed */ skip = 2; break; case RENX_FAIL: /* Or fail. */ skip = 3; if (!listing && !nolist) printf("?File already exists: %s\n",new); } } } debug(F110,"RENAMEONE new",new,0); debug(F101,"RENAMEONE flag","",flag); debug(F101,"RENAMEONE skip","",skip); debug(F100,"RENAMEONE ----------------","",0); if (skip == 3) { if (listing) printf("%s => %s (SKIPPED: %s already exists)\n", old,new,new); rc = 0; } else if (skip) { /* Skipping this one */ if (listing) printf("%s => %s (%s)\n", old,new, (skip == 2) ? "COLLISION: SKIPPED" : "SKIPPED"); } else { /* Have to rename this one */ if (op == REN_OP_CHK) { /* Checking for collisions */ return((zchki(new) > (CK_OFF_T)-1) ? 0 : 1 ); } else if (op == REN_OP_SIM) { /* Simulating */ if (listing) printf("%s => %s (SIMULATED)\n",old,new); } else { /* Really renaming */ if (listing) printf("%s => %s ",old,new); if (zrename(old,new) < 0) { rc = 0; if (listing) printf("(FAILED: %s)\n",ck_errstr()); else if (!nolist) printf("?%s\n",ck_errstr()); } else { if (listing) printf("(OK)\n"); } } } return(success = rc); /* Succeeds also if nothing needed to be renamed */ } int dorenam() { #ifndef NOCSETS #ifndef NOUNICODE extern int nfilc; extern struct keytab fcstab[]; extern struct csinfo fcsinfo[]; #endif /* NOUNICODE */ #endif /* NOCSETS */ int cset1 = 0, cset2 = 0; int x, z, fn, listing = 0, havename = 0, wild = 0, rc = 1, noarg = 0; int nolist = 0, all = 0, casing = 0, replacing = 0, getval = 0, sim = 0; int converting = 0, collision = 0; char c; struct FDB sw, fi; collision = ren_coll; /* Inherit SET RENAME COLLISION */ listing = ren_list; /* Inhereit SET RENAME LIST */ if (ren_sub[0]) makestr(&(ren_sub[0]),NULL); if (ren_sub[1]) makestr(&(ren_sub[1]),NULL); if (ren_sub[2]) makestr(&(ren_sub[2]),NULL); line[0] = NUL; tmpbuf[0] = NUL; cmfdbi(&sw, /* 1st FDB - switches */ _CMKEY, /* fcode */ "Filename or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nrenamsw, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ renamsw, /* Keyword table */ &fi /* Pointer to next FDB */ ); cmfdbi(&fi, /* 2nd FDB - file or directory name */ _CMIFI, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 3, /* Flags */ 0, /* 0 = Parse file or directory names */ xxstring, NULL, NULL ); if (cmflgs == 1) { printf("?File or directory name required\n"); return(-9); } while (!havename) { noarg = 0; x = cmfdb(&sw); /* Parse something */ if (x == -3) { /* They hit Enter prematurely */ printf("?Command incomplete\n"); return(-9); } else if (x < 0) { /* Other error */ if (x == -1) return(x); if (iswild(atmbuf) && nzxpand(atmbuf,nzxopts) == 0) printf("?No files match: %s\n",brstrip(atmbuf)); else if (zchki(atmbuf) == -1) printf("?File not found: %s\n",brstrip(atmbuf)); else printf("?Error with switch or filename: %s\n",brstrip(atmbuf)); return(-9); } fn = cmresult.nresult; /* For brevity */ switch (cmresult.fcode) { /* Handle each kind of field */ case _CMKEY: /* Keyword (switch) */ c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } if (!getval && (cmgkwflgs() & CM_ARG)) noarg = 1; /* Remember arg is missing */ switch (cmresult.nresult) { /* Handle the switch */ case DEL_LIS: /* /LIST */ case DEL_VRB: /* /VERBOSE */ listing = 1; break; case DEL_NOL: /* /NOLIST */ case DEL_QUI: /* /QUIET */ nolist = 1; listing = 0; break; case DEL_SIM: /* /SIMULATE */ sim = 1; break; case REN_UPP: /* /UPPER: */ case REN_LOW: /* /LOWER */ all = 1; if (!noarg) { if ((x = cmkey((fn == REN_UPP) ? r_upper : r_lower, 2, "","all",xxstring)) < 0) { if (x == -3) x = 1; else return(x); } all = x; } /* 0 = don't convert; 1 = convert to lower; 2 = to upper */ casing = (fn == REN_UPP) ? 2 : 1; converting = 0; break; case REN_OVW: /* /COLLISION */ if (!noarg) { if ((x = cmkey(r_collision, nr_collision,"","overwrite",xxstring))<0) { if (x == -3) x = RENX_OVWR; else return(x); } collision = x; } break; case REN_RPL: /* /REPLACE: */ if (noarg) { printf("?This switch requires an argument\n"); return(-9); } if ((x = cmfld("String to remove, or {{String1}{String2}}", "",&s,xxstring)) < 0) { if (x == -3) { printf("?Target string required\n"); x = -9; } return(x); } if (s[0]) { if (s[0] == '{' && s[1] == '{') /* Get the list */ makelist(s,ren_sub,3); else makestr(&(ren_sub[0]),s); } converting = 0; break; case REN_SPA: /* /FIXSPACES: */ if (!noarg) { if ((x = cmfld("Character or string to replace spaces with", "_",&s,xxstring)) < 0) { if (x == -3) { s = "_"; } else { return(x); } } } makestr(&(ren_sub[0])," "); makestr(&(ren_sub[1]),noarg ? "_" : brstrip(s)); makestr(&(ren_sub[3]),NULL); converting = 0; break; #ifndef NOCSETS #ifndef NOUNICODE case REN_XLA: /* /CONVERT:cset1:cset2 */ if (!xfcstab) { /* Make a copy of the file charset */ int i, x; /* table with CM_ARG set for each */ x = (nfilc + 1) * sizeof(struct keytab); xfcstab = (struct keytab *)malloc(x); if (!xfcstab) { printf("?Memory allocation failure\n"); return(-9); } for (i = 0; i < nfilc; i++) { xfcstab[i].kwd = fcstab[i].kwd; xfcstab[i].kwval = fcstab[i].kwval; xfcstab[i].flgs = fcstab[i].flgs | CM_ARG; } } if ((x = cmswi(xfcstab,nfilc, "Character-set of old name","",xxstring)) < 0) { if (x == -3) { printf("?Pair of character-set names required\n"); return(-9); } else return(x); } cset1 = x; c = cmgbrk(); if (!getval) { printf("?Secondcharacter-set name required\n"); return(-9); } if ((x = cmkey(fcstab,nfilc, "Character-set of new name","",xxstring)) < 0) { if (x == -3) { printf("?Second character-set name required\n"); return(-9); } else return(x); } cset2 = x; if (casing) casing = 0; if (ren_sub[0]) makestr(&(ren_sub[0]),NULL); if (ren_sub[1]) makestr(&(ren_sub[1]),NULL); if (ren_sub[2]) makestr(&(ren_sub[2]),NULL); converting = 1; break; #endif /* NOUNICODE */ #endif /* NOCSETS */ } break; case _CMIFI: /* File or directory name */ s = cmresult.sresult; havename = 1; break; default: printf("?File or directory name required\n"); return(-9); } } if (havename) { ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of source name */ } else { printf("?Internal error\n"); return(-9); /* Shouldn't happen */ } wild = cmresult.nresult; /* Source specification wild? */ if (!wild) wild = iswild(line); debug(F111,"RENAME WILD",line,wild); p = tmpbuf; /* Place for new name */ p[0] = NUL; replacing = ren_sub[0] ? 1 : 0; #ifdef COMMENT if (!(casing || replacing || converting)) { if ((x = cmofi(wild ? "Target directory" : "New name", "",&s,xxstring)) < 0) { /* Get new name */ if (x == -3) { printf("?%s required\n", wild ? "Target directory" : "New name"); return(-9); } else return(x); } ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */ } #else if ((x = cmofi(wild ? "Target directory" : "New name", "",&s,xxstring)) < 0) { /* Get new name */ if (x == -3) { if (casing || replacing || converting) { s = ""; } else { printf("?%s required\n", wild ? "Target directory" : "New name"); return(-9); } } else return(x); } ckstrncpy(p,s,TMPBUFSIZ); /* Make a safe copy of the new name */ #endif /* COMMENT */ if ((y = cmcfm()) < 0) return(y); /* Confirm the command */ #ifdef COMMENT #ifndef NOUNICODE if (converting) { printf(" From: %s\n",fcsinfo[cset1].keyword); printf(" To: %s\n",fcsinfo[cset2].keyword); } #endif /* NOUNICODE */ if (casing) { printf("CASING: %s\n", (casing == 1) ? "LOWER" : "UPPER"); } if (replacing) { printf("REPLACING: '%s' with '%s'\n", ren_sub[0], ren_sub[1] ? ren_sub[1] : ""); } #endif /* COMMENT */ s = line; if (!wild) /* Just one */ return(success = renameone(s,p, replacing,casing,all,converting,cset1,cset2, listing,nolist,sim,TMPBUFSIZ,collision)); if (!casing && !replacing && !converting) { /* Multiple files */ if (!isdir(p)) { printf( /* if target is not a directory */ "?Multiple source files not allowed if target is not a directory.\n"); return(-9); } } #ifdef COMMENT else { /* Show full path of target */ char buf[CKMAXPATH]; /* (too much) */ if (zfnqfp(p,CKMAXPATH,buf)) ckstrncpy(tmpbuf,buf,TMPBUFSIZ); } #endif /* COMMENT */ #ifdef VMS conres(); /* Let Ctrl-C work. */ #endif /* VMS */ debug(F110,"dorename line",line,0); #ifdef ZXREWIND z = zxrewind(); /* Rewind file list */ #else z = nzxpand(s,0); /* Expand file list */ #endif /* ZXREWIND */ debug(F111,"dorename p",p,z); #ifdef UNIX if (wild && z > 1) sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */ #endif /* UNIX */ /* For /COLLISION:FAIL make a silent pass to see if there would be any */ if (collision == RENX_FAIL) { int n = 0; char line[CKMAXPATH+2]; while (z-- > 0) { if (!(z == 0 && !wild)) znext(line); if (!line[0]) break; if (!renameone((char *)line,p, replacing,casing,all,converting,cset1,cset2, 0,1,REN_OP_CHK,TMPBUFSIZ,RENX_FAIL)) n++; } if (n > 0) { printf("?Failed: %d file%s would be overwritten\n", n, (n != 1) ? "s" : ""); #ifdef VMS concb((char)escape); #endif /* VMS */ return(success = 0); } /* Get the file list back. */ #ifdef ZXREWIND z = zxrewind(); #else z = nzxpand(s,0); #endif /* ZXREWIND */ } while (z-- > 0 && rc > 0) { char line[CKMAXPATH+2]; if (!(z == 0 && !wild)) znext(line); if (!line[0]) break; rc = renameone((char *)line,p, replacing,casing,all,converting,cset1,cset2, listing,nolist,sim,TMPBUFSIZ,collision); } #ifdef VMS concb((char)escape); #endif /* VMS */ return(success = rc); } #endif /* ZRENAME */ #endif /* NOFRILLS */ #endif /* NORENAME */ #ifndef NOSPL /* Do the RETURN command */ int #ifdef CK_ANSIC doreturn( char *s ) #else doreturn(s) char *s; #endif /* CK_ANSIC */ { int x; extern int tra_asg; char * line, * lp; if (cmdlvl < 1) { printf("\n?Can't return from level %d\n",maclvl); return(success = 0); } line = malloc(LINBUFSIZ); if (line == NULL) return(success = 0); lp = line; /* Expand return value now */ x = LINBUFSIZ-1; if (!s) s = ""; debug(F110,"RETURN s",s,0); if (zzstring(s,&lp,&x) > -1) { s = line; debug(F110,"RETURN zzstring",s,0); } /* Pop from all FOR/WHILE/SWITCH/XIFs */ while ((maclvl > 0) && (m_arg[maclvl-1][0]) && (cmdstk[cmdlvl].src == CMD_MD) && (!strncmp(m_arg[maclvl-1][0],"_xif",4) || !strncmp(m_arg[maclvl-1][0],"_for",4) || !strncmp(m_arg[maclvl-1][0],"_swi",4) || !strncmp(m_arg[maclvl-1][0],"_whi",4))) { debug(F111,"RETURN IF/FOR/WHI/SWI pop",m_arg[maclvl-1][0],maclvl); dogta(XXPTA); /* Put args back */ popclvl(); /* Pop up two levels */ popclvl(); } if (tra_asg) { /* If tracing show return value */ if (*s) printf("<<< %s: \"%s\"\n", m_arg[maclvl][0], s); else printf("<<< %s: (null)\n", m_arg[maclvl][0]); } popclvl(); /* Pop from enclosing TAKE or macro */ debug(F111,"RETURN tolevel",s,maclvl); if (!s) s = ""; if (!*s) s = NULL; makestr(&(mrval[maclvl+1]),s); /* Set the RETURN value */ free(line); return(success = 1); /* Macro succeeds if we RETURN */ } #endif /* NOSPL */ #ifndef NOSPL /* Do the OPEN command */ int doopen() { /* OPEN { append, read, write } */ int x, y, z = 0; char *s; static struct filinfo fcb; /* (must be static) */ if ((x = cmkey(opntab,nopn,"mode","",xxstring)) < 0) { if (x == -3) { printf("?Mode required\n"); return(-9); } else return(x); } switch (x) { case OPN_FI_R: /* Old file (READ) */ if (chkfn(ZRFILE) > 0) { printf("?Read file already open\n"); return(-2); } if ((z = cmifi("File to read","",&s,&y,xxstring)) < 0) { if (z == -3) { printf("?Input filename required\n"); return(-9); } else return(z); } if (y) { /* No wildcards allowed */ printf("\n?Please specify a single file\n"); return(-2); } ckstrncpy(line,s,LINBUFSIZ); if ((int)strlen(line) < 1) return(-2); if ((z = cmnum("buffer size","4096",10,&y,xxstring)) < 0) return(z); if (y < 1) { printf("?Positive number required\n"); return(-9); } if ((z = cmcfm()) < 0) return(z); readblock = y; if (readbuf) free((char *)readbuf); if (!(readbuf = (CHAR *) malloc(readblock+1))) { printf("?Can't allocate read buffer\n"); return(-9); } return(success = zopeni(ZRFILE,line)); #ifndef MAC #ifndef NOPUSH case OPN_PI_R: /* Pipe/Process (!READ) */ if (nopush) { printf("?Read from pipe disabled\n"); return(success=0); } if (chkfn(ZRFILE) > 0) { printf("?Read file already open\n"); return(-2); } if ((y = cmtxt("System command to read from","",&s,xxstring)) < 0) { if (y == -3) { printf("?Command name required\n"); return(-9); } else return(y); } ckstrncpy(line,brstrip(s),LINBUFSIZ); if (!line[0]) return(-2); if ((y = cmcfm()) < 0) return(y); if (!readbuf) { if (!(readbuf = (CHAR *) malloc(readblock+1))) { printf("?Can't allocate read buffer\n"); return(-9); } } return(success = zxcmd(ZRFILE,line)); case OPN_PI_W: /* Write to pipe */ if (nopush) { printf("?Write to pipe disabled\n"); return(success=0); } if (chkfn(ZWFILE) > 0) { printf("?Write file already open\n"); return(-2); } if ((y = cmtxt("System command to write to","",&s,xxstring)) < 0) { if (y == -3) { printf("?Command name required\n"); return(-9); } else return(y); } ckstrncpy(line,brstrip(s),LINBUFSIZ); if (!line[0]) return(-2); if ((y = cmcfm()) < 0) return(y); success = zxcmd(ZWFILE,line); if (!success && msgflg) printf("Can't open process for writing: %s\n",line); return(success); #endif /* NOPUSH */ #endif /* MAC */ case OPN_FI_W: /* New file (WRITE) */ case OPN_FI_A: /* (APPEND) */ if ((z = cmofi("Name of local file to create","",&s,xxstring)) < 0) { if (z == -3) { printf("?Filename required\n"); return(-9); } else return(z); } if (z == 2) { printf("?Sorry, %s is a directory name\n",s); return(-9); } if (chkfn(ZWFILE) > 0) { printf("?Write/Append file already open\n"); return(-2); } fcb.bs = fcb.cs = fcb.rl = fcb.fmt = fcb.org = fcb.cc = fcb.typ = 0; fcb.lblopts = 0; fcb.dsp = (x == OPN_FI_W) ? XYFZ_N : XYFZ_A; /* Create or Append */ ckstrncpy(line,s,LINBUFSIZ); if ((int)strlen(line) < 1) return(-2); if ((y = cmcfm()) < 0) return(y); return(success = zopeno(ZWFILE,line,NULL,&fcb)); #ifndef NOLOCAL case OPN_SER: /* OPEN PORT or LINE */ case OPN_NET: { /* OPEN HOST */ extern int didsetlin, ttnproto; if (x == OPN_NET) { z = ttnproto; ttnproto = NP_NONE; } if ((y = setlin((x == OPN_SER) ? XYLINE : XYHOST, 1, 0)) < 0) { if (x == OPN_NET) ttnproto = z; success = 0; } didsetlin++; return(y); } #endif /* NOLOCAL */ default: printf("?Not implemented"); return(-2); } } #endif /* NOSPL */ #ifndef NOXFER /* D O X G E T -- GET command parser with switches */ #ifdef CK_LABELED int g_lf_opts = -1; extern int lf_opts; #endif /* CK_LABELED */ int #ifdef CK_ANSIC doxget( int cx ) #else doxget(cx) int cx; #endif /* CK_ANSIC */ { extern int /* External variables we need */ #ifdef RECURSIVE recursive, #endif /* RECURSIVE */ xfermode, fdispla, protocol, usepipes, g_binary, g_xfermode, g_displa, g_rpath, g_usepipes; extern char * rcv_move; /* Directory to move new files to */ extern char * rcv_rename; /* What to rename new files to */ extern char * rcvexcept[]; /* RECEIVE / GET exception list */ int opkt = 0; /* Flag for O-Packet needed */ #ifdef PIPESEND extern int pipesend; extern char * rcvfilter; #endif /* PIPESEND */ extern struct keytab rpathtab[]; extern int nrpathtab; extern CK_OFF_T calibrate; int asname = 0; /* Flag for have as-name */ int konly = 0; /* Kermit-only function */ int c, i, n, confirmed = 0; /* Workers */ int getval = 0; /* Whether to get switch value */ int rcvcmd = 0; /* Whether it is the RECEIVE command */ int mget = 0; /* Whether it is the MGET command */ struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */ struct FDB sw, fl, cm; /* FDBs for each parse function */ char * cmdstr = "this command"; #ifdef NEWFTP if (cx == XXGET || cx == XXREGET || cx == XXMGET || cx == XXRETR) { extern int ftpget; extern int ftpisopen(); if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) { int x; x = doftpget(cx,0); debug(F101,"doftpget return","",x); if (x > -1) success = x; debug(F101,"doftpget success","",success); return(x); } } #endif /* NEWFTP */ debug(F101,"xget cx","",cx); oopts = -1; omode = -1; for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */ pv[i].sval = NULL; pv[i].ival = -1; pv[i].wval = (CK_OFF_T)-1; } /* Preset switch values based on top-level command that called us */ switch (cx) { case XXREC: /* RECEIVE */ cmdstr = "RECEIVE"; rcvcmd = 1; break; case XXGET: /* GET */ cmdstr = "GET"; konly = 1; break; #ifdef CK_RESEND case XXREGET: /* REGET */ cmdstr = "REGET"; konly = 1; pv[SND_BIN].ival = 1; /* Implies /BINARY */ pv[SND_RES].ival = 1; break; #endif /* CK_RESEND */ case XXRETR: /* RETRIEVE */ cmdstr = "RETRIEVE"; konly = 1; pv[SND_DEL].ival = 1; break; #ifdef PIPESEND case XXCREC: /* CRECEIVE */ cmdstr = "CRECEIVE"; konly = 1; rcvcmd = 1; pv[SND_CMD].ival = 1; break; case XXCGET: /* CGET */ cmdstr = "CGET"; konly = 1; pv[SND_CMD].ival = 1; break; #endif /* PIPESEND */ #ifndef NOMGET case XXMGET: /* MGET */ cmdstr = "MGET"; konly = 1; mget = 1; break; #endif /* NOMGET */ } debug(F111,"xget rcvcmd",cmdstr,rcvcmd); debug(F101,"xget konly","",konly); #ifdef CK_XYZ if (!rcvcmd && protocol != PROTO_K) { printf("?Sorry, %s works only with Kermit protocol\n",cmdstr); return(-9); } #endif /* CK_XYZ */ /* Set up chained parse functions... */ cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ rcvcmd ? "Optional name/template to store incoming files under, or switch" : "Remote filename, or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ rcvcmd ? nrcvtab : ngettab, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ rcvcmd ? rcvtab : gettab, /* Keyword table */ &fl /* Pointer to next FDB */ ); if (rcvcmd || mget) /* RECEIVE or MGET */ cmfdbi(&fl, _CMTXT, /* fcode */ rcvcmd ? /* hlpmsg */ "Output filename or Command" : /* Output filename */ "File(s) to GET", /* Files we are asking for */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ #ifdef COMMENT #ifdef CK_XYZ (protocol == PROTO_X || protocol == PROTO_XC) ? xxstring : (rcvcmd ? (xx_strp)0 : xxstring) #else rcvcmd ? (xx_strp)0 : xxstring /* Processing function */ #endif /* CK_XYZ */ #else /* COMMENT */ xxstring /* Always evaluate - fdc 2006/02/01 */ #endif /* COMMENT */ , NULL, &cm ); else cmfdbi(&fl, /* Remote filename or command */ _CMFLD, /* fcode */ "Remote filename", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, &cm ); cmfdbi(&cm, /* Confirmation */ _CMCFM, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, NULL, NULL ); /* (See doxsend() for fuller commentary) */ while (1) { /* Parse 0 or more switches */ x = cmfdb(&sw); /* Parse something */ debug(F101,"xget cmfdb","",x); if (x < 0) /* Error */ goto xgetx; /* or reparse needed */ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */ break; c = cmgbrk(); /* Get break character */ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); x = -9; goto xgetx; } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); x = -9; goto xgetx; } n = cmresult.nresult; /* Numeric result = switch value */ debug(F101,"xget switch","",n); switch (n) { /* Process the switch */ #ifdef PIPESEND case SND_CMD: /* These take no args */ if (nopush) { printf("?Sorry, system command access is disabled\n"); x = -9; goto xgetx; } else if (rcvfilter) { printf( "?Sorry, no GET /COMMAND when RECEIVE FILTER selected\n"); x = -9; goto xgetx; } if (rcvcmd) sw.hlpmsg = "Command, or switch"; /* Change help message */ /* Fall thru... */ #endif /* PIPESEND */ case SND_REC: /* /RECURSIVE */ pv[SND_PTH].ival = PATH_REL; /* Implies relative pathnames */ pv[n].ival = 1; /* Set the recursive flag */ break; case SND_RES: /* /RECOVER */ pv[SND_BIN].ival = 1; /* Implies /BINARY */ pv[n].ival = 1; /* Set the resend flag */ break; case SND_DEL: /* /DELETE */ case SND_SHH: /* /QUIET */ case SND_CAL: /* /CALIBRATE */ case SND_XPA: /* /TRANSPARENT */ pv[n].ival = 1; /* Just set the appropriate flag */ break; case SND_PIP: /* /PIPES:{ON,OFF} */ if (!getval) { pv[n].ival = 1; break; } if ((x = cmkey(onoff,2,"","on",xxstring)) < 0) goto xgetx; if (!nopush) pv[n].ival = x; break; /* File transfer modes - each undoes the others */ case SND_BIN: /* Binary */ case SND_TXT: /* Text */ case SND_IMG: /* Image */ case SND_LBL: /* Labeled */ pv[SND_BIN].ival = 0; /* Unset all */ pv[SND_TXT].ival = 0; pv[SND_IMG].ival = 0; pv[SND_LBL].ival = 0; pv[n].ival = 1; /* Set the requested one */ break; case SND_EXC: /* Excludes */ if (!getval) break; if ((x = cmfld("Pattern","",&s,xxstring)) < 0) { if (x == -3) { printf("?Pattern required\n"); x = -9; } goto xgetx; } if (pv[n].sval) free(pv[n].sval); y = strlen(s); if (y > 256) { printf("?Pattern too long - 256 max\n"); x = -9; goto xgetx; } pv[n].sval = malloc(y+1); if (pv[n].sval) { strcpy(pv[n].sval,s); /* safe */ pv[n].ival = 1; } break; #ifdef COMMENT /* Not implemented */ case SND_PRI: /* GET to printer */ pv[n].ival = 1; if (!getval) break; if ((x = cmfld("Print options","",&s,xxstring)) < 0) goto xgetx; pv[n].sval = malloc((int)strlen(s)+1); if (pv[n].sval) strcpy(pv[n].sval,s); /* safe */ break; #endif /* COMMENT */ case SND_MOV: /* MOVE after */ case SND_REN: /* RENAME after */ if (!getval) break; if ((x = cmfld(n == SND_MOV ? "device and/or directory for source file after sending" : "new name for source file after sending", "", &s, n == SND_MOV ? xxstring : NULL )) < 0) { if (x == -3) { printf("%s\n", n == SND_MOV ? "?Destination required" : "?New name required" ); x = -9; } goto xgetx; } if (pv[n].sval) { free(pv[n].sval); pv[n].sval = NULL; } s = brstrip(s); y = strlen(s); if (y > 0) { pv[n].sval = malloc(y+1); if (pv[n].sval) { strcpy(pv[n].sval,s); /* safe */ pv[n].ival = 1; } } break; case SND_ASN: /* As-name */ if (!getval) break; if (mget) { printf("?Sorry, as-name not allowed with MGET\n"); x = -9; goto xgetx; } if ( #ifdef COMMENT (x = cmfld("Name to store it under","",&s,NULL)) #else (x = cmfld("Name to store it under","",&s,xxstring)) #endif /* COMMENT */ < 0) goto xgetx; s = brstrip(s); if ((y = strlen(s)) > 0) { if (pv[n].sval) free(pv[n].sval); pv[n].sval = malloc(y+1); if (pv[n].sval) { strcpy(pv[n].sval,s); /* safe */ pv[n].ival = 1; } } break; #ifdef PIPESEND case SND_FLT: /* Filter */ debug(F101,"xget /filter getval","",getval); if (!getval) break; if ((x = cmfld("Filter program to receive through", "",&s,NULL)) < 0) { if (x == -3) s = ""; else goto xgetx; } if (*s) s = brstrip(s); y = strlen(s); for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */ if (s[x] != '\\') continue; if (s[x+1] == 'v') break; } if (x == y) { printf( "?Filter must contain a replacement variable for filename.\n" ); x = -9; goto xgetx; } pv[n].ival = 1; if (pv[n].sval) { free(pv[n].sval); pv[n].sval = NULL; } if ((y = strlen(s)) > 0) { if ((pv[n].sval = malloc(y+1))) strcpy(pv[n].sval,s); /* safe */ } break; #endif /* PIPESEND */ case SND_PTH: /* Pathnames */ if (!getval) { pv[n].ival = PATH_REL; break; } if ((x = cmkey(rpathtab,nrpathtab,"","on",xxstring)) < 0) goto xgetx; pv[n].ival = x; /* Ditto */ break; case SND_NAM: /* Filenames */ if (!getval) break; if ((x = cmkey(fntab,nfntab,"","converted",xxstring)) < 0) goto xgetx; pv[n].ival = x; break; case SND_PRO: /* Protocol to use */ if (!getval) break; if ((x = cmkey(protos,nprotos,"File-transfer protocol","", xxstring)) < 0) { if (x == -3) x = 0; else goto xgetx; } debug(F111,"xget /proto",atmbuf,x); pv[n].ival = x; if (konly && x != PROTO_K) { printf( "?Sorry, this command works only with Kermit protocol\n" ); x = -9; goto xgetx; } break; default: printf("?Unexpected switch value - %d\n",cmresult.nresult); x = -9; goto xgetx; } } debug(F101,"xget cmresult fcode","",cmresult.fcode); cmarg = line; /* Initialize string pointers */ cmarg2 = tmpbuf; asname = 0; line[0] = NUL; /* and buffers. */ tmpbuf[0] = NUL; switch (cmresult.fcode) { /* How did we get out of switch loop */ case _CMFLD: /* (3) Remote filespec */ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); break; case _CMTXT: /* (4) As-name */ if (rcvcmd) { ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ); if ((int)strlen(tmpbuf) > 0) asname = 1; } else { ckstrncpy(line,cmresult.sresult,LINBUFSIZ); } case _CMCFM: /* (6) Confirmation */ confirmed = 1; break; default: printf("?Unexpected function code: %d\n",cmresult.fcode); x = -9; goto xgetx; } debug(F110,"xget string",cmarg,0); debug(F101,"xget confirmed","",confirmed); cmarg = brstrip(cmarg); /* Strip any braces */ if (!confirmed) { /* CR not typed yet, get more fields */ if (pv[SND_CMD].ival > 0) { debug(F100,"xget calling cmtxt","",0); x = cmtxt("Local command to pipe into","",&s,NULL); if (x < 0 && x != -3) goto xgetx; if (x != -3) { ckstrncpy(tmpbuf,s,TMPBUFSIZ); asname = 1; } } else if (!rcvcmd) { #ifdef VMS /* cmofi() fails if you give it a directory name */ x = cmfld("Name or directory for incoming file","",&s,NULL); debug(F111,"xget cmfld",s,x); #else x = cmofi("Name or directory for incoming file","",&s,NULL); debug(F111,"xget cmofi",s,x); #endif /* VMS */ if (x < 0 && x != -3) goto xgetx; if (x != -3) { ckstrncpy(tmpbuf,s,TMPBUFSIZ); if ((x = cmcfm()) < 0) goto xgetx; asname = 1; } } } /* Arrive here with cmarg and cmarg2 all set */ debug(F111,"xget asname",cmarg2,asname); if (!asname) { if (pv[SND_ASN].sval) ckstrncpy(tmpbuf,pv[SND_ASN].sval,TMPBUFSIZ); else tmpbuf[0] = NUL; } cmarg2 = brstrip(cmarg2); /* Strip outer braces if any. */ debug(F110,"xget cmarg",cmarg,0); debug(F110,"xget cmarg2",cmarg2,0); if (!*cmarg && (cx == XXGET || cx == XXREGET || cx == XXCGET || cx == XXMGET)) { printf("?A remote file specification is required\n"); x = -9; goto xgetx; } #ifdef PIPESEND if (pv[SND_CMD].ival > 0) { /* /COMMAND sets pipesend flag */ x = -9; if (!*cmarg2) { printf("?Command required\n"); goto xgetx; } else if (nopush) { printf("?Sorry, system command access is disabled\n"); goto xgetx; } else if (rcvfilter) { printf("?Sorry, no GET /COMMAND while RECEIVE FILTER selected\n"); goto xgetx; } else pipesend = 1; } debug(F101,"xget /COMMAND pipesend","",pipesend); #endif /* PIPESEND */ #ifdef CK_RESEND if (pv[SND_RES].ival > 0) { /* REGET or GET /RECOVER */ #ifdef RECURSIVE if (pv[SND_REC].ival > 0) { /* RECURSIVE */ #ifdef COMMENT printf("?Unsupported option combination: /RECOVER /RECURSIVE\n"); x = -9; goto xgetx; #else opkt = 1; #endif /* COMMENT */ } #endif /* RECURSIVE */ if (pv[SND_DEL].ival > 0) { /* /DELETE */ #ifdef COMMENT printf("?Unsupported option combination: /RECOVER /DELETE\n"); x = -9; goto xgetx; #else opkt = 1; #endif /* COMMENT */ } } #endif /* CK_RESEND */ if (pv[SND_EXC].ival > 0) /* /EXCEPT */ makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT); #ifdef IKS_OPTION if (!rcvcmd #ifdef CK_XYZ && protocol == PROTO_K #endif /* CK_XYZ */ ) { if (!iks_wait(KERMIT_REQ_START,1)) { printf( "?A Kermit Server is not available to process this command\n"); x = -9; /* correct the return code */ goto xgetx; } } #endif /* IKS_OPTION */ #ifdef CK_XYZ { int po, pg; /* (for clarity) */ po = pv[SND_PRO].ival; /* /PROTOCOL option */ pg = protocol; /* Protocol global */ if ((rcvcmd && !*cmarg2) && /* If no as-name was given */ /* and /PROTOCOL is XMODEM or global protocol is XMODEM... */ ((po < 0 && (pg == PROTO_X || pg == PROTO_XC)) || (po > -1 && (po == PROTO_X || po == PROTO_XC))) ) { printf( "Sorry, you must specify a name when receiving a file with XMODEM protocol\n" ); x = -9; goto xgetx; } } #endif /* CK_XYZ */ #ifdef RECURSIVE if (pv[SND_REC].ival > 0) { /* RECURSIVE */ recursive = 1; pv[SND_PTH].ival = PATH_REL; /* Implies relative pathnames too */ } #endif /* RECURSIVE */ if (pv[SND_PIP].ival > -1) { g_usepipes = usepipes; usepipes = pv[SND_PIP].ival; } /* Save global protocol parameters */ g_proto = protocol; #ifdef CK_LABELED g_lf_opts = lf_opts; /* Save labeled transfer options */ #endif /* CK_LABELED */ g_urpsiz = urpsiz; /* Receive packet length */ g_spsizf = spsizf; /* Send packet length flag */ g_spsiz = spsiz; /* Send packet length */ g_spsizr = spsizr; /* etc etc */ g_spmax = spmax; g_wslotr = wslotr; g_prefixing = prefixing; g_fncact = fncact; g_fncnv = fncnv; g_fnspath = fnspath; g_fnrpath = fnrpath; g_xfrxla = xfrxla; if (pv[SND_PRO].ival > -1) { /* Change according to switch */ protocol = pv[SND_PRO].ival; if (ptab[protocol].rpktlen > -1) /* copied from initproto() */ urpsiz = ptab[protocol].rpktlen; if (ptab[protocol].spktflg > -1) spsizf = ptab[protocol].spktflg; if (ptab[protocol].spktlen > -1) { spsiz = ptab[protocol].spktlen; if (spsizf) spsizr = spmax = spsiz; } if (ptab[protocol].winsize > -1) wslotr = ptab[protocol].winsize; if (ptab[protocol].prefix > -1) prefixing = ptab[protocol].prefix; if (ptab[protocol].fnca > -1) fncact = ptab[protocol].fnca; if (ptab[protocol].fncn > -1) fncnv = ptab[protocol].fncn; if (ptab[protocol].fnsp > -1) fnspath = ptab[protocol].fnsp; if (ptab[protocol].fnrp > -1) fnrpath = ptab[protocol].fnrp; } debug(F101,"xget protocol","",protocol); debug(F111,"xget cmarg2",cmarg2,xfermode); g_xfermode = xfermode; g_binary = binary; if (pv[SND_BIN].ival > 0) { /* Change according to switch */ xfermode = XMODE_M; binary = XYFT_B; /* FILE TYPE BINARY */ omode = GMOD_BIN; /* O-Packet mode */ debug(F101,"doxget /BINARY xfermode","",xfermode); } else if (pv[SND_TXT].ival > 0) { /* Ditto for /TEXT */ xfermode = XMODE_M; binary = XYFT_T; omode = GMOD_TXT; debug(F101,"doxget /TEXT xfermode","",xfermode); } else if (pv[SND_IMG].ival > 0) { xfermode = XMODE_M; #ifdef VMS binary = XYFT_I; #else binary = XYFT_B; #endif /* VMS */ omode = GMOD_TXT; debug(F101,"doxget /IMAGE xfermode","",xfermode); } #ifdef CK_LABELED else if (pv[SND_LBL].ival > 0) { xfermode = XMODE_M; binary = XYFT_L; omode = GMOD_LBL; debug(F101,"doxget /LABELED xfermode","",xfermode); } #endif /* CK_LABELED */ debug(F101,"xget binary","",binary); debug(F101,"xget omode","",omode); if (pv[SND_XPA].ival > 0) /* /TRANSPARENT */ xfrxla = 0; /* Don't translate character sets */ #ifdef PIPESEND if (pv[SND_FLT].ival > 0) makestr(&rcvfilter,pv[SND_FLT].sval); #endif /* PIPESEND */ #ifdef CK_TMPDIR if (pv[SND_MOV].ival > 0) { int len; char * p = pv[SND_MOV].sval; #ifdef CK_LOGIN if (isguest) { printf("?Sorry, /MOVE-TO not available to guests\n"); x = -9; goto xgetx; } #endif /* CK_LOGIN */ len = strlen(p); if (!isdir(p)) { /* Check directory */ #ifdef CK_MKDIR char * s = NULL; s = (char *)malloc(len + 4); if (s) { strcpy(s,p); /* safe */ #ifdef datageneral if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; } #else if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; } #endif /* datageneral */ s[len++] = 'X'; s[len] = NUL; x = zmkdir(s); free(s); if (x < 0) { printf("?Can't create \"%s\"\n",p); x = -9; goto xgetx; } } #else printf("?Directory \"%s\" not found\n",p); x = -9; goto xgetx; #endif /* CK_MKDIR */ } zfnqfp(p,LINBUFSIZ,line); makestr(&rcv_move,line); } #endif /* CK_TMPDIR */ if (pv[SND_REN].ival > 0) { /* /RENAME-TO:name */ char * p = pv[SND_REN].sval; #ifdef CK_LOGIN if (isguest) { printf("?Sorry, /RENAME-TO not available to guests\n"); x = -9; goto xgetx; } #endif /* CK_LOGIN */ if (!p) p = ""; if (!*p) { printf("?New name required for /RENAME\n"); x = -9; goto xgetx; } p = brstrip(p); makestr(&rcv_rename,p); debug(F110,"xget rcv_rename","",0); } #ifdef CALIBRATE if (pv[SND_CAL].ival > 0) calibrate = (CK_OFF_T)1; #endif /* CALIBRATE */ g_displa = fdispla; if (pv[SND_SHH].ival > 0) fdispla = 0; debug(F101,"xget display","",fdispla); if (pv[SND_NAM].ival > -1) { /* /FILENAMES */ g_fncnv = fncnv; /* Save global value */ fncnv = pv[SND_NAM].ival; debug(F101,"xsend fncnv","",fncnv); /* We should also handle O packet filename option here */ /* but we don't really need to since WHATAMI already handles it */ } if (pv[SND_PTH].ival > -1) { /* PATHNAMES */ g_rpath = fnrpath; /* Save global values */ fnrpath = pv[SND_PTH].ival; debug(F101,"xsend fnrpath","",fnrpath); #ifndef NZLTOR if (fnrpath != PATH_OFF) { g_fncnv = fncnv; fncnv = XYFN_L; debug(F101,"xsend fncnv","",fncnv); } /* We should also handle O packet pathname option here */ /* but we don't really need to since WHATAMI already handles it */ #endif /* NZLTOR */ } /* Set protocol start state */ if (opkt) { /* Extended GET Options*/ sstate = (CHAR) 'o'; oopts = 0; if (pv[SND_DEL].ival > 0) oopts |= GOPT_DEL; /* GET /DELETE */ if (pv[SND_RES].ival > 0) oopts |= GOPT_RES; /* GET /RECOVER */ if (pv[SND_REC].ival > 0) oopts |= GOPT_REC; /* GET /RECURSIVE */ } else if (rcvcmd) sstate = (CHAR) 'v'; /* RECEIVE or CRECEIVE */ else if (pv[SND_DEL].ival > 0) sstate = (CHAR) 'h'; /* GET /DELETE (= RETRIEVE) */ else if (pv[SND_RES].ival > 0) sstate = (CHAR) 'j'; /* GET /RECOVER (= REGET) */ else sstate = (CHAR) 'r'; /* Regular GET */ getcmd = 1; debug(F000,"xget sstate","",sstate); #ifdef MAC what = W_RECV; scrcreate(); #endif /* MAC */ if (local) { if (pv[SND_SHH].ival != 0) displa = 1; if (protocol == PROTO_K) /* fdc 20070108 */ ttflui(); } x = 0; #ifdef PIPESEND if (pipesend) goto xgetx; #endif /* PIPESEND */ #ifdef CK_TMPDIR /* cmarg2 is also allowed to be a device or directory name; even the name of a directory that doesn't exist. */ y = strlen(cmarg2); debug(F111,"xget strlen(cmarg2)",cmarg2,y); if ((y > 0) && #ifdef OS2 ((isalpha(cmarg2[0]) && cmarg2[1] == ':' && cmarg2[2] == NUL) || (cmarg[y-1] == '/' || cmarg[y-1] == '\\') || isdir(cmarg2)) #else #ifdef UNIXOROSK (cmarg2[y-1] == '/' || isdir(cmarg2)) #else #ifdef VMS (cmarg2[y-1] == ']' || cmarg2[y-1] == '>' || isdir(cmarg2)) #else #ifdef STRATUS (cmarg2[y-1] == '>' || isdir(cmarg2)) #else #ifdef datageneral (cmarg2[y-1] == ':' || cmarg[0] == ':' || isdir(cmarg2)) #else isdir(cmarg2) #endif /* datageneral */ #endif /* STRATUS */ #endif /* VMS */ #endif /* UNIXOROSK */ #endif /* OS2 */ ) { debug(F110,"doxget RECEIVE cmarg2 disk or dir",cmarg2,0); if (!f_tmpdir) { int x; s = zgtdir(); if (s) { ckstrncpy(savdir,s,TMPDIRLEN); /* remember old disk/dir */ f_tmpdir = 1; /* and that we did this */ } else { printf("?Can't get current directory\n"); cmarg2 = ""; f_tmpdir = 0; x = -9; goto xgetx; } #ifdef CK_MKDIR x = zchki(cmarg2); /* Does as-name exist? */ if (x == -1) { /* Doesn't exist */ char * p = NULL; /* Try to create it */ x = strlen(cmarg2); if ((p = (char *)malloc(x+4))) { sprintf(p,"%s%s",cmarg2,"x.x"); /* SAFE (prechecked) */ x = zmkdir(p); free(p); if (x < 0) { printf("?Can't create %s\n",cmarg2); x = -9; goto xgetx; } } } #endif /* CK_MKDIR */ if (!zchdir(cmarg2)) { /* change to given disk/directory, */ printf("?Can't access %s\n",cmarg2); x = -9; goto xgetx; } cmarg2 = ""; } } #endif /* CK_TMPDIR */ ckstrncpy(fspec,cmarg,CKMAXPATH); /* Note - this is a REMOTE filespec */ debug(F111,"xget fspec",fspec,fspeclen); debug(F110,"xget cmarg2",cmarg2,0); xgetx: for (i = 0; i < SND_MAX; i++) if (pv[i].sval) free(pv[i].sval); return(x); } #endif /* NOXFER */ #ifndef NOSPL /* D O G T A -- Do _GETARGS or _PUTARGS Command. Used by IF, FOR, WHILE, and SWITCH, each of which are implemented as 2-level macros; the first level defines the macro, the second runs it. This routine hides the fact that they are macros by importing the macro arguments (if any) from two levels up, to make them available in the IF, FOR, SWITCH, and WHILE commands themselves; for example as loop indices, etc, and within the IF/FOR/WHILE/SWITCH body itself. _PUTARGS is in case we changed any of these variables or used SHIFT on them, so the new values won't be lost as we pop up the stack. */ int #ifdef CK_ANSIC dogta( int cx ) #else dogta(cx) int cx; #endif /* CK_ANSIC */ { int i; char c, *p, mbuf[4]; extern int topargc, cmdint; extern char ** topxarg; debug(F100,"GETARGS: dogta entry cx","",cx); if ((y = cmcfm()) < 0) return(y); debug(F101," dogta maclvl","",maclvl); if (cx == XXGTA) { debug(F101," dogta _GETARGS maclvl","",maclvl); } else if (cx == XXPTA) { debug(F101," dogta _PUTARGS maclvl","",maclvl); } else { return(-2); } if (maclvl < 1) return(success = 0); /* Make new copies of macro arguments /%0..9 */ mbuf[0] = '%'; mbuf[1] = '0'; mbuf[2] = NUL; /* Argument name buf */ if (cx == XXPTA) { /* Go NOINT because _PUTARGS */ if (cmdint) /* temporarily changes maclvl. */ connoi(); /* Interrupts OFF. */ } for (i = 0; i < 10; i++) { /* For all args */ c = (char) (i + '0'); /* Make name */ mbuf[1] = (char) c; /* Insert digit */ if (cx == XXGTA) { /* Get arg from level-minus-2 */ if (maclvl == 1) p = g_var[c]; /* If at level 1 use globals 0..9 */ else p = m_arg[maclvl-2][i]; /* Otherwise they're on the stack */ debug(F111," dogta _GETARGS m_arg addmac var i",mbuf,i); debug(F111," dogta _GETARGS m_arg addmac def i",p,i); addmac(mbuf,p); #ifdef COMMENT if (maclvl > 1) makestr(&(m_line[maclvl]),m_line[maclvl-2]); #endif /* COMMENT */ } else if (cx == XXPTA) { /* Put args level+2 */ maclvl -= 2; /* This is gross, it's because we're */ addmac(mbuf,m_arg[maclvl+2][i]); /* adding macros two levels up */ maclvl += 2; /* and addmac() uses maclvl. */ count[cmdlvl - 2] = count[cmdlvl]; intime[cmdlvl - 2] = intime[cmdlvl]; inpcas[cmdlvl - 2] = inpcas[cmdlvl]; takerr[cmdlvl - 2] = takerr[cmdlvl]; merror[cmdlvl - 2] = merror[cmdlvl]; xquiet[cmdlvl - 2] = xquiet[cmdlvl]; xvarev[cmdlvl - 2] = xvarev[cmdlvl]; } else return(success = 0); /* Bad call to this routine */ } if (cx == XXPTA) { /* Restore interrupts if we */ if (cmdint) /* turned them off above. */ conint(trap,stptrap); } /* Now take care of the argument vector array \&_[], \v(return), */ /* and \v(argc) by just copying the pointers. */ if (cx == XXGTA) { /* GETARGS from 2 levels up */ debug(F101," dogta _GETARGS m_xarg maclvl","",maclvl); if (maclvl == 1) { debug(F100," dogta _GETARGS m_xarg top level","",0); a_ptr[0] = topxarg; /* \&_[] array */ a_dim[0] = topargc - 1; /* Dimension doesn't include [0] */ m_xarg[maclvl] = topxarg; n_xarg[maclvl] = topargc; /* But \v(argc) does include \%0 */ macargc[maclvl] = topargc; makestr(&(mrval[maclvl+1]),mrval[0]); /* (see vnlook()) */ } else { debug(F100," dogta _GETARGS m_xarg in macro","",0); a_ptr[0] = m_xarg[maclvl-2]; a_dim[0] = n_xarg[maclvl-2]; m_xarg[maclvl] = m_xarg[maclvl-2]; n_xarg[maclvl] = n_xarg[maclvl-2]; macargc[maclvl] = n_xarg[maclvl-2]; makestr(&(mrval[maclvl+1]),mrval[maclvl-1]); /* (see vnlook()) */ } } else { /* PUTARGS 2 levels up */ if (maclvl > 1) { a_ptr[0] = m_xarg[maclvl]; m_xarg[maclvl-2] = m_xarg[maclvl]; a_dim[0] = n_xarg[maclvl]; n_xarg[maclvl-2] = n_xarg[maclvl]; macargc[maclvl-2] = n_xarg[maclvl]; } } return(1); /* Internal command - don't change success */ } #endif /* NOSPL */ #ifndef NOSPL /* Do the GOTO and [_]FORWARD commands. s = Label to search for, cx = function code: XXGOTO, XXFWD, or XXXFWD. */ int #ifdef CK_ANSIC dogoto( char *s, int cx ) #else dogoto(s, cx) char *s; int cx; #endif /* CK_ANSIC */ { int j, x, y, z, bc; int empty = 0, stopflg = 0; char * cmd; /* Name of this command */ char tmplbl[LBLSIZ+1], *lp; /* Current label from command stream */ char tmp2[LBLSIZ+1]; /* SWITCH label conversion buffer */ char tmp3[LBLSIZ+1]; /* Target label */ stopflg = (cx == XXXFWD); /* _FORWARD (used in SWITCH) */ bc = 0; /* Brace counter */ cmd = (cx == XXGOTO) ? "GOTO" : ((cx == XXFWD) ? "FORWARD" : "_FORWARD"); if (!s) s = ""; if (!*s) empty = 1; #ifdef DEBUG if (deblog) { debug(F111,"GOTO command",cmd,cx); debug(F101,"GOTO cmdlvl","",cmdlvl); debug(F101,"GOTO maclvl","",maclvl); debug(F101,"GOTO tlevel","",tlevel); debug(F111,"GOTO target",s,empty); } #endif /* DEBUG */ debug(F110,cmd,s,0); x = ckstrncpy(tmp3+1,s,LBLSIZ); debug(F101,"GOTO target len","",x); debug(F101,"GOTO target at x","",s[x]); if (s[x]) { debug(F100,"GOTO target overflow","",0); printf("?GOTO target or SWITCH case label too long\n"); if (stopflg) dostop(); /* If in SWITCH return to prompt */ return(success = 0); } s = tmp3+1; if (*s != ':') { /* Make copy of label */ tmp3[0] = ':'; /* guaranteed to start with ":" */ s--; } if (!stopflg && !empty) { if (s[1] == '.' || s[1] == SP || s[1] == NUL) { printf("?Bad label syntax - '%s'\n",s); if (stopflg) dostop(); /* If in SWITCH return to prompt */ return(success = 0); } } if (cmdlvl == 0) { printf("?Sorry, %s only works in a command file or macro\n",cmd); return(success = 0); } y = strlen(s); /* y = length of target label */ debug(F111,cmd,s,y); while (cmdlvl > 0) { /* As long as not at top level... */ if (cmdstk[cmdlvl].src == CMD_MD) { /* GOTO inside macro */ int i, m, flag; char *xp, *tp; /* GOTO: rewind the macro; FORWARD: start at current position */ lp = (cx == XXGOTO) ? macx[maclvl] : macp[maclvl]; m = (int)strlen(lp); debug(F111,"GOTO in macro",lp,m); flag = 1; /* flag for valid label position */ for (i = 0; i < m; i++,lp++) { /* search for label in macro body */ if (*lp == '{') /* But only at this level */ bc++; /* Anything inside braces is off */ else if (*lp == '}') /* limits. */ bc--; if (stopflg && bc > 0) /* This is good for SWITCH */ continue; /* but interferes with WHILE, etc. */ if (*lp == ',') { flag = 1; continue; } if (flag) { /* If in valid label position */ if (*lp == SP) /* eat leading spaces */ continue; if (*lp != ':') { /* Look for label introducer */ flag = 0; /* this isn't it */ continue; /* keep looking */ } } if (!flag) /* We don't have a label */ continue; /* so keep looking... */ xp = lp; tp = tmplbl; /* Copy the label from the macro */ j = 0; /* to make it null-terminated */ while ((*tp = *xp)) { if (j++ > LBLSIZ-1) { /* j = length of word from macro */ printf("?GOTO target or SWITCH case label too long\n"); if (stopflg) dostop(); /* Return to prompt */ return(success = 0); } if (!*tp || *tp == ',') /* Look for end of word */ break; else tp++, xp++; /* Next character */ } *tp = NUL; /* In case we stopped early */ /* Now do caseless string comparison, using longest length */ debug(F111,"macro GOTO label",s,y); debug(F111,"macro target label",tmplbl,j); if (stopflg) { /* Allow variables as SWITCH labels */ int n = LBLSIZ - 1; char * p = tmp2; zzstring(tmplbl,&p,&n); if (n < 0) { printf("?GOTO target or SWITCH case label too long\n"); if (stopflg) dostop(); /* Return to prompt */ return(0); } ckstrncpy(tmplbl,tmp2,LBLSIZ); } debug(F111,"GOTO s",s,y); debug(F111,"GOTO tmplbl",tmplbl,j); debug(F111,"GOTO empty",ckitoa(stopflg),empty); if (empty) { /* Empty target */ z = (!strcmp(s,":") && /* String is empty */ /* and Label is ":" or ":*"... */ (!strcmp(tmplbl,":") || !strcmp(tmplbl,":*"))) ? 0 : 1; debug(F111,"GOTO","A",z); } else if (stopflg) { z = ckmatch(tmplbl,s,inpcas[cmdlvl],1) ? 0 : 1; debug(F111,"GOTO","B",z); } else { z = (stopflg && inpcas[cmdlvl]) ? strcmp(s,tmplbl) : ckstrcmp(s,tmplbl,(y > j) ? y : j, 0); debug(F111,"GOTO","C",z); } if (!z) { break; } else if (stopflg && !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j, 0)) { debug(F100,"GOTO DEFAULT","",0); break; } else { flag = 0; } } debug(F111,"GOTO macro i",cmd,i); debug(F111,"GOTO macro m",cmd,m); if (i >= m) { /* Didn't find the label */ debug(F101,"GOTO failed cmdlvl","",cmdlvl); #ifdef COMMENT /* MOVED TO AFTER POPCLVL ABOUT 20 LINES DOWN 5 AUG 2002 */ if (stopflg) return(0); #endif /* COMMENT */ if ((maclvl > 0) && (m_arg[maclvl-1][0]) && (cmdstk[cmdlvl].src == CMD_MD) && (!strncmp(m_arg[maclvl-1][0],"_xif",4) || !strncmp(m_arg[maclvl-1][0],"_for",4) || !strncmp(m_arg[maclvl-1][0],"_swi",4) || !strncmp(m_arg[maclvl-1][0],"_whi",4))) { dogta(XXPTA); /* Restore args */ debug(F101,"GOTO in XIF/FOR/WHI/SWI popping","",cmdlvl); popclvl(); /* Pop an extra level */ } debug(F101,"GOTO popping","",cmdlvl); if (!popclvl()) { /* pop up to next higher level */ printf("?Label '%s' not found\n",s); /* if none */ return(0); /* Quit */ } else if (stopflg) { /* SWITCH no case label match */ return(0); /* and no DEFAULT lable. */ } else { continue; /* otherwise look again */ } } debug(F110,"GOTO found macro label",tmplbl,0); macp[maclvl] = lp; /* set macro buffer pointer */ return(1); } else if (cmdstk[cmdlvl].src == CMD_TF) { x = 0; /* GOTO issued in take file */ debug(F111,"GOTO in TAKE file",cmd,cx); if (cx == XXGOTO) { /* If GOTO, but not FORWARD, */ rewind(tfile[tlevel]); /* search file from beginning */ tfline[tlevel] = 0; } while (! feof(tfile[tlevel])) { #ifdef COMMENT /* This is wrong - it lets us jump to labels inside inferior blocks */ tfline[tlevel]++; if (fgets(line,LINBUFSIZ,tfile[tlevel]) == NULL) /* Get line */ #else if (getnct(line,LINBUFSIZ,tfile[tlevel],0) < 0) #endif /* COMMENT */ break; /* If no more, done, label not found */ lp = line; /* Got line */ while (*lp == SP || *lp == HT) lp++; /* Strip leading whitespace */ if (*lp != ':') continue; /* Check for label introducer */ while (*(lp+1) == SP) { /* Remove space between : and name */ *(lp+1) = ':'; lp++; /* Strip leading whitespace */ } tp = lp; /* Get end of word */ j = 0; while (*tp) { /* And null-terminate it */ if (*tp < 33) { *tp = NUL; break; } else tp++, j++; } if (!ckstrcmp(lp,s,(y > j) ? y : j,0)) { /* Caseless compare */ x = 1; /* Got it */ break; /* done. */ } else if (stopflg && !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j,0)) { x = 1; break; } } if (x == 0) { /* If not found, print message */ debug(F101,"GOTO failed at cmdlvl","",cmdlvl); if (stopflg) return(0); if (!popclvl()) { /* pop up to next higher level */ printf("?Label '%s' not found\n",s); /* if none */ return(0); /* quit */ } else continue; /* otherwise look again */ } return(x); /* Send back return code */ } } printf("?Stack problem in GOTO %s\n",s); /* Shouldn't see this */ return(0); } #endif /* NOSPL */ /* Finish parsing and do the IF, XIF, and WHILE commands */ #ifndef NOSPL /* C H K V A R -- Check (if it's a) Variable */ #ifdef OLDCHKVAR /* Crude and disgusting, but needed for OS/2, DOS, and Windows, where filenames have backslashes in them. How do we know if a backslash in a filename is a directory separator, or if it's a Kermit backslash? This routine does a rough syntax check of the next few characters and if it looks like it MIGHT be a variable, then it tries to evaluate it, and if the result is not empty, we say it's a variable, although sometimes it might not be -- some cases are truly ambiguous. For example there might a DOS directory called \%a, and we also have a variable with the same name. This is all for the sake of not having to tell PC users that they have to double all backslashes in file and directory names. */ #else /* Somewhat less crude & disgusting. The previous method was nondeterministic and (worse) it interfered with macro argument passing. So now we only check the syntax of backslash-items to see if they are variables, but we do NOT check their values. */ #endif /* OLDCHKVAR */ /* Call with a string pointer pointing at the backslash of the purported variable. Returns 1 if it has the syntax of a variable, 0 if not. */ int #ifdef CK_ANSIC chkvar( char *s ) #else chkvar(s) char *s; #endif /* CK_ANSIC */ { int z = 0; /* Return code - assume failure. */ if (!s) s = ""; /* Watch our for null pointers. */ if (!*s) return(0); /* Empty arg so not a variable. */ if (*s == CMDQ) { /* Object begins with backslash. */ char c; c = s[1]; /* Character following backslash. */ if (c) { int t = 0; if (c == CMDQ) /* Quoted backslash */ return(1); c = (char) (islower(c) ? toupper(c) : c); /* Otherwise... */ if (c == '%') { /* Simple variable */ #ifdef OLDCHKVAR t = 1; #else return(1); #endif /* OLDCHKVAR */ } else if (c == '&') { /* Array */ if (!s[2]) return(0); if (s[3] == '[') t = ckindex("]",s,4,0,1); #ifndef OLDCHKVAR return((t > 0) ? 1 : 0); #endif /* OLDCHKVAR */ } else if (c == '$' || /* Environment variable */ c == 'V' || /* Built-in variable */ c == 'M') { /* Macro name */ t = (s[2] == '('); #ifndef OLDCHKVAR return((t > 0) ? 1 : 0); #endif /* OLDCHKVAR */ } else if (c == 'F') { /* Function reference */ /* Don't actually call it - it might have side effects */ int x; if ((x = ckindex("(",s,3,0,1))) /* Just check syntax */ if ((x = ckindex(")",s,x,0,1))) z = 1; /* Insert a better syntax check here if necessary */ } #ifdef OLDCHKVAR if (t) { t = 255; /* This lets us test \v(xxx) */ lp = line; /* and even \f...(xxx) */ zzstring(s,&lp,&t); /* Evaluate it, whatever it is. */ t = strlen(line); /* Get its length. */ debug(F111,"chkvar",line,t); z = t > 0; /* If length > 0, it's defined */ } #endif /* OLDCHKVAR */ } } return(z); } /* B O O L E X P -- Evaluate a Boolean expression */ #define BOOLLEN 1024 static char boolval[BOOLLEN]; int #ifdef CK_ANSIC boolexp( int cx ) #else boolexp(cx) int cx; #endif /* CK_ANSIC */ { int x, y, z; char *s, *p; int parens = 0, pcount = 0, ecount = 0; char *q, *bx; struct FDB kw, nu; #ifdef FNFLOAT struct FDB fl; CKFLOAT f1 = 0.0, f2 = 0.0; int f1flag = 0, f2flag = 0; #endif /* FNFLOAT */ #ifdef OS2 extern int keymac; #endif /* OS2 */ char varnam[VNAML+1]; not = 0; /* Flag for whether "NOT" was seen */ z = 0; /* Initial IF condition */ ifargs = 0; /* Count of IF condition words */ bx = boolval; /* Initialize boolean value */ *bx = NUL; ifagain: cmfdbi(&kw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Number, numeric-valued variable, Boolean expression, or keyword", "", /* default */ "", /* addtl string data */ nif, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: 4 = silent */ xxstring, /* Processing function */ iftab, /* Keyword table */ &nu /* Pointer to next FDB */ ); cmfdbi(&nu, /* 2nd FDB - An integer */ _CMNUM, /* fcode */ "", /* hlpmsg */ "", /* Default */ "", /* addtl string data */ 0, 0, xxstring, NULL, #ifdef FNFLOAT &fl #else NULL #endif /* FNFLOAT */ ); #ifdef FNFLOAT cmfdbi(&fl, /* A floating-point number */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); #endif /* FNFLOAT */ x = cmfdb(&kw); /* Parse a keyword or a number */ debug(F111,"boolval cmfdb","",x); if (x < 0) { if (x == -3) x = -2; return(x); } debug(F111,"boolval switch","",cmresult.fcode); switch (cmresult.fcode) { /* What did we get? */ case _CMFLD: { /* A "field" */ int i; char * s; s = cmresult.sresult; /* fdc 2013/12/06 - Remember the variable name for error messages */ varnam[0] = NUL; i = ckindex("if ",cmdbuf,0,0,0); if (i) { i += 2; while (cmdbuf[i] == ' ') i++; if (cmdbuf[i]) { int j, k; j = i; k = 0; while (cmdbuf[j] && (cmdbuf[j] != ' ')) { varnam[k++] = cmdbuf[j++]; } varnam[k] = NUL; } } /* C-Kermit 9.0: This allows a macro name to serve as an IF condition without having to enclose it in \m(...). */ if ( #ifdef FNFLOAT !isfloat(cmresult.sresult,0) /* Not a number */ #else !chknum(cmresult.sresult) /* Not a number */ #endif /* FNFLOAT */ ) { i = mlook(mactab,cmresult.sresult,nmac); /* Look it up */ if (i > -1) /* in the macro table */ s = mactab[x].mval; /* and get its value */ else /* Otherwise if no such macro */ #ifdef COMMENT s = "0"; /* evaluate as FALSE (bad idea) */ #else { if (varnam[0]) printf("?Variable %s does not have a numeric value\n", varnam); else printf("?Not an IF condition, macro name or number: %s\n", cmresult.sresult); return(-9); } #endif /* COMMENT */ } #ifdef FNFLOAT if (isfloat(s,0)) { /* A floating-point number? */ f1 = floatval; /* Yes, get its value */ f1flag = 1; /* remember we did this */ ifc = 9999; /* Set special "if-code" */ } #else if (chknum(s)) { cmresult.nresult = atoi(s); ifc = 9999; break; } #endif /* FNFLOAT */ else return(-2); } case _CMNUM: /* A number... */ ifc = 9999; /* Set special "if-code" */ break; case _CMKEY: /* A keyword */ ifc = cmresult.nresult; /* Get if-code */ break; default: return(-2); } switch (ifc) { /* set z = 1 for true, 0 for false */ case 9999: /* Number */ #ifdef FNFLOAT if (f1flag) { z = (f1 == 0.0) ? 0 : 1; } else #endif /* FNFLOAT */ z = (cmresult.nresult == 0) ? 0 : 1; break; case XXIFLP: /* Left paren */ if (pcount == 0 && ifargs > 0) return(-2); parens = 1; pcount++; ifargs++; *bx++ = '('; goto ifagain; case XXIFRP: /* Right paren */ if (!parens) return(-2); if (--pcount < 0) return(-2); ifargs++; *bx++ = ')'; *bx = NUL; if (pcount == 0) goto ifend; goto ifagain; case XXIFAN: /* AND (&&) */ ifargs++; if (!ecount) return(-2); *bx++ = '&'; goto ifagain; case XXIFOR: /* OR (||) */ ifargs++; if (!ecount) return(-2); *bx++ = '|'; goto ifagain; case XXIFNO: /* IF NOT [ NOT [ NOT ... ] ] */ if (bx > boolval) { /* evala() doesn't like cascaded */ if (*(bx-1) == '!') { /* unary operators... */ *(bx-1) = NUL; /* So here, two wrongs make a right. */ bx--; } else { *bx++ = '!'; } } else { *bx++ = '!'; } ifargs++; goto ifagain; case XXIFTR: /* IF TRUE */ z = 1; debug(F101,"if true","",z); ifargs += 1; break; case XXIFNT: /* IF FALSE */ z = 0; debug(F101,"if true","",z); ifargs += 1; break; case XXIFSU: /* IF SUCCESS */ z = ( success != 0 ) ? 1 : 0; debug(F101,"if success","",z); ifargs += 1; break; case XXIFFA: /* IF FAILURE */ z = ( success == 0 ) ? 1 : 0; debug(F101,"if failure","",z); ifargs += 1; break; case XXIFDE: /* IF DEFINED */ if ((x = cmfld("Macro or variable name","",&s,NULL)) < 0) return((x == -3) ? -2 : x); if (*s == CMDQ) { char * lp; char line[256]; int t, x; if (*(s+1) == 'f' || *(s+1) == 'F') { /* Built-in function */ extern struct keytab fnctab[]; extern int nfuncs; ckstrncpy(line,s+2,256); if (line[0]) { lp = ckstrchr(line,'('); if (lp) *lp = NUL; x = lookup(fnctab,line,nfuncs,&t); z = x > -1; } debug(F111,"if defined function",line,z); } else if (*(s+1) == 'v' || *(s+1) == 'V') { /* 8.0.200 */ extern struct keytab vartab[]; extern int nvars; z = 0; if (*(s+2) == '(') { ckstrncpy(line,s+3,256); if (line[0]) { lp = ckstrchr(line,')'); if (lp) *lp = NUL; x = lookup(vartab,line,nvars,&t); z = x > -1; if (z) { /* 8.0.203 */ int t; /* It must have a value to succeed */ t = 255; /* as in C-Kermit 6.0 and 7.0 */ lp = line; /* (this was broken in 8.0.200-201) */ zzstring(s,&lp,&t); t = strlen(line); z = line[0] ? 1 : 0; } } } debug(F111,"if defined variable",line,z); } else { z = chkvar(s); /* Starts with backslash */ if (z > 0) { /* Yes... */ t = 255; /* than buffer so if zzstring fails */ lp = line; /* check for that -- overflow means */ line[0] = NUL; /* the quantity is defined. */ x = zzstring(s,&lp,&t); if ((x < 0 && t != 255) || !line[0]) z = 0; debug(F111,"if defined zzstring",line,z); debug(F101,"if defined zzstring t","",t); } } } else { z = (mxlook(mactab,s,nmac) > -1); /* Look for exact match */ } debug(F111,"if defined final",s,z); ifargs += 2; break; case XXIFDC: { /* IF DECLARED */ char * lp; char line[32]; int j, k, t, x; if ((x = cmfld("Array name","",&s,NULL)) < 0) return((x == -3) ? -2 : x); if (*s == CMDQ) { if (*(s+1) != '&') { t = 31; lp = line; line[0] = NUL; x = zzstring(s,&lp,&t); s = line; } } z = 0; if ((x = arraybounds(s,&j,&k)) > -1) { if (a_ptr[x]) { if (j < 1) z = 1; else if (j <= a_dim[x]) z = 1; if (z == 1 && k > a_dim[x]) z = 0; } } break; } case XXIFBG: /* IF BACKGROUND */ case XXIFFG: /* IF FOREGROUND */ bgchk(); /* Check background status */ if (ifc == XXIFFG) /* Foreground */ z = pflag ? 1 : 0; else z = pflag ? 0 : 1; /* Background */ ifargs += 1; break; case XXIFCO: /* IF COUNT */ z = ( --count[cmdlvl] > 0 ); if (cx == XXWHI) count[cmdlvl] += 2; /* Don't ask... */ debug(F101,"if count","",z); ifargs += 1; break; case XXIFEX: /* IF EXIST */ #ifdef CK_TMPDIR case XXIFDI: /* IF DIRECTORY */ #endif /* CK_TMPDIR */ case XXIFAB: /* IF ABSOLUTE */ case XXIFLN: /* IF LINK */ if ((x = cmfld( ((ifc == XXIFDI) ? "Directory name" : "File"), "",&s, #ifdef OS2 NULL /* This allows \'s in filenames */ #else xxstring #endif /* OS2 */ )) < 0) { if (x == -3) { extern int cmflgs; if (cmflgs == 1) { printf("?File or directory name required\n"); return(-9); } } else return(x); } s = brstrip(s); #ifdef UNIX if (ifc == XXIFLN) { z = isalink(s); } else #endif /* UNIX */ if (ifc == XXIFAB) { z = isabsolute(s); } else if (ifc == XXIFEX) { z = (zgetfs(s) > -1L); debug(F101,"if exist 1","",z); #ifdef OS2 if (!z) { /* File not found. */ int t; /* Try expanding variables */ t = LINBUFSIZ-1; /* and looking again. */ lp = line; zzstring(s,&lp,&t); s = line; z = ( zchki(s) > -1L ); debug(F101,"if exist 2","",z); } #endif /* OS2 */ #ifdef CK_TMPDIR } else { #ifdef VMS z = (zchki(s) == -2) #else /* Because this doesn't catch $DISK1:[FOO]BLAH.DIR;1 */ z = isdir(s) #ifdef OS2 || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL) #endif /* OS2 */ #endif /* VMS */ ; debug(F101,"if directory 1","",z); if (!z) { /* File not found. */ int t; /* Try expanding variables */ t = LINBUFSIZ-1; /* and looking again. */ lp = line; zzstring(s,&lp,&t); s = line; z = isdir(s) #ifdef OS2 || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL) #endif /* OS2 */ ; debug(F101,"if directory 2","",z); } #endif /* CK_TMPDIR */ } ifargs += 2; break; case XXIFEQ: /* IF EQUAL (string comparison) */ case XXIFLL: /* IF Lexically Less Than */ case XXIFLLE: /* IF Lexically Less Than or Equal */ case XXIFLG: /* If Lexically Greater Than */ case XXIFLGE: /* If Lexically Greater Than or Equal*/ case XXIFNN: /* If Lexically No Equal */ if ((x = cmfld("first word or variable name","",&s,xxstring)) < 0) { if (x == -3) { printf("?Text required\n"); return(-9); } else return(x); } s = brstrip(s); /* Strip braces */ x = (int)strlen(s); if (x > LINBUFSIZ-1) { printf("?IF: strings too long\n"); return(-2); } lp = line; /* lp points to first string */ ckstrncpy(line,s,LINBUFSIZ); if ((y = cmfld("second word or variable name","",&s,xxstring)) < 0) { if (y == -3) { printf("?Text required\n"); return(-9); } else return(y); } s = brstrip(s); y = (int)strlen(s); if (x + y + 2 > LINBUFSIZ) { printf("?IF: strings too long\n"); return(-2); } #ifdef COMMENT tp = lp + x + 2; /* tp points to second string */ strncpy(tp,s,LINBUFSIZ-x-3); #else tp = s; #endif /* COMMENT */ /*lexical:*/ x = ckstrcmp(lp,tp,-1,inpcas[cmdlvl]); /* Use longest length */ switch (ifc) { case XXIFEQ: /* EQUAL (string comparison) */ z = (x == 0); break; case XXIFLL: /* Lexically Less Than */ z = (x < 0); break; case XXIFLLE: /* Lexically Less Than or Equal */ z = (x <= 0); break; case XXIFLG: /* Lexically Greater Than */ z = (x > 0); break; case XXIFLGE: /* Lexically Greater Than or Equal */ z = (x >= 0); break; case XXIFNN: /* Lexically Not Equal */ z = (x != 0); break; } debug(F101,"IF EQ result","",z); ifargs += 3; break; case XXIFVE: /* IF VERSION */ case XXIFAE: /* IF (arithmetically) = */ case XXIFNQ: /* IF != (not arithmetically equal) */ case XXIFLT: /* IF < */ case XXIFLE: /* IF <= */ case XXIFGE: /* IF >= */ case XXIFGT: { /* IF > */ /* July 2006 - converted to use CK_OFF_T rather than int to */ /* allow long integers on platforms that have ck_off_t > 32 bits */ int xx; CK_OFF_T n1 = (CK_OFF_T)0, n2 = (CK_OFF_T)0; if (ifc == XXIFVE) { n1 = (CK_OFF_T) vernum; } else { x = cmfld("first number or variable name","",&s,xxstring); if (x == -3) { printf("?Quantity required\n"); return(-9); } if (x < 0) return(x); debug(F101,"xxifgt cmfld","",x); ckstrncpy(line,s,LINBUFSIZ); lp = brstrip(line); debug(F110,"xxifgt exp1",lp,0); /* The following bit is for compatibility with old versions of MS-DOS Kermit */ if (!ckstrcmp(lp,"count",5,0)) { n1 = (CK_OFF_T)count[cmdlvl]; } else if (!ckstrcmp(lp,"version",7,0)) { n1 = (CK_OFF_T) vernum; } else if (!ckstrcmp(lp,"argc",4,0)) { n1 = (CK_OFF_T) macargc[maclvl]; } else { /* End of compatibility bit */ #ifdef FNFLOAT if (isfloat(lp,0) > 1) { /* Allow floating-point comparisons */ f1 = floatval; f1flag = 1; } else #endif /* FNFLOAT */ if (chknum(lp)) { n1 = ckatofs(lp); } else { /* Check for arithmetic expression */ q = evala(lp); /* cmnum() does this but ... */ if (chknum(q)) { /* we're not using cmnum(). */ n1 = ckatofs(q); } else { printf("?Value not numeric - %s", lp); return(-9); } } } } y = cmfld("number or variable name","",&s,xxstring); if (y == -3) { printf("?Quantity required\n"); return(-9); } if (y < 0) return(y); s = brstrip(s); if (!*s) return(-2); if (ifc == XXIFVE) { tp = line; } else { x = (int)strlen(lp); tp = line + x + 2; } ckstrncpy(tp,s,LINBUFSIZ-x-2); debug(F110,"xxifgt exp2",tp,0); if (!ckstrcmp(tp,"count",5,0)) { n2 = (CK_OFF_T) count[cmdlvl]; } else if (!ckstrcmp(tp,"version",7,0)) { n2 = (CK_OFF_T) vernum; } else if (!ckstrcmp(tp,"argc",4,0)) { n2 = (CK_OFF_T) macargc[maclvl]; } else { #ifdef FNFLOAT if (isfloat(tp,0) > 1) { f2 = floatval; f2flag = 1; } else #endif /* FNFLOAT */ if (chknum(tp)) { n2 = ckatofs(tp); } else { q = evala(tp); if (chknum(q)) { /* we're not using cmnum(). */ n2 = ckatofs(q); } else { printf("?Value not numeric - %s", tp); return(-9); } } } xx = (ifc == XXIFVE) ? XXIFGE : ifc; #ifdef FNFLOAT if (f1flag && !f2flag) { f2 = (CKFLOAT)n2; f2flag = 1; } if (f2flag && !f1flag) f1 = (CKFLOAT)n1; if (f1flag) z = ((f1 < f2 && xx == XXIFLT) || (f1 != f2 && xx == XXIFNQ) || (f1 <= f2 && xx == XXIFLE) || (f1 == f2 && xx == XXIFAE) || (f1 >= f2 && xx == XXIFGE) || (f1 > f2 && xx == XXIFGT)); else #endif /* FNFLOAT */ z = ((n1 < n2 && xx == XXIFLT) || (n1 != n2 && xx == XXIFNQ) || (n1 <= n2 && xx == XXIFLE) || (n1 == n2 && xx == XXIFAE) || (n1 >= n2 && xx == XXIFGE) || (n1 > n2 && xx == XXIFGT)); debug(F101,"xxifge z","",z); if (ifc == XXIFVE) ifargs += 2; else ifargs += 3; break; } case XXIFNU: /* IF NUMERIC */ x = cmfld("variable name or constant","",&s,NULL); if (x == -3) { extern int cmflgs; if (cmflgs == 1) { printf("?Quantity required\n"); return(-9); } } else if (x < 0) return(x); x = LINBUFSIZ-1; lp = line; zzstring(s,&lp,&x); lp = line; debug(F110,"xxifnu quantity",lp,0); z = chknum(lp); #ifdef COMMENT /* This works, but it's not wise -- IF NUMERIC is mostly used to see if a string really does contain only numeric characters. If they want to force evaluation, they can use \feval() on the argument string. */ if (!z) { /* Not a number */ x_ifnum = 1; /* Avoid "eval" error messages */ q = evala(lp); /* Maybe it's an expression */ z = chknum(q); /* that evaluates to a number */ x_ifnum = 0; /* Put eval messages back to normal */ if (z) debug(F110,"xxifnu exp",lp,0); } #endif /* COMMENT */ debug(F101,"xxifnu chknum","",z); ifargs += 2; break; #ifdef ZFCDAT case XXIFNE: { /* IF NEWER */ char d1[20], * d2; /* Buffers for 2 dates */ if ((z = cmifi("First file","",&s,&y,xxstring)) < 0) return(z); ckstrncpy(d1,zfcdat(s),20); if ((z = cmifi("Second file","",&s,&y,xxstring)) < 0) return(z); d2 = zfcdat(s); if ((int)strlen(d1) != 17 || (int)strlen(d2) != 17) { printf("?Failure to get file date\n"); return(-9); } debug(F110,"xxifnewer d1",d1,0); debug(F110,"xxifnewer d2",d2,0); z = (strcmp(d1,d2) > 0) ? 1 : 0; debug(F101,"xxifnewer","",z); ifargs += 2; break; } #endif /* ZFCDAT */ #ifdef CK_IFRO case XXIFRO: /* REMOTE-ONLY advisory */ ifargs++; #ifdef NOLOCAL z = 1; #else z = remonly; #endif /* NOLOCAL */ break; #endif /* CK_IFRO */ case XXIFAL: /* ALARM */ ifargs++; debug(F101,"IF ALARM ck_alarm","",ck_alarm); debug(F110,"IF ALARM alrm_date",alrm_date,0); debug(F110,"IF ALARM alrm_time",alrm_time,0); if (ck_alarm < 1L || alrm_date[0] < '0' || alrm_time[0] < '0') { z = 0; /* ALARM not SET */ break; /* so IF ALARM fails */ } /* Get current date and time */ ckstrncpy(tmpbuf,ckcvtdate("",1),TMPBUFSIZ); s = tmpbuf; s[8] = NUL; z = (int) strncmp(tmpbuf,alrm_date,8); /* Compare dates */ debug(F101,"IF ALARM date z","",z); if (z == 0) { /* Dates are the same */ /* Compare times */ z = (tod2sec(tmpbuf+9) >= atol(alrm_time)) ? 1 : -1; debug(F101,"IF ALARM time z","",z); } tmpbuf[0] = NUL; /* z >= 0 if alarm is passed */ z = ((z >= 0) ? 1 : 0); /* z < 0 otherwise */ debug(F101,"IF ALARM final z","",z); break; case XXIFOP: /* IF OPEN */ if ((x = cmkey(iotab,niot,"file or log","",xxstring)) < 0) return(x); if (x == 9999 || x == ZSTDIO) { bgchk(); /* Check background status */ z = pflag ? 1 : 0; } else if (x == 8888) { z = local ? ttchk() > -1 : 0; #ifdef CKLOGDIAL } else if (x == 7777) { extern int dialog; z = dialog ? 1 : 0; #endif /* CKLOGDIAL */ } else z = (chkfn(x) > 0) ? 1 : 0; ifargs += 1; break; case XXIFSD: /* Started-From-Dialer */ #ifdef OS2 z = StartedFromDialer; #else z = 0; #endif /* OS2 */ break; case XXIFTM: /* Terminal-Macro */ #ifdef OS2 z = cmdstk[cmdlvl].ccflgs & CF_KMAC; #else z = 0; #endif /* OS2 */ break; case XXIFEM: /* Emulation is active */ #ifdef OS2 z = 1; #else z = 0; #endif /* OS2 */ break; case XXIFIK: /* Running as IKSD? */ z = inserver; break; case XXIFTA: /* Connection is TAPI */ z = 0; #ifndef NODIAL #ifdef CK_TAPI if (local && !network && tttapi) z = 1; #endif /* CK_TAPI */ #endif /* NODIAL */ break; case XXIFMA: /* IF MATCH */ x = cmfld("String or variable","",&s,xxstring); if (x == -3) { extern int cmflgs; if (cmflgs == 1) { printf("?String required\n"); return(-9); } } else if (x < 0) return(x); ckstrncpy(line,s,LINBUFSIZ); s = brstrip(line); debug(F110,"xxifma string",line,0); x = cmfld("Pattern","",&p,xxstring); if (x == -3) { extern int cmflgs; if (cmflgs == 1) { printf("?Pattern required\n"); return(-9); } } else if (x < 0) return(x); ckstrncpy(tmpbuf,p,TMPBUFSIZ); p = brstrip(tmpbuf); debug(F110,"xxifma pattern",tmpbuf,0); z = ckmatch(p,s,inpcas[cmdlvl],1); break; case XXIFFL: { /* IF FLAG */ extern int ooflag; z = ooflag; break; } case XXIFAV: { /* IF AVAILABLE */ if ((x = cmkey(availtab,availtabn,"","",xxstring)) < 0) return(x); switch (x) { case AV_KRB4: z = ck_krb4_is_installed(); break; case AV_KRB5: z = ck_krb5_is_installed(); break; case AV_SRP: z = ck_srp_is_installed(); break; case AV_SSL: z = ck_ssleay_is_installed(); break; case AV_NTLM: z = ck_ntlm_is_installed(); break; case AV_CRYPTO: z = ck_crypt_is_installed(); break; case AV_SSH: z = ck_ssh_is_installed(); break; default: z = 0; } break; } case XXIFAT: /* IF ASKTIMEOUT */ z = asktimedout; break; case XXIFRD: /* IF READABLE */ case XXIFWR: /* IF WRITEABLE */ if ((x = cmfld("File or directory name", "", &s, #ifdef OS2 NULL /* This allows \'s in filenames */ #else xxstring #endif /* OS2 */ )) < 0) { if (x == -3) { extern int cmflgs; if (cmflgs == 1) { printf("?File or directory name required\n"); return(-9); } } else return(x); } s = brstrip(s); /* zchk[io]() do not do what we want here for directories, so we set a global flag telling it to behave specially in this case. Othewise we'd have to change the API and change all ck?fio.c modules accordingly. */ y = 0; /* Try-again control */ #ifdef OS2 ifrdagain: #endif /* OS2 */ if (ifc == XXIFRD) { /* IF READABLE */ zchkid = 1; z = zchki(s) > -1; zchkid = 0; } else if (ifc == XXIFWR) { /* IF WRITEABLE */ zchkod = 1; z = zchko(s) > -1; zchkod = 0; } #ifdef OS2 if (!z && !y) { /* File not found. */ int t; /* Try expanding variables */ t = LINBUFSIZ-1; /* and looking again. */ lp = line; zzstring(s,&lp,&t); s = line; z = zchko(s) > -1; y++; goto ifrdagain; } #endif /* OS2 */ ifargs += 2; break; case XXIFQU: /* IF QUIET */ z = quiet ? 1 : 0; debug(F101,"if quiet","",z); ifargs += 1; break; case XXIFWI: /* WILD */ if ((x = cmfld("File specification","",&s,xxstring)) < 0) return(x); z = iswild(s); break; case XXIFCK: /* C-KERMIT */ #ifdef OS2 z = 0; #else z = 1; #endif /* OS2 */ break; case XXIFK9: /* K-95 */ #ifdef OS2 z = 1; #else z = 0; #endif /* OS2 */ break; case XXIFGU: /* GUI */ #ifdef KUI z = 1; #else z = 0; #endif /* KUI */ break; case XXIFMS: /* MS-KERMIT */ z = 0; break; case XXIFLO: /* IF LOCAL */ z = local ? 1 : 0; break; case XXIFCM: { /* IF COMMAND */ extern struct keytab cmdtab[]; extern int ncmd; if ((x = cmfld("Word","",&s,xxstring)) < 0) return(x); z = lookup(cmdtab,s,ncmd,&y); z = (z == -2 || z > -1) ? 1 : 0; break; } #ifdef CKFLOAT case XXIFFP: /* IF FLOAT */ if ((x = cmfld("Number","",&s,xxstring)) < 0) if (x != -3) /* e.g. empty variable */ return(x); z = isfloat(s,0); break; #endif /* CKFLOAT */ case XXIFKB: /* KBHIT */ z = conchk(); if (z < 0) z = 0; if (z > 1) z = 1; break; case XXIFKG: { /* KERBANG */ extern int cfilef; #ifdef COMMENT z = (xcmdsrc == 0) ? 0 : (cfilef && cmdlvl == 1); #else z = (xcmdsrc == 0) ? 0 : (cfilef && tlevel == 0); #endif /* COMMENT */ break; } case XXIFDB: { /* IF DEBUG - 2010/03/16 */ extern int debmsg; z = debmsg; break; } case XXIFFU: { /* IF FUNCTION - 2013/04/15 */ extern struct keytab fnctab[]; extern int nfuncs; int y; y = cmkeyx(fnctab,nfuncs,"Name of function","",NULL); if (y == -1) /* Reparse needed */ return(y); if (y < 0) { /* Something given but didn't match */ int dummy; char * p; for (p = atmbuf; *p; p++) { /* Chop off trailing parens if any */ if (*p == '(') { *p = NUL; break; } } /* Chop off leading "\\f" or "\f" or "f" */ p = atmbuf; if (*p == CMDQ) /* Allow for \\f... */ p++; if (*p == CMDQ && (*(p+1) == 'f' || *(p+1) == 'F')) { /* or \f */ p += 2; } else if (*p == 'f' || *p == 'F') { /* or just f */ p++; } y = lookup(fnctab,p,nfuncs,&dummy); /* Look up the result */ } z = (y < 1) ? 0 : 1; break; } case XXIFTXT: /* IF TEXT - 2013/04/17 */ case XXIFBIN: { /* IF BINARY - 2013/04/17 */ if ((x = cmifi("Filename","",&s,&y,xxstring)) < 0) return(x); if (y) { printf("?Please enter the name of a single file\n"); return(-9); } if (isdir(s)) { /* Is the file a directory? */ z = 0; } else { x = scanfile(s,NULL,nscanfile); if (x < 0) { printf("?Problem scanning %s\n",s); return(-9); } switch (x) { case FT_BIN: /* Binary */ z = (ifc == XXIFBIN) ? 1 : 0; break; case FT_7BIT: /* Different text encodings */ case FT_8BIT: case FT_UTF8: case FT_UCS2: case FT_TEXT: z = (ifc == XXIFTXT) ? 1 : 0; break; default: printf("?Problem scanning %s\n",s); return(-9); } } break; } default: /* Shouldn't happen */ return(-2); } /* end of switch */ if (z) *bx++ = '1'; else *bx++ = '0'; *bx = NUL; if (bx > boolval + BOOLLEN - 2) { printf("?Boolean expression too long"); return(-9); } ecount++; /* Expression counter */ debug(F101,"boolexp parens","",parens); debug(F101,"boolexp pcount","",pcount); if (parens && pcount > 0) goto ifagain; ifend: /* No more - done */ *bx = NUL; z = atoi(evalx(boolval)); debug(F111,"boolexp boolval",boolval,z); return(z); } /* D O I F -- Do the IF command */ int #ifdef CK_ANSIC doif( int cx ) #else doif(cx) int cx; #endif /* CK_ANSIC */ { int x, y, z; char *s, *p; #ifdef OS2 extern int keymac; #endif /* OS2 */ debug(F101,"doif cx","",cx); /* Boolexp() calls the parsing functions: cmkey, cmnum, cmfld */ z = boolexp(cx); /* Evaluate the condition(s) */ debug(F010,"doif cmdbuf",cmdbuf,0); debug(F101,"doif boolexp","",z); if (z < 0) return(z); if (cx == XXIF) { /* Allow IF to have XIF semantics. */ char * p; p = cmpeek(); if (!p) p = ""; while (*p) { if (*p == SP || *p == HT) p++; else break; } if (*p == '{') cx = XXIFX; } switch (cx) { /* Separate handling for IF and XIF */ case XXASSER: /* And ASSERT */ if ((x = cmcfm()) < 0) return(x); return(success = z); case XXIF: /* This is IF... */ ifcmd[cmdlvl] = 1; /* We just completed an IF command */ debug(F101,"doif condition","",z); if (z) { /* Condition is true */ iftest[cmdlvl] = 1; /* Remember that IF succeeded */ if (maclvl > -1) { /* In macro, */ pushcmd(NULL); /* save rest of command. */ } else if (tlevel > -1) { /* In take file, */ debug(F100, "doif: pushing command", "", 0); pushcmd(NULL); /* save rest of command. */ } else { /* If interactive, */ cmini(ckxech); /* just start a new command */ printf("\n"); /* (like in MS-DOS Kermit) */ if (pflag) prompt(xxstring); } } else { /* Condition is false */ iftest[cmdlvl] = 0; /* Remember command failed. */ if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0) return(y); /* Gobble up rest of line */ } return(0); case XXIFX: { /* This is XIF (Extended IF) */ char *p; char e[5]; int i; if ((y = cmtxt("Object command","",&s,NULL)) < 0) return(y); /* Get object command. */ p = s; lp = line; debug(F110,"doif THEN part",s,-54); if (litcmd(&p,&lp,LINBUFSIZ - 1) < 0) { /* Quote THEN-part */ return(-2); } debug(F111,"doif THEN part 2",line,z); while (*p == SP) p++; /* Strip trailing spaces */ ifcmd[cmdlvl] = 0; /* Assume ELSE part in same line */ iftest[cmdlvl] = z ? 1 : 0; if (*p) { /* At end? */ if (!z) { /* No, use ELSE-part, if any */ for (i = 0; i < 4; i++) e[i] = *p++; if (ckstrcmp(e,"else",4,0)) /* See if we have an ELSE */ return(-2); /* Something else - error. */ debug(F010,"doif ELSE line 1",p,0); while (*p == SP) p++; /* Skip spaces */ if (*p != '{') { /* Brace ELSE part if necessary */ ckmakmsg(tmpbuf,TMPBUFSIZ,"{",p," }",NULL); p = tmpbuf; debug(F010,"doif ELSE line 2",p,0); } lp = line; /* Write over THEN part... */ *lp = NUL; /* with ELSE part. */ if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) { return(-2); } while (*p == SP) p++; /* Strip trailing spaces */ if (*p) return(-2); /* Should be nothing here. */ debug(F010,"doif ELSE line 3",line,0); } } else { /* At end, treat like an IF command */ if (!z) line[0] = NUL; /* Condition not true and no ELSE */ ifcmd[cmdlvl] = 1; /* Allow ELSE on next line */ debug(F101,"IF condition","",z); } if (line[0]) { x = mlook(mactab,"_xif",nmac); /* Get index of "_xif" macro. */ if (x < 0) { /* Not there? */ addmmac("_xif",xif_def); /* Put it back. */ if (mlook(mactab,"_xif",nmac) < 0) { /* Look it up again. */ printf("?XIF macro gone!\n"); return(success = 0); } } dodo(x,line,cmdstk[cmdlvl].ccflgs | CF_IMAC); } return(0); } case XXWHI: { /* WHILE Command */ p = cmdbuf; /* Capture IF condition */ ifcond[0] = NUL; /* from command buffer */ while (*p == SP) p++; while (*p != SP) p++; ifcp = ifcond; ifcp += ckstrncpy(ifcp,"{ \\flit(if ( not ",IFCONDLEN); #ifdef COMMENT /* This doesn't work because it breaks on the first left brace, which does not necessarily start the command list, e.g. "while equal \%a {\35}". */ while (*p != '{' && *p != NUL) *ifcp++ = *p++; p = " ) goto _..bot) } "; while (*ifcp++ = *p++) ; #else /* The command parser sets cmbptr to the spot where it left off parsing in the command buffer. */ { extern char * cmbptr; if (cmbptr) { while (p < cmbptr && *p != NUL) *ifcp++ = *p++; p = " ) goto _..bot) } "; while ((*ifcp++ = *p++)) ; } else { printf("?Internal error parsing WHILE condition\n"); return(-9); } } #endif /* COMMENT */ debug(F110,"WHILE cmd",ifcond,0); if ((y = cmtxt("Object command","",&s,NULL)) < 0) return(y); /* Get object command. */ p = s; lp = line; if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) { /* Quote object command */ return(-2); } debug(F111,"WHILE body",line,-54); if (line[0]) { char *p; x = mlook(mactab,"_while",nmac); /* index of "_while" macro. */ if (x < 0) { /* Not there? */ addmmac("_while",whil_def); /* Put it back. */ /* Look it up again */ if ((x = mlook(mactab,"_while",nmac)) < 0) { printf("?WHILE macro definition gone!\n"); return(success = 0); } } p = malloc((int)strlen(ifcond) + (int)strlen(line) + 2); if (p) { strcpy(p,ifcond); /* safe (prechecked) */ strcat(p,line); /* safe (prechecked) */ debug(F110,"WHILE dodo",p,0); dodo(x,p,cmdstk[cmdlvl].ccflgs | CF_IMAC); free(p); p = NULL; } else { printf("?Can't allocate storage for WHILE command"); return(success = 0); } } return(0); } default: return(-2); } } #endif /* NOSPL */ /* Set up a TAKE command file */ int #ifdef CK_ANSIC dotake( char *s ) #else dotake(s) char *s; #endif /* CK_ANSIC */ { extern char lasttakeline[]; /* Last TAKE-file line */ #ifndef NOSPL extern int tra_cmd; #endif /* NOSPL */ #ifndef NOLOCAL #ifdef OS2 extern int term_io; int term_io_sav = term_io; #endif /* OS2 */ #endif /* NOLOCAL */ int slen; debug(F110,"dotake",s,0); if (!s) s = ""; if (!*s) return(success = 0); slen = strlen(s); debug(F101,"dotake len","",slen); if ((tfile[++tlevel] = fopen(s,"r")) == NULL) { perror(s); debug(F110,"dotake fail",s,0); tlevel--; return(success = 0); } else { lasttakeline[0] = NUL; tfline[tlevel] = 0; /* Line counter */ #ifdef VMS conres(); /* So Ctrl-C will work */ #endif /* VMS */ #ifndef NOLOCAL #ifdef OS2 term_io = 0; /* Disable Terminal Emulator I/O */ #endif /* OS2 */ #endif /* NOLOCAL */ #ifndef NOSPL cmdlvl++; /* Entering a new command level */ debug(F111,"CMD +F",s,cmdlvl); debug(F101,"dotake cmdlvl","",cmdlvl); debug(F101,"dotake tlevel","",tlevel); if (cmdlvl > CMDSTKL) { debug(F100,"dotake stack overflow","",0); cmdlvl--; debug(F111,"CMD*-F",s,cmdlvl); fclose(tfile[tlevel--]); printf("?TAKE files and/or DO commands nested too deeply\n"); return(success = 0); } if (tfnam[tlevel]) { /* Copy the filename */ free(tfnam[tlevel]); tfnam[tlevel] = NULL; } if ((tfnam[tlevel] = malloc(strlen(s) + 1))) { strcpy(tfnam[tlevel],s); /* safe */ } else { printf("?Memory allocation failure\n"); return(success = 0); } ifcmd[cmdlvl] = 0; /* Set variables for this cmd file */ iftest[cmdlvl] = 0; count[cmdlvl] = count[cmdlvl-1]; /* Inherit this */ intime[cmdlvl] = intime[cmdlvl-1]; /* Inherit this */ inpcas[cmdlvl] = inpcas[cmdlvl-1]; /* Inherit this */ takerr[cmdlvl] = takerr[cmdlvl-1]; /* Inherit this */ merror[cmdlvl] = merror[cmdlvl-1]; /* Inherit this */ xquiet[cmdlvl] = quiet; xvarev[cmdlvl] = vareval; xcmdsrc = CMD_TF; cmdstk[cmdlvl].src = CMD_TF; /* Say we're in a TAKE file */ cmdstk[cmdlvl].lvl = tlevel; /* nested at this level */ cmdstk[cmdlvl].ccflgs = cmdstk[cmdlvl-1].ccflgs; #else takerr[tlevel] = takerr[tlevel-1]; /* Inherit this */ #endif /* NOSPL */ } #ifndef NOSPL if (tra_cmd) printf("[%d] +F: \"%s\"\n",cmdlvl,s); #endif /* NOSPL */ #ifndef NOLOCAL #ifdef OS2 term_io = term_io_sav; #endif /* OS2 */ #endif /* NOLOCAL */ return(1); } #endif /* NOICP */ ckuus7.c000664 045065 024037 00002027037 14767411403 012572 0ustar00fdckermit000000 000000 #include "ckcsym.h" /* C K U U S 7 -- "User Interface" for C-Kermit, part 7 */ /* Authors: Frank da Cruz , The Kermit Project, New York City Jeffrey E Altman Secure Endpoints Inc., New York City Copyright (C) 1985, 2024, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Last big update: 14 April 2023 (ANSI function declarations and prototypes) Other updates: 5 May 2023 (change semicolon to comma in extern statement) Other updates: 25 Jan 2024 (add semantics of REMOTE CDUP) */ /* This file created from parts of ckuus3.c, which became too big for Mark Williams Coherent compiler to handle. */ /* Definitions here supersede those from system include files. */ #include "ckcdeb.h" /* Debugging & compiler things */ #include "ckcasc.h" /* ASCII character symbols */ #include "ckcker.h" /* Kermit application definitions */ #include "ckcxla.h" /* Character set translation */ #include "ckcnet.h" /* Network symbols */ #include "ckuusr.h" /* User interface symbols */ #include "ckucmd.h" #include "ckclib.h" #include "ckcfnp.h" /* Prototypes (must be last) */ #ifdef VMS #ifndef TCPSOCKET #include #endif /* TCPSOCKET */ #endif /* VMS */ #ifdef OS2 #ifndef NT #define INCL_NOPM #define INCL_VIO /* Needed for ckocon.h */ #define INCL_DOSMODULEMGR #define INCL_WINERRORS #include #undef COMMENT #else /* NT */ #define APIRET ULONG #include #ifdef CK_TAPI #include #include "ckntap.h" #endif /* CK_TAPI */ #include "cknwin.h" #endif /* NT */ #include "ckowin.h" #include "ckocon.h" #include "ckodir.h" #ifdef OS2MOUSE #include "ckokey.h" #endif /* OS2MOUSE */ #ifdef KUI #include "ikui.h" #endif /* KUI */ #ifdef putchar #undef putchar #endif /* putchar */ #define putchar(x) conoc(x) int popup_readpass(int,char*,char*,char*,int,int); /* ckocon.c */ int popup_readtext(int,char*,char*,char*,int,int); /* ckocon.c */ int cktomsk(int); /* ckokey.c */ int msktock(int); /* ckokey.c */ int os2settitle(char *, int); /* ckotio.c */ #ifdef KUI int setguifont(); /* ckuus3.c */ #endif extern int mskkeys; extern int mskrename; #endif /* OS2 */ #ifdef CK_AUTHENTICATION #include "ckuath.h" #endif /* CK_AUTHENTICATION */ #ifdef CK_SSL #include "ck_ssl.h" #endif /* CK_SSL */ #ifdef SSHBUILTIN #include "ckossh.h" #endif /* SSHBUILTIN */ #ifdef STRATUS /* Stratus Computer, Inc. VOS */ #ifdef putchar #undef putchar #endif /* putchar */ #define putchar(x) conoc(x) #ifdef getchar #undef getchar #endif /* getchar */ #define getchar(x) coninc(0) #endif /* STRATUS */ char * slmsg = NULL; static int x, y = 0, z; static char *s; extern CHAR feol; extern int g_matchdot, hints, xcmdsrc, rcdactive; extern char * k_info_dir; #ifdef CK_LOGIN #ifdef CK_PAM int gotemptypasswd = 0; /* distinguish empty passwd from none given */ #endif /* CK_PAM */ #endif /* CK_LOGIN */ #ifndef NOSPL extern int nmac; extern struct mtab *mactab; #endif /* NOSPL */ #ifndef NOXFER #ifdef CK_SPEED extern short ctlp[]; /* Control-char prefixing table */ #endif /* CK_SPEED */ #ifdef PIPESEND extern char * sndfilter, * g_sfilter; extern char * rcvfilter, * g_rfilter; #endif /* PIPESEND */ extern char * snd_move; extern char * snd_rename; extern char * g_snd_move; extern char * g_snd_rename; extern char * rcv_move; extern char * rcv_rename; extern char * g_rcv_move; extern char * g_rcv_rename; #ifdef PATTERNS extern char *binpatterns[], *txtpatterns[]; extern int patterns; #endif /* PATTERNS */ extern char * remdest; #ifdef CK_TMPDIR char * dldir = NULL; #endif /* CK_TMPDIR */ extern struct ck_p ptab[]; extern int protocol, remfile, rempipe, remappd, reliable, xreliable, fmask, fncnv, frecl, maxrps, wslotr, bigsbsiz, bigrbsiz, urpsiz, rpsiz, spsiz, bctr, npad, timef, timint, spsizr, spsizf, maxsps, spmax, nfils, displa, atcapr, pkttim, rtimo, fncact, mypadn, fdispla, f_save, pktpaus, setreliable, fnrpath, fnspath, atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko, attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso, rpsizf; extern int stathack; extern int atfrmi, atfrmo; #ifdef STRATUS extern int atcrei, atcreo, atacti, atacto; #endif /* STRATUS */ #ifdef CK_PERMS extern int atlpri, atlpro, atgpri, atgpro; #endif /* CK_PERMS */ extern CHAR sstate, eol, seol, stchr, mystch, mypadc, padch, ctlq, myctlq; #ifdef IKSD extern int inserver; #ifdef IKSDCONF extern int iksdcf; #endif /* IKSDCONF */ #endif /* IKSD */ extern char *cmarg, *cmarg2; #ifndef NOFRILLS extern char optbuf[]; /* Buffer for MAIL or PRINT options */ extern int rprintf; /* REMOTE PRINT flag */ #endif /* NOFRILLS */ #endif /* NOXFER */ #ifdef CK_TRIGGER extern char * tt_trigger[]; #endif /* CK_TRIGGER */ extern int tcs_transp; #ifdef PCTERM extern int tt_pcterm; #endif /* PCTERM */ #ifdef NT extern int tt_vtnt; #endif /* NT */ #ifdef SSHBUILTIN int sl_ssh_xfw = 0; int sl_ssh_xfw_saved = 0; int sl_ssh_ver = 0; int sl_ssh_ver_saved = 0; #endif /* SSHBUILTIN */ #ifdef CK_AUTHENTICATION extern int auth_type_user[]; int sl_auth_type_user[AUTHTYPLSTSZ] = {AUTHTYPE_NULL, AUTHTYPE_NULL}; int sl_auth_saved = 0; int sl_topt_a_su = 0; int sl_topt_a_s_saved = 0; int sl_topt_a_cm = 0; int sl_topt_a_c_saved = 0; #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION extern int cx_type; int sl_cx_type = 0; int sl_cx_saved = 0; int sl_topt_e_su = 0; int sl_topt_e_sm = 0; int sl_topt_e_s_saved = 0; int sl_topt_e_cu = 0; int sl_topt_e_cm = 0; int sl_topt_e_c_saved = 0; #endif /* CK_ENCRYPTION */ extern char uidbuf[]; static int uidflag = 0; char sl_uidbuf[UIDBUFLEN] = { NUL, NUL }; int sl_uid_saved = 0; #ifdef TNCODE int sl_tn_wait = 0; int sl_tn_saved = 0; #endif /* TNCODE */ #ifdef TNCODE extern int tn_wait_flg; #endif /* TNCODE */ VOID #ifdef CK_ANSIC slrestor(void) #else slrestor() #endif /* CK_ANSIC */ { #ifdef CK_AUTHENTICATION int x; if (sl_auth_saved) { for (x = 0; x < AUTHTYPLSTSZ; x++) auth_type_user[x] = sl_auth_type_user[x]; sl_auth_saved = 0; } if (sl_topt_a_s_saved) { TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = sl_topt_a_su; sl_topt_a_s_saved = 0; } if (sl_topt_a_c_saved) { TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = sl_topt_a_cm; sl_topt_a_c_saved = 0; } #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION if (sl_cx_saved) { cx_type = sl_cx_type; sl_cx_saved = 0; } if (sl_topt_e_s_saved) { TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = sl_topt_e_su; TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = sl_topt_e_sm; sl_topt_e_s_saved = 0; } if (sl_topt_e_c_saved) { TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = sl_topt_e_cu; TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = sl_topt_e_cm; sl_topt_e_c_saved = 0; } #endif /* CK_ENCRYPTION */ if (sl_uid_saved) { ckstrncpy(uidbuf,sl_uidbuf,UIDBUFLEN); sl_uid_saved = 0; } #ifdef TNCODE if (sl_tn_saved) { tn_wait_flg = sl_tn_wait; sl_tn_saved = 0; } #endif /* TNCODE */ #ifdef SSHBUILTIN if (sl_ssh_xfw_saved) { ssh_set_iparam(SSH_IPARAM_XFW, sl_ssh_xfw); sl_ssh_xfw_saved = 0; } if (sl_ssh_ver_saved) { ssh_set_iparam(SSH_IPARAM_VER, sl_ssh_ver); sl_ssh_ver_saved = 0; } #endif /* SSHBUILTIN */ } int oldplex = -1; /* Duplex holder around network */ #ifndef NOICP #ifdef LOCUS extern int locus, autolocus; #endif /* LOCUS */ #ifndef NODIAL extern int dialsta; #endif /* NODIAL */ /* Note: gcc -Wall wants braces around each keyword table entry. */ static struct keytab psltab[] = { /* SET LINE/PORT command options */ { "/connect", SL_CNX, 0 }, #ifdef OS2ORVMS { "/noshare", SL_NSH, 0 }, #endif /* OS2ORVMS */ { "/server", SL_SRV, 0 }, #ifdef OS2ORVMS { "/share", SL_SHR, 0 }, #endif /* OS2ORVMS */ { "", 0, 0 } }; static int npsltab = sizeof(psltab)/sizeof(struct keytab) - 1; #ifdef NETCONN static struct keytab shtab[] = { /* SET HOST command options */ #ifdef NETCMD /* (COMMAND is also a network type) */ { "/command", SL_CMD, CM_INV }, #endif /* NETCMD */ { "/connect", SL_CNX, 0 }, { "/network-type", SL_NET, CM_ARG }, { "/nowait", SL_NOWAIT, 0 }, #ifndef NOSPL #ifdef CK_AUTHENTICATION { "/password", SL_PSW, CM_ARG }, #endif /* CK_AUTHENTICATION */ #endif /* NOSPL */ #ifdef NETCMD { "/pipe", SL_CMD, 0 }, #endif /* NETCMD */ #ifdef NETPTY { "/pty", SL_PTY, 0 }, #endif /* NETPTY */ { "/server", SL_SRV, 0 }, #ifdef COMMENT /* The code implementing this was never written */ { "/timeout", SL_TMO, CM_ARG }, #endif /* COMMENT */ { "/userid", SL_UID, CM_ARG }, { "/wait", SL_WAIT, 0 }, { "", 0, 0 } }; static int nshtab = sizeof(shtab)/sizeof(struct keytab) - 1; static struct keytab shteltab[] = { /* TELNET command options */ #ifdef CK_AUTHENTICATION { "/auth", SL_AUTH, CM_ARG }, #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION { "/encrypt", SL_ENC, CM_ARG }, #endif /* CK_ENCRYPTION */ { "/nowait", SL_NOWAIT, 0 }, #ifndef NOSPL #ifdef CK_AUTHENTICATION { "/password", SL_PSW, CM_ARG }, #endif /* CK_AUTHENTICATION */ #endif /* NOSPL */ { "/timeout", SL_TMO, CM_ARG }, { "/userid", SL_UID, CM_ARG }, { "/wait", SL_WAIT, 0 }, { "", 0 ,0 } }; static int nshteltab = sizeof(shteltab)/sizeof(struct keytab) - 1; #ifdef RLOGCODE static struct keytab shrlgtab[] = { /* SET HOST RLOGIN command options */ #ifdef CK_KERBEROS #ifdef CK_ENCRYPTION { "/encrypt", SL_ENC, 0 }, #endif /* CK_ENCRYPTION */ { "/k4", SL_KRB4, CM_INV }, { "/k5", SL_KRB5, CM_INV }, { "/kerberos4", SL_KRB4, 0 }, { "/kerberos5", SL_KRB5, 0 }, { "/kerberos_iv", SL_KRB4, CM_INV }, { "/kerberos_v", SL_KRB5, CM_INV }, { "/krb4", SL_KRB4, CM_INV }, { "/krb5", SL_KRB5, CM_INV }, #endif /* CK_KERBEROS */ { "", 0 ,0 } }; static int nshrlgtab = sizeof(shrlgtab)/sizeof(struct keytab)-1; #endif /* RLOGCODE */ extern struct keytab netcmd[]; extern int nnets; #ifndef NODIAL extern int dirline; extern int nnetdir; /* Network services directory */ extern char *netdir[]; _PROTOTYP( VOID ndreset, (void) ); char *nh_p[MAXDNUMS + 1]; /* Network directory entry pointers */ char *nh_p2[MAXDNUMS + 1]; /* Network directory entry nettype */ char *nh_px[4][MAXDNUMS + 1]; /* Network-specific stuff... */ #endif /* NODIAL */ int nhcount = 0; int ndinited = 0; char * n_name = NULL; /* Network name pointer */ #endif /* NETCONN */ _PROTOTYP(int remtxt, (char **) ); _PROTOTYP(VOID rmsg, (void) ); _PROTOTYP(static int remcfm, (void) ); extern int nopush; int mdmsav = -1; /* Save modem type around network */ extern int isguest; /* Global flag for anonymous login */ extern xx_strp xxstring; extern int success, binary, b_save, ckwarn, msgflg, quiet, cmask, pflag, local, nettype, escape, mdmtyp, duplex, dfloc, network, cdtimo, autoflow, tnlm, sosi, tlevel, lf_opts, backgrd, flow, debses, parity, ttnproto, ckxech, x_ifnum, cmflgs, haveline, cxtype, cxflow[], maclvl; #ifdef DCMDBUF extern struct cmdptr *cmdstk; /* The command stack itself */ #else extern struct cmdptr cmdstk[]; /* The command stack itself */ #endif /* DCMDBUF */ extern FILE * tfile[]; extern char * macp[]; extern char psave[]; /* For saving & restoring prompt */ extern int sprmlen, rprmlen; #ifdef OS2 static struct keytab strmkeytab[] = { { "clear", 0, 0 }, { "default", 1, 0 } }; static int nstrmkeytab = sizeof(strmkeytab)/sizeof(struct keytab); static struct keytab strmswitab[] = { { "/literal", 0, 0 } }; static int nstrmswitab = sizeof(strmswitab)/sizeof(struct keytab); static struct keytab normrev[] = { { "dark-display", 0, 0 }, { "light-display", 1, 0 }, { "normal", 0, 0 }, { "reverse", 1, 0 } }; static struct keytab prnmtab[] = { { "auto", 1, 0 }, { "copy", 2, 0 }, { "off", 0, 0 }, { "on", 1, CM_INV }, /* Compatibility with XPRINT version */ { "user", 3, 0 }, { "transparent", 3, CM_INV } /* not really transparent */ }; static int nprnmtab = sizeof(prnmtab)/sizeof(struct keytab); extern int tt_diff_upd; #ifdef NT #define stricmp _stricmp extern int tt_attr_bug; #endif /* NT */ extern int tt_rows[], tt_cols[]; extern int tt_cols_usr; extern int tt_szchng[VNUM]; int tt_modechg = TVC_ENA; extern int tt_url_hilite, tt_url_hilite_attr; extern struct _vtG G[4]; extern int priority; extern bool send_c1; int send_c1_usr = FALSE; extern int sgrcolors; extern int marginbell, marginbellcol; extern int autoscroll, wy_autopage; extern int tt_sac; extern int dec_nrc, dec_lang, dec_kbd; #else /* OS2 */ extern int tt_rows, tt_cols; #endif /* OS2 */ extern int tt_escape; extern long speed; extern char *dftty; extern char *tp, *lp; /* Temporary buffer & pointers */ extern char ttname[]; #ifdef CK_TAPI int tttapi = 0; /* is Line TAPI? */ struct keytab * tapilinetab = NULL; struct keytab * _tapilinetab = NULL; int ntapiline = 0; #endif /* CK_TAPI */ #ifdef NETCONN /* Network items */ #ifdef ANYX25 extern int revcall, closgr, cudata, nx25; extern char udata[]; extern struct keytab x25tab[]; #ifndef IBMX25 extern int npadx3; extern CHAR padparms[]; extern struct keytab padx3tab[]; #endif /* IBMX25 */ #endif /* ANYX25 */ #ifdef OS2 extern bool ttshare; #ifndef NT extern bool ttslip,ttppp; #endif /* NT */ #endif /* OS2 */ #ifdef NPIPE extern char pipename[]; #endif /* NPIPE */ #ifdef TCPSOCKET static struct keytab tcprawtab[] = { /* SET HOST options */ { "/default", NP_DEFAULT, CM_INV }, #ifdef CK_AUTHENTICATION #ifdef CK_KERBEROS #ifdef RLOGCODE { "/ek4login", NP_EK4LOGIN, 0 }, { "/ek5login", NP_EK5LOGIN, 0 }, { "/k4login", NP_K4LOGIN, 0 }, { "/k5login", NP_K5LOGIN, 0 }, #endif /* RLOGCODE */ #ifdef KRB5_U2U { "/k5user2user", NP_K5U2U, 0 }, #endif /* KRB5_U2U */ #endif /* CK_KERBEROS */ #endif /* CK_AUTHENTICATION */ { "/no-telnet-init", NP_NONE, 0 }, { "/none", NP_NONE, CM_INV }, { "/raw-socket", NP_TCPRAW, 0 }, #ifdef RLOGCODE { "/rlogin", NP_RLOGIN, 0 }, #endif /* RLOGCODE */ #ifdef CK_SSL { "/ssl", NP_SSL, 0 }, { "/ssl-raw", NP_SSL_RAW, 0 }, { "/ssl-telnet", NP_SSL_TELNET, 0 }, #endif /* CK_SSL */ { "/telnet", NP_TELNET, 0 }, #ifdef CK_SSL { "/tls", NP_TLS, 0 }, { "/tls-raw", NP_TLS_RAW, 0 }, { "/tls-telnet", NP_TLS_TELNET, 0 }, #endif /* CK_SSL */ { "", 0, 0 } }; static int ntcpraw = (sizeof(tcprawtab) / sizeof(struct keytab)) - 1; #ifdef RLOGCODE _PROTOTYP( int rlog_naws, (void) ); #endif /* RLOGCODE */ #endif /* TCPSOCKET */ #ifdef SUPERLAT extern char slat_pwd[18]; #endif /* SUPERLAT */ #endif /* NETCONN */ #ifdef COMMENT #ifndef NOSETKEY extern KEY *keymap; #ifndef OS2 #define mapkey(x) keymap[x] #endif /* OS2 */ extern MACRO *macrotab; #ifndef NOKVERBS extern struct keytab kverbs[]; extern int nkverbs; #endif /* NOKVERBS */ #endif /* NOSETKEY */ #else #ifndef NOSETKEY extern KEY *keymap; extern MACRO *macrotab; #ifndef NOKVERBS extern struct keytab kverbs[]; extern int nkverbs; #endif /* NOKVERBS */ #endif /* NOSETKEY */ #endif /* COMMENT */ #ifdef OS2 /* AUTODOWNLOAD parameters */ extern int adl_kmode, adl_zmode; /* Match Packet to signal download */ extern char * adl_kstr; /* KERMIT Download String */ extern char * adl_zstr; /* ZMODEM Download String */ extern int adl_kc0, adl_zc0; /* Process ADL C0s in emulation */ #endif /* OS2 */ /* Keyword tables ... */ extern struct keytab onoff[], rltab[]; extern int nrlt; #ifndef NOCSETS static struct keytab fdfltab[] = { { "7bit-character-set", 7, 0 }, { "8bit-character-set", 8, 0 } }; static int nfdflt = (sizeof(fdfltab) / sizeof(struct keytab)); #endif /* NOCSETS */ /* SET FILE parameters */ static struct keytab filtab[] = { #ifndef NOXFER #ifdef PATTERNS { "binary-patterns", XYFIBP, 0 }, #endif /* PATTERNS */ { "bytesize", XYFILS, 0 }, #ifndef NOCSETS { "character-set", XYFILC, 0 }, #endif /* NOCSETS */ { "collision", XYFILX, 0 }, { "default", XYF_DFLT, 0 }, { "destination", XYFILY, 0 }, { "display", XYFILD, CM_INV }, #ifdef CK_TMPDIR { "download-directory", XYFILG, 0 }, #endif /* CK_TMPDIR */ #endif /* NOXFER */ { "end-of-line", XYFILA, 0 }, { "eol", XYFILA, CM_INV }, #ifdef CK_CTRLZ { "eof", XYFILV, 0 }, #endif /* CK_CTRLZ */ #ifndef NOXFER { "fastlookups", 9997, CM_INV }, { "incomplete", XYFILI, 0 }, #ifndef datageneral { "inspection", XYF_INSP, CM_INV }, #endif /* datageneral */ #ifdef CK_LABELED { "label", XYFILL, 0 }, #endif /* CK_LABELED */ #ifdef UNIX #ifdef DYNAMIC { "listsize", XYF_LSIZ, 0 }, #endif /* DYNAMIC */ #endif /* UNIX */ { "names", XYFILN, 0 }, #ifdef UNIX { "output", XYFILH, 0 }, #endif /* UNIX */ #ifdef PATTERNS { "patterns", XYFIPA, 0 }, #endif /* PATTERNS */ #ifdef COMMENT /* Not implemented (but see CHMOD) */ { "permissions", XYF_PRM, CM_INV }, { "protection", XYF_PRM, 0 }, #endif /* COMMENt */ #ifdef VMS { "record-length", XYFILR, 0 }, #endif /* VMS */ #ifndef datageneral { "scan", XYF_INSP, 0 }, #endif /* datageneral */ #ifdef UNIX #ifdef DYNAMIC { "stringspace", XYF_SSPA, 0 }, #endif /* DYNAMIC */ #endif /* UNIX */ #ifdef PATTERNS { "t", XYFILT, CM_INV|CM_ABR }, { "text-patterns", XYFITP, 0 }, #endif /* PATTERNS */ #endif /* NOXFER */ { "type", XYFILT, 0 }, #ifdef UNICODE { "ucs", XYFILU, 0 }, #endif /* UNICODE */ #ifndef NOXFER { "warning", XYFILW, CM_INV } #endif /* NOXFER */ }; static int nfilp = (sizeof(filtab) / sizeof(struct keytab)); struct keytab pathtab[] = { { "absolute", PATH_ABS, 0 }, { "none", PATH_OFF, CM_INV }, { "off", PATH_OFF, 0 }, { "on", PATH_ABS, CM_INV }, { "relative", PATH_REL, 0 } }; int npathtab = (sizeof(pathtab) / sizeof(struct keytab)); struct keytab rpathtab[] = { { "absolute", PATH_ABS, 0 }, { "auto", PATH_AUTO, 0 }, { "none", PATH_OFF, CM_INV }, { "off", PATH_OFF, 0 }, { "on", PATH_ABS, CM_INV }, { "relative", PATH_REL, 0 } }; int nrpathtab = (sizeof(rpathtab) / sizeof(struct keytab)); #ifdef CK_CTRLZ struct keytab eoftab[] = { /* EOF detection method */ { "ctrl-z", 1, 0 }, { "length", 0, 0 }, { "noctrl-z", 0, CM_INV } }; #endif /* CK_CTRLZ */ struct keytab fttab[] = { /* File types for SET FILE TYPE */ { "ascii", XYFT_T, CM_INV }, #ifdef VMS { "b", XYFT_B, CM_INV|CM_ABR }, #endif /* VMS */ { "binary", XYFT_B, 0 }, #ifdef VMS { "block", XYFT_I, CM_INV }, { "image", XYFT_I, 0 }, #endif /* VMS */ #ifdef CK_LABELED { "labeled", XYFT_L, 0 }, #endif /* CK_LABELED */ #ifdef MAC { "macbinary", XYFT_M, 0 }, #endif /* MAC */ { "text", XYFT_T, 0 } }; int nfttyp = (sizeof(fttab) / sizeof(struct keytab)); static struct keytab rfttab[] = { /* File types for REMOTE SET FILE */ { "ascii", XYFT_T, CM_INV }, { "binary", XYFT_B, 0 }, #ifdef VMS { "labeled", XYFT_L, 0 }, #else #ifdef OS2 { "labeled", XYFT_L, 0 }, #endif /* OS2 */ #endif /* VMS */ { "text", XYFT_T, 0 } }; static int nrfttyp = (sizeof(rfttab) / sizeof(struct keytab)); #ifdef UNIX #define ZOF_BLK 0 #define ZOF_NBLK 1 #define ZOF_BUF 2 #define ZOF_NBUF 3 static struct keytab zoftab[] = { { "blocking", ZOF_BLK, 0 }, { "buffered", ZOF_BUF, 0 }, { "nonblocking", ZOF_NBLK, 0 }, { "unbuffered", ZOF_NBUF, 0 } }; static int nzoftab = (sizeof(zoftab) / sizeof(struct keytab)); #endif /* UNIX */ extern int query; /* Global flag for QUERY active */ #ifndef NOSPL #ifndef NOXFER static struct keytab vartyp[] = { /* Variable types for REMOTE QUERY */ { "global", (int) 'G', CM_INV }, { "kermit", (int) 'K', 0 }, { "system", (int) 'S', 0 }, { "user", (int) 'G', 0 } }; static int nvartyp = (sizeof(vartyp) / sizeof(struct keytab)); #endif /* NOXFER */ #endif /* NOSPL */ #ifdef CK_TIMERS static struct keytab timotab[] = { /* Timer types */ { "dynamic", 1, 0 }, { "fixed", 0, 0 } }; #endif /* CK_TIMERS */ #ifdef DCMDBUF extern char *atxbuf, *atmbuf; /* Atom buffer */ extern char *cmdbuf; /* Command buffer */ extern char *line, *tmpbuf; /* Character buffers for anything */ extern int *intime; /* INPUT TIMEOUT */ #else /* Not DCMDBUF ... */ extern char atxbuf[], atmbuf[]; /* Atom buffer */ extern char cmdbuf[]; /* Command buffer */ extern char line[], tmpbuf[]; /* Character buffer for anything */ extern int intime[]; #endif /* DCMDBUF */ #ifndef NOCSETS extern struct keytab fcstab[]; /* For SET FILE CHARACTER-SET */ extern struct csinfo fcsinfo[]; /* File character set info. */ extern struct keytab ttcstab[]; extern int nfilc, fcharset, tcharset, ntermc, tcsr, tcsl, dcset7, dcset8; #ifdef CKOUNI extern int tt_utf8; #endif /* CKOUNI */ #ifdef OS2 _PROTOTYP( int os2setcp, (int) ); _PROTOTYP( int os2getcp, (void) ); _PROTOTYP( void os2debugoff, (void) ); #endif /* OS2 */ #endif /* NOCSETS */ extern int cmdlvl; /* Overall command level */ #ifndef NOSPL #ifdef DCMDBUF extern int *inpcas; /* INPUT CASE setting on cmd stack */ #else extern int inpcas[]; #endif /* DCMDBUF */ #endif /* NOSPL */ #ifdef CK_CURSES #ifndef VMS _PROTOTYP(int tgetent,(char *, char *)); #else #ifdef __DECC _PROTOTYP(int tgetent,(char *, char *)); #endif /* __DECC */ #endif /* VMS */ #endif /* CK_CURSES */ #ifndef NOXMIT #define XMITF 0 /* SET TRANSMIT values */ #define XMITL 1 /* (Local to this module) */ #define XMITP 2 #define XMITE 3 #define XMITX 4 #define XMITS 5 #define XMITW 6 #define XMITT 7 #define XMBUFL 50 extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw, xmitt; char xmitbuf[XMBUFL+1] = { NUL }; /* TRANSMIT eof string */ struct keytab xmitab[] = { /* SET TRANSMIT */ { "echo", XMITX, 0 }, { "eof", XMITE, 0 }, { "fill", XMITF, 0 }, { "linefeed", XMITL, 0 }, { "locking-shift", XMITS, 0 }, { "pause", XMITW, 0 }, { "prompt", XMITP, 0 }, { "timeout", XMITT, 0 } }; int nxmit = (sizeof(xmitab) / sizeof(struct keytab)); #endif /* NOXMIT */ /* For SET FILE COLLISION */ /* Some of the following may be possible for some C-Kermit implementations */ /* but not others. Those that are not possible for your implementation */ /* should be ifdef'd out. */ struct keytab colxtab[] = { /* SET FILE COLLISION options */ #ifndef MAC { "append", XYFX_A, 0 }, /* append to old file */ #endif /* MAC */ #ifdef COMMENT { "ask", XYFX_Q, 0 }, /* ask what to do (not implemented) */ #endif { "backup", XYFX_B, 0 }, /* rename old file */ #ifndef MAC /* This crashes Mac Kermit. */ { "discard", XYFX_D, CM_INV }, /* don't accept new file */ { "no-supersede", XYFX_D, CM_INV }, /* ditto (MSK compatibility) */ #endif /* MAC */ { "overwrite", XYFX_X, 0 }, /* overwrite the old file */ { "reject", XYFX_D, 0 }, /* (better word than discard) */ { "rename", XYFX_R, 0 }, /* rename the incoming file */ #ifndef MAC /* This crashes Mac Kermit. */ { "update", XYFX_U, 0 }, /* replace if newer */ #endif /* MAC */ { "", 0, 0 } }; int ncolx = (sizeof(colxtab) / sizeof(struct keytab)) - 1; static struct keytab rfiltab[] = { /* for REMOTE SET FILE */ #ifndef NOCSETS { "character-set", XYFILC, 0 }, #endif /* NOCSETS */ { "collision", XYFILX, 0 }, { "incomplete", XYFILI, 0 }, { "names", XYFILN, 0 }, { "record-length", XYFILR, 0 }, { "type", XYFILT, 0 } }; int nrfilp = (sizeof(rfiltab) / sizeof(struct keytab)); struct keytab eoltab[] = { /* File eof delimiters */ { "cr", XYFA_C, 0 }, { "crlf", XYFA_2, 0 }, { "lf", XYFA_L, 0 } }; static int neoltab = (sizeof(eoltab) / sizeof(struct keytab)); struct keytab fntab[] = { /* File naming */ { "converted", XYFN_C, 0 }, { "literal", XYFN_L, 0 }, { "standard", XYFN_C, CM_INV } }; int nfntab = (sizeof(fntab) / sizeof(struct keytab)); #ifndef NOLOCAL /* Terminal parameters table */ static struct keytab trmtab[] = { #ifdef OS2 { "answerback", XYTANS, 0 }, #endif /* OS2 */ #ifdef CK_APC { "apc", XYTAPC, 0 }, #endif /* CK_APC */ #ifdef OS2 { "arrow-keys", XYTARR, 0 }, #endif /* OS2 */ #ifdef NT { "at", XYTATTR, CM_INV|CM_ABR }, { "att", XYTATTR, CM_INV|CM_ABR }, { "attr", XYTATTR, CM_INV|CM_ABR }, { "attr-bug", XYTATTBUG, CM_INV }, #endif /* NT */ #ifdef OS2 { "attribute", XYTATTR, 0 }, #endif /* OS2 */ #ifdef CK_APC #ifdef CK_AUTODL { "autodownload", XYTAUTODL, 0, }, #endif /* CK_AUTODL */ #endif /* CK_APC */ #ifdef OS2 { "autopage", XYTAPAGE, 0 }, { "autoscroll", XYTASCRL, 0 }, { "bell", XYTBEL, CM_INV }, #endif /* OS2 */ { "bytesize", XYTBYT, 0 }, #ifndef NOCSETS { "character-set", XYTCS, 0 }, #endif /* NOCSETS */ #ifdef OS2 { "code-page", XYTCPG, 0 }, { "color", XYTCOL, 0 }, { "controls", XYTCTRL, 0 }, #endif /* OS2 */ { "cr-display", XYTCRD, 0 }, #ifdef OS2 { "cursor", XYTCUR, 0 }, #endif /* OS2 */ { "debug", XYTDEB, 0 }, #ifdef OS2 { "dg-unix-mode", XYTUNX, 0 }, #endif /* OS2 */ { "echo", XYTEC, 0 }, { "escape-character", XYTESC, 0 }, #ifdef OS2 #ifdef PCFONTS { "font", XYTFON, 0 }, #else #ifdef KUI { "font", XYTFON, 0 }, #endif /* KUI */ #endif /* PCFONTS */ #endif /* OS2 */ { "height", XYTHIG, 0 }, #ifdef CKTIDLE { "idle-action", XYTIACT, 0 }, { "idle-limit", XYTITMO, CM_INV }, { "idle-send", XYTIDLE, CM_INV }, { "idle-timeout", XYTITMO, 0 }, #endif /* CKTIDLE */ #ifdef OS2 #ifndef NOCSETS { "kbd-follows-gl/gr", XYTKBDGL, 0 }, #endif /* NOCSETS */ { "key", XYTKEY, 0 }, { "keyboard-mode", XYTKBMOD, 0 }, { "keypad-mode", XYTKPD, 0 }, #endif /* OS2 */ { "lf-display", XYTLFD, 0 }, #ifndef NOCSETS #ifdef OS2 #ifndef KUI { "line-spacing", XYTLSP, CM_INV }, { "local-character-set", XYTLCS, 0 }, #else { "line-spacing", XYTLSP, 0 }, { "local-character-set", XYTLCS, CM_INV }, #endif /* KUI */ #else { "local-character-set", XYTLCS, CM_INV }, #endif /* OS2 */ #endif /* NOCSETS */ { "locking-shift", XYTSO, 0 }, #ifdef OS2 { "margin-bell", XYTMBEL, 0 }, #endif /* OS2 */ #ifdef OS2MOUSE { "mouse", XYTMOU, CM_INV }, #endif /* OS2MOUSE */ { "newline-mode", XYTNL, 0 }, #ifdef OS2 { "output-pacing", XYTPAC, 0 }, #ifdef PCTERM { "pcterm", XYTPCTERM, 0 }, #endif /* PCTERM */ #endif /* OS2 */ #ifdef OS2ORUNIX { "print", XYTPRN, 0 }, #endif /* OS2ORUNIX */ #ifndef NOCSETS #ifdef OS2 { "remote-character-set", XYTRCS, 0 }, #else { "remote-character-set", XYTRCS, CM_INV }, #endif /* OS2 */ #endif /* NOCSETS */ #ifdef OS2 { "roll-mode", XYTROL, 0 }, { "s", XYTUPD, CM_ABR|CM_INV }, { "sc", XYTUPD, CM_ABR|CM_INV }, { "scr", XYTUPD, CM_ABR|CM_INV }, { "scree", XYTUPD, CM_ABR|CM_INV }, { "screen", XYTUPD, CM_ABR|CM_INV }, { "screen-", XYTUPD, CM_ABR|CM_INV }, { "screen-mode", XYTSCNM, 0 }, { "screen-optimize", XYTOPTI, 0 }, { "screen-update", XYTUPD, 0 }, { "scrollback", XYSCRS, 0 }, { "send-data", XYTSEND, 0 }, { "send-end-of-block", XYTSEOB, 0 }, { "sgr-colors", XYTSGRC, 0 }, { "sni-ch.code", XYTSNICC, 0 }, { "sni-firmware-versions", XYTSNIFV, 0 }, { "sni-language", XYTVTLNG, 0 }, { "sni-pagemode", XYTSNIPM, CM_INV }, { "sni-scrollmode", XYTSNISM, CM_INV }, { "spacing-attribute-character", XYTSAC, CM_INV }, { "statusline", XYTSTAT, 0 }, { "tra", XYTCTS, CM_INV|CM_ABR }, { "transmit-timeout", XYTCTS, 0 }, #endif /* OS2 */ #ifdef OS2ORUNIX { "transparent-print", XYTPRN, CM_INV }, #endif /* OS2ORUNIX */ #ifdef CK_TRIGGER { "trigger", XYTRIGGER,0 }, #endif /* CK_TRIGGER */ #ifdef OS2 { "type", XYTTYP, 0 }, #else { "type", XYTTYP, CM_INV }, #endif /* OS2 */ #ifndef NOCSETS #ifdef UNICODE #ifdef CKOUNI { "unicode", XYTUNI, CM_INV }, #endif /* CKOUNI */ #endif /* UNICODE */ #endif /* NOCSETS */ #ifdef OS2 { "unix-mode", XYTUNX, CM_INV }, { "url-highlight", XYTURLHI, 0 }, #ifdef NT { "video-change", XYTVCH, 0 }, #endif /* NT */ { "vt-language", XYTVTLNG, 0 }, { "vt-nrc-mode", XYTVTNRC, 0 }, #endif /* OS2 */ { "width", XYTWID, 0 }, #ifdef OS2 { "wrap", XYTWRP, 0 }, #endif /* OS2 */ { "", 0, 0 } }; int ntrm = (sizeof(trmtab) / sizeof(struct keytab)) - 1; #ifdef OS2 struct keytab termctrl[] = { /* SET TERM CONTROLS */ { "7", 7, 0 }, { "8", 8, 0 } }; int ntermctrl = (sizeof(termctrl) / sizeof(struct keytab)); struct keytab curontab[] = { /* SET TERM CURSOR */ #ifdef KUI { "noblink", 2, 0 }, #else { "noblink", 2, CM_INV }, #endif /* KUI */ { "off", 0, 0 }, { "on", 1, 0 } }; int ncuron = (sizeof(curontab) / sizeof(struct keytab)); struct keytab rolltab[] = { /* Set TERM Roll Options */ { "insert", TTR_INSERT, 0 }, { "keystrokes",TTR_KEYS, 0 }, { "off", TTR_OVER, CM_INV }, { "on", TTR_INSERT, CM_INV }, { "overwrite", TTR_OVER, 0 } }; int nroll = (sizeof(rolltab) / sizeof(struct keytab)); struct keytab rollkeytab[] = { /* Set TERM ROLL KEYSTROKES */ { "ignore", TTRK_IGN, 0 }, { "restore-and-send", TTRK_RST, 0 }, { "send", TTRK_SND, 0 } }; int nrollkey = (sizeof(rollkeytab) / sizeof(struct keytab)); #define TT_GR_ALL 4 #define TT_GR_G0 0 #define TT_GR_G1 1 #define TT_GR_G2 2 #define TT_GR_G3 3 #define TT_GR_KBD 4 struct keytab graphsettab[] = { /* DEC VT Graphic Sets */ { "all", TT_GR_ALL, 0 }, { "g0", TT_GR_G0, 0 }, { "g1", TT_GR_G1, 0 }, { "g2", TT_GR_G2, 0 }, { "g3", TT_GR_G3, 0 }, { "keyboard", TT_GR_KBD, 0 } }; int ngraphset = (sizeof(graphsettab) / sizeof(struct keytab)); #endif /* OS2 */ struct keytab adltab[] = { /* Autodownload Options */ { "ask", TAD_ASK, 0 }, { "error", TAD_ERR, 0 }, #ifdef OS2 { "kermit", TAD_K, 0 }, #endif /* OS2 */ { "off", TAD_OFF, 0 }, { "on", TAD_ON, 0 }, #ifdef OS2 { "zmodem", TAD_Z, 0 }, #endif /* OS2 */ { "", 0, 0 } }; int nadltab = (sizeof(adltab) / sizeof(struct keytab)) - 1; struct keytab adlerrtab[] = { /* Autodownload Error Options */ { "continue", 0, 0 }, { "go", 0, CM_INV }, { "stop", 1, 0 } }; int nadlerrtab = (sizeof(adlerrtab) / sizeof(struct keytab)); #ifdef OS2 struct keytab adlxtab[] = { /* Autodownload Options */ { "c0-conflicts", TAD_X_C0, 0 }, { "detection-method", TAD_X_DETECT, 0 }, { "string", TAD_X_STR, 0 } }; int nadlxtab = (sizeof(adlxtab) / sizeof(struct keytab)); struct keytab adldtab[] = { /* Auto-dl Detection Methods */ { "packet", ADL_PACK, 0 }, { "string", ADL_STR, 0 } }; int nadldtab = (sizeof(adldtab) / sizeof(struct keytab)); struct keytab adlc0tab[] = { /* Auto-dl Detection Methods */ { "ignored-by-emulator", 0, 0 }, { "processed-by-emulator", 1, 0 } }; int nadlc0tab = (sizeof(adlc0tab) / sizeof(struct keytab)); #ifndef NOCSETS struct keytab vtlangtab[] = { { "belgian", VTL_BELGIAN , 0 }, { "british", VTL_BRITISH , 0 }, { "canadian", VTL_CANADIAN, 0 }, { "czech", VTL_CZECH , 0 }, { "danish", VTL_DANISH , 0 }, { "dutch", VTL_DUTCH , 0 }, { "finnish", VTL_FINNISH , 0 }, { "french", VTL_FRENCH , 0 }, { "french-canadian",VTL_FR_CAN , 0 }, { "german", VTL_GERMAN , 0 }, { "greek", VTL_GREEK , 0 }, { "hebrew", VTL_HEBREW , 0 }, { "hungarian", VTL_HUNGARIA, 0 }, { "italian", VTL_ITALIAN , 0 }, { "latin-american", VTL_LATIN_AM, 0 }, { "north-american", VTL_NORTH_AM, 0 }, { "norwegian", VTL_NORWEGIA, 0 }, { "polish", VTL_POLISH , 0 }, { "portugese", VTL_PORTUGES, 0 }, { "romanian", VTL_ROMANIAN, 0 }, { "russian", VTL_RUSSIAN , 0 }, { "scs", VTL_SCS , CM_INV }, { "slovak", VTL_SLOVAK , 0 }, { "spanish", VTL_SPANISH , 0 }, { "swedish", VTL_SWEDISH , 0 }, { "swiss-french", VTL_SW_FR , 0 }, { "swiss-german", VTL_SW_GR , 0 }, { "turkish-f", VTL_TURK_F , CM_INV }, { "turkish-q", VTL_TURK_Q , CM_INV } }; int nvtlangtab = (sizeof(vtlangtab) / sizeof(struct keytab)); #endif /* NOCSETS */ #endif /* OS2 */ struct keytab crdtab[] = { /* Carriage-return display */ { "crlf", 1, 0 }, { "normal", 0, 0 } }; extern int tt_crd; /* Carriage-return display variable */ extern int tt_lfd; /* Linefeed display variable */ #ifdef CK_APC extern int apcstatus, apcactive; static struct keytab apctab[] = { /* Terminal APC parameters */ { "no-input", APC_ON|APC_NOINP,0 }, { "off", APC_OFF, 0 }, { "on", APC_ON, 0 }, { "unchecked", APC_ON|APC_UNCH, 0 }, { "unchecked-no-input", APC_ON|APC_NOINP|APC_UNCH, 0 } }; int napctab = (sizeof(apctab) / sizeof(struct keytab)); #endif /* CK_APC */ #endif /* NOLOCAL */ extern int autodl, adl_err, adl_ask; struct keytab beltab[] = { /* Terminal bell mode */ #ifdef OS2 { "audible", XYB_AUD, 0 }, { "none", XYB_NONE, 0 }, #else { "audible", XYB_AUD, CM_INV }, { "none", XYB_NONE, CM_INV }, #endif /* OS2 */ #ifdef OS2 { "off", XYB_NONE, CM_INV }, { "on", XYB_AUD, CM_INV }, #else { "off", XYB_NONE, 0 }, { "on", XYB_AUD, 0 }, #endif /* OS2 */ #ifdef OS2 { "visible", XYB_VIS, 0 }, #endif /* OS2 */ { "", 0, 0 } }; int nbeltab = sizeof(beltab)/sizeof(struct keytab) - 1; int tt_unicode = 1; /* Use Unicode if possible */ #ifdef CKTIDLE int tt_idlesnd_tmo = 0; /* Idle Send Timeout, disabled */ char * tt_idlesnd_str = NULL; /* Idle Send String, none */ char * tt_idlestr = NULL; extern int tt_idleact, tt_idlelimit; #endif /* CKTIDLE */ #ifdef OS2 #ifndef NOLOCAL /* OS/2 serial communication devices. */ struct keytab os2devtab[] = { { "1", 1, CM_INV }, /* Invisible synonyms, like */ { "2", 2, CM_INV }, /* "set port 1" */ { "3", 3, CM_INV }, { "4", 4, CM_INV }, { "5", 5, CM_INV }, { "6", 6, CM_INV }, { "7", 7, CM_INV }, { "8", 8, CM_INV }, { "com1", 1, 0 }, /* Real device names */ { "com2", 2, 0 }, { "com3", 3, 0 }, { "com4", 4, 0 }, { "com5", 5, 0 }, { "com6", 6, 0 }, { "com7", 7, 0 }, { "com8", 8, 0 }, #ifdef OS2ONLY { "slipcom1", 1, 0 }, /* For use with SLIP driver */ { "slipcom2", 2, 0 }, /* shared access */ { "slipcom3", 3, 0 }, { "slipcom4", 4, 0 }, { "slipcom5", 5, 0 }, { "slipcom6", 6, 0 }, { "slipcom7", 7, 0 }, { "slipcom8", 8, 0 }, { "pppcom1", 1, 0 }, /* For use with PPP driver */ { "pppcom2", 2, 0 }, /* shared access */ { "pppcom3", 3, 0 }, { "pppcom4", 4, 0 }, { "pppcom5", 5, 0 }, { "pppcom6", 6, 0 }, { "pppcom7", 7, 0 }, { "pppcom8", 8, 0 } #endif /* OS2ONLY */ }; int nos2dev = (sizeof(os2devtab) / sizeof(struct keytab)) - 1; #ifdef OS2ONLY struct keytab os2ppptab[] = { { "0", 0, CM_INV }, { "1", 1, CM_INV }, /* Invisible synonyms, like */ { "2", 2, CM_INV }, /* "set port 1" */ { "3", 3, CM_INV }, { "4", 4, CM_INV }, { "5", 5, CM_INV }, { "6", 6, CM_INV }, { "7", 7, CM_INV }, { "8", 8, CM_INV }, { "9", 9, CM_INV }, { "ppp0", 0, 0 }, { "ppp1", 1, 0 }, /* For use with PPP driver */ { "ppp2", 2, 0 }, /* shared access */ { "ppp3", 3, 0 }, { "ppp4", 4, 0 }, { "ppp5", 5, 0 }, { "ppp6", 6, 0 }, { "ppp7", 7, 0 }, { "ppp8", 8, 0 }, { "ppp9", 9, 0 } }; int nos2ppp = (sizeof(os2ppptab) / sizeof(struct keytab)); #endif /* OS2ONLY */ /* Terminal parameters that can be set by SET commands. Used by the ck?con.c terminal emulator code. For now, only used for #ifdef OS2. Should add these for Macintosh. */ int tt_arrow = TTK_NORM; /* Arrow key mode: normal (cursor) */ int tt_keypad = TTK_NORM; /* Keypad mode: normal (numeric) */ int tt_shift_keypad = 0; /* Keypad Shift mode: Off */ int tt_wrap = 1; /* Terminal wrap, 1 = On */ int tt_type = TT_VT220; /* Terminal type, initially VT220 */ int tt_type_mode = TT_VT220; /* Terminal type set by host command */ int tt_cursor = 0; /* Terminal cursor, 0 = Underline */ int tt_cursor_usr = 0; /* Users Terminal cursor type */ int tt_cursorena_usr = 1; /* Users Terminal cursor enabled */ int tt_cursor_blink = 1; /* Terminal Cursor Blink */ int tt_answer = 0; /* Terminal answerback (disabled) */ int tt_scrsize[VNUM] = {512,512,512,1}; /* Terminal scrollback buffer size */ int tt_roll[VNUM] = {1,1,1,1}; /* Terminal roll (on) */ int tt_rkeys[VNUM] = {1,1,1,1}; /* Terminal roll keys (send) */ int tt_pacing = 0; /* Terminal output-pacing (none) */ int tt_ctstmo = 15; /* Terminal transmit-timeout */ int tt_codepage = -1; /* Terminal code-page */ int tt_update = 100; /* Terminal screen-update interval */ int tt_updmode = TTU_FAST; /* Terminal screen-update mode FAST */ extern int updmode; #ifndef KUI int tt_status[VNUM] = {1,1,0,0}; /* Terminal status line displayed */ int tt_status_usr[VNUM] = {1,1,0,0}; #else /* KUI */ extern CKFLOAT floatval; CKFLOAT tt_linespacing[VNUM] = {1.0,1.0,1.0,1.0}; #ifdef K95G int tt_status[VNUM] = {1,1,0,0}; /* Terminal status line displayed */ int tt_status_usr[VNUM] = {1,1,0,0}; #else /* K95G */ int tt_status[VNUM] = {0,0,0,0}; /* Terminal status line displayed */ int tt_status_usr[VNUM] = {0,0,0,0}; #endif /* K95G */ #endif /* KUI */ int tt_senddata = 0; /* Let host read terminal data */ extern int wy_blockend; /* Terminal Send Data EOB type */ int tt_hidattr = 1; /* Attributes are hidden */ extern unsigned char colornormal, colorselect, colorunderline, colorstatus, colorhelp, colorborder, colorgraphic, colordebug, colorreverse, coloritalic; extern int trueblink, trueunderline, truereverse, trueitalic, truedim; extern int bgi, fgi; extern int scrninitialized[]; struct keytab audibletab[] = { /* Terminal Bell Audible mode */ { "beep", XYB_BEEP, 0 }, /* Values ORd with bell mode */ { "system-sounds", XYB_SYS, 0 } }; int naudibletab = sizeof(audibletab)/sizeof(struct keytab); struct keytab akmtab[] = { /* Arrow key mode */ { "application", TTK_APPL, 0 }, { "cursor", TTK_NORM, 0 } }; struct keytab kpmtab[] = { /* Keypad mode */ { "application", TTK_APPL, 0 }, { "numeric", TTK_NORM, 0 } }; struct keytab ttcolmodetab[] = { { "current-color", 0, 0 }, { "default-color", 1, 0 } }; int ncolmode = sizeof(ttcolmodetab)/sizeof(struct keytab); #define TTCOLNOR 0 #define TTCOLREV 1 #define TTCOLUND 2 #define TTCOLSTA 3 #define TTCOLHLP 4 #define TTCOLBOR 5 #define TTCOLSEL 6 #define TTCOLDEB 7 #define TTCOLGRP 8 #define TTCOLITA 9 #define TTCOLRES 10 #define TTCOLERA 11 struct keytab ttycoltab[] = { /* Terminal Screen coloring */ { "border", TTCOLBOR, 0 }, /* Screen border color */ { "debug-terminal", TTCOLDEB, 0 }, /* Debug color */ { "erase", TTCOLERA, 0 }, /* Erase mode */ { "graphic", TTCOLGRP, 0 }, /* Graphic Color */ { "help-text", TTCOLHLP, 0 }, /* Help screens */ { "italic", TTCOLITA, 0 }, /* Italic Color */ { "normal", TTCOLNOR, CM_INV }, /* Normal screen text */ { "reset-on-esc[0m", TTCOLRES, 0 }, /* Reset on ESC [ 0 m */ { "reverse-video", TTCOLREV, 0 }, /* Reverse video */ { "status-line", TTCOLSTA, 0 }, /* Status line */ { "selection", TTCOLSEL, 0 }, /* Selection color */ { "terminal-screen", TTCOLNOR, 0 }, /* Better name than "normal" */ { "underlined-text", TTCOLUND, 0 } /* Underlined text */ }; int ncolors = (sizeof(ttycoltab) / sizeof(struct keytab)); #define TTATTNOR 0 #define TTATTBLI 1 #define TTATTREV 2 #define TTATTUND 3 #define TTATTPRO 4 #define TTATTBLD 5 #define TTATTDIM 6 #define TTATTINV 7 #define TTATTITA 8 #define TTATTDONE 9 struct keytab ttyattrtab[] = { { "blink", TTATTBLI, 0 }, { "dim", TTATTDIM, 0 }, { "italic", TTATTITA, 0 }, { "protected", TTATTPRO, 0 }, { "reverse", TTATTREV, 0 }, { "underline", TTATTUND, 0 } }; int nattrib = (sizeof(ttyattrtab) / sizeof(struct keytab)); struct keytab ttyprotab[] = { { "blink", TTATTBLI, 0 }, { "bold", TTATTBLD, 0 }, { "dim", TTATTDIM, 0 }, { "done", TTATTDONE, CM_INV }, { "invisible", TTATTINV, 0 }, { "italic", TTATTITA, 0 }, { "normal", TTATTNOR, 0 }, { "reverse", TTATTREV, 0 }, { "underlined", TTATTUND, 0 } }; int nprotect = (sizeof(ttyprotab) / sizeof(struct keytab)); struct keytab ttyseobtab[] = { { "crlf_etx", 1, 0 }, { "us_cr", 0, 0 } }; struct keytab ttyclrtab[] = { /* Colors */ { "black", 0, 0 }, { "blue", 1, 0 }, { "brown", 6, 0 }, { "cyan", 3, 0 }, { "darkgray", 8, CM_INV }, { "dgray", 8, 0 }, { "green", 2, 0 }, { "lblue", 9, CM_INV }, { "lcyan", 11, CM_INV }, { "lgray", 7, CM_INV }, { "lgreen", 10, CM_INV }, { "lightblue", 9, 0 }, { "lightcyan", 11, 0 }, { "lightgray", 7, 0 }, { "lightgreen", 10, 0 }, { "lightmagenta", 13, 0 }, { "lightred", 12, 0 }, { "lmagenta", 13, CM_INV }, { "lred", 12, CM_INV }, { "magenta", 5, 0 }, { "red", 4, 0 }, { "white", 15, 0 }, { "yellow", 14, 0 } }; int nclrs = (sizeof (ttyclrtab) / sizeof (struct keytab)); struct keytab ttycurtab[] = { { "full", TTC_BLOCK, 0 }, { "half", TTC_HALF, 0 }, { "underline", TTC_ULINE, 0 } }; int ncursors = 3; struct keytab ttyptab[] = { { "aaa", TT_AAA, CM_INV }, /* AnnArbor */ { "adm3a", TT_ADM3A, 0 }, /* LSI ADM-3A */ { "adm5", TT_ADM5, 0 }, /* LSI ADM-5 */ { "aixterm", TT_AIXTERM, 0 }, /* IBM AIXterm */ { "annarbor", TT_AAA, 0 }, /* AnnArbor */ { "ansi-bbs", TT_ANSI, 0 }, /* ANSI.SYS (BBS) */ { "at386", TT_AT386, 0 }, /* Unixware ANSI */ { "avatar/0+",TT_ANSI, 0 }, /* AVATAR/0+ */ { "ba80", TT_BA80, 0 }, /* Nixdorf BA80 */ { "be", TT_BEOS, CM_INV|CM_ABR }, { "beos-ansi",TT_BEOS, CM_INV }, /* BeOS ANSI */ { "beterm", TT_BEOS, 0 }, /* BeOS Terminal (as of PR2 ) */ { "d200", TT_DG200, CM_INV|CM_ABR }, /* Data General DASHER 200 */ { "d210", TT_DG210, CM_INV|CM_ABR }, /* Data General DASHER 210 */ { "d217", TT_DG217, CM_INV|CM_ABR }, /* Data General DASHER 217 */ { "dg200", TT_DG200, 0 }, /* Data General DASHER 200 */ { "dg210", TT_DG210, 0 }, /* Data General DASHER 210 */ { "dg217", TT_DG217, 0 }, /* Data General DASHER 217 */ { "h1500", TT_HZL1500, CM_INV }, /* Hazeltine 1500 */ { "h19", TT_H19, CM_INV }, /* Heath-19 */ { "heath19", TT_H19, 0 }, /* Heath-19 */ { "hft", TT_HFT, 0 }, /* IBM High Function Terminal */ { "hp2621a", TT_HP2621, 0 }, /* HP 2621A */ { "hpterm", TT_HPTERM, 0 }, /* HP TERM */ { "hz1500", TT_HZL1500, 0 }, /* Hazeltine 1500 */ { "ibm3151", TT_IBM31, 0 }, /* IBM 3101-xx,3161 */ { "linux", TT_LINUX, 0 }, /* Linux */ { "qansi", TT_QANSI, 0 }, /* QNX ANSI */ { "qnx", TT_QNX, 0 }, /* QNX Console */ { "scoansi", TT_SCOANSI, 0 }, /* SCO ANSI */ { "sni-97801",TT_97801, 0 }, /* SNI 97801 */ { "sun", TT_SUN, 0 }, /* SUN Console */ /* The idea of NONE is to let the console driver handle the escape sequences, which, in theory at least, would give not only ANSI emulation, but also any other kind of emulation that might be provided by alternative console drivers, if any existed. For this to work, ckocon.c would need to be modified to make higher-level calls, like VioWrtTTY(), DosWrite(), or (simply) write(), rather than VioWrt*Cell() and similar, and it would also have to give up its rollback feature, and its status line and help screens would also have to be forgotten or else done in an ANSI way. As matters stand, we already have perfectly good ANSI emulation built in, and there are no alternative console drivers available, so there is no point in having a terminal type of NONE, so it is commented out. However, should you uncomment it, it will work like a "glass tty" -- no escape sequence interpretation at all; somewhat similar to debug mode, except without the debugging (no highlighting of control chars or escape sequences); help screens, status line, and rollback will still work. */ #ifdef OS2PM #ifdef COMMENT { "tek4014", TT_TEK40, 0 }, #endif /* COMMENT */ #endif /* OS2PM */ { "tty", TT_NONE, 0 }, { "tvi910+", TT_TVI910, 0 }, { "tvi925", TT_TVI925, 0 }, { "tvi950", TT_TVI950, 0 }, { "vc404", TT_VC4404, 0 }, { "vc4404", TT_VC4404, CM_INV }, { "vip7809", TT_VIP7809,0 }, { "vt100", TT_VT100, 0 }, { "vt102", TT_VT102, 0 }, { "vt220", TT_VT220, 0 }, { "vt220pc", TT_VT220PC,0 }, { "vt320", TT_VT320, 0 }, { "vt320pc", TT_VT320PC,0 }, { "vt52", TT_VT52, 0 }, #ifdef NT { "vtnt", TT_VTNT, 0 }, #else /* NT */ { "vtnt", TT_VTNT, CM_INV }, #endif /* NT */ { "wy160", TT_WY160, 0 }, { "wy30", TT_WY30, 0 }, { "wy370", TT_WY370, 0 }, { "wy50", TT_WY50, 0 }, { "wy60", TT_WY60, 0 }, { "wyse30", TT_WY30, CM_INV }, { "wyse370", TT_WY370, CM_INV }, { "wyse50", TT_WY50, CM_INV }, { "wyse60", TT_WY60, CM_INV } }; int nttyp = (sizeof(ttyptab) / sizeof(struct keytab)); struct keytab ttkeytab[] = { { "aaa", TT_AAA, CM_INV }, /* AnnArbor */ { "adm3a", TT_ADM3A, 0 }, /* LSI ADM-3A */ { "adm5", TT_ADM5, 0 }, /* LSI ADM-5 */ { "aixterm", TT_AIXTERM, 0 }, /* IBM AIXterm */ { "annarbor", TT_AAA, 0 }, /* AnnArbor */ { "ansi-bbs", TT_ANSI, 0 }, /* ANSI.SYS (BBS) */ { "at386", TT_AT386, 0 }, /* Unixware ANSI */ { "avatar/0+", TT_ANSI, 0 }, /* AVATAR/0+ */ { "ba80", TT_BA80, 0 }, /* Nixdorf BA80 */ { "be", TT_BEOS, CM_INV|CM_ABR }, { "beos-ansi", TT_BEOS, CM_INV }, /* BeOS ANSI */ { "beterm", TT_BEOS, 0 }, /* BeOS Terminal (DR2) */ { "d200", TT_DG200, CM_INV|CM_ABR }, /* DG DASHER 200 */ { "d210", TT_DG210, CM_INV|CM_ABR }, /* DG DASHER 210 */ { "d217", TT_DG217, CM_INV|CM_ABR }, /* DG DASHER 217 */ { "dg200", TT_DG200, 0 }, /* DG DASHER 200 */ { "dg210", TT_DG210, 0 }, /* DG DASHER 210 */ { "dg217", TT_DG217, 0 }, /* DG DASHER 217 */ { "emacs", TT_KBM_EMACS, 0 }, /* Emacs mode */ { "h19", TT_H19, CM_INV }, /* Heath-19 */ { "heath19", TT_H19, 0 }, /* Heath-19 */ { "hebrew", TT_KBM_HEBREW, 0 }, /* Hebrew mode */ { "hft", TT_HFT, 0 }, /* IBM High Function Term */ { "hp2621a", TT_HP2621, 0 }, /* HP 2621A */ { "hpterm", TT_HPTERM, 0 }, /* HP TERM */ { "hz1500", TT_HZL1500, 0 }, /* Hazeltine 1500 */ { "ibm3151", TT_IBM31, 0 }, /* IBM 3101-xx,3161 */ { "linux", TT_LINUX, 0 }, /* Linux */ { "qansi", TT_QANSI, 0 }, /* QNX ANSI */ { "qnx", TT_QNX, 0 }, /* QNX */ { "russian", TT_KBM_RUSSIAN,0 }, /* Russian mode */ { "scoansi", TT_SCOANSI, 0 }, /* SCO ANSI */ { "sni-97801", TT_97801, 0 }, /* SNI 97801 */ { "sun", TT_SUN, 0 }, /* SUN Console */ #ifdef OS2PM #ifdef COMMENT { "tek4014", TT_TEK40, 0 }, #endif /* COMMENT */ #endif /* OS2PM */ { "tty", TT_NONE, 0 }, { "tvi910+", TT_TVI910, 0 }, { "tvi925", TT_TVI925, 0 }, { "tvi950", TT_TVI950, 0 }, { "vc404", TT_VC4404, 0 }, { "vc4404", TT_VC4404, CM_INV }, { "vip7809", TT_VIP7809, 0 }, { "vt100", TT_VT100, 0 }, { "vt102", TT_VT102, 0 }, { "vt220", TT_VT220, 0 }, { "vt220pc", TT_VT220PC, 0 }, { "vt320", TT_VT320, 0 }, { "vt320pc", TT_VT320PC, 0 }, { "vt52", TT_VT52, 0 }, { "vtnt", TT_VTNT, CM_INV }, { "wp", TT_KBM_WP, 0 }, /* Word Perfect mode */ { "wy160", TT_WY160, 0 }, { "wy30", TT_WY30, 0 }, { "wy370", TT_WY370, 0 }, { "wy50", TT_WY50, 0 }, { "wy60", TT_WY60, 0 }, { "wyse30", TT_WY30, CM_INV }, { "wyse370", TT_WY370, CM_INV }, { "wyse50", TT_WY50, CM_INV }, { "wyse60", TT_WY60, CM_INV } }; int nttkey = (sizeof(ttkeytab) / sizeof(struct keytab)); #ifndef NOSETKEY struct keytab kbmodtab[] = { { "emacs", KBM_EM, 0 }, { "english", KBM_EN, CM_INV }, { "hebrew", KBM_HE, 0 }, { "normal", KBM_EN, 0 }, { "none", KBM_EN, CM_INV }, { "russian", KBM_RU, 0 }, { "wp", KBM_WP, 0 } }; int nkbmodtab = (sizeof(kbmodtab) / sizeof(struct keytab)); #endif /* NOSETKEY */ #endif /* NOLOCAL */ int tt_inpacing = 0; /* input-pacing (none) */ struct keytab prtytab[] = { /* OS/2 Priority Levels */ { "foreground-server", XYP_SRV, 0 }, { "idle", XYP_IDLE, CM_INV }, { "regular", XYP_REG, 0 }, { "time-critical", XYP_RTP, 0 } }; int nprty = (sizeof(prtytab) / sizeof(struct keytab)); #endif /* OS2 */ #ifdef NT struct keytab win95tab[] = { /* Win95 work-arounds */ { "8.3-filenames", XYW8_3, 0 }, { "alt-gr", XYWAGR, 0 }, { "horizontal-scan-line-substitutions", XYWHSL, 0 }, { "keyboard-translation", XYWKEY, 0 }, { "lucida-substitutions", XYWLUC, 0 }, { "overlapped-io", XYWOIO, 0 }, { "popups", XYWPOPUP, 0 }, { "select-bug", XYWSELECT, 0 } }; int nwin95 = (sizeof(win95tab) / sizeof(struct keytab)); #endif /* NT */ #ifdef OS2MOUSE extern int wideresult; int tt_mouse = 1; /* Terminal mouse on/off */ struct keytab mousetab[] = { /* Mouse items */ { "activate", XYM_ON, 0 }, { "button", XYM_BUTTON, 0 }, { "clear", XYM_CLEAR, 0 }, { "debug", XYM_DEBUG, 0 }, #ifdef NT /* Not implemented for OS/2 yet */ { "reporting", XYM_REPORTING, 0 }, #endif #ifndef NOSCROLLWHEEL { "wheel", XYM_WHEEL, 0 } #endif }; int nmtab = (sizeof(mousetab)/sizeof(struct keytab)); struct keytab mousebuttontab[] = { /* event button */ { "1", XYM_B1, 0 }, { "2", XYM_B2, 0 }, { "3", XYM_B3, 0 }, { "one", XYM_B1, CM_INV }, { "three", XYM_B3, CM_INV }, { "two", XYM_B2, CM_INV } }; int nmbtab = (sizeof(mousebuttontab) / sizeof(struct keytab)); struct keytab mousewheeltab[] = { /* event direction */ { "down", XYM_WHEEL_DN, 0 }, { "up", XYM_WHEEL_UP, 0 } }; int nmousewheeltab = (sizeof(mousewheeltab) / sizeof(struct keytab)); struct keytab mousereportingtab[] = { /* event direction */ { "disabled", XYM_REPORTING_DISABLED, 0 }, { "enabled", XYM_REPORTING_ENABLED, 0 }, { "override", XYM_REPORTING_OVERRIDE, 0 } }; int nmousereportingtab = (sizeof(mousereportingtab) / sizeof(struct keytab)); struct keytab mousemodtab[] = { /* event button key modifier */ { "alt", XYM_ALT, 0 }, { "alt-shift", XYM_SHIFT|XYM_ALT, 0 }, { "ctrl", XYM_CTRL, 0 }, { "ctrl-alt", XYM_CTRL|XYM_ALT, 0 }, { "ctrl-alt-shift", XYM_CTRL|XYM_SHIFT|XYM_ALT, 0 }, { "ctrl-shift", XYM_CTRL|XYM_SHIFT, 0 }, { "none", 0, 0 }, { "shift", XYM_SHIFT, 0 } }; int nmmtab = (sizeof(mousemodtab) / sizeof(struct keytab)); struct keytab mclicktab[] = { /* event button click modifier */ { "click", XYM_C1, 0 }, { "drag", XYM_DRAG, 0 }, { "double-click", XYM_C2, 0 } }; int nmctab = (sizeof(mclicktab) / sizeof(struct keytab)); #ifndef NOKVERBS extern int nkverbs; extern struct keytab kverbs[]; #endif /* NOKVERBS */ #endif /* OS2MOUSE */ /* #ifdef VMS */ struct keytab fbtab[] = { /* Binary record types for VMS */ { "fixed", XYFT_B, 0 }, /* Fixed is normal for binary */ { "undefined", XYFT_U, 0 } /* Undefined if they ask for it */ }; int nfbtyp = (sizeof(fbtab) / sizeof(struct keytab)); /* #endif */ #ifdef VMS struct keytab lbltab[] = { /* Labeled File info */ { "acl", LBL_ACL, 0 }, { "backup-date", LBL_BCK, 0 }, { "name", LBL_NAM, 0 }, { "owner", LBL_OWN, 0 }, { "path", LBL_PTH, 0 } }; int nlblp = (sizeof(lbltab) / sizeof(struct keytab)); #else #ifdef OS2 struct keytab lbltab[] = { /* Labeled File info */ { "archive", LBL_ARC, 0 }, { "extended", LBL_EXT, 0 }, { "hidden", LBL_HID, 0 }, { "read-only", LBL_RO, 0 }, { "system", LBL_SYS, 0 } }; int nlblp = (sizeof(lbltab) / sizeof(struct keytab)); #endif /* OS2 */ #endif /* VMS */ #ifdef CK_CURSES #ifdef CK_PCT_BAR static struct keytab fdftab[] = { /* SET FILE DISPLAY FULL options */ { "thermometer", 1, 0, }, { "no-thermometer", 0, 0 } }; extern int thermometer; #endif /* CK_PCT_BAR */ #endif /* CK_CURSES */ static struct keytab fdtab[] = { /* SET FILE DISPLAY options */ #ifdef MAC /* Macintosh */ { "fullscreen", XYFD_R, 0 }, /* Full-screen but not curses */ { "none", XYFD_N, 0 }, { "off", XYFD_N, CM_INV }, { "on", XYFD_R, CM_INV }, { "quiet", XYFD_N, CM_INV }, #else /* Not Mac */ { "brief", XYFD_B, 0 }, /* Brief */ { "crt", XYFD_S, 0 }, /* CRT display */ #ifdef CK_CURSES #ifdef COMMENT { "curses", XYFD_C, CM_INV }, /* Full-screen, curses */ #endif /* COMMENT */ { "fullscreen", XYFD_C, 0 }, /* Full-screen, whatever the method */ #endif /* CK_CURSES */ #ifdef KUI { "gui", XYFD_G, 0 }, /* GUI */ #endif /* KUI */ { "none", XYFD_N, 0 }, /* No display */ { "off", XYFD_N, CM_INV }, /* Ditto */ { "on", XYFD_R, CM_INV }, /* On = Serial */ { "quiet", XYFD_N, CM_INV }, /* No display */ { "serial", XYFD_R, 0 }, /* Serial */ #endif /* MAC */ { "", 0, 0 } }; int nfdtab = (sizeof(fdtab) / sizeof(struct keytab)) - 1; struct keytab rsrtab[] = { /* For REMOTE SET RECEIVE */ { "packet-length", XYLEN, 0 }, { "timeout", XYTIMO, 0 } }; int nrsrtab = (sizeof(rsrtab) / sizeof(struct keytab)); /* Send/Receive Parameters */ struct keytab srtab[] = { { "backup", XYBUP, 0 }, #ifndef NOCSETS { "character-set-selection", XYCSET, 0 }, #endif /* NOCSETS */ { "control-prefix", XYQCTL, 0 }, #ifdef CKXXCHAR { "double-character", XYDBL, 0 }, #endif /* CKXXCHAR */ { "end-of-packet", XYEOL, 0 }, #ifdef PIPESEND { "filter", XYFLTR, 0 }, #endif /* PIPESEND */ #ifdef CKXXCHAR { "ignore-character", XYIGN, 0 }, #endif /* CKXXCHAR */ { "i-packets", 993, 0 }, { "move-to", XYMOVE, 0 }, { "negotiation-string-max-length", XYINIL, CM_INV }, { "packet-length", XYLEN, 0 }, { "pad-character", XYPADC, 0 }, { "padding", XYNPAD, 0 }, { "pathnames", XYFPATH, 0 }, { "pause", XYPAUS, 0 }, #ifdef CK_PERMS { "permissions", 994, 0}, /* 206 */ #endif /* CK_PERMS */ { "quote", XYQCTL, CM_INV }, /* = CONTROL-PREFIX */ { "rename-to", XYRENAME, 0 }, { "start-of-packet", XYMARK, 0 }, { "timeout", XYTIMO, 0 }, #ifdef VMS { "version-numbers", 887, 0 }, /* VMS version numbers */ #endif /* VMS */ { "", 0, 0 } }; int nsrtab = (sizeof(srtab) / sizeof(struct keytab)) - 1; #ifdef UNICODE #define UCS_BOM 1 #define UCS_BYT 2 static struct keytab ucstab[] = { { "bom", UCS_BOM, 0 }, { "byte-order", UCS_BYT, 0 }, { "", 0, 0 } }; int nucstab = (sizeof(ucstab) / sizeof(struct keytab)) - 1; static struct keytab botab[] = { { "big-endian", 0, 0 }, { "little-endian", 1, 0 } }; static int nbotab = 2; #endif /* UNICODE */ /* REMOTE SET */ struct keytab rmstab[] = { { "attributes", XYATTR, 0 }, { "block-check", XYCHKT, 0 }, { "file", XYFILE, 0 }, { "incomplete", XYIFD, CM_INV }, /* = REMOTE SET FILE INCOMPLETE */ { "match", XYMATCH,0 }, { "receive", XYRECV, 0 }, { "retry", XYRETR, 0 }, { "server", XYSERV, 0 }, { "transfer", XYXFER, 0 }, { "window", XYWIND, 0 }, { "xfer", XYXFER, CM_INV } }; int nrms = (sizeof(rmstab) / sizeof(struct keytab)); struct keytab attrtab[] = { #ifdef STRATUS { "account", AT_ACCT, 0 }, #endif /* STRATUS */ { "all", AT_XALL, 0 }, #ifdef COMMENT { "blocksize", AT_BLKS, 0 }, /* (not used) */ #endif /* COMMENT */ #ifndef NOCSETS { "character-set", AT_ENCO, 0 }, #endif /* NOCSETS */ #ifdef STRATUS { "creator", AT_CREA, 0 }, #endif /* STRATUS */ { "date", AT_DATE, 0 }, { "disposition", AT_DISP, 0 }, { "encoding", AT_ENCO, CM_INV }, { "format", AT_RECF, CM_INV }, { "length", AT_LENK, 0 }, { "off", AT_ALLN, 0 }, { "on", AT_ALLY, 0 }, #ifdef COMMENT { "os-specific", AT_SYSP, 0 }, /* (not used by UNIX or VMS) */ #endif /* COMMENT */ #ifdef CK_PERMS { "protection", AT_LPRO, 0 }, { "permissions", AT_LPRO, CM_INV }, #endif /* CK_PERMS */ { "record-format", AT_RECF, 0 }, { "system-id", AT_SYSI, 0 }, { "type", AT_FTYP, 0 } }; int natr = (sizeof(attrtab) / sizeof(struct keytab)); /* how many attributes */ #ifdef CKTIDLE struct keytab idlacts[] = { { "exit", IDLE_EXIT, 0 }, { "hangup", IDLE_HANG, 0 }, { "output", IDLE_OUT, 0 }, { "return", IDLE_RET, 0 }, #ifdef TNCODE { "telnet-nop", IDLE_TNOP, 0 }, { "telnet-ayt", IDLE_TAYT, 0 }, #endif /* TNCODE */ { "", 0, 0 } }; int nidlacts = (sizeof(idlacts) / sizeof(struct keytab)) - 1; #endif /* CKTIDLE */ #ifndef NOSPL extern int indef, inecho, insilence, inbufsize, inautodl, inintr; #ifdef CKFLOAT extern CKFLOAT inscale; #endif /* CKFLOAT */ extern char * inpbuf, * inpbp; #ifdef OS2 extern int interm; #endif /* OS2 */ struct keytab inptab[] = { /* SET INPUT parameters */ #ifdef CK_AUTODL { "autodownload", IN_ADL, 0 }, #endif /* CK_AUTODL */ { "buffer-length", IN_BUF, 0 }, { "cancellation", IN_CAN, 0 }, { "case", IN_CAS, 0 }, { "default-timeout", IN_DEF, CM_INV }, /* There is no default timeout */ { "echo", IN_ECH, 0 }, #ifdef OS2 { "pacing", IN_PAC, CM_INV }, #endif /* OS2 */ { "scale-factor", IN_SCA, 0 }, { "silence", IN_SIL, 0 }, #ifdef OS2 { "terminal", IN_TRM, 0 }, #endif /* OS2 */ { "timeout-action", IN_TIM, 0 } }; int ninp = (sizeof(inptab) / sizeof(struct keytab)); struct keytab intimt[] = { /* SET INPUT TIMEOUT parameters */ { "proceed", 0, 0 }, /* 0 = proceed */ { "quit", 1, 0 } /* 1 = quit */ }; struct keytab incast[] = { /* SET INPUT CASE parameters */ { "ignore", 0, 0 }, /* 0 = ignore */ { "observe", 1, 0 } /* 1 = observe */ }; #endif /* NOSPL */ struct keytab nabltab[] = { /* For any command that needs */ { "disabled", 0, 0 }, { "enabled", 1, 0 }, { "off", 0, CM_INV }, /* these keywords... */ { "on", 1, CM_INV } }; int nnabltab = sizeof(nabltab) / sizeof(struct keytab); #ifdef OS2 struct keytab tvctab[] = { /* SET TERM VIDEO-CHANGE */ { "disabled", TVC_DIS, 0 }, { "enabled", TVC_ENA, 0 }, #ifdef NT { "win95-safe", TVC_W95, 0 }, #endif /* NT */ { "", 0, 0 } }; int ntvctab = (sizeof(tvctab) / sizeof(struct keytab)) - 1; struct keytab msktab[] = { /* SET MS-DOS KERMIT compatibilities */ #ifdef COMMENT { "color", MSK_COLOR, 0 }, #endif /* COMMENT */ { "file-renaming", MSK_REN, 0 }, { "keycodes", MSK_KEYS, 0 } }; int nmsk = (sizeof(msktab) / sizeof(struct keytab)); struct keytab scrnupd[] = { /* SET TERMINAL SCREEN-UPDATE */ { "fast", TTU_FAST, 0 }, { "smooth", TTU_SMOOTH, 0 } }; int nscrnupd = (sizeof(scrnupd) / sizeof(struct keytab)); #ifdef PCFONTS /* This definition of the term_font[] table is only for */ /* the OS/2 Full Screen Session and is not used on Windows */ struct keytab term_font[] = { /* SET TERMINAL FONT */ #ifdef COMMENT { "cp111", TTF_111, 0 }, { "cp112", TTF_112, 0 }, { "cp113", TTF_113, 0 }, #endif /* COMMENT */ { "cp437", TTF_437, 0 }, { "cp850", TTF_850, 0 }, #ifdef COMMENT { "cp851", TTF_851, 0 }, #endif /* COMMENT */ { "cp852", TTF_852, 0 }, #ifdef COMMENT { "cp853", TTF_853, 0 }, { "cp860", TTF_860, 0 }, { "cp861", TTF_861, 0 }, #endif /* COMMENT */ { "cp862", TTF_862, 0 }, #ifdef COMMENT { "cp863", TTF_863, 0 }, { "cp864", TTF_864, 0 }, { "cp865", TTF_865, 0 }, #endif /* COMMENT */ { "cp866", TTF_866, 0 }, #ifdef COMMENT { "cp880", TTF_880, 0 }, { "cp881", TTF_881, 0 }, { "cp882", TTF_882, 0 }, { "cp883", TTF_883, 0 }, { "cp884", TTF_884, 0 }, { "cp885", TTF_885, 0 }, #endif /* COMMENT */ { "default",TTF_ROM,0 } }; int ntermfont = (sizeof(term_font) / sizeof(struct keytab)); int tt_font = TTF_ROM; /* Terminal screen font */ #else /* PCFONTS */ #ifdef NT #ifdef KUI struct keytab * term_font = NULL; struct keytab * _term_font = NULL; char * tt_facename = NULL; int ntermfont = 0; int tt_font = 0; int tt_font_size = 0; #endif /* KUI */ #endif /* NT */ #endif /* PCFONTS */ struct keytab anbktab[] = { /* For any command that needs */ { "message", 2, 0 }, /* these keywords... */ { "off", 0, 0 }, { "on", 1, 0 }, { "unsafe-messag0", 99, CM_INV }, { "unsafe-message", 3, CM_INV } }; int nansbk = (sizeof(anbktab) / sizeof(struct keytab)); int win95_popup = 1; #ifdef NT #ifdef KUI int win95lucida = 0; int win95hsl = 1; #else /* KUI */ int win95lucida = 1; int win95hsl = 1; #endif /* KUI */ #else /* NT */ int win95lucida = 0; int win95hsl = 1; #endif /* NT */ #ifdef NT int win95altgr = 0; extern int win95selectbug; extern int win95_8_3; #ifdef COMMENT extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); extern struct keytab tcstab[]; extern int ntcs; #endif /* COMMENT */ extern int maxow, maxow_usr, owwait; /* Overlapped I/O variables */ #endif /* NT */ #endif /* OS2 */ /* The following routines broken out of doprm() to give compilers a break. */ /* S E T O N -- Parse on/off (default on), set parameter to result */ int #ifdef CK_ANSIC seton( int *prm ) #else seton(prm) int *prm; #endif /* CK_ANSIC */ { int x, y; if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); *prm = y; return(1); } /* S E T O N A U T O -- Parse on/off/auto (default auto) & set result */ struct keytab onoffaut[] = { { "auto", SET_AUTO, 0 }, /* 2 */ { "off", SET_OFF, 0 }, /* 0 */ { "on", SET_ON, 0 } /* 1 */ }; int #ifdef CK_ANSIC setonaut( int *prm ) #else setonaut(prm) int *prm; #endif /* CK_ANSIC */ { int x, y; if ((y = cmkey(onoffaut,3,"","auto",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); *prm = y; return(1); } /* S E T N U M -- Set parameter to result of cmnum() parse. */ /* Call with pointer to integer variable to be set, x = number from cnum parse, y = return code from cmnum, max = maximum value to accept, -1 if no maximum. Returns -9 on failure, after printing a message, or 1 on success. */ int #ifdef CK_ANSIC setnum( int *prm, int x, int y, int max ) #else setnum(prm,x,y,max) int x, y, *prm, max; #endif /* CK_ANSIC */ { debug(F101,"setnum","",y); if (y == -3) { printf("\n?Value required\n"); return(-9); } if (y == -2) { printf("%s?Not a number: %s\n",cmflgs == 1 ? "" : "\n", atxbuf); return(-9); } if (y < 0) return(y); if (max > -1 && x > max) { printf("?Sorry, %d is the maximum\n",max); return(-9); } if ((y = cmcfm()) < 0) return(y); *prm = x; return(1); } /* S E T C C -- Set parameter var to an ASCII control character value. */ /* Parses a number, or a literal control character, or a caret (^) followed by an ASCII character whose value is 63-95 or 97-122, then gets confirmation, then sets the parameter to the code value of the character given. If there are any parse errors, they are returned, otherwise on success 1 is returned. */ int #ifdef CK_ANSIC setcc( char *dflt, int *var ) #else setcc(dflt,var) char *dflt; int *var; #endif /* CK_ANSIC */ { int x, y; unsigned int c; char *hlpmsg = "Control character,\n\ numeric ASCII value,\n\ or in ^X notation,\n\ or preceded by a backslash and entered literally"; /* This is a hack to turn off complaints from expression evaluator. */ x_ifnum = 1; y = cmnum(hlpmsg, dflt, 10, &x, xxstring); /* Parse a number */ x_ifnum = 0; /* Allow complaints again */ if (y < 0) { /* Parse failed */ if (y != -2) /* Reparse needed or somesuch */ return(y); /* Pass failure back up the chain */ } /* Real control character or literal 8-bit character... */ for (c = strlen(atmbuf) - 1; c > 0; c--) /* Trim */ if (atmbuf[c] == SP) atmbuf[c] = NUL; if (y < 0) { /* It was not a number */ if (((c = atmbuf[0])) && !atmbuf[1]) { /* Literal character? */ c &= 0xff; if (((c > 31) && (c < 127)) || (c > 255)) { printf("\n?%d: Out of range - must be 0-31 or 127-255\n",c); return(-9); } else { if ((y = cmcfm()) < 0) /* Confirm */ return(y); *var = c; /* Set the variable */ return(1); } } else if (atmbuf[0] == '^' && !atmbuf[2]) { /* Or ^X notation? */ c = atmbuf[1]; if (islower((char) c)) /* Uppercase lowercase letters */ c = toupper(c); if (c > 62 && c < 96) { /* Check range */ if ((y = cmcfm()) < 0) return(y); *var = ctl(c); /* OK */ return(1); } else { printf("?Not a control character - %s\n", atmbuf); return(-9); } } else { /* Something illegal was typed */ printf("?Not valid here - '%s'\n", atmbuf); return(-9); } } if (((x > 31) && (x < 127)) || (x > 255)) { /* They typed a number */ printf("\n?%d: Out of range - must be 0-31 or 127-255\n",x); return(-9); } if ((y = cmcfm()) < 0) /* In range, confirm */ return(y); *var = x; /* Set variable */ return(1); } #ifndef NOSPL /* The SORT command... */ static struct keytab srtswtab[] = { /* SORT command switches */ { "/case", SRT_CAS, CM_ARG }, { "/key", SRT_KEY, CM_ARG }, { "/numeric", SRT_NUM, 0 }, { "/range", SRT_RNG, CM_ARG }, { "/reverse", SRT_REV, 0 } }; static int nsrtswtab = sizeof(srtswtab)/sizeof(struct keytab); extern char **a_ptr[]; /* Array pointers */ extern int a_dim[]; /* Array dimensions */ int dosort() { /* Do the SORT command */ char c, *p = NULL, ** ap, ** xp = NULL; struct FDB sw, fl, cm; int hi, lo; int xn = 0, xr = -1, xk = -1, xc = -1, xs = 0; int getval = 0, range[2], confirmed = 0; cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Array name or switch", "", /* default */ "", /* addtl string data */ nsrtswtab, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ NULL, /* Processing function */ srtswtab, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* Anything that doesn't match */ _CMFLD, /* fcode */ "Array name", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, NULL, &cm ); cmfdbi(&cm, /* Or premature confirmation */ _CMCFM, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, NULL, NULL ); range[0] = -1; range[1] = -1; while (1) { /* Parse 0 or more switches */ x = cmfdb(&sw); if (x < 0) return(x); if (cmresult.fcode != _CMKEY) /* Break out if not a switch */ break; c = cmgbrk(); getval = (c == ':' || c == '='); if (getval && !(cmresult.kflags & CM_ARG)) { printf("?This switch does not take arguments\n"); return(-9); } switch (cmresult.nresult) { case SRT_REV: xr = 1; break; case SRT_KEY: if (getval) { if ((y = cmnum("Column for comparison (1-based)", "1",10,&x,xxstring)) < 0) return(y); xk = x - 1; } else xk = 0; break; case SRT_CAS: if (getval) { if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); xc = y; } else xc = 1; break; case SRT_RNG: /* /RANGE */ if (getval) { char buf[32]; char buf2[16]; int i; char * p, * q; if ((y = cmfld("low:high element","1",&s,NULL)) < 0) return(y); s = brstrip(s); ckstrncpy(buf,s,32); p = buf; for (i = 0; *p && i < 2; i++) { /* Get low and high */ q = p; /* Start of this piece */ while (*p) { /* Find end of this piece */ if (*p == ':') { *p = NUL; p++; break; } p++; } y = 15; /* Evaluate this piece */ s = buf2; zzstring(q,&s,&y); s = evalx(buf2); if (s) if (*s) ckstrncpy(buf2,s,16); if (!rdigits(buf2)) { printf("?Not numeric: %s\n",buf2); return(-9); } range[i] = atoi(buf2); } } break; case SRT_NUM: /* /NUMERIC */ xn = 1; break; default: return(-2); } } switch (cmresult.fcode) { case _CMCFM: confirmed = 1; break; case _CMFLD: ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Safe copy of name */ s = line; break; default: printf("?Unexpected function code: %d\n",cmresult.fcode); return(-9); } if (confirmed) { printf("?Array name required\n"); return(-9); } ckmakmsg(tmpbuf,TMPBUFSIZ, "Second array to sort according to ",s,NULL,NULL); if ((x = cmfld(tmpbuf,"",&p,NULL)) < 0) if (x != -3) return(x); tmpbuf[0] = NUL; ckstrncpy(tmpbuf,p,TMPBUFSIZ); p = tmpbuf; if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); x = arraybounds(s,&lo,&hi); /* Get array index & bounds */ if (x < 0) { /* Check */ printf("?Bad array name: %s\n",s); return(-9); } if (lo > -1) range[0] = lo; /* Set range */ if (hi > -1) range[1] = hi; ap = a_ptr[x]; /* Get pointer to array element list */ if (!ap) { /* Check */ printf("?Array not declared: %s\n", s); return(-9); } if (range[0] < 0) /* Starting element */ range[0] = 1; if (range[1] < 0) /* Final element */ range[1] = a_dim[x]; if (range[1] > a_dim[x]) { printf("?range %d:%d exceeds array dimension %d\n", range[0],range[1],a_dim[x] ); return(-9); } ap += range[0]; xs = range[1] - range[0] + 1; /* Number of elements to sort */ if (xs < 1) { /* Check */ printf("?Bad range: %d:%d\n",range[0],range[1]); return(-9); } if (xk < 0) xk = 0; /* Key position */ if (xr < 0) xr = 0; /* Reverse flag */ if (xn) /* Numeric flag */ xc = 2; else if (xc < 0) /* Not numeric */ xc = inpcas[cmdlvl]; /* so alpha case option */ if (*p) { /* Parallel array given? */ y = xarray(p); /* Yes, get its index. */ if (y < 0) { printf("?Bad array name: %s\n", p); return(-9); } if (y != x) { /* If the 2 arrays are different */ xp = a_ptr[y]; /* Pointer to 2nd array element list */ if (!xp) { printf("?Array not declared: %s\n", p); return(-9); } if (a_dim[y] < range[1]) { printf("?Array %s smaller than %s\n", p, s); return(-9); } xp += range[0]; /* Set base to same as 1st array */ } } sh_sort(ap,xp,xs,xk,xr,xc); /* Sort the array(s) */ return(success = 1); /* Always succeeds */ } #endif /* NOSPL */ #ifdef CKPURGE static struct keytab purgtab[] = { /* PURGE command switches */ { "/after", PU_AFT, CM_ARG }, { "/ask", PU_ASK, 0 }, { "/before", PU_BEF, CM_ARG }, { "/delete", PU_DELE, CM_INV }, #ifdef UNIXOROSK { "/dotfiles", PU_DOT, 0 }, #endif /* UNIXOROSK */ { "/except", PU_EXC, CM_ARG }, { "/heading", PU_HDG, 0 }, { "/keep", PU_KEEP, CM_ARG }, { "/larger-than", PU_LAR, CM_ARG }, { "/list", PU_LIST, 0 }, { "/log", PU_LIST, CM_INV }, { "/noask", PU_NASK, 0 }, { "/nodelete", PU_NODE, CM_INV }, #ifdef UNIXOROSK { "/nodotfiles", PU_NODOT,0 }, #endif /* UNIXOROSK */ { "/noheading", PU_NOH, 0 }, { "/nol", PU_NOLI, CM_INV|CM_ABR }, { "/nolist", PU_NOLI, 0 }, { "/nolog", PU_NOLI, CM_INV }, #ifdef CK_TTGWSIZ { "/nopage", PU_NOPA, 0 }, #endif /* CK_TTGWSIZ */ { "/not-after", PU_NAF, CM_ARG }, { "/not-before", PU_NBF, CM_ARG }, { "/not-since", PU_NAF, CM_INV|CM_ARG }, #ifdef CK_TTGWSIZ { "/page", PU_PAGE, 0 }, #endif /* CK_TTGWSIZ */ { "/quiet", PU_QUIE, CM_INV }, #ifdef RECURSIVE { "/recursive", PU_RECU, 0 }, #endif /* RECURSIVE */ { "/since", PU_AFT, CM_ARG|CM_INV }, { "/simulate", PU_NODE, 0 }, { "/smaller-than", PU_SMA, CM_ARG }, { "/verbose", PU_VERB, CM_INV } }; static int npurgtab = sizeof(purgtab)/sizeof(struct keytab); #endif /* CKPURGE */ int #ifdef CK_ANSIC bkupnum( char * s, int *i ) #else bkupnum(s,i) char * s; int *i; #endif /* CK_ANSIC */ { int k = 0, pos = 0; char * p = NULL, *q; *i = pos; if (!s) s = ""; if (!*s) return(-1); if ((k = strlen(s)) < 5) return(-1); if (s[k-1] != '~') return(-1); pos = k - 2; q = s + pos; while (q >= s && isdigit(*q)) { p = q--; pos--; } if (!p) return(-1); if (q < s+2) return(-1); if (*q != '~' || *(q-1) != '.') return(-1); pos--; *i = pos; debug(F111,"bkupnum",s+pos,pos); return(atoi(p)); } #ifdef CKPURGE /* Presently only for UNIX because we need direct access to the file array. */ /* Not needed for VMS anyway, because we don't make backup files there. */ #define MAXKEEP 32 /* Biggest /KEEP: value */ static int pu_keep = 0, pu_list = 0, pu_dot = 0, pu_ask = 0, pu_hdg = 0; #ifdef CK_TTGWSIZ static int pu_page = -1; #else static int pu_page = 0; #endif /* CK_TTGWSIZ */ #ifndef NOSHOW VOID showpurgopts() { /* SHOW PURGE command options */ int x = 0; extern int optlines; prtopt(&optlines,"PURGE"); if (pu_ask > -1) { x++; prtopt(&optlines, pu_ask ? "/ASK" : "/NOASK"); } #ifdef UNIXOROSK if (pu_dot > -1) { x++; prtopt(&optlines, pu_dot ? "/DOTFILES" : "/NODOTFILES"); } #endif /* UNIXOROSK */ if (pu_keep > -1) { x++; ckmakmsg(tmpbuf,TMPBUFSIZ,"/KEEP:",ckitoa(pu_keep),NULL,NULL); prtopt(&optlines,tmpbuf); } if (pu_list > -1) { x++; prtopt(&optlines, pu_list ? "/LIST" : "/NOLIST"); } if (pu_hdg > -1) { x++; prtopt(&optlines, pu_hdg ? "/HEADING" : "/NOHEADING"); } #ifdef CK_TTGWSIZ if (pu_page > -1) { x++; prtopt(&optlines, pu_page ? "/PAGE" : "/NOPAGE"); } #endif /* CK_TTGWSIZ */ if (!x) prtopt(&optlines,"(no options set)"); prtopt(&optlines,""); } #endif /* NOSHOW */ int setpurgopts() { /* Set PURGE command options */ int c, z, getval = 0; int x_keep = -1, x_list = -1, x_page = -1, x_hdg = -1, x_ask = -1, x_dot = -1; while (1) { if ((y = cmswi(purgtab,npurgtab,"Switch","",xxstring)) < 0) { if (y == -3) break; else return(y); } c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } switch (y) { case PU_KEEP: z = 1; if (c == ':' || c == '=') if ((y = cmnum("How many backup files to keep", "1",10,&z,xxstring)) < 0) return(y); if (z < 0 || z > MAXKEEP) { printf("?Please specify a number between 0 and %d\n", MAXKEEP ); return(-9); } x_keep = z; break; case PU_LIST: case PU_VERB: x_list = 1; break; case PU_QUIE: case PU_NOLI: x_list = 0; break; #ifdef CK_TTGWSIZ case PU_PAGE: x_page = 1; break; case PU_NOPA: x_page = 0; break; #endif /* CK_TTGWSIZ */ case PU_HDG: x_hdg = 1; break; case PU_NOH: x_hdg = 0; break; case PU_ASK: x_ask = 1; break; case PU_NASK: x_ask = 0; break; #ifdef UNIXOROSK case PU_DOT: x_dot = 1; break; case PU_NODOT: x_dot = 0; break; #endif /* UNIXOROSK */ default: printf("?This option can not be set\n"); return(-9); } } if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); if (x_keep > -1) /* Set PURGE defaults. */ pu_keep = x_keep; if (x_list > -1) pu_list = x_list; #ifdef CK_TTGWSIZ if (x_page > -1) pu_page = x_page; #endif /* CK_TTGWSIZ */ if (x_hdg > -1) pu_hdg = x_hdg; if (x_ask > -1) pu_ask = x_ask; if (x_dot > -1) pu_dot = x_dot; return(success = 1); } int dopurge() { /* Do the PURGE command */ extern char ** mtchs; extern int xaskmore, cmd_rows, recursive; int simulate = 0, asking = 0; int listing = 0, paging = -1, lines = 0, deleting = 1, errors = 0; struct FDB sw, sf, cm; int g, i, j, k, m = 0, n, x, y, z, done = 0, count = 0, flags = 0; int tokeep = 0, getval = 0, havename = 0, confirmed = 0; int xx[MAXKEEP+1]; /* Array of numbers to keep */ int min = -1; int x_hdg = 0, fs = 0, rc = 0; CK_OFF_T minsize = -1L, maxsize = -1L; char namebuf[CKMAXPATH+4]; char basebuf[CKMAXPATH+4]; char * pu_aft = NULL, * pu_bef = NULL, * pu_naf = NULL, * pu_nbf = NULL, * pu_exc = NULL; char * pxlist[8]; /* Exception list */ if (pu_keep > -1) /* Set PURGE defaults. */ tokeep = pu_keep; if (pu_list > -1) listing = pu_list; #ifdef CK_TTGWSIZ if (pu_page > -1) paging = pu_page; #endif /* CK_TTGWSIZ */ for (i = 0; i <= MAXKEEP; i++) /* Clear this number buffer */ xx[i] = 0; for (i = 0; i < 8; i++) /* Initialize these... */ pxlist[i] = NULL; g_matchdot = matchdot; /* Save these... */ cmfdbi(&sw, /* 1st FDB - PURGE switches */ _CMKEY, /* fcode */ "Filename or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ npurgtab, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ purgtab, /* Keyword table */ &sf /* Pointer to next FDB */ ); cmfdbi(&sf, /* 2nd FDB - filespec to purge */ _CMIFI, /* fcode */ "", "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, &cm ); cmfdbi(&cm, /* Or premature confirmation */ _CMCFM, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, NULL, NULL ); while (!havename && !confirmed) { x = cmfdb(&sw); /* Parse something */ if (x < 0) { /* Error */ rc = x; goto xpurge; } else if (cmresult.fcode == _CMKEY) { char c; c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); rc = -9; goto xpurge; } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); rc = -9; goto xpurge; } switch (k = cmresult.nresult) { case PU_KEEP: z = 1; if (c == ':' || c == '=') { if ((y = cmnum("How many backup files to keep", "1",10,&z,xxstring)) < 0) { rc = y; goto xpurge; } } if (z < 0 || z > MAXKEEP) { printf("?Please specify a number between 0 and %d\n", MAXKEEP ); rc = -9; goto xpurge; } tokeep = z; break; case PU_LIST: listing = 1; break; case PU_NOLI: listing = 0; break; #ifdef CK_TTGWSIZ case PU_PAGE: paging = 1; break; case PU_NOPA: paging = 0; break; #endif /* CK_TTGWSIZ */ case PU_DELE: deleting = 1; break; case PU_NODE: deleting = 0; simulate = 1; listing = 1; break; case PU_ASK: asking = 1; break; case PU_NASK: asking = 0; break; case PU_AFT: case PU_BEF: case PU_NAF: case PU_NBF: if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) { if (x == -3) { printf("?Date-time required\n"); rc = -9; } else rc = x; goto xpurge; } fs++; switch (k) { case PU_AFT: makestr(&pu_aft,s); break; case PU_BEF: makestr(&pu_bef,s); break; case PU_NAF: makestr(&pu_naf,s); break; case PU_NBF: makestr(&pu_nbf,s); break; } break; case PU_SMA: case PU_LAR: if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0) { rc = x; goto xpurge; } fs++; switch (cmresult.nresult) { case PU_SMA: minsize = y; break; case PU_LAR: maxsize = y; break; } break; case PU_DOT: matchdot = 1; break; case PU_NODOT: matchdot = 0; break; case PU_EXC: if ((x = cmfld("Pattern","",&s,xxstring)) < 0) { if (x == -3) { printf("?Pattern required\n"); rc = -9; } else rc = x; goto xpurge; } fs++; makestr(&pu_exc,s); break; case PU_HDG: x_hdg = 1; break; #ifdef RECURSIVE case PU_RECU: /* /RECURSIVE */ recursive = 2; break; #endif /* RECURSIVE */ default: printf("?Not implemented yet - \"%s\"\n",atmbuf); rc = -9; goto xpurge; } } else if (cmresult.fcode == _CMIFI) { havename = 1; } else if (cmresult.fcode == _CMCFM) { confirmed = 1; } else { rc = -2; goto xpurge; } } if (havename) { #ifdef CKREGEX ckmakmsg(line,LINBUFSIZ,cmresult.sresult,".~[1-9]*~",NULL,NULL); #else ckmakmsg(line,LINBUFSIZ,cmresult.sresult,".~*~",NULL,NULL); #endif /* CKREGEX */ } else { #ifdef CKREGEX ckstrncpy(line,"*.~[1-9]*~",LINBUFSIZ); #else ckstrncpy(line,"*.~*~",LINBUFSIZ); #endif /* CKREGEX */ } if (!confirmed) { if ((x = cmcfm()) < 0) { rc = x; goto xpurge; } } /* Parse finished - now action */ #ifdef CK_LOGIN if (isguest) { printf("?File deletion by guests not permitted.\n"); rc = -9; goto xpurge; } #endif /* CK_LOGIN */ #ifdef CK_TTGWSIZ if (paging < 0) /* /[NO]PAGE not given */ paging = xaskmore; /* so use prevailing */ #endif /* CK_TTGWSIZ */ lines = 0; if (x_hdg > 0) { printf("Purging %s, keeping %d...%s\n", s, tokeep, simulate ? " (SIMULATION)" : ""); lines += 2; } flags = ZX_FILONLY; if (recursive) flags |= ZX_RECURSE; n = nzxpand(line,flags); /* Get list of backup files */ if (tokeep < 1) { /* Deleting all of them... */ for (i = 0; i < n; i++) { if (fs) if (fileselect(mtchs[i], pu_aft,pu_bef,pu_naf,pu_nbf, minsize,maxsize,0,8,pxlist) < 1) { if (listing > 0) { printf(" %s (SKIPPED)\n",mtchs[i]); #ifdef CK_TTGWSIZ if (paging) if (++lines > cmd_rows - 3) { if (!askmore()) goto xpurge; else lines = 0; } #endif /* CK_TTGWSIZ */ } continue; } if (asking) { int x; ckmakmsg(tmpbuf,TMPBUFSIZ," Delete ",mtchs[i],"?",NULL); x = getyesno(tmpbuf,1); switch (x) { case 0: continue; case 1: break; case 2: goto xpurge; } } x = deleting ? zdelet(mtchs[i]) : 0; if (x > -1) { if (listing) printf(" %s (%s)\n", mtchs[i],deleting ? "OK" : "SELECTED"); count++; } else { errors++; if (listing) printf(" %s (FAILED)\n", mtchs[i]); } #ifdef CK_TTGWSIZ if (listing && paging) if (++lines > cmd_rows - 3) { if (!askmore()) goto xpurge; else lines = 0; } #endif /* CK_TTGWSIZ */ } goto xpurge; } if (n < tokeep) { /* Not deleting any */ count = 0; if (listing) printf(" Matches = %d: Not enough to purge.\n",n); goto xpurge; } /* General case - delete some but not others */ sh_sort(mtchs,NULL,n,0,0,filecase); /* Alphabetize the list (ESSENTIAL) */ g = 0; /* Start of current group */ for (i = 0; i < n; i++) { /* Go thru sorted file list */ x = znext(namebuf); /* Get next file */ if (x < 1 || !namebuf[0] || i == n - 1) /* No more? */ done = 1; /* NOTE: 'done' must be 0 or 1 only */ if (fs) if (fileselect(namebuf, pu_aft,pu_bef,pu_naf,pu_nbf, minsize,maxsize,0,8,pxlist) < 1) { if (listing > 0) { printf(" %s (SKIPPED)\n",namebuf); if (++lines > cmd_rows - 3) { if (!askmore()) goto xpurge; else lines = 0; } } continue; } if (x > 0) if ((m = bkupnum(namebuf,&z)) < 0) /* This file's backup number. */ continue; for (j = 0; j < tokeep; j++) { /* Insert in list. */ if (m > xx[j]) { for (k = tokeep - 1; k > j; k--) xx[k] = xx[k-1]; xx[j] = m; break; } } /* New group? */ if (done || (i > 0 && ckstrcmp(namebuf,basebuf,z,1))) { if (i + done - g > tokeep) { /* Do we have enough to purge? */ min = xx[tokeep-1]; /* Yes, lowest backup number to keep */ debug(F111,"dopurge group",basebuf,min); for (j = g; j < i + done; j++) { /* Go through this group */ x = bkupnum(mtchs[j],&z); /* Get file backup number */ if (x > 0 && x < min) { /* Below minimum? */ x = deleting ? zdelet(mtchs[j]) : 0; if (x < 0) errors++; if (listing) printf(" %s (%s)\n", mtchs[j], ((x < 0) ? "ERROR" : (deleting ? "DELETED" : "SELECTED")) ); count++; } else if (listing) /* Not below minimum - keep this one */ printf(" %s (KEPT)\n",mtchs[j]); #ifdef CK_TTGWSIZ if (listing && paging) if (++lines > cmd_rows - 3) { if (!askmore()) goto xpurge; else lines = 0; } #endif /* CK_TTGWSIZ */ } } else if (listing && paging) { /* Not enough to purge */ printf(" %s.~*~ (KEPT)\n",basebuf); #ifdef CK_TTGWSIZ if (++lines > cmd_rows - 3) { if (!askmore()) goto xpurge; else lines = 0; } #endif /* CK_TTGWSIZ */ } for (j = 0; j < tokeep; j++) /* Clear the backup number list */ xx[j] = 0; g = i; /* Reset the group pointer */ } if (done) /* No more files, done. */ break; strncpy(basebuf,namebuf,z); /* Set basename of this file */ basebuf[z] = NUL; } xpurge: /* Common exit point */ if (g_matchdot > -1) { matchdot = g_matchdot; /* Restore these... */ g_matchdot = -1; } if (rc < 0) return(rc); /* Parse error */ if (x_hdg) printf("Files purged: %d%s\n", count, deleting ? "" : " (not really)" ); return(success = count > 0 ? 1 : (errors > 0) ? 0 : 1); } #endif /* CKPURGE */ #ifndef NOXFER #ifndef NOLOCAL int #ifdef CK_ANSIC doxdis( int which ) /* 1 = Kermit, 2 = FTP */ #else doxdis(which) int which; #endif /* CK_ANSIC */ { extern int nolocal; int x, y = 0, z; #ifdef NEWFTP extern int ftp_dis; #endif /* NEWFTP */ #ifdef COMMENT char *s; #endif /* COMMENT */ if ((x = cmkey(fdtab,nfdtab,"file transfer display style","", xxstring)) < 0) return(x); #ifdef CK_PCT_BAR if ((y = cmkey(fdftab,2,"","thermometer",xxstring)) < 0) return(y); #endif /* CK_PCT_BAR */ if ((z = cmcfm()) < 0) return(z); #ifdef CK_CURSES if (x == XYFD_C) { /* FULLSCREEN */ #ifdef COMMENT #ifndef MYCURSES extern char * trmbuf; /* Real curses */ int z; #endif /* MYCURSES */ #endif /* COMMENT */ if (nolocal) /* Nothing to do in this case */ return(success = 1); #ifdef COMMENT #ifndef MYCURSES #ifndef VMS s = getenv("TERM"); debug(F110,"doxdis TERM",s,0); if (!s) s = ""; fxdinit(x); if (*s && trmbuf) { /* Don't call tgetent */ z = tgetent(trmbuf,s); /* if trmbuf not allocated */ debug(F111,"doxdis tgetent",s,z); } else { z = 0; debug(F110,"doxdis tgetent skipped",s,0); } if (z < 1) { printf("Sorry, terminal type unknown: \"%s\"\n",s); return(success = 0); } #endif /* VMS */ #endif /* MYCURSES */ #else fxdinit(x); #endif /* COMMENT */ #ifdef CK_PCT_BAR thermometer = y; #endif /* CK_PCT_BAR */ line[0] = '\0'; /* (What's this for?) */ } #endif /* CK_CURSES */ if (which == 1) /* It's OK. */ fdispla = x; #ifdef NEWFTP else if (which == 2) ftp_dis = x; #endif /* NEWFTP */ return(success = 1); } #endif /* NOLOCAL */ #endif /* NOXFER */ int #ifdef CK_ANSIC setfil( int rmsflg ) #else setfil(rmsflg) int rmsflg; #endif /* CK_ANSIC */ { #ifdef COMMENT extern int en_del; #endif /* COMMENT */ #ifndef NOXFER if (rmsflg) { if ((y = cmkey(rfiltab,nrfilp,"Remote file parameter","", xxstring)) < 0) { if (y == -3) { printf("?Remote file parameter required\n"); return(-9); } else return(y); } } else { #endif /* NOXFER */ if ((y = cmkey(filtab,nfilp,"File parameter","",xxstring)) < 0) return(y); #ifndef NOXFER } #endif /* NOXFER */ switch (y) { #ifdef COMMENT /* Not needed */ case XYFILB: /* Blocksize */ if ((y = cmnum("file block size",ckitoa(DBLKSIZ),10,&z,xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); if (rmsflg) { sstate = setgen('S', "311", ckitoa(z), ""); return((int) sstate); } else { fblksiz = z; return(success = 1); } #endif /* COMMENT */ #ifndef NOXFER case XYFILS: /* Byte size */ if ((y = cmnum("file byte size (7 or 8)","8",10,&z,xxstring)) < 0) return(y); if (z != 7 && z != 8) { printf("\n?The choices are 7 and 8\n"); return(0); } if ((y = cmcfm()) < 0) return(y); if (z == 7) fmask = 0177; else if (z == 8) fmask = 0377; return(success = 1); #ifndef NOCSETS case XYFILC: { /* Character set */ char * csetname = NULL; extern int r_cset, s_cset, afcset[]; /* SEND CHARACTER-SET AUTO or MANUAL */ struct FDB kw, fl; cmfdbi(&kw, /* First FDB - command switches */ _CMKEY, /* fcode */ rmsflg ? "server character-set name" : "", /* help */ "", /* default */ "", /* addtl string data */ nfilc, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: 0 = keyword */ xxstring, /* Processing function */ fcstab, /* Keyword table */ rmsflg ? &fl : NULL /* Pointer to next FDB */ ); cmfdbi(&fl, /* Anything that doesn't match */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); if ((x = cmfdb(&kw)) < 0) return(x); if (cmresult.fcode == _CMKEY) { x = cmresult.nresult; csetname = fcsinfo[x].keyword; } else { ckstrncpy(line,cmresult.sresult,LINBUFSIZ); csetname = line; } if ((z = cmcfm()) < 0) return(z); if (rmsflg) { sstate = setgen('S', "320", csetname, ""); return((int) sstate); } fcharset = x; if (s_cset == XMODE_A) /* If SEND CHARACTER-SET is AUTO */ if (x > -1 && x <= MAXFCSETS) if (afcset[x] > -1 && afcset[x] <= MAXTCSETS) tcharset = afcset[x]; /* Pick corresponding xfer charset */ setxlatype(tcharset,fcharset); /* Translation type */ /* If I say SET FILE CHARACTER-SET blah, I want to be blah! */ r_cset = XMODE_M; /* Don't switch incoming set! */ x = fcsinfo[fcharset].size; /* Also set default x-bit charset */ if (x == 128) /* 7-bit... */ dcset7 = fcharset; else if (x == 256) /* 8-bit... */ dcset8 = fcharset; return(success = 1); } #endif /* NOCSETS */ #ifndef NOLOCAL case XYFILD: /* Display */ return(doxdis(1)); /* 1 == kermit */ #endif /* NOLOCAL */ #endif /* NOXFER */ case XYFILA: /* End-of-line */ #ifdef NLCHAR s = ""; if (NLCHAR == 015) s = "cr"; else if (NLCHAR == 012) s = "lf"; if ((x = cmkey(eoltab, neoltab, "local text-file line terminator",s,xxstring)) < 0) return(x); #else if ((x = cmkey(eoltab, neoltab, "local text-file line terminator","crlf",xxstring)) < 0) return(x); #endif /* NLCHAR */ if ((z = cmcfm()) < 0) return(z); feol = (CHAR) x; return(success = 1); #ifndef NOXFER case XYFILN: /* Names */ if ((x = cmkey(fntab,nfntab,"how to handle filenames","converted", xxstring)) < 0) return(x); if ((z = cmcfm()) < 0) return(z); if (rmsflg) { sstate = setgen('S', "301", ckitoa(1 - x), ""); return((int) sstate); } else { ptab[protocol].fncn = x; /* Set structure */ fncnv = x; /* Set variable */ f_save = x; /* And set "permanent" variable */ return(success = 1); } case XYFILR: /* Record length */ if ((y = cmnum("file record length", ckitoa(DLRECL),10,&z,xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); if (rmsflg) { sstate = setgen('S', "312", ckitoa(z), ""); return((int) sstate); } else { frecl = z; return(success = 1); } #ifdef COMMENT case XYFILO: /* Organization */ if ((x = cmkey(forgtab,nforg,"file organization","sequential", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); if (rmsflg) { sstate = setgen('S', "314", ckitoa(x), ""); return((int) sstate); } else { forg = x; return(success = 1); } #endif /* COMMENT */ #ifdef COMMENT /* Not needed */ case XYFILF: /* Format */ if ((x = cmkey(frectab,nfrec,"file record format","stream", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); if (rmsflg) { sstate = setgen('S', "313", ckitoa(x), ""); return((int) sstate); } else { frecfm = x; return(success = 1); } #endif /* COMMENT */ #ifdef COMMENT case XYFILP: /* Printer carriage control */ if ((x = cmkey(fcctab,nfcc,"file carriage control","newline", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); if (rmsflg) { sstate = setgen('S', "315", ckitoa(x), ""); return((int) sstate); } else { fcctrl = x; return(success = 1); } #endif /* COMMENT */ #endif /* NOXFER */ case XYFILT: /* Type */ if ((x = cmkey(rmsflg ? rfttab : fttab, rmsflg ? nrfttyp : nfttyp, "type of file transfer","text",xxstring)) < 0) return(x); #ifdef VMS /* Allow VMS users to choose record format for binary files */ if ((x == XYFT_B) && (rmsflg == 0)) { if ((x = cmkey(fbtab,nfbtyp,"VMS record format","fixed", xxstring)) < 0) return(x); } #endif /* VMS */ if ((y = cmcfm()) < 0) return(y); binary = x; b_save = x; #ifdef MAC (void) mac_setfildflg(binary); #endif /* MAC */ #ifndef NOXFER if (rmsflg) { /* Allow for LABELED in VMS & OS/2 */ sstate = setgen('S', "300", ckitoa(x), ""); return((int) sstate); } else { #endif /* NOXFER */ return(success = 1); #ifndef NOXFER } #endif /* NOXFER */ #ifndef NOXFER case XYFILX: /* Collision Action */ if ((x = cmkey(colxtab,ncolx,"Filename collision action","backup", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); #ifdef CK_LOGIN if (isguest) { /* Don't let guests change existing files */ printf("?This command not valid for guests\n"); return(-9); } #endif /* CK_LOGIN */ #ifdef COMMENT /* Not appropriate - DISABLE DELETE only refers to server */ if ((x == XYFX_X || x == XYFX_B || x == XYFX_U || x == XYFX_A) && (!ENABLED(en_del))) { printf("?Sorry, file deletion is disabled.\n"); return(-9); } #endif /* COMMENT */ fncact = x; ptab[protocol].fnca = x; if (rmsflg) { sstate = setgen('S', "302", ckitoa(fncact), ""); return((int) sstate); } else { if (fncact == XYFX_R) ckwarn = 1; /* FILE WARNING implications */ if (fncact == XYFX_X) ckwarn = 0; /* ... */ return(success = 1); } case XYFILW: /* Warning/Write-Protect */ if ((x = seton(&ckwarn)) < 0) return(x); if (ckwarn) fncact = XYFX_R; else fncact = XYFX_X; return(success = 1); #ifdef CK_LABELED case XYFILL: /* LABELED FILE parameters */ if ((x = cmkey(lbltab,nlblp,"Labeled file feature","", xxstring)) < 0) return(x); if ((success = seton(&y)) < 0) return(success); if (y) /* Set or reset the selected bit */ lf_opts |= x; /* in the options bitmask. */ else lf_opts &= ~x; return(success); #endif /* CK_LABELED */ case XYFILI: { /* INCOMPLETE */ extern struct keytab ifdatab[]; extern int keep; if ((y = cmkey(ifdatab,3,"","auto",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); if (rmsflg) { sstate = setgen('S', "310", y == 0 ? "0" : (y == 1 ? "1" : "2"), "" ); return((int) sstate); } else { keep = y; return(success = 1); } } #ifdef CK_TMPDIR case XYFILG: { /* Download directory */ int x; char *s; #ifdef ZFNQFP struct zfnfp * fnp; #endif /* ZFNQFP */ #ifdef MAC char temp[34]; #endif /* MAC */ #ifdef GEMDOS if ((x = cmdir("Name of local directory, or carriage return", "",&s, NULL)) < 0 ) { if (x != -3) return(x); } #else #ifdef OS2 if ((x = cmdir("Name of PC disk and/or directory,\n\ or press the Enter key to use current directory", "",&s,xxstring)) < 0 ) { if (x != -3) return(x); } #else #ifdef MAC x = ckstrncpy(temp,zhome(),32); if (x > 0) if (temp[x-1] != ':') { temp[x] = ':'; temp[x+1] = NUL; } if ((x = cmtxt("Name of Macintosh volume and/or folder,\n\ or press the Return key for the desktop on the boot disk", temp,&s, xxstring)) < 0 ) return(x); #else if ((x = cmdir("Name of local directory, or carriage return", "", &s, xxstring)) < 0 ) { if (x != -3) return(x); } #endif /* MAC */ #endif /* OS2 */ #endif /* GEMDOS */ debug(F110,"download dir",s,0); #ifndef MAC if (x == 2) { printf("?Wildcards not allowed in directory name\n"); return(-9); } #endif /* MAC */ #ifdef ZFNQFP if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) { if (fnp->fpath) if ((int) strlen(fnp->fpath) > 0) s = fnp->fpath; } debug(F110,"download zfnqfp",s,0); #endif /* ZFNQFP */ ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy */ #ifndef MAC if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); #endif /* MAC */ #ifdef CK_LOGIN if (isguest) { /* Don't let guests change existing files */ printf("?This command not valid for guests\n"); return(-9); } #endif /* CK_LOGIN */ x = strlen(s); if (x) { #ifdef datageneral /* AOS/VS */ if (s[x-1] == ':') /* homdir ends in colon, */ s[x-1] = NUL; /* and "dir" doesn't like that... */ #else #ifdef OS2ORUNIX /* Unix or K-95... */ if ((x < (LINBUFSIZ - 2)) && /* Add trailing dirsep */ (s[x-1] != '/')) { /* if none present. */ s[x] = '/'; /* Note that Windows path has */ s[x+1] = NUL; /* been canonicalized to forward */ } /* slashes at this point. */ #endif /* OS2ORUNIX */ #endif /* datageneral */ makestr(&dldir,s); } else makestr(&dldir,NULL); /* dldir is NULL when not assigned */ return(success = 1); } #endif /* CK_TMPDIR */ case XYFILY: return(setdest()); #endif /* NOXFER */ #ifdef CK_CTRLZ case XYFILV: { /* EOF */ extern int eofmethod; if ((x = cmkey(eoftab,3,"end-of-file detection method","", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); eofmethod = x; return(success = 1); } #endif /* CK_CTRLZ */ #ifndef NOXFER #ifdef UNIX case XYFILH: { /* OUTPUT */ extern int zofbuffer, zobufsize, zofblock; #ifdef DYNAMIC extern char * zoutbuffer; #endif /* DYNAMIC */ if ((x = cmkey(zoftab,nzoftab,"output file writing method","", xxstring)) < 0) return(x); if (x == ZOF_BUF || x == ZOF_NBUF) { if ((y = cmnum("output buffer size","32768",10,&z,xxstring)) < 0) return(y); if (z < 1) { printf("?Bad size - %d\n", z); return(-9); } } if ((y = cmcfm()) < 0) return(y); switch (x) { case ZOF_BUF: case ZOF_NBUF: zofbuffer = (x == ZOF_BUF); zobufsize = z; break; case ZOF_BLK: case ZOF_NBLK: zofblock = (x == ZOF_BLK); break; } #ifdef DYNAMIC if (zoutbuffer) free(zoutbuffer); if (!(zoutbuffer = (char *)malloc(z))) { printf("MEMORY ALLOCATION ERROR - FATAL\n"); doexit(BAD_EXIT,-1); } else zobufsize = z; #else if (z <= OBUFSIZE) { zobufsize = z; } else { printf("?Sorry, %d is too big - %d is the maximum\n",z,OBUFSIZE); return(-9); } #endif /* DYNAMIC */ return(success = 1); } #endif /* UNIX */ #ifdef PATTERNS case XYFIBP: /* BINARY-PATTERN */ case XYFITP: { /* TEXT-PATTERN */ char * tmp[FTPATTERNS]; int i, n = 0; while (n < FTPATTERNS) { tmp[n] = NULL; if ((x = cmfld("Pattern","",&s,xxstring)) < 0) break; ckstrncpy(line,s,LINBUFSIZ); s = brstrip(line); makestr(&(tmp[n++]),s); } if (x == -3) x = cmcfm(); for (i = 0; i <= n; i++) { if (x > -1) { if (y == XYFIBP) makestr(&(binpatterns[i]),tmp[i]); else makestr(&(txtpatterns[i]),tmp[i]); } free(tmp[i]); } if (y == XYFIBP) /* Null-terminate the list */ makestr(&(binpatterns[i]),NULL); else makestr(&(txtpatterns[i]),NULL); return(x); } case XYFIPA: /* PATTERNS */ if ((x = setonaut(&patterns)) < 0) return(x); return(success = 1); #endif /* PATTERNS */ #endif /* NOXFER */ #ifdef UNICODE case XYFILU: { /* UCS */ extern int ucsorder, ucsbom, byteorder; if ((x = cmkey(ucstab,nucstab,"","",xxstring)) < 0) return(x); switch (x) { case UCS_BYT: if ((y = cmkey(botab,nbotab, "Byte order", byteorder ? "little-endian" : "big-endian", xxstring ) ) < 0) return(y); if ((x = cmcfm()) < 0) return(x); ucsorder = y; return(success = 1); case UCS_BOM: if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); ucsbom = y; return(success = 1); default: return(-2); } } #endif /* UNICODE */ #ifndef datageneral case XYF_INSP: { /* SCAN (INSPECTION) */ extern int filepeek, nscanfile; if ((x = cmkey(onoff,2,"","on",xxstring)) < 0) return(x); if (y) { if ((y = cmnum("How much to scan",ckitoa(SCANFILEBUF), 10,&z,xxstring)) < 0) return(y); } if ((y = cmcfm()) < 0) return(y); #ifdef VMS filepeek = 0; nscanfile = 0; return(success = 0); #else filepeek = x; nscanfile = z; return(success = 1); #endif /* VMS */ } #endif /* datageneral */ case XYF_DFLT: y = 0; #ifndef NOCSETS if ((y = cmkey(fdfltab,nfdflt,"","",xxstring)) < 0) return(y); if (y == 7 || y == 8) { if (y == 7) s = fcsinfo[dcset7].keyword; else s = fcsinfo[dcset8].keyword; if ((x = cmkey(fcstab,nfilc,"character-set",s,xxstring)) < 0) return(x); } ckstrncpy(line,fcsinfo[x].keyword,LINBUFSIZ); s = line; #endif /* NOCSETS */ if ((z = cmcfm()) < 0) return(z); switch (y) { #ifndef NOCSETS case 7: if (fcsinfo[x].size != 128) { printf("%s - Not a 7-bit set\n",s); return(-9); } dcset7 = x; break; case 8: if (fcsinfo[x].size != 256) { printf("%s - Not an 8-bit set\n",s); return(-9); } dcset8 = x; break; #endif /* NOCSETS */ default: return(-2); } return(success = 1); #ifndef NOXFER case 9997: /* FASTLOOKUPS */ return(success = seton(&stathack)); #endif /* NOXFER */ #ifdef UNIX #ifdef DYNAMIC case XYF_LSIZ: { /* LISTSIZE */ int zz; y = cmnum("Maximum number of filenames","",10,&x,xxstring); if ((x = setnum(&zz,x,y,-1)) < 0) return(x); if (zsetfil(zz,3) < 0) { printf("?Memory allocation failure\n"); return(-9); } return(success = 1); } case XYF_SSPA: { /* STRINGSPACE */ int zz; y = cmnum("Number of characters for filename list", "",10,&x,xxstring); if ((x = setnum(&zz,x,y,-1)) < 0) return(x); if (zsetfil(zz,1) < 0) { printf("?Memory allocation failure\n"); return(-9); } return(success = 1); } #endif /* DYNAMIC */ #endif /* UNIX */ default: printf("?unexpected file parameter\n"); return(-2); } } #ifdef UNIX #ifndef NOPUTENV #ifdef BIGBUFOK #define NPUTENVS 4096 #else #define NPUTENVS 128 #endif /* BIGBUFOK */ /* environment variables must be static, not automatic */ static char * putenvs[NPUTENVS]; /* Array of environment var strings */ static int nputenvs = -1; /* Pointer into array */ /* If anyone ever notices the limitation on the number of PUTENVs, the list can be made dynamic, we can recycle entries with the same name, etc. */ int #ifdef CK_ANSIC doputenv( char * s1, char * s2 ) #else doputenv(s1, s2) char * s1; char * s2; #endif /* CK_ANSIC */ { char * s, * t = tmpbuf; /* Create or alter environment var */ if (nputenvs == -1) { /* Table not used yet */ int i; /* Initialize the pointers */ for (i = 0; i < NPUTENVS; i++) putenvs[i] = NULL; nputenvs = 0; } if (!s1) return(1); /* Nothing to do */ if (!*s1) return(1); /* ditto */ if (ckindex("=",s1,0,0,0)) { /* Does the name contain an '='? */ printf( /* putenv() does not allow this. */ /* This also catches the 'putenv name=value' case */ "?PUTENV - Equal sign in variable name - 'help putenv' for info.\n"); return(-9); } nputenvs++; /* Point to next free string */ debug(F111,"doputenv s1",s1,nputenvs); debug(F111,"doputenv s2",s2,nputenvs); if (nputenvs > NPUTENVS - 1) { /* Notice the end */ printf("?PUTENV - static buffer space exhausted\n"); return(-9); } /* Quotes are not needed but we allow them for familiarity */ /* but then we strip them, so syntax is same as for Unix shell */ if (s2) { s2 = brstrip(s2); } else { s2 = (char *)""; } ckmakmsg(t,TMPBUFSIZ,s1,"=",s2,NULL); debug(F111,"doputenv",t,nputenvs); (VOID) makestr(&(putenvs[nputenvs]),t); /* Make a safe permananent copy */ if (!putenvs[nputenvs]) { printf("?PUTENV - memory allocation failure\n"); return(-9); } if (putenv(putenvs[nputenvs])) { printf("?PUTENV - %s\n",ck_errstr()); return(-9); } else return(success = 1); } #endif /* NOPUTENV */ #endif /* UNIX */ int settrmtyp() { #ifdef OS2 #ifdef TNCODE extern int ttnum; /* Last Telnet Terminal Type sent */ extern int ttnumend; /* Has end of list been found */ #endif /* TNCODE */ if ((x = cmkey(ttyptab,nttyp,"","vt220",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); settermtype(x,1); #ifdef TNCODE /* So we send the correct terminal name to the host if it asks for it */ ttnum = -1; /* Last Telnet Terminal Type sent */ ttnumend = 0; /* end of list not found */ #endif /* TNCODE */ return(success = 1); #else /* Not OS2 */ #ifdef UNIX extern int fxd_inited; x = cmtxt("Terminal type name, case sensitive","",&s,NULL); #ifdef NOPUTENV success = 1; #else success = doputenv("TERM",s); /* Set the TERM variable */ #ifdef CK_CURSES fxd_inited = 0; /* Force reinitialization of curses database */ (void)doxdis(0); /* Re-initialize file transfer display */ concb((char)escape); /* Fix command terminal */ #endif /* CK_CURSES */ #endif /* NOPUTENV */ return(success); #else printf( "\n Sorry, this version of C-Kermit does not support the SET TERMINAL TYPE\n"); printf( " command. Type \"help set terminal\" for further information.\n"); return(success = 0); #endif /* UNIX */ #endif /* OS2 */ } #ifndef NOLOCAL #ifdef OS2 /* MS-DOS KERMIT compatibility modes */ int setmsk() { if ((y = cmkey(msktab,nmsk,"MS-DOS Kermit compatibility mode", "keycodes",xxstring)) < 0) return(y); switch ( y ) { #ifdef COMMENT case MSK_COLOR: return(seton(&mskcolors)); #endif /* COMMENT */ case MSK_KEYS: return(seton(&mskkeys)); case MSK_REN: return(seton(&mskrename)); default: /* Shouldn't get here. */ return(-2); } } #endif /* OS2 */ #ifdef CKTIDLE static char iactbuf[132]; char * getiact() { switch (tt_idleact) { case IDLE_RET: return("return"); case IDLE_EXIT: return("exit"); case IDLE_HANG: return("hangup"); #ifdef TNCODE case IDLE_TNOP: return("Telnet NOP"); case IDLE_TAYT: return("Telnet AYT"); #endif /* TNCODE */ case IDLE_OUT: { int c, k, n; char * p, * q; k = ckstrncpy(iactbuf,"output ",132); n = k; q = &iactbuf[k]; p = tt_idlestr; if (!p) p = ""; if (!*p) return("output NUL"); while ((c = *p++) && n < 131) { c &= 0xff; if (c == '\\') { if (n > 130) break; *q++ = '\\'; *q++ = '\\'; *q = NUL; n += 2; } else if ((c > 32 && c < 127) || c > 159) { *q++ = c; *q = NUL; n++; } else { if (n > (131 - 6)) break; sprintf(q,"\\{%d}",c); k = strlen(q); q += k; n += k; *q = NUL; } } *q = NUL; #ifdef OS2 k = tt_cols[VTERM]; #else k = tt_cols; #endif /* OS2 */ if (n > k - 52) { n = k - 52; iactbuf[n-2] = '.'; iactbuf[n-1] = '.'; iactbuf[n] = NUL; } return(iactbuf); } default: return("unknown"); } } #endif /* CKTIDLE */ #ifndef NOCSETS VOID #ifdef CK_ANSIC setlclcharset( int x ) #else setlclcharset(x) int x; #endif /* CK_ANSIC */ { int i; tcsl = y; /* Local character set */ #ifdef OS2 for (i = 0; i < 4; i++) { G[i].init = TRUE; x = G[i].designation; G[i].c1 = (x != tcsl) && cs_is_std(x); x = G[i].def_designation; G[i].def_c1 = (x != tcsl) && cs_is_std(x); } #endif /* OS2 */ } VOID #ifdef CK_ANSIC setremcharset( int x, int z ) #else setremcharset(x, z) int x, z; #endif /* CK_ANSIC */ { int i; #ifdef KUI KuiSetProperty( KUI_TERM_REMCHARSET, (intptr_t) x, (intptr_t) z ) ; #endif /* KUI */ #ifdef UNICODE if (x == TX_TRANSP) #else /* UNICODE */ if (x == FC_TRANSP) #endif /* UNICODE */ { /* TRANSPARENT? */ #ifndef OS2 tcsr = tcsl; /* Make both sets the same */ #else /* OS2 */ #ifdef CKOUNI tt_utf8 = 0; /* Turn off UTF8 flag */ tcsr = tcsl = dec_kbd = TX_TRANSP; /* No translation */ tcs_transp = 1; if (!cs_is_nrc(tcsl)) { G[0].def_designation = G[0].designation = TX_ASCII; G[0].init = TRUE; G[0].def_c1 = G[0].c1 = FALSE; G[0].size = cs94; G[0].national = FALSE; } for (i = cs_is_nrc(tcsl) ? 0 : 1; i < 4; i++) { G[i].def_designation = G[i].designation = tcsl; G[i].init = TRUE; G[i].def_c1 = G[i].c1 = FALSE; switch (cs_size(G[i].designation)) { /* 94, 96, or 128 */ case 128: case 96: G[i].size = G[i].def_size = cs96; break; case 94: G[i].size = G[i].def_size = cs94; break; default: G[i].size = G[i].def_size = csmb; break; } G[i].national = cs_is_nrc(x); } #else /* CKOUNI */ tcsr = tcsl; /* Make both sets the same */ for (i = 0; i < 4; i++) { G[i].def_designation = G[i].designation = FC_TRANSP; G[i].init = FALSE; G[i].size = G[i].def_size = cs96; G[i].c1 = G[i].def_c1 = FALSE; G[i].rtoi = NULL; G[i].itol = NULL; G[i].ltoi = NULL; G[i].itor = NULL; G[i].national = FALSE; } #endif /* CKOUNI */ #endif /* OS2 */ return; } #ifdef OS2 #ifdef CKOUNI else if (x == TX_UTF8) { tcs_transp = 0; tt_utf8 = 1; /* Turn it on if we are UTF8 */ return; } #endif /* CKOUNI */ else { tcs_transp = 0; tcsr = x; /* Remote character set */ #ifdef CKOUNI tt_utf8 = 0; /* Turn off UTF8 flag */ #endif /* CKOUNI */ if (z == TT_GR_ALL) { int i; #ifdef UNICODE dec_kbd = x; #endif /* UNICODE */ for (i = 0; i < 4; i++) { G[i].init = TRUE; if ( i == 0 && !cs_is_nrc(x) ) { G[0].designation = G[0].def_designation = FC_USASCII; G[0].size = G[0].def_size = cs94; G[0].national = 1; } else { G[i].def_designation = G[i].designation = x; switch (cs_size(x)) { /* 94, 96, or 128 */ case 128: case 96: G[i].size = G[i].def_size = cs96; break; case 94: G[i].size = G[i].def_size = cs94; break; default: G[i].size = G[i].def_size = csmb; break; } G[i].national = cs_is_nrc(x); } G[i].c1 = G[i].def_c1 = x != tcsl && cs_is_std(x); } #ifdef UNICODE } else if (z == TT_GR_KBD) { /* Keyboard only */ dec_kbd = x; #endif /* UNICODE */ } else { /* Specific Gn */ G[z].def_designation = G[z].designation = x; G[z].init = TRUE; switch (cs_size(x)) { /* 94, 96, or 128 */ case 128: case 96: G[z].size = G[z].def_size = cs96; break; case 94: G[z].size = G[z].def_size = cs94; break; default: G[z].size = G[z].def_size = csmb; break; } G[z].c1 = G[z].def_c1 = x != tcsl && cs_is_std(x); G[z].national = cs_is_nrc(x); } } #else /* not OS2 */ tcsr = x; /* Remote character set */ #endif /* OS2 */ } #endif /* NOCSETS */ VOID #ifdef CK_ANSIC setcmask( int x ) #else setcmask(x) int x; #endif /* CK_ANSIC */ { if (x == 7) { cmask = 0177; } else if (x == 8) { cmask = 0377; parity = 0; } #ifdef KUI KuiSetProperty(KUI_TERM_CMASK,x,0); #endif /* KUI */ } #ifdef CK_AUTODL VOID #ifdef CK_ANSIC setautodl( int x, int y ) #else setautodl(x,y) int x,y; #endif /* CK_ANSIC */ { autodl = x; adl_ask = y; #ifdef KUI KuiSetProperty(KUI_TERM_AUTODOWNLOAD,x?(y?2:1):0,0); #endif /* KUI */ } #endif /* CK_AUTODL */ #ifdef OS2 VOID seturlhl(int x) { tt_url_hilite = x; #ifdef KUI KuiSetProperty(KUI_TERM_URL_HIGHLIGHT,x,0); #endif /* KUI */ } VOID setaprint(int x) { extern int aprint; aprint = x; #ifdef KUI KuiSetProperty(KUI_TERM_PRINTERCOPY,x,0); #endif /* KUI */ } #endif /* OS2 */ int settrm() { int i = 0; #ifdef OS2 extern int colorreset, user_erasemode; #endif /* OS2 */ if ((y = cmkey(trmtab,ntrm,"", "",xxstring)) < 0) return(y); #ifdef MAC printf("\n?Sorry, not implemented yet. Please use the Settings menu.\n"); return(-9); #else #ifdef IKSD if (inserver) { if ((y = cmcfm()) < 0) return(y); printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ switch (y) { case XYTBYT: /* SET TERMINAL BYTESIZE */ if ((y = cmnum("bytesize for terminal connection","8",10,&x, xxstring)) < 0) return(y); if (x != 7 && x != 8) { printf("\n?The choices are 7 and 8\n"); return(success = 0); } if ((y = cmcfm()) < 0) return(y); setcmask(x); #ifdef OS2 if (IS97801(tt_type_mode)) SNI_bitmode(x); #endif /* OS2 */ return(success = 1); case XYTSO: /* SET TERMINAL LOCKING-SHIFT */ return(seton(&sosi)); case XYTNL: /* SET TERMINAL NEWLINE-MODE */ return(seton(&tnlm)); #ifdef OS2 case XYTCOL: if ((x = cmkey(ttycoltab,ncolors,"","terminal",xxstring)) < 0) return(x); else if (x == TTCOLRES) { if ((y = cmkey(ttcolmodetab,ncolmode, "","default-color",xxstring)) < 0) return(y); if ((z = cmcfm()) < 0) return(z); colorreset = y; return(success = 1); } else if (x == TTCOLERA) { if ((y = cmkey(ttcolmodetab,ncolmode,"", "current-color",xxstring)) < 0) return(y); if ((z = cmcfm()) < 0) return(z); user_erasemode = y; return(success=1); } else { /* No parse error */ int fg = 0, bg = 0; fg = cmkey(ttyclrtab, nclrs, (x == TTCOLBOR ? "color for screen border" : "foreground color and then background color"), "lgray", xxstring); if (fg < 0) return(fg); if (x != TTCOLBOR) { if ((bg = cmkey(ttyclrtab,nclrs, "background color","blue",xxstring)) < 0) return(bg); } if ((y = cmcfm()) < 0) return(y); switch (x) { case TTCOLNOR: colornormal = fg | bg << 4; fgi = fg & 0x08; bgi = bg & 0x08; break; case TTCOLREV: colorreverse = fg | bg << 4; break; case TTCOLITA: coloritalic = fg | bg << 4; break; case TTCOLUND: colorunderline = fg | bg << 4; break; case TTCOLGRP: colorgraphic = fg | bg << 4; break; case TTCOLDEB: colordebug = fg | bg << 4; break; case TTCOLSTA: colorstatus = fg | bg << 4; break; case TTCOLHLP: colorhelp = fg | bg << 4; break; case TTCOLBOR: colorborder = fg; break; case TTCOLSEL: colorselect = fg | bg << 4; break; default: printf("%s - invalid\n",cmdbuf); return(-9); break; } scrninitialized[VTERM] = 0; VscrnInit(VTERM); } return(success = 1); case XYTCUR: { /* SET TERMINAL CURSOR */ extern int cursorena[]; extern int cursoron[] ; /* Cursor state on/off */ if ((x = cmkey(ttycurtab,ncursors,"","underline",xxstring)) < 0) return(x); if ((z = cmkey(curontab,ncuron,"","on",xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); tt_cursor = tt_cursor_usr = x; if ( z == 2 ) { cursorena[VTERM] = tt_cursorena_usr = 1; tt_cursor_blink = 0; } else { cursorena[VTERM] = tt_cursorena_usr = z;/* turn cursor on/off */ tt_cursor_blink = 1; } cursoron[VTERM] = FALSE; /* Force newcursor to restore the cursor */ return(success = 1); } #endif /* OS2 */ case XYTTYP: /* SET TERMINAL TYPE */ return(settrmtyp()); #ifdef OS2 case XYTARR: /* SET TERMINAL ARROW-KEYS */ if ((x = cmkey(akmtab,2,"","",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); tt_arrow = x; /* TTK_NORM / TTK_APPL; see ckuusr.h */ return(success = 1); case XYTKPD: /* SET TERMINAL KEYPAD-MODE */ if ((x = cmkey(kpmtab,2,"","",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); tt_keypad = x; /* TTK_NORM / TTK_APPL; see ckuusr.h */ return(success = 1); case XYTUNX: { /* SET TERM UNIX-MODE (DG) */ extern int dgunix,dgunix_usr; x = seton(&dgunix); dgunix_usr = dgunix; return(x); } case XYTKBMOD: { /* SET TERM KEYBOARD MODE */ extern int tt_kb_mode; if ((x = cmkey(kbmodtab, nkbmodtab, "normal", "special keyboard mode for terminal emulation", xxstring) ) < 0) return(x); if ((y = cmcfm()) < 0) return(y); tt_kb_mode = x; return(success = 1); } case XYTWRP: /* SET TERMINAL WRAP */ return(seton(&tt_wrap)); case XYSCRS: if ((y = cmnum("CONNECT scrollback buffer size, lines","2000",10,&x, xxstring)) < 0) return(y); /* The max number of lines is the RAM */ /* we can actually dedicate to a */ /* scrollback buffer given the maximum */ /* process memory space of 512MB */ if (x < 256 || x > 2000000L) { printf("\n?The size must be between 256 and 2,000,000.\n"); return(success = 0); } if ((y = cmcfm()) < 0) return(y); tt_scrsize[VTERM] = x; VscrnInit(VTERM); return(success = 1); #endif /* OS2 */ #ifndef NOCSETS case XYTCS: { /* SET TERMINAL CHARACTER-SET */ int eol; /* set terminal character-set */ if ((x = cmkey( #ifdef CKOUNI txrtab,ntxrtab, #else /* CKOUNI */ ttcstab,ntermc, #endif /* CKOUNI */ "remote terminal character-set","",xxstring)) < 0) return(x); #ifdef UNICODE if (x == TX_TRANSP #ifdef CKOUNI || x == TX_UTF8 #endif /* CKOUNI */ ) { if ((y = cmcfm()) < 0) /* Confirm the command */ return(y); #ifdef OS2 if ( ck_isunicode() && x == TX_TRANSP ) { /* If we are in unicode display mode then transparent * only affects the output direction. We need to know * the actual remote character set in order to perform * the tcsr -> ucs2 translation for display. */ x = y = tcsl; } else #endif /* OS2 */ y = x; } #else /* UNICODE */ if (x == FC_TRANSP) { if ((y = cmcfm()) < 0) /* Confirm the command */ return(y); y = x; } #endif /* UNICODE */ /* Not transparent or UTF8, so get local set to translate it into */ s = ""; #ifdef OS2 y = os2getcp(); /* Default is current code page */ switch (y) { case 437: s = "cp437"; break; case 850: s = "cp850"; break; case 852: s = "cp852"; break; case 857: s = "cp857"; break; case 858: s = "cp858"; break; case 862: s = "cp862"; break; case 866: s = "cp866"; break; case 869: s = "cp869"; break; case 1250: s = "cp1250"; break; case 1251: s = "cp1251"; break; case 1252: s = "cp1252"; break; case 1253: s = "cp1253"; break; case 1254: s = "cp1254"; break; case 1255: s = "cp1255"; break; case 1256: s = "cp1256"; break; case 1257: s = "cp1257"; break; case 1258: s = "cp1258"; break; } #ifdef PCFONTS /* If the user has loaded a font with SET TERMINAL FONT then we want to change the default code page to the font that was loaded. */ if (tt_font != TTF_ROM) { for (y = 0; y < ntermfont; y++ ) { if (term_font[y].kwval == tt_font) { s = term_font[y].kwd; break; } } } #endif /* PCFONTS */ #else /* Not K95... */ s = fcsinfo[fcharset].keyword; #endif /* OS2 */ if ((y = cmkey( #ifdef CKOUNI txrtab,ntxrtab, #else /* CKOUNI */ ttcstab,ntermc, #endif /* CKOUNI */ "local character-set",s,xxstring)) < 0) return(y); #ifdef UNICODE if (y == TX_UTF8) { printf("?UTF8 may not be used as a local character set.\r\n"); return(-9); } #endif /* UNICODE */ #ifdef OS2 if ((z = cmkey(graphsettab,ngraphset, "DEC VT intermediate graphic set","all",xxstring)) < 0) return(z); #endif /* OS2 */ if ((eol = cmcfm()) < 0) return(eol); /* Confirm the command */ /* End of command parsing - actions begin */ setlclcharset(y); setremcharset(x,z); return(success = 1); } #endif /* NOCSETS */ #ifndef NOCSETS case XYTLCS: /* SET TERMINAL LOCAL-CHARACTER-SET */ /* set terminal character-set */ s = getdcset(); /* Get display character-set name */ if ((y = cmkey( #ifdef CKOUNI txrtab,ntxrtab, #else /* CKOUNI */ fcstab,nfilc, #endif /* CKOUNI */ "local character-set",s,xxstring)) < 0) return(y); #ifdef UNICODE if (y == TX_UTF8) { printf("?UTF8 may not be used as a local character set.\r\n"); return(-9); } #endif /* UNICODE */ if ((z = cmcfm()) < 0) return(z); /* Confirm the command */ /* End of command parsing - action begins */ setlclcharset(y); return(success = 1); #endif /* NOCSETS */ #ifndef NOCSETS #ifdef UNICODE case XYTUNI: /* SET TERMINAL UNICODE */ return(seton(&tt_unicode)); #endif /* UNICODE */ case XYTRCS: /* SET TERMINAL REMOTE-CHARACTER-SET */ /* set terminal character-set */ if ((x = cmkey( #ifdef CKOUNI txrtab, ntxrtab, #else /* CKOUNI */ ttcstab,ntermc, #endif /* CKOUNI */ "remote terminal character-set","",xxstring)) < 0) return(x); #ifdef UNICODE if (x == TX_TRANSP #ifdef CKOUNI || x == TX_UTF8 #endif /* CKOUNI */ ) { if ((y = cmcfm()) < 0) /* Confirm the command */ return(y); #ifdef OS2 if ( ck_isunicode() && x == TX_TRANSP ) { /* If we are in unicode display mode then transparent * only affects the output direction. We need to know * the actual remote character set in order to perform * the tcsr -> ucs2 translation for display. */ x = tcsl; } #endif /* OS2 */ } #else /* UNICODE */ if (x == FC_TRANSP) { if ((y = cmcfm()) < 0) /* Confirm the command */ return(y); } #endif /* UNICODE */ else { #ifdef OS2 if ((z = cmkey(graphsettab,ngraphset, "DEC VT intermediate graphic set","all",xxstring)) < 0) return(z); #endif /* OS2 */ if ((y = cmcfm()) < 0) /* Confirm the command */ return(y); } /* Command parsing ends here */ setremcharset(x,z); return(success = 1); #endif /* NOCSETS */ case XYTEC: /* SET TERMINAL ECHO */ if ((x = cmkey(rltab,nrlt,"which side echos during CONNECT", "remote", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); #ifdef NETCONN oldplex = x; #endif /* NETCONN */ duplex = x; return(success = 1); case XYTESC: /* SET TERM ESC */ if ((x = cmkey(nabltab,nnabltab,"","enabled",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); tt_escape = x; return(1); case XYTCRD: /* SET TERMINAL CR-DISPLAY */ if ((x = cmkey(crdtab,2,"", "normal", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); tt_crd = x; return(success = 1); case XYTLFD: /* SET TERMINAL LF-DISPLAY */ if ((x = cmkey(crdtab,2,"", "normal", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); tt_lfd = x; return(success = 1); #ifdef OS2 case XYTANS: { /* SET TERMINAL ANSWERBACK */ /* NOTE: We let them enable and disable the answerback sequence, but we do NOT let them change it, and we definitely do not let the host set it. This is a security feature. As of 1.1.8 we allow the SET TERM ANSWERBACK MESSAGE to be used just as MS-DOS Kermit does. C0 and C1 controls as well as DEL are not allowed to be used as characters. They are translated to underscore. This may not be set by APC. */ if ((x = cmkey(anbktab,nansbk,"", "off", xxstring)) < 0) return(x); if (x < 2) { if ((y = cmcfm()) < 0) return(y); tt_answer = x; return(success = 1); } else if ( x == 2 || x == 3) { int len = 0; extern int safeanswerbk; extern char useranswerbk[]; if ((y = cmtxt("Answerback extension","",&s,xxstring)) < 0) return(y); if (apcactive == APC_LOCAL || (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))) return(success = 0); len = strlen(s); if (x == 2) { /* Safe Answerback's don't have C0/C1 chars */ for (z = 0; z < len; z++) { if ((s[z] & 0x7F) <= SP || (s[z] & 0x7F) == DEL) useranswerbk[z] = '_'; else useranswerbk[z] = s[z]; } useranswerbk[z] = '\0'; safeanswerbk = 1 ; /* TRUE */ } else { ckstrncpy(useranswerbk,s,60); /* (see ckocon.c) */ safeanswerbk = 0; /* FALSE */ } updanswerbk(); return(success = 1); } else return(success = 0); } #endif /* OS2 */ #ifdef CK_APC case XYTAPC: if ((y = cmkey(apctab,napctab, "application program command execution","", xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); if (apcactive == APC_LOCAL || (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))) return(success = 0); apcstatus = y; return(success = 1); #ifdef CK_AUTODL case XYTAUTODL: /* AUTODOWNLOAD */ if ((y = cmkey(adltab,nadltab,"Auto-download options","", xxstring)) < 0) return(y); switch (y) { case TAD_ON: case TAD_OFF: if ((x = cmcfm()) < 0) return(x); setautodl(y,0); break; case TAD_ASK: if ((x = cmcfm()) < 0) return(x); setautodl(TAD_ON,1); break; case TAD_ERR: if ((y = cmkey(adlerrtab,nadlerrtab,"","", xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); adl_err = y; break; #ifdef OS2 case TAD_K: if ((y = cmkey(adlxtab,nadlxtab,"","", xxstring)) < 0) return(y); switch (y) { case TAD_X_C0: if ((y = cmkey(adlc0tab,nadlc0tab,"", "processed-by-emulator",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); adl_kc0 = y; break; case TAD_X_DETECT: if ((y = cmkey(adldtab,nadldtab,"","packet",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); adl_kmode = y; break; case TAD_X_STR: if ((y = cmtxt("Kermit start string","KERMIT READY TO SEND...", &s,xxstring)) < 0) return(y); free(adl_kstr); adl_kstr = strdup(s); break; } break; case TAD_Z: if ((y = cmkey(adlxtab,nadlxtab,"","",xxstring)) < 0) return(y); switch (y) { case TAD_X_C0: if ((y = cmkey(adlc0tab,nadlc0tab,"", "processed-by-emulator",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); adl_zc0 = y; break; case TAD_X_DETECT: if ((y = cmkey(adldtab,nadldtab,"","packet",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); adl_zmode = y; break; case TAD_X_STR: if ((y = cmtxt("","rz\\{13}",&s,xxstring)) < 0) return(y); free(adl_zstr); adl_zstr = strdup(s); break; } break; #endif /* OS2 */ } return(success = 1); #endif /* CK_AUTODL */ #endif /* CK_APC */ #ifdef OS2 case XYTBEL: return(success = setbell()); case XYTMBEL: /* MARGIN-BELL */ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if (y) { /* ON */ if ((z = cmnum("Column at which to set margin bell", "72",10,&x,xxstring)) < 0) return(z); } if ((z = cmcfm()) < 0) return(z); marginbell = y; marginbellcol = x; return(success = 1); #endif /* OS2 */ #ifdef CKTIDLE case XYTIDLE: /* IDLE-SEND */ case XYTITMO: /* IDLE-TIMEOUT */ if ((z = cmnum("seconds of idle time to wait, or 0 to disable", "0",10,&x,xxstring)) < 0) return(z); if (y == XYTIDLE) { if ((y = cmtxt("string to send, may contain kverbs and variables", "\\v(newline)",&s,xxstring)) < 0) return(y); tt_idlesnd_tmo = x; /* (old) */ tt_idlelimit = x; /* (new) */ makestr(&tt_idlestr,brstrip(s)); /* (new) */ tt_idlesnd_str = tt_idlestr; /* (old) */ tt_idleact = IDLE_OUT; /* (new) */ } else { if ((y = cmcfm()) < 0) return(y); tt_idlelimit = x; } #ifdef OS2 puterror(VTERM); #endif /* OS2 */ return(success = 1); case XYTIACT: { /* SET TERM IDLE-ACTION */ if ((y = cmkey(idlacts,nidlacts,"","",xxstring)) < 0) return(y); if (y == IDLE_OUT) { if ((x = cmtxt("string to send, may contain kverbs and variables" , "",&s,xxstring)) < 0) return(x); makestr(&tt_idlestr,brstrip(s)); /* (new) */ tt_idlesnd_str = tt_idlestr; /* (old) */ } else { if ((x = cmcfm()) < 0) return(x); } tt_idleact = y; return(success = 1); } #endif /* CKTIDLE */ case XYTDEB: /* TERMINAL DEBUG */ y = seton(&x); /* Go parse ON or OFF */ if (y > 0) /* Command succeeded? */ setdebses(x); return(y); #ifdef OS2 case XYTASCRL: /* SET TERMINAL AUTOSCROLL */ y = seton(&autoscroll); return(y); case XYTAPAGE: /* SET TERMINAL AUTOPAGE */ y = seton(&wy_autopage); return(y); case XYTROL: /* SET TERMINAL ROLL */ if ((y = cmkey(rolltab,nroll,"scrollback mode","insert",xxstring))<0) return(y); if (y == TTR_KEYS) { if ((x = cmkey(rollkeytab,nrollkey,"","send",xxstring))<0) return(x); if ((z = cmcfm()) < 0) return(z); tt_rkeys[VTERM] = x; } else { if ((x = cmcfm()) < 0) return(x); tt_roll[VTERM] = y; } return(success = 1); case XYTCTS: /* SET TERMINAL TRANSMIT-TIMEOUT */ y = cmnum("Maximum seconds to allow CTS off during CONNECT", "5",10,&x,xxstring); return(setnum(&tt_ctstmo,x,y,10000)); case XYTCPG: { /* SET TERMINAL CODE-PAGE */ int i; int cp = -1; y = cmnum("PC code page to use during terminal emulation", ckitoa(os2getcp()),10,&x,xxstring); if ((x = setnum(&cp,x,y,11000)) < 0) return(x); if (os2setcp(cp) != 1) { #ifdef NT if (isWin95()) printf( "Sorry, Windows 95 does not support code page switching\n"); else #endif /* NT */ printf( "Sorry, %d is not a valid code page for this system.\n",cp); return(-9); } /* Force the terminal character-sets conversions to be updated */ for ( i = 0; i < 4; i++ ) G[i].init = TRUE; return(1); } case XYTPAC: /* SET TERMINAL OUTPUT-PACING */ y = cmnum( "Pause between sending each character during CONNECT, milliseconds", "-1",10,&x,xxstring); return(setnum(&tt_pacing,x,y,10000)); #ifdef OS2MOUSE case XYTMOU: { /* SET TERMINAL MOUSE */ int old_mou = tt_mouse; if ((x = seton(&tt_mouse)) < 0) return(x); if (tt_mouse != old_mou) if (tt_mouse) os2_mouseon(); else os2_mouseoff(); return(1); } #endif /* OS2MOUSE */ #endif /* OS2 */ case XYTWID: { if ((y = cmnum( #ifdef OS2 "number of columns in display window during CONNECT", #else "number of columns on your screen", #endif /* OS2 */ "80",10,&x,xxstring)) < 0) return(y); if ((y = cmcfm()) < 0) return(y); #ifdef OS2 return(success = os2_settermwidth(x)); #else /* Not OS/2 */ tt_cols = x; return(success = 1); #endif /* OS2 */ } case XYTHIG: if ((y = cmnum( #ifdef OS2 "number of rows in display window during CONNECT, not including status line", tt_status[VTERM]?"24":"25", #else "24","number of rows on your screen", #endif /* OS2 */ 10,&x,xxstring)) < 0) return(y); if ((y = cmcfm()) < 0) return(y); #ifdef OS2 return (success = os2_settermheight(x)); #else /* Not OS/2 */ tt_rows = x; return(success = 1); #endif /* OS2 */ #ifdef OS2 case XYTPRN: { /* Print Mode */ extern bool xprint, aprint, cprint, uprint; if ((y = cmkey(prnmtab,nprnmtab,"","off", xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); switch (y) { case 0: if (cprint || uprint || aprint || xprint) printeroff(); cprint = xprint = uprint = 0; setaprint(0); break; case 1: if (!(cprint || uprint || aprint || xprint)) printeron(); setaprint(1); cprint = xprint = uprint = 0; break; case 2: if (!(cprint || uprint || aprint || xprint)) printeron(); cprint = 1; setaprint(0); xprint = uprint = 0; break; case 3: if (!(cprint || uprint || aprint || xprint)) printeron(); uprint = 1; setaprint(0); xprint = cprint = 0; break; } return(1); } #else #ifdef XPRINT case XYTPRN: { extern int tt_print; if ((x = seton(&tt_print)) < 0) return(x); return(success = 1); } #endif /* XPRINT */ #endif /* OS2 */ #ifdef OS2 case XYTSCNM: { extern int decscnm, decscnm_usr; if ((y = cmkey(normrev,4,"", decscnm_usr?"reverse":"normal", xxstring) ) < 0) return(y); if ((x = cmcfm()) < 0) return(x); decscnm_usr = y; if (decscnm != decscnm_usr) flipscreen(VTERM); return(1); } case XYTOPTI: if ((y = cmkey(onoff,2,"",tt_diff_upd?"on":"off", xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); tt_diff_upd = y; return(1); case XYTUPD: { int mode; if ((mode = cmkey(scrnupd,nscrnupd,"","fast",xxstring)) < 0) { return(mode); } else { y = cmnum( "Pause between FAST screen updates in CONNECT mode, milliseconds", "100",10,&x,xxstring ); if (x < 0 || x > 1000 ) { printf( "\n?The update rate must be between 0 and 1000 milliseconds.\n" ); return(success = 0); } if ((y = cmcfm()) < 0) return(y); updmode = tt_updmode = mode; return(setnum(&tt_update,x,y,10000)); } } case XYTCTRL: if ((x = cmkey(termctrl,ntermctrl,"","7",xxstring)) < 0) { return(x); } else { if ((y = cmcfm()) < 0) return(y); switch ( x ) { case 8: send_c1 = send_c1_usr = TRUE; break; case 7: default: send_c1 = send_c1_usr = FALSE; break; } } return(success = TRUE); break; #ifdef PCFONTS case XYTFON: if ( !IsOS2FullScreen() ) { printf( "\n?SET TERMINAL FONT is only supported in Full Screen sessions.\n"); return(success = FALSE); } if ((x = cmkey(term_font,ntermfont,"","default",xxstring)) < 0) { return(x); } else { if ((y = cmcfm()) < 0) return(y); if ( !os2LoadPCFonts() ) { tt_font = x; return(success = TRUE); } else { printf( "\n?PCFONTS.DLL is not available in CKERMIT executable directory.\n"); return(success = FALSE); } } break; #else /* PCFONTS */ #ifdef NT #ifdef KUI case XYTFON: return(setguifont()); /* ckuus3.c */ #endif /* KUI */ #endif /* NT */ #endif /* PCFONTS */ case XYTVCH: { extern int pheight, marginbot, cmd_rows, cmd_cols; if ((x = cmkey(tvctab,ntvctab,"",isWin95()?"win95-safe":"enabled", xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); #ifndef KUI if (x != tt_modechg) { switch (x) { case TVC_DIS: /* When disabled the heights of all of the virtual screens */ /* must be equal to the physical height of the console */ /* window and may not be changed. */ /* The width of the window may not be altered. */ tt_modechg = TVC_ENA; /* Temporary */ if (marginbot > pheight-(tt_status[VTERM]?1:0)) marginbot = pheight-(tt_status[VTERM]?1:0); tt_szchng[VCMD] = 1 ; tt_rows[VCMD] = pheight; VscrnInit(VCMD); SetCols(VCMD); cmd_rows = y; tt_szchng[VTERM] = 2 ; tt_rows[VTERM] = pheight - (tt_status[VTERM]?1:0); VscrnInit(VTERM); break; case TVC_ENA: /* When enabled the physical height of the console windows */ /* should be adjusted to the height of the virtual screen */ /* The width may be set to anything. */ /* nothing to do */ break; case TVC_W95: /* Win95-safe mode allows the physical height to change */ /* but restricts it to a width of 80 and a height equal to */ /* 25, 43, or 50. Must be adjusted now. */ /* The virtual heights must be equal to the above. */ if (pheight != 25 && pheight != 43 && pheight != 50) { if (pheight < 25) y = 25; else if (pheight < 43) y = 43; else y = 50; } else y = pheight; tt_modechg = TVC_ENA; /* Temporary */ tt_szchng[VCMD] = 1; tt_rows[VCMD] = y; tt_cols[VCMD] = 80; VscrnInit(VCMD); SetCols(VCMD); cmd_rows = y; cmd_cols = 80; marginbot = y-(tt_status[VTERM]?1:0); tt_szchng[VTERM] = 2; tt_rows[VTERM] = y - (tt_status[VTERM]?1:0); tt_cols[VTERM] = 80; VscrnInit(VTERM); break; } tt_modechg = x; } return(success = 1); #else return(success = 0); #endif /* KUI */ } case XYTSTAT: { extern int marginbot; if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); if (y != tt_status[VTERM] || y != tt_status_usr[VTERM]) { /* Might need to fixup the margins */ if ( marginbot == VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) ) if (y) { marginbot--; } else { marginbot++; } tt_status_usr[VTERM] = tt_status[VTERM] = y; if (y) { tt_szchng[VTERM] = 2; tt_rows[VTERM]--; VscrnInit(VTERM); /* Height set here */ #ifdef TNCODE if (TELOPT_ME(TELOPT_NAWS)) tn_snaws(); #endif /* TNCODE */ #ifdef RLOGCODE if (TELOPT_ME(TELOPT_NAWS)) rlog_naws(); #endif /* RLOGCODE */ #ifdef SSHBUILTIN if (TELOPT_ME(TELOPT_NAWS)) ssh_snaws(); #endif /* SSHBUILTIN */ } else { tt_szchng[VTERM] = 1; tt_rows[VTERM]++; VscrnInit(VTERM); /* Height set here */ #ifdef TNCODE if (TELOPT_ME(TELOPT_NAWS)) tn_snaws(); #endif /* TNCODE */ #ifdef RLOGCODE if (TELOPT_ME(TELOPT_NAWS)) rlog_naws(); #endif /* RLOGCODE */ #ifdef SSHBUILTIN if (TELOPT_ME(TELOPT_NAWS)) ssh_snaws(); #endif /* SSHBUILTIN */ } } return(1); } #endif /* OS2 */ #ifdef NT case XYTATTBUG: if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); tt_attr_bug = y; return(1); #endif /* NT */ #ifdef OS2 case XYTSGRC: if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); sgrcolors = y; return(1); case XYTSEND: if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); tt_senddata = y; return(1); case XYTSEOB: if ((y = cmkey(ttyseobtab,2,"","us_cr",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); wy_blockend = y; return(1); case XYTURLHI: { int done = 0, attr = VT_CHAR_ATTR_NORMAL; if ((x = cmkey(onoff,2,"","on",xxstring)) < 0) return(x); if (x) { z = 0; while (!done) { if ((y = cmkey(ttyprotab,nprotect,"", z?"done":"reverse",xxstring)) < 0) return(y); switch (y) { case TTATTDONE: done = TRUE; break; case TTATTBLI: attr |= VT_CHAR_ATTR_BLINK; break; case TTATTREV: attr |= VT_CHAR_ATTR_REVERSE; break; case TTATTITA: attr |= VT_CHAR_ATTR_ITALIC; break; case TTATTUND: attr |= VT_CHAR_ATTR_UNDERLINE; break; case TTATTBLD: attr |= VT_CHAR_ATTR_BOLD; break; case TTATTDIM: attr |= VT_CHAR_ATTR_DIM; break; case TTATTINV: attr |= VT_CHAR_ATTR_INVISIBLE; break; case TTATTNOR: break; } z = 1; /* One attribute has been chosen */ } } if ((z = cmcfm()) < 0) return(z); seturlhl(x); if (x) tt_url_hilite_attr = attr; return(1); } case XYTATTR: if ((x = cmkey(ttyattrtab,nattrib,"","underline",xxstring)) < 0) return(x); switch (x) { case TTATTBLI: if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); trueblink = y; #ifndef KUI if ( !trueblink && trueunderline ) { trueunderline = 0; printf("Warning: Underline being simulated by color.\n"); } #endif /* KUI */ break; case TTATTDIM: if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); truedim = y; break; case TTATTREV: if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); truereverse = y; break; case TTATTUND: if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); trueunderline = y; #ifndef KUI if (!trueblink && trueunderline) { trueblink = 1; printf("Warning: True blink mode is active.\n"); } #endif /* KUI */ break; case TTATTITA: if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); trueitalic = y; break; case TTATTPRO: { /* Set default Protected Character attribute */ extern vtattrib WPattrib; /* current WP Mode Attrib */ extern vtattrib defWPattrib; /* default WP Mode Attrib */ vtattrib wpa = {0,0,0,0,0,1,0,0,0,0,0}; /* Protected */ int done = 0; x = 0; while (!done) { if ((y = cmkey(ttyprotab,nprotect,"", x?"done":"dim",xxstring)) < 0) return(y); switch (y) { case TTATTNOR: break; case TTATTBLI: /* Blinking doesn't work */ wpa.blinking = TRUE; break; case TTATTREV: wpa.reversed = TRUE; break; case TTATTITA: wpa.italic = TRUE; break; case TTATTUND: wpa.underlined = TRUE; break; case TTATTBLD: wpa.bold = TRUE; break; case TTATTDIM: wpa.dim = TRUE; break; case TTATTINV: wpa.invisible = TRUE ; break; case TTATTDONE: done = TRUE; break; } x = 1; /* One attribute has been chosen */ } if ((x = cmcfm()) < 0) return(x); WPattrib = defWPattrib = wpa; break; } } return(1); case XYTKEY: { /* SET TERMINAL KEY */ int t, x, y; int clear = 0, deflt = 0; int flag = 0; int kc = -1; /* Key code */ int litstr = 0; /* Literal String? */ char *s = NULL; /* Key binding */ #ifndef NOKVERBS char *p = NULL; /* Worker */ #endif /* NOKVERBS */ con_event defevt; extern int os2gks; extern int mskkeys; extern int initvik; struct FDB kw,sw,nu,cm; defevt.type = error; if ((t = cmkey(ttkeytab,nttkey,"","",xxstring)) < 0) return(t); cmfdbi(&nu, /* First FDB - command switches */ _CMNUM, /* fcode */ "/literal, keycode, or action", "", /* default */ "", /* addtl string data */ 10, /* addtl numeric data 1: radix */ 0, /* addtl numeric data 2: 0 */ xxstring, /* Processing function */ NULL, /* Keyword table */ &sw /* Pointer to next FDB */ ); /* */ cmfdbi(&sw, /* Second FDB - switches */ _CMKEY, /* fcode */ "", "", /* default */ "", /* addtl string data */ nstrmswitab, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ strmswitab, /* Keyword table */ &kw /* Pointer to next FDB */ ); cmfdbi(&kw, /* Third FDB - command switches */ _CMKEY, /* fcode */ "/literal, keycode, or action", "", /* default */ "", /* addtl string data */ nstrmkeytab, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2 */ xxstring, /* Processing function */ strmkeytab, /* Keyword table */ &cm /* Pointer to next FDB */ ); cmfdbi(&cm, /* Final FDB - Confirmation */ _CMCFM, /* fcode */ "", "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ NULL, /* Keyword table */ NULL /* Pointer to next FDB */ ); while (kc < 0) { x = cmfdb(&nu); /* Parse something */ if (x < 0) return(x); switch (cmresult.fcode) { case _CMCFM: printf(" Press key to be defined: "); conbin((char)escape); /* Put terminal in binary mode */ os2gks = 0; /* Turn off Kverb preprocessing */ kc = congks(0); /* Get character or scan code */ os2gks = 1; /* Turn on Kverb preprocessing */ concb((char)escape); /* Restore terminal to cbreak mode */ if (kc < 0) { /* Check for error */ printf("?Error reading key\n"); return(0); } shokeycode(kc,t); /* Show current definition */ flag = 1; /* Remember it's a multiline command */ break; case _CMNUM: kc = cmresult.nresult; break; case _CMKEY: if (cmresult.fdbaddr == &sw) { /* Switch */ if (cmresult.nresult == 0) litstr = 1; } else if (cmresult.fdbaddr == &kw) { /* Keyword */ if (cmresult.nresult == 0) clear = 1; else deflt = 1; if ((x = cmcfm()) < 0) return(x); if (clear) clearkeymap(t); else if (deflt) defaultkeymap(t); initvik = 1; return(1); } } } /* Normal SET TERMINAL KEY command... */ if (mskkeys) kc = msktock(kc); if (kc < 0 || kc >= KMSIZE) { printf("?key code must be between 0 and %d\n", KMSIZE - 1); return(-9); } if (kc == escape) { printf("Sorry, %d is the CONNECT-mode escape character\n",kc); return(-9); } wideresult = -1; if (flag) { cmsavp(psave,PROMPTL); cmsetp(" Enter new definition: "); cmini(ckxech); } def_again: if (flag) prompt(NULL); if ((y = cmtxt("key definition,\n\ or Ctrl-C to cancel this command,\n\ or Enter to restore default definition", "",&s,NULL)) < 0) { if (flag) /* Handle parse errors */ goto def_again; else return(y); } s = brstrip(s); #ifndef NOKVERBS p = s; /* Save this place */ #endif /* NOKVERBS */ /* If the definition included any \Kverbs, quote the backslash so the \Kverb will still be in the definition when the key is pressed. We don't do this in zzstring(), because \Kverbs are valid only in this context and nowhere else. We use this code active for all versions that support SET KEY, even if they don't support \Kverbs, because otherwise \K would behave differently for different versions. */ for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */ if ((x > 0) && (s[x] == 'K' || s[x] == 'k') ) { /* Have K */ if ((x == 1 && s[x-1] == CMDQ) || (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) { line[y++] = CMDQ; /* Make it \\K */ } if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) { line[y-1] = CMDQ; /* Have \{K */ line[y++] = '{'; /* Make it \\{K */ } } line[y] = s[x]; } line[y++] = NUL; /* Terminate */ s = line + y + 1; /* Point to after it */ x = LINBUFSIZ - (int) strlen(line) - 1; /* Get remaining space */ if ((x < (LINBUFSIZ / 2)) || (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */ printf("?Key definition too long\n"); if (flag) cmsetp(psave); return(-9); } s = line + y + 1; /* Point to result. */ #ifndef NOKVERBS /* Special case: see if the definition starts with a \Kverb. If it does, point to it with p, otherwise set p to NULL. */ p = s; if (*p++ == CMDQ) { if (*p == '{') p++; p = (*p == 'k' || *p == 'K') ? p + 1 : NULL; } #endif /* NOKVERBS */ switch (strlen(s)) { /* Action depends on length */ case 0: /* Clear individual key def */ deletekeymap(t,kc); break; case 1: if (!litstr) { defevt.type = key; /* Single character */ defevt.key.scancode = *s; break; } default: /* Character string */ #ifndef NOKVERBS if (p) { y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */ /* Need exact match */ debug(F101,"set key kverb lookup",0,y); if (y > -1) { defevt.type = kverb; defevt.kverb.id = y; break; } } #endif /* NOKVERBS */ if (litstr) { defevt.type = literal; defevt.literal.string = (char *) malloc(strlen(s)+1); if (defevt.literal.string) strcpy(defevt.literal.string, s); /* safe */ } else { defevt.type = macro; defevt.macro.string = (char *) malloc(strlen(s)+1); if (defevt.macro.string) strcpy(defevt.macro.string, s); /* safe */ } break; } insertkeymap(t, kc, defevt); if (flag) cmsetp(psave); initvik = 1; /* Update VIK table */ return(1); } #ifdef PCTERM case XYTPCTERM: /* PCTERM Keyboard Mode */ if ((x = seton(&tt_pcterm)) < 0) return(x); return(success = 1); #endif /* PCTERM */ #endif /* OS2 */ #ifdef CK_TRIGGER case XYTRIGGER: if ((y = cmtxt("String to trigger automatic return to command mode", "",&s,xxstring)) < 0) return(y); makelist(s,tt_trigger,TRIGGERS); return(1); #endif /* CK_TRIGGER */ #ifdef OS2 case XYTSAC: if ((y = cmnum("ASCII value to use for spacing attributes", "32",10,&x,xxstring)) < 0) return(y); if ((y = cmcfm()) < 0) return(y); tt_sac = x; return(success = 1); case XYTKBDGL: { /* SET TERM KBD-FOLLOWS-GL/GR */ extern int tt_kb_glgr; /* from ckoco3.c */ if ((x = seton(&tt_kb_glgr)) < 0) return(x); return(success = 1); } #ifndef NOCSETS case XYTVTLNG: /* SET TERM DEC-LANGUAGE */ if ((y = cmkey(vtlangtab,nvtlangtab,"VT language", IS97801(tt_type_mode)?"german":"north-american", xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); /* A real VT terminal would use the language to set the */ /* default keyboard language for both 8-bit multinational */ /* and 7-bit national modes. For 8-bit mode it would */ /* set the terminal character-set to the ISO set if it */ /* is not already set. */ /* Latin-1 can be replaced by DEC Multinational */ switch (y) { case VTL_NORTH_AM: /* North American */ /* Multinational: Latin-1 */ /* National: US_ASCII */ dec_lang = y; dec_nrc = TX_ASCII; dec_kbd = TX_8859_1; break; case VTL_BRITISH : /* Multinational: Latin-1 */ /* National: UK_ASCII */ dec_lang = y; dec_nrc = TX_BRITISH; dec_kbd = TX_8859_1; break; case VTL_FRENCH : case VTL_BELGIAN : case VTL_CANADIAN: /* Multinational: Latin-1 */ /* National: FR_ASCII */ dec_lang = y; dec_nrc = TX_FRENCH; dec_kbd = TX_8859_1; break; case VTL_FR_CAN : /* Multinational: Latin-1 */ /* National: FC_ASCII */ dec_lang = y; dec_nrc = TX_CN_FRENCH; dec_kbd = TX_8859_1; break; case VTL_DANISH : case VTL_NORWEGIA: /* Multinational: Latin-1 */ /* National: NO_ASCII */ dec_lang = y; dec_nrc = TX_NORWEGIAN; dec_kbd = TX_8859_1; break; case VTL_FINNISH : /* Multinational: Latin-1 */ /* National: FI_ASCII */ dec_lang = y; dec_nrc = TX_FINNISH; dec_kbd = TX_8859_1; break; case VTL_GERMAN : /* Multinational: Latin-1 */ /* National: GR_ASCII */ dec_lang = y; dec_nrc = TX_GERMAN; dec_kbd = TX_8859_1; break; case VTL_DUTCH : /* Multinational: Latin-1 */ /* National: DU_ASCII */ dec_lang = y; dec_nrc = TX_DUTCH; dec_kbd = TX_8859_1; break; case VTL_ITALIAN : /* Multinational: Latin-1 */ /* National: IT_ASCII */ dec_lang = y; dec_nrc = TX_ITALIAN; dec_kbd = TX_8859_1; break; case VTL_SW_FR : case VTL_SW_GR : /* Multinational: Latin-1 */ /* National: CH_ASCII */ dec_lang = y; dec_nrc = TX_SWISS; dec_kbd = TX_8859_1; break; case VTL_SWEDISH : /* Multinational: Latin-1 */ /* National: SW_ASCII */ dec_lang = y; dec_nrc = TX_SWEDISH; dec_kbd = TX_8859_1; break; case VTL_SPANISH : /* Multinational: Latin-1 */ /* National: SP_ASCII */ dec_lang = y; dec_nrc = TX_SPANISH; dec_kbd = TX_8859_1; break; case VTL_PORTUGES: /* Multinational: Latin-1 */ /* National: Portugese ASCII */ dec_lang = y; dec_nrc = TX_PORTUGUESE; dec_kbd = TX_8859_1; break; case VTL_HEBREW : /* Multinational: Latin-Hebrew / DEC-Hebrew */ /* National: DEC 7-bit Hebrew */ dec_lang = y; dec_nrc = TX_HE7; dec_kbd = TX_8859_8; break; case VTL_GREEK : /* Multinational: Latin-Greek / DEC-Greek */ /* National: DEC Greek NRC */ /* is ELOT927 equivalent to DEC Greek???? */ dec_lang = y; dec_nrc = TX_ELOT927; dec_kbd = TX_8859_7; break; #ifdef COMMENT case VTL_TURK_Q : case VTL_TURK_F : /* Multinational: Latin-Turkish / DEC-Turkish */ /* National: DEC 7-bit Turkish */ break; #endif /* COMMENT */ case VTL_HUNGARIA: /* Multinational: Latin-2 */ /* National: no national mode */ dec_lang = y; dec_nrc = TX_HUNGARIAN; dec_kbd = TX_8859_2; break; case VTL_SLOVAK : case VTL_CZECH : case VTL_POLISH : case VTL_ROMANIAN: /* Multinational: Latin-2 */ /* National: no national mode */ dec_lang = y; dec_nrc = TX_ASCII; dec_kbd = TX_8859_2; break; case VTL_RUSSIAN : /* Multinational: Latin-Cyrillic / KOI-8 */ /* National: DEC Russian NRC */ dec_lang = y; dec_nrc = TX_KOI7; dec_kbd = TX_8859_5; break; case VTL_LATIN_AM: /* Multinational: not listed in table */ /* National: not listed in table */ dec_lang = y; dec_nrc = TX_ASCII; dec_kbd = TX_8859_1; break; #ifdef COMMENT case VTL_SCS : /* Multinational: Latin-2 */ /* National: SCS NRC */ break; #endif /* COMMENT */ default: return(success = 0); } if (IS97801(tt_type_mode)) { SNI_bitmode(cmask == 0377 ? 8 : 7); } return(success = 1); #endif /* NOCSETS */ case XYTVTNRC: { /* SET TERM DEC-NRC-MODE */ extern int decnrcm_usr, decnrcm; /* from ckoco3.c */ if ((x = seton(&decnrcm_usr)) < 0) return(x); decnrcm = decnrcm_usr; return(success = 1); } case XYTSNIPM: { /* SET TERM SNI-PAGEMODE */ extern int sni_pagemode, sni_pagemode_usr; if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); sni_pagemode_usr = sni_pagemode = y; return(success = 1); } case XYTSNISM: { /* SET TERM SNI-SCROLLMODE */ extern int sni_scroll_mode, sni_scroll_mode_usr; if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); sni_scroll_mode_usr = sni_scroll_mode = y; return(success = 1); } case XYTSNICC: { /* SET TERM SNI-CH.CODE */ extern int sni_chcode_usr; if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); sni_chcode_usr = y; SNI_chcode(y); return(success = 1); } case XYTSNIFV: { /* SET TERM SNI-FIRMWARE-VERSIONS */ extern CHAR sni_kbd_firmware[], sni_term_firmware[]; CHAR kbd[7],term[7]; if ((x = cmfld("Keyboard Firmware Version",sni_kbd_firmware, &s, xxstring)) < 0) return(x); if ((int)strlen(s) != 6) { printf("?Sorry - the firmware version must be 6 digits long\n"); return(-9); } for (i = 0; i < 6; i++) { if (!isdigit(s[i])) { printf("?Sorry - the firmware version can only contain digits [0-9]\n"); return(-9); } } ckstrncpy(kbd,s,7); if ((x = cmfld("Terminal Firmware Version",sni_term_firmware, &s, xxstring)) < 0) return(x); if ((int)strlen(s) != 6) { printf("?Sorry - the firmware version must be 6 digits long\n"); return(-9); } for (i = 0; i < 6; i++) { if (!isdigit(s[i])) { printf("?Sorry - the firmware version can only contain digits [0-9]\n"); return(-9); } } ckstrncpy(term,s,7); if ((x = cmcfm()) < 0) return(x); ckstrncpy(sni_kbd_firmware,kbd,7); ckstrncpy(sni_term_firmware,term,7); return(success = 1); } case XYTLSP: { /* SET TERM LINE-SPACING */ if ((x = cmfld("Line Spacing","1",&s, xxstring)) < 0) return(x); if (isfloat(s,0) < 1) { /* (sets floatval) */ printf("?Integer or floating-point number required\n"); return(-9); } if (floatval < 1.0 || floatval > 3.0) { printf("?Value must within the range 1.0 and 3.0 (inclusive)\n"); return(-9); } if ((x = cmcfm()) < 0) return(x); #ifdef KUI tt_linespacing[VCMD] = tt_linespacing[VTERM] = floatval; return(success = 1); #else /* KUI */ printf("?Sorry, Line-spacing is only supported in K95G.EXE.\n"); return(success = 0); #endif /* KUI */ } #endif /* OS2 */ default: /* Shouldn't get here. */ return(-2); } #endif /* MAC */ #ifdef COMMENT /* This was supposed to shut up picky compilers but instead it makes most compilers complain about "statement not reached". */ return(-2); #endif /* COMMENT */ #ifdef OS2 return(-2); #endif /* OS2 */ } #ifdef OS2 int settitle(void) { extern char usertitle[]; if ((y = cmtxt("title text","",&s,xxstring)) < 0) return(y); #ifdef IKSD if (inserver) { printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ s = brstrip(s); ckstrncpy(usertitle,s,64); os2settitle("",1); return(1); } static struct keytab dialertab[] = { /* K95 Dialer types */ "backspace", 0, 0, "enter", 1, 0 }; static int ndialer = 2; int setdialer(void) { int t, x, y; int kc; /* Key code */ char *s = NULL; /* Key binding */ #ifndef NOKVERBS char *p = NULL; /* Worker */ #endif /* NOKVERBS */ con_event defevt; extern int os2gks; extern int mskkeys; extern int initvik; defevt.type = error; if (( x = cmkey(dialertab, ndialer, "Kermit-95 dialer work-arounds", "", xxstring)) < 0 ) return(x); switch (x) { case 0: /* Backspace */ kc = 264; break; case 1: /* Enter */ kc = 269; break; default: printf("Illegal value in setdialer()\n"); return(-9); } if ((y = cmtxt("Key definition","",&s,xxstring)) < 0) return(y); #ifdef IKSD if (inserver) { printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ s = brstrip(s); #ifndef NOKVERBS p = s; /* Save this place */ #endif /* NOKVERBS */ /* If the definition included any \Kverbs, quote the backslash so the \Kverb will still be in the definition when the key is pressed. We don't do this in zzstring(), because \Kverbs are valid only in this context and nowhere else. We use this code active for all versions that support SET KEY, even if they don't support \Kverbs, because otherwise \K would behave differently for different versions. */ for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */ if ((x > 0) && (s[x] == 'K' || s[x] == 'k') ) { /* Have K */ if ((x == 1 && s[x-1] == CMDQ) || (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) { line[y++] = CMDQ; /* Make it \\K */ } if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) { line[y-1] = CMDQ; /* Have \{K */ line[y++] = '{'; /* Make it \\{K */ } } line[y] = s[x]; } line[y++] = NUL; /* Terminate */ s = line + y + 1; /* Point to after it */ x = LINBUFSIZ - (int) strlen(line) - 1; /* Calculate remaining space */ if ((x < (LINBUFSIZ / 2)) || (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */ printf("?Key definition too long\n"); return(-9); } s = line + y + 1; /* Point to result. */ #ifndef NOKVERBS /* Special case: see if the definition starts with a \Kverb. If it does, point to it with p, otherwise set p to NULL. */ p = s; if (*p++ == CMDQ) { if (*p == '{') p++; p = (*p == 'k' || *p == 'K') ? p + 1 : NULL; } #endif /* NOKVERBS */ /* Clear the definition for SET KEY */ if (macrotab[kc]) { /* Possibly free old macro from key. */ free((char *)macrotab[kc]); macrotab[kc] = NULL; } keymap[kc] = (KEY) kc; /* Now reprogram the default value for all terminal types */ /* remember to treat Wyse and Televideo terminals special */ /* because of their use of Kverbs for Backspace and Enter */ for (t = 0; t <= TT_MAX; t++) { if ( ISDG200(t) && kc == 264) { extern char * udkfkeys[] ; if (kc == 264) { /* \Kdgbs */ if (udkfkeys[83]) free(udkfkeys[83]); udkfkeys[83] = strdup(s); } } else if (ISWYSE(t) || ISTVI(t)) { extern char * udkfkeys[] ; if (kc == 264) { /* \Kwybs or \Ktvibs */ if (udkfkeys[32]) free(udkfkeys[32]); udkfkeys[32] = strdup(s); } if (kc == 269) { /* \Kwyenter and \Kwyreturn */ if (udkfkeys[39]) /* \Ktvienter and \Ktvireturn */ free(udkfkeys[39]); udkfkeys[39] = strdup(s); if (udkfkeys[49]) free(udkfkeys[49]); udkfkeys[49] = strdup(s); } } else { switch (strlen(s)) { /* Action depends on length */ case 0: /* Clear individual key def */ deletekeymap(t,kc); break; case 1: defevt.type = key; /* Single character */ defevt.key.scancode = *s; break; default: /* Character string */ #ifndef NOKVERBS if (p) { y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */ /* Exact match req'd */ debug(F101,"set key kverb lookup",0,y); if (y > -1) { defevt.type = kverb; defevt.kverb.id = y; break; } } #endif /* NOKVERBS */ defevt.type = macro; defevt.macro.string = (char *) malloc(strlen(s)+1); if (defevt.macro.string) strcpy(defevt.macro.string, s); /* safe */ break; } insertkeymap( t, kc, defevt ) ; initvik = 1; /* Update VIK table */ } } return(1); } #endif /* OS2 */ #ifdef NT int setwin95( void ) { int x, y, z; if (( y = cmkey(win95tab, nwin95, "Windows 95 specific work-arounds", "keyboard-translation", xxstring)) < 0 ) return (y); switch (y) { case XYWPOPUP: if ((y = cmkey(onoff,2,"popups are used to prompt the user for data", "on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); win95_popup = y; return(1); case XYW8_3: if ((y = cmkey(onoff,2,"8.3 FAT file names","off",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); win95_8_3 = y; return(1); case XYWSELECT: if ((y = cmkey(onoff,2,"\"select()\" fails on write","off", xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); win95selectbug = y; return(1); case XYWAGR: if ((y = cmkey(onoff,2,"Right-Alt is Alt-Gr","off",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); win95altgr = y; return(1); case XYWOIO: if ((y = cmkey(onoff,2,"Use Overlapped I/O","on",xxstring)) < 0) return(y); if (y) { if ((x = cmnum("Maximum number of outstanding I/O requests", "10",10,&z,xxstring)) < 0) return(x); if (z < 1 || z > 7) { printf( "?Maximum outstanding I/O requests must be between 1 and 7.\n"); return(-9); } } else z = 1; if ((x = cmcfm()) < 0) return(x); owwait = !y; maxow = maxow_usr = z; return(1); case XYWKEY: #ifndef COMMENT printf("\n?\"Keyboard-Translation\" is no longer required.\n"); return(-9); #else /* COMMENT */ if (( z = cmkey(tcstab, ntcs, "Keyboard Character Set", "latin1-iso", xxstring)) < 0) return (z); if ((x = cmcfm()) < 0) return(x); win95kcsi = z; win95kl2 = (win95kcsi == TC_2LATIN); if (win95kcsi == TC_TRANSP) { win95kcs = NULL; } else { #ifdef UNICODE win95kcs = xlr[win95kcsi][tx2fc(tcsl)]; #else /* UNICODE */ win95kcs = xlr[win95kcsi][tcsl]; #endif /* UNICODE */ } return(1); #endif /* COMMENT */ case XYWLUC: if ((y = cmkey(onoff,2,"Unicode-to-Lucida-Console substitutions", "on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); win95lucida = y; return(1); case XYWHSL: if ((y = cmkey(onoff,2,"Horizontal Scan Line substitutions", "on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); win95hsl = y; return(1); default: printf("Illegal value in setwin95()\n"); return(-9); } } #endif /* NT */ #ifdef OS2 int setprty ( #ifdef CK_ANSIC void #endif /* CK_ANSIC */ /* setprty */ ) { int x, y; if (( y = cmkey(prtytab, nprty, "priority level of terminal and communication threads", "foreground-server", xxstring)) < 0 ) return (y); if ((x = cmcfm()) < 0) return (x); #ifdef IKSD if (inserver && #ifdef IKSDCONF iksdcf #else 1 #endif /* IKSDCONF */ ) { if ((y = cmcfm()) < 0) return(y); printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ priority = y; return(TRUE); } #endif /* OS2 */ int setbell() { int y, x; #ifdef OS2 int z; #endif /* OS2 */ if ((y = cmkey(beltab,nbeltab, #ifdef OS2 "how console and terminal bells should\nbe generated", "audible", #else "Whether Kermit should ring the terminal bell (beep)", "on", #endif /* OS2 */ xxstring)) < 0) return(y); #ifdef IKSD if (inserver) { if ((y = cmcfm()) < 0) return(y); printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ switch (y) { /* SET BELL */ case XYB_NONE: #ifdef OS2 case XYB_VIS: #endif /* OS2 */ if ((x = cmcfm()) < 0) return(x); #ifdef OS2 tt_bell = y; #else tt_bell = 0; #endif /* OS2 */ break; case XYB_AUD: #ifdef OS2 if ((x = cmkey(audibletab, naudibletab, "how audible console and terminal\nbells should be generated", "beep",xxstring))<0) return(x); if ((z = cmcfm()) < 0) return(z); tt_bell = y | x; #else /* This lets C-Kermit accept but ignore trailing K95 keywords */ if ((x = cmtxt("Confirm with carriage return","",&s,xxstring)) < 0) return(x); tt_bell = 1; #endif /* OS2 */ break; } return(1); } #ifdef OS2MOUSE int setmou( #ifdef CK_ANSIC void #endif /* CK_ANSIC */ /* setmou */ ) { extern int initvik; int button = 0, event = 0; char * p; BOOL isWheelNotButton; if ((y = cmkey(mousetab,nmtab,"","",xxstring)) < 0) return(y); #ifdef IKSD if (inserver) { if ((y = cmcfm()) < 0) return(y); printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ if (y == XYM_ON) { /* MOUSE ACTIVATION */ int old_mou = tt_mouse; if ((x = seton(&tt_mouse)) < 0) return(x); if (tt_mouse != old_mou) if (tt_mouse) os2_mouseon(); else os2_mouseoff(); return(1); } if (y == XYM_DEBUG) { /* MOUSE DEBUG */ extern int MouseDebug; if ((x = seton(&MouseDebug)) < 0) return(x); return(1); } if (y == XYM_CLEAR) { /* Reset Mouse Defaults */ if ((x = cmcfm()) < 0) return(x); mousemapinit(-1,-1); initvik = 1; /* Update VIK Table */ return 1; } if (y == XYM_REPORTING) { extern int mouse_reporting_mode; extern BOOL mouse_reporting_override; int setting = cmkey(mousereportingtab,nmousereportingtab, "Mouse reporting behavior","enabled", xxstring); if (setting < 0) return setting; switch(setting) { case XYM_REPORTING_DISABLED: mouse_reporting_mode |= MOUSEREPORTING_DISABLE; break; case XYM_REPORTING_ENABLED: /* If mouse reporting isn't currently disabled do nothing * otherwise we might accidentally deactivate it if the mode * isn't already _NONE */ mouse_reporting_mode &= ~MOUSEREPORTING_DISABLE; mouse_reporting_override = FALSE; break; case XYM_REPORTING_OVERRIDE: mouse_reporting_mode &= ~MOUSEREPORTING_DISABLE; mouse_reporting_override = TRUE; break; } return 1; } if (y != XYM_BUTTON && y != XYM_WHEEL) { /* Shouldn't happen. */ printf("Internal parsing error\n"); return(-9); } /* MOUSE EVENT ... */ if (y == XYM_BUTTON) { if ((button = cmkey(mousebuttontab,nmbtab, "Button number","1", xxstring)) < 0) return(button); isWheelNotButton = FALSE; } else { if ((button = cmkey(mousewheeltab,nmousewheeltab, "Mouse wheel direction","up", xxstring)) < 0) return(button); isWheelNotButton = TRUE; } if ((y = cmkey(mousemodtab,nmmtab, "Keyboard modifier","none", xxstring)) < 0) return(y); event |= y; /* OR in the bits */ if (!isWheelNotButton) { if ((y = cmkey(mclicktab,nmctab,"","click",xxstring)) < 0) return(y); } else { y = XYM_C1; /* mouse wheel is always a single click. */ } /* Two bits are assigned, if neither are set then it is button one */ event |= y; /* OR in the bit */ wideresult = -1; if ((y = cmtxt("definition,\n\ or Ctrl-C to cancel this command,\n\ or Enter to restore default definition", "",&s,NULL)) < 0) { return(y); } s = brstrip(s); p = s; /* Save this place */ /* If the definition included any \Kverbs, quote the backslash so the \Kverb will still be in the definition when the key is pressed. We don't do this in zzstring(), because \Kverbs are valid only in this context and nowhere else. This code copied from SET KEY, q.v. for addt'l commentary. */ for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */ if ((x > 0) && (s[x] == 'K' || s[x] == 'k') ) { /* Have K */ if ((x == 1 && s[x-1] == CMDQ) || (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) { line[y++] = CMDQ; /* Make it \\K */ } if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) { line[y-1] = CMDQ; /* Have \{K */ line[y++] = '{'; /* Make it \\{K */ } } line[y] = s[x]; } line[y++] = NUL; /* Terminate */ s = line + y + 1; /* Point to after it */ x = LINBUFSIZ - (int) strlen(line) - 1; /* Calculate remaining space */ if ((x < (LINBUFSIZ / 2)) || (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */ printf("?Key definition too long\n"); return(-9); } s = line + y + 1; /* Point to result. */ #ifndef NOKVERBS /* Special case: see if the definition starts with a \Kverb. If it does, point to it with p, otherwise set p to NULL. */ p = s; if (*p++ == CMDQ) { if (*p == '{') p++; p = (*p == 'k' || *p == 'K') ? p + 1 : NULL; } #else p = NULL; #endif /* NOKVERBS */ /* free the old definition if necessary */ if (mousemap[button][event].type == macro) { free( mousemap[button][event].macro.string); mousemap[button][event].macro.string = NULL; } switch (strlen(s)) { /* Action depends on length */ case 0: /* Reset to default binding */ mousemapinit( button, event ); break; case 1: /* Single character */ mousemap[button][event].type = key; mousemap[button][event].key.scancode = *s; break; default: /* Character string */ #ifndef NOKVERBS if (p) { y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */ debug(F101,"set mouse kverb lookup",0,y); /* need exact match */ if (y > -1) { /* Assign the kverb to the event */ mousemap[button][event].type = kverb; mousemap[button][event].kverb.id = F_KVERB | y; break; } } #endif /* NOKVERBS */ /* Otherwise, it's a macro, so assign the macro to the event */ mousemap[button][event].type = macro; mousemap[button][event].macro.string = (MACRO) malloc(strlen(s)+1); if (mousemap[button][event].macro.string) strcpy((char *) mousemap[button][event].macro.string, s); /* safe */ break; } initvik = 1; /* Update VIK Table */ if ( (button == XYM_B3) && (mousebuttoncount() < 3) && !quiet ) { printf("?Warning: this machine does not have a three button mouse.\n"); return(0); } return(1); } #endif /* OS2MOUSE */ #endif /* NOLOCAL */ #ifndef NOXFER int /* SET SEND/RECEIVE */ #ifdef CK_ANSIC setsr( int xx, int rmsflg ) #else setsr(xx, rmsflg) int xx; int rmsflg; #endif /* CK_ANSIC */ { if (xx == XYRECV) ckstrncpy(line,"Parameter for inbound packets",LINBUFSIZ); else ckstrncpy(line,"Parameter for outbound packets",LINBUFSIZ); if (rmsflg) { if ((y = cmkey(rsrtab,nrsrtab,line,"",xxstring)) < 0) { if (y == -3) { printf("?Remote receive parameter required\n"); return(-9); } else return(y); } } else { if ((y = cmkey(srtab,nsrtab,line,"",xxstring)) < 0) return(y); } switch (y) { case XYQCTL: /* CONTROL-PREFIX */ if ((x = cmnum("ASCII value of control prefix","",10,&y,xxstring)) < 0) return(x); if ((x = cmcfm()) < 0) return(x); if ((y > 32 && y < 63) || (y > 95 && y < 127)) { if (xx == XYRECV) ctlq = (CHAR) y; /* RECEIVE prefix, use with caution! */ else myctlq = (CHAR) y; /* SEND prefix, OK to change */ return(success = 1); } else { printf("?Illegal value for prefix character\n"); return(-9); } case XYEOL: if ((y = setcc("13",&z)) < 0) return(y); if (z > 31) { printf("Sorry, the legal values are 0-31\n"); return(-9); } if (xx == XYRECV) eol = (CHAR) z; else seol = (CHAR) z; return(success = y); case XYLEN: y = cmnum("Maximum number of characters in a packet","90",10,&x, xxstring); if (xx == XYRECV) { /* Receive... */ if ((y = setnum(&z,x,y,maxrps)) < 0) return(y); if (protocol != PROTO_K) { printf("?Sorry, this command does not apply to %s protocol.\n", ptab[protocol].p_name ); printf("Use SET SEND PACKET-LENGTH for XYZMODEM\n"); return(-9); } if (z < 10) { printf("Sorry, 10 is the minimum\n"); return(-9); } if (rmsflg) { sstate = setgen('S', "401", ckitoa(z), ""); return((int) sstate); } else { if (protocol == PROTO_K) { if (z > MAXRP) z = MAXRP; y = adjpkl(z,wslotr,bigrbsiz); rpsizf = 1; /* Packet-size override flag fdc 20220917 */ if (y != z) { urpsiz = y; if (!xcmdsrc) if (msgflg) printf( " Adjusting receive packet-length to %d for %d window slots\n", y, wslotr); } urpsiz = y; ptab[protocol].rpktlen = urpsiz; rpsiz = (y > 94) ? 94 : y; } else { #ifdef CK_XYZ if ((protocol == PROTO_X || protocol == PROTO_XC) && z != 128 && z != 1024) { printf("Sorry, bad packet length for XMODEM.\n"); printf("Please use 128 or 1024.\n"); return(-9); } #endif /* CK_XYZ */ urpsiz = rpsiz = z; } } } else { /* Send... */ if ((y = setnum(&z,x,y,maxsps)) < 0) return(y); if (z < 10) { printf("Sorry, 10 is the minimum\n"); return(-9); } if (protocol == PROTO_K) { if (z > MAXSP) z = MAXSP; spsiz = z; /* Set it */ y = adjpkl(spsiz,wslotr,bigsbsiz); if (y != spsiz && !xcmdsrc) if (msgflg) printf("Adjusting packet size to %d for %d window slots\n", y,wslotr); } else y = z; #ifdef CK_XYZ if ((protocol == PROTO_X || protocol == PROTO_XC) && z != 128 && z != 1024) { printf("Sorry, bad packet length for XMODEM.\n"); printf("Please use 128 or 1024.\n"); return(-9); } #endif /* CK_XYZ */ spsiz = spmax = spsizr = y; /* Set it and flag that it was set */ spsizf = 1; /* to allow overriding Send-Init. */ ptab[protocol].spktflg = spsizf; ptab[protocol].spktlen = spsiz; } if (pflag && protocol == PROTO_K && !xcmdsrc) { if (z > 94 && !reliable && msgflg) { /* printf("Extended-length packets requested.\n"); */ if (bctr < 2 && z > 200) printf("\ Remember to SET BLOCK 2 or 3 for long packets.\n"); } if (speed <= 0L) speed = ttgspd(); #ifdef COMMENT /* Kermit does this now itself. */ if (speed <= 0L && z > 200 && msgflg) { printf("\ Make sure your timeout interval is long enough for %d-byte packets.\n",z); } #endif /* COMMENT */ } return(success = y); case XYMARK: #ifdef DOOMSDAY /* Printable start-of-packet works for UNIX and VMS only! */ x_ifnum = 1; y = cmnum("Code for packet-start character","1",10,&x,xxstring); x_ifnum = 0; if ((y = setnum(&z,x,y,126)) < 0) return(y); #else if ((y = setcc("1",&z)) < 0) return(y); #endif /* DOOMSDAY */ if (xx == XYRECV) stchr = (CHAR) z; else { mystch = (CHAR) z; #ifdef IKS_OPTION /* If IKS negotiation in use */ if (TELOPT_U(TELOPT_KERMIT) || TELOPT_ME(TELOPT_KERMIT)) tn_siks(KERMIT_SOP); /* Report change to other side */ #endif /* IKS_OPTION */ } return(success = y); case XYNPAD: /* PADDING */ y = cmnum("How many padding characters for inbound packets","0",10,&x, xxstring); if ((y = setnum(&z,x,y,94)) < 0) return(y); if (xx == XYRECV) mypadn = (CHAR) z; else npad = (CHAR) z; return(success = y); case XYPADC: /* PAD-CHARACTER */ if ((y = setcc("0",&z)) < 0) return(y); if (xx == XYRECV) mypadc = z; else padch = z; return(success = y); case XYTIMO: /* TIMEOUT */ if (xx == XYRECV) { y = cmnum("Packet timeout interval",ckitoa(URTIME),10,&x,xxstring); if ((y = setnum(&z,x,y,94)) < 0) return(y); if (rmsflg) { /* REMOTE SET RECEIVE TIMEOUT */ sstate = setgen('S', "402", ckitoa(z), ""); return((int) sstate); } else { /* SET RECEIVE TIMEOUT */ pkttim = z; /* Value to put in my negotiation */ } /* packet for other Kermit to use */ } else { /* SET SEND TIMEOUT */ #ifdef CK_TIMERS extern int rttflg, mintime, maxtime; int tmin = 0, tmax = 0; #endif /* CK_TIMERS */ y = cmnum("Packet timeout interval",ckitoa(DMYTIM),10,&x,xxstring); if (y == -3) { /* They cancelled a previous */ x = DMYTIM; /* SET SEND command, so restore */ timef = 0; /* and turn off the override flag */ y = cmcfm(); } #ifdef CK_TIMERS if (y < 0) return(y); if (x < 0) { printf("?Out of range - %d\n",x); return(-9); } if ((z = cmkey(timotab,2,"","dynamic",xxstring)) < 0) return(z); if (z) { if ((y = cmnum("Minimum timeout to allow", "1",10,&tmin,xxstring)) < 0) return(y); if (tmin < 1) { printf("?Out of range - %d\n",tmin); return(-9); } if ((y = cmnum("Maximum timeout to allow", "0",10,&tmax,xxstring)) < 0) return(y); /* 0 means let Kermit choose, < 0 means no maximum */ } if ((y = cmcfm()) < 0) return(y); rttflg = z; /* Round-trip timer flag */ z = x; #else if ((y = setnum(&z,x,y,94)) < 0) return(y); #endif /* CK_TIMERS */ timef = 1; /* Turn on the override flag */ timint = rtimo = z; /* Override value for me to use */ #ifdef CK_TIMERS if (rttflg) { /* Lower and upper bounds */ mintime = tmin; maxtime = tmax; } #endif /* CK_TIMERS */ } return(success = 1); case XYFPATH: /* PATHNAMES */ if (xx == XYRECV) { y = cmkey(rpathtab,nrpathtab,"","auto",xxstring); } else { y = cmkey(pathtab,npathtab,"","off",xxstring); } if (y < 0) return(y); if ((x = cmcfm()) < 0) return(x); if (xx == XYRECV) { /* SET RECEIVE PATHNAMES */ fnrpath = y; ptab[protocol].fnrp = fnrpath; } else { /* SET SEND PATHNAMES */ fnspath = y; ptab[protocol].fnsp = fnspath; } return(success = 1); /* Note: 0 = ON, 1 = OFF */ /* In other words, ON = leave pathnames ON, OFF = take them off. */ case XYPAUS: /* SET SEND/RECEIVE PAUSE */ y = cmnum("Milliseconds to pause between packets","0",10,&x,xxstring); if ((y = setnum(&z,x,y,15000)) < 0) return(y); pktpaus = z; return(success = 1); #ifdef CKXXCHAR /* SET SEND/RECEIVE IGNORE/DOUBLE */ case XYIGN: case XYDBL: { int i, zz; short *p; extern short dblt[]; extern int dblflag, ignflag; /* Make space for a temporary copy of the ignore/double table */ zz = y; #ifdef COMMENT if (zz == XYIGN && xx == XYSEND) { blah blah who cares } if (zz == XYDBL && xx == XYRECV) { blah blah } #endif /* COMMENT */ p = (short *)malloc(256 * sizeof(short)); if (!p) { printf("?Internal error - malloc failure\n"); return(-9); } for (i = 0; i < 256; i++) p[i] = dblt[i]; /* Copy current table */ while (1) { /* Collect a list of numbers */ #ifndef NOSPL x_ifnum = 1; /* Turn off complaints from eval() */ #endif /* NOSPL */ if ((x = cmnum(zz == XYDBL ? "Character to double" : "Character to ignore", "",10,&y,xxstring )) < 0) { #ifndef NOSPL x_ifnum = 0; #endif /* NOSPL */ if (x == -3) /* Done */ break; if (x == -2) { if (p) { free(p); p = NULL; } debug(F110,"SET S/R DOUBLE/IGNORE atmbuf",atmbuf,0); if (!ckstrcmp(atmbuf,"none",4,0) || !ckstrcmp(atmbuf,"non",3,0) || !ckstrcmp(atmbuf,"no",2,0) || !ckstrcmp(atmbuf,"n",1,0)) { if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); for (y = 0; y < 256; y++) dblt[y] &= (zz == XYDBL) ? 1 : 2; if (zz == XYDBL) dblflag = 0; if (zz == XYIGN) ignflag = 0; return(success = 1); } else { printf( "?Please specify a number or the word NONE\n"); return(-9); } } else { free(p); p = NULL; return(x); } } #ifndef NOSPL x_ifnum = 0; #endif /* NOSPL */ if (y < 0 || y > 255) { printf("?Please enter a character code in range 0-255\n"); free(p); p = NULL; return(-9); } p[y] |= (zz == XYDBL) ? 2 : 1; if (zz == XYDBL) dblflag = 1; if (zz == XYIGN) ignflag = 1; } /* End of while loop */ if ((x = cmcfm()) < 0) return(x); /* Get here only if they have made no mistakes. Copy temporary table back to permanent one, then free temporary table and return successfully. */ if (p) { for (i = 0; i < 256; i++) dblt[i] = p[i]; free(p); p = NULL; } return(success = 1); } #endif /* CKXXCHAR */ #ifdef PIPESEND case XYFLTR: { /* SET { SEND, RECEIVE } FILTER */ if ((y = cmtxt((xx == XYSEND) ? "Filter program for sending files -\n\ use \\v(filename) to substitute filename" : "Filter program for receiving files -\n\ use \\v(filename) to substitute filename", "",&s,NULL)) < 0) return(y); if (!*s) { /* Removing a filter... */ if (xx == XYSEND && sndfilter) { makestr(&g_sfilter,NULL); makestr(&sndfilter,NULL); } else if (rcvfilter) { makestr(&g_rfilter,NULL); makestr(&rcvfilter,NULL); } return(success = 1); } /* Adding a filter... */ s = brstrip(s); /* Strip any braces */ y = strlen(s); if (xx == XYSEND) { /* For SEND filter... */ for (x = 0; x < y; x++) { /* make sure they included "\v(...)" */ if (s[x] != '\\') continue; if (s[x+1] == 'v') break; } if (x == y) { printf( "?Filter must contain a replacement variable for filename.\n" ); return(-9); } } if (xx == XYSEND) { makestr(&sndfilter,s); makestr(&g_sfilter,s); } else { makestr(&rcvfilter,s); makestr(&g_rfilter,s); } return(success = 1); } #endif /* PIPESEND */ case XYINIL: y = cmnum("Max length for protocol init string","-1",10,&x,xxstring); if ((y = setnum(&z,x,y,-1)) < 0) return(y); if (xx == XYSEND) sprmlen = z; else rprmlen = z; return(success = 1); case 993: { extern int sendipkts; if (xx == XYSEND) { if ((x = seton(&sendipkts)) < 0) return(x); } return(1); } #ifdef CK_PERMS case 994: switch(xx) { case XYSEND: if ((x = seton(&atlpro)) < 0) return(x); atgpro = atlpro; return(1); case XYRECV: if ((x = seton(&atlpri)) < 0) return(x); atgpri = atlpri; return(1); default: return(-2); } #endif /* CK_PERMS */ #ifndef NOCSETS case XYCSET: { /* CHARACTER-SET-SELECTION */ extern struct keytab xfrmtab[]; extern int r_cset, s_cset; if ((y = cmkey(xfrmtab,2,"","automatic",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); if (xx == XYSEND) s_cset = y; else r_cset = y; return(success = 1); } #endif /* NOCSETS */ case XYBUP: if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); if ((x = cmcfm()) < 0) return(x); if (xx == XYSEND) { extern int skipbup; skipbup = (y == 0) ? 1 : 0; return(success = 1); } else { printf( "?Please use SET FILE COLLISION to choose the desired action\n"); return(-9); } case XYMOVE: #ifdef COMMENT y = cmdir("Directory to move file(s) to after successful transfer", "",&s,xxstring); #else y = cmtxt("Directory to move file(s) to after successful transfer", "",&s,xxstring); #endif /* COMMENT */ if (y < 0 && y != -3) return(y); ckstrncpy(line,s,LINBUFSIZ); s = brstrip(line); #ifdef COMMENT /* Only needed for cmdir() */ if ((x = cmcfm()) < 0) return(x); #endif /* COMMENT */ /* Check directory existence if absolute */ /* THIS MEANS IT CAN'T INCLUDE ANY DEFERRED VARIABLES! */ if (s) if (*s) { if (isabsolute(s) && !isdir(s)) { printf("?Directory does not exist - %s\n",s); return(-9); } } if (xx == XYSEND) { if (*s) { #ifdef COMMENT /* Allow it to be relative */ zfnqfp(s,LINBUFSIZ,line); #endif /* COMMENT */ makestr(&snd_move,line); makestr(&g_snd_move,line); } else { makestr(&snd_move,NULL); makestr(&g_snd_move,NULL); } } else { if (*s) { #ifdef COMMENT /* Allow it to be relative */ zfnqfp(s,LINBUFSIZ,line); #endif /* COMMENT */ makestr(&rcv_move,line); makestr(&g_rcv_move,line); } else { makestr(&rcv_move,NULL); makestr(&g_rcv_move,NULL); } } return(success = 1); case XYRENAME: y = cmtxt("Template to rename file(s) to after successful transfer", "",&s,NULL); /* NOTE: no xxstring */ if (y < 0 && y != -3) /* Evaluation is deferred */ return(y); ckstrncpy(line,s,LINBUFSIZ); s = brstrip(line); if ((x = cmcfm()) < 0) return(x); if (xx == XYSEND) { if (*s) { makestr(&snd_rename,s); makestr(&g_snd_rename,s); } else { makestr(&snd_rename,NULL); makestr(&g_snd_rename,NULL); } } else { if (*s) { makestr(&rcv_rename,s); makestr(&g_rcv_rename,s); } else { makestr(&rcv_rename,NULL); makestr(&g_rcv_rename,NULL); } } return(success = 1); #ifdef VMS case 887: /* VERSION-NUMBERS */ if (xx == XYSEND) { extern int vmssversions; return(seton(&vmssversions)); } else { extern int vmsrversions; return(seton(&vmsrversions)); } #endif /* VMS */ default: return(-2); } /* End of SET SEND/RECEIVE... */ } #endif /* NOXFER */ #ifndef NOXMIT int setxmit() { if ((y = cmkey(xmitab,nxmit,"","",xxstring)) < 0) return(y); switch (y) { case XMITE: /* EOF */ y = cmtxt("Characters to send at end of file,\n\ Use backslash codes for control characters","",&s,xxstring); if (y < 0) return(y); if ((int)strlen(s) > XMBUFL) { printf("?Too many characters, %d maximum\n",XMBUFL); return(-2); } ckstrncpy(xmitbuf,s,XMBUFL); return(success = 1); case XMITF: /* Fill */ y = cmnum("Numeric code for blank-line fill character","0",10,&x, xxstring); if ((y = setnum(&z,x,y,127)) < 0) return(y); xmitf = z; return(success = 1); case XMITL: /* Linefeed */ return(seton(&xmitl)); case XMITS: /* Locking-Shift */ return(seton(&xmits)); case XMITP: /* Prompt */ y = cmnum("Numeric code for host's prompt character, 0 for none", "10",10,&x,xxstring); if ((y = setnum(&z,x,y,127)) < 0) return(y); xmitp = z; return(success = 1); case XMITX: /* Echo */ return(seton(&xmitx)); case XMITW: /* Pause */ y = cmnum("Number of milliseconds to pause between binary characters\n\ or text lines during transmission","0",10,&x,xxstring); if ((y = setnum(&z,x,y,1000)) < 0) return(y); xmitw = z; return(success = 1); case XMITT: /* Timeout */ y = cmnum("Seconds to wait for each character to echo", "1",10,&x,xxstring); if ((y = setnum(&z,x,y,1000)) < 0) return(y); xmitt = z; return(success = 1); default: return(-2); } } #endif /* NOXMIT */ #ifndef NOXFER /* D O R M T -- Do a remote command */ VOID rmsg() { if (pflag && !quiet && fdispla != XYFD_N) printf( #ifdef CK_NEED_SIG " Type your escape character, %s, followed by X or E to cancel.\n", dbchr(escape) #else " Press the X or E key to cancel.\n" #endif /* CK_NEED_SIG */ ); } static int xzcmd = 0; /* Global copy of REMOTE cmd index */ /* R E M C F M -- Confirm a REMOTE command */ /* Like cmcfm(), but allows for a redirection indicator on the end, like "> filename" or "| command". Returns what cmcfm() would have returned: -1 if reparse needed, etc etc blah blah. On success, returns 1 with: char * remdest containing the name of the file or command. int remfile set to 1 if there is to be any redirection. int remappd set to 1 if output file is to be appended to. int rempipe set to 1 if remdest is a command, 0 if it is a file. */ static int remcfm() { int x = 0; char *s; char *helptxt = "> filename, | command,\n\ or type carriage return to confirm the command"; char c; remfile = 0; rempipe = 0; remappd = 0; if ((x = cmtxt(helptxt,"",&s,xxstring)) < 0) { return(x); } if (remdest) { free(remdest); remdest = NULL; } debug(F101,"remcfm local","",local); debug(F110,"remcfm s",s,0); debug(F101,"remcfm cmd","",xzcmd); /* This check was added in C-Kermit 6.0 or 7.0 but it turns out to be unhelpful in the situation where the remote is running a script that sends REMOTE commands to the local workstation. What happens is, the local server executes the command and sends the result back as screen text, which is indicated by using an X packet instead of an F packet as the file header. There are two parts to this: executing the command under control of the remote Kermit, which is desirable (and in fact some big applications depend on it, and therefore never installed any new C-Kermit versions after 5A), and displaying the result. Commenting out the check allows the command to be executed, but the result is still sent back to the remote in a file transfer, where it vanishes into the ether. Actually it's on the communication connection, mixed in with the packets. Pretty amazing that the file transfer still works, right? */ #ifdef COMMENT if (!*s) { /* No redirection indicator */ if (!local && (xzcmd == XZDIR || xzcmd == XZTYP || xzcmd == XZXIT || xzcmd == XZSPA || xzcmd == XZHLP || xzcmd == XZPWD || xzcmd == XZLGI || xzcmd == XZLGO || xzcmd == XZWHO || xzcmd == XZHOS)) { printf("?\"%s\" has no effect in remote mode\n",cmdbuf); return(-9); } else return(1); } #endif /* COMMENT */ if (!s) s = ""; /* 2014-11-03 */ if (!*s) return(1); /* 2014-11-03 */ c = *s; /* We have something */ if (c != '>' && c != '|') { /* Is it > or | ? */ printf("?Not confirmed\n"); /* No */ return(-9); } s++; /* See what follows */ if (c == '>' && *s == '>') { /* Allow for ">>" too */ s++; remappd = 1; /* Append to output file */ } while (*s == SP || *s == HT) s++; /* Strip intervening whitespace */ if (!*s) { printf("?%s missing\n", c == '>' ? "Filename" : "Command"); return(-9); } if (c == '>' && zchko(s) < 0) { /* Check accessibility */ printf("?Access denied - %s\n", s); return(-9); } remfile = 1; /* Set global results */ rempipe = (c == '|'); if (rempipe #ifndef NOPUSH && nopush #endif /* NOPUSH */ ) { printf("?Sorry, access to external commands is disabled.\n"); return(-9); } makestr(&remdest,s); #ifndef NODEBUG if (deblog) { debug(F101,"remcfm remfile","",remfile); debug(F101,"remcfm remappd","",remappd); debug(F101,"remcfm rempipe","",rempipe); debug(F110,"remcfm remdest",remdest, 0); } #endif /* NODEBUG */ return(1); } /* R E M T X T -- Like remcfm()... */ /* ... but for REMOTE commands that end with cmtxt(). Here we must decipher braces to discover whether the trailing redirection indicator is intended for local use, or to be sent out to the server, as in: remote host blah blah > file This end remote host { blah blah } > file This end remote host { blah blah > file } That end remote host { blah blah > file } > file Both ends Pipes too: remote host blah blah | cmd This end remote host { blah blah } | cmd This end remote host { blah blah | cmd } That end remote host { blah blah | cmd } | cmd Both ends Or both: remote host blah blah | cmd > file This end, etc etc... Note: this really only makes sense for REMOTE HOST, but why be picky? Call after calling cmtxt(), with pointer to string that cmtxt() parsed, as in "remtxt(&s);". Returns: 1 on success with braces & redirection things removed & pointer updated, -9 on failure (bad indirection), after printing error message. */ int #ifdef CK_ANSIC remtxt( char ** p ) #else remtxt(p) char ** p; #endif /* CK_ANSIC */ { int i, x, bpos, ppos; char c, *s, *q; remfile = 0; /* Initialize global results */ rempipe = 0; remappd = 0; if (remdest) { free(remdest); remdest = NULL; } s = *p; if (!s) /* No redirection indicator */ s = ""; #ifdef COMMENT if (!*s) { /* Ditto */ if (!local && (xzcmd == XZDIR || xzcmd == XZTYP || xzcmd == XZXIT || xzcmd == XZSPA || xzcmd == XZHLP || xzcmd == XZPWD || xzcmd == XZLGI || xzcmd == XZLGO || xzcmd == XZWHO || xzcmd == XZHOS)) { printf("?\"%s\" has no effect in remote mode\n",cmdbuf); if (hints) { printf("Hint: Try again with an output redirector.\n"); } return(-9); } else return(1); } #endif /* COMMENT */ bpos = -1; /* Position of > (bracket) */ ppos = -1; /* Position of | (pipe) */ x = strlen(s); /* Length of cmtxt() string */ for (i = x-1; i >= 0; i--) { /* Search right to left. */ c = s[i]; if (c == '}') /* Break on first right brace */ break; /* Don't look at contents of braces */ else if (c == '>') /* Record position of > */ bpos = i; else if (c == '|') /* and of | */ ppos = i; } if (bpos < 0 && ppos < 0) { /* No redirectors. */ #ifdef COMMENT if (!local && (xzcmd == XZDIR || xzcmd == XZTYP || xzcmd == XZXIT || xzcmd == XZSPA || xzcmd == XZHLP || xzcmd == XZPWD || xzcmd == XZLGI || xzcmd == XZLGO || xzcmd == XZWHO || xzcmd == XZHOS)) { printf("?\"%s\" has no effect in remote mode\n",cmdbuf); if (hints) { printf("Hint: Try again with an output redirector.\n"); } return(-9); } #endif /* COMMENT */ s = brstrip(s); /* Remove outer braces if any. */ *p = s; /* Point to result */ return(1); /* and return. */ } remfile = 1; /* It's | or > */ i = -1; /* Get leftmost symbol */ if (bpos > -1) /* Bracket */ i = bpos; if (ppos > -1 && (ppos < bpos || bpos < 0)) { /* or pipe */ i = ppos; rempipe = 1; } if (rempipe #ifndef NOPUSH && nopush #endif /* NOPUSH */ ) { printf("?Sorry, access to external commands is disabled.\n"); return(-9); } c = s[i]; /* Copy of symbol */ if (c == '>' && s[i+1] == '>') /* ">>" for append? */ remappd = 1; /* It's not just a flag it's a number */ q = s + i + 1 + remappd; /* Point past symbol in string */ while (*q == SP || *q == HT) q++; /* and any intervening whitespace */ if (!*q) { printf("?%s missing\n", c == '>' ? "Filename" : "Command"); return(-9); } if (c == '>' && zchko(q) < 0) { /* (Doesn't work for | cmd > file) */ printf("?Access denied - %s\n", q); return(-9); } makestr(&remdest,q); /* Create the destination string */ q = s + i - 1; /* Point before symbol */ while (q > s && (*q == SP || *q == HT)) /* Strip trailing whitespace */ q--; *(q+1) = NUL; /* Terminate the string. */ s = brstrip(s); /* Remove any braces */ *p = s; /* Set return value */ #ifndef NODEBUG if (deblog) { debug(F101,"remtxt remfile","",remfile); debug(F101,"remtxt remappd","",remappd); debug(F101,"remtxt rempipe","",rempipe); debug(F110,"remtxt remdest",remdest, 0); debug(F110,"remtxt command",s,0); } #endif /* NODEBUG */ return(1); } int #ifdef CK_ANSIC plogin( int xx ) #else plogin(xx) int xx; #endif /* CK_ANSIC */ { char *p1 = NULL, *p2 = NULL, *p3 = NULL; int psaved = 0, rc = 0; #ifdef CK_RECALL extern int on_recall; /* around Password prompting */ #endif /* CK_RECALL */ debug(F101,"plogin local","",local); if (!local || (network && ttchk() < 0)) { printf("?No connection\n"); return(-9); } if ((x = cmfld("User ID","",&s,xxstring)) < 0) { /* Get User ID */ if (x != -3) return(x); } y = strlen(s); if (y > 0) { if ((p1 = malloc(y + 1)) == NULL) { printf("?Internal error: malloc\n"); rc = -9; goto XZXLGI; } else strcpy(p1,s); /* safe */ if ((rc = cmfld("Password","",&s,xxstring)) < 0) if (rc != -3) goto XZXLGI; y = strlen(s); if (y > 0) { if ((p2 = malloc(y + 1)) == NULL) { printf("?Internal error: malloc\n"); rc = -9; goto XZXLGI; } else strcpy(p2,s); /* safe */ if ((rc = cmfld("Account","",&s,xxstring)) < 0) if (rc != -3) goto XZXLGI; y = strlen(s); if (y > 0) { if ((p3 = malloc(y + 1)) == NULL) { printf("?Internal error: malloc\n"); rc = -9; goto XZXLGI; } else strcpy(p3,s); /* safe */ } } } if ((rc = remtxt(&s)) < 0) /* Confirm & handle redirectors */ goto XZXLGI; if (!p1) { /* No Userid specified... */ debok = 0; /* Don't log this */ /* Prompt for username, password, and account */ #ifdef CK_RECALL on_recall = 0; #endif /* CK_RECALL */ cmsavp(psave,PROMPTL); /* Save old prompt */ psaved = 1; debug(F110,"REMOTE LOGIN saved",psave,0); cmsetp("Username: "); /* Make new prompt */ concb((char)escape); /* Put console in cbreak mode */ cmini(1); prompt(xxstring); rc = -9; for (x = -1; x < 0; ) { /* Prompt till they answer */ cmres(); /* Reset the parser */ x = cmtxt("","",&s,NULL); /* Get a literal line of text */ } y = strlen(s); if (y < 1) { printf("?Canceled\n"); goto XZXLGI; } if ((p1 = malloc(y + 1)) == NULL) { printf("?Internal error: malloc\n"); goto XZXLGI; } else strcpy(p1,s); /* safe */ cmsetp("Password: "); /* Make new prompt */ concb((char)escape); /* Put console in cbreak mode */ cmini(0); /* No echo */ prompt(xxstring); debok = 0; for (x = -1; x < 0 && x != -3; ) { /* Get answer */ cmres(); /* Reset the parser */ x = cmtxt("","",&s,NULL); /* Get literal line of text */ } if ((p2 = malloc((int)strlen(s) + 1)) == NULL) { printf("?Internal error: malloc\n"); goto XZXLGI; } else strcpy(p2,s); /* safe */ printf("\r\n"); if ((rc = cmcfm()) < 0) goto XZXLGI; } sstate = setgen('I',p1,p2,p3); /* Get here with at least user ID */ rc = 0; XZXLGI: /* Common exit point */ if (psaved) cmsetp(psave); /* Restore original prompt */ if (p3) { free(p3); p3 = NULL; } /* Free malloc'd storage */ if (p2) { free(p2); p2 = NULL; } if (p1) { free(p1); p1 = NULL; } if (rc > -1) { if (local && rc > -1) /* If local, flush tty input buffer */ ttflui(); } return(rc); } #ifdef OS2 #ifndef NOLOCAL int #ifdef CK_ANSIC dormt( int xx ) #else dormt(xx) int xx; #endif /* CK_ANSIC */ { int rc = 0; extern int term_io; int term_io_sav = term_io; #ifdef NEWFTP extern int ftpget, ftpisopen(); if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) return(doftprmt(xx,0)); #endif /* NEWFTP */ term_io = 0; rc = xxdormt(xx); term_io = term_io_sav; return rc; } int #ifdef CK_ANSIC xxdormt( int xx ) #else xxdormt(xx) int xx; #endif /* CK_ANSIC */ #else /* NOLOCAL */ int #ifdef CK_ANSIC dormt( int xx ) #else dormt(xx) int xx; #endif /* CK_ANSIC */ #endif /* NOLOCAL */ #else /* OS2 */ int #ifdef CK_ANSIC dormt( int xx ) #else dormt(xx) int xx; #endif /* CK_ANSIC */ #endif /* OS2 */ { /* REMOTE commands */ int x, y, retcode; char *s, sbuf[50], *s2; #ifdef NEWFTP extern int ftpget, ftpisopen(); if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) return(doftprmt(xx,0)); #endif /* NEWFTP */ remfile = 0; /* Clear these */ rempipe = 0; remappd = 0; debug(F101,"XXX xxdormt xx","",xx); if (xx < 0) return(xx); /* REMOTE what? */ xzcmd = xx; /* Make global copy of arg */ if (xx == XZSET) { /* REMOTE SET */ if ((y = cmkey(rmstab,nrms,"","",xxstring)) < 0) { if (y == -3) { printf("?Parameter name required\n"); return(-9); } else return(y); } return(doprm(y,1)); } switch (xx) { /* Others... */ case XZCDU: if ((x = cmcfm()) < 0) return(x); #ifdef VMS s = "[-]"; #else #ifdef datageneral s = "^"; #else s = ".."; #endif /* datageneral */ #endif /* VMS */ rcdactive = 1; sstate = setgen('C',s,"",""); retcode = 0; break; case XZSTA: /* Remote Status (2024) */ if ((x = cmcfm()) < 0) return(x); sstate = setgen('Q',"","",""); retcode = 0; break; case XZCWD: /* CWD (CD) */ if ((x = cmtxt("Remote directory name","",&s,xxstring)) < 0) return(x); if ((x = remtxt(&s)) < 0) return(x); debug(F111,"XZCWD: ",s,x); *sbuf = NUL; s2 = sbuf; /* The following is commented out because since the disappearance of the DECSYSTEM-20 from the planet, no known computer requires a password for changing directory. */ #ifdef DIRPWDPR if (*s != NUL) { /* If directory name given, */ /* get password on separate line. */ if (tlevel > -1) { /* From take file... */ if (fgets(sbuf,50,tfile[tlevel]) == NULL) fatal("take file ends prematurely in 'remote cwd'"); debug(F110," pswd from take file",s2,0); for (x = (int)strlen(sbuf); x > 0 && (sbuf[x-1] == NL || sbuf[x-1] == CR); x--) sbuf[x-1] = '\0'; } else { /* From terminal... */ printf(" Password: "); /* get a password */ #ifdef IKSD if (!local && inserver) { x = coninc(0); } else #endif /* IKSD */ #ifdef OS2 x = is_a_tty(0) ? coninc(0) : /* with no echo ... */ getchar(); #else /* OS2 */ x = getchar(); #endif /* OS2 */ while ((x != NL) && (x != CR)) { if ((x &= 0177) == '?') { printf("? Password of remote directory\n Password: "); s2 = sbuf; *sbuf = NUL; } else if (x == ESC) /* Mini command line editor... */ bleep(BP_WARN); else if (x == BS || x == 0177) s2--; else if (x == 025) { /* Ctrl-U */ s2 = sbuf; *sbuf = NUL; } else *s2++ = x; /* Get the next character */ #ifdef IKSD if (!local && inserver) { x = coninc(0); } else #endif /* IKSD */ #ifdef OS2 x = is_a_tty(0) ? coninc(0) : /* with no echo ... */ getchar(); #else /* OS2 */ x = getchar(); #endif /* OS2 */ } *s2 = NUL; putchar('\n'); } s2 = sbuf; } else s2 = ""; debug(F110," password",s2,0); #endif /* DIRPWDPR */ rcdactive = 1; sstate = setgen('C',s,s2,""); retcode = 0; break; case XZDEL: /* Delete */ if ((x = cmtxt("Name of remote file(s) to delete", "",&s,xxstring)) < 0) { if (x == -3) { printf("?Name of remote file(s) required\n"); return(-9); } else return(x); } if ((x = remtxt(&s)) < 0) return(x); if (local) ttflui(); /* If local, flush tty input buffer */ retcode = sstate = rfilop(s,'E'); break; case XZDIR: /* Directory */ if ((x = cmtxt("Remote directory or file specification","",&s, xxstring)) < 0) return(x); if ((x = remtxt(&s)) < 0) return(x); if (local) ttflui(); /* If local, flush tty input buffer */ rmsg(); retcode = sstate = setgen('D',s,"",""); break; case XZHLP: /* Help */ if ((x = remcfm()) < 0) return(x); sstate = setgen('H',"","",""); retcode = 0; break; case XZHOS: /* Host */ if ((x = cmtxt("Command for remote system","",&s,xxstring)) < 0) return(x); if ((x = remtxt(&s)) < 0) return(x); if ((y = (int)strlen(s)) < 1) return(x); ckstrncpy(line,s,LINBUFSIZ); cmarg = line; rmsg(); retcode = sstate = 'c'; break; #ifndef NOFRILLS case XZKER: if ((x = cmtxt("Command for remote Kermit","",&s,xxstring)) < 0) return(x); if ((x = remtxt(&s)) < 0) return(x); if ((int)strlen(s) < 1) { if (x == -3) { printf("?Remote Kermit command required\n"); return(-9); } else return(x); } ckstrncpy(line,s,LINBUFSIZ); cmarg = line; retcode = sstate = 'k'; rmsg(); break; case XZLGI: /* Login */ rcdactive = 1; /* Suppress "Logged in" msg if quiet */ return(plogin(XXREM)); case XZLGO: { /* Logout */ extern int bye_active; if ((x = remcfm()) < 0) return(x); sstate = setgen('I',"","",""); retcode = 0; bye_active = 1; /* Close connection when done */ break; } case XZPRI: /* Print */ if (!atdiso || !atcapr) { /* Disposition attribute off? */ printf("?Disposition Attribute is Off\n"); return(-2); } cmarg = ""; cmarg2 = ""; if ((x = cmifi("Local file(s) to print on remote printer","",&s,&y, xxstring)) < 0) { if (x == -3) { printf("?Name of local file(s) required\n"); return(-9); } return(x); } ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of filename */ *optbuf = NUL; /* Wipe out any old options */ if ((x = cmtxt("Options for remote print command","",&s,xxstring)) < 0) return(x); if ((x = remtxt(&s)) < 0) return(x); if ((int)strlen(optbuf) > 94) { /* Make sure this is legal */ printf("?Option string too long\n"); return(-9); } ckstrncpy(optbuf,s,OPTBUFLEN); /* Make a safe copy of options */ nfils = -1; /* Expand file list internally */ cmarg = line; /* Point to file list. */ rprintf = 1; /* REMOTE PRINT modifier for SEND */ sstate = 's'; /* Set start state to SEND */ if (local) displa = 1; retcode = 0; break; #endif /* NOFRILLS */ case XZSPA: /* Space */ if ((x = cmtxt("Confirm, or remote directory name", "",&s,xxstring)) < 0) return(x); if ((x = remtxt(&s)) < 0) return(x); retcode = sstate = setgen('U',s,"",""); break; case XZMSG: /* Message */ if ((x = cmtxt("Short text message for server","",&s,xxstring)) < 0) return(x); if ((x = remtxt(&s)) < 0) return(x); retcode = sstate = setgen('M',s,"",""); break; #ifndef NOFRILLS case XZTYP: /* Type */ if ((x = cmtxt("Remote file specification","",&s,xxstring)) < 0) return(x); if ((int)strlen(s) < 1) { printf("?Remote filename required\n"); return(-9); } if ((x = remtxt(&s)) < 0) return(x); rmsg(); retcode = sstate = rfilop(s,'T'); break; #endif /* NOFRILLS */ #ifndef NOFRILLS case XZWHO: if ((x = cmtxt("Remote user name, or carriage return", "",&s,xxstring)) < 0) return(x); if ((x = remtxt(&s)) < 0) return(x); retcode = sstate = setgen('W',s,"",""); break; #endif /* NOFRILLS */ case XZPWD: /* PWD */ if ((x = remcfm()) < 0) return(x); sstate = setgen('A',"","",""); retcode = 0; break; #ifndef NOSPL case XZQUE: { /* Query */ char buf[2]; extern char querybuf[], * qbufp; extern int qbufn; if ((y = cmkey(vartyp,nvartyp,"","",xxstring)) < 0) return(y); if ((x = cmtxt(y == 'F' ? "Remote function invocation" : ('K' ? "Remote variable name or function": "Remote variable name"), "", &s, (y == 'K') ? xxstring : NULL )) < 0) /* Don't evaluate */ return(x); if ((x = remtxt(&s)) < 0) return(x); query = 1; /* QUERY is active */ qbufp = querybuf; /* Initialize query response buffer */ qbufn = 0; querybuf[0] = NUL; buf[0] = (char) (y & 127); buf[1] = NUL; retcode = sstate = setgen('V',"Q",(char *)buf,s); break; } case XZASG: { /* Assign */ char buf[VNAML]; if ((y = cmfld("Remote variable name","",&s,NULL)) < 0) /* No eval */ return(y); if ((int)strlen(s) >= VNAML) { printf("?Too long\n"); return(-9); } ckstrncpy(buf,s,VNAML); if ((x = cmtxt("Assignment for remote variable", "",&s,xxstring)) < 0) /* Evaluate this one */ return(x); if ((x = remtxt(&s)) < 0) return(x); #ifdef COMMENT /* Server commands can't be long packets. In principle there's no reason why they shouldn't be, except that we don't know at this point if the server is capable of accepting long packets because we haven't started the protocol yet. In practice, allowing a long packet here breaks a lot of assumptions, causes buffer overruns and crashes, etc. To be fixed later. (But since this is commented out, evidently I fixed it later...) */ if ((int)strlen(s) > 85) { /* Allow for encoding expansion */ printf("?Sorry, value is too long - 85 characters max\n"); return(-9); } #endif /* COMMENT */ retcode = sstate = setgen('V',"S",(char *)buf,s); break; } #endif /* NOSPL */ case XZCPY: { /* COPY */ char buf[TMPBUFSIZ]; buf[TMPBUFSIZ-1] = '\0'; if ((x = cmfld("Name of remote file to copy","",&s,xxstring)) < 0) { if (x == -3) { printf("?Name of remote file required\n"); return(-9); } else return(x); } ckstrncpy(buf,s,TMPBUFSIZ); if ((x = cmfld("Name of remote destination file or directory", "",&s, xxstring)) < 0) { if (x == -3) { printf("?Name of remote file or directory required\n"); return(-9); } else return(x); } ckstrncpy(tmpbuf,s,TMPBUFSIZ); if ((x = remcfm()) < 0) return(x); if (local) ttflui(); /* If local, flush tty input buffer */ retcode = sstate = setgen('K',buf,tmpbuf,""); break; } case XZREN: { /* Rename */ char buf[TMPBUFSIZ]; buf[TMPBUFSIZ-1] = '\0'; if ((x = cmfld("Name of remote file to rename", "",&s,xxstring)) < 0) { if (x == -3) { printf("?Name of remote file required\n"); return(-9); } else return(x); } ckstrncpy(buf,s,TMPBUFSIZ); if ((x = cmfld("New name of remote file","",&s, xxstring)) < 0) { if (x == -3) { printf("?Name of remote file required\n"); return(-9); } else return(x); } ckstrncpy(tmpbuf,s,TMPBUFSIZ); if ((x = remcfm()) < 0) return(x); if (local) ttflui(); /* If local, flush device buffer */ retcode = sstate = setgen('R',buf,tmpbuf,""); break; } case XZMKD: /* mkdir */ case XZRMD: /* rmdir */ if ((x = cmtxt((xx == XZMKD) ? "Name of remote directory to create" : "Name of remote directory to delete", "", &s, xxstring )) < 0) { if (x == -3) { printf("?Name required\n"); return(-9); } else return(x); } if ((x = remtxt(&s)) < 0) return(x); if (local) ttflui(); /* If local, flush tty input buffer */ retcode = sstate = rfilop(s, (char)(xx == XZMKD ? 'm' : 'd')); break; case XZXIT: /* Exit */ if ((x = remcfm()) < 0) return(x); sstate = setgen('X',"","",""); retcode = 0; break; default: if ((x = remcfm()) < 0) return(x); printf("?Not implemented - %s\n",cmdbuf); return(-2); } if (local && retcode > -1) /* If local, flush tty input buffer */ ttflui(); return(retcode); } /* R F I L O P -- Remote File Operation */ CHAR #ifdef CK_ANSIC rfilop(char * s, char t) #else rfilop(s,t) char *s, t; #endif /* CK_ANSIC */ /* rfilop */ { if (*s == NUL) { printf("?File specification required\n"); return((CHAR) 0); } debug(F111,"rfilop",s,t); return(setgen(t,s,"","")); } #endif /* NOXFER */ #ifdef ANYX25 int setx25() { if ((y = cmkey(x25tab,nx25,"X.25 call options","",xxstring)) < 0) return(y); switch (y) { case XYUDAT: if ((z = cmkey(onoff,2,"X.25 call user data","",xxstring)) < 0) return(z); if (z == 0) { if ((z = cmcfm()) < 0) return(z); cudata = 0; /* disable call user data */ return (success = 1); } if ((x = cmtxt("X.25 call user data string","",&s,xxstring)) < 0) return(x); if ((int)strlen(s) == 0) { return (-3); } else if ((int)strlen(s) > MAXCUDATA) { printf("?The length must be > 0 and <= %d\n",MAXCUDATA); return(-2); } if ((y = cmcfm()) < 0) return(y); ckstrncpy(udata,s,MAXCUDATA); cudata = 1; /* X.25 call user data specified */ return (success = 1); case XYCLOS: if ((z = cmkey(onoff,2,"X.25 closed user group call","",xxstring)) < 0) return(z); if (z == 0) { if ((z = cmcfm()) < 0) return(z); closgr = -1; /* disable closed user group */ return (success = 1); } if ((y = cmnum("0 <= cug index >= 99","",10,&x,xxstring)) < 0) return(y); if (x < 0 || x > 99) { printf("?The choices are 0 <= cug index >= 99\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); closgr = x; /* closed user group selected */ return (success = 1); case XYREVC: if((z = cmkey(onoff,2,"X.25 reverse charge call","",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); revcall = z; return (success = 1); } } #ifndef IBMX25 int setpadp() { if ((y = cmkey(padx3tab,npadx3,"PAD X.3 parameter name","",xxstring)) < 0) return(y); x = y; switch (x) { case PAD_BREAK_CHARACTER: if ((y = cmnum("PAD break character value","",10,&z,xxstring)) < 0) return(y); if ((y = cmcfm()) < 0) return(y); break; case PAD_ESCAPE: if ((y = cmnum("PAD escape","",10,&z,xxstring)) < 0) return(y); if (z != 0 && z != 1) { printf("?The choices are 0 or 1\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_ECHO: if ((y = cmnum("PAD echo","",10,&z,xxstring)) < 0) return(y); if (z != 0 && z != 1) { printf("?The choices are 0 or 1\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_DATA_FORWARD_CHAR: if ((y = cmnum("PAD data forward char","",10,&z,xxstring)) < 0) return(y); if (z != 0 && z != 2) { printf("?The choices are 0 or 2\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_DATA_FORWARD_TIMEOUT: if ((y = cmnum("PAD data forward timeout","",10,&z,xxstring)) < 0) return(y); if (z < 0 || z > 255) { printf("?The choices are 0 or 1 <= timeout <= 255\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_FLOW_CONTROL_BY_PAD: if ((y = cmnum("PAD pad flow control","",10,&z,xxstring)) < 0) return(y); if (z != 0 && z != 1) { printf("?The choices are 0 or 1\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_SUPPRESSION_OF_SIGNALS: if ((y = cmnum("PAD service","",10,&z,xxstring)) < 0) return(y); if (z != 0 && z != 1) { printf("?The choices are 0 or 1\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_BREAK_ACTION: if ((y = cmnum("PAD break action","",10,&z,xxstring)) < 0) return(y); if (z != 0 && z != 1 && z != 2 && z != 5 && z != 8 && z != 21) { printf("?The choices are 0, 1, 2, 5, 8 or 21\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_SUPPRESSION_OF_DATA: if ((y = cmnum("PAD data delivery","",10,&z,xxstring)) < 0) return(y); if (z != 0 && z != 1) { printf("?The choices are 0 or 1\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_PADDING_AFTER_CR: if ((y = cmnum("PAD crpad","",10,&z,xxstring)) < 0) return(y); if (z < 0 || z > 7) { printf("?The choices are 0 or 1 <= crpad <= 7\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_LINE_FOLDING: if ((y = cmnum("PAD linefold","",10,&z,xxstring)) < 0) return(y); if (z < 0 || z > 255) { printf("?The choices are 0 or 1 <= linefold <= 255\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_LINE_SPEED: if ((y = cmnum("PAD baudrate","",10,&z,xxstring)) < 0) return(y); if (z < 0 || z > 18) { printf("?The choices are 0 <= baudrate <= 18\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_FLOW_CONTROL_BY_USER: if ((y = cmnum("PAD terminal flow control","",10,&z,xxstring)) < 0) return(y); if (z != 0 && z != 1) { printf("?The choices are 0 or 1\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_LF_AFTER_CR: if ((y = cmnum("PAD crpad","",10,&z,xxstring)) < 0) return(y); if (z < 0 || z == 3 || z > 7) { printf("?The choices are 0, 1, 2, 4, 5, 6 or 7\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_PADDING_AFTER_LF: if ((y = cmnum("PAD lfpad","",10,&z,xxstring)) < 0) return(y); if (z < 0 || z > 7) { printf("?The choices are 0 or 1 <= lfpad <= 7\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_EDITING: if ((y = cmnum("PAD edit control","",10,&z,xxstring)) < 0) return(y); if (z != 0 && z != 1) { printf("?The choices are 0 or 1\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_CHAR_DELETE_CHAR: if ((y = cmnum("PAD char delete char","",10,&z,xxstring)) < 0) return(y); if (z < 0 || z > 127) { printf("?The choices are 0 or 1 <= chardelete <= 127\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_BUFFER_DELETE_CHAR: if ((y = cmnum("PAD buffer delete char","",10,&z,xxstring)) < 0) return(y); if (z < 0 || z > 127) { printf("?The choices are 0 or 1 <= bufferdelete <= 127\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; case PAD_BUFFER_DISPLAY_CHAR: if ((y = cmnum("PAD display line char","",10,&z,xxstring)) < 0) return(y); if (z < 0 || z > 127) { printf("?The choices are 0 or 1 <= displayline <= 127\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); break; } padparms[x] = z; return(success = 1); } #endif /* IBMX25 */ #endif /* ANYX25 */ #ifndef NOXFER int #ifdef CK_ANSIC setat( int rmsflg ) #else setat(rmsflg) int rmsflg; #endif /* CK_ANSIC */ { int xx; if ((y = cmkey(attrtab,natr,"File Attribute packets","",xxstring)) < 0) return(y); if (y == AT_XALL) { /* ATTRIBUTES ALL ON or ALL OFF */ if ((z = seton(&xx)) < 0) return(z); if (rmsflg) { printf("Sorry, command not available\n"); return(-9); } else { atenci = xx; /* Encoding in */ atenco = xx; /* Encoding out */ atdati = xx; /* Date in */ atdato = xx; /* Date out */ atdisi = xx; /* Disposition in/out */ atdiso = xx; atleni = xx; /* Length in/out (both kinds) */ atleno = xx; atblki = xx; /* Blocksize in/out */ atblko = xx; attypi = xx; /* File type in/out */ attypo = xx; atsidi = xx; /* System ID in/out */ atsido = xx; atsysi = xx; /* System-dependent params in/out */ atsyso = xx; #ifdef CK_PERMS /* Protection */ atlpri = xx; /* Local in */ atlpro = xx; /* Local out */ atgpri = xx; /* Generic in */ atgpro = xx; /* Generic out */ #endif /* CK_PERMS */ #ifdef STRATUS atfrmi = xx; /* Format in/out */ atfrmo = xx; atcrei = xx; /* Creator id in/out */ atcreo = xx; atacti = xx; /* Account in/out */ atacto = xx; #endif /* STRATUS */ } return(z); } else if (y == AT_ALLY || y == AT_ALLN) { /* ATTRIBUTES ON or OFF */ if ((x = cmcfm()) < 0) return(x); atcapr = (y == AT_ALLY) ? 1 : 0; if (rmsflg) { sstate = setgen('S', "132", atcapr ? "1" : "0", ""); return((int) sstate); } else return(success = 1); } /* Otherwise, it's an individual attribute that wants turning off/on */ if ((z = cmkey(onoff,2,"","",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); /* There are better ways to do this... */ /* The real problem is that we're not separating the in and out cases */ /* and so we have to arbitrarily pick the "in" case, i.e tell the remote */ /* server to ignore incoming attributes of the specified type, rather */ /* than telling it not to send them. The protocol does not (yet) define */ /* codes for "in-and-out-at-the-same-time". */ switch (y) { #ifdef CK_PERMS /* We're lumping local and generic protection together for now... */ case AT_LPRO: case AT_GPRO: if (rmsflg) { sstate = setgen('S', "143", z ? "1" : "0", ""); return((int) sstate); } atlpri = atlpro = atgpri = atgpro = z; break; #endif /* CK_PERMS */ case AT_DISP: if (rmsflg) { sstate = setgen('S', "142", z ? "1" : "0", ""); return((int) sstate); } atdisi = atdiso = z; break; case AT_ENCO: if (rmsflg) { sstate = setgen('S', "141", z ? "1" : "0", ""); return((int) sstate); } atenci = atenco = z; break; case AT_DATE: if (rmsflg) { sstate = setgen('S', "135", z ? "1" : "0", ""); return((int) sstate); } atdati = atdato = z; break; case AT_LENB: case AT_LENK: if (rmsflg) { sstate = setgen('S', "133", z ? "1" : "0", ""); return((int) sstate); } atleni = atleno = z; break; case AT_BLKS: if (rmsflg) { sstate = setgen('S', "139", z ? "1" : "0", ""); return((int) sstate); } atblki = atblko = z; break; case AT_FTYP: if (rmsflg) { sstate = setgen('S', "134", z ? "1" : "0", ""); return((int) sstate); } attypi = attypo = z; break; #ifdef STRATUS case AT_CREA: if (rmsflg) { sstate = setgen('S', "136", z ? "1" : "0", ""); return((int) sstate); } atcrei = atcreo = z; break; case AT_ACCT: if (rmsflg) { sstate = setgen('S', "137", z ? "1" : "0", ""); return((int) sstate); } atacti = atacto = z; break; #endif /* STRATUS */ case AT_SYSI: if (rmsflg) { sstate = setgen('S', "145", z ? "1" : "0", ""); return((int) sstate); } atsidi = atsido = z; break; case AT_RECF: if (rmsflg) { sstate = setgen('S', "146", z ? "1" : "0", ""); return((int) sstate); } atfrmi = atfrmo = z; break; case AT_SYSP: if (rmsflg) { sstate = setgen('S', "147", z ? "1" : "0", ""); return((int) sstate); } atsysi = atsyso = z; break; default: printf("?Not available\n"); return(-2); } return(1); } #endif /* NOXFER */ #ifndef NOSPL int setinp() { if ((y = cmkey(inptab,ninp,"","",xxstring)) < 0) return(y); switch (y) { #ifdef OS2 case IN_PAC: /* SET INPUT PACING */ z = cmnum("milliseconds","0",10,&x,xxstring); return(setnum(&tt_inpacing,x,z,1000)); case IN_TRM: /* SET INPUT TERMINAL */ return(seton(&interm)); #endif /* OS2 */ case IN_DEF: /* SET INPUT DEFAULT-TIMEOUT */ z = cmnum("Positive number","",10,&x,xxstring); return(setnum(&indef,x,z,94)); #ifdef CKFLOAT case IN_SCA: /* SET INPUT SCALE-FACTOR */ if ((x = cmfld("Number such as 2 or 0.5","1.0",&s, xxstring)) < 0) return(x); if (isfloat(s,0)) { /* A floating-point number? */ extern char * inpscale; inscale = floatval; /* Yes, get its value */ makestr(&inpscale,s); /* Save it as \v(inscale) */ return(success = 1); } else { return(-2); } #endif /* CKFLOAT */ case IN_TIM: /* SET INPUT TIMEOUT-ACTION */ if ((z = cmkey(intimt,2,"","",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); intime[cmdlvl] = z; return(success = 1); case IN_CAS: /* SET INPUT CASE */ if ((z = cmkey(incast,2,"","",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); inpcas[cmdlvl] = z; return(success = 1); case IN_ECH: /* SET INPUT ECHO */ return(seton(&inecho)); case IN_SIL: /* SET INPUT SILENCE */ z = cmnum("Seconds of inactivity before INPUT fails","",10,&x, xxstring); return(setnum(&insilence,x,z,-1)); case IN_BUF: /* SET INPUT BUFFER-SIZE */ if ((z = cmnum("Number of bytes in INPUT buffer", ckitoa(INPBUFSIZ),10,&x, xxstring)) < 0) return(z); if ((y = cmcfm()) < 0) return(y); inbufsize = 0; if (inpbuf) { free(inpbuf); inpbuf = NULL; inpbp = NULL; } if (!(s = (char *)malloc(x + 1))) return(0); inpbuf = s; inpbp = s; inbufsize = x; for (x = 0; x <= inbufsize; x++) inpbuf[x] = NUL; return(success = 1); #ifdef CK_AUTODL case IN_ADL: /* AUTODOWNLOAD */ return(seton(&inautodl)); #endif /* CK_AUTODL */ case IN_CAN: /* SET INPUT INTERRUPTS */ return(seton(&inintr)); } return(0); } #endif /* NOSPL */ #ifdef NETCONN VOID ndreset() { #ifndef NODIAL /* This depends on DIAL... */ int i=0, j=0; if (!ndinited) /* Don't free garbage... */ return; for (i = 0; i < nhcount; i++) { /* Clean out previous list */ if (nh_p[i]) free(nh_p[i]); nh_p[i] = NULL; if (nh_p2[i]) free(nh_p2[i]); nh_p2[i] = NULL; for (j = 0; j < 4; j++) { if (nh_px[j][i]) free(nh_px[j][i]); nh_px[j][i] = NULL; } } #endif /* NODIAL */ } VOID ndinit() { /* Net directory pointers */ #ifndef NODIAL /* This depends on DIAL... */ int i, j; if (ndinited++) /* Don't do this more than once. */ return; for (i = 0; i < MAXDDIR; i++) { /* Init all pointers to NULL */ netdir[i] = NULL; } for (i = 0; i < MAXDNUMS; i++) { nh_p[i] = NULL; nh_p2[i] = NULL; for (j = 0; j < 4; j++) nh_px[j][i] = NULL; } #endif /* NODIAL */ } #ifndef NODIAL #ifdef NETCONN VOID /* Get net defaults from environment */ getnetenv() { char *p = NULL; makestr(&p,getenv("K_NET_DIRECTORY")); /* Dialing directories */ if (p) { int i; xwords(p,MAXDDIR,netdir,0); for (i = 0; i < MAXDDIR; i++) { /* Fill in any gaps... */ if (!netdir[i+1]) break; else netdir[i] = netdir[i+1]; debug(F111,"netdir[i]",netdir[i],i); } nnetdir = i; } } #endif /* NETCONN */ #endif /* NODIAL */ int #ifdef CK_ANSIC lunet(char *s) /* s = name to look up */ #else lunet(s) char *s; #endif /* CK_ANSIC */ /* lunet */ { #ifndef NODIAL /* This depends on DIAL... */ int n, n1, t, dd = 0; int ambiguous = 0; FILE * f; char *line = NULL; extern int dialdpy; int netdpy = dialdpy; char *info[8]; nhcount = 0; /* Set this before returning */ if (!s || nnetdir < 1) /* Validate arguments */ return(-1); if (isdigit(*s) || *s == '*' || *s == '.') return(0); if ((n1 = (int) strlen(s)) < 1) /* Length of string to look up */ return(-1); if (!(line = malloc(1024))) /* Allocate input buffer */ return(-1); lu_again: f = NULL; /* Network directory file descriptor */ t = nhcount = 0; /* Match count */ dd = 0; /* Directory counter */ dirline = 0; while (1) { /* We make one pass */ if (!f) { /* Directory not open */ if (dd >= nnetdir) /* No directories left? */ break; /* Done. */ if ((f = fopen(netdir[dd],"r")) == NULL) { /* Open it */ perror(netdir[dd]); /* Can't, print message saying why */ dd++; continue; /* But go on to next one. */ } if (netdpy) printf("Opening %s...\n",netdir[dd]); dd++; } line[0] = NUL; if (getnct(line,1023,f,1) < 0) { /* Read a line */ if (f) { /* f can be clobbered! */ fclose(f); /* Close the file */ f = NULL; /* Indicate next one needs opening */ } continue; } if (!line[0]) /* Empty line */ continue; xwords(line,7,info,0); /* Parse it */ if (!info[1] || !info[2] || !info[3]) /* Required fields */ continue; if (*info[1] == ';') /* Full-line comment */ continue; if ((n = (int) strlen(info[1])) < 1) /* Length of name-tag */ continue; if (n < n1) /* Search name is longer */ continue; /* Can't possibly match */ if (ambiguous && n != n1) continue; if (ckstrcmp(s,info[1],n1,0)) /* Compare using length of */ continue; /* search string s. */ /* Have a match */ makestr(&(nh_p[nhcount]), info[3]); /* address */ makestr(&(nh_p2[nhcount]),info[2]); /* net type */ makestr(&(nh_px[0][nhcount]),info[4]); /* net-specific stuff... */ makestr(&(nh_px[1][nhcount]),info[5]); makestr(&(nh_px[2][nhcount]),info[6]); makestr(&(nh_px[3][nhcount]),info[7]); nhcount++; /* Count this match */ if (nhcount > MAXDNUMS) { /* Watch out for too many */ printf("Warning: %d matches found, %d max\n", nhcount, MAXDNUMS ); nhcount = MAXDNUMS; break; } if (nhcount == 1) { /* First one - save entry name */ if (n_name) { /* Free the one from before if any */ free(n_name); n_name = NULL; } if (!(n_name = (char *)malloc(n + 1))) { /* Allocate new storage */ printf("?memory allocation error - lunet:3\n"); if (line) { free(line); line = NULL; } nhcount = 0; return(-1); } t = n; /* Remember its length */ strcpy(n_name,info[1]); /* safe */ } else { /* Second or subsequent one */ if ((int) strlen(info[1]) == t) /* Lengths compare */ if (!ckstrcmp(n_name,info[1],t,0)) /* Caseless compare OK */ continue; /* Name given by user matches entries with different names */ if (ambiguous) /* Been here before */ break; ambiguous = 1; /* Now an exact match is required */ ndreset(); /* Clear out previous list */ goto lu_again; /* Do it all over again. */ } } if (line) { free(line); line = NULL; } if (nhcount == 0 && ambiguous) printf("?\"%s\" - ambiguous in network directory\n",s); #else nhcount = 0; #endif /* NODIAL */ return(nhcount); } #endif /* NETCONN */ #ifndef NOLOCAL /* C L S C O N N X -- Close connection */ int #ifdef CK_ANSIC clsconnx( int ask ) #else clsconnx(ask) int ask; #endif /* CK_ANSIC */ { int x, rc = 0; #ifdef NEWFTP extern int ftpget, ftpisopen(); if ((ftpget == 1) || ((ftpget == 2) && !local && ftpisopen())) return(success = ftpbye()); #endif /* NEWFTP */ debug(F101,"clsconnx local","",local); if (local) { x = ask ? hupok(1) : 1; /* Make sure it's OK to close */ if (!x) { rc = -1; debug(F101,"clsconnx hupok says no","",rc); return(rc); } ttflui(); /* Clear away buffered up junk */ #ifndef NODIAL #ifdef OS2ONLY /* Don't hangup a line that is shared with the SLIP or PPP driver */ if (!ttslip && !ttppp) #endif /* OS2ONLY */ mdmhup(); #endif /* NODIAL */ if (network && msgflg) printf(" Closing connection\n"); ttclos(0); /* Close old connection, if any */ rc = 1; { extern int wasclosed, whyclosed; if (wasclosed) { whyclosed = WC_CLOS; #ifndef NOSPL if (nmac) { /* Any macros defined? */ int k; /* Yes */ /* printf("ON_CLOSE CLSCONNX\n"); */ wasclosed = 0; k = mlook(mactab,"on_close",nmac); /* Look this up */ if (k >= 0) { /* If found, */ if (dodo(k,ckitoa(whyclosed),0) > -1) /* set it up, */ parser(1); /* and execute it */ } } #endif /* NOSPL */ whyclosed = WC_REMO; wasclosed = 0; } } } #ifdef VMS /* Or maybe #ifndef UNIX? */ else { /* Need to do this in VMS to */ ttclos(0); /* free the tty channel number */ rc = 1; /* obtained in ttopen() or else */ } /* subsequent ttopen's won't work */ #endif /* VMS */ dologend(); haveline = 0; if (mdmtyp < 0) { /* Switching from net to async? */ if (mdmsav > -1) /* Restore modem type from last */ mdmtyp = mdmsav; /* SET MODEM command, if any. */ else mdmtyp = 0; mdmsav = -1; } if (network) network = 0; #ifdef NETCONN if (oldplex > -1) { /* Restore previous duplex setting. */ duplex = oldplex; oldplex = -1; } #endif /* NETCONN */ #ifndef MAC ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default communication */ #endif /* MAC */ local = dfloc; /* device and local/remote status */ if (local) { cxtype = CXT_DIRECT; /* Something reasonable */ speed = ttgspd(); /* Get the current speed */ } else { cxtype = CXT_REMOTE; speed = -1L; } #ifndef NOXFER if (xreliable > -1 && !setreliable) { reliable = xreliable; debug(F101,"clsconnx reliable A","",reliable); } else if (!setreliable) { reliable = SET_AUTO; debug(F101,"clsconnx reliable B","",reliable); } #endif /* NOXFER */ setflow(); /* Revert flow control */ return(rc); } int #ifdef CK_ANSIC clskconnx( int x ) /* Close Kermit connection only */ #else clskconnx(x) int x; #endif /* CK_ANSIC */ { int t, rc; /* (not FTP) */ #ifdef NEWFTP extern int ftpget; t = ftpget; ftpget = 0; #endif /* NEWFTP */ rc = clsconnx(x); #ifdef NEWFTP ftpget = t; #endif /* NEWFTP */ return(rc); } /* May 2002: setlin() decomposition starts here ... */ #ifdef OS2 #define SRVBUFSIZ PIPENAML #else /* OS2 */ #define SRVBUFSIZ 63 #endif /* OS2 */ #define HOSTNAMLEN 15*65 int netsave = -1; static char * tmpstring = NULL; static char * tmpusrid = NULL; #ifdef SSHCMD char * sshcmd = NULL; char * defsshcmd = "ssh -e none"; #else #ifdef SSHBUILTIN char * sshrcmd = NULL; char * sshtmpcmd = NULL; #endif /* SSHBUILTIN */ #endif /* SSHCMD */ /* c x _ f a i l -- Common error exit routine for cx_net, cx_line */ int #ifdef CK_ANSIC cx_fail( int msg, char * text ) #else cx_fail(msg, text) int msg; char * text; #endif /* CK_ANSIC */ { makestr(&slmsg,text); /* For the record (or GUI) */ if (msg) /* Not GUI, not quiet, etc */ printf("?%s\n",text); /* Print error message */ slrestor(); /* Restore LINE/HOST to known state */ return(msg ? -9 : (success = 0)); /* Return appropriate code */ } /* c x _ n e t -- Make a network connection */ /* Call with: net = network type protocol = protocol type host = string pointer to host name. svc = string pointer to service or port on host. username = username for connection password = password for connection command = command to execute param1 = Telnet: Authentication type SSH: Version param2 = Telnet: Encryption type SSH: Command as Subsystem param3 = Telnet: 1 to wait for negotiations, 0 otherwise SSH: X11 Forwarding cx = 1 to automatically enter Connect mode, 0 otherwise. sx = 1 to automatically enter Server mode, 0 otherwise. flag = if no host name given, 1 = close current connection, 0 = resume gui = 1 if called from GUI dialog, 0 otherwise. Returns: 1 on success 0 on failure and no message printed, slmsg set to failure message. -9 on failure and message printed, ditto. */ int #ifdef CK_ANSIC cx_net( int net, int protocol, char * xhost, char * svc, char * username, char * password, char * command, int param1, int param2, int param3, int cx, int sx, int flag, int gui) #else /* CK_ANSIC */ cx_net(net, protocol, xhost, svc, username, password, command, param1, param2, param3, cx, sx, flag, gui) char * xhost, * svc, * username, *password, *command; int net, protocol, cx, sx, flag, param1, param2, param3, gui; #endif /* CK_ANSIC */ /* cx_net */ { int i, n = 1, x, msg; int _local = -1; int did_ttopen = 0; extern char pwbuf[], * g_pswd; extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal; char srvbuf[SRVBUFSIZ+1]; /* Service */ char hostbuf[HOSTNAMLEN]; /* Host buffer to manipulate */ char hostname[HOSTNAMLEN]; /* Copy of host parameter */ char * host = hostbuf; /* Pointer to copy of host param */ if (!xhost) xhost = ""; /* Watch out for null pointers */ if (!svc) svc = ""; ckstrncpy(host,xhost,HOSTNAMLEN); /* Avoid buffer confusion */ debug(F110,"cx_net host",host,0); debug(F111,"cx_net service buffer size",svc,SRVBUFSIZ); debug(F101,"cx_net network type","",net); msg = (gui == 0) && msgflg; /* Whether to print messages */ #ifndef NODIAL #ifndef NONETDIR debug(F101,"cx_net nnetdir","",nnetdir); x = 0; /* Look up in network directory */ if (*host == '=') { /* If number starts with = sign */ host++; /* strip it */ while (*host == SP) host++; /* and any leading spaces */ debug(F110,"cx_net host 2",host,0); nhcount = 0; } else if (*host) { /* We want to look it up. */ if (nnetdir > 0) /* If there is a directory... */ x = lunet(host); /* (sets nhcount) */ else /* otherwise */ nhcount = 0; /* we didn't find any there */ if (x < 0) /* Internal error? */ return(cx_fail(msg,"Network directory lookup error")); debug(F111,"cx_net lunet nhcount",host,nhcount); } #endif /* NONETDIR */ #endif /* NODIAL */ /* New connection wanted. Make a copy of the host name/address... */ debug(F100,"cx_net A","",0); if (clskconnx(1) < 0) /* Close current Kermit connection */ return(cx_fail(msg,"Error closing previous connection")); debug(F100,"cx_net B","",0); if (*host) { /* They gave a hostname */ _local = 1; /* Network connection always local */ if (mdmsav < 0) mdmsav = mdmtyp; /* Remember old modem type */ mdmtyp = -net; /* Special code for network */ } else { /* They just said "set host" */ host = dftty; /* So go back to normal */ _local = dfloc; /* default tty, location, */ if (flag) { /* Close current connection */ setflow(); /* Maybe change flow control */ haveline = 1; /* (* is this right? *) */ dologend(); #ifndef NODIAL dialsta = DIA_UNK; #endif /* NODIAL */ #ifdef LOCUS if (autolocus) { setlocus(1,1); } #endif /* LOCUS */ /* XXX - Is this right? */ /* Should we be returning without doing anything ? */ /* Yes it's right -- we closed the old connection just above. */ return(success = 1); } } success = 0; if (host != line) /* line[] is a global */ ckstrncpy(line,host,LINBUFSIZ); ckstrncpy(hostname,host,HOSTNAMLEN); ckstrncpy(srvbuf,svc,SRVBUFSIZ+1); debug(F110,"cx_net hostname",host,0); debug(F110,"cx_net srvbuf",srvbuf,0); #ifndef NONETDIR #ifndef NODIAL if ((nhcount > 1) && msg) { int k; printf("%d entr%s found for \"%s\"%s\n", nhcount, (nhcount == 1) ? "y" : "ies", s, (nhcount > 0) ? ":" : "." ); for (i = 0; i < nhcount; i++) { printf("%3d. %-12s => %-9s %s", i+1,n_name,nh_p2[i],nh_p[i]); for (k = 0; k < 4; k++) { /* Also list net-specific items */ if (nh_px[k][i]) /* free format... */ printf(" %s",nh_px[k][i]); else break; } printf("\n"); } } if (nhcount == 0) n = 1; else n = nhcount; #else n = 1; nhcount = 0; #endif /* NODIAL */ n = 1; #endif /* NONETDIR */ for (i = 0; i < n; i++) { /* Loop for each entry found */ debug(F101,"cx_net loop i","",i); #ifndef NODIAL #ifndef NONETDIR if (nhcount > 0) { /* If we found at least one entry... */ ckstrncpy(line,nh_p[i],LINBUFSIZ); /* Copy current entry */ if (lookup(netcmd,nh_p2[i],nnets,&x) > -1) { /* Net type */ int xx; xx = netcmd[x].kwval; /* User specified SSH so don't let net directory override */ if (net != NET_SSH || xx != NET_TCPB) { net = xx; mdmtyp = 0 - net; } } else { makestr(&slmsg,"Network type not supported"); if (msg) printf("Error - network type \"%s\" not supported\n", nh_p2[i] ); continue; } switch (net) { /* Net-specific directory things */ #ifdef SSHBUILTIN case NET_SSH: /* SSH */ /* Any SSH specific network directory stuff? */ break; /* NET_SSH */ #endif /* SSHBUILTIN */ case NET_TCPB: { /* TCP/IP TELNET,RLOGIN,... */ #ifdef TCPSOCKET char *q; int flag = 0; /* Extract ":service", if any, from host string */ debug(F110,"cx_net service 1",line,0); for (q = line; (*q != '\0') && (*q != ':'); q++) ; if (*q == ':') { *q++ = NUL; flag = 1; } debug(F111,"cx_net service 2",line,flag); /* Get service, if any, from directory entry */ if (!*srvbuf) { if (nh_px[0][i]) { ckstrncpy(srvbuf,nh_px[0][i],SRVBUFSIZ); debug(F110,"cx_net service 3",srvbuf,0); } if (flag) { ckstrncpy(srvbuf,q,SRVBUFSIZ); debug(F110,"cx_net service 4",srvbuf,0); } } ckstrncpy(hostname,line,HOSTNAMLEN); /* If we have a service, append to host name/address */ if (*srvbuf) { ckstrncat(line, ":", LINBUFSIZ); ckstrncat(line, srvbuf, LINBUFSIZ); debug(F110,"cx_net service 5",line,0); } #ifdef RLOGCODE /* If no service given but command was RLOGIN */ else if (ttnproto == NP_RLOGIN) { /* add this... */ ckstrncat(line, ":login",LINBUFSIZ); debug(F110,"cx_net service 6",line,0); } #ifdef CK_AUTHENTICATION #ifdef CK_KERBEROS else if (ttnproto == NP_K4LOGIN || ttnproto == NP_K5LOGIN) { /* add this... */ ckstrncat(line, ":klogin",LINBUFSIZ); debug(F110,"cx_net service 7",line,0); } else if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN) { /* add this... */ ckstrncat(line, ":eklogin",LINBUFSIZ); debug(F110,"cx_net service 8",line,0); } #endif /* CK_KERBEROS */ #endif /* CK_AUTHENTICATION */ #endif /* RLOGCODE */ else { /* Otherwise, add ":telnet". */ ckstrncat(line, ":telnet", LINBUFSIZ); debug(F110,"cx_net service 9",line,0); } if (username) { /* This is a parameter... */ ckstrncpy(uidbuf,username,UIDBUFLEN); uidflag = 1; } /* Fifth field, if any, is user ID (for rlogin) */ if (nh_px[1][i] && !uidflag) ckstrncpy(uidbuf,username,UIDBUFLEN); #ifdef RLOGCODE if (IS_RLOGIN() && !uidbuf[0]) return(cx_fail(msg,"Username required")); #endif /* RLOGCODE */ #endif /* TCPSOCKET */ break; } case NET_PIPE: /* Pipe */ #ifdef NPIPE if (!pipename[0]) { /* User didn't give a pipename */ if (nh_px[0][i]) { /* But directory entry has one */ if (strcmp(pipename,"\\pipe\\")) { ckstrncpy(pipename,"\\pipe\\",LINBUFSIZ); ckstrncat(srvbuf,nh_px[0][i],PIPENAML-6); } else { ckstrncpy(pipename,nh_px[0][i],PIPENAML); } debug(F110,"cx_net pipeneme",pipename,0); } } #endif /* NPIPE */ break; case NET_SLAT: /* LAT / CTERM */ #ifdef SUPERLAT if (!slat_pwd[0]) { /* User didn't give a password */ if (nh_px[0][i]) { /* But directory entry has one */ ckstrncpy(slat_pwd,nh_px[0][i],18); debug(F110,"cx_net SuperLAT password",slat_pwd,0); } } #endif /* SUPERLAT */ break; case NET_SX25: /* X.25 keyword parameters */ case NET_IX25: case NET_VX25: { #ifdef ANYX25 int k; /* Cycle through the four fields */ for (k = 0; k < 4; k++) { if (!nh_px[k][i]) /* Bail out if none left */ break; if (!ckstrcmp(nh_px[k][i],"cug=",4,0)) { closgr = atoi(nh_px[k][i]+4); debug(F101,"X25 CUG","",closgr); } else if (!ckstrcmp(nh_px[k][i],"cud=",4,0)) { cudata = 1; ckstrncpy(udata,nh_px[k][i]+4,MAXCUDATA); debug(F110,"X25 CUD",cudata,0); } else if (!ckstrcmp(nh_px[k][i],"rev=",4,0)) { revcall = !ckstrcmp(nh_px[k][i]+4,"=on",3,0); debug(F101,"X25 REV","",revcall); #ifndef IBMX25 } else if (!ckstrcmp(nh_px[k][i],"pad=",4,0)) { int x3par, x3val; char *s1, *s2; s1 = s2 = nh_px[k][i]+4; /* PAD parameters */ while (*s2) { /* Pick them apart */ if (*s2 == ':') { *s2 = NUL; x3par = atoi(s1); s1 = ++s2; continue; } else if (*s2 == ',') { *s2 = NUL; x3val = atoi(s1); s1 = ++s2; debug(F111,"X25 PAD",x3par,x3val); if (x3par > -1 && x3par <= MAXPADPARMS) padparms[x3par] = x3val; continue; } else s2++; } #endif /* IBMX25 */ } } #endif /* ANYX25 */ break; } default: /* Nothing special for other nets */ break; } } else #endif /* NODIAL */ #endif /* NONETDIR */ { /* No directory entries found. */ ckstrncpy(line,hostname,LINBUFSIZ); /* Put this back... */ debug(F110,"cx_net after loop loop",line,0); /* If the user gave a TCP service */ if (net == NET_TCPB || net == NET_SSH) if (*srvbuf) { /* Append it to host name/address */ ckstrncat(line, ":", LINBUFSIZ); ckstrncat(line, srvbuf,LINBUFSIZ); } } /* Get here with host name/address and all net-specific parameters set, ready to open the connection. */ mdmtyp = -net; /* This should have been done */ /* already but just in case ... */ debug(F110,"cx_net net line[] before ttopen",line,0); debug(F101,"cx_net net mdmtyp before ttopen","",mdmtyp); debug(F101,"cx_net net ttnproto","",ttnproto); #ifdef SSHBUILTIN if (net == NET_SSH) { ssh_set_sparam(SSH_SPARAM_HST, hostname); /* Stash everything */ if (username) { if (!sl_uid_saved) { ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN); sl_uid_saved = 1; } ckstrncpy(uidbuf,username,UIDBUFLEN); } if (srvbuf[0]) { ssh_set_sparam(SSH_SPARAM_PRT,srvbuf); } else { ssh_set_sparam(SSH_SPARAM_PRT,NULL); } if (command) { ssh_set_sparam(SSH_SPARAM_CMD, brstrip(command)); ssh_set_iparam(SSH_IPARAM_CAS, param2); } else { ssh_set_sparam(SSH_SPARAM_CMD, NULL); } if (param1 > -1) { #ifndef SSHTEST if (!sl_ssh_ver_saved) { sl_ssh_ver = ssh_get_iparam(SSH_IPARAM_VER); sl_ssh_ver_saved = 1; } #endif /* SSHTEST */ ssh_set_iparam(SSH_IPARAM_VER, param1); } if (param3 > -1) { #ifndef SSHTEST if (!sl_ssh_xfw_saved) { sl_ssh_xfw = ssh_get_iparam(SSH_IPARAM_XFW); sl_ssh_xfw_saved = 1; } #endif /* SSHTEST */ ssh_set_iparam(SSH_IPARAM_XFW, param3); } } else /* NET_SSH */ #endif /* SSHBUILTIN */ #ifdef TCPSOCKET if (net == NET_TCPB) { switch (protocol) { #ifdef CK_SSL #ifdef COMMENT /* Jeff's version from 30 Dec 2006 - doesn't work - SSL/TLS_RAW still start Telnet negotions if a 0xff byte comes in. */ case NP_SSL_RAW: ttnproto = NP_SSL_RAW; debug(F101,"NP_SSL_RAW ttnproto","",ttnproto); ssl_only_flag = 1; tls_only_flag = 0; break; case NP_TLS_RAW: ttnproto = NP_TLS_RAW; debug(F101,"NP_TLS_RAW ttnproto","",ttnproto); ssl_only_flag = 0; tls_only_flag = 1; break; case NP_SSL: ttnproto = NP_SSL; debug(F101,"NP_SSL ttnproto","",ttnproto); ssl_only_flag = 1; tls_only_flag = 0; break; case NP_TLS: ttnproto = NP_TLS; debug(F101,"NP_TLS ttnproto","",ttnproto); ssl_only_flag = 0; tls_only_flag = 1; break; case NP_SSL_TELNET: ttnproto = NP_TELNET; debug(F101,"NP_SSL_TELNET ttnproto","",ttnproto); ssl_only_flag = 1; tls_only_flag = 0; break; case NP_TLS_TELNET: ttnproto = NP_TELNET; debug(F101,"NP_TLS_TELNET ttnproto","",ttnproto); ssl_only_flag = 0; tls_only_flag = 1; break; #else /* fdc version of 4 Dec 2006 works OK */ case NP_SSL_RAW: case NP_SSL: ssl_raw_flag = (protocol == NP_SSL_RAW) ? 1 : 0; ttnproto = protocol; debug(F101,protocol==NP_SSL ? "NP_SSL ttnproto" : "NP_SSL_RAW ttnproto", "",ttnproto); ssl_only_flag = 1; tls_only_flag = 0; break; case NP_TLS: case NP_TLS_RAW: tls_raw_flag = (protocol == NP_SSL_RAW) ? 1 : 0; ttnproto = protocol; debug(F101,protocol==NP_TLS ? "NP_TLS ttnproto" : "NP_TLS_RAW ttnproto", "",ttnproto); ssl_only_flag = 0; tls_only_flag = 1; break; case NP_SSL_TELNET: ssl_raw_flag = 0; ttnproto = NP_TELNET; debug(F101,"NP_SSL_TELNET ttnproto","",ttnproto); ssl_only_flag = 1; tls_only_flag = 0; break; case NP_TLS_TELNET: tls_raw_flag = 0; ttnproto = NP_TELNET; debug(F101,"NP_TLS_TELNET ttnproto","",ttnproto); ssl_only_flag = 0; tls_only_flag = 1; break; #endif /* COMMENT */ #endif /* CK_SSL */ case NP_NONE: case NP_TCPRAW: case NP_RLOGIN: case NP_K4LOGIN: case NP_K5LOGIN: case NP_EK4LOGIN: case NP_EK5LOGIN: case NP_TELNET: case NP_KERMIT: default: ttnproto = protocol; #ifdef CK_SSL #ifdef COMMENT /* Jeff version from 30 Dec 2006 */ ssl_only_flag = 0; tls_only_flag = 0; #else /* fdc version from 4 Dec 2006 */ ssl_raw_flag = 0; tls_raw_flag = 0; ssl_only_flag = 0; tls_only_flag = 0; #endif /* COMMENT */ #endif /* CK_SSL */ break; } #ifdef CK_AUTHENTICATION if ((ttnproto == NP_TELNET || ttnproto == NP_KERMIT) && param1 > -1) { if (!sl_auth_saved) { int x; for (x = 0; x < AUTHTYPLSTSZ; x++) sl_auth_type_user[x] = auth_type_user[x]; sl_auth_saved = 1; } if (!sl_topt_a_s_saved) { sl_topt_a_su = TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION); sl_topt_a_s_saved = 1; } if (!sl_topt_a_c_saved) { sl_topt_a_cm = TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION); sl_topt_a_c_saved = 1; } switch (param1) { case AUTHTYPE_AUTO: auth_type_user[0] = AUTHTYPE_AUTO; TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ; TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ; break; case AUTHTYPE_NULL: auth_type_user[0] = AUTHTYPE_NULL; TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF; TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF; break; #ifdef CK_SRP case AUTHTYPE_SRP: auth_type_user[0] = AUTHTYPE_SRP; auth_type_user[1] = AUTHTYPE_NULL; TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU; TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU; break; #endif /* CK_SRP */ #ifdef CK_SSL case AUTHTYPE_SSL: auth_type_user[0] = AUTHTYPE_SSL; auth_type_user[1] = AUTHTYPE_NULL; TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU; TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU; break; #endif /* CK_SSL */ #ifdef NT case AUTHTYPE_NTLM: auth_type_user[0] = AUTHTYPE_NTLM; auth_type_user[1] = AUTHTYPE_NULL; TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU; TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU; break; #endif /* NT */ #ifdef CK_KERBEROS case AUTHTYPE_KERBEROS_V4: auth_type_user[0] = AUTHTYPE_KERBEROS_V4; auth_type_user[1] = AUTHTYPE_NULL; TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU; TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU; break; case AUTHTYPE_KERBEROS_V5: auth_type_user[0] = AUTHTYPE_KERBEROS_V5; auth_type_user[1] = AUTHTYPE_NULL; TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU; TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU; break; #endif /* CK_KERBEROS */ } } /* If the user requires a particular type of Kerberos connection, make sure we have a valid TGT. */ makestr(&slmsg,"Authentication failure"); if ((ttnproto == NP_TELNET || ttnproto == NP_KERMIT) && (line[0] == '*' && TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) == TN_NG_MU || line[0] != '*' && TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) == TN_NG_MU) ) { #ifdef CK_KERBEROS if ( auth_type_user[0] == AUTHTYPE_KERBEROS_V4 ) { extern int krb4_autoget; if (!ck_krb4_is_installed()) return(cx_fail(msg, "Required authentication method (Kerberos 4) is not installed")); #ifdef COMMENT /* This code results in false failures when using */ /* kerberos to machines in realms other than the */ /* default since we don't know the realm of the */ /* other machine until perform the reverse DNS */ /* lookup. */ else if (line[0] != '*' && !ck_krb4_is_tgt_valid() && (!krb4_autoget || krb4_autoget && !ck_krb4_autoget_TGT(NULL))) { return(cx_fail(msg, "Kerberos 4: Ticket Getting Ticket not valid")); } #endif /* COMMENT */ } else if (auth_type_user[0] == AUTHTYPE_KERBEROS_V5) { extern int krb5_autoget; if (!ck_krb5_is_installed()) { return(cx_fail(msg, "Required authentication method (Kerberos 5) is not installed")); } #ifdef COMMENT /* This code results in false failures when using */ /* kerberos to machines in realms other than the */ /* default since we don't know the realm of the */ /* other machine until perform the reverse DNS */ /* lookup. */ else if (line[0] != '*' && !ck_krb5_is_tgt_valid() && (!krb5_autoget || krb5_autoget && !ck_krb5_autoget_TGT(NULL))) { return(cx_fail(msg, "Kerberos 5: Ticket Getting Ticket not valid.")); } #endif /* COMMENT */ } #endif /* CK_KERBEROS */ #ifdef NT if (auth_type_user[0] == AUTHTYPE_NTLM) { if (!ck_ntlm_is_installed()) { return(cx_fail(msg, "Required authentication method (NTLM) is not installed")); } #ifdef NTLM else if (line[0] != '*' && !ck_ntlm_is_valid(0)) { return(cx_fail(msg,"NTLM: Credentials are unavailable.")); } #endif /* NTLM */ } #endif /* NT */ #ifdef CK_SSL if (auth_type_user[0] == AUTHTYPE_SSL) { if (!ck_ssleay_is_installed()) { return(cx_fail(msg, "Required authentication method (SSL) is not installed")); } } #endif /* CK_SSL */ #ifdef CK_SRP if (auth_type_user[0] == AUTHTYPE_SRP) { if (!ck_srp_is_installed()) { return(cx_fail(msg, "Required authentication method (SRP) is not installed")); } } #endif /* CK_SRP */ } #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION if ((ttnproto == NP_TELNET || ttnproto == NP_KERMIT) && param2 > -1) { if (!sl_cx_saved) { sl_cx_type = cx_type; sl_cx_saved = 1; } if (!sl_topt_e_s_saved) { sl_topt_e_su = TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION); sl_topt_e_sm = TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION); sl_topt_e_s_saved = 1; } if (!sl_topt_e_c_saved) { sl_topt_e_cu = TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION); sl_topt_e_cm = TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION); sl_topt_e_c_saved = 1; } cx_type = param2; if (cx_type == CX_AUTO) { TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ; TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ; TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ; TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ; } else if (cx_type == CX_NONE) { TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; } else { TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; } } if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN || (ttnproto == NP_TELNET || ttnproto == NP_KERMIT) && ((line[0] == '*' && TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) == TN_NG_MU && TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_MU) || (line[0] != '*' && TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) == TN_NG_MU && TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_MU)) ) { if (!ck_crypt_is_installed()) { return(cx_fail(msg, "Required Encryption methods are not installed")); } } #endif /* CK_ENCRYPTION */ #ifdef RLOGCODE #ifdef CK_KERBEROS #ifdef KRB4 if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN) { extern int krb4_autoget; char tgt[256]; char * realm; /* We don't have the full hostname at yet so */ /* we do a DNS lookup before calling ttopen() */ realm = ck_krb4_realmofhost(ckgetfqhostname(hostname)); ckmakmsg(tgt,256,"krbtgt.",realm,"@",realm); if (!ck_krb4_is_installed()) { return(cx_fail(msg, "Required authentication method (Kerberos 4) is not installed" )); } else { if ((ck_krb4_tkt_isvalid(tgt) <= 0) && (!krb4_autoget || krb4_autoget && !ck_krb4_autoget_TGT(realm))) { return(cx_fail(msg, "Kerberos 4: Ticket Getting Ticket not valid")); } } } #endif /* KRB4 */ #ifdef KRB5 if (ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN || ttnproto == NP_K5U2U) { extern int krb5_autoget; char tgt[256]; char * realm; /* Must get full hostname before calling ttopen() */ realm = ck_krb5_realmofhost(ckgetfqhostname(hostname)); ckmakmsg(tgt,256,"krbtgt/",realm,"@",realm); if (!ck_krb5_is_installed()) { return(cx_fail(msg, "Required authentication method (Kerberos 5) not installed")); } else if (!((ck_krb5_tkt_isvalid(NULL,tgt) > 0) || ck_krb5_is_tgt_valid()) && (!krb5_autoget || krb5_autoget && !ck_krb5_autoget_TGT(realm))) { return(cx_fail(msg, "Kerberos 5: Ticket Getting Ticket not valid.")); } } #endif /* KRB5 */ #endif /* CK_KERBEROS */ #endif /* RLOGCODE */ #ifndef NOSPL #ifdef RLOGCODE if (username) { if (!sl_uid_saved) { ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN); sl_uid_saved = 1; } ckstrncpy(uidbuf,username,UIDBUFLEN); uidflag = 1; } #endif /* RLOGCODE */ #ifdef TNCODE if (!sl_tn_saved) { sl_tn_wait = tn_wait_flg; sl_tn_saved = 1; } tn_wait_flg = param3; #endif /* TNCODE */ #endif /* NOSPL */ } /* if (net == NET_TCPB) */ #endif /* TCPSOCKET */ #ifndef NOSPL #ifdef CK_SECURITY if (password) { if (password[0]) { ckstrncpy(pwbuf,password,PWBUFL+1); pwflg = 1; pwcrypt = 0; } else pwflg = 0; } #endif /* CK_SECURITY */ #endif /* NOSPL */ /* Try to open - network */ ckstrncpy(ttname,line,TTNAMLEN); y = ttopen(line, &_local, mdmtyp, 0 ); did_ttopen++; debug(F101,"cx_net did_ttopen A","",did_ttopen); #ifndef NOHTTP /* If the connection failed and we are using an HTTP Proxy * and the reason for the failure was an authentication * error, then we need to give the user to ability to * enter a username and password, just like a browser. * * I tried to do all of this within the netopen() call * but it is much too much work. */ while (y < 0 && tcp_http_proxy != NULL ) { if (tcp_http_proxy_errno == 401 || tcp_http_proxy_errno == 407 ) { char uid[UIDBUFLEN]; char pwd[256]; struct txtbox tb[2]; int ok; tb[0].t_buf = uid; tb[0].t_len = UIDBUFLEN; tb[0].t_lbl = "Proxy Userid: "; tb[0].t_dflt = NULL; tb[0].t_echo = 1; tb[1].t_buf = pwd; tb[1].t_len = 256; tb[1].t_lbl = "Proxy Passphrase: "; tb[1].t_dflt = NULL; tb[1].t_echo = 2; ok = uq_mtxt("Proxy Server Authentication Required\n", NULL, 2, tb); if (ok && uid[0]) { char * proxy_user, * proxy_pwd; proxy_user = tcp_http_proxy_user; proxy_pwd = tcp_http_proxy_pwd; tcp_http_proxy_user = uid; tcp_http_proxy_pwd = pwd; ckstrncpy(ttname,line,TTNAMLEN); y = ttopen(line, &_local, mdmtyp, 0); debug(F101,"cx_net did_ttopen B","",did_ttopen); memset(pwd,0,sizeof(pwd)); tcp_http_proxy_user = proxy_user; tcp_http_proxy_pwd = proxy_pwd; } else break; } else break; } #endif /* NOHTTP */ if (y < 0) { slrestor(); makestr(&slmsg,"Network connection failure"); #ifdef VMS /* 2024-06-08 SMS. Lame work-around for NONET build problem: * %CC-E-UNDECLARED, In this statement, "socket_errno" is not declared. * socket_errno is defined conditionally in ckcnet.h, but the * condition here is different. */ #ifndef socket_errno #define socket_errno errno /* Must match definition in ckcnet.h. */ #endif if (msg && hints && !xcmdsrc && IS_RLOGIN()) { makestr(&slmsg,"RLOGIN failure"); if (socket_errno == EACCES) { printf("*************************\n"); printf( "Hint: RLOGIN requires privileges to open an outbound port.\n"); printf( "(Use SET HINTS OFF to suppress future hints.)\n"); printf("*************************\n"); } } #else /* Not VMS... */ if (errno) { debug(F111,"set host line, errno","",errno); makestr(&slmsg,ck_errstr()); if (msg) { #ifdef OS2 printf("Can't connect to %s\n",line); #else /* OS2 */ #ifdef UNIX if (hints && !xcmdsrc && IS_RLOGIN()) { makestr(&slmsg,"RLOGIN failure"); printf("*************************\n"); printf( "Hint: RLOGIN requires privileges to open an outbound port.\n"); printf( "(Use SET HINTS OFF to suppress future hints.)\n"); printf("*************************\n"); } #endif /* UNIX */ #endif /* OS2 */ } else printf("Can't connect to %s\n",line); } else #endif /* VMS */ if (msg) printf("Can't open connection to %s\n",line); continue; } else { success = 1; #ifndef NODIAL dialsta = DIA_UNK; #endif /* NODIAL */ switch (net) { case NET_TCPA: case NET_TCPB: cxtype = CXT_TCPIP; #ifdef COMMENT /* This works but it messes up interactive anonymous login */ #ifndef NOXFER #ifdef IKS_OPTION /* If we have connected to an Internet Kermit service */ /* and a /USER: switch was given, then log in. */ if (TELOPT_U(TELOPT_KERMIT) || TELOPT_ME(TELOPT_KERMIT)) { debug(F111,"cx_net IKSD /USER:",uidbuf,haveuser); if (haveuser /* && cx == 0 */ ) { /* /USER: given */ char * psw = pwbuf; /* Do we have a password? */ if (!*psw) { /* No... */ if (!strcmp(uidbuf,"anonymous") || !strcmp(uidbuf,"ftp")) { extern char myhost[]; char * u = (char *)sl_uidbuf; char * h = (char *)myhost; if (!*u) u = "nobody"; if (!*h) h = "nowhere"; ckmakmsg(tmpbuf,TMPBUFSIZ,u,"@",h,NULL); psw = tmpbuf; debug(F110,"cx_net IKSD anon",psw,0); } else { readpass(" Password: ",pwbuf,PWBUFL); } } sstate = setgen('I',uidbuf,psw,""); } } #endif /* IKS_OPTION */ #endif /* NOXFER */ #endif /* COMMENT */ break; case NET_SSH: cxtype = CXT_SSH; duplex = 0; /* Remote echo */ break; case NET_SLAT: cxtype = CXT_LAT; break; case NET_SX25: case NET_IX25: case NET_HX25: case NET_VX25: cxtype = CXT_X25; break; case NET_BIOS: cxtype = CXT_NETBIOS; break; case NET_FILE: case NET_PIPE: case NET_CMD: case NET_DLL: case NET_PTY: cxtype = CXT_PIPE; break; default: cxtype = CXT_PIPE; break; } break; } } /* for-loop */ s = line; debug(F101,"cx_net after for-loop did_ttopen","",did_ttopen); if (did_ttopen == 0) { debug(F100,"cx_net didn't call ttopen - calling it now","",0); y = ttopen(line, &_local, mdmtyp, 0); debug(F101,"cx_net ttopen return code","",y); debug(F101,"cx_net ttopen _local","",_local); did_ttopen++; ckstrncpy(ttname,line,TTNAMLEN); success = 0; if (y > 0) success = 1; } debug(F101,"cx_net post ttopen success","",success); if (!success) { local = dfloc; /* Go back to normal */ #ifndef MAC ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty name */ #endif /* MAC */ speed = ttgspd(); network = 0; /* No network connection active */ haveline = 0; if (mdmtyp < 0) { /* Switching from net to async? */ if (mdmsav > -1) /* Restore modem type from last */ mdmtyp = mdmsav; /* SET MODEM command, if any. */ else mdmtyp = 0; mdmsav = -1; } return(0); /* Return failure */ } if (_local > -1) local = _local; /* Opened ok, set local/remote. */ makestr(&slmsg,NULL); network = (mdmtyp < 0); /* Remember connection type. */ ckstrncpy(ttname,s,TTNAMLEN); /* Copy name into real place. */ debug(F110,"cx_net ok",ttname,0); debug(F101,"cx_net network","",network); #ifndef NOXFER if ((reliable != SET_OFF || !setreliable)) /* Assume not reliable. */ reliable = SET_OFF; #endif /* NOXFER */ if (!network #ifdef NETCOMM || istncomport() #endif /* NETCOMM */ ) speed = ttgspd(); /* Get the current speed. */ debug(F101,"cx_net local","",local); if (network) { debug(F101,"cx_net net","",net); #ifndef NOXFER /* Force prefixing of 255 on TCP/IP connections... */ if (net == NET_TCPB #ifdef SSHBUILTIN || net == NET_SSH #endif /* SSHBUILTIN */ ) { debug(F101,"cx_net reliable A","",reliable); #ifdef CK_SPEED ctlp[(unsigned)255] = 1; #endif /* CK_SPEED */ if ((reliable != SET_OFF || !setreliable)) { #ifdef TN_COMPORT if (istncomport()) { /* Telnet communication port */ reliable = SET_OFF; /* Transport is not reliable */ debug(F101,"cx_net reliable istncomport()","",1); } else { reliable = SET_ON; /* Transport is reliable end to end */ debug(F101,"cx_net reliable istncomport()","",0); } #else reliable = SET_ON; /* Transport is reliable end to end */ #endif /* ifdef TN_COMPORT */ } debug(F101,"cx_net reliable B","",reliable); } else if (net == NET_SX25 || net == NET_VX25 || net == NET_IX25 || net == NET_HX25) { duplex = 1; /* Local echo for X.25 */ if (reliable != SET_OFF || !setreliable) reliable = SET_ON; /* Transport is reliable end to end */ } #endif /* NOXFER */ } #ifndef NOXFER debug(F101,"cx_net reliable","",reliable); #endif /* NOXFER */ #ifdef OS2 if (mdmtyp <= 0) /* Network or Direct Connection */ DialerSend(OPT_KERMIT_CONNECT, 0); #endif /* OS2 */ /*xcx_net:*/ setflow(); /* Set appropriate flow control */ haveline = 1; #ifdef NETCONN #ifdef CKLOGDIAL dolognet(); #endif /* CKLOGDIAL */ #endif /* NETCONN */ #ifndef NOSPL if (local) { if (nmac) { /* Any macros defined? */ int k; /* Yes */ k = mlook(mactab,"on_open",nmac); /* Look this up */ if (k >= 0) { /* If found, */ if (dodo(k,ttname,0) > -1) /* set it up, */ parser(1); /* and execute it */ } } } #endif /* NOSPL */ if (local && (cx || sx)) { /* /CONNECT or /SERVER switch given */ if (cx) { /* /CONNECT */ if (!gui) { /* Command was confirmed so we can pre-pop command level. */ /* This is so CONNECT module won't think we're executing a */ /* script if CONNECT was the final command in the script. */ if (cmdlvl > 0) prepop(); } #ifndef NODIAL dialsta = DIA_UNK; #endif /* NODIAL */ #ifdef LOCUS if (autolocus) { setlocus(1,1); } #endif /* LOCUS */ success = doconect(0, cmdlvl == 0 ? 1 : 0); if (ttchk() < 0) dologend(); debug(F101,"cx_net post doconect success","",success); return(success); #ifndef NOXFER } else if (sx) { /* /SERVER */ sstate = 'x'; #ifdef MAC what = W_RECV; scrcreate(); #endif /* MAC */ if (local) displa = 1; #ifdef AMIGA reqoff(); /* No DOS requestors while server */ #endif /* AMIGA */ #endif /* NOXFER */ } } #ifndef NODIAL dialsta = DIA_UNK; #endif /* NODIAL */ #ifdef LOCUS if (autolocus) { setlocus(1,1); } #endif /* LOCUS */ return(success = 1); } /* c x _ s e r i a l -- Make a serial connection */ /* Call with: device = string pointer to device name. cx = 1 to automatically enter Connect mode, 0 otherwise. sx = 1 to automatically enter Server mode, 0 otherwise. shr = 1 if device should be opened in shareable mode, 0 otherwise. flag = if no dev name given: 1 = close current connection, 0 = resume. gui = 1 if called from GUI dialog, 0 otherwise. Returns: 1 on success 0 on failure and no message printed, slmsg set to failure message. -9 on failure and message printed, ditto. */ /* these are bit flags */ #define CX_TAPI 1 #define CX_PPP 2 #define CX_SLIP 4 int #ifdef CK_ANSIC cx_serial(char *device, int cx, int sx, int shr, int flag, int gui, int special) #else /* CK_ANSIC */ cx_serial(device, cx, sx, shr, flag, gui, special) char * device; int cx, sx, shr, flag, gui, special; #endif /* CK_ANSIC */ /* cx_serial */ { int y, msg; int _local = -1; char *s; debug(F110,"cx_serial device",device,0); s = device; msg = (gui == 0) && msgflg; /* Whether to print messages */ success = 0; #ifndef NODIAL dialsta = DIA_UNK; #endif /* NODIAL */ debug(F101,"cx_serial mdmtyp","",mdmtyp); if (clskconnx(1) < 0) /* Close the Kermit connection */ return(success = 0); if (*s) { /* They gave a device name */ _local = -1; /* Let ttopen decide about it */ } else { /* They just said "set line" */ s = dftty; /* so go back to normal tty */ _local = dfloc; /* and mode. */ } #ifdef VMS { extern int ok_to_share; ok_to_share = shr; } #endif /* VMS */ #ifdef OS2 /* Must wait until after ttclos() */ #ifdef NT /* to change these settings */ #ifdef CK_TAPI tttapi = special & CX_TAPI; #endif /* CK_TAPI */ #else ttslip = special & CX_SLIP; ttppp = special & CX_PPP; #endif /* NT */ ttshare = shr; /* Shareable device ? */ debug(F110,"OS2 SET PORT final s",s,""); #endif /* OS2 */ /* Open the new line */ ckstrncpy(ttname,s,TTNAMLEN); if ((y = ttopen(s,&_local,mdmtyp,cdtimo)) > -1) { cxtype = (mdmtyp > 0) ? CXT_MODEM : CXT_DIRECT; #ifndef NODIAL dialsta = DIA_UNK; #ifdef CK_TAPI /* if the line is a tapi device, then we need to auto-execute */ /* SET MODEM TYPE TAPI - which we do the equivalent of here. */ if (tttapi) { extern int usermdm; usermdm = 0; initmdm(38); /* From ckudia.c n_TAPI == 38 */ } #endif /* CK_TAPI */ #endif /* NODIAL */ success = 1; } else { /* Failed */ #ifdef OS2ONLY if (!strcmp(s,dftty)) /* Do not generate an error with dftty */ ; else if (y == -6 && ttslip) { makestr(&slmsg,"Can't access SLIP driver"); if (msg) printf("?%s\n",slmsg); } else if (y == -6 && ttppp) { makestr(&slmsg,"Can't access PPP driver"); if (msg) printf("?%s\n",slmsg); } else #endif /* OS2ONLY */ if (y == -2) { makestr(&slmsg,"Timed out - no carrier"); if (msg) { printf("?%s\n",slmsg); if (hints) { printf("\n*************************\n"); printf( "HINT (Use SET HINTS OFF to suppress future hints):\n"); printf( "Try SET CARRIER OFF and SET LINE again, or else\n"); printf("SET MODEM, SET LINE, and then DIAL.\n"); printf("*************************\n\n"); } } } else if (y == -3) { makestr(&slmsg,"Access to lock denied"); if (msg) { #ifdef UNIX printf( "Sorry, write access to UUCP lockfile directory denied.\n"); #ifndef NOHINTS if (hints) { printf("\n*************************\n"); printf( "HINT (Use SET HINTS OFF to suppress future hints):\n"); printf( "Please read the installation instructions file, %sckuins.txt,\n", k_info_dir ? k_info_dir : "" ); printf( "or the UNIX appendix of the manual, \"Using C-Kermit\"\n" ); printf( "or visit http://www.kermitproject.org/ckuins.html \n" ); printf("*************************\n\n"); } #endif /* NOHINTS */ #else printf("Sorry, access to lock denied: %s\n",s); #endif /* UNIX */ } } else if (y == -4) { makestr(&slmsg,"Access to device denied"); if (msg) { printf("Sorry, access to device denied: %s\n",s); #ifdef UNIX #ifndef NOHINTS if (hints) { printf("\n*************************\n"); printf( "HINT (Use SET HINTS OFF to suppress future hints):\n"); printf( "Please read the installation instructions file, %sckuins.txt,\n", k_info_dir ? k_info_dir : "" ); printf( "or the UNIX appendix of the manual, \"Using C-Kermit\".\n" ); printf("*************************\n\n"); } #endif /* NOHINTS */ #endif /* UNIX */ } } else if (y == -5) { makestr(&slmsg,"Device is in use or unavailable"); if (msg) #ifdef VMS printf( "Sorry, device is in use or otherwise unavailable: %s\n",s); #else printf("Sorry, device is in use: %s\n",s); #endif /* VMS */ } else { /* Other error. */ makestr(&slmsg,"Device open failed"); if ( #ifdef VMS 1 #else errno #endif /* VMS */ ) { makestr(&slmsg,ck_errstr()); #ifndef VMS debug(F111,"cx_serial serial errno",slmsg,errno); #endif /* VMS */ if (msg) printf("Connection to %s failed: %s\n",s,slmsg); } else if (msg) printf("Sorry, can't open connection: %s\n",s); } } network = 0; /* No network connection active */ speed = ttgspd(); if (!success) { local = dfloc; /* Go back to normal */ #ifndef MAC ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty name */ #endif /* MAC */ haveline = 0; if (mdmtyp < 0) { /* Switching from net to async? */ if (mdmsav > -1) /* Restore modem type from last */ mdmtyp = mdmsav; /* SET MODEM command, if any. */ else mdmtyp = 0; mdmsav = -1; } return(msg ? -9 : 0); /* Return failure */ } if (_local > -1) local = _local; /* Opened ok, set local/remote. */ makestr(&slmsg,NULL); /* Erase SET LINE message */ ckstrncpy(ttname,s,TTNAMLEN); /* Copy name into real place. */ debug(F110,"cx_serial ok",ttname,0); #ifndef NOXFER if ((reliable != SET_OFF || !setreliable)) /* Assume not reliable. */ reliable = SET_OFF; #endif /* NOXFER */ /*xcx_serial:*/ setflow(); /* Set appropriate flow control */ haveline = 1; #ifdef CKLOGDIAL dologline(); #endif /* CKLOGDIAL */ #ifndef NOSPL if (local) { if (nmac) { /* Any macros defined? */ int k; /* Yes */ k = mlook(mactab,"on_open",nmac); /* Look this up */ if (k >= 0) { /* If found, */ if (dodo(k,ttname,0) > -1) /* set it up, */ parser(1); /* and execute it */ } } } #endif /* NOSPL */ if (local && (cx || sx)) { /* /CONNECT or /SERVER switch given */ extern int carrier; if (carrier != CAR_OFF) { /* Looking for carrier? */ /* Open() turns on DTR -- wait up to a second for CD to come up */ int i, x; for (i = 0; i < 10; i++) { /* WAIT 1 CD... */ x = ttgmdm(); if (x < 0 || x & BM_DCD) break; msleep(100); } } if (cx) { /* /CONNECT */ /* Command was confirmed so we can pre-pop command level. */ /* This is so CONNECT module won't think we're executing a */ /* script if CONNECT was the final command in the script. */ if (cmdlvl > 0) prepop(); #ifndef NODIAL dialsta = DIA_UNK; #endif /* NODIAL */ #ifdef LOCUS if (autolocus) { setlocus(1,1); } #endif /* LOCUS */ success = doconect(0, cmdlvl == 0 ? 1 : 0); if (ttchk() < 0) dologend(); return(success); #ifndef NOXFER } else if (sx) { /* /SERVER */ sstate = 'x'; #ifdef MAC what = W_RECV; scrcreate(); #endif /* MAC */ if (local) displa = 1; #ifdef AMIGA reqoff(); /* No DOS requestors while server */ #endif /* AMIGA */ #endif /* NOXFER */ } } #ifndef NODIAL dialsta = DIA_UNK; #endif /* NODIAL */ #ifdef LOCUS if (autolocus) { setlocus(1,1); } #endif /* LOCUS */ return(success = 1); } /* S E T L I N -- parse name of and then open communication device. */ /* Call with: xx == XYLINE for a serial (tty) line, XYHOST for a network host, zz == 0 means if user doesn't give a device name, continue current active connection (if any); zz != 0 means if user doesn't give a device name, then close the current connection and restore the default communication device. fc == 0 to just make the connection, 1 to also CONNECT (e.g. "telnet"). */ int #ifdef CK_ANSIC setlin( int xx, int zz, int fc ) #else setlin(xx, zz, fc) int xx, zz, fc; #endif /* CK_ANSIC */ { extern char pwbuf[], * g_pswd; extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal; int wait; /* int tn_wait_sv; */ int mynet; int c, i, haveswitch = 0; int haveuser = 0; int getval = 0; int wild = 0; /* Filespec has wildcards */ int cx = 0; /* Connect after */ int sx = 0; /* Become server after */ int a_type = -1; /* Authentication type */ int e_type = -1; /* Telnet /ENCRYPT type */ #ifdef CK_ENCRYPTION int encrypt = 0; /* Encrypted? */ #endif /* CK_ENCRYPTION */ int shr = 0; /* Share serial device */ int confirmed = 0; /* Command has been entered */ struct FDB sw, nx; #ifdef OS2 struct FDB fl; #else struct FDB tx; #endif /* OS2 */ char * ss; #ifdef TCPSOCKET int rawflg = 0; #endif /* TCPSOCKET */ char srvbuf[SRVBUFSIZ+1]; #ifdef OS2 #ifdef NT int xxtapi = 0; #else int xxslip = 0, xxppp = 0; #endif /* NT */ #endif /* OS2 */ int dossh = 0; debug(F101,"setlin fc","",fc); debug(F101,"setlin zz","",zz); debug(F101,"setlin xx","",xx); #ifdef SSHCMD if (xx == XXSSH) { /* SSH becomes PTY SSH ... */ dossh = 1; xx = XYHOST; } else if (!ckstrcmp("ssh ",line,4,0)) { /* 2010/03/01 */ dossh = 1; xx = XYHOST; } debug(F101,"setlin dossh","",dossh); #endif /* SSHCMD */ #ifdef TNCODE /* tn_wait_sv = tn_wait_flg; */ wait = tn_wait_flg; #else /* tn_wait_sv = 0; */ wait = 0; #endif /* TNCODE */ mynet = nettype; if (nolocal) { makestr(&slmsg,"Making connections is disabled"); printf("?Sorry, making connections is disabled\n"); return(-9); } if (netsave > -1) nettype = netsave; if (fc != 0 || zz == 0) /* Preset /CONNECT switch */ cx = 1; debug(F101,"setlin cx","",cx); *srvbuf = NUL; line[0] = NUL; s = line; #ifdef NETCONN #ifdef CK_SECURITY if (tmpstring) makestr(&tmpstring,NULL); #endif /* CK_SECURITY */ if (tmpusrid) makestr(&tmpusrid,NULL); #endif /* NETCONN */ autoflow = 1; /* Enable automatic flow setting */ debug(F101,"setlin xx","",xx); #ifdef SSHCMD debug(F100,"setlin SSHCMD","",0); #endif /* SSHCMD */ if (xx == XYHOST) { /* SET HOST */ debug(F100,"setlin XYHOST","",0); #ifndef NETCONN #ifndef SSHCMD debug(F100,"setlin XXX","",0); makestr(&slmsg,"Network connections not configured"); printf("?%s\n",slmsg); return(-9); #endif /* SSHCMD */ #endif /* NETCONN */ #ifndef NOPUSH debug(F101,"setlin mynet","",mynet); /* NET_CMD = 11, NET_PTY = 15 */ if ((mynet == NET_CMD || mynet == NET_PTY || dossh) && nopush) { makestr(&slmsg,"Access to external commands is disabled"); printf("?Sorry, access to external commands is disabled\n"); return(-9); } #endif /* NOPUSH */ debug(F101,"setlin dossh abc","",dossh); #ifdef SSHCMD debug(F101,"setlin dossh def","",dossh); if (dossh) { /* SSH connection via pty */ int k, q; int have_host = 0; extern int ttyfd; /* 2010/03/01 */ k = ckstrncpy(line, sshcmd ? sshcmd : defsshcmd, LINBUFSIZ); debug(F111,"setlin sshcmd 1",line,k); if ((x = cmtxt("Optional switches and hostname","",&s,xxstring))<0) return(x); debug(F111,"setlin dossh cmtxt",s,1); debug(F110,"setlin dossh ttname",ttname,0); if (!*s) debug(F111,"setlin dossh cmtxt is EMPTY",s,x); q = (int) strlen(s); debug(F111,"setlin dossh IF strlen(s)",s,q); if (q > 0) have_host = 1; /* 2010-03-30 */ if ((!q && (ttyfd < 0)) && !ckstrcmp("ssh ",ttname,4,0)) { x = ckstrncpy(line,ttname,LINBUFSIZ); debug(F110,"setlin dossh ttname *s == 0",s,0); } else { debug(F111,"setlin dossh ELSE have_host",s,have_host); if (have_host == 0) { debug(F101,"setlin dossh have_host IS ZERO","",have_host); printf("?SSH to where?\n"); return(-9); } if (k < LINBUFSIZ) { line[k++] = SP; line[k] = NUL; debug(F111,"setlin sshcmd 2",line,k); } if (k < LINBUFSIZ) { ckstrncpy(&line[k],s,LINBUFSIZ-k); debug(F111,"setlin sshcmd 3",line,k); } else { printf("?Too long\n"); return(-9); } } debug(F110,"setlin sshcmd calling cx_net",line,0); x = cx_net( NET_PTY, /* network type */ 0, /* protocol (not used) */ line, /* host */ NULL, /* service (not used) */ NULL, /* username (not used) */ NULL, /* password (not used) */ NULL, /* command (not used) */ -1,-1,-1, /* params 1-3 (not used) */ 1, /* connect immediately */ sx, /* server? */ zz, /* close current? */ 0); /* not gui */ debug(F111,"setlin cx_net",line,x); debug(F101,"setlin cx_net ttyfd","",ttyfd); return(x); } #endif /* SSHCMD */ /* Here we parse optional switches and then the hostname or whatever, which depends on the network type. The tricky part is, the network type can be set by a switch. */ #ifndef NOSPL makestr(&g_pswd,pwbuf); /* Save global pwbuf */ g_pflg = pwflg; /* and flag */ g_pcpt = pwcrypt; #endif /* NOSPL */ confirmed = 0; haveswitch = 0; #ifdef NETCONN #ifdef NETFILE if (mynet != NET_FILE) { #endif /* NETFILE */ ss = (mynet == NET_CMD || mynet == NET_PTY) ? "Command, or switch" : (mynet == NET_TCPA || mynet == NET_TCPB || mynet == NET_SSH) ? "Hostname, ip-address, or switch" :(mynet == NET_DLL) ? "Parameters, or switch" : "Host or switch"; if (fc) { if (mynet == NET_TCPB && (ttnproto == NP_TELNET || ttnproto == NP_KERMIT)) { if (nshteltab) { haveswitch++; cmfdbi(&sw,_CMKEY,ss,"","",nshteltab,4,xxstring, shteltab,&nx); } } #ifdef RLOGCODE else if (mynet == NET_TCPB && ttnproto == NP_RLOGIN) { if (nshrlgtab) { haveswitch++; cmfdbi(&sw,_CMKEY,ss,"","",nshrlgtab,4,xxstring, shrlgtab,&nx); } } #endif /* RLOGCODE */ } else { haveswitch++; cmfdbi(&sw,_CMKEY,ss,"","",nshtab,4,xxstring,shtab,&nx); } #ifdef NETFILE } #endif /* NETFILE */ if (mynet == NET_TCPB || mynet == NET_SLAT || mynet == NET_SSH || mynet == NET_DEC) { cmfdbi(&nx,_CMFLD,"Host","","",0,0,xxstring,NULL,NULL); #ifdef NETFILE } else if (mynet == NET_FILE) { cmfdbi(&nx,_CMIFI,"Filename","","",0,0,xxstring,NULL,NULL); #endif /* NETFILE */ #ifdef PTYORPIPE } else if (mynet == NET_CMD || mynet == NET_PTY) { cmfdbi(&nx,_CMTXT,"Command","","",0,0,xxstring,NULL,NULL); #endif /* PTYORPIPE */ #ifdef NETDLL } else if (mynet == NET_DLL) { cmfdbi(&nx,_CMTXT,"Parameters","","",0,0,xxstring,NULL,NULL); #endif /* NETFILE */ } else { cmfdbi(&nx,_CMTXT,"Host","","",0,0,xxstring,NULL,NULL); } while (1) { x = cmfdb(haveswitch ? &sw : &nx); debug(F101,"setlin cmfdb","",x); if (x < 0) if (x != -3) return(x); if (x == -3) { if ((x = cmcfm()) < 0) { return(x); } else { confirmed = 1; break; } } if (cmresult.fcode != _CMKEY) { /* Not a switch */ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Save the data */ s = line; /* that was parsed... */ if (cmresult.fcode == _CMIFI) { wild = cmresult.nresult; } else if (cmresult.fcode == _CMTXT) { confirmed = 1; } break; /* and break out of this loop */ } c = cmgbrk(); /* Have switch - get break character */ getval = (c == ':' || c == '='); /* Must parse an agument? */ if (getval && !(cmresult.kflags & CM_ARG)) { printf("?This switch does not take arguments\n"); return(-9); } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } switch (cmresult.nresult) { /* It's a switch.. */ case SL_CNX: /* /CONNECT */ cx = 1; sx = 0; break; case SL_SRV: /* /SERVER */ cx = 0; sx = 1; break; #ifdef NETCMD case SL_CMD: /* /COMMAND */ netsave = mynet; mynet = NET_CMD; break; #endif /* NETCMD */ #ifdef NETPTY case SL_PTY: /* /PTY */ netsave = mynet; mynet = NET_PTY; break; #endif /* NETPTY */ case SL_NET: /* /NETWORK-TYPE */ if ((x = cmkey(netcmd,nnets,"","",xxstring)) < 0) return(x); mynet = x; break; #ifdef CK_SECURITY case SL_PSW: /* /PASSWORD: */ if (!getval) break; debok = 0; if ((x = cmfld("Password","",&s,xxstring)) < 0) { if (x == -3) { makestr(&tmpstring,""); } else { return(x); } } else { s = brstrip(s); if ((x = (int)strlen(s)) > PWBUFL) { makestr(&slmsg,"Internal error"); printf("?Sorry, too long - max = %d\n",PWBUFL); return(-9); } makestr(&tmpstring,s); } break; #endif /* CK_SECURITY */ case SL_UID: /* /USERID: */ if (!getval) break; if ((x = cmfld("Userid","",&s,xxstring)) < 0) { if (x == -3) { makestr(&tmpusrid,""); } else { return(x); } } else { s = brstrip(s); if ((x = (int)strlen(s)) > 63) { makestr(&slmsg,"Internal error"); printf("?Sorry, too long - max = %d\n",63); return(-9); } makestr(&tmpusrid,s); haveuser = 1; } break; #ifdef CK_AUTHENTICATION #ifdef CK_SRP case SL_SRP: a_type = AUTHTYPE_SRP; break; #endif /* CK_SRP */ #ifdef CK_SSL case SL_SSL: a_type = AUTHTYPE_SSL; break; #endif /* CK_SSL */ #ifdef NT case SL_NTLM: a_type = AUTHTYPE_NTLM; break; #endif /* NT */ #ifdef CK_KERBEROS case SL_KRB4: a_type = AUTHTYPE_KERBEROS_V4; if (ttnproto == NP_RLOGIN) ttnproto = #ifdef CK_ENCRYPTION encrypt ? NP_EK4LOGIN : #endif /* CK_ENCRYPTION */ NP_K4LOGIN; else if (ttnproto == NP_K5LOGIN) ttnproto = NP_K4LOGIN; #ifdef CK_ENCRYPTION else if (ttnproto == NP_EK5LOGIN) ttnproto = NP_EK4LOGIN; #endif /* CK_ENCRYPTION */ break; case SL_KRB5: a_type = AUTHTYPE_KERBEROS_V5; if (ttnproto == NP_RLOGIN) ttnproto = #ifdef CK_ENCRYPTION encrypt ? NP_EK5LOGIN : #endif /* CK_ENCRYPTION */ NP_K5LOGIN; else if (ttnproto == NP_K4LOGIN) ttnproto = NP_K5LOGIN; #ifdef CK_ENCRYPTION else if (ttnproto == NP_EK4LOGIN) ttnproto = NP_EK5LOGIN; #endif /* CK_ENCRYPTION */ break; #endif /* CK_KERBEROS */ case SL_AUTH: { extern struct keytab autyptab[]; extern int nautyp; if ((x = cmkey(autyptab,nautyp,"type of authentication", "automatic",xxstring)) < 0) return(x); a_type = x; break; } #endif /* CK_AUTHENTICATION */ #ifdef CK_ENCRYPTION case SL_ENC: switch (ttnproto) { case NP_K4LOGIN: ttnproto = NP_EK4LOGIN; encrypt = 1; break; case NP_K5LOGIN: ttnproto = NP_EK5LOGIN; encrypt = 1; break; case NP_KERMIT: case NP_TELNET: { static struct keytab * tnetbl = NULL; static int ntnetbl = 0; x = ck_get_crypt_table(&tnetbl,&ntnetbl); debug(F101,"ck_get_crypt_table x","",x); debug(F101,"ck_get_crypt_table n","",ntnetbl); if (x < 1 || !tnetbl || ntnetbl < 1) /* Didn't get it */ x = 0; if (!x) { makestr(&slmsg,"Internal error"); printf("?Oops, types not loaded\n"); return(-9); } if ((x = cmkey(tnetbl,ntnetbl,"type of encryption", "automatic",xxstring)) < 0) return(x); e_type = x; break; } } break; #endif /* CK_ENCRYPTION */ case SL_WAIT: wait = 1; break; case SL_NOWAIT: wait = 0; break; } } #ifdef NETFILE if (mynet == NET_FILE) { /* Parsed by cmifi() */ if ((x = cmcfm()) < 0) /* Needs confirmation */ return(x); x = cx_net(mynet, /* nettype */ 0, /* protocol (not used) */ line, /* host */ "", /* port */ NULL, /* alternate username */ NULL, /* password */ NULL, /* command to execute */ 0, /* param1 */ 0, /* param2 */ 0, /* param3 */ cx, /* enter CONNECT mode */ sx, /* enter SERVER mode */ zz, /* close connection if open */ 0 /* gui */ ); } #endif /* NETFILE */ #ifdef NETCMD if (mynet == NET_CMD || mynet == NET_PTY) { char *p = NULL; if (!confirmed) { if ((x = cmtxt("Rest of command","",&s,xxstring)) < 0) return(x); if (*s) { ckstrncat(line," ",LINBUFSIZ); ckstrncat(line,s,LINBUFSIZ); } s = line; } /* s == line - so we must protect the line buffer */ s = brstrip(s); makestr(&p,s); ckstrncpy(line,p,LINBUFSIZ); makestr(&p,NULL); x = cx_net( mynet, /* nettype */ 0, /* protocol (not used) */ line, /* host */ "", /* port */ NULL, /* alternate username */ NULL, /* password */ NULL, /* command to execute */ 0, /* param1 */ 0, /* param2 */ 0, /* param3 */ cx, /* enter CONNECT mode */ sx, /* enter SERVER mode */ zz, /* close connection if open */ 0 /* gui */ ); } #endif /* NETCMD */ #ifdef NETDLL if (mynet == NET_DLL) { char *p = NULL; if (!confirmed) { if ((x = cmtxt("Rest of command","",&s,xxstring)) < 0) { return(x); } if (*s) { ckstrncat(line," ",LINBUFSIZ); ckstrncat(line,s,LINBUFSIZ); } s = line; } /* s == line - so we must protect the line buffer */ s = brstrip(s); makestr(&p,s); ckstrncpy(line,p,LINBUFSIZ); makestr(&p,NULL); x = cx_net( mynet, /* nettype */ 0, /* protocol (not used) */ line, /* host */ "", /* port */ NULL, /* alternate username */ NULL, /* password */ NULL, /* command to execute */ 0, /* param1 */ 0, /* param2 */ 0, /* param3 */ cx, /* enter CONNECT mode */ sx, /* enter SERVER mode */ zz, /* close connection if open */ 0 /* gui */ ); } #endif /* NETDLL */ #ifdef CK_NETBIOS if (mynet == NET_BIOS) { /* * TODO: * "server name, *,\n or carriage return to close an open connection" : * "server name, *,\n or carriage return to resume an open connection", */ x = cx_net(mynet, /* nettype */ 0, /* protocol (not used) */ line, /* host */ "", /* port */ NULL, /* alternate username */ NULL, /* password */ NULL, /* command to execute */ 0, /* param1 */ 0, /* param2 */ 0, /* param3 */ cx, /* enter CONNECT mode */ sx, /* enter SERVER mode */ zz, /* close connection if open */ 0 /* gui */ ); } #endif /* CK_NETBIOS */ #ifdef NPIPE /* Named pipe */ if (mynet == NET_PIPE) { /* Needs backslash twiddling */ if (line[0]) { if (strcmp(line,"*")) { /* If remote, begin with */ char * p = NULL; makestr(&p,line); ckstrncpy(line,"\\\\",LINBUFSIZ); /* server name */ ckstrncat(line,p,LINBUFSIZ); makestr(&p,NULL); } else { line[0]='\0'; } ckstrncat(line,"\\pipe\\", LINBUFSIZ); /* Make pipe name */ ckstrncat(line,pipename, LINBUFSIZ); /* Add name of pipe */ x = cx_net(mynet, /* nettype */ 0, /* protocol (not used) */ line, /* host */ "", /* port */ NULL, /* alternate username */ NULL, /* password */ NULL, /* command to execute */ 0, /* param1 */ 0, /* param2 */ 0, /* param3 */ cx, /* enter CONNECT mode */ sx, /* enter SERVER mode */ zz, /* close connection if open */ 0 /* gui */ ); } } #endif /* NPIPE */ #ifdef SUPERLAT if (mynet == NET_SLAT) { /* Needs password, etc. */ slat_pwd[0] = NUL; /* Erase any previous password */ debok = 0; if (*line) { /* If they gave a host name... */ if ((x = cmfld( "password,\n or carriage return if no password required", "", &s, xxstring )) < 0 && x != -3) return(x); ckstrncpy(slat_pwd,s,18); /* Set the password, if any */ } if ((x = cmcfm()) < 0) return(x); /* Confirm the command */ x = cx_net(mynet, /* nettype */ 0, /* protocol (not used) */ line, /* host */ "", /* port */ NULL, /* alternate username */ NULL, /* password */ NULL, /* command to execute */ 0, /* param1 */ 0, /* param2 */ 0, /* param3 */ cx, /* enter CONNECT mode */ sx, /* enter SERVER mode */ zz, /* close connection if open */ 0 /* gui */ ); } #endif /* SUPERLAT */ #ifdef DECNET if (mynet == NET_DEC) { if (!line[0]) { /* If they gave a host name... */ printf("?hostname required\n"); return(-3); } if ((x = cmcfm()) < 0) return(x); /* Confirm the command */ x = cx_net(mynet, /* nettype */ 0, /* protocol (not used) */ line, /* host */ "", /* port */ NULL, /* alternate username */ NULL, /* password */ NULL, /* command to execute */ 0, /* param1 */ 0, /* param2 */ 0, /* param3 */ cx, /* enter CONNECT mode */ sx, /* enter SERVER mode */ zz, /* close connection if open */ 0 /* gui */ ); } #endif /* DECNET */ #ifdef SSHBUILTIN if (mynet == NET_SSH) { /* SSH connection */ int k, havehost = 0, trips = 0; int tmpver = -1, tmpxfw = -1, tmpssh_cas; #ifndef SSHTEST extern int sl_ssh_xfw, sl_ssh_xfw_saved; extern int sl_ssh_ver, sl_ssh_ver_saved; #endif /* SSHTEST */ extern struct keytab sshopnsw[]; extern int nsshopnsw; extern char *ssh_tmpcmd, *ssh_tmpport; struct FDB sw, kw, fl; debug(F110,"setlin SSH service 0",srvbuf,0); debug(F110,"setlin SSH host s 2",s,0); if (*s) { /* If they gave a host name... */ debug(F110,"setlin SSH host s 1",s,0); if (*s == '*') { makestr(&slmsg,"Incoming connections not supported"); printf( "?Sorry, incoming connections not supported for SSH.\n" ); return(-9); } ckstrncpy(line,s,LINBUFSIZ); } else { printf("?hostname required\n"); return(-3); } /* Parse [ port ] [ switches ] */ cmfdbi(&kw, /* Switches */ _CMKEY, "Port number or service name,\nor switch", "", "", nsshopnsw, 4, xxstring, sshopnsw, &fl ); cmfdbi(&fl, /* Port number or service name */ _CMFLD, "", "", "", 0, 0, xxstring, NULL, NULL ); trips = 0; /* Explained below */ while (1) { /* Parse port and switches */ y = cmfdb(&kw); /* Get a field */ if (y == -3) /* User typed CR so quit from loop */ break; if (y < 0) /* Other parse error, pass it back */ return(y); switch (cmresult.fcode) { /* Field or Keyword? */ case _CMFLD: /* Field */ ckstrncpy(srvbuf,cmresult.sresult,SRVBUFSIZ); break; case _CMKEY: /* Keyword */ switch (cmresult.nresult) { /* Which one? */ case SSHSW_PWD: if (!cmgbrk()) { printf("?This switch requires an argument\n"); return(-9); } debok = 0; if ((y = cmfld("Password","",&s,xxstring)) < 0) { if (y == -3) { makestr(&tmpstring,""); } else { return(y); } } else { s = brstrip(s); if ((y = (int)strlen(s)) > PWBUFL) { makestr(&slmsg,"Internal error"); printf("?Sorry, too long - max = %d\n",PWBUFL); return(-9); } makestr(&tmpstring,s); } break; case SSHSW_USR: /* /USER: */ if (!cmgbrk()) { printf("?This switch requires an argument\n"); return(-9); } if ((y = cmfld("Username","",&s,xxstring)) < 0) return(y); s = brstrip(s); makestr(&tmpusrid,s); break; case SSHSW_VER: if ((y = cmnum("Number","",10,&z,xxstring)) < 0) return(y); if (z < 1 || z > 2) { printf("?Out of range: %d\n",z); return(-9); } tmpver = z; break; case SSHSW_CMD: case SSHSW_SUB: if ((y = cmfld("Text","",&s,xxstring)) < 0) return(y); makestr(&ssh_tmpcmd,s); tmpssh_cas = (cmresult.nresult == SSHSW_SUB); break; case SSHSW_X11: if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y); tmpxfw = y; break; default: return(-2); } } if (trips++ == 0) { /* After first time through */ cmfdbi(&kw, /* only parse switches, not port. */ _CMKEY, "Switch", "", "", nsshopnsw, 4, xxstring, sshopnsw, NULL ); } } if ((y = cmcfm()) < 0) /* Get confirmation */ return(y); debug(F110,"setlin pre-cx_net line",line,0); debug(F110,"setlin pre-cx_net srvbuf",srvbuf,0); x = cx_net( mynet, /* nettype */ 0, /* protocol (not used) */ line, /* host */ srvbuf, /* port */ tmpusrid, /* alternate username */ tmpstring, /* password */ ssh_tmpcmd, /* command to execute */ tmpver, /* param1 - ssh version */ tmpssh_cas, /* param2 - ssh cas */ tmpxfw, /* param3 - ssh x11fwd */ cx, /* enter CONNECT mode */ sx, /* enter SERVER mode */ zz, /* close connection if open */ 0 /* gui */ ); if (tmpusrid) makestr(&tmpusrid,NULL); if (ssh_tmpcmd) makestr(&ssh_tmpcmd,NULL); } #endif /* SSHBUILTIN */ #ifdef TCPSOCKET if (mynet == NET_TCPB) { /* TCP/IP connection */ debug(F110,"setlin service 0",srvbuf,0); debug(F110,"setlin host s 2",s,0); if (*s) { /* If they gave a host name... */ debug(F110,"setlin host s 1",s,0); #ifdef NOLISTEN if (*s == '*') { makestr(&slmsg,"Incoming connections not supported"); printf( "?Sorry, incoming connections not supported in this version of Kermit.\n" ); return(-9); } #endif /* NOLISTEN */ #ifdef RLOGCODE /* Allow a username if rlogin is requested */ if (mynet == NET_TCPB && (ttnproto == NP_RLOGIN || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN )) { int y; uidflag = 0; /* Check for "host:service" */ for ( ; (*s != '\0') && (*s != ':'); s++) ; if (*s) { /* Service, save it */ *s = NUL; ckstrncpy(srvbuf,++s,SRVBUFSIZ); } else { /* No :service, then use default. */ #ifdef VMS switch (ttnproto) { case NP_RLOGIN: ckstrncpy(srvbuf,"513",SRVBUFSIZ); /* "login" */ break; case NP_K4LOGIN: case NP_K5LOGIN: ckstrncpy(srvbuf,"543",SRVBUFSIZ); /* "klogin" */ break; case NP_EK4LOGIN: case NP_EK5LOGIN: ckstrncpy(srvbuf,"2105",SRVBUFSIZ); /* "eklogin" */ break; } #else /* VMS */ switch (ttnproto) { case NP_RLOGIN: ckstrncpy(srvbuf,"login",SRVBUFSIZ); break; case NP_K4LOGIN: case NP_K5LOGIN: ckstrncpy(srvbuf,"klogin",SRVBUFSIZ); break; case NP_EK4LOGIN: case NP_EK5LOGIN: ckstrncpy(srvbuf,"eklogin",SRVBUFSIZ); break; } #endif /* VMS */ } if (!confirmed) { y = cmfld("Userid on remote system", uidbuf,&s,xxstring); if (y < 0 && y != -3) return(y); if ((int)strlen(s) > 63) { makestr(&slmsg,"Internal error"); printf("Sorry, too long\n"); return(-9); } makestr(&tmpusrid,s); } } else { /* TELNET or SET HOST */ #endif /* RLOGCODE */ /* Check for "host:service" */ for ( ; (*s != '\0') && (*s != ':'); s++) ; if (*s) { /* Service, save it */ *s = NUL; ckstrncpy(srvbuf,++s,SRVBUFSIZ); } else if (!confirmed) { /* No :service, let them type one. */ if (*line != '*') { /* Not incoming */ if (mynet == NET_TCPB && ttnproto == NP_KERMIT) { if ((x = cmfld( "TCP service name or number", "kermit",&s,xxstring) ) < 0 && x != -3) return(x); #ifdef RLOGCODE } else if (mynet == NET_TCPB && ttnproto == NP_RLOGIN) { if ((x = cmfld( "TCP service name or number,\n or carriage return for rlogin (513)", "login",&s,xxstring) ) < 0 && x != -3) return(x); #ifdef CK_AUTHENTICATION #ifdef CK_KERBEROS } else if (mynet == NET_TCPB && (ttnproto == NP_K4LOGIN || ttnproto == NP_K5LOGIN)) { if ((x = cmfld( "TCP service name or number,\n or carriage return for klogin (543)", "klogin",&s,xxstring) ) < 0 && x != -3) return(x); } else if (mynet == NET_TCPB && (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN)) { if ((x = cmfld( "TCP service name or number,\n or carriage return for eklogin (2105)", "eklogin",&s,xxstring) ) < 0 && x != -3) return(x); #endif /* CK_KERBEROS */ #endif /* CK_AUTHENTICATION */ #endif /* RLOGCODE */ } else { /* Do not set a default value in this call */ /* If you do then it will prevent entries */ /* in the network directory from accessing */ /* alternate ports. */ if ((x = cmfld( "TCP service name or number", "",&s,xxstring) ) < 0 && x != -3) return(x); } } else { /* Incoming connection */ if ((x = cmfld("TCP service name or number", "",&s,xxstring) ) < 0 && x != -3) return(x); } if (*s) /* If they gave a service, */ ckstrncpy(srvbuf,s,SRVBUFSIZ); /* copy it */ debug(F110,"setlin service 0.5",srvbuf,0); } #ifdef RLOGCODE } #endif /* RLOGCODE */ if (!confirmed) { char * defproto; switch (ttnproto) { case NP_RLOGIN: defproto = "/rlogin"; break; case NP_K4LOGIN: defproto = "/k4login"; break; case NP_K5LOGIN: defproto = "/k5login"; break; case NP_EK4LOGIN: defproto = "/ek4login"; break; case NP_EK5LOGIN: defproto = "/ek5login"; break; case NP_KERMIT: case NP_TELNET: defproto = "/telnet"; break; default: defproto = "/default"; } if ((x = cmkey(tcprawtab,ntcpraw,"Switch",defproto, xxstring)) < 0) { if (x != -3) return(x); else if ((x = cmcfm()) < 0) return(x); } else { rawflg = x; if ((x = cmcfm()) < 0) return(x); } } } debug(F110,"setlin pre-cx_net line",line,0); debug(F110,"setlin pre-cx_net srvbuf",srvbuf,0); x = cx_net( mynet, /* nettype */ rawflg /* protocol */, line, /* host */ srvbuf, /* port */ tmpusrid, /* alternate username */ tmpstring, /* password */ NULL, /* command to execute */ a_type, /* param1 - telnet authtype */ e_type, /* param2 - telnet enctype */ wait, /* param3 - telnet wait */ cx, /* enter CONNECT mode */ sx, /* enter SERVER mode */ zz, /* close connection if open */ 0 /* gui */ ); } #endif /* TCPSOCKET */ #ifdef CK_SECURITY if (tmpstring) makestr(&tmpstring,NULL); #endif /* CK_SECURITY */ if (tmpusrid) makestr(&tmpusrid,NULL); debug(F111,"setlin cx_net",line,x); return(x); #endif /* NETCONN */ } /* Serial tty device, possibly modem, connection... */ #ifdef OS2 /* User can type: COM1..COM8 = Regular COM port 1..8 = Synonym for COM1..COM8, is translated to COM1..COM8 _n = (n is a number) = open file handle string = any text string = name of some other kind of device, taken literally, as given. */ s = "Communication device name"; #ifdef CK_TAPI if (TAPIAvail) cktapiBuildLineTable(&tapilinetab, &_tapilinetab, &ntapiline); if (!(tapilinetab && _tapilinetab && ntapiline > 0) && xx == XYTAPI_LIN ) { makestr(&slmsg,"TAPI device not configured"); printf("\nNo TAPI Line Devices are configured for this system\n"); return(-9); } if (xx == XYTAPI_LIN) { /* Default (first) TAPI line */ s = "tapi"; /* (whatever it is) */ } else { /* Query the user */ #endif /* CK_TAPI */ /* Now parse optional switches and then device name */ confirmed = 0; cmfdbi(&sw,_CMKEY,"Device name, or switch", "","",npsltab,4,xxstring,psltab,&fl); cmfdbi(&fl,_CMFLD,"",dftty,"",0,0,xxstring,NULL,NULL); while (1) { x = cmfdb(&sw); debug(F101,"setlin cmfdb","",x); if (x < 0) if (x != -3) return(x); if (x == -3) { if ((x = cmcfm()) < 0) { return(x); } else { confirmed = 1; break; } } if (cmresult.fcode == _CMFLD) { s = cmresult.sresult; break; } else if (cmresult.fcode == _CMKEY) { switch (cmresult.nresult) { case SL_CNX: /* /CONNECT */ cx = 1; sx = 0; break; case SL_SRV: /* /SERVER */ cx = 0; sx = 1; break; case SL_SHR: /* /SHARE */ shr = 1; break; case SL_NSH: /* /NOSHARE */ shr = 0; break; } } } #ifdef CK_TAPI } #endif /* CK_TAPI */ debug(F110,"OS2 SET PORT s",s,0); y = lookup(os2devtab,s,nos2dev,&x); /* Look up in keyword table */ debug(F101,"OS2 SET PORT x","",x); debug(F101,"OS2 SET PORT y","",y); if ((y > -1) && (x >= 0 && x < 8)) { /* User typed a digit 1..8 */ s = os2devtab[x+8].kwd; /* Substitite its real name */ #ifdef NT xxtapi = 0; #else /* NT */ xxslip = xxppp = 0; #endif /* NT */ debug(F110,"OS2 SET PORT subst s",s,""); #ifndef NT } else if ((y >-1) && (x >= 16 && x < 24)) { /* SLIP access */ s = os2devtab[x-8].kwd; /* Substitite its real name */ debug(F110,"OS2 SET PORT SLIP subst s",s,""); xxslip = 1; xxppp = 0; } else if ((y >-1) && (x >= 24 && x < 32)) { /* PPP access */ s = os2devtab[x-16].kwd; /* Substitite its real name */ debug(F110,"OS2 SET PORT PPP subst s",s,""); xxppp = 1; xxslip = 0; if ((y = cmkey(os2ppptab, nos2ppp, "PPP driver interface", "ppp0", xxstring) ) < 0) return(y); debug(F101,"OS2 SET PORT PPP INTERFACE y","",y); xxppp = (y % 10) + 1; #endif /* NT */ } else if (*s == '_') { /* User used "_" prefix */ s++; /* Remove it */ /* Rest must be numeric */ debug(F110,"OS2 SET PORT HANDLE _subst s",s,0); if (!rdigits(s)) { makestr(&slmsg,"Invalid file handle"); printf("?Invalid format for file handle\n"); return(-9); } #ifdef NT xxtapi = 0; #else /* NT */ xxslip = xxppp = 0; #endif /* NT */ } else { /* A normal COMx port or a string */ s = brstrip(s); /* Strip braces if any */ #ifdef NT #ifdef CK_TAPI /* Windows TAPI support - Look up in keyword table */ if (tapilinetab && _tapilinetab && ntapiline > 0) { if (!ckstrcmp(s,"tapi",4,0)) { /* Find out what the lowest numbered TAPI device is */ /* and use it as the default. */ int j = 9999, k = -1; for (i = 0; i < ntapiline; i++) { if (tapilinetab[i].kwval < j) { j = tapilinetab[i].kwval; k = i; } } if (k >= 0) s = _tapilinetab[k].kwd; else s = ""; if ((y = cmkey(_tapilinetab,ntapiline, "TAPI device name",s,xxstring)) < 0) return(y); xxtapi = 1; /* Get the non Underscored string */ for (i = 0; i < ntapiline; i++ ) { if (tapilinetab[i].kwval == y) { s = tapilinetab[i].kwd; break; } } } else xxtapi = 0; } #endif /* CK_TAPI */ #else /* NT */ /* not OS/2 SLIP or PPP */ xxslip = xxppp = 0; #endif /* NT */ } ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Copy to a safe place */ s = tmpbuf; if ((x = cmcfm()) < 0) return(x); #else /* !OS2 */ cmfdbi(&sw,_CMKEY,"Device name, or switch", "","",npsltab,4,xxstring,psltab,&tx); cmfdbi(&tx,_CMTXT,"",dftty,"",0,0,xxstring,NULL,NULL); while (!confirmed) { x = cmfdb(&sw); debug(F101,"setlin cmfdb","",x); if (x < 0) if (x != -3) return(x); if (x == -3) { if ((x = cmcfm()) < 0) { return(x); } else { confirmed = 1; break; } } switch (cmresult.fcode) { case _CMTXT: ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ); s = tmpbuf; debug(F110,"setlin CMTXT",tmpbuf,0); confirmed = 1; break; case _CMKEY: /* Switch */ debug(F101,"setlin CMKEY",tmpbuf,cmresult.nresult); switch (cmresult.nresult) { case SL_CNX: /* /CONNECT */ cx = 1; sx = 0; break; case SL_SRV: /* /SERVER */ cx = 0; sx = 1; break; #ifdef VMS case SL_SHR: /* /SHARE */ shr = 1; break; case SL_NSH: /* /NOSHARE */ shr = 0; break; #endif /* VMS */ } continue; default: debug(F101,"setlin bad cmfdb result","",cmresult.fcode); makestr(&slmsg,"Internal error"); printf("?Internal parsing error\n"); return(-9); } } #endif /* OS2 */ if (!confirmed) if ((x = cmcfm()) < 0) return(x); debug(F110,"setlin pre-cx_serial s",s,0); debug(F110,"setlin pre-cx_serial line",line,0); x = cx_serial(s,cx,sx,shr,zz,0, #ifdef OS2 #ifdef NT (xxtapi ? CX_TAPI : 0) #else (xxslip ? CX_SLIP : 0) | (xxppp ? CX_PPP : 0) #endif /* NT */ #else /* OS2 */ 0 #endif /* OS2 */ ); debug(F111,"setlin cx_serial",line,x); return(x); } #endif /* NOLOCAL */ #ifdef CKCHANNELIO /* C-Library based file-i/o package for scripts. This should be portable to all C-Kermit versions since it uses the same APIs we have always used for processing command files. The entire channel i/o package is contained herein, apart from some keyword table entries in the main keyword table and the help text in the HELP command module. On platforms like VMS and VOS, this package handles only UNIX-style stream files. If desired, it can be replaced for those platforms by <#>ifdef'ing out this code and adding the equivalent replacement routines to the ck?fio.c module, e.g. for RMS-based file i/o in ckvfio.c. */ #ifndef NOSTAT #ifdef VMS /* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */ #include #else /* def VMS */ #include #endif /* def VMS [else] */ #endif /* NOSTAT */ #ifdef NLCHAR static int z_lt = 1; /* Length of line terminator */ #else static int z_lt = 2; #endif /* NLCHAR */ struct ckz_file { /* C-Kermit file struct */ FILE * z_fp; /* Includes the C-Lib file struct */ unsigned int z_flags; /* Plus C-Kermit mode flags, */ CK_OFF_T z_nline; /* current line number if known, */ char z_name[CKMAXPATH+2]; /* and the file's name. */ }; static struct ckz_file ** z_file = NULL; /* Array of C-Kermit file structs */ static int z_inited = 0; /* Flag for array initialized */ int z_maxchan = Z_MAXCHAN; /* Max number of C-Kermit channels */ int z_openmax = CKMAXOPEN; /* Max number of open files overall */ int z_nopen = 0; /* How many channels presently open */ int z_error = 0; /* Most recent error */ int z_filcount = -1; /* Most recent FILE COUNT result */ #define RD_LINE 0 /* FILE READ options */ #define RD_CHAR 1 #define RD_SIZE 2 #define RD_TRIM 8 /* Like Snobol &TRIM = 1 */ #define RD_UNTA 9 /* Untabify */ #define WR_LINE RD_LINE /* FILE WRITE options */ #define WR_CHAR RD_CHAR #define WR_SIZE RD_SIZE #define WR_STRI 3 #define WR_LPAD 4 #define WR_RPAD 5 #ifdef UNIX extern int ckmaxfiles; /* Filled in by sysinit(). */ #endif /* UNIX */ /* See ckcker.h for error numbers */ /* See ckcdeb.h for Z_MAXCHAN and CKMAXOPEN definitions */ /* NOTE: For VMS we might be able to fill in ckmaxfiles */ /* from FILLM and CHANNELCNT -- find out about these... */ static char * fopnargs[] = { /* Mode combinations for fopen() */ #ifdef COMMENT /* All combinations of rwa */ "", "r", "w", "rw", "a", "ra", "wa", "rwa", /* Text mode */ "b", "rb", "wb", "rwb", "ab", "rab", "wab", "rwab" /* Binary mode */ #else /* Combinations and syntax permitted by C libraries... */ "", "r", "w", "r+", "a", "", "a", "", /* Text mode */ #ifdef OS2 "", "rb", "wb", "r+b", "ab", "", "ab", "" /* Binary modes for K95 */ #else #ifdef VMS "", "rb", "wb", "r+b", "ab", "", "ab", "" /* Binary modes for VMS */ #else "", "r", "w", "r+", "a", "", "a", "" /* Binary modes for UNIX */ #endif /* VMS */ #endif /* OS2 */ #endif /* COMMENT */ }; static int nfopnargs = sizeof(fopnargs) / sizeof(char *); char * /* Error messages */ #ifdef CK_ANSIC #else #endif /* CK_ANSIC */ #ifdef CK_ANSIC ckferror( int n ) #else ckferror(n) int n; #endif /* CK_ANSIC */ { switch (n) { case FX_NER: return("No error"); case FX_SYS: return(ck_errstr()); case FX_EOF: return("End of file"); case FX_NOP: return("File not open"); case FX_CHN: return("Channel out of range"); case FX_RNG: return("Parameter out of range"); case FX_NMF: return("Too many files open"); case FX_FOP: return("Operation conflicts with OPEN mode"); case FX_NYI: return("OPEN mode not supported"); case FX_BOM: return("Illegal combination of OPEN modes"); case FX_ACC: return("Access denied"); case FX_FNF: return("File not found"); case FX_OFL: return("Buffer overflow"); case FX_LNU: return("Current line number unknown"); case FX_ROO: return("Off limits"); case FX_UNK: return("Operation fails - reason unknown"); default: return("Error number out of range"); } } /* Z _ O P E N -- Open a file for the requested type of access. Call with: name: Name of file to be opened. flags: Any combination of FM_xxx values except FM_EOF (ckcker.h). Returns: >= 0 on success: The assigned channel number < 0 on failure: A negative FX_xxx error code (ckcker.h). */ int #ifdef CK_ANSIC z_open( char * name, int flags ) #else z_open(name, flags) char * name; int flags; #endif /* CK_ANSIC */ { int i, n; FILE * t; char * mode; #ifdef NT char * modetemp; int modelen; #endif debug(F111,"z_open",name,flags); if (!name) name = ""; /* Check name argument */ if (!name[0]) return(z_error = FX_BFN); if (flags & FM_CMD) /* Opening pipes not implemented yet */ return(z_error = FX_NYI); /* (and not portable either) */ debug(F101,"z_open nfopnargs","",nfopnargs); if (flags & FM_STDIN) { /* Read from standard input */ mode = "r"; } else if (flags & (FM_STDOUT|FM_STDERR)) { mode = "w"; } else { /* If regular file, not stdin.. */ if (flags < 0 || flags >= nfopnargs) /* Range check flags */ return(z_error = FX_RNG); mode = fopnargs[flags]; /* Get fopen() arg */ debug(F111,"z_open fopen args",mode,flags); if (!mode[0]) /* Check for illegal combinations */ return(z_error = FX_BOM); } #ifdef NT /* * Take a copy of the mode string and append the 'S' sequential read file * caching hint (_O_SEQUENTIAL). We'll free this copy after the call to * fopen later. */ modetemp = mode; mode = malloc(10); ckmakmsg(mode, 10, modetemp, "S", NULL, NULL); #endif /* NT */ if (!z_inited) { /* If file structs not inited */ debug(F101,"z_open z_maxchan 1","",z_maxchan); #ifdef UNIX debug(F101,"z_open ckmaxfiles","",ckmaxfiles); if (ckmaxfiles > 0) { /* Set in ck?tio.c: sysinit() */ int x; x = ckmaxfiles - ZNFILS - 5; if (x > z_maxchan) /* sysconf() value greater than */ z_maxchan = x; /* value from header files. */ debug(F101,"z_open z_maxchan 2","",z_maxchan); } #endif /* UNIX */ if (z_maxchan < Z_MINCHAN) /* Allocate at least this many. */ z_maxchan = Z_MINCHAN; debug(F101,"z_open z_maxchan 3","",z_maxchan); /* Note: This could be a pretty big chunk of memory */ /* if z_maxchan is a big number. If this becomes a problem */ /* we'll need to malloc and free each element at open/close time */ #ifdef COMMENT /* May 2006 - it's time - in current Linux this about 3MB */ if (!(z_file = (struct ckz_file *) malloc(sizeof(struct ckz_file) * (z_maxchan + 1)))) return(z_error = FX_NMF); for (i = 0; i < z_maxchan; i++) { z_file[i].z_fp = NULL; z_file[i].z_flags = 0; z_file[i].z_nline = 0; *(z_file[i].z_name) = '\0'; } #else /* New economical way, allocate storage for each channel as needed */ if (!z_file) { debug(F100,"z_file[] is NULL","",0); debug(F101,"sizeof(struct ckz_file *)","", sizeof(struct ckz_file *)); z_file = (struct ckz_file **)malloc((z_maxchan + 1) * sizeof(struct ckz_file *)); debug(F101,"z_open z_maxchan 4","",z_maxchan); if (!z_file) return(z_error = FX_NMF); for (i = 0; i < z_maxchan; i++) z_file[i] = NULL; debug(F101,"z_open z_maxchan 5","",z_maxchan); } #endif /* COMMENT */ debug(F101,"z_open z_maxchan 6","",z_maxchan); z_inited = 1; /* Remember we initialized */ } for (n = -1, i = 0; i < z_maxchan; i++) { /* Find a free channel */ #ifdef COMMENT if (!z_file[i].z_fp) { n = i; break; } #else debug(F101,"z_open find-free-channel loop","",i); if (!z_file[i]) { z_file[i] = (struct ckz_file *) malloc(sizeof(struct ckz_file)); if (!z_file[i]) return(z_error = FX_NMF); n = i; break; } #endif /* COMMENT */ } debug(F101,"z_open found free channel","",n); if (n < 0 || n >= z_maxchan) /* Any free channels? */ return(z_error = FX_NMF); /* No, fail. */ debug(F100,"z_open check n ok","",0); errno = 0; debug(F100,"z_open errno ok","",0); z_file[n]->z_flags = 0; /* In case of failure... */ debug(F100,"z_open z_file[n] flags ok","",0); z_file[n]->z_fp = NULL; /* Set file pointer to NULL */ debug(F100,"z_open z_file[n] fps ok","",0); #ifdef UNIX if (flags & FM_STDIN) { /* Standard input */ t = (FILE *)stdin; /* We just use the ready-made stream */ z_nopen++; /* Count it. */ z_file[n]->z_fp = t; /* Stash the file pointer */ z_file[n]->z_flags = flags; /* and the flags */ z_file[n]->z_nline = 0; /* Current line number is 0 */ ckstrncpy(z_file[n]->z_name,name,CKMAXPATH); /* "filename" */ z_error = 0; /* No error so far */ return(n); /* Return the channel number */ } if (flags & FM_STDOUT) { /* Standard output */ t = (FILE *)stdout; /* Same deal */ z_nopen++; z_file[n]->z_fp = t; z_file[n]->z_flags = flags; z_file[n]->z_nline = 0; ckstrncpy(z_file[n]->z_name,name,CKMAXPATH); z_error = 0; return(n); } if (flags & FM_STDERR) { /* Standard error */ t = (FILE *)stderr; z_nopen++; z_file[n]->z_fp = t; z_file[n]->z_flags = flags; z_file[n]->z_nline = 0; ckstrncpy(z_file[n]->z_name,name,CKMAXPATH); z_error = 0; return(n); } #endif /* UNIX */ t = fopen(name, mode); /* Try to open the file. */ #ifdef NT free(mode); /* This is a copy of the original mode string */ #endif /* NT */ if (!t) { /* Failed... */ debug(F111,"z_open error",name,errno); #ifdef EMFILE if (errno == EMFILE) return(z_error = FX_NMF); #endif /* EMFILE */ free(z_file[n]); z_file[n] = NULL; return(z_error = (errno ? FX_SYS : FX_UNK)); /* Return error code */ } #ifdef COMMENT /* * 2024-08-19 DavidG: This started crashing on Windows 11 in CKW Beta 6. The * call to setmode seems ok, it just doesn't like O_SEQUENTIAL anymore. Not * sure if this is something unsupported now, or if its a bug in the CRT. * For some reason I've not looked into too closely I'm not even getting * O_SEQUENTIAL defined on my local PC, while its clearly there on the * Gitub build agents. */ #ifdef NT #ifdef O_SEQUENTIAL if (t) /* Caching hint for NT */ _setmode(_fileno(t),O_SEQUENTIAL); #endif /* O_SEQUENTIAL */ #endif /* NT */ #endif /* COMMENT */ z_nopen++; /* Open, count it. */ z_file[n]->z_fp = t; /* Stash the file pointer */ z_file[n]->z_flags = flags; /* and the flags */ z_file[n]->z_nline = 0; /* Current line number is 0 */ z_error = 0; zfnqfp(name,CKMAXPATH,z_file[n]->z_name); /* and the file's full name */ return(n); /* Return the channel number */ } int #ifdef CK_ANSIC z_close( int channel ) /* Close file on given channel */ #else z_close(channel) int channel; #endif /* CK_ANSIC */ { int x; FILE * t; if (!z_inited) /* Called before any files are open? */ return(z_error = FX_NOP); if (channel >= z_maxchan) /* Channel out of range? */ return(z_error = FX_CHN); if (!z_file[channel]) return(z_error = FX_NOP); if (!(t = z_file[channel]->z_fp)) /* Channel wasn't open? */ return(z_error = FX_NOP); errno = 0; /* Set errno 0 to get a good reading */ if (!(z_file[channel]->z_flags & FM_STDM)) /* If not stdin/out/err... */ x = fclose(t); /* Try to close */ if (x == EOF) /* On failure */ return(z_error = FX_SYS); /* indicate system error. */ z_nopen--; /* Closed OK, decrement open count */ z_file[channel]->z_fp = NULL; /* Set file pointer to NULL */ z_file[channel]->z_nline = 0; /* Current line number is 0 */ z_file[channel]->z_flags = 0; /* Set flags to 0 */ *(z_file[channel]->z_name) = '\0'; /* Clear name */ free(z_file[channel]); z_file[channel] = NULL; return(z_error = 0); } /* Z _ O U T -- Output string to channel. Call with: channel: Channel number to write to. s: String to write. length > -1: How many characters of s to write. length < 0: Write entire NUL-terminated string. flags == 0: Supply line termination. flags > 0: Don't supply line termination. flags < 0: Write 'length' NUL characters. Special case: If flags > -1 and s is empty or NULL and length == 1, write 1 NUL. Returns: Number of characters written to channel on success, or negative FX_xxx error code on failure. */ int #ifdef CK_ANSIC z_out( int channel, char * s, int length, int flags ) #else z_out(channel,s,length,flags) int channel, flags, length; char * s; #endif /* CK_ANSIC */ { FILE * t; int x, n; char c = '\0'; if (!s) s = ""; /* Guard against null pointer */ #ifdef DEBUG if (deblog) { debug(F111,"z_out",s,channel); debug(F101,"z_out length","",length); debug(F101,"z_out flags","",flags); } #endif /* DEBUG */ if (!z_inited) /* File i/o inited? */ return(z_error = FX_NOP); if (channel >= z_maxchan) /* Channel in range? */ return(z_error = FX_CHN); if (!z_file[channel]) return(z_error = FX_NOP); if (!(t = z_file[channel]->z_fp)) /* File open? */ return(z_error = FX_NOP); if (!((z_file[channel]->z_flags) & (FM_WRI|FM_APP))) /* In write mode? */ return(z_error = FX_FOP); n = length; /* Length of string to write */ if (n < 0) { /* Negative means get it ourselves */ if (flags < 0) /* Except when told to write NULs in */ return(z_error = FX_RNG); /* which case args are inconsistent */ n = strlen(s); /* Get length of string arg */ } errno = 0; /* Reset errno */ debug(F101,"z_out n","",n); if (flags < 0) { /* Writing NULs... */ int i; for (i = 0; i < n; i++) { x = fwrite(&c,1,1,t); if (x < 1) return(z_error = (errno ? FX_SYS : FX_UNK)); } z_file[channel]->z_nline = -1; /* Current line no longer known */ z_error = 0; return(i); } else { /* Writing string arg */ if (n == 1 && !s[0]) /* Writing one char but it's NUL */ x = fwrite(&c,1,1,t); else /* Writing non-NUL char or string */ x = fwrite(s,1,n,t); debug(F101,"z_out fwrite",ckitoa(x),errno); if (x < n) /* Failure to write requested amount */ return(z_error = (errno ? FX_SYS : FX_UNK)); /* Return error */ if (flags == 0) { /* If supplying line termination */ if (fwrite("\n",1,1,t)) /* do that */ x += z_lt; /* count the terminator */ if (z_file[channel]->z_nline > -1) /* count this line */ z_file[channel]->z_nline++; } else { z_file[channel]->z_nline = -1; /* Current line no longer known */ } } z_error = 0; return(x); } #define Z_INBUFLEN 64 /* Z _ I N -- Multichannel i/o file input function. Call with: channel number to read from. s = address of destination buffer. buflen = destination buffer length. length = Number of bytes to read, must be < buflen. flags: 0 = read a line; nonzero = read the given number of bytes. Returns: Number of bytes read into buffer or a negative error code. A terminating NUL is deposited after the last byte that was read. */ int #ifdef CK_ANSIC z_in( int channel, char * s, int buflen, int length, int flags ) #else z_in(channel,s,buflen,length,flags) int channel, buflen, length, flags; char * s; #endif /* CK_ANSIC */ { int i, x; FILE * t; if (!z_inited) /* Check everything... */ return(z_error = FX_NOP); if (channel >= z_maxchan) return(z_error = FX_CHN); if (channel < 0) return(z_error = FX_CHN); if (!z_file[channel]) return(z_error = FX_NOP); if (!(t = z_file[channel]->z_fp)) return(z_error = FX_NOP); if (!((z_file[channel]->z_flags) & FM_REA)) return(z_error = FX_FOP); if (!s) /* Check destination */ return(z_error = FX_RNG); s[0] = NUL; if (length == 0) /* Read 0 bytes - easy. */ return(z_error = 0); debug(F101,"z_in channel","",channel); debug(F101,"z_in buflen","",buflen); debug(F101,"z_in length","",length); debug(F101,"z_in flags","",flags); if (length < 0 || buflen < 0) /* Check length args */ return(z_error = FX_RNG); if (buflen <= length) return(z_error = FX_RNG); errno = 0; /* Reset errno */ if (flags) { /* Read block or byte */ int n; /* 20050912 */ n = length; /* 20050912 */ i = 0; /* 20050912 */ while (n > 0) { /* 20050912 */ i = fread(s,1,n,t); /* 20050912 */ #ifdef DEBUG if (deblog) { debug(F111,"z_in block",s,i); debug(F101,"z_in block errno","",errno); debug(F101,"z_in block ferror","",ferror(t)); debug(F101,"z_in block feof","",feof(t)); } #endif /* DEBUG */ if (i == 0) break; /* 20050912 */ s += i; /* 20050912 */ n -= i; /* 20050912 */ } /* Current line no longer known */ z_file[channel]->z_nline = (CK_OFF_T)-1; } else { /* Read line */ #ifndef COMMENT /* This method is used because it's simpler than the others */ /* and also marginally faster. */ debug(F101,"z_in getc loop","",CKFTELL(t)); for (i = 0; i < length; i++) { if ((x = getc(t)) == EOF) { debug(F101,"z_in getc error","",CKFTELL(t)); s[i] = '\0'; break; } s[i] = x; if (s[i] == '\n') { s[i] = '\0'; break; } } debug(F111,"z_in line byte loop",ckitoa(errno),i); debug(F111,"z_in line got",s,z_file[channel]->z_nline); if (z_file[channel]->z_nline > -1) z_file[channel]->z_nline++; #else #ifdef COMMENT2 /* Straightforward but strlen() slows it down. */ s[0] = '\0'; i = 0; if (fgets(s,length,t)) { i = strlen(s); if (i > 0 && s[i-1] == '\n') i--; } debug(F111,"z_in line fgets",ckitoa(errno),i); if (z_file[channel]->z_nline > -1) z_file[channel]->z_nline++; #else /* This is a do-it-yourself fgets() with its own readahead and */ /* putback. It's a bit faster than real fgets() but not enough */ /* to justify the added complexity or the risk of the ftell() and */ /* fseek() calls failing. */ int j, k, flag = 0; CK_OFF_T pos; for (i = 0; !flag && i <= (length - Z_INBUFLEN); i += Z_INBUFLEN) { k = ((length - i) < Z_INBUFLEN) ? length - i : Z_INBUFLEN; if ((x = fread(s+i,1,k,t)) < 1) break; s[i+x] = '\0'; for (j = 0; j < x; j++) { if (s[i+j] == '\n') { s[i+j] = '\0'; flag ++; pos = CKFTELL(t); if (pos > -1) { pos -= (x - j - 1); x = CKFSEEK(t, pos, 0); i += j; break; } else return(z_error = FX_SYS); } } } if (z_file[channel]->z_nline > -1) z_file[channel]->z_nline++; debug(F111,"z_in line chunk loop",ckitoa(errno),i); #endif /* COMMENT2 */ #endif /* COMMENT */ } debug(F111,"z_in i",ckitoa(errno),i); if (i < 0) i = 0; /* NUL-terminate result */ s[i] = '\0'; if (i > 0) { z_error = 0; return(i); } if (i == 0 && feof(t)) /* EOF on reading? */ return(z_error = FX_EOF); /* Return EOF code */ return(errno ? (z_error = -1) : i); /* Return length or system error */ } int #ifdef CK_ANSIC z_flush( int channel ) /* Flush output channel */ #else z_flush(channel) int channel; #endif /* CK_ANSIC */ { FILE * t; int x; if (!z_inited) /* Regular checks */ return(z_error = FX_NOP); if (channel >= z_maxchan) return(z_error = FX_CHN); if (!z_file[channel]) return(z_error = FX_NOP); if (!(t = z_file[channel]->z_fp)) return(z_error = FX_NOP); if (!((z_file[channel]->z_flags) & (FM_WRI|FM_APP))) /* Write access? */ return(z_error = FX_FOP); errno = 0; /* Reset errno */ x = fflush(t); /* Try to flush */ return(x ? (z_error = FX_SYS) : 0); /* Return system error or 0 if OK */ } int #ifdef CK_ANSIC z_seek(int channel, CK_OFF_T pos) /* Move file pointer to byte */ #else z_seek(channel,pos) int channel; CK_OFF_T pos; /* (seek to given position) */ #endif /* CK_ANSIC */ { int x = 0, rc; FILE * t; if (!z_inited) /* Check... */ return(z_error = FX_NOP); if (channel >= z_maxchan) return(z_error = FX_CHN); if (!z_file[channel]) return(z_error = FX_NOP); if (!(t = z_file[channel]->z_fp)) return(z_error = FX_NOP); if (pos < 0L) { x = 2; pos = (pos == -2) ? -1L : 0L; } errno = 0; rc = CKFSEEK(t,pos,x); /* Try to seek */ debug(F111,"z_seek",ckitoa(errno),rc); if (rc < 0) /* OK? */ return(z_error = FX_SYS); /* No. */ z_file[channel]->z_nline = ((pos || x) ? -1 : 0); return(z_error = 0); } int #ifdef CK_ANSIC z_line(int channel, CK_OFF_T pos) /* Move file pointer to line */ #else z_line(channel,pos) int channel; CK_OFF_T pos; /* (seek to given position) */ #endif /* CK_ANSIC */ { int len, x = 0; CK_OFF_T current = (CK_OFF_T)0, prev = (CK_OFF_T)-1, old = (CK_OFF_T)-1; FILE * t; char tmpbuf[256]; if (!z_inited) /* Check... */ return(z_error = FX_NOP); if (channel >= z_maxchan) return(z_error = FX_CHN); if (!z_file[channel]) return(z_error = FX_NOP); if (!(t = z_file[channel]->z_fp)) return(z_error = FX_NOP); debug(F101,"z_line pos","",pos); if (pos < 0L) { /* EOF wanted */ CK_OFF_T n; n = z_file[channel]->z_nline; debug(F101,"z_line n","",n); if (n < 0 || pos < 0) { rewind(t); n = 0; } while (1) { /* This could take a while... */ if ((x = getc(t)) == EOF) break; if (x == '\n') { n++; if (pos == -2) { old = prev; prev = CKFTELL(t); } } } debug(F101,"z_line old","",old); debug(F101,"z_line prev","",prev); if (pos == -2) { if ((x = z_seek(channel,old)) < 0) return(z_error = x); else n--; } z_file[channel]->z_nline = n; return(z_error = 0); } if (pos == 0L) { /* Rewind wanted */ z_file[channel]->z_nline = 0L; rewind(t); debug(F100,"z_line rewind","",0); return(0L); } tmpbuf[255] = NUL; /* Make sure buf is NUL terminated */ current = z_file[channel]->z_nline; /* Current line */ /* If necessary the following could be optimized, e.g. for positioning to a previous line in a large file without starting over. */ if (current < 0 || pos < current) { /* Not known or behind us... */ debug(F101,"z_line rewinding","",pos); if ((x = z_seek(channel, 0L)) < 0) /* Rewind */ return(z_error = x); if (pos == 0) /* If 0th line wanted we're done */ return(z_error = 0); current = 0; } while (current < pos) { /* Search for specified line */ if (fgets(tmpbuf,255,t)) { len = strlen(tmpbuf); if (len > 0 && tmpbuf[len-1] == '\n') { current++; debug(F111,"z_line read",ckitoa(len),current); } else if (len == 0) { return(z_error = FX_UNK); } } else { z_file[channel]->z_nline = -1L; debug(F101,"z_line premature EOF","",current); return(z_error = FX_EOF); } } z_file[channel]->z_nline = current; debug(F101,"z_line result","",current); z_error = 0; return(current); } char * #ifdef CK_ANSIC z_getname( int channel ) /* Return name of file on channel */ #else z_getname(channel) int channel; #endif /* CK_ANSIC */ { FILE * t; if (!z_inited) { z_error = FX_NOP; return(NULL); } if (channel >= z_maxchan) { z_error = FX_CHN; return(NULL); } if (!z_file[channel]) { z_error = FX_NOP; return(NULL); } if (!(t = z_file[channel]->z_fp)) { z_error = FX_NOP; return(NULL); } return((char *)(z_file[channel]->z_name)); } int #ifdef CK_ANSIC z_getmode( int channel ) /* Return OPEN modes of channel */ #else z_getmode(channel) int channel; #endif /* CK_ANSIC */ { FILE * t; /* 0 if file not open */ #ifndef NOSTAT #ifdef NT struct _stat statbuf; #else /* NT */ struct stat statbuf; #endif /* NT */ #endif /* NOSTAT */ int x; if (!z_inited) return(0); if (channel >= z_maxchan) return(z_error = FX_CHN); if (!z_file[channel]) return(0); if (!(t = z_file[channel]->z_fp)) return(0); x = z_file[channel]->z_flags; if (feof(t)) { /* This might not work for */ x |= FM_EOF; /* output files */ #ifndef NOSTAT /* But this does if we can use it. */ } else if (stat(z_file[channel]->z_name,&statbuf) > -1) { if (CKFTELL(t) == statbuf.st_size) x |= FM_EOF; #endif /* NOSTAT */ } return(x); } CK_OFF_T #ifdef CK_ANSIC z_getpos( int channel ) #else z_getpos(channel) int channel; #endif /* CK_ANSIC */ { /* Get file pointer position on this channel */ FILE * t; CK_OFF_T x; if (!z_inited) return(z_error = FX_NOP); if (channel >= z_maxchan) return(z_error = FX_CHN); if (!z_file[channel]) return(z_error = FX_NOP); if (!(t = z_file[channel]->z_fp)) return(z_error = FX_NOP); x = CKFTELL(t); return((x < 0L) ? (z_error = FX_SYS) : x); } CK_OFF_T #ifdef CK_ANSIC z_getline( int channel ) #else z_getline(channel) int channel; #endif /* CK_ANSIC */ { /* Get current line number in file on this channel */ FILE * t; CK_OFF_T rc; if (!z_inited) return(z_error = FX_NOP); if (channel >= z_maxchan) return(z_error = FX_CHN); if (!z_file[channel]) return(z_error = FX_NOP); if (!(t = z_file[channel]->z_fp)) return(z_error = FX_NOP); debug(F101,"z_getline","",z_file[channel]->z_nline); rc = z_file[channel]->z_nline; return((rc < 0) ? (z_error = FX_LNU) : rc); } int #ifdef CK_ANSIC z_getfnum( int channel ) #else z_getfnum(channel) int channel; #endif /* CK_ANSIC */ { /* Get file number / handle for file on this channel */ FILE * t; if (!z_inited) return(z_error = FX_NOP); if (channel >= z_maxchan) return(z_error = FX_CHN); if (!z_file[channel]) return(z_error = FX_NOP); if (!(t = z_file[channel]->z_fp)) return(z_error = FX_NOP); z_error = 0; return(fileno(t)); } /* Line-oriented counts and seeks are as dumb as they can be at the moment. Later we can speed them up by building little indexes. */ CK_OFF_T #ifdef CK_ANSIC z_count( int channel, int what ) #else z_count(channel, what) int channel, what; #endif /* CK_ANSIC */ { /* Count bytes or lines in file */ FILE * t; int x; CK_OFF_T pos, count = (CK_OFF_T)0; if (!z_inited) /* Check stuff... */ return(z_error = FX_NOP); if (channel >= z_maxchan) return(z_error = FX_CHN); if (!z_file[channel]) return(z_error = FX_NOP); if (!(t = z_file[channel]->z_fp)) return(z_error = FX_NOP); pos = CKFTELL(t); /* Save current file pointer */ errno = 0; z_error = 0; if (what == RD_CHAR) { /* Size in bytes requested */ #ifdef COMMENT if (!CKFSEEK(t,0L,2)) { /* Seek to end */ count = CKFTELL(t); /* Get file pointer */ CKFSEEK(t,pos,0); /* Restore file file pointer */ return(count); } else /* Fallback in case seek fails */ #endif /* COMMENT */ return(zgetfs(z_file[channel]->z_name)); } rewind(t); /* Line count requested - rewind. */ while (1) { /* Count lines. */ if ((x = getc(t)) == EOF) /* Stupid byte loop */ break; /* but it works as well as anything */ if (x == '\n') /* else... */ count++; } x = CKFSEEK(t,pos,0); /* Restore file pointer */ return(count); } /* User interface for generalized channel-oriented file i/o */ struct keytab fctab[] = { /* FILE subcommands */ { "close", FIL_CLS, 0 }, { "count", FIL_COU, 0 }, { "flush", FIL_FLU, 0 }, { "list", FIL_LIS, 0 }, { "open", FIL_OPN, 0 }, { "read", FIL_REA, 0 }, { "rewind", FIL_REW, 0 }, { "seek", FIL_SEE, 0 }, { "status", FIL_STA, 0 }, { "write", FIL_WRI, 0 } }; int nfctab = (sizeof (fctab) / sizeof (struct keytab)); static struct keytab fcswtab[] = { /* OPEN modes */ { "/append", FM_APP, 0 }, { "/binary", FM_BIN, 0 }, #ifdef COMMENT { "/command", FM_CMD, 0 }, /* Not implemented */ #endif /* COMMENT */ { "/read", FM_REA, 0 }, #ifdef UNIX /* Could be expanded to VMS etc.. */ { "/stderr", FM_STDERR,0 }, { "/stdin", FM_STDIN,0 }, { "/stdout", FM_STDOUT,0 }, #endif /* UNIX */ { "/write", FM_WRI, 0 } }; static int nfcswtab = (sizeof (fcswtab) / sizeof (struct keytab)); static struct keytab fclkwtab[] = { /* CLOSE options */ { "all", 1, 0 } }; static struct keytab fsekwtab[] = { /* SEEK symbols */ { "eof", 1, 0 }, { "last", 2, 0 } }; static int nfsekwtab = (sizeof (fsekwtab) / sizeof (struct keytab)); #define SEE_LINE RD_LINE /* SEEK options */ #define SEE_CHAR RD_CHAR #define SEE_REL 3 #define SEE_ABS 4 #define SEE_FIND 5 static struct keytab fskswtab[] = { { "/absolute", SEE_ABS, 0 }, { "/byte", SEE_CHAR, 0 }, { "/character", SEE_CHAR, CM_INV }, { "/find", SEE_FIND, CM_ARG }, { "/line", SEE_LINE, 0 }, { "/relative", SEE_REL, 0 } }; static int nfskswtab = (sizeof (fskswtab) / sizeof (struct keytab)); #define COU_LINE RD_LINE /* COUNT options */ #define COU_CHAR RD_CHAR #define COU_LIS 3 #define COU_NOL 4 static struct keytab fcoswtab[] = { { "/bytes", COU_CHAR, 0 }, { "/characters",COU_CHAR, CM_INV }, { "/lines", COU_LINE, 0 }, { "/list", COU_LIS, 0 }, { "/nolist", COU_NOL, 0 }, { "/quiet", COU_NOL, CM_INV } }; static int nfcoswtab = (sizeof (fcoswtab) / sizeof (struct keytab)); static struct keytab frdtab[] = { /* READ types */ { "/block", RD_SIZE, CM_INV|CM_ARG }, { "/byte", RD_CHAR, CM_INV }, { "/character", RD_CHAR, 0 }, { "/line", RD_LINE, 0 }, { "/size", RD_SIZE, CM_ARG }, { "/trim", RD_TRIM, 0 }, { "/untabify", RD_UNTA, 0 } }; static int nfrdtab = (sizeof (frdtab) / sizeof (struct keytab)); static struct keytab fwrtab[] = { /* WRITE types */ { "/block", WR_SIZE, CM_INV|CM_ARG }, { "/byte", WR_CHAR, CM_INV }, { "/character", WR_CHAR, 0 }, { "/line", WR_LINE, 0 }, { "/lpad", WR_LPAD, CM_ARG }, { "/rpad", WR_RPAD, CM_ARG }, { "/size", WR_SIZE, CM_ARG }, { "/string", WR_STRI, 0 } }; static int nfwrtab = (sizeof (fwrtab) / sizeof (struct keytab)); static char blanks[] = "\040\040\040\040"; /* Some blanks for formatting */ static char * seek_target = NULL; int #ifdef CK_ANSIC dofile( int op ) /* Do the FILE command */ #else dofile(op) int op; #endif /* CK_ANSIC */ { char vnambuf[VNAML]; /* Buffer for variable names */ char *vnp = NULL; /* Pointer to same */ char zfilnam[CKMAXPATH+2]; char * p, * m; struct FDB fl, sw, nu; CK_OFF_T z; int rsize, filmode = 0, relative = -1, eofflg = 0; int rc, x, y, cx, n, getval, dummy, confirmed, listing = -1; int charflag = 0, sizeflag = 0; int pad = 32, wr_lpad = 0, wr_rpad = 0, rd_trim = 0, rd_untab = 0; makestr(&seek_target,NULL); if (op == XXFILE) { /* FILE command was given */ /* Get subcommand */ if ((cx = cmkey(fctab,nfctab,"Operation","",xxstring)) < 0) { if (cx == -3) { printf("?File operation required\n"); x = -9; } return(cx); } } else { /* Shorthand command was given */ switch (op) { case XXF_CL: cx = FIL_CLS; break; /* FCLOSE */ case XXF_FL: cx = FIL_FLU; break; /* FFLUSH */ case XXF_LI: cx = FIL_LIS; break; /* FLIST */ case XXF_OP: cx = FIL_OPN; break; /* etc... */ case XXF_RE: cx = FIL_REA; break; case XXF_RW: cx = FIL_REW; break; case XXF_SE: cx = FIL_SEE; break; case XXF_ST: cx = FIL_STA; break; case XXF_WR: cx = FIL_WRI; break; case XXF_CO: cx = FIL_COU; break; default: return(-2); } } switch (cx) { /* Do requested subcommand */ case FIL_OPN: /* OPEN */ cmfdbi(&sw, /* Switches */ _CMKEY, /* fcode */ "Variable or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nfcswtab, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ fcswtab, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* Anything that doesn't match */ _CMFLD, /* fcode */ "Variable", /* hlpmsg */ "", "", 0, 0, NULL, NULL, NULL ); while (1) { x = cmfdb(&sw); /* Parse something */ if (x < 0) { if (x == -3) { printf("?Variable name and file name required\n"); x = -9; } return(x); } if (cmresult.fcode == _CMFLD) break; else if (cmresult.fcode == _CMKEY) { char c; c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } #ifdef COMMENT /* Uncomment if we add any FOPEN switches that take args */ if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); /* (none do...) */ } #endif /* COMMENT */ debug(F101,"filmode A","",filmode); filmode |= cmresult.nresult; /* OR in the file mode */ debug(F101,"filmode B","",filmode); debug(F101,"filmode & (FM_REA|FM_STDIN)","", filmode & (FM_REA|FM_STDIN)); debug(F101,"filmode & (FM_WRI|FM_STDOUT|FM_STDERR)","", filmode & (FM_WRI|FM_STDOUT|FM_STDERR)); if ((filmode & (FM_REA|FM_STDIN)) && (filmode & (FM_WRI|FM_STDOUT|FM_STDERR))) { printf("?Conflicting file modes\n"); return(-9); } } else return(-2); } /* Not a switch - get the string */ ckstrncpy(vnambuf,cmresult.sresult,VNAML); if (!vnambuf[0] || chknum(vnambuf)) { /* (if there is one...) */ printf("?Variable name required\n"); return(-9); } vnp = vnambuf; /* Check variable-name syntax */ if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++; y = 0; if (*vnp == '%' || *vnp == '&') { if ((y = parsevar(vnp,&x,&dummy)) < 0) { printf("?Syntax error in variable name\n"); return(-9); } } /* Assign a negative channel number in case we fail */ addmac(vnambuf,"-1"); if (!(filmode & FM_RWA)) /* If no access mode specified */ filmode |= FM_REA; /* default to /READ. */ #ifdef UNIX if (filmode & FM_STDIN) { /* If STDIN specified */ filmode |= FM_REA; /* it implies /READ */ /* We don't need to parse anything further */ s = "(stdin)"; goto xdofile; /* Skip around the following */ } if (filmode & FM_STDOUT) { /* If STDOUT specified */ filmode |= FM_WRI; /* it implies /WRITE */ /* We don't need to parse anything further */ s = "(stdout)"; goto xdofile; /* Skip around the following */ } if (filmode & FM_STDIN) { /* If STDIN specified */ filmode |= FM_WRI; /* it implies /WRITE */ /* We don't need to parse anything further */ s = "(stderr)"; goto xdofile; /* Skip around the following */ } #endif /* UNIX */ y = 0; /* Now parse the filename */ if ((filmode & FM_RWA) == FM_WRI) { x = cmofi("Name of new file","",&s,xxstring); } else if ((filmode & FM_RWA) == FM_REA) { x = cmifi("Name of existing file","",&s,&y,xxstring); } else { x = cmiofi("Filename","",&s,&y,xxstring); debug(F111,"fopen /append x",s,x); } if (x < 0) { if (x == -3) { printf("?Filename required\n"); x = -9; } return(x); } if (y) { /* No wildcards */ printf("?Wildcards not allowed here\n"); return(-9); } if (filmode & (FM_APP|FM_WRI)) { /* Check output access */ #ifndef VMS if (zchko(s) < 0) { /* and set error code if denied */ z_error = FX_ACC; printf("?Write access denied - \"%s\"\n",s); return(-9); } #endif /* VMS */ } #ifdef UNIX xdofile: #endif /* UNIX */ ckstrncpy(zfilnam,s,CKMAXPATH); /* Is OK - make safe copy */ if ((x = cmcfm()) < 0) /* Get confirmation of command */ return(x); if ((n = z_open(zfilnam,filmode)) < 0) { printf("?OPEN failed - %s: %s\n",zfilnam,ckferror(n)); return(-9); } addmac(vnambuf,ckitoa(n)); /* Assign channel number to variable */ return(success = 1); case FIL_REW: /* REWIND */ if ((x = cmnum("Channel number","",10,&n, xxstring)) < 0) { if (x == -3) { printf("?Channel number required\n"); x = -9; } return(x); } if ((x = cmcfm()) < 0) return(x); if (n == -9) return(success = 0); if (n == -8) return(success = 1); if ((rc = z_seek(n,0L)) < 0) { printf("?REWIND failed - Channel %d: %s\n",n,ckferror(rc)); return(-9); } return(success = 1); case FIL_CLS: /* CLOSE */ #ifdef COMMENT /* fdc 20100804 - bad idea */ { int i, j, k; /* Supply default if only one open */ s = ""; for (k = 0, j = 0, i = 0; i < z_maxchan; i++) { if (z_file) if (z_file[i]) if (z_file[i]->z_fp) { k++; j = i; } } if (k == 1) s = ckitoa(j); } #endif /* COMMENT */ cmfdbi(&nu, /* Second FDB - channel number */ _CMNUM, /* fcode */ "Channel number or ALL", /* Help message */ s, /* default */ "", /* addtl string data */ 10, /* addtl numeric data 1: radix */ 0, /* addtl numeric data 2: 0 */ xxstring, /* Processing function */ NULL, /* Keyword table */ &sw /* Pointer to next FDB */ ); /* Pointer to next FDB */ cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "", /* help message */ "", /* Default */ "", /* No addtl string data */ 1, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ fclkwtab, /* Keyword table */ NULL /* Last in chain */ ); x = cmfdb(&nu); /* Parse something */ if (x < 0) { if (x == -3) { printf("?Channel number or ALL required\n"); x = -9; } return(x); } if (cmresult.fcode == _CMNUM) n = cmresult.nresult; else if (cmresult.fcode == _CMKEY) n = -1; if ((x = cmcfm()) < 0) return(x); if (n == -9) return(success = 0); if (n == -8) return(success = 1); rc = 1; if (n < 0) { int count = 0; int i; for (i = 0; i < z_maxchan; i++) { x = z_close(i); if (x == FX_SYS) { printf("?CLOSE failed - Channel %d: %s\n",n,ckferror(x)); rc = 0; } else if (x > -1) count++; } debug(F101,"FILE CLOSE ALL","",count); } else if ((x = z_close(n)) < 0) { printf("?CLOSE failed - Channel %d: %s\n",n,ckferror(x)); return(-9); } return(success = rc); case FIL_REA: /* READ */ case FIL_WRI: /* WRITE */ rsize = 0; cmfdbi(&sw, /* Switches */ _CMKEY, /* fcode */ "Channel or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ (cx == FIL_REA) ? nfrdtab : nfwrtab, 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ (cx == FIL_REA) ? frdtab : fwrtab, /* Keyword table */ &nu /* Pointer to next FDB */ ); cmfdbi(&nu, /* Channel number */ _CMNUM, /* fcode */ "Channel", "", /* default */ "", /* addtl string data */ 10, /* addtl numeric data 1: radix */ 0, /* addtl numeric data 2: 0 */ xxstring, /* Processing function */ NULL, /* Keyword table */ NULL /* Pointer to next FDB */ ); do { x = cmfdb(&sw); /* Parse something */ if (x < 0) { if (x == -3) { printf("?Channel number required\n"); x = -9; } return(x); } if (cmresult.fcode == _CMNUM) /* Channel number */ break; else if (cmresult.fcode == _CMKEY) { /* Switch */ char c; c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } switch (cmresult.nresult) { case WR_LINE: charflag = 0; sizeflag = 0; rsize = 0; break; case WR_CHAR: rsize = 1; charflag = 1; sizeflag = 1; break; case WR_SIZE: if ((x = cmnum("Bytes","",10,&rsize, xxstring)) < 0) { if (x == -3) { printf("?Number required\n"); x = -9; } return(x); } if (rsize > LINBUFSIZ) { printf("?Maximum FREAD/FWRITE size is %d\n",LINBUFSIZ); rsize = 0; return(-9); } charflag = 0; sizeflag = 1; break; case WR_STRI: rsize = 1; charflag = 0; sizeflag = 0; break; case WR_LPAD: case WR_RPAD: if ((x = cmnum("Numeric ASCII character value", "32",10,&pad, xxstring)) < 0) return(x); if (cmresult.nresult == WR_LPAD) wr_lpad = 1; else wr_rpad = 1; break; case RD_TRIM: rd_trim = 1; break; case RD_UNTA: rd_untab = 1; break; } debug(F101,"FILE READ rsize 2","",rsize); } else return(-2); } while (cmresult.fcode == _CMKEY); n = cmresult.nresult; /* Channel */ debug(F101,"FILE READ/WRITE channel","",n); if (cx == FIL_WRI) { /* WRITE */ int len = 0; if ((x = cmtxt("Text","",&s,xxstring)) < 0) return(x); if (n == -9) return(success = 0); if (n == -8) return(success = 1); ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy */ s = line; s = brstrip(s); /* Strip braces */ if (charflag) { /* Write one char */ len = 1; /* So length = 1 */ rsize = 1; /* Don't supply terminator */ } else if (!sizeflag) { /* Write a string */ len = -1; /* So length is unspecified */ } else { /* Write a block of given size */ int i, xx; if (rsize > TMPBUFSIZ) { z_error = FX_OFL; printf("?Buffer overflow\n"); return(-9); } len = rsize; /* rsize is really length */ rsize = 1; /* Don't supply a terminator */ xx = strlen(s); /* Size of given string */ if (xx >= len) { /* Bigger or equal */ s[len] = NUL; } else if (wr_lpad) { /* Smaller, left-padding requested */ for (i = 0; i < len - xx; i++) /* Must make a copy */ tmpbuf[i] = pad; ckstrncpy(tmpbuf+i,s,TMPBUFSIZ-i); tmpbuf[len] = NUL; s = tmpbuf; /* Redirect write source */ } else if (wr_rpad) { /* Smaller with right-padding */ for (i = xx; i < len; i++) s[i] = pad; s[len] = NUL; } } if ((rc = z_out(n,s,len,rsize)) < 0) { /* Try to write */ printf("?Channel %d WRITE error: %s\n",n,ckferror(rc)); return(-9); } } else { /* FIL_REA READ */ confirmed = 0; vnambuf[0] = NUL; x = cmfld("Variable name","",&s,NULL); debug(F111,"FILE READ cmfld",s,x); if (x < 0) { if (x == -3 || !*s) { if ((x = cmcfm()) < 0) return(x); else confirmed++; } else return(x); } ckstrncpy(vnambuf,s,VNAML); debug(F111,"FILE READ vnambuf",vnambuf,confirmed); if (vnambuf[0]) { /* Variable name given, check it */ if (!confirmed) { x = cmcfm(); if (x < 0) return(x); else confirmed++; } vnp = vnambuf; if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++; y = 0; if (*vnp == '%' || *vnp == '&') { if ((y = parsevar(vnp,&x,&dummy)) < 0) { printf("?Syntax error in variable name\n"); return(-9); } } } debug(F111,"FILE READ variable",vnambuf,confirmed); if (!confirmed) if ((x = cmcfm()) < 0) return(x); if (n == -9) return(success = 0); if (n == -8) return(success = 1); line[0] = NUL; /* Clear destination buffer */ #ifdef COMMENT if (rsize >= LINBUFSIZ) /* Don't overrun it */ rsize = LINBUFSIZ - 1; #endif /* COMMENT */ if (rsize == 0) { /* Read a line */ rc = z_in(n,line,LINBUFSIZ,LINBUFSIZ-1,0); } else { rc = z_in(n,line,LINBUFSIZ,rsize,1); /* Read a block */ } if (rc < 0) { /* Error... */ debug(F101,"FILE READ error","",rc); debug(F101,"FILE READ errno","",errno); if (rc == FX_EOF) { /* EOF - fail but no error message */ return(success = 0); } else { /* Other error - fail and print msg */ printf("?READ error: %s\n",ckferror(rc)); return(-9); } } if (rsize == 0) { /* FREAD /LINE postprocessing */ if (rd_trim) { /* Trim */ int i, k; k = strlen(line); if (k > 0) { for (i = k-1; i > 0; i--) { if (line[i] == SP || line[i] == '\t') line[i] = NUL; else break; } } } if (rd_untab) { /* Untabify */ if (untabify(line,tmpbuf,TMPBUFSIZ) > -1) ckstrncpy(line,tmpbuf,LINBUFSIZ); } } debug(F110,"FILE READ data",line,0); if (vnambuf[0]) /* Read OK - If variable name given */ addmac(vnambuf,line); /* Assign result to variable */ else /* otherwise */ printf("%s\n",line); /* just print it */ } return(success = 1); case FIL_SEE: /* SEEK */ case FIL_COU: /* COUNT */ rsize = RD_CHAR; /* Defaults to /BYTE */ cmfdbi(&sw, /* Switches */ _CMKEY, /* fcode */ "Channel or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ ((cx == FIL_SEE) ? nfskswtab : nfcoswtab), 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ ((cx == FIL_SEE) ? fskswtab : fcoswtab), &nu /* Pointer to next FDB */ ); cmfdbi(&nu, /* Channel number */ _CMNUM, /* fcode */ "Channel", "", /* default */ "", /* addtl string data */ 10, /* addtl numeric data 1: radix */ 0, /* addtl numeric data 2: 0 */ xxstring, /* Processing function */ NULL, /* Keyword table */ NULL /* Pointer to next FDB */ ); do { x = cmfdb(&sw); /* Parse something */ if (x < 0) { if (x == -3) { printf("?Channel number required\n"); x = -9; } return(x); } if (cmresult.fcode == _CMNUM) /* Channel number */ break; else if (cmresult.fcode == _CMKEY) { /* Switch */ char c; c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } if (cx == FIL_SEE) { switch (cmresult.nresult) { case SEE_REL: relative = 1; break; case SEE_ABS: relative = 0; break; case SEE_FIND: { if (getval) { y = cmfld("string or pattern","",&s,xxstring); if (y < 0) return(y); makestr(&seek_target,brstrip(s)); break; } } default: rsize = cmresult.nresult; } } else if (cx == FIL_COU) { switch (cmresult.nresult) { case COU_LIS: listing = 1; break; case COU_NOL: listing = 0; break; default: rsize = cmresult.nresult; } } } } while (cmresult.fcode == _CMKEY); n = cmresult.nresult; /* Channel */ debug(F101,"FILE SEEK/COUNT channel","",n); if (cx == FIL_COU) { if ((x = cmcfm()) < 0) return(x); if (n == -9) return(success = 0); if (n == -8) return(success = 1); z_filcount = z_count(n,rsize); if (z_filcount < 0) { rc = z_filcount; printf("?COUNT error: %s\n",ckferror(rc)); return(-9); } if (listing < 0) listing = !xcmdsrc; if (listing) printf(" %d %s%s\n", z_filcount, ((rsize == RD_CHAR) ? "byte" : "line"), ((z_filcount == 1L) ? "" : "s") ); return(success = (z_filcount > -1) ? 1 : 0); } m = (rsize == RD_CHAR) ? "Number of bytes;\n or keyword" : "Number of lines;\n or keyword"; cmfdbi(&sw, /* SEEK symbolic targets (EOF) */ _CMKEY, /* fcode */ m, "", "", /* addtl string data */ nfsekwtab, /* addtl numeric data 1: table size */ 0, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ fsekwtab, /* Keyword table */ &nu /* Pointer to next FDB */ ); cmfdbi(&nu, /* Byte or line number */ _CMNUW, /* fcode */ "", "", /* default */ "", /* addtl string data */ 10, /* addtl numeric data 1: radix */ 0, /* addtl numeric data 2: 0 */ xxstring, /* Processing function */ NULL, /* Keyword table */ NULL /* Pointer to next FDB */ ); x = cmfdb(&sw); /* Parse something */ if (x < 0) { if (x == -3) { printf("?Channel number or EOF required\n"); x = -9; } return(x); } if (cmresult.fcode == _CMNUW) { z = cmresult.wresult; debug(F110,"FILE SEEK atmbuf",atmbuf,0); if (relative < 0) { if (cx == FIL_SEE && (atmbuf[0] == '+' || atmbuf[0] == '-')) relative = 1; else relative = 0; } } else if (cmresult.fcode == _CMKEY) { eofflg = cmresult.nresult; relative = 0; y = 0 - eofflg; } if ((x = cmcfm()) < 0) return(x); if (n == -9) return(success = 0); if (n == -8) return(success = 1); y = 1; /* Recycle this */ z_flush(n); debug(F101,"FILE SEEK relative","",relative); debug(F101,"FILE SEEK rsize","",rsize); if (rsize == RD_CHAR) { /* Seek to byte position */ if (relative > 0) { CK_OFF_T pos; pos = z_getpos(n); if (pos < (CK_OFF_T)0) { rc = pos; printf("?Relative SEEK failed: %s\n",ckferror(rc)); return(-9); } z += pos; } else { if (z < 0 && !eofflg) { /* Negative arg but not relative */ y = 0; /* Remember this was bad */ z = 0; /* but substitute 0 */ } } debug(F101,"FILE SEEK /CHAR z","",z); if (z < 0 && !eofflg) { z_error = FX_RNG; return(success = 0); } if ((rc = z_seek(n,z)) < 0) { if (rc == FX_EOF) return(success = 0); printf("?SEEK /BYTE failed - Channel %d: %s\n",n,ckferror(rc)); return(-9); } } else { /* Seek to line */ if (relative > 0) { CK_OFF_T pos; pos = z_getline(n); debug(F101,"FILE SEEK /LINE pos","",pos); if (pos < 0) { rc = pos; printf("?Relative SEEK failed: %s\n",ckferror(rc)); return(-9); } z += pos; } debug(F101,"FILE SEEK /LINE z","",z); debug(F101,"FILE SEEK /LINE eofflg","",eofflg); if (z < 0 && !eofflg) { z_error = FX_RNG; return(success = 0); } if ((rc = z_line(n,z)) < 0) { if (rc == FX_EOF) return(success = 0); printf("?SEEK /LINE failed - Channel %d: %s\n",n,ckferror(rc)); return(-9); } } /* Now, having sought to the desired starting spot, if a /FIND: target was specified, look for it now. */ if (seek_target) { int flag = 0, matchresult = 0; while (!flag) { y = z_in(n,line,LINBUFSIZ,LINBUFSIZ-1,0); if (y < 0) { y = 0; break; } if (ispattern(seek_target)) { matchresult = ckmatch(seek_target,line,inpcas[cmdlvl],1+4); } else { /* This is faster */ matchresult = ckindex(seek_target,line,0,0,inpcas[cmdlvl]); } if (matchresult) { flag = 1; break; } } if (flag) { debug(F111,"FSEEK HAVE MATCH",seek_target,z_getline(n)); /* Back up to beginning of line where target found */ if ((y = z_line(n,z_getline(n)-1)) < 0) { if (rc == FX_EOF) return(success = 0); printf("?SEEK /LINE failed - Channel %d: %s\n", n,ckferror(rc)); return(-9); } debug(F101,"FSEEK LINE","",y); } } return(success = (y < 0) ? 0 : 1); case FIL_LIS: { /* LIST open files */ #ifdef CK_TTGWSIZ extern int cmd_rows, cmd_cols; #endif /* CK_TTGWSIZ */ extern int xaskmore; int i, x, n = 0, paging = 0; char * s; if ((x = cmcfm()) < 0) return(x); #ifdef CK_TTGWSIZ if (cmd_rows > 0 && cmd_cols > 0) #endif /* CK_TTGWSIZ */ paging = xaskmore; printf("System open file limit:%5d\n", z_openmax); printf("Maximum for FILE OPEN: %5d\n", z_maxchan); printf("Files currently open: %5d\n\n", z_nopen); n = 4; for (i = 0; i < z_maxchan; i++) { s = z_getname(i); /* Got one? */ if (s) { /* Yes */ char m[8]; m[0] = NUL; printf("%2d. %s",i,s); /* Print name */ n++; /* Count it */ x = z_getmode(i); /* Get modes & print them */ if (x > 0) { if (x & FM_REA) ckstrncat(m,"R",8); if (x & FM_WRI) ckstrncat(m,"W",8); if (x & FM_APP) ckstrncat(m,"A",8); if (x & FM_BIN) ckstrncat(m,"B",8); if (m[0]) printf(" (%s)",m); if (x & FM_EOF) printf(" [EOF]"); else /* And file position too */ printf(" %s",ckfstoa(z_getpos(i))); } printf("\n"); #ifdef CK_TTGWSIZ if (paging > 0) { /* Pause at end of screen */ if (n > cmd_rows - 3) { if (!askmore()) break; else n = 0; } } #endif /* CK_TTGWSIZ */ } } return(success = 1); } case FIL_FLU: /* FLUSH */ if ((x = cmnum("Channel number","",10,&n, xxstring)) < 0) { if (x == -3) { printf("?Channel number required\n"); x = -9; } return(x); } if ((x = cmcfm()) < 0) return(x); if (n == -9) return(success = 0); if (n == -8) return(success = 1); if ((rc = z_flush(n)) < 0) { printf("?FLUSH failed - Channel %d: %s\n",n,ckferror(rc)); return(-9); } return(success = 1); case FIL_STA: /* STATUS */ { int i, j, k; /* Supply default if only one open */ s = ""; for (k = 0, j = 0, i = 0; i < z_maxchan; i++) { if (z_file) if (z_file[i]) if (z_file[i]->z_fp) { k++; j = i; } } if (k == 1) s = ckitoa(j); } if ((x = cmnum("Channel number",s,10,&n, xxstring)) < 0) { if (x == -3) { if (z_nopen > 1) { printf("?%d files open - please supply channel number\n", z_nopen); return(-9); } } else return(x); } if ((y = cmcfm()) < 0) return(y); if ((!z_file || z_nopen == 0) && x == -3) { printf("No files open\n"); return(success = 1); } p = blanks + 3; /* Tricky formatting... */ if (n < 1000) p--; if (n < 100) p--; if (n < 10) p--; if ((rc = z_getmode(n)) < 0) { printf("Channel %d:%s%s\n",n,p,ckferror(rc)); return(success = 0); } else if (!rc) { printf("Channel %d:%sNot open\n",n,p); return(success = 0); } else { CK_OFF_T xx; s = z_getname(n); if (!s) s = "(name unknown)"; printf("Channel %d:%sOpen\n",n,p); printf(" File: %s\n Modes: ",s); if (rc & FM_REA) printf(" /READ"); if (rc & FM_WRI) printf(" /WRITE"); if (rc & FM_APP) printf(" /APPEND"); if (rc & FM_BIN) printf(" /BINARY"); if (rc & FM_CMD) printf(" /COMMAND"); if (rc & FM_EOF) printf(" [EOF]"); printf("\n Size: %s\n",ckfstoa(z_count(n,RD_CHAR))); printf(" At byte: %s\n",ckfstoa(z_getpos(n))); xx = z_getline(n); if (xx > (CK_OFF_T)-1) printf(" At line: %s\n",ckfstoa(xx)); return(success = 1); } default: return(-2); } } #endif /* CKCHANNELIO */ #ifndef NOSETKEY /* Save Key maps and in OS/2 Mouse maps */ int #ifdef CK_ANSIC savkeys( char * name, int disp ) #else savkeys(name,disp) char * name; int disp; #endif /* CK_ANSIC */ { char *tp; static struct filinfo xx; int savfil, i, j, k; char buf[1024]; zclose(ZMFILE); if (disp) { xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0; xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = ""; xx.lblopts = 0; savfil = zopeno(ZMFILE,name,NULL,&xx); } else savfil = zopeno(ZMFILE,name,NULL,NULL); if (savfil) { #ifdef OS2 ztime(&tp); zsout(ZMFILE, "; Kermit 95 SAVE KEYMAP file: "); zsoutl(ZMFILE,tp); if (mskkeys) { zsoutl(ZMFILE, "if eq \"\\v(program)\" \"C-Kermit\" set mskermit keycodes on"); } else { zsoutl(ZMFILE, "if NOT eq \"\\v(program)\" \"C-Kermit\" stop 1 C-Kermit required."); zsoutl(ZMFILE,"set mskermit keycodes off"); } zsoutl(ZMFILE,""); #else /* OS2 */ ztime(&tp); zsout(ZMFILE, "; C-Kermit SAVE KEYMAP file: "); zsoutl(ZMFILE,tp); #endif /* OS2 */ zsoutl(ZMFILE,"; Clear previous keyboard mappings "); zsoutl(ZMFILE,"set key clear"); #ifdef OS2 for (k = 0; k < nttkey; k++) { if (!ttkeytab[k].flgs) { ckmakmsg(buf,1024, "set terminal key ", ttkeytab[k].kwd, " clear", NULL ); zsoutl(ZMFILE,buf); } } #endif /* OS2 */ zsoutl(ZMFILE,""); for (i = 0; i < KMSIZE; i++) { if (macrotab[i]) { int len = strlen((char *)macrotab[i]); #ifdef OS2 ckmakmsg(buf, 1024, "set key \\", ckitoa(mskkeys ? cktomsk(i) : i), " ", NULL ); #else /* OS2 */ ckmakmsg(buf, 1024, "set key \\", ckitoa(i), NULL,NULL ); #endif /* OS2 */ zsout(ZMFILE,buf); for (j = 0; j < len; j++) { char ch = macrotab[i][j]; if (ch <= SP || ch >= DEL || ch == '-' || ch == ',' || ch == '{' || ch == '}' || ch == ';' || ch == '?' || ch == '.' || ch == '\'' || ch == '\\' || ch == '/' || ch == '#') { ckmakmsg(buf,1024,"\\{",ckitoa((int)ch),"}",NULL); zsout(ZMFILE,buf); } else { ckmakmsg(buf,1024,ckctoa((char)ch),NULL,NULL,NULL); zsout(ZMFILE,buf); } } #ifdef OS2 ckmakmsg(buf,1024,"\t; ",keyname(i),NULL,NULL); zsoutl(ZMFILE,buf); #else zsoutl(ZMFILE,""); #endif /* OS2 */ } else if ( keymap[i] != i ) { #ifndef NOKVERBS if (IS_KVERB(keymap[i])) { for (j = 0; j < nkverbs; j++) if (kverbs[j].kwval == (keymap[i] & ~F_KVERB)) break; if (j != nkverbs) { #ifdef OS2 #ifdef COMMENT sprintf(buf, "set key \\%d \\K%s\t; %s", mskkeys ? cktomsk(i) : i, kverbs[j].kwd, keyname(i) ); #else ckmakxmsg(buf, /* 12 string args */ 1024, "set key \\", ckitoa(mskkeys ? cktomsk(i) : i), " \\K", kverbs[j].kwd, "\t; ", keyname(i), NULL, NULL, NULL, NULL, NULL, NULL); #endif /* COMMENT */ zsoutl(ZMFILE,buf); #else #ifdef COMMENT sprintf(buf, "set key \\%d \\K%s", i, kverbs[j].kwd); #else ckmakmsg(buf,1024, "set key \\", ckitoa(i), " \\K", kverbs[j].kwd ); #endif /* COMMENT */ zsoutl(ZMFILE,buf); #endif } } else #endif /* NOKVERBS */ { #ifdef OS2 #ifdef COMMENT sprintf(buf, "set key \\%d \\{%d}\t; %s", mskkeys ? cktomsk(i) : i, keymap[i], keyname(i) ); #else ckmakxmsg(buf, /* 8 string args */ 1024, "set key \\", ckitoa(mskkeys ? cktomsk(i) : i), " \\{", ckitoa(keymap[i]), "}\t; ", keyname(i), NULL,NULL,NULL,NULL,NULL,NULL); #endif /* COMMENT */ zsoutl(ZMFILE,buf); #else #ifdef COMMENT sprintf(buf, "set key \\%d \\{%d}", i, keymap[i]); #else ckmakxmsg(buf,1024, "set key \\", ckitoa(i), " \\{", ckitoa(keymap[i]), "}", NULL,NULL,NULL,NULL,NULL,NULL,NULL); #endif /* COMMENT */ zsoutl(ZMFILE,buf); #endif /* OS2 */ } } } #ifdef OS2 /* OS/2 also has the SET TERMINAL KEY defines */ for (k = 0; k < nttkey; k++) { extern struct keynode * ttkeymap[]; struct keynode * pnode = NULL; if (ttkeytab[k].flgs) /* Don't process CM_INV or CM_ABR */ continue; zsoutl(ZMFILE,""); ckmakmsg(buf,1024,"; SET TERMINAL KEY ",ttkeytab[k].kwd,NULL,NULL); zsoutl(ZMFILE,buf); for (pnode = ttkeymap[ttkeytab[k].kwval]; pnode; pnode = pnode->next ) { switch (pnode->def.type) { case key: #ifdef COMMENT sprintf(buf, "set terminal key %s \\%d \\{%d}\t; %s", ttkeytab[k].kwd, mskkeys ? cktomsk(pnode->key) : pnode->key, pnode->def.key.scancode, keyname(pnode->key) ); #else ckmakxmsg(buf, 1024, "set terminal key ", ttkeytab[k].kwd, " \\", ckitoa(mskkeys ? cktomsk(pnode->key) : pnode->key), " \\{", ckitoa(pnode->def.key.scancode), "}\t; ", keyname(pnode->key), NULL,NULL,NULL,NULL ); #endif /* COMMENT */ zsoutl(ZMFILE,buf); break; case kverb: for (j = 0; j < nkverbs; j++) if (kverbs[j].kwval == (pnode->def.kverb.id & ~F_KVERB)) break; if (j != nkverbs) { #ifdef COMMENT sprintf(buf, "set terminal key %s \\%d \\K%s\t; %s", ttkeytab[k].kwd, mskkeys ? cktomsk(pnode->key) : pnode->key, kverbs[j].kwd, keyname(pnode->key) ); #else ckmakxmsg(buf, 1024, "set terminal key ", ttkeytab[k].kwd, " \\", ckitoa(mskkeys ? cktomsk(pnode->key) : pnode->key), " \\K", kverbs[j].kwd, "\t; ", keyname(pnode->key), NULL,NULL,NULL,NULL ); #endif /* COMMENT */ zsoutl(ZMFILE,buf); } break; case macro: { int len = strlen((char *)pnode->def.macro.string); #ifdef COMMENT sprintf(buf,"set terminal key %s \\%d ", ttkeytab[k].kwd, mskkeys ? cktomsk(pnode->key) : pnode->key); #else ckmakxmsg(buf, 1024, "set terminal key ", ttkeytab[k].kwd, " \\", ckitoa(mskkeys ? cktomsk(pnode->key) : pnode->key), " ", NULL,NULL,NULL,NULL,NULL,NULL,NULL ); #endif /* COMMENT */ zsout(ZMFILE,buf); for (j = 0; j < len; j++) { char ch = pnode->def.macro.string[j]; if (ch <= SP || ch >= DEL || ch == '-' || ch == ',' || ch == '{' || ch == '}' || ch == ';' || ch == '?' || ch == '.' || ch == '\'' || ch == '\\' || ch == '/' || ch == '#') { ckmakmsg(buf,1024, "\\{",ckitoa((int)ch),"}",NULL); zsout(ZMFILE,buf); } else { ckmakmsg(buf,1024, ckctoa((char)ch),NULL,NULL,NULL); zsout(ZMFILE,buf); } } ckmakmsg(buf,1024,"\t; ",keyname(pnode->key),NULL,NULL); zsoutl(ZMFILE,buf); break; } case literal: { int len = strlen((char *)pnode->def.literal.string); #ifdef COMMENT sprintf(buf,"set terminal key %s /literal \\%d ", ttkeytab[k].kwd, mskkeys ? cktomsk(pnode->key) : pnode->key); #else ckmakxmsg(buf, 1024, "set terminal key ", ttkeytab[k].kwd, " /literal \\", ckitoa(mskkeys ? cktomsk(pnode->key) : pnode->key), " ", NULL,NULL,NULL,NULL,NULL,NULL,NULL); #endif /* COMMENT */ zsout(ZMFILE,buf); for (j = 0; j < len; j++) { char ch = pnode->def.literal.string[j]; if (ch <= SP || ch >= DEL || ch == '-' || ch == ',' || ch == '{' || ch == '}' || ch == ';' || ch == '?' || ch == '.' || ch == '\'' || ch == '\\' || ch == '/' || ch == '#') { ckmakmsg(buf,1024, "\\{",ckitoa((int)ch),"}",NULL); zsout(ZMFILE,buf); } else { ckmakmsg(buf,1024, ckctoa((char)ch),NULL,NULL,NULL); zsout(ZMFILE,buf); } } ckmakmsg(buf,1024,"\t; ",keyname(pnode->key),NULL,NULL); zsoutl(ZMFILE,buf); break; } case esc: #ifdef COMMENT sprintf(buf, "set terminal key %s /literal \\%d \\{%d}\\{%d}\t; %s", ttkeytab[k].kwd, mskkeys ? cktomsk(pnode->key) : pnode->key, ISDG200(ttkeytab[k].kwval) ? 30 : 27, pnode->def.esc.key & ~F_ESC, keyname(pnode->key) ); #else ckmakxmsg(buf, 1024, "set terminal key ", ttkeytab[k].kwd, " /literal \\", ckitoa(mskkeys ? cktomsk(pnode->key) : pnode->key), " \\{", ckitoa(ISDG200(ttkeytab[k].kwval) ? 30 : 27), "}\\{", ckitoa(pnode->def.esc.key & ~F_ESC), "}\t; ", keyname(pnode->key), NULL,NULL ); #endif /* COMMENT */ zsoutl(ZMFILE,buf); break; case csi: #ifdef COMMENT sprintf(buf, "set terminal key %s /literal \\%d \\{27}[\\{%d}\t; %s", ttkeytab[k].kwd, mskkeys ? cktomsk(pnode->key) : pnode->key, pnode->def.csi.key & ~F_CSI, keyname(pnode->key) ); #else ckmakxmsg(buf, 1024, "set terminal key ", ttkeytab[k].kwd, " /literal \\", ckitoa(mskkeys ? cktomsk(pnode->key) : pnode->key), " \\{27}[\\{", ckitoa(pnode->def.csi.key & ~F_CSI), "}\t; ", keyname(pnode->key), NULL,NULL,NULL,NULL ); #endif /* COMMENT */ zsoutl(ZMFILE,buf); break; default: continue; } } } #endif /* OS2 */ zsoutl(ZMFILE,""); zsoutl(ZMFILE,"; End"); zclose(ZMFILE); return(success = 1); } else { return(success = 0); } } #endif /* NOSETKEY */ #define SV_SCRL 0 #define SV_HIST 1 #ifdef OS2 #ifndef NOLOCAL static struct keytab trmtrmopt[] = { { "scrollback", SV_SCRL, 0 } }; #endif /* NOLOCAL */ #endif /* OS2 */ static struct keytab cmdtrmopt[] = { #ifdef CK_RECALL { "history", SV_HIST, 0 }, #endif /* CK_RECALL */ #ifdef OS2 #ifndef NOLOCAL { "scrollback", SV_SCRL, 0 }, #endif /* NOLOCAL */ #endif /* OS2 */ { "", 0, 0 } }; static int ncmdtrmopt = (sizeof (cmdtrmopt) / sizeof (struct keytab)) - 1; #ifdef OS2 #ifndef NOLOCAL _PROTOTYP(int savscrbk, (int, char *, int)); #endif /* NOLOCAL */ #endif /* OS2 */ int #ifdef CK_ANSIC dosave( int xx ) #else dosave(xx) int xx; #endif /* CK_ANSIC */ { int x, y = 0, disp; char * s = NULL; extern struct keytab disptb[]; #ifdef ZFNQFP struct zfnfp * fnp; #endif /* ZFNQFP */ #ifndef NOSETKEY if (xx == XSKEY) { /* SAVE KEYMAP.. */ z = cmofi("Name of Kermit command file","keymap.ksc",&s,xxstring); } else { #endif /* NOSETKEY */ switch (xx) { case XSCMD: /* SAVE COMMAND.. */ if ((y = cmkey(cmdtrmopt, ncmdtrmopt, "What to save", #ifdef OS2 "scrollback", #else "history", #endif /* OS2 */ xxstring)) < 0) return(y); break; #ifdef OS2 #ifndef NOLOCAL case XSTERM: /* SAVE TERMINAL.. */ if ((y = cmkey(trmtrmopt,1, "What to save","scrollback",xxstring)) < 0) return(y); break; #endif /* NOLOCAL */ #endif /* OS2 */ } z = cmofi("Filename", ((y == SV_SCRL) ? "scrollbk.txt" : "history.txt"), &s, xxstring ); #ifndef NOSETKEY } #endif /* NOSETKEY */ if (z < 0) /* Check output-file parse results */ return(z); if (z == 2) { printf("?Sorry, %s is a directory name\n",s); return(-9); } #ifdef ZFNQFP if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) {/* Convert to full pathname */ if (fnp->fpath) if ((int) strlen(fnp->fpath) > 0) s = fnp->fpath; } #endif /* ZFNQFP */ ckstrncpy(line,s,LINBUFSIZ); /* Make safe copy of pathname */ s = line; #ifdef MAC z = 0; #else /* Get NEW/APPEND disposition */ if ((z = cmkey(disptb,2,"Disposition","new",xxstring)) < 0) return(z); #endif /* MAC */ disp = z; if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); switch (xx) { /* Do action.. */ #ifndef NOSETKEY case XSKEY: /* SAVE KEYMAP */ return (savkeys(s,disp)); #endif /* NOSETKEY */ case XSCMD: /* SAVE COMMAND.. */ #ifdef OS2 #ifndef NOLOCAL if (y == SV_SCRL) /* .. SCROLLBACK */ return(success = savscrbk(VCMD,s,disp)); #endif /* NOLOCAL */ #endif /* OS2 */ #ifndef NORECALL if (y == SV_HIST) /* .. HISTORY */ return(success = savhistory(s,disp)); #endif /* NORECALL */ break; #ifdef OS2 #ifndef NOLOCAL case XSTERM: /* SAVE TERMINAL SCROLLBACK */ return(success = savscrbk(VTERM,s,disp)); #endif /* NOLOCAL */ #endif /* OS2 */ } success = 0; return(-2); } /* R E A D T E X T Read text with a custom prompt into given buffer using command parser but with no echoing or entry into recall buffer. */ int #ifdef CK_ANSIC readtext( char * prmpt, char * buffer, int bufsiz ) #else readtext(prmpt, buffer, bufsiz) char * prmpt; char * buffer; int bufsiz; #endif /* CK_ANSIC */ { #ifdef CK_RECALL extern int on_recall; /* Around Password prompting */ #endif /* CK_RECALL */ int rc; #ifndef NOLOCAL #ifdef OS2 extern BYTE vmode; extern int startflags; int vmode_sav = vmode; if (!prmpt) prmpt = ""; if (win95_popup && !(startflags & 96) #ifdef IKSD && !inserver #endif /* IKSD */ ) return(popup_readtext(vmode,NULL,prmpt,buffer,bufsiz,0)); if (vmode == VTERM) { vmode = VCMD; VscrnIsDirty(VTERM); VscrnIsDirty(VCMD); } #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef CK_RECALL on_recall = 0; #endif /* CK_RECALL */ cmsavp(psave,PROMPTL); /* Save old prompt */ cmsetp(prmpt); /* Make new prompt */ concb((char)escape); /* Put console in cbreak mode */ cmini(1); /* and echo mode */ if (pflag) prompt(xxstring); /* Issue prompt if at top level */ cmres(); /* Reset the parser */ for (rc = -1; rc < 0; ) { /* Prompt till they answer */ rc = cmtxt("","",&s,NULL); /* Get a literal line of text */ cmres(); /* Reset the parser again */ } ckstrncpy(buffer,s,bufsiz); cmsetp(psave); /* Restore original prompt */ #ifndef NOLOCAL #ifdef OS2 if (vmode != vmode_sav) { vmode = VTERM; VscrnIsDirty(VCMD); VscrnIsDirty(VTERM); } #endif /* OS2 */ #endif /* NOLOCAL */ return(0); } #endif /* NOICP */ /* A general function to allow a Password or other information */ /* to be read from the command prompt without it going into */ /* the recall buffer or being echo'd. */ int #ifdef CK_ANSIC readpass( char * prmpt, char * buffer, int bufsiz ) #else readpass(prmpt, buffer, bufsiz) char * prmpt; char * buffer; int bufsiz; #endif /* CK_ANSIC */ { int x; #ifdef NOICP if (!prmpt) prmpt = ""; printf("%s", prmpt); #ifdef COMMENT /* Some linkers won't allow this because it's unsafe */ gets(buffer); #else /* COMMENT */ { int c, i; char * p; p = buffer; for (i = 0; i < bufsiz-1; i++) { if ((c = getchar()) == EOF) break; if (c < SP) break; buffer[i] = c; } buffer[i] = NUL; } #endif /* COMMENT */ return(1); #else /* NOICP */ #ifdef CK_RECALL extern int on_recall; /* around Password prompting */ #endif /* CK_RECALL */ int rc; #ifndef NOLOCAL #ifdef OS2 extern BYTE vmode; extern int startflags; int vmode_sav = vmode; #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef CKSYSLOG int savlog; #endif /* CKSYSLOG */ if (!prmpt) prmpt = ""; #ifndef NOLOCAL debok = 0; /* Don't log */ #ifdef OS2 if (win95_popup && !(startflags & 96) #ifdef IKSD && !inserver #endif /* IKSD */ ) { x = popup_readpass(vmode,NULL,prmpt,buffer,bufsiz,0); debok = 1; return(x); } #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef CKSYSLOG savlog = ckxsyslog; /* Save and turn off syslogging */ ckxsyslog = 0; #endif /* CKSYSLOG */ #ifndef NOLOCAL #ifdef OS2 if (vmode == VTERM) { vmode = VCMD; VscrnIsDirty(VTERM); VscrnIsDirty(VCMD); } #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef CK_RECALL on_recall = 0; #endif /* CK_RECALL */ cmsavp(psave,PROMPTL); /* Save old prompt */ cmsetp(prmpt); /* Make new prompt */ concb((char)escape); /* Put console in cbreak mode */ cmini(0); /* and no-echo mode */ if (pflag) prompt(xxstring); /* Issue prompt if at top level */ cmres(); /* Reset the parser */ for (rc = -1; rc < 0; ) { /* Prompt till they answer */ rc = cmtxt("","",&s,NULL); /* Get a literal line of text */ cmres(); /* Reset the parser again */ } ckstrncpy(buffer,s,bufsiz); printf("\r\n"); /* Echo a CRLF */ cmsetp(psave); /* Restore original prompt */ cmini(1); /* Restore echo mode */ #ifndef NOLOCAL #ifdef OS2 if (vmode != vmode_sav) { vmode = VTERM; VscrnIsDirty(VCMD); VscrnIsDirty(VTERM); } #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef CKSYSLOG ckxsyslog = savlog; /* Restore syslogging */ #endif /* CKSYSLOG */ debok = 1; return(0); #endif /* NOICP */ } #ifndef NOICP struct keytab authtab[] = { /* Available authentication types */ #ifdef CK_KERBEROS { "k4", AUTH_KRB4, CM_INV }, { "k5", AUTH_KRB5, CM_INV }, { "kerberos4", AUTH_KRB4, 0 }, { "kerberos5", AUTH_KRB5, 0 }, { "krb4", AUTH_KRB4, CM_INV }, { "krb5", AUTH_KRB5, CM_INV }, #endif /* CK_KERBEROS */ #ifdef NT { "ntlm", AUTH_NTLM, 0 }, #endif /* NT */ #ifdef CK_SRP { "srp", AUTH_SRP, 0 }, #endif /* CK_SRP */ #ifdef CK_SSL { "ssl", AUTH_SSL, 0 }, #endif /* CK_SSL */ { "", 0, 0 } }; int authtabn = sizeof(authtab)/sizeof(struct keytab)-1; #ifdef CK_KERBEROS struct keytab kerbtab[] = { /* Kerberos authentication types */ { "k4", AUTH_KRB4, CM_INV }, { "k5", AUTH_KRB5, CM_INV }, { "kerberos4", AUTH_KRB4, 0 }, { "kerberos5", AUTH_KRB5, 0 }, { "krb4", AUTH_KRB4, CM_INV }, { "krb5", AUTH_KRB5, CM_INV } }; int kerbtabn = sizeof(kerbtab)/sizeof(struct keytab); static struct keytab krb_s_tbl[] = { /* AUTHENTICATE command switches: */ { "/cache", KRB_S_CA, CM_ARG } }; static int krb_s_n = sizeof(krb_s_tbl)/sizeof(struct keytab); static struct keytab krb_v_tbl[] = { /* KERBEROS version values: */ { "4", 4, 0 }, { "5", 5, 0 }, /* (add others as needed...) */ { "auto", 0, 0 } /* Note: 0 = auto */ }; static int krb_v_n = sizeof(krb_v_tbl)/sizeof(struct keytab); static struct keytab krb_a_tbl[] = { /* KERBEROS actions: */ { "destroy", KRB_A_DE, 0 }, { "initialize", KRB_A_IN, 0 }, { "list-credentials", KRB_A_LC, 0 } }; static int krb_a_n = sizeof(krb_a_tbl)/sizeof(struct keytab); static struct keytab krb4_i_tbl[] = { /* KERBEROS 4 INITIALIZE switches: */ { "/brief", KRB_I_BR, 0 }, /* /BRIEF */ { "/instance", KRB_I_IN, CM_ARG }, /* /INSTANCE: */ { "/lifetime", KRB_I_LF, CM_ARG }, /* /LIFETIME: */ { "/not-preauth", KRB_I_NPA, 0 }, /* /NOT-PREAUTH */ { "/password", KRB_I_PW, CM_ARG }, /* /PASSWORD: */ #ifdef OS2 { "/popup", KRB_I_POP, 0 }, /* /POPUP */ #endif /* OS2 */ { "/preauth", KRB_I_PA, 0 }, /* /PREAUTH */ { "/realm", KRB_I_RL, CM_ARG }, /* /REALM: */ { "/verbose", KRB_I_VB, 0 }, /* /VERBOSE */ { "", 0, 0 } }; static int krb4_i_n = sizeof(krb4_i_tbl)/sizeof(struct keytab) - 1; static struct keytab krb5_i_tbl[] = { /* KERBEROS 5 INITIALIZE switches: */ { "/addresses", KRB_I_ADR, CM_ARG }, { "/forwardable", KRB_I_FW, 0 }, /* /FORWARDABLE */ { "/instance", KRB_I_IN, CM_ARG }, /* /INSTANCE: */ { "/k4", KRB_I_K4, CM_INV }, /* /KERBEROS4 */ { "/kerberos4", KRB_I_K4, 0 }, /* /KERBEROS4 */ { "/krb4", KRB_I_K4, CM_INV }, /* /KERBEROS4 */ { "/lifetime", KRB_I_LF, CM_ARG }, /* /LIFETIME: */ { "/no-addresses", KRB_I_NAD, 0 }, /* /NO-ADDRESSES */ { "/no-k4", KRB_I_NK4, CM_INV },/* /NO-KERBEROS4 */ { "/no-kerberos4", KRB_I_NK4, 0 }, /* /NO-KERBEROS4 */ { "/no-krb4", KRB_I_NK4, CM_INV },/* /NO-KERBEROS4 */ { "/not-forwardable", KRB_I_NFW, 0 }, /* /NOT-FORWARDABLE */ { "/not-proxiable", KRB_I_NPR, 0 }, /* /NOT-PROXIABLE */ { "/password", KRB_I_PW, CM_ARG }, /* /PASSWORD: */ #ifdef OS2 { "/popup", KRB_I_POP, 0 }, /* /POPUP */ #endif /* OS2 */ { "/postdate", KRB_I_PD, CM_ARG }, /* /POSTDATE: */ { "/pr", KRB_I_PR, CM_INV|CM_ABR }, /* to allow for */ { "/pro", KRB_I_PR, CM_INV|CM_ABR }, /* different spellings */ { "/prox", KRB_I_PR, CM_INV|CM_ABR }, { "/proxiable", KRB_I_PR, 0 }, /* /PROXIABLE */ { "/proxyable", KRB_I_PR, CM_INV }, /* /PROXYABLE */ { "/realm", KRB_I_RL, CM_ARG }, /* /REALM: */ { "/renew", KRB_I_RN, 0 }, /* /RENEW */ { "/renewable", KRB_I_RB, CM_ARG }, /* /RENEWABLE: */ { "/service", KRB_I_SR, CM_ARG }, /* /SERVICE: */ { "/validate", KRB_I_VA, 0 }, /* /VALIDATE */ { "", 0, 0 } }; static int krb5_i_n = sizeof(krb5_i_tbl)/sizeof(struct keytab) - 1; static struct keytab klctab[] = { /* List Credentials switches*/ { "/addresses", XYKLCAD, 0 }, { "/encryption", XYKLCEN, 0 }, { "/flags", XYKLCFL, 0 } }; static int nklctab = sizeof(klctab)/sizeof(struct keytab); extern int krb_action; extern struct krb_op_data krb_op; extern struct krb5_list_cred_data krb5_lc; extern struct krb5_init_data krb5_init; extern char * krb5_d_principal; /* Default principal */ extern char * krb5_d_instance; extern char * krb5_d_realm; /* Default realm */ extern char * krb5_d_cc; /* Default credentials cache */ extern char * krb5_d_srv; /* Default service name */ extern int krb5_d_lifetime; /* Default lifetime */ extern int krb5_d_forwardable; extern int krb5_d_proxiable; extern int krb5_d_renewable; extern int krb5_autoget; extern int krb5_autodel; extern int krb5_d_getk4; extern int krb5_d_no_addresses; extern int krb5_checkaddrs; extern char * krb5_d_addrs[]; extern char * k5_keytab; /* Keytab file */ extern struct krb4_init_data krb4_init; extern char * krb4_d_principal; /* Default principal */ extern char * krb4_d_realm; /* Default realm */ extern char * krb4_d_srv; /* Default service name */ extern int krb4_d_lifetime; /* Default lifetime */ extern int krb4_d_preauth; extern char * krb4_d_instance; extern int krb4_autoget; extern int krb4_autodel; extern int krb4_checkaddrs; extern char * k4_keytab; /* Keytab file */ #endif /* CK_KERBEROS */ #ifndef NOSHOW int sho_iks() { #ifdef IKSDCONF #ifdef CK_LOGIN extern int ckxsyslog, ckxwtmp, ckxanon; #ifdef UNIX extern int ckxpriv; #endif /* UNIX */ #ifdef CK_PERMS extern int ckxperms; #endif /* CK_PERMS */ extern char * anonfile, * userfile, * anonroot; #ifdef OS2 extern char * anonacct; #endif /* OS2 */ #ifdef NT extern char * iks_domain; #endif /* NT */ #endif /* CK_LOGIN */ #ifdef CKWTMP extern char * wtmpfile; #endif /* CKWTMP */ #ifdef IKSDB extern char * dbfile; extern int dbenabled; #endif /* IKSDB */ #ifdef CK_LOGIN extern int logintimo; #endif /* CK_LOGIN */ extern int srvcdmsg, success, iksdcf, noinit, arg_x; extern char * cdmsgfile[], * cdmsgstr, *kermrc; char * bannerfile = NULL; char * helpfile = NULL; extern int xferlog; extern char * xferfile; int i; if (isguest) { printf("?Command disabled\r\n"); return(success = 0); } printf("IKS Settings\r\n"); #ifdef CK_LOGIN #ifdef OS2 printf(" Anonymous Account: %s\r\n",anonacct?anonacct:""); #endif /* OS2 */ printf(" Anonymous Initfile: %s\r\n",anonfile?anonfile:""); printf(" Anonymous Login: %d\r\n",ckxanon); printf(" Anonymous Root: %s\r\n",anonroot?anonroot:""); #endif /* CK_LOGIN */ printf(" Bannerfile: %s\r\n",bannerfile?bannerfile:""); printf(" CDfile: %s\r\n",cdmsgfile[0]?cdmsgfile[0]:""); for ( i=1;i<16 && cdmsgfile[i];i++ ) printf(" CDfile: %s\r\n",cdmsgfile[i]); printf(" CDMessage: %d\r\n",srvcdmsg); #ifdef IKSDB printf(" DBfile: %s\r\n",dbfile?dbfile:""); printf(" DBenabled: %d\r\n",dbenabled); #endif /* IKSDB */ #ifdef CK_LOGIN #ifdef NT printf(" Default-domain: %s\r\n",iks_domain?iks_domain:"."); #endif /* NT */ #endif /* CK_LOGIN */ printf(" Helpfile: %s\r\n",helpfile?helpfile:""); printf(" Initfile: %s\r\n",kermrc?kermrc:""); printf(" No-Initfile: %d\r\n",noinit); #ifdef CK_LOGIN #ifdef CK_PERM printf(" Permission code: %0d\r\n",ckxperms); #endif /* CK_PERM */ #ifdef UNIX printf(" Privileged Login: %d\r\n",ckxpriv); #endif /* UNIX */ #endif /* CK_LOGIN */ printf(" Server-only: %d\r\n",arg_x); printf(" Syslog: %d\r\n",ckxsyslog); #ifdef CK_LOGIN printf(" Timeout (seconds): %d\r\n",logintimo); printf(" Userfile: %s\r\n",userfile?userfile:""); #ifdef CKWTMP printf(" Wtmplog: %d\r\n",ckxwtmp); printf(" Wtmpfile: %s\r\n",wtmpfile?wtmpfile:""); #endif /* CKWTMP */ #endif /* CK_LOGIN */ printf(" Xferfile: %s\r\n",xferfile?xferfile:""); printf(" Xferlog: %d\r\n",xferlog); #else /* IKSDCONF */ printf("?Nothing to show.\r\n"); #endif /* IKSDCONF */ return(success = 1); } #ifdef CK_AUTHENTICATION int #ifdef CK_ANSIC sho_auth( int cx ) #else sho_auth(cx) int cx; #endif /* CK_ANSIC */ { extern int auth_type_user[], cmd_rows; #ifdef CK_KERBEROS int i; char * p; #endif /* CK_KERBEROS */ int kv = 0, all = 0, n = 0; #ifdef IKSD if (inserver && isguest) { printf("?Sorry, command disabled.\r\n"); return(success = 0); } #endif /* IKSD */ if (cx) { kv = cx; } else if (auth_type_user[0] != AUTHTYPE_AUTO) { kv = auth_type_user[0]; } else { all = 1; kv = AUTHTYPE_KERBEROS_V4; } while (kv) { switch (kv) { case AUTHTYPE_KERBEROS_V4: kv = all ? AUTHTYPE_KERBEROS_V5 : 0; if (ck_krb4_is_installed()) { printf(" Authentication: Kerberos 4\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } else { printf(" Authentication: Kerberos 4 (not installed)\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } continue; } #ifdef CK_KERBEROS printf(" Keytab file: %s\n", k4_keytab ? k4_keytab : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } if (krb_action < 0) { p = "(none)"; } else { for (p = "", i = 0; i < krb_a_n; i++) { if (krb_action == krb_a_tbl[i].kwval) { p = krb_a_tbl[i].kwd; break; } } } printf(" Action: %s\n", p); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default lifetime %d\n",krb4_d_lifetime); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Lifetime: %d (minutes)\n",krb4_init.lifetime); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default preauth: %d\n",krb4_d_preauth); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Preauth: %d\n",krb4_init.preauth); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default principal: \"%s\"\n", krb4_d_principal ? krb4_d_principal : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Principal: \"%s\"\n", krb4_init.principal ? krb4_init.principal : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default realm: \"%s\"\n", krb4_d_realm ? krb4_d_realm : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Realm: \"%s\"\n", krb4_init.realm ? krb4_init.realm : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default instance: \"%s\"\n", krb4_d_instance ? krb4_d_instance : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Instance: \"%s\"\n", krb4_init.instance ? krb4_init.instance : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Auto-Get TGTs: %d\n",krb4_autoget); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Auto-Destroy TGTs: %s\n", krb4_autodel==KRB_DEL_NO?"never": krb4_autodel==KRB_DEL_CL?"on-close":"on-exit"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Check IP Addresses: %d\n",krb4_checkaddrs); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #ifdef COMMENT printf(" Password: \"%s\"\n", krb4_init.password ? krb4_init.password : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* COMMENT */ #endif /* CK_KERBEROS */ printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } break; case AUTHTYPE_KERBEROS_V5: kv = all ? AUTHTYPE_SSL : 0; if (ck_krb5_is_installed()) { if (ck_gssapi_is_installed()) printf(" Authentication: Kerberos 5 plus GSSAPI\n"); else printf(" Authentication: Kerberos 5\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } else { printf(" Authentication: Kerberos 5 (not installed)\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } continue; } #ifdef CK_KERBEROS printf(" Cache file: %s\n", krb_op.cache ? krb_op.cache : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default cache: %s\n", krb5_d_cc ? krb5_d_cc : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Keytab file: %s\n", k5_keytab ? k5_keytab : "(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } if (krb_action < 0) { p = "(none)"; } else { for (p = "", i = 0; i < krb_a_n; i++) { if (krb_action == krb_a_tbl[i].kwval) { p = krb_a_tbl[i].kwd; break; } } } printf(" Action: %s\n", p); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default forwardable %d\n",krb5_d_forwardable); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Forwardable: %d\n",krb5_init.forwardable); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default lifetime %d\n",krb5_d_lifetime); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Lifetime: %d (minutes)\n",krb5_init.lifetime); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Postdate: \"%s\"\n", krb5_init.postdate ? krb5_init.postdate: ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default proxiable: %d\n",krb5_d_proxiable); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Proxiable: %d\n",krb5_init.proxiable); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Renew: %d\n",krb5_init.renew); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default renewable: %d (minutes)\n",krb5_d_renewable); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Renewable: %d (minutes)\n",krb5_init.renewable); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Service: \"%s\"\n", krb5_init.service ? krb5_init.service : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Validate: %d\n",krb5_init.validate); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default principal: \"%s\"\n", krb5_d_principal ? krb5_d_principal : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Principal: \"%s\"\n", krb5_init.principal ? krb5_init.principal : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default instance: \"%s\"\n", krb5_d_instance ? krb5_d_instance : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default realm: \"%s\"\n", krb5_d_realm ? krb5_d_realm : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Realm: \"%s\"\n", krb5_init.realm ? krb5_init.realm : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Auto-Get TGTs: %d\n",krb5_autoget); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Auto-Destroy TGTs: %s\n", krb5_autodel==KRB_DEL_NO?"never": krb5_autodel==KRB_DEL_CL?"on-close":"on-exit"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Default get K4 TGTs: %d\n",krb5_d_getk4); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Get K4 TGTs: %d\n",krb5_init.getk4); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Check IP Addresses: %d\n",krb5_checkaddrs); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" No IP Addresses: %d\n",krb5_d_no_addresses); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" IP-Addresses: "); if (krb5_init.addrs && krb5_init.addrs[0]) { for (i = 0; krb5_init.addrs[i]; i++) { if (i) printf(","); printf("%s",krb5_init.addrs[i]); } } else if (krb5_d_addrs[0]) { for (i = 0;i < KRB5_NUM_OF_ADDRS && krb5_d_addrs[i];i++) { if (i) printf(","); printf("%s",krb5_d_addrs[i]); } } else { printf("(use default)"); } printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #ifdef COMMENT printf(" Password: \"%s\"\n", krb5_init.password ? krb5_init.password : ""); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* COMMENT */ #endif /* CK_KERBEROS */ printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } break; #ifdef CK_SSL case AUTHTYPE_SSL: kv = all ? AUTHTYPE_SRP : 0; if (ck_ssleay_is_installed()) { printf(" Authentication: SSL/TLS (%s)\n", SSLeay_version(SSLEAY_VERSION)); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } else { printf(" Authentication: SSL/TLS (not installed)\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } continue; } printf(" RSA Certs file: %s\n",ssl_rsa_cert_file? ssl_rsa_cert_file:"(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" RSA Certs Chain file: %s\n",ssl_rsa_cert_chain_file? ssl_rsa_cert_chain_file:"(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" RSA Key file: %s\n",ssl_rsa_key_file? ssl_rsa_key_file:"(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" DSA Certs file: %s\n",ssl_dsa_cert_file? ssl_dsa_cert_file:"(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" DSA Certs Chain file: %s\n",ssl_dsa_cert_chain_file? ssl_dsa_cert_chain_file:"(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" DH Key file: %s\n",ssl_dh_key_file? ssl_dh_key_file:"(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" DH Param file: %s\n",ssl_dh_param_file? ssl_dh_param_file:"(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" CRL file: %s\n",ssl_crl_file? ssl_crl_file:"(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" CRL dir: %s\n",ssl_crl_dir? ssl_crl_dir:"(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Random file: %s\n",ssl_rnd_file? ssl_rnd_file:"(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Verify file: %s\n",ssl_verify_file? ssl_verify_file:"(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Verify dir: %s\n",ssl_verify_dir? ssl_verify_dir:"(none)"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Cipher list: %s\n",ssl_cipher_list ? ssl_cipher_list : DEFAULT_CIPHER_LIST); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } if (ssl_con == NULL) { SSL_library_init(); ssl_ctx = (SSL_CTX *) /* old... SSL_CTX_new((SSL_METHOD *)TLSv1_method()); new below: */ SSL_CTX_new((SSL_METHOD *)SSLv23_method()); if (ssl_ctx != NULL) ssl_con= (SSL *) SSL_new(ssl_ctx); } if (ssl_con != NULL) { CHAR * p = NULL; int i; for (i = 0; ; i++) { p = (CHAR *) SSL_get_cipher_list(ssl_con,i); if (p == NULL) break; printf(" %s\n",p); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } } printf(" Certs OK? %s\n",ssl_certsok_flag? "yes" : "no"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Debug mode: %s\n", ssl_debug_flag ? "on" : "off"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Verbose mode: %s\n", ssl_verbose_flag ? "on" : "off"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" Verify mode: %s\n", ssl_verify_flag == SSL_VERIFY_NONE ? "none" : ssl_verify_flag == SSL_VERIFY_PEER ? "peer-cert" : "fail-if-no-peer-cert"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" SSL only? %s\n", ssl_only_flag ? "yes" : "no"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" TLS only? %s\n", tls_only_flag ? "yes" : "no"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } #endif /* CK_SSL */ break; case AUTHTYPE_NTLM: kv = 0; if (ck_ntlm_is_installed()) { printf(" Authentication: NTLM\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" No options\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } else { printf(" Authentication: NTLM (not installed)\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } continue; } printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } break; case AUTHTYPE_SRP: kv = all ? AUTHTYPE_NTLM : 0; if (ck_srp_is_installed()) { if (ck_krypto_is_installed()) printf(" Authentication: SRP plus Krypto API\n"); else printf(" Authentication: SRP\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } printf(" No options\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } } else { printf(" Authentication: SRP (not installed)\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } continue; } printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) return(0); else n = 0; } break; } } return(success = 1); } #endif /* CK_AUTHENTICATION */ #endif /* NOSHOW */ #ifdef CK_KERBEROS /* C P _ A U T H -- AUTHENTICATE command parsing */ int cp_auth() { /* Command_Parse AUTHENTICATE */ int c, i, n; /* Workers */ int rc = 0; /* Return code */ int getval; /* Parsing helpers */ int tmpauth = 0; /* Temporary authentication type */ int kv = 0; /* Temporary Kerberos version */ int tmp_action = -1; /* Temporary Kerberos action */ int tmp_klc = 0; /* Temporary list-credentials */ char tmphlp[256]; /* For building help message */ char * p; char * tmppswd = NULL; /* Password */ char * tmpprinz = NULL; /* Principal */ char * tmprealm = NULL; /* Realm */ char * tmpcache = NULL; /* Cache file */ char * tmpinst = NULL; /* K4 Instance */ char * tmpaddrs[KRB5_NUM_OF_ADDRS]; #ifdef CK_RECALL extern int on_recall; /* around Password prompting */ #endif /* CK_RECALL */ struct stringint pv[KRB_I_MAX+1]; /* Temporary array for switch values */ struct FDB kw, sw, fl; /* FDBs for each parse function */ krb_action = -1; /* Initialize Kerberos action. */ tmp_action = -1; /* And our local copy. */ for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) tmpaddrs[i] = NULL; if ((y = cmkey(kerbtab,kerbtabn,"authentication type","",xxstring)) < 0) { if (y == -3) printf("?Authentication type not specified - nothing happens\n"); return(y); } tmpauth = y; debug(F101,"kerberos authentication","",tmpauth); switch (tmpauth) { case AUTH_KRB4: kv = 4; break; /* Don't assume values are the same */ case AUTH_KRB5: kv = 5; break; default: printf("?Authentication type not supported: \"%s\"\n",atmbuf); return(-9); } /* From here down is Kerberos */ ini_kerb(); /* Reset Init data to defaults */ if (kv == 4) { /* Set K4 defaults */ if (krb4_d_realm) makestr(&tmprealm,krb4_d_realm); if (krb4_d_principal) makestr(&tmpprinz,krb4_d_principal); if (krb4_d_instance) makestr(&tmpinst,krb4_d_instance); } else if (kv == 5) { /* Set K5 defaults */ if (krb5_d_cc) makestr(&tmpcache,krb5_d_cc); if (krb5_d_realm) makestr(&tmprealm,krb5_d_realm); if (krb5_d_principal) makestr(&tmpprinz,krb5_d_principal); if (krb5_d_instance) makestr(&tmpinst,krb5_d_instance); } for (i = 0; i <= KRB_I_MAX; i++) { /* Initialize switch values */ pv[i].sval = NULL; /* to null pointers */ pv[i].ival = 0; /* and 0 int values */ pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */ } if (kv == 4) { /* Kerberos 4 */ pv[KRB_I_LF].ival = krb4_d_lifetime; pv[KRB_I_PA].ival = krb4_d_preauth; if ((n = cmkey(krb_a_tbl,krb_a_n,"Kerberos 4 action","",xxstring)) < 0) { if (n == -3) printf("?Action not specified - nothing happens.\n"); return(n); } } else if (kv == 5) { /* Kerberos 5 */ pv[KRB_I_FW].ival = krb5_d_forwardable; pv[KRB_I_PR].ival = krb5_d_proxiable; pv[KRB_I_LF].ival = krb5_d_lifetime; pv[KRB_I_RB].ival = krb5_d_renewable; pv[KRB_I_K4].ival = krb5_d_getk4; pv[KRB_I_NAD].ival = krb5_d_no_addresses; /* Make help message that shows switches and action keywords */ ckstrncpy(tmphlp,"Kerberos 5 action, one of the following:\n ",256); for (i = 0; i < krb_a_n; i++) { ckstrncat(tmphlp,krb_a_tbl[i].kwd,sizeof(tmphlp)); if (i == krb_a_n - 1) ckstrncat(tmphlp,"\nor switch",sizeof(tmphlp)); else ckstrncat(tmphlp," ",sizeof(tmphlp)); } /* Set up first set of chained FDB's */ cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ tmphlp, /* hlpmsg */ "", /* default (none) */ "", /* addtl string data */ krb_s_n, /* Switch table size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ krb_s_tbl, /* Switch table */ &kw /* Pointer to next FDB */ ); cmfdbi(&kw, /* Second FDB - action keywords */ _CMKEY, /* fcode */ "Kerberos action", /* hlpmsg */ "", /* default (none) */ "", /* addtl string data */ krb_a_n, /* Switch table size */ 0, /* addtl num data (0 = NOT switch) */ xxstring, /* Processing function */ krb_a_tbl, /* Keyword table */ NULL /* Pointer to next FDB (none) */ ); /* Parse */ while (1) { /* Parse 0 or more switches */ rc = cmfdb(&sw); /* Parse something */ debug(F101,"kerberos cmfdb 1 rc","",rc); if (rc < 0) { /* Error */ if (rc == -3) printf("?Action not specified - nothing happens.\n"); return(rc); /* or reparse needed */ } if (cmresult.fdbaddr != &sw) /* Break out if not a switch */ break; c = cmgbrk(); /* Have switch - get break character */ getval = (c == ':' || c == '='); /* Must parse an agument? */ if (getval && !(cmresult.kflags & CM_ARG)) { printf("?This switch does not take arguments\n"); return(-9); /* OK because nothing malloc'd yet */ } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } n = cmresult.nresult; /* Numeric result = switch value */ debug(F101,"kerberos command switch","",n); switch (n) { /* Handle the switch */ case KRB_S_CA: /* /CACHE: */ p = krb5_d_cc ? krb5_d_cc : ""; if ((y = cmofi("Name of cache file",p,&s,xxstring)) < 0) { if (y == -3) s = NULL; else return(y); } makestr(&tmpcache,s); break; default: printf("?Unexpected switch value - internal error\n"); return(-9); /* (if) nothing malloc'd yet. */ } } if (cmresult.fdbaddr != &kw) { /* Checking... */ printf("?Unexpected result - internal error\n"); return(-9); /* Nothing malloc'd yet. */ } n = cmresult.nresult; /* Get keyword value */ } else { printf("?Unexpected Kerberos version - Internal error\n"); return(-9); } debug(F101,"kerberos action","",n); switch (n) { case KRB_A_IN: /* INITIALIZE */ case KRB_A_DE: /* DESTROY */ case KRB_A_LC: /* LIST-CREDENTIALS */ tmp_action = n; /* OK, set */ break; default: /* Not OK, punt. */ printf("?Unexpected action - internal error\n"); return(-9); } if (tmp_action == KRB_A_IN) { /* Action is INITIALIZE */ int x; cmfdbi(&sw, /* INITIALIZE switches */ _CMKEY, /* fcode */ "Principal,\n or optional INITIALIZE switch(es)", /* hlpmsg */ "", /* default (none) */ "", /* addtl string data */ kv == 4 ? krb4_i_n : krb5_i_n, /* Switch table size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ kv == 4 ? krb4_i_tbl : krb5_i_tbl, /* Switch table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* 3rd FDB - command to send from */ _CMFLD, /* fcode */ "Principal", /* hlpmsg */ kv == 4 ? krb4_d_principal : krb5_d_principal, /* principal */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); while (1) { /* Parse INIT switches or principal */ rc = cmfdb(&sw); debug(F101,"kerberos cmfdb 2 rc","",rc); if (rc < 0) { if (rc == -3) printf("?Principal name required\n"); goto kerbx; } debug(F101,"kerberos cmfdb 2 fcode","",cmresult.fcode); if (cmresult.fcode != _CMKEY) /* Not a switch, quit switch loop */ break; c = cmgbrk(); /* Switch - get break character */ debug(F101,"kerberos cmfdb 2 cmgbrk","",c); getval = (c == ':' || c == '='); if (getval && !(cmresult.kflags & CM_ARG)) { printf("?This switch does not take arguments\n"); return(-9); /* OK because nothing malloc'd yet */ } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } n = cmresult.nresult; /* Numeric result = switch value */ switch (n) { /* These don't take args... */ case KRB_I_PA: /* /PREAUTH */ case KRB_I_FW: /* /FORWARDABLE */ case KRB_I_PR: /* /PROXIABLE */ case KRB_I_RN: /* /RENEW */ case KRB_I_VA: /* /VALIDATE */ case KRB_I_NPA: /* /NOT-PREAUTH */ case KRB_I_NFW: /* /NOT-FORWARDABLE */ case KRB_I_NPR: /* /NOT-PROXIABLE */ case KRB_I_VB: /* /VERBOSE */ case KRB_I_BR: /* /BRIEF */ case KRB_I_K4: /* /KERBEROS4 */ case KRB_I_NK4: /* /NO-KERBEROS4 */ case KRB_I_POP: /* /POPUP */ case KRB_I_NAD: /* /NO-ADDRESSES */ if (getval) { printf("?This switch does not take a value\n"); rc = -9; goto kerbx; } switch (n) { case KRB_I_NPA: pv[KRB_I_PA].ival = 0; break; case KRB_I_NFW: pv[KRB_I_FW].ival = 0; break; case KRB_I_NPR: pv[KRB_I_PR].ival = 0; break; case KRB_I_VB: pv[KRB_I_BR].ival = 0; break; case KRB_I_NK4: pv[KRB_I_K4].ival = 0; break; default: pv[n].ival = 1; } break; /* These do take arguments */ case KRB_I_RB: /* /RENEWABLE: */ pv[n].ival = 0; if (!getval) break; if ((rc = cmnum("Minutes",ckitoa(krb5_init.renewable), 10,&y, xxstring)) < 0) goto kerbx; pv[n].ival = y; break; case KRB_I_LF: /* /LIFETIME: */ pv[n].ival = 0; /* Default is previous value */ sprintf(tmpbuf,"%d", /* SAFE */ kv == 4 ? krb4_init.lifetime : krb5_init.lifetime ); if (!getval) break; if ((rc = cmnum("Minutes",tmpbuf,10,&y, xxstring)) < 0) goto kerbx; pv[n].ival = y; break; case KRB_I_PD: /* /POSTDATE: */ if (pv[n].sval) { free(pv[n].sval); pv[n].sval = NULL; } if (!getval) break; if ((rc = cmdate("date-time","",&s,0,xxstring)) < 0) goto kerbx; makestr(&(pv[n].sval),s); break; case KRB_I_SR: /* /SERVICE: */ if (pv[n].sval) { free(pv[n].sval); pv[n].sval = NULL; } if (!getval) break; if ((rc = cmfld("Service-name","",&s,xxstring)) < 0) goto kerbx; makestr(&(pv[n].sval),s); break; case KRB_I_RL: /* /REALM: */ if (pv[n].sval) { free(pv[n].sval); pv[n].sval = NULL; } if (!getval) break; if (kv == 4) p = krb4_d_realm ? krb4_d_realm : ""; else p = krb5_d_realm ? krb5_d_realm : ""; if ((rc = cmfld("Realm",p,&s,xxstring)) < 0) goto kerbx; makestr(&(pv[n].sval),s); break; case KRB_I_IN: /* /INSTANCE: */ if (pv[n].sval) { free(pv[n].sval); pv[n].sval = NULL; } if (!getval) break; if (kv == 4) p = krb4_d_instance ? krb4_d_instance : ""; else p = krb5_d_instance ? krb5_d_instance : ""; if ((rc = cmfld("Instance",p,&s,xxstring)) < 0) goto kerbx; makestr(&(pv[n].sval),s); break; case KRB_I_PW: /* /PASSWORD: */ debok = 0; if (pv[n].sval) { free(pv[n].sval); pv[n].sval = NULL; } if (!getval) break; if ((rc = cmfld("Password","",&s,xxstring)) < 0) if (rc != -3) goto kerbx; makestr(&(pv[n].sval),s); break; case KRB_I_ADR: /* /ADDRESSES:{} */ if (pv[n].sval) { free(pv[n].sval); pv[n].sval = NULL; } if (!getval) break; if ((rc = cmfld("List of IP addresses","",&s,xxstring)) < 0) goto kerbx; makelist(s,tmpaddrs,KRB5_NUM_OF_ADDRS); for (i = 0; i < KRB5_NUM_OF_ADDRS && tmpaddrs[i]; i++) { if (inet_addr(tmpaddrs[i]) == 0xffffffff) { printf("invalid ip address: %s\n",tmpaddrs[i]); rc = -9; goto kerbx; } } pv[KRB_I_NAD].ival = 0; break; default: printf("?Unexpected switch value - internal error\n"); rc = -9; goto kerbx; } } if (cmresult.fcode != _CMFLD) { printf("?Unexected result - internal error\n"); rc = -9; goto kerbx; } /* cmresult.sresult may be of the form PRINCIPAL@REALM */ i = ckindex("@",cmresult.sresult,0,0,0); if (i != 0) { makestr(&tmprealm,&cmresult.sresult[i]); cmresult.sresult[i-1] = '\0'; } makestr(&tmpprinz,cmresult.sresult); /* Principal (user) */ if ((rc = cmcfm()) < 0) { /* Now get confirmation */ if (rc == -3) { printf("?Principal name required\n"); } goto kerbx; } if (!tmpprinz || !tmpprinz[0]) { printf("?Principal name required\n"); goto kerbx; } if (!pv[KRB_I_RN].ival && !pv[KRB_I_VA].ival) { /* Don't use a password if Validating or Renewing */ if (pv[KRB_I_PW].sval) { /* If they gave a /PASSWORD switch */ makestr(&tmppswd,pv[KRB_I_PW].sval); /* use this value */ } #ifdef COMMENT /* Password prompting has been moved to ck_krb[45]_initTGT() */ else { /* Otherwise must prompt for it */ char prmpt[80]; if (pv[KRB_I_RL].sval) sprintf(prmpt,"%s@%s's Password: ", tmpprinz,pv[KRB_I_RL].sval); else if (tmprealm) sprintf(prmpt,"%s@%s's Password: ", tmpprinz,tmprealm); else sprintf(prmpt,"%s's Password: ",tmpprinz); #ifdef OS2 if (pv[KRB_I_POP].ival) { char passwd[80]=""; readpass(prmpt,passwd,80); makestr(&tmppswd,passwd); memset(passwd,0,80); } else #endif /* OS2 */ { #ifdef CK_RECALL on_recall = 0; #endif /* CK_RECALL */ cmsavp(psave,PROMPTL); /* Save old prompt */ cmsetp(prmpt); /* Make new prompt */ concb((char)escape); /* Put console in cbreak mode */ cmini(0); /* and no-echo mode */ /* Issue prompt if at top level */ if (pflag) prompt(xxstring); cmres(); /* Reset the parser */ for (rc = -1; rc < 0; ) { /* Prompt till they answer */ /* Get a literal line of text */ rc = cmtxt("","",&s,NULL); cmres(); /* Reset the parser again */ } makestr(&tmppswd,s); printf("\n"); /* Echo a CRLF */ cmsetp(psave); /* Restore original prompt */ } } x = 0; /* Check for password */ if (tmppswd) if (*tmppswd) x = 1; if (!x) { printf("?Password required\n"); goto kerbx; } #endif /* COMMENT */ } } else if (kv == 5 && tmp_action == KRB_A_LC) { /* LIST-CREDENTIALS */ tmp_klc = 0; while (1) { if ((x = cmkey(klctab,nklctab,"Switch","",xxstring)) < 0) { if (x == -3) { if ((rc = cmcfm()) < 0) goto kerbx; else break; } else { rc = x; goto kerbx; } } tmp_klc |= x; } } else if ((rc = cmcfm()) < 0) /* DESTROY, just confirm */ goto kerbx; /* Done - Move confirmed data to final locations */ krb_action = tmp_action; /* Action requested */ krb_op.version = kv; /* Kerberos version */ krb_op.cache = tmpcache; /* Cache file */ tmpcache = NULL; /* So we don't free it */ switch (krb_action) { case KRB_A_IN: /* INITIALIZE */ if (kv == 5) { krb5_init.forwardable = pv[KRB_I_FW].ival; krb5_init.proxiable = pv[KRB_I_PR].ival; krb5_init.lifetime = pv[KRB_I_LF].ival; krb5_init.renew = pv[KRB_I_RN].ival; krb5_init.renewable = pv[KRB_I_RB].ival; krb5_init.validate = pv[KRB_I_VA].ival; /* Here we just reassign the pointers and then set them to NULL */ /* so they won't be freed below. */ krb5_init.postdate = pv[KRB_I_PD].sval; pv[KRB_I_PD].sval = NULL; krb5_init.service = pv[KRB_I_SR].sval; pv[KRB_I_SR].sval = NULL; if (pv[KRB_I_RL].sval) { krb5_init.realm = pv[KRB_I_RL].sval; pv[KRB_I_RL].sval = NULL; } else if (tmprealm) { krb5_init.realm = tmprealm; tmprealm = NULL; } if (pv[KRB_I_IN].sval) { krb5_init.instance = pv[KRB_I_IN].sval; pv[KRB_I_IN].sval = NULL; } else if ( tmpinst ) { krb5_init.instance = tmpinst; tmpinst = NULL; } if (tmpprinz) { krb5_init.principal = tmpprinz; tmpprinz = NULL; } krb5_init.password = tmppswd; tmppswd = NULL; krb5_init.getk4 = pv[KRB_I_K4].ival; if (krb5_init.getk4) { krb4_init.lifetime = pv[KRB_I_LF].ival; if (krb5_init.realm) makestr(&krb4_init.realm,krb5_init.realm); krb4_init.preauth = krb4_d_preauth; krb4_init.verbose = pv[KRB_I_BR].ival ? 0 : 1; if (krb5_init.principal) makestr(&krb4_init.principal,krb5_init.principal); if (krb5_init.principal) makestr(&krb4_init.password,krb5_init.password); } krb5_init.no_addresses = pv[KRB_I_NAD].ival; if (tmpaddrs[0]) { for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) { if (krb5_init.addrs[i]) { free(krb5_init.addrs[i]); krb5_init.addrs[i] = NULL; } krb5_init.addrs[i] = tmpaddrs[i]; tmpaddrs[i] = NULL; } } } else if (kv == 4) { /* Same deal for Kerberos 4 */ krb4_init.lifetime = pv[KRB_I_LF].ival; if (pv[KRB_I_RL].sval) { krb4_init.realm = pv[KRB_I_RL].sval; pv[KRB_I_RL].sval = NULL; } else if ( tmprealm ) { krb4_init.realm = tmprealm; tmprealm = NULL; } if (pv[KRB_I_IN].sval) { krb4_init.instance = pv[KRB_I_IN].sval; pv[KRB_I_IN].sval = NULL; } else if ( tmpinst ) { krb4_init.instance = tmpinst; tmpinst = NULL; } krb4_init.preauth = pv[KRB_I_PA].ival; krb4_init.verbose = pv[KRB_I_BR].ival ? 0 : 1; if (tmpprinz) { krb4_init.principal = tmpprinz; tmpprinz = NULL; } krb4_init.password = tmppswd; tmppswd = NULL; } break; case KRB_A_LC: /* List Credentials */ krb5_lc.encryption = tmp_klc & XYKLCEN; krb5_lc.flags = tmp_klc & XYKLCFL; krb5_lc.addr = tmp_klc & XYKLCAD; break; } /* Common exit - Free temporary storage */ kerbx: for (i = 0; i <= KRB_I_MAX; i++) { /* Free malloc'd switch data */ if (pv[i].sval) free(pv[i].sval); } for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) { if (tmpaddrs[i]) free(tmpaddrs[i]); } if (tmpprinz) free(tmpprinz); /* And these too. */ if (tmppswd) free(tmppswd); if (tmpcache) free(tmpcache); if (tmprealm) free(tmprealm); if (tmpinst) free(tmpinst); return(rc); /* Return the return code */ } #endif /* CK_KERBEROS */ #ifdef CK_LOGIN int #ifdef CK_ANSIC ckxlogin(CHAR * userid, CHAR * passwd, CHAR * acct, int promptok) #else /* CK_ANSIC */ ckxlogin(userid, passwd, acct, promptok) CHAR * userid; CHAR * passwd; CHAR * acct; int promptok; #endif /* CK_ANSIC */ /* ckxlogin */ { #ifdef CK_RECALL extern int on_recall; /* around Password prompting */ #endif /* CK_RECALL */ #ifdef COMMENT extern int guest; #endif /* COMMENT */ int rprompt = 0; /* Restore prompt */ #ifdef CKSYSLOG int savlog; #endif /* CKSYSLOG */ extern int what, srvcdmsg; int x = 0, ok = 0, rc = 0; CHAR * _u = NULL, * _p = NULL, * _a = NULL; debug(F111,"ckxlogin userid",userid,promptok); debug(F110,"ckxlogin passwd",passwd,0); isguest = 0; /* Global "anonymous" flag */ if (!userid) userid = (CHAR *)""; if (!passwd) passwd = (CHAR *)""; debug(F111,"ckxlogin userid",userid,what); #ifdef CK_RECALL on_recall = 0; #endif /* CK_RECALL */ #ifdef CKSYSLOG savlog = ckxsyslog; /* Save and turn off syslogging */ #endif /* CKSYSLOG */ if ((!*userid || !*passwd) && /* Need to prompt for missing info */ promptok) { cmsavp(psave,PROMPTL); /* Save old prompt */ debug(F110,"ckxlogin saved",psave,0); rprompt = 1; } if (!*userid) { if (!promptok) return(0); cmsetp("Username: "); /* Make new prompt */ concb((char)escape); /* Put console in cbreak mode */ cmini(1); /* Flush typeahead */ #ifdef IKS_OPTION debug(F101, "ckxlogin TELOPT_SB(TELOPT_KERMIT).kermit.me_start", "", TELOPT_SB(TELOPT_KERMIT).kermit.me_start ); #endif /* IKS_OPTION */ while (ttchk() > 0) { x = ttinc(0); debug(F101,"ckxlogin flush user x","",x); if (x < 0) doexit(GOOD_EXIT,0); /* Connection lost */ #ifdef TNCODE if (sstelnet) { if (x == IAC) { x = tn_doop((CHAR)(x & 0xff),ckxech,ttinc); debug(F101,"ckxlogin user tn_doop","",x); #ifdef IKS_OPTION debug(F101, "ckxlogin user TELOPT_SB(TELOPT_KERMIT).kermit.me_start", "", TELOPT_SB(TELOPT_KERMIT).kermit.me_start ); #endif /* IKS_OPTION */ if (x < 0) goto XCKXLOG; switch (x) { case 1: ckxech = 1; break; /* Turn on echoing */ case 2: ckxech = 0; break; /* Turn off echoing */ #ifdef IKS_OPTION case 4: /* IKS event */ if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start) break; /* else fall thru... */ #endif /* IKS_OPTION */ case 6: /* Logout */ goto XCKXLOG; } } } #endif /* TNCODE */ } if (pflag) prompt(xxstring); /* Issue prompt if at top level */ cmres(); /* Reset the parser */ for (x = -1; x < 0;) { /* Prompt till they answer */ /* Get a literal line of text */ x=cmtxt("Your username, or \"ftp\", or \"anonymous\"","",&s,NULL); if (x == -4 || x == -10) { printf("\r\n%sLogin cancelled\n", x == -10 ? "Timed out: " : ""); #ifdef CKSYSLOG ckxsyslog = savlog; #endif /* CKSYSLOG */ doexit(GOOD_EXIT,0); } if (sstate) /* Did a packet come instead? */ goto XCKXLOG; cmres(); /* Reset the parser again */ } if ((_u = (CHAR *)malloc((int)strlen(s) + 1)) == NULL) { printf("?Internal error: malloc\n"); goto XCKXLOG; } else { strcpy((char *)_u,s); /* safe */ userid = _u; } } ok = zvuser((char *)userid); /* Verify username */ debug(F111,"ckxlogin zvuser",userid,ok); if (!*passwd && promptok #ifdef COMMENT && guest #endif /* COMMENT */ ) { char prmpt[80]; #ifdef CKSYSLOG savlog = ckxsyslog; /* Save and turn off syslogging */ ckxsyslog = 0; #endif /* CKSYSLOG */ /* Flush typeahead again */ while (ttchk() > 0) { x = ttinc(0); debug(F101,"ckxlogin flush user x","",x); #ifdef TNCODE if (sstelnet) { if (x == IAC) { x = tn_doop((CHAR)(x & 0xff),ckxech,ttinc); debug(F101,"ckxlogin pass tn_doop","",x); #ifdef IKS_OPTION debug(F101, "ckxlogin pass TELOPT_SB(TELOPT_KERMIT).kermit.me_start", "", TELOPT_SB(TELOPT_KERMIT).kermit.me_start ); #endif /* IKS_OPTION */ if (x < 0) goto XCKXLOG; switch (x) { case 1: ckxech = 1; break; /* Turn on echoing */ case 2: ckxech = 0; break; /* Turn off echoing */ case 4: /* IKS event */ if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start) break; /* else fall thru... */ case 6: /* Logout */ goto XCKXLOG; } } } #endif /* TNCODE */ } if (!strcmp((char *)userid,"anonymous") || !strcmp((char *)userid,"ftp")) { if (!ok) goto XCKXLOG; ckstrncpy(prmpt,"Enter e-mail address as Password: ",80); } else if (*userid && strlen((char *)userid) < 60) { #ifdef NT extern CHAR * pReferenceDomainName; if (pReferenceDomainName) ckmakxmsg(prmpt, 80, "Enter ", pReferenceDomainName, "\\\\", userid, "'s Password: ", NULL,NULL,NULL,NULL,NULL,NULL,NULL ); else #endif /* NT */ ckmakmsg(prmpt,80,"Enter ",(char *)userid,"'s Password: ",NULL); } else ckstrncpy(prmpt,"Enter Password: ",80); cmsetp(prmpt); /* Make new prompt */ concb((char)escape); /* Put console in cbreak mode */ if (strcmp((char *)userid,"anonymous") && strcmp((char *)userid,"ftp")) { /* and if not anonymous */ debok = 0; cmini(0); /* and no-echo mode */ } else { cmini(1); } if (pflag) prompt(xxstring); /* Issue prompt if at top level */ cmres(); /* Reset the parser */ for (x = -1; x < 0;) { /* Prompt till they answer */ #ifdef CK_PAM gotemptypasswd=0; #endif /* CK_PAM */ x = cmtxt("","",&s,NULL); /* Get a literal line of text */ if (x == -4 || x == -10) { printf("\r\n%sLogin cancelled\n", x == -10 ? "Timed out: " : ""); #ifdef CKSYSLOG ckxsyslog = savlog; #endif /* CKSYSLOG */ doexit(GOOD_EXIT,0); } #ifdef CK_PAM if (!*s) gotemptypasswd = 1; #endif /* CK_PAM */ if (sstate) /* In case of a Kermit packet */ goto XCKXLOG; cmres(); /* Reset the parser again */ } printf("\r\n"); /* Echo a CRLF */ if ((_p = (CHAR *)malloc((int)strlen(s) + 1)) == NULL) { printf("?Internal error: malloc\n"); goto XCKXLOG; } else { strcpy((char *)_p,s); /* safe */ passwd = _p; } } #ifdef CK_PAM else { cmres(); /* Reset the parser */ /* We restore the prompt now because the PAM engine will call */ /* readpass() which will overwrite psave. */ if (rprompt) { cmsetp(psave); /* Restore original prompt */ debug(F110,"ckxlogin restored",psave,0); rprompt = 0; } } #endif /* CK_PAM */ #ifdef CKSYSLOG ckxsyslog = savlog; #endif /* CKSYSLOG */ if (ok) { ok = zvpass((char *)passwd); /* Check password */ debug(F101,"ckxlogin zvpass","",ok); #ifdef CK_PAM } else { /* Fake pam password failure for nonexistent users */ sleep(1); printf("Authentication failure\n"); #endif /* CK_PAM */ } if (ok > 0 && isguest) { #ifndef NOPUSH nopush = 1; #endif /* NOPUSH */ srvcdmsg = 1; } rc = ok; /* Set the return code */ if ((char *)uidbuf != (char *)userid) ckstrncpy(uidbuf,(char *)userid,UIDBUFLEN); /* Remember username */ XCKXLOG: /* Common exit */ #ifdef CKSYSLOG ckxsyslog = savlog; /* In case of GOTO above */ #endif /* CKSYSLOG */ if (rprompt) { cmsetp(psave); /* Restore original prompt */ debug(F110,"ckxlogin restored",psave,0); } if (_u || _p || _a) { if (_u) free(_u); if (_p) free(_p); if (_a) free(_a); } return(rc); } int ckxlogout() { doexit(GOOD_EXIT,0); /* doexit calls zvlogout */ return(0); /* not reached */ } #endif /* CK_LOGIN */ #endif /* NOICP */ ckuusr.c000664 045065 024037 00001353275 14767410730 012674 0ustar00fdckermit000000 000000 #include "ckcsym.h" char *userv = "User Interface 10.0.332, 02 May 2023"; /* C K U U S R -- "User Interface" for C-Kermit (Part 1) */ /* Authors: Frank da Cruz , The Kermit Project, New York City Jeffrey E Altman Secure Endpoints Inc., New York City Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ /* Originally the entire user interface was in one module, ckuusr.c. Over the years it has been split into many modules: ckuus2.c, ckuus3.c, ..., ckuus7.c. ckuus2.c contains the HELP command parser and help-text strings; ckuusy.c contains the UNIX-style command-line interface; ckuusx.c contains routines needed by both the command-line interface and the interactive command parser. ckuusy.c handles command-line arguments. */ /* The ckuus*.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 different platforms -- like setting terminal modes or interrupts -- are invoked via calls to functions that are defined in the 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 usable by any program). Any command parser may be substituted for this one. The only requirements for the Kermit command parser are these: . Set parameters via global variables like duplex, speed, ttname, etc. See ckcmai.c for the declarations and descriptions of these variables. . If a command can be executed without the use of Kermit protocol, then execute the command directly and set the variable sstate to 0. Examples include 'set' commands, local directory listings, the 'connect' command. . 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. 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 an "as-name" - the name to send file(s) under, or the name under which to store incoming file(s); must not be wild. A null or empty value means to use the file's own name. cmlist is a list of 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. The debug() function writes to a debugging log. The intmsg() and chkint() functions provide the user i/o for interrupting file transfers. */ /* Includes */ #ifdef MULTINET #define MULTINET_OLD_STYLE /* Leave select prototype undefined */ #endif /* MULTINET */ #include "ckcdeb.h" #include "ckcasc.h" #include "ckcker.h" #include "ckcnet.h" /* Network symbols */ #include "ckuusr.h" #include "ckcxla.h" #ifdef CK_AUTHENTICATION /* fdc - only include this for secure builds */ #include "ckuath.h" /* AGN missing Kerberos prototypes 4-Nov-2021 */ #endif /* CK_AUTHENTICATION */ int g_fncact = -1; /* Needed for NOICP builds */ int noinit = 0; /* Flag for skipping init file */ int nscanfile = SCANFILEBUF; int rcdactive = 0; /* RCD active */ int keepallchars = 0; /* See cmfld() */ int locus = 1; /* Current LOCUS is LOCAL */ #ifdef OS2 int autolocus = 2; /* Automatic LOCUS switching: ASK */ #else /* OS2 */ int autolocus = 1; /* Automatic LOCUS switching enabled */ #endif /* OS2 */ #ifdef TYPEINTERPRET int type_intrp = 0; #endif /* TYPEINTERPRET */ #ifndef NOICP #ifdef CKLEARN #ifdef VMS #include /* For CKLEARN */ #endif /* VMS */ #endif /* CKLEARN */ #ifdef OS2 #ifndef NT #define INCL_NOPM #define INCL_VIO /* Needed for ckocon.h */ #define INCL_WINERRORS #include #undef COMMENT #else #define APIRET ULONG #include #ifdef CK_TAPI #include #include "ckntap.h" /* CK_TAPI definition */ #endif /* CK_TAPI */ #include "cknwin.h" #include "ckoreg.h" #endif /* NT */ #include "ckowin.h" #include "ckocon.h" extern int tcp_avail; extern bool viewonly; extern int k95stdout; extern int tt_scroll; #ifndef NOTERM extern int tt_status[VNUM]; #endif /* NOTERM */ #include "ckossh.h" #ifdef KUI #include "ikui.h" #endif /* KUI */ #ifdef SSHBUILTIN extern char * ssh_idf[32]; /* identity files */ extern int ssh_idf_n; #endif /* SSHBUILTIN */ #endif /* OS2 */ int optlines = 0; int didsetlin = 0; #ifdef NEWFTP extern int ftpget, ftpisopen(), doftpres(); _PROTOTYP(int doftptyp,(int)); _PROTOTYP(VOID doftpglobaltype,(int)); #endif /* NEWFTP */ #ifdef VMS extern int batch; #endif /* VMS */ #ifdef datageneral #include #define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd) #endif /* datageneral */ #include "ckcfnp.h" /* Prototypes (must be last) */ #ifdef CK_ANSIC /* Prototypes for static functions - fdc 30 November 2022 */ static VOID doend( int ); static int dodcl( int ); static int addsend( int ); static int clrarray( int ); static int doadd( int, int ); static int doeval( int ); static int xdohttp(int, char *, char *, char *, char *, char *, char *, char *, char *, char, int ); #endif /* CK_ANSIC */ #ifdef OS2 int ttgcwsz(); /* ckocon.c */ void os2push(); /* ckocon.c */ void clrboscr_escape(BYTE, CHAR); /* ckoco3.c */ int os2getcp(void); /* ckotio.c */ #ifndef NOLOCAL int clear(); /* ckuusx.c */ #endif /* NOLOCAL */ #ifdef NT void StartDialer(); /* cknwin.c */ DWORD ckGetLongPathName(LPCSTR,LPSTR,DWORD); /* ckofio.c */ #ifdef CK_TAPI int dotapi(); /* ckuus3.c */ #endif /* CK_TAPI */ #endif /* NT */ #endif /* OS2 */ extern int xcmdsrc, hints, cmflgs, whyclosed; int isinternal = 0; /* Flag for internally-defined macro */ char * hlptok = NULL; #ifdef CK_TTGWSIZ /* Whether to use more-prompting */ int xaskmore = 1; /* Momentary setting */ int saveask = 1; /* Permanent setting */ #else int xaskmore = 0; int saveask = 0; #endif /* CK_TTGWSIZ */ #ifndef NOCSETS extern int nfilc; extern struct keytab fcstab[]; extern int fcharset; #endif /* NOCSETS */ char * g_pswd = NULL; int g_pcpt = -1; int g_pflg = -1; extern int cmd_rows, cmd_cols; #ifdef CKROOT extern int ckrooterr; #endif /* CKROOT */ extern int inserver, filepeek; #ifdef CKLEARN FILE * learnfp = NULL; char * learnfile = NULL; int learning = 0; #endif /* CKLEARN */ #ifndef NOXFER extern int atcapr, atdiso, nfils, moving, protocol, sendmode, epktflg, size, sndsrc, server, displa, fncnv, fnspath, fnrpath, xfermode, urpsiz, spsizf, spsiz, spsizr, spmax, wslotr, prefixing, fncact, reliable, setreliable; #ifdef IKSDCONF extern int iksdcf; #endif /* IKSDCONF */ #ifdef CK_LOGIN extern int isguest; #endif /* CK_LOGIN */ extern CK_OFF_T sendstart; extern char *cmarg, *cmarg2, **cmlist, *dftty; extern struct keytab fntab[]; extern int nfntab; extern struct ck_p ptab[NPROTOS]; int sndcmd = 0; /* Last command was a SEND-class command. */ int g_xfermode = -1; int g_proto = -1; int g_urpsiz = -1; int g_spsizf = -1; int g_spsiz = -1; int g_spsizr = -1; int g_spmax = -1; int g_wslotr = -1; int g_prefixing = -1; int g_fncnv = -1; int g_fnspath = -1; int g_fnrpath = -1; int g_fnact = -1; int g_displa = -1; int g_spath = -1; int g_rpath = -1; char * g_sfilter = NULL; char * g_rfilter = NULL; extern int patterns; #ifdef PATTERNS extern char *txtpatterns[], *binpatterns[]; int g_patterns = -1; #endif /* PATTERNS */ int g_skipbup = -1; #ifdef PIPESEND extern int usepipes, pipesend; extern char * sndfilter; #endif /* PIPESEND */ #ifndef NOSPL extern int sndxlo, sndxhi, sndxin; #endif /* NOSPL */ extern char fspec[]; /* Most recent filespec */ extern int fspeclen; /* Length of fspec[] buffer */ #ifndef NOFRILLS extern int rmailf; /* MAIL command items */ extern char optbuf[]; #endif /* NOFRILLS */ extern int en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai, en_pri, en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who, en_ret, en_xit, en_mkd, en_rmd, en_asg; #ifndef NOMSEND /* Multiple SEND */ extern char *msfiles[]; int filesinlist = 0; /* And ADD ... */ extern struct filelist * filehead; extern struct filelist * filetail; extern struct filelist * filenext; extern int addlist; #endif /* NOMSEND */ static struct keytab addtab[] = { #ifdef PATTERNS { "binary-patterns", ADD_BIN, 0 }, #endif /* PATTERNS */ #ifndef NOMSEND { "send-list", ADD_SND, 0 }, #endif /* NOMSEND */ #ifdef PATTERNS { "text-patterns", ADD_TXT, 0 }, #endif /* PATTERNS */ { "", 0, 0 } }; static int naddtab = sizeof(addtab)/sizeof(struct keytab) - 1; #ifndef NOCSETS struct keytab assoctab[] = { { "file-character-set", ASSOC_FC, 0 }, { "transfer-character-set", ASSOC_TC, 0 }, { "xfer-character-set", ASSOC_TC, CM_INV } }; static int nassoc = sizeof(assoctab)/sizeof(struct keytab); extern int afcset[MAXFCSETS+1]; /* Character-set associations */ extern int axcset[MAXTCSETS+1]; #endif /* NOCSETS */ #ifndef ADDCMD #ifndef NOMSEND #define ADDCMD #endif /* NOMSEND */ #ifndef ADDCMD #ifdef PATTERNS #define ADDCMD #endif /* PATTERNS */ #endif /* ADDCMD */ #endif /* ADDCMD */ #endif /* NOXFER */ /* External Kermit Variables, see ckmain.c for description. */ extern xx_strp xxstring; extern long xvernum; extern int local, xitsta, binary, msgflg, escape, duplex, quiet, tlevel, pflag, zincnt, ckxech, carrier, what, nopush, haveline, bye_active; #ifdef TNCODE extern int debses; extern char tn_msg[]; #endif /* TNCODE */ int sleepcan = 1; int g_binary = -1; int g_recursive = -1; int g_matchdot = -1; extern int nolinks; extern long vernum; extern char *versio, *copyright[]; extern char *ckxsys; #ifndef NOHELP extern char *introtxt[]; extern char *newstxt[]; #endif /* NOHELP */ #ifndef OS2 #ifndef UNIX extern char *PWDCMD; #endif /* UNIX */ extern char *WHOCMD; #endif /* OS2 */ extern char ttname[]; extern CHAR sstate; extern int network; /* Have active network connection */ extern int nettype; /* Type of network */ extern int ttnproto; /* NET_TCPB protocol */ #ifndef NODIAL extern int dialsta, dialatmo, dialcon, dialcq; /* DIAL status, etc. */ #endif /* NODIAL */ #ifdef CK_APC extern int apcactive, apcstatus; #endif /* CK_APC */ #ifndef NOPUSH #ifndef NOFRILLS extern char editor[]; extern char editopts[]; extern char editfile[]; #endif /* NOFRILLS */ #endif /* NOPUSH */ #ifdef BROWSER extern char browser[]; /* Web browser application */ extern char browsopts[]; /* Web browser options */ extern char browsurl[]; /* Most recent URL */ #endif /* BROWSER */ #ifndef NOFTP char ftpapp[CKMAXPATH+1] = { NUL, NUL }; /* ftp executable */ char ftpopts[128] = { NUL, NUL }; /* ftp command-line options */ #endif /* NOFTP */ extern struct keytab onoff[]; /* On/Off keyword table */ #ifdef CK_TMPDIR int f_tmpdir = 0; /* Directory changed temporarily */ char savdir[TMPDIRLEN]; /* For saving current directory */ #endif /* CK_TMPDIR */ int activecmd = -1; /* Keyword index of active command */ int doconx = -1; /* CONNECT-class command active */ int ooflag = 0; /* User-settable on/off flag */ int rcflag = 0; /* Pointer to home directory string */ int repars, /* Reparse needed */ techo = 0; /* Take echo */ int secho = 1; /* SCRIPT echo */ int xitwarn = /* Warn about open connection on exit */ #ifdef NOWARN 0 #else 1 #endif /* NOWARN */ ; struct keytab onoffsw[] = { { "/off", 0, 0 }, { "/on", 1, 0 } }; #ifdef CKEXEC struct keytab redirsw[] = { { "/redirect", 1, 0 } }; #endif /* CKEXEC */ #ifndef NOXMIT /* Variables for TRANSMIT command */ int xmitx = 1; /* Whether to echo during TRANSMIT */ int xmitf = 0; /* Character to fill empty lines */ int xmitl = 0; /* 0 = Don't send linefeed too */ int xmitp = LF; /* Host line prompt */ int xmits = 0; /* Use shift-in/shift-out, 0 = no */ int xmitw = 0; /* Milliseconds to pause during TRANSMIT */ int xmitt = 1; /* Seconds to wait for each char to echo */ int xmita = 1; /* Action upon timeout */ #define XMI_BIN 1 #define XMI_TXT 2 #define XMI_CMD 3 #define XMI_TRA 4 #define XMI_VRB 5 #define XMI_QUI 6 #define XMI_NOW 7 #define XMI_NOE 8 static struct keytab xmitsw[] = { /* TRANSMIT command options */ { "/binary", XMI_BIN, 0 }, #ifdef PIPESEND { "/command", XMI_CMD, CM_INV|CM_PSH }, #endif /* PIPESEND */ { "/noecho", XMI_NOE, 0 }, { "/nowait", XMI_NOW, 0 }, #ifdef PIPESEND { "/pipe", XMI_CMD, 0 }, #endif /* PIPESEND */ #ifdef COMMENT { "/quiet", XMI_QUI, 0 }, #endif /* COMMENT */ { "/text", XMI_TXT, 0 }, { "/transparent", XMI_TRA, 0 }, #ifdef COMMENT { "/verbose", XMI_VRB, 0 }, #endif /* COMMENT */ { "", 0, 0 } }; #define NXMITSW sizeof(xmitsw)/sizeof(struct keytab) - 1 static int nxmitsw = NXMITSW; #endif /* NOXMIT */ /* Declarations from ck?fio.c module */ extern char *SPACMD, *SPACM2; /* SPACE commands */ /* Command-oriented items */ #ifdef DCMDBUF extern char *cmdbuf; /* Command buffers */ extern char *atmbuf; extern char *line; /* Character buffer for anything */ extern char *tmpbuf; /* Short temporary string buffer */ extern int *ifcmd; extern int *intime; extern int *inpcas; #else extern char cmdbuf[]; /* Command buffers */ extern char atmbuf[]; extern char line[]; /* Character buffer for anything */ extern char tmpbuf[]; /* Temporary buffer */ extern int ifcmd[]; extern int intime[]; extern int inpcas[]; #endif /* DCMDBUF */ #ifndef NOSPL extern char * prstring[]; #endif /* NOSPL */ char *lp; /* Pointer to line buffer */ #ifndef NOSPL int vareval = 1; /* Evaluation method */ int unkmacro = 0; /* Flag for in ON_UNKNOWN_COMMAND */ int oldeval = 0; char evalbuf[33]; /* EVALUATE result */ extern char * inpbuf; /* Buffer for INPUT and REINPUT */ char *inpbp; /* And pointer to same */ int m_found; /* MINPUT result */ int i_active = 0; /* INPUT command is active */ char *ms[MINPMAX]; /* Pointers to MINPUT strings */ static int mpinited = 0; /* Flag they have been initialized */ static int mp[MINPMAX]; /* and MINPUT flags */ extern int fndiags, fnerror, fnsuccess; /* Function diagnostics */ #ifndef NOSEXP char * lastsexp = NULL; /* S-Expressions */ char * sexpval = NULL; int sexpecho = SET_AUTO; #endif /* NOSEXP */ #endif /* NOSPL */ char psave[PROMPTL] = { NUL }; /* For saving & restoring prompt */ extern int success; /* Command success/failure flag */ extern int cmdlvl; /* Current position in command stack */ #ifndef NOSPL int /* SET INPUT parameters. */ /* Note, INPUT TIMEOUT, intime[], is on the command-level stack. */ inbufsize = 0, /* INPUT buffer size */ indef = 1, /* default timeout, seconds */ inecho = 1, /* 1 = echo on */ inautodl = 0, /* INPUT autodownload */ inintr = 1, /* INPUT interrupion allowed */ insilence = 0; /* 0 = no silence constraint */ #ifdef CKFLOAT CKFLOAT inscale = 1.0; /* Timeout scale factor */ #endif /* CKFLOAT */ #ifdef OS2 int interm = 1; /* Terminal emulator displays input */ #endif /* OS2 */ int maclvl = -1; /* Macro nesting level */ int mecho = 0; /* Macro echo, 0 = don't */ char varnam[6]; /* For variable names */ extern int macargc[]; /* ARGC from macro invocation */ extern char *m_arg[MACLEVEL][NARGS]; /* Stack of macro arguments */ extern char *mrval[]; extern char **a_ptr[]; /* Array pointers */ extern int a_dim[]; /* Array dimensions */ extern int a_link[]; #ifdef DCMDBUF extern struct cmdptr *cmdstk; /* The command stack itself */ #else extern struct cmdptr cmdstk[]; /* The command stack itself */ #endif /* DCMDBUF */ long ck_alarm = 0; /* SET ALARM value */ char alrm_date[24] = { ' ',' ',' ',' ',' ',' ',' ',' ',' ' }; char alrm_time[24] = { ' ',' ',' ',' ',' ',' ',' ' }; struct keytab inputsw[] = { { "/clear", INPSW_CLR, 0 }, { "/count", INPSW_COU, CM_ARG }, { "/nomatch", INPSW_NOM, 0 }, { "/nowrap", INPSW_NOW, 0 } }; static int ninputsw = sizeof(inputsw)/sizeof(struct keytab); /* The following should be reconciled with the above */ #ifdef COMMENT /* INPUT switches not used yet... */ static struct keytab inswtab[] = { #ifdef COMMENT { "/assign", IN_ASG, CM_ARG }, #endif /* COMMENT */ { "/autodownload", IN_ADL, CM_ARG }, { "/case", IN_CAS, CM_ARG }, { "/echo", IN_ECH, CM_ARG }, { "/interrupts", IN_NOI, CM_ARG }, { "/silence", IN_SIL, CM_ARG }, #ifdef COMMENT { "/pattern", IN_PAT, CM_ARG }, #endif /* COMMENT */ { "", 0, 0 } }; static int ninswtab = (sizeof(inswtab) / sizeof(struct keytab)) - 1; #endif /* COMMENT */ #endif /* NOSPL */ static int x, y, z = 0; /* Local workers */ static char *s; #ifdef CK_MINPUT static char c1chars[] = { /* C1 control chars escept NUL */ 001,002,003,004,005,006,007,010,011,012,013,014,015,016,017,020, 021,022,023,024,025,026,027,030,031,032,033,034,035,036,037 }; #endif /* CK_MINPUT */ #define xsystem(s) zsyscmd(s) /* Top-Level Interactive Command Keyword Table. HELP topics go here too, even when they aren't commands; they are marked with the CM_HLP|CM_INV attributes. Commands go to routines that execute them and HELP items go to the big switch statement in ckuus2.c. Entries must be in alphabetical order. */ struct keytab cmdtab[] = { #ifndef NOPUSH { "!", XXSHE, CM_INV|CM_PSH }, /* Shell escape */ #else { "!", XXNOTAV, CM_INV|CM_PSH }, #endif /* NOPUSH */ { "#", XXCOM, CM_INV }, /* Comment */ #ifndef NOSPL { "(", XXSEXP,CM_INV }, /* S-Expression */ { ".", XXDEF, CM_INV }, /* Assignment */ { ":", XXLBL, CM_INV }, /* Label */ #endif /* NOSPL */ #ifdef CK_REDIR #ifndef NOPUSH { "<", XXFUN, CM_INV|CM_PSH }, /* REDIRECT */ #else { "<", XXNOTAV, CM_INV|CM_PSH }, /* REDIRECT */ #endif /* NOPUSH */ #endif /* CK_REDIR */ #ifndef NOPUSH { "@", XXSHE, CM_INV|CM_PSH }, /* DCL escape */ #else { "@", XXNOTAV, CM_INV|CM_PSH }, /* DCL escape */ #endif /* NOPUSH */ #ifdef CK_RECALL { "^", XXREDO,CM_INV|CM_NOR }, /* Synonym for REDO */ #endif /* CK_RECALL */ #ifndef NOSPL { "_asg", XXASX, CM_INV }, /* Used internally by FOR, etc */ { "_assign", XXASX, CM_INV }, /* Used internally by FOR, etc */ { "_decrement", XX_DECR, CM_INV }, { "_define", XXDFX, CM_INV }, /* Used internally by FOR, etc */ { "_evaluate", XX_EVAL, CM_INV }, { "_forward", XXXFWD, CM_INV }, /* Used internally by SWITCH */ { "_getargs", XXGTA, CM_INV }, /* Used internally by FOR, etc */ { "_increment", XX_INCR, CM_INV }, { "_putargs", XXPTA, CM_INV }, /* Used internally by FOR, etc */ { "_undefine", XXUNDFX, CM_INV }, #endif /* NOSPL */ { "about", XXVER, CM_INV }, /* Synonym for VERSION */ #ifndef NOSPL #ifdef NEWFTP { "account", XXACCT, CM_INV }, /* (FTP) Account */ #endif /* NEWFTP */ #ifdef ADDCMD { "add", XXADD, 0 }, /* ADD */ #endif /* ADDCMD */ #ifndef NODIAL { "answer", XXANSW, CM_LOC }, /* ANSWER the phone */ #else { "answer", XXNOTAV, CM_INV|CM_LOC }, /* ANSWER the phone */ #endif /* NODIAL */ { "apc", XXAPC, 0 }, /* Application Program Command */ #ifndef NOSPL { "array", XXARRAY, 0 }, /* Array operations */ #endif /* NOSPL */ { "ascii", XXASC, CM_INV }, /* == SET FILE TYPE TEXT */ { "asg", XXASS, CM_INV }, /* Invisible synonym for ASSIGN */ { "ask", XXASK, 0 }, /* ASK for text, assign to variable */ { "askq", XXASKQ,0 }, /* ASK quietly (no echo) */ #ifndef NOSPL { "ass", XXASS, CM_INV|CM_ABR }, /* ASSIGN */ { "assert", XXASSER, CM_INV }, /* ASSERT */ { "assign", XXASS, 0 }, /* ASSIGN */ #endif /* NOSPL */ #ifndef NOXFER #ifndef NOCSETS { "associate", XXASSOC, 0 }, /* ASSOCIATE */ #else { "associate", XXNOTAV, CM_INV }, /* ASSOCIATE */ #endif /* NOCSETS */ #endif /* NOXFER */ #ifdef CK_KERBEROS #ifdef CK_AUTHENTICATION { "authenticate",XXAUTH, 0 }, /* Authentication */ #else { "authenticate",XXAUTH, CM_INV }, #endif /* CK_AUTHENTICATION */ #endif /* CK_KERBEROS */ #endif /* NOSPL */ #ifndef NOFRILLS { "back", XXBACK, 0 }, /* BACK to previous directory */ #else { "back", XXNOTAV,CM_INV }, #endif /* NOFRILLS */ { "beep", XXBEEP,CM_INV }, /* BEEP */ #ifndef NOXFER { "binary", XXBIN, CM_INV }, /* == SET FILE TYPE BINARY */ #endif /* NOXFER */ #ifndef NOFRILLS { "bug", XXBUG, CM_INV }, /* BUG report instructions */ #else { "bug", XXNOTAV, CM_INV }, #endif /* NOFRILLS */ #ifdef BROWSER { "browse", XXBROWS, CM_PSH|CM_LOC }, /* BROWSE (start browser) */ #else { "browse", XXNOTAV, CM_INV|CM_PSH|CM_LOC }, #endif /* BROWSER */ #ifndef NOXFER { "bye", XXBYE, 0 }, /* BYE to remote server */ #endif /* NOXFER */ #ifndef NOLOCAL { "c", XXCON, CM_INV|CM_ABR|CM_LOC }, /* (CONNECT) */ #endif /* NOLOCAL */ #ifndef NOFRILLS { "cat", XXCAT, CM_INV }, /* Invisible synonym for TYPE */ #endif /* NOFRILLS */ #ifndef NOSPL #ifndef NOXFER { "cautious", XXCAU, CM_INV }, #endif /* NOXFER */ #endif /* NOSPL */ { "cd", XXCWD, 0 }, /* Change Directory */ { "cdup", XXCDUP, CM_INV }, /* Change Directory Up */ #ifndef NOXFER #ifdef PIPESEND { "cget", XXCGET, CM_INV|CM_PSH }, /* CGET */ #else { "cget", XXNOTAV, CM_INV|CM_PSH }, /* CGET */ #endif /* PIPESEND */ #endif /* NOXFER */ { "ch", XXCHK, CM_INV|CM_ABR }, { "change", XXCHG, 0 }, /* CHANGE strings in file 2013-04-18 */ { "check", XXCHK, 0 }, /* CHECK for a feature */ #ifdef CK_PERMS #ifdef UNIX { "chmod", XXCHMOD, 0 }, /* CHMOD */ #else { "chmod", XXNOTAV, CM_INV }, #endif /* UNIX */ #else { "chmod", XXNOTAV, CM_INV }, #endif /* CK_PERMS */ #ifdef CKROOT { "chroot", XXCHRT, CM_INV }, /* CHROOT */ #endif /* CKROOT */ { "ckermit", XXKERMI, CM_INV }, /* CKERMIT (like KERMIT) */ { "cl", XXCLO, CM_ABR|CM_INV }, #ifndef NOFRILLS { "clear", XXCLE, 0 }, /* CLEAR input and/or device buffer */ #else { "clear", XXNOTAV, CM_INV }, #endif /* NOFRILLS */ { "close", XXCLO, 0 }, /* CLOSE a log or other file */ { "cls", XXCLS, CM_INV }, /* Clear Screen (CLS) */ { "comment", XXCOM, CM_INV }, /* Introduce a comment */ #ifndef NOSPL { "compact-substring", XXCSN, CM_INV|CM_HLP }, /* CS notation */ #endif /* NOSPL */ #ifndef NOLOCAL { "connect", XXCON, CM_LOC }, /* Begin terminal connection */ #else { "connect", XXNOTAV, CM_LOC }, #endif /* NOLOCAL */ { "continue", XXCONT, CM_INV }, /* CONTINUE */ #ifndef NOFRILLS #ifndef NOCSETS { "convert", XXXLA, 0 }, /* Synonym for TRANSLATE */ #else { "convert", XXNOTAV, CM_INV }, #endif /* NOCSETS */ #ifdef ZCOPY { "co", XXCPY, CM_INV|CM_ABR }, { "cop", XXCPY, CM_INV|CM_ABR }, { "copy", XXCPY, 0 }, /* COPY a file */ #else { "copy", XXNOTAV, CM_INV }, #endif /* ZCOPY */ { "copyright", XXCPR, CM_INV }, /* COPYRIGHT */ #ifdef ZCOPY { "cp", XXCPY, CM_INV }, /* COPY a file */ #endif /* ZCOPY */ #ifndef NOLOCAL #ifndef OS2 { "cq", XXCQ, CM_INV|CM_LOC }, /* CQ (connect quietly) */ #endif /* OS2 */ #endif /* NOLOCAL */ #ifndef NOXFER #ifdef PIPESEND { "creceive", XXCREC,CM_INV|CM_PSH }, /* RECEIVE to a command */ { "csend", XXCSEN,CM_INV|CM_PSH }, /* SEND from command */ #else { "creceive", XXNOTAV,CM_INV|CM_PSH }, { "csend", XXNOTAV,CM_INV|CM_PSH }, #endif /* PIPESEND */ #endif /* NOXFER */ #endif /* NOFRILLS */ { "cwd", XXCWD, CM_INV }, /* Traditional synonym for cd */ #ifndef NOSPL { "date", XXDATE, 0 }, /* DATE */ { "dcl", XXDCL, CM_INV }, /* DECLARE an array (see ARRAY) */ #ifdef COMMENT /* this command never actually did anything */ { "debug", XXDEBUG, 0 }, /* Print a debugging msg [9.0] */ #endif /* COMMENT */ { "declare", XXDCL, CM_INV }, /* DECLARE an array (see ARRAY) */ { "decrement", XXDEC, 0 }, /* DECREMENT a numeric variable */ { "define", XXDEF, 0 }, /* DEFINE a macro or variable */ #else { "date", XXNOTAV, CM_INV }, { "dcl", XXNOTAV, CM_INV }, { "declare", XXNOTAV, CM_INV }, { "decrement", XXNOTAV, CM_INV }, { "define", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef NOFRILLS { "delete", XXDEL, 0 }, /* DELETE a file */ #else { "delete", XXNOTAV, CM_INV }, #endif /* NOFRILLS */ #ifndef NODIAL { "dial", XXDIAL, CM_LOC }, /* DIAL a phone number */ #else { "dial", XXNOTAV, CM_INV|CM_LOC }, #endif /* NODIAL */ #ifdef NT { "dialer", XXDIALER, CM_INV }, /* K95 Dialer */ #endif /* NT */ { "directory", XXDIR, 0 }, /* DIRECTORY of files */ #ifndef NOFRILLS #ifndef NOSERVER { "disable", XXDIS, 0 }, /* DISABLE a server function */ #else { "disable", XXNOTAV, CM_INV }, #endif /* NOSERVER */ #endif /* NOFRILLS */ #ifndef NOSPL { "do", XXDO, 0 }, /* DO (execute) a macro */ #else { "do", XXNOTAV, CM_INV }, #endif /* NOSPL */ { "e", XXEXI, CM_INV|CM_ABR }, #ifndef NOFRILLS #ifndef NOXFER { "e-packet", XXERR, CM_INV }, /* Send an Error-Packet */ #endif /* NOXFER */ #endif /* NOFRILLS */ { "echo", XXECH, 0 }, /* ECHO text */ #ifndef NOFRILLS #ifndef NOPUSH { "edit", XXEDIT, CM_PSH }, /* EDIT */ #else { "edit", XXNOTAV, CM_INV|CM_PSH }, /* EDIT */ #endif /* NOPUSH */ #endif /* NOFRILLS */ { "eightbit", XXEIGHT, CM_INV }, /* EIGHTBIT */ #ifndef NOSPL { "else", XXELS, CM_INV }, /* ELSE part of IF statement */ #else { "else", XXNOTAV, CM_INV }, /* ELSE part of IF statement */ #endif /* NOSPL */ #ifndef NOSERVER #ifndef NOFRILLS { "enable", XXENA, 0 }, /* ENABLE a server function */ #else { "enable", XXNOTAV, CM_INV }, #endif /* NOFRILLS */ #endif /* NOSERVER */ #ifndef NOSPL { "end", XXEND, 0 }, /* END command file or macro */ #else { "end", XXNOTAV, CM_INV }, #endif /* NOSPL */ { "erase", XXDEL, CM_INV }, /* Synonym for DELETE */ #ifndef NOSPL { "evaluate", XXEVAL, 0 }, /* EVALUATE */ #else { "evaluate", XXNOTAV, CM_INV }, #endif /* NOSPL */ { "ex", XXEXI, CM_INV|CM_ABR }, /* Let "ex" still be EXIT */ #ifdef CKEXEC { "exec", XXEXEC, CM_INV|CM_LOC }, /* exec() */ #else { "exec", XXNOTAV, CM_INV|CM_LOC }, #endif /* CKEXEC */ { "exit", XXEXI, 0 }, /* EXIT from C-Kermit */ { "extended-options", XXXOPTS,CM_INV|CM_HLP }, /* Extended-Options */ #ifdef OS2 { "extproc", XXCOM, CM_INV }, /* Dummy command for OS/2 */ #endif /* OS2 */ #ifndef NOXFER { "f", XXFIN, CM_INV|CM_ABR }, /* Invisible abbrev for FIN */ #endif /* NOXFER */ #ifndef NOSPL { "fail", XXFAIL, CM_INV }, /* FAIL */ #ifndef NOXFER { "fast", XXFAST, CM_INV }, #endif /* NOXFER */ #ifdef CKCHANNELIO { "fclose", XXF_CL, CM_INV }, /* FCLOSE */ { "fcount", XXF_CO, CM_INV }, /* FCOUNT */ { "fflush", XXF_FL, CM_INV }, /* FFLUSH */ #endif /* CKCHANNELIO */ #ifndef NOXFER { "fi", XXFIN, CM_INV|CM_ABR }, /* FINISH */ #endif /* NOXFER */ #ifdef CKCHANNELIO { "file", XXFILE, 0 }, /* FILE */ #endif /* CKCHANNELIO */ #endif /* NOSPL */ #ifndef NOXFER { "fin", XXFIN, CM_INV|CM_ABR }, /* FINISH */ #endif /* NOXFER */ #ifndef UNIXOROSK { "find", XXGREP, 0 }, /* FIND (grep) */ #else { "find", XXGREP,CM_INV }, #endif /* UNIXOROSK */ #ifndef NOXFER { "finish", XXFIN, 0 }, /* FINISH */ #endif /* NOXFER */ #ifdef TCPSOCKET { "firewall", XXFIREW, CM_INV|CM_HLP }, #endif /* TCPSOCKET */ #ifdef CKCHANNELIO { "flist", XXF_LI, CM_INV }, /* FLIST */ { "fopen", XXF_OP, CM_INV }, /* FOPEN */ #endif /* CKCHANNELIO */ #ifndef NOSPL { "fo", XXFOR, CM_INV|CM_ABR }, /* Invisible abbrev for... */ { "for", XXFOR, 0 }, /* FOR loop */ { "forward", XXFWD, CM_INV }, /* FORWARD */ #endif /* NOSPL */ #ifndef NOFRILLS { "fot", XXDIR, CM_INV }, /* "fot" = "dir" (for Chris) */ #endif /* NOFRILLS */ #ifdef CKCHANNELIO { "fread", XXF_RE, CM_INV }, /* FREAD */ { "frewind", XXF_RW, CM_INV }, /* FREWIND */ { "fseek", XXF_SE, CM_INV }, /* FSEEK */ { "fstatus", XXF_ST, CM_INV }, /* FSTATUS */ #endif /* CKCHANNELIO */ #ifdef TCPSOCKET #ifndef NOFTP #ifdef SYSFTP #ifndef NOPUSH { "ftp", XXFTP, CM_INV|CM_PSH|CM_LOC }, /* System FTP */ #else { "ftp", XXNOTAV, CM_INV|CM_PSH|CM_LOC }, #endif /* NOPUSH */ #else /* SYSFTP */ { "ftp", XXFTP, 0 }, /* Built-in FTP */ #endif /* SYSFTP */ #else /* NOFTP */ { "ftp", XXNOTAV, CM_INV }, /* No FTP */ #endif /* NOFTP */ #endif /* TCPSOCKET */ #ifndef NOSPL { "function", XXFUNC, CM_INV|CM_HLP }, /* (for HELP FUNCTION) */ #endif /* NOSPL */ #ifdef CKCHANNELIO { "fwrite", XXF_WR, CM_INV }, /* FWRITE */ #endif /* CKCHANNELIO */ #ifndef NOXFER { "g", XXGET, CM_INV|CM_ABR }, /* Invisible abbrev for GET */ #ifndef NOSPL { "ge", XXGET, CM_INV|CM_ABR }, /* Ditto */ #endif /* NOSPL */ { "get", XXGET, 0 }, /* GET */ #endif /* NOXFER */ #ifndef NOSPL { "getc", XXGETC, 0 }, /* GETC */ #ifdef OS2 { "getkeycode", XXGETK, 0 }, /* GETKEYCODE */ #endif /* OS2 */ #ifndef NOFRILLS { "getok", XXGOK, 0 }, /* GETOK (ask for Yes/No/OK) */ #endif /* NOFRILLS */ #endif /* NOSPL */ #ifndef NOSPL { "goto", XXGOTO,0 }, /* GOTO label in take file or macro */ #endif /* NOSPL */ #ifdef UNIXOROSK { "grep", XXGREP,0 }, /* GREP (find) */ #else { "grep", XXGREP,CM_INV }, /* GREP (find) */ #endif /* UNIXOROSK */ { "h", XXHLP, CM_INV|CM_ABR }, /* Invisible synonym for HELP */ { "he", XXHLP, CM_INV|CM_ABR }, /* Invisible synonym for HELP */ #ifndef NOFRILLS { "head", XXHEAD, 0 }, #endif /* NOFRILLS */ #ifndef NOLOCAL { "hangup", XXHAN, CM_LOC }, /* HANGUP the connection */ #endif /* NOLOCAL */ { "hdirectory", XXHDIR, CM_INV }, /* DIR sorted by size biggest first */ { "HELP", XXHLP, 0 }, /* Display HELP text */ #ifndef NOHTTP #ifdef TCPSOCKET { "http", XXHTTP, 0 }, /* HTTP operations */ #endif /* TCPSOCKET */ #endif /* NOHTTP */ #ifndef NOSPL { "i", XXINP, CM_INV|CM_ABR }, /* Invisible synonym for INPUT */ { "if", XXIF, 0 }, /* IF ( condition ) command */ #ifdef TCPSOCKET { "iksd", XXIKSD, CM_INV }, /* Make connection to IKSD */ #else { "iksd", XXNOTAV, CM_INV }, #endif /* TCPSOCKET */ { "in", XXINP, CM_INV|CM_ABR }, /* Invisible synonym for INPUT */ { "increment", XXINC, 0 }, /* Increment a numeric variable */ { "input", XXINP, 0 }, /* INPUT text from comm device */ #endif /* NOSPL */ #ifndef NOHELP { "int", XXINT, CM_INV|CM_ABR }, { "intr", XXINT, CM_INV|CM_ABR }, { "INTRO", XXINT, 0 }, { "introduction",XXINT, CM_INV }, /* Print introductory text */ #else { "intro", XXNOTAV, CM_INV }, { "introduction",XXNOTAV, CM_INV }, #endif /* NOHELP */ #ifdef OS2 { "k95", XXKERMI, CM_INV }, /* Hmmm what's this... */ #endif /* OS2 */ #ifndef NOSPL { "kcd", XXKCD, 0 }, #endif /* NOSPL */ { "kermit", XXKERMI, CM_INV }, #ifdef OS2 #ifndef NOKVERBS { "kverb", XXKVRB, CM_INV|CM_HLP }, /* Keyboard verb */ #endif /* NOKVERBS */ #endif /* OS2 */ #ifndef NOFRILLS { "l", XXLOG, CM_INV|CM_ABR }, /* Invisible synonym for log */ #endif /* NOFRILLS */ { "lcd", XXLCWD, CM_INV }, { "lcdup", XXLCDU, CM_INV }, { "lcwd", XXLCWD, CM_INV }, { "ldelete", XXLDEL, CM_INV }, { "ldirectory", XXLDIR, CM_INV }, #ifdef CKLEARN { "learn", XXLEARN, 0 }, /* LEARN - automatic script writing */ #else { "learn", XXNOTAV, CM_INV }, #endif /* CKLEARN */ { "li", XXLNOUT, CM_INV|CM_ABR }, { "LICENSE", XXCPR, 0 }, /* LICENSE */ #ifndef NOSPL { "lineout", XXLNOUT, 0 }, /* LINEOUT = OUTPUT + eol */ #endif /* NOSPL */ #ifdef NT { "link", XXLINK, 0 }, /* LINK source destination */ #endif /* NT */ { "lmkdir", XXLMKD, CM_INV }, { "lmv", XXLREN, CM_INV }, #ifndef NOFRILLS { "lo", XXLOG, CM_INV|CM_ABR }, /* Invisible synonym for log */ #endif /* NOFRILLS */ #ifndef NOSPL { "local", XXLOCAL, CM_INV }, /* LOCAL variable declaration */ #else { "local", XXNOTAV, CM_INV }, #endif /* NOSPL */ { "locus", XXLOCU, CM_INV|CM_HLP }, /* "help locus" */ { "log", XXLOG, 0 }, /* Open a log file */ { "login", XXLOGIN, 0 }, /* (REMOTE) LOGIN to server or IKSD */ { "logout", XXLOGOUT, 0 }, /* LOGOUT from server or IKSD */ #ifndef NOFRILLS #ifndef NODIAL { "lookup", XXLOOK, 0 }, /* LOOKUP */ #else { "lookup", XXNOTAV, CM_INV }, #endif /* NODIAL */ { "lpwd", XXLPWD, CM_INV }, { "lrename", XXLREN, CM_INV }, { "lrmdir", XXLRMD, CM_INV }, #ifdef UNIXOROSK { "ls", XXLS, CM_INV|CM_PSH }, /* UNIX ls command */ #else { "ls", XXDIR, CM_INV }, /* Invisible synonym for DIR */ #endif /* UNIXOROSK */ #ifndef NOXFER { "mail", XXMAI, 0 }, /* Send a file as e-mail */ #endif /* NOXFER */ #ifndef NOHELP { "manual", XXMAN, CM_PSH }, /* MAN(UAL) */ #else { "manual", XXNOTAV, CM_INV|CM_PSH }, #endif /* NOHELP */ #endif /* NOFRILLS */ #ifdef CK_MKDIR { "md", XXMKDIR, CM_INV }, /* Synonym for MKDIR */ #endif /* CK_MKDIR */ { "message", XXMSG, 0 }, /* Print debugging message */ #ifdef CK_MINPUT { "minput", XXMINP, 0 }, /* MINPUT */ #else { "minput", XXNOTAV, CM_INV }, #endif /* CK_MINPUT */ #ifndef NOMSEND { "mget", XXMGET, 0 }, /* MGET */ #else { "mget", XXNOTAV, CM_INV }, #endif /* NOMSEND */ #ifdef CK_MKDIR { "mkdir", XXMKDIR, 0 }, /* MKDIR */ #else { "mkdir", XXNOTAV, CM_INV }, #endif /* CK_MKDIR */ #ifndef NOXFER #ifndef NOMSEND { "mmove", XXMMOVE, 0 }, /* MMOVE */ #else { "mmove", XXNOTAV, CM_INV }, #endif /* NOMSEND */ #endif /* NOXFER */ #ifndef NOFRILLS { "more", XXMORE, CM_INV }, /* MORE */ #endif /* NOFRILLS */ #ifdef OLDMOVE #ifndef NOXFER { "move", XXMOVE, 0 }, /* MOVE = SEND /DELETE */ #endif /* NOXFER */ #else { "move", XXREN, CM_INV }, /* MOVE = RENAME */ #endif /* OLDMOVE */ #ifndef NOSPL { "mpause", XXMSL, CM_INV }, /* Millisecond sleep */ #else { "mpause", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef NOXFER #ifndef NOMSEND { "mput", XXMSE, CM_INV }, /* MPUT = MSEND */ { "ms", XXMSE, CM_INV|CM_ABR }, { "msend", XXMSE, 0 }, /* Multiple SEND */ #else { "mput", XXNOTAV, CM_INV }, { "msend", XXNOTAV, CM_INV }, #endif /* NOMSEND */ #endif /* NOXFER */ { "msg", XXMSG, CM_INV }, /* Print debugging message */ #ifndef NOSPL { "msleep", XXMSL, 0 }, /* Millisecond sleep */ #else { "msleep", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef NOFRILLS { "mv", XXREN, CM_INV }, /* Synonym for rename */ #endif /* NOFRILLS */ #ifndef NOHELP { "news", XXNEW, CM_INV }, /* Display NEWS of new features */ #else { "news", XXNOTAV, CM_INV }, #endif /* NOHELP */ { "nolocal", XXNLCL, CM_INV }, /* Disable SET LINE / SET HOST */ { "nopush", XXNPSH, CM_INV }, /* Disable PUSH command/features */ #ifdef OS2 { "noscroll", XXNSCR, CM_INV }, /* Disable scroll operations */ #endif /* OS2 */ #ifndef NOSPL { "o", XXOUT, CM_INV|CM_ABR }, /* Invisible synonym for OUTPUT */ { "open", XXOPE, 0 }, /* OPEN file for reading or writing */ #else { "open", XXOPE, CM_INV }, /* OPEN */ #endif /* NOSPL */ #ifndef NOHELP { "options", XXOPTS,CM_INV|CM_HLP }, /* Options */ #endif /* NOHELP */ { "orientation", XXORIE, 0 }, #ifndef NOSPL { "output", XXOUT, 0 }, /* OUTPUT text to comm device */ #else { "output", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifdef ANYX25 #ifndef IBMX25 { "pad", XXPAD, CM_LOC }, /* X.3 PAD commands */ #endif /* IBMX25 */ #endif /* ANYX25 */ #ifdef NEWFTP { "passive", XXPASV, CM_INV }, /* (FTP) PASSIVE */ #endif /* NEWFTP */ #ifndef NOHELP { "patterns", XXPAT,CM_INV|CM_HLP }, /* Pattern syntax */ #endif /* NOHELP */ #ifndef NOSPL { "pause", XXPAU, 0 }, /* Sleep for specified interval */ #else { "pause", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef NODIAL { "pdial", XXPDIA, CM_LOC }, /* PDIAL (partial dial) */ #else { "pdial", XXNOTAV, CM_INV|CM_LOC }, #endif /* NODIAL */ #ifdef TCPSOCKET #ifndef NOPUSH { "ping", XXPNG, CM_INV|CM_PSH|CM_LOC }, /* PING */ #else { "ping", XXNOTAV, CM_INV|CM_PSH|CM_LOC }, #endif /* NOPUSH */ #endif /* TCPSOCKET */ #ifdef NETCMD #ifndef NOPUSH { "pipe", XXPIPE, CM_PSH }, /* PIPE */ #else { "pipe", XXNOTAV, CM_INV|CM_PSH }, /* PIPE */ #endif /* NOPUSH */ #endif /* NETCMD */ #ifndef NOSPL { "pop", XXEND, CM_INV }, /* Invisible synonym for END */ #endif /* NOSPL */ #ifndef NOFRILLS { "print", XXPRI, 0 }, /* PRINT a file locally */ #endif /* NOFRILLS */ { "prompt", XXPROMP, CM_INV }, /* Go interactive (from script) */ #ifndef NOXFER #ifdef CK_RESEND { "psend", XXPSEN, CM_INV }, /* PSEND */ #else { "psend", XXNOTAV, CM_INV }, #endif /* CK_RESEND */ #endif /* NOXFER */ #ifdef NETPTY { "pty", XXPTY, CM_PSH }, /* PTY */ #else { "pty", XXNOTAV, CM_INV|CM_PSH }, #endif /* NETPTY */ #ifndef NOPUSH { "pu", XXSHE, CM_INV|CM_ABR|CM_PSH }, /* PU = PUSH */ #endif /* NOPUSH */ #ifdef CKPURGE { "purge", XXPURGE, 0 }, /* PURGE (real) */ #else #ifdef VMS { "purge", XXPURGE, 0 }, /* PURGE (fake) */ #else { "purge", XXNOTAV, CM_INV }, #endif /* VMS */ #endif /* CKPURGE */ #ifndef NOPUSH { "push", XXSHE, CM_PSH }, /* PUSH command (like RUN, !) */ #else { "push", XXNOTAV, CM_INV|CM_PSH }, #endif /* NOPUSH */ #ifndef NOXFER { "put", XXSEN, CM_INV }, /* PUT = SEND */ #endif /* NOXFER */ #ifdef UNIX #ifndef NOPUTENV { "putenv", XXPUTE, CM_INV }, /* PUTENV */ #endif /* NOPUTENV */ #endif /* UNIX */ { "pwd", XXPWD, 0 }, /* Print Working Directory */ { "q", XXQUI, CM_INV|CM_ABR }, /* Invisible synonym for QUIT */ #ifndef NOXFER { "query", XXRQUE,CM_INV }, /* (= REMOTE QUERY) */ #endif /* NOXFER */ { "quit", XXQUI, 0 }, /* QUIT from program = EXIT */ #ifndef NOXFER { "r", XXREC, CM_INV|CM_ABR }, /* Inv synonym for RECEIVE */ #endif /* NOXFER */ #ifndef NOXFER { "rasg", XXRASG, CM_INV }, /* REMOTE ASSIGN */ { "rassign", XXRASG, CM_INV }, /* ditto */ { "rcd", XXRCWD, CM_INV }, /* REMOTE CD */ { "rcdup", XXRCDUP,CM_INV }, /* REMOTE CD */ { "rcopy", XXRCPY, CM_INV }, /* REMOTE COPY */ { "rcwd", XXRCWD, CM_INV }, /* REMOTE CWD */ { "rdelete", XXRDEL, CM_INV }, /* REMOTE DELETE */ { "rdirectory", XXRDIR, CM_INV }, /* REMODE DIRECTORY */ #endif /* NOXFER */ #ifndef NOSPL { "read", XXREA, 0 }, /* READ a line from a file */ #else { "read", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef NOXFER { "receive", XXREC, 0 }, /* RECEIVE files */ #endif /* NOXFER */ #ifndef NODIAL { "red", XXRED, CM_INV|CM_ABR|CM_LOC }, /* Inv syn for REDIAL */ { "redi", XXRED, CM_INV|CM_ABR|CM_LOC }, /* ditto */ { "redial", XXRED, CM_LOC }, /* REDIAL last DIAL number */ #else { "red", XXNOTAV, CM_INV|CM_LOC }, { "redi", XXNOTAV, CM_INV|CM_LOC }, { "redial", XXNOTAV, CM_INV|CM_LOC }, #endif /* NODIAL */ #ifdef CK_REDIR #ifdef OS2 #ifndef NOPUSH { "redirect", XXFUN, CM_INV|CM_PSH }, /* REDIRECT */ #else { "redirect", XXNOTAV, CM_INV|CM_PSH }, #endif /* NOPUSH */ #else /* OS2 */ #ifndef NOPUSH { "redirect", XXFUN, CM_PSH }, /* REDIRECT */ #else { "redirect", XXNOTAV, CM_INV|CM_PSH }, #endif /* NOPUSH */ #endif /* OS2 */ #endif /* CK_REDIR */ #ifdef CK_RECALL { "redo", XXREDO, CM_NOR }, /* REDO */ #else { "redo", XXNOTAV, CM_INV }, #endif /* CK_RECALL */ #ifndef NOXFER #ifdef CK_RESEND { "reget", XXREGET, 0 }, /* REGET */ #else { "reget", XXNOTAV, CM_INV }, #endif /* CK_RESEND */ #endif /* NOXFER */ #ifndef NOSPL { "reinput", XXREI, CM_INV }, /* REINPUT (from INPUT buffer) */ #else { "reinput", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef NOXFER #ifdef ADDCMD { "rem", XXREM, CM_INV|CM_ABR }, { "remo", XXREM, CM_INV|CM_ABR }, #endif /* ADDCMD */ { "remote", XXREM, 0 }, /* Send REMOTE command to server */ #endif /* NOXFER */ #ifdef ADDCMD { "remove", XXREMV,0 }, /* REMOVE (something from a list) */ #else { "remove", XXNOTAV, CM_INV }, #endif /* ADDCMD */ #ifndef NOFRILLS #ifndef NORENAME { "rename", XXREN, 0 }, /* RENAME a local file */ #else { "rename", XXNOTAV, CM_INV }, #endif /* NORENAME */ { "replay", XXTYP, CM_INV }, /* REPLAY (for now, just type) */ #endif /* NOFRILLS */ #ifndef NOXFER #ifdef CK_RESEND { "rep", XXTYP, CM_INV|CM_ABR }, /* REPLAY abbreviation */ { "reput", XXRSEN, CM_INV }, /* REPUT = RESEND */ { "res", XXRSEN, CM_INV|CM_ABR }, /* RESEND */ { "rese", XXRSEN, CM_INV|CM_ABR }, /* RESEND */ { "resend", XXRSEN, 0 }, /* RESEND */ #else { "reput", XXNOTAV, CM_INV }, { "res", XXNOTAV, CM_INV }, { "rese", XXNOTAV, CM_INV }, { "resend", XXNOTAV, CM_INV }, #endif /* CK_RESEND */ #endif /* NOXFER */ { "reset", XXRESET, CM_INV }, /* RESET */ #ifdef CK_RESEND #ifndef NOSPL { "ret", XXRET, CM_INV|CM_ABR }, #endif /* NOSPL */ #endif /* CK_RESEND */ #ifndef NOXFER { "retrieve", XXRETR, CM_INV }, /* RETRIEVE */ #endif /* NOXFER */ #ifndef NOSPL { "return", XXRET, 0 }, /* RETURN from a function */ #else { "return", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef NOXFER { "rexit", XXRXIT, CM_INV }, /* REMOTE EXIT */ #endif /* NOXFER */ #ifdef CK_REXX #ifndef NOPUSH { "rexx", XXREXX, CM_PSH }, /* Execute a Rexx command */ #else { "rexx", XXNOTAV, CM_INV|CM_PSH }, #endif /* NOPUSH */ #endif /* CK_REXX */ #ifndef NOXFER { "rhelp", XXRHLP, CM_INV }, /* REMOTE HELP */ { "rhost", XXRHOS, CM_INV }, /* REMOTE HOST */ { "rkermit", XXRKER, CM_INV }, /* REMOTE KERMIT */ #endif /* NOXFER */ #ifdef TCPSOCKET { "rlogin", XXRLOG, CM_LOC }, /* Make an Rlogin connection */ #else { "rlogin", XXNOTAV, CM_INV|CM_LOC }, #endif /* TCPSOCKET */ #ifndef NOFRILLS { "rm", XXDEL, CM_INV }, /* Invisible synonym for delete */ #endif /* NOFRILLS */ #ifdef CK_MKDIR { "rmdir", XXRMDIR, 0 }, /* RMDIR */ #else { "rmdir", XXNOTAV, CM_INV }, #endif /* CK_MKDIR */ #ifndef NOXFER { "rmessage", XXRMSG, CM_INV }, /* REMOTE MESSAGE */ { "rmkdir", XXRMKD, CM_INV }, /* REMOTE MKDIR */ { "rmsg", XXRMSG, CM_INV }, /* REMOTE MESSAGE */ #ifndef NOSPL { "robust", XXROB, CM_INV }, #else { "robust", XXNOTAV, CM_INV }, #endif /* NOSPL */ { "rprint", XXRPRI, CM_INV }, /* REMOTE PRINT */ { "rpwd", XXRPWD, CM_INV }, /* REMOTE PWD */ { "rquery", XXRQUE, CM_INV }, /* REMOTE QUERY */ #endif /* NOXFER */ #ifdef CK_RECALL { "rr", XXREDO, CM_INV|CM_NOR }, #endif /* CK_RECALL */ #ifndef NOXFER { "rrename", XXRREN, CM_INV }, /* REMOTE RENAME */ { "rrmdir", XXRRMD, CM_INV }, /* REMOTE REMDIR */ { "rset", XXRSET, CM_INV }, /* REMOTE SET */ { "rspace", XXRSPA, CM_INV }, /* REMOTE SPACE */ { "rtype", XXRTYP, CM_INV }, /* REMOTE TYPE */ #endif /* NOXFER */ #ifndef NOPUSH { "run", XXSHE, CM_PSH }, /* RUN a program or command */ #else { "run", XXNOTAV, CM_INV|CM_PSH }, #endif /* NOPUSH */ #ifndef NOXFER { "rwho", XXRWHO, CM_INV }, /* REMOTE WHO */ { "s", XXSEN, CM_INV|CM_ABR }, /* Invisible synonym for send */ #endif /* NOXFER */ #ifndef NOSETKEY #ifdef OS2 { "save", XXSAVE, 0 }, /* SAVE something */ #else { "save", XXSAVE, CM_INV }, #endif /* OS2 */ #else { "save", XXNOTAV, CM_INV }, #endif /* NOSETKEY */ #ifndef NOSCRIPT { "sc", XXLOGI, CM_INV|CM_ABR|CM_LOC }, { "scr", XXLOGI, CM_INV|CM_ABR|CM_LOC }, #endif /* NOSCRIPT */ { "screen", XXSCRN, 0 }, /* SCREEN actions */ #ifndef NOSCRIPT { "script", XXLOGI, CM_LOC }, /* Expect-Send-style script line */ #else { "script", XXNOTAV, CM_INV|CM_LOC }, #endif /* NOSCRIPT */ { "search", XXGREP,CM_INV }, /* Synonym for GREP and FIND */ #ifndef NOXFER { "send", XXSEN, 0 }, /* Send (a) file(s) */ #ifndef NOSERVER { "server", XXSER, 0 }, /* Be a SERVER */ #else { "server", XXNOTAV, CM_INV }, #endif /* NOSERVER */ #endif /* NOXFER */ { "set", XXSET, 0 }, /* SET parameters */ #ifndef NOSPL #ifndef NOSEXP { "sexpression", XXSEXP, CM_INV|CM_HLP }, /* SEXPR */ #endif /* NOSEXP */ #ifdef SFTP_BUILTIN { "sftp", XXSFTP, 0 }, /* SFTP */ #endif /* SFTP_BUILTIN */ #ifndef NOSHOW { "sh", XXSHO, CM_INV|CM_ABR }, /* SHOW parameters */ #endif /* NOSHOW */ { "shift", XXSHIFT, 0 }, /* SHIFT args */ #else { "shift", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef NOSHOW { "show", XXSHO, 0 }, /* SHOW parameters */ #else { "show", XXNOTAV, CM_INV }, #endif /* NOSHOW */ #ifdef NEWFTP { "site", XXSITE, CM_INV }, /* (FTP) SITE */ #endif /* NEWFTP */ #ifdef SSHBUILTIN { "skermit", XXSKRM, 0 }, /* SKERMIT */ #endif /* SSHBUILTIN */ #ifndef NOSPL #ifndef NOFRILLS { "sleep", XXPAU, CM_INV }, /* SLEEP for specified interval */ #endif /* NOFRILLS */ #endif /* NOSPL */ #ifndef NOSPL { "sort", XXSORT, CM_INV }, /* (see ARRAY) */ #else { "sort", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef MAC #ifndef NOFRILLS { "sp", XXSPA, CM_INV|CM_ABR }, { "spa", XXSPA, CM_INV|CM_ABR }, #endif /* NOFRILLS */ { "space", XXSPA, 0 }, /* Show available disk SPACE */ #endif /* MAC */ #ifndef NOFRILLS #ifndef NOPUSH { "spawn", XXSHE, CM_INV|CM_PSH }, /* Synonym for PUSH, RUN */ #else { "spawn", XXNOTAV, CM_INV|CM_PSH }, /* Synonym for PUSH, RUN */ #endif /* NOPUSH */ #endif /* NOFRILLS */ #ifdef ANYSSH { "ssh", XXSSH, 0 }, #endif /* ANYSSH */ #ifndef NOXFER { "sta", XXSTA, CM_INV|CM_ABR }, { "stat", XXSTA, CM_INV|CM_ABR }, { "statistics", XXSTA, 0 }, /* Display file transfer stats */ #endif /* NOXFER */ { "status", XXSTATUS,0 }, /* Show status of previous command */ #ifndef NOSPL { "stop", XXSTO, 0 }, /* STOP all take files and macros */ { "succeed", XXSUCC, CM_INV }, /* SUCCEED */ #else { "stop", XXNOTAV, CM_INV }, { "succeed", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef NOFRILLS { "SUPPORT", XXBUG, 0 }, /* Tech support instructions */ #else { "support", XXNOTAV, CM_INV }, #endif /* NOFRILLS */ #ifndef NOJC { "suspend", XXSUS, CM_PSH }, /* SUSPEND C-Kermit (UNIX only) */ #else { "suspend", XXNOTAV, CM_INV|CM_PSH }, #endif /* NOJC */ #ifndef NOSPL { "switch", XXSWIT, 0 }, /* SWITCH */ #else { "switch", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifdef CK_TAPI { "ta", XXTAK, CM_INV|CM_ABR }, /* (because of TAPI) */ #endif /* CK_TAPI */ #ifndef NOFRILLS { "tail", XXTAIL, 0 }, /* Display end of a local file */ #endif /* NOFRILLS */ { "take", XXTAK, 0 }, /* TAKE commands from a file */ #ifdef CK_TAPI { "tapi", XXTAPI, CM_LOC }, /* Microsoft TAPI commands */ #else { "tapi", XXNOTAV, CM_INV|CM_LOC }, #endif /* CK_TAPI */ #ifndef NOFRILLS #ifdef TCPSOCKET { "tel", XXTEL, CM_INV|CM_ABR|CM_LOC }, { "telnet", XXTEL, CM_LOC }, /* TELNET (TCP/IP only) */ { "telopt", XXTELOP, CM_INV }, /* TELOPT (ditto) */ #else { "tel", XXNOTAV, CM_INV|CM_LOC }, { "telnet", XXNOTAV, CM_INV|CM_LOC }, { "telopt", XXNOTAV, CM_INV }, #endif /* TCPSOCKET */ #ifdef OS2 { "terminal", XXTERM, CM_INV|CM_LOC }, /* == SET TERMINAL TYPE */ #else { "terminal", XXTERM, CM_INV }, #endif /* OS2 */ #endif /* NOFRILLS */ #ifndef NOXFER { "text", XXASC, CM_INV }, /* == SET FILE TYPE TEXT */ #endif /* NOXFER */ { "touch", XXTOUC, 0 }, /* TOUCH */ #ifndef NOSPL { "trace", XXTRACE, 0 }, /* TRACE */ #else { "trace", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef NOCSETS { "translate", XXXLA, 0 }, /* TRANSLATE local file char sets */ #else { "translate", XXNOTAV, CM_INV }, #endif /* NOCSETS */ #ifndef NOXMIT { "transmit", XXTRA, 0 }, /* Send (upload) a file, no protocol */ #else { "transmit", XXNOTAV, CM_INV }, #endif /* NOXMIT */ #ifndef NOFRILLS { "type", XXTYP, 0 }, /* Display a local file */ #endif /* NOFRILLS */ #ifndef NOSPL { "undcl", XXUNDCL, CM_INV }, { "undeclare", XXUNDCL, 0 }, /* UNDECLARE an array */ { "undefine", XXUNDEF, 0 }, /* UNDEFINE a variable or macro */ #else { "undcl", XXNOTAV, CM_INV }, { "undeclare", XXNOTAV, CM_INV }, { "undefine", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifdef NEWFTP { "user", XXUSER, CM_INV }, /* (FTP) USER */ #endif /* NEWFTP */ { "v", XXDIR, CM_INV|CM_ABR }, /* Like TOPS-20 VDIRECTORY */ { "vdirectory", XXDIR, CM_INV }, /* Like TOPS-20 VDIRECTORY */ { "version", XXVER, 0 }, /* VERSION-number display */ #ifdef OS2 { "viewonly", XXVIEW, CM_LOC }, /* VIEWONLY Terminal Mode */ #endif /* OS2 */ { "void", XXVOID, 0 }, /* VOID */ #ifndef NOSPL { "wait", XXWAI, 0 }, /* WAIT */ #else { "wait", XXNOTAV, CM_INV }, #endif /* NOSPL */ { "wdirectory", XXWDIR, CM_INV }, /* Like TOPS-20, reverse chron order */ { "wermit", XXKERMI, CM_INV }, #ifndef NOXFER { "where", XXWHERE, 0 }, /* WHERE (did my file go?) */ #endif /* NOXFER */ #ifndef NOSPL { "while", XXWHI, 0 }, /* WHILE loop */ #else { "while", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef OS2 #ifndef MAC #ifndef NOFRILLS { "who", XXWHO, CM_PSH }, /* WHO's logged in? */ #endif /* NOFRILLS */ #endif /* MAC */ #endif /* OS2 */ #ifndef NOHELP { "wildcards", XXWILD,CM_INV|CM_HLP }, /* Wildcard syntax */ #endif /* NOHELP */ #ifndef NOSPL { "wr", XXWRI, CM_INV|CM_ABR }, { "wri", XXWRI, CM_INV|CM_ABR }, { "writ", XXWRI, CM_INV|CM_ABR }, { "write", XXWRI, 0 }, /* WRITE characters to a file */ { "write-line", XXWRL, CM_INV }, /* WRITE a line to a file */ { "writeln", XXWRL, CM_INV }, /* Pascalisch synonym for write-line */ #else { "wr", XXNOTAV, CM_INV }, { "wri", XXNOTAV, CM_INV }, { "writ", XXNOTAV, CM_INV }, { "write", XXNOTAV, CM_INV }, { "write-line", XXNOTAV, CM_INV }, { "writeln", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef NOFRILLS { "xecho", XXXECH,0 }, /* XECHO */ #endif /* NOFRILLS */ #ifndef NOSPL { "xif", XXIFX, CM_INV }, /* Extended IF command (obsolete) */ #else { "xif", XXNOTAV, CM_INV }, #endif /* NOSPL */ #ifndef NOCSETS { "xlate", XXXLA, CM_INV }, /* Synonym for TRANSLATE */ #else { "xlate", XXNOTAV, CM_INV }, #endif /* NOCSETS */ #ifndef NOXMIT { "xm", XXTRA, CM_INV|CM_ABR }, /* Avoid conflict with XMESSAGE */ #else { "xm", XXNOTAV, CM_INV|CM_ABR }, /* Synonym for TRANSMIT */ #endif /* NOXMIT */ { "xmessage", XXXMSG, 0 }, /* Print debugging message */ #ifndef NOXMIT { "xmit", XXTRA, CM_INV }, /* Synonym for TRANSMIT */ #else { "xmit", XXNOTAV, CM_INV }, #endif /* NOXMIT */ { "xmsg", XXXMSG, CM_INV }, /* Synonym for XMESSAGE */ #ifndef OS2 #ifndef NOJC { "z", XXSUS, CM_INV|CM_PSH }, /* Synonym for SUSPEND */ #else { "z", XXNOTAV, CM_INV|CM_PSH }, #endif /* NOJC */ #endif /* OS2 */ #ifndef NOSPL { "{", XXMACRO, CM_INV }, /* Immediate macro */ #endif /* NOSPL */ { "", 0, 0 } }; int ncmd = (sizeof(cmdtab) / sizeof(struct keytab)) - 1; /* NOTE: Tokens must also be entered above into cmdtab[]. */ char toktab[] = { #ifndef NOPUSH '!', /* Shell escape */ #endif /* NOPUSH */ '#', /* Comment */ #ifndef NOSPL '(', /* S-Expression */ '.', /* Assignment */ #endif /* NOSPL */ ';', /* Comment */ #ifndef NOSPL ':', /* Label */ #endif /* NOSPL */ #ifndef NOPUSH #ifdef CK_REDIR '<', /* REDIRECT */ #endif /* CK_REDIR */ '@', /* DCL escape */ #endif /* NOPUSH */ #ifdef CK_RECALL '^', /* Command recall */ #endif /* CK_RECALL */ #ifndef NOSPL '{', /* Immediate macro */ #endif /* NOSPL */ '\0' /* End of this string */ }; int xxdot = 0; /* Used with "." token */ struct keytab yesno[] = { /* Yes/No keyword table */ { "no", 0, 0 }, { "ok", 1, 0 }, { "yes", 1, 0 } }; int nyesno = (sizeof(yesno) / sizeof(struct keytab)); /* Save keyword table */ struct keytab savtab[] = { #ifdef OS2 { "command", XSCMD, 0 }, #else #ifdef CK_RECALL { "command", XSCMD, 0 }, #endif /* CK_RECALL */ #endif /* OS2 */ #ifndef NOSETKEY { "keymap", XSKEY, 0 }, #endif /* NOSETKEY */ #ifdef OS2 { "terminal", XSTERM, 0 }, #endif /* OS2 */ { "", 0, 0 } }; int nsav = (sizeof(savtab) / sizeof(struct keytab)) - 1; /* Parameter keyword table (SET command) */ struct keytab prmtab[] = { { "alarm", XYALRM, 0 }, #ifdef COMMENT /* SET ANSWER not implemented yet */ #ifndef NODIAL { "answer", XYANSWER,0 }, #endif /* NODIAL */ #endif /* COMMENT */ { "ask-timer", XYTIMER, 0 }, #ifndef NOXFER { "attributes", XYATTR, 0 }, #endif /* NOXFER */ #ifdef CK_AUTHENTICATION { "authentication", XYAUTH, 0 }, #else /* CK_AUTHENTICATION */ #ifdef CK_SSL { "authentication", XYAUTH, 0 }, #endif /* CK_SSL */ #endif /* CK_AUTHENTICATION */ { "b", XYBACK, CM_INV|CM_ABR|CM_PSH }, { "ba", XYBACK, CM_INV|CM_ABR|CM_PSH }, #ifdef VMS { "background", XYBACK, CM_INV|CM_PSH }, { "batch", XYBACK, CM_PSH }, #else { "background", XYBACK, CM_PSH }, { "batch", XYBACK, CM_INV|CM_PSH }, #endif /* VMS */ #ifndef NOLOCAL { "baud", XYSPEE, CM_INV|CM_LOC }, #endif /* NOLOCAL */ { "bell", XYBELL, 0 }, #ifndef NOXFER { "block-check", XYCHKT, 0 }, #endif /* NOXFER */ #ifdef OS2 #ifdef BPRINT { "bprinter", XYBDCP, CM_INV }, #endif /* BPRINT */ #endif /* OS2 */ #ifdef BROWSER { "browser", XYBROWSE,CM_PSH|CM_LOC }, #endif /* BROWSER */ #ifndef NOXFER #ifdef DYNAMIC { "buffers", XYBUF, 0 }, #endif /* DYNAMIC */ #endif /* NOXFER */ #ifndef NOLOCAL #ifndef MAC { "carrier-watch", XYCARR, CM_LOC }, #endif /* MAC */ #endif /* NOLOCAL */ #ifndef NOSPL { "case", XYCASE, 0 }, #endif /* NOSPL */ { "cd", XYCD, 0 }, #ifndef NOXFER { "cl", XYCLEAR, CM_INV|CM_ABR }, { "cle", XYCLEAR, CM_INV|CM_ABR }, { "clea", XYCLEAR, CM_INV|CM_ABR }, { "clear", XYCLEAR, CM_INV|CM_ABR }, { "clear-channel", XYCLEAR, 0 }, { "clearchannel", XYCLEAR, CM_INV }, #endif /* NOXFER */ #ifndef NOLOCAL { "close-on-disconnect", XYDISC, CM_INV|CM_LOC }, #endif /* NOLOCAL */ { "cmd", XYCMD, CM_INV }, { "command", XYCMD, 0 }, #ifdef CK_SPEED { "con", XYQCTL, CM_INV|CM_ABR }, #endif /* CK_SPEED */ { "console", XYCMD, CM_INV }, #ifdef CK_SPEED { "control-character",XYQCTL, 0 }, #endif /* CK_SPEED */ #ifndef NOSPL { "count", XYCOUN, 0 }, #endif /* NOSPL */ #ifndef NOXFER { "d", XYDELA, CM_INV|CM_ABR }, { "de", XYDELA, CM_INV|CM_ABR }, #endif /* NOXFER */ { "debug", XYDEBU, 0 }, #ifdef VMS { "default", XYDFLT, 0 }, #else #ifndef MAC { "default", XYDFLT, CM_INV }, #endif /* MAC */ #endif /* VMS */ #ifndef NOXFER { "delay", XYDELA, 0 }, { "destination", XYDEST, 0 }, #endif /* NOXFER */ #ifndef NODIAL { "di", XYDIAL, CM_INV|CM_ABR|CM_LOC }, { "dia", XYDIAL, CM_INV|CM_ABR|CM_LOC }, { "dial", XYDIAL, CM_LOC }, #endif /* NODIAL */ #ifdef OS2 { "dialer", XYDLR, CM_INV }, #endif /* OS2 */ #ifndef NOLOCAL { "disconnect", XYDISC, CM_LOC }, { "duplex", XYDUPL, CM_LOC }, #endif /* NOLOCAL */ #ifndef NOPUSH #ifndef NOFRILLS { "editor", XYEDIT, CM_PSH }, #endif /* NOFRILLS */ #endif /* NOPUSH */ #ifdef CK_CTRLZ { "eof", XYEOF, CM_INV }, #endif /* CK_CTRLZ */ #ifndef NOLOCAL { "escape-character", XYESC, CM_LOC }, #endif /* NOLOCAL */ #ifndef NOSPL { "evaluate", XYEVAL, CM_INV }, #endif /* NOSPL */ { "exit", XYEXIT, 0 }, #ifndef NOXFER #ifdef CK_XYZ #ifndef NOPUSH #ifndef XYZ_INTERNAL { "external-protocol",XYEXTRN, 0 }, #endif /* XYZ_INTERNAL */ #endif /* NOPUSH */ #endif /* CK_XYZ */ { "f-ack-bug", XYFACKB, CM_INV }, { "f-ack-path", XYFACKP, CM_INV }, #endif /* NOXFER */ { "file", XYFILE, 0 }, { "fl", XYFLOW, CM_INV|CM_ABR }, #ifndef NOSPL { "flag", XYFLAG, 0 }, #endif /* NOSPL */ #ifdef TCPSOCKET #ifndef SYSFTP #ifndef NOFTP { "ft", XYFTPX, CM_INV|CM_ABR }, { "ftp", XYFTPX, 0 }, #endif /* NOFTP */ #endif /* SYSFTP */ #endif /* TCPSOCKET */ #ifdef BROWSER { "ftp-client", XYFTP, CM_PSH }, #endif /* BROWSER */ { "flow-control", XYFLOW, 0 }, #ifndef NOSPL { "function", XYFUNC, 0 }, #endif /* NOSPL */ #ifdef NEWFTP { "get-put-remote", XYGPR, 0 }, #endif /* NEWFTP */ #ifdef KUI { "gui", XYGUI, 0 }, #endif /* KUI */ { "handshake", XYHAND, 0 }, { "hints", XYHINTS, 0 }, #ifdef NETCONN { "host", XYHOST, CM_LOC }, #endif /* NETCONN */ #ifndef NOSPL { "i", XYINPU, CM_INV|CM_ABR }, #endif /* NOSPL */ #ifdef IKSD { "iks", XYIKS, 0 }, #else { "iks", XYIKS, CM_INV }, #endif /* IKSD */ #ifndef NOSPL { "in", XYINPU, CM_INV|CM_ABR }, #endif /* NOSPL */ #ifndef NOXFER { "incomplete", XYIFD, CM_INV }, #endif /* NOXFER */ #ifndef NOSPL { "input", XYINPU, 0 }, #endif /* NOSPL */ #ifndef NOSETKEY { "key", XYKEY, 0 }, #endif /* NOSETKEY */ { "l", XYLINE, CM_INV|CM_ABR }, #ifndef NOCSETS { "language", XYLANG, 0 }, #endif /* NOCSETS */ #ifndef NOLOCAL { "line", XYLINE, CM_LOC }, { "local-echo", XYLCLE, CM_INV|CM_LOC }, #endif /* NOLOCAL */ #ifdef HAVE_LOCALE { "locale", XYLOCALE,0 }, #endif /* HAVE_LOCALE */ #ifdef LOCUS { "locus", XYLOCUS, 0 }, #endif /* LOCUS */ #ifndef NOSPL { "login", XYLOGIN, CM_LOC }, #endif /* NOSPL */ #ifndef NOSPL { "macro", XYMACR, 0 }, #endif /* NOSPL */ { "match", XYMATCH, 0 }, #ifdef COMMENT #ifdef VMS { "messages", XYMSGS, 0 }, #endif /* VMS */ #endif /* COMMENT */ #ifndef NODIAL { "modem", XYMODM, CM_LOC }, #endif /* NODIAL */ #ifndef NOLOCAL #ifdef OS2MOUSE { "mouse", XYMOUSE, 0 }, #endif /* OS2MOUSE */ #endif /* NOLOCAL */ #ifdef OS2 { "mskermit", XYMSK, 0 }, #endif /* OS2 */ #ifdef NETCONN { "network", XYNET, CM_LOC }, #endif /* NETCONN */ #ifndef NOSPL { "output", XYOUTP, 0 }, #endif /* NOSPL */ { "options", XYOPTS, 0 }, { "pause", XYSLEEP, CM_INV }, #ifdef ANYX25 #ifndef IBMX25 { "pad", XYPAD, CM_LOC }, #endif /* IBMX25 */ #endif /* ANYX25 */ { "parity", XYPARI, 0 }, #ifndef NOLOCAL #ifdef OS2 { "port", XYLINE, CM_LOC }, #else { "port", XYLINE, CM_INV|CM_LOC }, #endif /* OS2 */ #endif /* NOLOCAL */ #ifndef NOFRILLS { "pr", XYPROM, CM_INV|CM_ABR }, { "printer", XYPRTR, 0 }, #endif /* NOFRILLS */ #ifdef OS2 { "priority", XYPRTY, 0 }, #endif /* OS2 */ #ifdef CK_SPEED { "prefixing", XYPREFIX, 0 }, #endif /* CK_SPEED */ #ifndef NOFRILLS { "prompt", XYPROM, 0 }, #endif /* NOFRILLS */ #ifndef NOXFER { "protocol", XYPROTO, 0 }, #endif /* NOXFER */ { "q", XYQUIE, CM_INV|CM_ABR }, #ifndef NOXFER { "q8flag", XYQ8FLG, CM_INV }, #endif /* NOXFER */ #ifdef QNX { "qnx-port-lock", XYQNXPL, 0 }, #else { "qnx-port-lock", XYQNXPL, CM_INV }, #endif /* QNX */ { "quiet", XYQUIE, 0 }, #ifndef NOXFER { "rec", XYRECV, CM_INV|CM_ABR }, { "receive", XYRECV, 0 }, { "recv", XYRECV, CM_INV }, #endif /* NOXFER */ { "reliable", XYRELY, 0 }, { "rename", XY_REN, 0 }, #ifndef NOXFER { "repeat", XYREPT, 0 }, { "retry-limit", XYRETR, 0 }, #endif /* NOXFER */ #ifdef CKROOT { "root", XYROOT, 0 }, #endif /* CKROOT */ #ifndef NOSCRIPT { "script", XYSCRI, CM_LOC }, #endif /* NOSCRIPT */ #ifndef NOXFER { "send", XYSEND, 0 }, #ifndef NOLOCAL #ifndef NOSERVER { "ser", XYSERV, CM_INV|CM_ABR }, #endif /* NOSERVER */ #endif /* NOXFER */ { "serial", XYSERIAL,CM_LOC }, #endif /* NOLOCAL */ #ifndef NOSERVER { "server", XYSERV, 0 }, #endif /* NOSERVER */ #ifdef SESLIMIT #ifndef NOLOCAL { "session-l", XYSESS, CM_INV|CM_ABR }, #endif /* NOLOCAL */ { "session-limit", XYLIMIT, CM_INV|CM_LOC }, /* Session Limit */ #endif /* SESLIMIT */ #ifndef NOLOCAL { "session-log", XYSESS, CM_LOC }, #endif /* NOLOCAL */ #ifndef NOSPL #ifndef NOSEXP { "sexpression", XYSEXP, CM_INV }, #endif /* NOSEXP */ #endif /* NOSPL */ { "sleep", XYSLEEP, 0 }, #ifndef NOLOCAL { "speed", XYSPEE, CM_LOC }, #endif /* NOLOCAL */ #ifdef ANYSSH { "ssh", XYSSH, 0 }, #endif /* ANYSSH */ #ifndef NOSPL { "startup-file", XYSTARTUP, CM_INV }, #endif /* NOSPL */ #ifndef NOLOCAL #ifdef HWPARITY { "stop-bits", XYSTOP, CM_LOC }, #else #ifdef TN_COMPORT { "stop-bits", XYSTOP, CM_LOC }, #endif /* TN_COMPORT */ #endif /* HWPARITY */ #endif /* NOLOCAL */ #ifndef NOXFER #ifdef STREAMING { "streaming", XYSTREAM, 0 }, #endif /* STREAMING */ #endif /* NOXFER */ #ifndef NOJC { "suspend", XYSUSP, CM_PSH }, #endif /* NOJC */ #ifdef CKSYSLOG { "syslog", XYSYSL, CM_INV }, #endif /* CKSYSLOG */ { "take", XYTAKE, 0 }, #ifdef CK_TAPI { "tapi", XYTAPI, CM_LOC }, #endif /* CK_TAPI */ #ifndef NOTCPOPTS #ifdef TCPSOCKET { "tcp", XYTCP, CM_LOC }, #endif /* TCPSOCKET */ #endif /* NOTCPOPTS */ #ifdef TNCODE { "tel", XYTEL, CM_INV|CM_ABR }, { "telnet", XYTEL, 0 }, { "telopt", XYTELOP, 0 }, #endif /* TNCODE */ #ifndef NOSPL { "temp-directory", XYTMPDIR,0 }, #endif /* NOSPL */ #ifndef NOLOCAL { "terminal", XYTERM, CM_LOC }, #endif /* NOLOCAL */ #ifdef OS2 { "title", XYTITLE, CM_LOC }, #endif /* OS2 */ #ifndef NOSPL { "tmp-directory", XYTMPDIR,CM_INV }, #endif /* NOSPL */ #ifdef TLOG { "transaction-log", XYTLOG, 0 }, #endif /* TLOG */ #ifndef NOXFER { "transfer", XYXFER, 0 }, #endif /* NOXFER */ #ifndef NOXMIT { "transmit", XYXMIT, 0 }, #endif /* NOXMIT */ #ifndef NOXFER #ifndef NOCSETS { "unknown-char-set", XYUNCS, 0 }, #endif /* NOCSETS */ #ifndef NOSPL { "variable-evaluation", XYVAREV, CM_INV }, #endif /* NOSPL */ #endif /* NOXFER */ #ifdef VMS { "vms_text", XYVMSTF, CM_ARG }, /* VMS Text-file Format */ #endif /* VMS */ { "wait", XYSLEEP, CM_INV }, #ifndef NOPUSH #ifdef UNIX { "wildcard-expansion", XYWILD, 0 }, #endif /* UNIX */ #endif /* NOPUSH */ #ifdef NT { "w", XYWIND, CM_INV|CM_ABR }, { "wi", XYWIND, CM_INV|CM_ABR }, { "win", XYWIND, CM_INV|CM_ABR }, #endif /* NT */ { "window-size", XYWIND, 0 }, #ifdef NT { "win95", XYWIN95, 0 }, #endif /* NT */ #ifdef ANYX25 { "x.25", XYX25, CM_LOC }, { "x25", XYX25, CM_INV|CM_LOC }, #endif /* ANYX25 */ { "xfer", XYXFER, CM_INV }, #ifndef NOXMIT { "xmit", XYXMIT, CM_INV }, #endif /* NOXMIT */ { "", 0, 0 } }; int nprm = (sizeof(prmtab) / sizeof(struct keytab)) - 1; /* How many */ struct keytab scntab[] = { /* Screen commands */ { "clear", SCN_CLR, 0 }, { "cleol", SCN_CLE, 0 }, { "move-to", SCN_MOV, 0 } }; int nscntab = (sizeof(scntab) / sizeof(struct keytab)); /* How many */ #ifdef ANYSSH /* SSH command table */ #ifdef SSHBUILTIN char * ssh_tmpuid = NULL, *ssh_tmpcmd = NULL, *ssh_tmpport = NULL, * ssh_tmpstr = NULL; int sshk_type = SSHKT_ED25519, /* SSH KEY CREATE /TYPE:x */ sshk_bits = 1024, /* SSH KEY CREATE /BITS:n */ sshk_din = SKDF_OSSH, /* SSH KEY DISPLAY /IN-FORMAT: */ sshk_dout = SKDF_OSSH; /* SSH KEY DISPLAY /OUT-FORMAT: */ char * sshk1_comment = NULL, /* SSH V1 COMMENT */ * sshkp_old = NULL, /* Old key passphrase */ * sshkp_new = NULL, /* New key passphrase */ * sshkc_pass = NULL, /* KEY CREATE /PASS:xxx */ * sshkc_comm = NULL, /* KEY CREATE /V1-RSA-COMMENT:xxx */ * sshd_file = NULL, /* DISPLAY file */ * sshk_file = NULL; /* SSH CREATE KEY file */ static struct keytab sshclr[] = { { "local-port-forward", SSHC_LPF, 0 }, { "remote-port-forward", SSHC_RPF, 0 }, { "", 0, 0 } }; static int nsshclr = (sizeof(sshclr) / sizeof(struct keytab)) - 1; static struct keytab sshrem[] = { { "local-port-forward", SSHR_LPF, 0 }, { "remote-port-forward", SSHR_RPF, 0 }, { "", 0, 0 } }; static int nsshrem = (sizeof(sshrem) / sizeof(struct keytab)) - 1; struct keytab sshopnsw[] = { { "/command", SSHSW_CMD, CM_ARG }, { "/password", SSHSW_PWD, CM_ARG }, { "/subsystem", SSHSW_SUB, CM_ARG }, { "/user", SSHSW_USR, CM_ARG }, { "/version", SSHSW_VER, CM_ARG }, /* SSH_FEAT_SSH_V1 */ { "/x11-forwarding", SSHSW_X11, CM_ARG }, /* SSH_FEAT_X11_FWD */ { "", 0, 0 } }; int nsshopnsw = (sizeof(sshopnsw) / sizeof(struct keytab)) - 1; static struct keytab sshkwtab[] = { { "add", XSSH_ADD, 0 }, /* SSH_FEAT_PORT_FWD */ { "agent", XSSH_AGT, 0 }, /* SSH_FEAT_AGENT_MGMT */ { "clear", XSSH_CLR, 0 }, /* SSH_FEAT_PORT_FWD */ { "forward-local-port", XSSH_FLP, CM_INV }, /* SSH_FEAT_PORT_FWD */ { "forward-remote-port", XSSH_FRP, CM_INV }, /* SSH_FEAT_PORT_FWD */ { "key", XSSH_KEY, 0 }, /* SSH_FEAT_KEY_MGMT */ { "load", XSSH_LOAD, CM_INV }, { "open", XSSH_OPN, 0 }, { "remove", XSSH_REM, 0 }, /* SSH_FEAT_PORT_FWD */ { "v2", XSSH_V2, 0 }, /* */ { "", 0, 0 } }; static int nsshcmd = (sizeof(sshkwtab) / sizeof(struct keytab)) - 1; #ifdef SSH_DLL /* SSH Commands that are available when the SSH backend hasn't been loaded */ static struct keytab sshloadkwtab[] = { { "load", XSSH_LOAD, 0 }, { "", 0, 0 } }; static int nsshloadcmd = (sizeof(sshloadkwtab) / sizeof(struct keytab)) - 1; #endif /* SSH_DLL */ static struct keytab ssh2tab[] = { { "rekey", XSSH2_RKE, 0 }, /* SSH_FEAT_REKEY_MANUAL */ { "", 0, 0 } }; static int nssh2tab = (sizeof(ssh2tab) / sizeof(struct keytab)); static struct keytab addfwd[] = { /* SET SSH ADD command table */ { "local-port-forward", SSHF_LCL, 0 }, { "remote-port-forward", SSHF_RMT, 0 }, { "", 0, 0 } }; static int naddfwd = (sizeof(addfwd) / sizeof(struct keytab)) - 1; static struct keytab sshagent[] = { /* SET SSH AGENT command table */ { "add", SSHA_ADD, 0 }, { "delete", SSHA_DEL, 0 }, { "list", SSHA_LST, 0 }, { "", 0, 0 } }; static int nsshagent = (sizeof(sshagent) / sizeof(struct keytab)) - 1; static struct keytab sshagtsw[] = { /* SET SSH AGENT LIST switch table */ { "/fingerprint", SSHASW_FP, 0 }, { "", 0, 0 } }; static int nsshagtsw = (sizeof(sshagtsw) / sizeof(struct keytab)) - 1; static struct keytab sshkey[] = { /* SET SSH KEY command table */ { "change-passphrase", SSHK_PASS, 0 }, { "create", SSHK_CREA, 0 }, { "display", SSHK_DISP, 0 }, /*{ "v1", SSHK_V1, 0 },*/ { "", 0, 0 } }; static int nsshkey = (sizeof(sshkey) / sizeof(struct keytab)) - 1; #ifdef COMMENT static struct keytab sshkv1[] = { /* SET SSH KEY V1 command table */ { "set-comment", 1, 0 } }; #endif /* COMMENT */ static struct keytab sshkpsw[] = { /* SET SSH KEY PASSPHRASE table */ { "/new-passphrase", 2, CM_ARG }, { "/old-passphrase", 1, CM_ARG } }; static struct keytab sshkcrea[] = { /* SSH KEY CREATE table */ { "/bits", SSHKC_BI, CM_ARG }, { "/passphrase", SSHKC_PP, CM_ARG }, { "/type", SSHKC_TY, CM_ARG }, /*{ "/v1-rsa-comment", SSHKC_1R, CM_ARG }*/ }; static int nsshkcrea = (sizeof(sshkcrea) / sizeof(struct keytab)); static struct keytab sshkcty[] = { /* SSH KEY CREATE /TYPE:xxx */ /*{ "srp", SSHKT_SRP, 0 }, { "v1-rsa", SSHKT_1R, 0 }, { "v2-dsa", SSHKT_2D, 0 }, { "v2-rsa", SSHKT_2R, 0 }*/ {"dss", SSHKT_DSS, 0 }, {"dss-cert01", SSHKT_DSS_CERT01, CM_INV }, {"ecdsa", SSHKT_ECDSA, 0 }, /* deprecated */ {"ecdsa-p256", SSHKT_ECDSA_P256, CM_INV }, {"ecdsa-p256-cert01", SSHKT_ECDSA_P256_CERT01, CM_INV }, {"ecdsa-p384", SSHKT_ECDSA_P384, CM_INV }, {"ecdsa-p384-cert01", SSHKT_ECDSA_P384_CERT01, CM_INV }, {"ecdsa-p521", SSHKT_ECDSA_P521, CM_INV }, {"ecdsa-p521-cert01", SSHKT_ECDSA_P521_CERT01, CM_INV }, {"ed25519", SSHKT_ED25519, 0 }, {"ed25519-cert01", SSHKT_ED25519_CERT01, CM_INV }, {"rsa", SSHKT_RSA, 0 }, {"rsa1", SSHKT_RSA1, CM_INV }, {"rsa-cert01", SSHKT_RSA_CERT01, CM_INV }, {"sk-ecdsa", SSHKT_SK_ECDSA, CM_INV }, {"sk-ecdsa-cert01", SSHKT_SK_ECDSA_CERT01, CM_INV }, {"sk-ed25519", SSHKT_SK_ED25519, CM_INV }, {"sk-ed25519-cert01", SSHKT_SK_ED25519_CERT01, CM_INV } }; static int nsshkcty = (sizeof(sshkcty) / sizeof(struct keytab)); static struct keytab sshdswi[] = { /* SET SSH KEY DISPLAY /switches */ { "/format", SSHKD_OUT, CM_ARG } }; static int nsshdswi = (sizeof(sshdswi) / sizeof(struct keytab)); #ifdef COMMENT static struct keytab sshdifmt[] = { /* SSH KEY DISPLAY /IN-FORMAT: */ { "openssh", SKDF_OSSH, 0 }, { "ssh.com", SKDF_SSHC, 0 } }; static int nsshdifmt = (sizeof(sshdifmt) / sizeof(struct keytab)); #endif /* COMMENT */ static struct keytab sshdofmt[] = { /* SSH KEY DISPLAY /IN-FORMAT: */ { "fingerprint", SKDF_FING, 0 }, /* "bubblebabble" representation not supported by libssh * { "ietf", SKDF_IETF, 0 }, */ { "openssh", SKDF_OSSH, 0 }, { "ssh.com", SKDF_SSHC, 0 } }; static int nsshdofmt = (sizeof(sshdofmt) / sizeof(struct keytab)); static struct keytab sshkermit[] = { /* SKERMIT */ { "open", SKRM_OPN, 0 } }; static int nsshkermit = (sizeof(sshkermit) / sizeof(struct keytab)); struct keytab sshkrmopnsw[] = { { "/password", SSHSW_PWD, CM_ARG }, { "/user", SSHSW_USR, CM_ARG }, { "/version", SSHSW_VER, CM_ARG }, { "", 0, 0 } }; int nsshkrmopnsw = (sizeof(sshkrmopnsw) / sizeof(struct keytab)) - 1; #endif /* SSHBUILTIN */ #ifdef SFTP_BUILTIN static struct keytab sftpkwtab[] = { /* SFTP */ { "cd", SFTP_CD, 0 }, { "chgrp", SFTP_CHGRP, 0 }, { "chmod", SFTP_CHMOD, 0 }, { "chown", SFTP_CHOWN, 0 }, { "delete", SFTP_RM, 0 }, { "dir", SFTP_DIR, 0 }, { "get", SFTP_GET, 0 }, { "mkdir", SFTP_MKDIR, 0 }, { "open", SFTP_OPN, 0 }, { "put", SFTP_PUT, 0 }, { "pwd", SFTP_PWD, 0 }, { "rename", SFTP_REN, 0 }, { "rm", SFTP_RM, CM_INV }, { "rmdir", SFTP_RMDIR, 0 }, { "symlink", SFTP_LINK, 0 }, { "version", SFTP_VER, 0 } }; static int nsftpkwtab = (sizeof(sftpkwtab) / sizeof(struct keytab)); #endif /* SFTP_BUILTIN */ #endif /* ANYSSH */ #ifdef NETCONN struct keytab netkey[] = { /* SET NETWORK table */ { "directory", XYNET_D, 0 }, { "type", XYNET_T, 0 } }; int nnetkey = (sizeof(netkey) / sizeof(struct keytab)); struct keytab netcmd[] = { /* These are the network types. */ #ifdef NETCMD { "command", NET_CMD, CM_INV }, /* Command */ #endif /* NETCMD */ #ifdef DECNET /* DECnet / PATHWORKS */ { "decnet", NET_DEC, 0 }, #endif /* DECNET */ #ifdef NETDLL { "dll", NET_DLL, CM_INV }, /* DLL to be loaded */ #endif /* NETDLL */ #ifdef NETFILE { "file", NET_FILE, CM_INV }, /* FILE (real crude) */ #endif /* NETFILE */ #ifdef NPIPE /* Named Pipes */ { "named-pipe", NET_PIPE, 0 }, #endif /* NPIPE */ #ifdef CK_NETBIOS { "netbios", NET_BIOS, 0 }, /* NETBIOS */ #endif /* CK_NETBIOS */ #ifdef DECNET /* DECnet / PATHWORKS (alias) */ { "pathworks", NET_DEC, CM_INV }, #endif /* DECNET */ #ifdef NETCMD { "pipe", NET_CMD, 0 }, /* Pipe */ #endif /* NETCMD */ #ifdef NETPTY { "pseudoterminal",NET_PTY, 0 }, /* Pseudoterminal */ #endif /* NETPTY */ #ifdef NETPTY { "pty", NET_PTY, CM_INV }, /* Inv syn for pseudoterm */ #endif /* NETPTY */ #ifdef SSHBUILTIN { "ssh", NET_SSH, 0 }, #endif /* SSHBUILTIN */ #ifdef SUPERLAT { "superlat", NET_SLAT, 0 }, /* Meridian Technologies' SuperLAT */ #endif /* SUPERLAT */ #ifdef TCPSOCKET /* TCP/IP sockets library */ { "tcp/ip", NET_TCPB, 0 }, #endif /* TCPSOCKET */ #ifdef SUPERLAT { "tes32", NET_SLAT, 0 }, /* Emulux TES32 */ #endif /* SUPERLAT */ #ifdef ANYX25 /* X.25 */ #ifdef SUNX25 { "x", NET_SX25, CM_INV|CM_ABR }, { "x.25", NET_SX25, 0 }, { "x25", NET_SX25, CM_INV }, #else #ifdef STRATUSX25 { "x", NET_VX25, CM_INV|CM_ABR }, { "x.25", NET_VX25, 0 }, { "x25", NET_VX25, CM_INV }, #endif /* STRATUSX25 */ #endif /* SUNX25 */ #ifdef IBMX25 { "x", NET_IX25, CM_INV|CM_ABR }, { "x.25", NET_IX25, CM_INV }, { "x25", NET_IX25, CM_INV }, #endif /* IBMX25 */ #ifdef HPX25 { "x", NET_IX25, CM_INV|CM_ABR }, { "x.25", NET_IX25, 0 }, { "x25", NET_IX25, CM_INV }, #endif /* HPX25 */ #endif /* ANYX25 */ { "", 0, 0 } }; int nnets = (sizeof(netcmd) / sizeof(struct keytab)); #ifndef NOTCPOPTS #ifdef TCPSOCKET /* TCP options */ struct keytab tcpopt[] = { { "address", XYTCP_ADDRESS, 0 }, #ifdef CK_DNS_SRV { "dns-service-records", XYTCP_DNS_SRV, 0 }, #endif /* CK_DNS_SRV */ #ifdef SO_DONTROUTE { "dontroute", XYTCP_DONTROUTE, 0 }, #endif /* SO_DONTROUTE */ #ifndef NOHTTP { "http-proxy", XYTCP_HTTP_PROXY, 0 }, #endif /* NOHTTP */ #ifdef SO_KEEPALIVE { "keepalive", XYTCP_KEEPALIVE, 0 }, #endif /* SO_KEEPALIVE */ #ifdef SO_LINGER { "linger", XYTCP_LINGER, 0 }, #endif /* SO_LINGER */ #ifdef TCP_NODELAY { "nagle", XYTCP_NAGLE, CM_INV }, { "nodelay", XYTCP_NODELAY, 0 }, #endif /* TCP_NODELAY */ { "reverse-dns-lookup", XYTCP_RDNS, 0 }, #ifdef SO_RCVBUF { "recvbuf", XYTCP_RECVBUF, 0 }, #endif /* SO_RCVBUF */ #ifdef SO_SNDBUF { "sendbuf", XYTCP_SENDBUF, 0 }, #endif /* SO_SNDBUF */ #ifdef NT #ifdef CK_SOCKS { "socks-server", XYTCP_SOCKS_SVR, 0 }, #endif /* CK_SOCKS */ #endif /* NT */ #ifdef VMS #ifdef DEC_TCPIP { "ucx-port-bug", XYTCP_UCX, 0 }, #endif /* DEC_TCPIP */ #endif /* VMS */ { "",0,0 } }; int ntcpopt = (sizeof(tcpopt) / sizeof(struct keytab)); #endif /* TCPSOCKET */ #endif /* NOTCPOPTS */ #endif /* NETCONN */ #ifdef OS2 /* K95 Manual Chapter Table -- Keep these two tables in sync! */ #ifdef COMMENT static char * linktbl[] = { /* Internal links in k95.htm */ "#top", /* 00 */ "#what", /* 01 */ "#install", /* 02 */ "#start", /* 03 */ "#dialer", /* 04 */ "#entries", /* 05 */ "#command", /* 06 */ "#terminal", /* 07 */ "#transfer", /* 08 */ "#hostmode" /* 09 */ }; static struct keytab chaptbl[] = { { "Command-Screen", 6, 0 }, { "Contents", 0, 0 }, { "Dialer-Entries", 5, 0 }, { "File-Transfer", 8, 0 }, { "Getting-Started", 3, 0 }, { "Host-Mode", 9, 0 }, { "Installation", 2, 0 }, { "Terminal-Emulation", 7, 0 }, { "Using-The-Dialer", 4, 0 }, { "What-Is-K95", 1, 0 }, { "", 0, 0 } }; static int nchaptbl = (sizeof(chaptbl) / sizeof(struct keytab) - 1); #endif /* COMMENT */ #endif /* OS2 */ #ifndef NOXFER /* Remote Command Table */ struct keytab remcmd[] = { #ifndef NOSPL { "as", XZASG, CM_INV|CM_ABR }, { "asg", XZASG, CM_INV }, { "assign", XZASG, 0 }, #endif /* NOSPL */ { "cd", XZCWD, 0 }, { "cdup", XZCDU, CM_INV }, { "copy", XZCPY, 0 }, { "cwd", XZCWD, CM_INV }, { "delete", XZDEL, 0 }, { "directory", XZDIR, 0 }, { "e", XZXIT, CM_ABR|CM_INV }, { "erase", XZDEL, CM_INV }, { "exit", XZXIT, 0 }, { "help", XZHLP, 0 }, #ifndef NOPUSH { "host", XZHOS, 0 }, #endif /* NOPUSH */ #ifndef NOFRILLS { "kermit", XZKER, 0 }, { "l", XZLGI, CM_ABR|CM_INV }, { "lo", XZLGI, CM_ABR|CM_INV }, { "log", XZLGI, CM_ABR|CM_INV }, { "login", XZLGI, 0 }, { "logout", XZLGO, 0 }, { "message", XZMSG, 0 }, { "mkdir", XZMKD, 0 }, { "print", XZPRI, 0 }, #endif /* NOFRILLS */ { "pwd", XZPWD, 0 }, #ifndef NOSPL { "query", XZQUE, 0 }, #endif /* NOSPL */ { "rename", XZREN, 0 }, { "rmdir", XZRMD, 0 }, { "set", XZSET, 0 }, { "space", XZSPA, 0 }, { "status", XZSTA, 0 }, #ifndef NOFRILLS { "type", XZTYP, 0 }, { "who", XZWHO, 0 }, #endif /* NOFRILLS */ { "", 0, 0} }; int nrmt = (sizeof(remcmd) / sizeof(struct keytab)) - 1; #endif /* NOXFER */ struct keytab logtab[] = { #ifdef CKLOGDIAL { "connections", LOGM, CM_INV }, { "cx", LOGM, 0 }, #endif /* CKLOGDIAL */ #ifdef DEBUG { "debugging", LOGD, 0 }, #endif /* DEBUG */ { "packets", LOGP, 0 }, #ifndef NOLOCAL { "session", LOGS, 0 }, #endif /* NOLOCAL */ #ifdef TLOG { "transactions", LOGT, 0 }, #endif /* TLOG */ { "", 0, 0 } }; int nlog = (sizeof(logtab) / sizeof(struct keytab)) - 1; struct keytab writab[] = { #ifndef NOSPL { "append-file", LOGW, CM_INV }, #endif /* NOSPL */ { "debug-log", LOGD, 0 }, { "error", LOGE, 0 }, #ifndef NOSPL { "file", LOGW, 0 }, #endif /* NOSPL */ { "packet-log", LOGP, 0 }, { "screen", LOGX, 0 }, #ifndef NOLOCAL { "session-log", LOGS, 0 }, #endif /* NOLOCAL */ { "sys$output", LOGX, CM_INV }, { "t", LOGT, CM_ABR|CM_INV }, /* Because of a typo in */ { "tr", LOGT, CM_ABR|CM_INV }, /* the book... */ { "tra", LOGT, CM_ABR|CM_INV }, { "tran", LOGT, CM_ABR|CM_INV }, { "trans", LOGT, CM_ABR|CM_INV }, { "transa", LOGT, CM_ABR|CM_INV }, { "transac", LOGT, CM_ABR|CM_INV }, { "transact", LOGT, CM_ABR|CM_INV }, { "transacti", LOGT, CM_ABR|CM_INV }, { "transactio", LOGT, CM_ABR|CM_INV }, { "transaction", LOGT, CM_ABR|CM_INV }, { "transaction-log", LOGT, 0 }, { "transactions", LOGT, CM_INV } }; int nwri = (sizeof(writab) / sizeof(struct keytab)); static struct keytab clrtab[] = { /* Keywords for CLEAR command */ #ifndef NOSPL { "alarm", CLR_ALR, 0 }, #ifdef CK_APC { "apc", CLR_APC, 0 }, #endif /* CK_APC */ #ifdef PATTERNS { "binary-patterns", CLR_BIN, 0 }, #endif /* PATTERNS */ { "both", CLR_DEV|CLR_INP, CM_INV }, #endif /* NOSPL */ #ifdef OS2 { "command-screen", CLR_CMD, 0 }, #endif /* OS2 */ #ifndef NOSPL { "device", CLR_DEV, CM_INV|CM_ABR }, { "device-and-input", CLR_DEV|CLR_INP, 0 }, #endif /* NOSPL */ { "device-buffer", CLR_DEV, 0 }, #ifndef NODIAL { "dial-status", CLR_DIA, 0 }, #endif /* NODIAL */ #ifndef NOSPL { "input-buffer", CLR_INP, 0 }, #endif /* NOSPL */ { "keyboard-buffer", CLR_KBD, 0 }, { "send-list", CLR_SFL, 0 }, #ifdef OS2 { "scr", CLR_SCL, CM_INV|CM_ABR }, #endif /* OS2 */ { "screen", CLR_SCR, 0 }, #ifdef OS2 { "scrollback", CLR_SCL, CM_INV }, { "terminal-screen", CLR_TRM, 0 }, #endif /* OS2 */ #ifdef PATTERNS { "text-patterns", CLR_TXT, 0 }, #endif /* PATTERNS */ { "", 0, 0 } }; int nclear = (sizeof(clrtab) / sizeof(struct keytab)) - 1; struct keytab clstab[] = { /* Keywords for CLOSE command */ #ifndef NOSPL { "!read", LOGR, CM_INV }, { "!write", LOGW, CM_INV }, #ifndef NOPUSH #endif /* NOPUSH */ #endif /* NOSPL */ #ifndef NOSPL { "append-file", LOGW, CM_INV }, #endif /* NOSPL */ #ifndef NOLOCAL { "connection", 9999, 0 }, #endif /* NOLOCAL */ #ifdef CKLOGDIAL { "cx-log", LOGM, 0 }, #endif /* CKLOGDIAL */ #ifdef DEBUG { "debug-log", LOGD, 0 }, #endif /* DEBUG */ { "host", 9999, CM_INV }, /* Synonym for CLOSE CONNECTION */ { "line", 9999, CM_INV }, /* Synonym for CLOSE CONNECTION */ { "p", LOGP, CM_INV|CM_ABR }, { "packet-log", LOGP, 0 }, { "port", 9999, CM_INV }, /* Synonym for CLOSE CONNECTION */ #ifndef NOSPL { "read-file", LOGR, 0 }, #endif /* NOSPL */ #ifndef NOLOCAL { "session-log", LOGS, 0 }, #endif /* NOLOCAL */ #ifdef TLOG { "t", LOGT, CM_ABR|CM_INV }, /* Because of a typo in */ { "tr", LOGT, CM_ABR|CM_INV }, /* the book... */ { "tra", LOGT, CM_ABR|CM_INV }, { "tran", LOGT, CM_ABR|CM_INV }, { "trans", LOGT, CM_ABR|CM_INV }, { "transa", LOGT, CM_ABR|CM_INV }, { "transac", LOGT, CM_ABR|CM_INV }, { "transact", LOGT, CM_ABR|CM_INV }, { "transacti", LOGT, CM_ABR|CM_INV }, { "transactio", LOGT, CM_ABR|CM_INV }, { "transaction", LOGT, CM_ABR|CM_INV }, { "transaction-log", LOGT, 0 }, { "transactions", LOGT, CM_INV }, #endif /* TLOG */ #ifndef NOSPL { "write-file", LOGW, 0 }, #endif /* NOSPL */ { "", 0, 0 } }; int ncls = (sizeof(clstab) / sizeof(struct keytab)) - 1; /* SHOW command arguments */ #ifndef NOSHOW struct keytab shotab[] = { #ifndef NOSPL { "alarm", SHALRM, 0 }, { "arg", SHARG, CM_INV|CM_ABR }, { "arguments", SHARG, 0 }, { "args", SHARG, CM_INV }, { "arrays", SHARR, 0 }, #endif /* NOSPL */ #ifndef NOCSETS { "associations", SHASSOC, 0 }, #endif /* NOCSETS */ #ifndef NOXFER { "attributes", SHATT, 0 }, #endif /* NOXFER */ #ifdef CK_AUTHENTICATION { "authentication", SHOAUTH, CM_INV }, #endif /* CK_AUTHENTICATION */ #ifndef NOPUSH #ifdef BROWSER { "browser", SHBROWSE, CM_PSH|CM_LOC }, #endif /* BROWSER */ #endif /* NOPUSH */ { "cd", SHCD, 0 }, { "character-sets", SHCSE, 0 }, { "cmd", SHCMD, CM_INV }, #ifndef NOLOCAL { "com", SHCOM, CM_INV|CM_ABR }, { "comm", SHCOM, CM_INV|CM_ABR }, { "communications", SHCOM, 0 }, #endif /* NOLOCAL */ { "command", SHCMD, 0 }, { "connection", SHCONNX, 0 }, #ifdef CK_SPEED { "control-prefixing", SHCTL, 0 }, #endif /* CK_SPEED */ #ifdef CKLOGDIAL { "cx", SHCONNX, CM_INV }, #endif /* CKLOGDIAL */ #ifndef NOSPL { "count", SHCOU, 0 }, #endif /* NOSPL */ { "d", SHDIA, CM_INV|CM_ABR }, #ifdef VMS { "default", SHDFLT, 0 }, #else { "default", SHDFLT, CM_INV }, #endif /* VMS */ #ifndef NODIAL { "dial", SHDIA, CM_LOC }, #endif /* NODIAL */ { "double/ignore",SHDBL, 0 }, #ifndef NOPUSH #ifndef NOFRILLS { "editor", SHEDIT, CM_PSH }, #endif /* NOFRILLS */ #endif /* NOPUSH */ #ifndef NOLOCAL { "escape", SHESC, CM_LOC }, #endif /* NOLOCAL */ { "exit", SHEXI, 0 }, { "extended-options", SHXOPT, CM_INV }, { "features", SHFEA, 0 }, { "file", SHFIL, 0 }, #ifndef NOLOCAL { "flow-control", SHOFLO, 0 }, #endif /* NOLOCAL */ #ifdef BROWSER { "ftp", SHOFTP, CM_PSH|CM_LOC }, #else #ifndef NOFTP #ifndef SYSFTP #ifdef TCPSOCKET { "ftp", SHOFTP, 0 }, /* (built-in ftp) */ #endif /* TCPSOCKET */ #endif /* SYSFTP */ #endif /* NOFTP */ #endif /* BROWSER */ #ifndef NOSPL { "functions", SHFUN, 0 }, { "globals", SHVAR, 0 }, #endif /* NOSPL */ #ifdef KUI { "gui", SHOGUI, 0 }, #endif /* KUI */ #ifdef CK_RECALL { "history", SHHISTORY, 0 }, #endif /* CK_RECALL */ { "ignore/double",SHDBL, CM_INV }, { "iksd", SHOIKS, CM_INV }, #ifndef NOSPL { "input", SHINP, 0 }, #endif /* NOSPL */ #ifndef NOSETKEY { "k", SHKEY, CM_INV|CM_ABR }, { "key", SHKEY, 0 }, #ifndef NOKVERBS { "kverbs", SHKVB, 0 }, #endif /* NOKVERBS */ #endif /* NOSETKEY */ #ifdef CK_LABELED { "labeled-file-info", SHLBL, 0 }, #endif /* CK_LABELED */ #ifndef NOCSETS { "languages", SHLNG, 0 }, #ifndef NO_LOCALE { "locale", SHOLOC,0 }, #endif /* NO_LOCALE */ #endif /* NOCSETS */ { "log", SHLOG, CM_INV|CM_ABR }, { "logs", SHLOG, 0 }, #ifndef NOSPL { "macros", SHMAC, 0 }, #endif /* NOSPL */ #ifndef NODIAL { "modem", SHMOD, CM_LOC }, #else { "modem-signals",SHCOM, CM_INV|CM_LOC }, #endif /* NODIAL */ #ifndef NOLOCAL #ifdef OS2MOUSE { "mouse", SHMOU, CM_LOC }, #endif /* OS2MOUSE */ #endif /* NOLOCAL */ #ifdef NETCONN { "network", SHNET, CM_LOC }, #else { "network", SHNET, CM_INV|CM_LOC }, #endif /* NETCONN */ { "options", SHOPTS, 0 }, #ifndef NOSPL { "output", SHOUTP, CM_INV }, #endif /* NOSPL */ #ifdef ANYX25 #ifndef IBMX25 { "pad", SHPAD, CM_LOC }, #endif /* IBMX25 */ #endif /* ANYX25 */ { "parameters", SHPAR, CM_INV }, #ifdef PATTERNS { "patterns", SHOPAT, 0 }, #endif /* PATTERNS */ { "printer", SHPRT, 0 }, #ifdef CK_SPEED { "prefixing", SHCTL, CM_INV }, #endif /* CK_SPEED */ #ifndef NOXFER { "protocol", SHPRO, 0 }, #endif /* NOXFER */ { "rename", SHOREN, 0 }, #ifndef NOSPL { "scripts", SHSCR, CM_LOC }, #endif /* NOSPL */ { "send-list", SHSFL, 0 }, #ifndef NOSERVER { "server", SHSER, 0 }, #endif /* NOSERVER */ #ifndef NOSEXP { "sexpression", SHSEXP, 0 }, #endif /* NOSEXP */ #ifdef ANYSSH { "ssh", SHOSSH, 0 }, #endif /* ANYSSH */ { "stack", SHSTK, 0 }, { "status", SHSTA, 0 }, #ifdef STREAMING { "streaming", SHOSTR, 0 }, #endif /* STREAMING */ #ifndef NOLOCAL #ifdef OS2 { "tabs", SHTAB, CM_INV|CM_LOC }, #endif /* OS2 */ #ifdef CK_TAPI { "tapi", SHTAPI, CM_LOC }, { "tapi-comm", SHTAPI_C, CM_INV|CM_LOC }, { "tapi-location", SHTAPI_L, CM_INV|CM_LOC }, { "tapi-modem", SHTAPI_M, CM_INV|CM_LOC }, #endif /* CK_TAPI */ { "tcp", SHTCP, CM_LOC }, #ifdef TNCODE { "tel", SHTEL, CM_INV|CM_ABR }, { "telnet", SHTEL, 0 }, { "telopt", SHTOPT, 0 }, { "temp-directory", SHOTMPDIR, 0 }, #endif /* TNCODE */ { "terminal", SHTER, CM_LOC }, #endif /* NOLOCAL */ #ifndef NOSPL { "tmp-directory", SHOTMPDIR, CM_INV }, #endif /* NOSPL */ #ifndef NOXMIT { "tr", SHXMI, CM_INV|CM_ABR }, { "tra", SHXMI, CM_INV|CM_ABR }, { "tran", SHXMI, CM_INV|CM_ABR }, { "trans", SHXMI, CM_INV|CM_ABR }, #endif /* NOXMIT */ #ifndef NOXFER { "transfer", SHOXFER, 0 }, #endif /* NOXFER */ #ifndef NOXMIT { "transmit", SHXMI, 0 }, #endif /* NOXMIT */ #ifdef CK_TRIGGER { "trigger", SHTRIG, CM_LOC }, #endif /* CK_TRIGGER */ #ifndef NOSETKEY #ifndef NOKVERBS #ifdef OS2 { "udk", SHUDK, CM_LOC }, #endif /* OS2 */ #endif /* NOKVERBS */ #endif /* NOSETKEY */ #ifndef NOSPL { "variables", SHBUI, 0 }, #endif /* NOSPL */ #ifndef NOFRILLS { "versions", SHVER, 0 }, #endif /* NOFRILLS */ #ifdef VMS { "vms_text", SHOVMSTXT, 0}, #endif /* VMS */ #ifdef OS2 { "vscrn", SHVSCRN, CM_INV|CM_LOC }, #endif /* OS2 */ { "xfer", SHOXFER, CM_INV }, #ifndef NOXMIT { "xmit", SHXMI, CM_INV }, #endif /* NOXMIT */ { "", 0, 0 } }; int nsho = (sizeof(shotab) / sizeof(struct keytab)) - 1; #endif /* NOSHOW */ #ifdef ANYX25 #ifndef IBMX25 struct keytab padtab[] = { /* PAD commands */ { "clear", XYPADL, 0 }, { "interrupt", XYPADI, 0 }, { "reset", XYPADR, 0 }, { "status", XYPADS, 0 } }; int npadc = (sizeof(padtab) / sizeof(struct keytab)); #endif /* IBMX25 */ #endif /* ANYX25 */ #ifndef NOSERVER static struct keytab kmstab[] = { { "both", 3, 0 }, { "local", 1, 0 }, { "remote", 2, 0 } }; static struct keytab enatab[] = { /* ENABLE commands */ { "all", EN_ALL, 0 }, #ifndef NOSPL { "as", EN_ASG, CM_INV|CM_ABR }, { "asg", EN_ASG, CM_INV }, { "assign", EN_ASG, 0 }, #endif /* NOSPL */ #ifndef datageneral { "bye", EN_BYE, 0 }, #endif /* datageneral */ { "cd", EN_CWD, 0 }, #ifdef ZCOPY { "copy", EN_CPY, 0 }, #endif /* ZCOPY */ { "cwd", EN_CWD, CM_INV }, { "delete", EN_DEL, 0 }, { "directory", EN_DIR, 0 }, { "enable", EN_ENA, CM_INV }, { "exit", EN_XIT, 0 }, { "finish", EN_FIN, 0 }, { "get", EN_GET, 0 }, { "host", EN_HOS, 0 }, { "mail", EN_MAI, 0 }, { "mkdir", EN_MKD, 0 }, { "print", EN_PRI, 0 }, #ifndef NOSPL { "query", EN_QUE, 0 }, #endif /* NOSPL */ { "rename", EN_REN, 0 }, { "retrieve", EN_RET, CM_INV }, { "rmdir", EN_RMD, 0 }, { "send", EN_SEN, 0 }, { "set", EN_SET, 0 }, { "space", EN_SPA, 0 }, { "type", EN_TYP, 0 }, { "who", EN_WHO, 0 } }; static int nena = (sizeof(enatab) / sizeof(struct keytab)); #endif /* NOSERVER */ struct keytab txtbin[] = { { "all", 2, 0 }, { "binary", 1, 0 }, { "text", 0, 0 } }; #ifndef NOXFER static struct keytab sndtab[] = { /* SEND command options */ { "/after", SND_AFT, CM_ARG }, #ifndef NOSPL { "/array", SND_ARR, CM_ARG }, #endif /* NOSPL */ { "/as-name", SND_ASN, CM_ARG }, { "/b", SND_BIN, CM_INV|CM_ABR }, { "/before", SND_BEF, CM_ARG }, { "/binary", SND_BIN, 0 }, #ifdef CALIBRATE { "/c", SND_CMD, CM_INV|CM_ABR }, { "/calibrate", SND_CAL, CM_INV|CM_ARG }, #endif /* CALIBRATE */ { "/command", SND_CMD, CM_PSH }, { "/delete", SND_DEL, 0 }, #ifdef UNIXOROSK { "/dotfiles", SND_DOT, 0 }, #endif /* UNIXOROSK */ { "/except", SND_EXC, CM_ARG }, #ifdef PIPESEND { "/filter", SND_FLT, CM_ARG|CM_PSH }, #endif /* PIPESEND */ { "/filenames", SND_NAM, CM_ARG }, #ifdef CKSYMLINK { "/followlinks", SND_LNK, 0 }, #endif /* CKSYMLINK */ #ifdef VMS { "/image", SND_IMG, 0 }, #else { "/image", SND_BIN, CM_INV }, #endif /* VMS */ #ifdef CK_LABELED { "/labeled", SND_LBL, 0 }, #endif /* CK_LABELED */ { "/larger-than", SND_LAR, CM_ARG }, { "/listfile", SND_FIL, CM_ARG }, #ifndef NOFRILLS { "/mail", SND_MAI, CM_ARG }, #endif /* NOFRILLS */ #ifdef CK_TMPDIR { "/move-to", SND_MOV, CM_ARG }, #endif /* CK_TMPDIR */ { "/nobackupfiles", SND_NOB, 0 }, #ifdef UNIXOROSK { "/nodotfiles", SND_NOD, 0 }, #endif /* UNIXOROSK */ #ifdef CKSYMLINK { "/nofollowlinks", SND_NLK, 0 }, #endif /* CKSYMLINK */ { "/not-after", SND_NAF, CM_ARG }, { "/not-before", SND_NBE, CM_ARG }, { "/pathnames", SND_PTH, CM_ARG }, { "/print", SND_PRI, CM_ARG }, #ifdef CK_XYZ { "/protocol", SND_PRO, CM_ARG }, #else { "/protocol", SND_PRO, CM_ARG|CM_INV }, #endif /* CK_XYZ */ { "/quiet", SND_SHH, 0 }, { "/recover", SND_RES, 0 }, #ifdef RECURSIVE /* Systems where we do recursion */ { "/recursive", SND_REC, 0 }, #else #ifdef VMS /* Systems that do recursion themselves without our assistance */ /* if we give them the right kind of wildcard */ { "/recursive", SND_REC, 0 }, #else #ifdef datageneral { "/recursive", SND_REC, 0 }, #else { "/recursive", SND_REC, CM_INV }, #endif /* datageneral */ #endif /* VMS */ #endif /* RECURSIVE */ { "/rename-to", SND_REN, CM_ARG }, { "/since", SND_AFT, CM_INV|CM_ARG }, { "/smaller-than", SND_SMA, CM_ARG }, { "/starting-at", SND_STA, CM_ARG }, #ifndef NOFRILLS { "/su", SND_ASN, CM_ARG|CM_INV|CM_ABR }, { "/sub", SND_ASN, CM_ARG|CM_INV|CM_ABR }, { "/subject", SND_ASN, CM_ARG }, #endif /* NOFRILLS */ #ifdef RECURSIVE { "/subdirectories", SND_REC, CM_INV }, #endif /* RECURSIVE */ { "/text", SND_TXT, 0 }, { "/transparent", SND_XPA, 0 }, { "/type", SND_TYP, CM_ARG } }; #define NSNDTAB sizeof(sndtab)/sizeof(struct keytab) static int nsndtab = NSNDTAB; #ifndef NOMSEND static struct keytab msndtab[] = { /* MSEND options */ { "/after", SND_AFT, CM_ARG }, { "/before", SND_BEF, CM_ARG }, { "/binary", SND_BIN, 0 }, { "/delete", SND_DEL, 0 }, { "/except", SND_EXC, CM_ARG }, { "/filenames", SND_NAM, CM_ARG }, #ifdef CKSYMLINK { "/followlinks", SND_LNK, 0 }, #endif /* CKSYMLINK */ #ifdef VMS { "/image", SND_IMG, 0 }, #else { "/image", SND_BIN, CM_INV }, #endif /* VMS */ #ifdef CK_LABELED { "/labeled", SND_LBL, 0 }, #endif /* CK_LABELED */ { "/larger-than", SND_LAR, CM_ARG }, { "/list", SND_FIL, CM_ARG }, #ifndef NOFRILLS { "/mail", SND_MAI, CM_ARG }, #endif /* NOFRILLS */ #ifdef CK_TMPDIR { "/move-to", SND_MOV, CM_ARG }, #endif /* CK_TMPDIR */ #ifdef CKSYMLINK { "/nofollowlinks", SND_NLK, 0 }, #endif /* CKSYMLINK */ { "/not-after", SND_NAF, CM_ARG }, { "/not-before", SND_NBE, CM_ARG }, { "/pathnames", SND_PTH, CM_ARG }, { "/print", SND_PRI, CM_ARG }, #ifdef CK_XYZ { "/protocol", SND_PRO, CM_ARG }, #endif /* CK_XYZ */ { "/quiet", SND_SHH, 0 }, { "/recover", SND_RES, 0 }, { "/rename-to", SND_REN, CM_ARG }, { "/since", SND_AFT, CM_INV|CM_ARG }, { "/smaller-than", SND_SMA, CM_ARG }, { "/starting-at", SND_STA, CM_ARG }, #ifndef NOFRILLS { "/subject", SND_ASN, CM_ARG }, #endif /* NOFRILLS */ { "/text", SND_TXT, 0 }, { "/transparent", SND_XPA, 0 }, { "/type", SND_TYP, CM_ARG } }; #define NMSNDTAB sizeof(msndtab)/sizeof(struct keytab) static int nmsndtab = NMSNDTAB; #endif /* NOMSEND */ #endif /* NOXFER */ /* CONNECT command switches */ #define CONN_II 0 /* Idle interval */ #define CONN_IS 1 /* Idle string */ #define CONN_IL 2 /* Idle limit */ #define CONN_NV 3 /* Non-Verbose */ #define CONN_TL 4 /* Time limit */ #define CONN_TS 5 /* Trigger string */ #define CONN_AS 6 /* Asynchronous */ #define CONN_SY 7 /* Synchronous */ #define CONN_MAX 7 /* Number of CONNECT switches */ #ifndef NOLOCAL static struct keytab conntab[] = { #ifdef OS2 { "/asynchronous", CONN_AS, CM_INV }, #endif /* OS2 */ #ifdef XLIMITS { "/idle-interval", CONN_II, CM_ARG }, { "/idle-limit", CONN_IL, CM_ARG }, { "/idle-string", CONN_IS, CM_ARG }, { "/quietly", CONN_NV, CM_INV }, #else { "/quietly", CONN_NV, 0 }, #endif /* XLIMITS */ #ifdef OS2 { "/synchronous", CONN_SY, CM_INV }, #endif /* OS2 */ #ifdef XLIMITS { "/time-limit", CONN_TL, CM_ARG }, #endif /* XLIMITS */ #ifdef CK_TRIGGER { "/trigger", CONN_TS, CM_ARG }, #endif /* CK_TRIGGER */ { "",0,0 } }; #define NCONNTAB sizeof(conntab)/sizeof(struct keytab) static int nconntab = NCONNTAB; #endif /* NOLOCAL */ #ifndef NOXFER static struct keytab stattab[] = { /* STATISTICS command switches */ { "/brief", 1, 0 }, { "/verbose", 0, 0 } }; #endif /* NOXFER */ #ifndef NOSPL #ifdef COMMENT struct mtab mactab[MAC_MAX] = { /* Preinitialized macro table */ { NULL, NULL, 0 } }; #else struct mtab *mactab; /* Dynamically allocated macro table */ #endif /* COMMENT */ int nmac = 0; struct keytab mackey[MAC_MAX]; /* Macro names as command keywords */ #endif /* NOSPL */ #ifndef NOSPL #ifdef OS2 struct keytab beeptab[] = { /* Beep options */ { "error", BP_FAIL, 0 }, { "information", BP_NOTE, 0 }, { "warning", BP_WARN, 0 } }; int nbeeptab = sizeof(beeptab)/sizeof(struct keytab); /* CLEAR COMMMAND-SCREEN options */ #define CLR_C_ALL 0 #define CLR_C_BOL 1 #define CLR_C_BOS 2 #define CLR_C_EOL 3 #define CLR_C_EOS 4 #define CLR_C_LIN 5 #define CLR_C_SCR 6 struct keytab clrcmdtab[] = { { "all", CLR_C_ALL, 0 }, { "bol", CLR_C_BOL, 0 }, { "bos", CLR_C_BOS, 0 }, { "eol", CLR_C_EOL, 0 }, { "eos", CLR_C_EOS, 0 }, { "line", CLR_C_LIN, 0 }, { "scrollback", CLR_C_SCR, 0 } }; int nclrcmd = sizeof(clrcmdtab)/sizeof(struct keytab); #endif /* OS2 */ #endif /* NOSPL */ #ifdef COMMENT /* Not used at present */ static struct keytab pagetab[] = { { "/more", 1, CM_INV }, { "/nopage", 0, 0 }, { "/page", 1, 0 } }; int npagetab = sizeof(pagetab)/sizeof(struct keytab); #endif /* COMMENT */ #define TYP_NOP 0 /* /NOPAGE */ #define TYP_PAG 1 /* /PAGE */ #define TYP_HEA 2 /* /HEAD:n */ #define TYP_TAI 3 /* /TAIL:n */ #define TYP_PAT 4 /* /MATCH:pattern */ #define TYP_WID 5 /* /WIDTH:cols */ #define TYP_COU 6 /* /COUNT */ #define TYP_OUT 7 /* /OUTPUT:file */ #define TYP_PFX 8 /* /PREFIX:string */ #ifdef UNICODE #define TYP_XIN 9 /* /TRANSLATE-FROM:charset */ #define TYP_XUT 10 /* /TRANSLATE-TO:charset */ #define TYP_XPA 11 /* /TRANSPARENT */ #endif /* UNICODE */ #ifdef KUI #define TYP_GUI 12 /* /GUI:title */ #define TYP_HIG 13 /* /HEIGHT:rows */ #endif /* KUI */ #define TYP_NUM 14 /* /NUMBER */ #define TYP_INT 15 /* /INTERPRET (kermit / escapes) */ static struct keytab typetab[] = { /* TYPE command switches */ { "/count", TYP_COU, 0 }, #ifdef UNICODE { "/character-set", TYP_XIN, CM_ARG }, { "/convert", TYP_XUT, CM_ARG }, #endif /* UNICODE */ #ifdef KUI { "/gui", TYP_GUI, CM_ARG }, #endif /* KUI */ { "/head", TYP_HEA, CM_ARG }, #ifdef KUI { "/height", TYP_HIG, CM_ARG }, #endif /* KUI */ #ifdef TYPEINTERPRET { "/interpret", TYP_INT, 0 }, /* New 2022-08-22 */ #endif /* TYPEINTERPRET */ { "/match", TYP_PAT, CM_ARG }, #ifdef CK_TTGWSIZ { "/more", TYP_PAG, CM_INV }, { "/nopage", TYP_NOP, 0 }, { "/number", TYP_NUM, 0 }, { "/output", TYP_OUT, CM_ARG }, { "/page", TYP_PAG, 0 }, #endif /* CK_TTGWSIZ */ { "/prefix", TYP_PFX, CM_ARG }, { "/tail", TYP_TAI, CM_ARG }, #ifdef UNICODE { "/translate-to", TYP_XUT, CM_INV|CM_ARG }, { "/transparent", TYP_XPA, 0 }, #endif /* UNICODE */ { "/width", TYP_WID, CM_ARG }, #ifdef UNICODE { "/xlate-to", TYP_XUT, CM_INV|CM_ARG }, #endif /* UNICODE */ { "", 0, 0 } }; int ntypetab = sizeof(typetab)/sizeof(struct keytab) - 1; int typ_page = -1; /* TYPE /[NO]PAGE default */ int typ_wid = -1; #ifndef NOSPL #define TRA_ALL 999 /* TRACE command */ #define TRA_ASG 0 #define TRA_CMD 1 int tra_asg = 0; int tra_cmd = 0; static struct keytab tracetab[] = { /* TRACE options */ { "all", TRA_ALL, 0 }, { "assignments", TRA_ASG, 0 }, { "command-level", TRA_CMD, 0 } }; static int ntracetab = sizeof(tracetab)/sizeof(struct keytab); #endif /* NOSPL */ #ifndef NOSHOW VOID showtypopts() { printf(" TYPE "); if (typ_page > -1) { prtopt(&optlines,typ_page ? "/PAGE" : "/NOPAGE"); } else prtopt(&optlines,"(no options set)"); if (typ_wid > -1) { ckmakmsg(tmpbuf,TMPBUFSIZ,"/WIDTH:",ckitoa(typ_wid),NULL,NULL); prtopt(&optlines,tmpbuf); } prtopt(&optlines,""); } #endif /* NOSHOW */ #ifdef LOCUS /* isauto == 1 if locus is being switched automatically */ VOID #ifdef CK_ANSIC setlocus(int x, int isauto) #else setlocus(x, isauto) int x, isauto; #endif /* CK_ANSIC */ { extern int quitting; if (x) x = 1; if (x && locus) return; if (!x && !locus) return; /* Get here if it actually needs to be changed */ #ifdef OS2 if (isauto && /* Automatically switching */ !quitting && /* not exiting */ autolocus == 2) { /* and AUTOLOCUS is set to ASK */ char locmsg[300]; ckmakmsg(locmsg,300, "Switching Locus to ", x ? "LOCAL" : "REMOTE", " for file management commands\n" "such as CD, DIRECTORY, DELETE, RENAME. Type HELP SET\n" "LOCUS at the K-95> prompt for further info. Use the\n" #ifdef KUI "Actions menu or SET LOCUS command to disable automatic\n" "Locus switching or to disable these queries.", #else /* KUI */ "SET LOCUS command to disable automatic locus switching\n" "or to disable these queries.", #endif /* KUI */ NULL); if (uq_ok(locmsg,"OK to switch Locus?",3,NULL,1)) { locus = x; #ifdef KUI KuiSetProperty(KUI_LOCUS,x,0); #endif /* KUI */ return; } } else { #endif /* OS2 */ if (isauto && msgflg && !quitting) printf("Switching LOCUS for file-management commands to %s %s.\n", x ? "LOCAL" : "REMOTE", "(HELP LOCUS for info)" ); locus = x; #ifdef OS2 #ifdef KUI KuiSetProperty(KUI_LOCUS,x,0); #endif /* KUI */ } #endif /* OS2 */ } VOID #ifdef CK_ANSIC setautolocus( int x ) #else setautolocus(x) int x; #endif /* CK_ANSIC */ { autolocus = x; #ifdef KUI KuiSetProperty(KUI_AUTO_LOCUS,x,0); #endif /* KUI */ } #endif /* LOCUS */ int settypopts() { /* Set TYPE option defaults */ int xp = -1; int c, getval; while (1) { if ((y = cmswi(typetab,ntypetab,"Switch","",xxstring)) < 0) { if (y == -3) break; else return(y); } c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } switch (y) { case TYP_NOP: xp = 0; break; case TYP_PAG: xp = 1; break; case TYP_WID: if (getval) if ((x = cmnum("Column at which to truncate", ckitoa(cmd_cols),10,&y,xxstring)) < 0) return(x); typ_wid = y; break; default: printf("?Sorry, this option can not be set\n"); return(-9); } } if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); if (xp > -1) typ_page = xp; /* Confirmed, save defaults */ return(success = 1); } _PROTOTYP (char * getbasename, ( char * ) ); /* Forward declarations of functions local to this module */ #ifdef UNIX _PROTOTYP (int douchmod, ( void ) ); #endif /* UNIX */ #ifdef CKPURGE _PROTOTYP (int dopurge, ( void ) ); #endif /* CKPURGE */ #ifndef NOSPL _PROTOTYP (int doundef, ( int ) ); _PROTOTYP (int doask, ( int ) ); _PROTOTYP (int dodef, ( int ) ); _PROTOTYP (int doelse, ( void ) ); _PROTOTYP (int dofor, ( void ) ); #endif /* NOSPL */ #ifndef NODIAL _PROTOTYP (int dodial, ( int ) ); #endif /* NODIAL */ _PROTOTYP (int dodel, ( void ) ); _PROTOTYP (int dopaus, ( int ) ); #ifndef NOPUSH #ifdef TCPSOCKET _PROTOTYP (int doping, ( void ) ); _PROTOTYP (int doftp, ( void ) ); #endif /* TCPSOCKET */ #endif /* NOPUSH */ #ifndef NORENAME #ifndef NOFRILLS _PROTOTYP (int dorenam, ( void ) ); #endif /* NOFRILLS */ #endif /* NORENAME */ #ifdef ZCOPY _PROTOTYP (int docopy, ( void ) ); #endif /* ZCOPY */ #ifdef NT _PROTOTYP (int dolink, ( void )); #endif /* NT */ #ifdef CK_REXX _PROTOTYP (int dorexx, ( void ) ); #endif /* CK_REXX */ #ifdef TNCODE static struct keytab telcmd[] = { { "abort", TN_ABORT, CM_INV }, /* Emotionally toned - don't show */ { "ao", TN_AO, 0 }, { "ayt", TN_AYT, 0 }, { "break", BREAK, 0 }, { "cancel",TN_ABORT, 0 }, { "dmark", TN_DM, 0 }, { "do", DO, 0 }, { "dont", DONT, 0 }, { "ec", TN_EC, 0 }, { "el", TN_EL, 0 }, { "eof", TN_EOF, 0 }, { "eor", TN_EOR, 0 }, #ifdef CK_KERBEROS #ifdef KRB5 #define TN_FWD 1 { "forward", TN_FWD, CM_INV }, #endif /* KRB5 */ #endif /* CK_KERBEROS */ { "ga", TN_GA, 0 }, { "ip", TN_IP, 0 }, { "nop", TN_NOP, 0 }, { "sak", TN_SAK, CM_INV }, { "sb", SB, 0 }, { "se", SE, 0 }, { "susp", TN_SUSP, 0 }, { "will", WILL, 0 }, { "wont", WONT, 0 } }; static int ntelcmd = (sizeof(telcmd) / sizeof(struct keytab)); static struct keytab tnopts[] = { #ifdef CK_AUTHENTICATION { "auth", TELOPT_AUTHENTICATION, 0 }, #else { "auth", TELOPT_AUTHENTICATION, CM_INV }, #endif /* CK_AUTHENTICATION */ { "binary", TELOPT_BINARY, 0 }, #ifdef TN_COMPORT { "c", TELOPT_COMPORT, CM_INV|CM_ABR}, { "co", TELOPT_COMPORT, CM_INV|CM_ABR}, { "com", TELOPT_COMPORT, CM_INV|CM_ABR}, { "com-port-control", TELOPT_COMPORT, 0 }, { "comport-control", TELOPT_COMPORT, CM_INV}, #else /* TN_COMPORT */ { "com-port-control", TELOPT_COMPORT, CM_INV }, { "comport-control", TELOPT_COMPORT, CM_INV}, #endif /* TN_COMPORT */ { "echo", TELOPT_ECHO, 0 }, #ifdef CK_ENCRYPTION { "encrypt", TELOPT_ENCRYPTION, 0 }, #else { "encrypt", TELOPT_ENCRYPTION, CM_INV }, #endif /* CK_ENCRYPTION */ #ifdef CK_FORWARD_X { "forward-x", TELOPT_FORWARD_X, 0 }, #else { "forward-x", TELOPT_FORWARD_X, CM_INV }, #endif /* CK_FORWARD_X */ #ifdef IKS_OPTION { "kermit", TELOPT_KERMIT, 0 }, #else { "kermit", TELOPT_KERMIT, CM_INV }, #endif /* IKS_OPTION */ { "lflow", TELOPT_LFLOW, CM_INV }, { "logout", TELOPT_LOGOUT, CM_INV }, #ifdef CK_NAWS { "naws", TELOPT_NAWS, 0 }, #else { "naws", TELOPT_NAWS, CM_INV }, #endif /* CK_NAWS */ #ifdef CK_ENVIRONMENT { "new-environment", TELOPT_NEWENVIRON, 0 }, #else { "new-environment", TELOPT_NEWENVIRON, CM_INV }, #endif /* CK_ENVIRONMENT */ { "pragma-heartbeat",TELOPT_PRAGMA_HEARTBEAT, CM_INV }, { "pragma-logon", TELOPT_PRAGMA_LOGON, CM_INV }, { "pragma-sspi", TELOPT_SSPI_LOGON, CM_INV }, { "sak", TELOPT_IBM_SAK, CM_INV }, #ifdef CK_SNDLOC { "send-location", TELOPT_SNDLOC, 0 }, #else { "send-location", TELOPT_SNDLOC, CM_INV }, #endif /* CK_SNDLOC */ { "sga", TELOPT_SGA, 0 }, #ifdef CK_SSL { "start-tls", TELOPT_START_TLS, 0 }, #else { "start-tls", TELOPT_START_TLS, CM_INV }, #endif /* CK_SSL */ { "ttype", TELOPT_TTYPE, 0 }, #ifdef CK_ENVIRONMENT { "xdisplay-location", TELOPT_XDISPLOC, 0 }, #else { "xdisplay-location", TELOPT_XDISPLOC, CM_INV }, #endif /* CK_ENVIRONMENT */ { "", 0, 0 } }; static int ntnopts = (sizeof(tnopts) / sizeof(struct keytab)) - 1; static struct keytab tnsbopts[] = { #ifdef CK_NAWS { "naws", TELOPT_NAWS, 0 }, #endif /* CK_NAWS */ { "", 0, 0 } }; static int ntnsbopts = (sizeof(tnsbopts) / sizeof(struct keytab)) - 1; #endif /* TNCODE */ #ifdef TCPSOCKET #ifndef NOPUSH #ifdef SYSFTP int doftp() { /* (External) FTP command */ char *p, *f; /* (See doxftp() for internal one) */ int x; if (network) /* If we have a current connection */ ckstrncpy(line,ttname,LINBUFSIZ); /* get the host name */ else *line = '\0'; /* as default host */ for (p = line; *p; p++) /* Remove ":service" from end. */ if (*p == ':') { *p = '\0'; break; } if ((x = cmtxt("IP host name or number", line, &s, xxstring)) < 0) return(x); if (nopush) { printf("?Sorry, FTP command disabled\n"); return(success = 0); } /* Construct FTP command */ #ifdef VMS #ifdef MULTINET /* TGV MultiNet */ ckmakmsg(line,LINBUFSIZ,"multinet ftp ",s,NULL,NULL); #else ckmakmsg(line,LINBUFSIZ,"ftp ",s,NULL,NULL); #endif /* MULTINET */ #else /* Not VMS */ #ifdef OS2ORUNIX #ifndef NOFTP f = ftpapp; if (!f) f = ""; if (!f[0]) f = "ftp"; ckmakmsg(line,LINBUFSIZ,f," ",s,NULL); #ifdef OS2 p = line + strlen(ftpapp); while (p != line) { if (*p == '/') *p = '\\'; p--; } #endif /* OS2 */ #else /* NOFTP */ ckmakmsg(line,LINBUFSIZ,"ftp ",s,NULL,NULL); #endif /* NOFTP */ #else /* OS2ORUNIX */ ckmakmsg(line,LINBUFSIZ,"ftp ",s,NULL,NULL); #endif /* OS2ORUNIX */ #endif /* VMS */ conres(); /* Make console normal */ #ifdef DEC_TCPIP printf("\n"); /* Prevent prompt-stomping */ #endif /* DEC_TCPIP */ x = zshcmd(line); concb((char)escape); return(success = x); } #endif /* SYSFTP */ int doping() { /* PING command */ char *p; /* just runs ping program */ int x; if (network) /* If we have a current connection */ ckstrncpy(line,ttname,LINBUFSIZ); /* get the host name */ else *line = '\0'; /* as default host to be pinged. */ for (p = line; *p; p++) /* Remove ":service" from end. */ if (*p == ':') { *p = '\0'; break; } if ((x = cmtxt("IP host name or number", line, &s, xxstring)) < 0) return(x); if (nopush) { printf("?Sorry, PING command disabled\n"); return(success = 0); } /* Construct PING command */ #ifdef VMS #ifdef MULTINET /* TGV MultiNet */ ckmakmsg(line,LINBUFSIZ,"multinet ping ",s," /num=1",NULL); #else ckmakmsg(line,LINBUFSIZ,"ping ",s," 56 1",NULL); /* Other VMS TCP/IP's */ #endif /* MULTINET */ #else /* Not VMS */ ckmakmsg(line,LINBUFSIZ,"ping ",s,NULL,NULL); #endif /* VMS */ conres(); /* Make console normal */ #ifdef DEC_TCPIP printf("\n"); /* Prevent prompt-stomping */ #endif /* DEC_TCPIP */ x = zshcmd(line); concb((char)escape); return(success = x); } #endif /* NOPUSH */ #endif /* TCPSOCKET */ static VOID #ifdef CK_ANSIC doend( int x ) #else doend(x) int x; #endif /* CK_ANSIC */ { #ifndef NOSPL /* Pop from all FOR/WHILE/XIF/SWITCH's */ debug(F101,"doend maclvl 1","",maclvl); while ((maclvl > 0) && (m_arg[maclvl-1][0]) && (cmdstk[cmdlvl].src == CMD_MD) && (!strncmp(m_arg[maclvl-1][0],"_xif",4) || !strncmp(m_arg[maclvl-1][0],"_for",4) || !strncmp(m_arg[maclvl-1][0],"_whi",4) || !strncmp(m_arg[maclvl-1][0],"_swi",4))) { debug(F110,"END popping",m_arg[maclvl-1][0],0); dogta(XXPTA); /* Put args back */ popclvl(); /* Pop up two levels */ popclvl(); debug(F101,"doend maclvl 2","",maclvl); } if (maclvl > -1) { if (mrval[maclvl]) /* Free previous retval if any */ free(mrval[maclvl]); mrval[maclvl] = malloc(16); /* Room for up to 15 digits */ if (mrval[maclvl]) /* Record current retval */ ckmakmsg(mrval[maclvl],16,ckitoa(x),NULL,NULL,NULL); } #endif /* NOSPL */ popclvl(); /* Now pop out of macro or TAKE file */ #ifndef NOSPL #ifdef DEBUG if (deblog) { debug(F101,"END maclvl 3","",maclvl); debug(F111,"END mrval[maclvl]",mrval[maclvl],maclvl); debug(F111,"END mrval[maclvl+1]",mrval[maclvl+1],maclvl+1); } #endif /* DEBUG */ #endif /* NOSPL */ } #ifdef CKROOT int dochroot() { if ((x = cmdir("Name of new root directory","",&s,xxstring)) < 0) { if (x == -3) { printf("?Directory name required\n"); return(-9); } return(x); } ckstrncpy(line,s,LINBUFSIZ); s = line; if ((x = cmcfm()) < 0) return(x); s = brstrip(s); x = zsetroot(s); if (x < 0) { char * m = NULL; switch (x) { case -1: case -2: m = "Not a directory"; break; case -3: m = "Internal error"; break; case -4: m = "Access denied"; break; case -5: m = "Off limits"; break; } if (m) printf("%s: \"%s\"\n", m, s); return(m ? -9 : -2); } else { nopush = 1; return(success = 1); } } #endif /* CKROOT */ #ifndef NOXFER static char * asnbuf = NULL; /* As-name buffer pointer */ char sndxnam[] = { "_array_x_" }; /* (with replaceable x!) */ /* The new SEND command, replacing BSEND, CSEND, PSEND, etc etc. Call with cx = top-level keyword value. Returns: < 0 On parse error. 0 On other type of failure (e.g. requested operation not allowed). 1 On success with sstate set to 's' so protocol will begin. */ /* D O X S E N D -- Parse SEND and related commands with switches */ int #ifdef CK_ANSIC doxsend( int cx ) #else doxsend(cx) int cx; #endif /* CK_ANSIC */ { int c, i, n, wild, confirmed = 0; /* Workers */ int x, y; /* of the world... */ int getval = 0; /* Whether to get switch value */ extern char * snd_move; /* Directory to move sent files to */ extern char * snd_rename; /* What to rename sent files to */ extern char * filefile; /* File containing filenames to send */ extern int xfiletype; /* Send only text (or binary) files */ extern struct keytab pathtab[]; /* PATHNAMES option keywords */ extern int npathtab; /* How many of them */ extern int recursive; /* Recursive directory traversal */ extern int rprintf; /* REMOTE PRINT flag */ extern int fdispla; /* TRANSFER DISPLAY setting */ extern int skipbup; /* Skip backup files when sending */ struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */ struct FDB sf, sw, fl, cm; /* FDBs for each parse function */ int mlist = 0; /* Flag for MSEND or MMOVE */ extern struct keytab protos[]; /* File transfer protocols */ extern int xfrxla, g_xfrxla, nprotos; extern char sndbefore[], sndafter[], *sndexcept[]; /* Selection criteria */ extern char sndnbefore[], sndnafter[]; extern CK_OFF_T sndsmaller, sndlarger, calibrate; #ifndef NOSPL int range[2]; /* Array range */ char ** ap = NULL; /* Array pointer */ int arrayx = -1; /* Array index */ #endif /* NOSPL */ #ifdef NEWFTP if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) { if (cx == XXMAI) { printf("?Sorry, No MAIL with FTP\n"); return(-9); } return(doftpput(cx,0)); } #endif /* NEWFTP */ for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */ pv[i].sval = NULL; /* to null pointers */ pv[i].ival = -1; /* and -1 int values */ pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */ } #ifndef NOSPL range[0] = -1; range[1] = -1; sndxin = -1; /* Array index */ #endif /* NOSPL */ sndarray = NULL; /* Array pointer */ #ifdef UNIXOROSK g_matchdot = matchdot; /* Match dot files */ #endif /* UNIXOROSK */ g_recursive = recursive; /* Recursive sending */ recursive = 0; /* Save global value, set local */ debug(F101,"xsend entry fncnv","",fncnv); /* Preset switch values based on top-level command that called us */ switch (cx) { case XXMSE: /* MSEND */ mlist = 1; break; case XXCSEN: /* CSEND */ pv[SND_CMD].ival = 1; break; case XXMMOVE: /* MMOVE */ mlist = 1; case XXMOVE: /* MOVE */ pv[SND_DEL].ival = 1; break; case XXRSEN: /* RESEND */ pv[SND_BIN].ival = 1; /* Implies /BINARY */ pv[SND_RES].ival = 1; break; case XXMAI: /* MAIL */ pv[SND_MAI].ival = 1; break; } /* Set up chained parse functions... */ cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Filename, or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ #ifdef NOMSEND nsndtab, /* addtl numeric data 1: tbl size */ #else mlist ? nmsndtab : nsndtab, /* addtl numeric data 1: tbl size */ #endif /* NOMSEND */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ #ifdef NOMSEND sndtab, /* Keyword table */ #else mlist ? msndtab : sndtab, #endif /* NOMSEND */ &sf /* Pointer to next FDB */ ); cmfdbi(&sf, /* 2nd FDB - file to send */ _CMIFI, /* fcode */ "File(s) to send", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nolinks, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, mlist ? &cm : &fl ); cmfdbi(&fl, /* 3rd FDB - command to send from */ _CMFLD, /* fcode */ "Command", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, &cm ); cmfdbi(&cm, /* 4th FDB - Confirmation */ _CMCFM, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, NULL, NULL ); while (1) { /* Parse 0 or more switches */ x = cmfdb(&sw); /* Parse something */ debug(F101,"xsend cmfdb","",x); if (x < 0) /* Error */ goto xsendx; /* or reparse needed */ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */ break; /* They gave a switch, but let's see how they terminated it. If they ended it with : or =, then we must parse a value. If they ended it with anything else, then we must NOT parse a value. */ c = cmgbrk(); /* Get break character */ getval = (c == ':' || c == '='); /* to see how they ended the switch */ if (getval && !(cmresult.kflags & CM_ARG)) { printf("?This switch does not take arguments\n"); x = -9; goto xsendx; } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); x = -9; goto xsendx; } n = cmresult.nresult; /* Numeric result = switch value */ debug(F101,"xsend switch","",n); switch (n) { /* Process the switch */ case SND_CMD: /* These take no args */ if (nopush) { printf("?Sorry, system command access is disabled\n"); x = -9; goto xsendx; } #ifdef PIPESEND else if (sndfilter) { printf( "?Sorry, no SEND /COMMAND or CSEND when SEND FILTER selected\n"); x = -9; goto xsendx; } #endif /* PIPESEND */ sw.hlpmsg = "Command, or switch"; /* Change help message */ pv[n].ival = 1; /* Just set the flag */ pv[SND_ARR].ival = 0; break; case SND_REC: /* /RECURSIVE */ recursive = 2; /* Set the real variable */ pv[SND_PTH].ival = PATH_REL; /* Give them relative pathnames */ pv[n].ival = 1; /* Just set the flag */ break; case SND_RES: /* /RECOVER (resend) */ pv[SND_ARR].ival = 0; pv[SND_BIN].ival = 1; /* Implies /BINARY */ case SND_NOB: /* /NOBACKUP */ case SND_DEL: /* /DELETE */ case SND_SHH: /* /QUIET */ pv[n].ival = 1; /* Just set the flag */ break; #ifdef UNIXOROSK /* Like recursive, these are set immediately because they affect cmifi() */ case SND_DOT: /* /DOTFILES */ matchdot = 1; break; case SND_NOD: /* /NODOTFILES */ matchdot = 0; break; #endif /* UNIXOROSK */ /* File transfer modes - each undoes the others */ case SND_BIN: /* Binary */ case SND_TXT: /* Text */ case SND_IMG: /* Image */ case SND_LBL: /* Labeled */ pv[SND_BIN].ival = 0; pv[SND_TXT].ival = 0; pv[SND_IMG].ival = 0; pv[SND_LBL].ival = 0; pv[n].ival = 1; break; #ifdef CKSYMLINK case SND_LNK: case SND_NLK: nolinks = (n == SND_NLK) ? 2 : 0; cmfdbi(&sf, /* Redo cmifi() */ _CMIFI, /* fcode */ "File(s) to send", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nolinks, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, mlist ? &cm : &fl ); break; #endif /* CKSYMLINK */ case SND_EXC: /* Excludes */ if (!getval) break; if ((x = cmfld("Pattern","",&s,xxstring)) < 0) { if (x == -3) { printf("?Pattern required\n"); x = -9; } goto xsendx; } if (pv[n].sval) free(pv[n].sval); y = strlen(s); if (y > 256) { printf("?Pattern too long - 256 max\n"); x = -9; goto xsendx; } pv[n].sval = malloc(y+1); if (pv[n].sval) { strcpy(pv[n].sval,s); /* safe */ pv[n].ival = 1; } break; case SND_MOV: /* MOVE after */ case SND_REN: /* RENAME after */ if (!getval) break; if ((x = cmfld(n == SND_MOV ? "device and/or directory for source file after sending" : "new name for source file after sending", "", &s, n == SND_MOV ? xxstring : NULL )) < 0) { if (x == -3) { printf("%s\n", n == SND_MOV ? "?Destination required" : "?New name required" ); x = -9; } goto xsendx; } if (pv[n].sval) free(pv[n].sval); s = brstrip(s); y = strlen(s); if (y > 0) { pv[n].sval = malloc(y+1); if (pv[n].sval) { strcpy(pv[n].sval,s); /* safe */ pv[n].ival = 1; } } break; case SND_SMA: /* Smaller / larger than */ case SND_LAR: { CK_OFF_T w; if (!getval) break; if ((x = cmnumw("Size in bytes","0",10,&w,xxstring)) < 0) goto xsendx; pv[n].wval = w; break; } case SND_AFT: /* Send /AFTER:date-time */ case SND_BEF: /* Send /BEFORE:date-time */ case SND_NAF: /* Send /NOT-AFTER:date-time */ case SND_NBE: /* Send /NOT-BEFORE:date-time */ if (!getval) break; if ((x = cmdate("File date-time","",&s,0,xxstring)) < 0) { if (x == -3) { printf("?Date-time required\n"); x = -9; } goto xsendx; } if (pv[n].sval) free(pv[n].sval); pv[n].sval = malloc((int)strlen(s)+1); if (pv[n].sval) { strcpy(pv[n].sval,s); /* safe */ pv[n].ival = 1; } break; case SND_MAI: /* Send as mail (= MAIL) */ #ifdef IKSD if (inserver && !ENABLED(en_mai)) { printf("?Sorry, sending files as mail is disabled\n"); return(-9); } #endif /* IKSD */ pv[n].ival = 1; if (!getval) break; if ((x = cmfld("e-mail address","",&s,xxstring)) < 0) { if (x == -3) { printf("?address required\n"); x = -9; } goto xsendx; } s = brstrip(s); if (pv[n].sval) free(pv[n].sval); pv[n].sval = malloc((int)strlen(s)+1); if (pv[n].sval) strcpy(pv[n].sval,s); /* safe */ break; case SND_PRI: /* Send to be printed (REMOTE PRINT) */ #ifdef IKSD if (inserver && !ENABLED(en_mai)) { printf("?Sorry, sending files for printing is disabled\n"); return(-9); } #endif /* IKSD */ pv[n].ival = 1; if (!getval) break; if ((x = cmfld("Print options","",&s,xxstring)) < 0) if (x != -3) goto xsendx; s = brstrip(s); if (pv[n].sval) free(pv[n].sval); pv[n].sval = malloc((int)strlen(s)+1); if (pv[n].sval) strcpy(pv[n].sval,s); /* safe */ break; case SND_ASN: /* As-name */ debug(F101,"xsend /as-name getval","",getval); if (!getval) break; if ((x = cmfld("Name to send under","",&s,NULL)) < 0) { if (x == -3) { printf("?name required\n"); x = -9; } goto xsendx; } s = brstrip(s); if ((y = strlen(s)) > 0) { if (pv[n].sval) free(pv[n].sval); pv[n].sval = malloc(y+1); if (pv[n].sval) { strcpy(pv[n].sval,s); /* safe */ pv[n].ival = 1; } } break; case SND_STA: { /* Starting position (= PSEND) */ CK_OFF_T w; if (!getval) break; if ((x = cmnumw("0-based position","0",10,&w,xxstring)) < 0) goto xsendx; pv[n].wval = w; break; } case SND_PRO: /* Protocol to use */ if (!getval) break; if ((x = cmkey(protos,nprotos,"File-transfer protocol","", xxstring)) < 0) { if (x == -3) { printf("?name of protocol required\n"); x = -9; } goto xsendx; } pv[n].ival = x; break; #ifdef PIPESEND case SND_FLT: /* Filter */ debug(F101,"xsend /filter getval","",getval); if (!getval) break; if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) { if (x == -3) s = ""; else goto xsendx; } if (*s) s = brstrip(s); y = strlen(s); for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */ if (s[x] != '\\') continue; if (s[x+1] == 'v') break; } if (x == y) { printf( "?Filter must contain a replacement variable for filename.\n" ); x = -9; goto xsendx; } pv[n].ival = 1; if (pv[n].sval) { free(pv[n].sval); pv[n].sval = NULL; } if ((y = strlen(s)) > 0) { if ((pv[n].sval = malloc(y+1))) strcpy(pv[n].sval,s); /* safe */ } break; #endif /* PIPESEND */ case SND_PTH: /* Pathnames */ if (!getval) { pv[n].ival = PATH_REL; break; } if ((x = cmkey(pathtab,npathtab,"","absolute",xxstring)) < 0) goto xsendx; pv[n].ival = x; break; case SND_NAM: /* Filenames */ if (!getval) break; if ((x = cmkey(fntab,nfntab,"","converted",xxstring)) < 0) goto xsendx; debug(F101,"xsend /filenames","",x); pv[n].ival = x; break; #ifdef CALIBRATE case SND_CAL: { /* /CALIBRATE */ CK_OFF_T w; if (getval) { if ((x = cmnumw("number of Kbytes to send", "1024",10,&w,xxstring)) < 0) goto xsendx; } else w = (CK_OFF_T)1024; pv[n].wval = w; pv[SND_ARR].ival = 0; break; } #endif /* CALIBRATE */ case SND_FIL: /* Name of file containing filnames */ if (!getval) break; if ((x = cmifi("Name of file containing list of filenames", "",&s,&y,xxstring)) < 0) { if (x == -3) { printf("?Filename required\n"); x = -9; } goto xsendx; } else if (y) { printf("?Wildcards not allowed\n"); x = -9; goto xsendx; } if (pv[n].sval) free(pv[n].sval); if (s) if (*s) { if ((pv[n].sval = malloc((int)strlen(s)+1))) { strcpy(pv[n].sval,s); pv[n].ival = 1; pv[SND_ARR].ival = 0; } } break; #ifndef NOSPL case SND_ARR: /* SEND /ARRAY: */ if (!getval) break; ap = NULL; if ((x = cmfld("Array name (a single letter will do)", "", &s, NULL )) < 0) { if (x == -3) break; else return(x); } if ((x = arraybounds(s,&(range[0]),&(range[1]))) < 0) { printf("?Bad array: %s\n",s); return(-9); } if (!(ap = a_ptr[x])) { printf("?No such array: %s\n",s); return(-9); } pv[n].ival = 1; pv[SND_CMD].ival = 0; /* Undo any conflicting ones... */ pv[SND_RES].ival = 0; pv[SND_CAL].ival = 0; pv[SND_FIL].ival = 0; arrayx = x; break; #endif /* NOSPL */ case SND_XPA: /* /TRANSPARENT */ pv[n].ival = 1; break; case SND_TYP: /* Only files of given type */ if (!getval) break; if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0) goto xsendx; pv[n].ival = (x == 2) ? -1 : x; break; default: printf("?Unexpected switch value - %d\n",cmresult.nresult); x = -9; goto xsendx; } } debug(F101,"xsend cmresult fcode","",cmresult.fcode); #ifdef COMMENT /* List switch parsing results in debug log */ for (i = 0; i <= SND_MAX; i++) { ckmakmsg(line,LINBUFSIZ,"xsend switch ",ckitoa(i),NULL,NULL); debug(F111,line, pv[i].sval, pv[i].ival); } #endif /* COMMENT */ /* Now we have all switches, plus maybe a filename or command, or nothing */ #ifdef PIPESEND if (protocol != PROTO_K && pv[SND_CMD].ival > 0) { printf("?Sorry, %s works only with Kermit protocol\n", (cx == XXCSEN) ? "CSEND" : "SEND /COMMAND"); x = -9; goto xsendx; } if (pv[SND_RES].ival > 0 || /* /RECOVER */ pv[SND_STA].wval > 0) { /* or /STARTING */ if (sndfilter || pv[SND_FLT].ival > 0) { printf("?Sorry, no /RECOVER or /START if SEND FILTER selected\n"); x = -9; goto xsendx; } } #endif /* PIPESEND */ cmarg = ""; cmarg2 = ""; line[0] = NUL; s = line; wild = 0; switch (cmresult.fcode) { /* How did we get out of switch loop */ case _CMIFI: /* Input filename */ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Name */ if (pv[SND_ARR].ival > 0) cmarg2 = line; else wild = cmresult.nresult; /* Wild flag */ if (!recursive && !wild) nolinks = 0; break; case _CMFLD: /* Field */ /* Only allowed with /COMMAND and /ARRAY */ if (pv[SND_CMD].ival < 1 && pv[SND_ARR].ival < 1) { #ifdef CKROOT if (ckrooterr) printf("?Off limits: %s\n",cmresult.sresult); else #endif /* CKROOT */ printf("?%s - \"%s\"\n", iswild(cmresult.sresult) ? "No files match" : "File not found", cmresult.sresult ); x = -9; goto xsendx; } ckstrncpy(line,cmresult.sresult,LINBUFSIZ); if (pv[SND_ARR].ival > 0) cmarg2 = line; break; case _CMCFM: /* Confirmation */ /* s = ""; */ confirmed = 1; break; default: printf("?Unexpected function code: %d\n",cmresult.fcode); x = -9; goto xsendx; } debug(F110,"xsend string",s,0); debug(F101,"xsend confirmed","",confirmed); /* Save and change protocol and transfer mode */ /* Global values are restored in main parse loop */ g_proto = protocol; /* Save current global protocol */ g_urpsiz = urpsiz; g_spsizf = spsizf; g_spsiz = spsiz; g_spsizr = spsizr; g_spmax = spmax; g_wslotr = wslotr; g_prefixing = prefixing; g_fncact = fncact; g_fncnv = fncnv; g_fnspath = fnspath; g_fnrpath = fnrpath; g_xfrxla = xfrxla; if (pv[SND_PRO].ival > -1) { /* Change according to switch */ protocol = pv[SND_PRO].ival; if (ptab[protocol].rpktlen > -1) /* copied from initproto() */ urpsiz = ptab[protocol].rpktlen; if (ptab[protocol].spktflg > -1) spsizf = ptab[protocol].spktflg; if (ptab[protocol].spktlen > -1) { spsiz = ptab[protocol].spktlen; if (spsizf) spsizr = spmax = spsiz; } if (ptab[protocol].winsize > -1) wslotr = ptab[protocol].winsize; if (ptab[protocol].prefix > -1) prefixing = ptab[protocol].prefix; if (ptab[protocol].fnca > -1) fncact = ptab[protocol].fnca; if (ptab[protocol].fncn > -1) fncnv = ptab[protocol].fncn; if (ptab[protocol].fnsp > -1) fnspath = ptab[protocol].fnsp; if (ptab[protocol].fnrp > -1) fnrpath = ptab[protocol].fnrp; } debug(F101,"xsend protocol","",protocol); if (pv[SND_NOB].ival > -1) { /* /NOBACKUP (skip backup file) */ g_skipbup = skipbup; skipbup = 1; } if (pv[SND_REC].ival > 0) /* /RECURSIVE */ recursive = 2; if (pv[SND_TYP].ival > -1) { /* /TYPE */ xfiletype = pv[SND_TYP].ival; if (xfiletype == 2) xfiletype = -1; } g_binary = binary; /* Save global transfer mode */ #ifdef PATTERNS g_patterns = patterns; /* Save FILE PATTERNS setting */ #endif /* PATTERNS */ if (pv[SND_BIN].ival > 0) { /* Change according to switch */ /* If they said /BINARY they mean /BINARY */ patterns = 0; /* So no pattern-based switching */ g_xfermode = xfermode; /* or automatic transfer mode */ xfermode = XMODE_M; binary = XYFT_B; debug(F101,"doxsend /BINARY xfermode","",xfermode); } else if (pv[SND_TXT].ival > 0) { /* Ditto for /TEXT */ patterns = 0; g_xfermode = xfermode; xfermode = XMODE_M; binary = XYFT_T; debug(F101,"doxsend /TEXT xfermode","",xfermode); } else if (pv[SND_IMG].ival > 0) { #ifdef VMS binary = XYFT_I; #else binary = XYFT_B; #endif /* VMS */ } #ifdef CK_LABELED else if (pv[SND_LBL].ival > 0) { binary = XYFT_L; } #endif /* CK_LABELED */ debug(F101,"xsend binary","",binary); if (pv[SND_XPA].ival > 0) /* /TRANSPARENT */ xfrxla = 0; /* Don't translate character sets */ /* Check for legal combinations of switches, filenames, etc */ #ifdef PIPESEND if (pv[SND_CMD].ival > 0) { /* COMMAND - strip any braces */ debug(F110,"SEND /COMMAND before stripping",s,0); s = brstrip(s); debug(F110,"SEND /COMMAND after stripping",s,0); if (!*s) { printf("?Sorry, a command to send from is required\n"); x = -9; goto xsendx; } cmarg = s; } #endif /* PIPESEND */ /* Set up /MOVE and /RENAME */ if (pv[SND_DEL].ival > 0 && (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) { printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n"); x = -9; goto xsendx; } #ifdef CK_TMPDIR if (pv[SND_MOV].ival > 0) { int len; char * p = pv[SND_MOV].sval; #ifdef CK_LOGIN if (isguest) { printf("?Sorry, /MOVE-TO not available to guests\n"); x = -9; goto xsendx; } #endif /* CK_LOGIN */ len = strlen(p); if (!isdir(p)) { /* Check directory */ #ifdef CK_MKDIR char * s = NULL; s = (char *)malloc(len + 4); if (s) { strcpy(s,p); /* safe */ #ifdef datageneral if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; } #else if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; } #endif /* datageneral */ s[len++] = 'X'; s[len] = NUL; x = zmkdir(s); free(s); if (x < 0) { printf("?Can't create \"%s\"\n",p); x = -9; goto xsendx; } } #else printf("?Directory \"%s\" not found\n",p); x = -9; goto xsendx; #endif /* CK_MKDIR */ } zfnqfp(p,LINBUFSIZ,tmpbuf); makestr(&snd_move,tmpbuf); } #endif /* CK_TMPDIR */ if (pv[SND_REN].ival > 0) { /* /RENAME */ char * p = pv[SND_REN].sval; #ifdef CK_LOGIN if (isguest) { printf("?Sorry, /RENAME-TO not available to guests\n"); x = -9; goto xsendx; } #endif /* CK_LOGIN */ if (!p) p = ""; if (!*p) { printf("?New name required for /RENAME\n"); x = -9; goto xsendx; } p = brstrip(p); #ifndef NOSPL /* If name given is wild, rename string must contain variables */ if (wild) { char * s = tmpbuf; x = TMPBUFSIZ; zzstring(p,&s,&x); if (!strcmp(tmpbuf,p)) { printf( "?/RENAME for file group must contain variables such as \\v(filename)\n" ); x = -9; goto xsendx; } } #endif /* NOSPL */ makestr(&snd_rename,p); } /* Handle /RECOVER and /START */ #ifdef CK_RESEND if (pv[SND_RES].ival > 0 && binary != XYFT_B && !filepeek #ifdef PATTERNS && !patterns #else #ifdef VMS /* VMS sets text/binary automatically later when it opens the file */ && 0 #endif /* VMS */ #endif /* PATTERNS */ ) { printf("?Sorry, /BINARY required\n"); x = -9; goto xsendx; } if (pv[SND_STA].wval > 0) { /* /START */ if (wild) { printf("?Sorry, wildcards not permitted with /START\n"); x = -9; goto xsendx; } if (sizeof(int) < 4) { printf("?Sorry, this command needs at least 32-bit integers\n"); x = -9; goto xsendx; } #ifdef CK_XYZ if (protocol != PROTO_K) { printf("?Sorry, SEND /START works only with Kermit protocol\n"); x = -9; goto xsendx; } #endif /* CK_XYZ */ } #ifdef CK_XYZ if (pv[SND_RES].ival > 0) { if (protocol != PROTO_K && protocol != PROTO_Z) { printf( "Sorry, /RECOVER is possible only with Kermit or ZMODEM protocol\n" ); x = -9; goto xsendx; } } #endif /* CK_XYZ */ #endif /* CK_RESEND */ if (protocol == PROTO_K) { if ((pv[SND_MAI].ival > 0 || /* MAIL */ pv[SND_PRI].ival > 0 || /* PRINT */ pv[SND_RES].ival > 0 /* RESEND */ ) && (!atdiso || !atcapr)) { /* Disposition attribute off? */ printf("?Sorry, ATTRIBUTE DISPOSITION must be ON\n"); x = -9; goto xsendx; } } #ifdef CK_XYZ if (wild && (protocol == PROTO_X || protocol == PROTO_XC)) { printf( "Sorry, you can only send one file at a time with XMODEM protocol\n" ); x = -9; goto xsendx; } #endif /* CK_XYZ */ if (!confirmed) { /* CR not typed yet, get more fields */ char *m; if (mlist) { /* MSEND or MMOVE */ nfils = 0; /* We already have the first one */ #ifndef NOMSEND msfiles[nfils++] = line; /* Store pointer */ lp = line + (int)strlen(line) + 1; /* Point past it */ debug(F111,"xsend msend",msfiles[nfils-1],nfils-1); while (1) { /* Get more filenames */ char *p; if ((x = cmifi("Names of files to send, separated by spaces", "", &s,&y,xxstring)) < 0) { if (x != -3) goto xsendx; if ((x = cmcfm()) < 0) goto xsendx; break; } msfiles[nfils++] = lp; /* Got one, count it, point to it, */ p = lp; /* remember pointer, */ while ((*lp++ = *s++)) /* and copy it into buffer */ if (lp > (line + LINBUFSIZ)) { /* Avoid memory leak */ printf("?MSEND list too long\n"); line[0] = NUL; x = -9; goto xsendx; } debug(F111,"xsend msend",msfiles[nfils-1],nfils-1); if (nfils == 1) fspec[0] = NUL; /* Take care of \v(filespec) */ #ifdef ZFNQFP zfnqfp(p,TMPBUFSIZ,tmpbuf); p = tmpbuf; #endif /* ZFNQFP */ if (((int)strlen(fspec) + (int)strlen(p) + 1) < fspeclen) { strcat(fspec,p); /* safe */ strcat(fspec," "); /* safe */ } else #ifdef COMMENT printf("WARNING - \\v(filespec) buffer overflow\n"); #else debug(F101,"doxsend filespec buffer overflow","",0); #endif /* COMMENT */ } #endif /* NOMSEND */ } else { /* Regular SEND */ char *p; int y; nfils = -1; if (pv[SND_MAI].ival > 0) m = (pv[SND_MAI].sval) ? "e-mail address (optional)" : "e-mail address (required)"; else if (pv[SND_PRI].ival > 0) m = "printer options (optional)"; else if (wild) m = "\nOptional as-name template containing replacement variables \ like \\v(filename)"; else m = "Optional name to send it with"; if ((x = cmtxt(m,"",&p,NULL)) < 0) goto xsendx; if (!p) p = ""; if (*p) { /* If some text was given... */ p = brstrip(p); /* Replace /AS-NAME: value if any */ if ((y = strlen(p)) > 0) { if (pv[SND_MAI].ival > 0) { makestr(&pv[SND_MAI].sval, p); } else { if (pv[SND_ASN].sval) free(pv[SND_ASN].sval); pv[SND_ASN].sval = malloc(y+1); if (pv[SND_ASN].sval) { strcpy(pv[SND_ASN].sval,p); /* safe */ pv[SND_ASN].ival = 1; } } } } } } /* Set cmarg2 from as-name, however we got it. */ if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !*cmarg2) { int x; x = strlen(line); ckstrncpy(line+x+2,pv[SND_ASN].sval,LINBUFSIZ-x-1); cmarg2 = line+x+2; debug(F110,"doxsend cmarg2",cmarg2,0); } #ifndef NOFRILLS if ((pv[SND_MAI].ival > 0) && (pv[SND_PRI].ival > 0)) { printf("Sorry, /MAIL and /PRINT are conflicting options\n"); x = -9; goto xsendx; } n = 0; /* /MAIL or /PRINT? */ if (pv[SND_MAI].ival > 0) n = SND_MAI; else if (pv[SND_PRI].ival > 0) n = SND_PRI; if (n) { /* Yes... */ #ifdef DEBUG char * p; if (n == SND_MAI) p = "/MAIL"; else p = "/PRINT"; debug(F111,"xsend",p,n); #endif /* DEBUG */ #ifdef CK_XYZ if (protocol != PROTO_K) { printf("Sorry, %s available only with Kermit protocol\n", (n == SND_MAI) ? "/MAIL" : "/PRINT" ); x = -9; goto xsendx; } #endif /* CK_XYZ */ debug(F101,"xsend print/mail wild","",wild); *optbuf = NUL; /* Wipe out any old options */ s = pv[n].sval; /* mail address or print switch val */ if (!s) s = ""; debug(F110,"doxsend mail address or printer options",s,0); if (n == SND_MAI && !*s) { printf("?E-mail address required\n"); x = -9; goto xsendx; } else if ((int)strlen(s) > 94) { /* Ensure legal size */ printf("?%s too long\n", (n == SND_MAI) ? "E-mail address" : "Print option string" ); x = -9; goto xsendx; } ckstrncpy(optbuf,s,OPTBUFLEN); /* OK, copy to option buffer */ cmarg = line; /* File to send */ if (n == SND_MAI) { debug(F110,"xsend mailing",cmarg,0); debug(F110,"xsend address:",optbuf,0); rmailf = 1; } else { debug(F110,"xsend printing",cmarg,0); debug(F110,"xsend options",optbuf,0); rprintf = 1; } } #endif /* NOFRILLS */ #ifdef CALIBRATE if (pv[SND_CAL].wval > 0) { /* Handle /CALIBRATE */ if (confirmed) { calibrate = pv[SND_CAL].wval * (CK_OFF_T)1024; sndsrc = -9; nfils = 1; wild = 0; #ifndef NOMSEND addlist = 0; #endif /* NOMSEND */ ckstrncpy(line,"CALIBRATION",LINBUFSIZ); s = cmarg = line; if (!cmarg2) cmarg2 = ""; debug(F110,"doxsend cmarg2 calibrate",cmarg2,0); } else if (line[0]) { calibrate = 0; pv[SND_CAL].ival = 0; pv[SND_CAL].wval = 0; } } #endif /* CALIBRATE */ if (pv[SND_FIL].ival > 0) { if (confirmed && !calibrate) { if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) { debug(F110,"xsend can't open",pv[SND_FIL].sval,0); printf("?Failure to open %s\n",filefile); x = -9; goto xsendx; } makestr(&filefile,pv[SND_FIL].sval); /* Open, remember name */ debug(F110,"xsend opened",filefile,0); wild = 1; } } /* SEND alone... */ #ifndef NOSPL if (confirmed && pv[SND_ARR].ival > 0) { if (!*cmarg2) { sndxnam[7] = (char)((arrayx == 1) ? 64 : arrayx + ARRAYBASE); cmarg2 = sndxnam; } cmarg = ""; goto sendend; } #endif /* NOSPL */ if (confirmed && !line[0] && !filefile && !calibrate) { #ifndef NOMSEND if (filehead) { /* OK if we have a SEND-LIST */ nfils = filesinlist; sndsrc = nfils; /* Like MSEND */ addlist = 1; /* But using a different list... */ filenext = filehead; goto sendend; } #endif /* NOMSEND */ printf("?Filename required but not given\n"); x = -9; goto xsendx; } /* Not send-list or array */ #ifndef NOMSEND addlist = 0; /* Don't use SEND-LIST. */ filenext = NULL; #endif /* NOMSEND */ if (mlist) { /* MSEND or MMOVE */ #ifndef NOMSEND cmlist = msfiles; /* List of files to send */ sndsrc = nfils; cmarg2 = ""; sendstart = (CK_OFF_T)0; #endif /* NOMSEND */ #ifdef PIPESEND pipesend = 0; #endif /* PIPESEND */ } else if (filefile) { /* File contains list of filenames */ s = ""; cmarg = ""; cmarg2 = ""; line[0] = NUL; nfils = 1; sndsrc = 1; } else if (!calibrate && pv[SND_ARR].ival < 1 && pv[SND_CMD].ival < 1) { nfils = sndsrc = -1; /* Not MSEND, MMOVE, /LIST, or /ARRAY */ if ( /* or /COMMAND */ #ifndef NOFRILLS !rmailf && !rprintf /* Not MAIL or PRINT */ #else 1 #endif /* NOFRILLS */ ) { CK_OFF_T y = (CK_OFF_T)1; if (!wild) y = zchki(s); if (y < (CK_OFF_T)0) { printf("?Read access denied - \"%s\"\n", s); x = -9; goto xsendx; } if (s != line) /* We might already have done this. */ ckstrncpy(line,s,LINBUFSIZ); /* Copy of string just parsed. */ else debug(F110,"doxsend line=s",line,0); cmarg = line; /* File to send */ } zfnqfp(cmarg,fspeclen,fspec); } if (!mlist) { /* For all but MSEND... */ #ifdef PIPESEND if (pv[SND_CMD].ival > 0) /* /COMMAND sets pipesend flag */ pipesend = 1; debug(F101,"xsend /COMMAND pipesend","",pipesend); if (pipesend && filefile) { printf("?Invalid switch combination\n"); x = -9; goto xsendx; } #endif /* PIPESEND */ #ifndef NOSPL /* If as-name given and filespec is wild, as-name must contain variables */ debug(F111,"doxsend cmarg2 wild",cmarg2,wild); if (wild && *cmarg2) { char * s = tmpbuf; x = TMPBUFSIZ; zzstring(cmarg2,&s,&x); if (!strcmp(tmpbuf,cmarg2)) { printf( "?As-name for file group must contain variables such as \\v(filename)\n" ); x = -9; goto xsendx; } } #endif /* NOSPL */ /* Strip braces from as-name */ debug(F110,"xsend cmarg2 before stripping",cmarg2,0); cmarg2 = brstrip(cmarg2); debug(F110,"xsend filename",cmarg,0); debug(F110,"xsend as-name",cmarg2,0); /* Copy as-name to a safe place */ if (asnbuf) { free(asnbuf); asnbuf = NULL; } if ((y = strlen(cmarg2)) > 0) { asnbuf = (char *) malloc(y + 1); if (asnbuf) { strcpy(asnbuf,cmarg2); /* safe */ cmarg2 = asnbuf; } else cmarg2 = ""; } #ifdef CK_RESEND debug(F111,"xsend pv[SND_STA].ival","",pv[SND_STA].ival); if (pv[SND_STA].wval > (CK_OFF_T)-1) { /* /START position */ if (wild) { printf("?/STARTING-AT may not be used with multiple files.\n"); x = -9; goto xsendx; } else sendstart = pv[SND_STA].wval; } else sendstart = (CK_OFF_T)0; debug(F101,"xsend /STARTING","",sendstart); #endif /* CK_RESEND */ } sendend: /* Common successful exit */ moving = 0; if (pv[SND_SHH].ival > 0) { /* SEND /QUIET... */ g_displa = fdispla; fdispla = 0; debug(F101,"xsend display","",fdispla); } #ifndef NOSPL /* SEND /ARRAY... */ if (pv[SND_ARR].ival > 0) { if (!ap) { x = -2; goto xsendx; } /* (shouldn't happen) */ if (range[0] == -1) /* If low end of range not specified */ range[0] = 1; /* default to 1 */ if (range[1] == -1) /* If high not specified */ range[1] = a_dim[arrayx]; /* default to size of array */ if ((range[0] < 0) || /* Check range */ (range[0] > a_dim[arrayx]) || (range[1] < range[0]) || (range[1] > a_dim[arrayx])) { printf("?Bad array range - [%d:%d]\n",range[0],range[1]); x = -9; goto xsendx; } sndarray = ap; /* Array pointer */ sndxin = arrayx; /* Array index */ sndxlo = range[0]; /* Array range */ sndxhi = range[1]; sndxnam[7] = (char)((sndxin == 1) ? 64 : sndxin + ARRAYBASE); #ifdef COMMENT printf("SENDING FROM ARRAY: &%c[]...\n", /* debugging */ (sndxin == 1) ? 64 : sndxin + ARRAYBASE); printf("Lo=%d\nHi=%d\n", sndxlo, sndxhi); printf("cmarg=[%s]\ncmarg2=[%s]\n", cmarg, cmarg2); while ((x = agnbyte()) > -1) { putchar((char)x); } return(1); #endif /* COMMENT */ } #endif /* NOSPL */ if (pv[SND_ARR].ival < 1) { /* File selection & disposition... */ if (pv[SND_DEL].ival > 0) /* /DELETE was specified */ moving = 1; debug(F101,"xsend /DELETE","",moving); if (pv[SND_AFT].ival > 0) /* Copy SEND criteria */ ckstrncpy(sndafter,pv[SND_AFT].sval,19); if (pv[SND_BEF].ival > 0) ckstrncpy(sndbefore,pv[SND_BEF].sval,19); if (pv[SND_NAF].ival > 0) ckstrncpy(sndnafter,pv[SND_NAF].sval,19); if (pv[SND_NBE].ival > 0) ckstrncpy(sndnbefore,pv[SND_NBE].sval,19); if (pv[SND_EXC].ival > 0) makelist(pv[SND_EXC].sval,sndexcept,NSNDEXCEPT); if (pv[SND_SMA].wval > (CK_OFF_T)-1) sndsmaller = pv[SND_SMA].wval; if (pv[SND_LAR].wval > (CK_OFF_T)-1) sndlarger = pv[SND_LAR].wval; if (pv[SND_NAM].ival > -1) { g_fncnv = fncnv; /* Save global value */ fncnv = pv[SND_NAM].ival; debug(F101,"xsend fncnv","",fncnv); } if (pv[SND_PTH].ival > -1) { g_spath = fnspath; /* Save global values */ fnspath = pv[SND_PTH].ival; #ifndef NZLTOR if (fnspath != PATH_OFF) { g_fncnv = fncnv; /* Bad bad... */ fncnv = XYFN_C; } #endif /* NZLTOR */ debug(F101,"xsend fnspath","",fnspath); debug(F101,"xsend fncnv","",fncnv); } } #ifdef PIPESEND if (pv[SND_FLT].ival > 0) { makestr(&sndfilter,pv[SND_FLT].sval); debug(F110,"xsend /FILTER", sndfilter, 0); } #endif /* PIPESEND */ #ifdef CK_APC /* MOVE not allowed in APCs */ if (moving && (apcactive == APC_LOCAL || apcactive == APC_REMOTE) && !(apcstatus & APC_UNCH)) return(success = 0); #endif /* CK_APC */ #ifdef IKS_OPTION if ( #ifdef CK_XYZ protocol == PROTO_K && #endif /* CK_XYZ */ !iks_wait(KERMIT_REQ_START,1)) { printf("?A Kermit Server is not available to process this command.\n"); printf("?Start a RECEIVE command to complement this command.\n"); } #endif /* IKS_OPTION */ #ifdef IKSD #ifdef CK_LOGIN if (moving && inserver && isguest) { printf("?File deletion not allowed for guests.\n"); return(-9); } #endif /* CK_LOGIN */ #endif /* IKSD */ sstate = 's'; /* Set start state to SEND */ sndcmd = 1; #ifdef CK_RESEND if (pv[SND_RES].ival > 0) /* Send sendmode appropriately */ sendmode = SM_RESEND; else if (pv[SND_STA].ival > 0) sendmode = SM_PSEND; else #endif /* CK_RESEND */ if (mlist) sendmode = SM_MSEND; else sendmode = SM_SEND; #ifdef MAC what = W_SEND; scrcreate(); #endif /* MAC */ if (local && pv[SND_SHH].ival != 0) { /* If in local mode, */ displa = 1; /* turn on file transfer display */ } x = 0; xsendx: /* Common exit, including failure */ debug(F101,"doxsend sndsrc","",sndsrc); for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */ if (pv[i].sval) free(pv[i].sval); } return(x); } #endif /* NOXFER */ #ifndef NOLOCAL /* D O X C O N N -- CONNECT command parsing with switches */ #ifdef XLIMITS #define XLIMORTRIGGER #else #ifdef CK_TRIGGER #define XLIMORTRIGGER #endif /* CK_TRIGGER */ #endif /* XLIMITS */ #ifdef CKTIDLE int tt_idlelimit = 0; /* Terminal idle limit */ int tt_idleact = IDLE_RET; /* Terminal idle action */ #endif /* CKTIDLE */ #ifdef OS2 /* K95 only: */ extern int tt_idlesnd_tmo; /* Idle interval */ int tt_timelimit = 0; /* Time limit, 0 = none */ extern char * /* Parse results - strings: */ tt_idlesnd_str; /* Idle string */ #endif /* OS2 */ #ifdef CK_TRIGGER extern char *tt_trigger[]; extern CHAR *tt_trmatch[]; extern char *triggerval; static char *g_tt_trigger[TRIGGERS]; #endif /* CK_TRIGGER */ #ifdef OS2 static int g_tt_idlesnd_tmo, g_tt_timelimit; /* For saving and restoring */ static int g_tt_idlelimit, g_tt_saved = 0; static char * g_tt_idlesnd_str; /* global settings */ #endif /* OS2 */ static struct stringint pv[CONN_MAX+1]; VOID resconn() { int i; #ifdef OS2 if ( g_tt_saved ) { tt_idlelimit = g_tt_idlelimit; tt_idlesnd_tmo = g_tt_idlesnd_tmo; tt_timelimit = g_tt_timelimit; tt_idlesnd_str = g_tt_idlesnd_str; g_tt_saved = 0; } #endif /* OS2 */ #ifdef CK_TRIGGER for (i = 0; i < TRIGGERS; i++) tt_trigger[i] = g_tt_trigger[i]; #endif /* CK_TRIGGER */ for (i = 0; i <= CONN_MAX; i++) { /* Free malloc'd memory */ if (pv[i].sval) free(pv[i].sval); pv[i].sval = NULL; } } int #ifdef CK_ANSIC doxconn( int cx ) #else doxconn(cx) int cx; #endif /* CK_ANSIC */ { int c, i, n; /* Workers */ int x, y; int getval = 0; /* Whether to get switch value */ int async = 0; /* Make an async connect */ struct FDB sw, cm; /* FDBs for each parse function */ extern FILE * tfile[]; extern char * macp[]; #ifdef OS2 g_tt_idlesnd_tmo = tt_idlesnd_tmo; /* Save global settings */ g_tt_timelimit = tt_timelimit; g_tt_idlelimit = tt_idlelimit; g_tt_idlesnd_str = tt_idlesnd_str; g_tt_saved = 1; #endif /* OS2 */ #ifdef CK_TRIGGER if (!tt_trigger[0]) { /* First initialization */ for (i = 1; i < TRIGGERS; i++) tt_trigger[i] = NULL; } for (i = 0; i < TRIGGERS; i++) g_tt_trigger[i] = tt_trigger[i]; if (triggerval) { free(triggerval); triggerval = NULL; } #endif /* CK_TRIGGER */ for (i = 0; i <= CONN_MAX; i++) { /* Initialize switch values */ pv[i].sval = NULL; /* to null pointers */ pv[i].ival = -1; /* and -1 int values */ pv[i].wval = (CK_OFF_T)-1; } if (cx == XXCQ) /* CQ == CONNECT /QUIETLY */ pv[CONN_NV].ival = 1; /* Set up chained parse functions... */ cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nconntab, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ conntab, /* Keyword table */ &cm /* Pointer to next FDB */ ); cmfdbi(&cm, /* 2nd FDB - Confirmation */ _CMCFM, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ NULL, NULL, NULL ); while (1) { /* Parse 0 or more switches */ x = cmfdb(&sw); /* Parse switch or confirmation */ debug(F101,"doxconn cmfdb","",x); if (x < 0) { /* Error */ if (x == -9 || x == -2) printf("?No switches match - \"%s\"\n",atmbuf); goto xconnx; /* or reparse needed */ } if (cmresult.fcode != _CMKEY) /* Break out if not a switch */ break; c = cmgbrk(); /* Get break character */ getval = (c == ':' || c == '='); /* to see how they ended the switch */ if (getval && !(cmresult.kflags & CM_ARG)) { printf("?This switch does not take arguments\n"); x = -9; goto xconnx; } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } n = cmresult.nresult; /* Numeric result = switch value */ debug(F101,"doxconn switch","",n); switch (n) { /* Process the switch */ #ifdef OS2 case CONN_AS: /* Asynchronous */ pv[CONN_AS].ival = 1; pv[CONN_SY].ival = 0; break; case CONN_SY: /* Synchronous */ pv[CONN_SY].ival = 1; pv[CONN_AS].ival = 0; break; #endif /* OS2 */ case CONN_NV: /* Non-verbal */ pv[n].ival = 1; break; #ifdef XLIMITS case CONN_II: /* Idle-interval */ case CONN_IL: /* Idle-limit */ case CONN_TL: /* Time-limit */ if (!getval) break; if ((x = cmnum("Seconds","0",10,&y,xxstring)) < 0) goto xconnx; pv[n].ival = y; break; case CONN_IS: /* Idle-string */ #endif /* XLIMITS */ #ifdef CK_TRIGGER case CONN_TS: /* Trigger-string */ #endif /* CK_TRIGGER */ #ifdef XLIMORTRIGGER if (!getval) break; if ((x = cmfld("String (enclose in braces if it contains spaces)", "",&s,xxstring)) < 0) { if (x == -3) { printf("?String required\n"); x = -9; } goto xconnx; } if (n != CONN_TS) s = brstrip(s); if ((y = strlen(s)) > 0) { if (pv[n].sval) free(pv[n].sval); pv[n].sval = malloc(y+1); if (pv[n].sval) { strcpy(pv[n].sval,s); /* safe */ pv[n].ival = 1; } } break; #endif /* XLIMORTRIGGER */ default: printf("?Unexpected switch value - %d\n",cmresult.nresult); x = -9; goto xconnx; } } debug(F101,"doxconn cmresult.fcode","",cmresult.fcode); if (cmresult.fcode != _CMCFM) { printf("?Unexpected function code: %d\n",cmresult.fcode); x = -9; goto xconnx; } /* Command was confirmed so we can pre-pop command level. */ /* This is so CONNECT module won't think we're executing a script */ /* if CONNECT was the final command in the script. */ if (cmdlvl > 0) prepop(); #ifdef OS2 /* Make results available globally */ if (pv[CONN_IL].ival > -1) /* Idle limit */ tt_idlelimit = pv[CONN_IL].ival; if (pv[CONN_II].ival > -1) /* Idle limit */ tt_idlesnd_tmo = pv[CONN_II].ival; if (pv[CONN_IS].sval) /* Idle string */ if (tt_idlesnd_str = (char *)malloc((int)strlen(pv[CONN_IS].sval)+1)) strcpy(tt_idlesnd_str,pv[CONN_IS].sval); /* safe */ if (pv[CONN_TL].ival > -1) /* Session limit */ tt_timelimit = pv[CONN_TL].ival; async = (pv[CONN_AS].ival > 0 || pv[CONN_SY].ival <= 0 && cmdlvl == 0) ? 1 : 0; #endif /* OS2 */ #ifdef CK_TRIGGER if (pv[CONN_TS].sval) /* Trigger strings */ makelist(pv[CONN_TS].sval,tt_trigger,TRIGGERS); for (i = 0; i < TRIGGERS; i++) /* Trigger match pointers */ tt_trmatch[i] = NULL; if (triggerval) { /* Reset trigger value */ free(triggerval); triggerval = NULL; } #endif /* CK_TRIGGER */ #ifdef SSHCMD /* 2010/03/01... The previous connection was through the external ssh client and now, with that connection closed, the user says "connect" and expects a new connection to be made to the same host, because that's how all the other connection methods work, so (and this is quite a hack)... */ if (!ckstrcmp("ssh ",ttname,4,0)) { /* Previous "host" was "ssh blah" */ _PROTOTYP (int redossh, ( void ) ); extern int ttyfd; if (ttyfd < 0) { /* And connection is no longer open */ int xx; xx = redossh(); /* So redo the SSH connection */ if (xx < 0) return(xx); goto xconnx; } } #endif /* SSHCMD */ x = doconect((pv[CONN_NV].ival > 0) ? 1 : 0, async); { int xx; debug(F101,"doxconn doconect returns","",x); if ((xx = ttchk()) < 0) dologend(); debug(F101,"doxconn ttchk returns","",xx); } #ifdef CK_TRIGGER debug(F111,"doxconn doconect triggerval",triggerval,x); #endif /* CK_TRIGGER */ xconnx: /* Back from CONNECT -- Restore global settings */ if (!async) resconn(); success = (x > 0) ? 1 : 0; return(x); } #endif /* NOLOCAL */ #ifdef ADDCMD /* cx == XXADD or XXREMV */ /* fc == ADD_BIN or ADD_TXT */ static int #ifdef CK_ANSIC doadd( int cx, int fc ) #else doadd(cx,fc) int cx, fc; #endif /* CK_ANSIC */ { #ifdef PATTERNS char * tmp[FTPATTERNS]; char **p = NULL; int i, j, n = 0, x = 0, last; #endif /* PATTERNS */ if (cx != XXADD && cx != XXREMV) { printf("?Unexpected function code: %d\n",cx); return(-9); } #ifdef PATTERNS while (n < FTPATTERNS) { /* Collect new patterns */ tmp[n] = NULL; if ((x = cmfld("Pattern","",&s,xxstring)) < 0) break; ckstrncpy(line,s,LINBUFSIZ); s = brstrip(line); makestr(&(tmp[n++]),s); } if (x == -3) x = cmcfm(); if (x < 0) goto xdoadd; p = (fc == ADD_BIN) ? binpatterns : txtpatterns; /* Which list */ last = 0; for (i = 0; i < FTPATTERNS; i++) { /* Find last one in list */ if (!p[i]) { last = i; break; } } if (cx == XXADD) { /* Adding */ if (last + n > FTPATTERNS) { /* Check if too many */ printf("?Too many patterns - %d is the maximum\n", FTPATTERNS); goto xdoadd; } for (i = 0; i < n; i++) { /* Copy in the new ones. */ for (j = 0, x = 0; x == 0 && j < last ; j++ ) x = !ckstrcmp(tmp[i],p[j],-1,filecase); /* match */ if (x == 0) makestr(&(p[last++]),tmp[i]); } makestr(&(p[last]),NULL); /* Null-terminate the list */ x = 1; goto xdoadd; /* Done */ } else if (cx == XXREMV) { /* Remove something(s) */ int j, k; if (last == 0) /* List is empty */ goto xdoadd; /* Nothing to remove */ for (i = 0; i < n; i++) { /* i = Patterns they typed */ for (j = 0; j < last; j++) { /* j = Patterns in list */ /* Change this to ckstrcmp()... */ if (filecase) x = !ckstrcmp(tmp[i],p[j],-1,filecase); /* match */ else x = ckstrcmp(tmp[i],p[j],-1,0); /* Case-independent match */ if (x) { /* This one matches */ makestr(&(p[j]),NULL); /* Free it */ for (k = j; k < last; k++) /* Move the rest up */ p[k] = p[k+1]; p[k] = NULL; /* Erase last one */ if (!p[k]) break; } } } } xdoadd: /* Common exit */ for (i = 0; i < n; i++) if (tmp[i]) free(tmp[i]); return(x); #endif /* PATTERNS */ } /* ADD SEND-LIST */ static int #ifdef CK_ANSIC addsend( int cx ) #else addsend(cx) int cx; #endif /* CK_ANSIC */ { #ifndef NOMSEND extern struct keytab fttab[]; extern int nfttyp; struct filelist * flp; char * fmode = ""; int xmode = 0; int xbinary = 0; #endif /* NOMSEND */ #ifdef NOMSEND printf("?Sorry, ADD/REMOVE SEND-LIST not available.\n"); return(-9); #endif /* NOMSEND */ if (cx == XXREMV) { printf("?Sorry, REMOVE SEND-LIST not implemented yet.\n"); return(-9); } #ifndef NOMSEND #ifndef XYZ_INTERNAL if (protocol != PROTO_K) { printf("?Sorry, ADD SEND-LIST does not work with external protocols\n"); return(-9); } #endif /* XYZ_INTERNAL */ x = cmifi("File specification to add","", &s,&y,xxstring); if (x < 0) { if (x == -3) { printf("?A file specification is required\n"); return(-9); } else return(x); } ckstrncpy(tmpbuf,s,TMPBUFSIZ); s = tmpbuf; if (filesinlist == 0) /* Take care of \v(filespec) */ fspec[0] = NUL; zfnqfp(s,LINBUFSIZ,line); s = line; if (((int)strlen(fspec) + (int)strlen(s) + 1) < fspeclen) { strcat(fspec,s); /* safe */ strcat(fspec," "); /* safe */ } else printf("WARNING - \\v(filespec) buffer overflow\n"); xbinary = binary; if ((patterns || filepeek) /* FILE PATTERNS or SCAN is ON */ #ifdef CK_LABELED && binary != XYFT_L /* And not if FILE TYPE LABELED */ #endif /* CK_LABELED */ #ifdef VMS && binary != XYFT_I /* or FILE TYPE IMAGE */ #endif /* VMS */ ) { int k, x; x = -1; k = scanfile(line,&x,nscanfile); if (k > 0) xbinary = (k == FT_BIN) ? XYFT_B : XYFT_T; } fmode = gfmode(xbinary,0); if ((x = cmkey(fttab,nfttyp, "type of file transfer", fmode, xxstring)) < 0) return(x); xmode = x; cmarg2 = ""; if ((x = cmfld(y ? "\nAs-name template containing replacement variables such as \\v(filename)" : "Name to send it with", "",&s,NULL)) < 0) if (x != -3) return(x); #ifndef NOSPL if (y && *s) { char * p = tmpbuf; x = TMPBUFSIZ; zzstring(s,&p,&x); if (!strcmp(tmpbuf,s)) { printf( "?As-name for file group must contain variables such as \\v(filename)\n" ); return(-9); } } #endif /* NOSPL */ ckstrncpy(tmpbuf,s,TMPBUFSIZ); cmarg2 = tmpbuf; if ((x = cmcfm()) < 0) return(x); flp = (struct filelist *) malloc(sizeof(struct filelist)); if (flp) { if (filetail) filetail->fl_next = flp; filetail = flp; if (!filehead) filehead = flp; x = (int) strlen(line); /* Length of filename */ s = (char *) malloc(x + 1); if (s) { strcpy(s,line); /* safe */ flp->fl_name = s; flp->fl_mode = xmode; x = (int) strlen(cmarg2); /* Length of as-name */ if (x < 1) { flp->fl_alias = NULL; } else { s = (char *) malloc(x + 1); if (s) { strcpy(s,cmarg2); /* safe */ flp->fl_alias = s; } else { printf("Sorry, can't allocate space for as-name"); return(-9); } } flp->fl_next = NULL; filesinlist++; /* Count this node */ return(success = 1); /* Finished adding this node */ } else { printf("Sorry, can't allocate space for name"); return(-9); } } else { printf("Sorry, can't allocate file list node"); return(-9); } #endif /* NOMSEND */ } #endif /* ADDCMD */ #ifndef NOHTTP /* HTTP ops... */ #ifdef TCPSOCKET #define HTTP_GET 0 /* GET */ #define HTTP_PUT 1 /* PUT */ #define HTTP_POS 2 /* POST */ #define HTTP_IDX 3 /* INDEX */ #define HTTP_HED 4 /* HEAD */ #define HTTP_DEL 5 /* DELETE */ #define HTTP_CON 6 /* CONNECT */ #define HTTP_OPN 7 /* OPEN */ #define HTTP_CLS 8 /* CLOSE */ static struct keytab httptab[] = { { "close", HTTP_CLS, 0 }, { "connect", HTTP_CON, 0 }, { "delete", HTTP_DEL, 0 }, { "get", HTTP_GET, 0 }, { "head", HTTP_HED, 0 }, { "index", HTTP_IDX, 0 }, { "open", HTTP_OPN, 0 }, { "put", HTTP_PUT, 0 }, { "post", HTTP_POS, 0 } }; static int nhttptab = sizeof(httptab)/sizeof(struct keytab); /* HTTP switches */ #define HT_SW_AG 0 /* /AGENT */ #define HT_SW_HD 1 /* /HEADER */ #define HT_SW_US 2 /* /USER */ #define HT_SW_PW 3 /* /PASSWORD */ #define HT_SW_AR 4 /* /ARRAY */ #define HT_SW_TP 5 /* /TOSCREEN */ static struct keytab httpswtab[] = { { "/agent", HT_SW_AG, CM_ARG }, #ifndef NOSPL { "/array", HT_SW_AR, CM_ARG }, #endif /* NOSPL */ { "/header", HT_SW_HD, CM_ARG }, { "/password", HT_SW_PW, CM_ARG }, { "/toscreen", HT_SW_TP, 0 }, { "/user", HT_SW_US, CM_ARG }, { "", 0, 0 } }; static int nhttpswtab = sizeof(httpswtab)/sizeof(struct keytab) - 1; /* HTTP PUT/POST switches */ #define HT_PP_MT 0 /* /MIME-TYPE */ static struct keytab httpptab[] = { { "/mime-type", HT_PP_MT, CM_ARG }, { "", 0, 0 } }; static int nhttpptab = sizeof(httpptab)/sizeof(struct keytab) - 1; #define HTTP_MAXHDR 8 static int #ifdef CK_ANSIC xdohttp(int action, char * lfile, char * rf, char * dfile, char * agent, char * hdr, char * user, char * pass, char * mime, char array, int type) #else xdohttp(action, lfile, rf, dfile, agent, hdr, user, pass, mime, array, type) int action; char *lfile, *rf, *dfile, *agent, *hdr, *user, *pass, *mime, array; int type; #endif /* CK_ANSIC */ /* xdohttp */ { int i, rc = 0; char * hdrlist[HTTP_MAXHDR]; char rfile[CKMAXPATH+1]; extern int httpfd; /* Check for a valid state to execute the command */ if (inserver) { printf("?The HTTP command may not be used from the IKS\r\n"); } else if (httpfd == -1) { if (http_reopen() < 0) printf("?No connection\n"); else rc = 1; } else { rc = 1; } /* If the command is not valid, exit with failure */ if (rc == 0) return(success = 0); if (action != HTTP_CON && rf[0] != '/') { rfile[0] = '/'; ckstrncpy(&rfile[1],rf,CKMAXPATH); } else { ckstrncpy(rfile,rf,CKMAXPATH); } for (i = 0; i < HTTP_MAXHDR; i++) /* Initialize header list */ hdrlist[i] = NULL; makelist(hdr,hdrlist,HTTP_MAXHDR); /* Make header list */ #ifdef BETADEBUG for (i = 0; i < nhttptab; i++) /* Find action keyword */ if (httptab[i].kwval == action) break; if (i == nhttptab) { /* Shouldn't happen... */ printf("?Invalid action - %d\n",action); return(0); /* Failure */ } printf("HTTP action: %s\n",httptab[i].kwd); printf(" Agent: %s\n",agent ? agent : "(null)"); if (hdrlist[1]) { printf(" Header list: 1. %s\n",hdrlist[0]); for (i = 1; i < HTTP_MAXHDR && hdrlist[i]; i++) printf("%15d. %s\n",i+1,hdrlist[i]); } else printf(" Header: %s\n",hdrlist[0] ? hdrlist[0] : "(null)"); printf(" User: %s\n",user ? user : "(null)"); #ifdef COMMENT printf(" Password: %s\n",pass ? pass : "(null)"); #endif /* COMMENT */ #ifndef NOSPL if (array) printf(" Array: \\%%%c[]\n", array); else printf(" Array: (none)\n"); #endif /* NOSPL */ if (action == HTTP_PUT || action == HTTP_POS) printf(" Mime-type: %s\n",mime ? mime : "(null)"); printf(" Local file: %s\n",lfile ? lfile : "(null)"); printf(" Remote file: %s\n",rfile ? rfile : "(null)"); printf(" Destination file: %s\n",dfile ? dfile : "(null)"); #endif /* BETADEBUG */ /* The http_xxxx() functions return 0 on success, -1 on failure */ switch (action) { case HTTP_CON: { extern int ttyfd; rc = http_connect(httpfd,agent,hdrlist,user,pass,array,rfile); break; } case HTTP_DEL: rc = http_delete(agent,hdrlist,user,pass,array,rfile); break; case HTTP_GET: rc = http_get(agent,hdrlist,user,pass,array,lfile,rfile,type); break; case HTTP_HED: rc = http_head(agent,hdrlist,user,pass,array,lfile,rfile,type); break; case HTTP_PUT: rc = http_put(agent,hdrlist,mime,user,pass,array,lfile,rfile,dfile, type); break; case HTTP_POS: rc = http_post(agent,hdrlist,mime,user,pass,array,lfile,rfile,dfile, type); break; case HTTP_IDX: rc = http_index(agent,hdrlist,user,pass,array,lfile,rfile,type); break; default: rc = -1; } return(rc == 0 ? 1 : 0); /* Success is set by caller */ } #endif /* TCPSOCKET */ #endif /* NOHTTP */ #ifndef NOSPL /* ARRAY ops... */ static struct keytab arraytab[] = { { "clear", ARR_CLR, 0 }, { "copy", ARR_CPY, 0 }, { "dcl", ARR_DCL, CM_INV }, { "declare", ARR_DCL, 0 }, { "destroy", ARR_DST, CM_INV }, { "equate", ARR_EQU, CM_INV }, { "link", ARR_EQU, 0 }, { "resize", ARR_RSZ, 0 }, { "set", ARR_SET, 0 }, #ifndef NOSHOW { "show", ARR_SHO, 0 }, #endif /* NOSHOW */ { "sort", ARR_SRT, 0 }, { "undeclare", ARR_DST, 0 }, { "", 0, 0 } }; static int narraytab = sizeof(arraytab)/sizeof(struct keytab) - 1; #ifdef CKLEARN static struct keytab learnswi[] = { { "/close", 2, 0 }, { "/off", 0, 0 }, { "/on", 1, 0 } }; #endif /* CKLEARN */ int #ifdef CK_ANSIC arrayitoa( int x ) /* Array index to array letter */ #else arrayitoa(x) int x; #endif /* CK_ANSIC */ { if (x == 1) return(64); else if (x < 0 || x > (122 - ARRAYBASE)) return(-1); else return(x + ARRAYBASE); } int #ifdef CK_ANSIC arrayatoi( int c ) /* Array letter to array index */ #else arrayatoi(c) int c; #endif /* CK_ANSIC */ { if (c == 64) c = 96; if (c > 63 && c < 91) c += 32; if (c < ARRAYBASE || c > 122) return(-1); return(c - ARRAYBASE); } static int /* Declare an array */ #ifdef CK_ANSIC dodcl( int cx ) #else dodcl(cx) int cx; #endif /* CK_ANSIC */ { int i, n, v, lo, hi, rc = 0; int isdynamic = 0; char tmpbuf[64]; char ** p = NULL; char tmp[64]; /* Local temporary string buffer */ if ((y = cmfld("Array name","",&s,NULL)) < 0) { /* Parse array name */ if (y == -3) { printf("?Array name required\n"); return(-9); } else return(y); } ckstrncpy(line,s,LINBUFSIZ); s = line; x = arraybounds(s,&lo,&hi); /* Check syntax and get bounds */ debug(F111,"dodcl arraybounds",s,x); if (x < 0) { /* Error - Maybe it's a variable */ char * p; /* whose value is an array name */ int n; p = tmpbuf; n = 63; p[0] = NUL; if (s[0] == CMDQ && s[1] == '&') s++; if (zzstring(s,&p,&n) > -1) { s = tmpbuf; x = arraybounds(s,&lo,&hi); debug(F111,"dodcl arraybounds 2",s,x); } if (x < 0) { printf("?Bad array name - \"%s\"\n",s); return(-9); } } debug(F101,"dodcl hi","",hi); debug(F101,"dodcl lo","",lo); debug(F101,"dodcl lo+1","",lo+1); if (lo == -1 && hi == -1) { /* Have good array name and bounds */ isdynamic = 1; n = CMDBL / 5; } else if (hi > -1) { printf("?Segment notation not allowed in array declarations\n"); return(-9); } else if ((lo+1) < 0) { debug(F101,"dodcl underflow","",lo+1); printf("?Dimension underflow\n"); return(-9); } else n = lo; x = arrayitoa(x); if (cx == XXUNDCL) { n = 0; v = 0; if ((y = cmcfm()) < 0) return(y); } else { p = (char **)malloc(sizeof(char **)*(n+1)); if (!p) { printf("?Memory allocation error\n"); return(-9); } v = 0; /* Highest initialized member */ p[0] = NULL; /* Element 0 */ keepallchars = 1; while (n > 0 && v < n) { /* Parse initializers */ p[v+1] = NULL; ckmakxmsg(tmp, 64, "Initial value for \\&", ckctoa((char)x), "[", ckitoa(v+1), "]", NULL,NULL,NULL,NULL,NULL,NULL,NULL ); rc = cmfld((char *)tmp,"",&s,xxstring); /* Get field */ if (rc < 0) { /* Error... */ if (rc == -3) { /* Empty element */ if (cmflgs == 1) /* because end of line? */ break; /* Yes, done initializing */ else /* No, it's just empty */ continue; /* Go on to next one. */ } else { /* Other parse error */ goto dclx; /* Go free temp pointers */ } } rc = 1; if (v == 0 && !strcmp(s,"=")) /* Skip the = sign. */ continue; s = brstrip(s); /* Strip any braces */ makestr(&(p[++v]),s); } keepallchars = 0; if ((y = cmtxt("Carriage return to confirm","",&s,NULL)) < 0) return(y); if (isdynamic) n = v; } if (dclarray((char)x,n) < 0) { /* Declare the array */ printf("?Declare failed\n"); goto dclx; } for (i = 1; i <= v; i++) { /* Add any initial values */ tmp[0] = '&'; ckmakmsg(&tmp[1],63,ckctoa((char)x),"[",ckitoa(i),"]"); if (addmac(tmp,p[i]) < 0) { printf("Array initialization error: %s %s\n",tmp,p[i]); rc = -9; goto dclx; } } dclx: if (p) { for (i = 1; i <= v; i++) if (p[i]) free(p[i]); free((char *)p); } debug(F101,"DCL rc","",rc); return(success = rc); } static int rszarray() { int i, x, y, n, lo, hi, islink = -1; char c, * s, ** ap = NULL; if ((x = cmfld("Array name","",&s,NULL)) < 0) { /* Parse array name */ if (x == -3) { printf("?Array name required\n"); return(-9); } else return(x); } ckstrncpy(line,s,LINBUFSIZ); /* Make safe copy of name */ s = line; x = arraybounds(s,&lo,&hi); if (x < 0) { /* Parse the name, get index */ printf("?Bad array reference - \"%s\"\n", s); return(-9); } if (lo < 0 && hi < 0) { y = cmnum("New size","",10,&lo,xxstring); if (y < 0) { if (y == -3) printf("?New size required\n"); return(y); } } if ((y = cmcfm()) < 0) return(y); if (a_link[x] > -1) { /* Link? */ islink = x; /* Yes follow it */ x = a_link[x]; /* and remember */ } if (!a_ptr[x]) { printf("?Array not declared - \"%s\"\n", s); return(-9); } if (lo < 0) { printf("?New size required\n"); return(-9); } if (hi > -1) { printf("?Array segments not allowed for this operation\n"); return(-9); } c = arrayitoa(x); /* Get array letter */ if (c == '@') { /* Argument vector array off limits */ printf("?Sorry, \\&@[] is read-only\n"); return(-9); } if (lo == 0) { /* If new size is 0... */ dclarray(c,0); /* Undeclare the array */ return(success = 1); } n = a_dim[x]; /* Current size */ ap = (char **) malloc((lo+1) * sizeof(char *)); /* New array */ y = (n < lo) ? n : lo; for (i = 0; i <= y; i++) /* Copy the part that fits */ ap[i] = a_ptr[x][i]; if (n < lo) { /* If original array smaller */ for (; i <= lo; i++) /* initialize extra elements in */ ap[i] = NULL; /* new array to NULL. */ } else if (n > lo) { /* If new array smaller */ for (; i <= lo; i++) /* deallocate leftover elements */ makestr(&(a_ptr[x][i]),NULL); /* from original array. */ } free((char *)a_ptr[x]); /* Free original array list */ a_ptr[x] = ap; /* Replace with new one */ a_dim[x] = lo; /* Record the new dimension */ if (islink > -1) { /* Was this a link? */ a_ptr[islink] = ap; /* If so point to the resized array */ a_dim[islink] = lo; } else { /* If not are there links to here? */ for (i = 0; i < (int) 'z' - ARRAYBASE; i++) { /* Any linked arrays? */ if (i != x && a_link[i] == x) { /* Find and update them */ a_ptr[i] = ap; a_dim[i] = lo; } } } return(success = 1); } static int copyarray() { int i, j, x1, lo1, hi1, x2, lo2, hi2, whole = 0; char c1, c2, * a1, * a2; if ((y = cmfld("Name of source array","",&s,NULL)) < 0) return(y); ckstrncpy(line,s,LINBUFSIZ); a1 = line; if ((x1 = arraybounds(a1,&lo1,&hi1)) < 0) { printf("?Bad array reference - \"%s\"\n", a1); return(-9); } else if (!a_ptr[x1]) { printf("?Array not declared - \"%s\"\n", a1); return(-9); } c1 = arrayitoa(x1); if ((y = cmfld("Name of destination array","",&s,NULL)) < 0) return(y); ckstrncpy(tmpbuf,s,TMPBUFSIZ); a2 = tmpbuf; if ((x2 = arraybounds(a2,&lo2,&hi2)) < 0) { printf("?Bad array reference - \"%s\"\n", a2); return(-9); } c2 = arrayitoa(x2); if ((x = cmcfm()) < 0) return(x); if (c2 == '@') { /* Argument vector array off limits */ printf("?Sorry, \\&@[] is read-only\n"); return(-9); } if (lo1 < 0 && lo2 < 0 && hi1 < 0 && hi2 < 0) /* Special case for */ whole = 1; /* whole array... */ if (lo1 < 0) lo1 = whole ? 0 : 1; /* Supply lower bound of source */ if (hi1 < 0) hi1 = a_dim[x1]; /* Supply upper bound of source */ if (lo2 < 0) lo2 = whole ? 0 : 1; /* Lower bound of target */ if (hi2 < 0) hi2 = lo2 + hi1 - lo1; /* Upper bound of target */ if (a_ptr[x2]) { /* Target array is already declared? */ if (hi2 > a_dim[x2]) /* If upper bound out of range */ hi2 = a_dim[x2]; /* shrink to fit */ } else { /* Otherwise... */ x2 = dclarray(c2, hi2); /* declare the target array */ } for (i = lo1, j = lo2; i <= hi1 && j <= hi2; i++,j++) { /* Copy */ makestr(&(a_ptr[x2][j]),a_ptr[x1][i]); } return(success = 1); } static int /* Undeclare an array */ unarray() { int x, y, n, rc = 0; char c, * s; if ((y = cmfld("Array name","",&s,NULL)) < 0) { /* Parse array name */ if (y == -3) { printf("?Array name required\n"); return(-9); } else return(y); } ckstrncpy(line,s,LINBUFSIZ); /* Make safe copy of name */ s = line; if ((y = cmcfm()) < 0) return(y); if ((x = arraybounds(s,&y,&n)) < 0) { /* Parse the name, get index */ printf("?Bad array reference - \"%s\"\n", s); return(-9); } if (y > 0 || n > 0) { printf("?Partial arrays can not be destroyed\n"); return(-9); } c = arrayitoa(x); /* Get array letter */ if (a_ptr[x]) { /* If array is declared */ if (c == '@') { /* Argument vector array off limits */ printf("?Sorry, \\&@[] is read-only\n"); return(-9); } rc = dclarray(c,-1); /* Undeclare the array */ } else /* It wasn't declared */ rc = 1; if (rc > -1) { /* Set return code and success */ success = 1; rc = 1; } else { success = 0; printf("?Failed - destroy \"\\&%c[]\"\n", c); rc = -9; } return(rc); } static int #ifdef CK_ANSIC clrarray( int cx ) #else clrarray(cx) int cx; #endif /* CK_ANSIC */ { int i, x, lo, hi; char c, * s, * val = NULL; if ((x = cmfld("Array name","",&s,NULL)) < 0) { /* Parse array name */ if (x == -3) { printf("?Array name required\n"); return(-9); } else return(x); } ckstrncpy(line,s,LINBUFSIZ); /* Make safe copy of name */ s = line; if (cx == ARR_SET) { /* SET */ if ((x = cmtxt("Value","",&val,xxstring)) < 0) return(x); ckstrncpy(tmpbuf,val,TMPBUFSIZ); /* Value to set */ val = tmpbuf; if (!*val) val = NULL; } else if ((x = cmcfm()) < 0) /* CLEAR */ return(x); if ((x = arraybounds(s,&lo,&hi)) < 0) { /* Parse the name */ printf("?Bad array reference - \"%s\"\n", s); return(-9); } c = arrayitoa(x); /* Get array letter */ if (!a_ptr[x]) { /* If array is declared */ printf("?Array %s is not declared\n", s); return(-9); } else if (c == '@') { /* Argument vector array off limits */ printf("?Sorry, \\&@[] is read-only\n"); return(-9); } if (lo < 0) lo = 0; if (hi < 0) hi = a_dim[x]; for (i = lo; i <= hi; i++) /* Clear/Set selected range */ makestr(&(a_ptr[x][i]),val); return(success = 1); } extern char **aa_ptr[CMDSTKL][32]; extern int aa_dim[CMDSTKL][32]; static int /* Create symbolic link to an array */ linkarray() { int i = 0, x, y, lo, hi, flag = 0; char c, * s, * p; if ((x = cmfld("Array name not currently in use","",&s,NULL)) < 0) { if (x == -3) { printf("?Array name required\n"); return(-9); } else return(x); } ckstrncpy(line,s,LINBUFSIZ); /* Make safe copy of link name */ s = line; if ((x = cmfld("Name of existing array","",&p,xxstring)) < 0) { if (x == -3) { printf("?Array name required\n"); return(-9); } else return(x); } ckstrncpy(tmpbuf,p,TMPBUFSIZ); /* Make safe copy of array name */ p = tmpbuf; if ((x = cmcfm()) < 0) return(x); if ((x = arraybounds(s,&lo,&hi)) < 0) { /* Parse the link name */ printf("?Bad array reference - \"%s\"\n", s); return(-9); } if (a_ptr[x]) { /* Must not already exist */ c = arrayitoa(x); printf("?Array already exists: \\&%c[]\n", c); return(-9); } if (lo > -1 || hi > -1) { printf("?Sorry, whole arrays only: %s\n",s); return(-9); } if ((y = arraybounds(p,&lo,&hi)) < 0) { /* Parse the array name */ printf("?Bad array reference - \"%s\"\n", s); return(-9); } if (lo > -1 || hi > -1) { printf("?Sorry, whole arrays only: %s\n",p); return(-9); } if (x == y) { for (i = cmdlvl; i >= 0; i--) if (aa_ptr[i][x]) { flag++; break; } } if (flag) { a_ptr[x] = aa_ptr[i][y]; /* Link to saved copy */ a_dim[x] = aa_dim[i][y]; } else { /* Otherwise... */ c = arrayitoa(y); /* Check if it's declared */ if (!a_ptr[y]) { printf("?Array is not declared: \\&%c[]\n", c); return(-9); } if (a_link[y] > -1) { /* And if it's a link itself */ printf("?Links to links not allowed: \\&%c[]\n", c); return(-9); } a_ptr[x] = a_ptr[y]; /* All OK, make the link */ a_dim[x] = a_dim[y]; } a_link[x] = y; return(success = 1); } #endif /* NOSPL */ #ifndef NOCSETS static char * dcsetname = NULL; /* Get Display Character-Set Name */ char * getdcset() { char * s; int y; #ifdef PCFONTS extern int tt_font, ntermfont; extern struct keytab term_font[]; #endif /* PCFONTS */ s = ""; #ifdef OS2 y = os2getcp(); /* Default is current code page */ switch (y) { case 437: s = "cp437"; break; case 850: s = "cp850"; break; case 852: s = "cp852"; break; case 857: s = "cp857"; break; case 858: s = "cp858"; break; case 862: s = "cp862"; break; case 866: s = "cp866"; break; case 869: s = "cp869"; break; case 1250: s = "cp1250"; break; case 1251: s = "cp1251"; break; case 1252: s = "cp1252"; break; case 1253: s = "cp1253"; break; case 1254: s = "cp1254"; break; case 1255: s = "cp1255"; break; case 1256: s = "cp1256"; break; case 1257: s = "cp1257"; break; case 1258: s = "cp1258"; break; } #ifdef PCFONTS /* If the user has loaded a font with SET TERMINAL FONT then we want to change the default code page to the font that was loaded. */ if (tt_font != TTF_ROM) { for (y = 0; y < ntermfont; y++ ) { if (term_font[y].kwval == tt_font) { s = term_font[y].kwd; break; } } } #endif /* PCFONTS */ #else /* OS2 */ #ifdef COMMENT /* Hack not needed as of C-Kermit 7.1 */ if (fcharset == FC_1LATIN) { s = "latin1-iso"; /* Hack to avoid reporting "cp1252" */ } else { /* Report current file character set */ #endif /* COMMENT */ for (y = 0; y <= nfilc; y++) if (fcstab[y].kwval == fcharset) { s = fcstab[y].kwd; break; } #ifdef COMMENT } #endif /* COMMENT */ #endif /* OS2 */ makestr(&dcsetname,s); /* Return stable pointer */ return((char *)dcsetname); } #endif /* NOCSETS */ #ifndef NOFRILLS static int doclear() { if ((x = cmkey(clrtab,nclear,"item to clear", #ifdef NOSPL "device-buffer" #else "device-and-input" #endif /* NOSPL */ ,xxstring)) < 0) return(x); #ifndef NOSPL #ifdef OS2 if (x == CLR_CMD || x == CLR_TRM) { if ((z = cmkey(clrcmdtab,nclrcmd,"how much screen to clear\n", "all",xxstring)) < 0) return(z); } #endif /* OS2 */ #endif /* NOSPL */ if ((y = cmcfm()) < 0) return(y); /* Clear device input buffer if requested */ y = (x & CLR_DEV) ? ttflui() : 0; if (x & CLR_SCR) /* CLEAR SCREEN */ y = ck_cls(); /* (= SCREEN CLEAR = CLS) */ if (x & CLR_KBD) { /* CLEAR KEYBOARD */ int n; n = conchk(); y = 0; while (n-- > 0 && (y = coninc(0) > -1)) ; y = (y > -1) ? 0 : -1; } #ifndef NOSPL /* Clear INPUT command buffer if requested */ if (x & CLR_INP) { for (z = 0; z < inbufsize; z++) inpbuf[z] = NUL; inpbp = inpbuf; y = 0; } #ifdef CK_APC if (x & CLR_APC) { debug(F101,"Executing CLEAR APC","",apcactive); apcactive = 0; y = 0; } #endif /* CK_APC */ if (x & CLR_ALR) { setalarm(0L); y = 0; } #endif /* NOSPL */ #ifdef PATTERNS if (x & (CLR_TXT|CLR_BIN)) { int i; for (i = 0; i < FTPATTERNS; i++) { if (x & CLR_TXT) makestr(&txtpatterns[i],NULL); if (x & CLR_BIN) makestr(&binpatterns[i],NULL); } y = 0; } #endif /* PATTERNS */ #ifndef NODIAL if (x & CLR_DIA) { dialsta = DIA_UNK; y = 0; } #endif /* NODIAL */ #ifndef NOMSEND if (x & CLR_SFL) { /* CLEAR SEND-LIST */ if (filehead) { struct filelist * flp, * next; flp = filehead; while (flp) { if (flp->fl_name) free(flp->fl_name); if (flp->fl_alias) free(flp->fl_alias); next = flp->fl_next; free((char *)flp); flp = next; } } filesinlist = 0; filehead = NULL; filetail = NULL; addlist = 0; y = 0; } #endif /* NOMSEND */ #ifdef OS2 #ifndef NOLOCAL switch (x) { case CLR_SCL: clearscrollback(VTERM); break; case CLR_CMD: switch ( z ) { case CLR_C_ALL: clear(); break; case CLR_C_BOS: clrboscr_escape(VCMD,SP); break; case CLR_C_BOL: clrbol_escape(VCMD,SP); break; case CLR_C_EOL: clrtoeoln(VCMD,SP); break; case CLR_C_EOS: clreoscr_escape(VCMD,SP); break; case CLR_C_LIN: clrline_escape(VCMD,SP); break; case CLR_C_SCR: clearscrollback(VCMD); break; default: printf("Not implemented yet, sorry.\n"); break; } break; #ifndef NOTERM case CLR_TRM: switch ( z ) { case CLR_C_ALL: if (VscrnGetBufferSize(VTERM) > 0 ) { VscrnScroll(VTERM, UPWARD, 0, VscrnGetHeight(VTERM)-(tt_status[VTERM]?2:1), VscrnGetHeight(VTERM) - (tt_status[VTERM]?1:0), TRUE, SP ); cleartermscreen(VTERM); } break; case CLR_C_BOS: clrboscr_escape(VTERM,SP); break; case CLR_C_BOL: clrbol_escape(VTERM,SP); break; case CLR_C_EOL: clrtoeoln(VTERM,SP); break; case CLR_C_EOS: clreoscr_escape(VTERM,SP); break; case CLR_C_LIN: clrline_escape(VTERM,SP); break; case CLR_C_SCR: clearscrollback(VTERM); break; default: printf("Not implemented yet, sorry.\n"); break; } break; #endif /* NOTERM */ } y = 0; #endif /* NOLOCAL */ #endif /* OS2 */ return(success = (y == 0)); } #endif /* NOFRILLS */ #ifndef NOSPL static int #ifdef CK_ANSIC doeval( int cx ) #else doeval(cx) int cx; #endif /* CK_ANSIC */ { char *p; char vnambuf[VNAML], * vnp = NULL; /* These must be on the stack */ if (!oldeval) { if ((y = cmfld("Variable name","",&s, ((cx == XX_EVAL) ? xxstring : NULL))) < 0) { if (y == -3) { printf("?Variable name required\n"); return(-9); } else return(y); } ckstrncpy(vnambuf,s,VNAML); /* Make a copy. */ vnp = vnambuf; if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++; y = 0; if (*vnp == '%' || *vnp == '&') { if ((y = parsevar(vnp,&x,&z)) < 0) return(y); } } if ((x = cmtxt("Integer arithmetic expression","",&s,xxstring)) < 0) return(x); p = evala(s); if (!p) p = ""; if (oldeval && *p) printf("%s\n", p); ckstrncpy(evalbuf,p,32); if (!oldeval) return(success = addmac(vnambuf,p)); else return(success = *p ? 1 : 0); } #endif /* NOSPL */ #ifdef TNCODE static int dotelopt() { if ((x = cmkey(telcmd, ntelcmd, "TELNET command", "", xxstring)) < 0 ) return(x); switch (x) { case WILL: case WONT: case DO: case DONT: if ((y = cmkey(tnopts,ntnopts,"TELNET option","",xxstring)) < 0) return(y); if ((z = cmcfm()) < 0) return(z); switch (x) { case WILL: if (TELOPT_UNANSWERED_WILL(y)) return(success = 0); break; case WONT: if (TELOPT_UNANSWERED_WONT(y)) return(success = 0); break; case DO: if (TELOPT_UNANSWERED_DO(y)) return(success = 0); break; case DONT: if (TELOPT_UNANSWERED_DONT(y)) return(success = 0); break; } if (local) { success = ((tn_sopt(x,y) > -1) ? 1 : 0); } else { printf("ff%02x%02x\n",x,y); success = 1; } if (success) { switch (x) { case WILL: TELOPT_UNANSWERED_WILL(y) = 1; break; case WONT: if ( TELOPT_ME(y) ) TELOPT_UNANSWERED_WONT(y) = 1; break; case DO: TELOPT_UNANSWERED_DO(y) = 1; break; case DONT: if ( TELOPT_ME(y) ) TELOPT_UNANSWERED_DONT(y) = 1; break; } if (tn_wait("XXTELOP") < 0) { tn_push(); success = 0; } } return(success); case SB: if ((y=cmkey(tnsbopts,ntnsbopts,"TELNET option","",xxstring)) < 0) return(y); switch (y) { case TELOPT_NAWS: /* Some compilers require switch() to have at least 1 case */ #ifdef CK_NAWS TELOPT_SB(TELOPT_NAWS).naws.x = 0; TELOPT_SB(TELOPT_NAWS).naws.y = 0; if (local) return(success = ((tn_snaws() > -1) ? 1 : 0)); else return(success = 0); #else return(success = 0); #endif /* CK_NAWS */ } return(success = 0); #ifdef CK_KERBEROS #ifdef KRB5 case TN_FWD: success = (kerberos5_forward() == AUTH_SUCCESS); return(success); #endif /* KRB5 */ #endif /* CK_KERBEROS */ default: if ((z = cmcfm()) < 0) return(z); #ifndef NOLOCAL if (local) { CHAR temp[3]; if (network && IS_TELNET()) { /* TELNET */ temp[0] = (CHAR) IAC; temp[1] = x; temp[2] = NUL; success = (ttol((CHAR *)temp,2) > -1 ? 1 : 0); if (tn_deb || debses || deblog) { /* TN_MSG_LEN is in ckctel.h */ ckmakmsg(tn_msg,256,"TELNET SENT ",TELCMD(x),NULL,NULL); debug(F101,tn_msg,"",x); if (debses || tn_deb) tn_debug(tn_msg); } return(success); } return(success = 0); } else { #endif /* NOLOCAL */ printf("ff%02x\n",x); return(success = 1); #ifndef NOLOCAL } #endif /* NOLOCAL */ } } #endif /* TNCODE */ #ifndef NOPUSH #ifndef NOFRILLS static int doedit() { #ifdef OS2 char * p = NULL; #endif /* OS2 */ if (!editor[0]) { s = getenv("EDITOR"); if (s) ckstrncpy(editor,s,CKMAXPATH); editor[CKMAXPATH] = NUL; if (!editor[0]) { printf("?Editor not defined - use SET EDITOR to define\n"); return(-9); } } ckstrncpy(tmpbuf,editfile,TMPBUFSIZ); /* cmiofi() lets us parse the name of an existing file, or the name of a nonexistent file to be created. */ x = cmiofi("File to edit", (char *)tmpbuf, &s, &y, xxstring); debug(F111,"edit",s,x); if (x < 0 && x != -3) return(x); if (x == -3) { tmpbuf[0] = NUL; } else { ckstrncpy(tmpbuf,s,TMPBUFSIZ); } if ((z = cmcfm()) < 0) return(z); if (y) { printf("?A single file please\n"); return(-9); } if (nopush) { printf("?Sorry, editing not allowed\n"); return(success = 0); } if (tmpbuf[0]) { /* Get full path in case we change directories between EDIT commands */ zfnqfp(tmpbuf, CKMAXPATH, editfile); editfile[CKMAXPATH] = NUL; #ifdef OS2 p = editfile; /* Flip the stupid slashes */ while (*p) { if (*p == '/') *p = '\\'; p++; } #endif /* OS2 */ } else editfile[0] = NUL; if (editfile[0]) { if (zchki(editfile) < (CK_OFF_T)0 && zchko(editfile) < 0) { printf("?Access denied: %s\n",editfile); return(-9); } } x = 0; if (editopts[0]) { #ifdef OS2 x = ckindex("%1",(char *)editopts,0,0,1); if (x > 0) editopts[x] = 's'; else #endif /* OS2 */ x = ckindex("%s",(char *)editopts,0,0,1); } if (((int)strlen(editopts) + (int)strlen(editfile) + 1) < TMPBUFSIZ) { if (x) sprintf(tmpbuf,editopts,editfile); else sprintf(tmpbuf,"%s %s",editopts,editfile); } s = line; ckmakmsg(s,LINBUFSIZ,editor," ",tmpbuf,NULL); #ifdef OS2 p = s + strlen(editor); /* And again with the slashes */ while (p != s) { if (*p == '/') *p = '\\'; p--; } #endif /* OS2 */ conres(); x = zshcmd(s); concb((char)escape); return(x); } #endif /* NOFRILLS */ #endif /* NOPUSH */ #ifdef BROWSER static int dobrowse() { #ifdef OS2 char * p = NULL; #endif /* OS2 */ if (nopush) { printf("?Sorry, browsing not allowed\n"); return(success = 0); } #ifndef NT /* Windows lets the Shell Execute the URL if no Browser is defined */ if (!browser[0]) { s = getenv("BROWSER"); if (s) ckstrncpy(browser,s,CKMAXPATH); browser[CKMAXPATH] = NUL; if (!browser[0]) { printf("?Browser not defined - use SET BROWSER to define\n"); return(-9); } } #endif /* NT */ ckstrncpy(tmpbuf,browsurl,TMPBUFSIZ); if ((x = cmtxt("URL",(char *)browsurl,&s,xxstring)) < 0) return(x); ckstrncpy(browsurl,s,4096); x = 0; if (browsopts[0]) { #ifdef OS2 x = ckindex("%1",(char *)browsopts,0,0,1); if (x > 0) browsopts[x] = 's'; else #endif /* OS2 */ x = ckindex("%s",(char *)browsopts,0,0,1); } if (((int)strlen(browsopts) + (int)strlen(browsurl) + 1) < TMPBUFSIZ) { if (x) sprintf(tmpbuf,browsopts,browsurl); else sprintf(tmpbuf,"%s %s",browsopts,browsurl); } #ifdef NT if (!browser[0]) return(success = Win32ShellExecute(browsurl)); #endif /* NT */ s = line; ckmakmsg(s,LINBUFSIZ,browser," ",tmpbuf,NULL); #ifdef OS2 p = line + strlen(browser); /* Flip slashes */ while (p != line) { if (*p == '/') *p = '\\'; p--; } #endif /* OS2 */ conres(); x = zshcmd(s); concb((char)escape); return(x); } #endif /* BROWSER */ #ifdef CK_RECALL static int doredo() { /* Find a previous cmd and redo it */ extern int on_recall, in_recall; int x; char * p; if ((x = cmtxt( "pattern, or first few characters of a previous command", "*",&s,xxstring)) < 0) return(x); ckstrncpy(line,s,LINBUFSIZ); x = strlen(s); s = line; if (*s == '{') { /* Braces disable adding * to end */ if (s[x-1] == '}') { s[x-1] = NUL; s++; x--; } } else { /* No braces, add * to end. */ s[x] = '*'; s[x+1] = NUL; } while (x > 0 && s[x] == '*' && s[x-1] == '*') s[x--] = NUL; if (!on_recall || !in_recall) { printf("?Sorry, command recall can't be used now.\n"); return(-9); } if ((p = cmgetcmd(s))) { /* Look for it history buffer */ ckmakmsg(cmdbuf,CMDBL,p,"\r",NULL,NULL); /* Copy to command buffer */ if (!quiet) /* Echo it */ printf("%s\n",cmdbuf); cmaddnext(); /* Force re-add to history buffer */ return(cmflgs = -1); /* Force reparse */ } else { printf("?Sorry - \"%s\" not found\n", s); return(-9); } } #endif /* CK_RECALL */ #ifndef NOXFER #ifndef NOCSETS static int doassoc() { /* ASSOCIATE */ extern struct keytab tcstab[]; extern int ntcs; if ((x = cmkey(assoctab, nassoc, "", "", xxstring)) < 0 ) return(x); switch (x) { /* Associate what? */ case ASSOC_TC: /* Transfer character-set... */ if ((x = cmkey(tcstab, ntcs, "transfer character-set name","",xxstring)) < 0) return(x); if ((y = cmkey(fcstab, nfilc, "with file character-set","", xxstring)) < 0) if (y != -3) return(y); if ((z = cmcfm()) < 0) return(z); axcset[x] = y; return(success = 1); case ASSOC_FC: /* File character-set... */ if ((x = cmkey(fcstab, nfilc, "file character-set name","",xxstring)) < 0) return(x); if ((y = cmkey(tcstab, ntcs, "with transfer character-set","", xxstring)) < 0) if (y != -3) return(y); if ((z = cmcfm()) < 0) return(z); afcset[x] = y; return(success = 1); default: return(-2); } } #endif /* NOCSETS */ #endif /* NOXFER */ #ifndef NOHELP static int domanual() { #ifdef OS2 if ((x = cmcfm()) < 0) return(x); if (nopush) { printf("?Sorry, access to system commands is disabled.\n"); return(-9); } y = mxlook(mactab,"manual",nmac); if (y > -1) { z = maclvl; /* Save the current maclvl */ dodo(y,NULL,cmdstk[cmdlvl].ccflgs); /* Run the macro */ while (maclvl > z) { debug(F101,"XXMAN loop maclvl 1","",maclvl); sstate = (CHAR) parser(1); debug(F101,"XXMAN loop maclvl 2","",maclvl); if (sstate) proto(); } debug(F101,"XXMAN loop exit maclvl","",maclvl); return(success); } return(success = 0); #else if ((x = cmtxt( #ifdef UNIX "Carriage return to confirm the command, or manual topic", #else "Carriage return to confirm the command, or help topic", #endif /* UNIX */ "kermit", &s, xxstring ) ) < 0) return(x); #ifdef UNIX ckmakmsg(tmpbuf,TMPBUFSIZ,"man ",s,NULL,NULL); #else ckmakmsg(tmpbuf,TMPBUFSIZ,"help ",s,NULL,NULL); #endif /* UNIX */ debug(F110,"MANUAL",tmpbuf,0); if (nopush) { printf("?Sorry, access to system commands is disabled.\n"); return(-9); } else { conres(); /* Restore the console */ success = zshcmd(tmpbuf); concb((char)escape); /* Restore CBREAK mode */ return(success); } #endif /* OS2 */ } #endif /* NOHELP */ #ifndef NOHTTP #ifdef TCPSOCKET #ifdef CK_SSL static struct keytab sslswtab[] = { { "/ssl", 1, 0 }, { "/tls", 1, 0 } }; #endif /* CK_SSL */ #ifndef NOURL struct urldata http_url = {NULL,NULL,NULL,NULL,NULL,NULL,NULL}; #endif /* NOURL */ static int dohttp() { /* HTTP */ struct FDB sw, kw, fi; int n, getval, allinone = 0; char c, * p; char rdns[128]; char * http_agent = NULL; /* Parse results */ char * http_hdr = NULL; char * http_user = NULL; char * http_pass = NULL; char * http_mime = NULL; char * http_lfile = NULL; char * http_rfile = NULL; char * http_dfile = NULL; char http_array = NUL; int http_action = -1; char * http_host = NULL; char * http_srv = NULL; int http_ssl = 0; static char * http_d_agent = NULL; static char * http_d_user = NULL; static char * http_d_pass = NULL; static int http_d_type = 0; int http_type = http_d_type; #ifdef OS2 p = "Kermit 95"; /* Default user agent */ #else p = "C-Kermit"; #endif /* OS2 */ makestr(&http_agent,p); makestr(&http_mime,"text/HTML"); /* MIME type default */ rdns[0] = '\0'; cmfdbi(&sw, /* 1st FDB - general switches */ _CMKEY, /* fcode */ "OPEN, CLOSE, GET, HEAD, PUT, INDEX, or POST,\n or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nhttpswtab, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ httpswtab, /* Keyword table */ &kw /* Pointer to next FDB */ ); cmfdbi(&kw, /* 2nd FDB - commands */ _CMKEY, /* fcode */ "Command", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nhttptab, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: 0 = keyword */ xxstring, /* Processing function */ httptab, /* Keyword table */ NULL /* Pointer to next FDB */ ); while (1) { x = cmfdb(&sw); /* Parse something */ if (x < 0) /* Error */ goto xhttp; n = cmresult.nresult; if (cmresult.fdbaddr == &kw) /* Command - exit this loop */ break; c = cmgbrk(); /* Switch... */ getval = (c == ':' || c == '='); x = -9; if (getval && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); goto xhttp; } switch (cmresult.nresult) { /* Handle each switch */ case HT_SW_TP: /* /TOSCREEN */ http_type = 1; break; case HT_SW_AG: /* /AGENT */ if (getval) { if ((x = cmfld("User agent",p,&s,xxstring)) < 0) goto xhttp; } else { s = p; } makestr(&http_agent,s); break; case HT_SW_HD: /* /HEADER */ s = NULL; if (getval) { if ((x = cmfld("Header line","",&s,xxstring)) < 0) { if (x == -3) s = NULL; else goto xhttp; } } makestr(&http_hdr,s); break; case HT_SW_US: /* /USER */ s = NULL; if (getval) { if ((x = cmfld("User ID","",&s,xxstring)) < 0) { if (x == -3) s = ""; else goto xhttp; } } makestr(&http_user,s); break; case HT_SW_PW: /* /PASSWORD */ debok = 0; s = NULL; if (getval) { if ((x = cmfld("Password","",&s,xxstring)) < 0) goto xhttp; } makestr(&http_pass,s); break; #ifndef NOSPL case HT_SW_AR: { /* /ARRAY: */ char * s2, array = NUL; if (!getval) { printf("?This switch requires an argument\n"); x = -9; goto xhttp; } if ((x = cmfld("Array name (a single letter will do)", "", &s, NULL )) < 0) { if (x == -3) { printf("?Array name required\n"); x = -9; goto xhttp; } else goto xhttp; } if (!*s) { printf("?Array name required\n"); x = -9; goto xhttp; } s2 = s; if (*s == CMDQ) s++; if (*s == '&') s++; if (!isalpha(*s)) { printf("?Bad array name - \"%s\"\n",s2); x = -9; goto xhttp; } array = *s++; if (isupper(array)) array = tolower(array); if (*s && (*s != '[' || *(s+1) != ']')) { printf("?Bad array name - \"%s\"\n",s2); http_array = NUL; x = -9; goto xhttp; } http_array = array; break; } #endif /* NOSPL */ default: x = -2; goto xhttp; } } http_action = n; /* Save the action */ if (http_action == HTTP_PUT || http_action == HTTP_POS) { cmfdbi(&sw, /* 1st FDB - switch */ _CMKEY, /* fcode */ "Local filename\n Or switch", /* help */ "", /* default */ "", /* addtl string data */ nhttpptab, /* keyword table size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ httpptab, /* Keyword table */ &fi /* Pointer to next FDB */ ); cmfdbi(&fi, /* 2nd FDB - filename */ _CMIFI, /* fcode */ "Local filename", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); while (1) { x = cmfdb(&sw); if (x < 0) goto xhttp; /* Free any malloc'd temp strings */ n = cmresult.nresult; if (cmresult.fcode != _CMKEY) break; c = cmgbrk(); /* Switch... */ getval = (c == ':' || c == '='); if (getval && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); x = -9; goto xhttp; } switch (n) { case HT_PP_MT: s = "text/HTML"; if (getval) { if ((x = cmfld("MIME type", "text/HTML",&s,xxstring)) < 0) goto xhttp; } makestr(&http_mime,s); break; default: x = -2; goto xhttp; } } makestr(&http_lfile,cmresult.sresult); n = ckindex("/",http_lfile,-1,1,0); if (n) p = &http_lfile[n]; else p = http_lfile; if ((x = cmfld("URL or remote filename",p,&s,xxstring)) < 0) { if (x == -3) { printf("?%s what?\n",(http_action == HTTP_PUT) ? "Put" : "Post"); x = -9; } goto xhttp; } if (!*s) s = NULL; makestr(&http_rfile,s); if ((x = cmtxt("Response filename","",&s,xxstring)) < 0) { if (x != -3) goto xhttp; } if (*s) makestr(&http_dfile,s); } switch (http_action) { case HTTP_DEL: /* DELETE */ if ((x = cmfld("URL or remote source file","",&s,xxstring)) < 0) { if (x == -3) { printf("?Delete what?\n"); x = -9; } goto xhttp; } makestr(&http_rfile,s); break; case HTTP_CON: /* CONNECT */ if ((x = cmfld("Remote host[:port]","",&s,xxstring)) < 0) { if (x == -3) { printf("?Remote host[:port] is required\n"); x = -9; } goto xhttp; } makestr(&http_rfile,s); break; case HTTP_HED: { /* HEAD */ char buf[CKMAXPATH+1]; if ((x = cmfld("URL or remote source file","",&s,xxstring)) < 0) { if (x == -3) { printf("?Head of what?\n"); x = -9; } goto xhttp; } makestr(&http_rfile,s); if (http_array || http_type) { /* Default result filename */ p = ""; /* None if /ARRAY or /TOSCREEN */ } else { n = ckindex("/",http_rfile,-1,1,0); /* Otherwise strip path */ if (n) /* and add ".head" */ p = &http_rfile[n]; else p = http_rfile; ckmakmsg(buf,CKMAXPATH,p,".head",NULL,NULL); p = buf; } if ((x = cmofi("Local filename",p,&s,xxstring)) < 0) { if (x != -3) goto xhttp; } makestr(&http_lfile,s); break; } case HTTP_GET: /* GET */ case HTTP_IDX: { /* INDEX */ extern int wildena; int tmp; char * lfile = ""; if ((x = cmfld("URL or remote source file","",&s,xxstring)) < 0) { if (x == -3) { printf("?Get what?\n"); x = -9; } goto xhttp; } makestr(&http_rfile,s); if (http_action == HTTP_GET && !http_type) zstrip(http_rfile,&lfile); /* URLs often contain question marks or other metacharacters */ /* cmofi() doesn't like them */ tmp = wildena; wildena = 0; if ((x = cmofi("Local filename",lfile,&s,xxstring)) < 0) { wildena = tmp; if (x != -3) goto xhttp; } wildena = tmp; makestr(&http_lfile,s); break; } case HTTP_OPN: { int sslswitch = 0; #ifdef CK_SSL struct FDB sw, fl; cmfdbi(&sw, _CMKEY, /* fcode */ "IP host name or address, or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 2, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ sslswtab, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* 2nd FDB - host */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); x = cmfdb(&sw); /* Parse switch or host */ if (x < 0) /* Error */ goto xhttp; if (cmresult.fcode == _CMFLD) { /* Host */ s = cmresult.sresult; /* Set up expected pointer */ goto havehost; /* Go parse rest of command */ } sslswitch = 1; /* /SSL or /TLS switch - set flag */ #endif /* CK_SSL */ /* Parse host */ if ((x = cmfld("URL, hostname, or ip-address","",&s,xxstring)) < 0) { if (x == -3) { printf("?Open what?\n"); x = -9; } goto xhttp; } #ifdef CK_SSL havehost: /* Come here with s -> host */ #endif /* CK_SSL */ #ifdef CK_URL x = urlparse(s,&http_url); /* Was a URL given? */ if (x < 1) { /* Not a URL */ #endif /* CK_URL */ makestr(&http_host,s); if ((x = cmfld("Service name or port number", sslswitch ? "https" : "http",&s,xxstring)) < 0) goto xhttp; else makestr(&http_srv,s); #ifdef CK_URL } else if (ckstrcmp(http_url.svc,"http",-1,0) && /* Non-HTTP URL */ ckstrcmp(http_url.svc,"https",-1,0)) { printf("?Non-HTTP URL\n"); x = -9; goto xhttp; } else { /* Have HTTP URL */ makestr(&http_srv, http_url.svc); makestr(&http_user,http_url.usr); makestr(&http_pass,http_url.psw); makestr(&http_host,http_url.hos); if (http_url.por) makestr(&http_srv,http_url.por); makestr(&http_rfile,http_url.pth); } if (http_rfile) { /* Open, GET, and Close */ printf("?Directory/file path not allowed in HTTP OPEN URL\n"); x = -9; goto xhttp; } if (!ckstrcmp("https",http_srv,-1,0) || sslswitch || !ckstrcmp("443",http_srv,-1,0)) http_ssl = 1; #endif /* CK_URL */ break; } case HTTP_CLS: break; } if ((x = cmcfm()) < 0) goto xhttp; if (http_action == HTTP_OPN) { x = (http_open(http_host,http_srv,http_ssl,rdns,128,http_agent) == 0); if (x) { if (!quiet) { if (rdns[0]) printf("Connected to %s [%s]\r\n",http_host,rdns); else printf("Connected to %s\r\n",http_host); } if (http_agent) { if (http_d_agent) free(http_d_agent); http_d_agent = http_agent; http_agent = NULL; } if (http_user) { if (http_d_user) free(http_d_user); http_d_user = http_user; http_user = NULL; } if (http_pass) { if (http_d_pass) { memset(http_d_pass,0,strlen(http_d_pass)); free(http_d_pass); } http_d_pass = http_pass; http_pass = NULL; } http_d_type = http_type; } else { if (!quiet) printf("?HTTP Connection failed.\r\n"); } } else if (http_action == HTTP_CLS) { if (http_d_agent) { free(http_d_agent); http_d_agent = NULL; } if (http_d_user) { free(http_d_user); http_d_user = NULL; } if (http_d_pass) { memset(http_d_pass,0,strlen(http_d_pass)); free(http_d_pass); http_d_pass = NULL; } http_d_type = 0; x = (http_close() == 0); } if ((http_action != HTTP_CLS) && (http_action != HTTP_CON) && http_rfile) { /* Remote file is URL? */ /* All-in-one actions when a URL is given... */ #ifdef CK_URL if (urlparse(http_rfile,&http_url) > 0) { /* Have URL? */ if (ckstrcmp(http_url.svc,"http",-1,0) && /* It's an HTTP URL? */ ckstrcmp(http_url.svc,"https",-1,0)) { printf("?Non-HTTP URL\n"); x = -9; goto xhttp; } else { /* Yes, collect the pieces */ makestr(&http_srv, http_url.svc); makestr(&http_user,http_url.usr); makestr(&http_pass,http_url.psw); makestr(&http_host,http_url.hos); if (http_url.por) makestr(&http_srv,http_url.por); makestr(&http_rfile,http_url.pth); } if (!http_rfile) { /* Still have a path? */ makestr(&http_rfile,"/"); } if (!ckstrcmp("https",http_srv,-1,0) || /* Check for SSL/TLS */ !ckstrcmp("443",http_srv,-1,0)) http_ssl = 1; if (http_isconnected()) /* Close any open HTTP connection */ http_close(); if (http_pass == NULL && http_d_pass != NULL) makestr(&http_pass,http_d_pass); x = (http_open(http_host, http_srv,http_ssl,rdns,128,http_d_agent) == 0); if (x < 0) { x = 0; goto xhttp; } allinone = 1; } #endif /* CK_URL */ if (http_pass == NULL && http_d_pass != NULL) makestr(&http_pass,http_d_pass); if (http_action == HTTP_OPN && allinone) { http_action = HTTP_GET; } x = xdohttp(http_action, http_lfile, http_rfile, http_dfile, http_agent ? http_agent : http_d_agent, http_hdr, http_user ? http_user : http_d_user, http_pass ? http_pass : http_d_pass, http_mime, http_array, http_type ); if (allinone) x = (http_close() == 0); } xhttp: if (http_agent) free(http_agent); if (http_hdr) free(http_hdr); if (http_user) free(http_user); if (http_pass) { memset(http_pass,0,strlen(http_pass)); free(http_pass); } if (http_mime) free(http_mime); if (http_lfile) free(http_lfile); if (http_rfile) free(http_rfile); if (http_dfile) free(http_dfile); if (http_host) free(http_host); if (http_srv) free(http_srv); if (x > -1) success = x; return(x); } #endif /* TCPSOCKET */ #endif /* NOHTTP */ #ifndef NOSPL static int dotrace() { int on = 1; struct FDB sw, kw; cmfdbi(&sw, /* 1st FDB - switch */ _CMKEY, /* fcode */ "Trace object;\n Or switch", /* help */ "", /* default */ "", /* addtl string data */ 2, /* keyword table size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ onoffsw, /* Keyword table */ &kw /* Pointer to next FDB */ ); cmfdbi(&kw, /* 2nd FDB - Trace object */ _CMKEY, /* fcode */ "Trace object", /* help */ "all", /* default */ "", /* addtl string data */ ntracetab, /* keyword table size */ 0, /* addtl numeric data 2: 0 = keyword */ xxstring, /* Processing function */ tracetab, /* Keyword table */ NULL /* Pointer to next FDB */ ); if ((x = cmfdb(&sw)) < 0) return(x); if (cmresult.fdbaddr == &sw) { on = cmresult.nresult; if ((x = cmkey(tracetab, ntracetab,"","all",xxstring)) < 0) return(x); } else { x = cmresult.nresult; } if ((y = cmcfm()) < 0) return(y); switch (x) { case TRA_ASG: tra_asg = on; break; case TRA_CMD: tra_cmd = on; break; case TRA_ALL: tra_asg = on; tra_cmd = on; break; default: return(-2); } printf("TRACE %s\n", on ? "ON" : "OFF"); return(success = 1); } #endif /* NOSPL */ static int doprompt() { extern int xcmdsrc; if ((x = cmtxt("Optional message","",&s,xxstring)) < 0) return(x); #ifdef NOSPL printf("?Sorry, PROMPT requires script programming language\n"); return(-9); #else debug(F101,"Prompt cmdlvl","",cmdlvl); cmdlvl++; if (cmdlvl > CMDSTKL) { printf("?Command stack overflow: %d\n",cmdlvl); cmdlvl--; return(-9); } xcmdsrc = CMD_KB; cmdstk[cmdlvl].src = CMD_KB; /* Say we're at the prompt */ cmdstk[cmdlvl].lvl = 0; cmdstk[cmdlvl].ccflgs = cmdstk[cmdlvl-1].ccflgs; if (tra_cmd) printf("[%d] +P: \"(prompt)\"\n",cmdlvl); concb((char)escape); if (!quiet) printf( "(Recursive command prompt: Resume script with CONTINUE, STOP to stop...)\n" ); if (*s) { /* If prompt given */ makestr(&(prstring[cmdlvl-1]),cmgetp()); /* Save current prompt */ cmsetp(s); /* Set new one */ } return(success = 1); #endif /* NOSPL */ } #ifdef CKLEARN VOID #ifdef CK_ANSIC learncmd( char *s ) /* Record commands in learned script */ #else learncmd(s) char *s; #endif /* CK_ANSIC */ { char buf[64]; int i, k; if (learnfp && learning) { /* Only if open and on */ k = ckstrncpy(buf,s,64); for (i = 0; i < k; i++) { /* Get top-level command keyword */ if (buf[i] <= SP) { buf[i] = NUL; break; } } k = lookup(cmdtab,buf,ncmd,NULL); /* Look it up */ if (k == XXCON || k == XXLEARN) /* Don't record CONNECT or LEARN */ return; if (k == XXTEL) { fputs("SET HOST /NETWORK:TCP",learnfp); fputs(&s[i],learnfp); fputs(" TELNET /TELNET",learnfp); fputs("\nIF FAIL STOP 1 Connection failed\n",learnfp); } else { fputs(s,learnfp); fputs("\n",learnfp); } } } #endif /* CKLEARN */ #ifdef SSHCMD /* 2010/03/01... Reopen a connection that was made with an external ssh client after it has been closed. */ int redossh() { int x, netsave; x = nettype; debug(F111,"redossh nettype",ttname,nettype); if ((y = setlin(XXSSH,0,1)) < 0) { if (errno) printf("?%s\n",ck_errstr()); else return(y); nettype = x; /* Failed, restore net type. */ success = 0; return(y); } netsave = x; return(y); } #endif /* SSHCMD */ /* Like hmsga() in ckuus2.c but takes a single substitution parameter, s2, which replaces every occurrence of "%s" in the first argument. Added to print text containing the copyright year, so the year doesn't have to be hardwired into lots of scattered text strings. */ int /* Print an array of lines, */ #ifdef CK_ANSIC hmsgaa(char *s[], char *s2) /* pausing at end of each screen. */ #else hmsgaa(s,s2) char *s[]; char *s2; #endif /* CK_ANSIC */ { extern int hmtopline; #ifdef OS2 extern int tt_rows[], tt_cols[]; #else /* OS2 */ extern int tt_rows, tt_cols; #endif /* OS2 */ int x, y, i, j, k, n; if ((x = cmcfm()) < 0) return(x); #ifdef CK_TTGWSIZ #ifdef OS2 ttgcwsz(); #else /* OS2 */ /* Check whether window size changed */ if (ttgwsiz() > 0) { if (tt_rows > 0 && tt_cols > 0) { cmd_rows = tt_rows; cmd_cols = tt_cols; } } #endif /* OS2 */ #endif /* CK_TTGWSIZ */ printf("\n"); /* Start off with a blank line */ n = (hmtopline > 0) ? hmtopline : 1; /* Line counter */ for (i = 0; *s[i]; i++) { printf((char *)s[i],s2); /* Print a line. */ printf("\n"); y = (int)strlen(s[i]); k = 1; for (j = 0; j < y; j++) /* See how many newlines were */ if (s[i][j] == '\n') k++; /* in the string... */ n += k; if (n > (cmd_rows - 3) && *s[i+1]) { /* After a screenful, give them */ if (!askmore()) { return(0); /* a "more?" prompt. */ } else { n = 0; } } } printf("\n"); return(0); } /* I S I N T E R N A L M A C R O -- April 2017 */ #ifndef NOSPL int #ifdef CK_ANSIC isinternalmacro( int x ) /* Test if macro is internally defined */ #else isinternalmacro(x) int x; #endif /* CK_ANSIC */ { char * m; /* 7 Dec 2021: "static" added to prevent fatal "Automatic aggregate initialization is an ANSI feature" error in HP-UX 10.00. */ static char * tags[] = { "_whi", "_for", "_sw_", "_if_" }; int internal = 0; m = mactab[x].kwd; #ifdef COMMENT /* Good idea but this flag is not set for _whi2, etc */ internal = ((cmdstk[cmdlvl].ccflgs & CF_IMAC) ? 1 : 0); debug(F111,"isinternalmacro",m,internal); return(internal); #endif /* COMMENT */ debug(F101,"isinternalmacro x","",x); if (*m != '_') { debug(F110," not internal",m,0); return(0); } if (!m) m = ""; if (*m) { debug(F110," macro name",m,0); internal = ckindex(m,"|_while|_forx|_forz|_xif|_switx|",0,0,0); debug(F111," internal macro","A",internal); if (!internal) { int i, n, len = 0; n = -1; for (i = 0; i < sizeof(* tags); i++) { if (ckindex(tags[i],m,0,0,0)) { n = i; break; } } debug(F111," tags index",tags[n],n); if (n > -1) { char * tag = tags[i]; len = (int)strlen(tag); debug(F111," tag len",tag,len); for (i = len; m[i]; i++) { debug(F101," loop i","",i); debug(F000," char","",m[i]); if (!isdigit(m[i])) { internal = 0; break; } else { internal = 1; } } } debug(F101," internal macro","B",internal); } } return(internal); } #endif /* NOSPL */ /* N E W E R R M S G -- New error message routine, April 2017 */ #define ERRMSGBUFSIZ 320 static char errmsgbuf[ERRMSGBUFSIZ] = { '\0' }; VOID #ifdef CK_ANSIC newerrmsg( char * s ) #else newerrmsg(s) char *s; #endif /* CK_ANSIC */ { char * tmperrbuf[ERRMSGBUFSIZ]; extern char lasttakeline[]; extern char *tfnam[]; extern int tfblockstart[]; extern int tlevel; int len1, len2, len3, len4, len5; char * takefile = getbasename(tfnam[tlevel]); char nbuf[20]; char * lineno = nbuf; int x; debug(F110,"newerrmsg",s,0); ckstrncpy(nbuf,ckitoa(tfblockstart[tlevel]),20); lineno = (char *)nbuf; if (!s) s = ""; if (!*s) s = "Syntax error"; if (tlevel < 0) { printf("?%s\n",s); return; } len1 = (int)strlen(s); len2 = (int)strlen(takefile); len3 = (int)strlen(lineno); len4 = (int)strlen((char *)lasttakeline); len5 = len1 + len2 + len3 + 12; x = 80 - len5; /* Free space for beginning of offending command */ if (x > len4) { /* Free space is greater than command length */ #ifdef HAVE_SNPRINTF snprintf((char *)tmperrbuf,ERRMSGBUFSIZ,"?%s[%s]: \"%s\": %s\n", takefile, lineno, (char *)lasttakeline, s ); #else sprintf((char *)tmperrbuf,"?%s[%s]: \"%s\": %s\n", takefile, lineno, (char *)lasttakeline, s ); #endif /* HAVE_SNPRINTF */ } else if (x > 40) { char c; c = lasttakeline[x]; lasttakeline[x] = NUL; #ifdef HAVE_SNPRINTF snprintf((char *)tmperrbuf,ERRMSGBUFSIZ,"?%s[%s]: \"%s...\": %s\n", takefile, lineno, (char *)lasttakeline, s); #else sprintf((char *)tmperrbuf,"?%s[%s]: \"%s...\": %s\n", takefile, lineno, (char *)lasttakeline, s); #endif /* HAVE_SNPRINTF */ lasttakeline[x] = c; } else { char c; if (len4 > 74) { x = 74 - (len2 + len3 + 8); c = lasttakeline[x]; lasttakeline[x] = NUL; #ifdef HAVE_SNPRINTF snprintf((char *)tmperrbuf,ERRMSGBUFSIZ, "?%s[%s]: \"%s...\":\n Error: %s\n", takefile, lineno, (char *)lasttakeline, s); #else sprintf((char *)tmperrbuf,"?%s[%s]: \"%s...\":\n Error: %s\n", takefile, lineno, (char *)lasttakeline, s); #endif /* HAVE_SNPRINTF */ lasttakeline[x] = c; } else { #ifdef HAVE_SNPRINTF snprintf((char *)tmperrbuf,ERRMSGBUFSIZ, "?%s[%s]: \"%s\":\n %s\n", takefile, lineno, (char *)lasttakeline, s); #else sprintf((char *)tmperrbuf,"?%s[%s]: \"%s\":\n %s\n", takefile, lineno, (char *)lasttakeline, s); #endif /* HAVE_SNPRINTF */ } } /*xnewerrmsg:*/ /* Print the message only if it's not the same as the last one */ if (ckstrcmp((char *)errmsgbuf,(char *)tmperrbuf,ERRMSGBUFSIZ,1)) { ckstrncpy((char *)errmsgbuf,(char *)tmperrbuf,ERRMSGBUFSIZ); printf("%s",(char *)errmsgbuf); } return; } /* D O C M D -- Do a command */ /* Returns: -2: user typed an illegal command -1: reparse needed 0: parse was successful (even tho command may have failed). */ #ifdef DEBUG int cmdstats[256] = { -1, -1 }; #endif /* DEBUG */ int #ifdef CK_ANSIC docmd( int cx ) #else docmd(cx) int cx; #endif /* CK_ANSIC */ { extern int nolocal, cmkwflgs; debug(F101,"docmd entry, cx","",cx); activecmd = cx; doconx = ((activecmd == XXCON) || (activecmd == XXTEL) || (activecmd == XXRLOG) || (activecmd == XXPIPE) || (activecmd == XXIKSD) || (activecmd == XXPTY)); /* Originally all commands were handled with a big switch() statement, but eventually this started blowing up compilers. Now we have a series of separate if statements and small switches, with the commands that are most commonly executed in scripts and loops coming first, to speed up compute-bound scripts. */ #ifdef DEBUG if (cmdstats[0] == -1) { /* Count commands */ int i; /* for tuning... */ for (i = 0; i < 256; i++) cmdstats[i] = 0; } #endif /* DEBUG */ switch (cx) { case -4: /* EOF */ #ifdef OSK if (msgflg) printf("\n"); #else if (msgflg) printf("\r\n"); #endif /* OSK */ doexit(GOOD_EXIT,xitsta); case -3: /* Null command */ return(0); case -9: /* Like -2, but errmsg already done */ case -1: /* Reparse needed */ return(cx); case -6: /* Special */ case -2: /* Error, maybe */ #ifndef NOSPL /* Maybe they typed a macro name. Let's look it up and see. */ if (cx == -6) /* If they typed CR */ ckstrncat(cmdbuf,"\015",CMDBL); /* add it back to command buffer. */ if (ifcmd[cmdlvl] == 2) /* Watch out for IF commands. */ ifcmd[cmdlvl]--; repars = 1; /* Force reparse */ cmres(); cx = XXDO; /* Try DO command */ #else return(cx); #endif /* NOSPL */ default: if (cx < 0) return(cx); break; } #ifdef DEBUG if (cx < 256) cmdstats[cx]++; #endif /* DEBUG */ if ((cmkwflgs & CM_PSH) #ifndef NOPUSH && nopush #endif /* NOPUSH */ ) { printf("?Access to system disabled\n"); return(-9); } if ((cmkwflgs & CM_LOC) #ifndef NOLOCAL && nolocal #endif /* NOLOCAL */ ) { printf("?Connections disabled\n"); return(-9); } #ifndef NOSPL /* Used in FOR loops */ if (cx == XX_INCR || cx == XXINC || /* _INCREMENT, INCREMENT */ cx == XX_DECR || cx == XXDEC) /* _DECREMENT, DECREMENT */ return(doincr(cx)); /* Define (or change the definition of) a macro or variable */ if (cx == XXUNDEF || cx == XXUNDFX) { #ifdef IKSD if (inserver && !ENABLED(en_asg)) { printf("?Sorry, DEFINE/ASSIGN disabled\n"); return(-9); } #endif /* IKSD */ return(doundef(cx)); /* [_]UNDEFINE */ } if (cx == XXDEF || cx == XXASS || cx == XXDFX || cx == XXASX) { #ifdef IKSD if (inserver && !ENABLED(en_asg)) { printf("?Sorry, DEFINE/ASSIGN disabled\n"); return(-9); } #endif /* IKSD */ if (atmbuf[0] == '.' && !atmbuf[1]) /* "." entered as keyword */ xxdot = 1; /* i.e. with space after it... */ return(dodef(cx)); /* DEFINE, ASSIGN, etc... */ } /* IF, WHILE, and friends */ if (cx == XXIF || cx == XXIFX || cx == XXWHI || cx == XXASSER) { return(doif(cx)); } if (cx == XXSWIT) { /* SWITCH */ return(doswitch()); } /* GOTO, FORWARD, and _FORWARD (used internally by FOR, WHILE, etc) */ if (cx == XXGOTO || cx == XXFWD || cx == XXXFWD) { /* GOTO or FORWARD */ /* Note, here we don't set SUCCESS/FAILURE flag */ #ifdef COMMENT if ((y = cmfld("label","",&s,xxstring)) < 0) { if (y == -3) { if (cx != XXXFWD) { printf("?Label name required\n"); return(-9); } } else return(y); } ckstrncpy(tmpbuf,s,TMPBUFSIZ); if ((x = cmcfm()) < 0) return(x); #else if ((y = cmtxt("label","",&s,xxstring)) < 0) { if (y == -3) { if (cx != XXXFWD) { printf("?GOTO: Label name required: \"%s\" \"%s\"\n", atmbuf, cmdbuf); return(-9); } } else return(y); } ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ); #endif /* COMMENT */ s = tmpbuf; debug(F111,"GOTO target",s,cx); return(dogoto(s,cx)); } if (cx == XXDO || cx == XXMACRO) { /* DO (a macro) */ char mnamebuf[16]; /* (buffer for controlled temp name) */ struct FDB kw, fl; int mx; /* Macro index (on stack!) */ debug(F101,"XXMACRO 0",line,cx); if (cx == XXDO) { if (nmac == 0) { printf("\n?No macros defined\n"); return(-9); } for (y = 0; y < nmac; y++) { /* copy the macro table into a */ mackey[y].kwd = mactab[y].kwd; /* regular keyword table */ mackey[y].kwval = y; /* with value = pointer to macro tbl */ mackey[y].flgs = mactab[y].flgs; } cmfdbi(&kw, /* First FDB - macro name */ _CMKEY, /* fcode */ "Macro", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nmac, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: 0 = cmkey */ xxstring, /* Processing function */ mackey, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* 2nd FDB - for "{" */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); x = cmfdb(&kw); /* Parse something */ if (x < 0) { /* Error */ if (x == -3) { printf("?Macro name required\n"); return(-9); } else return(x); } if (cmresult.fcode == _CMKEY) { extern int mtchanged; char * macroname = NULL; /* In case args include an \fexec() that changes the macro table */ mx = x; /* Save macro index on stack */ mtchanged = 0; /* Mark state of macro table */ makestr(¯oname,mactab[mx].kwd); /* Save name */ /* Prior to C-Kermit 9.0.304 Dev.22, April 23, 2017, cmtxt() was called in all cases with zzstring. But this fouled up the identification of macro arguments when their values contained grouping characters such as doublequotes and braces. Now we defer the evaluation of the macro arguments until after the arguments themselves have been correctly identified. An exception is made for the internal macros that implement the FOR, WHILE, IF, and SWITCH commands. */ if (isinternalmacro(x)) { debug(F100,"DO parser internal macro","",0); if ((y = cmtxt("optional arguments","",&s,zzstring)) < 0) return(y); /* Get macro args */ } else { debug(F100,"DO parser normal macro","",0); if ((y = cmtxt("optional arguments","",&s,NULL)) < 0) return(y); /* Get macro args */ } if (mtchanged) { /* Macro table changed? */ mx = mlook(mactab,macroname,nmac); /* Look up name again */ } if (macroname) free(macroname); return(dodo(mx,s,cmdstk[cmdlvl].ccflgs) < 1 ? (success = 0) : 1); } ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* _CMFLD */ if (atmbuf[0] == '{') { if ((y = cmcfm()) < 0) return(y); } } else { /* XXMACRO ("immediate macro") */ int k = 0; line[k++] = '{'; line[k++] = SP; line[k] = NUL; debug(F111,"XXMACRO A",line,k); if ((y = cmtxt("Braced list of commands","",&s,xxstring)) < 0) return(y); k = ckstrncpy(line+k,s,LINBUFSIZ-k); debug(F111,"XXMACRO B",line,k); } x = strlen(line); if ((line[0] == '{' && line[x-1] != '}') || line[0] == '}') return(-2); if (line[0] != '{' && line[x-1] != '}') { /* Unknown command. If ON_UNKNOWN_COMMAND macro is defined, */ /* parse args and then execute it, but only if it is not */ /* already active. */ int k = -1; if (!unkmacro) { k = mxlook(mactab,"on_unknown_command",nmac); } if (k > -1) { ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ); z = maclvl; /* Save the current maclvl */ if ((y = cmtxt("text","",&s,xxstring)) < 0) return(y); ckstrncat(tmpbuf," ",TMPBUFSIZ); ckstrncat(tmpbuf,s,TMPBUFSIZ); unkmacro = 1; debug(F110,"ON_UNKNOWN_COMMAND",s,0); dodo(k,tmpbuf,cmdstk[cmdlvl].ccflgs); /* Run the macro */ while (maclvl > z) { sstate = (CHAR) parser(1); if (sstate) proto(); } debug(F101,"UNKMAC loop exit maclvl","",maclvl); unkmacro = 0; return(success); } if (x > 0) printf("?Not a command or macro name: \"%s\"\n",line); else printf("?Not a command or macro name.\n"); return(-9); } s = brstrip(line); sprintf(mnamebuf," ..tmp:%03d",cmdlvl); /* safe (16) */ x = addmac(mnamebuf,s); return(dodo(x,NULL,cmdstk[cmdlvl].ccflgs) < 1 ? (success = 0) : 1); } if (cx == XXLBL) { /* LABEL */ if ((x = cmfld("label","",&s,xxstring)) < 0) { if (x == -3) { #ifdef COMMENT printf("?LABEL: Label name required: \"%s\"\n", cmdbuf); return(-9); #else s = ""; #endif /* COMMENT */ } else return(x); } debug(F111,"LABEL",s,x); if ((x = cmcfm()) < 0) return(x); return(0); } if (cx == XXEVAL || cx == XX_EVAL) /* _EVALUATE, EVALUATE */ return(doeval(cx)); #ifndef NOSEXP if (cx == XXSEXP) { /* Lisp-like S-Expression */ struct stringarray * q; char /* *p, *r, */ *tmp, *m; int i, k, n, quote = 0, contd = 0, size = 0, len = 0; extern int sexprc, sexppv; tmp = tmpbuf; /* Buffer to collect SEXP */ tmpbuf[0] = NUL; /* Clear it */ size = TMPBUFSIZ; /* Capacity of buffer */ sexprc = -1; /* Assume bad input */ n = 0; /* Paren balance counter */ while (1) { /* Allow SEXP on multiple lines */ m = contd ? "Continuation of S-Expression" : "S-Expression (\"help sexp\" for details)"; x = cmtxt(m,"",&s,xxstring); if (x < 0) return(x); if (!*s) /* Needed for (=) and (:) */ s = cmdbuf+1; /* I can't explain why. */ k = ckmakmsg(tmp, size, contd ? " " : "(", s, NULL, NULL); if (k < 1) { printf("?SEXP too long - %d max\n",TMPBUFSIZ); return(-9); } debug(F111,contd ? "sexp contd" : "sexp",s,k); for (i = len; i < len+k; i++) { /* Check balance */ if (!quote && tmpbuf[i] == CMDQ) { quote = 1; continue; } if (quote) { quote = 0; continue; } if (tmpbuf[i] == '(') n++; else if (tmpbuf[i] == ')') n--; } if (n == 0) { /* Break when balanced */ break; } if (n < 0) { /* Too many right parens */ printf("?Unbalanced S-Expression: \"%s\"\n",tmpbuf); return(-9); } contd++; /* Need more right parens */ cmini(ckxech); /* so keep parsing */ tmp += k; /* adjust buffer pointer */ size -= k; /* and capacity */ len += k; /* and length so far */ } s = tmpbuf; makestr(&lastsexp,s); q = cksplit(1,SEXPMAX,s,NULL,NULL,8,0,0,0); /* Precheck for > 1 SEXP */ debug(F101,"sexp split","",q->a_size); if (q->a_size == 1) { /* We should get exactly one back */ char * result; sexprc = 0; /* Reset out-of-band return code */ result = dosexp(s); /* Get result */ debug(F111,"sexp result",result,sexprc); if (sexprc == 0) { /* Success */ /* Echo the result if desired */ if ((!xcmdsrc && sexpecho != SET_OFF) || sexpecho == SET_ON) if (result) if (*result) printf(" %s\n",result); makestr(&sexpval,result); success = sexppv > -1 ? sexppv : 1; return(success); } } if (sexprc < 0) printf("?Invalid S-Expression: \"%s\"\n",lastsexp); return(-9); } #endif /* NOSEXP */ #endif /* NOSPL */ if (cx == XXECH || cx == XXXECH || cx == XXVOID #ifndef NOSPL || cx == XXAPC #endif /* NOSPL */ ) { /* ECHO or APC */ if ((x = cmtxt((cx == XXECH || cx == XXXECH) ? "Text to be echoed" : ((cx == XXVOID) ? "Text" : "Application Program Command text"), "", &s, xxstring ) ) < 0) return(x); if (!s) s = ""; #ifdef COMMENT /* This is to preserve the pre-8.0 behavior but it's too confusing */ x = strlen(s); x = (x > 1) ? ((s[0] == '"' && s[x-1] == '"') ? 1 : 0) : 0; #endif /* COMMENT */ s = brstrip(s); /* Strip braces and doublequotes */ if (cx == XXECH) { /* ECHO */ #ifndef NOSPL if (!fndiags || fnsuccess) { #endif /* NOSPL */ #ifdef COMMENT /* The "if (x)" business preserves previous behavior */ /* by putting back the doublequotes if they were included. */ if (x) printf("\"%s\"\n",s); else #endif /* COMMENT */ printf("%s\n",s); #ifndef NOSPL } #endif /* NOSPL */ } else if (cx == XXXECH) { /* XECHO */ if (x) printf("\"%s\"",s); else printf("%s",s); #ifdef UNIX fflush(stdout); #endif /* UNIX */ } else if (cx == XXAPC) { /* APC */ #ifdef CK_APC if (apcactive == APC_LOCAL || (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH))) return(success = 0); #endif /* CK_APC */ if (!local) { printf("%c_%s%c\\",ESC,s,ESC); #ifdef UNIX fflush(stdout); #endif /* UNIX */ } else { /* Local mode - have connection */ #ifndef NOSPL if (ckmakxmsg(tmpbuf, /* Form APC string in buffer */ TMPBUFSIZ, ckctoa((char)ESC), ckctoa('_'), s, ckctoa((char)ESC), ckctoa('\\'), NULL,NULL,NULL,NULL,NULL,NULL,NULL ) > 0) return(success = dooutput(tmpbuf, XXOUT)); printf("?Too long\n"); return(-9); #else printf("%c_%s%c\\",ESC,s,ESC); #endif /* NOSPL */ } } return(success = 1); } #ifndef NOSPL /* Copy macro args from/to two levels up, used internally by _floop et al. */ if (cx == XXGTA || cx == XXPTA) { /* _GETARGS, _PUTARGS */ int x; debug(F101,"docmd XXGTA","",XXGTA); debug(F101,"docmd cx","",cx); debug(F101,"docmd XXGTA maclvl","",maclvl); x = dogta(cx); debug(F101,"docmd dogta returns","",x); debug(F101,"docmd dogta maclvl","",maclvl); return(x); } #endif /* NOSPL */ #ifndef NOSPL #ifdef CKCHANNELIO if (cx == XXFILE) return(dofile(cx)); else if (cx == XXF_RE || cx == XXF_WR || cx == XXF_OP || cx == XXF_CL || cx == XXF_SE || cx == XXF_RW || cx == XXF_FL || cx == XXF_LI || cx == XXF_ST || cx == XXF_CO) return(dofile(cx)); #endif /* CKCHANNELIO */ /* ASK, ASKQ, READ */ if (cx == XXASK || cx == XXASKQ || cx == XXREA || cx == XXRDBL || cx == XXGETC || cx == XXGETK) { return(doask(cx)); } #endif /* NOSPL */ #ifndef NOFRILLS #ifndef NOHELP if (cx == XXBUG) { /* BUG */ if ((x = cmcfm()) < 0) return(x); return(dobug()); } #endif /* NOHELP */ #endif /* NOFRILLS */ #ifndef NOXFER if (cx == XXBYE) { /* BYE */ extern int ftp_cmdlin; if ((x = cmcfm()) < 0) return(x); #ifdef NEWFTP if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) { extern int stayflg, ftp_fai; success = ftpbye(); if (ftp_cmdlin && !stayflg && !local) doexit(ftp_fai ? BAD_EXIT : GOOD_EXIT,-1); else return(success); } #endif /* NEWFTP */ if (!local) { printf("?No connection - use EXIT to quit.\n"); return(-9); } #ifdef CK_XYZ if (protocol != PROTO_K) { printf("?Sorry, BYE only works with Kermit protocol\n"); return(-9); } #endif /* CK_XYZ */ #ifdef IKS_OPTION if ( #ifdef CK_XYZ protocol == PROTO_K && #endif /* CK_XYZ */ !iks_wait(KERMIT_REQ_START,1)) { printf( "?A Kermit Server is not available to process this command\n"); return(-9); /* Correct the return code */ } #endif /* IKS_OPTION */ bye_active = 1; sstate = setgen('L',"","",""); if (local) ttflui(); /* If local, flush tty input buffer */ return(0); } #endif /* NOXFER */ if (cx == XXBEEP) { /* BEEP */ int x; #ifdef OS2 int y; if ((y = cmkey(beeptab, nbeeptab, "which kind of beep", "information", xxstring)) < 0 ) return (y); if ((x = cmcfm()) < 0) return(x); bleep((short)y); /* y is one of the BP_ values */ #else /* OS2 */ if ((x = cmcfm()) < 0) return(x); #ifndef NOSPL bleep(BP_NOTE); #else putchar('\07'); #endif /* NOSPL */ #endif /* OS2 */ return(0); } #ifndef NOFRILLS if (cx == XXCLE) /* CLEAR */ return(success = doclear()); #endif /* NOFRILLS */ if (cx == XXCOM) { /* COMMENT */ if ((x = cmtxt("Text of comment line","",&s,NULL)) < 0) return(x); /* Don't change SUCCESS flag for this one */ return(0); } #ifndef NOLOCAL if (cx == XXCON || cx == XXCQ) /* CONNECT or CONNECT /QUIETLY */ return(doxconn(cx)); #endif /* NOLOCAL */ #ifndef NOFRILLS #ifdef ZCOPY if (cx == XXCPY) { /* COPY a file */ #ifdef IKSD if (inserver && !ENABLED(en_cpy)) { printf("?Sorry, COPY is disabled\n"); return(-9); } #endif /* IKSD */ #ifdef CK_APC if (apcactive == APC_LOCAL || (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)) ) return(success = 0); #endif /* CK_APC */ return(docopy()); } #endif /* ZCOPY */ #ifdef NT if ( cx == XXLINK ) { #ifdef IKSD if (inserver && !ENABLED(en_cpy)) { printf("?Sorry, LINK (COPY) is disabled\n"); return(-9); } #endif /* IKSD */ #ifdef CK_APC if (apcactive == APC_LOCAL || (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)) ) return(success = 0); #endif /* CK_APC */ return(dolink()); } #endif /* NT */ #endif /* NOFRILLS */ /* CD and friends */ if (cx == XXCWD || cx == XXCDUP || cx == XXBACK || cx == XXLCWD || cx == XXLCDU || cx == XXKCD) { #ifdef LOCUS if (!locus) { if (cx == XXCWD) { #ifdef NOXFER return(-2); #else return(dormt(XZCWD)); #endif /* NOXFER */ } else if (cx == XXCDUP) { #ifdef NOXFER return(-2); #else return(dormt(XZCDU)); #endif /* NOXFER */ } } #endif /* LOCUS */ #ifdef IKSD if (inserver && !ENABLED(en_cwd)) { printf("?Sorry, changing directories is disabled\n"); return(-9); } #endif /* IKSD */ return(success = docd(cx)); } if (cx == XXCHK) /* CHECK */ return(success = dochk()); if (cx == XXCLO) { /* CLOSE */ x = cmkey(clstab,ncls,"\"CONNECTION\", or log or file to close", "connection",xxstring); if (x == -3) { printf("?You must say which file or log\n"); return(-9); } if (x < 0) return(x); if ((y = cmcfm()) < 0) return(y); #ifndef NOLOCAL if (x == 9999) { /* CLOSE CONNECTION */ x = clsconnx(0); switch (x) { case 0: if (msgflg) printf("?Connection was not open\n"); case -1: return(0); case 1: whyclosed = WC_CLOS; return(1); } return(0); } #endif /* NOLOCAL */ y = doclslog(x); success = (y == 1); return(success); } #ifndef NOSPL if (cx == XXDCL || cx == XXUNDCL) { /* DECLARE an array */ return(dodcl(cx)); } #endif /* NOSPL */ #ifndef NODIAL if (cx == XXRED || cx == XXDIAL || cx == XXPDIA || cx == XXANSW || cx == XXLOOK) { /* DIAL, REDIAL etc */ #ifdef VMS extern int batch; #else #ifdef UNIXOROSK extern int backgrd; #endif /* UNIXOROSK */ #endif /* VMS */ x = dodial(cx); debug(F101,"dodial returns","",x); if ((cx == XXDIAL || cx == XXRED || cx == XXANSW) && (x > 0) && /* If DIAL or REDIAL succeeded */ (dialsta != DIA_PART) && /* and it wasn't partial */ (dialcon > 0)) { if ((dialcon == 1 || /* And DIAL CONNECT is ON, */ ((dialcon == 2) && /* or DIAL CONNECT is AUTO */ !xcmdsrc /* and we're at top level... */ #ifdef VMS && !batch /* Not if running from batch */ #else #ifdef UNIXOROSK && !backgrd /* Not if running in background */ #endif /* UNIXOROSK */ #endif /* VMS */ ))) /* Or AUTO */ x = doconect(dialcq, /* Then also CONNECT */ cmdlvl == 0 ? 1 : 0 ); if (ttchk() < 0) dologend(); } return(success = x); } #endif /* NODIAL */ #ifndef NOPUSH #ifdef CK_REXX if (cx == XXREXX) { /* REXX */ extern int nopush; if ( nopush ) return(success=0); return(dorexx()); } #endif /* CK_REXX */ #endif /* NOPUSH */ #ifndef NOFRILLS if (cx == XXDEL || cx == XXLDEL) { /* DELETE */ #ifdef LOCUS if (!locus && cx != XXLDEL) { #ifdef NOXFER return(-2); #else return(dormt(XZDEL)); #endif /* NOXFER */ } #endif /* LOCUS */ #ifdef IKSD if (inserver && (!ENABLED(en_del) #ifdef CK_LOGIN || isguest #endif /* CK_LOGIN */ )) { printf("?Sorry, DELETE is disabled\n"); return(-9); } #endif /* IKSD */ #ifdef CK_APC if ((apcactive == APC_LOCAL) || ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH)))) return(success = 0); #endif /* CK_APC */ return(dodel()); } #endif /* NOFRILLS */ if (cx == XXTOUC) /* TOUCH */ return(dodir(cx)); if (cx == XXCHG) /* CHANGE */ return(dodir(cx)); /* DIRECTORY commands */ if (cx == XXDIR || cx == XXLS || cx == XXLDIR || cx == XXWDIR || cx == XXHDIR) { #ifdef LOCUS if (!locus && cx != XXLDIR) { #ifdef NOXFER return(-2); #else return(dormt(XZDIR)); #endif /* NOXFER */ } #endif /* LOCUS */ #ifdef IKSD if (inserver && !ENABLED(en_dir)) { printf("?Sorry, DIRECTORY is disabled\n"); return(-9); } #endif /* IKSD */ return(dodir(cx)); } #ifndef NOSPL if (cx == XXELS) /* ELSE */ return(doelse()); #endif /* NOSPL */ #ifndef NOSERVER #ifndef NOFRILLS if (cx == XXENA || cx == XXDIS) { /* ENABLE, DISABLE */ s = (cx == XXENA) ? "Server function to enable" : "Server function to disable"; if ((x = cmkey(enatab,nena,s,"",xxstring)) < 0) { if (x == -3) { printf("?Name of server function required\n"); return(-9); } else return(x); } if ((y = cmkey(kmstab,3,"mode","both",xxstring)) < 0) { if (y == -3) { printf("?Please specify remote, local, or both\n"); return(-9); } else return(y); } if (cx == XXDIS) /* Disabling, not enabling */ y = 3 - y; if ((z = cmcfm()) < 0) return(z); #ifdef CK_APC if ((apcactive == APC_LOCAL) || ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH)))) return(success = 0); #endif /* CK_APC */ #ifdef IKSD /* This may seem like it duplicates the work in doenable() */ /* but this code returns failure whereas doenable() returns */ /* success. */ if (inserver && #ifdef IKSDCONF iksdcf && #endif /* IKSDCONF */ (x == EN_HOS || x == EN_PRI || x == EN_MAI || x == EN_WHO #ifdef CK_LOGIN || isguest #endif /* CK_LOGIN */ )) return(success = 0); #endif /* IKSD */ return(doenable(y,x)); } #endif /* NOFRILLS */ #endif /* NOSERVER */ #ifndef NOSPL if (cx == XXRET) { /* RETURN */ if ((x = cmtxt("Optional return value","",&s,NULL)) < 0) return(x); s = brstrip(s); /* Strip braces */ if (cmdlvl == 0) /* At top level, nothing happens... */ return(success = 1); switch (cmdstk[cmdlvl].src) { /* Action depends on command source */ case CMD_TF: /* Command file */ popclvl(); /* Pop command level */ return(success = 1); /* always succeeds */ case CMD_MD: /* Macro */ case CMD_KB: /* Prompt */ return(doreturn(s)); /* Trailing text is return value. */ default: /* Shouldn't happen */ return(-2); } } #endif /* NOSPL */ #ifndef NOSPL if (cx == XXOPE) /* OPEN */ return(doopen()); #endif /* NOSPL */ #ifndef NOSPL if (cx == XXOUT || cx == XXLNOUT) { /* OUTPUT or LINEOUT */ if ((x = cmtxt("Text to be output","",&s,NULL)) < 0) return(x); #ifdef CK_APC if ((apcactive == APC_LOCAL) || ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH)))) return(success = 0); #endif /* CK_APC */ debug(F110,"OUTPUT 1",s,0); s = brstrip(s); /* Strip enclosing braces, */ debug(F110,"OUTPUT 2",s,0); /* I don't think I could ever fully explain this in a million years... We have read the user's string without calling the variable-expander function. Now, before we call it, we have to double backslashes that appear before \N, \B, \L, and \ itself, so the expander function will reduce them back to single backslashes, so when we call dooutput()... But it's more complicated than that. */ if (cmdgquo()) { /* Only if COMMAND QUOTING ON ... */ for (x = 0, y = 0; s[x]; x++, y++) { if (s[x] == CMDQ) { char c = s[x+1]; if (c == 'n' || c == 'N' || c == 'b' || c == 'B' || c == 'l' || c == 'L' || c == CMDQ) line[y++] = CMDQ; } line[y] = s[x]; } line[y++] = '\0'; /* Now expand variables, etc. */ debug(F110,"OUTPUT 3",line,0); s = line+y+1; x = LINBUFSIZ - (int) strlen(line) - 1; debug(F101,"OUTPUT size","",x); if (zzstring(line,&s,&x) < 0) return(success = 0); s = line+y+1; debug(F110,"OUTPUT 4",s,0); } success = dooutput(s,cx); return(success); } #endif /* NOSPL */ #ifdef ANYX25 #ifndef IBMX25 if (cx == XXPAD) { /* PAD commands */ x = cmkey(padtab,npadc,"PAD command","",xxstring); if (x == -3) { printf("?You must specify a PAD command to execute\n"); return(-9); } if (x < 0) return(x); switch (x) { case XYPADL: if (x25stat() < 0) printf("Sorry, you must 'set network' & 'set host' first\r\n"); else { x25clear(); initpad(); } break; case XYPADS: if (x25stat() < 0) printf("Not connected\r\n"); else { extern int linkid, lcn; conol("Connected thru "); conol(ttname); printf(", Link id %d, Logical channel number %d\r\n", linkid,lcn); } break; case XYPADR: if (x25stat() < 0) printf("Sorry, you must 'set network' & 'set host' first\r\n"); else x25reset(0,0); break; case XYPADI: if (x25stat() < 0) printf("Sorry, you must 'set network' & 'set host' first\r\n"); else x25intr(0); } return(0); } #endif /* IBMX25 */ #endif /* ANYX25 */ #ifndef NOSPL if (cx == XXPAU || cx == XXWAI || cx == XXMSL) /* PAUSE, WAIT, etc */ return(dopaus(cx)); #endif /* NOSPL */ #ifndef NOFRILLS if (cx == XXPRI) { #ifdef IKSD #ifdef CK_LOGIN if (inserver && (isguest || !ENABLED(en_pri))) { printf("?Sorry, printing is disabled\n"); return(-9); } #endif /* CK_LOGIN */ #endif /* IKSD */ if ((x = cmifi("File to print","",&s,&y,xxstring)) < 0) { if (x == -3) { printf("?A file specification is required\n"); return(-9); } else return(x); } if (y != 0) { printf("?Wildcards not allowed\n"); return(-9); } ckstrncpy(line,s,LINBUFSIZ); s = ""; #ifndef NT if ((x = cmtxt("Local print command options, or carriage return","",&s, xxstring)) < 0) return(x); #endif /* NT */ if ((x = cmcfm()) < 0) return(x); return(success = (zprint(s,line) == 0) ? 1 : 0); } #endif /* NOFRILLS */ #ifdef TCPSOCKET #ifndef NOPUSH if (cx == XXPNG) /* PING an IP host */ return(doping()); #endif /* NOPUSH */ #ifndef NOFTP if (cx == XXFTP) /* FTP */ #ifdef SYSFTP #ifndef NOPUSH return(doftp()); /* Just runs system's ftp program */ #else return(-2); #endif /* NOPUSH */ #else return(doxftp()); #endif /* SYSFTP */ #endif /* NOFTP */ #endif /* TCPSOCKET */ if (cx == XXPWD || cx == XXLPWD) { /* PWD */ #ifdef OS2 char *pwp; #endif /* OS2 */ if ((x = cmcfm()) < 0) return(x); #ifdef LOCUS if (!locus && cx != XXLPWD) { #ifdef NOXFER return(-2); #else return(dormt(XZPWD)); #endif /* NOXFER */ } #endif /* LOCUS */ #ifndef MAC #ifndef OS2 #ifdef UNIX printf("%s\n",zgtdir()); #else xsystem(PWDCMD); #endif /* UNIX */ return(success = 1); /* Blind faith */ #else /* OS2 */ if (pwp = zgtdir()) { if (*pwp) { #ifdef NT line[0] = NUL; ckGetLongPathName(pwp,line,LINBUFSIZ); line[LINBUFSIZ-1] = NUL; tmpbuf[0] = NUL; ckGetShortPathName(pwp,tmpbuf,TMPBUFSIZ); tmpbuf[TMPBUFSIZ-1] = NUL; pwp = line; if (!strcmp(line,tmpbuf)) { #endif /* NT */ printf("%s\n",pwp); #ifdef NT } else { printf(" Long name: %s\n",line); printf(" Short name: %s\n",tmpbuf); } #endif /* NT */ } return(success = ((int)strlen(pwp) > 0)); } else return(success = 0); #endif /* OS2 */ #else /* MAC */ if (pwp = zgtdir()) { printf("%s\n",pwp); return(success = ((int)strlen(pwp) > 0)); } else return(success = 0); #endif /* MAC */ } if (cx == XXQUI || cx == XXEXI) { /* EXIT, QUIT */ extern int quitting; if ((y = cmnum("exit status code",ckitoa(xitsta),10,&x,xxstring)) < 0) return(y); if ((y = cmtxt("Optional EXIT message","",&s,xxstring)) < 0) return(y); s = brstrip(s); ckstrncpy(line,s,LINBUFSIZ); if (!hupok(0)) /* Check if connection still open */ return(success = 0); if (line[0]) { /* Print EXIT message if given */ extern int exitmsg; switch (exitmsg) { case 0: break; case 1: printf("%s\n",(char *)line); break; case 2: fprintf(stderr,"%s\n",(char *)line); break; } } quitting = 1; /* Flag that we are quitting. */ #ifdef VMS doexit(GOOD_EXIT,x); #else #ifdef OSK /* Returning any codes here makes the OS-9 shell print an error message. */ doexit(GOOD_EXIT,-1); #else #ifdef datageneral doexit(GOOD_EXIT,x); #else doexit(x,-1); #endif /* datageneral */ #endif /* OSK */ #endif /* VMS */ } #ifndef NOXFER #ifndef NOFRILLS if (cx == XXERR) { /* ERROR */ #ifdef CK_XYZ if (protocol != PROTO_K) { printf("Sorry, E-PACKET only works with Kermit protocol\n"); return(-9); } #endif /* CK_XYZ */ if ((x = cmcfm()) < 0) return(x); ttflui(); epktflg = 1; sstate = 'a'; return(0); } #endif /* NOFRILLS */ if (cx == XXFIN) { /* FINISH */ #ifdef NEWFTP if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) return(ftpbye()); #endif /* NEWFTP */ #ifdef CK_XYZ if (protocol != PROTO_K) { printf("Sorry, FINISH only works with Kermit protocol\n"); return(-9); } #endif /* CK_XYZ */ if ((x = cmcfm()) < 0) return(x); #ifdef IKS_OPTION if ( #ifdef CK_XYZ protocol == PROTO_K && #endif /* CK_XYZ */ !iks_wait(KERMIT_REQ_START,1)) { printf( "?A Kermit Server is not available to process this command\n"); return(-9); /* Correct the return code */ } #endif /* IKS_OPTION */ sstate = setgen('F',"","",""); if (local) ttflui(); /* If local, flush tty input buffer */ return(0); } #endif /* NOXFER */ #ifndef NOSPL if (cx == XXFOR) /* FOR loop */ return(dofor()); #endif /* NOSPL */ #ifndef NOXFER /* GET MGET REGET RETRIEVE etc */ if (cx == XXGET || cx == XXMGET || cx == XXREGET || cx == XXRETR) { #ifdef IKSD if (inserver && !ENABLED(en_sen)) { printf("?Sorry, reception of files is disabled\n"); return(-9); } #endif /* IKSD */ return(doxget(cx)); } #endif /* NOXFER */ #ifndef NOSPL #ifndef NOFRILLS if (cx == XXGOK) { /* GETOK */ return(success = doask(cx)); } #endif /* NOFRILLS */ #endif /* NOSPL */ if (cx == XXHLP) { /* HELP */ #ifdef NOHELP return(dohlp(XXHLP)); #else x = cmkey2(cmdtab, ncmd,"\nCommand or topic","help",toktab,xxstring,1+2+8); debug(F111,"HELP command x",cmdbuf,x); if (x == -5) { y = chktok(toktab); debug(F101,"HELP cmkey token","",y); /* ungword(); */ switch (y) { #ifndef NOPUSH case '!': case '@': x = XXSHE; break; case '<': x = XXFUN; break; #endif /* NOPUSH */ case '#': x = XXCOM; break; case ';': x = XXCOM; break; #ifndef NOSPL case '.': x = XXDEF; break; case ':': x = XXLBL; break; #ifndef NOSEXP case '(': x = XXSEXP; break; #endif /* NOSEXP */ #endif /* NOSPL */ #ifdef CK_RECALL case '^': x = XXREDO; break; #endif /* CK_RECALL */ default: printf("\n?Not a valid command or token - %s\n",cmdbuf); x = -2; } } makestr(&hlptok,atmbuf); debug(F111,"HELP token",hlptok,x); return(dohlp(x)); #endif /* NOHELP */ } #ifndef NOHELP if (cx == XXINT) /* INTRO */ return(hmsga(introtxt)); if (cx == XXNEW) { /* NEWS */ int x; extern char * k_info_dir; x = hmsga(newstxt); return(x); } #ifdef OS2ONLY if (cx == XXUPD) { /* View UPDATE file */ extern char exedir[]; char * pTopic; char updstr[2048]; if ((x = cmtxt("topic name","",&pTopic,xxstring)) < 0) return x; #ifdef COMMENT sprintf(updstr, "start view %s\\docs\\k2.inf+%s\\docs\\using_ck.inf+\ %s\\docs\\dialing.inf+%s\\docs\\modems.inf %s", exedir,exedir,exedir,exedir,pTopic ); #else if (ckmakxmsg(updstr, 2048, "start view ", exedir, "\\docs\\k2.inf+", exedir, "\\docs\\using_ck.inf+", exedir, "\\docs\\dialing.inf+", exedir, "\\docs\\modems.inf ", pTopic, NULL, NULL ) > 0) #endif /* COMMENT */ system(updstr); return(success = 1); } #endif /* OS2ONLY */ #endif /* NOHELP */ #ifndef NOLOCAL if (cx == XXHAN) { /* HANGUP */ if ((x = cmcfm()) < 0) return(x); #ifdef NEWFTP if ((ftpget == 1) || ((ftpget == 2) && !local && ftpisopen())) return(success = ftpbye()); #endif /* NEWFTP */ #ifndef NODIAL if ((x = mdmhup()) < 1) { debug(F101,"HANGUP mdmup","",x); #endif /* NODIAL */ x = tthang(); debug(F101,"HANGUP tthang","",x); x = (x > -1); #ifndef NODIAL } dialsta = DIA_UNK; #endif /* NODIAL */ whyclosed = WC_CLOS; ttchk(); /* In case of CLOSE-ON-DISCONNECT */ dologend(); #ifdef OS2 if (x) DialerSend(OPT_KERMIT_HANGUP, 0); #endif /* OS2 */ if (x) haveline = 0; return(success = x); } #endif /* NOLOCAL */ #ifndef NOSPL /* INPUT, REINPUT, and MINPUT */ if (cx == XXINP || cx == XXREI || cx == XXMINP) { long zz; int flags = 0, incount = 0; extern int itsapattern, isjoin, isinbuflen; int c, getval; struct FDB sw, nu, fl; int fc, havetime = 0; char * m; if (cx == XXREI) { m = "Timeout in seconds (ignored)"; } else { m = "Seconds to wait for input,\n or time of day hh:mm:ss,\ or switch"; } cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ m, /* helpmsg */ ckitoa(indef), /* default */ "", /* addtl string data */ ninputsw, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ inputsw, /* Keyword table */ &nu /* Pointer to next FDB */ ); cmfdbi(&nu, _CMNUM, /* Number */ m, /* Help message */ ckitoa(indef), /* default */ "", /* N/A */ 10, /* Radix = 10 */ 0, /* N/A */ xxstring, /* Processing function */ NULL, /* N/A */ &fl /* Next */ ); cmfdbi(&fl, /* Time of day hh:mm:ss */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); fc = (cx == XXREI) ? cmfdb(&nu) : cmfdb(&sw); /* Parse something */ for (y = 0; y < MINPMAX; y++) { /* Initialize search strings */ mp[y] = 0; /* Assume it's not a pattern */ if (!mpinited) { ms[y] = NULL; } if (ms[y]) { free(ms[y]); /* Free old strings, if any */ ms[y] = NULL; } } mpinited = 1; while (!havetime) { if (fc < 0) { /* Error */ if (fc == -3) { printf("?Syntax error in INPUT-class command\n"); return(-9); } else return(fc); } switch (cmresult.fcode) { case _CMKEY: /* Switch */ c = cmgbrk(); if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } if (getval && cmresult.nresult == INPSW_COU) { if ((y = cmnum("Number of bytes to read", "",10,&x,xxstring)) < 0) return(y); incount = x; } flags |= cmresult.nresult; fc = cmfdb(&sw); /* Maybe parse more switches */ continue; case _CMNUM: /* Seconds to time out */ x = cmresult.nresult; #ifdef CKFLOAT if (inscale != 1.0) /* Scale */ x *= inscale; #endif /* CKFLOAT */ havetime++; break; case _CMFLD: zz = tod2sec(atmbuf); /* Convert to secs since midnight */ if (zz < 0L) { printf("?Number, expression, or time of day required\n"); return(-9); } else { char now[32]; /* Current time */ char *p; long tnow; p = now; ztime(&p); tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17); if (zz < tnow) /* User's time before now */ zz += 86400L; /* So make it tomorrow */ zz -= tnow; /* Seconds from now. */ if (zz > -1L) { x = zz; if (zz != (long) x) { printf( "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n" ); return(-9); } } havetime++; } break; default: printf("?Internal error\n"); return(-9); } } /* Now parse the search text */ #ifdef CK_MINPUT if (cx == XXMINP) { /* MINPUT */ int i, k = 0, n = 0; struct stringarray * q; keepallchars = 1; while (k < MINPMAX) { if ((y = cmfld("String or pattern","",&s,xxstring)) < 0) { if (y == -3) { if ((y = cmcfm()) < 0) return(y); break; } else { return(y); } } debug(F111,"MINPUT field",s,k); if (isjoin) { if ((q = cksplit(1,0,s," ",(char *)c1chars,3,0,0,0))) { char ** ap = q->a_head; n = q->a_size; debug(F101,"minput cksplit size","",n); for (i = 1; i <= n && k < MINPMAX; i++) { if (!ap[i]) /* Add non-empty elements */ continue; if (!*(ap[i])) continue; makestr(&(ms[k]),ap[i]); debug(F111,"MINPUT JOIN",ms[k],k); k++; } } } else { if (s) if (*s) { makestr(&(ms[k]),brstrip(s)); if (itsapattern) mp[k] = 1; debug(F111,"MINPUT",ms[k],itsapattern); k++; } } } keepallchars = 0; } else { #endif /* CK_MINPUT */ /* INPUT or REINPUT */ if (flags & INPSW_COU) { if ((y = cmcfm()) < 0) return(y); } else { if ((y = cmtxt("Material to be input","",&s,xxstring)) < 0) return(y); } mp[0] = itsapattern ? 1 : 0; makestr(&(ms[0]),brstrip(s)); ms[1] = NULL; #ifdef CK_MINPUT } #endif /* CK_MINPUT */ if (incount > 0) /* No searching if /COUNT: given */ makestr(&(ms[0]),NULL); if (cx == XXINP || cx == XXMINP) { /* Not REINPUT... */ i_active = 1; /* Go try to input the search string */ success = doinput(x,ms,mp,flags,incount); i_active = 0; } else { /* REINPUT */ success = doreinp(x,ms[0],itsapattern); } if (intime[cmdlvl] && !success) { /* TIMEOUT-ACTION = QUIT? */ popclvl(); /* If so, pop command level. */ if (pflag && cmdlvl == 0) { if (cx == XXINP) printf("?INPUT timed out\n"); if (cx == XXMINP) printf("?MINPUT timed out\n"); if (cx == XXREI) printf("?REINPUT failed\n"); } } return(success); /* Return do(re)input's return code */ } #endif /* NOSPL */ if (cx == XXLOG) { /* LOG */ x = cmkey(logtab,nlog,"What to log","",xxstring); if (x == -3) { printf("?Type of log required\n"); return(-9); } if (x < 0) return(x); x = dolog(x); if (x < 0) return(x); else return(success = x); } if (cx == XXLOGIN) { /* (REMOTE) LOGIN */ #ifdef NEWFTP if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) return(success = doftpusr()); #endif /* NEWFTP */ #ifdef IKSD if (inserver) { printf("?Already logged in\n"); return(-9); } else #endif /* IKSD */ { #ifdef NOXFER return(-2); #else return(dormt(XZLGI)); #endif /* NOXFER */ } } if (cx == XXLOGOUT) { /* (REMOTE) LOGOUT */ #ifdef NEWFTP if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) return(success = doftpres()); #endif /* NEWFTP */ #ifdef IKSD if (inserver) { if ((x = cmcfm()) < 0) return(x); doexit(GOOD_EXIT,xitsta); } else #endif /* IKSD */ if (!local || (network && ttchk() < 0)) { printf("?No connection.\n"); return(-9); } else { #ifdef NOXFER return(-2); #else return(dormt(XZLGO)); #endif /* NOXFER */ } } #ifndef NOSCRIPT if (cx == XXLOGI) { /* UUCP-style script */ if ((x = cmtxt("expect-send expect-send ...","",&s,xxstring)) < 0) return(x); #ifdef CK_APC if ((apcactive == APC_LOCAL) || ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH)))) return(success = 0); #endif /* CK_APC */ #ifdef VMS conres(); /* For Ctrl-C to work... */ #endif /* VMS */ return(success = dologin(s)); /* Return 1=completed, 0=failed */ } #endif /* NOSCRIPT */ #ifndef NOXFER #ifdef PIPESEND if (cx == XXCREC) { /* CRECEIVE */ if (protocol != PROTO_K) { printf("?Sorry, CRECEIVE works only with Kermit protocol\n"); return(-9); } else return(doxget(cx)); } if (cx == XXCGET) { /* CGET */ return(doxget(cx)); } #endif /* PIPESEND */ if (cx == XXREC) /* RECEIVE */ return(doxget(cx)); #endif /* NOXFER */ #ifndef NOXFER if (cx == XXREM) { /* REMOTE */ #ifdef NEWFTP if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) return(doftprmt(0,0)); #endif /* NEWFTP */ #ifdef CK_XYZ if (protocol != PROTO_K) { printf("Sorry, REMOTE commands only work with Kermit protocol\n"); return(-9); } #endif /* CK_XYZ */ x = cmkey(remcmd,nrmt,"Remote Kermit server command","",xxstring); if (x == -3) { printf("?You must specify a command for the remote server\n"); return(-9); } return(dormt(x)); } #endif /* NOXFER */ #ifndef NORENAME #ifndef NOFRILLS if (cx == XXREN || cx == XXLREN) { /* RENAME */ #ifdef LOCUS if (!locus && cx != XXLREN) { #ifdef NOXFER return(-2); #else return(dormt(XZREN)); #endif /* NOXFER */ } #endif /* LOCUS */ #ifdef IKSD if (inserver && (!ENABLED(en_ren) #ifdef CK_LOGIN || isguest #endif /* CK_LOGIN */ )) { printf("?Sorry, renaming of files is disabled\n"); return(-9); } #endif /* IKSD */ #ifdef CK_APC if ((apcactive == APC_LOCAL) || ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH)))) return(success = 0); #endif /* CK_APC */ return(dorenam()); } #endif /* NOFRILLS */ #endif /* NORENAME */ if (cx == XXEIGHT) { /* EIGHTBIT */ extern int parity, cmask, cmdmsk; if ((x = cmcfm()) < 0) return(x); parity = 0; cmask = 0xff; cmdmsk = 0xff; return(success = 1); } #ifndef NOXFER /* SEND, CSEND, MOVE, MAIL, and RESEND use the new common code */ if (cx == XXSEN /* SEND */ #ifdef PIPESEND || cx == XXCSEN /* CSEND */ #endif /* PIPESEND */ || cx == XXMOVE /* MOVE */ || cx == XXMAI /* MAIL */ #ifdef CK_RESEND || cx == XXRSEN /* RESEND */ #endif /* CK_RESEND */ ) { #ifdef IKSD if (inserver && !ENABLED(en_get)) { printf("?Sorry, sending files is disabled\n"); return(-9); } #endif /* IKSD */ return(doxsend(cx)); } /* PSEND, ADD, and REMOVE use special parsing */ #ifdef ADDCMD /* ADD and REMOVE */ if (cx == XXADD || cx == XXREMV) { char * m; m = (cx == XXADD) ? "Add to which list?" : "Remove from which list?"; x = cmkey(addtab,naddtab,m,"",xxstring); if (x < 0) return(x); #ifndef NOMSEND if (x == ADD_SND) return(addsend(cx)); else #endif /* NOMSEND */ return(doadd(cx,x)); } #endif /* ADDCMD */ #ifdef CK_RESEND if (cx == XXPSEN) { /* PSEND */ int seekto = 0; /* FIX THIS */ cmarg = cmarg2 = ""; x = cmifi("File to partially send", "", &s, &y, xxstring); if (x < 0) { if (x == -3) { printf("?A file specification is required\n"); return(-9); } else return(x); } nfils = -1; /* Files come from internal list. */ #ifndef NOMSEND addlist = 0; /* Don't use SEND-LIST. */ filenext = NULL; #endif /* NOMSEND */ ckstrncpy(line,s,LINBUFSIZ); /* Save copy of string just parsed. */ debug(F110,"PSEND line",line,0); if (y != 0) { printf("?Sorry, wildcards not permitted in this command\n"); return(-9); } if (sizeof(int) < 4) { printf("?Sorry, this command needs 32-bit integers\n"); return(-9); } x = cmnum("starting position (byte number)", "",10,&seekto,xxstring); if (x < 0) return(x); zfnqfp(s,fspeclen,fspec); /* Get full path */ if ((x = cmtxt("Name to send it with","",&s,NULL)) < 0) return(x); ckstrncpy(tmpbuf,s,TMPBUFSIZ); #ifdef IKSD if (inserver && !ENABLED(en_get)) { printf("?Sorry, sending files is disabled\n"); return(-9); } #endif /* IKSD */ #ifdef PIPESEND if (sndfilter) { printf("?Sorry, no PSEND while SEND FILTER selected\n"); return(-9); } #endif /* PIPESEND */ #ifdef CK_XYZ if ((protocol == PROTO_X || protocol == PROTO_XC)) { printf("Sorry, PSEND works only with Kermit protocol\n"); return(-9); } #endif /* CK_XYZ */ cmarg2 = brstrip(tmpbuf); /* Strip braces */ cmarg = line; /* File to send */ debug(F110,"PSEND filename",cmarg,0); debug(F110,"PSEND as-name",cmarg2,0); sendstart = seekto; sstate = 's'; /* Set start state to SEND */ #ifndef NOMSEND addlist = 0; filenext = NULL; #endif /* NOMSEND */ sendmode = SM_PSEND; #ifdef MAC what = W_SEND; scrcreate(); #endif /* MAC */ if (local) { /* If in local mode, */ displa = 1; /* enable file transfer display */ } return(0); } #endif /* CK_RESEND */ #endif /* NOXFER */ #ifndef NOXFER #ifndef NOMSEND if (cx == XXMSE || cx == XXMMOVE) { #ifdef NEWFTP if ((ftpget == 1) || ((ftpget == 2) && ftpisopen())) return(doftpput(cx,0)); #endif /* NEWFTP */ #ifdef CK_XYZ if (protocol == PROTO_X || protocol == PROTO_XC) { printf( "Sorry, you can only send one file at a time with XMODEM protocol\n" ); return(-9); } #endif /* CK_XYZ */ return(doxsend(cx)); } #ifdef COMMENT /* (moved to doxsend) */ if (cx == XXMSE || cx == XXMMOVE) { /* MSEND and MMOVE commands */ nfils = 0; /* Like getting a list of */ lp = line; /* files on the command line */ addlist = 0; /* Do not use SEND-LIST */ filenext = NULL; /* Ditto ! */ while (1) { char *p; if ((x = cmifi("Names of files to send, separated by spaces","", &s,&y,xxstring)) < 0) { if (x == -3) { if (nfils <= 0) { printf("?A file specification is required\n"); return(-9); } else break; } return(x); } msfiles[nfils++] = lp; /* Got one, count it, point to it, */ p = lp; /* remember pointer, */ while (*lp++ = *s++) /* and copy it into buffer */ if (lp > (line + LINBUFSIZ)) { /* Avoid memory leak */ printf("?MSEND list too long\n"); line[0] = NUL; return(-9); } debug(F111,"msfiles",msfiles[nfils-1],nfils-1); if (nfils == 1) *fspec = NUL; /* Take care of \v(filespec) */ #ifdef ZFNQFP zfnqfp(p,TMPBUFSIZ,tmpbuf); p = tmpbuf; #endif /* ZFNQFP */ if (((int)strlen(fspec) + (int)strlen(p) + 1) < fspeclen) { strcat(fspec,p); /* safe */ strcat(fspec," "); /* safe */ } else printf("WARNING - \\v(filespec) buffer overflow\n"); } cmlist = msfiles; /* Point cmlist to pointer array */ cmarg2 = ""; /* No internal expansion list (yet) */ sndsrc = nfils; /* Filenames come from cmlist */ sendmode = SM_MSEND; /* Remember this kind of SENDing */ sstate = 's'; /* Set start state for SEND */ if (cx == XXMMOVE) /* If MMOVE'ing, */ moving = 1; /* set this flag. */ #ifdef MAC what = W_SEND; scrcreate(); #endif /* MAC */ if (local) { /* If in local mode, */ displa = 1; /* turn on file transfer display */ ttflui(); /* and flush tty input buffer. */ } return(0); } #endif /* COMMENT */ #endif /* NOMSEND */ #endif /* NOXFER */ #ifndef NOSERVER if (cx == XXSER) { /* SERVER */ #ifdef CK_XYZ if (protocol != PROTO_K) { printf("Sorry, SERVER only works with Kermit protocol\n"); return(-9); } #endif /* CK_XYZ */ #ifdef COMMENT /* Parse for time limit, but since we don't use it yet, the parsing is commented out. */ x_ifnum = 1; /* Turn off internal complaints */ y = cmnum("optional time limit, seconds, or time of day as hh:mm:ss", "0", 10, &x, xxstring ); x_ifnum = 0; if (y < 0) { if (y == -2) { /* Invalid number or expression */ zz = tod2sec(atmbuf); /* Convert to secs since midnight */ if (zz < 0L) { printf("?Number, expression, or time of day required\n"); return(-9); } else { char now[32]; /* Current time */ char *p; long tnow; p = now; ztime(&p); tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17); if (zz < tnow) /* User's time before now */ zz += 86400L; /* So make it tomorrow */ zz -= tnow; /* Seconds from now. */ } } else return(y); } if (zz > -1L) { x = zz; if (zz != (long) x) { printf( "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n" ); return(-9); } } if (x < 0) x = 0; #endif /* COMMENT */ if ((x = cmcfm()) < 0) return(x); sstate = 'x'; #ifdef MAC what = W_RECV; scrcreate(); #endif /* MAC */ if (local) displa = 1; #ifdef AMIGA reqoff(); /* No DOS requestors while server */ #endif /* AMIGA */ return(0); } #endif /* NOSERVER */ if (cx == XXSAVE) { /* SAVE command */ x = cmkey(savtab,nsav,"option","keymap",xxstring); if (x == -3) { printf("?You must specify an option to save\n"); return(-9); } if (x < 0) return(x); /* have to set success separately for each item in doprm()... */ /* actually not really, could have just had doprm return 0 or 1 */ /* and set success here... */ y = dosave(x); if (y == -3) { printf("?More fields required\n"); return(-9); } else return(y); } if (cx == XXSET) { /* SET command */ x = cmkey(prmtab,nprm,"Parameter","",xxstring); if (x == -3) { printf("?You must specify a parameter to set\n"); return(-9); } if (x < 0) return(x); /* have to set success separately for each item in doprm()... */ /* actually not really, could have just had doprm return 0 or 1 */ /* and set success here... */ y = doprm(x,0); if (y == -3) { printf("?More fields required\n"); return(-9); } else return(y); } #ifndef NOPUSH if (cx == XXSHE /* SHELL (system) command */ || cx == XXEXEC /* exec() */ ) { #ifdef CKEXEC int rx = 0; char * p = NULL; int i; #endif /* CKEXEC */ #ifdef UNIXOROSK char * args[256]; #endif /* UNIXOROSK */ #ifdef IKSD if (inserver && (nopush || !ENABLED(en_hos))) { printf("?Sorry, host command access is disabled\n"); return(-9); } #endif /* IKSD */ #ifdef CKEXEC if (cx == XXEXEC) { /* EXEC (overlay ourselves) */ struct FDB sw, fl; cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Command to overlay C-Kermit\n or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 1, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ redirsw, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* 2nd FDB - command to exec */ _CMFLD, /* fcode */ "Command to overlay C-Kermit", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL /* No more after this */ ); while (1) { x = cmfdb(&sw); /* Parse something */ debug(F101,"exec cmfdb","",x); if (x < 0) return(x); /* Generalize this if we add more switches */ if (cmresult.fcode == _CMKEY) { rx = 1; continue; } if (cmresult.fcode == _CMFLD) break; return(-2); } ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ); if (!tmpbuf[0]) { printf("?Command required\n"); return(-9); } p = brstrip(tmpbuf); args[0] = NULL; /* Set argv[0] to it */ makestr(&args[0],p); for (i = 1; i < 255; i++) { /* Get arguments for command */ if ((x = cmfld("Argument","",&s,xxstring)) < 0) { if (x == -3) { if ((x = cmcfm()) < 0) return(x); break; } else return(x); } args[i] = NULL; s = brstrip(s); makestr(&args[i],s); } args[i] = NULL; } else { #endif /* CKEXEC */ if ((x = cmtxt("System command to execute","",&s,xxstring)) < 0) return(x); #ifdef CKEXEC } #endif /* CKEXEC */ if (nopush) return(success = 0); #ifdef CK_APC if (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)) return(success = 0); #endif /* CK_APC */ conres(); /* Make console normal */ #ifdef OS2 if (!(s && *s)) { os2push(); return(success = 1); } else #endif /* OS2 */ if (cx == XXSHE) { x = zshcmd(s); debug(F101,"RUN zshcmd code","",x); concb((char)escape); return(success = x); #ifdef CKEXEC } else { #ifdef DEBUG if (deblog) { debug(F111,"EXEC cmd",p,0); for (i = 0; i < 256 && args[i]; i++) debug(F111,"EXEC arg",args[i],i); } #endif /* DEBUG */ if (p) { z_exec(p,args,rx); /* Overlay ourself */ debug(F100,"EXEC fails","",0); concb((char)escape); /* In case it returns */ } return(success = 0); #endif /* CKEXEC */ } } #ifdef CK_REDIR if (cx == XXFUN) { /* REDIRECT */ #ifdef CK_APC if ((apcactive == APC_LOCAL) || ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH)))) return(success = 0); #endif /* CK_APC */ ckmakmsg(tmpbuf, TMPBUFSIZ, "Local command to run,\n", "with its standard input/output redirected to ", local ? ttname : "the communications connection", "\n" ); if ((x = cmtxt(tmpbuf,"",&s,xxstring)) < 0) return(x); if (nopush) { printf("?REDIRECT disabled\n"); return(success=0); } if (!local) { printf("?SET LINE or SET HOST required first\n"); return(-9); } if (!*s) { printf("?REDIRECT requires a command to redirect\n"); return(-9); } return(success = ttruncmd(s)); } #endif /* CK_REDIR */ #endif /* NOPUSH */ #ifndef NOSHOW if (cx == XXSHO) { /* SHOW */ x = cmkey(shotab,nsho,"","parameters",xxstring); if (x < 0) return(x); return(doshow(x)); } #endif /* NOSHOW */ #ifndef MAC if (cx == XXSPA) { /* SPACE */ #ifdef IKSD if (inserver && !ENABLED(en_spa)) { printf("?Sorry, SPACE command disabled\n"); return(-9); } #endif /* IKSD */ #ifdef datageneral /* AOS/VS can take an argument after its "space" command. */ if ((x = cmtxt("Confirm, or local directory name","",&s,xxstring)) < 0) return(x); if (nopush) { printf("?Sorry, SPACE command disabled\n"); return(-9); } else if (*s == NUL) { xsystem(SPACMD); } else { ckmakmsg(line,LINBUFSIZ,"space ",s,NULL,NULL); xsystem(line); } #else #ifdef OS2 if ((x = cmtxt("Press Enter for current disk,\n\ or specify a disk letter like A:","",&s,xxstring)) < 0) return(x); if (*s == NUL) { /* Current disk */ CK_OFF_T space = zdskspace(0); if (space > 0 && space < 1024) printf(" Free space: unknown\n"); else printf(" Free space: %ldK\n", space/1024L); } else { int drive = toupper(*s); CK_OFF_T space = zdskspace(drive - 'A' + 1); if (space > 0 && space < 1024) printf(" Drive %c: unknown free\n"); else printf(" Drive %c: %ldK free\n", drive,space / 1024L); } #else #ifdef UNIXOROSK x = cmdir("Confirm for current disk,\n\ or specify a disk device or directory","",&s,xxstring); if (x == -3) s = ""; else if (x < 0) return(x); ckstrncpy(tmpbuf,s,TMPBUFSIZ); s = tmpbuf; if ((x = cmcfm()) < 0) return(x); if (nopush) { printf("?Sorry, SPACE command disabled\n"); return(-9); } if (!*s) { /* Current disk */ xsystem(SPACMD); } else { /* Specified disk */ ckmakmsg(line,LINBUFSIZ,SPACM2," ",s,NULL); xsystem(line); } #else if ((x = cmcfm()) < 0) return(x); if (nopush) { printf("?Sorry, SPACE command disabled\n"); return(-9); } xsystem(SPACMD); #endif /* UNIXOROSK */ #endif /* OS2 */ #endif /* datageneral */ return(success = 1); /* Pretend it worked */ } #endif /* MAC */ #ifndef NOXFER if (cx == XXSTA) { /* STATISTICS */ if ((x = cmkey(stattab,2,"Carriage return, or option", "/brief",xxstring)) < 0) return(x); if ((y = cmcfm()) < 0) return(y); return(success = dostat(x)); } #endif /* NOXFER */ if (cx == XXSTO || cx == XXEND) { /* STOP, END, or POP */ if ((y = cmnum("exit status code","0",10,&x,xxstring)) < 0) return(y); if ((y = cmtxt("Message to print","",&s,xxstring)) < 0) return(y); s = brstrip(s); if (*s) printf("%s\n",s); if (cx == XXSTO) { dostop(); } else { doend(x); } return(success = (x == 0)); } if (cx == XXSUS) { /* SUSPEND */ if ((y = cmcfm()) < 0) return(y); #ifdef NOJC printf("Sorry, this version of Kermit cannot be suspended\n"); #else #ifdef IKSD if (inserver) { printf("?Sorry, IKSD can not be suspended\n"); return(-9); } else #endif /* IKSD */ if (nopush) { printf("?Sorry, access to system is disabled\n"); return(-9); } stptrap(0); #endif /* NOJC */ return(0); } if (cx == XXTAK) { /* TAKE */ char * scriptenv = NULL; #ifdef OS2 char * GetAppData(int); extern char startupdir[],exedir[],inidir[]; char * keymapenv = NULL; char * appdata0 = NULL, *appdata1 = NULL; #define TAKEPATHLEN 4096 #else /* OS2 */ #define TAKEPATHLEN 1024 #endif /* OS2 */ char takepath[TAKEPATHLEN]; if (tlevel >= MAXTAKE-1) { printf("?Take files nested too deeply\n"); return(-9); } #ifdef OS2 #ifdef NT scriptenv = getenv("K95SCRIPTS"); keymapenv = getenv("K95KEYMAPS"); makestr(&appdata0,(char *)GetAppData(0)); makestr(&appdata1,(char *)GetAppData(1)); #else /* NT */ scriptenv = getenv("K2SCRIPTS"); keymapenv = getenv("K2KEYMAPS"); #endif /* NT */ #endif /* OS2 */ if (!scriptenv) /* Let this work for Unix etc too */ scriptenv = getenv("CK_SCRIPTS"); /* Use this if defined */ #ifndef OS2 if (!scriptenv) /* Otherwise use home directory */ scriptenv = homepath(); #endif /* OS2 */ if (!scriptenv) scriptenv = ""; ckstrncpy(takepath,scriptenv,TAKEPATHLEN); debug(F110,"TAKE initial takepath",takepath,0); #ifdef OS2 if (!keymapenv) keymapenv = getenv("CK_KEYMAPS"); if (!keymapenv) keymapenv = ""; ckstrncat(takepath, (scriptenv && scriptenv[strlen(scriptenv)-1]==';')?"":";", TAKEPATHLEN ); ckstrncat(takepath,keymapenv?keymapenv:"",TAKEPATHLEN); ckstrncat(takepath, (keymapenv && keymapenv[strlen(keymapenv)-1]==';')?"":";", TAKEPATHLEN ); ckstrncat(takepath,startupdir,TAKEPATHLEN); ckstrncat(takepath,";",TAKEPATHLEN); ckstrncat(takepath,startupdir,TAKEPATHLEN); ckstrncat(takepath,"SCRIPTS/;",TAKEPATHLEN); ckstrncat(takepath,startupdir,TAKEPATHLEN); ckstrncat(takepath,"KEYMAPS/;",TAKEPATHLEN); ckstrncat(takepath,appdata1,TAKEPATHLEN); ckstrncat(takepath,"Kermit 95/;",TAKEPATHLEN); ckstrncat(takepath,appdata1,TAKEPATHLEN); ckstrncat(takepath,"Kermit 95/SCRIPTS/;",TAKEPATHLEN); ckstrncat(takepath,appdata1,TAKEPATHLEN); ckstrncat(takepath,"Kermit 95/KEYMAPS/;",TAKEPATHLEN); ckstrncat(takepath,appdata0,TAKEPATHLEN); ckstrncat(takepath,"Kermit 95/;",TAKEPATHLEN); ckstrncat(takepath,appdata0,TAKEPATHLEN); ckstrncat(takepath,"Kermit 95/SCRIPTS/;",TAKEPATHLEN); ckstrncat(takepath,appdata0,TAKEPATHLEN); ckstrncat(takepath,"Kermit 95/KEYMAPS/;",TAKEPATHLEN); ckstrncat(takepath,inidir,TAKEPATHLEN); ckstrncat(takepath,";",TAKEPATHLEN); ckstrncat(takepath,inidir,TAKEPATHLEN); ckstrncat(takepath,"SCRIPTS/;",TAKEPATHLEN); ckstrncat(takepath,inidir,TAKEPATHLEN); ckstrncat(takepath,"KEYMAPS/;",TAKEPATHLEN); ckstrncat(takepath,zhome(),TAKEPATHLEN); ckstrncat(takepath,";",TAKEPATHLEN); ckstrncat(takepath,zhome(),TAKEPATHLEN); ckstrncat(takepath,"SCRIPTS/;",TAKEPATHLEN); ckstrncat(takepath,zhome(),TAKEPATHLEN); ckstrncat(takepath,"KEYMAPS/;",TAKEPATHLEN); ckstrncat(takepath,exedir,TAKEPATHLEN); ckstrncat(takepath,";",TAKEPATHLEN); ckstrncat(takepath,exedir,TAKEPATHLEN); ckstrncat(takepath,"SCRIPTS/;",TAKEPATHLEN); ckstrncat(takepath,exedir,TAKEPATHLEN); ckstrncat(takepath,"KEYMAPS/;",TAKEPATHLEN); #endif /* OS2 */ debug(F110,"TAKE final takepath",takepath,0); if ((y = cmifip("Commands from file", "",&s,&x,0,takepath,xxstring)) < 0) { if (y == -3) { printf("?A file name is required\n"); return(-9); } else return(y); } if (x != 0) { printf("?Wildcards not allowed in command file name\n"); return(-9); } ckstrncpy(line,s,LINBUFSIZ); debug(F110,"TAKE file",s,0); if (isdir(s)) { printf("?Can't execute a directory - \"%s\"\n", s); return(-9); } #ifndef NOTAKEARGS { char * p; x = strlen(line); debug(F111,"TAKE args",line,x); p = line + x + 1; if ((y = cmtxt("Optional arguments","",&s,xxstring)) < 0) return(y); if (*s) { /* Args given? */ ckstrncpy(p,s,LINBUFSIZ-x-1); #ifdef ZFNQFP zfnqfp(line,TMPBUFSIZ,tmpbuf); s = tmpbuf; #else s = line; #endif /* ZFNQFP */ debug(F110,"TAKE filename",s,0); x = strlen(s); debug(F101,"TAKE new len",s,x); #ifdef COMMENT /* This was added in C-Kermit 7.0 to allow args to be passed from the TAKE command to the command file. But it overwrites the current argument vector, which is at best surprising, and at worst unsafe. */ addmac("%0",s); /* Define %0 = name of file */ varnam[0] = '%'; varnam[2] = '\0'; debug(F110,"take arg 0",s,0); debug(F110,"take args",p,0); for (y = 1; y < 10; y++) { /* Clear current args %1..%9 */ varnam[1] = (char) (y + '0'); delmac(varnam,0); } xwords(p,MAXARGLIST,NULL,0); /* Assign new args */ debug(F110,"take args",p,0); #else /* This method is used in 8.0. If the TAKE command includes arguments, we insert an intermediate temporary macro between the current level; we pass the arguments to the macro and then the macro TAKEs the command file. If the user Ctrl-C's out of the TAKE file, some temporary macro definitions and other small malloc'd bits might be left behind. */ { char * q = NULL; char * r = NULL; int k, m; m = maclvl; q = (char *)malloc(x+24); if (q) { r = (char *)malloc(x+24); if (r) { sprintf(q,"_file[%s](%d)",s,cmdlvl); /* safe */ sprintf(r,"take %s",s); /* safe */ k = addmac(q,r); if (k > -1) { dodo(k,p,0); while (maclvl > m) { sstate = (CHAR) parser(1); if (sstate) proto(); } } k = delmac(q,0); free(q); free(r); return(success); } } } return(success = 0); #endif /* COMMENT */ } } #else if ((y = cmcfm()) < 0) return(y); #endif /* NOTAKEARGS */ return(success = dotake(line)); } #ifndef NOLOCAL #ifdef OS2 if (cx == XXVIEW) { /* VIEW Only Terminal mode */ viewonly = TRUE; success = doconect(0, 0); viewonly = FALSE; return success; } #endif /* OS2 */ #ifdef NETCONN if (cx == XXTEL || cx == XXIKSD) { /* TELNET */ int x,z; #ifdef OS2 if (!tcp_avail) { printf("?Sorry, either TCP/IP is not available on this system or\n\ necessary DLLs did not load. Use SHOW NETWORK to check network status.\n"); success = 0; return(-9); } else #endif /* OS2 */ { x = nettype; /* Save net type in case of failure */ z = ttnproto; /* Save protocol in case of failure */ nettype = NET_TCPB; ttnproto = (cx == XXTEL) ? NP_TELNET : NP_KERMIT; if ((y = setlin(XYHOST,0,1)) <= 0) { nettype = x; /* Failed, restore net type. */ ttnproto = z; /* and protocol */ success = 0; } didsetlin++; } return(y); } #ifndef PTYORPIPE #ifdef NETCMD #define PTYORPIPE #else #ifdef NETPTY #define PTYORPIPE #endif /* NETPTY */ #endif /* NETCMD */ #endif /* PTYORPIPE */ #ifdef PTYORPIPE if (cx == XXPIPE || cx == XXPTY) { /* PIPE or PTY */ int x; extern int netsave; x = nettype; /* Save net type in case of failure */ nettype = (cx == XXPIPE) ? NET_CMD : NET_PTY; if ((y = setlin(XYHOST,0,1)) < 0) { nettype = x; /* Failed, restore net type. */ ttnproto = z; /* and protocol */ success = 0; } didsetlin++; netsave = x; return(y); } #endif /* PTYORPIPE */ #endif /* NETCONN */ #ifdef ANYSSH if (cx == XXSSH) { /* SSH (Secure Shell) */ extern int netsave; #ifdef SSHBUILTIN int k, havehost = 0, trips = 0; int tmpver = -1, tmpxfw = -1; #ifndef SSHTEST extern int sl_ssh_xfw, sl_ssh_xfw_saved; extern int sl_ssh_ver, sl_ssh_ver_saved; #endif /* SSHTEST */ extern int mdmtyp, mdmsav, cxtype, sl_uid_saved; extern char * slmsg; extern char uidbuf[], sl_uidbuf[]; extern char pwbuf[], * g_pswd; extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal; struct FDB sw, kw, fl; if (ssh_tmpstr) memset(ssh_tmpstr,0,strlen(ssh_tmpstr)); makestr(&ssh_tmpstr,NULL); makestr(&ssh_tmpuid,NULL); makestr(&ssh_tmpcmd,NULL); makestr(&ssh_tmpport,NULL); /* Hide any "ssh" commands not supported by the currently loaded SSH * backend */ for (z = 0; z < nsshcmd; z++) { if ((sshkwtab[z].kwval == XSSH_ADD || sshkwtab[z].kwval == XSSH_CLR || sshkwtab[z].kwval == XSSH_FLP || sshkwtab[z].kwval == XSSH_FRP || sshkwtab[z].kwval == XSSH_REM) && !ssh_feature_supported(SSH_FEAT_PORT_FWD)) { /* Port forwarding * "ssh add" - adds port fowards * "ssh clear" - clears port fowards * And these, which are already hidden by default: * "ssh forward-local-port" * "ssh forward-remote-port" * Possibly an unimplemented feature ("arbitrary forwarding")? */ sshkwtab[z].flgs = CM_INV; } else if (sshkwtab[z].kwval == XSSH_AGT && !ssh_feature_supported(SSH_FEAT_AGENT_MGMT)) { /* * "ssh agent" */ sshkwtab[z].flgs = CM_INV; } else if (sshkwtab[z].kwval == XSSH_KEY && !ssh_feature_supported(SSH_FEAT_KEY_MGMT)) { /* * "ssh agent" */ sshkwtab[z].flgs = CM_INV; } else if (sshkwtab[z].kwval == XSSH_V2 && !ssh_feature_supported(SSH_FEAT_REKEY_MANUAL)) { /* * "ssh v2 rekey" */ sshkwtab[z].flgs = CM_INV; } } /* Hide any "ssh open" arguments not supported by the currently loaded * SSH backend */ for (z = 0; z < nsshopnsw; z++) { if (sshopnsw[z].kwval == SSHSW_VER && !ssh_feature_supported(SSH_FEAT_SSH_V1)) { /* * "ssh open x /version:y" - if we don't support SSH V1 then we * only support SSH V2 so this at best does nothing. We only * hide this argument - it will still be parsed and the entered * value passed through to the SSH backend to reject if * necessary. */ sshopnsw[z].flgs = CM_INV; } else if (sshopnsw[z].kwval == SSHSW_X11 && !ssh_feature_supported(SSH_FEAT_X11_FWD)) { /* * "ssh open x /x11-forwarding" */ sshopnsw[z].flgs = CM_INV; } } debug(F101,"SSH external parsing","",0); #ifdef SSH_DLL if (!ssh_avail()) { /* There is a different set of "ssh" commands available when the * SSH backend hasn't been loaded. */ cmfdbi(&kw, /* load command only */ _CMKEY, /* fcode */ "action", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nsshloadcmd, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: 0 = keyword */ xxstring, /* Processing function */ sshloadkwtab, /* Keyword table */ 0 /* Pointer to next FDB */ ); x = cmfdb(&kw); debug(F101,"SSH external cmfdb &kw","",x); if (x == -3) { printf("?ssh what?\n"); return(-9); } if (x < 0) return(x); } else { #endif /* SSH_DLL */ cmfdbi(&kw, /* 1st FDB - commands */ _CMKEY, /* fcode */ "host [ port ],\n or action", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nsshcmd, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: 0 = keyword */ xxstring, /* Processing function */ sshkwtab, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* Host */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); x = cmfdb(&kw); debug(F101,"SSH external cmfdb &kw","",x); if (x == -3) { printf("?ssh what?\n"); return(-9); } if (x < 0) return(x); havehost = 0; if (cmresult.fcode == _CMFLD) { havehost = 1; ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Hostname */ cmresult.nresult = XSSH_OPN; } #ifdef SSH_DLL } #endif /* SSH_DLL */ switch (cmresult.nresult) { /* SSH keyword */ #ifdef SSH_DLL case XSSH_LOAD: { /* SSH LOAD */ if ((x = cmfld("SSH DLL filename","",&s,xxstring)) < 0) { return(x); } ssh_dll_load(s, FALSE); } #endif /* SSH_DLL */ case XSSH_OPN: { /* SSH OPEN */ char tmpline[LINBUFSIZ], tmpline2[LINBUFSIZ]; char* token; if (!havehost) { if ((x = cmfld("Host","",&s,xxstring)) < 0) return(x); ckstrncpy(line,s,LINBUFSIZ); } /* Try to handle username@hostname syntax */ ckstrncpy(tmpline,line,LINBUFSIZ); token = strtok(tmpline, "@"); if (token != NULL) { /* First part is the username */ makestr(&ssh_tmpuid,brstrip(token)); debug(F110, "Found username in the hostname!", ssh_tmpuid, 0); token = strtok(NULL, "@"); if (token != NULL) { /* Second part is the hostname */ debug(F110, "Found hostname", token, 0); ckstrncpy(tmpline2,token,LINBUFSIZ); token = strtok(NULL, "@"); if (token != NULL) { /* Error - there should not be a third part. Give up */ debug(F110, "Error - found third token. Giving up.", token, 0); makestr(&ssh_tmpuid,NULL); } else { ckstrncpy(line,tmpline2,LINBUFSIZ); } } else { /* No second part - give up. */ makestr(&ssh_tmpuid,NULL); } } /* Parse [ port ] [ switches ] */ cmfdbi(&kw, /* Switches */ _CMKEY, "Port number or service name,\nor switch", "", "", nsshopnsw, 4, xxstring, sshopnsw, &fl ); cmfdbi(&fl, /* Port number or service name */ _CMFLD, "", "", "", 0, 0, xxstring, NULL, NULL ); trips = 0; /* Explained below */ while (1) { /* Parse port and switches */ x = cmfdb(&kw); /* Get a field */ if (x == -3) /* User typed CR so quit from loop */ break; if (x < 0) /* Other parse error, pass it back */ return(x); switch (cmresult.fcode) { /* Field or Keyword? */ case _CMFLD: /* Field */ makestr(&ssh_tmpport,cmresult.sresult); break; case _CMKEY: /* Keyword */ switch (cmresult.nresult) { /* Which one? */ case SSHSW_USR: /* /USER: */ if (!cmgbrk()) { printf("?This switch requires an argument\n"); return(-9); } if ((y = cmfld("Username","",&s,xxstring)) < 0) return(y); s = brstrip(s); makestr(&ssh_tmpuid,s); break; case SSHSW_PWD: if (!cmgbrk()) { printf("?This switch requires an argument\n"); return(-9); } debok = 0; if ((x = cmfld("Password","",&s,xxstring)) < 0) { if (x == -3) { makestr(&ssh_tmpstr,""); } else { return(x); } } else { s = brstrip(s); if ((x = (int)strlen(s)) > PWBUFL) { makestr(&slmsg,"Internal error"); printf("?Sorry, too long - max = %d\n",PWBUFL); return(-9); } makestr(&ssh_tmpstr,s); } break; case SSHSW_VER: if ((x = cmnum("Number","",10,&z,xxstring)) < 0) return(x); if (z < 1 || z > 2) { printf("?Out of range: %d\n",z); return(-9); } tmpver = z; break; case SSHSW_CMD: case SSHSW_SUB: if ((x = cmfld("Text","",&s,xxstring)) < 0) return(x); makestr(&ssh_tmpcmd,s); ssh_set_iparam(SSH_IPARAM_CAS, cmresult.nresult == SSHSW_SUB); break; case SSHSW_X11: if (!ssh_feature_supported(SSH_FEAT_X11_FWD)) { printf("\r\nX11 forwarding is not supported by the current SSH backend\r\n"); return(-9); } if ((x = cmkey(onoff,2,"","on",xxstring)) < 0) return(x); tmpxfw = x; break; default: return(-2); } } if (trips++ == 0) { /* After first time through */ cmfdbi(&kw, /* only parse switches, not port. */ _CMKEY, "Switch", "", "", nsshopnsw, 4, xxstring, sshopnsw, NULL ); } } if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); if (clskconnx(1) < 0) { /* Close current Kermit connection */ if ( ssh_tmpstr ) { memset(ssh_tmpstr,0,strlen(ssh_tmpstr)); makestr(&ssh_tmpstr,NULL); } return(success = 0); } ssh_set_sparam(SSH_SPARAM_HST,line); /* Stash everything */ if (ssh_tmpuid) { if (!sl_uid_saved) { ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN); sl_uid_saved = 1; } ckstrncpy(uidbuf,ssh_tmpuid,UIDBUFLEN); makestr(&ssh_tmpuid,NULL); } if (ssh_tmpport) { ssh_set_sparam(SSH_SPARAM_PRT,ssh_tmpport); makestr(&ssh_tmpport,NULL); } else { ssh_set_sparam(SSH_SPARAM_PRT,NULL); } if (ssh_tmpcmd) { ssh_set_sparam(SSH_SPARAM_CMD, brstrip(ssh_tmpcmd)); makestr(&ssh_tmpcmd,NULL); } else { ssh_set_sparam(SSH_SPARAM_CMD, NULL); } if (tmpver > -1) { #ifndef SSHTEST if (!sl_ssh_ver_saved) { sl_ssh_ver = ssh_get_iparam(SSH_IPARAM_VER); sl_ssh_ver_saved = 1; } #endif /* SSHTEST */ ssh_set_iparam(SSH_IPARAM_VER, tmpver); } if (tmpxfw > -1) { #ifndef SSHTEST if (!sl_ssh_xfw_saved) { sl_ssh_xfw = ssh_get_iparam(SSH_IPARAM_XFW); sl_ssh_xfw_saved = 1; } #endif /* SSHTEST */ ssh_set_iparam(SSH_IPARAM_XFW, tmpxfw); } if (ssh_tmpstr) { if (ssh_tmpstr[0]) { ckstrncpy(pwbuf,ssh_tmpstr,PWBUFL+1); pwflg = 1; pwcrypt = 0; } else pwflg = 0; makestr(&ssh_tmpstr,NULL); } nettype = NET_SSH; if (mdmsav < 0) mdmsav = mdmtyp; mdmtyp = -nettype; x = 1; #ifndef NOSPL makestr(&g_pswd,pwbuf); /* Save global pwbuf */ g_pflg = pwflg; /* and flag */ g_pcpt = pwcrypt; #endif /* NOSPL */ /* Line parameter to ttopen() is ignored */ debug(F110,"SSH line",line,0); k = ttopen(line,&x,mdmtyp, 0); if (k < 0) { printf("?Unable to connect to %s\n",ssh_get_sparam(SSH_SPARAM_HST)); mdmtyp = mdmsav; slrestor(); return(success = 0); } duplex = 0; /* Remote echo */ ckstrncpy(ttname,line,TTNAMLEN); /* Record the command */ debug(F110,"ssh ttname",ttname,0); makestr(&slmsg,NULL); /* No SET LINE error message */ cxtype = CXT_SSH; #ifndef NODIAL dialsta = DIA_UNK; #endif /* NODIAL */ success = 1; /* SET LINE succeeded */ network = 1; /* Network connection (not serial) */ local = 1; /* Local mode (not remote) */ if ((reliable != SET_OFF || !setreliable)) reliable = SET_ON; /* Transport is reliable end to end */ #ifdef OS2 DialerSend(OPT_KERMIT_CONNECT, 0); #endif /* OS2 */ setflow(); /* Set appropriate flow control */ haveline = 1; #ifdef CKLOGDIAL #ifdef NETCONN dolognet(); #endif /* NETCONN */ #endif /* CKLOGDIAL */ #ifndef NOSPL if (local) { if (nmac) { /* Any macros defined? */ int k; /* Yes */ k = mlook(mactab,"on_open",nmac); /* Look this up */ if (k >= 0) { /* If found, */ if (dodo(k,ssh_get_sparam(SSH_SPARAM_HST),0) > -1) /* set it up, */ parser(1); /* and execute it */ } } } #endif /* NOSPL */ #ifdef LOCUS if (autolocus) setlocus(1,1); #endif /* LOCUS */ /* Command was confirmed so we can pre-pop command level. */ /* This is so CONNECT module won't think we're executing a */ /* script if CONNECT was the final command in the script. */ if (cmdlvl > 0) prepop(); success = doconect(0,cmdlvl == 0 ? 1 : 0); if (ttchk() < 0) dologend(); return(success); case XSSH_CLR: if (!ssh_feature_supported(SSH_FEAT_PORT_FWD)) { printf("\r\nPort forwarding is not supported by the current SSH backend\r\n"); return(-9); } if ((y = cmkey(sshclr,nsshclr,"","", xxstring)) < 0) { if (y == -3) { printf("?clear what?\n"); return(-9); } return(y); } /* TODO: A switch to apply these changes to any active connection * rather than only affecting future connections */ if ((x = cmcfm()) < 0) { return(x); } switch (y) { case SSHC_LPF: ssh_fwd_clear_local_ports(FALSE); break; case SSHC_RPF: ssh_fwd_clear_remote_ports(FALSE); break; default: return(-2); } return(success = 1); /* or whatever */ } case XSSH_REM: { int port; if (!ssh_feature_supported(SSH_FEAT_PORT_FWD)) { printf("\r\nPort forwarding is not supported by the current SSH backend\r\n"); return(-9); } if ((y = cmkey(sshrem,nsshrem,"","", xxstring)) < 0) { if (y == -3) { printf("?remove what?\n"); return(-9); } return(y); } if ((x = cmnum((y == SSHR_LPF) ? "Local port number" : "Remote port number", "",10,&port,xxstring)) < 0) { return(x); } /* TODO: A switch to apply these changes to any active connection * rather than only affecting future connections */ if ((x = cmcfm()) < 0) { return(x); } switch (y) { case SSHR_LPF: ssh_fwd_remove_local_port(port, FALSE); break; case SSHR_RPF: ssh_fwd_remove_remote_port(port, FALSE); break; default: return(-2); } return(success = 1); /* or whatever */ } case XSSH_AGT: { /* SSH AGENT */ int doeach = 0; if (!ssh_feature_supported(SSH_FEAT_AGENT_MGMT)) { printf("\r\nAgent management is not supported by the current SSH backend\r\n"); return(-9); } if ((y = cmkey(sshagent,nsshagent,"","",xxstring)) < 0) return(y); switch (y) { case SSHA_ADD: /* SSH AGENT ADD ... */ if ((x = cmifi("Identity file","",&s,&y,xxstring)) < 0) { #ifndef SSHTEST if (x == -3) /* No name given */ doeach = 1; /* so do them all */ else #endif /* SSHTEST */ return(x); } ckstrncpy(line,s,LINBUFSIZ); if ((x = cmcfm()) < 0) return(x); #ifdef SSHTEST x = 0; #else if (doeach) { int i; x = 0; for (i = 0; i < ssh_idf_n; i++) x += ssh_agent_add_file(ssh_idf[i]); } else x = ssh_agent_add_file(line); #endif /* SSHTEST */ return(success = (x == 0)); case SSHA_DEL: { /* SSH AGENT DELETE ... */ int doall = 0; if ((x = cmifi("Identity file","",&s,&y,xxstring)) < 0) { #ifndef SSHTEST if (x == -3) /* No name given */ doall = 1; /* so do them all */ else #endif /* SSHTEST */ return(x); } ckstrncpy(line,s,LINBUFSIZ); if ((x = cmcfm()) < 0) return(x); #ifdef SSHTEST x = 0; #else if (doall) x = ssh_agent_delete_all(); else x = ssh_agent_delete_file(line); #endif /* SSHTEST */ return(success = (x == 0)); } case SSHA_LST: { int fingerprint = 0; if ((y = cmswi(sshagtsw,nsshagtsw,"","",xxstring)) < 0) { if (y != -3) return(y); } else if (cmgbrk() > SP) { printf("?This switch does not take an argument\n"); return(-9); } else if (y == SSHASW_FP) { fingerprint = 1; } if ((x = cmcfm()) < 0) return(x); #ifdef SSHTEST return(success = 1); #else return(success = (ssh_agent_list_identities(fingerprint) == 0)); #endif /* SSHTEST */ } default: return(-2); } } #ifdef COMMENT case XSSH_ADD: { /* SSH ADD */ /* ssh add { local, remote } port host port */ int cx, i, j, k; char * h; if (!ssh_feature_supported(SSH_FEAT_PORT_FWD)) { printf("\r\nPort forwarding is not supported by the current SSH backend\r\n"); return(-9); } if ((cx = cmkey(addfwd,naddfwd,"","", xxstring)) < 0) { return(cx); } if ((x = cmnum((cx == SSHF_LCL) ? "Local port number" : "Remote port number", "",10,&j,xxstring)) < 0) { return(x); } if ((x = cmfld("Host","",&s,xxstring)) < 0) { return(x); } makestr(&h,s); if ((x = cmnum("Port","",10,&k,xxstring)) < 0) { return(x); } if ((x = cmcfm()) < 0) { return(x); } switch(cx) { case SSHF_LCL: if (ssh_pf_lcl_n == 32) { printf("?Maximum number of local port forwardings already " "specified\n"); free(h); return(success = 0); } ssh_pf_lcl[ssh_pf_lcl_n].p1 = j; makestr(&(ssh_pf_lcl[ssh_pf_lcl_n].host),h); makestr(&h,NULL); ssh_pf_lcl[ssh_pf_lcl_n].p2 = k; ssh_pf_lcl_n++; break; case SSHF_RMT: if (ssh_pf_rmt_n == 32) { printf("?Maximum number of remote port forwardings already " "specified\n"); free(h); return(success = 0); } ssh_pf_rmt[ssh_pf_rmt_n].p1 = j; makestr(&(ssh_pf_rmt[ssh_pf_rmt_n].host),h); makestr(&h,NULL); ssh_pf_rmt[ssh_pf_rmt_n].p2 = k; ssh_pf_rmt_n++; } return(success = 1); } #endif /* COMMENT */ case XSSH_ADD: /* SSH ADD { LOCAL, REMOTE } */ case XSSH_FLP: /* SSH FORWARD-LOCAL-PORT */ case XSSH_FRP: { /* SSH FORWARD-REMOTE-PORT */ int li_port = 0; int to_port = 0; char * fw_host = NULL; int n, rc; char* ssh_hst = NULL; BOOL local = FALSE; /* * In K95 2.1.3, the way to add ports was: * SSH ADD { LOCAL, REMOTE } * These only took effect at connection establishment - you couldn't * add a new forwarding to an already established connection. The * SSH { FORWARD-LOCAL-PORT, FORWARD-REMOTE-PORT } * commands are present in the K95 2.1.3 codebase for adding forwards * to established connections but they were invisible and didn't do * anything besides parse parameters unless SSH_TEST was defined. * * Here we're just treating * SSH { FORWARD-LOCAL-PORT, FORWARD-REMOTE-PORT } * as a synonym for * SSH ADD { LOCAL, REMOTE } * and eventually will allow adding forwards to established * connections using either command. */ if (!ssh_feature_supported(SSH_FEAT_PORT_FWD)) { printf("\r\nPort forwarding is not supported by the current SSH backend\r\n"); return(-9); } switch(cmresult.nresult) { case XSSH_ADD: { int cx; if ((cx = cmkey(addfwd,naddfwd,"","", xxstring)) < 0) { return(cx); } local = cx == SSHF_LCL; break; } case XSSH_FLP: { local = TRUE; break; } case XSSH_FRP: { local = FALSE; break; } } if ((x = cmnum(local ? "local-port":"remote-port", "",10,&li_port,xxstring)) < 0) { return(x); } if (li_port < 1 || li_port > 65535) { printf("?Out range - min: 1, max: 65535\n"); return(-9); } ssh_hst = ssh_get_sparam(SSH_SPARAM_HST); if ((x = cmfld("host",ssh_hst?ssh_hst:"",&s,xxstring)) < 0) { return(x); } n = ckstrncpy(tmpbuf,s,TMPBUFSIZ); fw_host = tmpbuf; if ((x = cmnum("host-port",ckuitoa(li_port),10, &to_port,xxstring)) < 0) { return(x); } if (to_port < 1 || to_port > 65535) { printf("?Out range - min: 1, max: 65535\n"); return(-9); } if ((x = cmcfm()) < 0) { return(x); } /* TODO: Either a switch to make it apply immediately (last parameter * on ssh_fwd_*_port = TRUE), or have the currently hidden * "SSH FORWARD-*" commands do this. */ if (local) { /* SSH FORWARD-LOCAL-PORT local-port host port * SSH ADD LOCAL-PORT-FORWARD local-port host port */ rc = ssh_fwd_local_port("localhost", li_port,fw_host,to_port, FALSE); if (rc != 0) return(success = 0); } else { /* SSH FORWARD-REMOTE-PORT remote-port host port * SSH ADD REMOTE-PORT-FORWARD remote-port host port */ rc = ssh_fwd_remote_port("localhost", li_port,fw_host,to_port, FALSE); if (rc != 0) return(success = 0); } return(success = 1); } case XSSH_V2: /* SSH V2 */ if ((cx = cmkey(ssh2tab,nssh2tab,"","", xxstring)) < 0) return(cx); switch (cx) { case XSSH2_RKE: if (!ssh_feature_supported(SSH_FEAT_REKEY_MANUAL)) { printf("\r\nManual rekeying is not supported by the current SSH backend\r\n"); return(-9); } if ((x = cmcfm()) < 0) return(x); #ifndef SSHTEST ssh_v2_rekey(); #endif /* SSHTEST */ return(success = 1); default: return(-2); } case XSSH_KEY: if (!ssh_feature_supported(SSH_FEAT_KEY_MGMT)) { printf("\r\nKey management is not supported by the current SSH backend\r\n"); return(-9); } if ((cx = cmkey(sshkey,nsshkey,"","", xxstring)) < 0) return(cx); switch (cx) { case SSHK_PASS: { /* Change passphrase */ char * oldp = NULL, * newp = NULL; struct FDB df, sw; cmfdbi(&sw, _CMKEY, /* fcode */ "Filename, or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 2, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ sshkpsw, /* Keyword table */ &df /* Pointer to next FDB */ ); cmfdbi(&df, /* 2nd FDB - file for display */ _CMIFI, /* output file */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); line[0] = NUL; while (1) { x = cmfdb(&sw); if (x == -3) break; if (x < 0) return(x); if (cmresult.fcode != _CMKEY) break; if (!cmgbrk()) { printf("?This switch requires an argument\n"); return(-9); } if ((y = cmfld("Passphrase","",&s,xxstring)) < 0) return(y); switch (cmresult.nresult) { case 1: /* Old */ makestr(&oldp,s); break; case 2: /* New */ makestr(&newp,s); } } if (cmresult.fcode == _CMIFI) { /* Filename */ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); if (zfnqfp(line,TMPBUFSIZ,tmpbuf)) ckstrncpy(line,tmpbuf,LINBUFSIZ); } if ((x = cmcfm()) < 0) return(x); #ifndef SSHTEST x = sshkey_change_passphrase(line[0] ? line : NULL, oldp, newp); #endif /* SSHTEST */ makestr(&oldp,NULL); makestr(&newp,NULL); success = (x == 0); return(success); } case SSHK_CREA: { /* SSH KEY CREATE /switches... */ int bits = 0, keytype = SSHKT_ED25519; char * pass = NULL, * comment = NULL; struct FDB df, sw; /* * char * sshkey_default_file(int keytype) * will provide the default filename for a given keytype * is it possible to have the default value for the 2nd * FDB set and changed when a /TYPE switch is provided? * Would this allow for tab completion of the filename? */ cmfdbi(&sw, _CMKEY, /* fcode */ "Filename, or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nsshkcrea, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ sshkcrea, /* Keyword table */ &df /* Pointer to next FDB */ ); cmfdbi(&df, /* 2nd FDB - file for display */ _CMOFI, /* output file */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); line[0] = NUL; while (1) { x = cmfdb(&sw); if (x == -3) break; if (x < 0) return(x); if (cmresult.fcode != _CMKEY) break; if (!cmgbrk()) { printf("?This switch requires an argument\n"); return(-9); } switch (cmresult.nresult) { case SSHKC_BI: /* /BITS:n */ if ((y = cmnum("","0",10,&z,xxstring)) < 0) return(y); bits = z; break; case SSHKC_PP: /* /PASSPHRASE:blah */ if ((y = cmfld("Passphrase","",&s,xxstring)) < 0) return(y); makestr(&pass,s); break; case SSHKC_TY: /* /TYPE:keyword */ if ((y = cmkey(sshkcty,nsshkcty,"", "ed25519",xxstring)) < 0) return(y); keytype = y; break; case SSHKC_1R: /* /COMMENT */ if ((y = cmfld("Text","",&s,xxstring)) < 0) return(y); makestr(&comment,s); break; } } if (cmresult.fcode == _CMOFI) { /* Filename */ if (cmresult.sresult) { ckstrncpy(line,cmresult.sresult,LINBUFSIZ); if (zfnqfp(line,TMPBUFSIZ,tmpbuf)) ckstrncpy(line,tmpbuf,LINBUFSIZ); } } if ((y = cmcfm()) < 0) /* Confirm */ return(y); #ifndef SSHTEST x = sshkey_create(line[0] ? line : NULL, bits, pass, keytype, comment); if (pass) memset(pass,0,strlen(pass)); #endif /* SSHTEST */ makestr(&pass,NULL); makestr(&comment,NULL); return(success = (x == 0)); } case SSHK_DISP: { /* SSH KEY DISPLAY /switches... */ char c; int infmt = 0, outfmt = SKDF_FING; struct FDB df, sw; cmfdbi(&sw, _CMKEY, /* fcode */ "Filename, or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nsshdswi, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ sshdswi, /* Keyword table */ &df /* Pointer to next FDB */ ); cmfdbi(&df, /* 2nd FDB - file for display */ _CMIFI, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); line[0] = NUL; while (1) { x = cmfdb(&sw); if (x == -3) break; if (x < 0) return(x); if (cmresult.fcode != _CMKEY) break; if (!cmgbrk()) { printf("?This switch requires an argument\n"); return(-9); } switch (cmresult.nresult) { #ifdef COMMENT case SSHKD_IN: /* /IN-FORMAT: */ if ((y = cmkey(sshdifmt,nsshdifmt, "","",xxstring)) < 0) return(y); infmt = y; break; #endif /* COMMENT */ case SSHKD_OUT: /* /FORMAT: */ if ((y = cmkey(sshdofmt,nsshdofmt, "","",xxstring)) < 0) return(y); outfmt = y; break; } } if (cmresult.fcode == _CMIFI) { /* Filename */ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); if (zfnqfp(line,TMPBUFSIZ,tmpbuf)) ckstrncpy(line,tmpbuf,LINBUFSIZ); } #ifdef COMMENT if (!line[0]) { printf("?Key filename required\n"); return(-9); } #endif /* COMMENT */ if ((y = cmcfm()) < 0) /* Confirm */ return(y); #ifndef SSHTEST switch (outfmt) { case SKDF_OSSH: /* 2nd param is optional passphrase */ x = sshkey_display_public(line[0] ? line : NULL, NULL); break; case SKDF_SSHC: /* 2nd param is optional passphrase */ x = sshkey_display_public_as_ssh2(line[0] ? line : NULL, NULL); break; case SKDF_IETF: x = sshkey_display_fingerprint(line[0] ? line : NULL, 1); break; case SKDF_FING: x = sshkey_display_fingerprint(line[0] ? line : NULL, 0); break; } #endif /* SSHTEST */ return(success = (x == 0)); } #ifdef COMMENT case SSHK_V1: /* SSH KEY V1 SET-COMMENT */ if ((x = cmkey(sshkv1,1,"","set-comment", xxstring)) < 0) return(x); if (x != 1) return(-2); if ((x = cmifi("Key file name","",&s,&y,xxstring)) < 0) { if (x == -3) { printf("?Name of key file required\n"); return(-9); } } ckstrncpy(line,s,LINBUFSIZ); if ((x = cmtxt("Comment text","",&s,xxstring)) < 0) return(x); #ifndef SSHTEST x = sshkey_v1_change_comment(line, /* filename */ s, /* new comment */ NULL /* passphrase */ ); #endif /* SSHTEST */ success = (x == 0); return(success); #endif /* COMMENT - SSH KEY V1 SET-COMMENT */ } default: return(-2); } #else /* SSHBUILTIN */ #ifdef SSHCMD x = nettype; debug(F101,"SSH external nettype","",nettype); debug(F101,"SSH external calling setlin","",0); if ((y = setlin(XXSSH,0,1)) < 0) { if (errno) printf("?%s\n",ck_errstr()); else #ifdef COMMENT /* This isn't right either because it catches command editing */ printf("?Sorry, pseudoterminal open failed\n"); if (hints) printf("Hint: Try \"ssh -t %s\"\n",line); #else return(y); #endif /* COMMENT */ nettype = x; /* Failed, restore net type. */ ttnproto = z; /* and protocol */ success = 0; } didsetlin++; netsave = x; return(y); #endif /* SSHCMD */ #endif /* SSHBUILTIN */ } #endif /* ANYSSH */ #ifdef SSHBUILTIN if (cx == XXSKRM) { /* SKERMIT (Secure Shell Kermit) */ extern int netsave; int k, x, havehost = 0, trips = 0; int tmpver = -1, tmpxfw = -1; #ifndef SSHTEST extern int sl_ssh_xfw, sl_ssh_xfw_saved; extern int sl_ssh_ver, sl_ssh_ver_saved; #endif /* SSHTEST */ extern int mdmtyp, mdmsav, cxtype, sl_uid_saved; extern char * slmsg; extern char uidbuf[], sl_uidbuf[]; extern char pwbuf[], * g_pswd; extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal; struct FDB sw, kw, fl; #if SSH_DLL if (!ssh_avail()) { printf("\nNo SSH backend DLL loaded. SSH commands unavailable. Use the SSH LOAD command\n"); printf("to load a compatible SSH backend if you have one.\n"); return (-9); } #endif /* SSH_DLL */ if (ssh_tmpstr) memset(ssh_tmpstr,0,strlen(ssh_tmpstr)); makestr(&ssh_tmpstr,NULL); makestr(&ssh_tmpuid,NULL); makestr(&ssh_tmpcmd,NULL); makestr(&ssh_tmpport,NULL); cmfdbi(&kw, /* 1st FDB - commands */ _CMKEY, /* fcode */ "host [ port ],\n or action", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nsshkermit, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: 0 = keyword */ xxstring, /* Processing function */ sshkermit, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* Host */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); x = cmfdb(&kw); if (x == -3) { printf("?skermit what?\n"); return(-9); } if (x < 0) return(x); havehost = 0; if (cmresult.fcode == _CMFLD) { havehost = 1; ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Hostname */ cmresult.nresult = SKRM_OPN; } switch (cmresult.nresult) { /* SSH keyword */ case SKRM_OPN: /* SSH OPEN */ if (!havehost) { if ((x = cmfld("Host","",&s,xxstring)) < 0) return(x); ckstrncpy(line,s,LINBUFSIZ); } /* Parse [ port ] [ switches ] */ cmfdbi(&kw, /* Switches */ _CMKEY, "Port number or service name,\nor switch", "", "", nsshkrmopnsw, 4, xxstring, sshkrmopnsw, &fl ); cmfdbi(&fl, /* Port number or service name */ _CMFLD, "", "", "", 0, 0, xxstring, NULL, NULL ); trips = 0; /* Explained below */ while (1) { /* Parse port and switches */ x = cmfdb(&kw); /* Get a field */ if (x == -3) /* User typed CR so quit from loop */ break; if (x < 0) /* Other parse error, pass it back */ return(x); switch (cmresult.fcode) { /* Field or Keyword? */ case _CMFLD: /* Field */ makestr(&ssh_tmpport,cmresult.sresult); break; case _CMKEY: /* Keyword */ switch (cmresult.nresult) { /* Which one? */ case SSHSW_USR: /* /USER: */ if (!cmgbrk()) { printf("?This switch requires an argument\n"); return(-9); } if ((y = cmfld("Username","",&s,xxstring)) < 0) return(y); s = brstrip(s); makestr(&ssh_tmpuid,s); break; case SSHSW_PWD: if (!cmgbrk()) { printf("?This switch requires an argument\n"); return(-9); } debok = 0; if ((x = cmfld("Password","",&s,xxstring)) < 0) { if (x == -3) { makestr(&ssh_tmpstr,""); } else { return(x); } } else { s = brstrip(s); if ((x = (int)strlen(s)) > PWBUFL) { makestr(&slmsg,"Internal error"); printf("?Sorry, too long - max = %d\n",PWBUFL); return(-9); } makestr(&ssh_tmpstr,s); } break; case SSHSW_VER: if ((x = cmnum("Number","",10,&z,xxstring)) < 0) return(x); if (z < 1 || z > 2) { printf("?Out of range: %d\n",z); return(-9); } tmpver = z; break; default: return(-2); } } if (trips++ == 0) { /* After first time through */ cmfdbi(&kw, /* only parse switches, not port. */ _CMKEY, "Switch", "", "", nsshkrmopnsw, 4, xxstring, sshkrmopnsw, NULL ); } } if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); if (clskconnx(1) < 0) { /* Close current Kermit connection */ if ( ssh_tmpstr ) { memset(ssh_tmpstr,0,strlen(ssh_tmpstr)); makestr(&ssh_tmpstr,NULL); } return(success = 0); } ssh_set_sparam(SSH_SPARAM_HST,line); /* Stash everything */ if (ssh_tmpuid) { if (!sl_uid_saved) { ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN); sl_uid_saved = 1; } ckstrncpy(uidbuf,ssh_tmpuid,UIDBUFLEN); makestr(&ssh_tmpuid,NULL); } if (ssh_tmpport) { ssh_set_sparam(SSH_SPARAM_PRT,ssh_tmpport); makestr(&ssh_tmpport,NULL); } else { ssh_set_sparam(SSH_SPARAM_PRT,NULL); } /* Set the Subsystem to Kermit */ ssh_set_iparam(SSH_IPARAM_CAS, 1); ssh_set_sparam(SSH_SPARAM_CMD, "kermit"); if (tmpver > -1) { #ifndef SSHTEST if (!sl_ssh_ver_saved) { sl_ssh_ver = ssh_get_iparam(SSH_IPARAM_VER); sl_ssh_ver_saved = 1; } #endif /* SSHTEST */ ssh_set_iparam(SSH_IPARAM_VER, tmpver); } /* Disable X11 Forwarding */ #ifndef SSHTEST if (!sl_ssh_xfw_saved) { sl_ssh_xfw = ssh_get_iparam(SSH_IPARAM_XFW); sl_ssh_xfw_saved = 1; } #endif /* SSHTEST */ ssh_set_iparam(SSH_IPARAM_XFW, 0); if (ssh_tmpstr) { if (ssh_tmpstr[0]) { ckstrncpy(pwbuf,ssh_tmpstr,PWBUFL+1); pwflg = 1; pwcrypt = 0; } else pwflg = 0; makestr(&ssh_tmpstr,NULL); } nettype = NET_SSH; if (mdmsav < 0) mdmsav = mdmtyp; mdmtyp = -nettype; x = 1; #ifndef NOSPL makestr(&g_pswd,pwbuf); /* Save global pwbuf */ g_pflg = pwflg; /* and flag */ g_pcpt = pwcrypt; #endif /* NOSPL */ /* Line parameter to ttopen() is ignored */ k = ttopen(line,&x,mdmtyp, 0); if (k < 0) { printf("?Unable to connect to %s\n",ssh_get_sparam(SSH_SPARAM_HST)); mdmtyp = mdmsav; slrestor(); return(success = 0); } duplex = 0; /* Remote echo */ ckstrncpy(ttname,line,TTNAMLEN); /* Record the command */ debug(F110,"ssh ttname",ttname,0); makestr(&slmsg,NULL); /* No SET LINE error message */ cxtype = CXT_SSH; #ifndef NODIAL dialsta = DIA_UNK; #endif /* NODIAL */ success = 1; /* SET LINE succeeded */ network = 1; /* Network connection (not serial) */ local = 1; /* Local mode (not remote) */ if ((reliable != SET_OFF || !setreliable)) reliable = SET_ON; /* Transport is reliable end to end */ #ifdef OS2 DialerSend(OPT_KERMIT_CONNECT, 0); #endif /* OS2 */ setflow(); /* Set appropriate flow control */ haveline = 1; #ifdef CKLOGDIAL #ifdef NETCONN dolognet(); #endif /* NETCONN */ #endif /* CKLOGDIAL */ #ifndef NOSPL if (local) { if (nmac) { /* Any macros defined? */ int k; /* Yes */ k = mlook(mactab,"on_open",nmac); /* Look this up */ if (k >= 0) { /* If found, */ if (dodo(k,ssh_get_sparam(SSH_SPARAM_HST),0) > -1) /* set it up, */ parser(1); /* and execute it */ } } } #endif /* NOSPL */ #ifdef LOCUS if (autolocus) setlocus(1,1); #endif /* LOCUS */ /* Command was confirmed so we can pre-pop command level. */ /* This is so CONNECT module won't think we're executing a */ /* script if CONNECT was the final command in the script. */ if (cmdlvl > 0) prepop(); return(success = 1); default: return(-2); } } #endif /* SSHBUILTIN */ #ifdef SFTP_BUILTIN if (cx == XXSFTP) { /* SFTP (Secure Shell File Transfer) */ extern int netsave; int k, x, havehost = 0, trips = 0; int tmpver = -1, tmpxfw = -1; #ifndef SSHTEST extern int sl_ssh_xfw, sl_ssh_xfw_saved; extern int sl_ssh_ver, sl_ssh_ver_saved; #endif /* SSHTEST */ extern int mdmtyp, mdmsav, cxtype, sl_uid_saved; extern char * slmsg; extern char uidbuf[], sl_uidbuf[]; extern char pwbuf[], * g_pswd; extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal; struct FDB sw, kw, fl; if (ssh_tmpstr) memset(ssh_tmpstr,0,strlen(ssh_tmpstr)); makestr(&ssh_tmpstr,NULL); makestr(&ssh_tmpuid,NULL); makestr(&ssh_tmpcmd,NULL); makestr(&ssh_tmpport,NULL); cmfdbi(&kw, /* 1st FDB - commands */ _CMKEY, /* fcode */ "host [ port ],\n or action", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nsftpkwtab, /* addtl numeric data 1: tbl size */ 0, /* addtl numeric data 2: 0 = keyword */ xxstring, /* Processing function */ sftpkwtab, /* Keyword table */ &fl /* Pointer to next FDB */ ); cmfdbi(&fl, /* Host */ _CMFLD, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); x = cmfdb(&kw); if (x == -3) { printf("?sftp what?\n"); return(-9); } if (x < 0) return(x); havehost = 0; if (cmresult.fcode == _CMFLD) { havehost = 1; ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Hostname */ cmresult.nresult = SFTP_OPN; } switch (cmresult.nresult) { /* SFTP keyword */ case SFTP_OPN: /* SFTP OPEN */ if (!havehost) { if ((x = cmfld("Host","",&s,xxstring)) < 0) return(x); ckstrncpy(line,s,LINBUFSIZ); } /* Parse [ port ] [ switches ] */ cmfdbi(&kw, /* Switches */ _CMKEY, "Port number or service name,\nor switch", "", "", nsshkrmopnsw, 4, xxstring, sshkrmopnsw, &fl ); cmfdbi(&fl, /* Port number or service name */ _CMFLD, "", "", "", 0, 0, xxstring, NULL, NULL ); trips = 0; /* Explained below */ while (1) { /* Parse port and switches */ x = cmfdb(&kw); /* Get a field */ if (x == -3) /* User typed CR so quit from loop */ break; if (x < 0) /* Other parse error, pass it back */ return(x); switch (cmresult.fcode) { /* Field or Keyword? */ case _CMFLD: /* Field */ makestr(&ssh_tmpport,cmresult.sresult); break; case _CMKEY: /* Keyword */ switch (cmresult.nresult) { /* Which one? */ case SSHSW_USR: /* /USER: */ if (!cmgbrk()) { printf("?This switch requires an argument\n"); return(-9); } if ((y = cmfld("Username","",&s,xxstring)) < 0) return(y); s = brstrip(s); makestr(&ssh_tmpuid,s); break; case SSHSW_PWD: if (!cmgbrk()) { printf("?This switch requires an argument\n"); return(-9); } debok = 0; if ((x = cmfld("Password","",&s,xxstring)) < 0) { if (x == -3) { makestr(&ssh_tmpstr,""); } else { return(x); } } else { s = brstrip(s); if ((x = (int)strlen(s)) > PWBUFL) { makestr(&slmsg,"Internal error"); printf("?Sorry, too long - max = %d\n",PWBUFL); return(-9); } makestr(&ssh_tmpstr,s); } break; case SSHSW_VER: if ((x = cmnum("Number","",10,&z,xxstring)) < 0) return(x); if (z < 1 || z > 2) { printf("?Out of range: %d\n",z); return(-9); } tmpver = z; break; default: return(-2); } } if (trips++ == 0) { /* After first time through */ cmfdbi(&kw, /* only parse switches, not port. */ _CMKEY, "Switch", "", "", nsshkrmopnsw, 4, xxstring, sshkrmopnsw, NULL ); } } if ((x = cmcfm()) < 0) /* Get confirmation */ return(x); if (clskconnx(1) < 0) { /* Close current Kermit connection */ if ( ssh_tmpstr ) { memset(ssh_tmpstr,0,strlen(ssh_tmpstr)); makestr(&ssh_tmpstr,NULL); } return(success = 0); } ssh_set_sparam(SSH_SPARAM_HST, line); /* Stash everything */ if (ssh_tmpuid) { if (!sl_uid_saved) { ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN); sl_uid_saved = 1; } ckstrncpy(uidbuf,ssh_tmpuid,UIDBUFLEN); makestr(&ssh_tmpuid,NULL); } if (ssh_tmpport) { ssh_set_sparam(SSH_SPARAM_PRT,ssh_tmpport); makestr(&ssh_tmpport,NULL); } else { ssh_set_sparam(SSH_SPARAM_PRT,NULL); } /* Set the Subsystem to sftp */ ssh_set_iparam(SSH_IPARAM_CAS, 1); ssh_set_sparam(SSH_SPARAM_CMD, "sftp"); if (tmpver > -1) { #ifndef SSHTEST if (!sl_ssh_ver_saved) { sl_ssh_ver = ssh_ver; sl_ssh_ver_saved = 1; } #endif /* SSHTEST */ ssh_ver = tmpver; } /* Disable X11 Forwarding */ #ifndef SSHTEST if (!sl_ssh_xfw_saved) { sl_ssh_xfw = ssh_xfw; sl_ssh_xfw_saved = 1; } #endif /* SSHTEST */ ssh_xfw = 0; if (ssh_tmpstr) { if (ssh_tmpstr[0]) { ckstrncpy(pwbuf,ssh_tmpstr,PWBUFL+1); pwflg = 1; pwcrypt = 0; } else pwflg = 0; makestr(&ssh_tmpstr,NULL); } nettype = NET_SSH; if (mdmsav < 0) mdmsav = mdmtyp; mdmtyp = -nettype; x = 1; #ifndef NOSPL makestr(&g_pswd,pwbuf); /* Save global pwbuf */ g_pflg = pwflg; /* and flag */ g_pcpt = pwcrypt; #endif /* NOSPL */ /* Line parameter to ttopen() is ignored */ k = ttopen(line,&x,mdmtyp, 0); if (k < 0) { printf("?Unable to connect to %s\n", ssh_get_sparam(SSH_SPARAM_HST)); mdmtyp = mdmsav; slrestor(); return(success = 0); } duplex = 0; /* Remote echo */ ckstrncpy(ttname,line,TTNAMLEN); /* Record the command */ debug(F110,"ssh ttname",ttname,0); makestr(&slmsg,NULL); /* No SET LINE error message */ cxtype = CXT_SSH; #ifndef NODIAL dialsta = DIA_UNK; #endif /* NODIAL */ success = 1; /* SET LINE succeeded */ network = 1; /* Network connection (not serial) */ local = 1; /* Local mode (not remote) */ if ((reliable != SET_OFF || !setreliable)) reliable = SET_ON; /* Transport is reliable end to end */ #ifdef OS2 DialerSend(OPT_KERMIT_CONNECT, 0); #endif /* OS2 */ setflow(); /* Set appropriate flow control */ haveline = 1; #ifdef CKLOGDIAL #ifdef NETCONN dolognet(); #endif /* NETCONN */ #endif /* CKLOGDIAL */ #ifndef NOSPL if (local) { if (nmac) { /* Any macros defined? */ int k; /* Yes */ k = mlook(mactab,"on_open",nmac); /* Look this up */ if (k >= 0) { /* If found, */ if (dodo(k,ssh_get_sparam(SSH_SPARAM_HST),0) > -1) /* set it up, */ parser(1); /* and execute it */ } } } #endif /* NOSPL */ #ifdef LOCUS if (autolocus) setlocus(1,1); #endif /* LOCUS */ /* Command was confirmed so we can pre-pop command level. */ /* This is so CONNECT module won't think we're executing a */ /* script if CONNECT was the final command in the script. */ if (cmdlvl > 0) prepop(); success = sftp_do_init(); return(success = 1); case SFTP_CD: case SFTP_CHGRP: case SFTP_CHMOD: case SFTP_CHOWN: case SFTP_RM: case SFTP_DIR: case SFTP_GET: case SFTP_MKDIR: case SFTP_PUT: case SFTP_PWD: case SFTP_REN: case SFTP_RMDIR: case SFTP_LINK: case SFTP_VER: if ((y = cmtxt("command parameters","",&s,xxstring)) < 0) return(y); if (ssh_tchk() < 0 || !ssh_get_iparam(SSH_IPARAM_CAS) || strcmp(ssh_get_sparam(SSH_SPARAM_CMD), "sftp")) { printf("?Not connected to SFTP Service\n"); return(success = 0); } success = sftp_do_cmd(cmresult.nresult,s); return(success); default: return(-2); } } #endif /* SFTP_BUILTIN */ if (cx == XXRLOG) { /* RLOGIN */ #ifdef RLOGCODE int x,z; #ifdef OS2 if (!tcp_avail) { printf("?Sorry, either TCP/IP is not available on this system or\n\ necessary DLLs did not load. Use SHOW NETWORK to check network status.\n" ); success = 0; return(-9); } else { #endif /* OS2 */ x = nettype; /* Save net type in case of failure */ z = ttnproto; /* Save protocol in case of failure */ nettype = NET_TCPB; ttnproto = NP_RLOGIN; if ((y = setlin(XYHOST,0,1)) <= 0) { nettype = x; /* Failed, restore net type. */ ttnproto = z; /* and protocol */ success = 0; } didsetlin++; #ifdef OS2 } #endif /* OS2 */ return(y); #else printf("?Sorry, RLOGIN is not configured in this copy of C-Kermit.\n"); return(-9); #endif /* RLOGCODE */ } #endif /* NOLOCAL */ #ifndef NOXMIT if (cx == XXTRA) { /* TRANSMIT */ extern int xfrxla; int n, xpipe = 0, xbinary = 0, xxlate = 1, xxnowait = 0, getval; int xxecho = 0; int scan = 1; char c; struct FDB sf, sw, tx; /* FDBs for parse functions */ #ifndef NOCSETS extern int tcs_transp; /* Term charset is transparent */ #else int tcs_transp = 1; #endif /* NOCSETS */ #ifdef COMMENT xbinary = binary; /* Default text/binary mode */ #else xbinary = 0; /* Default is text */ #endif /* COMMENT */ xxecho = xmitx; cmfdbi(&sw, /* First FDB - command switches */ _CMKEY, /* fcode */ "Filename, or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ nxmitsw, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ xmitsw, /* Keyword table */ &sf /* Pointer to next FDB */ ); cmfdbi(&sf, /* 2nd FDB - file to send */ _CMIFI, /* fcode */ "File to transmit", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, #ifdef PIPESEND &tx #else NULL #endif /* PIPESEND */ ); #ifdef PIPESEND cmfdbi(&tx, _CMTXT, /* fcode */ "Command", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); #endif /* PIPESEND */ while (1) { x = cmfdb(&sw); if (x < 0) return(x); if (cmresult.fcode != _CMKEY) break; c = cmgbrk(); /* Have switch, get break character */ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } n = cmresult.nresult; /* Numeric result = switch ID */ switch (n) { /* Process the switch */ #ifdef PIPESEND case XMI_CMD: /* Transmit from a command */ if (nopush) { printf("?Sorry, system command access is disabled\n"); return(-9); } sw.hlpmsg = "Command, or switch"; /* Change help message */ xpipe = 1; /* (No way to undo this one) */ break; #endif /* PIPESEND */ case XMI_BIN: /* Binary */ xbinary = 1; xxlate = 0; /* Don't translate charsets */ scan = 0; break; case XMI_TXT: /* Text */ xbinary = 0; xxlate = !tcs_transp; /* Translate if TERM CHAR not TRANSP */ scan = 0; break; case XMI_TRA: /* Transparent text */ xbinary = 0; xxlate = 0; /* But don't translate charsets */ scan = 0; break; #ifdef COMMENT case XMI_VRB: /* /VERBOSE */ case XMI_QUI: /* /QUIET */ break; /* (not implemented yet) */ #endif /* COMMENT */ case XMI_NOW: /* /NOWAIT */ xxnowait = 1; break; case XMI_NOE: /* /NOWAIT */ xxecho = 0; break; default: return(-2); } } if (cmresult.fcode != _CMIFI && cmresult.fcode != _CMTXT) return(-2); ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Filename */ if (zfnqfp(line,TMPBUFSIZ,tmpbuf)) ckstrncpy(line,tmpbuf,LINBUFSIZ); s = line; if ((y = cmcfm()) < 0) /* Confirm */ return(y); #ifdef CK_APC if ((apcactive == APC_LOCAL) || ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH)))) return(success = 0); #endif /* CK_APC */ if (cmresult.nresult != 0) { printf("?Only a single file may be transmitted\n"); return(-9); } #ifdef PIPESEND if (xpipe) { s = brstrip(s); if (!*s) { printf("?Sorry, a command to send from is required\n"); return(-9); } pipesend = 1; } #endif /* PIPESEND */ if (scan && (filepeek #ifndef NOXFER || patterns #endif /* NOXFER */ )) { /* If user didn't specify type */ int k, x; /* scan the file to see */ x = -1; k = scanfile(s,&x,nscanfile); if (k > 0) xbinary = (k == FT_BIN) ? XYFT_B : XYFT_T; } if (!xfrxla) xxlate = 0; success = transmit(s, (char) (xxnowait ? '\0' : (char)xmitp), xxlate, xbinary, xxecho ); return(success); } #endif /* NOXMIT */ #ifndef NOFRILLS if (cx == XXTYP || cx == XXCAT || cx == XXMORE || cx == XXHEAD || cx == XXTAIL) { int paging = 0, havename = 0, head = 0, width = 0; int count = 0; char pfxbuf[64], * prefix = NULL; char outfile[CKMAXPATH+1]; struct FDB sf, sw; char * pat = NULL; int incs = 0, outcs = 0, cset = -1, number = 0; #ifdef UNICODE char * tocs = ""; extern int fileorder; #ifdef OS2 #ifdef NT #ifdef KUI int height = 0; char guibuf[128], * gui_title = NULL; int gui = 0; #endif /* KUI */ #endif /* NT */ #ifndef NOCSETS extern int tcsr, tcsl; #endif /* NOCSETS */ #endif /* OS2 */ #endif /* UNICODE */ #ifdef TYPEINTERPRET type_intrp = 0; /* Always start with this off */ #endif /* TYPEINTERPRET */ outfile[0] = NUL; if (cx == XXMORE) paging = 1; else if (cx == XXCAT) paging = 0; else paging = (typ_page < 0) ? xaskmore : typ_page; if (paging < 0) paging = saveask; if (cx == XXHEAD) { head = 10; cx = XXTYP; } else if (cx == XXTAIL) { head = -10; cx = XXTYP; } #ifdef IKSD if (inserver && !ENABLED(en_typ)) { printf("?Sorry, TYPE command disabled\n"); return(-9); } #endif /* IKSD */ cmfdbi(&sw, /* 2nd FDB - optional /PAGE switch */ _CMKEY, /* fcode */ "Filename or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ ntypetab, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ typetab, /* Keyword table */ &sf /* Pointer to next FDB */ ); cmfdbi(&sf, /* 1st FDB - file to type */ _CMIFI, /* fcode */ "", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 0, /* addtl numeric data 1 */ 0, /* addtl numeric data 2 */ xxstring, NULL, NULL ); while (!havename) { x = cmfdb(&sw); /* Parse something */ debug(F101,"type cmfdb","",x); debug(F101,"type cmresult.fcode","",cmresult.fcode); debug(F101,"type cmresult.nresult","",cmresult.nresult); if (x < 0) { /* Error */ if (x == -3) { x = -9; printf("?Filename required\n"); } return(x); } else if (cmresult.fcode == _CMKEY) { char c; int getval; c = cmgbrk(); getval = (c == ':' || c == '='); if (getval && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } #ifdef COMMENT if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); /* Not if it has a default! */ return(-9); } #endif /* COMMENT */ switch (cmresult.nresult) { #ifdef CK_TTGWSIZ case TYP_PAG: paging = 1; break; case TYP_NOP: paging = 0; break; #endif /* CK_TTGWSIZ */ case TYP_COU: paging = 0; count = 1; break; case TYP_HEA: case TYP_TAI: y = 10; if (getval) if ((x = cmnum("Number of lines", "10",10,&y,xxstring)) < 0) return(x); head = (cmresult.nresult == TYP_TAI) ? -y : y; break; case TYP_WID: y = typ_wid > -1 ? typ_wid : cmd_cols; if (getval) if ((x = cmnum("Column at which to truncate", ckitoa(y),10,&y,xxstring)) < 0) return(x); width = y; break; #ifdef KUI case TYP_HIG: if (getval) if ((x = cmnum("Height of GUI dialog", ckitoa(y),10,&y,xxstring)) < 0) return(x); height = y; break; #endif /* KUI */ case TYP_PAT: if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } if ((x = cmfld("pattern","",&s,xxstring)) < 0) return(x); ckstrncpy(tmpbuf,s,TMPBUFSIZ); pat = tmpbuf; break; case TYP_PFX: if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } if ((x = cmfld("prefix for each line","",&s,xxstring)) < 0) return(x); if ((int)strlen(s) > 63) { printf("?Too long - 63 max\n"); return(-9); } ckstrncpy(pfxbuf,s,64); prefix = brstrip(pfxbuf); number = 0; break; #ifdef KUI case TYP_GUI: if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } if ((x = cmfld("Dialog box title","",&s,xxstring)) < 0) { if (x != -3) return(x); } else { if ((int)strlen(s) > 127) { printf("?Too long - 127 max\n"); return(-9); } ckstrncpy(guibuf,s,128); gui_title = brstrip(guibuf); } gui = 1; break; #endif /* KUI */ case TYP_NUM: /* /NUMBER */ number = 1; prefix = NULL; break; #ifdef UNICODE case TYP_XPA: /* /TRANSPARENT */ incs = 0; cset = 0; outcs = -1; break; #ifdef TYPEINTERPRET case TYP_INT: /* /INTERPRET */ type_intrp = 1; break; #endif /* TYPEINTERPRET */ case TYP_XIN: /* /CHARACTER-SET: */ if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } if ((incs = cmkey(fcstab,nfilc, "character-set name","",xxstring)) < 0) { if (incs == -3) /* Note: No default */ incs = -2; return(incs); } cset = incs; break; case TYP_XUT: /* /TRANSLATE-TO: */ if (!getval && (cmgkwflgs() & CM_ARG)) { printf("?This switch requires an argument\n"); return(-9); } #ifdef OS2 if (!inserver && !k95stdout) { tocs = "ucs2"; } else { #ifdef CKOUNI tocs = rlookup(txrtab,ntxrtab,tcsl); #else /* CKOUNI */ extern struct keytab ttcstab[]; extern int ntxrtab; tocs = rlookup(ttcstab,ntermc,tocs); if (!tocs) tocs = getdcset(); #endif /* CKOUNI */ } #else /* OS2 */ tocs = getdcset(); #endif /* OS2 */ if ((outcs = cmkey(fcstab,nfilc, "character-set",tocs,xxstring)) < 0) return(outcs); break; #endif /* UNICODE */ case TYP_OUT: if ((x = cmofi("File for result lines","", &s,xxstring)) < 0) return(x); ckstrncpy(outfile,s,CKMAXPATH); break; } } else if (cmresult.fcode == _CMIFI) havename = 1; else return(-2); } if (havename) { ckstrncpy(line,cmresult.sresult,LINBUFSIZ); y = cmresult.nresult; } else { if ((x = cmifi("Filename","",&s,&y,xxstring)) < 0) { if (x == -3) { printf("?Name of an existing file required\n"); return(-9); } else return(x); } ckstrncpy(line,s,LINBUFSIZ); } if (y != 0) { printf("?A single file please\n"); return(-9); } #ifdef KUI if ( outfile[0] && gui ) { printf("?/GUI and /OUTPUT are incompatible\n"); return(-9); } #endif /* KUI */ if ((y = cmcfm()) < 0) /* Confirm the command */ return(y); #ifdef UNICODE fileorder = -1; if (cset < 0 && filepeek) { /* If no charset switches given */ int k, x = -1; k = scanfile(line,&x,nscanfile); /* Call file analyzer */ debug(F111,"type scanfile",line,k); debug(F101,"type scanfile flag","",x); switch(k) { case FT_UTF8: /* which can detect UTF-8... */ cset = 0; incs = FC_UTF8; break; case FT_UCS2: /* and UCS-2... */ cset = 0; incs = FC_UCS2; fileorder = x; /* even if there is no BOM. */ debug(F101,"type fileorder","",fileorder); break; } } #ifdef OS2 if (cset < 0) { /* If input charset still not known */ #ifdef CKOUNI tocs = rlookup(txrtab,ntxrtab,tcsl); #else /* CKOUNI */ extern struct keytab ttcstab[]; extern int ntxrtab; tocs = rlookup(ttcstab,ntermc,incs); if (!tocs) tocs = getdcset(); #endif /* CKOUNI */ incs = lookup(fcstab,tocs,nfilc,&x); } #endif /* OS2 */ if (outcs == 0 && incs != 0) { /* Supply default target charset */ int x = 0; /* if switch not given. */ tocs = getdcset(); outcs = lookup(fcstab,tocs,nfilc,&x); } #else /* !UNICODE */ if (cset < 0) incs = outcs = 0; #endif /* UNICODE */ if (outfile[0] && paging) /* This combination makes no sense */ paging = 0; /* so turn off paging */ #ifdef KUI /* No paging when dialog is used */ if ( gui && paging ) paging = 0; if ( !gui && height ) { printf("?The /HEIGHT switch is not supported without /GUI\n"); return(-9); } #endif /* KUI */ if (count) paging = -1; debug(F111,"type",line,paging); #ifdef KUI #ifndef NORICHEDIT if ( gui ) { s = (char *)1; /* ok, its an ugly hack */ if (gui_text_popup_create(gui_title ? gui_title : line, height,width) < 0) { printf("?/GUI not supported on this system\n"); gui = 0; return(-9); } width = 0; } else #endif /* NORICHEDIT */ #endif /* KUI */ s = outfile; success = dotype(line,paging,0,head,pat,width,prefix,incs,outcs,s,number); return(success); } #endif /* NOFRILLS */ #ifndef NOCSETS if (cx == XXXLA) { /* TRANSLATE file's charset */ _PROTOTYP (int doxlate, ( void ) ); return(doxlate()); } #endif /* NOCSETS */ if (cx == XXVER) { /* VERSION */ int n = 0; extern char * ck_patch, * ck_s_test; #ifdef COMMENT extern int hmtopline; #endif /* COMMENT */ if ((y = cmcfm()) < 0) return(y); #ifdef CK_64BIT printf("\n%s, for%s (64-bit)\n Numeric: %ld",versio,ckxsys,vernum); #else printf("\n%s, for%s\n Numeric: %ld",versio,ckxsys,vernum); #endif /* CK_64BIT */ printf("\n\n"); printf("Authors:\n"); printf(" Frank da Cruz, the Kermit Project %s\n", "" ); printf(" Jeffrey Eric Altman, Secure Endpoints, Inc. %s\n", "" ); printf(" David Goodwin %s\n", "" ); printf(" Contributions from many others.\n"); n = 7; if (*ck_s_test) { printf("\nTHIS IS A TEST VERSION, NOT FOR PRODUCTION USE.\n"); n += 2; } if (*ck_patch) { printf(" Patches: %s\n", ck_patch); n++; } printf(" Type COPYRIGHT for copyright and license.\n\n"); #ifdef OS2 #ifdef COMMENT shoreg(); #endif /* COMMENT */ #else #ifdef COMMENT hmtopline = n+1; hmsga(copyright); hmtopline = 0; #endif /* COMMENT */ #endif /* OS2 */ return(success = 1); } if (cx == XXCPR) { /* COPYRIGHT or LICENSE */ _PROTOTYP( int hmsgaa, (char * [], char *) ); extern char * ck_cryear; if ((y = cmcfm()) < 0) return(y); hmsgaa(copyright,ck_cryear); return(success = 1); } #ifndef MAC /* Only for multiuser systems */ #ifndef OS2 #ifndef NOFRILLS if (cx == XXWHO) { /* WHO */ char *wc; #ifdef IKSD if (inserver && !ENABLED(en_who)) { printf("?Sorry, WHO command disabled\n"); return(-9); } #endif /* IKSD */ #ifdef datageneral if ((z = cmcfm()) < 0) return(z); if (nopush) { printf("?Sorry, who not allowed\n"); return(success = 0); } xsystem(WHOCMD); #else if ((y = cmtxt("user name","",&s,xxstring)) < 0) return(y); if (nopush) { printf("?Sorry, WHO command disabled\n"); return(success = 0); } if (!(wc = getenv("CK_WHO"))) wc = WHOCMD; if (wc) if ((int) strlen(wc) > 0) { ckmakmsg(line,LINBUFSIZ,wc," ",s,NULL); xsystem(line); } #endif /* datageneral */ return(success = 1); } #endif /* NOFRILLS */ #endif /* OS2 */ #endif /* MAC */ #ifndef NOFRILLS if (cx == XXWRI || cx == XXWRL || cx == XXWRBL) { /* WRITE */ int x,y; /* On stack in case of \fexec() */ if ((x = cmkey(writab,nwri,"to file or log","",xxstring)) < 0) { if (x == -3) printf("?Write to what?\n"); return(x); } if ((y = cmtxt("text","",&s,xxstring)) < 0) return(y); s = brstrip(s); switch (x) { case LOGD: y = ZDFILE; break; case LOGP: y = ZPFILE; break; #ifndef NOLOCAL case LOGS: y = ZSFILE; break; #endif /* NOLOCAL */ case LOGT: y = ZTFILE; break; #ifndef NOSPL case LOGW: y = ZWFILE; break; #endif /* NOSPL */ case LOGX: /* SCREEN (stdout) */ case LOGE: /* ERROR (stderr) */ if (x == LOGE) { debug(F110, (cx == XXWRL) ? "WRITELN ERROR" : "WRITE ERROR", s,0); fprintf(stderr,"%s%s",s,(cx == XXWRL) ? "\n" : ""); } else { debug(F110, (cx == XXWRL) ? "WRITELN SCREEN" : "WRITE SCREEN", s,0); printf("%s%s",s,(cx == XXWRL) ? "\n" : ""); } return(success = 1); default: return(-2); } if (chkfn(y) > 0) { x = (cx == XXWRI) ? zsout(y,s) : zsoutl(y,s); debug(F111,"WRITE", (cx == XXWRI) ? "zsout" : "zsoutl", x); if (x < 0) printf("?Write error\n"); } else { x = -1; printf("?File or log not open\n"); } debug(F101,"WRITE x","",x); return(success = (x == 0) ? 1 : 0); } #endif /* NOFRILLS */ #ifndef NOXFER if (cx == XXASC || cx == XXBIN) { if ((x = cmcfm()) < 0) return(x); #ifdef NEWFTP /* Make C-Kermit work like other ftp clients, where the ASCII (TEXT) and BINARY commands are global settings. */ if (ftpisopen()) { doftpglobaltype((cx == XXASC) ? XYFT_T : XYFT_B); /* Fall thru--the command it should apply to both FTP and Kermit */ /* return(success = 1); */ } #endif /* NEWFTP */ xfermode = XMODE_M; /* Set manual Kermit transfer mode */ binary = (cx == XXASC) ? XYFT_T : XYFT_B; return(success = 1); } #endif /* NOXFER */ if (cx == XXCLS) { if ((x = cmcfm()) < 0) return(x); y = ck_cls(); return(success = (y > -1) ? 1 : 0); } #ifdef CK_MKDIR if (cx == XXMKDIR || cx == XXLMKD) { char *p; #ifdef LOCUS if (!locus && cx != XXLMKD) { #ifdef NOXFER return(-2); #else return(dormt(XZMKD)); #endif /* NOXFER */ } #endif /* LOCUS */ #ifdef IKSD if (inserver && !ENABLED(en_mkd)) { printf("?Sorry, directory creation is disabled\n"); return(-9); } #endif /* IKSD */ if ((x = cmfld("Name for new directory","",&s,xxstring)) < 0) { if (x != -3) { return(x); } else { printf("?Directory name required\n"); return(-9); } } ckstrncpy(line,s,LINBUFSIZ); s = line; if ((x = cmcfm()) < 0) return(x); s = brstrip(s); bgchk(); /* Set msgflg */ x = ckmkdir(0,s,&p,msgflg,0); #ifdef COMMENT if (msgflg && x == 0) printf("?Directory already exists\n"); #endif /* COMMENT */ return(success = (x < 0) ? 0 : 1); } if (cx == XXRMDIR || cx == XXLRMD) { /* RMDIR */ char *p; #ifdef LOCUS if (!locus && cx != XXLRMD) { #ifdef NOXFER return(-2); #else return(dormt(XZRMD)); #endif /* NOXFER */ } #endif /* LOCUS */ #ifdef IKSD if (inserver && !ENABLED(en_rmd)) { printf("?Sorry, directory removal is disabled\n"); return(-9); } #endif /* IKSD */ if ((x = cmdir("Name of directory to be removed","",&s,xxstring)) < 0) return(x); ckstrncpy(line,s,LINBUFSIZ); s = line; if ((x = cmcfm()) < 0) return(x); s = brstrip(s); x = ckmkdir(1,s,&p,msgflg,0); return(success = (x < 0) ? 0 : 1); } #endif /* CK_MKDIR */ #ifdef TNCODE if (cx == XXTELOP) return(dotelopt()); #endif /* TNCODE */ #ifndef NOPUSH if (cx == XXNPSH) { if ((z = cmcfm()) < 0) return(z); nopush = 1; #ifndef NOSERVER en_hos = 0; #endif /* NOSERVER */ #ifdef PIPESEND usepipes = 0; #endif /* PIPESEND */ return(success = 1); } #endif /* NOPUSH */ #ifdef OS2 if (cx == XXNSCR) { if ((z = cmcfm()) < 0) return(z); tt_scroll = 0; return(success = 1); } #endif /* OS2 */ #ifndef NOSPL if (cx == XXLOCAL) /* LOCAL variable declarations */ return(success = dolocal()); #endif /* NOSPL */ if (cx == XXKERMI) { /* The KERMIT command */ char * list[65]; extern char **xargv; extern int xargc; int i; if ((y = cmtxt("kermit command-line arguments, -h for help", "",&s,xxstring)) < 0) return(y); ckstrncpy(line,"kermit ",LINBUFSIZ); ckstrncat(line,s,LINBUFSIZ-8); xwords(line,64,list,0); for (i = 1; i < 64; i++) { if (!list[i]) break; } i--; xargc = i; xargv = list; xargv++; sstate = cmdlin(); if (sstate) { extern int justone; debug(F000,"KERMIT sstate","",sstate); justone = 1; /* Force return to command mode */ proto(); /* after protocol */ return(success); } else { debug(F101,"KERMIT sstate","",sstate); return(success = 1); /* Not exactly right, but... */ } } if (cx == XXDATE) { /* DATE command */ extern char cmdatebuf[], * cmdatemsg; #ifndef COMMENT char * dp; if ((y = cmtxt("date and/or time, or carriage return for current", "",&s,xxstring)) < 0) return(y); s = brstrip(s); dp = cmcvtdate(s,1); if (!dp) { printf("?%s\n",cmdatemsg ? cmdatemsg : "Date conversion error"); success = 0; } else { printf("%s\n",dp); success = 1; } #else /* This works fine but messes up my "dates" torture-test script */ if ((x = cmdate("Date and/or time, or carriage return for current", "",&s,0,xxstring)) < 0) { return(x); } else { printf("%s\n",cmdatebuf); success = 1; } #endif /* COMMENT */ return(success); } #ifndef NOPUSH #ifndef NOFRILLS if (cx == XXEDIT) return(doedit()); #endif /* NOFRILLS */ #endif /* NOPUSH */ #ifdef BROWSER /* Defined only ifndef NOPUSH */ if (cx == XXBROWS) return(dobrowse()); #endif /* BROWSER */ #ifdef CK_TAPI if (cx == XXTAPI) { /* Microsoft TAPI */ return (success = dotapi()); } #endif /* CK_TAPI */ #ifndef NOXFER if (cx == XXWHERE) { extern char * rfspec, * sfspec, * srfspec, * rrfspec; if ((x = cmcfm()) < 0) return(x); printf("\nFile most recently...\n\n"); printf(" Sent: %s\n", sfspec ? sfspec : "(none)"); if (sfspec && srfspec) { printf(" Stored as: %s\n", srfspec); printf("\n"); } printf(" Received: %s\n", rrfspec ? rrfspec : "(none)"); if (rfspec && rrfspec) printf(" Stored as: %s\n", rfspec); printf( "\nIf the full path is not shown, then the file is probably in your current\n" ); printf( "directory or your download directory (if any - SHOW FILE to find out).\n\n" ); return(success = 1); } #endif /* NOXFER */ #ifdef CK_RECALL if (cx == XXREDO) return(doredo()); #endif /* CK_RECALL */ #ifdef CKROOT if (cx == XXCHRT) /* Change Kermit's root directory */ return(dochroot()); #endif /* CKROOT */ #ifdef CK_KERBEROS if (cx == XXAUTH) { /* KERBEROS */ x = cp_auth(); /* Parse it */ #ifdef IKSD if (inserver) { printf("?Command disabled in IKSD.\r\n"); return(success = 0); } #endif /* IKSD */ if (x < 0) /* Pass parse errors back */ return(x); return(success = doauth(cx)); } #endif /* CK_KERBEROS */ #ifndef NOLOCAL if (cx == XXTERM) { return(settrmtyp()); } #endif /* NOLOCAL */ if (cx == XXSTATUS) { if ((x = cmcfm()) < 0) return(x); printf( " %s\n", success ? "SUCCESS" : "FAILURE" ); return(0); /* Don't change it */ } if (cx == XXFAIL) { if ((x = cmcfm()) < 0) return(x); return(success = 0); } if (cx == XXSUCC) { if ((x = cmcfm()) < 0) return(x); return(success = 1); } if (cx == XXNLCL) { extern int nolocal; if ((x = cmcfm()) < 0) return(x); nolocal = 1; return(success = 1); } #ifndef NOXFER if (cx == XXRASG) /* Shortcuts for REMOTE commands */ return(dormt(XZASG)); if (cx == XXRCWD) return(dormt(XZCWD)); if (cx == XXRCPY) return(dormt(XZCPY)); if (cx == XXRDEL) return(dormt(XZDEL)); if (cx == XXRDIR) return(dormt(XZDIR)); if (cx == XXRXIT) return(dormt(XZXIT)); if (cx == XXRHLP) return(dormt(XZHLP)); if (cx == XXRHOS) return(dormt(XZHOS)); if (cx == XXRKER) return(dormt(XZKER)); if (cx == XXRPWD) return(dormt(XZPWD)); if (cx == XXRQUE) return(dormt(XZQUE)); if (cx == XXRREN) return(dormt(XZREN)); if (cx == XXRMKD) return(dormt(XZMKD)); if (cx == XXRMSG) return(dormt(XZMSG)); if (cx == XXRRMD) return(dormt(XZRMD)); if (cx == XXRSET) return(dormt(XZSET)); if (cx == XXRSPA) return(dormt(XZSPA)); if (cx == XXRTYP) return(dormt(XZTYP)); if (cx == XXRWHO) return(dormt(XZWHO)); if (cx == XXRCDUP) return(dormt(XZCDU)); if (cx == XXRPRI) return(dormt(XZPRI)); #endif /* NOXFER */ if (cx == XXRESET) { /* RESET */ if ((x = cmcfm()) < 0) return(x); concb((char)escape); /* Make command echoing to normal */ doclean(0); /* Close all files */ return(success = 1); } #ifndef NOXFER #ifndef NOCSETS if (cx == XXASSOC) /* ASSOCIATE */ return(doassoc()); #endif /* NOCSETS */ #endif /* NOXFER */ #ifndef NOSPL if (cx == XXSHIFT) { /* SHIFT */ if ((y = cmnum("Number of arguments to shift","1",10,&x,xxstring)) < 0) return(y); if ((z = cmcfm()) < 0) return(z); return(success = doshift(x)); } #endif /* NOSPL */ #ifndef NOHELP if (cx == XXMAN) return(domanual()); #endif /* NOHELP */ #ifndef NOSPL if (cx == XXSORT) /* SORT an array */ return(dosort()); #endif /* NOSPL */ if (cx == XXPURGE) { #ifdef IKSD if (inserver && (!ENABLED(en_del) #ifdef CK_LOGIN || isguest #endif /* CK_LOGIN */ )) { printf("?Sorry, DELETE is disabled\n"); return(-9); } #endif /* IKSD */ #ifdef CK_APC if ((apcactive == APC_LOCAL) || ((apcactive == APC_REMOTE) && (!(apcstatus & APC_UNCH)))) return(success = 0); #endif /* CK_APC */ #ifdef CKPURGE return(dopurge()); #else #ifdef VMS if ((x = cmtxt("optional switches followed by filespec", "",&s,xxstring)) < 0) return(x); if (nopush) { printf("?Sorry, DCL access is disabled\n"); return(-9); } ckstrncpy(line,s,LINBUFSIZ); s = line; x = mlook(mactab,"purge",nmac); return(success = dodo(x,s,cmdstk[cmdlvl].ccflgs)); #else return(-2); #endif /* VMS */ #endif /* CKPURGE */ } #ifndef NOSPL if (cx == XXFAST) { if ((x = cmcfm()) < 0) return(x); x = mlook(mactab,"fast",nmac); return(success = dodo(x,NULL,cmdstk[cmdlvl].ccflgs)); } if (cx == XXCAU) { if ((x = cmcfm()) < 0) return(x); x = mlook(mactab,"cautious",nmac); return(success = dodo(x,NULL,cmdstk[cmdlvl].ccflgs)); } if (cx == XXROB) { if ((x = cmcfm()) < 0) return(x); x = mlook(mactab,"robust",nmac); return(success = dodo(x,NULL,cmdstk[cmdlvl].ccflgs)); } #endif /* NOSPL */ if (cx == XXSCRN) { /* SCREEN */ int row, col; if ((x = cmkey(scntab, nscntab,"screen action","", xxstring)) < 0) return(x); switch (x) { /* MOVE-TO (cursor position) */ case SCN_MOV: if ((y = cmnum("Row (1-based)","",10,&z,xxstring)) < 0) return(y); row = z; y = cmnum("Column (1-based)","1",10,&z,xxstring); if (y < 0) return(y); col = z; if ((y = cmcfm()) < 0) return(y); if (row < 0 || col < 0) { printf("?Row and Column must be 1 or greater\n"); return(-9); } if (cmd_rows > 0 && row > cmd_rows) row = cmd_rows; if (cmd_cols > 0 && col > cmd_cols) col = cmd_cols; y = ck_curpos(row,col); return(success = (y > -1) ? 1 : 0); case SCN_CLR: /* CLEAR */ if ((y = cmcfm()) < 0) return(y); debug(F100,"screen calling ck_cls()","",0); y = ck_cls(); return(success = (y > -1) ? 1 : 0); case SCN_CLE: /* CLEOL */ if ((y = cmcfm()) < 0) return(y); y = ck_cleol(); return(success = (y > -1) ? 1 : 0); } } #ifndef NOHTTP #ifdef TCPSOCKET if (cx == XXHTTP) return(dohttp()); #endif /* TCPSOCKET */ #endif /* NOHTTP */ #ifndef NOSPL if (cx == XXARRAY) { /* ARRAY */ #ifndef NOSHOW extern int showarray(); #endif /* NOSHOW */ if ((x = cmkey(arraytab, narraytab,"Array operation","",xxstring)) < 0) return(x); switch (x) { case ARR_DCL: return(dodcl(XXDCL)); case ARR_SRT: return(dosort()); #ifndef NOSHOW case ARR_SHO: return(showarray()); #endif /* NOSHOW */ case ARR_CPY: return(copyarray()); case ARR_SET: case ARR_CLR: return(clrarray(x)); case ARR_DST: return(unarray()); case ARR_RSZ: return(rszarray()); case ARR_EQU: return(linkarray()); default: printf("?Sorry, not implemented yet - \"%s\"\n",cmdbuf); return(-9); } } if (cx == XXTRACE) /* TRACE */ return(dotrace()); #endif /* NOSPL */ #ifdef CK_PERMS #ifdef UNIX if (cx == XXCHMOD) return(douchmod()); /* Do Unix chmod */ #endif /* UNIX */ #endif /* CK_PERMS */ if (cx == XXPROMP) return(doprompt()); if (cx == XXGREP) return(dogrep()); #ifdef COMMENT if (cx == XXDEBUG) { /* DEBUG */ #ifndef DEBUG int dummy = 0; return(seton(&dummy)); #else /* This has been in C-Kermit since 9.0 but doesn't do anything */ return(seton(&deblog)); #endif /* DEBUG */ } #endif /* COMMENT */ if (cx == XXMSG || cx == XXXMSG) { /* MESSAGE */ extern int debmsg; /* Script debugging messages */ if ((x = cmtxt("Message to print if SET DEBUG MESSAGE is ON or STDERR", "",&s,xxstring)) < 0) return(x); if (!s) /* Watch out for null result */ s = ""; /* Make it an empty string */ else /* Not null */ s = brstrip(s); /* Strip braces and doublequotes */ switch (debmsg) { /* Not debugging - don't print */ case 0: break; case 1: printf("%s",s); /* Print to stdout */ if (cx == XXMSG) printf("\n"); break; case 2: fprintf(stderr,"%s",s); /* Ditto but print to stderr */ if (cx == XXMSG) fprintf(stderr,"\n"); break; } return(0); /* Return without affecting SUCCESS */ } #ifdef CKLEARN if (cx == XXLEARN) { /* LEARN */ struct FDB of, sw, cm; int closing = 0, off = 0, on = 0, confirmed = 0; char c; cmfdbi(&sw, /* 2nd FDB - optional /PAGE switch */ _CMKEY, /* fcode */ "Script file name, or switch", /* hlpmsg */ "", /* default */ "", /* addtl string data */ 3, /* addtl numeric data 1: tbl size */ 4, /* addtl numeric data 2: 4 = cmswi */ xxstring, /* Processing function */ learnswi, /* Keyword table */ &of /* Pointer to next FDB */ ); cmfdbi(&of,_CMOFI,"","","",0,0,xxstring,NULL,&cm); cmfdbi(&cm,_CMCFM,"","","",0,0,NULL,NULL,NULL); line[0] = NUL; while (!confirmed) { x = cmfdb(&sw); /* Parse something */ if (x < 0) return(x); switch (cmresult.fcode) { /* What was it? */ case _CMOFI: /* Output file name */ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); break; case _CMKEY: /* Switch */ c = cmgbrk(); if ((c == ':' || c == '=') && !(cmgkwflgs() & CM_ARG)) { printf("?This switch does not take an argument\n"); return(-9); } switch (cmresult.nresult) { case 2: /* /CLOSE */ closing = 1; /* Fall thru on purpose */ case 0: /* /OFF */ off = 1; on = 0; break; case 1: /* /ON */ on = 1; off = 0; break; } break; case _CMCFM: /* Confirmation */ confirmed++; break; } } if (closing) { if (learnfp) { fclose(learnfp); learnfp = NULL; } makestr(&learnfile,NULL); } if (line[0]) { if (!on && !off) on = 1; if (learnfp) { fclose(learnfp); learnfp = NULL; } makestr(&learnfile,line); if (learnfile) { char * modes = "w"; learnfp = fopen(learnfile,modes); if (!learnfp) { debug(F110,"LEARN file open error",learnfile,0); perror(learnfile); return(-9); } else { #ifdef ZFNQFP if (zfnqfp(learnfile,TMPBUFSIZ,tmpbuf)) makestr(&learnfile,tmpbuf); #endif /* ZFNQFP */ debug(F110,"LEARN file open ok",learnfile,0); if (!quiet) { printf("Recording to %s...\n\n",learnfile); printf( " WARNING: If you type your password during script recording, it will appear\n\ in the file. Be sure to edit it or take other appropriate precautions.\n\n" ); } fputs( "; Scriptfile: ",learnfp); fputs(learnfile,learnfp); fputs("\n; Directory: ",learnfp); fputs(zgtdir(),learnfp); fputs("\n; Recorded: ",learnfp); fputs(ckdate(),learnfp); fputs("\n",learnfp); } } } if (on) { learning = 1; } else if (off) { learning = 0; } debug(F101,"LEARN learning","",learning); return(success = 1); } #endif /* CKLEARN */ #ifdef NEWFTP if (cx == XXUSER || cx == XXACCT) { if (!ftpisopen()) { printf("?FTP connection is not open\n"); return(-9); } return(success = (cx == XXUSER) ? doftpusr() : doftpacct()); } if (cx == XXSITE || cx == XXPASV) { if (!ftpisopen()) { printf("?FTP connection is not open\n"); return(-9); } return(success = (cx == XXSITE) ? doftpsite() : dosetftppsv()); } #endif /* NEWFTP */ if (cx == XXORIE) { /* ORIENTATION */ extern char * myname; int i, y, n = 0; char * s, vbuf[32]; char * vars[16]; char * legend[16]; if ((y = cmcfm()) < 0) return(y); printf("\nProgram name:\n %s\n\n",myname); n += 4; #ifdef NT vars[0] = "home"; legend[0] = "Your home directory"; vars[1] = "directory"; legend[1] = "K95's current directory"; vars[2] = "exedir"; legend[2] = "K95 Program directory"; vars[3] = "inidir"; legend[3] = "K95 Initialization file directory"; vars[4] = "startup"; legend[4] = "Current directory when started"; vars[5] = "common"; legend[5] = "K95 data for all users and K95SITE.INI file"; vars[6] = "personal"; legend[6] = "Your personal data directory tree"; vars[7] = "desktop"; legend[7] = "Your deskop directory tree"; vars[8] = "appdata"; legend[8] = "Your personal K95 data tree and K95CUSTOM.INI file"; vars[9] = "download"; legend[9] = "Your K95 download directory"; vars[10] = "tmpdir"; legend[10] = "Your TEMP directory"; vars[11] = NULL; legend[11] = NULL; for (i = 0; i < 16 && vars[i]; i++) { printf("%s:\n",legend[i]); if (++n > cmd_rows - 3) { if (!askmore()) { return(0); } else { n = 0; } } ckmakmsg(vbuf,32,"\\v(",vars[i],")",NULL); printf(" Variable: %s\n",vbuf); if (++n > cmd_rows - 3) { if (!askmore()) { return(0); } else { n = 0; }} y = TMPBUFSIZ; s = tmpbuf; zzstring(vbuf,&s,&y); line[0] = NUL; ckGetLongPathName(tmpbuf,line,LINBUFSIZ); printf(" Long name: %s\n",line); if (++n > cmd_rows - 3) { if (!askmore()) { return(0); } else { n = 0; } } line[0] = NUL; ckGetShortPathName(tmpbuf,line,LINBUFSIZ); printf(" Short name: %s\n",line); if (++n > cmd_rows - 3) { if (!askmore()) { return(0); } else { n = 0; } } printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return(0); } else { n = 0; } } } #else /* NT */ vars[0] = "home"; legend[0] = "Your home directory"; vars[1] = "directory"; legend[1] = "Kermit's current directory"; vars[2] = "exedir"; legend[2] = "Kermit's program directory"; vars[3] = "inidir"; legend[3] = "Initialization file directory"; vars[4] = "startup"; legend[4] = "Current directory when started"; vars[5] = "download"; legend[5] = "Kermit download directory"; vars[6] = NULL; legend[6] = NULL; for (i = 0; i < 16 && vars[i]; i++) { printf("%s:\n",legend[i]); if (++n > cmd_rows - 3) { if (!askmore()) { return(0); } else { n = 0; }} ckmakmsg(vbuf,32,"\\v(",vars[i],")",NULL); printf(" Variable: %s\n",vbuf); if (++n > cmd_rows - 3) { if (!askmore()) { return(0); } else { n = 0; }} y = TMPBUFSIZ; s = tmpbuf; zzstring(vbuf,&s,&y); printf(" Value: %s\n",tmpbuf); if (++n > cmd_rows - 3) { if (!askmore()) { return(0); } else { n = 0; }} printf("\n"); if (++n > cmd_rows - 3) { if (!askmore()) { return(0); } else { n = 0; }} } #endif /* NT */ return(success = 1); } #ifdef NT if (cx == XXDIALER) { StartDialer(); return(success = 1); } #endif /* NT */ if (cx == XXCONT) { /* CONTINUE */ if ((x = cmcfm()) < 0) return(x); if (!xcmdsrc) { /* At prompt: continue script */ if (cmdlvl > 0) popclvl(); /* Pop command level */ return(success = 1); /* always succeeds */ #ifndef NOSPL } else { /* In script: whatever... */ x = mlook(mactab,"continue",nmac); /* Don't set success */ return(dodo(x,NULL,cmdstk[cmdlvl].ccflgs)); #endif /* NOSPL */ } } #ifdef UNIX #ifndef NOPUTENV /* NOTE: Syntax is PUTENV name value, not PUTENV name=value. I could check for this but it would be too much magic. */ if (cx == XXPUTE) { /* PUTENV */ char * t = tmpbuf; /* Create or alter environment var */ char * s1 = NULL, * s2 = NULL; if ((x = cmfld("Variable name","",&s,xxstring)) < 0) return(x); if (s) if (s == (char *)0) s = NULL; (VOID) makestr(&s1,s); if (s && !s1) { printf("?PUTENV - memory allocation failure\n"); return(-9); } if ((x = cmtxt("Value","",&s,xxstring)) < 0) return(x); if (s) if (s == (char *)0) s = NULL; (VOID) makestr(&s2,s); success = doputenv(s1,s2); (VOID) makestr(&s1,NULL); (VOID) makestr(&s2,NULL); return(success); } #endif /* NOPUTENV */ #endif /* UNIX */ if (cx == XXNOTAV) { /* Command in table not available */ ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ); if ((x = cmtxt("Rest of command","",&s,NULL)) < 0) return(x); printf("Sorry, \"%s\" not configured in this version of Kermit.\n", tmpbuf ); return(success = 0); } return(-2); /* None of the above */ } /* end of docmd() */ #endif /* NOICP */ ckuusr.h000664 045065 024037 00000342702 14767410745 012677 0ustar00fdckermit000000 000000 /* C K U U S R . H -- Symbol definitions for C-Kermit ckuus*.c modules */ /* Author: Frank da Cruz , Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Thu Feb 16 15:57:01 2023 */ #ifndef CKUUSR_H #define CKUUSR_H #include "ckucmd.h" /* Get symbols from command package */ #ifndef NOLUCACHE /* Use lookup() cache */ #ifndef NOSPL /* To speed up script programs */ #ifndef USE_LUCACHE #define USE_LUCACHE #endif /* USE_LUCACHE */ #endif /* NOSPL */ #endif /* NOLUCACHE */ #ifndef NODOUBLEQUOTING /* New to 8.0 */ #define DOUBLEQUOTING /* Allow fields to be enclosed in */ #endif /* NODOUBLEQUOTING */ /* doublequotes. */ #ifndef NOLOCUS /* SET LOCUS */ #define LOCUS #endif /* NOLOCUS */ /* Sizes of things - FNVALL and MAXARGLEN increased from 8K 2005/09/12 */ /* Other things increased even more for 64-bit builds 2016/02/03 */ #ifdef BIGBUFOK #define FNVALL CMDBL /* Function return value length */ #define MAXARGLEN CMDBL /* Max func arg length after eval */ #define MAXARGLIST 1024 /* Max number of args for a macro */ #define FSPECL CMDBL /* Max length for MSEND/GET string */ #define MSENDMAX 1024 /* Number of filespecs for MSEND */ #define MAC_MAX 16384 /* Maximum number of macros */ #else /* Same as above but for smaller builds... */ #define FNVALL 1022 #define MAXARGLEN 1023 #define MAXARGLIST 64 #define FSPECL 300 #define MSENDMAX 128 #define MAC_MAX 1024 #endif /* BIGBUFOK */ #define GVARS 127 /* Highest global var allowed */ #ifdef BIGBUFOK #define VNAML 4096 /* Max length for variable name */ #define ARRAYREFLEN 1024 /* Max length for array reference */ #define FORDEPTH 32 /* Maximum depth of nested FOR loops */ #define MAXTAKE 54 /* Maximum nesting of TAKE files */ #define MACLEVEL 128 /* Maximum nesting for macros */ #define INPBUFSIZ 4096 /* Size of INPUT buffer */ #define PROMPTL 1024 /* Max length for prompt */ #define LBLSIZ 8192 /* Maximum length for a GOTO label */ #else #define VNAML 256 /* Max length for variable name */ #define ARRAYREFLEN 128 /* Max length for array reference */ #define FORDEPTH 10 /* Maximum depth of nested FOR loops */ #define MAXTAKE 32 /* Maximum nesting of TAKE files */ #define MACLEVEL 64 /* Maximum nesting for macros */ #define INPBUFSIZ 256 #define PROMPTL 256 /* Max length for prompt */ #define LBLSIZ 128 /* Maximum length for a GOTO label */ #endif /* BIGBUFOK */ #define NARGS 10 /* Max number of macro arguments */ #define LINBUFSIZ (CMDBL + 10) /* Size of line[] buffer */ #define TMPBUFSIZ (CMDBL + 10) /* Size of temporary buffer */ #define CMDSTKL ( MACLEVEL + MAXTAKE + 2) /* Command stack depth */ #ifndef NOPURGE /* PURGE command */ #ifdef UNIX #define CKPURGE #endif /* UNIX */ #endif /* NOPURGE */ #ifndef NOMINPUT /* MINPUT command */ #ifndef NOSPL #define CK_MINPUT #ifndef MINPMAX #ifdef BIGBUFOK #define MINPMAX 96 /* Max number of MINPUT strings */ #else #define MINPMAX 16 #endif /* BIGBUFOK */ #endif /* MINPMAX */ #define MINPBUFL 256 /* Size of MINPUT temp buffer */ #endif /* NOSPL */ #endif /* NOMINPUT */ #define ARRAYBASE 95 /* Lowest array-name character */ #ifndef NOKERBANG #ifndef KERBANG #define KERBANG #endif /* KERBANG */ #endif /* NOKERBANG */ /* Bit values (1, 2, 4, 8, ...) for the ccflgs field */ #define CF_APC 1 /* Executing an APC command */ #define CF_KMAC 2 /* Executing a \Kmacro */ #define CF_CMDL 4 /* Macro from -C "blah" command line */ #define CF_REXX 8 /* Macro from REXX interpreter */ #define CF_IMAC 16 /* Internal macro like FOR, WHILE... */ struct cmdptr { /* Command stack structure */ int src; /* Command Source */ int lvl; /* Current TAKE or DO level */ int ccflgs; /* Flags */ }; struct mtab { /* Macro table, like keyword table */ char *kwd; /* But with pointers for vals */ char *mval; /* instead of ints. */ short flgs; }; struct localvar { /* Local variable structure. */ char * lv_name; char * lv_value; struct localvar * lv_next; }; struct stringlist { /* General purpose string list */ char * sl_name; struct stringlist * sl_next; }; struct stringint { /* String and (wide) integer */ char * sval; /* used mainly with command switches */ int ival; CK_OFF_T wval; }; #ifndef NOICP /* C-Kermit Initialization file... System-dependent defaults are built into the program, see below. These can be overridden in either of two ways: 1. CK_DSYSINI is defined at compile time, in which case a default system-wide initialization file name is chosen from below, or: 2: CK_SYSINI is defined to be a string, which lets the program builder choose the initialization filespec at compile time. These can be given on the CC command line, so the source code need not be changed. */ #ifndef CK_SYSINI /* If no initialization file given, */ #ifdef CK_DSYSINI /* but CK_DSYSINI is defined... */ /* Supply system-dependent "default default" initialization file */ #ifdef UNIX /* For UNIX, system-wide */ /* This allows one copy of the standard init file on the whole system, */ /* rather than a separate copy in each user's home directory. */ #ifdef HPUX10 #define CK_SYSINI "/usr/share/lib/kermit/ckermit.ini" #else #ifdef CU_ACIS #define CK_SYSINI "/usr/share/lib/kermit/ckermit.ini" #else #ifdef __linux__ #define CK_SYSINI "/usr/share/kermit/ckermit.ini" #else #define CK_SYSINI "/usr/local/bin/ckermit.ini" #endif /* linux */ #endif /* CU_ACIS */ #endif /* HPUX10 */ /* Fill in #else..#ifdef's here for VMS, OS/2, etc. */ /* Fill in matching #endif's here. */ #endif /* UNIX */ #endif /* CK_DSYSINI */ #endif /* CK_SYSINI */ #ifdef CK_SYSINI /* Init-file precedence */ #ifndef CK_INI_A /* A means system-wide file first */ #ifndef CK_INI_B /* B means user's first */ #define CK_INI_A /* A is default */ #endif /* CK_INI_B */ #endif /* CK_INI_A */ #else #ifdef CK_INI_A /* Otherwise */ #undef CK_INI_A /* make sure these aren't defined */ #endif /* CK_INI_A */ #ifdef CK_INI_B #undef CK_INI_B #endif /* CK_INI_B */ #endif /* CK_SYSINI */ #ifdef CK_SYSINI /* One more check... */ #ifdef CK_INI_A /* Make sure they're not both */ #ifdef CK_INI_B /* defined. */ #undef CK_INI_B #endif /* CK_INI_B */ #endif /* CK_INI_A */ #endif /* CK_SYSINI */ /* If neither CK_DSYSINI nor CK_SYSINI are defined, these are the built-in defaults for each platform. USE_CUSTOM means to execute the customization file automatically if the initialization file is not found. */ #ifndef NOCUSTOM #ifndef USE_CUSTOM #define USE_CUSTOM #endif /* USE_CUSTOM */ #endif /* NOCUSTOM */ #ifndef KERMRCL /* Path length for init file */ #define KERMRCL CKMAXPATH #endif /* KERMRCL */ #ifdef vms #define KERMRC "CKERMIT.INI" /* Init file name */ #define MYCUSTOM "CKERMOD.INI" /* Customization file name */ #else #ifdef OS2 #ifdef NT #define KERMRC "k95.ini" #define MYCUSTOM "k95custom.ini" #else #define KERMRC "k2.ini" #define MYCUSTOM "k2custom.ini" #endif /* NT */ #else #ifdef UNIXOROSK #define KERMRC ".kermrc" #define MYCUSTOM ".mykermrc" #else #ifdef STRATUS #define KERMRC "ckermit.ini" #define MYCUSTOM "ckermod.ini" #else #define KERMRC "CKERMIT.INI" #define MYCUSTOM "ckermod.ini" #endif /* STRATUS */ #endif /* UNIXOROSK */ #endif /* OS2 */ #endif /* vms */ #ifndef KERMRCL #define KERMRCL 256 #endif /* KERMRCL */ #endif /* NOICP */ /* User interface features */ #ifndef NORPLWORDMODE /* \freplace() word mode */ #define RPLWORDMODE #endif /* NORPLWORDMODE */ #ifdef CK_CURSES /* Thermometer */ #ifndef NO_PCT_BAR #ifndef CK_PCT_BAR #define CK_PCT_BAR #endif /* NO_PCT_BAR */ #endif /* CK_PCT_BAR */ #endif /* CK_CURSES */ #ifdef KUI /* KUI requires the Thermometer code */ #ifndef NO_PCT_BAR #ifndef CK_PCT_BAR #define CK_PCT_BAR #endif /* NO_PCT_BAR */ #endif /* CK_PCT_BAR */ #endif /* KUI */ /* Includes */ #ifdef MINIX /* why? */ #include #endif /* MINIX */ /* Symbols for command source */ #define CMD_KB 0 /* KeyBoard or standard input */ #define CMD_TF 1 /* TAKE command File */ #define CMD_MD 2 /* Macro Definition */ /* SET TRANSFER CANCELLATION command should be available in all versions. But for now... */ #ifdef UNIX /* UNIX has it */ #ifndef XFRCAN #define XFRCAN #endif /* XFRCAN */ #endif /* UNIX */ #ifdef VMS /* VMS has it */ #ifndef XFRCAN #define XFRCAN #endif /* XFRCAN */ #endif /* VMS */ #ifdef datageneral /* DG AOS/VS has it */ #ifndef XFRCAN #define XFRCAN #endif /* XFRCAN */ #endif /* datageneral */ #ifdef STRATUS /* Stratus VOS has it */ #ifndef XFRCAN #define XFRCAN #endif /* XFRCAN */ #endif /* STRATUS */ #ifdef OSK /* OS-9 */ #ifndef XFRCAN #define XFRCAN #endif /* XFRCAN */ #endif /* OSK */ #ifndef NOCMDL /* Extended Command-Line Option Codes (keep alphabetical by keyword) */ #define XA_ANON 0 /* --anonymous */ #define XA_BAFI 1 /* --bannerfile */ #define XA_CDFI 2 /* --cdfile */ #define XA_CDMS 3 /* --cdmessage */ #define XA_HELP 4 /* --help */ #define XA_HEFI 5 /* --helpfile */ #define XA_IKFI 6 /* --xferfile */ #define XA_IKLG 7 /* --xferlog */ #define XA_ANFI 8 /* --initfile */ #define XA_PERM 9 /* --permissions */ #define XA_ROOT 10 /* --root */ #define XA_SYSL 11 /* --syslog */ #define XA_USFI 12 /* --userfile */ #define XA_WTFI 13 /* --wtmpfile */ #define XA_WTMP 14 /* --wtmplog */ #define XA_TIMO 15 /* --timeout */ #define XA_NOIN 16 /* --nointerrupts */ #define XA_DBAS 17 /* --database */ #define XA_DBFI 18 /* --dbfile */ #define XA_PRIV 19 /* --privid */ #define XA_VERS 20 /* --version */ #define XA_NPRM 21 /* --noperms */ #define XA_XPOS 22 /* Window position X coordinate */ #define XA_YPOS 23 /* Window position Y coordinate */ #define XA_FNAM 24 /* Font Facename */ #define XA_FSIZ 25 /* Font Size */ #define XA_TERM 26 /* Terminal type */ #define XA_CSET 27 /* Remote Character Set */ #define XA_ROWS 28 /* Screen rows (height) */ #define XA_COLS 29 /* Screen columns (width) */ #define XA_TEL 30 /* Make a Telnet connection */ #define XA_FTP 31 /* Make an FTP connection */ #define XA_SSH 32 /* Make an SSH connection */ #define XA_USER 33 /* Username for login */ #define XA_PASS 34 /* Password for login */ #define XA_TITL 35 /* Window Title */ #define XA_NOMN 36 /* No GUI Menu Bar */ #define XA_NOTB 37 /* No GUI Tool Bar */ #define XA_NOSB 38 /* No GUI Status Bar */ #define XA_NOPUSH 39 /* Disable external commands */ #define XA_NOSCROLL 40 /* Disable scrollback operations */ #define XA_NOESCAPE 41 /* Disable escape from connect mode */ #define XA_LOCK 42 /* All lockdown options */ #define XA_NOBAR 43 /* No GUI Bars */ #define XA_WMAX 44 #define XA_WMIN 45 #define XA_SCALE 46 /* GUI Scale Font */ #define XA_CHGD 47 /* GUI Change Dimensions */ #define XA_NOCLOSE 48 /* GUI Disable Close Window */ #define XA_UNBUF 49 /* UNIX unbuffered console */ #define XA_NOLOCALE 50 /* Don't access or use locale */ #define XA_MAX 50 /* Highest extended option number */ #endif /* NOCMDL */ #ifndef NOICP /* Top Level Commands */ /* Values associated with top-level commands must be 0 or greater. */ #define XXBYE 0 /* BYE */ #define XXCLE 1 /* CLEAR */ #define XXCLO 2 /* CLOSE */ #define XXCON 3 /* CONNECT */ #define XXCPY 4 /* COPY */ #define XXCWD 5 /* CWD (Change Working Directory) */ #define XXDEF 6 /* DEFINE (a macro or variable) */ #define XXDEL 7 /* (Local) DELETE */ #define XXDIR 8 /* (Local) DIRECTORY */ /* DIRECTORY Command options... */ #define DIR_BRF 1 /* BRIEF */ #define DIR_VRB 2 /* VERBOSE */ #define DIR_PAG 3 /* PAGE */ #define DIR_NOP 4 /* NOPAGE */ #define DIR_ISO 5 /* ISODATE */ #define DIR_DAT 6 /* ENGLISHDATE */ #define DIR_HDG 7 /* HEADINGS */ #define DIR_NOH 8 /* NOHEADINGS */ #define DIR_SRT 9 /* SORT */ #define DIR_NOS 10 /* NOSORT */ #define DIR_ASC 11 /* ASCENDING */ #define DIR_DSC 12 /* DESCENDING */ #define DIR_REC 13 /* RECURSIVE */ #define DIR_NOR 14 /* NORECURIVE */ #define DIR_DOT 15 /* DOTFILES */ #define DIR_NOD 16 /* NODOTFILES */ #define DIR_DIR 17 /* DIRECTORIES */ #define DIR_FIL 18 /* FILES */ #define DIR_ALL 19 /* ALL */ #define DIR_NAM 20 /* NAMES: */ #define DIR_TYP 21 /* FILETYPES */ #define DIR_NOT 22 /* NOFILETYPES */ #define DIR_BUP 23 /* BACKUP */ #define DIR_NOB 24 /* NOBACKUP */ #define DIR_MSG 25 /* MESSAGE */ #define DIR_NOM 26 /* NOMESSAGE */ #define DIR_ARR 27 /* ARRAY: */ #define DIR_NAR 28 /* NOARRAY */ #define DIR_EXC 29 /* EXCEPT: */ #define DIR_LAR 30 /* LARGER-THAN: */ #define DIR_SMA 31 /* SMALLER-THAN: */ #define DIR_AFT 32 /* AFTER: */ #define DIR_NAF 33 /* NOT-AFTER: */ #define DIR_BEF 34 /* BEFORE: */ #define DIR_NBF 35 /* NOT-BEFORE: */ #define DIR_SUM 36 /* SUMMARY */ #define DIR_BIN 37 /* TYPE (only show binary or text) */ #define DIR_LNK 38 /* follow symlinks */ #define DIR_NLK 39 /* don't follow symlinks */ #define DIR_OUT 40 /* Output file for listing */ #define DIR_TOP 41 /* Top n lines */ #define DIR_COU 42 /* COUNT:var */ #define DIR_NOL 43 /* NOLINKS (don't show symlinks at at all) */ #define DIR_MOD 44 /* Set modification time (used only by TOUCH) */ #define DIR_SIM 45 /* /SIMULATE (for TOUCH) */ #define DIR_DES 46 /* /DESTINATION: (for CHANGE) */ #define DIR_BAK 47 /* /BACKUP: (for CHANGE) */ #define DIRS_NM 0 /* Sort directory by NAME */ #define DIRS_DT 1 /* Sort directory by DATE */ #define DIRS_SZ 2 /* Sort directory by SIZE */ #define XXDIS 9 /* DISABLE */ #define XXECH 10 /* ECHO */ #define XXEXI 11 /* EXIT */ #define XXFIN 12 /* FINISH */ #define XXGET 13 /* GET */ #define XXHLP 14 /* HELP */ #define XXINP 15 /* INPUT */ #define XXLOC 16 /* LOCAL */ #define XXLOG 17 /* LOG */ #define XXMAI 18 /* MAIL */ #define XXMOU 19 /* (Local) MOUNT */ #define XXMSG 20 /* (Local) MESSAGE */ #define XXOUT 21 /* OUTPUT */ #define XXPAU 22 /* PAUSE */ #define XXPRI 23 /* (Local) PRINT */ #define XXQUI 24 /* QUIT */ #define XXREC 25 /* RECEIVE */ #define XXREM 26 /* REMOTE */ #define XXREN 27 /* (Local) RENAME */ #define XXSEN 28 /* SEND */ /* SEND switches */ #define SND_BIN 0 /* Binary mode */ #define SND_DEL 1 /* Delete after */ #define SND_EXC 2 /* Except */ #define SND_LAR 3 /* Larger than */ #define SND_MAI 4 /* Mail */ #define SND_BEF 5 /* Before */ #define SND_AFT 6 /* After */ #define SND_PRI 7 /* Print */ #define SND_SHH 8 /* Quiet */ #define SND_REC 9 /* Recursive */ #define SND_SMA 10 /* Smaller than */ #define SND_STA 11 /* Starting-from */ #define SND_TXT 12 /* Text mode */ #define SND_CMD 13 /* From command (pipe) */ #define SND_RES 14 /* Resend/Recover */ #define SND_PRO 15 /* Protocol */ #define SND_ASN 16 /* As-name */ #define SND_IMG 17 /* Image */ #define SND_LBL 18 /* Labeled */ #define SND_NAF 19 /* Not-After */ #define SND_NBE 20 /* Not-Before */ #define SND_FLT 21 /* Filter */ #define SND_PTH 22 /* Pathnames */ #define SND_NAM 23 /* Filenames */ #define SND_MOV 24 /* MOVE to another directory */ #define SND_REN 25 /* RENAME after sending */ #define SND_CAL 26 /* Calibrate */ #define SND_FIL 27 /* File containing list of files to send */ #define SND_NOB 28 /* Skip backup files */ #define SND_DOT 29 /* Include dot-files */ #define SND_NOD 30 /* Exclude dot-files */ #define SND_ARR 31 /* Send from array */ #define SND_TYP 32 /* TYPE (only send text (or binary)) */ #define SND_XPA 33 /* TRANSPARENT */ #define SND_PIP 34 /* PIPES */ #define SND_ERR 35 /* ERROR */ #define SND_CSL 36 /* Local character set */ #define SND_CSR 37 /* Remote character set */ #define SND_UPD 38 /* Update */ #define SND_COL 39 /* Collision */ #define SND_NML 40 /* Namelist */ #define SND_SRN 41 /* Server-Rename */ #define SND_LNK 42 /* Follow links */ #define SND_NLK 43 /* Don't follow links */ #define SND_SIM 44 /* Simulate */ #define SND_DIF 45 /* If dates Differ */ #define SND_PAT 46 /* Pattern to use locally when GET'ing */ #define SND_NLS 47 /* (FTP only) MGET forces NLST */ #define SND_MLS 48 /* (FTP only) MGET forces MLSD */ #define SND_MAX 48 /* Highest SEND switch */ #define XXSER 29 /* SERVER */ #define XXSET 30 /* SET */ #define XXSHE 31 /* Command for SHELL */ #define XXSHO 32 /* SHOW */ #define XXSPA 33 /* (Local) SPACE */ #define XXSTA 34 /* STATISTICS */ #define XXSUB 35 /* (Local) SUBMIT */ #define XXTAK 36 /* TAKE */ #define XXTRA 37 /* TRANSMIT */ #define XXTYP 38 /* (Local) TYPE */ #define XXWHO 39 /* (Local) WHO */ #define XXDIAL 40 /* (Local) DIAL */ #define XXLOGI 41 /* (Local) SCRIPT */ #define XXCOM 42 /* Comment */ #define XXHAN 43 /* HANGUP */ #define XXXLA 44 /* TRANSLATE */ #define XXIF 45 /* IF */ #define XXLBL 46 /* label */ #define XXGOTO 47 /* GOTO */ #define XXEND 48 /* END */ #define XXSTO 49 /* STOP */ #define XXDO 50 /* DO */ #define XXPWD 51 /* PWD */ #define XXTES 52 /* TEST */ #define XXASK 53 /* ASK */ #define XXASKQ 54 /* ASKQ */ #define XXASS 55 /* ASSIGN */ #define XXREI 56 /* REINPUT */ #define XXINC 57 /* INCREMENT */ #define XXDEC 59 /* DECREMENT */ #define XXELS 60 /* ELSE */ #define XXEXE 61 /* EXECUTE */ #define XXWAI 62 /* WAIT */ #define XXVER 63 /* VERSION */ #define XXENA 64 /* ENABLE */ #define XXWRI 65 /* WRITE */ #define XXCLS 66 /* CLS (clear screen) */ #define XXRET 67 /* RETURN */ #define XXOPE 68 /* OPEN */ #define XXREA 69 /* READ */ #define XXON 70 /* ON */ #define XXDCL 71 /* DECLARE */ #define XXBEG 72 /* BEGIN (not used) */ #define XXFOR 72 /* FOR */ #define XXWHI 73 /* WHILE */ #define XXIFX 74 /* Extended IF */ #define XXCMS 75 /* SEND from command output (not yet) */ #define XXCMR 76 /* RECEIVE to a command's input (not yet) */ #define XXCMG 77 /* GET to a command's input (not yet) */ #define XXSUS 78 /* SUSPEND */ #define XXERR 79 /* ERROR */ #define XXMSE 80 /* MSEND */ #define XXBUG 81 /* BUG */ #define XXPAD 82 /* PAD (as in X.25 PAD) ANYX25 */ #define XXRED 83 /* REDIAL */ #define XXGTA 84 /* _getargs (invisible internal) */ #define XXPTA 85 /* _putargs (invisible internal) */ #define XXGOK 86 /* GETOK - Ask for YES/NO */ #define XXTEL 87 /* TELNET */ #define XXASX 88 /* _ASSIGN (evaluates var name) */ #define XXDFX 89 /* _DEFINE (evaluates var name) */ #define XXPNG 90 /* PING (for TCP/IP) */ #define XXINT 91 /* INTRODUCTION */ #define XXCHK 92 /* CHECK (a feature) */ #define XXMSL 93 /* MSLEEP, MPAUSE (millisecond sleep) */ #define XXNEW 94 /* NEWS */ #define XXAPC 95 /* APC */ #define XXFUN 96 /* REDIRECT */ #define XXWRL 97 /* WRITE-LINE */ #define XXREXX 98 /* Rexx */ #define XXMINP 100 /* MINPUT */ #define XXRSEN 101 /* RESEND */ #define XXPSEN 102 /* PSEND */ #define XXGETC 103 /* GETC */ #define XXEVAL 104 /* EVALUATE */ #define XXFWD 105 /* FORWARD */ #define XXUPD 106 /* UPDATES */ #define XXBEEP 107 /* BEEP */ #define XXMOVE 108 /* MOVE */ #define XXMMOVE 109 /* MMOVE */ #define XXREGET 110 /* REGET */ #define XXLOOK 111 /* LOOKUP */ #define XXVIEW 112 /* VIEW (terminal buffer) */ #define XXANSW 113 /* ANSWER (the phone) */ #define XXPDIA 114 /* PDIAL (partial dial) */ #define XXASC 115 /* ASCII / TEXT */ #define XXBIN 116 /* BINARY */ #define XXFTP 117 /* FTP */ #define XXMKDIR 118 /* MKDIR */ #define XXRMDIR 119 /* RMDIR */ #define XXTELOP 120 /* TELOPT */ #define XXRLOG 121 /* RLOGIN */ #define XXUNDEF 122 /* UNDEFINE */ #define XXNPSH 123 /* NOPUSH */ #define XXADD 124 /* ADD */ #define ADD_SND 0 /* ADD SEND-LIST */ #define ADD_BIN 1 /* ADD BINARY-PATTERNS */ #define ADD_TXT 2 /* ADD TEXT-PATTERNS */ #define XXLOCAL 125 /* LOCAL */ #define XXKERMI 126 /* KERMIT */ #define XXDATE 127 /* DATE */ #define XXSWIT 128 /* SWITCH */ #define XXXFWD 129 /* _FORWARD */ #define XXSAVE 130 /* SAVE */ #define XXXECH 131 /* XECHO */ #define XXRDBL 132 /* READBLOCK */ #define XXWRBL 133 /* WRITEBLOCK */ #define XXRETR 134 /* RETRIEVE */ #define XXEIGHT 135 /* EIGHTBIT */ #define XXEDIT 136 /* EDIT */ #define XXCSEN 137 /* CSEND */ #define XXCREC 138 /* CRECEIVE */ #define XXCQ 139 /* CQ */ #define XXTAPI 140 /* TAPI actions such as dialogs */ #define XXRES 141 /* RESET */ #define XXCGET 142 /* CGET */ #define XXFUNC 143 /* Function (help-only) */ #define XXKVRB 144 /* Kverb (help-only) */ #define XXBROWS 145 /* BROWSE */ #define XXMGET 146 /* MGET */ #define XXBACK 147 /* BACK */ #define XXWHERE 148 /* WHERE */ #define XXREDO 149 /* REDO */ #define XXEXCH 150 /* EXCHANGE */ #define XXREMV 151 /* REMOVE */ #define XXCHRT 152 /* CHROOT */ #define XXOPTS 153 /* Options (help-only) */ #define XXAUTH 154 /* AUTHORIZE */ #define XXPIPE 155 /* PIPE */ #define XXSSH 156 /* SSH */ #define XXTERM 157 /* TERMINAL */ #define XXSTATUS 158 /* STATUS */ #define XXCPR 159 /* COPYRIGHT */ #define XXASSER 160 /* ASSERT */ #define XXSUCC 161 /* SUCCEED */ #define XXFAIL 162 /* FAIL */ #define XXLOGIN 163 /* LOGIN */ #define XXLOGOUT 164 /* LOGOUT */ #define XXNLCL 165 /* NOLOCAL */ #define XXWILD 166 /* WILDCARDS (help-only) */ /* One-word synonyms for REMOTE commands */ #define XXRCPY 167 /* REMOTE COPY */ #define XXRCWD 168 /* Change Working Directory */ #define XXRDEL 169 /* Delete */ #define XXRDIR 170 /* Directory */ #define XXRHLP 171 /* Help */ #define XXRHOS 172 /* Host */ #define XXRKER 173 /* Kermit */ #define XXRMSG 174 /* Message */ #define XXRPRI 175 /* Print */ #define XXRREN 176 /* Rename */ #define XXRSET 177 /* Set */ #define XXRSPA 178 /* Space */ #define XXRSUB 179 /* Submit */ #define XXRTYP 180 /* Type */ #define XXRWHO 181 /* Who */ #define XXRPWD 182 /* Print Working Directory */ #define XXRQUE 183 /* Query */ #define XXRASG 184 /* Assign */ #define XXRMKD 185 /* mkdir */ #define XXRRMD 186 /* rmdir */ #define XXRXIT 187 /* Exit */ /* Top-Level commands, cont'd... */ #define XXGETK 188 /* GETKEYCODE */ #define XXMORE 189 /* MORE */ #define XXXOPTS 190 /* Extended-Options (help-only) */ #define XXIKSD 191 /* IKSD */ #define XXRESET 192 /* RESET */ #define XXASSOC 193 /* ASSOCIATE */ #define ASSOC_FC 0 /* ASSOCIATE FILE-CHARACTER-SET */ #define ASSOC_TC 1 /* ASSOCIATE TRANSFER-CHARACTER-SET */ #define XXSHIFT 194 /* SHIFT */ #define XXMAN 195 /* MANUAL */ #define XXLS 196 /* LS */ #define XXSORT 197 /* SORT */ #define XXPURGE 198 /* PURGE */ #define XXFAST 199 /* FAST */ #define XXCAU 200 /* CAUTIOUS */ #define XXROB 201 /* ROBUST */ #define XXMACRO 202 /* Immediate macro */ #define XXSCRN 203 /* SCREEN */ #define XXLNOUT 204 /* LINEOUT */ #define XX_INCR 205 /* _INCREMENT */ #define XX_DECR 206 /* _DECREMENT */ #define XX_EVAL 207 /* _EVALUATE */ #define XXARRAY 208 /* ARRAY */ #define XXPARSE 209 /* PARSE */ #define XXHTTP 210 /* HTTP */ #ifdef CKCHANNELIO #define XXFILE 211 /* FILE */ #define XXF_CL 212 /* FCLOSE */ #define XXF_FL 213 /* FFLUSH */ #define XXF_LI 214 /* FLIST */ #define XXF_OP 215 /* FOPEN */ #define XXF_RE 216 /* FREAD */ #define XXF_SE 217 /* FSEEK */ #define XXF_ST 218 /* FSTATUS */ #define XXF_WR 219 /* FWRITE */ #define XXF_RW 220 /* FREWIND */ #define XXF_CO 221 /* FCOUNT */ #endif /* CKCHANNELIO */ #define XXEXEC 222 /* exec() */ #define XXTRACE 223 /* TRACE */ #define XXNOTAV 224 /* The "not available" command */ #define XXPTY 225 /* PTY (like PIPE) */ #define XXCHMOD 226 /* CHMOD */ #define XXPROMP 227 /* PROMPT */ #define XXFEACH 228 /* FOREACH */ #define XXGREP 229 /* GREP */ #define XXSEXP 230 /* S-Expression */ #define XXUNDCL 231 /* UNDECLARE */ #define XXVOID 232 /* VOID */ #define XXPUT 233 /* PUT */ #define XXUNDFX 234 /* _UNDEFINE */ #define XXHEAD 235 /* HEAD */ #define XXTAIL 236 /* TAIL */ #define XXDEBUG 237 /* DEBUG */ #define XXLEARN 238 /* LEARN */ #define XXPAT 239 /* PATTERNS (help only) */ #define XXCDUP 240 /* CDUP (Change working directory upwards) */ #define XXRCDUP 241 /* REMOTE CDUP */ #define XXCAT 242 /* CAT (= TYPE /NOPAGE) */ #define XXFIREW 243 /* FIREWALL (help only) */ #define XXLCWD 244 /* Local C(W)D */ #define XXLCDU 245 /* Local CDUP */ #define XXLPWD 246 /* Local PWD */ #define XXLDEL 247 /* Local DELETE */ #define XXLDIR 248 /* Local DIRECTORY */ #define XXLREN 249 /* Local RENAME */ #define XXLMKD 250 /* Local MKDIR */ #define XXLRMD 251 /* Local RMDIR */ #define XXUSER 252 /* (FTP) USER */ #define XXACCT 253 /* (FTP) ACCOUNT */ #define XXLINK 254 /* LINK source destination */ #define XXORIE 255 /* ORIENT(ATION) */ #define XXDIALER 256 /* DIALER */ #define XXKCD 257 /* KCD */ #define XXSITE 258 /* (FTP) SITE */ #define XXPASV 259 /* (FTP) PASSIVE */ #define XXCONT 260 /* CONTINUE */ #define XXNSCR 261 /* NOSCROLL */ #define XXSFTP 262 /* SFTP */ #define XXSKRM 263 /* SKERMIT */ #define XXWDIR 264 /* WDIRECTORY */ #define XXHDIR 265 /* HDIRECTORY */ #define XXTOUC 266 /* TOUCH */ #define XXLOCU 267 /* LOCUS (for HELP) */ #define XXPUTE 268 /* PUTENV */ #define XXXMSG 269 /* XMESSAGE */ #define XXCHG 270 /* CHANGE */ #define XXCSN 271 /* COMPACT-SUBSTRING */ /* End of Top-Level Commands */ #define SCN_CLR 0 /* SCREEN CLEAR */ #define SCN_CLE 1 /* SCREEN CLEOL */ #define SCN_MOV 2 /* SCREEN MOVE */ /* ARRAY operations */ #define ARR_DCL 0 /* Declare */ #define ARR_CPY 1 /* Copy */ #define ARR_RSZ 2 /* Resize */ #define ARR_SRT 3 /* Sort */ #define ARR_CLR 4 /* Clear */ #define ARR_SEA 5 /* Search */ #define ARR_DST 6 /* Destroy */ #define ARR_SHO 7 /* Show */ #define ARR_SET 8 /* Set */ #define ARR_EQU 9 /* Equate */ /* SORT options */ #define SRT_CAS 0 /* /CASE */ #define SRT_KEY 1 /* /KEY:n */ #define SRT_REV 2 /* /REVERSE */ #define SRT_RNG 3 /* /RANGE:n:m */ #define SRT_NUM 4 /* /NUMERIC */ /* PURGE command options */ #define PU_KEEP 0 /* /KEEP: */ #define PU_LIST 1 /* /LIST */ #define PU_PAGE 2 /* /PAGE */ #define PU_NOPA 3 /* /NOPAGE */ #define PU_NODE 4 /* /SIMULATE */ #define PU_DELE 5 /* /DELETE */ #define PU_NOLI 6 /* /NOLIST */ #define PU_QUIE 7 /* /QUIET (= NOLIST) */ #define PU_VERB 8 /* /VERBOSE (= LIST) */ #define PU_ASK 9 /* /ASK */ #define PU_NASK 10 /* /NOASK */ #define PU_LAR 11 /* /LARGER-THAN: */ #define PU_SMA 12 /* /SMALLER-THAN: */ #define PU_AFT 13 /* /AFTER: */ #define PU_NAF 14 /* /NOT-AFTER: */ #define PU_BEF 15 /* /BEFORE: */ #define PU_NBF 16 /* /NOT-BEFORE: */ #define PU_EXC 17 /* /EXCEPT: */ #define PU_RECU 18 /* /RECURSIVE */ #define PU_DOT 19 /* /DOTFILES */ #define PU_NODOT 20 /* /NODOTFILES */ #define PU_HDG 21 /* /HEADING */ #define PU_NOH 22 /* /NOHEADING */ /* DELETE command options */ #define DEL_NOL 0 /* /NOLIST */ #define DEL_LIS 1 /* /LIST */ #define DEL_HDG 2 /* /HEADINGS */ #define DEL_NOH 2 /* /NOHEADINGS */ #define DEL_BEF 3 /* /BEFORE: */ #define DEL_NBF 4 /* /NOT-BEFORE: */ #define DEL_AFT 5 /* /AFTER: */ #define DEL_NAF 6 /* /NOT-AFTER: */ #define DEL_DOT 7 /* /DOTFILES */ #define DEL_NOD 8 /* /NODOTFILES */ #define DEL_EXC 9 /* /EXCEPT:*/ #define DEL_PAG 10 /* /PAGE */ #define DEL_NOP 11 /* /NOPAGE */ #define DEL_REC 12 /* /RECURSIVE */ #define DEL_NOR 13 /* /NORECURSIVE */ #define DEL_VRB 14 /* /VERBOSE */ #define DEL_QUI 15 /* /QUIET */ #define DEL_SMA 16 /* /SMALLER-THAN: */ #define DEL_LAR 17 /* /LARGER-THAN: */ #define DEL_SIM 18 /* /SIMULATE */ #define DEL_ASK 19 /* /ASK */ #define DEL_NAS 20 /* /NOASK */ #define DEL_SUM 21 /* /SUMMARY */ #define DEL_DIR 22 /* /DIRECTORY */ #define DEL_ALL 23 /* /ALL */ #define DEL_TYP 24 /* /TYPE: */ #define DEL_LNK 25 /* /FOLLOWLINKS */ #define DEL_NLK 26 /* /NOFOLLOWLINKS */ /* RENAME switches that can be used in the same table as the DEL switches */ #define REN_LOW 100 /* Convert to lowercase */ #define REN_UPP 101 /* Converto to uppercase */ #define REN_RPL 102 /* String replacement */ #define REN_OVW 103 /* Overwrite file with same name */ #define REN_XLA 104 /* Translate character sets */ #define REN_SPA 105 /* Fix spaces */ /* FILE operations */ #define FIL_OPN 0 /* OPEN */ #define FIL_CLS 1 /* CLOSE */ #define FIL_REA 2 /* READ */ #define FIL_GET 3 /* GET */ #define FIL_WRI 4 /* WRITE */ #define FIL_REW 5 /* REWIND */ #define FIL_LIS 6 /* LIST */ #define FIL_FLU 7 /* FLUSH */ #define FIL_SEE 8 /* SEEK */ #define FIL_STA 9 /* STATUS */ #define FIL_COU 10 /* COUNT */ /* OPEN / CLOSE items */ #define OPN_FI_R 1 /* FILE READ */ #define OPN_FI_W 2 /* FILE WRITE */ #define OPN_FI_A 3 /* FILE APPEND */ #define OPN_PI_R 4 /* PIPE READ */ #define OPN_PI_W 5 /* PIPE WRITE */ #define OPN_PT_R 6 /* PTY READ */ #define OPN_PT_W 7 /* PTY WRITE */ #define OPN_SER 8 /* PORT or LINE */ #define OPN_NET 9 /* HOST */ /* KERBEROS command switches */ #define KRB_S_VE 0 /* /VERSION */ #define KRB_S_CA 1 /* /CACHE: */ #define KRB_S_MAX 1 /* Highest KERBEROS switch number */ #ifdef CK_KERBEROS /* KERBEROS actions */ #define KRB_A_IN 0 /* INITIALIZE */ #define KRB_A_DE 1 /* DESTROY */ #define KRB_A_LC 2 /* LIST-CREDENTIALS */ /* KERBEROS INIT switches */ #define KRB_I_FW 0 /* /FORWARDABLE */ #define KRB_I_LF 1 /* /LIFETIME: */ #define KRB_I_PD 2 /* /POSTDATE: */ #define KRB_I_PR 3 /* /PROXIABLE */ #define KRB_I_RB 4 /* /RENEWABLE: */ #define KRB_I_RN 5 /* /RENEW */ #define KRB_I_SR 6 /* /SERVICE: */ #define KRB_I_VA 7 /* /VALIDATE */ #define KRB_I_RL 8 /* /REALM: */ #define KRB_I_IN 9 /* /INSTANCE: */ #define KRB_I_PW 10 /* /PASSWORD: */ #define KRB_I_PA 11 /* /PREAUTH */ #define KRB_I_VB 12 /* /VERBOSE */ #define KRB_I_BR 13 /* /BRIEF */ #define KRB_I_NFW 14 /* /NOT-FORWARDABLE */ #define KRB_I_NPR 15 /* /NOT-PROXIABLE */ #define KRB_I_NPA 16 /* /NOT-PREAUTH */ #define KRB_I_K4 17 /* /KERBEROS4 (should k5 get k4 as well) */ #define KRB_I_NK4 18 /* /NO-KERBEROS4 */ #define KRB_I_POP 19 /* /POPUP */ #define KRB_I_ADR 20 /* /ADDRESSES: */ #define KRB_I_NAD 21 /* /NO-ADDRESSES */ #define KRB_I_MAX 21 /* Highest KERBEROS INIT switch number */ #endif /* CK_KERBEROS */ /* SET parameters */ #define XYBREA 0 /* BREAK simulation */ #define XYCHKT 1 /* Block check type */ #define XYDEBU 2 /* Debugging */ #define XYDELA 3 /* Delay */ #define XYDUPL 4 /* Duplex */ #define XYEOL 5 /* End-Of-Line (packet terminator) */ #define XYESC 6 /* Escape character */ #define XYFILE 7 /* File Parameters (see ckcker.h for values) */ /* (this space available) */ #define XYFLOW 9 /* Flow Control */ #define XYHAND 10 /* Handshake */ #define XYIFD 11 /* Incomplete File Disposition */ #define XYIMAG 12 /* "Image Mode" */ #define XYINPU 13 /* INPUT command parameters */ #define XYLEN 14 /* Maximum packet length to send */ #define XYLINE 15 /* Communication line to use */ /* SET LINE / SET HOST command switches */ #define SL_CNX 0 /* /CONNECT */ #define SL_SRV 1 /* /SERVER */ #define SL_SHR 2 /* /SHARE */ #define SL_NSH 3 /* /NOSHARE */ #define SL_BEE 4 /* /BEEP */ #define SL_ANS 5 /* /ANSWER */ #define SL_DIA 6 /* /DIAL:xxx */ #define SL_SPD 7 /* /SPEED:xxx */ #define SL_FLO 8 /* /FLOW:xxx */ #define SL_TMO 9 /* /TIMEOUT:xxx */ #define SL_CMD 10 /* /COMMAND */ #define SL_PSW 11 /* /PASSWORD:xxx */ #define SL_IKS 12 /* /KERMIT-SERVICE */ #define SL_NET 13 /* /NETWORK-TYPE:xxx */ #define SL_ENC 14 /* /ENCRYPT:type (telnet) /ENCRYPT (rlogin) */ #define SL_KRB4 15 /* /KERBEROS 4 (rlogin/telnet) */ #define SL_KRB5 16 /* /KERBEROS 5 (rlogin/telnet) */ #define SL_SRP 17 /* /SRP (telnet) */ #define SL_NTLM 18 /* /NTLM (telnet) */ #define SL_SSL 19 /* /SSL (telnet) */ #define SL_UID 20 /* /USERID:xxxx */ #define SL_AUTH 21 /* /AUTH:type */ #define SL_WAIT 22 /* /WAIT */ #define SL_NOWAIT 23 /* /NOWAIT */ #define SL_PTY 24 /* /PTY */ #define XYLOG 16 /* Log file */ #define XYMARK 17 /* Start of Packet mark */ #define XYNPAD 18 /* Amount of padding */ #define XYPADC 19 /* Pad character */ #define XYPARI 20 /* Parity */ #define XYPAUS 21 /* Interpacket pause */ #define XYPROM 22 /* Program prompt string */ #define XYQBIN 23 /* 8th-bit prefix */ #define XYQCTL 24 /* Control character prefix */ #define XYREPT 25 /* Repeat count prefix */ #define XYRETR 26 /* Retry limit */ #define XYSPEE 27 /* Line speed (baud rate) */ #define XYTACH 28 /* Character to be doubled */ #define XYTIMO 29 /* Timeout interval */ #define XYMODM 30 /* Modem - also see XYDIAL */ #define XYSEND 31 /* SET SEND parameters */ #define XYRECV 32 /* SET RECEIVE parameters */ #define XYTERM 33 /* SET TERMINAL parameters */ #define XYTBYT 0 /* Terminal Bytesize (7 or 8) */ #define XYTTYP 1 /* Terminal emulation Type */ #define TT_NONE 0 /* NONE, no emulation */ #ifdef OS2 /* Note, the symbols for VT and VT-like terminals should be in ascending numerical order, so that higher ones can be treated as supersets of lower ones with respect to capabilities. This is no longer the case with the influx of new terminal types. Just make sure that the ISXXXXX() macros include the proper family groups. */ #define TT_DG200 1 /* Data General 200 */ #define TT_DG210 2 /* Data General 210 */ #define TT_DG217 3 /* Data General 217 */ #define TT_HP2621 4 /* Hewlett-Packard 2621A */ #define TT_HPTERM 5 /* Hewlett-Packard Console */ #define TT_HZL1500 6 /* Hazeltine 1500 */ #define TT_VC4404 7 /* Volker Craig VC4404/404 */ #define TT_WY30 8 /* WYSE-30/30+ */ #define TT_WY50 9 /* WYSE-50/50+ */ #define TT_WY60 10 /* WYSE-60 */ #define TT_WY160 11 /* WYSE-160 */ #define TT_QNX 12 /* QNX */ #define TT_QANSI 13 /* QNX Ansi emulation */ #define TT_VT52 14 /* DEC VT-52 */ #define TT_H19 15 /* Heath-19 */ #define TT_IBM31 16 /* IBM 31xx */ #define TT_SCOANSI 17 /* SCOANSI (Unix mode) */ #define TT_AT386 18 /* Unixware AT386 (Unix mode) */ #define TT_ANSI 19 /* IBM ANSI.SYS (BBS) */ #define TT_VIP7809 20 /* Honeywell VIP7809 */ #define TT_LINUX 21 /* Linux Console */ #define TT_HFT 22 /* IBM High Function Terminal */ #define TT_AIXTERM 23 /* IBM AIXterm */ #define TT_SUN 24 /* SUN Console */ #define TT_BA80 25 /* Nixdorf BA80 */ #define TT_BEOS 26 /* BeOS Ansi */ #define TT_VT100 27 /* DEC VT-100 */ #define TT_VT102 28 /* DEC VT-102 */ #define TT_VT220 29 /* DEC VT-220 */ #define TT_VT220PC 30 /* DEC VT-220 with PC keyboard */ #define TT_VT320 31 /* DEC VT-320 */ #define TT_VT320PC 32 /* DEC VT-320 with PC keyboard */ #define TT_WY370 33 /* WYSE 370 ANSI Terminal */ #define TT_97801 34 /* Sinix 97801-5xx terminal */ #define TT_AAA 35 /* Ann Arbor Ambassador */ #define TT_TVI910 36 /* TVI 910+ */ #define TT_TVI925 37 /* TVI 925 */ #define TT_TVI950 38 /* TVI950 */ #define TT_ADM3A 39 /* LSI ADM 3A */ #define TT_ADM5 40 /* LSI ADM 5 */ #define TT_VTNT 41 /* Microsoft NT Virtual Terminal */ #define TT_MAX TT_VTNT #define TT_VT420 96 /* DEC VT-420 */ #define TT_VT520 97 /* DEC VT-520/525 */ #define TT_XTERM 98 /* XTerm */ #define TT_TEK40 99 /* Tektronix 401x */ #define TT_KBM_EMACS TT_MAX+1 #define TT_KBM_HEBREW TT_MAX+2 #define TT_KBM_RUSSIAN TT_MAX+3 #define TT_KBM_WP TT_MAX+4 #define ISAAA(x) (x == TT_AAA) #define ISANSI(x) (x >= TT_SCOANSI && x <= TT_ANSI) #define ISBA80(x) (x == TT_BA80) #define ISBEOS(x) (x == TT_BEOS) #define ISQNX(x) (x == TT_QNX) #define ISQANSI(x) (x == TT_QANSI) #define ISLINUX(x) (x == TT_LINUX) #define ISSCO(x) (x == TT_SCOANSI) #define ISAT386(x) (x == TT_AT386) #define ISAVATAR(x) (x == TT_ANSI) #define ISSUN(x) (x == TT_SUN) #define ISUNIXCON(x) (x == TT_SCOANSI || x == TT_AT386 || \ x == TT_LINUX || x == TT_SUN) #define ISDG200(x) (x >= TT_DG200 && x <= TT_DG217) #define ISHZL(x) (x == TT_HZL1500) #define ISH19(x) (x == TT_H19) #define ISIBM31(x) (x == TT_IBM31) #define ISTVI(x) (x >= TT_TVI910 && x <= TT_TVI950) #define ISTVI910(x) (x == TT_TVI910) #define ISTVI925(x) (x == TT_TVI925) #define ISTVI950(x) (x == TT_TVI950) #define ISVT52(x) (x == TT_VT52 || x == TT_H19) #ifdef COMMENT #define ISVT520(x) (x == TT_VT520) #define ISVT420(x) (x >= TT_VT420 && x <= TT_VT520) #else /* COMMENT */ /* Since we do not yet support 420/520 extend 320 */ #define ISVT520(x) (ISVT320(x)) #define ISVT420(x) (ISVT320(x)) #endif /* COMMENT */ #define ISVT320(x) (x >= TT_VT320 && x <= TT_AAA) #define ISVT220(x) (x >= TT_VT220 && x <= TT_AAA || \ ISBEOS(x) || ISQANSI(x) || \ ISLINUX(x) || ISSUN(x)) #define ISVT102(x) (x >= TT_VIP7809 && x <= TT_BA80 || \ x == TT_VT102 || ISVT220(x)) #define ISVT100(x) (x == TT_VT100 || ISVT102(x)) #define ISWY30(x) (x == TT_WY30) #define ISWYSE(x) (x >= TT_WY30 && x <= TT_WY160) #define ISWY50(x) (x == TT_WY50) #define ISWY60(x) (x == TT_WY60 || x == TT_WY160) #define ISWY160(x) (x == TT_WY160) #define ISWY370(x) (x == TT_WY370) #define ISVC(x) (x == TT_VC4404) #define ISHP(x) (x == TT_HPTERM || x == TT_HP2621) #define ISHPTERM(x) (x == TT_HPTERM) #define ISVIP(x) (x == TT_VIP7809) #define IS97801(x) (x == TT_97801) #define ISHFT(x) (x == TT_HFT || x == TT_AIXTERM) #define ISAIXTERM(x) (x == TT_AIXTERM) #define ISTEK(x) (x == TT_TEK40) #define ISVTNT(x) (x == TT_VTNT) #define ISADM3A(x) (x == TT_ADM3A) #define ISADM5(x) (x == TT_ADM5) #define ISXTERM(x) (x == TT_XTERM) #endif /* OS2 */ #define XYTCS 2 /* Terminal Character Set */ #define XYTSO 3 /* Terminal Shift-In/Shift-Out */ #define XYTNL 4 /* Terminal newline mode */ #ifdef OS2 #define XYTCOL 5 /* Terminal colors */ #endif /* OS2 */ #define XYTEC 6 /* Terminal echo = duplex = local-echo */ #ifdef OS2 #define XYTCUR 7 /* Terminal cursor */ #define TTC_ULINE 0 #define TTC_HALF 1 #define TTC_BLOCK 2 #define XYTARR 8 /* Terminal arrow-key mode */ #define XYTKPD 9 /* Terminal keypad mode */ #define TTK_NORM 0 /* Normal mode for arrow / keyad keys */ #define TTK_APPL 1 /* Application mode for arrow / keyad keys */ #define XYTWRP 10 /* Terminal wrap */ #endif /* OS2 */ #define XYTCRD 11 /* Terminal CR-display */ #define XYTANS 12 /* Terminal answerback */ #ifdef OS2 #define XYSCRS 13 /* Terminal scrollback buffer size */ #endif /* OS2 */ #define XYTAPC 14 /* Terminal APC */ #ifdef OS2 #define XYTBEL 15 /* Terminal Bell */ #endif /* OS2 */ #define XYTDEB 16 /* Terminal Debug */ #ifdef OS2 #define XYTROL 17 /* Terminal Rollback */ #define TTR_OVER 0 /* Rollback Overwrite */ #define TTR_INSERT 1 /* Rollback Insert */ #define TTR_KEYS 2 /* Keystrokes */ #define TTRK_IGN 0 /* Ignore */ #define TTRK_RST 2 /* Restore and Send */ #define TTRK_SND 1 /* Send */ #define XYTCTS 18 /* Terminal Transmit-Timeout */ #define XYTCPG 19 /* Terminal Code Page */ #ifdef COMMENT #define XYTHCU 20 /* Terminal Hide-Cursor */ #endif /* COMMENT */ #define XYTPAC 21 /* Terminal Output-Pacing */ #define XYTMOU 22 /* Terminal Mouse */ #endif /* OS2 */ #define XYTHIG 23 /* Terminal Width */ #define XYTWID 24 /* Terminal Height */ #ifdef OS2 #define XYTUPD 25 /* Terminal Screen-update */ #define TTU_FAST 0 /* FAST but jerky */ #define TTU_SMOOTH 1 /* SMOOTH but slow */ #define XYTFON 26 /* Terminal Full screen Font */ #define TTF_ROM 0 /* ROM font */ #define TTF_CY1 1 /* CYRILL1 font */ #define TTF_CY2 2 /* CYRILL2 font */ #define TTF_CY3 3 /* CYRILL3 font */ #define TTF_111 111 /* CP111 font */ #define TTF_112 112 /* CP112 font */ #define TTF_113 113 /* CP113 font */ #define TTF_437 437 /* CP437 font */ #define TTF_850 850 /* CP850 font */ #define TTF_851 851 /* CP851 font */ #define TTF_852 852 /* CP852 font */ #define TTF_853 853 /* CP853 font */ #define TTF_860 860 /* CP860 font */ #define TTF_861 861 /* CP861 font */ #define TTF_862 862 /* CP862 font */ #define TTF_863 863 /* CP863 font */ #define TTF_864 864 /* CP864 font */ #define TTF_865 865 /* CP865 font */ #define TTF_866 866 /* CP866 font */ #define TTF_880 880 /* CP880 font */ #define TTF_881 881 /* CP881 font */ #define TTF_882 882 /* CP882 font */ #define TTF_883 883 /* CP883 font */ #define TTF_884 884 /* CP884 font */ #define TTF_885 885 /* CP885 font */ #define XYTVCH 27 /* SET TERMINAL VIDEO-CHANGE */ #define TVC_DIS 0 /* DISABLED */ #define TVC_ENA 1 /* ENABLED */ #define TVC_W95 2 /* WIN95-SAFE */ #endif /* OS2 */ #define XYTAUTODL 28 /* SET TERMINAL AUTODOWNLOAD */ #define TAD_OFF 0 /* OFF */ #define TAD_ON 1 /* ON */ #define TAD_K 2 /* KERMIT */ #define TAD_Z 3 /* ZMODEM */ #define TAD_X_STR 0 /* STRING */ #define TAD_X_DETECT 1 /* DETECTION ( PACKET, STRING ) */ #define TAD_X_C0 2 /* C0 CONFLICTS */ #define TAD_ERR 4 /* ERROR { STOP, CONTINUE } */ #define TAD_ASK 5 /* ASK (dialog) */ #define XYTAUTOUL 29 /* SET TERMINAL AUTOUPLOAD */ #ifdef OS2 #define XYTATTBUG 30 /* SET TERM ATTR-BUG */ #define XYTSTAT 31 /* SET TERM STATUSLINE */ #endif /* OS2 */ #define XYTESC 32 /* SET TERM ESCAPE-CHARACTER */ #define XYTCTRL 33 /* SET TERM CONTROLS */ #ifdef OS2 #define XYTATTR 34 /* SET TERM ATTRIBUTE representation */ #define XYTSGRC 35 /* SET TERM SGRCOLORS */ #endif /* OS2 */ #define XYTLCS 36 /* SET TERM LOCAL-CHARACTER-SET */ #define XYTRCS 37 /* SET TERM REMOTE-CHARACTER-SET */ #define XYTUNI 38 /* SET TERM UNICODE */ #define XYTKEY 39 /* SET TERM KEY */ #ifdef OS2 #define XYTSEND 40 /* SET TERM SEND-DATA */ #define XYTSEOB 41 /* SET TERM SEND-END-OF-BLOCK */ #define XYTMBEL 42 /* SET TERM MARGIN-BELL */ #endif /* OS2 */ #define XYTIDLE 43 /* SET TERM IDLE-SEND */ #ifdef OS2 #define XYTKBMOD 44 /* SET TERM KEYBOARD-MODE */ #define XYTUNX 45 /* SET TERM UNIX-MODE (DG) */ #define XYTASCRL 46 /* SET TERM AUTOSCROLL */ #define XYTAPAGE 47 /* SET TERM AUTOPAGE */ #endif /* OS2 */ #define XYTRIGGER 48 /* SET TERM TRIGGER */ #ifdef OS2 #define XYTPCTERM 49 /* SET TERM PCTERM */ #define XYTOPTI 50 /* SET TERM SCREEN-OPTIMIZE */ #define XYTSCNM 51 /* SET TERM SCREEN-MODE (DECSCNM) */ #endif /* OS2 */ #define XYTPRN 52 /* SET TERM PRINT {AUTO, COPY, OFF} */ #ifdef OS2 #define XYTSAC 53 /* SET TERM SPACING-ATTRIBUTE-CHARACTER (inv) */ #define XYTSNIPM 54 /* SET TERM SNI-AUTOROLL */ #define XYTSNISM 55 /* SET TERM SNI-SCROLLMODE */ #define XYTKBDGL 56 /* SET TERM KBD-FOLLOWS-GL/GR */ #define XYTVTLNG 57 /* SET TERM VT-LANGUAGE */ #define VTL_NORTH_AM 1 #define VTL_BRITISH 2 #define VTL_BELGIAN 3 #define VTL_FR_CAN 4 #define VTL_DANISH 5 #define VTL_FINNISH 6 #define VTL_GERMAN 7 #define VTL_DUTCH 8 #define VTL_ITALIAN 9 #define VTL_SW_FR 10 #define VTL_SW_GR 11 #define VTL_SWEDISH 12 #define VTL_NORWEGIA 13 #define VTL_FRENCH 14 #define VTL_SPANISH 15 #define VTL_PORTUGES 16 #define VTL_HEBREW 19 #define VTL_GREEK 22 #define VTL_CANADIAN 28 #define VTL_TURK_Q 29 #define VTL_TURK_F 30 #define VTL_HUNGARIA 31 #define VTL_SLOVAK 33 #define VTL_CZECH 34 #define VTL_POLISH 35 #define VTL_ROMANIAN 36 #define VTL_SCS 38 #define VTL_RUSSIAN 39 #define VTL_LATIN_AM 40 #define XYTVTNRC 58 /* SET TERM VT-NRC-MODE */ #define XYTSNICC 59 /* SET TERM SNI-CH.CODE */ #define XYTSNIFV 60 /* SET TERM SNI-FIRMWARE-VERSIONS */ #define XYTURLHI 61 /* SET TERM URL-HIGHLIGHT */ #endif /* OS2 */ #define XYTITMO 62 /* SET TERM IDLE-TIMEOUT */ #define XYTIACT 63 /* SET TERM IDLE-ACTION */ #define XYTLSP 64 /* SET TERM LINE-SPACING */ #define XYTLFD 65 /* SET TERM LF-DISPLAY */ #define XYATTR 34 /* Attribute packets */ #define XYSERV 35 /* Server parameters */ #define XYSERT 0 /* Server timeout */ #define XYSERD 1 /* Server display */ #define XYSERI 2 /* Server idle */ #define XYSERP 3 /* Server get-path */ #define XYSERL 4 /* Server login */ #define XYSERC 5 /* Server CD-Message */ #define XYSERK 6 /* Server keepalive */ #define XYWIND 36 /* Window size */ #define XYXFER 37 /* Transfer */ #define XYX_CAN 0 /* Cancellation */ #define XYX_CSE 1 /* Character-Set */ #define XYX_LSH 2 /* Locking-Shift */ #define XYX_PRO 3 /* Protocol */ #define XYX_MOD 4 /* Mode */ #define XYX_DIS 5 /* Display */ #define XYX_SLO 6 /* Slow-start */ #define XYX_CRC 7 /* CRC calculation */ #define XYX_BEL 8 /* Bell */ #define XYX_PIP 9 /* Pipes */ #define XYX_INT 10 /* Interruption */ #define XYX_XLA 11 /* (character-set) Translation On/Off */ #define XYX_MSG 12 /* Message */ #define XYX_RPT 13 /* Report */ #define XYLANG 38 /* Language */ #define XYCOUN 39 /* Count */ #define XYTAKE 40 /* Take */ #define XYUNCS 41 /* Unknown-character-set */ #define XYKEY 42 /* Key */ #define XYMACR 43 /* Macro */ #define XYHOST 44 /* Hostname on network */ #define XYNET 45 /* SET NETWORK things */ #define XYNET_D 99 /* NETWORK DIRECTORY */ #define XYNET_T 100 /* NETWORK TYPE */ #define XYCARR 46 /* Carrier */ #define XYXMIT 47 /* Transmit */ #define XYDIAL 48 /* Dial options */ /* And now we interrupt the flow to bring you lots of stuff about dialing */ #ifndef MAXTOLLFREE /* Maximum number of toll-free area codes */ #define MAXTOLLFREE 8 #endif /* MAXTOLLFREE */ #ifndef MAXTPCC /* Maximum Tone or Pulse dialing countries */ #define MAXTPCC 160 #endif /* MAXTPCC */ #ifndef MAXPBXEXCH /* Maximum number of PBX exchanges */ #define MAXPBXEXCH 8 #endif /* MAXPBXEXCH */ #ifndef MAXLOCALAC #define MAXLOCALAC 32 #endif /* MAXLOCALAC */ #ifndef MAXDNUMS #ifdef BIGBUFOK #define MAXDDIR 32 /* Maximum number of dialing directories */ #define MAXDNUMS 4095 /* Max numbers to fetch from dialing directories */ #else #define MAXDDIR 12 #define MAXDNUMS 1024 #endif /* BIGBUFOK */ #endif /* MAXDNUMS */ /* IMPORTANT: In 5A(192), the old SET DIAL command was split into two commands: SET MODEM (for modem-related parameters) and SET DIAL (for dialing items). To preserve the old formats, etc, invisibly we keep one symbol space for both commands. */ #define XYDHUP 0 /* Dial Hangup */ #define XYDINI 1 /* MODEM (dial) Initialization string */ #define XYDKSP 2 /* MODEM (dial) Kermit-Spoof */ #define XYDTMO 3 /* Dial Timeout */ #define XYDDPY 4 /* Dial Display */ #define XYDSPD 5 /* Dial Speed matching */ #define XYDMNP 6 /* MODEM (dial) MNP negotiation enabled (obsolete) */ #define XYDEC 7 /* MODEM (dial) error correction enabled */ #define XYDDC 8 /* MODEM (dial) compression enabled */ #define XYDHCM 9 /* MODEM (dial) hangup-string (moved elsewhere) */ #define XYDDIR 10 /* Dial directory */ #define XYDDIA 11 /* MODEM (dial) dial-command */ #define XYDMHU 12 /* MODEM HANGUP (dial modem-hangup) */ #ifndef DEFMDHUP /* Default MODEM HANGUP-METHOD */ #define DEFMDMHUP 1 /* 0 = RS232, 1 = modem command */ #endif /* DEFMDMHUP */ #define XYDNPR 13 /* Dial PREFIX */ #define XYDSTR 14 /* MODEM COMMAND (dial string) ... */ #define XYDS_DC 0 /* Data compression */ #define XYDS_EC 1 /* Error correction */ #define XYDS_HU 2 /* Hangup command */ #define XYDS_HW 3 /* Hardware flow control */ #define XYDS_IN 4 /* Init-string */ #define XYDS_NF 5 /* No flow control */ #define XYDS_PX 6 /* Prefix (no, this goes in SET DIAL) */ #define XYDS_SW 7 /* Software flow control */ #define XYDS_DT 8 /* Tone dialing command */ #define XYDS_DP 9 /* Pulse dialing command */ #define XYDS_AN 10 /* Autoanswer */ #define XYDS_RS 11 /* Reset */ #define XYDS_MS 12 /* Dial mode string */ #define XYDS_MP 13 /* Dial mode prompt */ #define XYDS_SP 14 /* Modem speaker */ #define XYDS_VO 15 /* Modem speaker volume */ #define XYDS_ID 16 /* Ignore dialtone */ #define XYDS_I2 17 /* Init string #2 */ #define XYDM_A 9 /* Method: Auto */ #define XYDM_D 0 /* Default */ #define XYDM_T 2 /* Tone */ #define XYDM_P 3 /* Pulse */ #define XYDFC 15 /* MODEM (dial) flow-control */ #define XYDMTH 16 /* Dial method */ #define XYDESC 17 /* MODEM (dial) escape-character */ #define XYDMAX 18 /* MODEM (dial) maximum interface speed */ #define XYDCAP 19 /* MODEM (dial) capabilities */ #define XYDTYP 20 /* MODEM TYPE */ #define XYDINT 21 /* DIAL retries */ #define XYDRTM 22 /* DIAL time between retries */ #define XYDNAM 23 /* MODEM NAME */ #define XYDLAC 24 /* DIAL (LOCAL-)AREA-CODE */ #define XYDMCD 25 /* MODEM CARRIER */ #define XYDCNF 26 /* DIAL CONFIRMATION */ #define XYDCVT 27 /* DIAL CONVERT-DIRECTORY */ #define XYDIXP 28 /* DIAL INTERNATIONAL-PREFIX */ #define XYDIXS 29 /* DIAL INTERNATIONAL-SUFFIX */ #define XYDLCC 30 /* DIAL LOCAL-COUNTRY-CODE */ #define XYDLDP 31 /* DIAL LONG-DISTANCE-PREFIX */ #define XYDLDS 32 /* DIAL LONG-DISTANCE-SUFFIX */ #define XYDPXX 33 /* DIAL PBX-EXCHANGE */ #define XYDPXI 34 /* DIAL PBX-INTERNAL-PREFIX */ #define XYDPXO 35 /* DIAL PBX-OUTSIDE-PREFIX */ #define XYDSFX 36 /* DIAL SUFFIX */ #define XYDSRT 37 /* DIAL SORT */ #define XYDTFC 38 /* DIAL TOLL-FREE-AREA-CODE */ #define XYDTFP 39 /* DIAL TOLL-FREE-PREFIX */ #define XYDTFS 40 /* DIAL TOLL-FREE-SUFFIX */ #define XYDCON 41 /* DIAL CONNECT */ #define XYDRSTR 42 /* DIAL RESTRICT */ #define XYDRSET 43 /* MODEM RESET */ #define XYDLCP 44 /* DIAL LOCAL-PREFIX */ #define XYDLCS 45 /* DIAL LOCAL-SUFFIX */ #define XYDLLAC 46 /* DIAL LC-AREA-CODES */ #define XYDFLD 47 /* DIAL FORCE LONG-DISTANCE */ #define XYDSPK 48 /* MODEM SPEAKER */ #define XYDVOL 49 /* MODEM VOLUME */ #define XYDIDT 50 /* IGNORE DIALTONE */ #define XYDPAC 51 /* PACING */ #define XYDMAC 52 /* MACRO */ #define XYDPUCC 53 /* PULSE-COUNTRIES */ #define XYDTOCC 54 /* TONE-COUNTRIES */ #define XYDTEST 55 /* TEST */ #define XYA_CID 1 /* SET ANSWER CALLER-ID */ #define XYA_RNG 2 /* SET ANSWER RINGS */ #define XYSESS 49 /* SET SESSION options */ #define XYBUF 50 /* Buffer length */ #define XYBACK 51 /* Background */ #define XYDFLT 52 /* Default */ #define XYDBL 53 /* Double */ #define XYCMD 54 /* COMMAND */ #define XYCASE 55 /* Case */ #define XYCOMP 56 /* Compression */ #define XYX25 57 /* X.25 parameter (ANYX25) */ #define XYPAD 58 /* X.3 PAD parameter (ANYX25) */ #define XYWILD 59 /* Wildcard expansion method */ #define WILD_OFF 0 /* Wildcard expansion off */ #define WILD_ON 1 /* Wildcard expansion on */ #define WILD_KER 2 /* Wildcard expansion by Kermit */ #define WILD_SHE 3 /* Wildcard expansion by Shell */ #define XYSUSP 60 /* Suspend */ #define XYMAIL 61 /* Mail-Command */ #define XYPRIN 62 /* Print-Command */ #define XYQUIE 63 /* Quiet */ #define XYLCLE 64 /* Local-echo */ #define XYSCRI 65 /* SCRIPT command parameters */ #define XYMSGS 66 /* MESSAGEs ON/OFF */ #ifdef TNCODE #define XYTEL 67 /* SET TELNET parameters */ #define CK_TN_EC 0 /* TELNET ECHO */ #define CK_TN_TT 1 /* TELNET TERMINAL-TYPE */ #define CK_TN_NL 2 /* TELNET NEWLINE-MODE */ #define CK_TN_BM 3 /* TELNET BINARY-MODE */ #define CK_TN_BUG 4 /* TELNET BUG */ #define CK_TN_ENV 5 /* TELNET ENVIRONMENT */ #define TN_ENV_USR 0 /* VAR USER */ #define TN_ENV_JOB 1 /* VAR JOB */ #define TN_ENV_ACCT 2 /* VAR ACCT */ #define TN_ENV_PRNT 3 /* VAR PRINTER */ #define TN_ENV_SYS 4 /* VAR SYSTEMTYPE */ #define TN_ENV_DISP 5 /* VAR DISPLAY */ #define TN_ENV_UVAR 6 /* USERVAR */ #define TN_ENV_LOC 7 /* USERVAR LOCATION */ #define TN_ENV_ON 98 /* ON (enabled) */ #define TN_ENV_OFF 99 /* OFF (disabled) */ #define CK_TN_LOC 6 /* TELNET LOCATION */ #define CK_TN_AU 7 /* TELNET AUTHENTICATION */ #define TN_AU_FWD 4 /* AUTH FORWARD */ #define TN_AU_TYP 5 /* AUTH TYPE */ #define AUTH_NONE 0 /* AUTH NONE */ #define AUTH_KRB4 1 /* AUTH Kerberos IV */ #define AUTH_KRB5 2 /* AUTH Kerberos V */ #define AUTH_SSL 7 /* AUTH Secure Sockets Layer */ #define AUTH_TLS 98 /* AUTH Transport Layer Security */ #define AUTH_SRP 5 /* AUTH Secure Remote Password */ #define AUTH_NTLM 15 /* AUTH NT Lan Manager */ #define AUTH_AUTO 99 /* AUTH AUTOMATIC */ #define TN_AU_HOW 8 /* AUTH HOW FLAG */ #define TN_AU_ENC 9 /* AUTH ENCRYPT FLAG */ #define CK_TN_ENC 8 /* TELNET ENCRYPTION */ #define TN_EN_TYP 4 /* ENCRYPT TYPE */ #define TN_EN_START 5 /* ENCRYPT START */ #define TN_EN_STOP 6 /* ENCRYPT STOP */ #define CK_TN_IKS 9 /* TELNET KERMIT-SERVER */ #define CK_TN_RE 10 /* TELNET REMOTE-ECHO */ #define CK_TN_TLS 11 /* TELNET START_TLS */ #define CK_TN_XD 12 /* TELNET XDISPLOC */ #define CK_TN_NAWS 13 /* TELNET NAWS */ #define CK_TN_WAIT 14 /* TELNET WAIT-FOR-NEGOTIATIONS */ #define CK_TN_SGA 15 /* TELNET SGA */ #define CK_TN_CLIENT 16 /* TELNET CLIENT */ #define CK_TN_SERVER 17 /* TELNET SERVER */ #define CK_TN_PHR 18 /* TELNET PRAGMA-HEARTBEAT */ #define CK_TN_PLG 19 /* TELNET PRAGMA-LOGON */ #define CK_TN_PSP 20 /* TELNET PRAGMA-SSPI */ #define CK_TN_SAK 21 /* TELNET IBM SAK */ #define CK_TN_FLW 22 /* TELNET LFLOW */ #define CK_TN_XF 23 /* TELNET TRANSFER-MODE */ #define CK_TN_PUID 24 /* TELNET PROMPT-FOR-USERID */ #define CK_TN_NE 25 /* TELNET NO-ENCRYPT-DURING-XFER */ #define CK_TN_CPC 26 /* TELNET COM-PORT-CONTROL */ #define CK_TN_DB 27 /* TELNET DEBUG */ #define CK_TN_FX 28 /* TELNET FORWARD_X */ #define CK_TN_DL 29 /* TELNET DELAY-SB */ #define CK_TN_SFU 30 /* TELNET SFU-COMPATIBILITY */ #define CK_TN_LOG 31 /* TELNET LOGOUT */ #endif /* TNCODE */ #define XYOUTP 68 /* OUTPUT command parameters */ #define OUT_PAC 0 /* OUTPUT PACING */ #define OUT_ESC 1 /* OUTPUT SPECIAL-ESCAPES */ #define XYEXIT 69 /* SET EXIT */ #define XYPRTR 70 /* SET PRINTER */ #define XYFPATH 71 /* PATHNAME */ #ifdef OS2 #define XYMOUSE 72 /* MOUSE SUPPORT */ #define XYM_ON 0 /* Mouse ON/OFF */ #define XYM_BUTTON 1 /* Define Mouse Events */ #define XYM_CLEAR 2 /* Clear Mouse Events */ #define XYM_DEBUG 3 /* Debug Mode ON/OFF */ #define XYM_REPORTING 4 /* Mouse Reporting */ #define XYM_WHEEL 5 /* Mouse wheel events */ #define XYM_REPORTING_DISABLED 1 /* No mouse reporting */ #define XYM_REPORTING_ENABLED 2 /* Allow reporting unassigned events only */ #define XYM_REPORTING_OVERRIDE 3 /* Allow reporting all events */ /* These must match similar definitions in ckokey.h */ #define XYM_B1 0 /* Mouse Button One */ #define XYM_B2 1 /* Mouse Button Two */ #define XYM_B3 2 /* Mouse Button Three */ #define XYM_WHEEL_UP 3 /* Mouse wheel up / forewards / away from user */ #define XYM_WHEEL_DN 4 /* Mouse wheel down / backwards / towards user */ #define XYM_ALT 1 /* Alt */ #define XYM_CTRL 2 /* Ctrl */ #define XYM_SHIFT 4 /* Shift */ #define XYM_C1 0 /* Single Click */ #define XYM_C2 8 /* Double Click */ #define XYM_DRAG 16 /* Drag Event */ #endif /* OS2 */ #define XYBELL 73 /* BELL */ #ifdef OS2 #define XYPRTY 74 /* Thread Priority Level */ #define XYP_IDLE 1 #define XYP_REG 2 #define XYP_SRV 4 #define XYP_RTP 3 #endif /* OS2 */ #define XYALRM 75 /* SET ALARM */ #define XYPROTO 76 /* SET PROTOCOL */ #define XYPREFIX 77 /* SET PREFIXING */ #define XYLOGIN 78 /* Login info for script programs... */ #define LOGI_UID 0 /* User ID */ #define LOGI_PSW 1 /* Password */ #define LOGI_PRM 2 /* Prompt */ #define XYSTARTUP 79 /* Startup file */ #define XYTMPDIR 80 /* Temporary directory */ #ifdef OS2 #define XYTAPI 81 /* Microsoft Telephone API options */ #define XYTAPI_CFG 1 /* TAPI Configure-Line Dialog */ #define XYTAPI_DIAL 2 /* TAPI Dialing-Properties Dialog */ #define XYTAPI_LIN 3 /* TAPI Line */ #define XYTAPI_LOC 4 /* TAPI Location */ #define XYTAPI_PASS 5 /* TAPI Passthrough */ #define XYTAPI_CON 6 /* TAPI Conversions */ #define XYTAPI_LGHT 7 /* TAPI Modem Lights */ #define XYTAPI_PRE 8 /* TAPI Pre-dialing Terminal */ #define XYTAPI_PST 9 /* TAPI Post-dialing Terminal */ #define XYTAPI_INA 10 /* TAPI Inactivity Timeout */ #define XYTAPI_BNG 11 /* TAPI Wait for Credit Card Tone */ #define XYTAPI_MAN 12 /* TAPI Manual Dialing */ #define XYTAPI_USE 13 /* TAPI Use Line Config settings */ #endif /* OS2 */ #ifdef TCPSOCKET #define XYTCP 82 /* TCP options */ #define XYTCP_NODELAY 1 /* No Delay */ #define XYTCP_SENDBUF 2 /* Send Buffer Size */ #define XYTCP_LINGER 3 /* Linger */ #define XYTCP_RECVBUF 4 /* Receive Buffer Size */ #define XYTCP_KEEPALIVE 5 /* Keep Alive packets */ #define XYTCP_UCX 6 /* UCX 2.0 port swabbing bug */ #define XYTCP_NAGLE 7 /* Delay - inverse of 1 */ #define XYTCP_RDNS 8 /* Reverse DNS lookup */ #define XYTCP_ADDRESS 9 /* Set preferred IP Address */ #define XYTCP_DNS_SRV 10 /* Use DNS Service Records */ #define XYTCP_DONTROUTE 11 /* Dont Route */ #define XYTCP_SOCKS_SVR 12 /* Name of Socks Server */ #define XYTCP_HTTP_PROXY 13 /* Name/Port of HTTP Proxy Server */ #define XYTCP_SOCKS_NS 14 /* Name of Socks Name Server */ #endif /* TCPSOCKET */ #ifdef OS2 #define XYMSK 83 /* MS-DOS Kermit compatibility options */ #define MSK_COLOR 0 /* Terminal color handling */ #define MSK_KEYS 1 /* SET KEY uses MSK keycodes */ #define MSK_REN 2 /* File renaming uses 8.3 notation always */ #endif /* OS2 */ #define XYDEST 84 /* SET DESTINATION as in MS-DOS Kermit */ #ifdef OS2 #define XYWIN95 85 /* SET WIN95 work arounds */ #define XYWKEY 0 /* Keyboard translation */ #define XYWAGR 1 /* Alt-Gr */ #define XYWOIO 2 /* Overlapped I/O */ #define XYWLUC 3 /* Lucida Console substitutions */ #define XYWSELECT 4 /* Select on Write Bug */ #define XYW8_3 5 /* Use 8.3 filenames? */ #define XYWPOPUP 6 /* Use Popups? */ #define XYWHSL 7 /* Horz Scan Line substitutions */ #define XYDLR 86 /* SET K95 DIALER work arounds */ #define XYTITLE 87 /* SET TITLE of window */ #endif /* OS2 */ #define XYIGN 88 /* SET IGNORE-CHARACTER */ #define XYEDIT 89 /* SET EDITOR */ #define XYFLTR 90 /* SET { SEND, RECEIVE } FILTER */ #define XYBROWSE 91 /* SET BROWSER */ #define XYEOF 92 /* EOF (= FILE EOF) */ #ifdef OS2 #define XYBDCP 93 /* BPRINTER */ #endif /* OS2 */ #define XYFLAG 94 /* FLAG */ #define XYLIMIT 95 /* SESSION-LIMIT */ #define XYINIL 96 /* Protocol negotiation string max length */ #define XYRELY 97 /* RELIABLE */ #define XYSTREAM 98 /* STREAMING */ #define XYTLOG 99 /* TRANSACTION-LOG */ #define XYCLEAR 100 /* CLEARCHANNEL */ #define XYAUTH 101 /* AUTHENTICATION */ #ifdef TNCODE #define XYKRBPR 0 /* Kerberos Principal */ #define XYKRBRL 1 /* Kerberos Realm */ #define XYKRBCC 2 /* Kerberos 5 Credentials-Cache */ #define XYKRBSRV 3 /* Kerberos Service Name */ #define XYKRBDBG 4 /* Kerberos Debugging */ #define XYKRBLIF 5 /* Kerberos Lifetime */ #define XYKRBPRE 6 /* Kerberos 4 Preauth */ #define XYKRBINS 7 /* Kerberos 4 Instance */ #define XYKRBFWD 8 /* Kerberos 5 Forwardable */ #define XYKRBPRX 9 /* Kerberos 5 Proxiable */ #define XYKRBRNW 10 /* Kerberos 5 Renewable lifetime */ #define XYKRBGET 11 /* Kerberos Auto-Get-TGTs */ #define XYKRBDEL 12 /* Kerberos Auto-Destroy-TGTs */ #define KRB_DEL_NO 0 /* Kerberos No Auto Destroy */ #define KRB_DEL_CL 1 /* Kerberos Auto Destory on Close */ #define KRB_DEL_EX 2 /* Kerberos Auto Destroy on Exit */ #define XYKRBK5K4 13 /* Kerberos 5 Get K4 Tickets */ #define XYKRBPRM 14 /* Kerberos 4/5 Prompt */ #define XYKRBADR 15 /* Kerberos 4/5 CheckAddrs */ #define XYKRBNAD 16 /* Kerberos 5 No Addresses */ #define XYKRBADD 17 /* Kerberos 5 Address List */ #define XYKRBKTB 18 /* Kerberos 4/5 Key Table */ #define XYSRPPRM 0 /* SRP Prompt */ #define XYSSLRCFL 0 /* SSL/TLS RSA Certs file */ #define XYSSLCOK 1 /* SSL/TLS Certs-Ok flag */ #define XYSSLCRQ 2 /* SSL/TLS Certs-Required flag */ #define XYSSLCL 3 /* SSL/TLS Cipher List */ #define XYSSLDBG 4 /* SSL/TLS Debug flag */ #define XYSSLRKFL 5 /* SSL/TLS RSA Key File */ #define XYSSLLFL 6 /* SSL/TLS Log File */ #define XYSSLON 7 /* SSL/TLS Only flag */ #define XYSSLSEC 8 /* SSL/TLS Secure flag */ #define XYSSLVRB 9 /* SSL/TLS Verbose flag */ #define XYSSLVRF 10 /* SSL/TLS Verify flag */ #define XYSSLDUM 11 /* SSL/TLS Dummy flag */ #define XYSSLDCFL 12 /* SSL/TLS DSA Certs file */ #define XYSSLDKFL 13 /* SSL/TLS DH Certs file */ #define XYSSLDPFL 14 /* SSL/TLS DH Param file */ #define XYSSLCRL 15 /* SSL/TLS CRL file */ #define XYSSLCRLD 16 /* SSL/TLS CRL dir */ #define XYSSLVRFF 17 /* SSL/TLS Verify file */ #define XYSSLVRFD 18 /* SSL/TLS Verify dir */ #define XYSSLRND 19 /* SSL/TLS Random file */ #define XYSSLDCCF 20 /* SSL/TLS DSA Certs Chain File */ #define XYSSLRCCF 21 /* SSL/TLS RSA Certs Chain File */ /* The following must be powers of 2 for a bit mask */ #define XYKLCEN 1 /* Kerberos List Credentials: Encryption */ #define XYKLCFL 2 /* Kerberos List Credentials: Flags */ #define XYKLCAD 4 /* Kerberos List Credentials: Addresses */ #endif /* TNCODE */ #define XYFUNC 102 /* SET FUNCTION */ #define FUNC_DI 0 /* FUNCTION DIAGNOSTICS */ #define FUNC_ER 1 /* FUNCTION ERROR */ #define XYFTP 103 /* FTP application */ #define XYSLEEP 104 /* SLEEP / PAUSE options */ #define XYSSH 105 /* SSH options */ #define XYTELOP 106 /* TELNET OPTIONS (TELOPT) */ #define XYCD 107 /* SET CD */ #define XYCSET 108 /* CHARACTER-SET */ #define XYSTOP 109 /* STOP-BITS */ #define XYSERIAL 110 /* SERIAL */ #define XYDISC 111 /* CLOSE-ON-DISCONNECT */ #define XYOPTS 112 /* OPTIONS */ #define XYQ8FLG 113 /* Q8FLAG (invisible) */ #define XYTIMER 114 /* TIMER */ #define XYFACKB 115 /* F-ACK-BUG */ #define XYBUP 116 /* SET SEND/RECEIVE BACKUP */ #define XYMOVE 117 /* SET SEND/RECEIVE MOVE-TO */ #define XYRENAME 118 /* SET SEND/RECEIVE RENAME-TO */ #define XYHINTS 119 /* SET HINTS */ #define XYEVAL 120 /* SET EVALUATE */ #define XYFACKP 121 /* F-ACK-PATH */ #define XYSYSL 122 /* SysLog */ #define XYQNXPL 123 /* QNX Port Lock */ #define XYIKS 124 /* SET IKS ... */ #define XYROOT 125 /* SET ROOT */ #define XYFTPX 126 /* SET FTP */ #define XYSEXP 127 /* SET SEXP */ #define XYGPR 128 /* SET GET-PUT-REMOTE */ #define XYLOCUS 129 /* SET LOCUS */ #define XYGUI 130 /* SET GUI */ #define XYANSWER 131 /* SET ANSWER */ #define XYMATCH 132 /* SET MATCHDOT */ #define XYSFTP 133 /* SET SFTP */ #define XY_REN 134 /* SET RENAME */ #define XYEXTRN 135 /* SET EXTERNAL-PROTOCOL */ #define XYVAREV 136 /* SET VARIABLE-EVALUATION */ #define XYLOCALE 137 /* SET LOCALE */ #ifdef VMS #define XYVMSTF 138 /* SET VMS_TEXT */ #define VMSTFS 1 /* STREAM_LF */ #define VMSTFV 2 /* VARIABLE */ #endif /* VMS */ /* End of SET commands */ /* S-Expressions -- floating-point support required */ #ifndef CKFLOAT #ifndef NOSEXP #define NOSEXP #endif /* NOSEXP */ #endif /* CKFLOAT */ /* Maximum number of elements in an S-Expression */ #ifndef NOSEXP #ifndef SEXPMAX #ifdef BIGBUFOK #define SEXPMAX 1024 #else #define SEXPMAX 32 #endif /* BIGBUFOK */ #endif /* SEXPMAX */ #endif /* NOSEXP */ #ifdef ANYX25 /* PAD command parameters */ #define XYPADL 0 /* clear virtual call */ #define XYPADS 1 /* status of virtual call */ #define XYPADR 2 /* reset of virtual call */ #define XYPADI 3 /* send an interrupt packet */ /* Used with XYX25... */ #define XYUDAT 0 /* X.25 call user data */ #define XYCLOS 1 /* X.25 closed user group call */ #define XYREVC 2 /* X.25 reverse charge call */ #endif /* ANYX25 */ #ifdef OS2 /* SET PRINTER switches */ #define PRN_OUT 0 /* Output only */ #define PRN_BID 1 /* Bidirectional */ #define PRN_DOS 2 /* DOS device */ #define PRN_WIN 3 /* Windows queue */ #define PRN_TMO 4 /* Timeout */ #define PRN_TRM 5 /* Terminator */ #define PRN_SEP 6 /* Separator */ #define PRN_SPD 7 /* COM-port speed */ #define PRN_FLO 8 /* COM-port flow control */ #define PRN_PAR 9 /* COM-port parity */ #define PRN_NON 10 /* No printer */ #define PRN_FIL 11 /* Filename */ #define PRN_PIP 12 /* Pipename */ #define PRN_PS 13 /* Text to PS */ #define PRN_WID 14 /* PS Width */ #define PRN_LEN 15 /* PS Length */ #define PRN_RAW 16 /* Non-PS */ #define PRN_CS 17 /* Character Set */ #define PRN_MAX 17 /* Number of switches defined */ /* Printer types */ #define PRT_DOS 0 /* DOS */ #define PRT_WIN 1 /* Windows Queue */ #define PRT_FIL 2 /* File */ #define PRT_PIP 3 /* Pipe */ #define PRT_NON 4 /* None */ #define PRINTSWI #endif /* OS2 */ #endif /* NOICP */ #ifndef NODIAL /* Symbols for modem types, moved here from ckudia.c, May 1997, because now they are also used in some other modules. The numbers MUST correspond to the ordering of entries within the modemp[] array. */ #ifdef MINIDIAL /* Minimum dialer support */ #define n_DIRECT 0 /* Direct connection -- no modem */ #define n_CCITT 1 /* CCITT/ITU-T V.25bis */ #define n_HAYES 2 /* Hayes 2400 */ #define n_UNKNOWN 3 /* Unknown */ #define n_UDEF 4 /* User-Defined */ #define n_GENERIC 5 /* Generic High Speed */ #define n_ITUTV250 6 /* ITU-T V.250 */ #define MAX_MDM 6 /* Number of modem types */ #else /* Full-blown dialer support */ #define n_DIRECT 0 /* Direct connection -- no modem */ #define n_ATTDTDM 1 #define n_ATTISN 2 #define n_ATTMODEM 3 #define n_CCITT 4 #define n_CERMETEK 5 #define n_DF03 6 #define n_DF100 7 #define n_DF200 8 #define n_GDC 9 #define n_HAYES 10 #define n_PENRIL 11 #define n_RACAL 12 #define n_UNKNOWN 13 #define n_VENTEL 14 #define n_CONCORD 15 #define n_ATTUPC 16 /* aka UNIX PC and ATT7300 */ #define n_ROLM 17 /* Rolm CBX DCM */ #define n_MICROCOM 18 /* Microcoms in SX command mode */ #define n_USR 19 /* Modern USRs */ #define n_TELEBIT 20 /* Telebits of all kinds */ #define n_DIGITEL 21 /* Digitel DT-22 (CCITT variant) */ #define n_H_1200 22 /* Hayes 1200 */ #define n_H_ULTRA 23 /* Hayes Ultra and maybe Optima */ #define n_H_ACCURA 24 /* Hayes Accura and maybe Optima */ #define n_PPI 25 /* Practical Peripherals */ #define n_DATAPORT 26 /* AT&T Dataport */ #define n_BOCA 27 /* Boca */ #define n_MOTOROLA 28 /* Motorola Fastalk or Lifestyle */ #define n_DIGICOMM 29 /* Digicomm Connection */ #define n_DYNALINK 30 /* Dynalink 1414VE */ #define n_INTEL 31 /* Intel 14400 Faxmodem */ #define n_UCOM_AT 32 /* Microcoms in AT mode */ #define n_MULTI 33 /* Multitech MT1432 */ #define n_SUPRA 34 /* SupraFAXmodem */ #define n_ZOLTRIX 35 /* Zoltrix */ #define n_ZOOM 36 /* Zoom */ #define n_ZYXEL 37 /* ZyXEL */ #define n_TAPI 38 /* TAPI Line modem - whatever it is */ #define n_TBNEW 39 /* Newer Telebit models */ #define n_MAXTECH 40 /* MaxTech XM288EA */ #define n_UDEF 41 /* User-Defined */ #define n_RWV32 42 /* Generic Rockwell V.32 */ #define n_RWV32B 43 /* Generic Rockwell V.32bis */ #define n_RWV34 44 /* Generic Rockwell V.34 */ #define n_MWAVE 45 /* IBM Mwave Adapter */ #define n_TELEPATH 46 /* Gateway Telepath */ #define n_MICROLINK 47 /* MicroLink modems */ #define n_CARDINAL 48 /* Cardinal modems */ #define n_GENERIC 49 /* Generic high-speed */ #define n_XJACK 50 /* Megahertz X-Jack */ #define n_SPIRITII 51 /* Quickcomm Spirit II */ #define n_MONTANA 52 /* Motorola Montana */ #define n_COMPAQ 53 /* Compaq Data+Fax Modem */ #define n_FUJITSU 54 /* Fujitsu Fax/Modem Adpater */ #define n_MHZATT 55 /* Megahertz AT&T V.34 */ #define n_SUPRASON 56 /* SupraSonic */ #define n_BESTDATA 57 /* Best Data */ #define n_ATT1900 58 /* AT&T STU III Model 1900 */ #define n_ATT1910 59 /* AT&T STU III Model 1910 */ #define n_KEEPINTOUCH 60 /* AT&T KeepinTouch */ #define n_USRX2 61 /* USR XJ-1560 X2 56K */ #define n_ROLMAT 62 /* Rolm with AT command set */ #define n_ATLAS 63 /* Atlas / Newcom ixfC 33.6 */ #define n_CODEX 64 /* Motorola Codex 326X Series */ #define n_MT5634ZPX 65 /* Multitech MT5634ZPX */ #define n_ULINKV250 66 /* Microlink ITU-T V.250 56K */ #define n_ITUTV250 67 /* Generic ITU-T V.250 */ #define n_RWV90 68 /* Generic Rockwell V.90 */ #define n_SUPRAX 69 /* Diamond Supra Express V.90 */ #define n_LUCENT 70 /* Lucent Venus chipset */ #define n_PCTEL 71 /* PCTel chipset */ #define n_CONEXANT 72 /* Conexant modem family */ #define n_ZOOMV34 73 /* Zoom */ #define n_ZOOMV90 74 /* Zoom */ #define n_ZOOMV92 75 /* ZOOM V.92 */ #define n_MOTSM56 76 /* Motorola SM56 chipset */ #define MAX_MDM 76 /* Number of modem types */ #endif /* MINIDIAL */ #endif /* NODIAL */ #ifndef NOICP /* SHOW command symbols */ #define SHPAR 0 /* Parameters */ #define SHVER 1 /* Versions */ #define SHCOM 2 /* Communications */ #define SHPRO 3 /* Protocol */ #define SHFIL 4 /* File */ #define SHLNG 5 /* Language */ #define SHCOU 6 /* Count */ #define SHMAC 7 /* Macros */ #define SHKEY 8 /* Key */ #define SHSCR 9 /* Scripts */ #define SHSPD 10 /* Speed */ #define SHSTA 11 /* Status */ #define SHSER 12 /* Server */ #define SHXMI 13 /* Transmit */ #define SHATT 14 /* Attributes */ #define SHMOD 15 /* Modem */ #define SHDFLT 16 /* Default (as in VMS) */ #define SHVAR 17 /* Show global variables */ #define SHARG 18 /* Show macro arguments */ #define SHARR 19 /* Show arrays */ #define SHBUI 20 /* Show builtin variables */ #define SHFUN 21 /* Show functions */ #define SHPAD 22 /* Show (X.25) PAD */ #define SHTER 23 /* Show terminal settings */ #define SHESC 24 /* Show escape character */ #define SHDIA 25 /* Show DIAL parameters */ #define SHNET 26 /* Show network parameters */ #define SHLBL 27 /* Show VMS labeled file parameters */ #define SHSTK 28 /* Show stack, MAC debugging */ #define SHCSE 29 /* Show character sets */ #define SHFEA 30 /* Show features */ #define SHCTL 31 /* Show control-prefix table */ #define SHEXI 32 /* Show EXIT items */ #define SHPRT 33 /* Show printer */ #define SHCMD 34 /* Show command parameters */ #define SHKVB 35 /* Show \Kverbs */ #define SHMOU 36 /* Show Mouse (like Show Key) */ #define SHTAB 37 /* Show Tabs (OS/2) */ #define SHVSCRN 38 /* Show Virtual Screen (OS/2) */ #define SHALRM 39 /* ALARM */ #define SHSFL 40 /* SEND-LIST */ #define SHUDK 41 /* DEC VT UDKs (OS/2) */ #define SHDBL 42 /* DOUBLE/IGNORE characters */ #define SHEDIT 43 /* EDITOR */ #define SHBROWSE 44 /* BROWSER */ #define SHTAPI 45 /* TAPI */ #define SHTAPI_L 46 /* TAPI Location */ #define SHTAPI_M 47 /* TAPI Modem Properties */ #define SHTAPI_C 48 /* TAPI Comm Properties */ #define SHTEL 49 /* SHOW TELNET */ #define SHINP 50 /* SHOW INPUT */ #define SHTRIG 51 /* SHOW TRIGGER */ #define SHLOG 52 /* SHOW LOGS */ #define SHOUTP 53 /* SHOW OUTPUT */ #define SHOPAT 54 /* SHOW PATTERNS */ #define SHOSTR 55 /* SHOW STREAMING */ #define SHOAUTH 56 /* SHOW AUTHENTICATION */ #define SHOFTP 57 /* SHOW FTP */ #define SHTOPT 58 /* SHOW TELOPT */ #define SHXOPT 59 /* SHOW EXTENDED-OPTIONS */ #define SHCD 60 /* SHOW CD */ #define SHASSOC 61 /* SHOW ASSOCIATIONS */ #define SHCONNX 62 /* SHOW CONNECTION */ #define SHOPTS 63 /* SHOW OPTIONS */ #define SHOFLO 64 /* SHOW FLOW-CONTROL */ #define SHOXFER 65 /* SHOW TRANSFER */ #define SHTCP 66 /* SHOW TCP */ #define SHHISTORY 67 /* SHOW (command) HISTORY */ #define SHSEXP 68 /* SHOW SEXPRESSIONS */ #define SHOSSH 69 /* SHOW SSH */ #define SHOIKS 70 /* SHOW IKS */ #define SHOGUI 71 /* SHOW GUI (K95) */ #define SHOREN 72 /* SHOW RENAME */ #define SHOLOC 73 /* SHOW LOCALE */ #define SHOTMPDIR 74 /* SHOW TEMP-DIRECTORY */ #define SHOVMSTXT 75 /* SHOW VMS_TEXT */ /* REMOTE command symbols */ #define XZCPY 0 /* Copy */ #define XZCWD 1 /* Change Working Directory */ #define XZDEL 2 /* Delete */ #define XZDIR 3 /* Directory */ #define XZHLP 4 /* Help */ #define XZHOS 5 /* Host */ #define XZKER 6 /* Kermit */ #define XZLGI 7 /* Login */ #define XZLGO 8 /* Logout */ #define XZMAI 9 /* Mail <-- wrong, this should be top-level */ #define XZMOU 10 /* Mount */ #define XZMSG 11 /* Message */ #define XZPRI 12 /* Print */ #define XZREN 13 /* Rename */ #define XZSET 14 /* Set */ #define XZSPA 15 /* Space */ #define XZSUB 16 /* Submit */ #define XZTYP 17 /* Type */ #define XZWHO 18 /* Who */ #define XZPWD 19 /* Print Working Directory */ #define XZQUE 20 /* Query */ #define XZASG 21 /* Assign */ #define XZMKD 22 /* mkdir */ #define XZRMD 23 /* rmdir */ #define XZXIT 24 /* Exit */ #define XZCDU 25 /* CDUP */ #define XZSTA 26 /* Status (fdc 2023-02-16) */ /* SET INPUT command parameters */ #define IN_DEF 0 /* Default timeout */ #define IN_TIM 1 /* Timeout action */ #define IN_CAS 2 /* Case (matching) */ #define IN_ECH 3 /* Echo */ #define IN_SIL 4 /* Silence */ #define IN_BUF 5 /* Buffer size */ #define IN_PAC 6 /* Input Pacing (debug) */ #define IN_TRM 7 /* Input Terminal Display */ #define IN_ADL 8 /* Input autodownload */ #define IN_PAT 9 /* Pattern to match */ #define IN_ASG 10 /* Assign matching text to variable */ #define IN_CAN 11 /* Keyboard cancellation of INPUT */ #define IN_SCA 12 /* Timeout scaling */ /* ENABLE/DISABLE command parameters */ #define EN_ALL 0 /* ALL */ #define EN_CWD 1 /* CD/CWD */ #define EN_DIR 2 /* DIRECTORY */ #define EN_FIN 3 /* FINISH */ #define EN_GET 4 /* GET */ #define EN_HOS 5 /* HOST command */ #define EN_KER 6 /* KERMIT command */ #define EN_LOG 7 /* LOGIN */ #define EN_SEN 8 /* SEND */ #define EN_SET 9 /* SET */ #define EN_SPA 10 /* SPACE */ #define EN_TYP 11 /* TYPE */ #define EN_WHO 12 /* WHO, finger */ #define EN_DEL 13 /* Delete */ #define EN_BYE 14 /* BYE (as opposed to FINISH) */ #define EN_QUE 15 /* QUERY */ #define EN_ASG 16 /* ASSIGN */ #define EN_CPY 17 /* COPY */ #define EN_REN 18 /* RENAME */ #define EN_RET 19 /* RETRIEVE */ #define EN_MAI 20 /* MAIL */ #define EN_PRI 21 /* PRINT */ #define EN_MKD 22 /* MKDIR */ #define EN_RMD 23 /* RMDIR */ #define EN_XIT 24 /* EXIT */ #define EN_ENA 25 /* ENABLE */ #endif /* NOICP */ #ifndef NOICP /* CLEAR command symbols */ #define CLR_DEV 1 /* Clear Device Buffers */ #define CLR_INP 2 /* Clear Input Buffers */ #define CLR_BTH CLR_DEV|CLR_INP /* Clear Device and Input */ #define CLR_SCL 4 /* Clear Scrollback buffer */ #define CLR_CMD 8 /* Clear Command Screen */ #define CLR_TRM 16 /* Clear Terminal Screen */ #define CLR_DIA 32 /* Clear Dial Status */ #define CLR_SFL 64 /* Clear Send-File-List */ #define CLR_APC 128 /* Clear APC */ #define CLR_ALR 256 /* Clear Alarm */ #define CLR_TXT 512 /* Clear text-patterns */ #define CLR_BIN 1024 /* Clear binary-patterns */ #define CLR_SCR 2048 /* Clear screen */ #define CLR_KBD 4096 /* Clear keyboard buffer */ #endif /* NOICP */ /* Symbols for logs */ #define LOGD 0 /* Debugging */ #define LOGP 1 /* Packets */ #define LOGS 2 /* Session */ #define LOGT 3 /* Transaction */ #define LOGX 4 /* Screen */ #define LOGR 5 /* The "open read" file */ #define LOGW 6 /* The "open write/append" file */ #define LOGE 7 /* Error (e.g. stderr) */ #define LOGM 8 /* The dialing log */ #ifndef NOSPL /* Symbols for builtin variables */ #define VN_ARGC 0 /* ARGC */ #define VN_COUN 1 /* COUNT */ #define VN_DATE 2 /* DATE */ #define VN_DIRE 3 /* DIRECTORY */ #define VN_ERRO 4 /* ERRORLEVEL */ #define VN_TIME 5 /* TIME */ #define VN_VERS 6 /* VERSION */ #define VN_IBUF 7 /* INPUT buffer */ #define VN_SUCC 8 /* SUCCESS flag */ #define VN_LINE 9 /* LINE */ #define VN_ARGS 10 /* Program command-line arg count */ #define VN_SYST 11 /* System type */ #define VN_SYSV 12 /* System version */ #define VN_RET 13 /* RETURN value */ #define VN_FILE 14 /* Most recent filespec */ #define VN_NDAT 15 /* Numeric date yyyy/mm/dd */ #define VN_HOME 16 /* Home directory */ #define VN_SPEE 17 /* Transmission speed */ #define VN_HOST 18 /* Host name */ #define VN_TTYF 19 /* TTY file descriptor (UNIX only) */ #define VN_PROG 20 /* Program name */ #define VN_NTIM 21 /* NTIME */ #define VN_FFC 22 /* Characters in last file xferred */ #define VN_TFC 23 /* Chars in last file group xferred */ #define VN_CPU 24 /* CPU type */ #define VN_CMDL 25 /* Command level */ #define VN_DAY 26 /* Day of week, string */ #define VN_NDAY 27 /* Day of week, numeric */ #define VN_LCL 28 /* Local (vs) remote mode */ #define VN_CMDS 29 /* Command source */ #define VN_CMDF 30 /* Command file name */ #define VN_MAC 31 /* Macro name */ #define VN_EXIT 32 /* Exit status */ #define VN_ICHR 33 /* INPUT character */ #define VN_ICNT 34 /* INPUT count */ #define VN_PRTY 35 /* Current parity */ #define VN_DIAL 36 /* DIAL status */ #define VN_KEYB 37 /* Keyboard type */ #define VN_CPS 38 /* Chars per second, last transfer */ #define VN_RPL 39 /* Receive packet length */ #define VN_SPL 40 /* Send packet length */ #define VN_MODE 41 /* Transfer mode (text, binary) */ #define VN_REXX 42 /* Rexx return value */ #define VN_NEWL 43 /* Newline character or sequence */ #define VN_COLS 44 /* Columns on console screen */ #define VN_ROWS 45 /* Rows on console screen */ #define VN_TTYP 46 /* Terminal type */ #define VN_MINP 47 /* MINPUT result */ #define VN_CONN 48 /* Connection type */ #define VN_SYSI 49 /* System ID */ #define VN_TZ 50 /* Timezone */ #define VN_SPA 51 /* Space */ #define VN_QUE 52 /* Query */ #define VN_STAR 53 /* Startup directory */ #define VN_CSET 54 /* Local character set */ #define VN_MDM 55 /* Modem type */ #define VN_EVAL 56 /* Most recent EVALUATE result */ #define VN_D_CC 57 /* DIAL COUNTRY-CODE */ #define VN_D_AC 58 /* DIAL AREA-CODE */ #define VN_D_IP 59 /* DIAL INTERNATIONAL-PREFIX */ #define VN_D_LP 60 /* DIAL LD-PREFIX */ #define VN_UID 61 #define VN_PWD 62 #define VN_PRM 63 #define VN_PROTO 64 /* Protocol */ #define VN_DLDIR 65 /* Download directory */ #define VN_M_AAA 66 /* First MODEM one */ #define VN_M_INI 66 /* Modem init string */ #define VN_M_DCM 67 /* Modem dial command */ #define VN_M_DCO 68 /* Modem data compression on */ #define VN_M_DCX 69 /* Modem data compression off */ #define VN_M_ECO 70 /* Modem error correction on */ #define VN_M_ECX 71 /* Modem error correction off */ #define VN_M_AAO 72 /* Modem autoanswer on */ #define VN_M_AAX 73 /* Modem autoanswer off */ #define VN_M_HUP 74 /* Modem hangup command */ #define VN_M_HWF 75 /* Modem hardware flow command */ #define VN_M_SWF 76 /* Modem software flow command */ #define VN_M_NFC 77 /* Modem no flow-control command */ #define VN_M_PDM 78 /* Modem pulse dialing mode */ #define VN_M_TDM 79 /* Modem tone dialing mode */ #define VN_M_ZZZ 79 /* Last MODEM one */ #define VN_SELCT 80 /* Selected Text from Mark Mode */ #define VN_TEMP 81 /* Temporary directory */ #define VN_ISTAT 82 /* INPUT command status */ #define VN_INI 83 /* INI (kermrc) directory */ #define VN_EXEDIR 84 /* EXE directory */ #define VN_ERRNO 85 /* Value of errno */ #define VN_ERSTR 86 /* Corresponding error message */ #define VN_TFLN 87 /* TAKE file line number */ #define VN_XVNUM 88 /* Product-specific version number */ #define VN_RPSIZ 89 /* Receive packet length */ #define VN_WINDO 90 /* Window size */ #define VN_MDMSG 91 /* Modem message */ #define VN_DNUM 92 /* Dial number */ #define VN_APC 93 /* APC active */ #define VN_IPADDR 94 /* My IP address */ #define VN_CRC16 95 /* CRC-16 of most recent file group */ #define VN_TRMK 96 /* Macro executed from Terminal Mode */ #define VN_PID 97 /* Process ID */ #define VN_FNAM 98 /* Name of file being transferred */ #define VN_FNUM 99 /* Number of file being transferred */ #define VN_PEXIT 100 /* Process exit status */ #define VN_P_CTL 101 /* Control Prefix */ #define VN_P_8BIT 102 /* 8-bit prefix */ #define VN_P_RPT 103 /* Repeat count prefix */ #define VN_D_LCP 104 /* DIAL LOCAL-PREFIX */ #define VN_URL 105 /* Last URL selected */ #ifdef COMMENT /* Not used in Open Source version but should not be recycled */ #define VN_REGN 106 /* Registration Name */ #define VN_REGO 107 /* Registration Organization */ #define VN_REGS 108 /* Registration Serial number */ #endif /* COMMENT */ #define VN_XPROG 109 /* xprogram (like xversion) */ #define VN_EDITOR 110 /* Editor */ #define VN_EDOPT 111 /* Editor options */ #define VN_EDFILE 112 /* Editor file */ #define VN_BROWSR 113 /* Browser */ #define VN_BROPT 114 /* Browser options */ #define VN_HERALD 115 /* Program herald */ #define VN_TEST 116 /* Program test level or "0" */ #define VN_XFSTAT 117 /* File-Transfer status */ #define VN_XFMSG 119 /* File-Transfer message */ #define VN_SNDL 120 /* Send-list status */ #define VN_TRIG 121 /* Trigger value */ #define VN_MOU_X 122 /* OS/2 Mouse Cursor X */ #define VN_MOU_Y 123 /* OS/2 Mouse Cursor Y */ #define VN_PRINT 124 /* Printer */ #define VN_ESC 125 /* Escape character */ #define VN_INTIME 126 /* INPUT elapsed time */ #define VN_K4RLM 127 /* Kerberos 4 Realm */ #define VN_K5RLM 128 /* Kerberos 5 Realm */ #define VN_K4PRN 129 /* Kerberos 4 Principal */ #define VN_K5PRN 130 /* Kerberos 5 Principal */ #define VN_K4CC 131 /* Kerberos 4 Credentials Cache */ #define VN_K5CC 132 /* Kerberos 5 Credentials Cache */ #define VN_OSNAM 133 /* OS name */ #define VN_OSVER 134 /* OS version */ #define VN_OSREL 135 /* OS release */ #define VN_NAME 136 /* Name I was called by */ #define VN_MODL 137 /* CPU model */ #define VN_X25LA 138 /* X.25 local address */ #define VN_X25RA 139 /* X.25 remote address */ #define VN_K4SRV 140 /* Kerberos 4 Service Name */ #define VN_K5SRV 141 /* Kerberos 5 Service Name */ #define VN_PDSFX 142 /* PDIAL suffix */ #define VN_DTYPE 143 /* DIAL type */ #define VN_LCKPID 144 /* Lockfile PID (UNIX) */ #define VN_BLK 145 /* Block check */ #define VN_TFTIM 146 /* File transfer elapsed time */ #define VN_D_PXX 147 /* DIAL PBX-EXCHANGE */ #define VN_HWPAR 148 /* Hardware Parity */ #define VN_SERIAL 149 /* SET SERIAL value */ #define VN_LCKDIR 150 /* Lockfile directory (UNIX) */ #define VN_K4ENO 151 /* Kerberos 4 Last Errno */ #define VN_K4EMSG 152 /* Kerberos 4 Last Err Msg */ #define VN_K5ENO 153 /* Kerberos 5 Last Errno */ #define VN_K5EMSG 154 /* Kerberos 5 Last Err Msg */ #define VN_INTMO 155 /* Input timeout */ #define VN_AUTHS 156 /* Authentication State */ #define VN_DM_LP 157 /* Dial Modifier: Long Pause */ #define VN_DM_SP 158 /* Dial Modifier: Short Pause */ #define VN_DM_PD 159 /* Dial Modifier: Pulse Dial */ #define VN_DM_TD 160 /* Dial Modifier: Tone Dial */ #define VN_DM_WA 161 /* Dial Modifier: Wait for Answer */ #define VN_DM_WD 162 /* Dial Modifier: Wait for Dialtone */ #define VN_DM_RC 163 /* Dial Modifier: Return to Command */ /* (more below...) */ #define VN_TY_LN 164 /* TYPE command line number */ #define VN_TY_LC 165 /* TYPE command line count */ #define VN_TY_LM 166 /* TYPE command match count */ #define VN_MACLVL 167 /* \v(maclevel) */ #define VN_XF_BC 168 /* Transfer blockcheck errors */ #define VN_XF_TM 169 /* Transfer timeouts */ #define VN_XF_RX 170 /* Transfer retransmissions */ #define VN_M_NAM 171 /* Modem full name */ #define VN_MS_CD 172 /* Modem signal CD */ #define VN_MS_CTS 173 /* Modem signal CTS */ #define VN_MS_DSR 174 /* Modem signal DSR */ #define VN_MS_DTR 175 /* Modem signal DTR */ #define VN_MS_RI 176 /* Modem signal RI */ #define VN_MS_RTS 177 /* Modem signal RTS */ #define VN_MATCH 178 /* Most recent pattern match */ #define VN_SLMSG 179 /* SET LINE (error) message */ #define VN_TXTDIR 180 /* Kermit text-file directory */ #define VN_MA_PI 181 /* Math constant Pi */ #define VN_MA_E 182 /* Math constant e */ #define VN_MA_PR 183 /* Math precision (digits) */ #define VN_CMDBL 184 /* Command buffer length */ #define VN_AUTHT 185 /* Authentication Type */ #ifdef CKCHANNELIO #define VN_FERR 186 /* FILE error */ #define VN_FMAX 187 /* FILE max */ #define VN_FCOU 188 /* Result of last FILE COUNT */ #endif /* CKCHANNELIO */ #define VN_DRTR 189 /* DIAL retry counter */ #define VN_CXTIME 190 /* Elapsed time in session */ #define VN_BYTE 191 /* Byte order */ #define VN_AUTHN 192 /* Authentication Name */ #define VN_KBCHAR 193 /* kbchar */ #define VN_TTYNAM 194 /* Name of controlling terminal */ #define VN_X509_S 195 /* X.509 Certificate Subject */ #define VN_X509_I 196 /* X.509 Certificate Issuer */ #define VN_PROMPT 197 /* C-Kermit's prompt */ #define VN_BUILD 198 /* Build ID string */ #define VN_SEXP 199 /* Last S-Expression */ #define VN_VSEXP 200 /* Value of last S-Expression */ #define VN_LSEXP 201 /* SEXP depth */ #define VN_FTIME 202 /* Time as floating-poing number */ #define VN_FTP_C 203 /* FTP Reply Code */ #define VN_FTP_M 204 /* FTP Reply Message */ #define VN_FTP_S 205 /* FTP Server type */ #define VN_FTP_H 206 /* FTP Host */ #define VN_FTP_X 207 /* FTP Connected */ #define VN_FTP_L 208 /* FTP Logged in */ #define VN_FTP_G 209 /* FTP GET-PUT-REMOTE setting */ #define VN_SECURE 210 /* Encrypted connection 0 or 1 */ #define VN_DM_HF 211 /* Dial Modifier: Hook Flash */ #define VN_DM_WB 212 /* Dial Modifier: Wait for Bong */ #define VN_CX_STA 213 /* CX_STATUS */ #define VN_FTP_B 214 /* FTP CPL */ #define VN_FTP_D 215 /* FTP DPL */ #define VN_FTP_Z 216 /* FTP SECURITY */ #define VN_HTTP_C 217 /* HTTP Code */ #define VN_HTTP_N 218 /* HTTP Connected */ #define VN_HTTP_H 219 /* HTTP Host */ #define VN_HTTP_M 220 /* HTTP Message */ #define VN_HTTP_S 221 /* HTTP Security */ #define VN_NOW 222 /* Timestamp yyyymmdd hh:mm:ss */ #define VN_HOUR 223 /* Current hour of the day 0-23 */ #define VN_CI_DA 224 /* Caller ID date */ #define VN_CI_TI 225 /* Caller ID time */ #define VN_CI_NA 226 /* Caller ID name */ #define VN_CI_NU 227 /* Caller ID number */ #define VN_CI_ME 228 /* Caller ID message */ #define VN_PERSONAL 229 /* Personal Directory on Windows */ #define VN_APPDATA 230 /* User AppData directory */ #define VN_COMMON 231 /* Common AppData directory */ #define VN_DESKTOP 232 /* User Desktop directory */ #define VN_TNC_SIG 233 /* RFC 2717 Signature */ #ifdef KUI #define VN_GUI_XP 234 /* GUI Window X position */ #define VN_GUI_YP 235 /* GUI Window Y position */ #define VN_GUI_XR 236 /* GUI Window X resolution */ #define VN_GUI_YR 237 /* GUI Window Y resolution */ #define VN_GUI_RUN 238 /* GUI Window Run mode */ #define VN_GUI_FNM 239 /* GUI Window Font Name */ #define VN_GUI_FSZ 240 /* GUI Window Font Size */ #endif /* KUI */ #define VN_LOG_PKT 241 /* Packet Log Filename */ #define VN_LOG_TRA 242 /* Transaction Log Filename */ #define VN_LOG_SES 243 /* Session Log Filename */ #define VN_LOG_DEB 244 /* Debug Log Filename */ #define VN_LOG_CON 245 /* Connection Log Filename */ #define VN_ISCALE 246 /* INPUT scale factor */ #define VN_BITS 247 /* Bits of this build (16, 32, 64) */ #define VN_LASTFIL 248 /* Last input filespec */ #define VN_LASTKWV 249 /* Last \fkeywordvalue() keyword */ #define VN_DMSG 250 /* Msg corresponding to dialstatus */ #define VN_HOSTIP 251 /* IP address of remote host */ #define VN_INPMSG 252 /* Msg corresponding to instatus */ #define VN_VAREVAL 253 /* SET VARIABLE-EVALUATION setting */ #define VN_PREVCMD 254 /* Previous command */ #define VN_YEAR 255 /* This year */ #define VN_MONTH 256 /* This month (name) */ #define VN_NMONTH 257 /* This month (numeric) */ #define VN_FULLVER 258 /* Full version number */ #endif /* NOSPL */ /* INPUT status values */ #define INP_OK 0 /* Succeeded */ #define INP_TO 1 /* Timed out */ #define INP_UI 2 /* User interrupted */ #define INP_IE 3 /* Internal error */ #define INP_IO 4 /* I/O error or connection lost */ #define INP_IKS 5 /* Kermit Server Active */ #define INP_BF 6 /* Buffer full */ /* INPUT switch values */ #define INPSW_NOM 1 /* /NOMATCH */ #define INPSW_CLR 2 /* /CLEAR */ #define INPSW_NOW 4 /* /NOWRAP */ #define INPSW_COU 8 /* /COUNT */ #ifndef NOSPL /* Symbols for builtin functions */ #define FNARGS 6 /* Maximum number of function args */ #define FN_IND 0 /* Index (of string 1 in string 2) */ #define FN_LEN 1 /* Length (of string) */ #define FN_LIT 2 /* Literal (don't expand the string) */ #define FN_LOW 3 /* Lower (convert to lowercase) */ #define FN_MAX 4 /* Max (maximum) */ #define FN_MIN 5 /* Min (minimum) */ #define FN_MOD 6 /* Mod (modulus) */ #define FN_EVA 7 /* Eval (evaluate arith expression) */ #define FN_SUB 8 /* Substr (substring) */ #define FN_UPP 9 /* Upper (convert to uppercase) */ #define FN_REV 10 /* Reverse (a string) */ #define FN_REP 11 /* Repeat (a string) */ #define FN_EXE 12 /* Execute (a macro) */ #define FN_VAL 13 /* Return value (of a macro) */ #define FN_LPA 14 /* LPAD (left pad) */ #define FN_RPA 15 /* RPAD (right pad) */ #define FN_DEF 16 /* Definition of a macro, unexpanded */ #define FN_CON 17 /* Contents of a variable, ditto */ #define FN_FIL 18 /* File list */ #define FN_FC 19 /* File count */ #define FN_CHR 20 /* Character (like BASIC CHR$()) */ #define FN_RIG 21 /* Right (like BASIC RIGHT$()) */ #define FN_COD 22 /* Code value of character */ #define FN_RPL 23 /* Replace */ #define FN_FD 24 /* File date */ #define FN_FS 25 /* File size */ #define FN_RIX 26 /* Rindex (index from right) */ #define FN_VER 27 /* Verify */ #define FN_IPA 28 /* Find and return IP address */ #define FN_CRY 39 /* ... */ #define FN_OOX 40 /* ... */ #define FN_HEX 41 /* Hexify */ #define FN_UNH 42 /* Unhexify */ #define FN_BRK 43 /* Break */ #define FN_SPN 44 /* Span */ #define FN_TRM 45 /* Trim */ #define FN_LTR 46 /* Left-Trim */ #define FN_CAP 47 /* Capitalize */ #define FN_TOD 48 /* Time-of-day-to-secs-since-midnite */ #define FN_SEC 49 /* Secs-since-midnite-to-time-of-day */ #define FN_FFN 50 /* Full file name */ #define FN_CHK 51 /* Checksum of text */ #define FN_CRC 52 /* CRC-16 of text */ #define FN_BSN 53 /* Basename of file */ #define FN_CMD 54 /* Output of a command (cooked) */ #define FN_RAW 55 /* Output of a command (raw) */ #define FN_STX 56 /* Strip from right */ #define FN_STL 57 /* Strip from left */ #define FN_STN 58 /* Strip n chars */ #define FN_SCRN_CX 59 /* Screen Cursor X Pos */ #define FN_SCRN_CY 60 /* Screen Cursor Y Pos */ #define FN_SCRN_STR 61 /* Screen String */ #define FN_2HEX 62 /* Number (not string) to hex */ #define FN_2OCT 63 /* Number (not string) to octal */ #define FN_RFIL 64 /* Recursive file list */ #define FN_DIR 65 /* Directory list */ #define FN_RDIR 66 /* Recursive directory list */ #define FN_DNAM 67 /* Directory part of filename */ #define FN_RAND 68 /* Random number */ #define FN_WORD 69 /* Word extraction */ #define FN_SPLIT 70 /* Split string into words */ #define FN_KRB_TK 71 /* Kerberos tickets */ #define FN_KRB_NX 72 /* Kerberos next ticket */ #define FN_KRB_IV 73 /* Kerberos ticket is valid */ #define FN_KRB_TT 74 /* Kerberos ticket time */ #define FN_ERRMSG 75 /* Error code to message */ #ifndef UNIX #ifndef VMS #undef FN_ERRMSG #endif /* VMS */ #endif /* UNIX */ #define FN_DIM 76 /* Dimension of array */ #define FN_DTIM 77 /* Convert to standard date/time */ #define FN_JDATE 78 /* Regular date to day of year */ #define FN_PNCVT 79 /* Convert phone number for dialing */ #define FN_DATEJ 80 /* Day of year to date */ #define FN_MJD 81 /* Date to modified Julian date */ #define FN_MJD2 82 /* Modified Julian date to date */ #define FN_DAY 83 /* Day of week of given date */ #define FN_NDAY 84 /* Numeric day of week of given date */ #define FN_TIME 85 /* Convert to hh:mm:ss */ #define FN_NTIM 86 /* Convert to seconds since midnite */ #define FN_N2TIM 87 /* Sec since midnite to hh:mm:ss */ #define FN_PERM 88 /* Permissions of file */ #define FN_KRB_FG 89 /* Kerberos Ticket Flags */ #define FN_SEARCH 90 /* Search for pattern in string */ #define FN_RSEARCH 91 /* Ditto, but right to left */ #define FN_XLATE 92 /* Translate string charset */ #define FN_ALOOK 93 /* Array lookup */ #define FN_TLOOK 94 /* Table lookup */ #define FN_TOB64 95 /* Encode into Base64 */ #define FN_FMB64 96 /* Decode from Base64 */ #define FN_ABS 97 /* Absolute value */ #ifdef CKFLOAT #define FN_FPADD 98 /* Floating-point add */ #define FN_FPSUB 99 /* Floating-point substract */ #define FN_FPMUL 100 /* Floating-point multiply */ #define FN_FPDIV 101 /* Floating-point divide */ #define FN_FPEXP 102 /* Floating-point e to the x */ #define FN_FPLN 103 /* Floating-point natural log */ #define FN_FPLOG 104 /* Floating-point base-10 log */ #define FN_FPPOW 105 /* Floating-point raise to power */ #define FN_FPSQR 106 /* Floating-point square root */ #define FN_FPABS 107 /* Floating-point absolute value */ #define FN_FPMOD 108 /* Floating-point modulus */ #define FN_FPMAX 109 /* Floating-point maximum */ #define FN_FPMIN 110 /* Floating-point minimum*/ #define FN_FPINT 111 /* Floating-point to integer */ #define FN_FPROU 112 /* Floating-point round */ #define FN_FPSIN 113 /* FP sine */ #define FN_FPCOS 114 /* FP cosine */ #define FN_FPTAN 115 /* FP tangent */ #endif /* CKFLOAT */ #ifdef CKCHANNELIO #define FN_FSTAT 116 /* File status */ #define FN_FPOS 117 /* File position */ #define FN_FEOF 118 /* File eof */ #define FN_FILNO 119 /* File number / handle */ #define FN_FGCHAR 120 /* File getchar */ #define FN_FGLINE 121 /* File getline */ #define FN_FGBLK 122 /* File getblock */ #define FN_FPCHAR 123 /* File putchar */ #define FN_FPLINE 124 /* File putline */ #define FN_FPBLK 125 /* File putblock */ #define FN_NLINE 126 /* File get current line number */ #define FN_FERMSG 127 /* File error message */ #endif /* CKCHANNELIO */ #define FN_LEF 128 /* Left (= substr starting on left) */ #define FN_AADUMP 129 /* Associative Array Dump */ #define FN_STB 130 /* \fstripb() */ #define FN_PATTERN 131 /* \fpattern() */ #define FN_HEX2N 132 /* \fhexton() */ #define FN_OCT2N 133 /* \foctton() */ #define FN_HEX2IP 134 /* \fhextoip() */ #define FN_IP2HEX 135 /* \fiptohex() */ #define FN_RADIX 136 /* \fradix() */ #define FN_JOIN 137 /* \fjoin() */ #define FN_SUBST 138 /* \fsubstitute() */ #define FN_SEXP 139 /* \fsexpression() */ #define FN_CMDSTK 140 /* \fcmdstack() */ #define FN_TOGMT 141 /* \ftogmt() */ #define FN_CMPDATE 142 /* \fcmpdates() */ #define FN_DIFDATE 143 /* \fdiffdates() */ #ifdef TCPSOCKET #define FN_HSTADD 144 /* \faddr2name() */ #define FN_HSTNAM 145 /* \fname2addr() */ #endif /* TCPSOCKET */ #define FN_DELSEC 146 /* \fdelta2sec() */ #define FN_PC_DU 147 /* Path conversion DOS to Unix */ #define FN_PC_VU 148 /* Path conversion VMS to Unix */ #define FN_PC_UD 149 /* Path conversion Unix to DOS */ #define FN_PC_UV 150 /* Path conversion Unix to VMS */ #define FN_KWVAL 151 /* \fkeywordvalue() */ #define FN_SLEEP 152 /* \fsleep() */ #define FN_MSLEEP 153 /* \fmsleep() */ #define FN_LNAME 154 /* \fLongPathName() (Windows) */ #define FN_SNAME 155 /* \fShortPathName() (Windows) */ #define FN_UNTAB 156 /* \funtabify() */ #define FN_LOPX 157 /* \flopx() */ #define FN_EMAIL 158 /* \femailaddress() */ #define FN_PICTURE 159 /* \fpictureinfo() */ #define FN_PID 160 /* \fpidinfo() */ #define FN_COUNT 161 /* \fcount() */ #define FN_FUNC 162 /* \ffunction() */ #define FN_RECURSE 163 /* \frecurse() */ #define FN_SQUEEZE 164 /* \fsqueeze() */ #define FN_UNPCT 165 /* \fdecodehex() */ #define FN_STRINGT 166 /* \fstringtype() */ #define FN_STRCMP 167 /* \fstrcmp() */ #define FN_FILEINF 168 /* File information */ #define FN_FILECMP 169 /* File compare */ #define FN_DAYNAME 170 /* Day name according to locale */ #define FN_MONNAME 171 /* Month name according to locale */ #endif /* NOSPL */ /* Time Units */ #define TU_DAYS 0 #define TU_WEEKS 1 #define TU_MONTHS 2 #define TU_YEARS 3 #ifdef CK_CURSES /* Screen line numbers for fullscreen file-transfer display */ #define CW_BAN 0 /* Curses Window Banner */ #define CW_DIR 2 /* Current directory */ #define CW_LIN 3 /* Communication device */ #define CW_SPD 4 /* Communication speed */ #define CW_PAR 5 /* Parity */ #define CW_TMO 6 #define CW_NAM 7 /* Filename */ #define CW_TYP 8 /* File type */ #define CW_SIZ 9 /* File size */ #define CW_PCD 10 /* Percent done */ #ifndef CK_PCT_BAR #define CW_TR 11 /* Time remaining */ #define CW_CP 12 /* Characters per second */ #define CW_WS 13 /* Window slots */ #define CW_PT 14 /* Packet type */ #define CW_PC 15 /* Packet count */ #define CW_PL 16 /* Packet length */ #define CW_PR 17 /* Packet retry */ #ifdef COMMENT #define CW_PB 17 /* Packet block check */ #endif /* COMMENT */ #else /* CK_PCT_BAR */ #define CW_BAR 11 /* Percent Bar Scale */ #define CW_TR 12 /* Time remaining */ #define CW_CP 13 /* Chars per sec */ #define CW_WS 14 /* Window slots */ #define CW_PT 15 /* Packet type */ #define CW_PC 16 /* Packet count */ #define CW_PL 17 /* Packet length */ #define CW_PR 18 /* Packet retry */ #ifdef COMMENT #define CW_PB 18 /* Packet block check */ #endif /* COMMENT */ #endif /* CK_PCT_BAR */ #define CW_ERR 19 /* Error message */ #define CW_MSG 20 /* Info message */ #define CW_INT 22 /* Instructions */ #define CW_FFC 99 /* File Characters Sent/Received */ #endif /* CK_CURSES */ #ifndef NOICP /* Save Commands */ #define XSKEY 0 /* Key map file */ #define XSCMD 1 /* Command mode */ #define XSTERM 2 /* Terminal mode */ #endif /* NOICP */ #ifndef NODIAL /* Dial routine sort priorities */ #define DN_INTERN 0 #define DN_FREE 1 #define DN_LOCAL 2 #define DN_UNK 3 #define DN_LONG 4 #define DN_INTL 5 #endif /* NODIAL */ #ifdef SSHBUILTIN #define XSSH_OPN 1 #define XSSH_V2 2 #define XSSH_FLP 3 #define XSSH_FRP 4 #define XSSH_ADD 5 #define XSSH_KEY 6 #define XSSH_CLR 7 #define XSSH_AGT 8 #define XSSH_LOAD 9 #define XSSH_REM 10 #ifdef COMMENT #define SSHKT_1R 0 /* SSH KEY TYPE symbols */ #define SSHKT_2R 1 /* must match ssh/key.h values */ #define SSHKT_2D 2 #define SSHKT_SRP 3 #endif #define SSHKT_DSS 0 #define SSHKT_RSA 1 #define SSHKT_RSA1 2 #define SSHKT_ECDSA 3 /* deprecated */ #define SSHKT_ED25519 4 #define SSHKT_DSS_CERT01 5 #define SSHKT_RSA_CERT01 6 #define SSHKT_ECDSA_P256 7 #define SSHKT_ECDSA_P384 8 #define SSHKT_ECDSA_P521 9 #define SSHKT_ECDSA_P256_CERT01 10 #define SSHKT_ECDSA_P384_CERT01 11 #define SSHKT_ECDSA_P521_CERT01 12 #define SSHKT_ED25519_CERT01 13 #define SSHKT_SK_ECDSA 14 #define SSHKT_SK_ECDSA_CERT01 15 #define SSHKT_SK_ED25519 16 #define SSHKT_SK_ED25519_CERT01 17 #define SSHKD_IN 1 /* SSH KEY DISPLAY /IN-FORMAT */ #define SSHKD_OUT 2 /* SSH KEY DISPLAY /OUT-FORMAT */ #define SKDF_OSSH 1 /* Key display format OpenSSH */ #define SKDF_SSHC 2 /* Key display format SSH.COM */ #define SKDF_IETF 3 /* Key display format IETF */ #define SKDF_FING 4 /* Key display format FINGERPRINT */ #define SSHSW_USR 1 #define SSHSW_VER 2 #define SSHSW_CMD 3 #define SSHSW_X11 4 #define SSHSW_PWD 5 #define SSHSW_SUB 6 #define SSHC_LPF 1 #define SSHC_RPF 2 #define SSHR_LPF 1 #define SSHR_RPF 2 #define XSSH2_RKE 1 #define SSHF_LCL 1 #define SSHF_RMT 2 #define SSHA_ADD 1 #define SSHA_DEL 2 #define SSHA_LST 3 #define SSHASW_FP 1 #define SSHK_PASS 1 #define SSHK_CREA 2 #define SSHK_DISP 3 #define SSHK_V1 4 #define SSHKC_BI 1 #define SSHKC_PP 2 #define SSHKC_TY 3 #define SSHKC_1R 4 #define SKRM_OPN 1 #endif /* SSHBUILTIN */ #ifdef SFTP_BUILTIN #define SFTP_OPN 1 #define SFTP_CD 2 #define SFTP_CHGRP 3 #define SFTP_CHMOD 4 #define SFTP_CHOWN 5 #define SFTP_DIR 6 #define SFTP_GET 7 #define SFTP_MKDIR 8 #define SFTP_PWD 9 #define SFTP_PUT 10 #define SFTP_REN 11 #define SFTP_RM 12 #define SFTP_RMDIR 13 #define SFTP_LINK 14 #define SFTP_VER 15 #define XY_SFTP_RCS 1 #define XY_SFTP_EOL 2 #endif /* SFTP_BUILTIN */ /* ANSI-C prototypes for user interface functions */ _PROTOTYP( VOID newerrmsg, (char *) ); _PROTOTYP( int isinternalmacro, ( int ) ); #ifdef UNIX _PROTOTYP( int doputenv, ( char *, char * ) ); #endif /* UNIX */ #ifndef OS2 _PROTOTYP( int chkaes, ( char, int ) ); #endif /* OS2 */ #ifndef NOICP _PROTOTYP( int matchname, ( char *, int, int ) ); _PROTOTYP( int ck_cls, ( void ) ); _PROTOTYP( int ck_cleol, ( void ) ); _PROTOTYP( int ck_curpos, ( int, int ) ); _PROTOTYP( int cmdsrc, ( void ) ); _PROTOTYP( int parser, ( int ) ); _PROTOTYP( int chkvar, (char *) ); _PROTOTYP( int zzstring, (char *, char **, int *) ); #ifndef NOFRILLS _PROTOTYP( int yystring, (char *, char **) ); #endif /* NOFRILLS */ _PROTOTYP( int getncm, (char *, int) ); _PROTOTYP( int getnct, (char *, int, FILE *, int) ); #endif /* NOICP */ _PROTOTYP( VOID bgchk, (void) ); _PROTOTYP( char * nvlook, (char *) ); _PROTOTYP( int xarray, (char *) ); _PROTOTYP( int arraynam, (char *, int *, int *) ); _PROTOTYP( int arraybounds, (char *, int *, int *) ); _PROTOTYP( int boundspair, (char *, char *, int *, int *, char *) ); _PROTOTYP( int arrayitoa, (int) ); _PROTOTYP( int arrayatoi, (int) ); _PROTOTYP( char * bldlen, (char *, char *) ); _PROTOTYP( int chkarray, (int, int) ); _PROTOTYP( int dclarray, (char, int) ); _PROTOTYP( int pusharray, (int, int) ); _PROTOTYP( int parsevar, (char *, int *, int *) ); _PROTOTYP( int macini, (void) ); _PROTOTYP( VOID initmac, (void) ); _PROTOTYP( int delmac, (char *, int) ); _PROTOTYP( int addmac, (char *, char *) ); _PROTOTYP( int domac, (char *, char *, int) ); _PROTOTYP( int addmmac, (char *, char *[]) ); _PROTOTYP( int dobug, (void) ); _PROTOTYP( int docd, (int) ); _PROTOTYP( int doclslog, (int) ); _PROTOTYP( int docmd, (int) ); _PROTOTYP( int dodir, (int) ); _PROTOTYP( int dodo, (int, char *, int) ); _PROTOTYP( int doenable, (int, int) ); _PROTOTYP( int dogoto, (char *, int) ); _PROTOTYP( int dogta, (int) ); _PROTOTYP( int dohlp, (int) ); _PROTOTYP (int doincr, (int) ); _PROTOTYP( int dohrmt, (int) ); _PROTOTYP( int doif, (int) ); _PROTOTYP( int doinput, (int, char *[], int[], int, int) ); _PROTOTYP( int doreinp, (int, char *, int) ); _PROTOTYP( int dolog, (int) ); _PROTOTYP( int dologin, (char *) ); _PROTOTYP( int doopen, (void) ); _PROTOTYP( int doprm, (int, int) ); _PROTOTYP( int doreturn, (char *) ); _PROTOTYP( int dormt, (int) ); _PROTOTYP( int dosort, (void) ); _PROTOTYP( int dostat, (int) ); _PROTOTYP( int dostop, (void) ); _PROTOTYP( int dotype, (char *, int, int, int, char *, int, char *, int, int, char *, int)); _PROTOTYP( int transmit, (char *, char, int, int, int) ); _PROTOTYP( int xlate, (char *, char *, int, int) ); _PROTOTYP( int litcmd, (char **, char **, int) ); _PROTOTYP( int incvar, (char *, CK_OFF_T, int) ); _PROTOTYP( int ckdial, (char *, int, int, int, int) ); _PROTOTYP( int hmsg, (char *) ); _PROTOTYP( int hmsga, (char * []) ); _PROTOTYP( int prtopt, (int *, char *) ); _PROTOTYP( CHAR rfilop, (char *, char) ); _PROTOTYP( int setcc, (char *, int *) ); _PROTOTYP( int setnum, (int *, int, int, int) ); _PROTOTYP( int seton, (int *) ); _PROTOTYP( int setonaut, (int *) ); _PROTOTYP( VOID shmdmlin, (void) ); _PROTOTYP( VOID slrestor, (void) ); _PROTOTYP( VOID initmdm, (int) ); _PROTOTYP( char * showoff, (int) ); _PROTOTYP( char * showooa, (int) ); _PROTOTYP( char * showstring, (char *) ); _PROTOTYP( int pktopn, (char *,int) ); _PROTOTYP( int traopn, (char *,int) ); _PROTOTYP( int sesopn, (char *,int) ); _PROTOTYP( int debopn, (char *,int) ); _PROTOTYP( int diaopn, (char *,int,int) ); _PROTOTYP( int prepop, (void) ); _PROTOTYP( int popclvl, (void) ); _PROTOTYP( int varval, (char *, CK_OFF_T *) ); _PROTOTYP( char * evala, (char *) ); _PROTOTYP( char * evalx, (char *) ); _PROTOTYP( int setalarm, (long) ); _PROTOTYP( int setat, (int) ); _PROTOTYP( int setinp, (void) ); _PROTOTYP( VOID dolognet, (void) ); _PROTOTYP( VOID dologline, (void) ); _PROTOTYP( int setlin, (int, int, int) ); _PROTOTYP( int setmodem, (void) ); _PROTOTYP( int setfil, (int) ); _PROTOTYP( char * homepath, (void) ); #ifdef OS2 #ifdef COMMENT /* [jt] 2013/11/21 - static/non-static issue */ _PROTOTYP( int settapi, (void) ) ; #endif /* COMMENT */ #ifdef OS2MOUSE _PROTOTYP( int setmou, (void) ); #endif /* OS2MOUSE */ #endif /* OS2 */ #ifdef LOCUS _PROTOTYP( VOID setlocus, (int,int) ); _PROTOTYP( VOID setautolocus, (int) ); #endif /* LOCUS */ _PROTOTYP( int setbell, (void) ); _PROTOTYP( VOID setcmask, (int)); _PROTOTYP( VOID setautodl, (int,int)); _PROTOTYP( VOID setdebses, (int)); _PROTOTYP( VOID setseslog, (int)); _PROTOTYP( VOID setaprint, (int)); _PROTOTYP( int settrm, (void) ); _PROTOTYP( int settrmtyp, (void) ); _PROTOTYP( int setsr, (int, int) ); _PROTOTYP( int setxmit, (void) ); _PROTOTYP( int dosetkey, (void) ); _PROTOTYP( int dochk, (void) ); _PROTOTYP( int ludial, (char *, int) ); _PROTOTYP( char * getdnum, (int) ); _PROTOTYP( VOID getnetenv, (void) ); _PROTOTYP( int getyesno, (char *, int) ); _PROTOTYP( VOID xwords, (char *, int, char *[], int) ); #ifdef OS2 _PROTOTYP( VOID keynaminit, (void) ); #endif /* OS2 */ _PROTOTYP( int xlookup, (struct keytab[], char *, int, int *) ); _PROTOTYP( char * rlookup, (struct keytab[], int, int) ); _PROTOTYP( int hupok, (int) ); _PROTOTYP( char * zzndate, (void) ); _PROTOTYP( char * zjdate, (char *) ); _PROTOTYP( char * jzdate, (char *) ); _PROTOTYP( char * ckdate, (void) ); _PROTOTYP( char * chk_ac, (int, char[]) ); _PROTOTYP( char * gmdmtyp, (void) ); _PROTOTYP( char * gfmode, (int, int) ); _PROTOTYP( int setdest, (void) ); _PROTOTYP( VOID ndinit, (void) ); _PROTOTYP( int doswitch, (void) ); _PROTOTYP( int dolocal, (void) ); _PROTOTYP( long tod2sec, (char *) ); _PROTOTYP( int lunet, (char *) ); _PROTOTYP( int doxdis, (int) ); _PROTOTYP( int dosave, (int) ); _PROTOTYP( int doxsend, (int) ); _PROTOTYP( int doxget, (int) ); _PROTOTYP( int doxconn, (int) ); _PROTOTYP( int clsconnx, (int) ); _PROTOTYP( VOID ftreset, (void) ); #ifdef CK_KERBEROS _PROTOTYP (int cp_auth, ( void ) ); #endif /* CK_KERBEROS */ _PROTOTYP( long mjd, (char *) ); _PROTOTYP( char * mjd2date, (long) ); _PROTOTYP( char * ckgetpid, (void) ); _PROTOTYP( int dogrep, (void) ); #ifndef NOFTP #ifndef SYSFTP _PROTOTYP( int doxftp, (void) ); _PROTOTYP( int doftphlp, (void) ); _PROTOTYP( int dosetftp, (void) ); _PROTOTYP( int dosetftphlp, (void) ); _PROTOTYP( int shoftp, (int) ); #endif /* SYSFTP */ #endif /* NOFTP */ _PROTOTYP( VOID cmhistory, (void) ); _PROTOTYP( char * getdcset, (void) ); _PROTOTYP( char * ttgtpn, (void) ); #ifndef NOSHOW _PROTOTYP( int doshow, (int) ); _PROTOTYP( int shotcp, (int) ); _PROTOTYP( VOID shopar, (void) ); _PROTOTYP( VOID shofil, (void) ); _PROTOTYP( VOID shoparp, (void) ); _PROTOTYP( int shoatt, (void) ); _PROTOTYP( VOID shover, (void) ); _PROTOTYP( VOID shoctl, (void) ); _PROTOTYP( VOID shodbl, (void) ); #ifndef NOSPL _PROTOTYP( int shomac, (char *, char *) ); _PROTOTYP( int doshift, (int) ); #endif /* NOSPL */ #ifndef NOCSETS _PROTOTYP( VOID shocharset, (void) ); _PROTOTYP( VOID shoparl, (void) ); _PROTOTYP( VOID shotcs, (int, int) ); #endif /* NOCSETS */ #ifndef NOLOCAL _PROTOTYP( VOID shoparc, (void) ); _PROTOTYP( int shomodem, (void) ); #ifndef NODIAL _PROTOTYP( VOID shods, (char *) ); _PROTOTYP( VOID shodial, (void) ); _PROTOTYP( int doshodial, (void) ); #endif /* NODIAL */ #ifndef NONET _PROTOTYP( int shonet, (void) ); _PROTOTYP( int shotopt, (int) ); _PROTOTYP( int shotel, (int) ); #ifdef CK_AUTHENTICATION _PROTOTYP (int sho_auth,( int ) ); #endif /* CK_AUTHENTICATION */ #endif /* NONET */ _PROTOTYP( VOID shomdm, (void) ); #endif /* NOLOCAL */ #ifdef OS2 _PROTOTYP( VOID shokeycode, (int,int) ); #else _PROTOTYP( VOID shokeycode, (int) ); #endif /* OS2 */ _PROTOTYP( VOID showassoc, (void) ); _PROTOTYP( VOID showdiropts, (void) ); _PROTOTYP( VOID showdelopts, (void) ); _PROTOTYP( VOID showtypopts, (void) ); _PROTOTYP( VOID showpurgopts, (void) ); _PROTOTYP( VOID shoflow, (void) ); _PROTOTYP( VOID shoxfer, (void) ); #ifdef ANYSSH _PROTOTYP( VOID shossh, (void) ); #endif /* ANYSSH */ #endif /* NOSHOW */ _PROTOTYP( VOID shostrdef, (CHAR *) ); #ifndef NOSPL _PROTOTYP( int addlocal, (char *) ); #endif /* NOSPL */ _PROTOTYP( int setdelopts, (void) ); #ifdef VMS _PROTOTYP( int cvtdir, (char *, char *, int) ); #endif /* VMS */ #ifdef FNFLOAT _PROTOTYP( VOID initfloat, (void) ); #endif /* FNFLOAT */ #ifdef CKCHANNELIO _PROTOTYP( int dofile, (int) ); #endif /* CKCHANNELIO */ #ifdef CKROOT _PROTOTYP( int dochroot, (void) ); #endif /* CKROOT */ #ifdef NEWFTP _PROTOTYP( int doftpusr, (void) ); _PROTOTYP( int doftpput, (int,int) ); _PROTOTYP( int doftpget, (int,int) ); _PROTOTYP( int doftprmt, (int,int) ); _PROTOTYP( int ftpopen, (char *, char *, int) ); _PROTOTYP( int cmdlinget, (int) ); _PROTOTYP( int cmdlinput, (int) ); _PROTOTYP( int doftparg, (char) ); _PROTOTYP( int doftpacct, (void) ); _PROTOTYP( int doftpsite, (void) ); _PROTOTYP( int dosetftppsv, (void) ); _PROTOTYP( int ftpbye, (void) ); #endif /* NEWFTP */ #ifdef COMMENT /* These prototypes are no longer used */ _PROTOTYP( char * getdws, (int) ); _PROTOTYP( char * getdcs, (int) ); _PROTOTYP( int doget, (int) ); _PROTOTYP( char * arrayval, (int, int) ); #endif /* COMMENT */ #ifdef KUI _PROTOTYP(int BuildFontTable, (struct keytab ** pTable, struct keytab ** pTable2, int * pN)); #endif /* KUI */ _PROTOTYP(int cx_net, (int net, int protocol, char * xhost, char * svc, char * username, char * password, char * command, int param1, int param2, int param3, int cx, int sx, int flag, int gui)); _PROTOTYP(int cx_serial, (char *device, int cx, int sx, int shr, int flag, int gui, int special)); #endif /* CKUUSR_H */ /* End of ckuusr.h */ ckuusx.c000664 045065 024037 00001065545 14767410770 012706 0ustar00fdckermit000000 000000 #include "ckcsym.h" /* C K U U S X -- "User Interface" common functions. */ /* Authors: Frank da Cruz , The Kermit Project, New York City Jeffrey E Altman Secure Endpoints Inc., New York City Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Last update: 12 April 2023 (prototypes) */ /* This module contains user interface functions needed by both the interactive user interface and the command-line-only user interface, as well as the screen-control routines (curses and equivalent). Fri Jun 3 10:54:47 2022 */ /* Includes */ #include "ckcdeb.h" #include "ckcasc.h" #include "ckcker.h" #include "ckuusr.h" #include "ckcxla.h" /* Curses/Termcap function prototypes... Indented for easier reading 3 November 2021. Un-indented 7 December 2021 because some old C compilers require '#' directives to be on the left margin. */ #ifdef __OpenBSD__ #ifdef HAVETERMH #include #endif /* HAVETERMH */ #else /* Not __OpenBSD__ */ #ifndef NOHTERMCAP #ifdef NOTERMCAP #define NOHTERMCAP #else #ifndef BSD44 #define NOHTERMCAP #else #ifdef __bsdi__ #define NOHTERMCAP #else #ifdef MACOSX #ifndef OLDMACOSX #include /* macOS after 10.12 */ #include #endif /* OLDMACOSX */ #define NOHTERMCAP #endif /* MACOSX */ #endif /* __bsdi__ */ #endif /* BSD44 */ #endif /* NOTERMCAP */ #endif /* NOHTERMCAP */ #endif /* __OpenBSD__ */ #ifndef NOTERMCAP #ifdef BSD44 #ifndef NOHTERMCAP #include #endif /* NOHTERMCAP */ #endif /* BSD44 */ #else /* !BSD44 */ #ifdef linux #include #endif /* linux */ #endif /* NOTERMCAP */ /* None of the above works on Ubuntu: not curses.h, term.h, termcap.h so... */ #ifdef __linux__ int tgetent (char *, const char *); int tputs (const char *, int, int (*)(int)); char * tgetstr (const char *, char **); char * tgoto (const char *, int, int); #endif /* __linux__ */ #ifdef OS2 #include #include /* for getpid() */ _PROTOTYP(char * os2_gethostname, (void)); #ifndef __WATCOMC__ #define getpid _getpid #endif /* __WATCOMC__ */ #endif /* OS2 */ /* fdc 26 Sep 2022 */ #ifdef CK_ENCRYPTION _PROTOTYP(int ck_tn_encrypting, (void)); _PROTOTYP(int ck_tn_decrypting, (void)); #endif /* CK_ENCRYPTION */ #ifdef BSD44 #include #endif /* BSD44 */ extern xx_strp xxstring; #ifdef OS2 #include "ckcnet.h" #else /* OS2 */ _PROTOTYP( char * ckgetpeer, (VOID)); _PROTOTYP(int getlocalipaddr, (void)); _PROTOTYP(int istncomport, (void)); #ifndef NOCKGETFQHOST _PROTOTYP( char * ckgetfqhostname,(char *)); #endif /* NOCKGETFQHOST */ #ifndef NETCONN /* We should just pull in ckcnet.h here, but it causes a conflict with curses.h. */ #ifdef TCPSOCKET #define NETCONN #else #ifdef SUNX25 #define NETCONN #else #ifdef STRATUSX25 #define NETCONN #else #ifdef IBMX25 #define NETCONN #else #ifdef HPX25 #define NETCONN #else #ifdef DECNET #define NETCONN #else #ifdef NPIPE #define NETCONN #else #ifdef CK_NETBIOS #define NETCONN #ifdef SUPERLAT #define NETCONN #else #endif /* SUPERLAT */ #endif /* TCPSOCKET */ #endif /* SUNX25 */ #endif /* STRATUSX25 */ #endif /* IBMX25 */ #endif /* HPX25 */ #endif /* DECNET */ #endif /* NPIPE */ #endif /* CK_NETBIOS */ #endif /* NETCONN */ #endif /* OS2 */ #ifndef TCPSOCKET #ifdef MULTINET #define TCPSOCKET #endif /* MULTINET */ #ifdef DEC_TCPIP #define TCPSOCKET #endif /* DEC_TCPIP */ #ifdef WINTCP #define TCPSOCKET #endif /* WINTCP */ #ifdef TCPWARE #define TCPSOCKET #endif /* TCPWARE */ #endif /* TCPSOCKET */ #ifdef OS2 #ifdef NT #include #ifdef CK_TAPI #include #include "ckntap.h" #endif /* CK_TAPI */ #else /* NT */ #define INCL_VIO #define INCL_WINERRORS #include #endif /* NT */ #ifdef COMMENT /* Would you believe */ #undef COMMENT /* defines this ? */ #endif /* COMMENT */ #ifdef CK_NETBIOS #include "ckonbi.h" #endif /* CK_NETBIOS */ #include "ckocon.h" extern ascreen commandscreen; #ifdef KUI #include "ikui.h" #endif /* KUI */ #endif /* OS2 */ #ifdef NT #include "cknwin.h" #endif /* NT */ #ifdef OS2 #include "ckowin.h" #include "ckosyn.h" #endif /* OS2 */ #ifdef CK_TAPI extern int tttapi; extern int tapipass; #endif /* CK_TAPI */ #ifdef CK_KERBEROS #include "ckuath.h" #endif /* CK_KERBEROS */ #ifndef WINTCP #include #endif /* WINTCP */ #ifdef VMS #include #include #include #ifndef OLD_VMS #include /* Not for VAX C 2.3 */ #else #include #endif /* OLD_VMS */ #ifdef WINTCP #include #endif /* WINTCP */ #endif /* VMS */ #ifdef DCLFDOPEN /* fdopen() needs declaring because it's not declared in */ _PROTOTYP( FILE * fdopen, (int, char *) ); #endif /* DCLFDOPEN */ #ifdef DCLPOPEN /* popen() needs declaring because it's not declared in */ _PROTOTYP( FILE * popen, (char *, char *) ); #endif /* DCLPOPEN */ #ifdef OS2 #ifndef KUI APIRET IsVscrnDirty( int vmode ); #endif /* KUI */ #endif /* OS2 */ int tt_crd = 0; /* Carriage return display */ int tt_lfd = 0; /* Linefeed display */ int interrupted = 0; /* Interrupted from keyboard flag */ int fxd_inited = 0; /* Fullscreen stuff initialized */ #ifdef DEBUG char debfil[CKMAXPATH+1]; /* Debugging log file name */ #endif /* DEBUG */ #ifdef TLOG char trafil[CKMAXPATH+1]; /* Transaction log file name */ #endif /* TLOG */ char sesfil[CKMAXPATH+1]; /* Session log file name */ #ifdef CKLOGDIAL char diafil[CKMAXPATH+1]; /* Connection log file name */ char cxlogbuf[CXLOGBUFL+1]; /* Connection log record buffer */ int cx_active = 0; /* Connection is active */ extern int dialog; #endif /* CKLOGDIAL */ #ifdef DYNAMIC static char *cmdstr = NULL; /* Place to build generic command */ #else #ifdef pdp11 static char cmdstr[256]; #else static char cmdstr[4096]; #endif /* pdp11 */ #endif /* DYNAMIC */ #ifndef NOMSEND char fspec[CMDBL+4]; /* Filename string for \v(filespec) */ int fspeclen = CMDBL; #else char fspec[CKMAXPATH+4]; int fspeclen = CKMAXPATH; #endif /* NOMSEND */ _PROTOTYP( int getslot, () ); char * rfspec = NULL; /* Received filespec: local */ char * prfspec = NULL; /* Preliminary rfspec */ char * sfspec = NULL; /* Sent filespec: local */ char * psfspec = NULL; /* Preliminary sfspec */ char * srfspec = NULL; /* Received filespec: remote */ char * psrfspec = NULL; /* Preliminary srfspec */ char * rrfspec = NULL; /* Sent filespec: remote */ char * prrfspec = NULL; /* Preliminary rrfspec */ int success = 1, /* Command success/failure flag */ cmdlvl = 0, /* Command level */ action = 0, /* Action selected on command line */ slogts = 0, /* Session-log timestamps on/off */ slognul = 0, /* Session-log null-terminated lines */ #ifdef UNIX sessft = XYFT_T, /* Session log file type */ #else sessft = XYFT_B, /* (text for UNIX binary for others) */ #endif /* UNIX */ pflag = 1, /* Print prompt */ msgflg = 1; /* Print informational messages */ extern int xaskmore, saveask; /* More-prompting */ #ifdef CK_APC extern int apcactive; #endif /* CK_APC */ /* External variables */ extern int local, quiet, binary, network, what, parity, xitsta, escape, tlevel, bgset, backgrd, xsuspend, cmdint, nettype, seslog, dfloc; extern int cmd_rows, cmd_cols, xcmdsrc; extern char cmdfil[]; #ifdef VMS extern int batch; #endif /* VMS */ #ifdef datageneral /* 2/12/92 ENH */ #include extern int con_reads_mt, conint_ch, conint_avl; #endif /* datageneral */ #ifdef UNIX #include /* For creat() */ #endif /* UNIX */ #include "ckcnet.h" /* for struct sockaddr */ /* Note, ckcet.h is already included above in OS/2, but no worries, it protects itself against multiple inclusion. */ #include "ckcfnp.h" /* Prototypes (must be last) */ extern long speed; extern char ttname[], *dftty, *cmarg, **cmlist, *versio, myhost[]; #ifndef NOCSETS extern int fcharset, tcharset, xfrxla; extern struct csinfo fcsinfo[], tcsinfo[]; #endif /* NOCSETS */ #ifdef OS2 extern unsigned char colorcmd; #endif /* OS2 */ #ifdef NOXFER int fdispla = XYFD_N; #else /* NOXFER is not defined */ #ifdef OS2 /* File transfer display type */ int fdispla = XYFD_C; /* Curses (fullscreen) if we have it */ #else #ifdef CK_CURSES int fdispla = XYFD_C; #else int fdispla = XYFD_S; /* Otherwise CRT */ #endif /* CK_CURSES */ #endif /* OS2 */ extern struct ck_p ptab[]; extern int protocol, xfrbel, xfrint; #ifdef STREAMING extern int streaming, streamok; #endif /* STREAMING */ /* Used internally */ #ifdef KUI _PROTOTYP( VOID screeng, (int, char, long, char *) ); #endif /* KUI */ _PROTOTYP( VOID screenc, (int, char, CK_OFF_T, char *) ); #ifdef CK_CURSES #ifndef DYNAMIC static char xtrmbuf[TRMBUFL]; /* tgetent() buffer */ char * trmbuf = xtrmbuf; #else char * trmbuf = NULL; #endif /* DYNAMIC */ _PROTOTYP( static VOID dpyinit, (void) ); _PROTOTYP( static long shocps, (int, CK_OFF_T, CK_OFF_T) ); _PROTOTYP( static CK_OFF_T shoetl, (CK_OFF_T, long, CK_OFF_T, CK_OFF_T) ); #endif /* CK_CURSES */ static int ft_win = 0; /* Fullscreen file transfer display window is active */ /* Variables declared here */ static char * skreason[] = { "", /* 0 */ "Remote file not older", /* SKP_DAT */ "Identical modification times", /* SKP_EQU */ "Type", /* SKP_TYP */ "Size", /* SKP_SIZ */ "Name collision", /* SKP_NAM */ "Exception List", /* SKP_EXL */ "Dot file", /* SKP_DOT */ "Backup file", /* SKP_BKU */ "Recovery not needed", /* SKP_RES */ "Access denied", /* SKP_ACC */ "Not a regular file", /* SKP_NRF */ "Simulated", /* SKP_SIM */ "Simulated - Remote file older", /* SKP_XUP */ "Simulated - No remote file", /* SKP_XNX */ }; static int nskreason = (sizeof(skreason) / sizeof(char *)); char * #ifdef CK_ANSIC gskreason( int n ) #else gskreason(n) int n; #endif /* CK_ANSIC */ { return((n > 0 && n < nskreason) ? skreason[n] : ""); } char pktfil[CKMAXPATH+1]; /* Packet log file name */ #ifndef NOMSEND /* Multiple SEND */ char *msfiles[MSENDMAX]; #endif /* NOMSEND */ #ifdef CK_TIMERS extern long rttdelay; extern int rttflg; #endif /* CK_TIMERS */ extern int rcvtimo; #ifdef CK_RESEND extern int sendmode; extern CK_OFF_T sendstart, rs_len; #endif /* CK_RESEND */ #ifdef CK_PCT_BAR /* File transfer thermometer */ int thermometer = 1; /* ON by default */ #endif /* CK_PCT_BAR */ #ifdef GFTIMER CKFLOAT gtv = -1.0, oldgtv = -1.0; #else #ifndef OS2 static #endif /* OS2 */ long gtv = -1L, oldgtv = -1L; #endif /* GFTIMER */ extern int server, bctu, rptflg, ebqflg, spsiz, urpsiz, wmax, czseen, cxseen, winlo, displa, timint, npad, ebq, bctr, rptq, atcapu, lpcapu, swcapu, wslotn, wslotr, rtimo, mypadn, sq, capas, rpsiz, tsecs, pktlog, lscapu, dest, srvdis, wslots, spackets, spktl, rpktl, retrans, wcur, numerrs, fsecs, whatru, crunched, timeouts, rpackets, fncnv, bye_active, discard, inserver, diractive, cdactive; extern long filcnt, filrej, rptn, filcps, tfcps, cps, peakcps; extern CK_OFF_T ffc, tfc, fsize; long oldcps = 0L; extern CHAR *rdatap, padch, seol, ctlq, mypadc, eol, *epktmsg; extern char *xfrmsg; #ifdef IKSDB FILE * dbfp = NULL; /* File pointer to database file */ int dbenabled = 1; /* Flag for database is enabled */ extern int ikdbopen; /* Flag for database is open */ unsigned long mydbseek = 0L; /* Seek pointer to my record */ int mydbslot = 0; /* My slot number */ unsigned long myflags = 0L; /* My flags */ unsigned long myatype = 0L; /* My authorization type */ unsigned long myamode = 0L; /* My authorization mode */ unsigned long mystate = 0L; /* My state (SEND, RECEIVE, etc) */ unsigned long mypid = 0L; /* My PID */ unsigned long myip = 0L; /* My IP address */ unsigned long peerip = 0L; /* My peer's IP address */ unsigned long dbip = 0L; /* IP address in db record */ unsigned long dbpid = 0L; /* PID in db record */ unsigned long dbflags = 0L; /* Flags field in db record */ unsigned long dblastused = 0L; /* Last in-use record in db */ char dbrec[DB_RECL]; /* Database record buffer */ char * dbdir = NULL; /* Database directory */ char * dbfile = NULL; /* Database file full pathname */ char myhexip[33] = { NUL, NUL }; /* My IP address in hex */ char peerhexip[33] = { NUL, NUL }; /* Client's IP address in hex */ #endif /* IKSDB */ #ifdef GFTIMER extern CKFLOAT fpfsecs, fptsecs, fpxfsecs; #else extern long xfsecs; #endif /* GFTIMER */ #endif /* NOXFER */ #ifdef TCPSOCKET #ifdef NEWFTP extern char * ftp_host, ftp_srvtyp[]; extern int ftp_csx, ftp_csl, ftp_deb; #endif /* NEWFTP */ extern char myipaddr[]; #endif /* TCPSOCKET */ #ifndef NOICP #ifndef NOSPL extern struct mtab *mactab; /* For ON_EXIT macro. */ extern int nmac; #endif /* NOSPL */ #ifdef DCMDBUF extern char *cmdbuf; /* Command buffer */ #else extern char cmdbuf[]; /* Command buffer */ #endif /* DCMDBUF */ extern int cmd_quoting; #endif /* NOICP */ #ifndef NOCCTRAP #ifdef NT #include #else /* NT */ #include #endif /* NT */ #include "ckcsig.h" extern ckjmpbuf cmjbuf; #endif /* NOCCTRAP */ extern int xfiletype, nscanfile; int #ifdef CK_ANSIC shoesc( int escape ) #else shoesc(escape) int escape; #endif /* CK_ANSIC */ { extern char * ccntab[]; /* C0 control character name table */ extern int tt_escape; if ((escape > 0 && escape < 32) || (escape == 127)) { printf(" Escape character: Ctrl-%c (ASCII %d, %s): %s\r\n", ctl(escape), escape, (escape == 127 ? "DEL" : ccntab[escape]), tt_escape ? "enabled" : "disabled" ); } else { printf(" Escape character: Code %d",escape); if (escape > 160 && escape < 256) printf(" (%c)",escape); printf(": %s\r\n", tt_escape ? "enabled" : "disabled"); } return(0); } #ifndef NOXFER /* P R E S E T -- Reset global protocol variables */ extern int recursive; #ifdef PATTERNS int patterns = SET_AUTO; /* Whether to use filename patterns */ extern int g_patterns; /* For saving and restoring */ #else int patterns = SET_OFF; #endif /* PATTERNS */ #ifndef NOICP #ifdef CK_LABELED extern int g_lf_opts, lf_opts; #endif /* CK_LABELED */ extern int g_matchdot, g_usepipes, usepipes; extern int g_binary, g_proto, g_displa, g_spath, g_rpath, g_fncnv; extern int g_recursive; extern int g_xfermode, xfermode; extern int g_urpsiz, g_spsizf, g_spsiz; extern int g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact; extern int g_fnspath, g_fnrpath, g_skipbup; extern int nolinks; #ifdef CKSYMLINK extern int zgfs_link; #endif /* CKSYMLINK */ #ifndef NOSPL extern int g_pflg, pwflg, g_pcpt, pwcrypt; extern char * g_pswd, pwbuf[]; #endif /* NOSPL */ #endif /* NOICP */ extern int spsizf, spsizr, spmax, prefixing, fncact, fnspath, fnrpath; extern int moving; /* SEND criteria */ extern char sndafter[], sndbefore[], *sndexcept[], *rcvexcept[]; extern CK_OFF_T sndlarger, sndsmaller, calibrate; extern int rmailf, rprintf, skipbup; extern char optbuf[]; #ifdef PIPESEND extern char * g_sfilter, * g_rfilter; extern char * sndfilter, * rcvfilter; #endif /* PIPESEND */ extern char ** sndarray; VOID ftreset() { #ifndef NOICP int i; extern char * filefile; extern int reliable, xreliable, c_save, ss_save, slostart, urclear; extern int oopts, omode, oname, opath, kactive, autopath; extern char * snd_move; /* Directory to move sent files to */ extern char * snd_rename; /* What to rename sent files to */ extern char * rcv_move; extern char * rcv_rename; extern char * g_snd_move; extern char * g_snd_rename; extern char * g_rcv_move; extern char * g_rcv_rename; #ifdef CK_TMPDIR extern int f_tmpdir; extern char savdir[]; #endif /* CK_TMPDIR */ #ifdef CK_SPEED #ifdef COMMENT extern int f_ctlp; extern short s_ctlp[], ctlp[]; #endif /* COMMENT */ #endif /* CK_SPEED */ #ifndef NOCSETS extern int fcs_save, tcs_save; extern int g_xfrxla, xfrxla; #endif /* NOCSETS */ /* Restore / reset per-command file-transfer switches */ makestr(&snd_move,g_snd_move); makestr(&rcv_move,g_rcv_move); makestr(&snd_rename,g_snd_rename); makestr(&rcv_rename,g_rcv_rename); kactive = 0; /* Kermit protocol no longer active */ oopts = -1; /* O-Packet Options */ omode = -1; /* O-Packet Transfer Mode */ oname = -1; /* O-Packet Filename Options */ opath = -1; /* O-Packet Pathname Options */ #ifdef CK_RESEND rs_len = 0L; /* REGET position */ #endif /* CK_RESEND */ #ifdef COMMENT #ifdef CK_SPEED if (f_ctlp) { for (i = 0; i < 256; i++) ctlp[i] = s_ctlp[i]; f_ctlp = 0; } #endif /* CK_SPEED */ #endif /* COMMENT */ #ifdef CK_TMPDIR if (f_tmpdir) { /* If we changed to download dir */ zchdir((char *) savdir); /* Go back where we came from */ f_tmpdir = 0; } #endif /* CK_TMPDIR */ calibrate = 0L; /* Calibration run */ if (xreliable > -1) { reliable = xreliable; debug(F101,"ftreset reliable","",reliable); } urclear = 0; if (autopath) { /* SET RECEIVE PATHNAMES AUTO */ fnrpath = PATH_AUTO; autopath = 0; } if (filefile) { /* File list */ zclose(ZMFILE); makestr(&filefile,NULL); } if (c_save > -1) { /* Block Check Type */ bctr = c_save; c_save = -1; } if (ss_save > -1) { /* Slow Start */ slostart = ss_save; ss_save = -1; } #ifdef CK_LABELED if (g_lf_opts > -1) { lf_opts = g_lf_opts; /* Restore labeled transfer options */ g_lf_opts = -1; } #endif /* CK_LABELED */ #ifndef NOCSETS if (tcs_save > -1) { /* Character sets */ tcharset = tcs_save; tcs_save = -1; } if (fcs_save > -1) { fcharset = fcs_save; fcs_save = -1; } if (g_xfrxla > -1) { xfrxla = g_xfrxla; g_xfrxla = -1; } setxlatype(tcharset,fcharset); /* Translation type */ #endif /* NOCSETS */ #ifdef NETCONN #ifndef NOSPL if (g_pswd) { ckstrncpy(pwbuf,g_pswd,PWBUFL); makestr(&g_pswd,NULL); } if (g_pflg > -1) { pwflg = g_pflg; g_pflg = -1; } if (g_pcpt > -1) { pwcrypt = g_pcpt; g_pcpt = -1; } #endif /* NOSPL */ #endif /* NETCONN */ if (g_binary > -1) { /* File type */ binary = g_binary; g_binary = -1; } if (g_xfermode > -1) { /* Transfer mode */ xfermode = g_xfermode; g_xfermode = -1; } #ifdef PATTERNS if (g_patterns > -1) { /* Filename patterns */ patterns = g_patterns; g_patterns = -1; } #endif /* PATTERNS */ if (g_usepipes > -1) { usepipes = g_usepipes; g_usepipes = -1; } if (g_matchdot > -1) { matchdot = g_matchdot; g_matchdot = -1; } if (g_proto > -1) { /* Protocol */ protocol = g_proto; g_proto = -1; } if (g_urpsiz > -1) { urpsiz = g_urpsiz; debug(F101,"ftreset restoring urpsiz","",urpsiz); g_urpsiz = -1; } if (g_spsizf > -1) { spsizf = g_spsizf; debug(F101,"ftreset restoring spsizf","",spsizf); g_spsizf = -1; } if (g_spsiz > -1) { spsiz = g_spsiz; debug(F101,"ftreset restoring spsiz","",spsiz); g_spsiz = -1; } if (g_spsizr > -1) { spsizr = g_spsizr; debug(F101,"ftreset restoring spsizr","",spsizr); g_spsizr = -1; } if (g_spmax > -1) { spmax = g_spmax; g_spmax = -1; } if (g_wslotr > -1) { wslotr = g_wslotr; g_wslotr = -1; } if (g_prefixing > -1) { prefixing = g_prefixing; g_prefixing = -1; } if (g_fncact > -1) { fncact = g_fncact; g_fncact = -1; } if (g_fncnv > -1) { fncnv = g_fncnv; g_fncnv = -1; } if (g_fnspath > -1) { fnspath = g_fnspath; g_fnspath = -1; } if (g_fnrpath > -1) { fnrpath = g_fnrpath; g_fnrpath = -1; } if (g_skipbup > -1) { skipbup = g_skipbup; g_skipbup = -1; } nolinks = 2; /* /FOLLOWLINKS is never global */ recursive = 0; /* /RECURSIVE can never be global */ xfiletype = -1; if (g_displa > -1) { /* File transfer display */ fdispla = g_displa; g_displa = -1; } if (g_spath > -1) { /* Send pathnames */ fnspath = g_spath; g_spath = -1; } if (g_rpath > -1) { /* Receive pathnames */ fnrpath = g_rpath; g_rpath = -1; } if (g_fncnv > -1) { /* Filename conversion */ fncnv = g_fncnv; g_fncnv = -1; } #ifdef PIPESEND makestr(&sndfilter,g_sfilter); /* Send filter */ makestr(&rcvfilter,g_rfilter); /* Receive filter */ #endif /* PIPESEND */ #ifndef NOFRILLS rmailf = rprintf = 0; /* MAIL and PRINT modifiers for SEND */ optbuf[0] = NUL; /* MAIL and PRINT options */ #endif /* NOFRILLS */ moving = 0; /* Reset delete-after-send indicator */ sndafter[0] = NUL; /* Reset SEND selection switches */ sndbefore[0] = NUL; for (i = 0; i < NSNDEXCEPT; i++) { if (sndexcept[i]) free(sndexcept[i]); sndexcept[i] = NULL; if (rcvexcept[i]) free(rcvexcept[i]); rcvexcept[i] = NULL; } sndlarger = (CK_OFF_T)-1; sndsmaller = (CK_OFF_T)-1; debug(F101,"present sndsmaller","",sndsmaller); #ifdef GFTIMER gtv = -1.0; oldgtv = -1.0; #else gtv = -1L; oldgtv = -1L; #endif /* GFTIMER */ #endif /* NOICP */ } #endif /* NOXFER */ char * ttgtpn() { /* Get typical port name */ /* Ideally this routine would be implemented in each of the cku?io.* modules, but that requires changing the API definition. */ return( #ifdef OS2 #ifdef OS2ONLY "COM1" #else /* OS2ONLY */ "TAPI [ name ] or COM1" #endif /* OS2ONLY */ #else /* OS2 */ #ifdef VMS "TXA0:, TTA0:, or LTA0:" #else /* VMS */ #ifdef SOLARIS "/dev/cua/a" #else /* SOLARIS */ #ifdef HPUX10 "/dev/cua0p0" #else /* HPUX10 */ #ifdef HPUX "/dev/cua00" #else /* HPUX */ #ifdef __FreeBSD__ "/dev/cuaa0" #else /* __FreeBSD__ */ #ifdef __linux__ "/dev/ttyS0" #else /* __linux__ */ #ifdef BSD44 "/dev/tty00" #else /* BSD44 */ #ifdef OSK "/t1" #else /* OSK */ #ifdef QNX "/dev/ser1" #else /* QNX */ #ifdef QNX6 "/dev/ser1" #else /* QNX6 */ #ifdef UNIXWARE "/dev/term/00 or /dev/tty00" #else /* UNIXWARE */ #ifdef CK_SCOV5 "/dev/tty1A" #else /* CK_SCOV5 */ #ifdef CK_SCO32V4 "/dev/tty1A" #else /* CK_SCO32V4 */ #ifdef M_XENIX "/dev/tty1A" #else /* M_XENIX */ #ifdef AIXRS "/dev/tty0" #else /* AIXRS */ #ifdef DGUX "/dev/tty00" #else /* DGUX */ #ifdef datageneral "@con1" #else /* datageneral */ #ifdef IRIX "/dev/ttym0" #else /* IRIX */ #ifdef SUNOS4 "/dev/ttyh0" #else /* SUNOS4 */ #ifdef SV68R3V6 "/dev/scc0" #else /* SV68R3V6 */ #ifdef MOTSV88R4 "/dev/contty00" #else /* MOTSV88R4 */ #ifdef NEXT "/dev/cufa" #else #ifdef OSF "/dev/ttyd1" #else #ifdef SINIX "/dev/ttyc1" #else #ifdef UNIX "/dev/cua, /dev/acu, /dev/tty0, etc" #else /* UNIX */ "(sorry no example available)" #endif /* UNIX */ #endif /* SINIX */ #endif /* OSF */ #endif /* NEXT */ #endif /* MOTSV88R4 */ #endif /* SV68R3V6 */ #endif /* SUNOS4 */ #endif /* IRIX */ #endif /* datageneral */ #endif /* DGUX */ #endif /* AIX */ #endif /* M_XENIX */ #endif /* CK_SCO32V4 */ #endif /* CK_SCOV5 */ #endif /* UNIXWARE */ #endif /* QNX6 */ #endif /* QNX */ #endif /* OSK */ #endif /* BSD44 */ #endif /* __linux__ */ #endif /* __FreeBSD__ */ #endif /* HPUX */ #endif /* HPUX10 */ #endif /* SOLARIS */ #endif /* VMS */ #endif /* OS2 */ ); } /* C K _ E R R S T R -- Return message from most recent system error */ #ifdef CKROOT extern int ckrooterr; #endif /* CKROOT */ char * ck_errstr() { #ifdef USE_STRERROR #ifndef CK_ANSILIBS /* Should have been declared in */ _PROTOTYP( char * strerror, (int) ); #endif /* CK_ANSILIBS */ #ifdef CKROOT if (ckrooterr) return("Off limits"); #endif /* CKROOT */ debug(F101,"ck_errstr errno","",errno); return(strerror(errno)); #else /* !USE_STRERROR */ #ifdef VMS extern char * ckvmserrstr(unsigned long); #ifdef CKROOT if (ckrooterr) return("Off limits"); #endif /* CKROOT */ return(ckvmserrstr(0L)); #else /* !VMS */ #ifdef BSD44 #ifdef __386BSD__ #ifndef NDSYSERRLIST extern int sys_nerr; extern char *sys_errlist[]; #endif /* NDSYSERRLIST */ #else /* !__386BSD__ */ #ifndef __bsdi__ #ifndef NDSYSERRLIST extern int sys_nerr; extern const char *const sys_errlist[]; #endif /* NDSYSERRLIST */ #endif /* __bsdi__ */ #endif /* __386BSD__ */ #ifdef CKROOT if (ckrooterr) return("Off limits"); else #endif /* CKROOT */ if (errno >= sys_nerr) return("Error number out of range"); else return((char *) sys_errlist[errno]); #else /* !BSD44 */ #ifdef ATTSV #ifndef NDSYSERRLIST extern int sys_nerr; extern char *sys_errlist[]; #endif /* NDSYSERRLIST */ #ifdef CKROOT if (ckrooterr) return("Off limits"); else #endif /* CKROOT */ if (errno >= sys_nerr) return("Error number out of range"); else return((char *) sys_errlist[errno]); #else /* !ATTSV */ #ifdef BSD4 #ifndef NDSYSERRLIST extern int sys_nerr; extern char *sys_errlist[]; #endif /* NDSYSERRLIST */ #ifdef CKROOT if (ckrooterr) return("Off limits"); else #endif /* CKROOT */ if (errno >= sys_nerr) return("Error number out of range"); else return((char *) sys_errlist[errno]); #else #ifdef OS2 #ifndef NDSYSERRLIST extern char *sys_errlist[]; #endif /* NDSYSERRLIST */ #ifdef NT extern int_sys_nerr; #endif /* NT */ char *e; #ifdef CKROOT if (ckrooterr) return("Off limits"); #endif /* CKROOT */ e = (errno > -1 #ifdef NT && errno <= _sys_nerr #endif /* NT */ ) ? #ifdef NT (char *) sys_errlist[errno] #else /* NT */ /* I don't know how to get a CLIB error string in OS/2 */ strerror(errno) #endif /* NT */ : ""; return(e ? e : ""); #else /* OS2 */ return(""); #endif /* OS2 */ #endif /* BSD4 */ #endif /* ATTSV */ #endif /* BSD44 */ #endif /* VMS */ #endif /* USE_STRERROR */ } #ifdef PATTERNS /* Filename pattern recognition lists for automatic text/binary switching. These are somewhat passe after the addition of scanfile() (7.0). But with the addition of FTP [M]GET, they're back in style (8.0). Although, with FTP the lists need to be used in the reverse. With Kermit the list is used to imply the types of the local system. Whereas with FTP, the list must be used to imply the type of the remote system. Therefore, all platforms must now support all of the lists. */ char *txtpatterns[FTPATTERNS+1] = { NULL, NULL }; char *binpatterns[FTPATTERNS+1] = { NULL, NULL }; /* Default pattern lists for each platform... NOTE: In most cases we leave ".hlp", ".ini", and ".scr" alone; although they are traditionally text types, they are binary in Windows. So they are handled by the prevailing SET FILE TYPE, rather than automatically. Similarly for ".dat", ".inf", and so on. Also ".ps" since PostScript files are not always text. ".log" is omitted since logs can be text or binary, except in VMS they are usually text, etc etc. Later (Sep 2003): Add PostScript to binary patterns. */ static char *txtp[SYS_MAX][FTPATTERNS] = { /* UNKNOWN */ { NULL, NULL }, { /* UNIX */ "*.txt","*.c","*.h","*.r","*.w","*.cpp","*.cc","*.ksc","*.bwr","*.upd", "*.html","*.htm","*.mss","*.tex","*.nr","[Mm]akefile", "*.hex", "*.hqx", "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp","*.sh", "*.m4","*.perl","*.pl","*.pod","*.pm","*.awk","*.sno","*.spt","*.sed", "*.ksc","*.TXT", "*read.me", "*READ.ME", ".*", "*/.*", "*.mem","*.mac", NULL }, { /* WIN32 */ "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex", "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w", "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile", "*.mem","*.mac","*.cc","*.pl","*.pod","*.pm","*.m4",NULL }, { /* VMS */ "*.com","*.txt","*.c", "*.for","*.pas","*.rno","*.rnh","*.mar","*.bli", "*.hlp","*.mss","*.doc","*.bwr","*.cld","*.hex","*.bas","*.ini","*.log", "*.mms","*.opt","*.ksc","*.perl","*.pl","*.pod","*.pm","*.sno","*.spt", "*.mem",NULL }, { /* OS2 */ "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex", "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w", "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile", NULL }, { /* DOS */ "*.txt","*.ksc","*.htm","*.bat","*.cmd","*.jav","*.asm", "*.hex", "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile", NULL }, { /* TOPS-10 */ "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli", "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub", "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL }, { /* TOPS-20 */ "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli", "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub", "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL }, { /* STRATUS VOS */ "*.txt","*.ksc","*.htm","*.html","*.bat", "*.cmd","*.jav","*.asm","*.hex", "*.hqx","*.c", "*.h", "*.w", "*.java","*.bwr","*.upd","*.ttp","*.cm", "*.pl1","*.emacs", "read.me", "*.pl", "makefile", NULL }, { /* DG AOS/VS */ "*.txt", "*.c", "*.h", "*.w", "*.er", "*.bwr", "*.upd", "read.me", "*.cli", "*.ksc", NULL }, { /* OSK */ "*.c","*.cpp","*.h","*.a","*akefile", /* program sources */ "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp", "*.sh","*.perl","*.awk","*.sno","*.spt","*.sed", "*.txt","*.w", /* general text */ "*.ksc","*.bwr","*.upd", "*.html","*.htm","*.mss","*.tex","*.nr","*.hex", "*.hqx", "*.TXT", "*read.me", "*READ.ME", ".*", "*/.*", NULL } }; /* Note: .DOC added to (some) binary patterns June 1998... Microsoft wins. */ static char *binp[SYS_MAX][FTPATTERNS] = { { /* UNKNOWN */ NULL, NULL }, { /* UNIX */ "*.gz","*.Z","*.tgz","*.gif", "*.tar","*.zip","*.o","*.so","*.a","*.out", "*.exe", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.so.*", "*.class", "*.rpm", "*.bmp", "*.bz2", "*.BMP", "*.dll", "*.doc", "*.vxd", "*.dcx", "*.xl*", "*.lzh", "*.lhz", "*.au", "*.voc", "*.mpg", "*.mpeg","[wk]ermit", "*.ps", NULL }, { /* WIN32 */ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram", "*.class","*.cla","*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico", "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd", "*.pdf", "*.lzh", "*.vxd", "*.snd", "*.au", "* .voc", "*.mpg", "*.mpeg", "*.ps", NULL }, { /* VMS */ "*.exe","*.obj","*.bak","*.bin","*.adf","*.stb","*.mai","*.sys","*.dmp", "*.ps", "*.dat","*.par", NULL }, { /* OS2 */ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram", "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico", "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd", "*.pdf", "*.ps", "*.lzh", NULL }, { /* DOS */ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico", "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd", "*.pdf", "*.ps", "*.lzh", NULL }, { /* TOPS10 */ "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi", "*.ps", NULL }, { /* TOPS20 */ "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi", "*.ps", NULL }, { /* STRATUS VOS */ "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram", "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico", "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd", "*.pdf", "*.ps", "*.lzh", "*.pm", NULL }, { /* DG */ "*.ob", "*.pr", "*.dmp", "*.ps", NULL }, { /* OSK */ "*.gz","*.Z","*.z","*.tgz","*.lhz","*.tar", /* archivers */ "*.zip","*.ar","*.zoo","*.rpm","*.lzh", /* object files, libraries, executables */ "*.r","*.l","*.exe", "*.dll", "*.so.*", "*.class", /* images */ "*.gif", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.ps", "*.bmp", "*.bz2", "*.BMP","*.pcx", NULL } }; /* Set up default pattern lists so they can be freed and re-malloc'd. Each pattern list must terminated by a null element. */ VOID initpat() { int i; for (i = 0; i < FTPATTERNS; i++) { txtpatterns[i] = NULL; binpatterns[i] = NULL; } for (i = 0; i < FTPATTERNS; i++) { #ifdef UNIX makestr(&(txtpatterns[i]),txtp[SYS_UNIX][i]); #else /* UNIX */ #ifdef OS2 #ifdef NT makestr(&(txtpatterns[i]),txtp[SYS_WIN32][i]); #else /* NT */ makestr(&(txtpatterns[i]),txtp[SYS_OS2][i]); #endif /* NT */ #else /* OS2 */ #ifdef VMS makestr(&(txtpatterns[i]),txtp[SYS_VMS][i]); #else /* VMS */ #ifdef STRATUS makestr(&(txtpatterns[i]),txtp[SYS_VOS][i]); #else /* STRATUS */ #ifdef datageneral makestr(&(txtpatterns[i]),txtp[SYS_DG][i]); #else /* datageneral */ #ifdef OSK makestr(&(txtpatterns[i]),txtp[SYS_OSK][i]); #else /* OSK */ makestr(&(txtpatterns[i]),txtp[SYS_UNK][i]); #endif /* OSK */ #endif /* datageneral */ #endif /* STRATUS */ #endif /* VMS */ #endif /* OS2 */ #endif /* UNIX */ if (!txtp[i]) break; } for (i = 0; i < FTPATTERNS; i++) { #ifdef UNIX makestr(&(binpatterns[i]),binp[SYS_UNIX][i]); #else /* UNIX */ #ifdef OS2 #ifdef NT makestr(&(binpatterns[i]),binp[SYS_WIN32][i]); #else /* NT */ makestr(&(binpatterns[i]),binp[SYS_OS2][i]); #endif /* NT */ #else /* OS2 */ #ifdef VMS makestr(&(binpatterns[i]),binp[SYS_VMS][i]); #else /* VMS */ #ifdef STRATUS makestr(&(binpatterns[i]),binp[SYS_VOS][i]); #else /* STRATUS */ #ifdef datageneral makestr(&(binpatterns[i]),binp[SYS_DG][i]); #else /* datageneral */ #ifdef OSK makestr(&(binpatterns[i]),binp[SYS_OSK][i]); #else /* OSK */ makestr(&(binpatterns[i]),binp[SYS_UNK][i]); #endif /* OSK */ #endif /* datageneral */ #endif /* STRATUS */ #endif /* VMS */ #endif /* OS2 */ #endif /* UNIX */ if (!binp[i]) break; } } /* m a t c h n a m e -- Compare filename with text & binary name patterns. Returns: 0 if name matches a text pattern but not a binary pattern. 1 if name matches a binary pattern but not a text pattern. -1 if name matches no patterns. -2 if name matches a binary pattern and a text pattern. */ int #ifdef CK_ANSIC matchname( char * filename, int local, int os ) #else matchname(filename, local, os) char * filename; int local; int os; #endif /* CK_ANSIC */ { int rc = -1; /* Return code */ char * name, * p; #ifdef OS2ORUNIX char tmpbuf[CKMAXPATH+1]; #endif /* OS2ORUNIX */ name = filename ? filename : ""; /* Copy of original arg */ if (patterns && *name) { /* If PATTERNS ON... */ int i; #ifdef OS2ORUNIX if (ckmatch("*.~[1-9]*~",name,1,1)) { /* Name has backup suffix? */ int k; k = ckstrncpy(tmpbuf,name,CKMAXPATH+1); /* Yes, copy and strip */ for (i = k - 3; i > 4; i--) { if (tmpbuf[i] == '~' && tmpbuf[i-1] == '.') { tmpbuf[i-1] = NUL; break; } } name = tmpbuf; /* And point to stripped copy */ } #endif /* OS2ORUNIX */ zstrip(name,&p); /* Strip pathname too */ name = p; if (local) { if (txtpatterns[0]) { /* Search text patterns */ for (i = 0; i < FTPATTERNS && txtpatterns[i]; i++) { if (ckmatch(txtpatterns[i],name,filecase,1)) { rc = 0; break; } } } if (binpatterns[0]) { /* And search binary patterns */ for (i = 0; i < FTPATTERNS && binpatterns[i]; i++) { if (ckmatch(binpatterns[i],name,filecase,1)) { rc = (rc > -1) ? -2 : 1; break; } } } } else { if (os >= 0 && os < SYS_MAX) { if (txtp[os][0]) { for (i = 0; i < FTPATTERNS && txtp[os][i]; i++) { if (ckmatch(txtp[os][i],name,filecase,1)) { rc = 0; break; } } } if (binp[os][0]) { for (i = 0; i < FTPATTERNS && binp[os][i]; i++) { if (ckmatch(binp[os][i],name,filecase,1)) { rc = (rc > -1) ? -2 : 1; break; } } } } } } debug(F111,"matchname",name,rc); return(rc); } #endif /* PATTERNS */ #ifdef UNICODE #ifndef NOEVENMAX #define EVENMAX #endif /* NOEVENMAX */ #endif /* UNICODE */ /* S C A N F I L E -- Analyze a file's contents */ /* Call with: name: Pointer to name of existing file. flag: Pointer to int in which to return additional numeric data. Returns: -1 on failure (to open file or to read from it). Integer, 0..5, on success indicating file type: 0 = 7-bit text (flag = -1) 1 = 8-bit text (flag = 0: no C1 bytes; flag = 1: includes C1 bytes) 2 = UTF-8 text (flag = -1) 3 = UCS-2 text (flag = 0: big-endian; flag = 1: little-endian) 4 = Text (type unknown) 5 = binary (flag = -1) If UNICODE is defined: 1. If file begins with a valid BOM, it is believed. Otherwise we read the first 4K of the file (since it might be email with verbose headers) and analyze it: 2. If file contains only valid UTF-8 sequences, we call it UTF-8; otherwise: 3. If the file contains lots of alternate 0 bytes, we call it UCS-2, and set the polarity according to whether the preponderance of them are in even or odd positions; otherwise: 4. If EVENMAX is defined and the file contains lots of alternate bytes that are identical, even if they aren't zero, and the number of such bytes is at least four times the length of the maximum run of alternating identical bytes of the opposite polarity, we call it UCS-2; otherwise: 5. If the file contained no bytes with their 8th bits on and no controls other than CR, LF, HT, and FF, we call it ASCII; otherwise: 6. If it contains C0 control characters other than CR, LF, HT, and FF, we call it binary; otherwise: 7. We call it 8-bit text, character set unknown (could be Latin-1 or anything else). Note that malformed UTF-8 is not diagnosed as UTF-8. If UNICODE is not defined: 1. If the file contains C0 control characters other than CR, LF, HT, and FF, we call it binary; otherwise: 2. If the file contains any 8-bit bytes, we call it 8-bit text; otherwise: 3. We call it 7-bit text. In the non-Unicode case, UCS-2 is diagnosed as binary, but UTF-8 as 8-bit text. There is no significant speed difference between the Unicode and non-Unicode cases. */ int #ifdef CK_ANSIC scanfile( char * name, int * flag, int nscanfile ) #else scanfile(name,flag,nscanfile) char * name; int * flag, nscanfile; #endif /* CK_ANSIC */ { FILE * fp; /* File pointer */ unsigned char buf[SCANFILEBUF]; /* File data buffer for analysis */ int x, val = -1, count = 0; /* Workers */ int rc = -1; /* Return code */ int pv = -1; /* Pattern-match value */ int eof = 0; /* Flag for file EOF encountered */ int bytes = 0; /* Total byte count */ #ifdef UNICODE unsigned int c0, c1; /* First 2 file bytes (for BOM) */ #endif /* UNICODE */ extern int pipesend, filepeek; register int i; /* Loop control */ int readsize = 0; /* How much to read */ int eightbit = 0; /* Number of bytes with 8th bit on */ int c0controls = 0; /* C0 non-text control-char counter */ int c0noniso = 0; /* C0 non-ISO control-char counter */ int c1controls = 0; /* C1 control-character counter */ unsigned int c; /* Current character */ int runmax = 0; /* Longest run of 0 bytes */ int runzero = 0; /* Run of 0 bytes */ int pctzero = 0; /* Percentage of 0 bytes */ int txtcz = 0; #ifdef CK_CTRLZ extern int eofmethod; #endif /* CK_CTRLZ */ #ifdef UNICODE int notutf8 = 0; /* Nonzero if definitely not UTF-8 */ int utf8state = 0; /* UTF-8 recognizer state */ int oddzero = 0; /* Number of 0 bytes in odd postions */ int evenzero = 0; /* and in even positions */ int lfnul = 0; /* Number of sequences */ int crlf = 0; /* Number of sequences */ #else int notutf8 = 1; #endif /* UNICODE */ #ifdef COMMENT #ifdef EVENMAX int oddrun = 0, oddmax = 0, oddbyte = 0, oddmaxbyte = 0; int evenrun = 0, evenmax = 0, evenbyte = 0, evenmaxbyte = 0; #endif /* EVENMAX */ #endif /* COMMENT */ #ifndef NOXFER if (pipesend || calibrate || sndarray) /* Only for real files */ return(-1); #endif /* NOXFER */ debug(F111,"scanfile",name,nscanfile); #ifdef PATTERNS if (!filepeek) { pv = matchname(name,1,-1); if (pv < 0) rc = -1; else rc = (pv == 1) ? FT_BIN : FT_TEXT; debug(F111,"scanfile !filepeek result",name,rc); return(rc); } #endif /* PATTERNS */ #ifdef VMS /* We don't scan in VMS where text files have various record formats in */ /* which record headers contain seemingly non-text bytes. So the best */ /* we can do in VMS is tell whether the file is text or binary, period. */ { int b, x; b = binary; /* Save current binary setting */ if (zopeni(ZIFILE,name) > 0) { /* In VMS this sets binary */ x = binary; /* Get result */ zclose(ZIFILE); /* Close the file */ binary = b; /* Restore previous binary setting */ rc = x ? FT_BIN : FT_TEXT; val = 0; goto xscanfile; } } #endif /* VMS */ eof = 0; /* End-of-file reached indicator */ #ifdef OS2 fp = fopen(name, "rb"); /* Open the file in binary mode */ #else fp = fopen(name, "r"); #endif /* OS2 */ if (!fp) /* Failed? */ return(-1); while (1) { /* One or more gulps from file */ if (eof) { /* EOF from last time? */ debug(F111,"scanfile at EOF",name,bytes); if (runzero > runmax) runmax = runzero; break; } if (nscanfile < 0) { /* Reading whole file */ readsize = SCANFILEBUF; } else { /* Reading first nscanfilee bytes */ readsize = nscanfile - bytes; if (readsize < 1) break; if (readsize > SCANFILEBUF) readsize = SCANFILEBUF; } debug(F101,"scanfile readsize","",readsize); count = fread(buf,1,readsize,fp); /* Read a buffer */ if (count == EOF || count == 0) { debug(F111,"scanfile EOF",name,count); break; } debug(F111,"scanfile buffer ok",name,count); if (bytes == 0 && count > 8) { /* PDF files can look like text in the beginning. */ if (!ckstrcmp((char *)buf,"%PDF-1.",7,1)) { if (isdigit(buf[7])) { if (buf[8] == '\015' || count > 9 && buf[8] == SP && buf[9] == '\015') { #ifdef DEBUG buf[8] = NUL; debug(F110,"scanfile PDF",buf,0); #endif /* DEBUG */ binary = 1; /* But they are binary. */ break; } } } else if (!ckstrcmp((char *)buf,"%!PS-Ado",8,1)) { /* Ditto for PostScript */ #ifdef DEBUG int i; for (i = 8; i < count; i++) { if (buf[i] < '!') { buf[i] = NUL; break; } } debug(F110,"scanfile PostScript",buf,0); #endif /* DEBUG */ binary = 1; break; #ifndef NOPCLSCAN } else if (!ckstrcmp((char *)buf,") HP-PCL",8,1)) { /* HP PCL printer language */ #ifdef DEBUG int i; for (i = 8; i < count; i++) { if (buf[i] < '!') { buf[i] = NUL; break; } } debug(F110,"scanfile PCL",buf,0); #endif /* DEBUG */ binary = 1; break; } #endif /* NOPCLSCAN */ #ifndef NOPJLSCAN else if (buf[0] == '\033' && (buf[1] == 'E' || buf[1] == '%')) { /* Ditto for PJL Job printer header */ #ifdef DEBUG int i; for (i = 2; i < count; i++) { if (buf[i] < '!') { buf[i] = NUL; break; } } debug(F110,"scanfile PJL Job printer header",buf,0); #endif /* DEBUG */ binary = 1; break; #endif /* NOPJLSCAN */ } } #ifdef UNICODE if (bytes == 0 && count > 1) { int incl_cnt = 0; /* First look for BOM */ c0 = (unsigned)((unsigned)buf[0]&0xFF); /* First file byte */ c1 = (unsigned)((unsigned)buf[1]&0xFF); /* Second byte */ if (c0 == 0xFE && c1 == 0xFF) { /* UCS-2 BE */ rc = FT_UCS2; val = 0; debug(F111,"scanfile UCS2 BOM BE",ckitoa(val),rc); incl_cnt++; } else if (c0 == 0xFF && c1 == 0xFE) { /* UCS-2 LE */ rc = FT_UCS2; val = 1; debug(F111,"scanfile UCS2 BOM LE",ckitoa(val),rc); incl_cnt++; } else if (count > 2) if (c0 == 0xEF && c1 == 0xBB && (unsigned)((unsigned)buf[2]&0xFF) == 0xBF) { rc = FT_UTF8; debug(F111,"scanfile UTF8 BOM",ckitoa(val),rc); incl_cnt++; } if (incl_cnt) { /* Have BOM */ bytes += count; goto xscanfile; } } #endif /* UNICODE */ bytes += count; /* Count bytes read */ eof = feof(fp); /* Flag for at EOF */ for (i = 0; i < count; i++) { /* For each byte... */ c = (unsigned)buf[i]; /* For ease of reference */ if (!c) { /* Zero byte? */ #ifdef EVENMAX if (i&1) /* In odd position */ oddzero++; else evenzero++; /* In even position */ #endif /* EVENMAX */ runzero++; } else { /* Not a zero byte */ if (runzero > runmax) runmax = runzero; if (runmax > 2) /* That's all we need to be certain */ break; /* it's a binary file. */ runzero = 0; } #ifdef COMMENT #ifdef EVENMAX /* This is to catch UCS-2 with a non-ASCII, non-Latin-1 repertoire */ if (i > 1) { /* Look for runs of alternating chars */ if (i&1) { if (c == buf[i-2]) { /* In odd positions */ oddrun++; oddbyte = c; } else { oddmax = oddrun; oddmaxbyte = oddbyte; } } else { /* and even positions */ if (c == buf[i-2]) { evenrun++; evenbyte = c; } else { evenmax = evenrun; evenmaxbyte = evenbyte; } } } #endif /* EVENMAX */ #endif /* COMMENT */ if ((c & 0x80) == 0) { /* We have a 7-bit byte */ #ifdef UNICODE if (i > 0 && c == 10) { /* Linefeed */ if (buf[i-1] == 0) lfnul++; /* Preceded by NUL */ else if (buf[i-1] == 13) crlf++; /* or by CR... */ } #endif /* UNICODE */ if (c < ' ') { /* Check for CO controls */ if (c != LF && c != CK_CR && c != HT && c != FF) { c0controls++; if (c != ESC && c != SO && c != SI) c0noniso++; } if (c == '\032' /* Ctrl-Z */ #ifdef COMMENT && eof && (i >= count - 2) #endif /* COMMENT */ ) { c0controls--; c0noniso--; #ifdef CK_CTRLZ if (eofmethod == XYEOF_Z && txtcz == 0) { if (c0controls == 0) /* All text prior to Ctrl-Z */ txtcz = 1; } #endif /* CK_CTRLZ */ } } #ifdef UNICODE if (!notutf8 && utf8state) { /* In UTF-8 sequence? */ utf8state = 0; debug(F000,"scanfile","7-bit byte in UTF8 sequence",c); notutf8++; /* Then it's not UTF-8 */ continue; } #endif /* UNICODE */ } else { /* We have an 8-bit byte */ eightbit++; /* Count it */ if (c >= 0x80 && c < 0xA0) /* Check for C1 controls */ c1controls++; #ifdef UNICODE if (!notutf8) { /* If it might still be UTF8... */ switch (utf8state) { /* Enter the UTF-8 state machine */ case 0: /* First byte... */ if ((c & 0xE0) == 0xC0) { /* Tells number of */ utf8state = 1; /* subsequent bytes */ } else if ((c & 0xF0) == 0xE0) { utf8state = 2; } else if ((c & 0xF8) == 0xF0) { utf8state = 3; } else { notutf8++; } break; case 1: /* Subsequent byte */ case 2: case 3: if ((c & 0xC0) != 0x80) { /* Must start with 10 */ debug(F000,"scanfile", "bad byte in UTF8 sequence",c); notutf8++; break; } utf8state--; /* Good, one less in this sequence */ break; default: /* Shouldn't happen */ debug(F111,"scanfile","bad UTF8 state",utf8state); notutf8++; } } #endif /* UNICODE */ } } } fclose(fp); /* Close the file */ debug(F101,"scanfile bytes","",bytes); if (bytes == 0) /* If nothing was read */ return(-1); /* we're done. */ #ifdef EVENMAX /* In case we had a run that never broke... */ #ifdef COMMENT if (oddmax == 0) { oddmax = oddrun; oddmaxbyte = oddbyte; } if (evenmax == 0) { evenmax = evenrun; evenmaxbyte = evenbyte; } #endif /* COMMENT */ if (runmax == 0) { runmax = runzero; } #endif /* EVENMAX */ #ifdef UNICODE if (bytes > 100) /* Bytes is not 0 */ pctzero = (evenzero + oddzero) / (bytes / 100); else pctzero = ((evenzero + oddzero) * 100) / bytes; #endif /* UNICODE */ #ifdef DEBUG if (deblog) { /* If debugging, dump statistics */ debug(F101,"scanfile c0controls ","",c0controls); debug(F101,"scanfile c0noniso ","",c0noniso); debug(F101,"scanfile c1controls ","",c1controls); debug(F101,"scanfile eightbit ","",eightbit); #ifdef UNICODE debug(F101,"scanfile crlf ","",crlf); debug(F101,"scanfile lfnul ","",lfnul); debug(F101,"scanfile notutf8 ","",notutf8); debug(F101,"scanfile evenzero ","",evenzero); debug(F101,"scanfile oddzero ","",oddzero); debug(F101,"scanfile even/odd ","",(evenzero / (oddzero + 1))); debug(F101,"scanfile odd/even ","",(oddzero / (evenzero + 1))); debug(F101,"scanfile pctzero ","",pctzero); #endif /* UNICODE */ #ifdef COMMENT #ifdef EVENMAX debug(F101,"scanfile oddmax ","",oddmax); debug(F101,"scanfile oddmaxbyte ","",oddmaxbyte); debug(F101,"scanfile evenmax ","",evenmax); debug(F101,"scanfile evenmaxbyte","",evenmaxbyte); #endif /* EVENMAX */ #endif /* COMMENT */ debug(F101,"scanfile runmax ","",runmax); } #endif /* DEBUG */ #ifdef UNICODE x = eightbit ? bytes / 20 : bytes / 4; /* For UCS-2... */ if (runmax > 2) { /* File has run of more than 2 NULs */ debug(F100,"scanfile BIN runmax","",0); rc = FT_BIN; /* so it can't be any kind of text. */ goto xscanfile; } else if (rc == FT_UCS2 || (rc == FT_UTF8 && runmax == 0)) { goto xscanfile; /* File starts with a BOM */ } else if (eightbit > 0 && !notutf8) { /* File has 8-bit data */ if (runmax > 0) { /* and runs of NULs */ debug(F100,"scanfile BIN (nnUTF8) runmax","",0); rc = FT_BIN; /* UTF-8 doesn't have NULs */ } else { /* No NULs */ debug(F100,"scanfile UTF8 (nnUTF8 + runmax == 0)","",0); rc = FT_UTF8; /* and not not UTF-8, so is UTF-8 */ } goto xscanfile; } /* For UCS-2 detection, see if the text contains lines delimited by ASCII controls and containing spaces, ASCII digits, or other ASCII characters, thus forcing the presence of a certain percentage of zero bytes. For this purpose require 20% zero bytes, with at least six times as many in even (odd) positions as in odd (even) positions. */ if ((evenzero >= x && oddzero == 0) || ((((evenzero / (oddzero + 1)) > 6) && (pctzero > 20)) && (crlf == 0) && (lfnul > 1)) ) { debug(F100,"scanfile UCS2 noBOM BE (even/oddzero)","",0); rc = FT_UCS2; val = 0; } else if ((evenzero == 0 && oddzero >= x) || ((((oddzero / (evenzero + 1)) > 6) && (pctzero > 20)) && (crlf == 0) && (lfnul > 1)) ) { debug(F100,"scanfile UCS2 noBOM LE (even/oddzero)","",0); rc = FT_UCS2; val = 1; #ifdef COMMENT #ifdef EVENMAX /* If the tests above fail, we still might have UCS-2 if there are significant runs of identical bytes in alternating positions, but only if it also has unusual C0 controls (otherwise we'd pick up hex files here). NOTE: We don't actually do this -- EVENMAX is not defined (see comments above at first occurrence of EVENMAX). */ } else if (c0noniso && evenmax > bytes / 4) { debug(F100,"scanfile UCS2 BE (evenmax)","",0); rc = FT_UCS2; val = 0; } else if (c0noniso && oddmax > bytes / 4) { debug(F100,"scanfile UCS2 LE (evenmax)","",0); rc = FT_UCS2; val = 1; #endif /* EVENMAX */ #endif /* COMMENT */ } /* It seems to be UCS-2 but let's be more certain since there is no BOM... If the number of 7- and 8-bit characters is approximately equal, it might be a compressed file. In this case we decide based on the name. */ if (rc == FT_UCS2) { if (eightbit > 0) { int j, k; j = (c1controls * 100) / (c0controls + 1); debug(F101,"scanfile c1/c0 ","",j); k = (bytes * 100) / eightbit; debug(F101,"scanfile pct 8bit ","",k); if (k > 40 && k < 60 && j > 60) { if (ckmatch("{*.Z,*.gz,*.zip,*.ZIP}",name,1,1)) { debug(F110,"scanfile 8-bit BIN compressed",name,0); rc = FT_BIN; goto xscanfile; } } } /* Small file - not enough evidence unless ... */ if (bytes < 100) { if (oddzero != 0 && evenzero != 0) { debug(F100,"scanfile small UCS2 doubtful","",0); rc = FT_BIN; goto xscanfile; } else if (oddzero == 0 && evenzero == 0) { rc = eightbit ? FT_8BIT : FT_7BIT; } } goto xscanfile; /* Seems to be UCS-2 */ } /* If none of the above, it's probably not Unicode. */ if (!eightbit) { /* It's 7-bit */ if (c0controls) { /* This would be strange */ if ((c0noniso > 0) && (txtcz == 0)) { debug(F100,"scanfile 7-bit BIN (c0coniso)","",0); rc = FT_BIN; } else { debug(F100,"scanfile 7-bit ISO2022 TEXT (no c0noniso)","",0); rc = FT_7BIT; } } else { /* 7-bit text */ debug(F100,"scanfile 7-bit TEXT (no c0controls)","",0); rc = FT_7BIT; } } else if (!c0noniso || txtcz) { /* 8-bit text */ debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0); rc = FT_8BIT; val = c1controls ? 1 : 0; } else { /* 8-bit binary */ debug(F100,"scanfile 8-bit BIN (c0noniso)","",0); rc = FT_BIN; } #else /* !UNICODE */ if (c0noniso) { debug(F100,"scanfile 8-bit BIN (c0noniso)","",0); rc = FT_BIN; } else if (eightbit) { debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0); rc = FT_8BIT; val = c1controls ? 1 : 0; } else { debug(F100,"scanfile 7-bit TEXT (no c0noniso)","",0); rc = FT_7BIT; } #endif /* UNICODE */ xscanfile: if (flag) *flag = val; debug(F101,"scanfile result ","",rc); return(rc); } /* scanstring - like scan file but for a string. This is just a quick butchery of scanfile without thinking too much. */ int #ifdef CK_ANSIC scanstring( char * s ) #else scanstring(s) char * s; #endif /* CK_ANSIC */ { int x, val = -1, count = 0; /* Workers */ int rc = -1; /* Return code */ int bytes = 0; /* Total byte count */ #ifdef UNICODE unsigned int c0, c1; /* First 2 file bytes (for BOM) */ #endif /* UNICODE */ extern int pipesend, filepeek; register int i; /* Loop control */ int eightbit = 0; /* Number of bytes with 8th bit on */ int c0controls = 0; /* C0 non-text control-char counter */ int c0noniso = 0; /* C0 non-ISO control-char counter */ int c1controls = 0; /* C1 control-character counter */ unsigned int c; /* Current character */ int runmax = 0; /* Longest run of 0 bytes */ int pctzero = 0; /* Percentage of 0 bytes */ int txtcz = 0; #ifdef UNICODE int notutf8 = 0; /* Nonzero if definitely not UTF-8 */ int utf8state = 0; /* UTF-8 recognizer state */ int oddzero = 0; /* Number of 0 bytes in odd postions */ int evenzero = 0; /* and in even positions */ int lfnul = 0; /* Number of sequences */ int crlf = 0; /* Number of sequences */ #else int notutf8 = 1; #endif /* UNICODE */ char * buf = s; if (!s) s = ""; count = strlen(s); #ifdef UNICODE if (bytes == 0 && count > 1) { int incl_cnt = 0; /* First look for BOM */ c0 = (unsigned)((unsigned)buf[0]&0xFF); /* First file byte */ c1 = (unsigned)((unsigned)buf[1]&0xFF); /* Second byte */ if (c0 == 0xFE && c1 == 0xFF) { /* UCS-2 BE */ rc = FT_UCS2; val = 0; debug(F111,"scanstring UCS2 BOM BE",ckitoa(val),rc); incl_cnt++; } else if (c0 == 0xFF && c1 == 0xFE) { /* UCS-2 LE */ rc = FT_UCS2; val = 1; debug(F111,"scanstring UCS2 BOM LE",ckitoa(val),rc); incl_cnt++; } else if (count > 2) if (c0 == 0xEF && c1 == 0xBB && (unsigned)((unsigned)buf[2]&0xFF) == 0xBF) { rc = FT_UTF8; debug(F111,"scanstring UTF8 BOM",ckitoa(val),rc); incl_cnt++; } if (incl_cnt) { /* Have BOM */ bytes += count; goto xscanstring; } } #endif /* UNICODE */ bytes += count; /* Count bytes read */ for (i = 0; i < count; i++) { /* For each byte... */ c = (unsigned)buf[i]; /* For ease of reference */ if (!c) { /* Zero byte? */ goto xscanstring; /* Null terminated string */ } if ((c & 0x80) == 0) { /* We have a 7-bit byte */ #ifdef UNICODE if (i > 0 && c == 10) { /* Linefeed */ if (buf[i-1] == 0) lfnul++; /* Preceded by NUL */ else if (buf[i-1] == 13) crlf++; /* or by CR... */ } #endif /* UNICODE */ if (c < ' ') { /* Check for CO controls */ if (c != LF && c != CK_CR && c != HT && c != FF) { c0controls++; if (c != ESC && c != SO && c != SI) c0noniso++; } if (c == '\032') { /* Ctrl-Z */ c0controls--; c0noniso--; } } #ifdef UNICODE if (!notutf8 && utf8state) { /* In UTF-8 sequence? */ utf8state = 0; debug(F000,"scanstring","7-bit byte in UTF8 sequence",c); notutf8++; /* Then it's not UTF-8 */ continue; } #endif /* UNICODE */ } else { /* We have an 8-bit byte */ eightbit++; /* Count it */ if (c >= 0x80 && c < 0xA0) /* Check for C1 controls */ c1controls++; #ifdef UNICODE if (!notutf8) { /* If it might still be UTF8... */ switch (utf8state) { /* Enter the UTF-8 state machine */ case 0: /* First byte... */ if ((c & 0xE0) == 0xC0) { /* Tells number of */ utf8state = 1; /* subsequent bytes */ } else if ((c & 0xF0) == 0xE0) { utf8state = 2; } else if ((c & 0xF8) == 0xF0) { utf8state = 3; } else { notutf8++; } break; case 1: /* Subsequent byte */ case 2: case 3: if ((c & 0xC0) != 0x80) { /* Must start with 10 */ debug(F000,"scanstring", "bad byte in UTF8 sequence",c); notutf8++; break; } utf8state--; /* Good, one less in this sequence */ break; default: /* Shouldn't happen */ debug(F111,"scanstring","bad UTF8 state",utf8state); notutf8++; } } #endif /* UNICODE */ } } if (bytes == 0) /* If nothing was read */ return(-1); /* we're done. */ #ifdef UNICODE if (bytes > 100) /* Bytes is not 0 */ pctzero = (evenzero + oddzero) / (bytes / 100); else pctzero = ((evenzero + oddzero) * 100) / bytes; #endif /* UNICODE */ #ifdef UNICODE x = eightbit ? bytes / 20 : bytes / 4; /* For UCS-2... */ if (runmax > 2) { /* File has run of more than 2 NULs */ debug(F100,"scanstring BIN runmax","",0); rc = FT_BIN; /* so it can't be any kind of text. */ goto xscanstring; } else if (rc == FT_UCS2 || (rc == FT_UTF8 && runmax == 0)) { goto xscanstring; /* File starts with a BOM */ } else if (eightbit > 0 && !notutf8) { /* File has 8-bit data */ if (runmax > 0) { /* and runs of NULs */ debug(F100,"scanstring BIN (nnUTF8) runmax","",0); rc = FT_BIN; /* UTF-8 doesn't have NULs */ } else { /* No NULs */ debug(F100,"scanstring UTF8 (nnUTF8 + runmax == 0)","",0); rc = FT_UTF8; /* and not not UTF-8, so is UTF-8 */ } goto xscanstring; } /* It seems to be UCS-2 but let's be more certain since there is no BOM... If the number of 7- and 8-bit characters is approximately equal, it might be a compressed file. In this case we decide based on the name. */ if (rc == FT_UCS2) { if (bytes < 100) { if (oddzero != 0 && evenzero != 0) { debug(F100,"scanstring small UCS2 doubtful","",0); rc = FT_BIN; goto xscanstring; } else if (oddzero == 0 && evenzero == 0) { rc = eightbit ? FT_8BIT : FT_7BIT; } } goto xscanstring; /* Seems to be UCS-2 */ } /* If none of the above, it's probably not Unicode. */ if (!eightbit) { /* It's 7-bit */ if (c0controls) { /* This would be strange */ if ((c0noniso > 0) && (txtcz == 0)) { debug(F100,"scanstring 7-bit BIN (c0coniso)","",0); rc = FT_BIN; } else { debug(F100,"scanstring 7-bit ISO2022 TEXT (no c0noniso)","",0); rc = FT_7BIT; } } else { /* 7-bit text */ debug(F100,"scanstring 7-bit TEXT (no c0controls)","",0); rc = FT_7BIT; } } else if (!c0noniso || txtcz) { /* 8-bit text */ debug(F100,"scanstring 8-bit TEXT (no c0noniso)","",0); rc = FT_8BIT; val = c1controls ? 1 : 0; } else { /* 8-bit binary */ debug(F100,"scanstring 8-bit BIN (c0noniso)","",0); rc = FT_BIN; } #else /* !UNICODE */ if (c0noniso) { debug(F100,"scanstring 8-bit BIN (c0noniso)","",0); rc = FT_BIN; } else if (eightbit) { debug(F100,"scanstring 8-bit TEXT (no c0noniso)","",0); rc = FT_8BIT; val = c1controls ? 1 : 0; } else { debug(F100,"scanstring 7-bit TEXT (no c0noniso)","",0); rc = FT_7BIT; } #endif /* UNICODE */ xscanstring: debug(F101,"scanstring result ","",rc); return(rc); } /* F I L E S E L E C T -- Select this file for sending */ int #ifdef CK_ANSIC fileselect( char *f, char *sa, char *sb, char *sna, char *snb, CK_OFF_T minsiz, CK_OFF_T maxsiz, int nbu, int nxlist, char ** xlist ) #else fileselect(f,sa,sb,sna,snb,minsiz,maxsiz,nbu,nxlist,xlist) char *f,*sa,*sb,*sna,*snb; CK_OFF_T minsiz,maxsiz; int nbu,nxlist; char ** xlist; #endif /* CK_ANSIC */ /* fileselect */ { char *fdate; int n; CK_OFF_T z; debug(F111,"fileselect minsiz",ckfstoa(minsiz),minsiz); debug(F111,"fileselect maxsiz",ckfstoa(maxsiz),maxsiz); debug(F111,"fileselect (CK_OFF_T)-1",ckfstoa((CK_OFF_T)-1),(CK_OFF_T)-1); if (!sa) sa = ""; if (!sb) sb = ""; if (!sna) sna = ""; if (!snb) snb = ""; #ifdef CKSYMLINK #ifndef NOICP #ifndef NOXFER if (nolinks) { CK_OFF_T zz; zz = zgetfs(f); debug(F111,"fileselect NOLINKS zgetfs",f,zz); if (zz < (CK_OFF_T)0) return(0); debug(F111,"fileselect NOLINKS zgfs_link",f,zgfs_link); if (zgfs_link) return(0); } #endif /* NOXFER */ #endif /* NOICP */ #endif /* CKSYMLINK */ debug(F110,"fileselect",f,0); if (*sa || *sb || *sna || *snb) { fdate = zfcdat(f); /* Date/time of this file */ if (!fdate) fdate = ""; n = strlen(fdate); debug(F111,"fileselect fdate",fdate,n); if (n != 17) /* Failed to get it */ return(1); /* /AFTER: */ if (sa[0] && (strcmp(fdate,(char *)sa) <= 0)) { debug(F110,"fileselect sa",sa,0); /* tlog(F110,"Skipping (too old)",f,0); */ return(0); } /* /BEFORE: */ if (sb[0] && (strcmp(fdate,(char *)sb) >= 0)) { debug(F110,"fileselect sb",sb,0); /* tlog(F110,"Skipping (too new)",f,0); */ return(0); } /* /NOT-AFTER: */ if (sna[0] && (strcmp(fdate,(char *)sna) > 0)) { debug(F110,"fileselect sna",sna,0); /* tlog(F110,"Skipping (too new)",f,0); */ return(0); } /* /NOT-BEFORE: */ if (snb[0] && (strcmp(fdate,(char *)snb) < 0)) { debug(F110,"fileselect snb",snb,0); /* tlog(F110,"Skipping (too old)",f,0); */ return(0); } } /* Smaller or larger */ if (minsiz > (CK_OFF_T)-1 || maxsiz > (CK_OFF_T)-1) { z = zchki(f); /* Get size */ debug(F101,"fileselect filesize","",z); if (z < (CK_OFF_T)0) return(1); if ((minsiz > (CK_OFF_T)-1) && (z >= minsiz)) { debug(F111,"fileselect minsiz skipping",f,minsiz); /* tlog(F111,"Skipping (too big)",f,z); */ return(0); } if ((maxsiz > (CK_OFF_T)-1) && (z <= maxsiz)) { debug(F111,"fileselect maxsiz skipping",f,maxsiz); /* tlog(F110,"Skipping (too small)",f,0); */ return(0); } } if (nbu) { /* Skipping backup files? */ if (ckmatch( #ifdef CKREGEX "*.~[0-9]*~" /* Not perfect but close enough. */ #else "*.~*~" /* Less close. */ #endif /* CKREGEX */ ,f,filecase,1)) { debug(F110,"fileselect skipping backup",f,0); return(0); } } for (n = 0; xlist && n < nxlist; n++) { if (!xlist[n]) { debug(F101,"fileselect xlist empty",0,n); break; } if (ckmatch(xlist[n],f,filecase,1)) { debug(F111,"fileselect xlist",xlist[n],n); debug(F110,"fileselect skipping",f,0); return(0); } } if (xfiletype > -1) { n = scanfile(f,NULL,nscanfile); if (n < 0) { n = binary ? 1 : 0; } else { n = (n == FT_BIN) ? 1 : 0; } if (n != xfiletype) return(0); } debug(F110,"fileselect selecting",f,0); return(1); } #ifdef TCPSOCKET #ifdef NT extern int WSASafeToCancel; #endif /* NT */ #endif /* TCPSOCKET */ VOID setflow() { extern int flow, autoflow, mdmtyp, cxtype, cxflow[]; #ifndef NODIAL extern int dialfc; extern long dialcapas; extern MDMINF * modemp[]; MDMINF * p = NULL; long bits = 0; #endif /* NODIAL */ debug(F101,"setflow autoflow","",autoflow); /* #ifdef COMMENT */ /* WHY WAS THIS COMMENTED OUT? */ if (!autoflow) /* Only if FLOW is AUTO */ return; /* #endif */ /* COMMENT */ debug(F101,"setflow local","",local); debug(F101,"setflow network","",network); debug(F101,"setflow cxtype","",cxtype); #ifdef TN_COMPORT if (network && istncomport()) { flow = cxflow[CXT_MODEM]; debug(F101,"setflow TN_COMPORT flow","",flow); return; } #endif /* TN_COMPORT */ if (network || !local || cxtype == CXT_DIRECT) { flow = cxflow[cxtype]; /* Set appropriate flow control */ debug(F101,"setflow flow","",flow); return; } if (cxtype != CXT_MODEM) /* Connection type should be modem */ return; #ifndef NODIAL bits = dialcapas; /* Capability bits */ if (!bits) { /* No bits? */ p = modemp[mdmtyp]; /* Look in modem info structure */ if (p) bits = p->capas; } if (dialfc == FLO_AUTO) { /* If DIAL flow is AUTO */ #ifdef CK_RTSCTS /* If we can do RTS/CTS flow control */ if (bits & CKD_HW) /* and modem can do it too */ flow = FLO_RTSC; /* then switch to RTS/CTS */ else /* otherwise */ flow = FLO_XONX; /* use Xon/Xoff. */ #else #ifndef NEXT #ifndef IRIX flow = FLO_XONX; /* Use Xon/Xoff. */ #endif /* IRIX */ #endif /* NEXT */ #endif /* CK_RTSCTS */ } #endif /* NODIAL */ debug(F101,"setflow modem flow","",flow); return; } #ifndef NOLOCAL #ifdef CK_TRIGGER /* A U T O E X I T C H K -- Check for CONNECT-mode trigger string */ /* Returns -1 if trigger not found, or else the trigger index, 0 or greater. (Replace with fancier and more efficient matcher later...) NOTE: to prevent unnecessary function call overhead, call this way: x = tt_trigger[0] ? autoexitchk(c) : -1; */ int #ifdef CK_ANSIC autoexitchk(CHAR c) #else autoexitchk(c) CHAR c; #endif /* CK_ANSIC */ /* autoexitchk */ { extern CHAR * tt_trmatch[]; extern char * tt_trigger[]; int i; for (i = 0; i < TRIGGERS; i++) { if (!tt_trigger[i]) { /* No more triggers in list */ break; } else if (*tt_trigger[i]) { if (!tt_trmatch[i]) /* Just starting? */ tt_trmatch[i] = (CHAR *)tt_trigger[i]; /* Set match pointer */ if (c == *tt_trmatch[i]) { /* Compare this character */ tt_trmatch[i]++; /* It matches */ if (!*tt_trmatch[i]) { /* End of match string? */ tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Yes, rewind, */ debug(F101,"autoexitchk",tt_trigger[i],i); /* log, */ return(i); /* and return success */ } } else /* No match */ tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Rewind match string */ } /* and go on the next match string */ } return(-1); /* No match found */ } #endif /* CK_TRIGGER */ #ifndef NOSHOW /* S H O M D M -- Show modem signals */ VOID shomdm() { /* Note use of "\r\n" to make sure this report prints right, even when called during CONNECT mode. */ int y; y = ttgmdm(); switch (y) { case -3: printf( "Modem signals unavailable in this version of Kermit\r\n"); break; case -2: printf("No modem control for this device\r\n"); break; case -1: printf("Modem signals unavailable\r\n"); break; default: #ifndef MAC printf( " Carrier Detect (CD): %s\r\n",(y & BM_DCD) ? "On": "Off"); printf( " Dataset Ready (DSR): %s\r\n",(y & BM_DSR) ? "On": "Off"); #endif /* MAC */ printf( " Clear To Send (CTS): %s\r\n",(y & BM_CTS) ? "On": "Off"); #ifndef STRATUS #ifndef MAC printf( " Ring Indicator (RI): %s\r\n",(y & BM_RNG) ? "On": "Off"); #endif /* MAC */ printf( " Data Terminal Ready (DTR): %s\r\n", #ifdef NT "(unknown)" #else /* NT */ (y & BM_DTR) ? "On": "Off" #endif /* NT */ ); #ifndef MAC printf( " Request To Send (RTS): %s\r\n", #ifdef NT "(unknown)" #else /* NT */ (y & BM_RTS) ? "On": "Off" #endif /* NT */ ); #endif /* MAC */ #endif /* STRATUS */ } #ifdef BETADEBUG #ifdef CK_TAPI if (tttapi && !tapipass) { LPDEVCFG lpDevCfg = NULL; LPCOMMCONFIG lpCommConfig = NULL; LPMODEMSETTINGS lpModemSettings = NULL; DCB * lpDCB = NULL; if (cktapiGetModemSettings(&lpDevCfg,&lpModemSettings, &lpCommConfig,&lpDCB)) { printf("\n"); cktapiDisplayModemSettings(lpDevCfg,lpModemSettings, lpCommConfig,lpDCB); } } #endif /* CK_TAPI */ #endif /* BETADEBUG */ } #endif /* NOSHOW */ #endif /* NOLOCAL */ #ifndef NOXFER /* S D E B U -- Record spar results in debugging log */ VOID #ifdef CK_ANSIC sdebu( int len ) #else sdebu(len) int len; #endif /* CK_ANSIC */ { debug(F111,"spar: data",(char *) rdatap,len); debug(F101," spsiz ","", spsiz); debug(F101," timint","",timint); debug(F101," npad ","", npad); debug(F101," padch ","", padch); debug(F101," seol ","", seol); debug(F101," ctlq ","", ctlq); debug(F101," ebq ","", ebq); debug(F101," ebqflg","",ebqflg); debug(F101," bctr ","", bctr); debug(F101," rptq ","", rptq); debug(F101," rptflg","",rptflg); debug(F101," lscapu","",lscapu); debug(F101," atcapu","",atcapu); debug(F101," lpcapu","",lpcapu); debug(F101," swcapu","",swcapu); debug(F101," wslotn","", wslotn); debug(F101," whatru","", whatru); } /* R D E B U -- Debugging display of rpar() values */ VOID #ifdef CK_ANSIC rdebu( CHAR *d, int len ) #else rdebu(d,len) CHAR *d; int len; #endif /* CK_ANSIC */ { debug(F111,"rpar: data",d,len); debug(F101," rpsiz ","", xunchar(d[0])); debug(F101," rtimo ","", rtimo); debug(F101," mypadn","",mypadn); debug(F101," mypadc","",mypadc); debug(F101," eol ","", eol); debug(F101," ctlq ","", ctlq); debug(F101," sq ","", sq); debug(F101," ebq ","", ebq); debug(F101," ebqflg","",ebqflg); debug(F101," bctr ","", bctr); debug(F101," rptq ","", d[8]); debug(F101," rptflg","",rptflg); debug(F101," capas ","", capas); debug(F101," bits ","",d[capas]); debug(F101," lscapu","",lscapu); debug(F101," atcapu","",atcapu); debug(F101," lpcapu","",lpcapu); debug(F101," swcapu","",swcapu); debug(F101," wslotr","", wslotr); debug(F101," rpsiz(extended)","",rpsiz); } #ifdef COMMENT /* C H K E R R -- Decide whether to exit upon a protocol error */ VOID chkerr() { if (backgrd && !server) fatal("Protocol error"); } #endif /* COMMENT */ #endif /* NOXFER */ /* F A T A L -- Fatal error message */ VOID #ifdef CK_ANSIC fatal( char *msg ) #else fatal(msg) char *msg; #endif /* CK_ANSIC */ { extern int initflg; static int initing = 0; if (!msg) msg = ""; debug(F111,"fatal",msg,initflg); if (!initflg) { /* If called from prescan */ if (initing) /* or called from sysinit() */ exit(253); initing = 1; sysinit(); } debug(F111,"fatal",msg,xitsta); tlog(F110,"Fatal:",msg,0L); #ifdef VMS if (strncmp(msg,"%CKERMIT",8)) conol("%CKERMIT-E-FATAL, "); conoll(msg); #else /* !VMS */ conoll(msg); #endif /* VMS */ #ifdef OS2 #ifndef NOXFER if (xfrbel) { bleep(BP_FAIL); sleep(1); bleep(BP_FAIL); } #endif /* NOXFER */ #endif /* OS2 */ doexit(BAD_EXIT,xitsta | 1); /* Exit indicating failure */ } #ifndef NOXFER /* B L D L E N -- Make length-encoded copy of string */ char * #ifdef CK_ANSIC bldlen( char * str, char * dest ) #else bldlen(str,dest) char *str, *dest; #endif /* CK_ANSIC */ { int len; len = (int)strlen(str); if (len > 94) *dest = SP; else *dest = (char) tochar(len); strcpy(dest+1,str); /* Checked below in setgen() */ return(dest+len+1); } /* S E T G E N -- Construct a generic command */ /* Call with Generic command character followed by three string arguments. Trailing strings are allowed to be empty (""). Each string except the last non-empty string must be less than 95 characters long. The final nonempty string is allowed to be longer. */ CHAR #ifdef CK_ANSIC setgen(char type, char * arg1, char * arg2, char * arg3) #else setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3; #endif /* CK_ANSIC */ /* setgen */ { char *upstr, *cp; #ifdef DYNAMIC if (!cmdstr) if (!(cmdstr = malloc(MAXSP + 1))) fatal("setgen: can't allocate memory"); #endif /* DYNAMIC */ cp = cmdstr; *cp++ = type; *cp = NUL; if (!arg1) arg1 = ""; if (!arg2) arg2 = ""; if (!arg3) arg3 = ""; if (((int)strlen(arg1)+(int)strlen(arg2)+(int)strlen(arg3)+4) < MAXSP) { if (*arg1 != NUL) { upstr = bldlen(arg1,cp); if (*arg2 != NUL) { upstr = bldlen(arg2,upstr); if (*arg3 != NUL) bldlen(arg3,upstr); } } cmarg = cmdstr; debug(F110,"setgen",cmarg,0); return('g'); } return('E'); } #endif /* NOXFER */ #ifndef NOMSEND static char *mgbufp = NULL; /* F N P A R S E -- */ /* Argument is a character string containing one or more filespecs. This function breaks the string apart into an array of pointers, one to each filespec, and returns the number of filespecs. Used by server when it receives a GET command to allow it to process multiple file specifications in one transaction. Sets cmlist to point to a list of file pointers, exactly as if they were command line arguments. This version of fnparse treats spaces as filename separators. If your operating system allows spaces in filenames, you'll need a different separator. This version of fnparse mallocs a string buffer to contain the names. It cannot assume that the string that is pointed to by the argument is safe. */ int #ifdef CK_ANSIC fnparse( char * string ) #else fnparse(string) char * string; #endif /* CK_ANSIC */ { char *p, *s, *q; int r = 0, x; /* Return code */ #ifdef RECURSIVE debug(F111,"fnparse",string,recursive); #endif /* RECURSIVE */ if (mgbufp) free(mgbufp); /* Free this from last time. */ mgbufp = malloc((int)strlen(string)+2); if (!mgbufp) { debug(F100,"fnparse malloc error","",0); return(0); } #ifndef NOICP #ifndef NOSPL ckstrncpy(fspec,string,fspeclen); /* Make copy for \v(filespec) */ #endif /* NOSPL */ #endif /* NOICP */ s = string; /* Input string */ p = q = mgbufp; /* Point to the copy */ r = 0; /* Initialize our return code */ while (*s == SP || *s == HT) /* Skip leading spaces and tabs */ s++; for (x = strlen(s); /* Strip trailing spaces */ (x > 1) && (s[x-1] == SP || s[x-1] == HT); x--) s[x-1] = NUL; while (1) { /* Loop through rest of string */ #ifndef NOICP if (*s == CMDQ) { /* Backslash (quote character)? */ if ((x = xxesc(&s)) > -1) { /* Go interpret it. */ *q++ = (char) x; /* Numeric backslash code, ok */ } else { /* Just let it quote next char */ s++; /* get past the backslash */ *q++ = *s++; /* deposit next char */ } continue; } else if (*s == SP || *s == NUL) { /* Unquoted space or NUL? */ *q++ = NUL; /* End of output filename. */ msfiles[r] = p; /* Add this filename to the list */ debug(F111,"fnparse",msfiles[r],r); r++; /* Count it */ if (*s == NUL) break; /* End of string? */ while (*s == SP) s++; /* Skip repeated spaces */ p = q; /* Start of next name */ continue; } else #endif /* NOICP */ *q++ = *s; /* Otherwise copy the character */ s++; /* Next input character */ } debug(F101,"fnparse r","",r); msfiles[r] = ""; /* Put empty string at end of list */ cmlist = msfiles; return(r); } #endif /* NOMSEND */ char * /* dbchr() for DEBUG SESSION */ #ifdef CK_ANSIC dbchr( int c ) #else dbchr(c) int c; #endif /* CK_ANSIC */ { static char s[8]; char *cp = s; c &= 0xff; if (c & 0x80) { /* 8th bit on */ *cp++ = '~'; c &= 0x7f; } if (c < SP) { /* Control character */ *cp++ = '^'; *cp++ = (char) ctl(c); } else if (c == DEL) { *cp++ = '^'; *cp++ = '?'; } else { /* Printing character */ *cp++ = (char) c; } *cp = '\0'; /* Terminate string */ cp = s; /* Return pointer to it */ return(cp); } /* C K H O S T -- Get name of local host (where C-Kermit is running) */ /* Call with pointer to buffer to put hostname in, and length of buffer. Copies hostname into buffer on success, puts null string in buffer on failure. */ #ifdef BSD44 #define BSD4 #undef ATTSV #endif /* BSD44 */ #ifdef SVORPOSIX #ifndef BSD44 #ifndef apollo #include #endif /* apollo */ #endif /* BSD44 */ #else #ifdef BELLV10 #include #endif /* BELLV10 */ #endif /* SVORPOSIX*/ #ifdef CKSYSLOG extern char uidbuf[], * clienthost; #endif /* CKSYSLOG */ VOID #ifdef CK_ANSIC ckhost( char * vvbuf, int vvlen ) #else ckhost(vvbuf,vvlen) char * vvbuf; int vvlen; #endif /* CK_ANSIC */ { #ifndef NOPUSH extern int nopush; #ifndef NOSERVER extern int en_hos; #endif /* NOSERVER */ #endif /* NOPUSH */ #ifdef pdp11 *vvbuf = NUL; #else /* Everything else - rest of this routine */ char *g; #ifdef VMS int x; #endif /* VMS */ #ifdef SVORPOSIX #ifndef BSD44 #ifndef _386BSD #ifndef APOLLOSR10 struct utsname hname; #endif /* APOLLOSR10 */ #endif /* _386BSD */ #endif /* BSD44 */ #endif /* SVORPOSIX */ #ifdef datageneral int ac0 = (char *) vvbuf, ac1 = -1, ac2 = 0; #endif /* datageneral */ #ifndef NOPUSH if (getenv("CK_NOPUSH")) { /* No shell access allowed */ nopush = 1; /* on this host... */ #ifndef NOSERVER en_hos = 0; #endif /* NOSERVER */ } #endif /* NOPUSH */ *vvbuf = NUL; /* How let's get our host name ... */ #ifndef BELLV10 /* Does not have gethostname() */ #ifndef OXOS #ifdef SVORPOSIX #ifdef APOLLOSR10 ckstrncpy(vvbuf,"Apollo",vvlen); #else #ifdef BSD44 if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL; #else #ifdef _386BSD if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL; #else #ifdef QNX #ifdef TCPSOCKET if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL; #else if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen); #endif /* TCPSOCKET */ #else /* SVORPOSIX but not _386BSD or BSD44 */ #ifdef __ia64__ if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen); #else if (uname(&hname) > -1) { char * p; p = hname.nodename; #ifdef TCPSOCKET #ifndef NOCKGETFQHOST if (!ckstrchr(p,'.')) p = (char *)ckgetfqhostname(p); #endif /* NOCKGETFQHOST */ #endif /* TCPSOCKET */ if (!p) p = ""; if (!*p) p = "(unknown)"; ckstrncpy(vvbuf,p,vvlen); } #endif /* __ia64__ */ #endif /* QNX */ #endif /* _386BSD */ #endif /* BSD44 */ #endif /* APOLLOSR10 */ #else /* !SVORPOSIX */ #ifdef BSD4 if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL; #else /* !BSD4 */ #ifdef VMS g = getenv("SYS$NODE"); if (g) ckstrncpy(vvbuf,g,vvlen); x = (int)strlen(vvbuf); if (x > 1 && vvbuf[x-1] == ':' && vvbuf[x-2] == ':') vvbuf[x-2] = NUL; #else #ifdef datageneral if (sys($HNAME,&ac0,&ac1,&ac2) == 0) /* successful */ vvlen = ac2 + 1; /* enh - have to add one */ #else #ifdef OS2 /* OS/2 */ g = os2_gethostname(); if (g) ckstrncpy(vvbuf,g,vvlen); #else /* OS2 */ #ifdef OSK #ifdef TCPSOCKET if (gethostname(vvbuf, vvlen) < 0) *vvbuf = NUL; #endif /* TCPSOCKET */ #endif /* OSK */ #endif /* OS2 */ #endif /* datageneral */ #endif /* VMS */ #endif /* BSD4 */ #endif /* SVORPOSIX */ #else /* OXOS */ /* If TCP/IP is not installed, gethostname() fails, use uname() */ if (gethostname(vvbuf,vvlen) < 0) { if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen); else *vvbuf = NUL; } #endif /* OXOS */ #endif /* BELLV10 */ if (*vvbuf == NUL) { /* If it's still empty */ g = getenv("HOST"); /* try this */ if (g) ckstrncpy(vvbuf,g,vvlen); } vvbuf[vvlen-1] = NUL; /* Make sure result is terminated. */ #endif /* pdp11 */ } #ifdef BSD44 #undef BSD4 #define ATTSV #endif /* BSD44 */ /* A S K M O R E -- Poor person's "more". Returns 0 if no more, 1 if more wanted. */ int askmore() { char c; int rv, cx; #ifdef IKSD extern int timelimit; #endif /* IKSD */ #ifdef IKSDCONF extern int iksdcf; #endif /* IKSDCONF */ #ifdef CK_APC extern int apcstatus, apcactive; #endif /* CK_APC */ #ifdef NOICP return(1); #else if (!xaskmore) return(1); #ifdef IKSDCONF if (inserver && !iksdcf) return(1); #endif /* IKSDCONF */ #ifdef CK_APC if (apcactive == APC_LOCAL || (apcactive == APC_REMOTE && (apcstatus & APC_NOINP))) return(1); #endif /* CK_APC */ #ifdef VMS if (batch) return(1); #else #ifdef UNIX if (backgrd) return(1); #endif /* UNIX */ #endif /* VMS */ #ifndef VMS concb((char)escape); /* Force CBREAK mode. */ #endif /* VMS */ rv = -1; while (rv < 0) { #ifndef OS2 printf("more? "); #ifdef UNIX #ifdef NOSETBUF fflush(stdout); #endif /* NOSETBUF */ #endif /* UNIX */ #else printf("more? "); fflush(stdout); #endif /* OS2 */ #ifdef IKSD if (inserver) { cx = cmdgetc(timelimit); if (cx < -1 && timelimit) { printf("\n?IKS idle timeout - Goodbye.\n"); doexit(GOOD_EXIT,0); } else if (cx == -1) { /* Connection lost */ doexit(BAD_EXIT,0); } c = (char) cx; } else { #endif /* IKSD */ #ifdef VMS conbin((char)escape); /* Protect against Ctrl-Z */ cx = coninc(0); concb((char)escape); #else cx = cmdgetc(0); #endif /* VMS */ debug(F101,"askmore cmdgetc","",cx); if (cx == EOF) { debug(F100,"askmore EOF","",0); #ifdef VMS c = '\032'; #else c = 'n'; #endif /* VMS */ } else { c = (char)cx; } debug(F101,"askmore c","",c); #ifdef IKSD } #endif /* IKSD */ switch (c) { /* Yes */ case 'p': case 'P': case 'g': case 'G': /* Proceed or Go */ xaskmore = 0; /* fall thru on purpose */ case SP: case 'y': case 'Y': case 012: case 015: #ifdef OSK write(1, "\015 \015", sizeof "\015 \015" - 1); #else printf("\015 \015"); #endif /* OSK */ rv = 1; break; /* No */ case 'n': case 'N': case 'q': case 'Q': #ifdef OSK printf("\n"); #else printf("\015\012"); #endif /* OSK */ rv = 0; break; case '\003': case '\004': case '\032': #ifdef OSK printf("^%c...\n", (c + 0100)); #else printf("^%c...\015\012", (c + 0100)); #endif /* OSK */ rv = 0; break; /* Invalid answer */ default: debug(F111,"askmore","invalid answer",c); printf("Y or space-bar for yes, N for no, G to show the rest\n"); continue; } #ifdef OS2 printf("\r \r"); fflush(stdout); #endif /* OS2 */ } return(rv); #endif /* NOICP */ } /* T R A P -- Terminal interrupt handler */ SIGTYP #ifdef CK_ANSIC trap(int sig) #else trap(sig) int sig; #endif /* CK_ANSIC */ /* trap */ { extern int b_save, f_save; #ifndef NOICP extern int timelimit; #endif /* NOICP */ #ifdef OS2 extern unsigned long startflags; #ifndef NOSETKEY extern int os2gks; #endif /* NOSETKEY */ int i; #endif /* OS2 */ #ifndef NOSPL extern int i_active, instatus; #endif /* NOSPL */ #ifdef VMS int i; FILE *f; #endif /* VMS */ extern int zchkod, zchkid; #ifndef NOSPL extern int unkmacro; #endif /* NOSPL */ debok = 1; #ifdef NTSIG connoi(); #endif /* NTSIG */ #ifdef __EMX__ signal(SIGINT, SIG_ACK); #endif #ifdef GEMDOS /* GEM is not reentrant, no i/o from interrupt level */ cklongjmp(cmjbuf,1); /* Jump back to parser now! */ #endif /* GEMDOS */ #ifdef DEBUG if (deblog) { debug(F100,"*********************","",0); if (sig == SIGINT) debug(F101,"trap caught SIGINT","",sig); else debug(F101,"trap caught signal","",sig); debug(F100,"*********************","",0); } #endif /* DEBUG */ #ifdef OS2 if ( sig == SIGBREAK && (startflags & 128) ) { debug(F101,"trap ignoring SIGBREAK","",sig); return; } #endif /* OS2 */ #ifndef NOICP timelimit = 0; /* In case timed ASK interrupted */ #ifndef NOSPL unkmacro = 0; /* Or ON_UNKNOWN_MACRO interrupted.. */ #endif /* NOSPL */ #endif /* NOICP */ zchkod = 0; /* Or file expansion interrupted... */ zchkid = 0; interrupted = 1; if (what & W_CONNECT) { /* Are we in CONNECT mode? */ /* The HP workstation Reset key sends some kind of ueber-SIGINT that can not be SIG_IGNored, so we wind up here somehow (even though this is *not* the current SIGINT handler). Just return. */ debug(F101,"trap: SIGINT caught during CONNECT","",sig); SIGRETURN; } #ifndef NOSPL if (i_active) { /* INPUT command was active? */ i_active = 0; /* Not any more... */ instatus = INP_UI; /* INPUT status = User Interrupted */ } #endif /* NOSPL */ #ifndef NOXFER ftreset(); /* Restore global protocol settings */ binary = b_save; /* Then restore these */ fncnv = f_save; bye_active = 0; diractive = 0; cdactive = 0; #endif /* NOXFER */ zclose(ZIFILE); /* If we were transferring a file, */ zclose(ZOFILE); /* close it. */ #ifndef NOICP cmdsquo(cmd_quoting); /* If command quoting was turned off */ #ifdef CKLEARN { extern FILE * learnfp; extern int learning; if (learnfp) { fclose(learnfp); learnfp = NULL; learning = 0; } } #endif /* CKLEARN */ #endif /* NOICP */ #ifdef CK_APC delmac("_apc_commands",1); apcactive = APC_INACTIVE; #endif /* CK_APC */ #ifdef VMS /* Fix terminal. */ if (ft_win) { /* If curses window open */ debug(F100,"^C trap() curses","",0); xxscreen(SCR_CW,0,0L,""); /* Close it */ conres(); /* Restore terminal */ i = printf("^C..."); /* Echo ^C to standard output */ } else { conres(); i = printf("^C...\n"); /* Echo ^C to standard output */ } if (i < 1 && ferror(stdout)) { /* If there was an error */ debug(F100,"^C trap() error","",0); fclose(stdout); /* close standard output */ f = fopen(dftty, "w"); /* open the controlling terminal */ if (f) stdout = f; /* and make it standard output */ printf("^C...\n"); /* and echo the ^C again. */ } #else /* Not VMS */ #ifdef STRATUS conres(); /* Set console back to normal mode */ #endif /* STRATUS */ #ifndef NOXFER if (ft_win) { /* If curses window open, */ debug(F100,"^C trap() curses","",0); xxscreen(SCR_CW,0,0L,""); /* close it. */ printf("^C..."); /* Echo ^C to standard output */ } else { #endif /* NOXFER */ printf("^C...\n"); #ifndef NOXFER } #endif /* NOXFER */ #endif /* VMS */ #ifdef datageneral connoi_mt(); /* Kill asynch task that listens to */ ttimoff(); conres(); /* the keyboard */ #endif /* datageneral */ #ifndef NOCCTRAP /* This is stupid -- every version should have ttimoff()... */ #ifdef UNIX ttimoff(); /* Turn off any timer interrupts */ #else #ifdef OSK ttimoff(); /* Turn off any timer interrupts */ #else #ifdef STRATUS ttimoff(); /* Turn off any timer interrupts */ #else #ifdef OS2 #ifndef NOSETKEY os2gks = 1; /* Turn back on keycode mapping */ #endif /* NOSETKEY */ #ifndef NOLOCAL for (i = 0; i < VNUM; i++) VscrnResetPopup(i); #endif /* NOLOCAL */ #ifdef TCPSOCKET #ifdef NT /* WSAIsBlocking() returns FALSE in Win95 during a blocking accept call */ if ( WSASafeToCancel /* && WSAIsBlocking() */ ) { WSACancelBlockingCall(); } #endif /* NT */ #endif /* TCPSOCKET */ #ifdef CK_NETBIOS NCBCancelOutstanding(); #endif /* CK_NETBIOS */ ttimoff(); /* Turn off any timer interrupts */ #else #ifdef VMS ttimoff(); /* Turn off any timer interrupts */ #endif /* VMS */ #endif /* OS2 */ #endif /* STRATUS */ #endif /* OSK */ #endif /* UNIX */ #ifdef NETPTY #ifdef NT /* Do nothing - PTYs on Windows NT have more in common with NET_CMD than * anything else. No special handling beyond what is already being done * elsewhere in this function. * */ #else /* Clean up Ctrl-C out of REDIRECT or external protocol */ { extern PID_T pty_fork_pid; extern int pty_master_fd, pty_slave_fd; int x; signal(SIGCHLD,SIG_IGN); /* We don't want this any more */ debug(F101,"trap pty_master_fd","",pty_master_fd); if (pty_master_fd > 2) { x = close(pty_master_fd); debug(F101,"trap pty_master_fd close","",x); } pty_master_fd = -1; debug(F101,"trap pty_slave_fd","",pty_slave_fd); if (pty_slave_fd > 2) { x = close(pty_slave_fd); debug(F101,"trap pty_slave_fd close","",x); } pty_slave_fd = -1; debug(F101,"trap pty_fork_pid","",pty_fork_pid); if (pty_fork_pid > 0) { x = kill(pty_fork_pid,0); /* See if the fork is really there */ debug(F111,"trap pty_fork_pid kill 0 errno",ckitoa(x),errno); if (x == 0) { /* Seems to be active */ x = kill(pty_fork_pid,SIGHUP); /* Ask it to clean up & exit */ debug(F101,"trap pty_fork_pid kill SIGHUP","",x); msleep(100); errno = 0; x = kill(pty_fork_pid,0); /* Is it still there? */ if (x == 0 #ifdef ESRCH /* This module is not always exposed to */ || errno != ESRCH #endif /* ESRCH */ ) { x = kill(pty_fork_pid,SIGKILL); debug(F101,"trap pty_fork_pid kill SIGKILL","",x); } } pty_fork_pid = -1; } } #endif /* NT */ #endif /* NETPTY */ #ifdef OSK sigmask(-1); /* We are in an intercept routine but do not perform a F$RTE (done implicitly by rts). We have to decrement the sigmask as F$RTE does. Warning: longjump only restores the cpu registers, NOT the fpu registers. So don't use fpu at all or at least don't use common fpu (double or float) register variables. */ #endif /* OSK */ #ifdef NTSIG PostCtrlCSem(); #else /* NTSIG */ debug(F100,"trap about to longjmp","",0); #ifdef NT cklongjmp(ckjaddr(cmjbuf),1); #else /* NT */ cklongjmp(cmjbuf,1); #endif /* NT */ #endif /* NTSIG */ #else /* NOCCTRAP */ /* No Ctrl-C trap, just exit. */ #ifdef CK_CURSES /* Curses support? */ xxscreen(SCR_CW,0,0L,""); /* Close curses window */ #endif /* CK_CURSES */ doexit(BAD_EXIT,what); /* Exit poorly */ #endif /* NOCCTRAP */ SIGRETURN; } /* C K _ T I M E -- Returns pointer to current time. */ char * ck_time() { static char tbuf[10]; char *p; int x; ztime(&p); /* "Thu Feb 8 12:00:00 1990" */ if (!p) /* like asctime()! */ return(""); if (*p) { for (x = 11; x < 19; x++) /* copy hh:mm:ss */ tbuf[x - 11] = p[x]; /* to tbuf */ tbuf[8] = NUL; /* terminate */ } return(tbuf); /* and return it */ } /* C C _ C L E A N -- Cleanup after terminal interrupt handler */ #ifdef GEMDOS int cc_clean() { zclose(ZIFILE); /* If we were transferring a file, */ zclose(ZOFILE); /* close it. */ printf("^C...\n"); /* Not VMS, no problem... */ } #endif /* GEMDOS */ /* S T P T R A P -- Handle SIGTSTP (suspend) signals */ SIGTYP #ifdef CK_ANSIC stptrap(int sig) #else stptrap(sig) int sig; #endif /* CK_ANSIC */ /* stptrap */ { #ifndef NOJC int x; extern int cmflgs; debug(F101,"stptrap() caught signal","",sig); if (!xsuspend) { printf("\r\nsuspend disabled\r\n"); #ifndef NOICP if (what & W_COMMAND) { /* If we were parsing commands */ prompt(xxstring); /* reissue the prompt and partial */ if (!cmflgs) /* command (if any) */ printf("%s",cmdbuf); } #endif /* NOICP */ } else { conres(); /* Reset the console */ #ifndef OS2 /* Flush pending output first, in case we are continued */ /* in the background, which could make us block */ fflush(stdout); x = psuspend(xsuspend); /* Try to suspend. */ if (x < 0) #endif /* OS2 */ printf("Job control not supported\r\n"); conint(trap,stptrap); /* Rearm the trap. */ debug(F100,"stptrap back from suspend","",0); switch (what) { case W_CONNECT: /* If suspended during CONNECT? */ conbin((char)escape); /* put console back in binary mode */ debug(F100,"stptrap W_CONNECT","",0); break; #ifndef NOICP case W_COMMAND: /* Suspended in command mode */ debug(F101,"stptrap W_COMMAND pflag","",pflag); concb((char)escape); /* Put back CBREAK tty mode */ if (pflag) { /* If command parsing was */ prompt(xxstring); /* reissue the prompt and partial */ if (!cmflgs) /* command (if any) */ printf("%s",cmdbuf); } break; #endif /* NOICP */ default: /* All other cases... */ debug(F100,"stptrap default","",0); concb((char)escape); /* Put it back in CBREAK mode */ break; } } #endif /* NOJC */ SIGRETURN; } #ifdef TLOG #define TBUFL 1000 /* T L O G -- Log a record in the transaction file */ /* Call with a format and 3 arguments: two strings and a number: f - Format, a bit string in range 0-7, bit x is on, arg #x is printed. s1,s2 - String arguments 0 and 1. n - Long, argument 2. */ VOID #ifdef CK_ANSIC dotlog(int f, char *s1, char *s2, CK_OFF_T n) #else dotlog(f,s1,s2,n) int f; CK_OFF_T n; char *s1, *s2; #endif /* CK_ANSIC */ /* dotlog */ { static char s[TBUFL]; extern int tlogfmt; char *sp = s; int x; if (!s1) s1 = ""; if (!s2) s2 = ""; if (!tralog) return; /* If no transaction log, don't */ if (tlogfmt != 1) return; switch (f) { case F000: /* 0 (special) "s1 n s2" */ if ((int)strlen(s1) + (int)strlen(s2) + 15 > TBUFL) sprintf(sp,"?T-Log string too long"); else sprintf(sp,"%s %s %s",s1,ckfstoa(n),s2); if (zsoutl(ZTFILE,s) < 0) tralog = 0; break; case F001: /* 1, " n" */ sprintf(sp," %s",ckfstoa(n)); if (zsoutl(ZTFILE,s) < 0) tralog = 0; break; case F010: /* 2, "[s2]" */ x = (int)strlen(s2); if (s2[x] == '\n') s2[x] = '\0'; if (x + 6 > TBUFL) sprintf(sp,"?String too long"); else sprintf(sp,"[%s]",s2); if (zsoutl(ZTFILE,"") < 0) tralog = 0; break; case F011: /* 3, "[s2] n" */ x = (int)strlen(s2); if (s2[x] == '\n') s2[x] = '\0'; if (x + 6 > TBUFL) sprintf(sp,"?String too long"); else sprintf(sp,"[%s] %s",s2,ckfstoa(n)); if (zsoutl(ZTFILE,s) < 0) tralog = 0; break; case F100: /* 4, "s1" */ if (zsoutl(ZTFILE,s1) < 0) tralog = 0; break; case F101: /* 5, "s1: n" */ if ((int)strlen(s1) + 15 > TBUFL) sprintf(sp,"?String too long"); else sprintf(sp,"%s: %s",s1,ckfstoa(n)); if (zsoutl(ZTFILE,s) < 0) tralog = 0; break; case F110: /* 6, "s1 s2" */ x = (int)strlen(s2); if (s2[x] == '\n') s2[x] = '\0'; if ((int)strlen(s1) + x + 4 > TBUFL) sprintf(sp,"?String too long"); else sprintf(sp,"%s%s%s",s1,((*s2 == ':') ? "" : " "),s2); if (zsoutl(ZTFILE,s) < 0) tralog = 0; break; case F111: /* 7, "s1 s2: n" */ x = (int)strlen(s2); if (s2[x] == '\n') s2[x] = '\0'; if ((int)strlen(s1) + x + 15 > TBUFL) sprintf(sp,"?String too long"); else sprintf(sp,"%s%s%s: %s",s1,((*s2 == ':') ? "" : " "),s2,ckfstoa(n)); if (zsoutl(ZTFILE,s) < 0) tralog = 0; break; default: sprintf(sp,"?Invalid format for tlog() - %d",f); if (zsoutl(ZTFILE,s) < 0) tralog = 0; } } /* D O X L O G This is the transaction-log writer for BRIEF format. The idea is produce one record (line) per file. Each record has the following delimited fields: Date (yyyymmdd) Time (hh:mm:ss) Action: SEND or RECV File name File size Transfer mode (text, binary, image, labeled, etc). Status: OK or FAILED Free-form comments in doublequotes The default separator is comma. If a field contains the separator, it is enclosed in doublequotes. */ VOID #ifdef CK_ANSIC doxlog(int x, char * fn, CK_OFF_T fs, int fm, int status, char * msg) #else doxlog(x, fn, fs, fm, status, msg) int x; char * fn; CK_OFF_T fs; int fm; int status; char * msg; #endif /* CK_ANSIC */ /* doxlog */ { extern int tlogsep; char sep[2]; char buf[CKMAXPATH+256], * bufp; char tmpbuf[32]; char * s, * p; int len, left, ftp = 0, k; if (!tralog) return; /* If no transaction log, don't */ if (!fn) fn = ""; /* Protect against null pointers */ if (!msg) msg = ""; if (x & W_FTP) ftp++; sep[0] = (char) tlogsep; sep[1] = NUL; if (!sep[0]) sep[0] = ','; bufp = buf; left = sizeof(buf); debug(F101,"XXX doxlog left 1","",left); p = zzndate(); /* Date */ ckmakmsg(buf, left, p ? p : "00000000", sep, NULL, NULL); bufp += 9; left -= 9; debug(F111,"XXX doxlog left 2",buf,left); ztime(&p); ckstrncpy(bufp,p+11,left); bufp += 8; left -= 8; debug(F111,"XXX doxlog left 3",buf,left); if (ftp) { if (!(x & (W_SEND|W_RECV))) return; s = (x & W_SEND) ? "PUT" : "GET"; k = 3; } else { s = (x & W_SEND) ? "SEND" : "RECV"; k = 4; } ckmakmsg(bufp,left,sep,s,sep,NULL); bufp += k + 2; left -= (k + 2); debug(F111,"XXX doxlog left 4",buf,left); s = ""; if (ckstrchr(fn,sep[0])) /* Filename */ s = "\""; ckmakmsg(bufp,left,s,fn,s,sep); sprintf(tmpbuf,"%s",ckfstoa(fs)); /* Size */ ckstrncat(buf,tmpbuf,CKMAXPATH); ckstrncat(buf,sep,CKMAXPATH); debug(F110,"doxlog 4",buf,0); #ifdef NOICP /* Transfer mode */ ckstrncpy(tmpbuf, (binary ? "binary" : "text"), TMPBUFSIZ); #else ckstrncpy(tmpbuf,gfmode(fm,0),TMPBUFSIZ); #endif /* NOICP */ if (ckstrchr(tmpbuf,sep[0])) { /* Might contain spaces */ ckstrncat(buf,"\"",CKMAXPATH); ckstrncat(buf,tmpbuf,CKMAXPATH); ckstrncat(buf,"\"",CKMAXPATH); } else ckstrncat(buf,tmpbuf,CKMAXPATH); ckstrncat(buf,sep,CKMAXPATH); debug(F110,"doxlog 5",buf,0); ckstrncat(buf, status ? "FAILED" : "OK",CKMAXPATH); len = strlen(buf); left = CKMAXPATH+256 - len; if (left < 2) fatal("doxlog buffer overlow"); debug(F111,"XXX doxlog left 5",buf,left); debug(F110,"doxlog buf 1", buf, len); s = buf + len; if (status == 0 && left > 32) { long cps = 0L; #ifdef GFTIMER debug(F101,"DOXLOG fpxfsecs","",(long)(fpxfsecs * 1000)); if (fpxfsecs) cps = (long)((CKFLOAT) fs / fpxfsecs); sprintf(s,"%s\"%0.3fsec %ldcps\"",sep,fpxfsecs,cps); #else if (xfsecs) cps = fs / xfsecs; sprintf(s,"%s\"%ldsec %ldcps\"",sep,xfsecs,cps); #endif /* GFTIMER */ } else if ((int)strlen(msg) + 4 < left) { sprintf(s,"%s\"%s\"",sep,msg); } debug(F111,"XXX doxlog left 5",buf,left); debug(F110,"doxlog 5",buf,0); x = zsoutl(ZTFILE,buf); debug(F101,"doxlog zsoutl","",x); if (x < 0) tralog = 0; } #endif /* TLOG */ #ifndef MAC /* The rest of this file is for all implementations but the Macintosh. */ #ifdef CK_CURSES static int repaint = 0; /* Transfer display needs repainting */ #endif /* CK_CURSES */ #ifndef NOXFER /* C H K I N T -- Check for console interrupts */ /* Used during file transfer in local mode only: . If user has not touched the keyboard, returns 0 with no side effects. . If user typed S or A (etc, see below) prints status message and returns 0. . If user typed X or F (etc, see below) returns 0 with cxseen set to 1. . If user typed Z or B (etc, see below) returns 0 with czseen set to 1. . If user typed E or C (etc, see below) returns -1. */ int chkint() { int ch, cn, ofd; long zz; if (!xfrint) return(0); if ((!local) || (quiet)) return(0); /* Only do this if local & not quiet */ #ifdef datageneral if (con_reads_mt) /* if conint_mt task is active */ if (conint_avl) { /* and there's an interrupt pending */ cn = 1; /* process it */ ch = conint_ch; conint_avl = 0; /* turn off flag so conint_mt can */ } else /* proceed */ return(0); else /* if conint_mt not active */ if ((ch = coninc(2)) < 0) /* try to get char manually */ return(0); /* I/O error, or no data */ else /* if successful, set cn so we */ cn = 1; /* know we got one */ debug(F101,"chkint got keyboard character",ch,cn); #else /* !datageneral */ #ifdef NTSIG { extern int TlsIndex; struct _threadinfo * threadinfo; threadinfo = (struct _threadinfo *) TlsGetValue(TlsIndex); if (threadinfo) { if (!WaitSem(threadinfo->DieSem,0)) return -1; /* Cancel Immediately */ } } #endif /* NTSIG */ cn = conchk(); /* Any input waiting? */ debug(F101,"conchk","",cn); if (cn < 1) return(0); ch = coninc(5) ; debug(F101,"coninc","",ch); if (ch < 0) return(0); #endif /* datageneral */ ch &= 0177; switch (ch) { case 'A': case 'a': case 0001: /* Status report */ case 'S': case 's': if (fdispla != XYFD_R && fdispla != XYFD_S && fdispla != XYFD_N) return(0); /* Only for serial, simple or none */ ofd = fdispla; /* [MF] Save file display type */ if (fdispla == XYFD_N) fdispla = XYFD_R; /* [MF] Pretend serial if no display */ xxscreen(SCR_TN,0,0l,"Status report:"); xxscreen(SCR_TN,0,0l," file type: "); if (binary) { switch(binary) { case XYFT_L: xxscreen(SCR_TZ,0,0l,"labeled"); break; case XYFT_I: xxscreen(SCR_TZ,0,0l,"image"); break; case XYFT_U: xxscreen(SCR_TZ,0,0l,"binary undefined"); break; default: case XYFT_B: xxscreen(SCR_TZ,0,0l,"binary"); break; } } else { #ifdef NOCSETS xxscreen(SCR_TZ,0,0l,"text"); #else xxscreen(SCR_TU,0,0l,"text, "); if (tcharset == TC_TRANSP || xfrxla == 0) { xxscreen(SCR_TZ,0,0l,"transparent"); } else { if (what & W_SEND) { xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword); xxscreen(SCR_TU,0,0l," => "); xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword); } else { xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword); xxscreen(SCR_TU,0,0l," => "); xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword); } } #endif /* NOCSETS */ } xxscreen(SCR_QE,0,filcnt," file number"); if (fsize) xxscreen(SCR_QE,0,fsize," size"); xxscreen(SCR_QE,0,ffc," characters so far"); if (fsize > 0L) { #ifdef CK_RESEND zz = what & W_SEND ? sendstart : what & W_RECV ? rs_len : 0; zz = ( (ffc + zz) * 100L ) / fsize; #else zz = ( ffc * 100L ) / fsize; #endif /* CK_RESEND */ xxscreen(SCR_QE,0,zz, " percent done"); } if (bctu == 4) { /* Block check */ xxscreen(SCR_TU,0,0L," block check: "); xxscreen(SCR_TZ,0,0L,"blank-free-2"); } else xxscreen(SCR_QE,0,(long)bctu, " block check"); xxscreen(SCR_QE,0,(long)rptflg," compression"); xxscreen(SCR_QE,0,(long)ebqflg," 8th-bit prefixing"); xxscreen(SCR_QE,0,(long)lscapu," locking shifts"); if (!network) xxscreen(SCR_QE,0, speed, " speed"); if (what & W_SEND) { xxscreen(SCR_QE,0,spsiz, " packet length"); } else if (what & W_RECV || what & W_REMO) { xxscreen(SCR_QE,0,urpsiz," packet length"); } xxscreen(SCR_QE,0,wslots, " window slots"); fdispla = ofd; /* [MF] Restore file display type */ return(0); case 'B': case 'b': case 0002: /* Cancel batch */ case 'Z': case 'z': case 0032: czseen = 1; interrupted = 1; xxscreen(SCR_ST,ST_MSG,0l, (((what & W_RECV) && (wslots > 1)) ? "Canceling batch, wait... " : "Canceling batch... ") ); return(0); case 'F': case 'f': case 0006: /* Cancel file */ case 'X': case 'x': case 0030: cxseen = 1; interrupted = 1; xxscreen(SCR_ST,ST_MSG,0l, (((what & W_RECV) && (wslots > 1)) ? "Canceling file, wait... " : "Canceling file... ") ); return(0); case 'R': case 'r': case 0022: /* Resend packet */ case 0015: case 0012: #ifdef STREAMING if (streaming) return(0); #endif /* STREAMING */ xxscreen(SCR_ST,ST_MSG,0l,"Resending packet... "); numerrs++; resend(winlo); return(0); #ifdef datageneral case '\03': /* We're not trapping ^C's with */ trap(0); /* signals, so we check here */ #endif /* datageneral */ case 'C': case 'c': /* Ctrl-C */ #ifndef datageneral case '\03': #endif /* datageneral */ case 'E': case 'e': /* Send error packet */ case 0005: interrupted = 1; return(-1); #ifdef CK_CURSES case 0014: /* Ctrl-L to refresh screen */ case 'L': case 'l': /* Also accept L (upper, lower) */ case 0027: /* Ctrl-W synonym for VMS & Ingres */ repaint = 1; return(0); #endif /* CK_CURSES */ case 'T': case 't': /* Turn on debug-log timestamps */ #ifdef DEBUG { extern int debtim; if (ch == 'T') { debtim = 1; xxscreen(SCR_ST,ST_MSG,0l, "Debug timestamps On... "); } else { debtim = 1; xxscreen(SCR_ST,ST_MSG,0l, "Debug timestamps Off... "); } } #endif /* DEBUG */ return(0); case 'D': #ifdef DEBUG if (!deblog) { debopn("debug.log",0); if (deblog) { xxscreen(SCR_ST,ST_MSG,0l,"debug.log open... "); } else { xxscreen(SCR_ST,ST_MSG,0l,"debug.log open FAILED... "); } } else { xxscreen(SCR_ST,ST_MSG,0l,"Debug log On... "); } if (deblog) debok = 1; #endif /* DEBUG */ return(0); case 'd': /* Turn off debugging */ #ifdef DEBUG if (deblog) xxscreen(SCR_ST,ST_MSG,0l,"Debug log Off... "); debok = 0; #endif /* DEBUG */ return(0); default: /* Anything else, print message */ intmsg(1L); return(0); } } /* I N T M S G -- Issue message about terminal interrupts */ VOID #ifdef CK_ANSIC intmsg(long n) #else intmsg(n) long n; #endif /* CK_ANSIC */ /* intmsg */ { #ifdef CK_NEED_SIG char buf[80]; #endif /* CK_NEED_SIG */ if (!displa || quiet) /* Not if we're being quiet */ return; if (server && (!srvdis || n > -1L)) /* Special for server */ return; #ifdef CK_NEED_SIG buf[0] = NUL; /* Keep compilers happy */ #endif /* CK_NEED_SIG */ #ifndef OXOS #ifdef SVORPOSIX conchk(); /* Clear out pending escape-signals */ #endif /* SVORPOSIX */ #endif /* ! OXOS */ #ifdef VMS conres(); /* So Ctrl-C will work */ #endif /* VMS */ if ((!server && n == 1L) || (server && n < 0L)) { #ifdef CK_NEED_SIG if (xfrint) { ckmakmsg(buf, 80, "Type escape character (", dbchr(escape), ") followed by:", NULL ); xxscreen(SCR_TN,0,0l,buf); } #endif /* CK_NEED_SIG */ if (xfrint) { if (protocol == PROTO_K) { xxscreen(SCR_TN,0,0l,"X to cancel file, CR to resend current packet"); xxscreen(SCR_TN,0,0l,"Z to cancel group, A for status report"); xxscreen(SCR_TN,0,0l,"E to send Error packet, Ctrl-C to quit immediately: "); } else { xxscreen(SCR_TN,0,0l,"Ctrl-C to cancel file transfer: "); } } else { xxscreen(SCR_TN,0,0l,"Transfer interruption disabled. "); } } else xxscreen(SCR_TU,0,0l," "); } #ifndef NODISPLAY static int newdpy = 0; /* New display flag */ static char fbuf[80]; /* Filename buffer */ static char abuf[80]; /* As-name buffer */ static char a2buf[80]; /* Second As-name buffer */ static CK_OFF_T oldffc = 0L; static CK_OFF_T dots = 0L; static int hpos = 0; static VOID /* Initialize Serial or CRT display */ dpyinit() { int m = 0, n = 0; char * s = ""; newdpy = 0; /* Don't do this again */ oldffc = (CK_OFF_T)0; /* Reset this */ dots = (CK_OFF_T)0; /* and this.. */ oldcps = cps = 0L; conoll(""); /* New line */ if (what & W_SEND) s = "Sending: "; /* Action */ else if (what & W_RECV) s = "Receiving: "; n = (int)strlen(s) + (int)strlen(fbuf); conol(fbuf); m = (int)strlen(abuf) + 4; if (n + m > cmd_cols) { conoll(""); n = 0; } else n += m; if (*abuf) { conol(" => "); conol(abuf); } m = (int)strlen(a2buf) + 4; if (n + m > cmd_cols) { conoll(""); n = 0; } else n += m; if (*a2buf) { conol(" => "); conol(a2buf); } *fbuf = NUL; *abuf = NUL; *a2buf = NUL; conoll(""); if (fsize > (CK_OFF_T)-1) { /* Size */ sprintf(fbuf,"Size: %s, Type: ",ckfstoa(fsize)); /* SAFE (80) */ conol(fbuf); *fbuf = NUL; } else conol("Size: unknown, Type: "); if (binary) { /* Type */ switch(binary) { case XYFT_L: conol("labeled"); break; case XYFT_I: conol("image"); break; case XYFT_U: conol("binary undefined"); break; default: case XYFT_B: conol("binary"); break; } } else { #ifdef NOCSETS conol("text"); #else conol("text, "); if (tcharset == TC_TRANSP || xfrxla == 0) { conol("transparent"); } else { if (what & W_SEND) { conol(fcsinfo[fcharset].keyword); conol(" => "); conol(tcsinfo[tcharset].keyword); } else { conol(tcsinfo[tcharset].keyword); conol(" => "); conol(fcsinfo[fcharset].keyword); } } #endif /* NOCSETS */ } #ifdef STREAMING if (streaming) conol(", STREAMING"); #endif /* STREAMING */ conoll(""); if (fdispla == XYFD_S) { /* CRT field headings */ /* Define CK_CPS to show current transfer rate. Leave it undefined to show estimated time remaining. Estimated-time-remaining code from Andy Fyfe, not tested on pathological cases. */ #define CK_CPS #ifdef CK_CPS conoll(" File Percent Packet"); conoll(" Bytes Done CPS Length"); #else conoll(" File Percent Secs Packet"); conoll(" Bytes Done Left Length"); #endif /* CK_CPS */ newdpy = 0; } hpos = 0; } /* showpkt(c) c = completion code: 0 means transfer in progress, nonzero means it's done. Show the file transfer progress counter and perhaps verbose packet type. */ VOID #ifdef CK_ANSIC showpkt(char c) #else showpkt(c) char c; #endif /* CK_ANSIC */ /* showpkt */ { #ifndef GFTIMER long et; /* Elapsed time, entire batch */ #endif /* GFTIMER */ CK_OFF_T howfar; /* How far into file */ long pd; /* Percent done, this file */ long tp; /* Transfer rate, entire batch */ long ps; /* Packet size, current packet */ CK_OFF_T mytfc; /* Local copy of byte counter */ #ifdef GFTIMER CKFLOAT tnow; #endif /* GFTIMER */ if (newdpy) /* Put up filenames, etc, */ dpyinit(); /* if they're not there already. */ howfar = ffc; /* How far */ /* Calculate CPS rate even if not displaying on screen for use in file transfer statistics. */ #ifdef GFTIMER tnow = gftimer(); /* Time since we started */ ps = (what & W_RECV) ? rpktl : spktl; /* Packet size */ #ifdef CK_RESEND if (what & W_SEND) /* In case we didn't start at */ howfar += sendstart; /* the beginning... */ else if (what & W_RECV) howfar += rs_len; #endif /* CK_RESEND */ pd = -1; /* Percent done. */ if (c == NUL) { /* Still going, figure % done */ if (!fsize) return; /* Empty file, don't bother */ pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0; if (pd > 100) pd = 100; /* Expansion */ } if (c != NUL) if (!cxseen && !discard && !czseen) pd = 100; /* File complete, so 100%. */ mytfc = (pd < 100) ? tfc + ffc : tfc; /* CPS */ tp = (long)((tnow > 0.0) ? (CKFLOAT) mytfc / tnow : 0); if (c && (tp == 0)) tp = ffc; cps = tp; /* Set global variable */ if (cps > peakcps && /* Peak transfer rate */ ((what & W_SEND && spackets > wslots + 4) || (!(what & W_SEND) && spackets > 10))) { peakcps = cps; } #else /* Not GFTIMER */ et = gtimer(); /* Elapsed time */ ps = (what & W_RECV) ? rpktl : spktl; /* Packet length */ #ifdef CK_RESEND if (what & W_SEND) /* And if we didn't start at */ howfar += sendstart; /* the beginning... */ else if (what & W_RECV) howfar += rs_len; #endif /* CK_RESEND */ pd = -1; /* Percent done. */ if (c == NUL) { /* Still going, figure % done */ if (fsize == 0L) return; /* Empty file, don't bother */ pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0; if (pd > 100) pd = 100; /* Expansion */ } if (c != NUL) if (!cxseen && !discard && !czseen) pd = 100; /* File complete, so 100%. */ #ifndef CK_CPS /* fsecs = time (from gtimer) that this file started (set in sfile()). Rate so far is ffc / (et - fsecs), estimated time for remaining bytes is (fsize - ffc) / (ffc / (et - fsecs)). */ tp = (howfar > 0) ? (fsize - howfar) * (et - fsecs) / howfar : 0; #endif /* CK_CPS */ #ifdef CK_CPS mytfc = (pd < 100) ? tfc + ffc : tfc; tp = (et > 0) ? mytfc / et : 0; /* Transfer rate */ if (c && (tp == 0)) /* Watch out for subsecond times */ tp = ffc; cps = tp; /* Set global variable */ if (cps > peakcps && /* Peak transfer rate */ ((what & W_SEND && spackets > wslots + 4) || (!(what & W_SEND) && spackets > 10))) { peakcps = cps; } #endif /* CK_CPS */ #endif /* GFTIMER */ if (fdispla == XYFD_S) { /* CRT display */ char buffer[128]; /* These sprintfs should be safe until we have 32-digit numbers */ if (pd > -1L) sprintf(buffer, "%c%9s%5ld%%%8ld%8ld ", CK_CR,ckfstoa(howfar),pd,tp,ps); else sprintf(buffer, "%c%9s %8ld%8ld ", CK_CR,ckfstoa(howfar),tp,ps); conol(buffer); hpos = 31; } else if (fdispla == XYFD_R) { /* SERIAL */ long i, k; if (howfar - oldffc < 1024) /* Update display every 1K */ return; oldffc = howfar; /* Time for new display */ k = (howfar / 1024L) - dots; /* How many K so far */ for (i = 0L; i < k; i++) { if (hpos++ > (cmd_cols - 3)) { /* Time to wrap? */ conoll(""); hpos = 0; } conoc('.'); /* Print a dot for this K */ dots++; /* Count it */ } } } /* C K S C R E E N -- Screen display function */ /* ckscreen(f,c,n,s) f - argument descriptor c - a character or small integer n - a long integer s - a string. and global fdispla = SET FILE DISPLAY value: XYFD_N = NONE XYFD_R = SERIAL: Dots, etc, works on any terminal, even hardcopy. XYFD_S = CRT: Works on any CRT, writes over current line. XYFD_C = FULLSCREEN: Requires terminal-dependent screen control. XYFD_B = BRIEF: Like SERIAL but only filename & completion status. XYFD_G = GUI; Windows GUI, same behavior as FULLSCREEN */ VOID #ifdef CK_ANSIC ckscreen(int f, char c,CK_OFF_T n,char *s) #else ckscreen(f,c,n,s) int f; char c; CK_OFF_T n; char *s; #endif /* CK_ANSIC */ /* screen */ { char buf[80]; int len; /* Length of string */ #ifdef UNIX #ifndef NOJC int obg; _PROTOTYP( VOID conbgt, (int) ); #endif /* NOJC */ #endif /* UNIX */ int ftp = 0; ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit? */ if (!local && !ftp) /* In remote mode - don't do this */ return; if (!s) s = ""; if (!fxd_inited) /* Initialize if necessary */ fxdinit(fdispla); #ifdef UNIX #ifndef NOJC obg = backgrd; /* Previous background status */ conbgt(1); /* See if running in background */ if (!backgrd && obg) { /* Just came into foreground? */ concb((char)escape); /* Put console back in CBREAK mode */ setint(); /* Restore interrupts */ } #endif /* NOJC */ #endif /* UNIX */ if ((f != SCR_WM) && (f != SCR_EM)) /* Always update warnings & errors */ if (!displa || (backgrd && bgset) || fdispla == XYFD_N || (server && !srvdis) ) return; #ifdef VMS if (f == SCR_FN) /* VMS - shorten the name */ s = zrelname(s,zgtdir()); #endif /* VMS */ if (dest == DEST_S) /* SET DESTINATION SCREEN */ return; /* would interfere... */ #ifdef KUI if (fdispla == XYFD_G) { /* If gui display selected */ screeng(f,c,n,s); /* call the gui version */ return; } #endif /* KUI */ #ifdef CK_CURSES if (fdispla == XYFD_C) { /* If fullscreen display selected */ screenc(f,c,n,s); /* call the fullscreen version */ return; } #endif /* CK_CURSES */ len = (int)strlen(s); /* Length of string */ switch (f) { /* Handle our function code */ case SCR_FN: /* Filename */ if (fdispla == XYFD_B) { #ifdef NEWFTP if (ftp) printf(" %s %s", what & W_SEND ? "PUT" : "GET", s); else #endif /* NEWFTP */ printf(" %s %s", what & W_SEND ? "SEND" : "RECV", s); #ifdef UNIX fflush(stdout); #endif /* UNIX */ return; } #ifdef MAC conoll(""); conol(s); conoc(SP); hpos = len + 1; #else ckstrncpy(fbuf,s,80); abuf[0] = a2buf[0] = NUL; newdpy = 1; /* New file so refresh display */ #endif /* MAC */ return; case SCR_AN: /* As-name */ if (fdispla == XYFD_B) { #ifdef COMMENT printf("(as %s) ",s); #endif /* COMMENT */ return; } #ifdef MAC if (hpos + len > 75) { conoll(""); hpos = 0; } conol("=> "); conol(s); if ((hpos += (len + 3)) > 78) { conoll(""); hpos = 0; } #else if (abuf[0]) { ckstrncpy(a2buf,s,80); } else { ckstrncpy(abuf,s,80); } #endif /* MAC */ return; case SCR_FS: /* File-size */ if (fdispla == XYFD_B) { printf(" (%s) (%s byte%s)", #ifdef NOICP (binary ? "binary" : "text") #else gfmode(binary,0) #endif /* NOICP */ , ckfstoa(n), n == 1 ? "" : "s"); #ifdef UNIX fflush(stdout); #endif /* UNIX */ return; } #ifdef MAC sprintf(buf,", Size: %s",ckfstoa(n)); conoll(buf); hpos = 0; #endif /* MAC */ return; case SCR_XD: /* X-packet data */ if (fdispla == XYFD_B) return; #ifdef MAC conoll(""); conoll(s); hpos = 0; #else ckstrncpy(fbuf,s,80); abuf[0] = a2buf[0] = NUL; #endif /* MAC */ return; case SCR_ST: /* File status */ switch (c) { case ST_OK: /* Transferred OK */ showpkt('Z'); /* Update numbers one last time */ if (fdispla == XYFD_B) { #ifdef GFTIMER if (fpxfsecs) printf(": OK (%0.3f sec, %ld cps)",fpxfsecs, (long)((CKFLOAT)ffc / fpxfsecs)); #else if (xfsecs) printf(": OK (%ld sec, %ld cps)",xfsecs,ffc/xfsecs); #endif /* GFTIMER */ printf("\n"); return; } if ((hpos += 5) > 78) conoll(""); /* Wrap screen line. */ conoll(" [OK]"); hpos = 0; /* Print OK message. */ if (fdispla == XYFD_S) { /* We didn't show Z packet when */ conoc('Z'); /* it came, so show it now. */ hpos = 1; } return; case ST_DISC: /* Discarded */ if (fdispla == XYFD_B) { printf(": DISCARDED\n"); return; } if ((hpos += 12) > 78) conoll(""); conoll(" [discarded]"); hpos = 0; return; case ST_INT: /* Interrupted */ if (fdispla == XYFD_B) { printf(": INTERRUPTED\n"); return; } if ((hpos += 14) > 78) conoll(""); conoll(" [interrupted]"); hpos = 0; return; case ST_SIM: if (fdispla == XYFD_B) { if (n == SKP_XNX) printf(": WOULD BE TRANSFERRED (New file)\n"); else if (n == SKP_XUP) printf(": WOULD BE TRANSFERRED (Remote file older)\n"); else if (n == SKP_SIM) printf(": WOULD BE TRANSFERRED\n"); else if (n > 0 && n < nskreason) printf(": SKIPPED (%s)\n",skreason[n]); else printf(": SKIPPED\n"); return; } else if (fdispla == XYFD_S) { if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */ conoll(""); /* New line */ if (what & W_SEND) conol("Would Send: "); /* Action */ else if (what & W_RECV) conol("Would Receive: "); conol(fbuf); if (*abuf) conol(" => "); conol(abuf); /* Names */ if (*a2buf) conol(" => "); conol(a2buf); /* Names */ *fbuf = NUL; *abuf = NUL; *a2buf = NUL; } conoll(" [simulated]"); return; } if ((hpos += 10) > 78) conoll(""); conol(" [simulated]"); hpos = 0; return; case ST_SKIP: /* Skipped */ if (fdispla == XYFD_B) { if (n == SKP_XNX) printf(": WOULD BE TRANSFERRED (New file)\n"); else if (n == SKP_XUP) printf(": WOULD BE TRANSFERRED (Remote file older)\n"); else if (n == SKP_SIM) printf(": WOULD BE TRANSFERRED\n"); else if (n > 0 && n < nskreason) printf(": SKIPPED (%s)\n",skreason[n]); else printf(": SKIPPED\n"); return; } else if (fdispla == XYFD_S) { if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */ conoll(""); /* New line */ if (what & W_SEND) conol("Sending: "); /* Action */ else if (what & W_RECV) conol("Receiving: "); conol(fbuf); if (*abuf) conol(" => "); conol(abuf); /* Names */ if (*a2buf) conol(" => "); conol(a2buf); /* Names */ *fbuf = NUL; *abuf = NUL; *a2buf = NUL; } conoll(" [skipped]"); return; } if ((hpos += 10) > 78) conoll(""); conol(" "); conol(fbuf); conoll(" [skipped]"); hpos = 0; return; case ST_ERR: /* Error */ if (fdispla == XYFD_B) { printf(": ERROR: %s\n",s); return; } conoll(""); conol("Error: "); conoll(s); hpos = 0; return; case ST_MSG: /* Message */ #ifdef NEWFTP if (fdispla == XYFD_B) { if (ftp && ftp_deb) printf(": MESSAGE: %s\n",s); return; } #endif /* NEWFTP */ conoll(""); conol("Message: "); conoll(s); hpos = 0; return; case ST_REFU: /* Refused */ if (fdispla == XYFD_B) { printf(": REFUSED\n"); return; } else if (fdispla == XYFD_S) { if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */ conoll(""); /* New line */ if (what & W_SEND) conol("Sending: "); /* Action */ else if (what & W_RECV) conol("Receiving: "); conol(fbuf); if (*abuf) conol(" => "); conol(abuf); /* Names */ if (*a2buf) conol(" => "); conol(a2buf); /* Names */ *fbuf = NUL; *abuf = NUL; *a2buf = NUL; conoll(""); } conol("Refused: "); conoll(s); return; } conoll(""); conol("Refused: "); conoll(s); hpos = 0; return; case ST_INC: /* Incomplete */ if (fdispla == XYFD_B) { printf(": INCOMPLETE\n"); return; } if ((hpos += 12) > 78) conoll(""); conoll(" [incomplete]"); hpos = 0; return; default: conoll("*** screen() called with bad status ***"); hpos = 0; return; } #ifdef MAC case SCR_PN: /* Packet number */ if (fdispla == XYFD_B) { return; } ckmakmsg(buf,80,s,": ",ckltoa(n),NULL); conol(buf); hpos += (int)strlen(buf); return; #endif /* MAC */ case SCR_PT: /* Packet type or pseudotype */ if (fdispla == XYFD_B) return; if (c == 'Y') return; /* Don't bother with ACKs */ if (c == 'D') { /* In data transfer phase, */ showpkt(NUL); /* show progress. */ return; } #ifndef AMIGA if (hpos++ > 77) { /* If near right margin, */ conoll(""); /* Start new line */ hpos = 0; /* and reset counter. */ } #endif /* AMIGA */ if (c == 'Z' && fdispla == XYFD_S) return; else conoc(c); /* Display the packet type. */ #ifdef AMIGA if (c == 'G') conoll(""); /* New line after G packets */ #endif /* AMIGA */ return; case SCR_TC: /* Transaction complete */ if (xfrbel) bleep(BP_NOTE); if (fdispla == XYFD_B) { /* Brief display... */ if (filcnt > 1) { long fx; fx = filcnt - filrej; printf(" SUMMARY: %ld file%s", fx, ((fx == 1) ? "" : "s")); printf(", %s byte%s", ckfstoa(tfc), ((tfc == 1) ? "" : "s")); #ifdef GFTIMER printf(", %0.3f sec, %ld cps", fptsecs, tfcps); #else printf(", %d sec, %ld cps", tsecs, tfcps); #endif /* GFTIMER */ printf(".\n"); } } else { conoll(""); } #ifdef UNIX fflush(stdout); #endif /* UNIX */ return; case SCR_EM: /* Error message */ if (fdispla == XYFD_B) { printf(" ERROR: %s\n",s); return; } conoll(""); conoc('?'); conoll(s); hpos = 0; return; case SCR_WM: /* Warning message */ if (fdispla == XYFD_B) { printf(" WARNING: %s\n",s); return; } conoll(""); conoll(s); hpos = 0; return; case SCR_MS: /* Message from other Kermit */ if (fdispla == XYFD_B) { printf(" MESSAGE: %s\n",s); return; } conoll(""); conoll(s); hpos = 0; return; case SCR_TU: /* Undelimited text */ if (fdispla == XYFD_B) return; if ((hpos += len) > 77) { conoll(""); hpos = len; } conol(s); return; case SCR_TN: /* Text delimited at beginning */ if (fdispla == XYFD_B) return; conoll(""); conol(s); hpos = len; return; case SCR_TZ: /* Text delimited at end */ if (fdispla == XYFD_B) return; if ((hpos += len) > 77) { conoll(""); hpos = len; } conoll(s); return; case SCR_QE: /* Quantity equals */ if (fdispla == XYFD_B) return; ckmakmsg(buf,80,s,": ",ckltoa(n),NULL); conoll(buf); hpos = 0; return; case SCR_CW: /* Close fullscreen window */ return; /* No window to close */ case SCR_CD: return; default: conoll("*** screen() called with bad object ***"); hpos = 0; return; } } #endif /* NODISPLAY */ /* E R M S G -- Nonfatal error message */ /* Should be used only for printing the message text from an Error packet. */ VOID #ifdef CK_ANSIC ermsg( char * msg ) /* Print error message */ #else ermsg(msg) char * msg; #endif /* CK_ANSIC */ { debug(F110,"ermsg",msg,0); if (local) xxscreen(SCR_EM,0,0L,msg); tlog(F110,"Protocol Error:",msg,0L); } #endif /* NOXFER */ VOID #ifdef CK_ANSIC setseslog( int x ) #else setseslog(x) int x; #endif /* CK_ANSIC */ { seslog = x; #ifdef KUI KuiSetProperty(KUI_TERM_CAPTURE,x,0); #endif /* KUI */ } VOID #ifdef CK_ANSIC doclean( int fc ) /* General cleanup */ #else doclean(fc) int fc; #endif /* CK_ANSIC */ { #ifdef OS2ORUNIX extern int ttyfd; #endif /* OS2ORUNIX */ extern int keep; extern int exithangup; #ifndef NOXFER extern char filnam[]; #endif /* NOXFER */ #ifndef NOICP int x; if (fc > 0) dostop(); /* Stop all command files and end macros */ #endif /* NOICP */ #ifndef NOXFER if (pktlog) { *pktfil = '\0'; pktlog = 0; zclose(ZPFILE); } #endif /* NOXFER */ if (seslog) { *sesfil = '\0'; setseslog(0); zclose(ZSFILE); } #ifdef TLOG if (tralog) { tlog(F100,"Transaction Log Closed","",0L); *trafil = '\0'; tralog = 0; zclose(ZTFILE); } #endif /* TLOG */ debug(F100,"doclean calling dologend","",0); dologend(); /* End current log record if any */ #ifdef COMMENT if (dialog) { /* If connection log open */ dialog = 0; *diafil = '\0'; /* close it. */ zclose(ZDIFIL); } #endif /* COMMENT */ #ifndef NOICP #ifndef NOSPL zclose(ZRFILE); /* READ and WRITE files, if any. */ zclose(ZWFILE); #ifndef NOXFER zclose(ZIFILE); /* And other files too */ x = chkfn(ZOFILE); /* Download in progress? */ debug(F111,"doclean chkfn ZOFILE",filnam,x); debug(F111,"doclean keep","",keep); zclose(ZOFILE); /* Close output file */ if (x > 0 && !keep) { /* If it was being downloaded */ if (filnam[0]) x = zdelet(filnam); /* Delete if INCOMPLETE = DISCARD */ debug(F111,"doclean download filename",filnam,x); } #endif /* NOXFER */ zclose(ZSYSFN); zclose(ZMFILE); if (fc < 1) { /* RESETing, not EXITing */ #ifdef DEBUG if (deblog) { /* Close the debug log. */ *debfil = '\0'; deblog = 0; zclose(ZDFILE); } #endif /* DEBUG */ return; } #endif /* NOSPL */ #endif /* NOICP */ #ifndef NOLOCAL debug(F101,"doclean exithangup","",exithangup); if (local && exithangup) { /* Close communication connection */ extern int haslock; int x; x = ttchk(); debug(F101,"doclean ttchk()","",x); #ifdef OS2ORUNIX debug(F101,"doclean ttyfd","",ttyfd); #endif /* OS2ORUNIX */ if (x >= 0 #ifdef OS2 || ttyfd != -1 #else #ifdef UNIX || haslock /* Make sure we get lockfile! */ || (!network && ttyfd > -1) #endif /* UNIX */ #endif /* OS2 */ ) { extern int wasclosed, whyclosed; debug(F100,"doclean hanging up and closing","",0); if (msgflg) { #ifdef UNIX fflush(stdout); #endif /* UNIX */ printf("Closing %s...",ttname); } #ifndef NODIAL mdmhup(); /* Hangup the modem??? */ #endif /* NODIAL */ ttclos(0); /* Close external line, if any */ if (msgflg) { printf("OK\n"); #ifdef UNIX fflush(stdout); #endif /* UNIX */ } if (wasclosed) { whyclosed = WC_CLOS; #ifndef NOSPL if (nmac) { /* Any macros defined? */ int k; /* Yes */ k = mlook(mactab,"on_close",nmac); /* Look this up */ if (k >= 0) { /* If found, */ wasclosed = 0; /* printf("ON_CLOSE DOCLEAN\n"); */ *(mactab[k].kwd) = NUL; /* See comment below */ if (dodo(k,ckitoa(whyclosed),0) > -1) /* set it up, */ parser(1); /* and execute it */ } } #endif /* NOSPL */ wasclosed = 0; } } ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty */ local = dfloc; /* And default remote/local status */ } #ifdef DEBUG else if (local) debug(F100,"doclean hangup/close skipped","",0); #endif /* DEBUG */ #endif /* NOLOCAL */ #ifdef NEWFTP ftpbye(); /* If FTP connection open, close it */ #endif /* NEWFTP */ #ifdef IKSD if (inserver) ttclos(0); /* If IKSD, close socket */ #endif /* IKSD */ #ifndef NOSPL /* If a macro named "on_exit" is defined, execute it. Also remove it from the macro table, in case its definition includes an EXIT or QUIT command, which would cause much recursion and would prevent the program from ever actually EXITing. */ if (nmac) { /* Any macros defined? */ int k; /* Yes */ char * cmd = "on_exit"; /* MSVC 2.x compiler error */ k = mlook(mactab,cmd,nmac); /* Look up "on_exit" */ if (k >= 0) { /* If found, */ #ifdef COMMENT /* This makes a mess if ON_EXIT itself executes macros */ *(mactab[k].kwd) = NUL; /* poke its name from the table, */ #else /* Replace the keyword with something that doesn't wreck the */ /* order of the keyword table */ ckstrncpy(mactab[k].kwd,"on_exxx",8); #endif /* COMMENT */ if (dodo(k,"",0) > -1) /* set it up, */ parser(1); /* and execute it */ } } #endif /* NOSPL */ /* Put console terminal back to normal. This is done here because the ON_EXIT macro calls the parser, which meddles with console terminal modes. */ conres(); /* Restore console terminal. */ #ifdef COMMENT /* Should be no need for this, and maybe it's screwing things up? */ connoi(); /* Turn off console interrupt traps */ #endif /* COMMENT */ /* Delete the Startup File if we are supposed to. */ #ifndef NOICP { extern int DeleteStartupFile; debug(F111,"doclean DeleteStartupFile",cmdfil,DeleteStartupFile); if (DeleteStartupFile) { int rc = zdelet(cmdfil); debug(F111,"doclean zdelet",cmdfil,rc); } } #endif /* NOICP */ syscleanup(); /* System-dependent cleanup, last */ } /* D O E X I T -- Exit from the program. */ /* First arg is general, system-independent symbol: GOOD_EXIT or BAD_EXIT. If second arg is -1, take 1st arg literally. If second arg is not -1, work it into the exit code. */ VOID #ifdef CK_ANSIC doexit( int exitstat, int code ) #else doexit(exitstat,code) int exitstat, code; #endif /* CK_ANSIC */ { extern int x_logged, quitting; #ifdef OS2 extern int SysInited; #endif /* OS2 */ #ifdef CK_KERBEROS #ifdef KRB4 extern int krb4_autodel; #endif /* KRB4 */ #ifdef KRB5 extern int krb5_autodel; #endif /* KRB5 */ #endif /* CK_KERBEROS */ #ifdef VMS char envstr[64]; static $DESCRIPTOR(symnam,"CKERMIT_STATUS"); static struct dsc$descriptor_s symval; #endif /* VMS */ int i; #ifdef DEBUG #ifdef USE_LUCACHE extern long lucalls, luhits, xxhits, luloop; extern int lusize; #endif /* USE_LUCACHE */ #ifndef NOSPL extern int cmdstats[]; #endif /* NOSPL */ quitting++; #ifdef OS2 if ( !SysInited ) { static int initing = 0; if ( initing ) exit(253); initing = 1; sysinit(); } #endif /* OS2 */ if (deblog) { #ifdef USE_LUCACHE debug(F101,"lookup cache size","",lusize); debug(F101,"lookup calls ....","",lucalls); debug(F101,"lookup cache hits","",luhits); debug(F101,"lookup start hits","",xxhits); debug(F101,"lookup loop iterations","",luloop); #endif /* USE_LUCACHE */ #ifndef NOSPL for (i = 0; i < 256; i++) { if (cmdstats[i]) debug(F111,"CMSTATS",ckitoa(i),cmdstats[i]); } #endif /* NOSPL */ debug(F101,"doexit exitstat","",exitstat); debug(F101,"doexit code","",code); debug(F101,"doexit xitsta","",xitsta); } #endif /* DEBUG */ #ifdef CK_KERBEROS /* If we are automatically destroying Kerberos credentials on Exit */ /* do it now. */ #ifdef KRB4 if (krb4_autodel == KRB_DEL_EX) { extern struct krb_op_data krb_op; krb_op.version = 4; krb_op.cache = NULL; ck_krb4_destroy(&krb_op); } #endif /* KRB4 */ #ifdef KRB5 if (krb5_autodel == KRB_DEL_EX) { extern struct krb_op_data krb_op; extern char * krb5_d_cc; krb_op.version = 5; krb_op.cache = krb5_d_cc; ck_krb5_destroy(&krb_op); } #endif /* KRB5 */ #endif /* CK_KERBEROS */ #ifndef NOLOCAL #ifdef OS2 if (SysInited) { #ifdef DCMDBUF extern struct cmdptr *cmdstk; #else extern struct cmdptr cmdstk[]; #endif /* DCMDBUF */ extern int tt_status[]; extern BYTE vmode; #ifndef KUI /* This is going to be hideous. If we have a status line */ /* in the command window turn it off before we exit. */ if ( tt_status[VCMD] && vmode == VCMD ) { domac("_clear_statusline","set command statusline off", cmdstk[cmdlvl].ccflgs); delmac("_clear_statusline",1); RequestScreenMutex(-1); VscrnIsDirty(vmode); ReleaseScreenMutex(); while ( IsVscrnDirty(vmode) ) msleep(200); RequestScreenMutex(-1); ReleaseScreenMutex(); } #endif /* KUI */ DialerSend(OPT_KERMIT_EXIT,exitstat); #ifndef KUI debug(F100,"doexit about to msleep","",0); if ( isWin95() ) msleep(250); #endif /* KUI */ } #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef IKSD #ifdef CK_LOGIN if (inserver && x_logged) { #ifndef NOSPL /* If a macro named "on_logout" is defined, execute it. Also remove it from the macro table, in case its definition includes an EXIT or QUIT command, which would cause much recursion and would prevent the program from ever actually EXITing. */ if (nmac) { /* Any macros defined? */ int k; /* Yes */ char * cmd = "on_logout"; /* MSVC 2.x compiler error */ k = mlook(mactab,cmd,nmac); /* Look up "on_logout" */ if (k >= 0) { /* If found, */ *(mactab[k].kwd) = NUL; /* poke its name from the table, */ if (dodo(k,"",0) > -1) /* set it up, */ parser(1); /* and execute it */ } } #endif /* NOSPL */ zvlogout(); } #endif /* CK_LOGIN */ #endif /* IKSD */ debug(F100,"doexit about to doclean","",0); doclean(1); /* Clean up most things */ #ifdef VMS if (code == -1) code = 0; /* Since we set two different items */ sprintf(envstr,"%d", exitstat | code); /* SAFE */ symval.dsc$w_length = (int)strlen(envstr); symval.dsc$a_pointer = envstr; symval.dsc$b_class = DSC$K_CLASS_S; symval.dsc$b_dtype = DSC$K_DTYPE_T; i = 2; /* Store in global table */ #ifdef COMMENT /* Martin Zinser */ LIB$SET_SYMBOL(&symnam, &symval, &i); #else lib$set_symbol(&symnam, &symval, &i); #endif /* COMMENT */ if (exitstat == BAD_EXIT) exitstat = SS$_ABORT | STS$M_INHIB_MSG; if (exitstat == GOOD_EXIT) exitstat = SS$_NORMAL | STS$M_INHIB_MSG; #else /* Not VMS */ if (code != -1) /* Take 1st arg literally */ exitstat |= code; #endif /* VMS */ #ifndef NOICP #ifdef IKSD #ifdef IKSDB debug(F101,"doexit ikdbopen","",ikdbopen); if (ikdbopen && dbfp) { /* If IKSD database open */ int x; x = freeslot(mydbslot); /* Free our slot... */ debug(F101,"doexit freeslot","",x); fclose(dbfp); /* and close it. */ } #endif /* IKSDB */ #endif /* IKSD */ #endif /* NOICP */ /* We have put this off till the very last moment... */ #ifdef DEBUG if (deblog) { /* Close the debug log. */ debug(F101,"C-Kermit EXIT status","",exitstat); *debfil = '\0'; deblog = 0; zclose(ZDFILE); } #endif /* DEBUG */ #ifdef OS2 _exit(exitstat); /* Exit from C-Kermit (no matter what) */ #else /* OS2 */ exit(exitstat); /* Exit from C-Kermit */ #endif /* OS2 */ } VOID bgchk() { /* Check background status */ if (bgset < 0) { /* They didn't type SET BACKGROUND */ #ifdef VMS /* Set prompt flag based on */ pflag = !batch; /* what we detected at startup. */ #else pflag = !backgrd; #endif /* VMS */ } else { /* Otherwise SET BACKGROUND value */ pflag = (bgset == 0 ? 1 : 0); } #ifndef NOICP /* Message flag on only if at top level, pflag is on, and QUIET is OFF */ if (!xcmdsrc) msgflg = (pflag == 0) ? 0 : !quiet; else msgflg = 0; #else msgflg = 0; #endif /* NOICP */ } /* Set console interrupts */ VOID setint() { /* According to SET COMMAND INTERRUP */ int x = 0; if (cmdint) x |= 1; if (xsuspend) x |= 2; debug(F101,"setint","",x); switch (x) { /* Set the desired combination */ case 0: connoi(); break; /* No interrupts */ case 1: conint(trap,SIG_IGN); break; case 2: conint(SIG_IGN,stptrap); break; case 3: conint(trap,stptrap); break; } bgchk(); /* Check background status */ } #ifdef DEBUG /* D E B U G -- Enter a record in the debugging log */ /* Call with a format, two strings, and a number: f - Format, a bit string in range 0-7. If bit x is on, then argument number x is printed. s1 - String, argument number 1. If selected, printed as is. s2 - String, argument number 2. If selected, printed in brackets. n - Long int, argument 3. If selected, printed preceded by equals sign. f=0 is special: print s1,s2, and interpret n as a char. f=F011 (3) is also special; in this case s2 is interpeted as a counted string that might contain NULs. n is the length. If n is negative, this means the string has been truncated and ".." should be printed after the first n bytes. NUL and LF bytes are printed as "" and "". Globals: deblog: nonzero if debug log open. debok: nonzero if ok to write entries. */ /* WARNING: Don't change DEBUFL without changing sprintf() formats below, accordingly. */ #define DBUFL 4000 /* WARNING: This routine is not thread-safe, especially when Kermit is executing on multiple CPUs -- as different threads write to the same static buffer, the debug statements are all interleaved. To be fixed later... */ static char *dbptr = (char *)0; int #ifdef CK_ANSIC dodebug(int f, char *s1, char *s2, CK_OFF_T n) #else dodebug(f,s1,s2,n) int f; char *s1, *s2; CK_OFF_T n; #endif /* CK_ANSIC */ /* dodebug */ { char *sp; int len1, len2; extern int debtim; #ifdef OS2 extern int SysInited; #endif /* OS2 */ if (!deblog || !debok) return(0); #ifdef COMMENT /* expensive... */ if (!chkfn(ZDFILE)) /* Debug log not open, don't. */ return(0); #endif /* COMMENT */ if (!dbptr) { /* Allocate memory buffer */ dbptr = malloc(DBUFL+4); /* This only happens once */ if (!dbptr) { zclose(ZDFILE); return(0); } } /* This prevents infinite recursion in case we accidentally put a debug() call in this routine, or call another routine that contains debug() calls. From this point on, all returns from this return must be via goto xdebug, which sets deblog back to 1. */ #ifdef OS2 if (SysInited) { if (RequestDebugMutex(30000)) goto xdebug; } #else /* OS2 */ deblog = 0; /* Prevent infinite recursion */ #endif /* OS2 */ if (debtim) { /* Timestamp */ char *tb, tsbuf[48]; ztime(&tb); ckstrncpy(tsbuf,tb,32); if (ztmsec > -1L) { sprintf(tsbuf+19,".%03ld ",ztmsec); /* SAFE */ } else { tsbuf[19] = ':'; tsbuf[20] = SP; tsbuf[21] = NUL; } zsout(ZDFILE,tsbuf+11); } if (!s1) s1="(NULL)"; if (!s2) s2="(NULL)"; len1 = strlen(s1); len2 = strlen(s2); #ifdef COMMENT /* This should work, but it doesn't. So instead we'll cope with overflow via sprintf formats. N.B.: UNFORTUNATELY, this means we have to put constants in the sprintf formats. */ if (f != F011 && (!f || (f & 6))) { /* String argument(s) included? */ x = (int) strlen(s1) + (int) strlen(s2) + 18; if (x > dbufl) { /* Longer than buffer? */ if (dbptr) /* Yes, free previous buffer */ free(dbptr); dbptr = (char *) malloc(x + 2); /* Allocate a new one */ if (!dbptr) { zsoutl(ZDFILE,"DEBUG: Memory allocation failure"); deblog = 0; zclose(ZDFILE); goto xdebug; } else { dbufl = x; sprintf(dbptr,"DEBUG: Buffer expanded to %d\n", x + 18); zsoutl(ZDFILE,dbptr); } } } #endif /* COMMENT */ #ifdef COMMENT /* The aforementioned sprintf() formats were like this: */ if (n > 31 && n < 127) sprintf(sp,"%.100s%.2000s:%c\n",s1,s2,(CHAR) n); else if (n < 32 || n == 127) sprintf(sp,"%.100s%.2000s:^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F)); else if (n > 127 && n < 160) sprintf(sp,"%.100s%.2000s:~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F)); else if (n > 159 && n < 256) sprintf(sp,"%.100s%.2000s:~%c\n",s1,s2,(CHAR) (n & 0x7F)); else sprintf(sp,"%.100s%.2000s:%ld\n",s1,s2,n); /* But, naturally, it turns out these are not portable either, so now we do the stupidest possible thing. */ #endif /* COMMENT */ #ifdef BIGBUFOK /* Need to accept longer strings when debugging authenticated connections */ if (f == F010) { if (len2 + 2 >= DBUFL) s2 = "(string too long)"; } else if (f != F011 && f != F100) { if (len1 > 100) s1 = "(string too long)"; if (len2 + 101 >= DBUFL) s2 = "(string too long)"; } #else if (f != F011) { if (len1 > 100) s1 = "(string too long)"; if (len2 + 101 >= DBUFL) s2 = "(string too long)"; } #endif /* BIGBUFOK */ sp = dbptr; switch (f) { /* Write log record according to format. */ case F000: /* 0 = print both strings, and n as a char. */ if (len2 > 0) { if ((n > 31 && n < 127) || (n > 159 && n < 256)) sprintf(sp,"%s[%s]=%c\n",s1,s2,(CHAR) n); else if (n < 32 || n == 127) sprintf(sp,"%s[%s]=^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F)); else if (n > 127 && n < 160) sprintf(sp,"%s[%s]=~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F)); else sprintf(sp,"%s[%s]=0x%lX\n",s1,s2,(long)n); } else { if ((n > 31 && n < 127) || (n > 159 && n < 256)) sprintf(sp,"%s=%c\n",s1,(CHAR) n); else if (n < 32 || n == 127) sprintf(sp,"%s=^%c\n",s1,(CHAR) ((n+64) & 0x7F)); else if (n > 127 && n < 160) sprintf(sp,"%s=~^%c\n",s1,(CHAR)((n-64) & 0x7F)); else sprintf(sp,"%s=0x%lX\n",s1,(long)n); } if (zsout(ZDFILE,dbptr) < 0) { deblog = 0; zclose(ZDFILE); } #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_DB && ckxlogging) { cksyslog(SYSLG_DB,1,"debug",dbptr,NULL); } #endif /* CKSYSLOG */ break; case F001: /* 1, "=n" */ #ifdef COMMENT /* This was never used */ sprintf(sp,"=%s\n",ckfstoa(n)); #else /* Like F111, but shows number n in hex */ ckmakxmsg(sp,DBUFL, s1, (*s1 ? ":" : ""), s2, (*s2 ? ":" : ""), ckltox(n), "\n", NULL,NULL,NULL,NULL,NULL,NULL ); #endif /* COMMENT */ if (zsout(ZDFILE,dbptr) < 0) { deblog = 0; zclose(ZDFILE); } #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_DB && ckxlogging) { cksyslog(SYSLG_DB,1,"debug",dbptr,NULL); } #endif /* CKSYSLOG */ break; /* This one was never used so (October 2000) we now use it like F011, except in this case we treat s2 as NUL terminated. */ case F010: n = -debxlen; /* This one treats n as the length of the string s2, which may contain NULs. It's good for logging NUL-bearing data in the debug log. */ case F011: { int i, j, contd = 0; char * p = s2, *pbuf = NULL; /* p = source pointer */ int m; /* pbuf = destination pointer */ if (f == F011) { if (n < 0) { /* n = size of source */ n = 0 - n; /* Negative means to add "..." */ contd = 1; } } else { int x, flag = 0; x = strlen(s2); if (n < 0) { flag = 1; n = 0 - n; } if (x < n) n = x; } if (n == 0) /* 0 means do nothing */ goto xdebug; m = DBUFL - 8; /* Get size for interpreted part */ if (n > m) /* Ensure requested size not too big */ n = m; pbuf = dbptr; /* Construction pointer */ i = 0; pbuf[i++] = '['; /* Interpret the string into it */ for (j = 0; j < n && i < m-4; p++,j++) { /* char by char... */ if (*p == LF) { if (i >= m-4) break; pbuf[i++] = '<'; pbuf[i++] = 'L'; pbuf[i++] = 'F'; pbuf[i++] = '>'; continue; } else if (*p == CK_CR) { if (i >= m-4) break; pbuf[i++] = '<'; pbuf[i++] = 'C'; pbuf[i++] = 'R'; pbuf[i++] = '>'; continue; } else if (*p == HT) { if (i >= m-5) break; pbuf[i++] = '<'; pbuf[i++] = 'T'; pbuf[i++] = 'A'; pbuf[i++] = 'B'; pbuf[i++] = '>'; continue; } else if (*p) { pbuf[i++] = *p; continue; } else { if (i >= m-5) break; pbuf[i++] = '<'; pbuf[i++] = 'N'; pbuf[i++] = 'U'; pbuf[i++] = 'L'; pbuf[i++] = '>'; continue; } } if (i < m-2 && (*p || contd)) { pbuf[i++] = '.'; pbuf[i++] = '.'; } pbuf[i++] = ']'; pbuf[i] = NUL; if (zsout(ZDFILE,s1) < 0) { deblog = 0; zclose(ZDFILE); } if (zsoutl(ZDFILE,pbuf) < 0) { deblog = 0; zclose(ZDFILE); } #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_DB && ckxlogging) { cksyslog(SYSLG_DB,1,"debug",s1,pbuf); } #endif /* CKSYSLOG */ } break; case F100: /* 4, "s1" */ if (zsoutl(ZDFILE,s1) < 0) { deblog = 0; zclose(ZDFILE); } #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_DB && ckxlogging) { cksyslog(SYSLG_DB,1,"debug",s1,NULL); } #endif /* CKSYSLOG */ break; case F101: /* 5, "s1=n" */ sprintf(sp,"%s=%s\n",s1,ckfstoa(n)); if (zsout(ZDFILE,dbptr) < 0) { deblog = 0; zclose(ZDFILE); } #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_DB && ckxlogging) { cksyslog(SYSLG_DB,1,"debug",dbptr,NULL); } #endif /* CKSYSLOG */ break; case F110: /* 6, "s1[s2]" */ sprintf(sp,"%s[%s]\n",s1,s2); if (zsout(ZDFILE,dbptr) < 0) { deblog = 0; zclose(ZDFILE); } #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_DB && ckxlogging) { cksyslog(SYSLG_DB,1,"debug",dbptr,NULL); } #endif /* CKSYSLOG */ break; case F111: /* 7, "s1[s2]=n" */ sprintf(sp,"%s[%s]=%s\n",s1,s2,ckfstoa(n)); if (zsout(ZDFILE,dbptr) < 0) { deblog = 0; zclose(ZDFILE); } #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_DB && ckxlogging) { cksyslog(SYSLG_DB,1,"debug",dbptr,NULL); } #endif /* CKSYSLOG */ break; default: sprintf(sp,"\n?Invalid format for debug() - %d\n",f); if (zsout(ZDFILE,dbptr) < 0) { deblog = 0; zclose(ZDFILE); } #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_DB && ckxlogging) { cksyslog(SYSLG_DB,1,"debug",dbptr,NULL); } #endif /* CKSYSLOG */ break; } xdebug: /* Common exit point */ #ifdef OS2 if (SysInited) ReleaseDebugMutex(); #else /* OS2 */ deblog = 1; /* Restore this */ #endif /* OS2 */ return(0); } int #ifdef CK_ANSIC dohexdump(CHAR *msg, CHAR *st, int cnt) #else dohexdump(msg,st,cnt) CHAR *msg; CHAR *st; int cnt; #endif /* CK_ANSIC */ /* dohexdump */ { int i = 0, j = 0, k = 0; char tmp[8]; #ifdef OS2 extern int SysInited; #endif /* OS2 */ if (!deblog) return(0); /* If no debug log, don't. */ if (!dbptr) { /* Allocate memory buffer */ dbptr = malloc(DBUFL+1); /* This only happens once */ if (!dbptr) { deblog = 0; zclose(ZDFILE); return(0); } } #ifdef OS2 if (SysInited) { if (RequestDebugMutex(30000)) goto xdebug; } #else /* OS2 */ deblog = 0; /* Prevent infinite recursion */ #endif /* OS2 */ if (msg != NULL) { ckmakxmsg(dbptr, DBUFL, "HEXDUMP: ", (char *)msg, " (", ckitoa(cnt), " bytes)\n", NULL,NULL,NULL,NULL,NULL,NULL,NULL ); if (zsout(ZDFILE,dbptr) < 0) { deblog = 0; zclose(ZDFILE); goto xdebug; } } else { ckmakmsg(dbptr, DBUFL, "HEXDUMP: (", ckitoa(cnt), " bytes)\n", NULL ); zsout(ZDFILE,dbptr); if (zsout(ZDFILE,dbptr) < 0) { deblog = 0; zclose(ZDFILE); goto xdebug; } } for (i = 0; i < cnt; i++) { dbptr[0] = '\0'; for (j = 0 ; (j < 16); j++) { if ((i + j) < cnt) sprintf(tmp, "%s%02x ", (j == 8 ? "| " : ""), (CHAR) st[i + j] ); else sprintf(tmp, "%s ", (j == 8 ? "| " : "") ); ckstrncat(dbptr,tmp,DBUFL+1); } ckstrncat(dbptr," ",DBUFL+1); for (k = 0; (k < 16) && ((i + k) < cnt); k++) { sprintf(tmp, "%s%c", (k == 8 ? " " : ""), isprint(st[i + k]) ? st[i + k] : '.' ); ckstrncat(dbptr,tmp,DBUFL+1); } ckstrncat(dbptr,"\n",DBUFL+1); i += j - 1; if (zsout(ZDFILE,dbptr) < 0) { deblog = 0; zclose(ZDFILE); goto xdebug; } } /* end for */ xdebug: #ifdef OS2 if (SysInited) ReleaseDebugMutex(); #else /* OS2 */ deblog = 1; #endif /* OS2 */ return(0); } #endif /* DEBUG */ /* Session Log... */ int tsstate = 0; VOID #ifdef OS2 logchar(unsigned short c) #else /* OS2 */ #ifdef CK_ANSIC logchar(char c) #else logchar(c) char c; #endif /* CK_ANSIC */ #endif /* OS2 */ /* logchar */ { /* Log character c to session log */ extern int slognul; int oktolog = 0; #ifndef NOLOCAL if (!seslog) return; if ((sessft != XYFT_T) || ( #ifdef UNIX c != '\r' && #else #ifdef datageneral c != '\r' && #else #ifdef STRATUS c != '\r' && #else #ifdef AMIGA c != '\r' && #else #ifdef GEMDOS c != '\r' && #endif /* GEMDOS */ #endif /* AMIGA */ #endif /* STRATUS */ #endif /* datageneral */ #endif /* UNIX */ #ifdef OSK c != '\n' && #else #ifdef MAC c != '\n' && #endif /* MAC */ #endif /* OSK */ c != XON && c != XOFF)) oktolog = 1; if (c == '\0' && !sessft) /* NUL in text mode */ if (slognul) oktolog = 1; /* only if padding (2009/10/22) */ if (!oktolog) return; if (slogts) { /* Log is timestamped */ if (tsstate == 0) { /* State = between-lines */ char * p; /* zstime() pointer */ char ts[48]; /* timestamp buffer */ ztime(&p); /* Get asctime() string */ ckstrncpy(ts,p,32); /* Make safe copy */ if (ztmsec > -1L) { /* Add msecs if we have them */ sprintf(&ts[19],".%03ld: ",ztmsec); /* SAFE */ } else { ts[19] = ':'; ts[20] = SP; ts[21] = NUL; } if (zsout(ZSFILE,&ts[11]) < 0) goto xlogchar; } } if (c == '\n') /* At end of line? */ tsstate = 0; /* yes */ else tsstate = 1; /* no */ if (zchout(ZSFILE,(CHAR)(c & 0xFF)) < 0) /* Log the character */ goto xlogchar; if (tsstate == 0 && slognul != 0) { /* Null-terminating lines? */ if (zchout(ZSFILE,(CHAR)0) < 0) /* Add a NUL */ goto xlogchar; } return; xlogchar: conoll(""); conoll("ERROR WRITING SESSION LOG, LOG CLOSED!"); setseslog(0); zclose(ZSFILE); #endif /* NOLOCAL */ } VOID #ifdef CK_ANSIC logstr(char * s, int len ) /* Log string to session log */ #else logstr(s, len) char * s; int len; #endif /* CK_ANSIC */ { #ifndef NOLOCAL int n = 0; if (!s) return; while (seslog && (n < len)) logchar(s[n++]); #endif /* NOLOCAL */ } #ifdef CK_CURSES int ck_repaint() { repaint = 1; return(0); } #ifdef STRATUS /* VOS has curses but no tgetent() */ int tgetent(s1, s2) char * s1, * s2; { return(1); } #endif /* STRATUS */ #ifdef VMS #ifdef __DECC _PROTOTYP(int tgetent,(char *, char *)); #endif /* __DECC */ #endif /* VMS */ /* There are three different ways to do fullscreen on VMS. 1. Use the real curses library, VAXCCURSE. 2. Use do-it-yourself code. 3. Use the Screen Manager, SMG$. Method 1 doesn't work quite right; you can't call endwin(), so once you've started curses mode, you can never leave. Method 2 doesn't optimize the screen, and so much more time is spent in screen writes. This actually causes file transfers to fail because the tty device input buffer can be overrun while the screen is being updated, especially on a slow MicroVAX that has small typeahead buffers. In the following #ifdef block, #define one of them and #undef the other 2. So now let's try method 3... */ #ifdef VMS #define CK_SMG /* Screen Manager */ #undef MYCURSES /* Do-it-yourself */ #undef VMSCURSE /* VAXCCURSE library */ #endif /* VMS */ /* But just before New Years, 2000, the SMG library seemed to break on both VMS systems we have here (an Alpha with VMS 7.1 and a VAX with 5.5). So back to MYCURSES, which works fine. */ #ifdef VMS #undef CK_SMG #define MYCURSES #endif /* VMS */ #ifdef MYCURSES #define stdscr 0 #ifdef CK_WREFRESH #undef CK_WREFRESH #endif /* CK_WREFRESH */ #endif /* MYCURSES */ /* S C R E E N C -- Screen display function, uses curses */ /* Idea for curses display contributed by Chris Pratt of APV Baker, UK */ /* Avoid conficts with curses.h */ #ifdef QNX /* Same as ckcasc.h, but in a different radix... */ #ifdef ESC #undef ESC #endif /* ESC */ #endif /* QNX */ #ifndef MYCURSES #undef VOID /* This was defined in ckcdeb.h */ #endif /* MYCURSES */ #undef BS /* These were defined in ckcasc.h */ #undef CR #undef NL #undef SO #ifdef US #undef US #endif /* US */ #undef SP /* Used in ncurses */ #define CHR_SP 32 /* Use this instead */ #ifdef VMS /* VMS fullscreen display */ #ifdef MYCURSES /* Do-it-yourself method */ extern int isvt52; /* From CKVTIO.C */ #define printw printf #else #ifdef VMSCURSE /* VMS curses library VAXCCURSE */ #include /* Note: Screen manager doesn't need a header file */ #endif /* VMSCURSE */ #endif /* MYCURSES */ #else /* Not VMS */ #ifdef MYCURSES /* Do-it-yourself method */ #define isvt52 0 /* Used by OS/2, VT-100/ANSI always */ #ifdef CKXPRINTF #define printw ckxprintf #else /* CKXPRINTF */ #ifdef KUI #define printw Vscrnprintw #else /* KUI */ #define printw printf #endif /* KUI */ #endif /* CKXPRINTF */ #else /* Use real curses */ #ifdef CK_NCURSES /* or ncurses... */ #ifdef CKXPRINTF /* Our printf macro conflicts with */ #undef printf /* use of "printf" in ncurses.h */ #endif /* CKXPRINTF */ #include #ifdef CKXPRINTF #define printf ckxprintf #endif /* CKXPRINTF */ #else /* Not ncurses */ #ifdef CKXPRINTF /* Our printf macro conflicts with */ #undef printf /* use of "printf" in curses.h */ #endif /* CKXPRINTF */ #ifdef M_XENIX /* SCO XENIX... */ #ifdef M_TERMCAP #undef M_TERMCAP #endif /* M_TERMCAP */ #ifndef M_TERMINFO #define M_TERMINFO #endif /* M_TERMINFO */ #endif /* M_XENIX */ #ifdef RTAIX #undef NLS /* Avoid 'redeclaration of free'. */ #endif /* RTAIX */ #include #ifdef CKXPRINTF #define printf ckxprintf #endif /* CKXPRINTF */ #endif /* CK_NCURSES */ #endif /* MYCURSES */ #endif /* VMS */ #endif /* CK_CURSES */ /* F X D I N I T -- File Xfer Display Initialization */ #ifdef CK_CURSES #ifndef MYCURSES #ifndef CK_SMG static #ifdef CK_ANSIC /* Can't use VOID because of curses.h */ void ck_termset(int); #else ck_termset(); #endif /* CK_ANSIC */ #endif /* CK_SMG */ #endif /* MYCURSES */ #endif /* CK_CURSES */ #ifndef OS2 #ifdef NOTERMCAP static int notermcap = 1; #else static int notermcap = 0; #endif /* NOTERMCAP */ #endif /* OS2 */ #ifndef NODISPLAY CKVOID #ifdef CK_ANSIC fxdinit(int xdispla ) #else fxdinit(xdispla) int xdispla; #endif /* CK_ANSIC */ { #ifndef COHERENT #ifndef OS2 #ifndef STRATUS char *s; int x, dummy; debug(F101,"fxdinit xdispla","",xdispla); debug(F101,"fxdinit fxd_inited","",fxd_inited); #ifdef IKSD #ifndef NOXFER /* No curses for IKSD */ if (inserver) { fdispla = XYFD_N; return; } if (fxd_inited) /* Only do this once */ return; #endif /* NOXFER */ #endif /* IKSD */ if (xdispla == XYFD_R || xdispla == XYFD_S || xdispla == XYFD_B) { if (xfrmsg) { printf("%s\n",xfrmsg); makestr(&xfrmsg,NULL); } } #ifdef CK_CURSES #ifdef VMS /* Force BRIEF in Batch logs */ if (batch && (xdispla == XYFD_C || xdispla == XYFD_S)) xdispla = XYFD_B; #else if (xdispla == XYFD_C || xdispla == 9999) { #ifdef DYNAMIC if (!trmbuf) { /* Allocate tgetent() buffer. Make it big -- some termcaps can be huge; tgetent() merrily writes past the end of the buffer, causing core dumps or worse. */ trmbuf = (char *)malloc(TRMBUFL); if (!trmbuf) { notermcap = 1; debug(F101,"fxdinit malloc trmbuf","FAILED",TRMBUFL); fdispla = XYFD_S; return; } #ifdef COMMENT debug(F111,"fxdinit malloc trmbuf","OK",TRMBUFL); debug(F001,"fxdinit trmbuf","",trmbuf); memset(trmbuf,'\0',(size_t)TRMBUFL); debug(F100,"fxdinit memset OK","",0); #endif /* COMMENT */ } #endif /* DYNAMIC */ debug(F100,"fxdinit before getenv(TERM)","",0); s = getenv("TERM"); debug(F110,"fxdinit after getenv(TERM)",s,0); if (!s) s = ""; if (*s) { debug(F110,"fxdinit before tgetent()",s,0); x = tgetent(trmbuf,s); debug(F111,"fxdinit tgetent",s,x); } else { x = 0; notermcap = 1; debug(F110,"fxdinit TERM null - no tgetent",s,0); } if (x < 1 && !quiet && !backgrd #ifdef VMS && !batch #endif /* VMS */ ) { printf("Warning: terminal type unknown: \"%s\"\n",s); #ifdef COMMENT /* Confusing - nobody knows what this means */ printf("SCREEN command will use ANSI sequences.\n"); #endif /* COMMENT */ if (local) printf("Fullscreen file transfer display disabled.\n"); fdispla = XYFD_S; } #ifndef MYCURSES #ifndef CK_SMG ck_termset(x); #endif /* CK_SMG */ #endif /* MYCURSES */ fxd_inited = 1; } #endif /* CK_CURSES */ #endif /* VMS */ #endif /* STRATUS */ #endif /* OS2 */ #endif /* COHERENT */ } #endif /* NODISPLAY */ #ifdef CK_CURSES #ifdef CK_SMG /* Long section for Screen Manager starts here... By William Bader. */ #include "ckvvms.h" #ifdef OLD_VMS #include /* use this on VAX C 2.4 */ /* #include */ #else #include /* Martin Zinser */ #endif /* OLD_VMS */ extern unsigned int vms_status; /* Used for system service return status */ static long smg_pasteboard_id = -1; /* pasteboard identifier */ static long smg_display_id = -1; /* display identifier */ static int smg_open = 0; /* flag if smg current open */ static int smg_inited = 0; /* flag if smg initialized */ #ifdef COMMENT #define clrtoeol() SMG$ERASE_LINE(&smg_display_id, 0, 0) #define clear() SMG$ERASE_DISPLAY(&smg_display_id, 0, 0, 0, 0) #define touchwin(scr) SMG$REPAINT_SCREEN(&smg_pasteboard_id) #else /* Not COMMENT */ #define clrtoeol() smg$erase_line(&smg_display_id, 0, 0) #define clear() smg$erase_display(&smg_display_id, 0, 0, 0, 0) #define touchwin(scr) smg$repaint_screen(&smg_pasteboard_id) #endif /* COMMENT */ #define clearok(curscr,ok) /* Let wrefresh() do the work */ #define wrefresh(cursrc) touchwin(scr) static void #ifdef CK_ANSIC move(int row, int col) #else move(row, col) int row; int col; #endif /* CK_ANSIC */ { /* Change from 0-based for curses to 1-based for SMG */ if (!smg_open) return; ++row; ++col; debug(F111,"VMS smg move",ckitoa(row),col); #ifdef COMMENT /* Martin Zinser */ CHECK_ERR("move: smg$set_cursor_abs", SMG$SET_CURSOR_ABS(&smg_display_id, &row, &col)); #else CHECK_ERR("move: smg$set_cursor_abs", smg$set_cursor_abs(&smg_display_id, &row, &col)); #endif /* COMMENT */ debug(F101,"VMS smg move vms_status","",vms_status); } #ifdef VMS_V40 #define OLD_VMS #endif /* VMS_V40 */ #ifdef VMS_V42 #define OLD_VMS #endif /* VMS_V42 */ #ifdef VMS_V44 #define OLD_VMS #endif /* VMS_V44 */ static int initscr() { int rows = 24, cols = 80; int row = 1, col = 1; debug(F101,"VMS initscr smg_pasteboard_id A","",smg_pasteboard_id); if (smg_pasteboard_id == -1) { /* Open the screen */ #ifdef OLD_VMS /* Note: Routine calls lowercased 9/96 */ CHECK_ERR("initscr: smg$create_pasteboard", smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0)); #else /* For VMS V5, not tested */ CHECK_ERR("initscr: smg$create_pasteboard", smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0, 0)); #endif /* OLD_VMS */ } debug(F101,"VMS initscr smg_pasteboard_id B","",smg_pasteboard_id); if (smg_pasteboard_id == -1) { printf("?Error initializing fullscreen display\n"); fdispla = XYFD_S; dpyinit(); return(0); } debug(F101,"VMS initscr smg_display_id","",smg_display_id); if (smg_display_id == -1) { /* Create a display window */ #ifdef COMMENT /* Martin Zinser */ CHECK_ERR("initscr: smg$create_virtual_display", SMG$CREATE_VIRTUAL_DISPLAY(&rows, &cols, &smg_display_id, 0, 0, 0)); /* Connect the display window to the screen */ CHECK_ERR("initscr: smg$paste_virtual_display", SMG$PASTE_VIRTUAL_DISPLAY(&smg_display_id,&smg_pasteboard_id, &row,&col)); #else CHECK_ERR("initscr: smg$create_virtual_display", smg$create_virtual_display(&rows, &cols, &smg_display_id, 0, 0, 0)); /* Connect the display window to the screen */ CHECK_ERR("initscr: smg$paste_virtual_display", smg$paste_virtual_display(&smg_display_id,&smg_pasteboard_id, &row,&col)); #endif /* COMMENT */ } debug(F101,"VMS initscr smg_open A","",smg_open); if (!smg_open) { /* Start a batch update */ smg_open = 1; #ifdef COMMENT CHECK_ERR("initscr: smg$begin_pasteboard_update", SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id)); #else CHECK_ERR("initscr: smg$begin_pasteboard_update", smg$begin_pasteboard_update(&smg_pasteboard_id)); #endif /* COMMENT */ debug(F101,"VMS initscr smg$begin_pasteboard_update","",vms_status); } debug(F101,"VMS initscr smg_open B","",smg_open); smg_inited = 1; return(1); } static void refresh() { debug(F101,"refresh smg_pasteboard_id","",smg_pasteboard_id); if (smg_open == 0 || smg_pasteboard_id == -1) return; #ifdef COMMENT /* Martin Zinser */ CHECK_ERR("refresh: smg$end_pasteboard_update", SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id)); CHECK_ERR("refresh: smg$begin_pasteboard_update", SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id)); #else CHECK_ERR("refresh: smg$end_pasteboard_update", smg$end_pasteboard_update(&smg_pasteboard_id)); CHECK_ERR("refresh: smg$begin_pasteboard_update", smg$begin_pasteboard_update(&smg_pasteboard_id)); #endif /* COMMENT */ } static void endwin() { if (!smg_open) return; smg_open = 0; #ifdef COMMENT CHECK_ERR("endwin: smg$end_pasteboard_update", SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id)); #else CHECK_ERR("endwin: smg$end_pasteboard_update", smg$end_pasteboard_update(&smg_pasteboard_id)); #endif /* COMMENT */ move(22, 0); #ifdef COMMENT /* These calls clear the screen. (convert routine calls to lowercase - Martin Zinser) */ CHECK_ERR("endwin: smg$delete_virtual_display", SMG$DELETE_VIRTUAL_DISPLAY(&smg_display_id)); smg_display_id = -1; CHECK_ERR("endwin: smg$delete_pasteboard", SMG$DELETE_PASTEBOARD(&smg_pasteboard_id, 0)); smg_pasteboard_id = -1; #endif /* COMMENT */ } #ifdef COMMENT /* DECC 6.2 screams bloody murder about printw ("not enough args") */ /* but adding the following prototype only makes it holler louder. */ #ifdef __DECC /* "varargs" prototype for printw */ _PROTOTYP(static int printw,(char *, ...)); #endif /* __DECC */ #endif /* COMMENT */ #ifdef __DECC #include _PROTOTYP(static void printw,(char *, ...)); static void printw(char *str,...) { char buf[255]; va_list ap; $DESCRIPTOR(text_dsc, 0); text_dsc.dsc$a_pointer=buf; if (!smg_open) return; va_start(ap,str); text_dsc.dsc$w_length = vsprintf(buf, str, ap); va_end(ap); CHECK_ERR("printw: smg$put_chars", smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0)); } #else static void printw(str, a1, a2, a3, a4, a5, a6, a7, a8) char *str; long a1, a2, a3, a4, a5, a6, a7, a8; /* printw */ { char buf[255]; $DESCRIPTOR(text_dsc, 0); if (!smg_open) return; text_dsc.dsc$a_pointer=buf; text_dsc.dsc$w_length = sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8); CHECK_ERR("printw: smg$put_chars", smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0)); } #endif /* __DECC */ #define CK_CURPOS int #ifdef CK_ANSIC ck_curpos(int row, int col) #else ck_curpos(row, col) int row; int col; #endif /* CK_ANSIC */ { debug(F111,"VMS smg ck_curpos",ckitoa(row),col); if (!smg_inited || !smg_open) { initscr(); } debug(F101,"VMS smg curpos smg_open","",smg_open); if (!smg_open) return(0); debug(F111,"VMS smg ck_curpos",ckitoa(row-1),col-1); move(row - 1, col - 1); /* SMG is 0-based */ refresh(); /* endwin(); */ return(0); } int ck_cls() { debug(F101,"VMS smg ck_cls smg_inited","",smg_inited); if (!smg_inited || !smg_open) { initscr(); } debug(F101,"VMS smg ck_cls smg_open","",smg_open); if (!smg_open) return(0); clear(); refresh(); /* endwin(); */ return(0); } int ck_cleol() { debug(F101,"VMS smg ck_cleol smg_inited","",smg_inited); if (!smg_inited || !smg_open) { initscr(); } debug(F101,"VMS smg ck_cleol smg_open","",smg_open); if (!smg_open) return(0); clrtoeol(); refresh(); /* endwin(); */ return(0); } #endif /* CK_SMG */ #ifdef MYCURSES /* Do-it-yourself curses implementation for VMS, OS/2 and other ANSI/VT-100's. Supports only the VT52 and VT1xx (and later VT2xx/3xx/4xx) terminals. By Terry Kennedy, St Peters College. First, some stuff we can just ignore: */ #ifdef VMS static int touchwin(x) int x; { return(0); } #endif /* VMS */ static int initscr() { return(0); } static int refresh() { return(0); } static int endwin() { return(0); } /* * Now, some stuff we need to do: */ _PROTOTYP( int move, (int, int) ); #ifndef OS2 int move(row, col) int row, col; { if (isvt52) printf("\033Y%c%c", row + 037, col + 037); else printf("\033[%d;%dH", row + 1, col + 1); return(0); } int clear() { move(0,0); if (isvt52) printf("\033J"); else printf("\033[J"); return(0); } int clrtoeol() { if (isvt52) printf("\033K"); else printf("\033[K"); return(0); } #define CK_CURPOS int ck_cls() { return(clear()); } int ck_cleol() { return(clrtoeol()); } int #ifdef CK_ANSIC ck_curpos(int row, int col) #else ck_curpos(row, col) int row, int col; #endif /* CK_ANSIC */ { move(row, col); return(0); } #else /* OS2 */ /* Windows NT and Windows 95 do not provide ANSI emulation */ /* Therefore we might as well not use it for OS/2 either */ int move(row, col) int row, col; { #ifndef ONETERMUPD SetCurPos(row, col); #endif /* ONETERMUPD */ lgotoxy( VCMD, col+1, row+1); VscrnIsDirty(VCMD); return(0); } int clear() { #ifndef ONETERMUPD viocell cell; #endif /* ONETERMUPD*/ move(0,0); #ifdef ONETERMUPD if (VscrnGetBufferSize(VCMD) > 0) { VscrnScroll(VCMD, UPWARD, 0, VscrnGetHeight(VCMD)-(1), VscrnGetHeight(VCMD)-(0), TRUE, CHR_SP); cleartermscreen(VCMD); } #else cell.c = ' '; cell.a = colorcmd; WrtNCell(cell, cmd_rows * cmd_cols, 0, 0); #endif /* ONETERMUPD */ return(0); } int clrtoeol() { #ifndef ONETERMUPD USHORT row, col; #endif /* ONETERMUPD */ viocell cell; cell.c = ' '; cell.a = colorcmd; #ifndef ONETERMUPD GetCurPos(&row, &col ); WrtNCell(cell, cmd_cols - col -1, row, col); #endif /* ONETERMUPD */ clrtoeoln(VCMD,CHR_SP); return(0); } #define CK_CURPOS int #ifdef CK_ANSIC ck_curpos(int row, int col) #else ck_curpos(row, col) int row, int col; #endif { move(row, col); return(0); } int ck_cls() { return(clear()); } int ck_cleol() { return(clrtoeol()); } #endif /* OS2 */ #endif /* MYCURSES */ #ifndef NOTERMCAP #ifndef CK_CURPOS #define CK_CURPOS /* Termcap/Terminfo section */ static char cur_cls[32] = { NUL, NUL }; static char cur_cleol[32] = { NUL, NUL }; static char cur_cm[64] = { NUL, NUL }; static char tgsbuf[128] = { NUL, NUL }; static #ifdef CK_ANSIC void #endif /* CK_ANSIC */ #ifdef CK_ANSIC ck_termset( int x ) #else ck_termset(x) int x; #endif /* CK_ANSIC */ { cur_cls[0] = NUL; cur_cleol[0] = NUL; cur_cm[0] = NUL; #ifdef tgetent debug(F100,"tgetent is a macro","",0); #endif /* tgetent */ #ifdef tgetstr debug(F100,"tgetstr is a macro","",0); #endif /* tgetstr */ #ifdef tputs debug(F100,"tputs is a macro","",0); #endif /* tputs */ #ifdef tgoto debug(F100,"tgoto is a macro","",0); #endif /* tgoto */ #ifdef NOTERMCAP /* tgetstr() gets a segmentation fault on OSF/1 */ debug(F100,"ck_termset NOTERMCAP","",0); #else if (notermcap) { debug(F100,"ck_termset notermcap","",0); return; } debug(F101,"ck_termset x","",x); if (x > 0) { char * bp; bp = tgsbuf; *bp = NUL; debug(F110,"ck_termset calling tgetstr","cl",0); if (tgetstr("cl", &bp)) { /* Get clear-screen code */ debug(F110,"ck_termset tgetstr cl",tgsbuf,0); if ((int)strlen(tgsbuf) < 32) ckstrncpy(cur_cls,tgsbuf,32); } else return; bp = tgsbuf; if (tgetstr("ce", &bp)) { /* Get clear-to-end-of-line code */ debug(F110,"ck_termset tgetstr ce",tgsbuf,0); if ((int)strlen(tgsbuf) < 32) ckstrncpy(cur_cleol,tgsbuf,32); } else return; bp = tgsbuf; if (tgetstr("cm", &bp)) { /* Get cursor-movement code */ debug(F110,"ck_termset tgetstr cm",tgsbuf,0); if ((int)strlen(tgsbuf) < 64) ckstrncpy(cur_cm,tgsbuf,64); } else return; } #endif /* NOTERMCAP */ } #ifndef TPUTSFNTYPE #ifdef TPUTSISVOID #define TPUTSFNTYPE void #else #define TPUTSFNTYPE int #endif /* TPUTSISVOID */ #endif /* TPUTSFNTYPE */ #ifndef TPUTSARGTYPE #ifdef HPUX9 #define TPUTSARGTYPE char #else #ifdef HPUX10 #define TPUTSARGTYPE char #else #define TPUTSARGTYPE int #endif /* HPUX10 */ #endif /* HPUX9 */ #endif /* TPUTSARGTYPE */ static TPUTSFNTYPE #ifdef CK_ANSIC ck_outc(TPUTSARGTYPE x) #else ck_outc(x) TPUTSARGTYPE x; #endif /* CK_ANSIC */ { /* To satisfy tputs() arg3 prototype */ int rc; char c; c = (char) x; rc = (inserver) ? ttoc(c) : conoc(c); #ifndef TPUTSISVOID return(rc); #endif /* TPUTSISVOID */ } int #ifdef CK_ANSIC ck_curpos( int row, int col ) #else ck_curpos(row, col) int row, col; #endif /* CK_ANSIC */ { #ifdef CK_ANSIC TPUTSFNTYPE (*fn)(TPUTSARGTYPE); #else TPUTSFNTYPE (*fn)(); #endif /* CK_ANSIC */ if (!fxd_inited) fxdinit(9999); if (!cur_cm[0]) { /* We don't have escape sequences */ #ifdef COMMENT return(-1); /* Do nothing */ #else /* Both C-Kermit's SCREEN command and ANSI/VT100 are 1-based */ printf("\033[%d;%dH", row, col); /* Or default to ANSI */ #endif /* COMMENT */ } else { fn = ck_outc; /* termcap/terminfo is 0-based */ tputs( #ifdef TPUTSARG1CONST (const char *) #endif /* TPUTSARG1CONST */ tgoto(cur_cm,col-1,row-1),1,fn); } return(0); } int ck_cls() { #ifdef CK_ANSIC TPUTSFNTYPE (*fn)(TPUTSARGTYPE); #else TPUTSFNTYPE (*fn)(); #endif /* CK_ANSIC */ if (!fxd_inited) fxdinit(9999); if (!cur_cls[0]) { /* If we don't have escape sequences */ #ifdef COMMENT return(-1); /* Do nothing */ #else printf("\033[;H\033[2J"); /* Or default to ANSI */ #endif /* COMMENT */ } else { fn = ck_outc; debug(F111,"ck_cls 2",cur_cls,fxd_inited); tputs(cur_cls,cmd_rows,fn); } return(0); } int ck_cleol() { #ifdef CK_ANSIC TPUTSFNTYPE (*fn)(TPUTSARGTYPE); #else TPUTSFNTYPE (*fn)(); #endif /* CK_ANSIC */ if (!fxd_inited) fxdinit(9999); if (!cur_cleol[0]) { /* If we don't have escape sequences */ #ifdef COMMENT return(-1); /* Do nothing */ #else printf("\033[K"); /* Or use ANSI */ #endif /* COMMENT */ } else { fn = ck_outc; tputs(cur_cleol,1,fn); } return(0); } #endif /* CK_CURPOS */ #else static void ck_termset(x) int x; { if (x) return; } #endif /* NOTERMCAP */ #ifndef CK_CURPOS #define CK_CURPOS int ck_cls() { printf("\033[;H\033[2J"); return(0); } int ck_cleol() { printf("\033[K"); return(0); } int ck_curpos(row, col) int row, int col; { printf("\033[%d;%dH", row, col); return(0); } #endif /* CK_CURPOS */ #ifndef NOXFER static int cinit = 0; /* Flag for curses init'd */ static int cendw = 0; /* endwin() was called */ static #ifdef CK_ANSIC /* Because VOID used by curses.h */ void #else #ifdef MYCURSES VOID #else int #endif /* MYCURSES */ #endif /* CK_ANSIC */ #ifdef CK_ANSIC /* Update % transfered and % bar */ updpct(long old, long new) #else /* CK_ANSIC */ updpct(old, new) long old, new; #endif /* CK_ANSIC */ /* updpct */ { #ifdef COMMENT int m, n; move(CW_PCD,22); printw("%ld", new); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_PCD, (intptr_t) new); #endif /* K95G */ #endif /* KUI */ #ifdef CK_PCT_BAR if (thermometer) { if (old > new) { old = 0; move(CW_PCD, 26); clrtoeol(); } m = old/2; move(CW_PCD, 26 + m); n = new / 2 - m; #ifndef OS2 while (n > 0) { if ((m + 1) % 5 == 0) printw("*"); else printw("="); m++; n--; } if (new % 2 != 0) printw("-"); /* move(CW_PCD, 22+53); */ #else /* OS2 */ while (n > 0) { printw("%c", '\333'); m++; n--; } if (new % 2 != 0) printw("%c", '\261'); #endif /* OS2 */ } #endif /* CK_PCT_BAR */ /* clrtoeol(); */ #else /* !COMMENT */ #ifdef OS2 #define CHAR1 '\333' /* OS2 - CP437 */ #define CHAR2 '\261' #else #define CHAR1 '/' /* Default */ #define CHAR2 '-' #endif /* OS2 */ debug(F101,"updpct old","",old); debug(F101,"updpct new","",new); move(CW_PCD,22); printw("%-3ld", new); /* (was) printw("%ld", new); */ #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_PCD, (intptr_t) new ); #endif /* K95G */ #endif /* KUI */ #ifdef CK_PCT_BAR if (thermometer) { int m, n; if (old > new) { old = 0 ; move(CW_PCD, 26); clrtoeol(); } if (new <= 100L) { m = old / 2; n = new / 2 - m; move(CW_PCD, 26+m); while (n-- > 0) printw("%c", CHAR1); if (new % 2 != 0) printw("%c", CHAR2); } } #endif /* CK_PCT_BAR */ #endif /* COMMENT */ } static CK_OFF_T old_tr = (CK_OFF_T)-1; /* Time remaining previously */ static CK_OFF_T #ifdef CK_ANSIC shoetl(CK_OFF_T old_tr, long cps, CK_OFF_T fsiz, CK_OFF_T howfar) #else shoetl(old_tr, cps, fsiz, howfar) long cps; CK_OFF_T old_tr, fsiz, howfar; #endif /* CK_ANSIC */ /* shoetl */ { /* Estimated time left in transfer */ CK_OFF_T tr; /* Time remaining, seconds */ #ifdef GFTIMER if (fsiz > 0L && cps > 0L) tr = (CK_OFF_T)((CKFLOAT)(fsiz - howfar) / (CKFLOAT)cps); else tr = (CK_OFF_T)-1; #else tr = (fsiz > 0L && cps > 0L) ? ((fsiz - howfar) / cps) : (CK_OFF_T)-1; #endif /* GFTIMER */ move(CW_TR,22); if (tr > (CK_OFF_T)-1) { if (tr != old_tr) { printw("%s",hhmmss(tr)); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t)CW_TR, (intptr_t)hhmmss(tr)); #endif /* K95G */ #endif /* KUI */ clrtoeol(); } } else { printw("(unknown)"); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_TR, (intptr_t) "(unknown)" ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); } return(tr); } static long #ifdef CK_ANSIC shocps(int pct, CK_OFF_T fsiz, CK_OFF_T howfar) #else shocps(pct, fsiz, howfar) int pct; CK_OFF_T fsiz, howfar; #endif /* CK_ANSIC */ /* shocps */ { #ifdef CPS_WEIGHTED static CK_OFF_T oldffc = 0L; #endif /* CPS_WEIGHTED */ #ifdef GFTIMER CKFLOAT secs, xx; #else CK_OFF_T secs, xx; #endif /* GFTIMER */ #ifdef GFTIMER xx = (gtv >= 0.0) ? gtv : 0.0; /* Floating-point version */ gtv = gftimer(); if ((gtv - oldgtv) < (CKFLOAT) 1.0) /* Only do this once per second */ return(oldcps); oldgtv = xx; #else xx = (gtv >= 0) ? gtv : 0; /* Whole-number version */ gtv = gtimer(); if ((gtv - oldgtv) < 1) return(oldcps); oldgtv = xx; #endif /* GFTIMER */ #ifdef CPS_WEIGHTED /* debug(F100,"SHOCPS: WEIGHTED","",0); */ if (gtv != oldgtv) { /* The first packet is ignored */ if (ffc < oldffc) oldffc = ffc; oldcps = cps; if (oldcps && oldgtv > #ifdef GFTIMER 1.0 #else 1 #endif /* GFTIMER */ ) { /* The first second is ignored */ /* This version of shocps() produces a weighted average that some people like, but most people find it disconcerting and bombard us with questions and complaints about why the CPS figure fluctuates so wildly. So now you only get the weighted average if you build the program yourself with CPS_WEIGHTED defined. */ #ifndef CPS_VINCE #ifdef GFTIMER cps = (long)((((CKFLOAT)oldcps * 3.0) + (CKFLOAT)(ffc - oldffc) / (gtv-oldgtv) ) / 4.0); #else cps = ( (oldcps * 3) + (ffc - oldffc) / (gtv-oldgtv) ) / 4; #endif /* GFTIMER */ #else /* And an alternate weighting scheme from Vincent Fatica... */ cps = (3 * ((1+pct/300)*oldffc/oldgtv+(1-pct/100)*(ffc-oldffc)/(gtv-oldgtv))) / 4; #endif /* CPS_VINCE */ } else { /* No weighted average since there is nothing to weigh */ #ifdef GFTIMER cps = (long)(gtv != 0.0 ? (CKFLOAT)(ffc - oldffc) / (gtv - oldgtv) : (ffc - oldffc)) ; #else cps = gtv ? (ffc - oldffc) / (gtv - oldgtv) : (ffc - oldffc) ; #endif /* GFTIMER */ } #ifdef COMMENT #ifdef DEBUG if (deblog) { debug(F101,"SHOCPS: pct ","",pct); debug(F101,"SHOCPS: gtv ","",gtv); debug(F101,"SHOCPS: oldgtv","",oldgtv); debug(F101,"SHOCPS: dgtv ","",(long)(gtv-oldgtv)); debug(F101,"SHOCPS: ffc ","",ffc); debug(F101,"SHOCPS: oldffc","",oldffc); debug(F101,"SHOCPS: dffc ","",ffc-oldffc); debug(F101,"SHOCPS: cps ","",cps); } #endif /* DEBUG */ #endif /* COMMENT */ move(CW_CP,22); printw("%ld", cps); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_CP, (intptr_t) cps ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); oldffc = ffc; } #else /* !CPS_WEIGHTED */ #ifdef COMMENT #ifdef DEBUG if (deblog) { debug(F100,"SHOCPS: NOT WEIGHTED","",0); debug(F101,"SHOCPS: pct ","",pct); debug(F101,"SHOCPS: gtv ","",gtv); debug(F101,"SHOCPS: oldgtv ","",oldgtv); debug(F101,"SHOCPS: dgtv ","",(long)gtv - (long)oldgtv); debug(F101,"SHOCPS: ffc ","",ffc); debug(F101,"SHOCPS: oldffc ","",oldffc); debug(F101,"SHOCPS: dffc ","",ffc-oldffc); debug(F101,"SHOCPS: cps ","",cps); debug(F101,"SHOCPS: filcnt ","",filcnt); #ifdef GFTIMER debug(F101,"SHOCPS: fpfsecs","",fpfsecs); #endif /* GFTIMER */ } debug(F101,"shocps gtv","",gtv); #endif /* DEBUG */ #ifdef GFTIMER #endif /* COMMENT */ /* debug(F101,"shocps fpfsecs","",fpfsecs); */ secs = gtv - fpfsecs; /* debug(F101,"shocps secs","",(long)secs); */ if (secs > 0.0) { cps = (long)((CKFLOAT) ffc / secs); /* debug(F101,"shocps cps","",cps); */ move(CW_CP,22); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_CP, (intptr_t) cps ); #endif /* K95G */ #endif /* KUI */ printw("%ld", cps); clrtoeol(); } #else /* Not GFTIMER */ if ((secs = gtv - fsecs) > 0) { cps = (secs < 1L) ? ffc : ffc / secs; move(CW_CP,22); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_CP, (intptr_t) cps ); #endif /* K95G */ #endif /* KUI */ printw("%ld", cps); clrtoeol(); } #endif /* GFTIMER */ #endif /* CPS_WEIGHTED */ if (cps > peakcps && /* Peak transfer rate */ ((what & W_SEND && spackets > wslots + 4) || (!(what & W_SEND) && spackets > 10))) { peakcps = cps; } old_tr = shoetl(old_tr, cps, fsiz, howfar); return(cps); } static #ifdef CK_ANSIC /* Because VOID used by curses.h */ void #else #ifdef MYCURSES VOID #else int #endif /* MYCURSES */ #endif /* CK_ANSIC */ scrft() { /* Display file type */ char xferstr[256]; xferstr[0] = NUL; debug(F101,"scrft binary","",binary); if (binary) { switch(binary) { case XYFT_L: ckstrncpy(xferstr,"LABELED",256); break; case XYFT_I: ckstrncpy(xferstr,"IMAGE",256); break; case XYFT_U: ckstrncpy(xferstr,"BINARY UNDEFINED",256); break; case XYFT_M: ckstrncpy(xferstr,"MACBINARY",256); break; case XYFT_X: ckstrncpy(xferstr,"TENEX",256); break; default: case XYFT_B: ckstrncpy(xferstr,"BINARY",256); break; } #ifdef CK_RESEND if (what & W_SEND && sendstart > 0L) { if (sendmode == SM_PSEND) { ckstrncat(xferstr, " / partial", 256); } else if (sendmode == SM_RESEND) { ckstrncat(xferstr, " / resend", 256); } } else if (what & W_RECV && rs_len > 0L) { ckstrncat(xferstr, " / resend", 256); } #endif /* CK_RESEND */ } else { #ifndef NOCSETS ckstrncpy(xferstr,"TEXT",256); #ifdef NEWFTP #ifndef NOUNICODE if (what & W_FTP) { if (ftp_csx < 0) ckstrncat(xferstr," (no translation)", 256); else ckmakxmsg(&xferstr[4],252, " (", fcsinfo[(what & W_SEND) ? ftp_csl : ftp_csx].keyword, " => ", fcsinfo[(what & W_SEND) ? ftp_csx : ftp_csl].keyword, ")", NULL,NULL,NULL,NULL,NULL,NULL,NULL ); } else #endif /* NOUNICODE */ #endif /* NEWFTP */ if (tcharset == TC_TRANSP) { ckstrncat(xferstr, " (no translation)", 256); } else { if (what & W_SEND) { sprintf( &xferstr[strlen(xferstr)], /* safe */ " (%s => %s)", fcsinfo[fcharset].keyword, /* built-in keywords */ tcsinfo[tcharset].keyword /* lengths are controlled */ ); } else { sprintf( &xferstr[strlen(xferstr)], /* safe */ " (%s => %s)", tcsinfo[tcharset].keyword, /* built-in keywords */ fcsinfo[fcharset].keyword); /* lengths controlled */ } } #endif /* NOCSETS */ } move(CW_TYP,22); printw("%s", xferstr); clrtoeol(); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_TYP, (intptr_t) xferstr ); #endif /* K95G */ #endif /* KUI */ return; } #ifdef CK_NEWTERM static FILE *ck_stdout = NULL; static int ck_fd = -1; #endif /* CK_NEWTERM */ static long pct = 0L, oldpct = 0L, oldrtt = -1L; static int oldtyp = 0, oldwin = -1, oldtry = -1, oldlen = -1, oldtim = -1; #ifdef NETCONN static char *netname[] = { "none", /* 00 */ "TCP/IP", /* 01 TCP (Sockets) */ "TCP/IP", /* 02 TCP (Streams) */ "X.25", /* 03 SunLink X.24 */ "DECnet", /* 04 DECnet */ "VAX PSI", /* 05 VAX PSI */ "Named Pipes", /* 06 LAN Manager Named Pipe */ "X.25", /* 07 Stratus VOS X.25 */ "NetBIOS", /* 08 IBM NETBIOS */ "SuperLAT", /* 07 Meridian SuperLAT */ "File", /* 10 File */ "Command", /* 11 Subprocess (pipe) */ "DLL", /* 12 DLL does i/o */ "X.25", /* 13 IBM AIXLink X.25 */ "X.25", /* 14 HP-UX X.25 */ "PTY", /* 15 Pseudoterminal */ "SSH", /* 16 SSH */ "", /* 17 In case new types are added */ "", /* 18 but nobody remembers to update */ "", /* 19 this table ... */ NULL /* 20 */ }; static int nnetname = (sizeof(netname) / sizeof(char *)); #endif /* NETCONN */ #ifdef CK_ANSIC void screenc(int f, char c,CK_OFF_T n,char *s) #else CKVOID screenc(f,c,n,s) int f; /* argument descriptor */ char c; /* a character or small integer */ CK_OFF_T n; /* a long integer */ char *s; /* a string */ #endif /* CK_ANSIC */ /* screenc() */ { #ifdef CK_SSL extern int tls_active_flag, ssl_active_flag; #endif /* CK_SSL */ #ifdef RLOGCODE extern int ttnproto; #endif /* RLOGCODE */ static int q = 0; static long fcnt = 0L; /* Number of files transferred */ static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */ static CK_OFF_T fbyt = 0L; /* Total file bytes of all files transferred */ static CK_OFF_T howfar = 0L; /* How much of current file has been xfer'd */ static int pctlbl = 0L; /* Percent done vs Bytes so far */ long cps = 0L; int net = 0; int xnet = 0; int ftp = 0; int len; /* Length of string */ int errors = 0; /* Error counter */ int x; /* Worker */ debug(F101,"screenc cinit","",cinit); debug(F101,"screenc cendw","",cendw); if (!s) s = ""; /* Always do this. */ ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */ net = network || ftp; xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */ if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */ if (f == SCR_CW) { /* Close window, but it's not open */ ft_win = 0; return; } debug(F111,"screenc A",s,f); if (f == SCR_EM || (f == SCR_PT && c == 'E')) { /* Fatal error before window open */ conoll(""); conoc('?'); conoll(s); return; /* Regular display */ } } if (cinit == 0) { /* Only call initscr() once */ char * s; /* Check these now -- if they are defined but not numeric */ /* they can crash curses */ s = getenv("LINES"); if (s) if (!rdigits(s)) { printf("?LINES variable not numeric: \"%s\".\n",s); printf("(Fullscreen display disabled)\n"); fdispla = XYFD_S; return; } s = getenv("COLUMNS"); if (s) if (!rdigits(s)) { printf("?COLUMNS variable not numeric: \"%s\".\n",s); printf("(Fullscreen display disabled)\n"); fdispla = XYFD_S; return; } cendw = 1; /* New window needs repainting */ #ifdef COMMENT if (!initscr()) { /* Oops, can't initialize window? */ /* In fact, this doesn't happen. "man curses" says initscr() halts the entire program if it fails, which is true on the systems where I've tested it. It will fail if your terminal type is not known to it. That's why SET FILE DISPLAY FULLSCREEN calls tgetent() to make sure the terminal type is known before allowing a curses display. */ fprintf(stderr,"CURSES INITSCR ERROR\r\n"); fdispla = XYFD_S; /* Fall back to CRT display */ return; } else { cinit++; /* Window initialized ok */ debug(F100,"CURSES INITSCR OK","",0); } #else /* Save some memory. */ #ifdef CK_NEWTERM /* (From Andy Fyfe ) System V curses seems to reserve the right to alter the buffering on the output FILE* without restoring it. Fortunately System V curses provides newterm(), an alternative to initscr(), that allows us to specify explicitly the terminal type and input and output FILE pointers. Thus we duplicate stdout, and let curses have the copy. The original remains unaltered. Unfortunately, newterm() seems to be particular to System V. */ s = getenv("TERM"); if (ck_fd < 0) { ck_fd = dup(fileno(stdout)); ck_stdout = (ck_fd >= 0) ? (FILE *)fdopen(ck_fd, "w") : NULL; } debug(F100,"screenc newterm...","",0); /* NOTE: It might be necessary to do this with stdin too! */ /* This would have been the case in FreeBSD 4.1 but they fixed the */ /* problem by restoring the buffering of stdin before the final release. */ /* (But T.E. Dickey says stdin is not buffered?) */ if (ck_stdout == NULL || newterm(s, ck_stdout, stdin) == 0) { fprintf(stderr, "Fullscreen display not supported for terminal type: %s\r\n",s); fdispla = XYFD_S; /* Use CRT instead */ return; } debug(F100,"screenc newterm ok","",0); #else debug(F100,"screen calling initscr","",0); initscr(); /* Initialize curses. */ debug(F100,"screen initscr ok","",0); #endif /* CK_NEWTERM */ cinit++; /* Remember curses was initialized. */ #endif /* COMMENT */ } ft_win = 1; /* Window is open */ if (repaint) { #ifdef CK_WREFRESH /* This totally repaints the screen, just what we want, but we can only do this with real curses, and then only if clearok() and wrefresh() are provided in the curses library. */ #ifdef OS2 RestoreCmdMode(); #else #ifdef QNX #ifndef QNX16 clearok(stdscr, 1); /* QNX doesn't have curscr */ #endif /* QNX16 */ wrefresh(stdscr); #else wrefresh(curscr); #endif /* QNX */ #endif /* OS2 */ #else /* No CK_WREFRESH */ /* Kermit's do-it-yourself method, works with all types of fullscreen support, but does not repaint all the fields. For example, the filename is lost, because it arrives at a certain time and never comes again, and Kermit presently does not save it anywhere. Making this method work for all fields would be a rather major recoding task, duplicating what curses already does, and would add a lot of complexity and storage space. */ cendw = 1; #endif /* CK_WREFRESH */ repaint = 0; } if (cendw) { /* endwin() was called previously */ #ifdef VMS initscr(); /* (or should have been!) */ clear(); touchwin(stdscr); refresh(); #else #ifdef QNX /* In QNX, if we don't call initscr() here we core dump. I don't have any QNX curses documentation, but other curses manuals say that initscr() should be called only once per application, and experience shows that on other systems, calling initscr() here generally results in a core dump. */ debug(F100,"screenc re-calling initscr QNX","",0); initscr(); clear(); refresh(); #ifdef COMMENT /* But even so, second and subsequent curses displays are messed up. Calling touchwin, refresh, etc, doesn't make any difference. */ debug(F100,"screenc calling touchwin QNX","",0); touchwin(stdscr); debug(F100,"screenc calling refresh QNX","",0); refresh(); #endif /* COMMENT */ #else /* All others... */ debug(F100,"screenc calling clear","",0); clear(); debug(F100,"screenc clear ok","",0); #endif /* QNX */ #endif /* VMS */ debug(F100,"screenc setup ok","",0); debug(F100,"screenc doing first move","",0); move(CW_BAN,0); /* Display the banner */ debug(F110,"screenc myhost",myhost,0); #ifdef TCPSOCKET debug(F110,"screenc myipaddr",myipaddr,0); #endif /* TCPSOCKET */ #ifdef HPUX1010 debug(F100,"screenc calling first printw...","",0); /* Right here is where HP-UX 10.10 libxcurse.1 Rev 76.20 hangs... */ #endif /* HPUX1010 */ if (myhost[0]) { #ifdef TCPSOCKET if (!myipaddr[0] #ifdef OS2 /* We need to perform this test because on non-TCP/IP */ /* systems the call to getlocalipaddr() results in a */ /* DNS Lookup which takes several minutes to time out */ && net && (xnet == NET_TCPA || xnet == NET_TCPB #ifdef SSHBUILTIN || xnet == NET_SSH #endif /* SSHBUILTIN */ ) #endif /* OS2 */ ) getlocalipaddr(); if (myipaddr[0] && strcmp((char *)myhost,(char *)myipaddr)) printw("%s, %s [%s]",versio,(char *)myhost,(char *)myipaddr); else #endif /* TCPSOCKET */ printw("%s, %s",versio,(char *)myhost); } else { printw("%s",versio); } #ifdef HPUX1010 debug(F100,"screenc first printw returns","",0); #endif /* HPUX1010 */ move(CW_DIR,3); printw("Current Directory: %s",zgtdir()); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_DIR, (intptr_t) zgtdir() ); #endif /* K95G */ #endif /* KUI */ if (net) { move(CW_LIN,8); printw("Network Host: %s", #ifdef NEWFTP ftp ? (ftp_host ? ftp_host : "(unknown)") : #endif /* NEWFTP */ ttname ); } else { move(CW_LIN,0); printw("Communication Device: %s",ttname); } #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_LIN, (intptr_t) ttname ); #endif /* K95G */ #endif /* KUI */ if (net) { move(CW_SPD,8); printw("Network Type: "); } else { move(CW_SPD,1); printw("Communication Speed: "); } move(CW_SPD,22); /* Serial speed or network type */ if (net) { #ifdef NETCONN int secure = 0; char * xname; if (xnet > nnetname) xname = "[ERROR]"; else xname = netname[xnet]; #ifdef NEWFTP if (ftp) { if (ftpissecure()) secure = 1; } else #endif /* NEWFTP */ if (0 #ifdef SSHBUILTIN || IS_SSH() #endif /* SSHBUILTIN */ #ifdef CK_ENCRYPTION || ck_tn_encrypting() && ck_tn_decrypting() #endif /* CK_ENCRYPTION */ #ifdef CK_SSL || tls_active_flag || ssl_active_flag #endif /* CK_SSL */ #ifdef RLOGCODE #ifdef CK_KERBEROS #ifdef CK_ENCRYPTION || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN #endif /* CK_ENCRYPTION */ #endif /* CK_KERBEROS */ #endif /* RLOGCODE */ ) { /* You may get an "unreachable code" warning in builds with no SSL, * Kerberos or SSH support. This is OK. */ secure = 1; } if (secure) { #ifdef KUI #ifndef K95G char buf[30]; sprintf(buf,"%s (SECURE)",xname); KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_SPD, (intptr_t) buf ); #endif /* K95G */ #endif /* KUI */ printw("%s (SECURE)",xname); } else { printw("%s",xname); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_SPD, (intptr_t) xname ); #endif /* K95G */ #endif /* KUI */ } #else printw("(network)"); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_SPD, (intptr_t) "(network)" ); #endif /* K95G */ #endif /* KUI */ #endif /* NETCONN */ } else { if (speed < 0L) speed = ttgspd(); if (speed > 0L) { if (speed == 8880) { printw("75/1200"); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_SPD, (intptr_t) "75/1200" ); #endif /* K95G */ #endif /* KUI */ } else { char speedbuf[64] ; sprintf(speedbuf, "%ld", speed); printw("%s",speedbuf); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_SPD, (intptr_t) speedbuf ); #endif /* K95G */ #endif /* KUI */ } } else { printw("unknown"); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_SPD, (intptr_t) "(unknown)" ); #endif /* K95G */ #endif /* KUI */ } } move(CW_PAR,14); printw("Parity: %s",ftp ? "none" : parnam((char)parity)); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_PAR, (intptr_t) parnam((char)parity) ); #endif /* K95G */ #endif /* KUI */ #ifdef CK_TIMERS if (/* rttflg && */ protocol == PROTO_K) { move(CW_TMO, 9); printw("RTT/Timeout:"); } #endif /* CK_TIMERS */ move(CW_TYP,11); printw("File Type:"); move(CW_SIZ,11); printw("File Size:"); move(CW_PCD, 8); clrtoeol(); pctlbl = (what & W_SEND); printw("%s:", pctlbl ? "Percent Done" : "Bytes So Far"); #ifdef XYZ_INTERNAL move(CW_BAR, 1); printw("%10s Protocol:", ftp ? "FTP" : ptab[protocol].p_name); #endif /* XYZ_INTERNAL */ #ifdef CK_PCT_BAR if (thermometer) { oldpct = pct = 0; move(CW_BAR,22); printw(" ...10...20...30...40...50...60...70...80...90..100"); move(CW_BAR,22+56); } #endif /* CK_PCT_BAR */ move(CW_TR, 1); printw("Estimated Time Left:"); move(CW_CP, 2); printw("Transfer Rate, CPS:"); move(CW_WS, 8); printw("Window Slots:%s", ((protocol == PROTO_K) && !ftp) ? "" : " N/A" ); move(CW_PT, 9); printw("Packet Type:"); if (ftp || protocol != PROTO_K) { move(CW_PT,22); printw("%s", "N/A"); move(CW_PC, 11); printw("I/O Count:"); move(CW_PL, 10); printw("I/O Length:"); } else { move(CW_PC, 8); printw("Packet Count:"); move(CW_PL, 7); printw("Packet Length:"); } #ifndef COMMENT move(CW_PR, 9); printw("Error Count:"); #else move(CW_PR, 2); printw("Packet Retry Count:"); #endif #ifdef COMMENT move(CW_PB, 2); printw("Packet Block Check:"); #endif /* COMMENT */ move(CW_ERR,10); printw("Last Error:"); move(CW_MSG, 8); printw("Last Message:"); if (xfrmsg) { move(CW_MSG, 22); printw("%s",xfrmsg); makestr(&xfrmsg,NULL); } move(CW_INT, 0); if (!xfrint) { printw("(Transfer interruption is disabled)"); } else { #ifdef CK_NEED_SIG printw( "<%s>X to cancel file, <%s>Z to cancel group, <%s> to resend last packet", dbchr(escape), dbchr(escape), dbchr(escape) ); move(CW_INT + 1, 0); printw( "<%s>E to send Error packet, ^C to quit immediately, <%s>L to refresh screen.", dbchr(escape), dbchr(escape) ); #else /* !CK_NEED_SIG */ move(CW_INT, 0); #ifdef OS2 if (protocol == PROTO_K) { printw( "X to cancel file, Z to cancel group, to resend last packet," ); } #else /* !OS2 */ #ifdef VMS /* In VMS avoid bottom line */ printw( "X: Cancel this file; E: Cancel transfer; ^C: Quit now; ^W: Refresh screen." ); #else printw( "X to cancel file, Z to cancel group, to resend last packet," ); #endif /* VMS */ #endif /* OS2 */ #ifndef VMS move(CW_INT + 1, 0); if (protocol == PROTO_K) { printw( "E to send Error packet, ^C to quit immediately, ^L to refresh screen." ); } else { printw("^C to cancel file transfer."); } #endif /* VMS */ #endif /* CK_NEED_SIG */ } refresh(); cendw = 0; } debug(F101,"SCREENC switch","",f); debug(F000,"SCREENC c","",c); debug(F101,"SCREENC n","",n); len = strlen(s); /* Length of argument string */ switch (f) { /* Handle our function code */ case SCR_FN: /* Filename */ oldpct = pct = 0L; /* Reset percents */ #ifdef GFTIMER gtv = (CKFLOAT) -1.0; /* oldgtv = (CKFLOAT) -1.0; */ #else gtv = -1L; /* oldgtv = -1L; */ #endif /* GFTIMER */ oldwin = -1; fsiz = (CK_OFF_T)-1; /* Invalidate previous file size */ move(CW_PCD,22); /* Erase percent done from last time */ #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_PCD, (intptr_t) 0 ); KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_FFC, (intptr_t) 0 ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); move(CW_SIZ,22); /* Erase file size from last time */ #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_SIZ, (intptr_t) 0 ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); move(CW_ERR,22); /* And last error message */ #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "" ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); #ifdef COMMENT #ifdef STREAMING if (protocol == PROTO_K && streamok) { move(CW_BAR, 1); #ifdef XYZ_INTERNAL printw(" Kermit STREAMING:"); #else printw(" STREAMING:"); #endif /* XYZ_INTERNAL */ } #endif /* STREAMING */ #endif /* COMMENT */ if (what & W_SEND) { /* If we're sending... */ #ifdef NEWFTP if (what & W_FTP) { /* FTP */ move(CW_NAM,10); printw(" FTP PUT:"); } else #endif /* NEWFTP */ #ifdef CK_RESEND switch (sendmode) { /* Kermit */ case SM_RESEND: move(CW_NAM,10); printw(" RESENDING:"); break; default: move(CW_NAM,10); printw(" SENDING:"); break; } #else move(CW_NAM,10); printw(" SENDING:"); #endif /* CK_RESEND */ } else if (what & W_RECV) { /* If we're receiving... */ #ifdef NEWFTP if (what & W_FTP) { /* FTP */ move(CW_NAM,10); printw(" FTP GET:"); } else { #endif /* NEWFTP */ move(CW_NAM,10); printw(" RECEIVING:"); #ifdef NEWFTP } } else if (what == (W_FTP|W_FT_DELE)) { move(CW_NAM,10); printw("FTP DELETE:"); #endif /* NEWFTP */ } else { /* If we don't know... */ move(CW_NAM,10); /* (should never see this) */ printw(" File Name:"); } move(CW_NAM,22); /* Display the filename */ if (len > 57) { printw("%.55s..",s); len = 57; } else printw("%s",s); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_NAM, (intptr_t) s ); #endif /* K95G */ #endif /* KUI */ q = len; /* Remember name length for later */ clrtoeol(); scrft(); /* Display file type (can change) */ refresh(); #ifdef OS2 SaveCmdMode(0, 0); #endif /* OS2 */ return; case SCR_AN: /* File as-name */ if (q + len + 4 < 58) { /* Will fit */ move(CW_NAM, 22 + q); printw(" => %s",s); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_NAM, (intptr_t) s ); #endif /* K95G */ #endif /* KUI */ } else { /* Too long */ move(CW_NAM, 22); /* Overwrite previous name */ q = 0; if (len + 4 > 57) { /* wg15 */ printw(" => %.51s..",s); /* wg15 */ len = 53; /* wg15 */ } else printw(" => %s",s); /* wg15 */ #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_NAM, (intptr_t) s ); #endif /* K95G */ #endif /* KUI */ } q += len + 4; /* Remember horizontal position */ clrtoeol(); refresh(); #ifdef OS2 SaveCmdMode(0, 0); #endif /* OS2 */ return; case SCR_FS: /* File size */ fsiz = n; move(CW_SIZ,22); if (fsiz > (CK_OFF_T)-1) { #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_SIZ, (intptr_t) n ); #endif /* K95G */ #endif /* KUI */ printw("%s",ckfstoa(n)); } if (fsiz == -2L) { printw("POSSIBLY EXCEEDS LOCAL FILE SIZE LIMIT"); } clrtoeol(); #ifdef COMMENT move(CW_PCD, 8); if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */ pctlbl = 1; clrtoeol(); printw("Percent Done:"); } #else move(CW_PCD, 8); clrtoeol(); if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */ pctlbl = 1; printw("Percent Done:"); } else { pctlbl = 0; printw("Bytes So Far:"); } #endif /* COMMENT */ clrtoeol(); scrft(); /* File type */ refresh(); #ifdef OS2 SaveCmdMode(0, 0); #endif /* OS2 */ return; case SCR_PT: /* Packet type or pseudotype */ if (spackets < 5) { extern int sysindex; extern struct sysdata sysidlist[]; /* Things that won't change after the 4th packet */ move(CW_PAR,22); printw("%s",parnam((char)parity)); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_PAR, (intptr_t) parnam((char)parity) ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); #ifdef COMMENT move(CW_PB, 22); /* Block check on this packet */ if (bctu == 4) printw("B"); else printw("%d",bctu); clrtoeol(); #endif /* COMMENT */ if ( #ifdef NEWFTP (ftp && (spackets == 1 || rpackets == 1)) || #endif /* NEWFTP */ spackets == 4 ) { move(CW_LIN,8); if ( #ifdef NEWFTP ftp || #endif /* NEWFTP */ ((protocol == PROTO_K) && (sysindex > -1)) ) { if (net) { move(CW_LIN,8); printw("Network Host: %s (%s)", #ifdef NEWFTP ftp ? (ftp_host ? ftp_host : "") : #endif /* NEWFTP */ ttname, #ifdef NEWFTP ftp ? ftp_srvtyp : #endif /* NEWFTP */ sysidlist[sysindex].sid_name ); } else { move(CW_LIN,0); printw("Communication Device: %s (remote host is %s)", ttname, sysidlist[sysindex].sid_name ); } clrtoeol(); } } } #ifdef CK_TIMERS if (/* rttflg && */ protocol == PROTO_K) { long xx; if ( #ifdef STREAMING streaming && oldwin != -2 #else 0 #endif /* STREAMING */ ) { move(CW_TMO, 22); printw("00 / 00"); clrtoeol(); } else { xx = (rttdelay + 500) / 1000; if (xx != oldrtt || rcvtimo != oldtim) { move(CW_TMO, 22); printw("%02ld / %02d", xx, rcvtimo); oldrtt = xx; oldtim = rcvtimo; clrtoeol(); } } } #endif /* CK_TIMERS */ x = (what & W_RECV) ? /* Packet length */ rpktl+(protocol==PROTO_K?1:0) : spktl; if (x != oldlen) { /* But only if it changed. */ move(CW_PL, 22); printw("%d",x); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_PL, (intptr_t) x ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); oldlen = x; } move(CW_PC, 22); /* Packet count (always). */ printw("%d", (what & W_RECV) ? rpackets : spackets); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_PC, (intptr_t) spackets ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); if (protocol == PROTO_K && !ftp) { /* Window slots */ char ws[16]; int flag; flag = 0; #ifdef STREAMING if (streaming) { if (oldwin != -2) { sprintf(ws,"STREAMING"); flag = 1; oldwin = -2; } } else #endif /* STREAMING */ if (wcur != oldwin) { sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn); flag = 1; oldwin = wcur; } if (flag) { move(CW_WS, 22); printw("%s", ws); clrtoeol(); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_WS, (intptr_t) ws ); #endif /* K95G */ #endif /* KUI */ } } errors = retrans + crunched + timeouts; if (errors != oldtry) { /* Retry count, if changed */ move(CW_PR, 22); printw("%d",errors); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_PR, (intptr_t) errors ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); oldtry = errors; } /* Sender's packet type */ if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) { char type[2]; sprintf(type, "%c",c); move(CW_PT,22); printw("%s", type); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_PT, (intptr_t) type ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); oldtyp = c; } switch (c) { /* Now handle specific packet types */ case 'S': /* Beginning of transfer */ fcnt = fbyt = 0L; /* Clear counters */ #ifdef GFTIMER gtv = -1.0; #else /* GFTIMER */ gtv = -1L; /* And old/new things... */ #endif /* GFTIMER */ oldpct = pct = 0L; break; case 'Z': /* or EOF */ debug(F101,"screenc SCR_PT Z pktnum","",n); debug(F101,"screenc SCR_PT Z oldpct","",oldpct); debug(F101,"screenc SCR_PT Z pct","",pct); case 'D': /* Data packet */ if (fsiz > 0L) { /* Show percent done if known */ oldpct = pct; /* Remember previous percent */ howfar = ffc; #ifdef CK_RESEND if (what & W_SEND) /* Account for PSEND or RESEND */ howfar += sendstart; else if (what & W_RECV) howfar += rs_len; #endif /* CK_RESEND */ /* Percent done, to be displayed... */ if (c == 'Z') { if (!discard && !cxseen && !czseen) pct = 100L; } else pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L; if (pct > 100L || /* Allow for expansion and */ (oldpct == 99L && pct < 0L)) /* other boundary conditions */ pct = 100L; if (pct != oldpct) /* Only do this 100 times per file */ updpct(oldpct, pct); } else { move(CW_PCD,22); printw("%s", ckfstoa(ffc)); } #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_FFC, (intptr_t) howfar); #endif /* K95G */ #endif /* KUI */ cps = shocps((int) pct, fsiz, howfar); /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */ break; case '%': /* Timeouts, retransmissions */ cps = shocps((int) pct, fsiz, howfar); /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */ errors = retrans + crunched + timeouts; if (errors != oldtry) { /* Error count, if changed */ move(CW_PR, 22); printw("%d",errors); clrtoeol(); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_PR, (intptr_t) errors ); #endif /* K95G */ #endif /* KUI */ } oldtry = errors; if (s) if (*s) { move(CW_ERR,22); printw("%s",s); clrtoeol(); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) s); #endif /* K95G */ #endif /* KUI */ } break; case 'E': /* Error packet */ #ifdef COMMENT move(CW_ERR,22); /* Print its data field */ if (*s) { printw("%s",s); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) s ); #endif /* K95G */ #endif /* KUI */ } clrtoeol(); #endif /* COMMENT */ fcnt = fbyt = 0L; /* So no bytes for this file */ break; case 'Q': /* Crunched packet */ cps = shocps((int) pct, fsiz, howfar); /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */ move(CW_ERR,22); printw("Damaged Packet"); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "Damaged Packet" ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); break; case 'q': /* Ctrl-C or connection lost */ move(CW_MSG,22); clrtoeol(); if (!s) s = ""; /* 30092021: fails to compile on Debian with "-Wformat -Werror=format-security" printw(*s ? s : "User interruption or connection lost"); */ fputs(*s ? s : "User interruption or connection lost", stdout); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_MSG, (intptr_t) s ); #endif /* K95G */ #endif /* KUI */ break; case 'T': /* Timeout */ cps = shocps((int) pct, fsiz, howfar); /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */ move(CW_ERR,22); printw("Timeout %d sec",rcvtimo); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "Timeout" ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); errors = retrans + crunched + timeouts; if (errors != oldtry) { /* Error count, if changed */ move(CW_PR, 22); printw("%d",errors); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_PR, (intptr_t) errors ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); oldtry = errors; } break; default: /* Others, do nothing */ break; } refresh(); #ifdef OS2 SaveCmdMode(0, 0); #endif /* OS2 */ return; case SCR_ST: /* File transfer status */ debug(F101,"screenc SCR_ST c","",c); debug(F101,"screenc SCR_ST success","",success); debug(F101,"screenc SCR_ST cxseen","",cxseen); #ifdef COMMENT move(CW_PCD,22); /* Update percent done */ if (c == ST_OK) { /* OK, print 100 % */ if (pctlbl) updpct(oldpct,100); else printw("%s", ckfstoa(ffc)); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_FFC, (intptr_t) ffc); #endif /* K95G */ #endif /* KUI */ pct = 100; oldpct = 0; } else if (fsiz > 0L) /* Not OK, update final percent */ /* The else part writes all over the screen -- howfar and/or fsiz have been reset as a consequence of the not-OKness of the transfer. */ if (pctlbl) updpct(oldpct, (howfar * 100L) / fsiz); clrtoeol(); #else if (c == ST_OK) { /* OK, print 100 % */ move(CW_PCD,22); /* Update percent done */ if (pctlbl) { if (oldpct == 0) /* Switching from "bytes so far" */ clrtoeol(); /* to "percent done"... */ updpct(oldpct,100); } else printw("%s", ckfstoa(ffc)); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_FFC, (intptr_t) ffc); #endif /* K95G */ #endif /* KUI */ #ifdef COMMENT pct = 100; oldpct = 0; #endif /* COMMENT */ clrtoeol(); } #endif /* COMMENT */ #ifdef COMMENT /* No, leave it there so they can read it */ move(CW_MSG,22); /* Remove any previous message */ #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_MSG, (intptr_t) "" ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); refresh(); #endif /* COMMENT */ move(CW_TR, 22); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_TR, (intptr_t) "" ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); refresh(); switch (c) { /* Print new status message */ case ST_OK: /* Transfer OK */ fcnt++; /* Count this file */ if (what == (W_FTP|W_FT_DELE)) { move(CW_MSG,22); clrtoeol(); printw("Delete OK"); } else { fbyt += ffc; move(CW_MSG,22); clrtoeol(); printw("Transfer OK"); } #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_MSG, (intptr_t) "Transfer OK" ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); refresh(); return; case ST_DISC: /* Discarded */ move(CW_ERR,22); printw("File discarded"); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "File discarded" ); #endif /* K95G */ #endif /* KUI */ #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ clrtoeol(); refresh(); return; case ST_INT: /* Interrupted */ move(CW_ERR,22); printw("Transfer interrupted"); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "Transfer interrupted" ); #endif /* K95G */ #endif /* KUI */ #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ clrtoeol(); refresh(); return; case ST_SKIP: /* Skipped */ move(CW_ERR,22); if (n > 0 && n < nskreason) printw("File skipped (%s)",skreason[n]); else printw("File skipped"); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "File skipped" ); #endif /* K95G */ #endif /* KUI */ #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ clrtoeol(); refresh(); return; case ST_ERR: /* Error message */ move(CW_ERR,22); if (!s) s = (char *)epktmsg; printw("%s",s); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) s ); #endif /* K95G */ #endif /* KUI */ #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ clrtoeol(); refresh(); return; case ST_REFU: /* Refused */ move(CW_ERR,22); if (*s) { char errbuf[64] ; sprintf( errbuf, "Refused, %s", s ) ; printw("%s", errbuf); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER,(intptr_t) CW_ERR,(intptr_t) errbuf); #endif /* K95G */ #endif /* KUI */ } else { printw("Refused"); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER,(intptr_t)CW_ERR,(intptr_t)"Refused"); #endif /* K95G */ #endif /* KUI */ } #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ clrtoeol(); refresh(); return; case ST_INC: move(CW_ERR,22); printw("Incomplete"); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER,(intptr_t)CW_ERR,(intptr_t)"Incomplete"); #endif /* K95G */ #endif /* KUI */ #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ clrtoeol(); refresh(); return; case ST_MSG: move(CW_MSG,22); printw("%s",s); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER,(intptr_t)CW_MSG,(intptr_t)s); #endif /* K95G */ #endif /* KUI */ clrtoeol(); refresh(); return; default: /* Bad call */ move(CW_ERR,22); printw("*** screen() called with bad status ***"); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "*** screen() called with bad status ***" ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); refresh(); return; } case SCR_TC: { /* Transaction complete */ char msgbuf[128]; move(CW_CP,22); /* Overall transfer rate */ #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_CP, tfcps); #endif /* K95G */ #endif /* KUI */ printw("%s", ckfstoa(tfcps)); clrtoeol(); if (success) { move(CW_MSG,22); /* Print statistics in message line */ clrtoeol(); } if (success) { sprintf(msgbuf, "SUCCESS. Files: %ld, Bytes: %s, %ld CPS", filcnt - filrej, ckfstoa(fbyt), tfcps ); printw("%s", msgbuf); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_MSG, (intptr_t) msgbuf ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); } move(CW_TR, 1); printw(" Elapsed Time: %s",hhmmss((long) #ifdef GFTIMER (fptsecs + 0.5) #else tsecs #endif /* GFTIMER */ )); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_TR, (intptr_t) hhmmss((long) #ifdef GFTIMER (fptsecs + 0.5) #else tsecs #endif /* GFTIMER */ )); #endif /* K95G */ #endif /* KUI */ clrtoeol(); move(23,0); clrtoeol(); /* Clear instructions lines */ move(22,0); clrtoeol(); /* to make room for prompt. */ refresh(); #ifdef GFTIMER oldgtv = (CKFLOAT) -1.0; #else oldgtv = -1L; #endif /* GFTIMER */ #ifndef VMSCURSE debug(F100,"screenc endwin A","",0); endwin(); #ifdef COMMENT /* Why and when was this call to conres() added? It makes no sense, and it breaks echoing on Solaris 8. */ #ifdef SOLARIS conres(); #endif /* SOLARIS */ #endif /* COMMENT */ #endif /* VMSCURSE */ #ifdef COMMENT pct = 100; oldpct = 0; /* Reset these for next time. */ #endif /* COMMENT */ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1; oldtim = -1; cendw = 1; if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */ #ifdef UNIX fflush(stdout); #endif /* UNIX */ ft_win = 0; /* Window closed. */ return; } case SCR_EM: /* Error packet (fatal) */ move (CW_ERR,22); printw("FAILURE: %s",s); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) s ); #endif /* K95G */ #endif /* KUI */ if (xfrbel) bleep(BP_FAIL); #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ clrtoeol(); refresh(); return; case SCR_QE: /* Quantity equals */ case SCR_TU: /* Undelimited text */ case SCR_TN: /* Text delimited at start */ case SCR_TZ: /* Text delimited at end */ return; /* (ignored in fullscreen display) */ case SCR_MS: /* Message from Kermit partner */ move(CW_MSG,22); printw("%s",s); clrtoeol(); refresh(); return; case SCR_XD: /* X-packet data */ pct = oldpct = 0; move(CW_NAM,22); printw("%s",s); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_NAM, (intptr_t) s ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); refresh(); return; case SCR_CW: /* Close Window */ clrtoeol(); move(23,0); clrtoeol(); move(22,0); clrtoeol(); refresh(); #ifdef COMMENT pct = 100; oldpct = 0; /* Reset these for next time. */ #endif /* COMMENT */ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1; oldtim = -1; #ifndef VMSCURSE debug(F100,"screenc endwin B","",0); endwin(); #endif /* VMSCURSE */ ft_win = 0; /* Flag that window is closed. */ cendw = 1; return; case SCR_CD: /* Display current directory */ move(CW_DIR,22); printw("%s", s); #ifdef KUI #ifndef K95G KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_DIR, (intptr_t) s ); #endif /* K95G */ #endif /* KUI */ clrtoeol(); refresh(); #ifdef OS2 SaveCmdMode(0, 0); #endif /* OS2 */ return; default: /* Bad call */ move (CW_ERR,22); #ifdef KUI #ifndef K95G KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "*** screen() called with bad function code ***" ); #endif /* K95G */ #endif /* KUI */ printw("*** screen() called with bad function code ***"); clrtoeol(); refresh(); return; } } #endif /* CK_CURSES */ #ifdef KUI #ifdef CK_ANSIC void screeng(int f, char c,long n,char *s) #else CKVOID screeng(f,c,n,s) int f; /* argument descriptor */ char c; /* a character or small integer */ long n; /* a long integer */ char *s; /* a string */ #endif /* CK_ANSIC */ /* screeng() */ { #ifdef CK_SSL extern int tls_active_flag, ssl_active_flag; #endif /* CK_SSL */ #ifdef RLOGCODE extern int ttnproto; #endif /* RLOGCODE */ static int q = 0; static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */ static long fcnt = 0L; /* Number of files transferred */ static long fbyt = 0L; /* Total file bytes of all files transferred */ static CK_OFF_T howfar = (CK_OFF_T)0; /* How much of file xfer'd so far */ static int pctlbl = 0L; /* Percent done vs Bytes so far */ long cps = 0L; int net = 0; int xnet = 0; int ftp = 0; int len; /* Length of string */ int errors = 0; /* Error counter */ int x; /* Worker */ debug(F101,"screeng cinit","",cinit); debug(F101,"screeng cendw","",cendw); if (!s) s = ""; /* Always do this. */ ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */ net = network || ftp; xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */ if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */ if (f == SCR_CW) { /* Close window, but it's not open */ ft_win = 0; return; } debug(F111,"screeng A",s,f); if (f == SCR_EM || (f == SCR_PT && c == 'E')) { /* Fatal error before window open */ conoll(""); conoc('?'); conoll(s); return; /* Regular display */ } } if (cinit == 0) { /* Only call initscr() once */ /* Check these now -- if they are defined but not numeric */ /* they can crash curses */ cendw = 1; /* New window needs repainting */ debug(F100,"screeng calling initscr","",0); initscr(); /* Initialize curses. */ debug(F100,"screeng initscr ok","",0); cinit++; /* Remember curses was initialized. */ } ft_win = 1; /* Window is open */ if (repaint) { #ifdef CK_WREFRESH /* This totally repaints the screen, just what we want, but we can only do this with real curses, and then only if clearok() and wrefresh() are provided in the curses library. */ RestoreCmdMode(); #else /* No CK_WREFRESH */ /* Kermit's do-it-yourself method, works with all types of fullscreen support, but does not repaint all the fields. For example, the filename is lost, because it arrives at a certain time and never comes again, and Kermit presently does not save it anywhere. Making this method work for all fields would be a rather major recoding task, duplicating what curses already does, and would add a lot of complexity and storage space. */ cendw = 1; #endif /* CK_WREFRESH */ repaint = 0; } if (cendw) { /* endwin() was called previously */ debug(F100,"screeng setup ok","",0); KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_DIR, (intptr_t) zgtdir() ); KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_LIN, (intptr_t) ( #ifdef NEWFTP ftp ? (ftp_host ? ftp_host : "(unknown)") : #endif /* NEWFTP */ ttname) ); if (net) { #ifdef NETCONN int secure = 0; char * xname; if (xnet > nnetname) xname = "[ERROR]"; else xname = netname[xnet]; #ifdef NEWFTP if (ftp) { if (ftpissecure()) secure = 1; } else #endif /* NEWFTP */ if (0 #ifdef SSHBUILTIN || IS_SSH() #endif /* SSHBUILTIN */ #ifdef CK_ENCRYPTION || ck_tn_encrypting() && ck_tn_decrypting() #endif /* CK_ENCRYPTION */ #ifdef CK_SSL || tls_active_flag || ssl_active_flag #endif /* CK_SSL */ #ifdef RLOGCODE #ifdef CK_KERBEROS #ifdef CK_ENCRYPTION || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN #endif /* CK_ENCRYPTION */ #endif /* CK_KERBEROS */ #endif /* RLOGCODE */ ) { /* You may get an "unreachable code" warning in builds with no SSL, * Kerberos or SSH support. This is OK. */ secure = 1; } if (secure) { char buf[30]; sprintf(buf,"%s (SECURE)",xname); KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_SPD, (intptr_t) buf ); } else { KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_SPD, (intptr_t) xname ); } #else KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_SPD, (intptr_t) "(network)" ); #endif /* NETCONN */ } else { if (speed < 0L) speed = ttgspd(); if (speed > 0L) { if (speed == 8880) { KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_SPD, (intptr_t) "75/1200" ); } else { char speedbuf[64] ; sprintf(speedbuf, "%ld", speed); KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_SPD, (intptr_t) speedbuf ); } } else { KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_SPD, (intptr_t) "(unknown)" ); } } KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_PAR, (intptr_t) parnam((char)parity) ); pctlbl = (what & W_SEND); cendw = 0; } debug(F101,"SCREENC switch","",f); debug(F000,"SCREENC c","",c); debug(F101,"SCREENC n","",n); len = strlen(s); /* Length of argument string */ switch (f) { /* Handle our function code */ case SCR_FN: /* Filename */ oldpct = pct = 0L; /* Reset percents */ #ifdef GFTIMER gtv = (CKFLOAT) -1.0; /* oldgtv = (CKFLOAT) -1.0; */ #else gtv = -1L; /* oldgtv = -1L; */ #endif /* GFTIMER */ oldwin = -1; fsiz = (CK_OFF_T)-1L; /* Invalidate previous file size */ KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_PCD, (intptr_t) 0 ); KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_FFC, (intptr_t) 0 ); KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_SIZ, (intptr_t) 0 ); KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "" ); KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_NAM, (intptr_t) s ); q = len; /* Remember name length for later */ scrft(); /* Display file type (can change) */ #ifdef OS2 SaveCmdMode(0, 0); #endif /* OS2 */ return; case SCR_AN: /* File as-name */ KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_NAM, (intptr_t) s ); #ifdef OS2 SaveCmdMode(0, 0); #endif /* OS2 */ return; case SCR_FS: /* File size */ fsiz = n; if (fsiz > (CK_OFF_T)-1) { KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_SIZ, (intptr_t) n ); } if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */ pctlbl = 1; } else { pctlbl = 0; } scrft(); /* File type */ #ifdef OS2 SaveCmdMode(0, 0); #endif /* OS2 */ return; case SCR_PT: /* Packet type or pseudotype */ if (spackets < 5) { extern int sysindex; extern struct sysdata sysidlist[]; /* Things that won't change after the 4th packet */ KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_PAR, (intptr_t) parnam((char)parity) ); if ( #ifdef NEWFTP (ftp && (spackets == 1 || rpackets == 1)) || #endif /* NEWFTP */ spackets == 4 ) { if ( #ifdef NEWFTP ftp || #endif /* NEWFTP */ ((protocol == PROTO_K) && (sysindex > -1)) ) { char msgbuf[128]; if (net) { sprintf(msgbuf,"Network Host: %s (%s)", #ifdef NEWFTP ftp ? (ftp_host ? ftp_host : "") : #endif /* NEWFTP */ ttname, #ifdef NEWFTP ftp ? ftp_srvtyp : #endif /* NEWFTP */ sysidlist[sysindex].sid_name ); } else { sprintf(msgbuf, "Communication Device: %s (remote host is %s)", ttname, sysidlist[sysindex].sid_name ); } KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_LIN, (intptr_t) msgbuf ); } } } #ifdef CK_TIMERS if (/* rttflg && */ protocol == PROTO_K) { long xx; if ( #ifdef STREAMING streaming && oldwin != -2 #else 0 #endif /* STREAMING */ ) { char msgbuf[64]; sprintf(msgbuf,"00 / 00"); KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_TMO, (intptr_t) msgbuf ); } else { xx = (rttdelay + 500) / 1000; if (xx != oldrtt || rcvtimo != oldtim) { char msgbuf[64]; sprintf(msgbuf,"%02ld / %02d", xx, rcvtimo); KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_TMO, (intptr_t) msgbuf ); oldrtt = xx; oldtim = rcvtimo; clrtoeol(); } } } #endif /* CK_TIMERS */ x = (what & W_RECV) ? /* Packet length */ rpktl+(protocol==PROTO_K?1:0) : spktl; if (x != oldlen) { /* But only if it changed. */ KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_PL, (intptr_t) x ); oldlen = x; } KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_PC, (intptr_t) spackets ); if (protocol == PROTO_K && !ftp) { /* Window slots */ char ws[16]; int flag; flag = 0; #ifdef STREAMING if (streaming) { if (oldwin != -2) { sprintf(ws,"STREAMING"); flag = 1; oldwin = -2; } } else #endif /* STREAMING */ if (wcur != oldwin) { sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn); flag = 1; oldwin = wcur; } if (flag) { KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_WS, (intptr_t) ws ); } } errors = retrans + crunched + timeouts; if (errors != oldtry) { /* Retry count, if changed */ KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_PR, (intptr_t) errors ); oldtry = errors; } /* Sender's packet type */ if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) { char type[2]; sprintf(type, "%c",c); KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_PT, (intptr_t) type ); oldtyp = c; } switch (c) { /* Now handle specific packet types */ case 'S': /* Beginning of transfer */ fcnt = fbyt = 0L; /* Clear counters */ #ifdef GFTIMER gtv = -1.0; #else /* GFTIMER */ gtv = -1L; /* And old/new things... */ #endif /* GFTIMER */ oldpct = pct = 0L; break; case 'Z': /* or EOF */ debug(F101,"screeng SCR_PT Z pktnum","",n); debug(F101,"screeng SCR_PT Z oldpct","",oldpct); debug(F101,"screeng SCR_PT Z pct","",pct); case 'D': /* Data packet */ if (fsiz > 0L) { /* Show percent done if known */ oldpct = pct; /* Remember previous percent */ howfar = ffc; #ifdef CK_RESEND if (what & W_SEND) /* Account for PSEND or RESEND */ howfar += sendstart; else if (what & W_RECV) howfar += rs_len; #endif /* CK_RESEND */ /* Percent done, to be displayed... */ if (c == 'Z') { if (!discard && !cxseen && !czseen) pct = 100L; } else pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L; if (pct > 100L || /* Allow for expansion and */ (oldpct == 99L && pct < 0L)) /* other boundary conditions */ pct = 100L; if (pct != oldpct) /* Only do this 100 times per file */ updpct(oldpct, pct); } else { KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_FFC, (intptr_t) ffc); } KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_FFC, (intptr_t) howfar); cps = shocps((int) pct, fsiz, howfar); /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */ break; case '%': /* Timeouts, retransmissions */ cps = shocps((int) pct, fsiz, howfar); /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */ errors = retrans + crunched + timeouts; if (errors != oldtry) { /* Error count, if changed */ KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_PR, (intptr_t) errors ); } oldtry = errors; if (s) if (*s) { KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) s); } break; case 'E': /* Error packet */ if (*s) { KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) s ); } fcnt = fbyt = 0L; /* So no bytes for this file */ break; case 'Q': /* Crunched packet */ cps = shocps((int) pct, fsiz, howfar); /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */ KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "Damaged Packet" ); break; case 'q': /* Ctrl-C or connection lost */ if (!s) s = ""; if (!*s) s = "User interruption or connection lost"; KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_MSG, (intptr_t) s ); break; case 'T': /* Timeout */ cps = shocps((int) pct, fsiz, howfar); /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */ KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "Timeout" ); errors = retrans + crunched + timeouts; if (errors != oldtry) { /* Error count, if changed */ KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_PR, (intptr_t) errors ); oldtry = errors; } break; default: /* Others, do nothing */ break; } #ifdef OS2 SaveCmdMode(0, 0); #endif /* OS2 */ return; case SCR_ST: /* File transfer status */ debug(F101,"screeng SCR_ST c","",c); debug(F101,"screeng SCR_ST success","",success); debug(F101,"screeng SCR_ST cxseen","",cxseen); #ifdef COMMENT if (c == ST_OK) { /* OK, print 100 % */ if (pctlbl) updpct(oldpct,100); else KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_FFC, (intptr_t) ffc); pct = 100; oldpct = 0; } else if (fsiz > 0L) /* Not OK, update final percent */ /* The else part writes all over the screen -- howfar and/or fsiz have been reset as a consequence of the not-OKness of the transfer. */ if (pctlbl) updpct(oldpct, (howfar * 100L) / fsiz); #else if (c == ST_OK) { /* OK, print 100 % */ if (pctlbl) { updpct(oldpct,100); } else KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_FFC, (intptr_t) ffc); #ifdef COMMENT pct = 100; oldpct = 0; #endif /* COMMENT */ } #endif /* COMMENT */ KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_TR, (intptr_t) "" ); switch (c) { /* Print new status message */ case ST_OK: /* Transfer OK */ fcnt++; /* Count this file */ if (what == (W_FTP|W_FT_DELE)) { KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_MSG, (intptr_t) "Delete OK" ); } else { fbyt += ffc; KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_MSG, (intptr_t) "Transfer OK" ); } return; case ST_DISC: /* Discarded */ KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "File discarded" ); #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ return; case ST_INT: /* Interrupted */ KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "Transfer interrupted" ); #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ return; case ST_SKIP: { /* Skipped */ char errbuf[64] ; if (n > 0 && n < nskreason) sprintf( errbuf, "File skipped, (%s)", skreason[n] ) ; else sprintf( errbuf, "File skipped" ) ; KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) errbuf ); #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ return; } case ST_ERR: /* Error message */ if (!s) s = (char *)epktmsg; KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) s ); #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ return; case ST_REFU: /* Refused */ if (*s) { char errbuf[64] ; sprintf( errbuf, "Refused, %s", s ) ; KuiSetProperty(KUI_FILE_TRANSFER,(intptr_t) CW_ERR,(intptr_t) errbuf); } else { KuiSetProperty(KUI_FILE_TRANSFER,(intptr_t)CW_ERR,(intptr_t)"Refused"); } #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ return; case ST_INC: KuiSetProperty(KUI_FILE_TRANSFER,(intptr_t)CW_ERR,(intptr_t)"Incomplete"); #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ return; case ST_MSG: KuiSetProperty(KUI_FILE_TRANSFER,(intptr_t)CW_MSG,(intptr_t)s); return; default: /* Bad call */ KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "*** screen() called with bad status ***" ); return; } case SCR_TC: { /* Transaction complete */ char msgbuf[128]; KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_CP, tfcps); if (success) { sprintf(msgbuf, "SUCCESS. Files: %s, Bytes: %ld, %ld CPS", filcnt - filrej, ckfstoa(fbyt), tfcps ); KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_MSG, (intptr_t) msgbuf ); } KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_TR, (intptr_t) hhmmss((long) #ifdef GFTIMER (fptsecs + 0.5) #else tsecs #endif /* GFTIMER */ )); #ifdef GFTIMER oldgtv = (CKFLOAT) -1.0; #else oldgtv = -1L; #endif /* GFTIMER */ #ifdef COMMENT pct = 100; oldpct = 0; /* Reset these for next time. */ #endif /* COMMENT */ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1; oldtim = -1; cendw = 1; if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */ ft_win = 0; /* Window closed. */ return; } case SCR_EM: /* Error packet (fatal) */ KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) s ); if (xfrbel) bleep(BP_FAIL); #ifdef COMMENT pct = oldpct = 0; #endif /* COMMENT */ return; case SCR_QE: /* Quantity equals */ case SCR_TU: /* Undelimited text */ case SCR_TN: /* Text delimited at start */ case SCR_TZ: /* Text delimited at end */ return; /* (ignored in fullscreen display) */ case SCR_XD: /* X-packet data */ pct = oldpct = 0; KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_NAM, (intptr_t) s ); return; case SCR_CW: /* Close Window */ #ifdef COMMENT pct = 100; oldpct = 0; /* Reset these for next time. */ #endif /* COMMENT */ oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1; oldtim = -1; ft_win = 0; /* Flag that window is closed. */ cendw = 1; return; case SCR_CD: /* Display current directory */ KuiSetProperty( KUI_FILE_TRANSFER, (intptr_t) CW_DIR, (intptr_t) s ); #ifdef OS2 SaveCmdMode(0, 0); #endif /* OS2 */ return; default: /* Bad call */ KuiSetProperty(KUI_FILE_TRANSFER, (intptr_t) CW_ERR, (intptr_t) "*** screen() called with bad function code ***" ); return; } } #endif /* KUI */ #endif /* MAC */ #endif /* NOXFER */ #ifndef CK_CURPOS /* Dummies for when cursor control is not supported */ int #ifdef CK_ANSIC ck_curpos(int row, int col) #else ck_curpos(row, col) int row; int col; #endif /* CK_ANSIC */ { return(-1); } int ck_cls() { return(-1); } int ck_cleol() { return(-1); } #endif /* CK_CURPOS */ #ifndef NOICP #ifndef NOIKSD #ifdef IKSDB struct iksdbfld dbfld[] = { /* Offset Length Type */ { DB_FLAGS, dB_FLAGS, DBT_HEX }, /* 0 db_FLAGS Flags */ { DB_ATYPE, dB_ATYPE, DBT_HEX }, /* 1 db_ATYPE Auth type */ { DB_AMODE, dB_AMODE, DBT_HEX }, /* 3 db_AMODE Auth mode */ { DB_STATE, dB_STATE, DBT_HEX }, /* 2 db_STATE State */ { DB_MYPID, dB_MYPID, DBT_HEX }, /* 5 db_MYPID PID */ { DB_SADDR, dB_SADDR, DBT_HEX }, /* 4 db_SADDR Server address */ { DB_CADDR, dB_CADDR, DBT_HEX }, /* 6 db_CADDR Client address */ { DB_START, dB_START, DBT_DAT }, /* 7 db_START Session start */ { DB_LASTU, dB_LASTU, DBT_DAT }, /* 8 db_LASTU Last update */ { DB_ULEN, dB_ULEN, DBT_HEX }, /* 9 db_ULEN Username length */ { DB_DLEN, dB_DLEN, DBT_HEX }, /* 10 db_DLEN Directory name length */ { DB_ILEN, dB_ILEN, DBT_HEX }, /* 11 db_ILEN Info length */ { DB_PAD1, dB_PAD1, DBT_UND }, /* 12 db_PAD1 (Reserved) */ { DB_USER, dB_USER, DBT_STR }, /* 13 db_USER Username */ { DB_DIR, dB_DIR, DBT_STR }, /* 14 db_DIR Current Directory */ { DB_INFO, dB_INFO, DBT_STR } /* 15 db_INFO State-specific info */ }; static char lcknam[CKMAXPATH+1]; /* Lockfile pathname */ static char tmplck[CKMAXPATH+1]; /* Temporary lockfile name */ static char * updmode = /* Update mode for fopen() */ #ifdef OS2 "r+b" #else #ifdef VMS "r+b" #else "r+" #endif /* VMS */ #endif /* OS2 */ ; /* D B I N I T -- Initialize the IKSD database... */ int dbinit() { extern int dbinited; int x = 0; debug(F110,"dbinit dbdir 1",dbdir,0); debug(F110,"dbinit dbfile 1",dbfile,0); if (dbinited) return(0); #ifdef OS2 if (!dbdir) { #ifdef NT char * p = NULL; if (!isWin95()) { p = getenv("SystemRoot"); } else { p = getenv("winbootdir"); if (!p) p = getenv("windir"); } if (!p) p = "C:/"; dbdir = malloc(strlen(p)+2); strcpy(dbdir,p); /* safe */ p = dbdir; while (*p) { if (*p == '\\') *p = '/'; p++; } if (*(p-1) != '/' ) { *p++ = '/'; *p = '\0'; } #else /* NT */ makestr(&dbdir,"C:/"); #endif /* NT */ } #else /* OS2 */ if (!dbdir) makestr(&dbdir,IK_DBASEDIR); #endif /* OS2 */ if (!dbfile) { char * s = ""; x = strlen(dbdir); if (dbdir[x-1] != '/') { s = "/"; x++; } x += (int)strlen(IK_DBASEFIL); dbfile = (char *)malloc(x+1); sprintf(dbfile,"%s%s%s",dbdir,s,IK_DBASEFIL); } debug(F110,"dbinit dbdir 2",dbdir,0); debug(F110,"dbinit dbfile 2",dbfile,0); mypid = getpid(); /* Get my pid */ debug(F101,"dbinit mypid","",mypid); if (!myhexip[0]) { /* Set my hex IP address */ #ifdef TCPSOCKET extern unsigned long myxipaddr; if (getlocalipaddr() > -1) { myip = myxipaddr; sprintf(myhexip,"%08lx",myip); /* (Needs fixing for IPv6) */ } else #endif /* TCPSOCKET */ ckstrncpy(myhexip,"00000000",9); } debug(F111,"dbinit myip",myhexip,myip); if (!peerhexip[0]) { /* Get peer's hex IP address */ #ifdef TCPSOCKET extern unsigned long peerxipaddr; if (ckgetpeer()) { peerip = peerxipaddr; sprintf(peerhexip,"%08lx",peerip); /* (Needs fixing for IPv6) */ debug(F111,"dbinit peerip",peerhexip,peerip); } else { debug(F101,"dbinit ckgetpeer failure","",errno); ckstrncpy(peerhexip,"00000000",9); } #else ckstrncpy(peerhexip,"00000000",9); #endif /* TCPSOCKET */ } debug(F111,"dbinit peerip",peerhexip,peerip); debug(F101,"dbinit dbenabled","",dbenabled); if (dbenabled && inserver) { mydbslot = getslot(); debug(F111,"dbinit getslot",ckitoa(ikdbopen),x); if (ikdbopen) dbinited = 1; } return(0); } /* U P D S L O T -- Update slot n */ /* Opens the database if necessary, seeks to slot n, writes current record and adds current time to last-update field. n is the record sequence number (0, 1, 2, ...), not the seek pointer. Returns -1 on failure, 0 on success. */ int #ifdef CK_ANSIC updslot( int n ) /* Update our slot */ #else updslot(n) int n; #endif /* CK_ANSIC */ { int rc = 0; CK_OFF_T position; debug(F111,"updslot","ikdbopen",ikdbopen); if (!ikdbopen) /* Not if not ok */ return(0); if (!dbfp) { /* Open database if not open */ dbfp = fopen(dbfile,updmode); /* In update no-truncate mode */ if (!dbfp) { debug(F110,"updslot fopen failed",dbfile,0); ikdbopen = 0; return(-1); } } /* debug(F111,"updslot dbfile",dbfile,dbfp); */ position = n * DB_RECL; if (CKFSEEK(dbfp,position,0) < 0) { /* Seek to desired slot */ debug(F111,"updslot fseek failed",dbfile,mydbseek); ikdbopen = 0; rc = -1; } else { /* Update the update time */ strncpy(&dbrec[dbfld[db_LASTU].off], ckdate(), dbfld[db_LASTU].len ); if (fwrite(dbrec,1,DB_RECL,dbfp) < DB_RECL) { /* Write the record */ debug(F110,"updslot fwrite failed",dbfile,0); ikdbopen = 0; rc = -1; } else { /* Flush the write */ fflush(dbfp); } } return(rc); } /* I N I T S L O T -- Initialize slot n with my info */ int #ifdef CK_ANSIC initslot( int n ) /* Initialize slot */ #else initslot(n) int n; #endif /* CK_ANSIC */ { int k; #ifdef TCPSOCKET extern unsigned long peerxipaddr; #endif /* TCPSOCKET */ debug(F101,"initslot","",n); #ifdef USE_MEMCPY memset(dbrec,32,DB_RECL); #else for (k = 0; k < DB_RECL; k++) dbrec[k] = '\040'; #endif /* USE_MEMCPY */ myflags = DBF_INUSE; /* Set in-use flag */ mystate = W_NOTHING; myatype = 0L; myamode = 0L; k = dbfld[db_FLAGS].len; /* Length of flags field */ strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(myflags,k),k); k = dbfld[db_ATYPE].len; strncpy(&dbrec[dbfld[db_ATYPE].off],ulongtohex(myatype,k),k); k = dbfld[db_AMODE].len; strncpy(&dbrec[dbfld[db_AMODE].off],ulongtohex(myamode,k),k); k = dbfld[db_STATE].len; strncpy(&dbrec[dbfld[db_STATE].off],ulongtohex(mystate,k),k); k = dbfld[db_SADDR].len; strncpy(&dbrec[dbfld[db_SADDR].off],ulongtohex(myip,k),k); #ifdef TCPSOCKET ckgetpeer(); k = dbfld[db_CADDR].len; strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(peerxipaddr,k),k); #else k = dbfld[db_CADDR].len; strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(0L,k),k); #endif /* TCPSOCKET */ k = dbfld[db_MYPID].len; strncpy(&dbrec[dbfld[db_MYPID].off],ulongtohex(mypid,k),k); k = dbfld[db_START].len; strncpy(&dbrec[dbfld[db_START].off],ckdate(),k); k = dbfld[db_ULEN].len; strncpy(&dbrec[dbfld[db_ULEN].off],"0000",4); k = dbfld[db_DLEN].len; strncpy(&dbrec[dbfld[db_DLEN].off],"0000",4); k = dbfld[db_ILEN].len; strncpy(&dbrec[dbfld[db_ILEN].off],"0000",4); strncpy(&dbrec[dbfld[db_INFO].off],"INIT",4); return(updslot(n)); } int #ifdef CK_ANSIC slotstate( int x, char *s1, char *s2, char *s3 ) #else slotstate(x,s1,s2,s3) int x; char *s1, *s2, *s3; #endif /* CK_ANSIC */ { int k, l1, l2, l3, z; mystate = x; debug(F101,"slotstate ikdbopen","",ikdbopen); if (!ikdbopen) return(-1); if (!s1) s1 = ""; l1 = strlen(s1); if (!s2) s2 = ""; l2 = strlen(s2); if (!s3) s3 = ""; l3 = strlen(s3); strncpy(&dbrec[DB_STATE],ulongtohex(mystate,4),4); k = dbfld[db_ILEN].len; z = l1 + l2 + l3 + 2; if (z > dB_INFO) z = dB_INFO; strncpy(&dbrec[DB_ILEN],ulongtohex((unsigned long)z,k),k); k = dbfld[db_INFO].len; z = dbfld[db_INFO].off; if (l1 <= k) { lset(&dbrec[z],s1,l1+1,32); z += l1+1; k -= l1+1; if (l2 <= k) { lset(&dbrec[z],s2,l2+1,32); z += l2+1; k -= l2+1; if (l3 <= k) lset(&dbrec[z],s3,k,32); } } #ifdef DEBUG if (deblog) { char buf[128]; int i; strncpy(buf,&dbrec[DB_INFO],127); buf[127] = NUL; for (i = 126; i > 0 && buf[i] == 32; i--) buf[i] = 0; debug(F111,"slotstate",buf,mystate); } #endif /* DEBUG */ z = updslot(mydbslot); debug(F101,"slotstate updslot","",z); return(z); } int #ifdef CK_ANSIC slotdir( char * s1, char * s2 ) /* Update current directory */ #else slotdir(s1,s2) char * s1, * s2; #endif /* CK_ANSIC */ { int k, len1, len2; if (!ikdbopen) return(-1); if (!s1) s1 = ""; if (!s2) s2 = ""; len1 = strlen(s1); len2 = strlen(s2); k = dbfld[db_DLEN].len; strncpy(&dbrec[DB_DLEN],ulongtohex((unsigned long)(len1+len2),k),k); k = dbfld[db_DIR].len; if (len1 > 0) { lset(&dbrec[dbfld[db_DIR].off],s1,len1,32); lset(&dbrec[dbfld[db_DIR].off+len1],s2,k-len1,32); } else { lset(&dbrec[dbfld[db_DIR].off],s2,k,32); } return(updslot(mydbslot)); } /* F R E E S L O T -- Free slot n */ int #ifdef CK_ANSIC freeslot( int n ) #else freeslot(n) int n; #endif /* CK_ANSIC */ { int k; if (!ikdbopen) return(0); dbflags = 0L; if (n == mydbslot) { dbflags = myflags & ~DBF_INUSE; dbflags &= ~DBF_LOGGED; } k = dbfld[db_FLAGS].len; strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(dbflags,k),k); return(updslot(n)); } /* G E T S L O T -- Find a free database slot; returns slot number */ #ifdef CK_ANSIC /* prototype for static function - fdc 30 November 2022 */ static void ck_termset( int ); #endif /* CK_ANSIC */ int getslot() { /* Find a free slot for us */ FILE * rfp = NULL; /* Returns slot number (0, 1, ...) */ char idstring[64]; /* PID string buffer (decimal) */ char pidbuf[64]; int j, k, n, x, rc = -1; int lockfd, tries, haveslot = 0; int dummy; long lockpid; CK_OFF_T i; /* char ipbuf[17]; */ if (!myhexip[0]) /* Set my hex IP address if not set */ ckstrncpy((char *)myhexip,"7F000001",33); sprintf(idstring,"%08lx:%010ld\n",myip,mypid); debug(F110,"getslot idstring", idstring, 0); /* Make temporary lockfile name IP.PID (hex.hex) */ /* This should fit in 14 chars -- huge PIDs are usually not possible */ /* on 14-char filename systems. */ sprintf(tmplck,"%s%08lx.%lx",dbdir,myip,mypid); debug(F110,"getslot tempfile",tmplck,0); /* Make a temporary file */ lockfd = creat(tmplck, 0600); /* BUT THIS ISN'T PORTABLE */ if (lockfd < 0) { debug(F111,"getslock temp lockfile create failure", tmplck, errno); return(-1); } /* Write my (decimal) PID into the temp file */ dummy = write(lockfd,idstring,(int)strlen(idstring)); if (close(lockfd) < 0) { /* Close lockfile */ debug(F101,"getslot error closing temp lockfile", "", errno); return(-1); } sprintf(lcknam,"%s%s",dbdir,IK_LOCKFILE); /* Build lockfile name */ debug(F110,"getslot lockfile",lcknam,0); rfp = fopen(lcknam,"r"); /* See if lockfile exists */ if (rfp) { /* If so... */ rset(pidbuf,"",64,0); x = fread(pidbuf,1,63,rfp); /* Read ID string from it */ fclose(rfp); /* and close it quickly */ debug(F110,"getslot lock exists",pidbuf,0); if (x > 0) { /* If we have a PID, check it */ char * s = pidbuf; while (*s) { if (islower(*s)) *s = toupper(*s); if (*s == ':') { *s = NUL; debug(F110,"getslot lock IP",pidbuf,0); debug(F110,"gteslot my IP",myhexip,0); if (!strcmp(pidbuf,myhexip)) { /* Same IP address? */ lockpid = atol(s+1); /* Yes, now get PID */ debug(F101,"getslot lockpid","",lockpid); /* Check if PID lockpid on this computer is alive */ x = zchkpid(lockpid); if (!x) { debug(F100,"getslot PID stale,removing lock","",0); unlink(lcknam); } break; } } s++; } } else { debug(F111,"getslot lockfile open failure",lcknam,errno); } } /* Try IK_LCKTRIES (16) times to rename temp file to lockfile */ for (tries = IK_LCKTRIES; tries > 0; tries--) { if (zrename(tmplck,lcknam) == 0) break; debug(F101,"getslot database locked by pid", "", dbpid); sleep(IK_LCKSLEEP); } if (tries < 1) { /* Couldn't */ debug(F110,"getslot create lock failure",lcknam,0); return(-1); } /* Have lock, open database */ debug(F110,"getslot has lock",lcknam,0); /* Have lock */ if (!dbfile) return(-1); /* If database doesn't exist, create it. */ debug(F110,"getslot dbfile",dbfile,0); if (zchki(dbfile) < 0) { debug(F110,"getslot creating new database",dbfile,0); x = creat(dbfile,0660); if (x < 0) { debug(F111,"getslot creat() failed", dbfile, errno); goto xslot; } close(x); } dbfp = fopen(dbfile,updmode); /* Open it in update mode */ if (!dbfp) { debug(F111,"getslot fopen failed",dbfile,errno); goto xslot; } /* Now find a free (or new) slot... */ dblastused = 0L; /* Seek pointer to last record inuse */ mydbseek = 0L; /* Seek pointer for my record */ /* Quickly read the whole database; n = record counter, i = seek pointer */ for (n = 0, i = 0; !feof(dbfp); i += DB_RECL, n++) { x = fread(dbrec,1,DB_RECL,dbfp); /* Read a record */ if (x < 1) /* EOF not caught by feof() */ break; #ifndef NOFTRUNCATE if (x != DB_RECL) { /* Watch out for trailing junk */ debug(F101,"getslot bad size","",x); /* (Shouldn't happen...) */ #ifdef COHERENT chsize(fileno(dbfp),i); #else dummy = ftruncate(fileno(dbfp),(CK_OFF_T)i); #endif /* COHERENT */ x = 0; CKFSEEK(dbfp,i,0); break; } #endif /* NOFTRUNCATE */ debug(F101,"getslot record","",n); k = dbfld[db_FLAGS].off; j = dbfld[db_FLAGS].len; dbflags = hextoulong(&dbrec[k],j); debug(F001,"getslot dbflags","",dbflags); k = dbfld[db_MYPID].off; j = dbfld[db_MYPID].len; dbpid = hextoulong(&dbrec[k],j); debug(F001,"getslot dbpid","",dbpid); k = dbfld[db_SADDR].off; j = dbfld[db_SADDR].len; dbip = hextoulong(&dbrec[k],j); debug(F001,"getslot dbip","",dbip); if (dbflags & DBF_INUSE) { /* Remember last slot in use */ x = 0; /* Make sure it's REALLY in use */ if (dbpid == mypid && dbip == myip) { /* Check for PID == my PID */ x = 1; debug(F101,"getslot record pid","",dbpid); } else { /* Or for stale PID */ x = zchkpid(dbpid); debug(F101,"getslot zchkpid()","",x); } if (!x) { /* Bogus record */ x = freeslot(n); debug(F101,"getslot stale record pid: freeslot()","",x); if (x > -1 && !haveslot) dbflags = 0; } else { /* It's really in use */ dblastused = i; } } if (!haveslot) { /* If I don't have a slot yet */ if (!(dbflags & DBF_INUSE)) { /* Claim this one */ debug(F101,"getslot free slot", "", n); haveslot = 1; mydbseek = i; mydbslot = n; /* But keep going... */ } } } /* Come here with i == seek pointer to first record after eof */ if (!haveslot) { /* Found no free slot so add to end */ debug(F101,"getslot new slot","",n); haveslot = 1; mydbseek = i; mydbslot = n; } ikdbopen = 1; /* OK to make database entries */ debug(F101,"getslot records","",n); debug(F101,"getslot dblastused","",dblastused); debug(F101,"getslot i","",i); /* Trim stale records from end */ #ifndef NOFTRUNCATE if (i > dblastused+DB_RECL) { debug(F101,"getslot truncating at","",dblastused+DB_RECL); #ifdef COHERENT x = chsize(fileno(dbfp),dblastused+DB_RECL); #else x = ftruncate(fileno(dbfp),(CK_OFF_T)(dblastused+DB_RECL)); #endif /* COHERENT */ if (x < 0) /* (Not fatal) */ debug(F101,"getslot ftruncate failed", "", errno); } #endif /* NOFTRUNCATE */ /* Initialize my record */ if (initslot(mydbslot) < 0) { debug(F101,"getslot initslot() error","",n); ikdbopen = 0; goto xslot; } debug(F101,"getslot OK","",mydbslot); rc = mydbslot; /* OK return code */ xslot: /* Unlock the database and return */ if (unlink(lcknam) < 0) { debug(F111,"getslot lockfile removal failed",lcknam,errno); rc = -1; } return(rc); } #endif /* IKSDB */ #endif /* NOIKSD */ #endif /* NOICP */ ckuusy.c000664 045065 024037 00000413573 14767411021 012672 0ustar00fdckermit000000 000000 #include "ckcsym.h" #define XFATAL fatal /* C K U U S Y -- "User Interface" for C-Kermit Kermit, part Y */ /* Command-Line Argument Parser */ /* Authors: Frank da Cruz , The Kermit Project, New York City Jeffrey E Altman Secure Endpoints Inc., New York City Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Most recent update: Fri Apr 14 14:37:46 2023 (function prototypes and declations) */ #include "ckcdeb.h" char * bannerfile = NULL; char * helpfile = NULL; extern int xferlog, filepeek, nolinks; extern char * xferfile; extern int debtim; #include "ckcasc.h" #include "ckcker.h" #include "ckucmd.h" #include "ckcnet.h" #include "ckuusr.h" #include "ckcxla.h" #ifdef CK_SSL #include "ck_ssl.h" #endif /* CK_SSL */ #include #ifdef CK_ANSIC /* prototype for static funtion - fdc 30 November 2022 */ static int xx_ftp( char *, char * ); #endif /* CK_ANSIC */ #ifdef OS2 #include #include "ckocon.h" #ifdef KUI #include "ikui.h" extern struct _kui_init kui_init; #endif /* KUI */ _PROTOTYP( int os2settitle, (char *, int) ); #ifdef SSHBUILTIN #include "ckossh.h" #endif /* SSHBUILTIN */ #endif /* OS2 */ /* ckcfnp.c: new to C-Kermit 1.0. Prototypes for functions used in multiple modules. This header file should be included only after all others that define symbols or typedefs needed for the prototypes. */ #include "ckcfnp.h" #ifdef OS2 #endif /* OS2 */ /* Prototypes for static functions used only in this module */ #ifdef CK_ANSIC #ifdef USE_CL_INT /* Clang 16 wrongly says cl_int() has no prototype. But it does have a prototype and it has an ANSI function declaration. In Clang 17 this will be a fatal error and C-Kermit can't be built any more. cl_int() is for trapping Ctrl-C before C-Kermit enters its command parser. Let's see if we can live without it - fdc, Fri Apr 14 14:35:16 2023 */ static SIGTYP cl_int( int ); /* SIGTYP is typdef'd in ckcdeb.h */ #endif /* USE_CL_INT */ static int pmsg( char * ); static int fmsg( char * ); #ifdef TNCODE static int dotnarg( char ); #endif /* TNCODE */ #ifdef RLOGCODE static int dorlgarg( char ); #endif /* RLOGCODE */ #ifdef SSHBUILTIN static int dossharg(char ); #endif /* SSHBUILTIN */ #endif /* CK_ANSIC */ extern int inserver, fncnv, f_save, xfermode; #ifdef PATTERNS extern int patterns; #endif /* PATTERNS */ #ifndef NOICP extern int cmdint; #endif /* NOICP */ extern int xsuspend; #ifdef NETCONN #ifdef ANYX25 extern int revcall, closgr, cudata; extern char udata[]; extern int x25fd; #endif /* ANYX25 */ #ifndef VMS #ifndef OS2 #ifndef OSK extern #endif /* OSK */ #endif /* OS2 */ #endif /* VMS */ int telnetfd; extern struct keytab netcmd[]; extern int tn_exit; #ifndef NOICP #ifndef NODIAL extern int nnets, nnetdir; /* Network services directory */ extern char *netdir[]; extern char *nh_p[]; /* Network directory entry pointers */ extern char *nh_p2[]; /* Network directory entry nettype */ extern char *nh_px[4][MAXDNUMS + 1]; #endif /* NODIAL */ extern int nhcount; extern char * n_name; /* Network name pointer */ #endif /* NOICP */ #endif /* NETCONN */ #ifndef NOSPL extern int nmac; extern struct mtab *mactab; #endif /* NOSPL */ extern char uidbuf[]; #ifdef CK_LOGIN extern int logintimo; #endif /* CK_LOGIN */ extern char * myname, * dftty; extern int howcalled; extern char *ckxsys, *ckzsys, **xargv, *xarg0, **cmlist, *clcmds; extern int action, cflg, xargc, cnflg, local, quiet, escape, network, mdmtyp, bgset, backgrd, xargs, binary, parity, turn, turnch, duplex, flow, clfils, noinit, stayflg, nettype, cfilef, noherald, cmask, cmdmsk, exitonclose, haveline, justone, cxtype, xfinish, ttnproto; extern long speed; extern char ttname[]; extern char * pipedata, cmdfil[]; #ifndef NOXFER extern char *cmarg, *cmarg2; extern int nfils, stdouf, stdinf, displa, maxrps, rpsiz, ckwarn, urpsiz, wslotr, swcapr, ckdelay, recursive, reliable, xreliable, fnspath, fncact, clearrq, setreliable; #ifdef PIPESEND extern int usepipes, pipesend; #endif /* PIPESEND */ extern int protocol; #endif /* NOXFER */ #ifndef NOPUSH extern int nopush; #endif /* NOPUSH */ #ifdef OS2 extern struct keytab os2devtab[]; extern int nos2dev; extern int ttslip; extern int tt_scroll, tt_escape; #ifdef OS2PM extern int os2pm; #endif /* OS2PM */ extern int usageparm; extern unsigned long startflags; #endif /* OS2 */ #ifdef CK_NETBIOS extern unsigned char NetBiosAdapter; #endif /* CK_NETBIOS */ #ifdef XFATAL #undef XFATAL #endif /* XFATAL */ int haveftpuid = 0; /* Have FTP user ID */ static char * failmsg = NULL; /* Failure message */ #ifdef NEWFTP extern char * ftp_host; #endif /* NEWFTP */ extern int what; #ifndef NOICP #ifndef NODIAL extern int nmdm, telephony; extern struct keytab mdmtab[]; extern int usermdm, dialudt; #endif /* NODIAL */ static int #ifdef CK_ANSIC pmsg( char *s ) #else pmsg(s) char *s; #endif /* CK_ANSIC */ { printf("%s\n", s); return(0); } static int #ifdef CK_ANSIC fmsg( char *s ) #else fmsg(s) char *s; #endif /* CK_ANSIC */ { fatal(s); return(0); } #define XFATAL(s) return(what==W_COMMAND?pmsg(s):fmsg(s)) #else #define XFATAL fatal #endif /* NOICP */ #ifndef NOHTTP #define HTTP_GET 1 #define HTTP_PUT 2 #define HTTP_HED 3 #endif /* NOHTTP */ #ifdef CK_URL /* URLs we recognize */ #define URL_FTP 1 #define URL_HTTP 2 #define URL_HTTPS 3 #define URL_IKSD 4 #define URL_TELNET 5 #define URL_LOGIN 6 struct keytab urltab[] = { #ifdef NEWFTP "ftp", URL_FTP, 0, #endif /* NEWFTP */ #ifndef NOHTTP "http", URL_HTTP, 0, "https", URL_HTTPS, 0, #endif /* NOHTTP */ "iksd", URL_IKSD, 0, "kermit", URL_IKSD, 0, "telnet", URL_TELNET, 0, "", 0, 0 }; int nurltab = sizeof(urltab)/sizeof(struct keytab) - 1; struct urldata g_url = {NULL,NULL,NULL,NULL,NULL,NULL,NULL}; /* u r l p a r s e -- Parse a possible URL */ /* Returns 0 if the candidate does not seem to be a URL. Returns 1 if it might be a URL, with the above pointers set to its pieces: service : [ // ] [ user [ : password ] @ ] host [ : service ] [ / path ] - [ ? name [ = value ]] Example: ftp://ds.internic.net:21/rfc/rfc1234.txt url.svc = [ftp] url.usr = [(NULL)] url.psw = [(NULL)] url.hos = [ds.internic.net] url.por = [21] url.pth = [rfc/rfc1234.txt] It might be a URL if it contains a possible service name followed by a a colon (:). Thus "telnet:xyzcorp.com" is a minimal URL, whereas a full-blown example would be: ftp://olga:secret@ftp.xyzcorp.com/public/oofa.txt The caller must verify the results, i.e. that the service string is a real TCP service, etc. This routine just parses the fields. struct urldata defined in ckcker.h */ int #ifdef CK_ANSIC urlparse( char *s, struct urldata * url ) #else urlparse(s,url) char *s; struct urldata * url; #endif /* CK_ANSIC */ { char * p = NULL, * urlbuf = NULL; #ifdef COMMENT int x; #endif /* COMMENT */ if (!s || !url) return(0); if (!*s) return(0); makestr(&urlbuf,s); if (url->sav) { /* In case we were called before... */ free(url->sav); url->sav = NULL; } if (url->svc) { free(url->svc); url->svc = NULL; } if (url->hos) { free(url->hos); url->hos = NULL; } if (url->por) { free(url->por); url->por = NULL; } if (url->usr) { free(url->usr); url->usr = NULL; } if (url->psw) { free(url->psw); url->psw = NULL; } if (url->pth) { free(url->pth); url->pth = NULL; } if (url->nopts) { int i; for (i = 0; i < url->nopts && i < MAX_URL_OPTS; i++ ) { if (url->opt[i].nam) { free(url->opt[i].nam); url->opt[i].nam = NULL; } if (url->opt[i].val) { free(url->opt[i].val); url->opt[i].val = NULL; } } url->nopts = 0; } p = urlbuf; /* Was a service requested? */ while (*p && *p != ':') /* Look for colon */ p++; if (*p == ':') { /* Have a colon */ *p++ = NUL; /* Get service name or number */ if (*p == ':') /* a second colon */ *p++ = NUL; /* get rid of that one too */ while (*p == '/') *p++ = NUL; /* and slashes */ #ifdef COMMENT /* Trailing slash is part of path - leave it - jaltman */ x = strlen(p); /* Length of remainder */ if (p[x-1] == '/') /* If there is a trailing slash */ p[x-1] = NUL; /* remove it. */ #endif /* COMMENT */ if (urlbuf[0]) { /* Anything left? */ char *q = p, *r = p, *w = p; makestr(&url->svc,urlbuf); while (*p != NUL && *p != '@') /* look for @ */ p++; if (*p == '@') { /* Signifies user ID, maybe password */ *p++ = NUL; url->hos = p; while (*w != NUL && *w != ':') w++; if (*w == ':') *w++ = NUL; url->usr = r; /* Username */ if (*w) url->psw = w; /* Password */ q = p; } else { /* No username or password */ p = q; url->hos = p; } #ifdef COMMENT debug(F111,"urlparse url->usr",url->usr,url->usr); debug(F111,"urlparse url->psw",url->usr,url->psw); debug(F111,"urlparse url->hos",url->usr,url->hos); #endif /* COMMENT */ while (*p != NUL && *p != ':' && *p != '/') /* Port? */ p++; if (*p == ':') { /* TCP port */ *p++ = NUL; r = p; url->por = r; while (*p != NUL && *p != '/') p++; /* '/' is part of path, leave it until we can copy */ if (*p == '/') { makestr(&url->pth,p); /* Path */ *p = NUL; } } else { /* No port */ /* '/' is part of path, leave it */ if (*p == '/') { makestr(&url->pth,p); /* Path */ *p = NUL; } } } /* Copy non-NULL result strings */ if (url->svc) if (*url->svc) { p = url->svc; url->svc = NULL; makestr(&url->svc,p); } if (url->hos) if (*url->hos) { p = url->hos; url->hos = NULL; makestr(&url->hos,p); } if (url->por) if (*url->por) { p = url->por; url->por = NULL; makestr(&url->por,p); } /* WARNING (Wed Oct 9 16:09:03 2002): We now allow the username and password to be empty strings. These are treated differently from null pointers: an empty string means the URL included username and/or password fields that were empty, e.g. ftp://:@ftp.xyzcorp.com/somepath/somefile, which causes the client to prompt for the username and/or password. */ if (url->usr) /* if (*url->usr) */ { p = url->usr; url->usr = NULL; makestr(&url->usr,p); } if (url->psw) /* if (*url->psw) */ { p = url->psw; url->psw = NULL; makestr(&url->psw,p); } /* Save a copy of the full url if one was found. */ if (url->svc) makestr(&url->sav,s); free(urlbuf); return(url->svc ? 1 : 0); } return(0); } #endif /* CK_URL */ #ifndef NOCMDL char *hlp1[] = { #ifndef NOICP " [filename] [-x arg [-x arg]...[-yyy]..] [ = text ] ]\n", #else "[-x arg [-x arg]...[-yyy]..]\n", #endif /* NOICP */ "\n", " -x is an option requiring an argument, -y an option with no argument.\n", " If the first command-line argument is the name of a file, interactive-\n", " mode commands are executed from the file. The '=' argument tells Kermit\n", " not to parse the remainder of the command line, but to make the words\n", " following '=' available as \\%1, \\%2, ... \\%9. The command file \ (if any)\n", " is executed before the command-line options.\n", "\n", #ifndef NOICP "If no action command is included, or -S is, then after the command line is\n", "executed, Kermit issues its prompt and waits for you to type commands.\n", #else "Operation by command-line options only.\n", #endif /* NOICP */ "" }; static char *hlp2[] = { " [option-list] host[:port] [port]\n", " The option-list consists of zero, one, or more of:\n", " -8 Negotiate Telnet Binary in both directions\n", " -a Require use of Telnet authentication\n", " -d Turn on debug mode\n", " -E No escape character\n", " -K Refuse use of authentication; do not send username\n", " -l user Set username and request Telnet authentication\n", " -L Negotiate Telnet Binary Output only\n", " -x Require Encryption\n", " -D Disable forward-X\n", #ifndef NOICP " -T cert=file Use certificate in file\n", " -T key=file Use private key in file\n", " -T crlfile=file Use CRL in file\n", " -T crldir=dir Use CRLs in directory\n", " -T cipher=string Use only ciphers in string\n", #endif /* NOICP */ " -f Forward credentials to host\n", " -k realm Set default Kerberos realm\n", "" }; static char *hlp3[] = { /* rlogin */ " [option-list] host[:port] [port]\n", " The option-list consists of zero, one, or more of:\n", " -d Turn on debug mode\n", " -l user Set username\n", "" }; static char *hlp4[] = { /* ssh */ " [option-list] host[:port] [port]\n", " The option-list consists of zero, one, or more of:\n", #ifdef OS2 " -# flags Kermit 95 Startup Flags\n", " 1 turn off Win95 special fixes\n", " 2 do not load optional network dlls\n", " 4 do not load optional tapi dlls\n", " 8 do not load optional kerberos dlls\n", " 16 do not load optional zmodem dlls\n", " 32 use stdin for input instead of the console\n", " 64 use stdout for output instead of the console\n", " 128 do not terminate process in response to Session Logoff\n", #endif /* OS2 */ " -d Turn on debug mode\n", " -Y Disable init file processing\n", " -l user Set username\n", "" }; /* Command-line option help lines. Update this when adding new options! */ char * opthlp[128]; /* Option help */ char * arghlp[128]; /* Argument for option */ int optact[128]; /* Action-option flag */ VOID #ifdef CK_ANSIC fatal2( char *msg1, char *msg2 ) #else fatal2(msg1,msg2) char *msg1, *msg2; #endif /* CK_ANSIC */ { char buf[256]; if (!msg1) msg1 = ""; if (!msg2) msg2 = ""; ckmakmsg(buf,256,"\"",msg1,"\" - ",msg2); #ifndef NOICP if (what == W_COMMAND) printf("%s\n",buf); else #endif /* NOICP */ fatal((char *)buf); } #ifdef USE_CL_INT /* cl_int() ("command-line interrupt") is for trapping Ctrl-C as C-Kermit executes any command-line options before entering its command parser. But cl_int() generates an inexplicable "non-prototype" warning by Clang 15 that will turn into a fatal error in Clang C2x. Look, here's the prototype right here, in which SIGTYP is typedef'd appropriately in ckcdeb.h, which has already been processed above. fdc - Fri Apr 14 14:51:22 2023 */ static SIGTYP #ifdef CK_ANSI cl_int( int dummy ) /* Command-line interrupt handler */ #else /* CK_ANSI */ cl_int( dummy ) int dummy; #endif /* CK_ANSI */ { doexit(BAD_EXIT,1); SIGRETURN; } #endif /* USE_CL_INT */ #ifdef NEWFTP extern int ftp_action, ftp_cmdlin; static int #ifdef CK_ANSIC xx_ftp( char * host, char * port ) #else xx_ftp(host, port) char * host, * port; #endif /* CK_ANSIC */ { #ifdef CK_URL extern int haveurl; #endif /* CK_URL */ extern char * ftp_logname; int use_tls = 0; char * p; if (port) if (!*port) port = NULL; if (!host) return(0); if (!*host) return(0); debug(F111,"ftp xx_ftp host",ftp_host,haveftpuid); debug(F111,"ftp xx_ftp uidbuf 1",uidbuf,haveftpuid); ftp_cmdlin = 1; /* 1 = FTP started from command line */ if (nfils > 0) ftp_cmdlin++; /* 2 = same plus file transfer */ #ifndef NOURL /* debug(F111,"ftp xx_ftp g_url.usr",g_url.usr,g_url.usr); */ if (haveurl && g_url.usr) { /* Wed Oct 9 15:15:22 2002 */ if (!*(g_url.usr)) { /* Force username prompt if */ haveftpuid = 0; /* "ftp://:@host" given. */ uidbuf[0] = NUL; makestr(&ftp_logname,NULL); } debug(F111,"ftp xx_ftp uidbuf 2",uidbuf,haveftpuid); } #endif /* NOURL */ debug(F111,"ftp xx_ftp uidbuf 3",uidbuf,haveftpuid); if (haveftpuid) { makestr(&ftp_logname,uidbuf); debug(F111,"ftp_logname",ftp_logname,haveftpuid); } if (!port) { if ((p = ckstrchr(ftp_host,':'))) *p++ = NUL; port = p; } if (!port) { #ifdef CK_URL if (haveurl) { if (g_url.por) port = g_url.por; else if (g_url.svc) port = g_url.svc; else port = "ftp"; } else #endif /* CK_URL */ port = "ftp"; } #ifdef CK_SSL if (haveurl && g_url.svc) use_tls = !ckstrcmp("ftps",g_url.svc,-1,0); #endif /* CK_SSL */ if (ftpopen(ftp_host,port,use_tls) < 1) return(-1); debug(F111,"ftp xx_ftp action",ckctoa((char)ftp_action),nfils); if (nfils > 0) { switch (ftp_action) { case 'g': return(cmdlinget(stayflg)); case 'p': case 's': return(cmdlinput(stayflg)); } } return(1); } #endif /* NEWFTP */ #ifndef NOHTTP static char * http_hlp[] = { " -h This message.\n", " -d Debug to debug.log.\n", " -S Stay (issue command prompt when done).\n", " -Y Do not execute Kermit initialization file.\n", " -q Quiet (suppress most messages).\n", " -u name Username.\n", " -P password Password.\n", " -g pathname Get remote pathname.\n", " -p pathname Put remote pathname.\n", " -H pathname Head remote pathname.\n", " -l pathname Local path for -g, -p, and -H.\n", #ifdef CK_SSL " -z opt[=value] Security options...\n", " cert=file Client certificate file\n", " certsok Accept all certificates\n", " key=file Client private key file\n", " secure Use SSL\n", " verify=n 0 = none, 1 = peer , 2 = certificate required\n", #endif /* CK_SSL */ "" }; #ifdef CK_SSL #ifndef NOICP #define HT_CERTFI 0 #define HT_OKCERT 1 #define HT_KEY 2 #define HT_SECURE 3 #define HT_VERIFY 4 static struct keytab httpztab[] = { { "cert", HT_CERTFI, CM_ARG }, { "certsok", HT_OKCERT, 0 }, { "key", HT_KEY, CM_ARG }, { "secure", HT_SECURE, 0 }, { "verify", HT_VERIFY, CM_ARG }, { "", 0, 0 } }; static int nhttpztab = sizeof(httpztab) / sizeof(struct keytab) - 1; #endif /* NOICP */ #endif /* CK_SSL */ #endif /* NOHTTP */ /* U S A G E */ VOID usage() { #ifdef MINIX conol("Usage: "); conol(xarg0); conol(" [-x arg [-x arg]...[-yyy]..] ]\n"); #else conol("Usage: "); conol(xarg0); if (howcalled == I_AM_KERMIT || howcalled == I_AM_IKSD || howcalled == I_AM_SSHSUB) conola(hlp1); else if (howcalled == I_AM_TELNET) conola(hlp2); else if (howcalled == I_AM_RLOGIN) conola(hlp3); else if (howcalled == I_AM_SSH) conola(hlp4); if (howcalled == I_AM_KERMIT || howcalled == I_AM_IKSD || howcalled == I_AM_SSHSUB) { int c; conoll(""); conoll("Complete listing of command-line options:"); conoll(""); for (c = 31; c < 128; c++) { if (!opthlp[c]) continue; if (arghlp[c]) { printf(" -%c %s\n", (char)c, (optact[c] ? " (action option)" : "") ); printf(" %s\n",opthlp[c]); printf(" Argument: %s\n\n",arghlp[c]); } else { /* Option without arg */ printf(" -%c %s%s\n", (char)c, opthlp[c], (optact[c]?" (action option)":"") ); printf(" Argument: (none)\n\n"); } } #ifdef OS2ORUNIX printf("To prevent this message from scrolling, use '%s -h | more'.\n", xarg0); #endif /* OS2ORUNIX */ printf("For a list of extended options use '%s --help'.\n", xarg0); } #endif /* MINIX */ } /* C M D L I N -- Get arguments from command line */ int cmdlin() { char x; /* Local general-purpose char */ extern int haveurl; #ifdef NEWFTP char * port = NULL; #endif /* NEWFTP */ #ifndef NOXFER cmarg = ""; /* Initialize globals */ cmarg2 = ""; #endif /* NOXFER */ action = 0; cflg = 0; #ifdef USE_CL_INT signal(SIGINT,cl_int); #endif /* USE_CL_INT */ /* Here we handle different "Command Line Personalities" */ #ifdef TCPSOCKET #ifndef NOHTTP if (howcalled == I_AM_HTTP) { /* If I was called as HTTP... */ char rdns[128]; #ifdef OS2 char * agent = "Kermit 95"; #else char * agent = "C-Kermit"; #endif /* OS2 */ debug(F100,"http personality","",0); #ifndef NOICP #ifdef CK_URL if (haveurl) { int type; char * lfile; type = lookup(urltab,g_url.svc,nurltab,NULL); if (!(type == URL_HTTP || type == URL_HTTPS)) { printf("?Internal Error: HTTP command line processing\n"); debug(F100,"Error: HTTP command line processing","",0); doexit(BAD_EXIT,1); } rdns[0] = '\0'; lfile = ""; x = (http_open(g_url.hos,g_url.por ? g_url.por : g_url.svc, type == URL_HTTPS, rdns,128,NULL) == 0); if (x) { #ifdef KUI char asname[CKMAXPATH+1]; #endif /* KUI */ if (!quiet) { if (rdns[0]) printf("Connected to %s [%s]\r\n",g_url.hos,rdns); else printf("Connected to %s\r\n",g_url.hos); } if (g_url.pth) zstrip(g_url.pth,&lfile); else g_url.pth = "/"; if (!*lfile) lfile = "index.html"; #ifdef KUI if (uq_file(NULL, /* K95 GUI: Put up file box. */ NULL, /* (not tested...) */ 4, NULL, lfile, asname, CKMAXPATH+1 ) > 0) lfile = asname; #endif /* KUI */ x = http_get(agent, NULL, /* hdrlist */ g_url.usr, g_url.psw, 0, lfile, g_url.pth, 0 /* stdio */ ); x = (http_close() == 0); } else { if (!quiet) printf("?HTTP Connection failed.\r\n"); } doexit(x ? GOOD_EXIT : BAD_EXIT, -1); } else #endif /* CK_URL */ #endif /* NOICP */ { int http_action = 0; char * host = NULL, * svc = NULL, * lpath = NULL; char * user = NULL, * pswd = NULL, * path = NULL; char * xp; while (--xargc > 0) { /* Go through command line words */ xargv++; debug(F111,"cmdlin http xargv",*xargv,xargc); xp = *xargv+1; if (**xargv == '-') { /* Got an option */ x = *(*xargv+1); /* Get the option letter */ switch (x) { case 'd': /* Debug */ #ifdef DEBUG if (deblog) { debtim = 1; } else { deblog = debopn("debug.log",0); } #endif /* DEBUG */ break; case 'S': /* Stay */ case 'Y': /* No initialization file */ break; /* (already done in prescan) */ case 'q': /* Quiet */ quiet = 1; break; case 'u': /* Options that require arguments */ case 'P': case 'g': case 'p': case 'H': case 'l': if (*(xp+1)) { XFATAL("Invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("Missing argument"); } switch (x) { case 'u': user = *xargv; break; case 'P': pswd = *xargv; break; case 'l': if (http_action != HTTP_PUT) lpath = *xargv; break; case 'g': http_action = HTTP_GET; path = *xargv; debug(F111,"cmdlin http GET",path,http_action); break; case 'p': http_action = HTTP_PUT; path = *xargv; break; case 'H': http_action = HTTP_HED; path = *xargv; } break; #ifdef CK_SSL #ifndef NOICP case 'z': { /* *xargv contains a value of the form tag=value */ /* we need to lookup the tag and save the value */ int x,y,z; char * p, * q; makestr(&p,*xargv); y = ckindex("=",p,0,0,1); if (y > 0) p[y-1] = '\0'; x = lookup(httpztab,p,nhttpztab,&z); if (x < 0) { printf("?Invalid security option: \"%s\"\n",p); } else { printf("Security option: \"%s",p); if (httpztab[z].flgs & CM_ARG) { q = &p[y]; if (!*q) fatal("?Missing required value"); } /* -z options w/args */ switch (httpztab[z].kwval) { case HT_CERTFI: makestr(&ssl_rsa_cert_file,q); break; case HT_OKCERT: ssl_certsok_flag = 1; break; case HT_KEY: makestr(&ssl_rsa_key_file,q); break; case HT_SECURE: svc="https"; break; case HT_VERIFY: if (!rdigits(q)) printf("?Bad number: %s\n",q); ssl_verify_flag = atoi(q); break; } } free(p); break; } #endif /* NOICP */ #endif /* CK_SSL */ case 'h': /* Help */ default: printf("Usage: %s host [ options... ]\n",xarg0); conola(http_hlp); doexit(GOOD_EXIT,-1); } } else { /* No dash - must be hostname */ host = *xargv; if (xargc > 1) { svc = *(xargv+1); if (svc) if (*svc == '-' || !*svc) svc = NULL; if (svc) { xargv++; xargc--; } } } } if (!svc) svc = ""; if (!*svc) svc = "http"; if (!host) XFATAL("No http host given"); /* Check action args before opening the connection */ if (http_action) { if (http_action == HTTP_PUT) { if (!lpath) XFATAL("No local path for http PUT"); } if (!path) XFATAL("No remote path for http action"); } /* Now it's OK to open the connection */ rdns[0] = NUL; x = (http_open(host, svc,!ckstrcmp("https",svc,-1,0),rdns,128,NULL ) == 0); if (!x) { if (!quiet) printf("?HTTP Connection failed.\r\n"); doexit(BAD_EXIT,-1); } if (!quiet) { if (rdns[0]) printf("Connected to %s [%s]\r\n",host,rdns); else printf("Connected to %s\r\n",host); } if (http_action) { int pcpy = 0; if (http_action != HTTP_PUT) { /* Supply default */ if (!lpath) { /* local path... */ zstrip(path,&lpath); if (!lpath) lpath = ""; if (!*lpath) lpath = "index.html"; } } if (*path != '/') { char * p = (char *) malloc(strlen(path)+2); if (!p) fatal("?Memory allocation error\n"); *p = '/'; strcpy(&p[1],path); /* safe */ path = p; pcpy = 1; } switch (http_action) { case HTTP_GET: x = http_get(agent,NULL,user,pswd,0,lpath,path,0); break; case HTTP_PUT: x = http_put(agent,NULL,"text/HTML", user,pswd,0,lpath,path,NULL,0); break; case HTTP_HED: x = http_head(agent,NULL,user,pswd,0,lpath,path,0); break; } debug(F101,"cmdline http result","",x); x = (http_close() == 0); if (pcpy) free(path); doexit(x ? GOOD_EXIT : BAD_EXIT, -1); } return(0); } } else #endif /* NOHTTP */ #ifdef NEWFTP if (howcalled == I_AM_FTP) { /* If I was called as FTP... */ debug(F100,"ftp personality","",0); #ifdef CK_URL if (haveurl) doftparg('U'); else #endif /* CK_URL */ { while (--xargc > 0) { /* Go through command line words */ xargv++; debug(F111,"cmdlin ftp xargv",*xargv,xargc); if (**xargv == '-') { /* Got an option */ int xx; x = *(*xargv+1); /* Get the option letter */ xx = doftparg(x); if (xx < 0) { if (what == W_COMMAND) return(0); else doexit(BAD_EXIT,1); } } else { /* No dash - must be hostname */ makestr(&ftp_host,*xargv); if (xargc > 1) { port = *(xargv+1); if (port) if (*port == '-' || !*port) port = NULL; if (port) { xargv++; xargc--; } } debug(F110,"cmdlin ftp host",ftp_host,0); debug(F110,"cmdlin ftp port",port,0); } } /* while */ } /* if (haveurl) */ if (ftp_host) { int xx; #ifdef NODIAL xx = xx_ftp(ftp_host,port); if (xx < 0 && (haveurl || ftp_cmdlin > 1)) doexit(BAD_EXIT,-1); #else #ifdef NOICP xx = xx_ftp(ftp_host,port); if (xx < 0 && (haveurl || ftp_cmdlin > 1)) doexit(BAD_EXIT,-1); #else if (*ftp_host == '=') { /* Skip directory lookup */ xx = xx_ftp(&ftp_host[1],port); if (xx < 0 && (haveurl || ftp_cmdlin > 1)) doexit(BAD_EXIT,-1); } else { /* Want lookup */ int i; nhcount = 0; /* Check network directory */ debug(F101,"cmdlin nnetdir","",nnetdir); if (nnetdir > 0) /* If there is a directory... */ lunet(ftp_host); /* Look up the name */ else /* If no directory */ nhcount = 0; /* we didn't find anything there */ #ifdef DEBUG if (deblog) { debug(F101,"cmdlin lunet nhcount","",nhcount); if (nhcount > 0) { debug(F110,"cmdlin lunet nh_p[0]",nh_p[0],0); debug(F110,"cmdlin lunet nh_p2[0]",nh_p2[0],0); debug(F110,"cmdlin lunet nh_px[0][0]", nh_px[0][0],0); } } #endif /* DEBUG */ if (nhcount == 0) { xx = xx_ftp(ftp_host,port); if (xx < 0 && (haveurl || ftp_cmdlin > 1)) doexit(BAD_EXIT,-1); } else { for (i = 0; i < nhcount; i++) { if (ckstrcmp(nh_p2[i],"tcp/ip",6,0)) continue; makestr(&ftp_host,nh_p[i]); debug(F110,"cmdlin calling xx_ftp",ftp_host,0); if (!quiet) printf("Trying %s...\n",ftp_host); if (xx_ftp(ftp_host,port) > -1) break; } } } #endif /* NODIAL */ #endif /* NOICP */ if (!ftpisconnected()) doexit(BAD_EXIT,-1); } return(0); } #endif /* NEWFTP */ #ifdef TNCODE if (howcalled == I_AM_TELNET) { /* If I was called as Telnet... */ while (--xargc > 0) { /* Go through command line words */ xargv++; debug(F111,"cmdlin telnet xargv",*xargv,xargc); if (**xargv == '=') return(0); if (!strcmp(*xargv,"--")) /* getopt() conformance */ return(0); #ifdef VMS else if (**xargv == '/') continue; #endif /* VMS */ else if (**xargv == '-') { /* Got an option (begins with dash) */ int xx; x = *(*xargv+1); /* Get the option letter */ debug(F111,"cmdlin telnet args 1",*xargv,xargc); xx = dotnarg(x); debug(F101,"cmdlin telnet doarg","",xx); debug(F111,"cmdlin telnet args 2",*xargv,xargc); if (xx < 0) { #ifndef NOICP if (what == W_COMMAND) return(0); else #endif /* NOICP */ { #ifdef OS2 sleep(1); /* Give it a chance... */ #endif /* OS2 */ doexit(BAD_EXIT,1); /* Go handle option */ } } } else { /* No dash must be hostname */ ckstrncpy(ttname,*xargv,TTNAMLEN+1); debug(F110,"cmdlin telnet host",ttname,0); #ifndef NOICP #ifndef NODIAL nhcount = 0; /* Check network directory */ debug(F101,"cmdlin telnet nnetdir","",nnetdir); if (nnetdir > 0) /* If there is a directory... */ lunet(*xargv); /* Look up the name */ else /* If no directory */ nhcount = 0; /* we didn't find anything there */ #ifdef DEBUG if (deblog) { debug(F101,"cmdlin telnet lunet nhcount","",nhcount); if (nhcount > 0) { debug(F110,"cmdlin telnet lunet nh_p[0]",nh_p[0],0); debug(F110,"cmdlin telnet lunet nh_p2[0]",nh_p2[0],0); debug(F110,"cmdlin telnet lunet nh_px[0][0]", nh_px[0][0],0); } } #endif /* DEBUG */ if (nhcount > 0 && nh_p2[0]) /* If network type specified */ if (ckstrcmp(nh_p2[0],"tcp/ip",6,0)) /* it must be TCP/IP */ nhcount = 0; if (nhcount == 1) { /* Still OK, so make substitution */ ckstrncpy(ttname,nh_p[0],TTNAMLEN+1); debug(F110,"cmdlin telnet lunet substitution",ttname,0); } #endif /* NODIAL */ #endif /* NOICP */ if (--xargc > 0 && !haveurl) { /* Service from command line? */ xargv++; ckstrncat(ttname,":",TTNAMLEN+1); ckstrncat(ttname,*xargv,TTNAMLEN+1); debug(F110,"cmdlin telnet host2",ttname,0); } #ifndef NOICP #ifndef NODIAL else if (nhcount) { /* No - how about in net directory? */ if (nh_px[0][0]) { ckstrncat(ttname,":",TTNAMLEN+1); ckstrncat(ttname,nh_px[0][0],TTNAMLEN+1); } } #endif /* NODIAL */ #endif /* NOICP */ local = 1; /* Try to open the connection */ nettype = NET_TCPB; mdmtyp = -nettype; if (ttopen(ttname,&local,mdmtyp,0) < 0) { XFATAL("can't open host connection"); } network = 1; /* It's open */ #ifdef CKLOGDIAL dolognet(); #endif /* CKLOGDIAL */ #ifndef NOXFER reliable = 1; /* It's reliable */ xreliable = 1; /* ... */ setreliable = 1; #endif /* NOXFER */ cflg = 1; /* Connect */ stayflg = 1; /* Stay */ tn_exit = 1; /* Telnet-like exit condition */ quiet = 1; exitonclose = 1; /* Exit when connection closes */ #ifndef NOSPL if (local) { if (nmac) { /* Any macros defined? */ int k; /* Yes */ k = mlook(mactab,"on_open",nmac); /* Look this up */ if (k >= 0) { /* If found, */ if (dodo(k,ttname,0) > -1) /* set it up, */ parser(1); /* and execute it */ } } } #endif /* NOSPL */ break; } } return(0); } #endif /* TNCODE */ #ifdef RLOGCODE else if (howcalled == I_AM_RLOGIN) { /* If I was called as Rlogin... */ while (--xargc > 0) { /* Go through command line words */ xargv++; debug(F111,"cmdlin rlogin xargv",*xargv,xargc); if (**xargv == '=') return(0); if (!strcmp(*xargv,"--")) /* getopt() conformance */ return(0); #ifdef VMS else if (**xargv == '/') continue; #endif /* VMS */ else if (**xargv == '-') { /* Got an option (begins with dash) */ int xx; x = *(*xargv+1); /* Get the option letter */ debug(F111,"cmdlin rlogin args 1",*xargv,xargc); xx = dorlgarg(x); debug(F101,"cmdlin rlogin doarg","",xx); debug(F111,"cmdlin rlogin args 2",*xargv,xargc); if (xx < 0) { #ifndef NOICP if (what == W_COMMAND) return(0); else #endif /* NOICP */ { #ifdef OS2 sleep(1); /* Give it a chance... */ #endif /* OS2 */ doexit(BAD_EXIT,1); /* Go handle option */ } } } else { /* No dash must be hostname */ ckstrncpy(ttname,*xargv,TTNAMLEN+1); debug(F110,"cmdlin rlogin host",ttname,0); #ifndef NOICP #ifndef NODIAL nhcount = 0; /* Check network directory */ debug(F101,"cmdlin rlogin nnetdir","",nnetdir); if (nnetdir > 0) /* If there is a directory... */ lunet(*xargv); /* Look up the name */ else /* If no directory */ nhcount = 0; /* we didn't find anything there */ #ifdef DEBUG if (deblog) { debug(F101,"cmdlin rlogin lunet nhcount","",nhcount); if (nhcount > 0) { debug(F110,"cmdlin rlogin lunet nh_p[0]",nh_p[0],0); debug(F110,"cmdlin rlogin lunet nh_p2[0]",nh_p2[0],0); debug(F110,"cmdlin rlogin lunet nh_px[0][0]", nh_px[0][0],0); } } #endif /* DEBUG */ if (nhcount > 0 && nh_p2[0]) /* If network type specified */ if (ckstrcmp(nh_p2[0],"tcp/ip",6,0)) /* it must be TCP/IP */ nhcount = 0; if (nhcount == 1) { /* Still OK, so make substitution */ ckstrncpy(ttname,nh_p[0],TTNAMLEN+1); debug(F110,"cmdlin rlogin lunet substitution",ttname,0); } #endif /* NODIAL */ #endif /* NOICP */ if (!haveurl) { /* Service from command line? */ ckstrncat(ttname,":login",TTNAMLEN+1); debug(F110,"cmdlin rlogin host2",ttname,0); } local = 1; /* Try to open the connection */ nettype = NET_TCPB; mdmtyp = -nettype; if (ttopen(ttname,&local,mdmtyp,0) < 0) { XFATAL("can't open host connection"); } network = 1; /* It's open */ #ifdef CKLOGDIAL dolognet(); #endif /* CKLOGDIAL */ #ifndef NOXFER reliable = 1; /* It's reliable */ xreliable = 1; /* ... */ setreliable = 1; #endif /* NOXFER */ cflg = 1; /* Connect */ stayflg = 1; /* Stay */ tn_exit = 1; /* Telnet-like exit condition */ quiet = 1; exitonclose = 1; /* Exit when connection closes */ #ifndef NOSPL if (local) { if (nmac) { /* Any macros defined? */ int k; /* Yes */ k = mlook(mactab,"on_open",nmac); /* Look this up */ if (k >= 0) { /* If found, */ if (dodo(k,ttname,0) > -1) /* set it up, */ parser(1); /* and execute it */ } } } #endif /* NOSPL */ break; } } return(0); } #endif /* RLOGCODE */ #endif /* TCPSOCKET */ #ifdef SSHBUILTIN if (howcalled == I_AM_SSH) { /* If I was called as SSH... */ debug(F100,"ssh personality","",0); #ifdef CK_URL if (haveurl) { ssh_set_sparam(SSH_SPARAM_HST, g_url.hos); ssh_set_sparam(SSH_SPARAM_PRT,g_url.svc); ckstrncpy(ttname,ssh_get_sparam(SSH_SPARAM_HST),TTNAMLEN+1); ckstrncat(ttname,":",TTNAMLEN+1); ckstrncat(ttname,ssh_get_sparam(SSH_SPARAM_PRT),TTNAMLEN+1); } else #endif /* CK_URL */ { while (--xargc > 0) { /* Go through command line words */ xargv++; debug(F111,"cmdlin ssh xargv",*xargv,xargc); if (**xargv == '=') return(0); if (!strcmp(*xargv,"--")) /* getopt() conformance */ return(0); #ifdef VMS else if (**xargv == '/') continue; #endif /* VMS */ /* Got an option (begins with dash) */ else if (**xargv == '-') { int xx; x = *(*xargv+1); /* Get the option letter */ debug(F111,"cmdlin args 1",*xargv,xargc); xx = dossharg(x); debug(F101,"cmdlin doarg","",xx); debug(F111,"cmdlin args 2",*xargv,xargc); if (xx < 0) { #ifndef NOICP if (what == W_COMMAND) return(0); else #endif /* NOICP */ { #ifdef OS2 sleep(1); /* Give it a chance... */ #endif /* OS2 */ doexit(BAD_EXIT,1); /* Go handle option */ } } } else { /* No dash must be hostname */ ckstrncpy(ttname,*xargv,TTNAMLEN+1); ssh_set_sparam(SSH_SPARAM_HST, ttname); debug(F110,"cmdlin ssh host",ttname,0); #ifndef NOICP #ifndef NODIAL nhcount = 0; /* Check network directory */ debug(F101,"cmdlin nnetdir","",nnetdir); if (nnetdir > 0) /* If there is a directory... */ lunet(*xargv); /* Look up the name */ else /* If no directory */ nhcount = 0; /* we didn't find anything there */ #ifdef DEBUG if (deblog) { debug(F101,"cmdlin lunet nhcount","",nhcount); if (nhcount > 0) { debug(F110,"cmdlin lunet nh_p[0]",nh_p[0],0); debug(F110,"cmdlin lunet nh_p2[0]",nh_p2[0],0); debug(F110, "cmdlin lunet nh_px[0][0]",nh_px[0][0],0); } } #endif /* DEBUG */ /* If network type specified */ /* it must be TCP/IP */ if (nhcount > 0 && nh_p2[0]) if (ckstrcmp(nh_p2[0],"tcp/ip",6,0)) nhcount = 0; if (nhcount == 1) { /* Still OK, so make substitution */ ckstrncpy(ttname,nh_p[0],TTNAMLEN+1); ssh_set_sparam(SSH_SPARAM_HST, ttname); debug(F110,"cmdlin lunet substitution",ttname,0); } #endif /* NODIAL */ #endif /* NOICP */ /* Service from command line? */ if (--xargc > 0 && !haveurl) { xargv++; ckstrncat(ttname,":",TTNAMLEN+1); ckstrncat(ttname,*xargv,TTNAMLEN+1); ssh_set_sparam(SSH_SPARAM_PRT,*xargv); debug(F110,"cmdlin telnet host2",ttname,0); } #ifdef COMMENT /* Do not substitute net dir service for ssh port */ #ifndef NOICP #ifndef NODIAL /* No - how about in net directory? */ else if (nhcount) { if (nh_px[0][0]) { ckstrncat(ttname,":",TTNAMLEN+1); ckstrncat(ttname,nh_px[0][0],TTNAMLEN+1); ssh_set_sparam(SSH_SPARAM_PRT,nh_px[0][0]); } } #endif /* NODIAL */ #endif /* NOICP */ #endif /* COMMENT */ break; } } } local = 1; /* Try to open the connection */ nettype = NET_SSH; mdmtyp = -nettype; if (ttopen(ttname,&local,mdmtyp,0) < 0) { XFATAL("can't open host connection"); } network = 1; /* It's open */ #ifdef CKLOGDIAL dolognet(); #endif /* CKLOGDIAL */ #ifndef NOXFER reliable = 1; /* It's reliable */ xreliable = 1; /* ... */ setreliable = 1; #endif /* NOXFER */ cflg = 1; /* Connect */ stayflg = 1; /* Stay */ tn_exit = 1; /* Telnet-like exit condition */ quiet = 1; exitonclose = 1; /* Exit when connection closes */ #ifndef NOSPL if (local) { if (nmac) { /* Any macros defined? */ int k; /* Yes */ k = mlook(mactab,"on_open",nmac); /* Look this up */ if (k >= 0) { /* If found, */ if (dodo(k,ttname,0) > -1) /* set it up, */ parser(1); /* and execute it */ } } } #endif /* NOSPL */ return(0); } #endif /* SSHBUILTIN */ if (howcalled == I_AM_SSHSUB) return(0); /* From here down: We were called as "kermit" or "iksd". If we were started directly from a Kermit script file, the filename of the script is in argv[1], so skip past it. */ if (xargc > 1) { int n = 1; if (*xargv[1] != '-') { #ifdef KERBANG /* If we were started with a Kerbang script, the script */ /* arguments were already picked up in prescan / cmdini() */ /* and there is nothing here for us anyway. */ if (!strcmp(xargv[1],"+")) return(0); #endif /* KERBANG */ if (cfilef) { /* Command file found in prescan() */ xargc -= n; /* Skip past it */ xargv += n; cfilef = 0; debug(F101,"cmdlin cfilef set to 0","",cfilef); } } } /* Regular Unix-style command line parser, mostly conforming with 'A Proposed Command Syntax Standard for Unix Systems', Hemenway & Armitage, Unix/World, Vol.1, No.3, 1984. */ while (--xargc > 0) { /* Go through command line words */ xargv++; debug(F111,"cmdlin xargv",*xargv,xargc); if (**xargv == '=') return(0); if (!strcmp(*xargv,"--")) /* getopt() conformance */ return(0); #ifdef VMS else if (**xargv == '/') continue; #endif /* VMS */ else if (**xargv == '-') { /* Got an option (begins with dash) */ int xx; x = *(*xargv+1); /* Get the option letter */ debug(F111,"cmdlin args 1",*xargv,xargc); xx = doarg(x); debug(F101,"cmdlin doarg","",xx); debug(F111,"cmdlin args 2",*xargv,xargc); if (xx < 0) { #ifndef NOICP if (what == W_COMMAND) return(0); else #endif /* NOICP */ { #ifdef OS2 sleep(1); /* Give it a chance... */ #endif /* OS2 */ doexit(BAD_EXIT,1); /* Go handle option */ } } } else if (!haveurl) { /* No dash where expected */ char xbuf[40]; /* enlarged a bit due to warning 20211209 */ char buf[128]; int k; k = ckstrncpy(xbuf,*xargv,40); if (k > 30) { xbuf[30] = '.'; xbuf[29] = '.'; xbuf[28] = '.'; } xbuf[31] = NUL; ckmakmsg(buf, 128, "invalid command-line option, type \"", myname, " -h\" for help", NULL ); fatal2(xbuf,buf); } } #ifdef DEBUG if (deblog) { #ifndef NOICP debug(F101,"cmdlin what","",what); #endif /* NOICP */ debug(F101,"cmdlin action","",action); #ifndef NOXFER debug(F101,"cmdlin stdouf","",stdouf); #endif /* NOXFER */ } #endif /* DEBUG */ #ifdef NOICP if (!action && !cflg && !cnflg) { debug(F100,"cmdlin NOICP fatal no action","",0); XFATAL("?No actions specified on command line"); } #else if (inserver && what == 0) { /* Internet Kermit server checks */ if (local || (action != 0 && action != 'x')) { if (local) printf("local\r\n"); if (action) printf("action=%c\r\n",action); debug(F100,"cmdlin fatal 1","",0); XFATAL("No actions or connections allowed with -A"); } } #endif /* NOICP */ #ifndef NOLOCAL if (!local) { if ((action == 'c') || (cflg != 0)) { debug(F100,"cmdlin fatal 2","",0); XFATAL("-l or -j or -X required"); } } #endif /* NOLOCAL */ #ifndef NOXFER if (*cmarg2 != 0) { if ((action != 's') && (action != 'r') && (action != 'v')) { debug(F100,"cmdlin fatal 3","",0); XFATAL("-a without -s, -r, or -g"); } if (action == 'r' || action == 'v') { #ifdef CK_TMPDIR if (isdir(cmarg2)) { /* -a is a directory */ if (!zchdir(cmarg2)) { /* try to change to it */ debug(F100,"cmdlin fatal 4","",0); XFATAL("can't change to '-a' directory"); } else cmarg2 = ""; } else #endif /* CK_TMPDIR */ if (zchko(cmarg2) < 0) { debug(F100,"cmdlin fatal 5","",0); XFATAL("write access to -a file denied"); } } } if ((action == 'v') && (stdouf) && (!local)) { if (is_a_tty(1)) { debug(F100,"cmdlin fatal 6","",0); XFATAL("unredirected -k can only be used in local mode"); } } if ((action == 's') || (action == 'v') || (action == 'r') || (action == 'x')) { if (local) displa = 1; if (stdouf) { displa = 0; quiet = 1; } } if (quiet) displa = 0; /* No display if quiet requested */ #endif /* NOXFER */ #ifdef DEBUG if (action) debug(F000,"cmdlin returns action","",action); else debug(F101,"cmdlin returns action","",action); #endif /* DEBUG */ return(action); /* Then do any requested protocol */ } /* Extended argument parsing: --keyword[:value] (or =value) */ /* XA_xxxx symbols are defined in ckuusr.h. If you add a new one, also remember to update doshow(), SHXOPT section, in ckuus5.c. */ struct keytab xargtab[] = { #ifdef CK_LOGIN { "anonymous", XA_ANON, CM_ARG|CM_PRE }, #endif /* CK_LOGIN */ { "bannerfile", XA_BAFI, CM_ARG }, { "cdfile", XA_CDFI, CM_ARG }, { "cdmessage", XA_CDMS, CM_ARG }, { "cdmsg", XA_CDMS, CM_ARG|CM_INV }, #ifdef KUI { "changedim", XA_CHGD, CM_PRE }, #endif /* KUI */ #ifndef NOCSETS { "charset", XA_CSET, CM_ARG|CM_PRE }, #endif /* NOCSETS */ #ifdef IKSDB { "database", XA_DBAS, CM_ARG|CM_PRE }, { "dbfile", XA_DBFI, CM_ARG|CM_PRE }, #endif /* IKSDB */ #ifdef KUI { "facename", XA_FNAM, CM_ARG|CM_PRE|CM_INV }, { "fontname", XA_FNAM, CM_ARG|CM_PRE }, { "fontsize", XA_FSIZ, CM_ARG|CM_PRE }, #endif /* KUI */ #ifdef COMMENT #ifdef NEWFTP { "ftp", XA_FTP, CM_ARG }, #endif /* NEWFTP */ #endif /* COMMENT */ #ifndef NOLOCAL #ifdef OS2 { "height", XA_ROWS, CM_ARG|CM_PRE }, #endif /* OS2 */ #endif /* NOLOCAL */ { "help", XA_HELP, 0 }, #ifndef NOHELP { "helpfile", XA_HEFI, CM_ARG }, #endif /* NOHELP */ #ifdef CK_LOGIN { "initfile", XA_ANFI, CM_ARG|CM_PRE }, #endif /* CK_LOGIN */ #ifdef OS2 { "lockdown", XA_LOCK, CM_PRE }, #ifdef KUI { "maximize", XA_WMAX, CM_PRE }, { "minimize", XA_WMIN, CM_PRE }, { "nobars", XA_NOBAR, CM_PRE }, { "noclose" , XA_NOCLOSE, CM_PRE }, #endif /* KUI */ { "noescape", XA_NOESCAPE, CM_PRE }, #endif /* OS2 */ { "nointerrupts",XA_NOIN, CM_PRE }, { "nolocale", XA_NOLOCALE, CM_PRE }, #ifdef KUI { "nomenubar", XA_NOMN, CM_PRE }, #endif /* KUI */ { "noperms", XA_NPRM, 0 }, #ifndef NOPUSH { "nopush", XA_NOPUSH, CM_PRE }, #endif /* NOPUSH */ #ifdef OS2 { "noscroll", XA_NOSCROLL, CM_PRE }, #endif /* OS2 */ #ifdef KUI { "nostatusbar", XA_NOSB, CM_PRE }, { "notoolbar", XA_NOTB, CM_PRE }, #endif /* KUI */ #ifdef COMMENT { "password", XA_PASS, CM_ARG|CM_INV }, #endif /* COMMENT */ #ifdef CK_LOGIN #ifndef NOXFER #ifdef CK_PERM { "permissions", XA_PERM, CM_ARG|CM_PRE }, { "perms", XA_PERM, CM_ARG|CM_PRE|CM_INV }, #endif /* CK_PERM */ #endif /* NOXFER */ #ifdef UNIX { "privid", XA_PRIV, CM_ARG|CM_PRE }, #endif /* UNIX */ #ifndef NOLOCAL #ifndef NOCSETS { "rcharset", XA_CSET, CM_ARG|CM_PRE|CM_INV }, #endif /* NOCSETS */ #endif /* NOLOCAL */ #ifdef UNIX { "root", XA_ROOT, CM_ARG|CM_PRE }, #else /* UNIX */ #ifdef CKROOT { "root", XA_ROOT, CM_ARG|CM_PRE }, #endif /* CKROOT */ #endif /* UNIX */ #ifdef KUI { "scalefont", XA_SCALE, CM_PRE }, #endif /* KUI */ #ifdef COMMENT #ifdef SSHBUILTIN { "ssh", XA_SSH, CM_ARG }, #endif /* SSHBUILTIN */ #endif /* COMMENT */ #ifdef CKSYSLOG { "syslog", XA_SYSL, CM_ARG|CM_PRE }, #endif /* CKSYSLOG */ #ifndef NOLOCAL #ifdef COMMENT #ifdef TNCODE { "telnet", XA_TEL, CM_ARG }, #endif /* TNCODE */ #endif /* COMMENT */ { "termtype", XA_TERM, CM_ARG|CM_PRE }, #endif /* NOLOCAL */ { "timeout", XA_TIMO, CM_ARG|CM_PRE }, #ifndef NOLOCAL #ifdef OS2 { "title", XA_TITL, CM_ARG }, #endif /* OS2 */ #ifdef UNIX { "unbuffered", XA_UNBUF, 0 }, #endif /* UNIX */ #ifndef NOSPL { "user", XA_USER, CM_ARG }, #endif /* NOSPL */ #endif /* NOLOCAL */ { "userfile", XA_USFI, CM_ARG|CM_PRE }, { "version", XA_VERS, 0 }, #ifndef NOLOCAL #ifdef OS2 { "width", XA_COLS, CM_ARG|CM_PRE }, #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef CKWTMP { "wtmpfile", XA_WTFI, CM_ARG|CM_PRE }, { "wtmplog", XA_WTMP, CM_ARG|CM_PRE }, #endif /* CKWTMP */ #endif /* CK_LOGIN */ { "xferfile", XA_IKFI, CM_ARG|CM_PRE }, { "xferlog", XA_IKLG, CM_ARG|CM_PRE }, #ifndef NOLOCAL #ifdef KUI { "xpos", XA_XPOS, CM_ARG|CM_PRE }, { "ypos", XA_YPOS, CM_ARG|CM_PRE }, #endif /* KUI */ #endif /* NOLOCAL */ {"", 0, 0 } }; int nxargs = sizeof(xargtab)/sizeof(struct keytab) - 1; static struct keytab oktab[] = { { "0", 0, 0 }, { "1", 1, 0 }, { "2", 2, 0 }, { "3", 3, 0 }, { "4", 4, 0 }, { "5", 5, 0 }, { "6", 6, 0 }, { "7", 7, 0 }, { "8", 8, 0 }, { "9", 9, 0 }, { "false", 0, 0 }, { "no", 0, 0 }, { "off", 0, 0 }, { "ok", 1, 0 }, { "on", 1, 0 }, { "true", 1, 0 }, { "yes", 1, 0 } }; static int noktab = sizeof(oktab)/sizeof(struct keytab); #define XARGBUFL 32 char * xopthlp[XA_MAX+1]; /* Extended option help */ char * xarghlp[XA_MAX+1]; /* Extended argument for option */ static VOID inixopthlp() { int i, j; for (i = 0; i <= XA_MAX; i++) { /* Initialize all to null */ xopthlp[i] = NULL; xarghlp[i] = NULL; } for (i = 0; i < nxargs; i++) { /* Then for each defined keyword */ j = xargtab[i].kwval; /* index by associated value */ if (j < 0 || j > XA_MAX) continue; switch (j) { #ifdef CK_LOGIN case XA_ANON: /* "--anonymous" */ xopthlp[j] = "--anonymous:{on,off} [IKSD only]"; xarghlp[j] = "Whether to allow anonymous IKSD logins"; break; #ifdef UNIX case XA_PRIV: xopthlp[j] = "--privid:{on,off} [IKSD only]"; xarghlp[j] = "Whether to allow privileged IDs to login to IKSD"; break; #endif /* UNIX */ #endif /* CK_LOGIN */ case XA_BAFI: /* "--bannerfile" */ xopthlp[j] = "--bannerfile:"; xarghlp[j] = "File to display upon startup or IKSD login"; break; case XA_CDFI: /* "--cdfile" */ xopthlp[j] = "--cdfile:"; xarghlp[j] = "File to display when server changes directory"; break; case XA_CDMS: /* "--cdmessage" */ xopthlp[j] = "--cdmessage:{on,off}"; xarghlp[j] = "Whether to display CD message file"; break; case XA_HELP: /* "--help" */ xopthlp[j] = "--help"; xarghlp[j] = "Print this help text about extended options"; break; case XA_HEFI: /* "--help" */ xopthlp[j] = "--helpfile:"; xarghlp[j] = "File containing custom info for HELP command"; break; case XA_IKFI: /* "--xferfile" */ xopthlp[j] = "--xferfile: [IKSD only]"; xarghlp[j] = "Name of ftpd-like logfile."; break; case XA_IKLG: /* "--xferlog" */ xopthlp[j] = "--xferlog:{on,off} [IKSD only]"; xarghlp[j] = "Whether to keep an ftpd-like logfile."; break; #ifdef CK_LOGIN case XA_ANFI: /* "--initfile" */ xopthlp[j] = "--initfile: [IKSD only]"; xarghlp[j] = "Initialization file for anonymous users."; break; #ifdef CK_PERM case XA_PERM: /* "--permissions" */ xopthlp[j] = "--permissions: [IKSD only]"; xarghlp[j] = "Permissions for files uploaded by anonymous users."; break; #endif /* CK_PERM */ #ifdef UNIX case XA_ROOT: /* "--root" */ xopthlp[j] = "--root: [IKSD only]"; xarghlp[j] = "File-system root for anonymous users."; break; #else /* UNIX */ #ifdef CKROOT case XA_ROOT: /* "--root" */ xopthlp[j] = "--root: [IKSD only]"; xarghlp[j] = "File-system root for anonymous users."; break; #endif /* CKROOT */ #endif /* UNIX */ #endif /* CK_LOGIN */ #ifdef CKSYSLOG case XA_SYSL: /* "--syslog" */ xopthlp[j] = "--syslog: [IKSD only]"; xarghlp[j] = "Syslog recording level, 0-6."; break; #endif /* CKSYSLOG */ case XA_USFI: /* "--userfile" */ xopthlp[j] = "--userfile: [IKSD only]"; xarghlp[j] = "Forbidden user file."; break; #ifdef CKWTMP case XA_WTFI: /* "--wtmpfile" */ xopthlp[j] = "--wtmpfile: [IKSD only]"; xarghlp[j] = "Name of wtmp logfile."; break; case XA_WTMP: /* "--wtmplog" */ xopthlp[j] = "--wtmplog:{on,off} [IKSD only]"; xarghlp[j] = "Whether to keep a wtmp logfile."; break; #endif /* CKWTMP */ #ifdef CK_LOGIN case XA_TIMO: /* "--timeout" */ xopthlp[j] = "--timeout: [IKSD only]"; xarghlp[j] = "How long to wait for login before closing the connection."; break; #endif /* CK_LOGIN */ case XA_NOIN: xopthlp[j] = "--nointerrupts"; xarghlp[j] = "Disable keyboard interrupts."; break; #ifdef UNIX case XA_UNBUF: xopthlp[j] = "--unbuffered"; xarghlp[j] = "Force unbuffered console i/o."; break; #endif /* UNIX */ #ifdef IKSDB case XA_DBAS: xopthlp[j] = "--database:{on,off}"; xarghlp[j] = "Enable/Disable IKSD database (IKSD only)"; break; case XA_DBFI: xopthlp[j] = "--dbfile:"; xarghlp[j] = "Specify IKSD database file (IKSD only)"; break; #endif /* IKSDB */ #ifdef CK_PERMS case XA_NPRM: xopthlp[j] = "--noperms"; xarghlp[j] = "Disable file-transfer Permissions attribute."; break; #endif /* CK_PERMS */ #ifdef KUI case XA_CHGD: xopthlp[j] = "--changedim"; xarghlp[j] = "Change Dimension on Window Resize"; case XA_SCALE: xopthlp[j] = "--scalefont"; xarghlp[j] = "Scale Font on Window Resize"; case XA_WMAX: xopthlp[j] = "--maximize"; xarghlp[j] = "start K95G window maximized."; break; case XA_WMIN: xopthlp[j] = "--minimize"; xarghlp[j] = "start K95G window minimized."; break; case XA_XPOS: xopthlp[j] = "--xpos:n"; xarghlp[j] = "X-coordinate of window position (number)."; break; case XA_YPOS: xopthlp[j] = "--ypos:n"; xarghlp[j] = "Y-coordinate of window position (number)."; break; case XA_FNAM: xopthlp[j] = "--fontname:s (or --facename:s)"; xarghlp[j] = "Font/typeface name: string with _ replacing blank."; break; case XA_FSIZ: xopthlp[j] = "--fontsize:n"; xarghlp[j] = "Font point size (number)."; break; case XA_NOMN: xopthlp[j] = "--nomenubar"; xarghlp[j] = "No Menu Bar"; break; case XA_NOTB: xopthlp[j] = "--notoolbar"; xarghlp[j] = "No Tool Bar"; break; case XA_NOSB: xopthlp[j] = "--nostatusbar"; xarghlp[j] = "No Status Bar"; break; case XA_NOBAR: xopthlp[j] = "--nobars"; xarghlp[j] = "No Menu, Status, or Tool Bars"; break; #endif /* KUI */ #ifndef NOPUSH case XA_NOPUSH: xopthlp[j] = "--nopush"; xarghlp[j] = "Disable external command execution."; break; #endif /* NOPUSH */ #ifdef OS2 case XA_LOCK: xopthlp[j] = "--lockdown"; xarghlp[j] = "Enable all lockdown options."; break; case XA_NOCLOSE: xopthlp[j] = "--noclose"; xarghlp[j] = "Disable Close Window and Menu Exit."; break; case XA_NOSCROLL: xopthlp[j] = "--noscroll"; xarghlp[j] = "Disable scrollback operations."; break; case XA_NOESCAPE: xopthlp[j] = "--noescape"; xarghlp[j] = "Disable escape from connect mode."; break; case XA_ROWS: xopthlp[j] = "--height:n"; xarghlp[j] = "Screen height (number of rows)."; break; case XA_COLS: xopthlp[j] = "--width:n"; xarghlp[j] = "Screen width (number of columns)."; break; case XA_TITL: xopthlp[j] = "--title:string"; xarghlp[j] = "Window Title."; break; #endif /* OS2 */ case XA_CSET: xopthlp[j] = "--rcharset:name"; xarghlp[j] = "Name of remote terminal character set."; break; case XA_TERM: xopthlp[j] = "--termtype:name"; #ifdef OS2 xarghlp[j] = "Choose terminal emulation."; #else xarghlp[j] = "Choose terminal type."; #endif /* OS2 */ break; case XA_USER: xopthlp[j] = "--user:name"; #ifndef NETCONN xarghlp[j] = "Username (for network login)"; #else xarghlp[j] = "Username."; #endif /* NETCONN */ break; #ifdef HAVE_LOCALE case XA_NOLOCALE: xopthlp[j] = "--nolocale"; xarghlp[j] = "Disable use of locale for messages and strings."; break; #endif /* HAVE_LOCALE */ } } } VOID iniopthlp() { int i; for (i = 0; i < 128; i++) { optact[i] = 0; switch(i) { #ifdef OS2 case '#': /* K95 Startup Flags */ opthlp[i] = "Kermit 95 Startup Flags"; arghlp[i] = "\n"\ " 1 - turn off Win95 special fixes\n"\ " 2 - do not load optional network dlls\n"\ " 4 - do not load optional tapi dlls\n"\ " 8 - do not load optional kerberos dlls\n"\ " 16 - do not load optional zmodem dlls\n"\ " 32 - use stdin for input instead of the console\n"\ " 64 - use stdout for output instead of the console\n"\ " 128 - do not terminate process in response to Session Logoff"; break; #endif /* OS2 */ case '0': /* In the middle */ opthlp[i] = "100% transparent CONNECT mode for \"in-the-middle\" operation"; arghlp[i] = NULL; break; case '8': opthlp[i] = "Connection is 8-bit clean"; arghlp[i] = NULL; break; #ifdef NEWFTP case '9': opthlp[i] = "Make a connection to an FTP server"; arghlp[i] = "IP-address-or-hostname[:optional-TCP-port]"; break; #endif /* NEWFTP */ #ifdef IKSD case 'A': opthlp[i] = "Kermit is to be started as an Internet service"; #ifdef NT arghlp[i] = " socket handle of incoming connection"; #else /* NT */ arghlp[i] = NULL; #endif /* NT */ break; #endif /* IKSD */ case 'B': opthlp[i] = "Kermit is running in Batch or Background (no controlling terminal)"; break; #ifndef NOSPL case 'C': opthlp[i] = "Interactive-mode Commands to be executed"; arghlp[i] = "Commands separated by commas, list in doublequotes"; break; #endif /* NOSPL */ case 'D': opthlp[i] = "Delay before starting to send"; arghlp[i] = "Number of seconds"; break; case 'E': opthlp[i] = "Exit automatically when connection closes"; arghlp[i] = NULL; break; #ifdef TCPSOCKET case 'F': opthlp[i] = "Use an existing TCP connection"; arghlp[i] = "Numeric file descriptor of open TCP connection"; break; #endif /* TCPSOCKET */ case 'G': opthlp[i] = "GET from server, send to standard output"; arghlp[i] = "Remote file specification"; optact[i] = 1; break; case 'H': opthlp[i] = "Suppress program startup Herald and greeting"; arghlp[i] = NULL; break; case 'I': opthlp[i] = "Connection is reliable, streaming is allowed"; arghlp[i] = NULL; break; #ifdef TCPSOCKET case 'J': opthlp[i] = "'Be like Telnet'"; arghlp[i] = "IP hostname/address optionally followed by service"; break; #endif /* TCPSOCKET */ case 'L': opthlp[i] = "Recursive directory descent for files in -s option"; arghlp[i] = NULL; break; case 'M': opthlp[i] = "My user name (for use with Telnet, Rlogin, etc)"; arghlp[i] = "Username string"; break; #ifdef NETBIOS case 'N': opthlp[i] = "NETBIOS adapter number"; arghlp[i] = "Number"; break; #endif /* NETBIOS */ case 'O': /* Be a server for One command only */ opthlp[i] = "Be a server for One command only"; arghlp[i] = NULL; optact[i] = 1; break; case 'P': opthlp[i] = "Don't convert file (Path) names"; arghlp[i] = NULL; break; case 'Q': opthlp[i] = "Quick (FAST) Kermit protocol settings"; arghlp[i] = NULL; break; case 'R': /* Remote-Only */ opthlp[i] = "Remote-only (makes IF REMOTE true)"; arghlp[i] = NULL; break; case 'S': /* "Stay" - enter interactive */ opthlp[i] = "Stay (enter command parser after action options)"; arghlp[i] = NULL; break; case 'T': /* Text file transfer mode */ opthlp[i] = "Transfer files in Text mode"; arghlp[i] = NULL; break; #ifdef ANYX25 case 'U': /* X.25 call user data */ opthlp[i] = "X.25 call User data"; arghlp[i] = "Call-user-data string"; break; #endif /* ANYX25 */ case 'V': /* No automatic filetype switching */ opthlp[i] = "Disable automatic per-file text/binary switching"; arghlp[i] = NULL; break; #ifdef COMMENT #ifdef OS2 case 'W': /* Win32 Window Handle */ opthlp[i] = ""; arghlp[i] = NULL; break; #endif /* OS2 */ #endif /* COMMENT */ #ifdef ANYX25 case 'X': /* SET HOST to X.25 address */ opthlp[i] = "Make an X.25 connection"; arghlp[i] = "X.25 or X.121 address"; break; #endif /* ANYX25 */ case 'Y': /* No initialization file */ opthlp[i] = "Skip initialization file"; arghlp[i] = NULL; break; #ifdef ANYX25 case 'Z': /* SET HOST to X.25 file descriptor */ opthlp[i] = "Make an X.25 connection"; arghlp[i] = "Numeric file descriptor of open X.25 connection"; break; #endif /* ANYX25 */ case 'a': /* as-name */ opthlp[i] = "As-name for file(s) in -s, -r, or -g"; arghlp[i] = "As-name string (alternative filename)"; break; case 'b': /* Set bits-per-second for serial */ opthlp[i] = "Speed for serial device"; arghlp[i] = "Numeric Bits per second"; break; case 'c': /* Connect before */ optact[i] = 1; opthlp[i] = "CONNECT before transferring files"; arghlp[i] = NULL; break; case 'd': /* DEBUG */ opthlp[i] = "Create debug.log file (a second -d adds timestamps)"; arghlp[i] = NULL; break; case 'e': /* Extended packet length */ opthlp[i] = "Maximum length for incoming file-transfer packets"; arghlp[i] = "Length in bytes"; break; case 'f': /* finish */ optact[i] = 1; opthlp[i] = "Send Finish command to a Kermit server"; arghlp[i] = NULL; break; case 'g': /* get */ optact[i] = 1; opthlp[i] = "GET file(s) from a Kermit server"; arghlp[i] = "Remote file specification"; break; case 'h': /* help */ optact[i] = 1; #ifdef OS2ORUNIX opthlp[i] = "Print this message (pipe thru 'more' to prevent scrolling)"; #else "Print this message"; #endif /* OS2ORUNIX */ arghlp[i] = NULL; break; case 'i': /* Treat files as binary */ opthlp[i] ="Transfer files in binary mode"; arghlp[i] = NULL; break; #ifdef TCPSOCKET case 'j': /* SET HOST (TCP/IP socket) */ opthlp[i] = "Make a TCP connection"; arghlp[i] = "TCP host name/address and optional service name or number"; break; #endif /* TCPSOCKET */ case 'k': /* receive to stdout */ optact[i] = 1; opthlp[i] = "RECEIVE file(s) to standard output"; arghlp[i] = NULL; break; case 'l': /* SET LINE */ opthlp[i] = "Make connection on serial communications device"; arghlp[i] = "Serial device name"; break; case 'm': /* Modem type */ opthlp[i] = "Modem type for use with -l device"; arghlp[i] = "Modem name as in SET MODEM TYPE command"; break; case 'n': /* connect after */ optact[i] = 1; opthlp[i] = "CONNECT after transferring files"; arghlp[i] = NULL; break; #ifdef ANYX25 case 'o': /* X.25 closed user group */ opthlp[i] = "X.25 closed user group"; arghlp[i] = "User group string"; break; #endif /* ANYX25 */ case 'p': /* SET PARITY */ opthlp[i] = "Parity"; arghlp[i] = "One of the following: even, odd, mark, none, space"; break; case 'q': /* Quiet */ opthlp[i] = "Quiet (suppress most messages)"; arghlp[i] = NULL; break; case 'r': /* receive */ optact[i] = 1; opthlp[i] = "RECEIVE file(s)"; arghlp[i] = NULL; break; case 's': /* send */ optact[i] = 1; opthlp[i] = "SEND file(s)"; arghlp[i] = "One or more file specifications"; break; case 't': /* Line turnaround handshake */ opthlp[i] = "XON Turnaround character for half-duplex connections"; arghlp[i] = NULL; break; #ifdef ANYX25 case 'u': /* X.25 reverse charge call */ opthlp[i] = "X.25 reverse charge call"; arghlp[i] = NULL; break; #endif /* ANYX25 */ case 'v': /* Vindow size */ opthlp[i] = "Window size"; arghlp[i] = "Number, 1 to 32"; break; case 'w': /* Writeover */ opthlp[i] = "Incoming files Write over existing files"; arghlp[i] = NULL; break; case 'x': /* Server */ optact[i] = 1; opthlp[i] = "Be a Kermit SERVER"; arghlp[i] = NULL; break; case 'y': /* Alternate init-file name */ opthlp[i] = "Alternative initialization file"; arghlp[i] = "File specification"; break; case 'z': /* Not background */ opthlp[i] = "Force foreground behavior"; arghlp[i] = NULL; break; default: opthlp[i] = NULL; arghlp[i] = NULL; } } inixopthlp(); } #ifndef NOICP int #ifdef CK_ANSIC doxarg( char ** s, int pre ) #else doxarg(s,pre) char ** s; int pre; #endif /* CK_ANSIC */ { #ifdef IKSD #ifdef CK_LOGIN extern int ckxsyslog, ckxwtmp, ckxanon; #ifdef UNIX extern int ckxpriv; #endif /* UNIX */ #ifdef CK_PERMS extern int ckxperms; #endif /* CK_PERMS */ extern char * anonfile, * userfile, * anonroot; #endif /* CK_LOGIN */ #ifdef CKWTMP extern char * wtmpfile; #endif /* CKWTMP */ #endif /* IKSD */ extern int srvcdmsg; extern char * cdmsgfile[], * cdmsgstr; char tmpbuf[CKMAXPATH+1]; int i, x, y, z, havearg = 0; char buf[XARGBUFL], c, * p; if (nxargs < 1) return(-1); c = *(*s + 1); /* Hyphen or Plus sign */ p = *s + 2; for (i = 0; *p && i < XARGBUFL; i++) { buf[i] = *p++; if (buf[i] == '=' || buf[i] == ':') { havearg = 1; buf[i] = NUL; break; } else if (buf[i] < ' ') { buf[i] = NUL; break; } } if (i > XARGBUFL - 1) return(-1); buf[i] = NUL; x = lookup(xargtab,buf,nxargs,&z); /* Lookup the option keyword */ if (x < 0) /* On any kind of error */ return(-1); /* fail. */ /* Handle prescan versus post-initialization file */ #ifdef OS2 if (x == XA_HELP) { noinit = 1; startflags |= 2; /* No network DLLs */ startflags |= 4; /* No TAPI DLLs */ startflags |= 8; /* No Security DLLs */ startflags |= 16; /* No Zmodem DLLs */ startflags |= 32; /* Stdin */ startflags |= 64; /* Stdout */ usageparm = 1; /* Showing usage and exiting */ } #endif if (((xargtab[z].flgs & CM_PRE) || (c == '+')) && !pre) return(0); else if (pre && !(xargtab[z].flgs & CM_PRE) && (c != '+')) return(0); /* Ensure that argument is given if and only if required */ p = havearg ? *s + i + 3 : NULL; if ((xargtab[z].flgs & CM_ARG) && !havearg) return(-1); else if ((!(xargtab[z].flgs & CM_ARG)) && havearg) return(-1); switch (x) { /* OK to process this option... */ #ifdef CKSYSLOG case XA_SYSL: /* IKS: Syslog level */ y = 0; if (isdigit(*p)) { while (*p) { if (*p < '0' || *p > '9') return(-1); y = y * 10 + (*p++ - '0'); } } else { y = lookup(oktab,p,noktab,&z); if (y > 0) y = SYSLG_DF; /* Yes = default logging level */ } #ifndef SYSLOGLEVEL /* If specified on cc command line, user can't change it. */ if (!inserver) /* Don't allow voluminous syslogging */ if (y > SYSLG_FA) /* by ordinary users. */ y = SYSLG_FA; #endif /* SYSLOGLEVEL */ if (y < 0) return(-1); #ifdef DEBUG if (y >= SYSLG_DB) if (!deblog) deblog = debopn("debug.log",0); #endif /* DEBUG */ #ifdef SYSLOGLEVEL /* If specified on cc command line, user can't change it. */ y = SYSLOGLEVEL; #endif /* SYSLOGLEVEL */ ckxsyslog = y; /* printf("ckxsyslog=%d\n",ckxsyslog); */ break; #endif /* CKSYSLOG */ #ifdef CK_LOGIN #ifdef CKWTMP case XA_WTMP: /* IKS: wtmp log */ y = lookup(oktab,p,noktab,&z); if (y < 0) return(-1); ckxwtmp = y; /* printf("ckxwtmp=%d\n",ckxwtmp); */ break; case XA_WTFI: /* IKS: wtmp logfile */ if (zfnqfp(p,CKMAXPATH,tmpbuf)) p = tmpbuf; makestr(&wtmpfile,p); /* printf("wtmpfile=%s\n",wtmpfile); */ break; #endif /* CKWTMP */ #ifndef NOIKSD case XA_ANON: /* IKS: Anonymous login allowed */ y = lookup(oktab,p,noktab,&z); if (y < 0) return(-1); ckxanon = y; /* printf("ckxanon=%d\n",ckxanon); */ break; #ifdef UNIX case XA_PRIV: /* IKS: Priv'd login allowed */ y = lookup(oktab,p,noktab,&z); if (y < 0) return(-1); ckxpriv = y; /* printf("ckxpriv=%d\n",ckxpriv); */ break; #endif /* UNIX */ #endif /* NOIKSD */ #ifndef NOIKSD #ifdef CK_PERMS case XA_PERM: /* IKS: Anonymous Upload Permissions */ y = 0; while (*p) { if (*p < '0' || *p > '7') return(-1); y = y * 8 + (*p++ - '0'); } ckxperms = y; /* printf("ckxperms=%04o\n",ckxperms); */ break; #endif /* CK_PERMS */ case XA_ANFI: /* Anonymous init file */ if (!isabsolute(p)) if (zfnqfp(p,CKMAXPATH,tmpbuf)) p = tmpbuf; makestr(&anonfile,p); /* printf("anonfile=%s\n",anonfile); */ break; case XA_USFI: /* IKS: Forbidden user file */ if (!isabsolute(p)) if (zfnqfp(p,CKMAXPATH,tmpbuf)) p = tmpbuf; makestr(&userfile,p); /* printf("userfile=%s\n",userfile); */ break; case XA_ROOT: /* IKS: Anonymous root */ if (!isabsolute(p)) if (zfnqfp(p,CKMAXPATH,tmpbuf)) p = tmpbuf; makestr(&anonroot,p); /* printf("anonroot=%s\n",anonroot); */ break; #endif /* NOIKSD */ #endif /* CK_LOGIN */ case XA_CDFI: /* CD filename */ #ifdef COMMENT /* Do NOT expand this one! */ if (zfnqfp(p,CKMAXPATH,tmpbuf)) p = tmpbuf; #endif /* COMMENT */ makelist(p,cdmsgfile,16); makestr(&cdmsgstr,p); /* printf("cdmsgstr=%s\n",cdmsgstr); */ break; case XA_CDMS: /* CD messages */ y = lookup(oktab,p,noktab,&z); if (y < 0) return(-1); srvcdmsg = y; /* printf("srvcdmsg=%d\n",srvcdmsg); */ break; #ifndef NOXFER case XA_IKLG: /* Transfer log on/off */ y = lookup(oktab,p,noktab,&z); if (y < 0) return(-1); xferlog = y; /* printf("xferlog=%d\n",xferlog); */ break; case XA_IKFI: /* Transfer log file */ if (!isabsolute(p)) if (zfnqfp(p,CKMAXPATH,tmpbuf)) p = tmpbuf; makestr(&xferfile,p); xferlog = 1; /* printf("xferfile=%s\n",xferfile); */ break; case XA_BAFI: /* IKS: banner (greeting) file */ if (!isabsolute(p)) if (zfnqfp(p,CKMAXPATH,tmpbuf)) p = tmpbuf; makestr(&bannerfile,p); /* printf("bannerfile=%s\n",bannerfile); */ break; #endif /* NOXFER */ #ifndef NOHELP case XA_HELP: /* Help */ /* printf("help\n"); */ for (i = 0; i <= XA_MAX; i++) if (xopthlp[i]) printf("%s\n %s\n\n",xopthlp[i],xarghlp[i]); if (stayflg || what == W_COMMAND) break; else doexit(GOOD_EXIT,-1); #endif /* NOHELP */ #ifndef NOHELP case XA_HEFI: /* IKS: custom help file */ if (!isabsolute(p)) if (zfnqfp(p,CKMAXPATH,tmpbuf)) p = tmpbuf; makestr(&helpfile,p); /* printf("helpfile=%s\n",helpfile); */ break; #endif /* NOHELP */ #ifdef CK_LOGIN case XA_TIMO: if (!rdigits(p)) return(-1); logintimo = atoi(p); /* printf("logintimo=%d\n",p); */ break; #endif /* CK_LOGIN */ case XA_NOIN: /* No interrupts */ #ifndef NOICP cmdint = 0; #endif /* NOICP */ xsuspend = 0; break; #ifdef UNIX case XA_UNBUF: /* Unbuffered console i/o*/ break; /* This one is handled in ckcmai.c */ #endif /* UNIX */ #ifdef IKSDB case XA_DBFI: { extern char * dbdir, * dbfile; extern int dbenabled; struct zfnfp * zz; if ((zz = zfnqfp(p,CKMAXPATH,tmpbuf))) { char *s, *s2 = NULL; makestr(&dbdir,zz->fpath); makestr(&dbfile,zz->fpath); for (s = dbdir; *s; s++) { if (ISDIRSEP(*s)) s2 = s+1; } if (s2) *s2 = NUL; debug(F110,"XA_DBFI dbdir",dbdir,0); debug(F110,"XA_DBFI dbfile",dbfile,0); dbenabled = 1; } break; } case XA_DBAS: { extern int dbenabled; y = lookup(oktab,p,noktab,&z); if (y < 0) return(-1); dbenabled = y; break; } #endif /* IKSDB */ case XA_VERS: { extern char * ck_s_ver; printf("%s",ck_s_ver); printf("\n"); if (stayflg || what == W_COMMAND) break; else doexit(GOOD_EXIT,-1); } #ifndef NOXFER #ifdef CK_PERMS case XA_NPRM: { extern int atlpri, atlpro, atgpri, atgpro; atlpri = 0; atlpro = 0; atgpri = 0; atgpro = 0; break; } #endif /* CK_PERMS */ #endif /* NOXFER */ #ifdef KUI case XA_SCALE: kui_init.resizeMode = 1; break; case XA_CHGD: kui_init.resizeMode = 2; break; case XA_WMAX: kui_init.nCmdShow = SW_MAXIMIZE; break; case XA_WMIN: kui_init.nCmdShow = SW_MINIMIZE; break; case XA_XPOS: if (!rdigits(p)) return(-1); kui_init.pos_init++; kui_init.pos_x = atoi(p); break; case XA_YPOS: if (!rdigits(p)) return(-1); kui_init.pos_init++; kui_init.pos_y = atoi(p); break; case XA_FNAM: { extern struct _kui_init kui_init; extern struct keytab * term_font; extern struct keytab * _term_font; extern int tt_font, ntermfont; int x, z; if (ntermfont == 0) BuildFontTable(&term_font, &_term_font, &ntermfont); if (!(term_font && _term_font && ntermfont > 0)) { printf("?Unable to construct Font Facename Table\n"); return(0); } x = lookup(term_font,p,ntermfont,&z); if (x < 0) { x = lookup(_term_font,p,ntermfont,&z); if (x < 0) { printf("?Invalid Font Facename: %s\n",p); return(0); } } tt_font = x; kui_init.face_init++; makestr(&kui_init.facename,term_font[z].kwd); break; } case XA_FSIZ: { extern struct _kui_init kui_init; extern int tt_font_size; char * q; int halfpoint = 0; kui_init.font_init++; for ( q=p ; *q ; q++ ) { if ( *q == '.') { *q++ = '\0'; if (!rdigits(q)) return(-1); if (!*q || atoi(q) == 0) break; /* no halfpoint */ halfpoint = 1; if (atoi(q) != 5) printf("? Font sizes are treated in half-point increments\n"); break; } } if (!rdigits(p)) return(-1); tt_font_size = kui_init.font_size = 2 * atoi(p) + halfpoint; break; } case XA_NOMN: kui_init.nomenubar = 1; break; case XA_NOTB: kui_init.notoolbar = 1; break; case XA_NOSB: kui_init.nostatusbar = 1; break; case XA_NOBAR: kui_init.nomenubar = 1; kui_init.notoolbar = 1; kui_init.nostatusbar = 1; break; #endif /* KUI */ #ifndef NOPUSH case XA_NOPUSH: nopush = 1; break; #endif /* NOPUSH */ #ifdef OS2 case XA_LOCK: tt_scroll = 0; tt_escape = 0; #ifndef NOPUSH nopush = 1; #endif #ifdef KUI kui_init.nomenubar = 1; kui_init.notoolbar = 1; kui_init.nostatusbar = 1; #endif break; #ifdef KUI case XA_NOCLOSE: kui_init.noclose = 1; break; #endif /* KUI */ case XA_NOSCROLL: tt_scroll = 0; break; case XA_NOESCAPE: tt_escape = 0; break; #endif /* OS2 */ #ifndef NOLOCAL case XA_TERM: { /* Terminal type */ extern struct keytab ttyptab[]; extern int nttyp; #ifdef TNCODE extern char * tn_term; #endif /* TNCODE */ #ifdef OS2 int x, z; extern int tt_type, tt_type_mode; x = lookup(ttyptab,p,nttyp,&z); if (x < 0) return(-1); tt_type_mode = tt_type = x; #endif /* OS2 */ #ifdef TNCODE makestr(&tn_term,p); #endif /* TNCODE */ break; } case XA_CSET: { /* Remote Character Set */ #ifndef NOCSETS #ifdef CKOUNI extern struct keytab txrtab[]; extern int ntxrtab; x = lookup(txrtab,p,ntxrtab,&z); #else /* CKOUNI */ extern struct keytab ttcstab[]; extern int ntermc; x = lookup(ttcstab,p,ntermc,&z); #endif /* CKOUNI */ if (x < 0) return(-1); setremcharset(z,4 /* TT_GR_ALL (in ckuus7.c) */); #else /* NOCSETS */ return(-1); #endif /* NOCSETS */ break; } case XA_ROWS: { /* Screen rows (height) */ #ifdef OS2 extern int row_init; #else /* OS2 */ extern int tt_rows; #endif /* OS2 */ if (!rdigits(p)) return(-1); #ifdef OS2 if (!os2_settermheight(atoi(p))) return(-1); row_init++; #else /* Not OS/2 */ tt_rows = atoi(p); #endif /* OS2 */ break; } case XA_COLS: { /* Screen columns (width) */ #ifdef OS2 extern int col_init; #else /* OS2 */ extern int tt_cols; #endif /* OS2 */ if (!rdigits(p)) return(-1); #ifdef OS2 if (!os2_settermwidth(atoi(p))) return(-1); col_init++; #else /* Not OS/2 */ tt_cols = atoi(p); #endif /* OS2 */ break; } #ifdef OS2 case XA_TITL: { extern char usertitle[]; ckstrncpy(usertitle,p,64); os2settitle("",1); break; } #endif /* OS2 */ #ifdef COMMENT /* TO BE FILLED IN ... */ case XA_TEL: /* Make a Telnet connection */ case XA_FTP: /* Make an FTP connection */ case XA_SSH: /* Make an SSH connection */ #endif /* COMMENT */ #ifndef NOSPL case XA_USER: /* Username for login */ #ifdef IKSD if (!inserver) #endif /* IKSD */ { ckstrncpy(uidbuf,*xargv,UIDBUFLEN); haveftpuid = 1; } break; #endif /* NOSPL */ #endif /* NOLOCAL */ case XA_NOLOCALE: { /* Don't do locale */ extern int nolocale; nolocale = 1; break; } default: return(-1); } return(0); } #endif /* NOICP */ #ifdef IKSD #ifdef IKSDCONF #define IKS_ANON 0 #define IKS_BAFI 1 #define IKS_CDFI 2 #define IKS_CDMS 3 #define IKS_HEFI 4 #define IKS_ANFI 5 #define IKS_USFI 6 #define IKS_IKLG 7 #define IKS_IKFI 8 #define IKS_DBAS 9 #define IKS_DBFI 10 #define IKS_PERM 11 #define IKS_PRIV 12 #define IKS_ROOT 13 #define IKS_TIMO 14 #define IKS_WTFI 15 #define IKS_WTMP 16 #define IKS_SRVR 17 #define IKS_NOIN 18 #define IKS_INIT 19 #define IKS_ANLG 20 #define IKS_ACCT 21 #define IKS_NTDOM 22 #define IKS_SYSL 23 #ifdef CK_LOGIN static struct keytab iksantab[] = { #ifdef OS2 { "account", IKS_ACCT, 0 }, #endif /* OS2 */ { "initfile", IKS_ANFI, 0 }, { "login", IKS_ANLG, 0 }, #ifdef UNIX { "root", IKS_ROOT, 0 }, #else #ifdef CKROOT { "root", IKS_ROOT, 0 }, #endif /* CKROOT */ #endif /* UNIX */ { "", 0, 0 } }; static int niksantab = sizeof(iksantab) / sizeof(struct keytab) - 1; #endif /* CK_LOGIN */ static struct keytab ikstab[] = { #ifdef CK_LOGIN { "anonymous", IKS_ANON, 0 }, #endif /* CK_LOGIN */ { "bannerfile", IKS_BAFI, 0 }, { "cdfile", IKS_CDFI, 0 }, { "cdmessage", IKS_CDMS, 0 }, { "cdmsg", IKS_CDMS, CM_INV }, #ifdef IKSDB { "database", IKS_DBAS, 0 }, { "dbfile", IKS_DBFI, 0 }, #endif /* IKSDB */ #ifdef CK_LOGIN #ifdef NT { "default-domain", IKS_NTDOM, 0 }, #endif /* NT */ #endif /* CK_LOGIN */ #ifndef NOHELP { "helpfile", IKS_HEFI, 0 }, #endif /* NOHELP */ { "initfile", IKS_INIT, 0 }, { "no-initfile", IKS_NOIN, 0 }, #ifdef CK_LOGIN #ifdef CK_PERM { "permissions", IKS_PERM, 0 }, { "perms", IKS_PERM, CM_INV }, #endif /* CK_PERM */ #ifdef UNIX { "privid", IKS_PRIV, 0 }, #endif /* UNIX */ { "server-only", IKS_SRVR, 0 }, #ifdef CKSYSLOG { "syslog", IKS_SYSL, 0 }, #endif /* CKSYSLOG */ { "timeout", IKS_TIMO, 0 }, { "userfile", IKS_USFI, 0 }, #ifdef CKWTMP { "wtmpfile", IKS_WTFI, 0 }, { "wtmplog", IKS_WTMP, 0 }, #endif /* CKWTMP */ #endif /* CK_LOGIN */ { "xferfile", IKS_IKFI, 0 }, { "xferlog", IKS_IKLG, 0 } }; static int nikstab = sizeof(ikstab) / sizeof(struct keytab); #endif /* IKSDCONF */ #ifndef NOICP int setiks() { /* SET IKS */ #ifdef IKSDCONF #ifdef CK_LOGIN extern int ckxsyslog, ckxwtmp, ckxanon; #ifdef UNIX extern int ckxpriv; #endif /* UNIX */ #ifdef CK_PERMS extern int ckxperms; #endif /* CK_PERMS */ extern char * anonfile, * userfile, * anonroot; #ifdef OS2 extern char * anonacct; #endif /* OS2 */ #ifdef NT extern char * iks_domain; #endif /* NT */ #endif /* CK_LOGIN */ #ifdef CKWTMP extern char * wtmpfile; #endif /* CKWTMP */ extern int srvcdmsg, success, iksdcf, rcflag, noinit, arg_x; extern char * cdmsgfile[], * cdmsgstr, *kermrc; extern xx_strp xxstring; int x, y, z; char *s; char tmpbuf[CKMAXPATH+1]; if ((y = cmkey(ikstab,nikstab,"","",xxstring)) < 0) return(y); #ifdef CK_LOGIN if (y == IKS_ANON) { if ((y = cmkey(iksantab,niksantab,"","",xxstring)) < 0) return(y); } #endif /* CK_LOGIN */ switch (y) { #ifdef CKSYSLOG case IKS_SYSL: /* IKS: Syslog level */ if ((z = cmkey(oktab,noktab,"","",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); #ifndef SYSLOGLEVEL /* If specified on cc command line, user can't change it. */ if (!inserver) /* Don't allow voluminous syslogging */ if (y > SYSLG_FA) /* by ordinary users. */ y = SYSLG_FA; #endif /* SYSLOGLEVEL */ if (y < 0) return(-1); #ifdef DEBUG if (y >= SYSLG_DB) if (!deblog) deblog = debopn("debug.log",0); #endif /* DEBUG */ #ifdef SYSLOGLEVEL /* If specified on cc command line, user can't change it. */ y = SYSLOGLEVEL; #endif /* SYSLOGLEVEL */ ckxsyslog = y; /* printf("ckxsyslog=%d\n",ckxsyslog); */ break; #endif /* CKSYSLOG */ #ifdef CK_LOGIN #ifdef NT case IKS_NTDOM: if ((z = cmtxt( "DOMAIN to be used for user authentication when none is specified", "", &s,xxstring)) < 0) return(z); if (iksdcf) return(success = 0); if (!*s) s= NULL; makestr(&iks_domain,s); break; #endif /* NT */ #ifdef OS2 case IKS_ACCT: if ((z = cmtxt("Name of local account to use for anonymous logins", "GUEST", &s,xxstring)) < 0) return(z); if (iksdcf) return(success = 0); if (*s) { makestr(&anonacct,s); } else if ( anonacct ) { free(anonacct); anonacct = NULL; } break; #endif /* OS2 */ case IKS_ANLG: if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); ckxanon = z; #ifdef OS2 if (ckxanon && !anonacct) makestr(&anonacct,"GUEST"); #endif /* OS2 */ break; #endif /* CK_LOGIN */ case IKS_BAFI: if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0) return(z); if (x) { printf("?Wildcards not allowed\n"); return(-9); } debug(F110,"bannerfile before zfnqfp()",s,0); if (zfnqfp(s,CKMAXPATH,tmpbuf)) { debug(F110,"bannerfile after zfnqfp()",tmpbuf,0); s = tmpbuf; } if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); if (*s) makestr(&bannerfile,s); break; case IKS_CDFI: if ((z = cmtxt("list of cd message file names","READ.ME", &s,xxstring)) < 0) return(z); if (iksdcf) return(success = 0); if (*s) { makelist(s,cdmsgfile,16); makestr(&cdmsgstr,s); } break; case IKS_CDMS: if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); srvcdmsg = z; break; case IKS_HEFI: if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0) return(z); if (x) { printf("?Wildcards not allowed\n"); return(-9); } if (zfnqfp(s,CKMAXPATH,tmpbuf)) s = tmpbuf; if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); if (*s) makestr(&helpfile,s); break; case IKS_ANFI: if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0) return(z); if (x) { printf("?Wildcards not allowed\n"); return(-9); } if (zfnqfp(s,CKMAXPATH,tmpbuf)) s = tmpbuf; if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); #ifdef CK_LOGIN if (*s) makestr(&anonfile,s); #endif /* CK_LOGIN */ break; case IKS_USFI: if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0) return(z); if (x) { printf("?Wildcards not allowed\n"); return(-9); } if (zfnqfp(s,CKMAXPATH,tmpbuf)) s = tmpbuf; if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); #ifdef CK_LOGIN if (*s) makestr(&userfile,s); #endif /* CK_LOGIN */ break; case IKS_IKFI: if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0) return(z); if (x) { printf("?Wildcards not allowed\n"); return(-9); } if (zfnqfp(s,CKMAXPATH,tmpbuf)) s = tmpbuf; if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); if (*s) { makestr(&xferfile,s); xferlog = 1; } break; case IKS_IKLG: if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); xferlog = z; break; #ifdef CK_LOGIN #ifdef CK_PERM case IKS_PERM: if ((z = cmtxt("Octal file permssion code","000", &s,xxstring)) < 0) return(z); if (z < 0) return(z); if (iksdcf) return(success = 0); y = 0; while (*s) { if (*s < '0' || *s > '7') return(-9); y = y * 8 + (*s++ - '0'); } ckxperms = y; break; #endif /* CK_PERM */ #ifdef UNIX case IKS_PRIV: /* IKS: Priv'd login allowed */ if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); ckxpriv = z; break; #endif /* UNIX */ case IKS_ROOT: /* IKS: Anonymous root */ if ((z = cmdir("Name of disk and/or directory","",&s, xxstring)) < 0 ) { if (z != -3) return(z); } if (*s) { if (zfnqfp(s,CKMAXPATH,tmpbuf)) s = tmpbuf; } else s = ""; if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); if (*s) makestr(&anonroot,s); /* printf("anonroot=%s\n",anonroot); */ break; case IKS_TIMO: z = cmnum("login timeout, seconds","0",10,&x,xxstring); if (z < 0) return(z); if (x < 0 || x > 7200) { printf("?Value must be between 0 and 7200\r\n"); return(-9); } if ((z = cmcfm()) < 0) return(z); if (iksdcf) return(success = 0); logintimo = x; break; #ifdef CKWTMP case IKS_WTMP: /* IKS: wtmp log */ if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); ckxwtmp = z; break; case IKS_WTFI: /* IKS: wtmp logfile */ if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0) return(z); if (x) { printf("?Wildcards not allowed\n"); return(-9); } if (zfnqfp(s,CKMAXPATH,tmpbuf)) s = tmpbuf; if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); if (*s) makestr(&wtmpfile,s); break; #endif /* CKWTMP */ #endif /* CK_LOGIN */ #ifdef IKSDB case IKS_DBFI: { extern char * dbdir, * dbfile; extern int dbenabled; struct zfnfp * zz; if ((z = cmifi("Filename","",&s,&x,xxstring)) < 0) return(z); if (x) { printf("?Wildcards not allowed\n"); return(-9); } zz = zfnqfp(s,CKMAXPATH,tmpbuf); if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); if (zz) { makestr(&dbdir,zz->fpath); makestr(&dbfile,(char *)tmpbuf); dbenabled = 1; } else return(success = 0); break; } case IKS_DBAS: { extern int dbenabled; if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); dbenabled = z; break; } #endif /* IKSDB */ case IKS_INIT: if ((z = cmtxt("Alternate init file specification","", &s,xxstring)) < 0) return(z); if (z < 0) return(z); if (iksdcf) return(success = 0); ckstrncpy(kermrc,s,KERMRCL); rcflag = 1; /* Flag that this has been done */ break; case IKS_NOIN: if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); noinit = z; break; case IKS_SRVR: if ((z = cmkey(oktab,noktab,"","no",xxstring)) < 0) return(z); if ((x = cmcfm()) < 0) return(x); if (iksdcf) return(success = 0); arg_x = z; break; default: return(-9); } return(success = (inserver ? 1 : 0)); #else /* IKSDCONF */ if ((x = cmcfm()) < 0) return(x); return(success = 0); #endif /* IKSDCONF */ } #endif /* NOICP */ #endif /* IKSD */ /* D O A R G -- Do a command-line argument. */ int #ifdef CK_ANSIC doarg(char x) #else doarg(x) char x; #endif /* CK_ANSIC */ /* doarg */ { int i, n, y, z, xx; long zz; char *xp; #ifdef NETCONN extern char *line, *tmpbuf; /* Character buffers for anything */ #endif /* NETCONN */ #ifdef IKSD /* Internet Kermit Server set some way besides -A... */ if (inserver) dofast(); #endif /* IKSD */ xp = *xargv+1; /* Pointer for bundled args */ debug(F111,"doarg entry",xp,xargc); while (x) { debug(F000,"doarg arg","",x); switch (x) { /* Big switch on arg */ #ifndef NOICP case '-': /* Extended commands... */ if (doxarg(xargv,0) < 0) { XFATAL("Extended option error"); } /* Full thru... */ case '+': /* Extended command for prescan() */ return(0); #else /* NOICP */ case '-': case '+': XFATAL("Extended options not configured"); #endif /* NOICP */ #ifndef NOSPL case 'C': { /* Commands for parser */ char * s; xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("No commands given for -C"); } s = *xargv; /* Get the argument (must be quoted) */ if (!*s) /* If empty quotes */ s = NULL; /* ignore this option */ if (s) { makestr(&clcmds,s); /* Make pokeable copy */ s = clcmds; /* Change tabs to spaces */ while (*s) { if (*s == '\t') *s = ' '; s++; } } break; } #endif /* NOSPL */ #ifndef NOXFER case 'D': /* Delay */ if (*(xp+1)) { XFATAL("invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing delay value"); } z = atoi(*xargv); /* Convert to number */ if (z > -1) /* If in range */ ckdelay = z; /* set it */ else { XFATAL("bad delay value"); } break; #endif /* NOXFER */ case 'E': /* Exit on close */ #ifdef NETCONN tn_exit = 1; #endif /* NETCONN */ exitonclose = 1; break; #ifndef NOICP case 'S': /* "Stay" - enter interactive */ stayflg = 1; /* command parser after executing */ xfinish = 0; /* command-line actions. */ break; #endif /* NOICP */ case 'T': /* File transfer mode = text */ binary = XYFT_T; xfermode = XMODE_M; /* Transfer mode manual */ filepeek = 0; #ifdef PATTERNS patterns = 0; #endif /* PATTERNS */ break; case '7': break; #ifdef IKSD case 'A': { /* Internet server */ /* Already done in prescan() */ /* but implies 'x' && 'Q' */ #ifdef OS2 char * p; if (*(xp+1)) { XFATAL("invalid argument bundling"); } #ifdef NT /* Support for Pragma Systems Telnet/Terminal Servers */ p = getenv("PRAGMASYS_INETD_SOCK"); if (!(p && atoi(p) != 0)) { xargv++, xargc--; if (xargc < 1 || **xargv == '-') { XFATAL("missing socket handle"); } } #else /* NT */ xargv++, xargc--; if (xargc < 1 || **xargv == '-') { XFATAL("missing socket handle"); } #endif /* NT */ #endif /* OS2 */ #ifdef NOICP /* If no Interactive Command Parser */ action = 'x'; /* -A implies -x. */ #endif /* NOICP */ #ifndef NOXFER dofast(); #endif /* NOXFER */ break; } #endif /* IKSD */ #ifndef NOXFER case 'Q': /* Quick (i.e. FAST) */ dofast(); break; #endif /* NOXFER */ case 'R': /* Remote-Only */ break; /* This is handled in prescan(). */ #ifndef NOSERVER case 'x': /* server */ case 'O': /* (for One command only) */ if (action) { XFATAL("conflicting actions"); } if (x == 'O') justone = 1; xfinish = 1; action = 'x'; break; #endif /* NOSERVER */ #ifndef NOXFER case 'f': /* finish */ if (action) { XFATAL("conflicting actions"); } action = setgen('F',"","",""); break; #endif /* NOXFER */ case 'r': { /* receive */ if (action) { XFATAL("conflicting actions"); } action = 'v'; break; } #ifndef NOXFER case 'k': /* receive to stdout */ if (action) { XFATAL("conflicting actions"); } stdouf = 1; action = 'v'; break; case 's': { /* send */ int fil2snd, rc; if (!recursive) nolinks = 0; /* Follow links by default */ if (action) { XFATAL("conflicting actions"); } if (*(xp+1)) { XFATAL("invalid argument bundling after -s"); } nfils = 0; /* Initialize file counter */ fil2snd = 0; /* Assume nothing to send */ z = 0; /* Flag for stdin */ cmlist = xargv + 1; /* Remember this pointer */ while (++xargv, --xargc > 0) { /* Traverse the list */ #ifdef PIPESEND if (usepipes && protocol == PROTO_K && **xargv == '!') { cmarg = *xargv; cmarg++; debug(F110,"doarg pipesend",cmarg,0); nfils = -1; z = 1; pipesend = 1; } else #endif /* PIPESEND */ if (**xargv == '-') { /* Check for sending stdin */ if (strcmp(*xargv,"-") != 0) /* next option? */ break; z++; /* "-" alone means send from stdin. */ #ifdef RECURSIVE } else if (!strcmp(*xargv,".")) { fil2snd = 1; nfils++; recursive = 1; nolinks = 2; #endif /* RECURSIVE */ } else /* Check if file exists */ if ((rc = zchki(*xargv)) > -1 || (rc == -2)) { if (rc != -2) fil2snd = 1; nfils++; /* Bump file counter */ } else if (iswild(*xargv) && nzxpand(*xargv,0) > 0) { /* or contains wildcard characters matching real files */ fil2snd = 1; nfils++; } else { if (!failmsg) failmsg = (char *)malloc(2000); if (failmsg) { ckmakmsg(failmsg,2000, #ifdef VMS "%CKERMIT-E-SEARCHFAIL " #else "kermit -s " #endif /* VMS */ , *xargv, ": ", ck_errstr() ); } } } xargc++, xargv--; /* Adjust argv/argc */ if (!fil2snd && z == 0) { if (!failmsg) { #ifdef VMS failmsg = "%CKERMIT-E-SEARCHFAIL, no files for -s"; #else failmsg = "No files for -s"; #endif /* VMS */ } XFATAL(failmsg); } if (z > 1) { XFATAL("kermit -s: too many -'s"); } if (z == 1 && fil2snd) { XFATAL("invalid mixture of filenames and '-' in -s"); } debug(F101,"doarg s nfils","",nfils); debug(F101,"doarg s z","",z); if (nfils == 0) { /* no file parameters were specified */ if (is_a_tty(0)) { /* (used to be is_a_tty(1) - why?) */ XFATAL("sending from terminal not allowed"); } else stdinf = 1; } debug(F101,"doarg s stdinf","",stdinf); debug(F111,"doarg",*xargv,nfils); action = 's'; break; } case 'g': /* get */ case 'G': /* get to stdout */ if (action) { XFATAL("conflicting actions"); } if (*(xp+1)) { XFATAL("invalid argument bundling after -g"); } xargv++, xargc--; if ((xargc == 0) || (**xargv == '-')) { XFATAL("missing filename for -g"); } if (x == 'G') stdouf = 1; cmarg = *xargv; action = 'r'; break; #endif /* NOXFER */ #ifndef NOLOCAL case 'c': /* connect before */ cflg = 1; break; case 'n': /* connect after */ cnflg = 1; break; #endif /* NOLOCAL */ case 'h': /* help */ usage(); #ifndef NOICP if (stayflg || what == W_COMMAND) break; else #endif /* NOICP */ doexit(GOOD_EXIT,-1); #ifndef NOXFER case 'a': /* "as" */ if (*(xp+1)) { XFATAL("invalid argument bundling after -a"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing name in -a"); } cmarg2 = *xargv; debug(F111,"doarg a",cmarg2,xargc); break; #endif /* NOXFER */ #ifndef NOICP case 'Y': /* No initialization file */ noinit = 1; break; case 'y': /* Alternate init-file name */ noinit = 0; if (*(xp+1)) { XFATAL("invalid argument bundling after -y"); } xargv++, xargc--; if (xargc < 1) { XFATAL("missing filename in -y"); } /* strcpy(kermrc,*xargv); ... already done in prescan()... */ break; #endif /* NOICP */ #ifndef NOXFER case 'I': /* Assume we have an "Internet" */ reliable = 1; /* or other reliable connection */ xreliable = 1; setreliable = 1; /* I'm not so sure about this -- what about VMS? (next comment) */ clearrq = 1; /* therefore the channel is clear */ #ifndef VMS /* Since this can trigger full control-character unprefixing, we need to ensure that our terminal or pty driver is not doing Xon/Xoff; otherwise we can become deadlocked the first time we receive a file that contains Xoff. */ flow = FLO_NONE; #endif /* VMS */ break; #endif /* NOXFER */ #ifndef NOLOCAL case 'l': /* SET LINE */ #ifdef NETCONN #ifdef ANYX25 case 'X': /* SET HOST to X.25 address */ #ifdef SUNX25 case 'Z': /* SET HOST to X.25 file descriptor */ #endif /* SUNX25 */ #endif /* ANYX25 */ #ifdef TCPSOCKET case 'J': case 'j': /* SET HOST (TCP/IP socket) */ #endif /* TCPSOCKET */ #endif /* NETCONN */ #ifndef NOXFER if (x == 'j' || x == 'J' || x == 'X' || x == 'Z') { reliable = 1; /* or other reliable connection */ xreliable = 1; setreliable = 1; } #endif /* NOXFER */ network = 0; if (*(xp+1)) { XFATAL("invalid argument bundling after -l or -j"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("communication line device name missing"); } #ifdef NETCONN if (x == 'J') { cflg = 1; /* Connect */ stayflg = 1; /* Stay */ tn_exit = 1; /* Telnet-like exit condition */ exitonclose = 1; } #endif /* NETCONN */ ckstrncpy(ttname,*xargv,TTNAMLEN+1); local = (strcmp(ttname,CTTNAM) != 0); if (local && strcmp(ttname,"0") == 0) local = 0; /* NOTE: We really do not need to call ttopen here, since it should be called again later, automatically, when we first try to condition the device via ttpkt or ttvt. Calling ttopen here has the bad side effect of making the order of the -b and -l options significant when the order of command-line options should not matter. However, the network cases immediately below complicate matters a bit, so we'll settle this in a future edit. */ if (x == 'l') { if (ttopen(ttname,&local,mdmtyp,0) < 0) { XFATAL("can't open device"); } #ifdef CKLOGDIAL dologline(); #endif /* CKLOGDIAL */ debug(F101,"doarg speed","",speed); cxtype = (mdmtyp > 0) ? CXT_MODEM : CXT_DIRECT; speed = ttgspd(); /* Get the speed. */ setflow(); /* Do something about flow control. */ #ifndef NOSPL if (local) { if (nmac) { /* Any macros defined? */ int k; /* Yes */ k = mlook(mactab,"on_open",nmac); /* Look this up */ if (k >= 0) { /* If found, */ if (dodo(k,ttname,0) > -1) /* set it up, */ parser(1); /* and execute it */ } } } #endif /* NOSPL */ #ifdef NETCONN } else { if (x == 'j' || x == 'J') { /* IP network host name */ char * s = line; char * service = tmpbuf; if (xargc > 0) { /* Check if it's followed by */ /* A service name or number */ if (*(xargv+1) && *(*(xargv+1)) != '-') { xargv++, xargc--; ckstrncat(ttname,":",TTNAMLEN+1); ckstrncat(ttname,*xargv,TTNAMLEN+1); } } nettype = NET_TCPB; mdmtyp = -nettype; /* Perhaps already set in init file */ telnetfd = 1; /* Or maybe an open file descriptor */ ckstrncpy(line, ttname, LINBUFSIZ); /* Working copy */ for (s = line; *s != NUL && *s != ':'; s++); if (*s) { *s++ = NUL; ckstrncpy(service, s, TMPBUFSIZ); } else *service = NUL; s = line; #ifndef NODIAL #ifndef NOICP /* Look up in network directory */ x = 0; if (*s == '=') { /* If number starts with = sign */ s++; /* strip it */ while (*s == SP) /* and also any leading spaces */ s++; ckstrncpy(line,s,LINBUFSIZ); /* Do this again. */ nhcount = 0; } else if (!isdigit(line[0])) { /* nnetdir will be greater than 0 if the init file has been processed and it contained a SET NETWORK DIRECTORY command. */ xx = 0; /* Initialize this */ if (nnetdir > 0) /* If there is a directory... */ xx = lunet(line); /* Look up the name */ else /* If no directory */ nhcount = 0; /* we didn't find anything there */ if (xx < 0) { /* Lookup error: */ ckmakmsg(tmpbuf, TMPBUFSIZ, "?Fatal network directory lookup error - ", line, "\n", NULL ); XFATAL(tmpbuf); } } #endif /* NOICP */ #endif /* NODIAL */ /* Add service to line specification for ttopen() */ if (*service) { /* There is a service specified */ ckstrncat(line, ":",LINBUFSIZ); ckstrncat(line, service,LINBUFSIZ); ttnproto = NP_DEFAULT; } else { ckstrncat(line, ":telnet",LINBUFSIZ); ttnproto = NP_TELNET; } #ifndef NOICP #ifndef NODIAL if ((nhcount > 1) && !quiet && !backgrd) { printf("%d entr%s found for \"%s\"%s\n", nhcount, (nhcount == 1) ? "y" : "ies", s, (nhcount > 0) ? ":" : "." ); for (i = 0; i < nhcount; i++) printf("%3d. %s %-12s => %s\n", i+1, n_name, nh_p2[i], nh_p[i] ); } if (nhcount == 0) n = 1; else n = nhcount; #else n = 1; nhcount = 0; #endif /* NODIAL */ for (i = 0; i < n; i++) { #ifndef NODIAL if (nhcount >= 1) { /* Copy the current entry to line */ ckstrncpy(line,nh_p[i],LINBUFSIZ); /* Check to see if the network entry contains a service */ for (s = line ; (*s != NUL) && (*s != ':'); s++) ; /* If directory does not have a service ... */ /* and the user specified one */ if (!*s && *service) { ckstrncat(line, ":",LINBUFSIZ); ckstrncat(line, service,LINBUFSIZ); } if (lookup(netcmd,nh_p2[i],nnets,&z) > -1) { mdmtyp = 0 - netcmd[z].kwval; } else { printf( "Error - network type \"%s\" not supported\n", nh_p2[i] ); continue; } } #endif /* NODIAL */ } #endif /* NOICP */ ckstrncpy(ttname, line,TTNAMLEN+1); cxtype = CXT_TCPIP; /* Set connection type */ setflow(); /* Set appropriate flow control. */ #ifdef SUNX25 } else if (x == 'X') { /* X.25 address */ nettype = NET_SX25; mdmtyp = -nettype; } else if (x == 'Z') { /* Open X.25 file descriptor */ nettype = NET_SX25; mdmtyp = -nettype; x25fd = 1; #endif /* SUNX25 */ #ifdef STRATUSX25 } else if (x == 'X') { /* X.25 address */ nettype = NET_VX25; mdmtyp = -nettype; #endif /* STRATUSX25 */ #ifdef IBMX25 } else if (x == 'X') { /* X.25 address */ nettype = NET_IX25; mdmtyp = -nettype; #endif /* IBMX25 */ #ifdef HPX25 } else if (x == 'X') { /* X.25 address */ nettype = NET_HX25; mdmtyp = -nettype; #endif /* HPX25 */ } if (ttopen(ttname,&local,mdmtyp,0) < 0) { XFATAL("can't open host connection"); } network = 1; #ifdef CKLOGDIAL dolognet(); #endif /* CKLOGDIAL */ cxtype = CXT_X25; /* Set connection type */ setflow(); /* Set appropriate flow control. */ #ifndef NOSPL if (local) { if (nmac) { /* Any macros defined? */ int k; /* Yes */ k = mlook(mactab,"on_open",nmac); /* Look this up */ if (k >= 0) { /* If found, */ if (dodo(k,ttname,0) > -1) /* set it up, */ parser(1); /* and execute it */ } } } #endif /* NOSPL */ #endif /* NETCONN */ } /* add more here -- decnet, etc... */ haveline = 1; break; #ifdef ANYX25 case 'U': /* X.25 call user data */ if (*(xp+1)) { XFATAL("invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing call user data string"); } ckstrncpy(udata,*xargv,MAXCUDATA); if ((int)strlen(udata) <= MAXCUDATA) { cudata = 1; } else { XFATAL("Invalid call user data"); } break; case 'o': /* X.25 closed user group */ if (*(xp+1)) { XFATAL("invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing closed user group index"); } z = atoi(*xargv); /* Convert to number */ if (z >= 0 && z <= 99) { closgr = z; } else { XFATAL("Invalid closed user group index"); } break; case 'u': /* X.25 reverse charge call */ revcall = 1; break; #endif /* ANYX25 */ #endif /* NOLOCAL */ case 'b': /* Bits-per-second for serial device */ if (*(xp+1)) { XFATAL("invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing bps"); } zz = atol(*xargv); /* Convert to long int */ i = zz / 10L; #ifndef NOLOCAL if (ttsspd(i) > -1) /* Check and set it */ #endif /* NOLOCAL */ speed = ttgspd(); /* and read it back. */ #ifndef NOLOCAL else { XFATAL("unsupported transmission rate"); } #endif /* NOLOCAL */ break; #ifndef NODIAL #ifndef NOICP case 'm': /* Modem type */ if (*(xp+1)) { XFATAL("invalid argument bundling after -m"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("modem type missing"); } y = lookup(mdmtab,*xargv,nmdm,&z); if (y < 0) { XFATAL("unknown modem type"); } usermdm = 0; usermdm = (y == dialudt) ? x : 0; initmdm(y); break; #endif /* NOICP */ #endif /* NODIAL */ #ifndef NOXFER case 'e': /* Extended packet length */ if (*(xp+1)) { XFATAL("invalid argument bundling after -e"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing length"); } z = atoi(*xargv); /* Convert to number */ if (z > 10 && z <= maxrps) { rpsiz = urpsiz = z; if (z > 94) rpsiz = 94; /* Fallback if other Kermit can't */ } else { XFATAL("Unsupported packet length"); } break; case 'v': /* Vindow size */ if (*(xp+1)) { XFATAL("invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing or bad window size"); } z = atoi(*xargv); /* Convert to number */ if (z < 32) { /* If in range */ wslotr = z; /* set it */ if (z > 1) swcapr = 1; /* Set capas bit if windowing */ } else { XFATAL("Unsupported packet length"); } break; #endif /* NOXFER */ case 'i': /* Treat files as binary */ binary = XYFT_B; xfermode = XMODE_M; /* Transfer mode manual */ filepeek = 0; #ifdef PATTERNS patterns = 0; #endif /* PATTERNS */ break; #ifndef NOXFER case 'w': /* Writeover */ ckwarn = 0; fncact = XYFX_X; break; #endif /* NOXFER */ case 'q': /* Quiet */ quiet = 1; break; #ifdef DEBUG case 'd': /* DEBUG */ break; /* Handled in prescan() */ #endif /* DEBUG */ case '0': { /* In the middle */ extern int tt_escape, lscapr; tt_escape = 0; /* No escape character */ flow = 0; /* No Xon/Xoff (what about hwfc?) */ #ifndef NOXFER lscapr = 0; /* No locking shifts */ #endif /* NOXFER */ #ifdef CK_APC { extern int apcstatus; /* No APCs */ apcstatus = APC_OFF; } #endif /* CK_APC */ #ifndef NOLOCAL #ifdef CK_AUTODL setautodl(0,0); /* No autodownload */ #endif /* CK_AUTODL */ #endif /* NOLOCAL */ #ifndef NOCSETS { extern int tcsr, tcsl; /* No character-set translation */ tcsr = 0; tcsl = tcsr; /* Make these equal */ } #endif /* NOCSETS */ #ifdef TNCODE TELOPT_DEF_C_U_MODE(TELOPT_KERMIT) = TN_NG_RF; TELOPT_DEF_C_ME_MODE(TELOPT_KERMIT) = TN_NG_RF; TELOPT_DEF_S_U_MODE(TELOPT_KERMIT) = TN_NG_RF; TELOPT_DEF_S_ME_MODE(TELOPT_KERMIT) = TN_NG_RF; #endif /* TNCODE */ } /* Fall thru... */ case '8': /* 8-bit clean */ parity = 0; cmdmsk = 0xff; cmask = 0xff; break; case 'V': { extern int xfermode; #ifdef PATTERNS extern int patterns; patterns = 0; /* No patterns */ #endif /* PATTERNS */ xfermode = XMODE_M; /* Manual transfer mode */ filepeek = 0; break; } case 'p': /* SET PARITY */ if (*(xp+1)) { XFATAL("invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing parity"); } switch(x = **xargv) { case 'e': case 'o': case 'm': case 's': parity = x; break; case 'n': parity = 0; break; default: { XFATAL("invalid parity"); } } break; case 't': /* Line turnaround handshake */ turn = 1; turnch = XON; /* XON is turnaround character */ duplex = 1; /* Half duplex */ flow = 0; /* No flow control */ break; case 'B': bgset = 1; /* Force background (batch) */ backgrd = 1; break; case 'z': /* Force foreground */ bgset = 0; backgrd = 0; break; #ifndef NOXFER #ifdef RECURSIVE case 'L': recursive = 2; nolinks = 2; fnspath = PATH_REL; break; #endif /* RECURSIVE */ #endif /* NOXFER */ #ifndef NOSPL case 'M': /* My User Name */ if (*(xp+1)) { XFATAL("invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing username"); } if ((int)strlen(*xargv) > 63) { XFATAL("username too long"); } #ifdef IKSD if (!inserver) #endif /* IKSD */ { ckstrncpy(uidbuf,*xargv,UIDBUFLEN); haveftpuid = 1; } break; #endif /* NOSPL */ #ifdef CK_NETBIOS case 'N': /* NetBios Adapter Number follows */ if (*(xp+1)) { XFATAL("invalid argument bundling after -N"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing NetBios Adapter number"); } if ((strlen(*xargv) != 1) || (*xargv)[0] != 'X' && (atoi(*xargv) < 0) && (atoi(*xargv) > 9)) { XFATAL("Invalid NetBios Adapter - Adapters 0 to 9 are valid"); } break; #endif /* CK_NETBIOS */ #ifdef NETCONN case 'F': network = 1; if (*(xp+1)) { XFATAL("invalid argument bundling after -F"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("network file descriptor missing"); } ckstrncpy(ttname,*xargv,TTNAMLEN+1); nettype = NET_TCPB; mdmtyp = -nettype; telnetfd = 1; local = 1; break; #endif /* NETCONN */ #ifdef COMMENT #ifdef OS2PM case 'P': /* OS/2 Presentation Manager */ if (*(xp+1)) { XFATAL("invalid argument bundling after -P"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("pipe data missing"); } pipedata = *xargv; break; #endif /* OS2PM */ #else case 'P': /* Filenames literal */ fncnv = XYFN_L; f_save = XYFN_L; break; #endif /* COMMENT */ #ifndef NOICP case 'H': noherald = 1; break; #endif /* NOICP */ #ifdef OS2 case 'W': if (*(xp+1)) { XFATAL("invalid argument bundling after -W"); } xargv++, xargc--; if ((xargc < 1)) { /* could be negative */ XFATAL("Window handle missing"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("Kermit Instance missing"); } /* Action done in prescan */ break; case '#': /* K95 stdio threads */ xargv++, xargc--; /* Skip past argument */ break; /* Action done in prescan */ #endif /* OS2 */ #ifdef NEWFTP case '9': /* FTP */ if (*(xp+1)) { XFATAL("invalid argument bundling after -9"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("FTP server address missing"); } makestr(&ftp_host,*xargv); break; #endif /* NEWFTP */ default: fatal2(*xargv, #ifdef NT "invalid command-line option, type \"k95 -h\" for help" #else #ifdef OS2 "invalid command-line option, type \"k2 -h\" for help" #else "invalid command-line option, type \"kermit -h\" for help" #endif /* OS2 */ #endif /* NT */ ); } if (!xp) break; x = *++xp; /* See if options are bundled */ } return(0); } #ifdef TNCODE /* D O T N A R G -- Do a telnet command-line argument. */ static int #ifdef CK_ANSIC dotnarg(char x) #else dotnarg(x) char x; #endif /* CK_ANSIC */ /* dotnarg */ { char *xp; xp = *xargv+1; /* Pointer for bundled args */ debug(F111,"dotnarg entry",xp,xargc); while (x) { debug(F000,"dotnarg arg","",x); switch (x) { /* Big switch on arg */ #ifndef NOICP case '-': /* Extended commands... */ if (doxarg(xargv,0) < 0) { XFATAL("Extended option error"); } /* Full thru... */ case '+': /* Extended command for prescan() */ return(0); #else /* NOICP */ case '-': case '+': XFATAL("Extended options not configured"); #endif /* NOICP */ /* * -# Kermit 95 Startup Flags * -8 Negotiate Telnet Binary in both directions * -a Require use of Telnet authentication * -c Do not read the .telnetrc file * -d Turn on debug mode * -E No escape character * -f Forward credentials to host * -K Refuse use of authentication; do not send username * -k realm Set default realm * -l user Set username and request Telnet authentication * -L Negotiate Telnet Binary Output only * -q Quiet mode (suppress messages) * -S tos Use the IP type-of-service tos * -x Require Encryption * -D Disable forward-X * -T cert=file Use certificate in file * -T key=file Use private key in file * -T crlfile=file Use CRL in file * -T crldir=dir Use CRLs in directory * -T cipher=string Use only ciphers in string * -X atype Disable use of atype authentication * -Y Disable init file processing * */ case 'h': /* help */ usage(); doexit(GOOD_EXIT,-1); break; case '8': /* Telnet Binary in both directions */ TELOPT_DEF_C_U_MODE(TELOPT_BINARY) = TN_NG_MU; TELOPT_DEF_C_ME_MODE(TELOPT_BINARY) = TN_NG_MU; parity = 0; cmdmsk = 0xff; cmask = 0xff; break; case 'a': /* Require Telnet Auth */ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU; break; case 'Y': xargv++, xargc--; /* Skip past argument */ break; /* Action done in prescan */ #ifdef OS2 case '#': /* K95 stdio threads */ xargv++, xargc--; /* Skip past argument */ break; /* Action done in prescan */ #endif /* OS2 */ case 'q': /* Quiet */ quiet = 1; break; case 'd': #ifdef DEBUG if (deblog) { debtim = 1; } else { deblog = debopn("debug.log",0); } #endif /* DEBUG */ break; case 'E': { /* No Escape character */ extern int tt_escape; tt_escape = 0; } break; case 'K': TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF; uidbuf[0] = NUL; break; case 'l': /* Set username and request telnet authentication */ if (*(xp+1)) { XFATAL("invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing username"); } if ((int)strlen(*xargv) > 63) { XFATAL("username too long"); } ckstrncpy(uidbuf,*xargv,UIDBUFLEN); TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU; break; case 'L': /* Require BINARY mode outbound only */ TELOPT_DEF_C_ME_MODE(TELOPT_BINARY) = TN_NG_MU; break; case 'x': /* Require Encryption */ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU; break; case 'D': /* Disable use of Forward X */ TELOPT_DEF_C_U_MODE(TELOPT_FORWARD_X) = TN_NG_RF; break; case 'f': /* Forward credentials to host */ { #ifdef CK_AUTHENTICATION extern int forward_flag; forward_flag = 1; #endif break; } case 'k': { #ifdef CK_KERBEROS extern char * krb5_d_realm, * krb4_d_realm; #endif /* CK_KERBEROS */ if (*(xp+1)) { XFATAL("invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing realm"); } #ifdef CK_KERBEROS if ((int)strlen(*xargv) > 63) { XFATAL("realm too long"); } makestr(&krb5_d_realm,*xargv); makestr(&krb4_d_realm,*xargv); #endif /* CK_KERBEROS */ break; } case 'T': { if (*(xp+1)) { XFATAL("invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing cert=, key=, crlfile=, crldir=, or cipher="); } #ifdef CK_SSL if (!strncmp(*xargv,"cert=",5)) { extern char * ssl_rsa_cert_file; makestr(&ssl_rsa_cert_file,&(*xargv[5])); } else if ( !strncmp(*xargv,"key=",4) ) { extern char * ssl_rsa_key_file; makestr(&ssl_rsa_key_file,&(*xargv[4])); } else if ( !strncmp(*xargv,"crlfile=",8) ) { extern char * ssl_crl_file; makestr(&ssl_crl_file,&(*xargv[8])); } else if ( !strncmp(*xargv,"crldir=",7) ) { extern char * ssl_crl_dir; makestr(&ssl_crl_dir,&(*xargv[7])); } else if ( !strncmp(*xargv,"cipher=",7) ) { extern char * ssl_cipher_list; makestr(&ssl_cipher_list,&(*xargv[7])); } else { XFATAL("invalid parameter"); } #endif /* CK_SSL */ break; } default: fatal2(*xargv, "invalid command-line option, type \"telnet -h\" for help" ); } if (!xp) break; x = *++xp; /* See if options are bundled */ } return(0); } #endif /* TNCODE */ #ifdef RLOGCODE /* D O R L G A R G -- Do a rlogin command-line argument. */ static int #ifdef CK_ANSIC dorlgarg(char x) #else dorlgarg(x) char x; #endif /* CK_ANSIC */ /* dorlgarg */ { char *xp; xp = *xargv+1; /* Pointer for bundled args */ debug(F111,"dorlgarg entry",xp,xargc); while (x) { debug(F000,"dorlgarg arg","",x); switch (x) { /* Big switch on arg */ #ifndef NOICP case '-': /* Extended commands... */ if (doxarg(xargv,0) < 0) { XFATAL("Extended option error"); } /* Full thru... */ case '+': /* Extended command for prescan() */ return(0); #else /* NOICP */ case '-': case '+': XFATAL("Extended options not configured"); #endif /* NOICP */ /* * -d Debug * -l user Set username * */ case 'h': /* help */ usage(); doexit(GOOD_EXIT,-1); break; case 'Y': xargv++, xargc--; /* Skip past argument */ break; /* Action done in prescan */ #ifdef OS2 case '#': /* K95 stdio threads */ xargv++, xargc--; /* Skip past argument */ break; /* Action done in prescan */ #endif /* OS2 */ case 'q': /* Quiet */ quiet = 1; break; case 'd': #ifdef DEBUG if (deblog) { debtim = 1; } else { deblog = debopn("debug.log",0); } #endif /* DEBUG */ break; case 'l': /* Set username and request telnet authentication */ if (*(xp+1)) { XFATAL("invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing username"); } if ((int)strlen(*xargv) > 63) { XFATAL("username too long"); } ckstrncpy(uidbuf,*xargv,UIDBUFLEN); break; default: fatal2(*xargv, "invalid command-line option, type \"rlogin -h\" for help" ); } if (!xp) break; x = *++xp; /* See if options are bundled */ } return(0); } #endif /* RLOGCODE */ #ifdef SSHBUILTIN /* D O S S H A R G -- Do a ssh command-line argument. */ static int #ifdef CK_ANSIC dossharg(char x) #else dossharg(x) char x; #endif /* CK_ANSIC */ /* dossharg */ { char *xp; xp = *xargv+1; /* Pointer for bundled args */ debug(F111,"dossharg entry",xp,xargc); while (x) { debug(F000,"dossharg arg","",x); switch (x) { /* Big switch on arg */ #ifndef NOCICP case '-': /* Extended commands... */ if (doxarg(xargv,0) < 0) { XFATAL("Extended option error"); } /* Full thru... */ case '+': /* Extended command for prescan() */ return(0); #else /* NOICP */ case '-': case '+': XFATAL("Extended options not configured"); #endif /* NOICP */ /* * -d Debug * -# args Init * -Y no init file * -l user Set username * */ case 'h': /* help */ usage(); doexit(GOOD_EXIT,-1); break; case 'Y': xargv++, xargc--; /* Skip past argument */ break; /* Action done in prescan */ #ifdef OS2 case '#': /* K95 stdio threads */ xargv++, xargc--; /* Skip past argument */ break; /* Action done in prescan */ #endif /* OS2 */ case 'q': /* Quiet */ quiet = 1; break; case 'd': #ifdef DEBUG if (deblog) { debtim = 1; } else { deblog = debopn("debug.log",0); } #endif /* DEBUG */ break; case 'l': /* Set username and request telnet authentication */ if (*(xp+1)) { XFATAL("invalid argument bundling"); } xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) { XFATAL("missing username"); } if ((int)strlen(*xargv) > 63) { XFATAL("username too long"); } ckstrncpy(uidbuf,*xargv,UIDBUFLEN); break; default: fatal2(*xargv, "invalid command-line option, type \"ssh -h\" for help" ); } if (!xp) break; x = *++xp; /* See if options are bundled */ } return(0); } #endif /* SSHBUILTIN */ #else /* No command-line interface... */ int cmdlin() { extern int xargc; if (xargc > 1) { XFATAL("Sorry, command-line options disabled."); } } #endif /* NOCMDL */ ckuver.h000664 045065 024037 00000057107 14767402177 012664 0ustar00fdckermit000000 000000 /* ckuver.h -- C-Kermit UNIX Version heralds */ /* Author: Frank da Cruz . Copyright (C) 1985, 2022, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ #ifndef CKUVER_H #define CKUVER_H /* Arranged more or less alphabetically by compiler symbol */ /* Must be included AFTER ckcdeb.h. */ #ifdef BEOS #ifdef BEOS45 #define HERALD " BeOS 4.5" #else #define HERALD " BeOS" #endif /* BEOS45 */ #else #ifdef BEBOX #ifdef BE_DR_7 #define HERALD " BeBox DR7" #else #define HERALD " BeBox" #endif /* BE_DR_7 */ #endif /* BEBOX */ #endif /* BEOS */ #ifdef BELLV10 #define HERALD " Bell Labs Research UNIX V10" #endif /* BELLV10 */ #ifdef APOLLOSR10 #define HERALD " Apollo SR10" #endif /* APOLLOSR10 */ #ifdef MAC #define HERALD " Apple Macintosh" #endif /* MAC */ #ifdef A986 #define HERALD " Altos 986 / Xenix 3.0" #endif /* A986 */ #ifdef AS400 #define HERALD " AS/400" #endif /* AS400 */ #ifdef aegis #ifdef BSD4 #define HERALD " Apollo DOMAIN/IX 4.2 BSD" #else #ifdef ATTSV #define HERALD " Apollo DOMAIN/IX System V" #else #define HERALD " Apollo Aegis" #endif /* BSD4 */ #endif /* ATTSV */ #endif /* aegis */ #ifndef HERALD #ifdef AIXRS #ifdef AIX53 #define HERALD " IBM AIX 5.3" #else #ifdef AIX52 #define HERALD " IBM AIX 5.2" #else #ifdef AIX51 #define HERALD " IBM AIX 5.1" #else #ifdef AIX45 #define HERALD " IBM AIX 5.0" #else #ifdef AIX45 #define HERALD " IBM AIX 4.5" #else #ifdef AIX44 #define HERALD " IBM AIX 4.4" #else #ifdef AIX43 #define HERALD " IBM AIX 4.3" #else #ifdef AIX42 #define HERALD " IBM AIX 4.2" #else #ifdef SVR4 #ifdef AIX41 #define HERALD " IBM AIX 4.1" #else #define HERALD " IBM RS/6000 AIX 3.2" #endif /* AIX41 */ #else #define HERALD " IBM RS/6000 AIX 3.0/3.1" #endif /* SVR4 */ #endif /* AIX42 */ #endif /* AIX43 */ #endif /* AIX44 */ #endif /* AIX45 */ #endif /* AIX50 */ #endif /* AIX51 */ #endif /* AIX52 */ #endif /* AIX53 */ #endif /* AIXRS */ #ifdef PS2AIX10 #define HERALD " IBM PS/2 AIX 1.x" #endif /* PS2AIX10 */ #ifdef AIXPS2 #define HERALD " IBM PS/2 AIX 3.x" #endif /* AIXPS2 */ #ifdef AIX370 #ifndef HERALD #define HERALD " IBM System/370 AIX/370" #endif #endif /* AIX370 */ #ifdef AIXESA #ifndef HERALD #define HERALD " IBM AIX/ESA version 2.1" #endif #endif /* AIXESA */ #ifdef ATT6300 #define HERALD " AT&T 6300" #endif /* ATT6300 */ #ifdef ATT7300 #ifdef UNIX351M #define HERALD " AT&T 7300 UNIX PC UNIX 3.51m" #else #define HERALD " AT&T 7300 UNIX PC" #endif /* UNIX351M */ #endif /* ATT7300 */ #ifdef AUX #define HERALD " Apple Macintosh AUX" #endif /* AUX */ #ifdef BSD44 #ifdef MACOSX #define HERALD " Mac OS X" #else #ifdef __OpenBSD__ #define HERALD " OpenBSD" #else #ifdef __bsdi__ #ifdef BSDI4 #define HERALD " BSDI BSD/OS 4.0" #else #ifdef BSDI3 #define HERALD " BSDI BSD/OS 3.0" #else #ifdef BSDI2 #define HERALD " BSDI BSD/OS 2.0" /* 1.1++ name... */ #else #define HERALD " BSDI BSD/386" /* Original 1.0 name */ #endif /* BSDI2 */ #endif /* BSDI3 */ #endif /* BSDI4 */ #else /* __bsdi__ */ #ifdef __NetBSD__ #ifndef HERALD #ifdef NETBSD16 #define HERALD " NetBSD 1.6" #else #ifdef NETBSD15 #define HERALD " NetBSD 1.5" #else #define HERALD " NetBSD" #endif /* NETBSD15 */ #endif /* NETBSD16 */ #endif /* HERALD */ #else /* __NetBSD__ */ #ifdef __FreeBSD__ #ifdef FREEBSD51 #define HERALD " FreeBSD 5.1" #else #ifdef FREEBSD50 #define HERALD " FreeBSD 5.0" #else #ifdef FREEBSD49 #define HERALD " FreeBSD 4.9" #else #ifdef FREEBSD48 #define HERALD " FreeBSD 4.8" #else #ifdef FREEBSD47 #define HERALD " FreeBSD 4.7" #else #ifdef FREEBSD46 #define HERALD " FreeBSD 4.6" #else #ifdef FREEBSD45 #define HERALD " FreeBSD 4.5" #else #ifdef FREEBSD44 #define HERALD " FreeBSD 4.4" #else #ifdef FREEBSD43 #define HERALD " FreeBSD 4.3" #else #ifdef FREEBSD42 #define HERALD " FreeBSD 4.2" #else #ifdef FREEBSD41 #define HERALD " FreeBSD 4.1" #else #ifdef FREEBSD4 #define HERALD " FreeBSD 4.0" #else #ifdef FREEBSD3 #define HERALD " FreeBSD 3.0" #else #ifdef FREEBSD2 #define HERALD " FreeBSD 2.0" #else #define HERALD " FreeBSD" #endif /* FREEBSD2 */ #endif /* FREEBSD3 */ #endif /* FREEBSD4 */ #endif /* FREEBSD41 */ #endif /* FREEBSD42 */ #endif /* FREEBSD43 */ #endif /* FREEBSD44 */ #endif /* FREEBSD45 */ #endif /* FREEBSD46 */ #endif /* FREEBSD47 */ #endif /* FREEBSD48 */ #endif /* FREEBSD49 */ #endif /* FREEBSD50 */ #endif /* FREEBSD51 */ #else #ifdef __386BSD__ #define HERALD " 386BSD" #else #define HERALD " 4.4BSD" #endif /* __386BSD__ */ #endif /* __FreeBSD__ */ #endif /* __NetBSD__ */ #endif /* __bsdi__ */ #endif /* __OpenBSD__ */ #endif /* MACOSX */ #endif /* BSD44 */ #ifdef ENCORE #ifdef BSD43 #define HERALD " Encore Multimax UMAX 4.3" #else #define HERALD " Encore Multimax UMAX 4.2" #endif #endif /* ENCORE */ #ifdef BSD29 #define HERALD " 2.9 BSD" #endif /* BSD29 */ #ifdef BSD41 #define HERALD " 4.1 BSD" #endif /* BSD41 */ #ifdef C70 #define HERALD " BBN C/70" #endif /* c70 */ #ifdef CIE #define HERALD " CIE Systems 680/20 Regulus" #endif /* CIE */ #ifdef COHERENT #ifdef _I386 #define HERALD " MWC Coherent 386 4.x" #ifndef i386 #define i386 #endif /* i386 */ #else #define HERALD " PC/AT MWC Coherent 286 3.x" #ifndef i286 #define i286 #endif /* i286 */ #endif /* _I386 */ #endif /* COHERENT */ #ifdef CONVEX9 #define HERALD " Convex/OS" #endif /* CONVEX9 */ #ifdef CONVEX10 #define HERALD " Convex/OS 10.1" #endif /* CONVEX10 */ #ifdef _CRAY #ifdef _CRAYCOM #define HERALD " Cray CSOS" #else /* _CRAYCOM */ #define HERALD " Cray UNICOS" #endif /* _CRAYCOM */ #endif /* _CRAY */ #ifdef DGUX #ifdef DGUX54420 #define HERALD " Data General DG/UX R4.20" #else #ifdef DGUX54411 #define HERALD " Data General DG/UX R4.11" #else #ifdef DGUX54410 #define HERALD " Data General DG/UX R4.10" #else #ifdef DGUX54310 #define HERALD " Data General DG/UX 5.4R3.10" #else #ifdef DGUX543 #define HERALD " Data General DG/UX 5.4R3.00" #else #ifdef DGUX540 #define HERALD " Data General DG/UX 5.4" #else #ifdef DGUX430 #define HERALD " Data General DG/UX 4.30" #else #define HERALD " Data General DG/UX" #endif /* DGUX430 */ #endif /* DGUX540 */ #endif /* DGUX543 */ #endif /* DGUX54310 */ #endif /* DGUX54410 */ #endif /* DGUX54411 */ #endif /* DGUX54420 */ #endif /* DGUX */ #ifdef datageneral #ifndef HERALD #define HERALD " Data General AOS/VS" #endif /* HERALD */ #endif /* datageneral */ #ifdef SINIX #ifdef SNI544 #define HERALD " Siemens Nixdorf Reliant UNIX V5.44" #else #ifdef SNI543 #define HERALD " Siemens Nixdorf Reliant UNIX V5.43" #else #ifdef SNI541 #define HERALD " Siemens Nixdorf SINIX V5.41" #else #define HERALD " Siemens Nixdorf SINIX V5.42" #endif /* SNI541 */ #endif /* SNI543 */ #endif /* SNI544 */ #endif /* SINIX */ #ifdef POWERMAX #define HERALD " Concurrent PowerMAX OS" #endif /* POWERMAX */ #ifdef DELL_SVR4 #define HERALD " Dell System V R4" #endif /* DELL_SVR4 */ #ifdef NCRMPRAS #define HERALD " NCR MP-RAS" #endif /* NCRMPRAS */ #ifdef UNIXWARE #define HERALD " UnixWare" #else #ifdef OLD_UNIXWARE #define HERALD " UnixWare" #endif /* OLD_UNIXWARE */ #endif /* UNIXWARE */ #ifdef ICL_SVR4 #define HERALD " ICL System V R4 DRS N/X" #endif /* ICL_SVR4 */ #ifdef FT18 #ifdef FT21 #define HERALD " Fortune For:Pro 2.1" #else #define HERALD " Fortune For:Pro 1.8" #endif /* FT21 */ #endif /* FT18 */ #ifdef GEMDOS #define HERALD " Atari ST GEM 1.0" #endif /* GEMDOS */ #ifdef XF68R3V6 #define HERALD " Motorola UNIX System V/68 R3V6" #endif /* XF68R3V6 */ #ifdef XF88R32 #define HERALD " Motorola UNIX System V/88 R32" #endif /* XF88R32 */ #ifdef I386IX #ifdef SVR3JC #define HERALD " Interactive UNIX System V/386 R3.2" #else #define HERALD " Interactive Systems Corp 386/ix" #endif /* SVR3JC */ #endif /* I386IX */ #ifdef IRIX65 #define HERALD " Silicon Graphics IRIX 6.5" #else #ifdef IRIX64 #define HERALD " Silicon Graphics IRIX 6.4" #else #ifdef IRIX63 #define HERALD " Silicon Graphics IRIX 6.3" #else #ifdef IRIX62 #define HERALD " Silicon Graphics IRIX 6.2" #else #ifdef IRIX60 #define HERALD " Silicon Graphics IRIX 6.0" #else #ifdef IRIX53 #define HERALD " Silicon Graphics IRIX 5.3" #else #ifdef IRIX52 #define HERALD " Silicon Graphics IRIX 5.2" #else #ifdef IRIX51 #define HERALD " Silicon Graphics IRIX 5.1" #else #ifdef IRIX40 #define HERALD " Silicon Graphics IRIX 4.0" #endif /* IRIX40 */ #endif /* IRIX51 */ #endif /* IRIX52 */ #endif /* IRIX53 */ #endif /* IRIX60 */ #endif /* IRIX62 */ #endif /* IRIX63 */ #endif /* IRIX64 */ #endif /* IRIX65 */ #ifdef ISIII #define HERALD " Interactive Systems Corp System III" #endif /* ISIII */ #ifdef IX370 #define HERALD " IBM IX/370" #endif /* IX370 */ #ifdef HPUX #ifdef HPUX5 #define HERALD " HP-UX 5.00" #else #ifdef HPUX6 #define HERALD " HP-UX 6.00" #else #ifdef HPUX7 #define HERALD " HP-UX 7.00" #else #ifdef HPUX8 #define HERALD " HP-UX 8.00" #else #ifdef HPUX9 #define HERALD " HP-UX 9.00" #else #ifdef HPUX1100 #define HERALD " HP-UX 11.00" #else #ifdef HPUX10 #ifdef HPUX1030 #define HERALD " HP-UX 10.30" #else #ifdef HPUX1020 #define HERALD " HP-UX 10.20" #else #ifdef HPUX1010 #define HERALD " HP-UX 10.10" #else #ifdef HPUX10xx #define HERALD " HP-UX 10.xx" #else #define HERALD " HP-UX 10.00" #endif /* HPUX10XX */ #endif /* HPUX1010 */ #endif /* HPUX1020 */ #endif /* HPUX1030 */ #else #define HERALD " HP-UX" #endif /* HPUX10 */ #endif /* HPUX1100 */ #endif /* HPUX9 */ #endif /* HPUX8 */ #endif /* HPUX7 */ #endif /* HPUX6 */ #endif /* HPUX5 */ #endif /* HPUX */ #ifndef MINIX #ifdef MINIX340 #define MINIX #endif /* MINIX340 */ #endif /* MINIX */ #ifndef MINIX #ifdef MINIX315 #define MINIX #endif /* MINIX315 */ #endif /* MINIX */ #ifndef MINIX #ifdef MINIX3 #define MINIX #endif /* MINIX3 */ #endif /* MINIX */ #ifdef MINIX #ifdef MINIX340 #ifdef HERALD #undef HERALD #endif /* HERALD */ #define HERALD " Minix 3.4.0" #ifndef MINIX3 #define MINIX3 #endif /* MINIX3 */ #endif /* MINIX340 */ #ifdef MINIX315 #define HERALD " Minix 3.1.5" #ifndef MINIX3 #define MINIX3 #endif /* MINIX3 */ #endif /* MINIX315 */ #ifdef MINIX3 #ifndef MINIX2 #define MINIX2 #endif /* MINIX2 */ #ifndef HERALD #define HERALD " Minix 3.0" #endif /* HERALD */ #else #ifdef MINIX2 #define HERALD " Minix 2.0" #else #define HERALD " Minix 1.0" #endif /* MINIX3 */ #endif /* MINIX2 */ #endif /* MINIX */ #ifdef MIPS #define HERALD " MIPS RISC/OS SVR3" #endif /* MIPS */ #ifdef NEXT #ifdef OPENSTEP42 #define HERALD " OPENSTEP 4.2" #else #ifdef NEXT33 #define HERALD " NeXTSTEP 3.3" #else #define HERALD " NeXTSTEP" #endif /* NEXT33 */ #endif /* OPENSTEP42 */ #endif /* NEXT */ #ifdef OSF #ifdef i386 #define HERALD " DECpc OSF/1" #ifdef __GNUC #define OSFPC #endif /* __GNUC */ #else /* Not i386 so Alpha */ #ifdef TRU64 #ifdef OSF51B #define HERALD " Compaq Tru64 UNIX 5.1B" #else #ifdef OSF51A #define HERALD " Compaq Tru64 UNIX 5.1A" #else #ifdef OSF50 #define HERALD " Compaq Tru64 UNIX 5.0A" #else #ifdef OSF40G #define HERALD " Compaq Tru64 UNIX 4.0G" #else #ifdef OSF40F #define HERALD " Compaq Tru64 UNIX 4.0F" #else #ifdef OSF40E #define HERALD " Compaq Tru64 UNIX 4.0E" #endif /* OSF40E */ #endif /* OSF40F */ #endif /* OSF40G */ #endif /* OSF50 */ #endif /* OSF51A */ #endif /* OSF51B */ #else /* Not TRU64 */ #ifdef OSF40 #define HERALD " Digital UNIX 4.0" #else #ifdef OSF32 #define HERALD " Digital UNIX 3.2" #else #define HERALD " DEC OSF/1 Alpha" #endif /* OSF40 */ #endif /* OSF32 */ #endif /* TRU64 */ #endif /* i386 */ #endif /* OSF */ #ifdef PCIX #define HERALD " PC/IX" #endif /* PCIX */ #ifdef sxaE50 #define HERALD " PFU SX/A V10/L50" #endif /* sxaE50 */ #ifdef PROVX1 #define HERALD " DEC Professional 300 (Venix 1.0)" #endif /* PROVX1 */ #ifdef PYRAMID #ifdef SVR4 #define HERALD " Pyramid DC/OSx" #else #define HERALD " Pyramid Dual Port OSx" #endif /* SVR4 */ #endif /* PYRAMID */ #ifdef RTAIX #define HERALD " IBM RT PC (AIX 2.2)" #endif /* RTAIX */ #ifdef RTU #define HERALD " Masscomp/Concurrent RTU" #endif /* RTU */ #ifdef sony_news #define HERALD " SONY NEWS" #endif /* sony_news */ #ifdef SOLARIS24 #define HERALD " Solaris 2.4" #else #ifdef SOLARIS23 #define HERALD " Solaris 2.3" #else #ifdef SOLARIS #define HERALD " Solaris 2.x" #endif /* SOLARIS */ #endif /* SOLARIS23 */ #endif /* SOLARIS24 */ #ifdef SUNOS4 #ifdef BSD4 #ifdef SUNOS41 #define HERALD " SunOS 4.1" #else #define HERALD " SunOS 4.0" #endif /* SUNOS41 */ #endif /* BSD4 */ #endif /* SUNOS4 */ #ifdef SUN4S5 #ifdef HDBUUCP #define HERALD " SunOS 4.1 (SVR3)" #else #define HERALD " SunOS 4.0 (SVR3)" #endif /* HDBUUCP */ #endif /* SUN4S5 */ #ifdef STRATUS #define HERALD " Stratus VOS" #endif /* STRATUS */ #ifdef TOWER1 #define HERALD " NCR Tower 1632 OS 1.02" #endif /* TOWER1 */ #ifdef TRS16 #define HERALD " Tandy 16/6000 Xenix 3.0" #ifndef CKCPU #define CKCPU "mc68000" #endif /* CKCPU */ #endif /* TRS16 */ #ifdef u3b2 #ifndef HERALD #ifdef SVR3 #define HERALD " AT&T 3B2 System V R3" #else #define HERALD " AT&T 3B2 System V" #endif /* SVR3 */ #endif /* HERALD */ #endif /* u3b2 */ #ifdef ultrix #ifdef vax #ifdef ULTRIX3 #define HERALD " VAX/ULTRIX 3.0" #else #define HERALD " VAX/ULTRIX" #endif /* ULTRIX3 */ #else #ifdef mips #ifdef ULTRIX43 #define HERALD " DECstation/ULTRIX 4.3" #else #ifdef ULTRIX44 #define HERALD " DECstation/ULTRIX 4.4" #else #ifdef ULTRIX45 #define HERALD " DECstation/ULTRIX 4.5" #else #define HERALD " DECstation/ULTRIX" #endif /* ULTRIX45 */ #endif /* ULTRIX44 */ #endif /* ULTRIX43 */ #else #define HERALD " ULTRIX" #endif /* mips */ #endif /* vax */ #endif /* ultrix */ #ifdef OXOS #define HERALD " Olivetti X/OS" #endif /* OXOS */ #ifdef _386BSD #define HERALD " 386BSD" #endif /* _386BSD */ #ifdef POSIX #ifdef PTX #ifdef PTX4 #define HERALD " DYNIX/ptx V4" #else #define HERALD " DYNIX/ptx" #endif /* PTX4 */ #else /* PTX */ #ifndef OSF /* Let OSF -DPOSIX keep previously defined HERALD */ #ifdef HERALD #undef HERALD #endif /* HERALD */ #endif /* OSF */ #ifdef OU8 #define HERALD " OpenUNIX 8" #else #ifdef UW7 #define HERALD " Unixware 7" #else #ifdef QNX #ifdef QNX16 #define HERALD " QNX 16-bit" #else #define HERALD " QNX 32-bit" #endif /* QNX16 */ #else #ifdef NEUTRINO #define HERALD " QNX Neutrino 2" #else /* NEUTRINO */ #ifdef QNX6 #define HERALD " QNX6" #else /* QNX6 */ #ifdef __linux__ #ifdef ZSL5500 #define HERALD " Sharp Zaurus SL-5500" #else #ifdef RH90 #define HERALD " Red Hat Linux 9.0" #else #ifdef RH80 #define HERALD " Red Hat Linux 8.0" #else #ifdef RH73 #define HERALD " Red Hat Linux 7.3" #else #ifdef RH72 #define HERALD " Red Hat Linux 7.2" #else #ifdef RH71 #define HERALD " Red Hat Linux 7.1" #else #ifdef ANDROID #define HERALD " Android" #else #define HERALD " Linux" #endif /* ANDROID */ #endif /* RH71 */ #endif /* RH72 */ #endif /* RH73 */ #endif /* RH80 */ #endif /* RH90 */ #endif /* ZSL5500 */ #else /* __linux__ */ #ifdef _386BSD /* 386BSD Jolix */ #define HERALD " 386BSD" #else #ifdef LYNXOS /* Lynx OS 2.2 */ #define HERALD " Lynx OS" #else #ifdef Plan9 #define HERALD " Plan 9 from Bell Labs" #else #ifdef SOLARIS11 #define HERALD " Solaris 11" #else #ifdef SOLARIS10 #define HERALD " Solaris 10" #else #ifdef SOLARIS9 #define HERALD " Solaris 9" #else #ifdef SOLARIS8 #define HERALD " Solaris 8" #else #ifdef SOLARIS7 #define HERALD " Solaris 7" #else #ifdef SOLARIS26 #define HERALD " Solaris 2.6" #else #ifdef SOLARIS25 #define HERALD " Solaris 2.5" #else #ifdef SOLARIS24 #define HERALD " Solaris 2.4" #else #ifdef SOLARIS #define HERALD " Solaris 2.x" #endif /* SOLARIS */ #endif /* SOLARIS24 */ #endif /* SOLARIS25 */ #endif /* SOLARIS26 */ #endif /* SOLARIS7 */ #endif /* SOLARIS8 */ #endif /* SOLARIS9 */ #endif /* SOLARIS10 */ #endif /* SOLARIS11 */ #endif /* Plan9 */ #endif /* LYNXOS */ #endif /* _386BSD */ #endif /* __linux__ */ #endif /* QNX6 */ #endif /* NEUTRINO */ #endif /* QNX */ #endif /* UW7 */ #endif /* OU8 */ #endif /* PTX */ #endif /* POSIX */ #ifdef UTS24 #define HERALD " Amdahl UTS 2.4" #endif /* UTS24 */ #ifdef UTSV #define HERALD " Amdahl UTS V" #endif /* UTSV */ #ifdef VXVE #define HERALD " CDC VX/VE 5.2.1 System V" #endif /* VXVE */ #ifdef SCO234 #ifdef HERALD #undef HERALD #endif /* HERALD */ #define HERALD " SCO XENIX 2.3.4" #else #ifdef CK_SCO32V4 #ifdef HERALD #undef HERALD #endif /* HERALD */ #ifdef ODT30 #define HERALD " SCO ODT 3.0" #else #define HERALD " SCO UNIX/386 V4" #endif /* ODT30 */ #else #ifdef CK_SCOV5 #ifdef HERALD #undef HERALD #endif /* HERALD */ #ifdef SCO_OSR507 #define HERALD " SCO OpenServer R5.0.7" #else #ifdef SCO_OSR506A #define HERALD " SCO OpenServer R5.0.6a" #else #ifdef SCO_OSR506 #define HERALD " SCO OpenServer R5.0.6" #else #ifdef SCO_OSR505 #define HERALD " SCO OpenServer R5.0.5" #else #ifdef SCO_OSR504 #define HERALD " SCO OpenServer R5.0.4" #else #ifdef SCO_OSR502 #define HERALD " SCO OpenServer R5.0.2" #else #define HERALD " SCO OpenServer R5.0" #endif /* SCO_OSR502 */ #endif /* SCO_OSR504 */ #endif /* SCO_OSR505 */ #endif /* SCO_OSR506 */ #endif /* SCO_OSR506A */ #endif /* SCO_OSR507 */ #else #ifdef XENIX #ifdef HERALD #undef HERALD #endif /* HERALD */ #ifdef M_UNIX #define HERALD " SCO UNIX/386" #else #ifdef M_I386 #define HERALD " Xenix/386" #else #ifdef M_I286 #define HERALD " Xenix/286" #else #define HERALD " Xenix" #endif /* M_I286 */ #endif /* M_I386 */ #endif /* M_UNIX */ #endif /* XENIX */ #endif /* CK_SCOV5 */ #endif /* CK_SCOV32V4 */ #endif /* SCO234 */ #ifdef ZILOG #define HERALD " Zilog S8000 Zeus 3.21+" #endif /* ZILOG */ #ifdef UTEK #define HERALD " UTek" #endif /* UTEK */ /* Catch-alls for anything not defined explicitly above */ #ifndef HERALD #ifdef SVR4 #ifdef i386 #define HERALD " AT&T System V/386 R4" #else #ifdef AMIX #define HERALD " Commodore Amiga System V/m68k R4" #else #define HERALD " AT&T System V R4" #endif /* AMIX */ #endif /* i386 */ #else #ifdef SVR3 #define HERALD " AT&T System V R3" #else #ifdef ATTSV #define HERALD " AT&T System III / System V" #else #ifdef BSD43 #ifdef pdp11 #define HERALD " 2.10 BSD PDP-11" #else #ifdef vax #define HERALD " 4.3 BSD VAX" #else #define HERALD " 4.3 BSD" #endif /* vax */ #endif /* pdp11 */ #else #ifdef BSD4 #ifdef vax #define HERALD " 4.2 BSD VAX" #else #define HERALD " 4.2 BSD" #endif /* vax */ #else #ifdef V7 #define HERALD " UNIX Version 7" #endif /* V7 */ #endif /* BSD4 */ #endif /* BSD43 */ #endif /* ATTSV */ #endif /* SVR3 */ #endif /* SVR4 */ #endif /* HERALD */ #endif /* HERALD */ #ifdef OS2 #ifdef HERALD #undef HERALD #endif /* HERALD */ #ifdef NT #define HERALD " Windows" #else /* NT */ #define HERALD " 32-bit OS/2" #endif /* NT */ #endif /* OS/2 */ #ifndef HERALD #define HERALD " Unknown Platform" #endif /* HERALD */ /* Hardware type */ #ifdef vax /* DEC VAX */ #ifndef CKCPU #define CKCPU "vax" #endif /* CKCPU */ #endif /* vax */ #ifdef pdp11 /* DEC PDP-11 */ #ifndef CKCPU #define CKCPU "pdp11" #endif /* CKCPU */ #endif /* pdp11 */ #ifdef __ALPHA /* DEC Alpha */ #ifndef CKCPU #define CKCPU "Alpha" #endif /* CKCPU */ #endif /* __ALPHA */ #ifdef __alpha /* OSF/1 uses lowercase... */ #ifndef CKCPU #define CKCPU "Alpha" #endif /* CKCPU */ #endif /* __alpha */ #ifdef DGUX /* Override Motorola 88k assumption */ #ifndef CKCPU /* New AViiONs are Intel based... */ #ifdef i586 #define CKCPU "i586" #else #ifdef i486 #define CKCPU "i486" #else #ifdef i386 #define CKCPU "i386" #endif /* i386 */ #endif /* i486 */ #endif /* i586 */ #endif /* CKCPU */ #endif /* DGUX */ /* HP 9000 */ #ifdef __hp9000s700 #ifndef CKCPU #define CKCPU "hp9000s700" #endif /* CKCPU */ #endif /* __hp9000s700 */ #ifdef __hp9000s800 #ifndef CKCPU #define CKCPU "hp9000s800" #endif /* CKCPU */ #endif /* __hp9000s800 */ #ifdef __hp9000s500 #ifndef CKCPU #define CKCPU "hp9000s500" #endif /* CKCPU */ #endif /* __hp9000s500 */ #ifdef __hp9000s400 #ifndef CKCPU #define CKCPU "hp9000s400" #endif /* CKCPU */ #endif /* __hp9000s400 */ #ifdef __hp9000s300 #ifndef CKCPU #define CKCPU "hp9000s300" #endif /* CKCPU */ #endif /* __hp9000s300 */ #ifdef __hp9000s200 #ifndef CKCPU #define CKCPU "hp9000s200" #endif /* CKCPU */ #endif /* __hp9000s200 */ #ifdef m88000 /* Motorola 88000 */ #ifndef CKCPU #define CKCPU "mc88000" #endif /* CKCPU */ #endif /* m88000 */ #ifdef __using_M88KBCS /* DG symbol for Motorola 88000 */ #ifndef CKCPU #define CKCPU "mc88000" #endif /* CKCPU */ #endif /* __using_M88KBCS */ #ifdef m88k /* Motorola symbol for 88000 */ #ifndef CKCPU #define CKCPU "mc88000" #endif /* CKCPU */ #endif /* m88k */ #ifdef mc68040 /* Motorola 68040 */ #ifndef CKCPU #define CKCPU "mc68040" #endif /* CKCPU */ #endif /* mc68040 */ #ifdef mc68030 /* Motorola 68030 */ #ifndef CKCPU #define CKCPU "mc68030" #endif /* CKCPU */ #endif /* mc68030 */ #ifdef mc68020 /* Motorola 68020 */ #ifndef CKCPU #define CKCPU "mc68020" #endif /* CKCPU */ #endif /* mc68020 */ #ifdef mc68010 /* Motorola 68010 */ #ifndef CKCPU #define CKCPU "mc68010" #endif /* CKCPU */ #endif /* mc68010 */ #ifdef mc68000 /* Motorola 68000 */ #ifndef CKCPU #define CKCPU "mc68000" #endif /* CKCPU */ #endif /* mc68000 */ #ifdef mc68k /* Ditto (used by DIAB DS90) */ #ifndef CKCPU #define CKCPU "mc68000" #endif /* CKCPU */ #endif /* mc68k */ #ifdef m68 /* Ditto */ #ifndef CKCPU #define CKCPU "mc68000" #endif /* CKCPU */ #endif /* m68 */ #ifdef m68k /* Ditto */ #ifndef CKCPU #define CKCPU "mc68000" #endif /* CKCPU */ #endif /* m68k */ #ifdef ia64 /* IA64 / Itanium */ #ifndef CKCPU #define CKCPU "ia64" #endif /* CKCPU */ #endif /* i686 */ #ifdef i686 /* Intel 80686 */ #ifndef CKCPU #define CKCPU "i686" #endif /* CKCPU */ #endif /* i686 */ #ifdef i586 /* Intel 80586 */ #ifndef CKCPU #define CKCPU "i586" #endif /* CKCPU */ #endif /* i586 */ #ifdef i486 /* Intel 80486 */ #ifndef CKCPU #define CKCPU "i486" #endif /* CKCPU */ #endif /* i80486 */ #ifdef i386 /* Intel 80386 */ #ifndef CKCPU #define CKCPU "i386" #endif /* CKCPU */ #endif /* i80386 */ #ifdef i286 /* Intel 80286 */ #ifndef CKCPU #define CKCPU "i286" #endif /* CKCPU */ #endif /* i286 */ #ifdef i186 /* Intel 80186 */ #ifndef CKCPU #define CKCPU "i186" #endif /* CKCPU */ #endif /* i186 */ #ifdef M_I586 /* Intel 80586 */ #ifndef CKCPU #define CKCPU "i586" #endif /* CKCPU */ #endif /* M_I586 */ #ifdef M_I486 /* Intel 80486 */ #ifndef CKCPU #define CKCPU "i486" #endif /* CKCPU */ #endif /* M_I486 */ #ifdef _M_I386 /* Intel 80386 */ #ifndef CKCPU #define CKCPU "i386" #endif /* CKCPU */ #endif /* _M_I386 */ #ifdef M_I286 /* Intel 80286 */ #ifndef CKCPU #define CKCPU "i286" #endif /* CKCPU */ #endif /* M_I286 */ #ifdef M_I86 /* Intel 80x86 */ #ifndef CKCPU #define CKCPU "ix86" #endif /* CKCPU */ #endif /* M_I86 */ #ifdef sparc /* SUN SPARC */ #ifndef CKCPU #define CKCPU "sparc" #endif /* CKCPU */ #endif /* sparc */ #ifdef mips /* MIPS RISC processor */ #ifndef CKCPU #define CKCPU "mips" #endif /* CKCPU */ #endif /* mips */ #ifdef _IBMR2 /* IBM RS/6000 */ #ifndef CKCPU /* (what do they call the chip?) */ #define CKCPU "rs6000" #endif /* CKCPU */ #endif /* rs6000 */ #ifdef u3b5 /* WE32000 MAC-32, AT&T 3Bx */ #ifndef CKCPU #define CKCPU "u3b5" #endif /* CKCPU */ #endif /* u3b5 */ #ifdef n3b #ifndef CKCPU #define CKCPU "n3b" #endif /* CKCPU */ #endif /* n3b */ #ifdef u3b #ifndef CKCPU #define CKCPU "u3b" #endif /* CKCPU */ #endif /* u3b */ #ifdef n16 /* Encore Multimax */ #ifndef CKCPU #define CKCPU "n16" #endif /* CKCPU */ #endif /* n16 */ #ifdef u370 /* IBM 370 */ #ifndef CKCPU #define CKCPU "u370" #endif /* CKCPU */ #endif /* u370 */ #ifdef MAC /* Macintosh catch-all */ #ifndef CKCPU #define CKCPU "mc68000" #endif /* CKCPU */ #endif /* MAC */ #ifdef STRATUS #ifndef CKCPU #ifdef __I860__ #define CKCPU "I860 Family" #else #ifdef __MC68K__ #define CKCPU "MC680x0 Family" #else #define CKCPU "Stratus unknown processor" #endif /* __MC68K__ */ #endif /* __I860__ */ #endif /* CKCPU */ #endif /* STRATUS */ #ifdef COMMENT #ifndef CKCPU /* All others */ #define CKCPU "unknown" #endif /* CKCPU */ #endif /* COMMENT */ #endif /* CKUVER_H */ ckuxla.c000664 045065 024037 00001035566 14767402203 012643 0ustar00fdckermit000000 000000 #include "ckcsym.h" #include "ckcdeb.h" /* Includes... */ #include "ckcker.h" #include "ckucmd.h" #include "ckcxla.h" #include "ckcxla.h" #include "ckuusr.h" #include "ckcnet.h" /* struct sockaddr */ #include "ckcfnp.h" /* Prototypes (must be last) */ #ifdef CK_ANSIC /* prototypes for static functions - fdc 30 November 2022 */ static int jpnxas( int, int[] ); static int jpnxkn( int[], int[] ); static int jpnxkt( int, int[] ); #endif /* C_ANSIC */ #ifdef NOXFER #define zdstuff(a) #endif /* NOXFER */ #ifndef NOCSETS char *xlav = "Character Set Translation 10.0.045, 15 Apr 2023"; /* C K U X L A */ /* C-Kermit tables and functions supporting character set translation. */ /* Author: Frank da Cruz , Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 2023, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. Note: the date and version number changed in 2022 but the code hasn't been touched since 2011 - fdc, Fri Sep 23 20:15:40 2022 */ /* Character set translation data and functions */ extern int zincnt; /* File i/o macros and variables */ extern char *zinptr; extern int zoutcnt; extern char *zoutptr; extern int byteorder; extern int xfrxla; int tslevel = TS_L0; /* Transfer syntax level (0,1,2) */ int tcharset = TC_TRANSP; /* Transfer syntax character set */ int tcs_save = -1; /* For save/restore term charset */ int tcs_transp = 0; /* Term charset is TRANSPARENT flag */ #ifdef CKOUNI int tcsr = TX_8859_1; /* Remote terminal character set */ #else /* CKOUNI */ int tcsr = FC_USASCII; #endif /* CKOUNI */ int language = L_USASCII; /* Language */ #ifdef UNICODE int ucsbom = 1; /* Add BOM to new UCS files? */ int ucsorder = -1; /* Default byte order for UCS files */ int fileorder = -1; /* Byte order of current file */ /* 0 = BE, 1 = LE */ #endif /* UNICODE */ /* Default local file and terminal character set. Normally ASCII, but for some systems we know otherwise. */ int fcs_save = -1; #ifdef datageneral /* Data General AOS/VS */ int fcharset = FC_DGMCS; /* uses the DG International set */ int dcset8 = FC_DGMCS; int dcset7 = FC_USASCII; int tcsl = FC_DGMCS; #else #ifdef NEXT /* The NeXT workstation */ int fcharset = FC_NEXT; /* uses its own 8-bit set */ int dcset8 = FC_NEXT; int dcset7 = FC_USASCII; int tcsl = FC_NEXT; #else #ifdef MAC /* The Macintosh */ int fcharset = FC_APPQD; /* uses an extended version of */ int dcset8 = FC_APPQD; int dcset7 = FC_USASCII; int tcsl = FC_APPQD; /* Apple Quickdraw */ #else #ifdef AUX int fcharset = FC_APPQD; /* Ditto for Apple A/UX */ int dcset8 = FC_APPQD; int dcset7 = FC_USASCII; int tcsl = FC_APPQD; #else #ifdef AMIGA /* The Commodore Amiga */ int fcharset = FC_1LATIN; /* uses Latin-1 */ int dcset8 = FC_1LATIN; int dcset7 = FC_USASCII; int tcsl = FC_1LATIN; #else /* All others */ #ifdef CKOUNI /* OS/2 Unicode */ int fcharset = FC_1LATIN; int dcset8 = FC_1LATIN; int dcset7 = FC_USASCII; int tcsl = TX_8859_1; int prncs = TX_CP437; #else /* All others */ int fcharset = FC_USASCII; /* use ASCII by default */ int dcset8 = FC_1LATIN; /* But default 8-bit set is Latin-1 */ int dcset7 = FC_USASCII; int tcsl = FC_USASCII; int prncs = FC_CP437; #endif /* CKOUNI */ #endif /* AMIGA */ #endif /* AUX */ #endif /* MAC */ #endif /* NEXT */ #endif /* datageneral */ int s_cset = XMODE_A; /* SEND charset selection = AUTO */ int r_cset = XMODE_A; /* RECV charset selection = AUTO */ int afcset[MAXFCSETS+1]; /* Character-set associations */ int axcset[MAXTCSETS+1]; int xlatype = XLA_NONE; /* Translation type */ #ifdef UNICODE #ifdef CK_ANSIC extern int (*xl_utc[MAXTCSETS+1])(USHORT); /* Unicode to TCS */ extern int (*xl_ufc[MAXFCSETS+1])(USHORT); /* Unicode to FCS */ extern USHORT (*xl_tcu[MAXTCSETS+1])(CHAR); /* TCS to Unicode */ extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */ #else extern int (*xl_utc[MAXTCSETS+1])(); extern int (*xl_ufc[MAXFCSETS+1])(); extern USHORT (*xl_tcu[MAXTCSETS+1])(); extern USHORT (*xl_fcu[MAXFCSETS+1])(); #endif /* CK_ANSIC */ #endif /* UNICODE */ /* Bureaucracy section */ _PROTOTYP( CHAR xnel1, (CHAR c) ); /* NeXT to Latin-1 */ _PROTOTYP( CHAR xl143, (CHAR c) ); /* Latin-1 to IBM CP437 */ _PROTOTYP( CHAR xl1as, (CHAR c) ); /* Latin-1 to US ASCII */ _PROTOTYP( CHAR zl1as, (CHAR c) ); /* Latin-1 to US ASCII */ #ifdef CYRILLIC _PROTOTYP( CHAR xassk, (CHAR c) ); /* ASCII to Short KOI */ _PROTOTYP( CHAR xskcy, (CHAR c) ); /* Short KOI to Latin/Cyrillic */ #endif /* CYRILLIC */ #ifdef LATIN2 _PROTOTYP( CHAR xnel2, (CHAR c) ); /* NeXT to Latin-2 */ _PROTOTYP( CHAR xl243, (CHAR c) ); /* Latin-2 to IBM CP437 */ _PROTOTYP( CHAR xl2as, (CHAR c) ); /* Latin-2 to US ASCII */ _PROTOTYP( CHAR zl2as, (CHAR c) ); /* Latin-2 to US ASCII */ _PROTOTYP( CHAR xl2r8, (CHAR c) ); /* Latin-2 to HP */ _PROTOTYP( CHAR xl2l9, (CHAR c) ); /* Latin-2 to Latin-9 */ _PROTOTYP( CHAR xl9l2, (CHAR c) ); /* Latin-9 to Latin-2 */ _PROTOTYP( CHAR xl2mz, (CHAR c) ); /* Latin-2 to Mazovia */ _PROTOTYP( CHAR xmzl2, (CHAR c) ); /* Mazovia to Latin-2 */ _PROTOTYP( CHAR xl1mz, (CHAR c) ); /* Latin-1 to Mazovia */ _PROTOTYP( CHAR xmzl1, (CHAR c) ); /* Mazovia to Latin-1 */ _PROTOTYP( CHAR xmzl9, (CHAR c) ); /* Latin-9 to Mazovia */ _PROTOTYP( CHAR xl9mz, (CHAR c) ); /* Mazovia to Latin-9 */ #endif /* LATIN2 */ /* Transfer character-set info */ struct csinfo tcsinfo[] = { /* Name size code designator alphabet keyword */ "TRANSPARENT", 256,TC_TRANSP, "", AL_UNK, "transparent", /* 0 */ "ASCII", 128,TC_USASCII,"", AL_ROMAN,"ascii", /* 1 */ "ISO 8859-1 Latin-1",256,TC_1LATIN, "I6/100",AL_ROMAN,"latin1-iso", /* 2 */ #ifdef LATIN2 "ISO 8859-2 Latin-2",256,TC_2LATIN, "I6/101",AL_ROMAN,"latin2-iso", /* 3 */ #endif /* LATIN2 */ #ifdef CYRILLIC /* 4 */ "ISO 8859-5 Latin/Cyrillic",256,TC_CYRILL,"I6/144",AL_CYRIL,"cyrillic-iso", #endif /* CYRILLIC */ #ifdef KANJI "Japanese EUC",16384,TC_JEUC, "I14/87/13", AL_JAPAN, "euc-jp", /* 5 */ #endif /* KANJI */ #ifdef HEBREW /* 6 */ "ISO 8859-8 Latin/Hebrew",256,TC_HEBREW,"I6/138",AL_HEBREW,"hebrew-iso", #endif /* HEBREW */ #ifdef GREEK "ISO 8859-7 Latin/Greek",256,TC_GREEK,"I6/126",AL_GREEK,"greek-iso", /* 7 */ #endif /* GREEK */ "ISO 8859-15 Latin-9",256,TC_9LATIN,"I6/203",AL_ROMAN,"latin9-iso", /* 8 */ "ISO 10646 / Unicode UCS-2",64000,TC_UCS2,"I162",AL_UNIV,"ucs2", /* 9 */ "ISO 10646 / Unicode UTF-8",64000,TC_UTF8,"I190",AL_UNIV,"utf8", /* 10 */ "",0,0,"",0,"" }; int ntcsets = (sizeof(tcsinfo) / sizeof(struct csinfo)) - 1; struct keytab tcstab[] = { /* Keyword table for */ "ascii", TC_USASCII, 0, /* SET TRANSFER CHARACTER-SET */ #ifdef CYRILLIC "cyrillic-iso", TC_CYRILL, 0, #endif /* CYRILLIC */ #ifdef GREEK "elot928-greek", TC_GREEK, CM_INV, #endif /* GREEK */ #ifdef KANJI "euc-jp", TC_JEUC, 0, #endif /* KANJI */ #ifdef GREEK "greek-iso", TC_GREEK, 0, #endif /* GREEK */ #ifdef HEBREW "hebrew-iso", TC_HEBREW, 0, #endif /* HEBREW */ #ifdef UNICODE "iso-10646-ucs-2", TC_UCS2, CM_INV, /* ISO 10646 / Unicode UCS-2 */ #endif /* UNICODE */ "iso-8859-1", TC_1LATIN, CM_INV, /* ISO Latin Alphabet 1 */ "iso-8859-15", TC_9LATIN, CM_INV, /* ISO Latin Alphabet 9 (yes) */ "iso-8859-2", TC_2LATIN, CM_INV, /* ISO Latin Alphabet 2 */ #ifdef CYRILLIC "iso-8859-5", TC_CYRILL, CM_INV, /* ISO Latin/Cyrillic Alphabet */ #endif /* CYRILLIC */ #ifdef GREEK "iso-8859-7", TC_GREEK, CM_INV, /* ISO 8859-7 Latin/Greek */ #endif /* GREEK */ #ifdef HEBREW "iso-8859-8", TC_HEBREW, CM_INV, /* ISO Latin/Hebrew */ #endif /* HEBREW */ #ifdef KANJI "japanese-euc", TC_JEUC, CM_INV, #endif /* KANJI */ "l", TC_1LATIN, CM_ABR|CM_INV, "la", TC_1LATIN, CM_ABR|CM_INV, "lat", TC_1LATIN, CM_ABR|CM_INV, "lati", TC_1LATIN, CM_ABR|CM_INV, "latin", TC_1LATIN, CM_ABR|CM_INV, "latin1-iso", TC_1LATIN, 0, #ifdef LATIN2 "latin2-iso", TC_2LATIN, 0, #endif /* LATIN2 */ "latin9-iso", TC_9LATIN, 0, "transparent", TC_TRANSP, 0, #ifdef UNICODE "ucs2", TC_UCS2, 0, #endif /* UNICODE */ "us-ascii", TC_USASCII, CM_INV, "usascii", TC_USASCII, CM_INV, #ifdef UNICODE "utf-8", TC_UTF8, CM_INV, "utf8", TC_UTF8, 0, #endif /* UNICODE */ "", 0, 0 }; int ntcs = (sizeof(tcstab) / sizeof(struct keytab)) - 1; /* File character set information structure, indexed by character set code, */ /* as defined in ckuxla.h. This table must be in order of file character */ /* set number! */ struct csinfo fcsinfo[] = { /* File character set information... */ /* Descriptive Name Size Designator */ "US ASCII", 128, FC_USASCII, NULL, AL_ROMAN, "ascii", "British/UK ISO-646", 128, FC_UKASCII, NULL, AL_ROMAN, "british", "Dutch ISO-646", 128, FC_DUASCII, NULL, AL_ROMAN, "dutch", "Finnish ISO-646", 128, FC_FIASCII, NULL, AL_ROMAN, "finnish", "French ISO-646", 128, FC_FRASCII, NULL, AL_ROMAN, "french", "Canadian-French NRC", 128, FC_FCASCII, NULL, AL_ROMAN, "canadian-french", "German ISO-646", 128, FC_GEASCII, NULL, AL_ROMAN, "german", "Hungarian ISO-646", 128, FC_HUASCII, NULL, AL_ROMAN, "hungarian", "Italian ISO-646", 128, FC_ITASCII, NULL, AL_ROMAN, "italian", "Norwegian/Danish ISO-646",128,FC_NOASCII,NULL,AL_ROMAN,"norwegian/danish", "Portuguese ISO-646", 128, FC_POASCII, NULL, AL_ROMAN,"portuguese", "Spanish ISO-646", 128, FC_SPASCII, NULL, AL_ROMAN, "spanish", "Swedish ISO-646", 128, FC_SWASCII, NULL, AL_ROMAN, "swedish", "Swiss NRC", 128, FC_CHASCII, NULL, AL_ROMAN, "swiss", "ISO 8859-1 Latin-1", 256, FC_1LATIN, NULL, AL_ROMAN,"latin1-iso", "ISO 8859-2 Latin-2", 256, FC_2LATIN, NULL, AL_ROMAN,"latin2-iso", "DEC Multinational", 256, FC_DECMCS, NULL,AL_ROMAN,"dec-multinational", "NeXT Multinational", 256, FC_NEXT, NULL,AL_ROMAN,"next-multinational", "PC Code Page 437", 256, FC_CP437, NULL, AL_ROMAN,"cp437", "PC Code Page 850", 256, FC_CP850, NULL, AL_ROMAN,"cp850", "PC Code Page 852", 256, FC_CP852, NULL, AL_ROMAN,"cp852", "Apple Macintosh Latin", 256, FC_APPQD, NULL, AL_ROMAN,"macintosh-latin", "Data General International",256,FC_DGMCS,NULL,AL_ROMAN,"dg-international", "Hewlett Packard Roman8", 256, FC_HPR8, NULL, AL_ROMAN, "hp-roman8", "ISO 8859-5 Latin/Cyrillic", 256, FC_CYRILL, NULL, AL_CYRIL,"cyrillic-iso", "CP866 Cyrillic", 256, FC_CP866, NULL, AL_CYRIL,"cp866", "Short KOI", 128, FC_KOI7, NULL, AL_CYRIL,"short-koi", "Old KOI-8 Cyrillic", 256, FC_KOI8, NULL, AL_CYRIL,"koi8-cyrillic", "Japanese JIS7", 16384, FC_JIS7, NULL, AL_JAPAN, "jis7-kanji", "Japanese Shift JIS", 16384, FC_SHJIS, NULL, AL_JAPAN, "shift-jis-kanji", "Japanese EUC", 16384, FC_JEUC, NULL, AL_JAPAN, "euc-jp", "Japanese DEC Kanji", 16384, FC_JDEC, NULL, AL_JAPAN, "dec-kanji", "Hebrew-7 DEC", 128, FC_HE7, NULL, AL_HEBREW, "hebrew-7", "ISO 8859-8 Latin/Hebrew",256, FC_HEBREW, NULL, AL_HEBREW, "hebrew-iso", "CP862 Hebrew", 256, FC_CP862, NULL, AL_HEBREW, "cp862-hebrew", "ELOT 927 Greek", 128, FC_ELOT, NULL, AL_GREEK, "elot927-greek", "ISO 8859-7 Latin/Greek", 256, FC_GREEK, NULL, AL_GREEK, "greek-iso", "CP869 Greek", 256, FC_CP869, NULL, AL_GREEK, "cp869-greek", "ISO 8859-15 Latin-9", 256, FC_9LATIN, NULL, AL_ROMAN, "latin9-iso", "PC Code Page 858", 256, FC_CP850, NULL, AL_ROMAN, "cp858", "PC Code Page 855", 256, FC_CP855, NULL, AL_CYRIL, "cp855-cyrillic", "Windows Code Page 1251", 256, FC_CP1251, NULL, AL_CYRIL, "cp1251-cyrillic", "Bulgarian PC Code Page", 256, FC_BULGAR, NULL, AL_CYRIL, "bulgaria-pc", "Windows Code Page 1250", 256, FC_CP1250, NULL, AL_ROMAN, "cp1250", "Polish Mazovia PC Code Page", 256, FC_MAZOVIA, NULL, AL_ROMAN, "mazovia-pc", "ISO 10646 / Unicode UCS-2", 64000, FC_UCS2, NULL, AL_UNIV, "ucs2", "ISO 10646 / Unicode UTF-8", 64000, FC_UCS2, NULL, AL_UNIV, "utf8", "KOI8-R Russian+Boxdrawing",256, FC_KOI8R, NULL, AL_CYRIL,"koi8r", "KOI8-U Ukrainian+Boxdrawing",256,FC_KOI8U, NULL, AL_CYRIL,"koi8u", "Windows Code Page 1252", 256, FC_CP1252, NULL, AL_ROMAN, "cp1252", "",0,0,NULL,0,NULL }; /* Local file character sets */ /* Includes 7-bit National Replacement Character Sets of ISO 646 */ /* Plus ISO Latin-1, DEC Multinational Character Set (MCS), NeXT char set, */ /* Various PC and Windows code pages, etc. */ /* As of C-Kermit 9.0 MIME names are included as invisible synomyms for */ /* those character sets that have MIME names. */ struct keytab fcstab[] = { /* Keyword table for 'set file character-set' */ /* IMPORTANT: This table is replicated below as ttcstab (terminal character set table). The only differences are the addition of TRANSPARENT and the removal of the Kanji sets, which are not supported for terminal emulation. If you make changes to this table, also change ttcstab. */ /* Keyword Value Flags */ "apple-quickdraw", FC_APPQD, CM_INV, /* Apple Quickdraw */ "ascii", FC_USASCII, 0, /* ASCII */ "british", FC_UKASCII, 0, /* British NRC */ "bulgaria-pc", FC_BULGAR, 0, /* Bulgarian PC Code Page */ "canadian-french", FC_FCASCII, 0, /* French Canadian NRC */ #ifdef LATIN2 "cp1250", FC_CP1250, 0, /* Windows CP 1250 */ #endif /* LATIN2 */ #ifdef CYRILLIC "cp1251-cyrillic", FC_CP1251, 0, /* Windows CP 1251 */ #endif /* CYRILLIC */ "cp1252", FC_CP1252, 0, /* Windows CP 1252 */ "cp437", FC_CP437, 0, /* PC CP437 */ "cp850", FC_CP850, 0, /* PC CP850 */ #ifdef LATIN2 "cp852", FC_CP852, 0, /* PC CP852 */ #endif /* LATIN2 */ #ifdef CYRILLIC "cp855-cyrillic", FC_CP855, 0, /* PC CP855 */ #endif /* CYRILLIC */ "cp858", FC_CP858, 0, /* PC CP858 */ #ifdef HEBREW "cp862-hebrew", FC_CP862, 0, /* PC CP862 */ #endif /* HEBREW */ #ifdef CYRILLIC "cp866-cyrillic", FC_CP866, 0, /* CP866 Cyrillic */ #endif /* CYRILLIC */ #ifdef GREEK "cp869-greek", FC_CP869, 0, /* CP869 Greek */ #endif /* GREEK */ #ifdef CYRILLIC "cyrillic-iso", FC_CYRILL, 0, /* ISO Latin/Cyrillic Alphabet */ #endif /* CYRILLIC */ "danish", FC_NOASCII, 0, /* Norwegian and Danish NRC */ #ifdef KANJI "dec-kanji", FC_JDEC, 0, /* Japanese DEC Kanji */ #endif /* KANJI */ "dec-mcs", FC_DECMCS, CM_INV, /* DEC multinational char set */ "dec-multinational", FC_DECMCS, 0, /* DEC multinational character set */ "dg-international", FC_DGMCS, 0, /* Data General multinational */ "dutch", FC_DUASCII, 0, /* Dutch NRC */ #ifdef GREEK "elot927-greek", FC_ELOT, 0, /* ELOT 927 Greek */ "elot928-greek", FC_GREEK, 0, /* Same as ISO 8859-7 Latin/Greek */ #endif /* GREEK */ #ifdef KANJI "euc-jp", FC_JEUC, 0, /* Japanese EUC */ #endif /* KANJI */ "finnish", FC_FIASCII, 0, /* Finnish NRC */ "french", FC_FRASCII, 0, /* French NRC */ "fr-canadian", FC_FCASCII, CM_INV, /* French Canadian NRC */ "german", FC_GEASCII, 0, /* German NRC */ #ifdef GREEK "greek-iso", FC_GREEK, 0, /* ISO 8859-7 Latin/Greek */ #endif /* GREEK */ #ifdef HEBREW "he", FC_HEBREW, CM_ABR|CM_INV, "heb", FC_HEBREW, CM_ABR|CM_INV, "hebr", FC_HEBREW, CM_ABR|CM_INV, "hebre", FC_HEBREW, CM_ABR|CM_INV, "hebrew", FC_HEBREW, CM_ABR|CM_INV, "hebrew-7", FC_HE7, 0, /* DEC 7-Bit Hebrew */ "hebrew-iso", FC_HEBREW, 0, /* ISO Latin/Hebrew */ #endif /* HEBREW */ "hp-roman8", FC_HPR8, 0, /* Hewlett Packard Roman8 */ "hungarian", FC_HUASCII, 0, /* Hungarian NRC */ "ibm437", FC_CP437, CM_INV, /* PC CP437 */ "ibm850", FC_CP850, CM_INV, /* PC CP850 (not in MIME) */ #ifdef LATIN2 "ibm852", FC_CP852, CM_INV, /* PC CP852 */ #endif /* LATIN2 */ #ifdef CYRILLIC "ibm855", FC_CP855, CM_INV, /* PC CP855 */ #endif /* CYRILLIC */ "ibm858", FC_CP858, CM_INV, /* PC CP858 (not in MIME) */ #ifdef HEBREW "ibm862", FC_CP862, CM_INV, /* PC CP862 (not in MIME) */ #endif /* HEBREW */ #ifdef CYRILLIC "ibm866", FC_CP866, CM_INV, /* CP866 Cyrillic */ #endif /* CYRILLIC */ #ifdef GREEK "ibm869", FC_CP869, CM_INV, /* CP869 Greek */ #endif /* GREEK */ #ifdef UNICODE "iso-10646-ucs-2", FC_UCS2, CM_INV, /* ISO 10646 / Unicode UCS-2 */ #endif /* UNICODE */ "iso-8859-1", FC_1LATIN, CM_INV, /* ISO Latin Alphabet 1 */ "iso-8859-15", FC_9LATIN, CM_INV, /* ISO Latin Alphabet 9 (yes) */ "iso-8859-2", FC_2LATIN, CM_INV, /* ISO Latin Alphabet 2 */ #ifdef CYRILLIC "iso-8859-5", FC_CYRILL, CM_INV, /* ISO Latin/Cyrillic Alphabet */ #endif /* CYRILLIC */ #ifdef GREEK "iso-8859-7", FC_GREEK, CM_INV, /* ISO 8859-7 Latin/Greek */ #endif /* GREEK */ #ifdef HEBREW "iso-8859-8", FC_HEBREW, CM_INV, /* ISO Latin/Hebrew */ #endif /* HEBREW */ #ifdef KANJI "iso2022jp-kanji", FC_JIS7, CM_INV, /* Synonym for JIS-7 */ #endif /* KANJI */ "iso646-gb", FC_UKASCII, CM_INV, /* British NRC */ "iso646-ca", FC_FCASCII, CM_INV, /* French Canadian NRC */ "iso646-de", FC_GEASCII, CM_INV, /* German NRC */ "iso646-dk", FC_NOASCII, CM_INV, /* Norwegian and Danish NRC */ "iso646-es", FC_SPASCII, CM_INV, /* Spanish NRC */ "iso646-fi", FC_FIASCII, CM_INV, /* Finnish NRC */ "iso646-fr", FC_FRASCII, CM_INV, /* French NRC */ "iso646-hu", FC_HUASCII, CM_INV, /* Hungarian NRC */ "iso646-it", FC_ITASCII, CM_INV, /* Italian NRC */ "iso646-no", FC_NOASCII, CM_INV, /* Norwegian and Danish NRC */ "iso646-po", FC_POASCII, CM_INV, /* Portuguese NRC */ "iso646-se", FC_SWASCII, CM_INV, /* Swedish NRC */ "italian", FC_ITASCII, CM_INV, /* Italian NRC */ #ifdef KANJI "japanese-euc", FC_JEUC, CM_INV, /* Japanese EUC */ "jis7-kanji", FC_JIS7, 0, /* Japanese JIS7 7bit code */ #endif /* KANJI */ #ifdef CYRILLIC "k", FC_KOI8, CM_ABR|CM_INV, "ko", FC_KOI8, CM_ABR|CM_INV, "koi", FC_KOI8, CM_ABR|CM_INV, "koi7", FC_KOI7, 0, /* Short KOI Cyrillic */ "koi8", FC_KOI8, 0, /* Old KOI-8 Cyrillic */ "koi8-e", FC_KOI8, CM_INV, /* Old KOI-8 Cyrillic */ "koi8-cyrillic", FC_KOI8, CM_INV, "koi8-r", FC_KOI8R, CM_INV, /* KOI8-R RFC1489 */ "koi8-u", FC_KOI8U, CM_INV, /* KOI8-U RFC2319 */ "koi8r", FC_KOI8R, 0, /* KOI8-R RFC1489 */ "koi8u", FC_KOI8U, 0, /* KOI8-U RFC2319 */ #endif /* CYRILLIC */ "l", FC_1LATIN, CM_ABR|CM_INV, "la", FC_1LATIN, CM_ABR|CM_INV, "lat", FC_1LATIN, CM_ABR|CM_INV, "lati", FC_1LATIN, CM_ABR|CM_INV, "latin", FC_1LATIN, CM_ABR|CM_INV, "latin1-iso", FC_1LATIN, 0, /* ISO Latin Alphabet 1 */ #ifdef LATIN2 "latin2-iso", FC_2LATIN, 0, /* ISO Latin Alphabet 2 */ #endif /* LATIN2 */ "latin9-iso", FC_9LATIN, 0, /* ISO Latin Alphabet 9 */ "macintosh-latin", FC_APPQD, 0, /* "Extended Mac Latin" */ #ifdef LATIN2 "mazovia-pc", FC_MAZOVIA, 0, /* Polish Mazovia PC code page */ #endif /* LATIN2 */ "next-multinational", FC_NEXT, 0, /* NeXT workstation */ "norwegian", FC_NOASCII, 0, /* Norwegian and Danish NRC */ "portuguese", FC_POASCII, 0, /* Portuguese NRC */ #ifdef KANJI "shift-jis-kanji", FC_SHJIS, 0, /* Japanese Kanji Shift-JIS */ "shift_jis", FC_SHJIS, CM_INV, /* Japanese Kanji Shift-JIS */ #endif /* KANJI */ #ifdef CYRILLIC "short-koi", FC_KOI7, 0, /* Short KOI Cyrillic */ #endif /* CYRILLIC */ "spanish", FC_SPASCII, 0, /* Spanish NRC */ "swedish", FC_SWASCII, 0, /* Swedish NRC */ "swiss", FC_CHASCII, 0, /* Swiss NRC */ #ifdef UNICODE "ucs2", FC_UCS2, 0, /* ISO 10646 / Unicode UCS-2 */ #endif /* UNICODE */ "us-ascii", FC_USASCII, CM_INV, /* MIME */ "usascii", FC_USASCII, CM_INV, #ifdef UNICODE "utf-8", FC_UTF8, CM_INV, /* ISO 10646 / Unicode UTF-8 */ "utf8", FC_UTF8, 0, /* ISO 10646 / Unicode UTF-8 */ #endif /* UNICODE */ #ifdef LATIN2 "windows-1250", FC_CP1250, CM_INV, /* Windows CP 1250 */ #endif /* LATIN2 */ #ifdef CYRILLIC "windows-1251", FC_CP1251, CM_INV, /* Windows CP 1251 */ #endif /* CYRILLIC */ "windows-1252", FC_CP1252, CM_INV, /* Windows CP 1252 */ "", 0, 0 }; int nfilc = (sizeof(fcstab) / sizeof(struct keytab)) - 1; struct keytab ttcstab[] = { /* Keyword table for SET TERMINAL CHARACTER-SET */ /* IMPORTANT: This table is a replica of fcstab, immediately above, with the addition of TRANSPARENT and deletion of the Japanese sets. If you make changes to this table, make the corresponding changes to fcstab. */ /* Keyword Value Flags */ "apple-quickdraw", FC_APPQD, CM_INV, /* Apple Quickdraw */ "ascii", FC_USASCII, 0, /* ASCII */ "british", FC_UKASCII, 0, /* British NRC */ "bulgaria-pc", FC_BULGAR, 0, /* Bulgarian PC Code Page */ "canadian-french", FC_FCASCII, 0, /* French Canadian NRC */ #ifdef LATIN2 "cp1250", FC_CP1250, 0, /* Windows CP 1250 */ #endif /* LATIN2 */ #ifdef CYRILLIC "cp1251-cyrillic", FC_CP1251, 0, /* Windows CP 1251 */ #endif /* CYRILLIC */ "cp1252", FC_CP1252, 0, /* Windows CP 1252 */ "cp437", FC_CP437, 0, /* PC CP437 */ "cp850", FC_CP850, 0, /* PC CP850 */ #ifdef LATIN2 "cp852", FC_CP852, 0, /* PC CP852 */ #endif /* LATIN2 */ #ifdef CYRILLIC "cp855-cyrillic", FC_CP855, 0, /* PC CP855 */ #endif /* CYRILLIC */ "cp858", FC_CP858, 0, /* PC CP858 */ #ifdef HEBREW "cp862-hebrew", FC_CP862, 0, /* PC CP862 */ #endif /* HEBREW */ #ifdef CYRILLIC "cp866-cyrillic", FC_CP866, 0, /* CP866 Cyrillic */ #endif /* CYRILLIC */ #ifdef GREEK "cp869-greek", FC_CP869, 0, /* CP869 Greek */ #endif /* GREEK */ #ifdef CYRILLIC "cyrillic-iso", FC_CYRILL, 0, /* ISO Latin/Cyrillic Alphabet */ #endif /* CYRILLIC */ "danish", FC_NOASCII, 0, /* Norwegian and Danish NRC */ "dec-mcs", FC_DECMCS, CM_INV, /* DEC multinational char set */ "dec-multinational", FC_DECMCS, 0, /* DEC multinational character set */ "dg-international", FC_DGMCS, 0, /* Data General multinational */ "dutch", FC_DUASCII, 0, /* Dutch NRC */ #ifdef GREEK "elot927-greek", FC_ELOT, 0, /* ELOT 927 Greek */ "elot928-greek", FC_GREEK, 0, /* Same as ISO 8859-7 Latin/Greek */ #endif /* GREEK */ "finnish", FC_FIASCII, 0, /* Finnish NRC */ "french", FC_FRASCII, 0, /* French NRC */ "fr-canadian", FC_FCASCII, CM_INV, /* French Canadian NRC */ "german", FC_GEASCII, 0, /* German NRC */ #ifdef GREEK "greek-iso", FC_GREEK, 0, /* ISO 8859-7 Latin/Greek */ #endif /* GREEK */ #ifdef HEBREW "he", FC_HEBREW, CM_ABR|CM_INV, "heb", FC_HEBREW, CM_ABR|CM_INV, "hebr", FC_HEBREW, CM_ABR|CM_INV, "hebre", FC_HEBREW, CM_ABR|CM_INV, "hebrew", FC_HEBREW, CM_ABR|CM_INV, "hebrew-7", FC_HE7, 0, /* DEC 7-Bit Hebrew */ "hebrew-iso", FC_HEBREW, 0, /* ISO Latin/Hebrew */ #endif /* HEBREW */ "hp-roman8", FC_HPR8, 0, /* Hewlett Packard Roman8 */ "hungarian", FC_HUASCII, 0, /* Hungarian NRC */ "ibm437", FC_CP437, CM_INV, /* PC CP437 */ "ibm850", FC_CP850, CM_INV, /* PC CP850 (not in MIME) */ #ifdef LATIN2 "ibm852", FC_CP852, CM_INV, /* PC CP852 */ #endif /* LATIN2 */ #ifdef CYRILLIC "ibm855", FC_CP855, CM_INV, /* PC CP855 */ #endif /* CYRILLIC */ "ibm858", FC_CP858, CM_INV, /* PC CP858 (not in MIME) */ #ifdef HEBREW "ibm862", FC_CP862, CM_INV, /* PC CP862 (not in MIME) */ #endif /* HEBREW */ #ifdef CYRILLIC "ibm866", FC_CP866, CM_INV, /* CP866 Cyrillic */ #endif /* CYRILLIC */ #ifdef GREEK "ibm869", FC_CP869, CM_INV, /* CP869 Greek */ #endif /* GREEK */ #ifdef UNICODE "iso-10646-ucs-2", FC_UCS2, CM_INV, /* ISO 10646 / Unicode UCS-2 */ #endif /* UNICODE */ "iso-8859-1", FC_1LATIN, CM_INV, /* ISO Latin Alphabet 1 */ "iso-8859-15", FC_9LATIN, CM_INV, /* ISO Latin Alphabet 9 (yes) */ "iso-8859-2", FC_2LATIN, CM_INV, /* ISO Latin Alphabet 2 */ #ifdef CYRILLIC "iso-8859-5", FC_CYRILL, CM_INV, /* ISO Latin/Cyrillic Alphabet */ #endif /* CYRILLIC */ #ifdef GREEK "iso-8859-7", FC_GREEK, CM_INV, /* ISO 8859-7 Latin/Greek */ #endif /* GREEK */ #ifdef HEBREW "iso-8859-8", FC_HEBREW, CM_INV, /* ISO Latin/Hebrew */ #endif /* HEBREW */ "iso646-gb", FC_UKASCII, CM_INV, /* British NRC */ "iso646-ca", FC_FCASCII, CM_INV, /* French Canadian NRC */ "iso646-de", FC_GEASCII, CM_INV, /* German NRC */ "iso646-dk", FC_NOASCII, CM_INV, /* Norwegian and Danish NRC */ "iso646-es", FC_SPASCII, CM_INV, /* Spanish NRC */ "iso646-fi", FC_FIASCII, CM_INV, /* Finnish NRC */ "iso646-fr", FC_FRASCII, CM_INV, /* French NRC */ "iso646-hu", FC_HUASCII, CM_INV, /* Hungarian NRC */ "iso646-it", FC_ITASCII, CM_INV, /* Italian NRC */ "iso646-no", FC_NOASCII, CM_INV, /* Norwegian and Danish NRC */ "iso646-po", FC_POASCII, CM_INV, /* Portuguese NRC */ "iso646-se", FC_SWASCII, CM_INV, /* Swedish NRC */ "italian", FC_ITASCII, CM_INV, /* Italian NRC */ #ifdef CYRILLIC "k", FC_KOI8, CM_ABR|CM_INV, "ko", FC_KOI8, CM_ABR|CM_INV, "koi", FC_KOI8, CM_ABR|CM_INV, "koi7", FC_KOI7, 0, /* Short KOI Cyrillic */ "koi8", FC_KOI8, 0, /* Old KOI-8 Cyrillic */ "koi8-e", FC_KOI8, CM_INV, /* Old KOI-8 Cyrillic */ "koi8-cyrillic", FC_KOI8, CM_INV, "koi8-r", FC_KOI8R, CM_INV, /* KOI8-R RFC1489 */ "koi8-u", FC_KOI8U, CM_INV, /* KOI8-U RFC2319 */ "koi8r", FC_KOI8R, 0, /* KOI8-R RFC1489 */ "koi8u", FC_KOI8U, 0, /* KOI8-U RFC2319 */ #endif /* CYRILLIC */ "l", FC_1LATIN, CM_ABR|CM_INV, "la", FC_1LATIN, CM_ABR|CM_INV, "lat", FC_1LATIN, CM_ABR|CM_INV, "lati", FC_1LATIN, CM_ABR|CM_INV, "latin", FC_1LATIN, CM_ABR|CM_INV, "latin1-iso", FC_1LATIN, 0, /* ISO Latin Alphabet 1 */ #ifdef LATIN2 "latin2-iso", FC_2LATIN, 0, /* ISO Latin Alphabet 2 */ #endif /* LATIN2 */ "latin9-iso", FC_9LATIN, 0, /* ISO Latin Alphabet 9 */ "macintosh-latin", FC_APPQD, 0, /* "Extended Mac Latin" */ #ifdef LATIN2 "mazovia-pc", FC_MAZOVIA, 0, /* Polish Mazovia PC code page */ #endif /* LATIN2 */ "next-multinational", FC_NEXT, 0, /* NeXT workstation */ "norwegian", FC_NOASCII, 0, /* Norwegian and Danish NRC */ "portuguese", FC_POASCII, 0, /* Portuguese NRC */ #ifdef CYRILLIC "short-koi", FC_KOI7, 0, /* Short KOI Cyrillic */ #endif /* CYRILLIC */ "spanish", FC_SPASCII, 0, /* Spanish NRC */ "swedish", FC_SWASCII, 0, /* Swedish NRC */ "swiss", FC_CHASCII, 0, /* Swiss NRC */ "transparent", FC_TRANSP, 0, /* Transparent */ #ifdef UNICODE "ucs2", FC_UCS2, 0, /* ISO 10646 / Unicode UCS-2 */ #endif /* UNICODE */ "us-ascii", FC_USASCII, CM_INV, /* MIME */ "usascii", FC_USASCII, CM_INV, #ifdef UNICODE "utf-8", FC_UTF8, CM_INV, /* ISO 10646 / Unicode UTF-8 */ "utf8", FC_UTF8, 0, /* ISO 10646 / Unicode UTF-8 */ #endif /* UNICODE */ #ifdef LATIN2 "windows-1250", FC_CP1250, CM_INV, /* Windows CP 1250 */ #endif /* LATIN2 */ #ifdef CYRILLIC "windows-1251", FC_CP1251, CM_INV, /* Windows CP 1251 */ #endif /* CYRILLIC */ "windows-1252", FC_CP1252, CM_INV, /* Windows CP 1252 */ "", 0, 0 }; int ntermc = (sizeof(ttcstab) / sizeof(struct keytab)) - 1; /* This table contains the equivalent FCS number for each TCS. */ /* If the TC_xxx symbol definitions are ever changed, fix this table. */ /* Ditto if another TCS is added. */ int cseqtab[MAXTCSETS+1] = { /* TCS/FCS equivalency table */ -1, /* 0 = Transparent */ FC_USASCII, /* 1 = ASCII */ FC_1LATIN, /* 2 = Latin-1 */ FC_2LATIN, /* 3 = Latin-2 */ FC_CYRILL, /* 4 = Latin/Cyrillic */ FC_JEUC, /* 5 = Japanese EUC */ FC_HEBREW, /* 6 = Latin/Hebrew */ FC_GREEK, /* 7 = Latin/Greek */ FC_9LATIN, /* 8 = Latin-9 */ FC_UCS2, /* 9 = UCS-2 */ FC_UTF8 /* 10 = UTF-8 */ }; /* Languages: This table allows C-Kermit to have a SET LANGUAGE command to apply special language-specific rules when translating from a character set that contains national characters into plain ASCII, like German umlaut-a becomes ae. Originally, I thought it would be a good idea to let SET LANGUAGE also select an appropriate FILE CHARACTER-SET and TRANSFER CHARACTER-SET automatically, and these are included in the langinfo structure. Later I realized that this was a bad idea. Any particular language (e.g. Dutch) can be represented by many different and incompatible character sets. (But we could use the new (1998) ASSOCIATE command for this...) */ struct langinfo langs[] = { /* Language code File Charset Xfer Charset Name */ L_USASCII, FC_USASCII, TC_USASCII, "ASCII (American English)", L_DANISH, FC_NOASCII, TC_1LATIN, "Danish", L_DUTCH, FC_DUASCII, TC_1LATIN, "Dutch", L_FINNISH, FC_FIASCII, TC_1LATIN, "Finnish", L_FRENCH, FC_FRASCII, TC_1LATIN, "French", L_GERMAN, FC_GEASCII, TC_1LATIN, "German", #ifdef GREEK L_GREEK, FC_GREEK, TC_GREEK, "Greek", #endif /* GREEK */ #ifdef HEBREW L_HEBREW, FC_HEBREW, TC_HEBREW, "Hebrew", #endif /* HEBREW */ L_HUNGARIAN, FC_HUASCII, TC_2LATIN, "Hungarian", L_ICELANDIC, FC_USASCII, TC_1LATIN, "Icelandic", L_ITALIAN, FC_ITASCII, TC_1LATIN, "Italian", #ifdef KANJI L_JAPANESE, FC_JEUC, TC_JEUC, "Japanese", #endif /* KANJI */ L_NORWEGIAN, FC_NOASCII, TC_1LATIN, "Norwegian", L_PORTUGUESE, FC_POASCII, TC_1LATIN, "Portuguese", #ifdef CYRILLIC L_RUSSIAN, FC_CP866, TC_CYRILL, "Russian", #endif /* CYRILLIC */ L_SPANISH, FC_SPASCII, TC_1LATIN, "Spanish", L_SWEDISH, FC_SWASCII, TC_1LATIN, "Swedish", L_SWISS, FC_CHASCII, TC_1LATIN, "Swiss" }; int nlangs = (sizeof(langs) / sizeof(struct langinfo)); /* Keyword table for the SET LANGUAGE command. Only a few of these (German, Scandinavian, etc) actually do anything. The language is used to invoke special translation rules when converting from an 8-bit character set to ASCII; for example, German u-diaeresis becomes "ue", Dutch y-diaeresis becomes "ij". Languages without associated rules are invisible (CM_INV). */ struct keytab lngtab[] = { "ascii", L_USASCII, CM_INV, "danish", L_DANISH, 0, "dutch", L_DUTCH, 0, "english", L_USASCII, CM_INV, "finnish", L_FINNISH, 0, "french", L_FRENCH, 0, "german", L_GERMAN, 0, #ifdef GREEK "greek", L_GREEK, CM_INV, #endif /* GREEK */ #ifdef HEBREW "hebrew", L_HEBREW, CM_INV, #endif /* HEBREW */ "hungarian", L_HUNGARIAN, CM_INV, "icelandic", L_ICELANDIC, 0, "italian", L_ITALIAN, CM_INV, #ifdef KANJI "japanese", L_JAPANESE, CM_INV, #endif /* KANJI */ "norwegian", L_NORWEGIAN, 0, "none", L_USASCII, 0, "portuguese", L_PORTUGUESE, CM_INV, #ifdef CYRILLIC "russian", L_RUSSIAN, 0, #endif /* CYRILLIC */ "spanish", L_SPANISH, CM_INV, "swedish", L_SWEDISH, 0, #ifdef CYRILLIC "ukrainian", L_RUSSIAN, 0, #endif /* CYRILLIC */ "", 0, 0 }; int nlng = (sizeof(lngtab) / sizeof(struct keytab)) - 1; /* how many */ /* Translation tables ... */ /* For each pair of (transfer,file) character sets, we need two translation functions, one for sending, one for receiving. */ /* Here is the first table, Latin-1 to ASCII, fully annotated... This one is absolutely NOT invertible, since we're going from an 8-bit set to a 7-bit set. Accented letters are mapped to unaccented equivalents, C1 control characters are all translated to "?", etc. */ CONST CHAR yl1as[] = { /* ISO 8859-1 Latin Alphabet 1 to US ASCII */ /* Source character Description => Translation */ /* Dec row/col Set */ 0, /* 000 00/00 C0 NUL Ctrl-@ => (self) */ 1, /* 001 00/01 C0 SOH Ctrl-A => (self) */ 2, /* 002 00/02 C0 STX Ctrl-B => (self) */ 3, /* 003 00/03 C0 ETX Ctrl-C => (self) */ 4, /* 004 00/04 C0 EOT Ctrl-D => (self) */ 5, /* 005 00/05 C0 ENQ Ctrl-E => (self) */ 6, /* 006 00/06 C0 ACK Ctrl-F => (self) */ 7, /* 007 00/07 C0 BEL Ctrl-G => (self) */ 8, /* 008 00/08 C0 BS Ctrl-H => (self) */ 9, /* 009 00/09 C0 HT Ctrl-I => (self) */ 10, /* 010 00/10 C0 LF Ctrl-J => (self) */ 11, /* 011 00/11 C0 VT Ctrl-K => (self) */ 12, /* 012 00/12 C0 FF Ctrl-L => (self) */ 13, /* 013 00/13 C0 CR Ctrl-M => (self) */ 14, /* 014 00/14 C0 SO Ctrl-N => (self) */ 15, /* 015 00/15 C0 SI Ctrl-O => (self) */ 16, /* 016 01/00 C0 DLE Ctrl-P => (self) */ 17, /* 017 01/01 C0 DC1 Ctrl-Q => (self) */ 18, /* 018 01/02 C0 DC2 Ctrl-R => (self) */ 19, /* 019 01/03 C0 DC3 Ctrl-S => (self) */ 20, /* 020 01/04 C0 DC4 Ctrl-T => (self) */ 21, /* 021 01/05 C0 NAK Ctrl-U => (self) */ 22, /* 022 01/06 C0 SYN Ctrl-V => (self) */ 23, /* 023 01/07 C0 ETB Ctrl-W => (self) */ 24, /* 024 01/08 C0 CAN Ctrl-X => (self) */ 25, /* 025 01/09 C0 EM Ctrl-Y => (self) */ 26, /* 026 01/10 C0 SUB Ctrl-Z => (self) */ 27, /* 027 01/11 C0 ESC Ctrl-[ => (self) */ 28, /* 028 01/12 C0 FS Ctrl-\ => (self) */ 29, /* 029 01/13 C0 GS Ctrl-] => (self) */ 30, /* 030 01/14 C0 RS Ctrl-^ => (self) */ 31, /* 031 01/15 C0 US Ctrl-_ => (self) */ 32, /* 032 02/00 SP Space => (self) */ 33, /* 033 02/01 G0 ! Exclamation mark => (self) */ 34, /* 034 02/02 G0 " Doublequote => (self) */ 35, /* 035 02/03 G0 # Number sign => (self) */ 36, /* 036 02/04 G0 $ Dollar sign => (self) */ 37, /* 037 02/05 G0 % Percent sign => (self) */ 38, /* 038 02/06 G0 & Ampersand => (self) */ 39, /* 039 02/07 G0 ' Apostrophe => (self) */ 40, /* 040 02/08 G0 ( Left parenthesis => (self) */ 41, /* 041 02/09 G0 ) Right parenthesis => (self) */ 42, /* 042 02/10 G0 * Asterisk => (self) */ 43, /* 043 02/11 G0 + Plus sign => (self) */ 44, /* 044 02/12 G0 , Comma => (self) */ 45, /* 045 02/13 G0 - Hyphen, minus sign => (self) */ 46, /* 046 02/14 G0 . Period, full stop => (self) */ 47, /* 047 02/15 G0 / Slash, solidus => (self) */ 48, /* 048 03/00 G0 0 Digit 0 => (self) */ 49, /* 049 03/01 G0 1 Digit 1 => (self) */ 50, /* 050 03/02 G0 2 Digit 2 => (self) */ 51, /* 051 03/03 G0 3 Digit 3 => (self) */ 52, /* 052 03/04 G0 4 Digit 4 => (self) */ 53, /* 053 03/05 G0 5 Digit 5 => (self) */ 54, /* 054 03/06 G0 6 Digit 6 => (self) */ 55, /* 055 03/07 G0 7 Digit 7 => (self) */ 56, /* 056 03/08 G0 8 Digit 8 => (self) */ 57, /* 057 03/09 G0 9 Digit 9 => (self) */ 58, /* 058 03/10 G0 : Colon => (self) */ 59, /* 059 03/11 G0 ; Semicolon => (self) */ 60, /* 060 03/12 G0 < Less-than sign => (self) */ 61, /* 061 03/13 G0 = Equals sign => (self) */ 62, /* 062 03/14 G0 > Greater-than sign => (self) */ 63, /* 063 03/15 G0 ? Question mark => (self) */ 64, /* 064 04/00 G0 @ Commercial at sign => (self) */ 65, /* 065 04/01 G0 A Letter A => (self) */ 66, /* 066 04/02 G0 B Letter B => (self) */ 67, /* 067 04/03 G0 C Letter C => (self) */ 68, /* 068 04/04 G0 D Letter D => (self) */ 69, /* 069 04/05 G0 E Letter E => (self) */ 70, /* 070 04/06 G0 F Letter F => (self) */ 71, /* 071 04/07 G0 G Letter G => (self) */ 72, /* 072 04/08 G0 H Letter H => (self) */ 73, /* 073 04/09 G0 I Letter I => (self) */ 74, /* 074 04/10 G0 J Letter J => (self) */ 75, /* 075 04/11 G0 K Letter K => (self) */ 76, /* 076 04/12 G0 L Letter L => (self) */ 77, /* 077 04/13 G0 M Letter M => (self) */ 78, /* 078 04/14 G0 N Letter N => (self) */ 79, /* 079 04/15 G0 O Letter O => (self) */ 80, /* 080 05/00 G0 P Letter P => (self) */ 81, /* 081 05/01 G0 Q Letter Q => (self) */ 82, /* 082 05/02 G0 R Letter R => (self) */ 83, /* 083 05/03 G0 S Letter S => (self) */ 84, /* 084 05/04 G0 T Letter T => (self) */ 85, /* 085 05/05 G0 U Letter U => (self) */ 86, /* 086 05/06 G0 V Letter V => (self) */ 87, /* 087 05/07 G0 W Letter W => (self) */ 88, /* 088 05/08 G0 X Letter X => (self) */ 89, /* 089 05/09 G0 Y Letter Y => (self) */ 90, /* 090 05/10 G0 Z Letter Z => (self) */ 91, /* 091 05/11 G0 [ Left square bracket => (self) */ 92, /* 092 05/12 G0 \ Reverse slash => (self) */ 93, /* 093 05/13 G0 ] Right square bracket => (self) */ 94, /* 094 05/14 G0 ^ Circumflex accent => (self) */ 95, /* 095 05/15 G0 _ Underline, low line => (self) */ 96, /* 096 06/00 G0 ` Grave accent => (self) */ 97, /* 097 06/01 G0 a Letter a => (self) */ 98, /* 098 06/02 G0 b Letter b => (self) */ 99, /* 099 06/03 G0 c Letter c => (self) */ 100, /* 100 06/04 G0 d Letter d => (self) */ 101, /* 101 06/05 G0 e Letter e => (self) */ 102, /* 102 06/06 G0 f Letter f => (self) */ 103, /* 103 06/07 G0 g Letter g => (self) */ 104, /* 104 06/08 G0 h Letter h => (self) */ 105, /* 105 06/09 G0 i Letter i => (self) */ 106, /* 106 06/10 G0 j Letter j => (self) */ 107, /* 107 06/11 G0 k Letter k => (self) */ 108, /* 108 06/12 G0 l Letter l => (self) */ 109, /* 109 06/13 G0 m Letter m => (self) */ 110, /* 110 06/14 G0 n Letter n => (self) */ 111, /* 111 06/15 G0 o Letter o => (self) */ 112, /* 112 07/00 G0 p Letter p => (self) */ 113, /* 113 07/01 G0 q Letter q => (self) */ 114, /* 114 07/02 G0 r Letter r => (self) */ 115, /* 115 07/03 G0 s Letter s => (self) */ 116, /* 116 07/04 G0 t Letter t => (self) */ 117, /* 117 07/05 G0 u Letter u => (self) */ 118, /* 118 07/06 G0 v Letter v => (self) */ 119, /* 119 07/07 G0 w Letter w => (self) */ 120, /* 120 07/08 G0 x Letter x => (self) */ 121, /* 121 07/09 G0 y Letter y => (self) */ 122, /* 122 07/10 G0 z Letter z => (self) */ 123, /* 123 07/11 G0 { Left curly bracket => (self) */ 124, /* 124 07/12 G0 | Vertical bar => (self) */ 125, /* 125 07/13 G0 } Right curly bracket => (self) */ 126, /* 126 07/14 G0 ~ Tilde => (self) */ 127, /* 127 07/15 DEL Delete, Rubout => (self) */ UNK, /* 128 08/00 C1 => UNK */ UNK, /* 129 08/01 C1 => UNK */ UNK, /* 130 08/02 C1 => UNK */ UNK, /* 131 08/03 C1 => UNK */ UNK, /* 132 08/04 C1 IND => UNK */ UNK, /* 133 08/05 C1 NEL => UNK */ UNK, /* 134 08/06 C1 SSA => UNK */ UNK, /* 135 08/07 C1 ESA => UNK */ UNK, /* 136 08/08 C1 HTS => UNK */ UNK, /* 137 08/09 C1 => UNK */ UNK, /* 138 08/10 C1 => UNK */ UNK, /* 139 08/11 C1 => UNK */ UNK, /* 140 08/12 C1 => UNK */ UNK, /* 141 08/13 C1 RI => UNK */ UNK, /* 142 08/14 C1 SS2 => UNK */ UNK, /* 143 08/15 C1 SS3 => UNK */ UNK, /* 144 09/00 C1 DCS => UNK */ UNK, /* 145 09/01 C1 => UNK */ UNK, /* 146 09/02 C1 => UNK */ UNK, /* 147 09/03 C1 STS => UNK */ UNK, /* 148 09/04 C1 => UNK */ UNK, /* 149 09/05 C1 => UNK */ UNK, /* 150 09/06 C1 SPA => UNK */ UNK, /* 151 09/07 C1 EPA => UNK */ UNK, /* 152 09/08 C1 => UNK */ UNK, /* 153 09/09 C1 => UNK */ UNK, /* 154 09/10 C1 => UNK */ UNK, /* 155 09/11 C1 CSI => UNK */ UNK, /* 156 09/12 C1 ST => UNK */ UNK, /* 157 09/13 C1 OSC => UNK */ UNK, /* 158 09/14 C1 PM => UNK */ UNK, /* 159 09/15 C1 APC => UNK */ 32, /* 160 10/00 G1 No-break space => SP */ 33, /* 161 10/01 G1 Inverted exclamation => ! */ 99, /* 162 10/02 G1 Cent sign => c */ 35, /* 163 10/03 G1 Pound sign => # */ 36, /* 164 10/04 G1 Currency sign => $ */ 89, /* 165 10/05 G1 Yen sign => Y */ 124, /* 166 10/06 G1 Broken bar => | */ 80, /* 167 10/07 G1 Paragraph sign => P */ 34, /* 168 10/08 G1 Diaeresis => " */ 67, /* 169 10/09 G1 Copyright sign => C */ 97, /* 170 10/10 G1 Feminine ordinal => a */ 34, /* 171 10/11 G1 Left angle quotation => " */ 126, /* 172 10/12 G1 Not sign => ~ */ 45, /* 173 10/13 G1 Soft hyphen => - */ 82, /* 174 10/14 G1 Registered trade mark => R */ 95, /* 175 10/15 G1 Macron => _ */ 111, /* 176 11/00 G1 Degree sign, ring above => o */ UNK, /* 177 11/01 G1 Plus-minus sign => UNK */ 50, /* 178 11/02 G1 Superscript two => 2 */ 51, /* 179 11/03 G1 Superscript three => 3 */ 39, /* 180 11/04 G1 Acute accent => ' */ 117, /* 181 11/05 G1 Micro sign => u */ 45, /* 182 11/06 G1 Pilcrow sign => - */ 45, /* 183 11/07 G1 Middle dot => - */ 44, /* 184 11/08 G1 Cedilla => , */ 49, /* 185 11/09 G1 Superscript one => 1 */ 111, /* 186 11/10 G1 Masculine ordinal => o */ 34, /* 187 11/11 G1 Right angle quotation => " */ UNK, /* 188 11/12 G1 One quarter => UNK */ UNK, /* 189 11/13 G1 One half => UNK */ UNK, /* 190 11/14 G1 Three quarters => UNK */ 63, /* 191 11/15 G1 Inverted question mark => ? */ 65, /* 192 12/00 G1 A grave => A */ 65, /* 193 12/01 G1 A acute => A */ 65, /* 194 12/02 G1 A circumflex => A */ 65, /* 195 12/03 G1 A tilde => A */ 65, /* 196 12/04 G1 A diaeresis => A */ 65, /* 197 12/05 G1 A ring above => A */ 65, /* 198 12/06 G1 A with E => A */ 67, /* 199 12/07 G1 C Cedilla => C */ 69, /* 200 12/08 G1 E grave => E */ 69, /* 201 12/09 G1 E acute => E */ 69, /* 202 12/10 G1 E circumflex => E */ 69, /* 203 12/11 G1 E diaeresis => E */ 73, /* 204 12/12 G1 I grave => I */ 73, /* 205 12/13 G1 I acute => I */ 73, /* 206 12/14 G1 I circumflex => I */ 73, /* 207 12/15 G1 I diaeresis => I */ 68, /* 208 13/00 G1 Icelandic Eth => D */ 78, /* 209 13/01 G1 N tilde => N */ 79, /* 210 13/02 G1 O grave => O */ 79, /* 211 13/03 G1 O acute => O */ 79, /* 212 13/04 G1 O circumflex => O */ 79, /* 213 13/05 G1 O tilde => O */ 79, /* 214 13/06 G1 O diaeresis => O */ 120, /* 215 13/07 G1 Multiplication sign => x */ 79, /* 216 13/08 G1 O oblique stroke => O */ 85, /* 217 13/09 G1 U grave => U */ 85, /* 218 13/10 G1 U acute => U */ 85, /* 219 13/11 G1 U circumflex => U */ 85, /* 220 13/12 G1 U diaeresis => U */ 89, /* 221 13/13 G1 Y acute => Y */ 84, /* 222 13/14 G1 Icelandic Thorn => T */ 115, /* 223 13/15 G1 German sharp s => s */ 97, /* 224 14/00 G1 a grave => a */ 97, /* 225 14/01 G1 a acute => a */ 97, /* 226 14/02 G1 a circumflex => a */ 97, /* 227 14/03 G1 a tilde => a */ 97, /* 228 14/04 G1 a diaeresis => a */ 97, /* 229 14/05 G1 a ring above => a */ 97, /* 230 14/06 G1 a with e => a */ 99, /* 231 14/07 G1 c cedilla => c */ 101, /* 232 14/08 G1 e grave => e */ 101, /* 233 14/09 G1 e acute => e */ 101, /* 234 14/10 G1 e circumflex => e */ 101, /* 235 14/11 G1 e diaeresis => e */ 105, /* 236 14/12 G1 i grave => i */ 105, /* 237 14/13 G1 i acute => i */ 105, /* 238 14/14 G1 i circumflex => i */ 105, /* 239 14/15 G1 i diaeresis => i */ 100, /* 240 15/00 G1 Icelandic eth => d */ 110, /* 241 15/01 G1 n tilde => n */ 111, /* 242 15/02 G1 o grave => o */ 111, /* 243 15/03 G1 o acute => o */ 111, /* 244 15/04 G1 o circumflex => o */ 111, /* 245 15/05 G1 o tilde => o */ 111, /* 246 15/06 G1 o diaeresis => o */ 47, /* 247 15/07 G1 Division sign => / */ 111, /* 248 15/08 G1 o oblique stroke => o */ 117, /* 249 15/09 G1 u grave => u */ 117, /* 250 15/10 G1 u acute => u */ 117, /* 251 15/11 G1 u circumflex => u */ 117, /* 252 15/12 G1 u diaeresis => u */ 121, /* 253 15/13 G1 y acute => y */ 116, /* 254 15/14 G1 Icelandic thorn => t */ 121 /* 255 15/15 G1 y diaeresis => y */ }; /* Translation tables for ISO Latin Alphabet 1 to local file character sets */ /* Most of the remaining tables are not annotated like the one above, because the size of the resulting source file would be ridiculous. Each row in the following tables corresponds to a column of ISO 8859-1. */ CONST CHAR yl185[] = { /* ISO 8859-1 Latin Alphabet 1 (Latin-1) to IBM Code Page 850 */ /* This is based on IBM's official invertible translation. Reference: IBM Character Data Representation Architecture (CDRA), Level 1, Registry, SC09-1291-00 (1990), p.152. (Note: Latin-1 is IBM Code Page 00819.) Note: IBM's bizarre rearrangement of C0 controls and DEL has been undone in this table. */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 186, 205, 201, 187, 200, 188, 204, 185, 203, 202, 206, 223, 220, 219, 254, 242, 179, 196, 218, 191, 192, 217, 195, 180, 194, 193, 197, 176, 177, 178, 213, 159, 255, 173, 189, 156, 207, 190, 221, 245, 249, 184, 166, 174, 170, 240, 169, 238, 248, 241, 253, 252, 239, 230, 244, 250, 247, 251, 167, 175, 172, 171, 243, 168, 183, 181, 182, 199, 142, 143, 146, 128, 212, 144, 210, 211, 222, 214, 215, 216, 209, 165, 227, 224, 226, 229, 153, 158, 157, 235, 233, 234, 154, 237, 232, 225, 133, 160, 131, 198, 132, 134, 145, 135, 138, 130, 136, 137, 141, 161, 140, 139, 208, 164, 149, 162, 147, 228, 148, 246, 155, 151, 163, 150, 129, 236, 231, 152 }; CONST CHAR y85l1[] = { /* IBM Code Page 850 to Latin-1 */ /* This is from IBM CDRA page 153. It is the inverse of yl185[]. As of edit 183, this table is no longer pure CDRA. The translations involving C0 controls and DEL have been removed. */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197, 201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 248, 163, 216, 215, 159, 225, 237, 243, 250, 241, 209, 170, 186, 191, 174, 172, 189, 188, 161, 171, 187, 155, 156, 157, 144, 151, 193, 194, 192, 169, 135, 128, 131, 133, 162, 165, 147, 148, 153, 152, 150, 145, 154, 227, 195, 132, 130, 137, 136, 134, 129, 138, 164, 240, 208, 202, 203, 200, 158, 205, 206, 207, 149, 146, 141, 140, 166, 204, 139, 211, 223, 212, 210, 245, 213, 181, 254, 222, 218, 219, 217, 253, 221, 175, 180, 173, 177, 143, 190, 182, 167, 247, 184, 176, 168, 183, 185, 179, 178, 142, 160 }; #ifdef COMMENT CONST CHAR yl1r8[] = { /* Latin-1 to Hewlett Packard Roman8 */ /* This is HP's official translation, straight from iconv */ /* It is NOT invertible. */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 184, 191, 187, 186, 188, 124, 189, 171, 99, 249, 251, 126, 45, 82, 176, 179, 254, 50, 51, 168, 243, 244, 242, 44, 49, 250, 253, 247, 248, 245, 185, 161, 224, 162, 225, 216, 208, 211, 180, 163, 220, 164, 165, 230, 229, 166, 167, 227, 182, 232, 231, 223, 233, 218, 120, 210, 173, 237, 174, 219, 177, 240, 222, 200, 196, 192, 226, 204, 212, 215, 181, 201, 197, 193, 205, 217, 213, 209, 221, 228, 183, 202, 198, 194, 234, 206, 47, 214, 203, 199, 195, 207, 178, 241, 239 }; CONST CHAR yr8l1[] = { /* Hewlett Packard Roman8 to Latin-1 */ /* This is HP's official translation, straight from iconv */ /* It is NOT invertible. */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 192, 194, 200, 202, 203, 206, 207, 180, 96, 94, 168, 126, 217, 219, 163, 175, 221, 253, 176, 199, 231, 209, 241, 161, 191, 164, 163, 165, 167, 102, 162, 226, 234, 244, 251, 225, 233, 243, 250, 224, 232, 242, 249, 228, 235, 246, 252, 197, 238, 216, 198, 229, 237, 248, 230, 196, 236, 214, 220, 201, 239, 223, 212, 193, 195, 227, 208, 240, 205, 204, 211, 210, 213, 245, 83, 115, 218, 89, 255, 222, 254, 183, 181, 182, 190, 45, 188, 189, 170, 186, 171, 42, 187, 177, 160 }; #else /* !COMMENT */ /* This is an invertible mapping, approved by HP in January 1994. */ CONST CHAR yl1r8[] = { /* ISO Latin-1 to HP Roman8, Invertible */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 184, 191, 187, 186, 188, 169, 189, 171, 170, 249, 251, 172, 175, 190, 176, 179, 254, 235, 236, 168, 243, 244, 242, 238, 246, 250, 253, 247, 248, 245, 185, 161, 224, 162, 225, 216, 208, 211, 180, 163, 220, 164, 165, 230, 229, 166, 167, 227, 182, 232, 231, 223, 233, 218, 252, 210, 173, 237, 174, 219, 177, 240, 222, 200, 196, 192, 226, 204, 212, 215, 181, 201, 197, 193, 205, 217, 213, 209, 221, 228, 183, 202, 198, 194, 234, 206, 255, 214, 203, 199, 195, 207, 178, 241, 239 }; CONST CHAR yr8l1[] = { /* HP Roman8 to ISO Latin-1, Invertible */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 192, 194, 200, 202, 203, 206, 207, 180, 166, 169, 168, 172, 217, 219, 173, 175, 221, 253, 176, 199, 231, 209, 241, 161, 191, 164, 163, 165, 167, 174, 162, 226, 234, 244, 251, 225, 233, 243, 250, 224, 232, 242, 249, 228, 235, 246, 252, 197, 238, 216, 198, 229, 237, 248, 230, 196, 236, 214, 220, 201, 239, 223, 212, 193, 195, 227, 208, 240, 205, 204, 211, 210, 213, 245, 178, 179, 218, 184, 255, 222, 254, 183, 181, 182, 190, 185, 188, 189, 170, 186, 171, 215, 187, 177, 247 }; #endif /* COMMENT */ CONST CHAR yl143[] = { /* Latin-1 to IBM Code Page 437 */ /* Although the IBM CDRA does not include an official translation between CP437 and ISO Latin Alphabet 1, it does include an official, invertible translation between CP437 and CP850 (page 196), and another from CP850 to Latin-1 (CP819) (page 153). This translation was obtained with a two-step process based on those tables. As of edit 183, the translation is modified to leave C0 controls alone. */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 186, 205, 201, 187, 200, 188, 204, 185, 203, 202, 206, 223, 220, 219, 254, 242, 179, 196, 218, 191, 192, 217, 195, 180, 194, 193, 197, 176, 177, 178, 213, 159, 255, 173, 155, 156, 207, 157, 221, 245, 249, 184, 166, 174, 170, 240, 169, 238, 248, 241, 253, 252, 239, 230, 244, 250, 247, 251, 167, 175, 172, 171, 243, 168, 183, 181, 182, 199, 142, 143, 146, 128, 212, 144, 210, 211, 222, 214, 215, 216, 209, 165, 227, 224, 226, 229, 153, 158, 190, 235, 233, 234, 154, 237, 232, 225, 133, 160, 131, 198, 132, 134, 145, 135, 138, 130, 136, 137, 141, 161, 140, 139, 208, 164, 149, 162, 147, 228, 148, 246, 189, 151, 163, 150, 129, 236, 231, 152 }; CONST CHAR y43l1[] = { /* IBM Code Page 437 to Latin-1 */ /* This table is the inverse of yl143[]. */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197, 201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 162, 163, 165, 215, 159, 225, 237, 243, 250, 241, 209, 170, 186, 191, 174, 172, 189, 188, 161, 171, 187, 155, 156, 157, 144, 151, 193, 194, 192, 169, 135, 128, 131, 133, 248, 216, 147, 148, 153, 152, 150, 145, 154, 227, 195, 132, 130, 137, 136, 134, 129, 138, 164, 240, 208, 202, 203, 200, 158, 205, 206, 207, 149, 146, 141, 140, 166, 204, 139, 211, 223, 212, 210, 245, 213, 181, 254, 222, 218, 219, 217, 253, 221, 175, 180, 173, 177, 143, 190, 182, 167, 247, 184, 176, 168, 183, 185, 179, 178, 142, 160 }; CONST CHAR yl1aq[] = { /* Latin-1 to Extended Mac Latin (based on Apple QuickDraw) */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 182, 183, 184, 185, 189, 196, 197, 198, 206, 207, 210, 211, 217, 218, 195, 212, 209, 215, 213, 226, 227, 228, 240, 245, 246, 247, 249, 250, 251, 253, 254, 255, 202, 193, 162, 163, 219, 180, 201, 164, 172, 169, 187, 199, 194, 208, 168, 248, 161, 177, 170, 173, 171, 181, 166, 225, 252, 176, 188, 200, 178, 179, 186, 192, 203, 231, 229, 204, 128, 129, 174, 130, 233, 131, 230, 232, 237, 234, 235, 236, 220, 132, 241, 238, 239, 205, 133, 165, 175, 244, 242, 243, 134, 160, 222, 167, 136, 135, 137, 139, 138, 140, 190, 141, 143, 142, 144, 145, 147, 146, 148, 149, 221, 150, 152, 151, 153, 155, 154, 214, 191, 157, 156, 158, 159, 224, 223, 216 }; CONST CHAR yl1du[] = { /* Latin-1 to Dutch ISO 646 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, UNK, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, 39, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 32, 33, UNK, 35, 124, UNK, UNK, 93, 123, 67, UNK, 34, UNK, 45, 82, UNK, 91, UNK, UNK, UNK, 126, 117, UNK, UNK, 44, UNK, UNK, 34, 125, 92, 64, 63, 65, 65, 65, 65, 91, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73, UNK, 78, 79, 79, 79, 79, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115, 97, 97, 97, 97, 97, 97, 97, 99, 101, 101, 101, 101, 105, 105, 105, 105, UNK, 110, 111, 111, 111, 111, 111, 47, 111, 117, 117, 117, 117, 121, UNK, 91 }; CONST CHAR yl1fi[] = { /* Latin-1 to Finnish ISO NRC (*not* ISO 646) */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, UNK, 95, UNK, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 32, 33, UNK, UNK, UNK, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK, UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63, 65, 65, 65, 65, 91, 93, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73, UNK, 78, 79, 79, 79, 79, 92, 120, 79, 85, 85, 85, 94, 89, UNK, 115, 97, 97, 97, 97, 123, 125, 97, 99, 101, 96, 101, 101, 105, 105, 105, 105, UNK, 110, 111, 111, 111, 111, 124, 47, 111, 117, 117, 117, 126, 121, UNK, 121 }; CONST CHAR yl1fr[] = { /* Latin-1 to French ISO 646 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, UNK, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 32, 33, UNK, 35, UNK, UNK, UNK, 93, 34, 67, UNK, 34, UNK, 45, 82, UNK, 91, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63, 65, 65, 65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73, UNK, 78, 79, 79, 79, 79, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115, 64, 97, 97, 97, 97, 97, 97, 92, 125, 123, 101, 101, 105, 105, 105, 105, UNK, 110, 111, 111, 111, 111, 111, 47, 111, 124, 117, 117, 117, 121, UNK, 121 }; CONST CHAR yl1fc[] = { /* Latin-1 to French-Canadian ISO 646 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, UNK, 95, UNK, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 32, 33, UNK, UNK, UNK, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK, UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63, 65, 65, 65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73, UNK, 78, 79, 79, 79, 79, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115, 64, 97, 91, 97, 97, 97, 97, 92, 125, 123, 93, 101, 105, 105, 94, 105, UNK, 110, 111, 111, 96, 111, 111, 47, 111, 124, 117, 126, 117, 121, UNK, 121 }; CONST CHAR yl1ge[] = { /* Latin-1 to German ISO 646 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 32, 33, UNK, UNK, UNK, UNK, UNK, 64, 34, 67, UNK, 34, UNK, 45, 82, UNK, UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63, 65, 65, 65, 65, 91, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73, UNK, 78, 79, 79, 79, 79, 92, 120, 79, 85, 85, 85, 93, 89, UNK, 126, 97, 97, 97, 97, 123, 97, 97, 99, 101, 101, 101, 101, 105, 105, 105, 105, UNK, 110, 111, 111, 111, 111, 124, 47, 111, 117, 117, 117, 125, 121, UNK, 121 }; CONST CHAR yl1hu[] = { /* Latin-1 to Hungarian ISO-646 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 32, 33, UNK, UNK, 36, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK, UNK, 64, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63, 65, 65, 65, 65, 65, 65, 65, 67, 69, 91, 69, 69, 73, 73, 73, 73, UNK, 78, 79, 79, 79, 79, 92, 120, 79, 85, 85, 85, 93, 89, UNK, 115, 97, 96, 97, 97, 97, 97, 97, 99, 101, 123, 101, 101, 105, 105, 105, 105, UNK, 110, 111, 111, 111, 111, 124, 47, 111, 117, 117, 117, 125, 121, UNK, 121 }; CONST CHAR yl1it[] = { /* Latin-1 to Italian ISO 646 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, UNK, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95, UNK, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 32, 33, UNK, 35, UNK, UNK, UNK, 64, 34, 67, UNK, 34, UNK, 45, 82, UNK, 91, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63, 65, 65, 65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73, UNK, 78, 79, 79, 79, 79, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115, 123, 97, 97, 97, 97, 97, 97, 92, 125, 93, 101, 101, 126, 105, 105, 105, UNK, 110, 124, 111, 111, 111, 111, 47, 111, 96, 117, 117, 117, 121, UNK, 121 }; CONST CHAR yl1ne[] = { /* Latin-1 to NeXT */ /* NEED TO MAKE THIS ONE INVERTIBLE, LIKE CP850 */ /* Which means finding all the graphic characters in the NeXT set that have no equivalent in Latin-1 and assigning them to the UNK positions (mostly Latin-1 C1 controls). Then make the ynel1[] table be the inverse of this one. But first we should try to get an official Latin-1/NeXT translation table from NeXT, Inc. */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 32, 161, 162, 163, 168, 165, 181, 167, 200, 160, 227, 171, 190, UNK, 176, 197, 202, 209, 201, 204, 194, 157, 182, 183, 203, 192, 235, 187, 210, 211, 212, 191, 129, 130, 131, 132, 133, 134, 225, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 158, 233, 151, 152, 153, 154, 155, 156, 251, 213, 214, 215, 216, 217, 218, 241, 219, 220, 221, 222, 223, 224, 226, 228, 229, 230, 231, 236, 237, 238, 239, 240, 159, 249, 242, 243, 244, 246, 247, 252, 253 }; CONST CHAR yl1no[] = { /* Latin-1 to Norwegian/Danish ISO 646 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 32, 33, UNK, UNK, UNK, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK, UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63, 65, 65, 65, 65, 65, 93, 91, 67, 69, 69, 69, 69, 73, 73, 73, 73, UNK, 78, 79, 79, 79, 79, 79, 120, 92, 85, 85, 85, 85, 89, UNK, 115, 97, 97, 97, 97, 97, 125, 123, 99, 101, 101, 101, 101, 105, 105, 105, 105, UNK, 110, 111, 111, 111, 111, 111, 47, 124, 117, 117, 117, 117, 121, UNK, 121 }; CONST CHAR yl1po[] = { /* Latin-1 to Portuguese ISO 646 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 32, 33, UNK, UNK, UNK, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK, UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63, 65, 65, 65, 91, 65, 65, 65, 92, 69, 69, 69, 69, 73, 73, 73, 73, UNK, 78, 79, 79, 79, 93, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115, 97, 97, 97, 123, 97, 97, 97, 124, 101, 101, 101, 101, 105, 105, 105, 105, UNK, 110, 111, 111, 111, 125, 111, 47, 111, 117, 117, 117, 117, 121, UNK, 121 }; CONST CHAR yl1sp[] = { /* Latin-1 to Spanish ISO 646 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, UNK, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 96, UNK, UNK, 126, 127, 126, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 32, 91, UNK, 35, UNK, UNK, UNK, 64, 34, 67, UNK, 34, UNK, 45, 82, UNK, 123, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 93, 65, 65, 65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73, UNK, 92, 79, 79, 79, 79, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115, 124, 97, 97, 97, 97, 97, 97, 125, 101, 101, 101, 101, 105, 105, 105, 105, UNK, 124, 111, 111, 111, 111, 111, 47, 111, 117, 117, 117, 117, 121, UNK, 121 }; CONST CHAR yl1sw[] = { /* Latin-1 to Swedish ISO 646 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, UNK, 95, UNK, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 32, 33, UNK, UNK, UNK, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK, UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63, 65, 65, 65, 65, 91, 93, 65, 67, 69, 64, 69, 69, 73, 73, 73, 73, UNK, 78, 79, 79, 79, 79, 92, 120, 79, 85, 85, 85, 94, 89, UNK, 115, 97, 97, 97, 97, 123, 125, 97, 99, 101, 96, 101, 101, 105, 105, 105, 105, UNK, 110, 111, 111, 111, 111, 124, 47, 111, 117, 117, 117, 126, 121, UNK, 121 }; CONST CHAR yl1ch[] = { /* Latin-1 to Swiss ISO 646 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, UNK, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, UNK, UNK, UNK, UNK, UNK, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 32, 33, UNK, UNK, UNK, UNK, UNK, UNK, 34, 67, UNK, 34, UNK, 45, 82, UNK, UNK, UNK, UNK, UNK, 39, 117, UNK, UNK, 44, UNK, UNK, 34, UNK, UNK, UNK, 63, 65, 65, 65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73, UNK, 78, 79, 79, 79, 79, 79, 120, 79, 85, 85, 85, 85, 89, UNK, 115, 64, 97, 97, 97, 123, 97, 97, 92, 95, 91, 93, 101, 105, 105, 94, 105, UNK, 110, 111, 111, 96, 111, 124, 47, 111, 35, 117, 126, 125, 121, UNK, 121 }; CONST CHAR yl1dm[] = { /* Latin-1 to DEC Multinational Character Set */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 32, 161, 162, 163, 168, 165, 124, 167, 34, 169, 170, 171, 126, UNK, 82, UNK, 176, 177, 178, 179, 39, 181, 182, 183, 44, 185, 186, 187, 188, 189, UNK, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, UNK, 209, 210, 211, 212, 213, 214, 120, 216, 217, 218, 219, 220, 221, UNK, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, UNK, 241, 242, 243, 244, 245, 246, 47, 248, 249, 250, 251, 252, UNK, UNK, 253 }; CONST CHAR yl1dg[] = { /* Latin-1 to Data General International Character Set */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 171, 167, 168, 166, 181, 191, 187, 189, 173, 169, 177, 161, 255, 174, 175, 188, 182, 164, 165, 190, 163, 178, 185, 186, 179, 170, 176, 223, 162, 220, 172, 193, 192, 194, 196, 195, 197, 198, 199, 201, 200, 202, 203, 205, 204, 206, 207, 184, 208, 210, 209, 211, 213, 212, 215, 214, 217, 216, 218, 219, 221, 222, 252, 225, 224, 226, 228, 227, 229, 230, 231, 233, 232, 234, 235, 237, 236, 238, 239, 183, 240, 242, 241, 243, 245, 244, 247, 246, 249, 248, 250, 251, 180, 254, 253 }; /* Local file character sets to ISO Latin Alphabet 1 */ #ifdef NOTUSED CONST CHAR yasl1[] = { /* ASCII to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127 }; #endif /* NOTUSED */ CONST CHAR yaql1[] = { /* Extended Mac Latin (based on Apple Quickdraw) to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 196, 197, 199, 201, 209, 214, 220, 225, 224, 226, 228, 227, 229, 231, 233, 232, 234, 235, 237, 236, 238, 239, 241, 243, 242, 244, 246, 245, 250, 249, 251, 252, 221, 176, 162, 163, 167, 215, 182, 223, 174, 169, 178, 180, 168, 179, 198, 216, 185, 177, 188, 189, 165, 181, 128, 129, 130, 131, 190, 170, 186, 132, 230, 248, 191, 161, 172, 142, 133, 134, 135, 171, 187, 166, 160, 192, 195, 213, 136, 137, 173, 144, 138, 139, 143, 146, 247, 145, 255, 140, 141, 164, 208, 240, 222, 254, 253, 183, 147, 148, 149, 194, 202, 193, 203, 200, 205, 206, 207, 204, 211, 212, 150, 210, 218, 219, 217, 151, 152, 153, 175, 154, 155, 156, 184, 157, 158, 159 }; CONST CHAR ydul1[] = { /* Dutch ISO 646 to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 163, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 190, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 255, 189, 124, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 168, 164, 188, 39, 127 }; CONST CHAR yfil1[] = { /* Finnish NRC (*not* ISO-646) to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 196, 214, 197, 220, 95, 233, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 228, 246, 229, 252, 127 }; CONST CHAR yfrl1[] = { /* French ISO 646 to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 163, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 224, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 176, 231, 167, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 233, 249, 232, 168, 127 }; CONST CHAR yfcl1[] = { /* French-Canadian ISO 646 to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 224, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 226, 231, 234, 238, 95, 244, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 233, 249, 232, 251, 127 }; CONST CHAR ygel1[] = { /* German ISO 646 to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 167, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 196, 214, 220, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 228, 246, 252, 223, 127 }; CONST CHAR yitl1[] = { /* Italian ISO 646 to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 163, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 167, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 176, 231, 233, 94, 95, 249, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 224, 242, 232, 236, 127 }; CONST CHAR ynel1[] = { /* NeXT to Latin-1 */ /* NEED TO MAKE THIS ONE INVERTIBLE */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 160, 192, 193, 194, 195, 196, 197, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 217, 218, 219, 220, 221, 222, 181, 215, 247, 169, 161, 162, 163, UNK, 165, UNK, 167, 164, UNK, UNK, 171, UNK, UNK, UNK, UNK, 174, UNK, UNK, UNK, 183, 166, 182, UNK, UNK, UNK, UNK, 187, UNK, UNK, 172, 191, 185, 96, 180, 94, 126, 175, UNK, UNK, 168, 178, 176, 184, 179, UNK, UNK, UNK, UNK, 177, 188, 189, 190, 224, 225, 226, 227, 228, 229, 231, 232, 233, 234, 235, 236, 198, 237, 170, 238, 239, 240, 241, UNK, 216, UNK, 186, 242, 243, 244, 245, 246, 230, 249, 250, 251, UNK, 252, 253, UNK, 248, UNK, 223, 254, 255, UNK, UNK }; CONST CHAR ynol1[] = { /* Norwegian/Danish ISO 646 to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 198, 216, 197, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 230, 248, 229, 126, 127 }; CONST CHAR ypol1[] = { /* Portuguese ISO 646 to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 195, 199, 213, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 227, 231, 245, 126, 127 }; CONST CHAR yspl1[] = { /* Spanish ISO 646 to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 163, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 167, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 161, 209, 191, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 176, 241, 231, 126, 127 }; CONST CHAR yswl1[] = { /* Swedish ISO 646 to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 201, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 196, 214, 197, 220, 95, 233, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 228, 246, 229, 252, 127 }; CONST CHAR ychl1[] = { /* Swiss ISO 646 to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 249, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 224, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 233, 231, 234, 238, 232, 244, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 228, 246, 252, 251, 127 }; CONST CHAR yhul1[] = { /* Hungarian ISO 646 to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 164, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 193, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 201, 214, 220, 94, 95, 225, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 233, 246, 252, 34, 127 }; CONST CHAR ydml1[] = { /* DEC Multinational Character Set to Latin-1 */ /* Note: This is a null translation */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 }; CONST CHAR ydgl1[] = { /* Data General International to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 172, 189, 181, 178, 179, 164, 162, 163, 170, 186, 161, 191, 169, 174, 175, 187, 171, 182, 185, 253, 165, 177, 240, 208, 183, 184, 167, 176, 168, 180, 166, 193, 192, 194, 196, 195, 197, 198, 199, 201, 200, 202, 203, 205, 204, 206, 207, 209, 211, 210, 212, 214, 213, 216, 215, 218, 217, 219, 220, 190, 221, 222, 188, 225, 224, 226, 228, 227, 229, 230, 231, 233, 232, 234, 235, 237, 236, 238, 239, 241, 243, 242, 244, 246, 245, 248, 247, 250, 249, 251, 252, 223, 255, 254, 173 }; /* Translation tables for Cyrillic character sets */ #ifdef CYRILLIC CONST CHAR ylcac[] = { /* Latin/Cyrillic to CP866 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 208, 209, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 196, 179, 192, 217, 191, 218, 195, 193, 180, 194, 197, 176, 177, 178, 211, 216, 205, 186, 200, 188, 187, 201, 204, 202, 185, 203, 206, 223, 220, 219, 254, UNK, 255, 240, 132, 131, 242, 83, 73, 244, 74, 139, 141, 151, 138, 45, 246, 135, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 252, 241, 164, 163, 243, 115, 105, 245, 106, 171, 173, 231, 170, 21, 247, 167 }; CONST CHAR ylc55[] = { /* Latin/Cyrillic to CP855 (inverse of y55lc) */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 174, 175, 176, 177, 178, 179, 180, 185, 186, 187, 188, 191, 192, 193, 194, 195, 196, 197, 200, 201, 202, 203, 204, 205, 206, 207, 217, 218, 219, 220, 223, 254, 255, 133, 129, 131, 135, 137, 139, 141, 143, 145, 147, 149, 151, 240, 153, 155, 161, 163, 236, 173, 167, 169, 234, 244, 184, 190, 199, 209, 211, 213, 215, 221, 226, 228, 230, 232, 171, 182, 165, 252, 246, 250, 159, 242, 238, 248, 157, 224, 160, 162, 235, 172, 166, 168, 233, 243, 183, 189, 198, 208, 210, 212, 214, 216, 225, 227, 229, 231, 170, 181, 164, 251, 245, 249, 158, 241, 237, 247, 156, 222, 239, 132, 128, 130, 134, 136, 138, 140, 142, 144, 146, 148, 150, 253, 152, 154 }; CONST CHAR ylc1251[] = { /* Latin/Cyrillic to CP1251 (inverse of y1251lc) */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 130, 132, 133, 134, 135, 136, 137, 139, 145, 146, 147, 148, 149, 150, 151, 152, 153, 155, 164, 165, 166, 169, 171, 172, 174, 176, 177, 180, 181, 182, 183, 187, 160, 168, 128, 129, 170, 189, 178, 175, 163, 138, 140, 142, 141, 173, 161, 143, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 185, 184, 144, 131, 186, 190, 179, 191, 188, 154, 156, 158, 157, 167, 162, 159 }; CONST CHAR ylcbu[] = { /* Latin/Cyrillic to Bulgarian PC Code Page */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 255, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 213, 207, 208, 209, 210, 211, 212, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 214, 253, 254 }; CONST CHAR ylck8[] = { /* Latin/Cyrillic to Old KOI-8 Cyrillic */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, UNK, 229, UNK, UNK, UNK, 83, 73, 73, 74, UNK, UNK, UNK, 235, UNK, 245, UNK, 225, 226, 247, 231, 228, 229, 246, 250, 233, 234, 235, 236, 237, 238, 239, 240, 242, 243, 244, 245, 230, 232, 227, 254, 251, 253, 255, 249, 248, 252, 224, 241, 193, 194, 215, 199, 196, 197, 214, 218, 201, 202, 203, 204, 205, 206, 207, 208, 210, 211, 212, 213, 198, 200, 195, 222, 219, 221, 223, 217, 216, 220, 192, 209, UNK, 197, UNK, UNK, UNK, 115, 105, 105, 106, UNK, UNK, UNK, 203, UNK, 213, UNK }; CONST CHAR yaclc[] = { /* CP866 to Latin/Cyrillic */ /* NEED TO MAKE THIS ONE INVERTIBLE */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 161, 241, 164, 244, 167, 247, 174, 254, UNK, UNK, UNK, UNK, 240, UNK, UNK, UNK }; CONST CHAR y55lc[] = { /* CP855 to Latin/Cyrillic (inverse of ylc55) */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 242, 162, 243, 163, 241, 161, 244, 164, 245, 165, 246, 166, 247, 167, 248, 168, 249, 169, 250, 170, 251, 171, 252, 172, 254, 174, 255, 175, 238, 206, 234, 202, 208, 176, 209, 177, 230, 198, 212, 180, 213, 181, 228, 196, 211, 179, 128, 129, 130, 131, 132, 133, 134, 229, 197, 216, 184, 135, 136, 137, 138, 217, 185, 139, 140, 141, 142, 143, 144, 145, 218, 186, 146, 147, 148, 149, 150, 151, 152, 153, 219, 187, 220, 188, 221, 189, 222, 190, 223, 154, 155, 156, 157, 191, 239, 158, 207, 224, 192, 225, 193, 226, 194, 227, 195, 214, 182, 210, 178, 236, 204, 240, 173, 235, 203, 215, 183, 232, 200, 237, 205, 233, 201, 231, 199, 253, 159, 160 }; CONST CHAR y1251lc[] = { /* CP1251 to Latin/Cyrillic (inverse of ylc1251) */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 162, 163, 128, 243, 129, 130, 131, 132, 133, 134, 169, 135, 170, 172, 171, 175, 242, 136, 137, 138, 139, 140, 141, 142, 143, 144, 249, 145, 250, 252, 251, 255, 160, 174, 254, 168, 146, 147, 148, 253, 161, 149, 164, 150, 151, 173, 152, 167, 153, 154, 166, 246, 155, 156, 157, 158, 241, 240, 244, 159, 248, 165, 245, 247, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239 }; CONST CHAR ybulc[] = { /* Bulgarian PC Code Page to Latin/Cyrillic */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 209, 210, 211, 212, 213, 214, 208, 253, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 254, 255, 128 }; CONST CHAR yk8lc[] = { /* Old KOI-8 Cyrillic to Latin/Cyrillic */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 238, 208, 209, 230, 212, 213, 228, 211, 229, 216, 217, 218, 219, 220, 221, 222, 223, 239, 224, 225, 226, 227, 214, 210, 236, 235, 215, 232, 237, 233, 231, 234, 206, 176, 177, 198, 180, 181, 196, 179, 197, 184, 185, 186, 187, 188, 189, 190, 191, 207, 192, 193, 194, 195, 182, 178, 204, 203, 183, 200, 205, 201, 199, 127 }; CONST CHAR ylcsk[] = { /* Latin/Cyrillic to Short KOI */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 127, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 101, UNK, UNK, UNK, 83, 73, 73, 74, UNK, UNK, UNK, 107, 45, 117, UNK, 97, 98, 119, 103, 100, 101, 118, 122, 105, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 117, 102, 104, 99, 126, 123, 125, 39, 121, 120, 124, 96, 113, 97, 98, 119, 103, 100, 101, 118, 122, 105, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 117, 102, 104, 99, 126, 123, 125, 39, 121, 120, 124, 96, 113, UNK, 101, UNK, UNK, UNK, 83, 73, 73, 74, UNK, UNK, UNK, 107, UNK, 117, UNK }; CONST CHAR yskcy[] = { /* Short KOI to Latin/Cyrillic */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 206, 176, 177, 198, 180, 181, 196, 179, 197, 184, 185, 186, 187, 188, 189, 190, 191, 207, 192, 193, 194, 195, 182, 178, 204, 203, 183, 200, 205, 201, 199, 127 }; #endif /* CYRILLIC */ #ifdef LATIN2 /* Latin-2 tables */ CONST CHAR yl252[] = { /* Latin-2 to Code Page 852 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 174, 175, 176, 177, 178, 179, 180, 185, 186, 187, 188, 191, 192, 193, 194, 195, 196, 197, 200, 201, 202, 203, 204, 205, 206, 217, 218, 219, 220, 223, 240, 254, 255, 164, 244, 157, 207, 149, 151, 245, 249, 230, 184, 155, 141, 170, 166, 189, 248, 165, 242, 136, 239, 150, 152, 243, 247, 231, 173, 156, 171, 241, 167, 190, 232, 181, 182, 198, 142, 145, 143, 128, 172, 144, 168, 211, 183, 214, 215, 210, 209, 227, 213, 224, 226, 138, 153, 158, 252, 222, 233, 235, 154, 237, 221, 225, 234, 160, 131, 199, 132, 146, 134, 135, 159, 130, 169, 137, 216, 161, 140, 212, 208, 228, 229, 162, 147, 139, 148, 246, 253, 133, 163, 251, 129, 236, 238, 250 }; CONST CHAR y52l2[] = { /* Code Page 852 to Latin-2 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 199, 252, 233, 226, 228, 249, 230, 231, 179, 235, 213, 245, 238, 172, 196, 198, 201, 197, 229, 244, 246, 165, 181, 166, 182, 214, 220, 171, 187, 163, 215, 232, 225, 237, 243, 250, 161, 177, 174, 190, 202, 234, 173, 188, 200, 186, 128, 129, 130, 131, 132, 133, 134, 193, 194, 204, 170, 135, 136, 137, 138, 175, 191, 139, 140, 141, 142, 143, 144, 145, 195, 227, 146, 147, 148, 149, 150, 151, 152, 164, 240, 208, 207, 203, 239, 210, 205, 206, 236, 153, 154, 155, 156, 222, 217, 157, 211, 223, 212, 209, 241, 242, 169, 185, 192, 218, 224, 219, 253, 221, 254, 180, 158, 189, 178, 183, 162, 167, 247, 184, 176, 168, 255, 251, 216, 248, 159, 160 }; CONST CHAR yl21250[] = { /* Latin-2 to Code Page 1250 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 139, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 155, 166, 169, 171, 172, 174, 177, 181, 182, 183, 187, 160, 165, 162, 163, 164, 188, 140, 167, 168, 138, 170, 141, 143, 173, 142, 175, 176, 185, 178, 179, 180, 190, 156, 161, 184, 154, 186, 157, 159, 189, 158, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 }; CONST CHAR y1250l2[] = { /* Code Page 1250 to Latin-2 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 169, 138, 166, 171, 174, 172, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 185, 149, 182, 187, 190, 188, 160, 183, 162, 163, 164, 161, 150, 167, 168, 151, 170, 152, 153, 173, 154, 175, 176, 155, 178, 179, 180, 156, 157, 158, 184, 177, 186, 159, 165, 189, 181, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 }; CONST CHAR yl2mz[] = { /* Latin-2 to Mazovia (NOT invertible) */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 255, 143, UNK, 156, 155, 76, 152, 21, 34, 83, 83, 84, 160, 45, 90, 161, 248, 134, 44, 146, 39, 108, 158, UNK, 44, 115, 115, 116, 166, 34, 122, 167, 82, 65, 65, 65, 142, 76, 149, 128, 67, 69, 144, 69, 69, 73, 73, 68, 68, 165, 78, 163, 79, 153, 153, 250, 82, 85, 85, 154, 154, 89, 84, 225, 114, 97, 131, 97, 132, 108, 141, 135, 99, 130, 145, 137, 101, 105, 140, 101, 100, 164, 110, 162, 147, 148, 148, 246, 114, 117, 117, 129, 129, 121, 116, 249 }; CONST CHAR ymzl2[] = { /* Mazovia to Latin-2 (NOT INVERTIBLE) */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 252, 233, 226, 228, 97, 177, 231, 101, 235, 101, 105, 238, 230, 196, 161, 202, 234, 179, 244, 246, 198, 117, 117, 166, 214, 220, 164, 163, 89, 182, 102, 172, 175, 243, 211, 242, 210, 188, 191, 63, UNK, UNK, UNK, UNK, 33, 34, 34, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 247, UNK, 176, 255, 215, UNK, UNK, UNK, UNK, 160 }; CONST CHAR yl2l1[] = { /* Latin-2 to Latin-1 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 'A', UNK, 'L', 164, 'L', 'S', 167, 168, 'S', 'S', 'T', 'Z', 173, 'Z', 'Z', 176, 'a', UNK, 'l', 180, 'l', 's', UNK, 184, 's', 's', 't', 'z', UNK, 'z', 'z', 'R', 193, 194, 'A', 196, 'L', 'C', 199, 'C', 201, 'E', 203, 'E', 205, 'I', 'D', 208, 'N', 'N', 211, 212, 'O', 214, 215, 'R', 'U', 218, 'U', 220, 221, 'T', 223, 'r', 225, 226, 'a', 228, 'l', 'c', 231, 'c', 233, 'e', 235, 'e', 237, 'i', 'd', 240, 'n', 'n', 243, 244, 'o', 246, 247, 'r', 'u', 250, 'u', 252, 253, 't', '.' }; CONST CHAR yl1l2[] = { /* Latin-1 to Latin-2 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 'A', UNK, 'L', 164, UNK, UNK, 167, 168, 'C', 'a', '<', '>', 173, 'R', UNK, 176, UNK, UNK, UNK, 180, UNK, UNK, UNK, 184, UNK, 'o', '>', UNK, UNK, UNK, UNK, 'A', 193, 194, 'A', 196, 'A', 'A', 199, 'E', 201, 'E', 203, 'I', 205, 'I', 'I', 208, 'N', 'O', 211, 212, 'O', 214, 215, 'O', 'U', 218, 'U', 220, 221, UNK, 223, 'a', 225, 226, 'a', 228, 'a', 'a', 231, 'e', 233, 'e', 235, 'i', 237, 'i', 'i', 240, 'n', 'o', 243, 244, 'o', 246, 247, 'o', 'u', 250, 'u', 252, 253, UNK, 'y' }; CONST CHAR yl2as[] = { /* Latin-2 to ASCII */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 32, 'A', UNK, 'L', UNK, 'L', 'S', UNK, 34, 'S', 'S', 'T', 'Z', '-', 'Z', 'Z', UNK, 'a', UNK, 'l', 39, 'l', 's', UNK, 44, 's', 's', 't', 'z', UNK, 'z', 'z', 'R', 'A', 'A', 'A', 'A', 'L', 'C', 'C', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'D', 'D', 'N', 'N', 'O', 'O', 'O', 'O', 'x', 'R', 'U', 'U', 'U', 'U', 'Y', 'T', 's', 'r', 'a', 'a', 'a', 'a', 'l', 'c', 'c', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'd', 'd', 'n', 'n', 'o', 'o', 'o', 'o', '/', 'r', 'u', 'u', 'u', 'u', 'y', 't', '.' }; #endif /* LATIN2 */ #ifdef HEBREW /* 8-bit Tables providing invertible translation between Latin/Hebrew and CP862. */ CONST CHAR y62lh[] = { /* PC Code Page 862 to ISO 8859-8 Latin/Hebrew */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 162, 163, 165, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 172, 189, 188, 140, 171, 187, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 161, 164, 166, 167, 168, 169, 170, 173, 174, 175, 223, 179, 180, 182, 184, 185, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 181, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 177, 219, 220, 221, 222, 186, 251, 176, 183, 252, 253, 254, 178, 255, 160 }; CONST CHAR ylh62[] = { /* ISO 8859-8 Latin/Hebrew to PC Code Page 862 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 173, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 255, 195, 155, 156, 196, 157, 197, 198, 199, 200, 201, 174, 170, 202, 203, 204, 248, 241, 253, 206, 207, 230, 208, 249, 209, 210, 246, 175, 172, 171, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 242, 243, 244, 245, 205, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 247, 250, 251, 252, 254 }; /* 7-bit table providing readable translation from DEC Hebrew-7 to CP862. */ CONST CHAR yh762[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, UNK, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127 }; /* 8-bit table providing readable translation from CP862 to Hebrew-7. */ CONST CHAR y62h7[] = { /* PC Code Page 862 to Hebrew-7 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK }; /* 7-bit table providing readable translation from Hebrew-7 to ISO Latin/Hebrew. */ CONST CHAR yh7lh[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 123, 124, 125, 126, 127 }; /* 8-bit table providing readable translation from ISO Latin/Hebrew to Hebrew-7. */ CONST CHAR ylhh7[] = { /* Latin/Hebrew to Hebrew-7 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, UNK, UNK, UNK, UNK, UNK }; #endif /* HEBREW */ #ifdef GREEK /* 8-bit Tables providing invertible translation between Latin/Greek and CP869. */ CONST CHAR ylg69[] = { /* ISO 8859-7 Latin/Greek to PC Code Page 869 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 135, 147, 148, 176, 177, 178, 179, 180, 185, 186, 187, 188, 191, 192, 193, 194, 195, 196, 197, 200, 201, 202, 203, 204, 205, 206, 217, 218, 219, 220, 223, 254, 255, 139, 140, 156, 128, 129, 138, 245, 249, 151, 130, 174, 137, 240, 131, 142, 248, 241, 153, 154, 239, 247, 134, 136, 141, 143, 144, 175, 146, 171, 149, 152, 161, 164, 165, 166, 167, 168, 169, 170, 172, 173, 181, 182, 183, 184, 189, 190, 198, 199, 132, 207, 208, 209, 210, 211, 212, 213, 145, 150, 155, 157, 158, 159, 252, 214, 215, 216, 221, 222, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 237, 236, 238, 242, 243, 244, 246, 250, 160, 251, 162, 163, 253, 133 }; CONST CHAR y69lg[] = { /* PC Code Page 869 to ISO 8859-7 Latin/Greek */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 164, 165, 170, 174, 210, 255, 182, 128, 183, 172, 166, 161, 162, 184, 175, 185, 186, 218, 188, 129, 130, 190, 219, 169, 191, 178, 179, 220, 163, 221, 222, 223, 250, 192, 252, 253, 193, 194, 195, 196, 197, 198, 199, 189, 200, 201, 171, 187, 131, 132, 133, 134, 135, 202, 203, 204, 205, 136, 137, 138, 139, 206, 207, 140, 141, 142, 143, 144, 145, 146, 208, 209, 147, 148, 149, 150, 151, 152, 153, 211, 212, 213, 214, 215, 216, 217, 225, 226, 227, 154, 155, 156, 157, 228, 229, 158, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 243, 242, 244, 180, 173, 177, 245, 246, 247, 167, 248, 181, 176, 168, 249, 251, 224, 254, 159, 160 }; /* 7-bit table providing readable translation from ELOT 927 to CP869. */ CONST CHAR yeg69[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 164, 165, 166, 167, 168, 169, 170, 172, 173, 181, 182, 183, 184, 189, 190, 198, 199, 207, 208, 209, 210, 211, 212, 213, 32, 32, 23, 124, 125, 126, 127 }; /* 8-bit table providing readable translation from CP869 to ELOT 927. */ CONST CHAR y69eg[] = { /* PC Code Page 869 to ELOT 927 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127, UNK, UNK, UNK, UNK, UNK, UNK, 97, UNK, 46, UNK, 124, 39, 39, 101, 45, 103, 105, 105, 111, UNK, UNK, 116, 116, UNK, 120, 50, 51, 97, UNK, 101, 103, 105, 105, 105, 111, 116, 97, 98, 99, 100, 101, 102, 103, UNK, 104, 105, 34, 34, UNK, UNK, UNK, UNK, UNK, 106, 107, 108, 109, UNK, UNK, UNK, UNK, 110, 111, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 112, 113, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 114, 115, 116, 117, 118, 119, 120, 97, 98, 99, UNK, UNK, UNK, UNK, 100, 101, UNK, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 39, 45, UNK, 116, 117, 118, UNK, 119, UNK, UNK, UNK, 120, 116, 116, 120, UNK, 32 }; /* 7-bit table providing readable translation from ELOT 927 to ISO Latin/Greek. */ CONST CHAR yeglg[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 211, 212, 213, 214, 215, 216, 217, 32, 32, 123, 124, 125, 126, 127 }; /* 8-bit table providing readable translation from ISO Latin/Greek to ELOT 927. */ CONST CHAR ylgeg[] = { /* Latin/Greek to ELOT 927 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, 32, 39, 39, UNK, UNK, UNK, 124, UNK, 34, UNK, UNK, 34, UNK, 45, UNK, 45, UNK, UNK, 50, 51, 39, UNK, 97, 46, 101, 103, 105, 34, 111, UNK, 116, 120, UNK, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, UNK, 114, 115, 116, 117, 118, 119, 120, 105, 116, 97, 101, 103, 105, 116, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118, 119, 120, 105, 116, 111, 116, 120, UNK }; #endif /* GREEK */ /* Translation functions ... */ CHAR /* The identity function... */ #ifdef CK_ANSIC ident(CHAR c) /* (no longer used) */ #else ident(c) CHAR c; #endif /* CK_ANSIC */ { /* ident */ return(c); /* Instead, enter NULL in the */ } /* table of functions to avoid */ /* needless function calls. */ CHAR #ifdef CK_ANSIC xleft128(CHAR c) #else xleft128(c) CHAR c; #endif /* CK_ANSIC */ { /* xleft128 */ return((c < 128) ? c : '?'); } CHAR #ifdef CK_ANSIC xleft160(CHAR c) #else xleft160(c) CHAR c; #endif /* CK_ANSIC */ { /* xleft160 */ return((c < 160) ? c : '?'); } CHAR #ifdef CK_ANSIC xl1as(CHAR c) #else xl1as(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1as */ /* Latin-1 to US ASCII... */ switch(langs[language].id) { case L_DUTCH: if (c == 255) { /* Dutch umlaut-y */ zmstuff('j'); /* becomes ij */ return('i'); } else return(yl1as[c]); /* all others by the book */ case L_GERMAN: switch (c) { /* German, special rules. */ case 196: /* umlaut-A -> Ae */ zmstuff('e'); return('A'); case 214: /* umlaut-O -> Oe */ zmstuff('e'); return('O'); case 220: /* umlaut-U -> Ue */ zmstuff('e'); return('U'); case 228: /* umlaut-a -> ae */ zmstuff('e'); return('a'); case 246: /* umlaut-o -> oe */ zmstuff('e'); return('o'); case 252: /* umlaut-u -> ue */ zmstuff('e'); return('u'); case 223: /* ess-zet -> ss */ zmstuff('s'); return('s'); default: return(yl1as[c]); /* all others by the book */ } case L_DANISH: case L_FINNISH: case L_NORWEGIAN: case L_SWEDISH: switch (c) { /* Scandanavian languages. */ case 196: /* umlaut-A -> Ae */ case 198: /* AE ligature also -> Ae */ zmstuff('e'); return('A'); case 214: /* umlaut-O -> Oe */ case 216: /* O-slash -> Oe */ zmstuff('e'); return('O'); case 220: /* umlaut-U -> Ue */ /* return('Y'); replaced by "Ue" by popular demand. */ /* Y for Umlaut-U is only used in German names. */ zmstuff('e'); return('U'); case 228: /* umlaut-a -> ae */ case 230: /* ditto for ae ligature */ zmstuff('e'); return('a'); case 246: /* umlaut-o -> oe */ case 248: /* o-slash -> oe */ zmstuff('e'); return('o'); case 252: /* umlaut-u -> ue */ /* return('y'); replaced by "ue" by popular demand. */ zmstuff('e'); return('u'); case 197: /* A-ring -> Aa */ zmstuff('a'); return('A'); case 229: /* a-ring -> aa */ zmstuff('a'); return('a'); default: return(yl1as[c]); /* All others by the book */ } case L_ICELANDIC: /* Icelandic. */ switch (c) { case 198: /* uppercase AE -> AE */ zmstuff('e'); return('A'); case 208: /* uppercase Eth -> D */ return('D'); case 214: /* uppercase O-diaeresis -> Oe */ zmstuff('e'); return('O'); case 222: /* uppercase Thorn -> Th */ zmstuff('h'); return('T'); case 230: /* lowercase ae -> ae */ zmstuff('e'); return('a'); case 240: /* lowercase Eth -> d */ return('d'); case 246: /* lowercase O-diaeresis -> oe */ zmstuff('e'); return('o'); case 254: /* lowercase Thorn -> th */ zmstuff('h'); return('t'); default: return(yl1as[c]); /* All others by the book */ } default: return(yl1as[c]); /* None of the above, by the table. */ } } CHAR /* CP1252 to ASCII */ #ifdef CK_ANSIC xw1as(CHAR c) #else xw1as(c) CHAR c; #endif /* CK_ANSIC */ { /* xw1as */ switch(c) { /* Microsoft name... */ case 0x80: return('?'); /* Euro Sign */ case 0x82: return('\047'); /* Single Low-9 Quotation Mark */ case 0x83: return('f'); /* Latin Small Letter f with Hook */ case 0x84: return('"'); /* Double low-9 Quotation Mark */ case 0x85: return('-'); /* Horizontal Ellipsis */ case 0x86: return('+'); /* Dagger */ case 0x87: return('+'); /* Double Dagger */ case 0x88: return('^'); /* Modifier Letter Circumflex Accent */ case 0x89: return('?'); /* Per Mille Sign */ case 0x8A: return('S'); /* Latin Capital Letter S with Caron */ case 0x8B: return('<'); /* Single Left Angle Quotation Mark */ case 0x8C: return('O'); /* Latin Capital Ligature OE */ case 0x8E: return('Z'); /* Latin Capital Letter Z with Caron */ case 0x91: return('\047'); /* Left Single Quotation Mark */ case 0x92: return('\047'); /* Right Single Quotation Mark */ case 0x93: return('"'); /* Left Double Quotation Mark */ case 0x94: return('"'); /* Right Double Quotation Mark */ case 0x95: return('.'); /* Bullet */ case 0x96: return('-'); /* En Dash */ case 0x97: return('-'); /* Em Dash */ case 0x98: return('~'); /* Small Tilde */ case 0x99: return('T'); /* Trade Mark Sign */ case 0x9A: return('s'); /* Latin Small Letter s with Caron */ case 0x9B: return('>'); /* Single Right Angle Quotation Mark */ case 0x9C: return('o'); /* Latin Small Ligature OE */ case 0x9E: return('z'); /* Latin Small Letter z with Caron */ case 0x9F: return('Y'); /* Latin Capital Letter Y Diaeresis */ default: if (c > 0x80 && c < 0xa0) return('?'); else return(yl1as[c]); } } CHAR /* CP1252 to Latin-1 */ #ifdef CK_ANSIC xw1l1(CHAR c) #else xw1l1(c) CHAR c; #endif /* CK_ANSIC */ { /* xw1l1 */ if (c == 0x95) return(0xb7); /* Middle dot */ return((c < 160) ? xw1as(c) : c); } CHAR /* Latin-1 to German */ #ifdef CK_ANSIC xl1ge(CHAR c) #else xl1ge(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1ge */ return(yl1ge[c]); } CHAR /* German to Latin-1 */ #ifdef CK_ANSIC xgel1(CHAR c) #else xgel1(c) CHAR c; #endif /* CK_ANSIC */ { /* xgel1 */ if (c & 0x80) return(UNK); return(ygel1[c]); } CHAR #ifdef CK_ANSIC xgeas(CHAR c) #else xgeas(c) CHAR c; #endif /* CK_ANSIC */ { /* xgeas */ /* German ISO 646 to ASCII */ if (c & 0x80) return(UNK); switch (c) { case 91: /* umlaut-A -> Ae */ zmstuff('e'); return('A'); case 92: /* umlaut-O -> Oe */ zmstuff('e'); return('O'); case 93: /* umlaut-U -> Ue */ zmstuff('e'); return('U'); case 123: /* umlaut-a -> ae */ zmstuff('e'); return('a'); case 124: /* umlaut-o -> oe */ zmstuff('e'); return('o'); case 125: /* umlaut-u -> ue */ zmstuff('e'); return('u'); case 126: /* ess-zet -> ss */ zmstuff('s'); return('s'); default: return(c); /* all others stay the same */ } } CHAR #ifdef CK_ANSIC xl1w1(CHAR c) #else xl1w1(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1w1 */ /* Latin-1 to CP1252 (Windows L1) */ if (c > 127 && c < 160) return(UNK); else return(c); } CHAR #ifdef CK_ANSIC xduas(CHAR c) #else xduas(c) CHAR c; #endif /* CK_ANSIC */ { /* xduas */ /* Dutch ISO 646 to US ASCII */ if (c & 0x80) return(UNK); switch (c) { case 64: return(UNK); /* 3/4 */ case 91: /* y-diaeresis */ zmstuff('j'); return('i'); case 92: return(UNK); /* 1/2 */ case 93: return(124); /* vertical bar */ case 123: return(34); /* diaeresis */ case 124: return(UNK); /* Florin */ case 125: return(UNK); /* 1/4 */ case 126: return(39); /* Apostrophe */ default: return(c); } } CHAR #ifdef CK_ANSIC xfias(CHAR c) #else xfias(c) CHAR c; #endif /* CK_ANSIC */ { /* xfias */ /* Finnish ISO 646 to US ASCII */ if (c & 0x80) return(UNK); switch (c) { case 91: /* A-diaeresis */ zmstuff('e'); return('A'); case 92: /* O-diaeresis */ zmstuff('e'); return('O'); case 93: /* A-ring */ zmstuff('a'); return('A'); case 94: /* U-diaeresis */ /* return('Y'); */ zmstuff('e'); return('U'); case 96: /* e-acute */ return('e'); case 123: /* a-diaeresis */ zmstuff('e'); return('a'); case 124: /* o-diaeresis */ zmstuff('e'); return('o'); case 125: /* a-ring */ zmstuff('a'); return('a'); case 126: /* u-diaeresis */ /* return('y'); */ zmstuff('e'); return('U'); default: return(c); } } CHAR #ifdef CK_ANSIC xfras(CHAR c) #else xfras(c) CHAR c; #endif /* CK_ANSIC */ { /* xfras */ /* French ISO 646 to US ASCII */ if (c & 0x80) return(UNK); switch (c) { case 64: return(97); /* a grave */ case 91: return(UNK); /* degree sign */ case 92: return(99); /* c cedilla */ case 93: return(UNK); /* paragraph sign */ case 123: return(101); /* e acute */ case 124: return(117); /* u grave */ case 125: return(101); /* e grave */ case 126: return(34); /* diaeresis */ default: return(c); } } CHAR #ifdef CK_ANSIC xfcas(CHAR c) #else xfcas(c) CHAR c; #endif /* CK_ANSIC */ { /* xfcas */ /* French Canadian ISO 646 to ASCII */ if (c & 0x80) return(UNK); switch (c) { case 64: return('a'); /* a grave */ case 91: return('a'); /* a circumflex */ case 92: return('c'); /* c cedilla */ case 93: return('e'); /* e circumflex */ case 94: return('i'); /* i circumflex */ case 96: return('o'); /* o circumflex */ case 123: return('e'); /* e acute */ case 124: return('u'); /* u grave */ case 125: return('e'); /* e grave */ case 126: return('u'); /* u circumflex */ default: return(c); } } CHAR #ifdef CK_ANSIC xitas(CHAR c) #else xitas(c) CHAR c; #endif /* CK_ANSIC */ { /* xitas */ /* Italian ISO 646 to ASCII */ if (c & 0x80) return(UNK); switch (c) { case 91: return(UNK); /* degree */ case 92: return('c'); /* c cedilla */ case 93: return('e'); /* e acute */ case 96: return('u'); /* u grave */ case 123: return('a'); /* a grave */ case 124: return('o'); /* o grave */ case 125: return('e'); /* e grave */ case 126: return('i'); /* i grave */ default: return(c); } } CHAR #ifdef CK_ANSIC xneas(CHAR c) #else xneas(c) CHAR c; #endif /* CK_ANSIC */ { /* xneas */ /* NeXT to ASCII */ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */ if (c == 234) { /* handle OE digraph. */ zmstuff('E'); return('O'); } else if (c == 250) { /* Also lowercase oe. */ zmstuff('e'); return('o'); } } c = xnel1(c); /* Convert to Latin-1 */ return(yl1as[c]); /* Convert Latin-1 to ASCII */ } CHAR #ifdef CK_ANSIC xnoas(CHAR c) #else xnoas(c) CHAR c; #endif /* CK_ANSIC */ { /* xnoas */ /* Norge/Danish ISO 646 to ASCII */ if (c & 0x80) return(UNK); switch (c) { case 91: zmstuff('E'); /* AE digraph */ return('A'); case 92: return('O'); /* O slash */ case 93: /* A ring */ zmstuff('a'); return('A'); case 123: /* ae digraph */ zmstuff('e'); return('a'); case 124: return('o'); /* o slash */ case 125: /* a ring */ zmstuff('a'); return('a'); default: return(c); } } CHAR #ifdef CK_ANSIC xpoas(CHAR c) #else xpoas(c) CHAR c; #endif /* CK_ANSIC */ { /* xpoas */ /* Portuguese ISO 646 to ASCII */ if (c & 0x80) return(UNK); switch (c) { case 91: return('A'); /* A tilde */ case 92: return('C'); /* C cedilla */ case 93: return('O'); /* O tilde */ case 123: return('a'); /* a tilde */ case 124: return('c'); /* c cedilla */ case 125: return('o'); /* o tilde */ default: return(c); } } CHAR #ifdef CK_ANSIC xspas(CHAR c) #else xspas(c) CHAR c; #endif /* CK_ANSIC */ { /* xspas */ /* Spanish ISO 646 to ASCII */ if (c & 0x80) return(UNK); switch (c) { case 91: return(33); /* Inverted exclamation */ case 92: return('N'); /* N tilde */ case 93: return(63); /* Inverted question mark */ case 123: return(UNK); /* degree */ case 124: return('n'); /* n tilde */ case 125: return('c'); /* c cedilla */ default: return(c); } } CHAR #ifdef CK_ANSIC xswas(CHAR c) #else xswas(c) CHAR c; #endif /* CK_ANSIC */ { /* xswas */ /* Swedish ISO 646 to ASCII */ if (c & 0x80) return(UNK); switch (c) { case 64: return('E'); /* E acute */ case 91: /* A diaeresis */ zmstuff('e'); return('A'); case 92: /* O diaeresis */ zmstuff('e'); return('O'); case 93: /* A ring */ zmstuff('a'); return('A'); case 94: /* U diaeresis */ /* return('Y'); */ zmstuff('e'); return('U'); case 96: return('e'); /* e acute */ case 123: /* a diaeresis */ zmstuff('e'); return('a'); case 124: /* o diaeresis */ zmstuff('e'); return('o'); case 125: /* a ring */ zmstuff('a'); return('a'); case 126: /* u diaeresis */ /* return('y'); */ zmstuff('e'); return('u'); default: return(c); } } CHAR #ifdef CK_ANSIC xchas(CHAR c) #else xchas(c) CHAR c; #endif /* CK_ANSIC */ { /* xchas */ /* Swiss ISO 646 to ASCII */ if (c & 0x80) return(UNK); switch (c) { case 35: return('u'); /* u grave */ case 64: return('a'); /* a grave */ case 91: return('e'); /* e acute */ case 92: return('c'); /* c cedilla */ case 93: return('e'); /* e circumflex */ case 94: return('i'); /* i circumflex */ case 95: return('e'); /* e grave */ case 96: return('o'); /* o circumflex */ case 123: /* a diaeresis */ zmstuff('e'); return('a'); case 124: /* o diaeresis */ zmstuff('e'); return('o'); case 125: /* u diaeresis */ zmstuff('e'); return('u'); case 126: return('u'); /* u circumflex */ default: return(c); } } CHAR #ifdef CK_ANSIC xhuas(CHAR c) #else xhuas(c) CHAR c; #endif /* CK_ANSIC */ { /* xhuas */ /* Hungarian ISO 646 to ASCII */ if (c & 0x80) return(UNK); switch (c) { case 64: return('A'); /* A acute */ case 91: return('E'); /* E acute */ case 92: return('O'); /* O diaeresis */ case 93: return('U'); /* U diaeresis */ case 96: return('a'); /* a acute */ case 123: return('e'); /* e acute */ case 124: return('o'); /* o acute */ case 125: return('u'); /* u acute */ case 126: return(34); /* double acute accent */ default: return(c); } } CHAR #ifdef CK_ANSIC xdmas(CHAR c) #else xdmas(c) CHAR c; #endif /* CK_ANSIC */ { /* xdmas */ /* DEC MCS to ASCII */ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */ if (c == 215) { /* handle OE digraph. */ zmstuff('E'); return('O'); } else if (c == 247) { /* Also lowercase oe. */ zmstuff('e'); return('o'); } } return(yl1as[c]); /* Otherwise treat like Latin-1 */ } CHAR #ifdef CK_ANSIC xdgas(CHAR c) #else xdgas(c) CHAR c; #endif /* CK_ANSIC */ { /* xdgas */ /* Data General to ASCII */ switch(c) { case 180: return('f'); /* Florin */ case 183: return('<'); /* Less-equal */ case 184: return('>'); /* Greater-equal */ case 186: return(96); /* Grave accent */ case 191: return('^'); /* Uparrow */ case 215: if (langs[language].id == L_FRENCH) { /* OE digraph */ zmstuff('E'); return('O'); } else return('O'); case 247: if (langs[language].id == L_FRENCH) { /* oe digraph */ zmstuff('e'); return('o'); } else return('o'); case 175: case 179: case 220: case 222: case 223: case 254: case 255: return(UNK); default: /* The rest, convert to Latin-1 */ return(yl1as[ydgl1[c]]); /* and from there to ASCII */ } } CHAR #ifdef CK_ANSIC xr8as(CHAR c) #else xr8as(c) CHAR c; #endif /* CK_ANSIC */ { /* xr8as */ /* Hewlett Packard Roman8 to ASCII */ switch(c) { case 175: return('L'); /* Lira */ case 190: return('f'); /* Florin */ case 235: return('S'); /* S caron */ case 236: return('s'); /* s caron */ case 246: return('-'); /* Horizontal bar */ case 252: return('*'); /* Solid box */ default: /* The rest, convert to Latin-1 */ return(yl1as[yr8l1[c]]); /* and from there to ASCII */ } } CHAR #ifdef CK_ANSIC xukl1(CHAR c) #else xukl1(c) CHAR c; #endif /* CK_ANSIC */ { /* xukl1 */ /* UK ASCII to Latin-1 */ if (c & 0x80) return(UNK); if (c == 35) return(163); else return(c); } CHAR #ifdef CK_ANSIC xl1uk(CHAR c) #else xl1uk(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1uk */ /* Latin-1 to UK ASCII */ if (c == 163) return(35); else return(yl1as[c]); } CHAR /* Latin-1 to French ISO 646 */ #ifdef CK_ANSIC xl1fr(CHAR c) #else xl1fr(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1fr */ return(yl1fr[c]); } CHAR /* French ISO 646 to Latin-1 */ #ifdef CK_ANSIC xfrl1(CHAR c) #else xfrl1(c) CHAR c; #endif /* CK_ANSIC */ { /* xfrl1 */ if (c & 0x80) return(UNK); return(yfrl1[c]); } CHAR /* Latin-1 to Dutch ASCII */ #ifdef CK_ANSIC xl1du(CHAR c) #else xl1du(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1du */ return(yl1du[c]); } CHAR #ifdef CK_ANSIC xdul1(CHAR c) #else xdul1(c) CHAR c; #endif /* CK_ANSIC */ { /* xdul1 */ /* Dutch ISO 646 to Latin-1 */ if (c & 0x80) return(UNK); return(ydul1[c]); } CHAR #ifdef CK_ANSIC xfil1(CHAR c) #else xfil1(c) CHAR c; #endif /* CK_ANSIC */ { /* xfil1 */ /* Finnish ISO 646 to Latin-1 */ if (c & 0x80) return(UNK); return(yfil1[c]); } CHAR #ifdef CK_ANSIC xl1fi(CHAR c) #else xl1fi(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1fi */ /* Latin-1 to Finnish ISO 646 */ return(yl1fi[c]); } CHAR #ifdef CK_ANSIC xfcl1(CHAR c) #else xfcl1(c) CHAR c; #endif /* CK_ANSIC */ { /* xfcl1 */ /* French Canadian ISO646 to Latin-1 */ if (c & 0x80) return(UNK); return(yfcl1[c]); } CHAR #ifdef CK_ANSIC xl1fc(CHAR c) #else xl1fc(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1fc */ /* Latin-1 to French Canadian ISO646 */ return(yl1fc[c]); } CHAR #ifdef CK_ANSIC xitl1(CHAR c) #else xitl1(c) CHAR c; #endif /* CK_ANSIC */ { /* xitl1 */ /* Italian ISO 646 to Latin-1 */ if (c & 0x80) return(UNK); return(yitl1[c]); } CHAR #ifdef CK_ANSIC xl1it(CHAR c) #else xl1it(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1it */ /* Latin-1 to Italian ISO 646 */ return(yl1it[c]); } CHAR #ifdef CK_ANSIC xnel1(CHAR c) #else xnel1(c) CHAR c; #endif /* CK_ANSIC */ { /* xnel1 */ /* NeXT to Latin-1 */ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */ if (c == 234) { /* handle OE digraph. */ zmstuff('E'); return('O'); } else if (c == 250) { /* Also lowercase oe. */ zmstuff('e'); return('o'); } } return(ynel1[c]); } CHAR #ifdef CK_ANSIC xnel9(CHAR c) #else xnel9(c) CHAR c; #endif /* CK_ANSIC */ { /* xnel9 */ /* NeXT to Latin-9 */ switch (c) { case 234: return(188); /* OE */ case 250: return(189); /* oe */ case 188: return(234); /* keep it invertible... */ case 189: return(250); /* oe */ default: return(ynel1[c]); } } CHAR #ifdef CK_ANSIC xl1ne(CHAR c) #else xl1ne(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1ne */ /* Latin-1 to NeXT */ return(yl1ne[c]); } CHAR #ifdef CK_ANSIC xl9ne(CHAR c) #else xl9ne(c) CHAR c; #endif /* CK_ANSIC */ { /* xl9ne */ /* Latin-9 to NeXT */ switch (c) { case 188: return(234); /* OE */ case 189: return(250); /* oe */ case 234: return(188); /* OE */ case 250: return(189); /* oe */ default: return(yl1ne[c]); } } CHAR #ifdef CK_ANSIC xnol1(CHAR c) #else xnol1(c) CHAR c; #endif /* CK_ANSIC */ { /* xnol1 */ /* Norway/Denmark ISO 646 to Latin-1 */ if (c & 0x80) return(UNK); return(ynol1[c]); } CHAR #ifdef CK_ANSIC xl1no(CHAR c) #else xl1no(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1no */ /* Latin-1 to Norway/Denmark ISO 646 */ return(yl1no[c]); } CHAR #ifdef CK_ANSIC xpol1(CHAR c) #else xpol1(c) CHAR c; #endif /* CK_ANSIC */ { /* xpol1 */ /* Portuguese ISO 646 to Latin-1 */ if (c & 0x80) return(UNK); return(ypol1[c]); } CHAR #ifdef CK_ANSIC xl1po(CHAR c) #else xl1po(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1po */ /* Latin-1 to Portuguese ISO 646 */ return(yl1po[c]); } CHAR #ifdef CK_ANSIC xspl1(CHAR c) #else xspl1(c) CHAR c; #endif /* CK_ANSIC */ { /* xspl1 */ /* Spanish ISO 646 to Latin-1 */ if (c & 0x80) return(UNK); return(yspl1[c]); } CHAR #ifdef CK_ANSIC xl1sp(CHAR c) #else xl1sp(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1sp */ /* Latin-1 to Spanish ISO 646 */ return(yl1sp[c]); } CHAR #ifdef CK_ANSIC xswl1(CHAR c) #else xswl1(c) CHAR c; #endif /* CK_ANSIC */ { /* xswl1 */ /* Swedish ISO 646 to Latin-1 */ if (c & 0x80) return(UNK); return(yswl1[c]); } CHAR #ifdef CK_ANSIC xl1sw(CHAR c) #else xl1sw(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1sw */ /* Latin-1 to Swedish ISO 646 */ return(yl1sw[c]); } CHAR #ifdef CK_ANSIC xchl1(CHAR c) #else xchl1(c) CHAR c; #endif /* CK_ANSIC */ { /* xchl1 */ /* Swiss ISO 646 to Latin-1 */ if (c & 0x80) return(UNK); return(ychl1[c]); } CHAR #ifdef CK_ANSIC xl1ch(CHAR c) #else xl1ch(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1ch */ /* Latin-1 to Swiss ISO 646 */ return(yl1ch[c]); } CHAR #ifdef CK_ANSIC xhul1(CHAR c) #else xhul1(c) CHAR c; #endif /* CK_ANSIC */ { /* xhul1 */ /* Hungarian ISO 646 to Latin-1 */ if (c & 0x80) return(UNK); return(yhul1[c]); } CHAR #ifdef CK_ANSIC xl1hu(CHAR c) #else xl1hu(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1hu */ /* Latin-1 to Hungarian ISO 646 */ return(yl1hu[c]); } CHAR #ifdef CK_ANSIC xl1dm(CHAR c) #else xl1dm(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1dm */ /* Latin-1 to DEC MCS */ return(yl1dm[c]); } CHAR #ifdef CK_ANSIC xl9dm(CHAR c) #else xl9dm(c) CHAR c; #endif /* CK_ANSIC */ { /* xl9dm */ /* Latin-9 to DEC MCS */ switch (c) { case 188: return(215); case 189: return(247); case 215: return(188); case 247: return(189); default: return(yl1dm[c]); } } CHAR #ifdef CK_ANSIC xl9w1(CHAR c) #else xl9w1(c) CHAR c; #endif /* CK_ANSIC */ { /* xl9w1 */ /* Latin-9 to CP1252 */ if (c < 128) return(c); else if (c < 160) return('?'); switch (c) { case 0xa4: return(0x80); /* Euro */ case 0xa6: return(0x8a); /* S-caron */ case 0xa8: return(0x9a); /* s-caron */ case 0xb4: return(0x8e); /* Z-caron */ case 0xb8: return(0x9e); /* z-caron */ case 0xbc: return(0x8c); /* OE */ case 0xbd: return(0x9c); /* oe */ case 0xbe: return(0x9f); /* Y-diaeresis */ default: return(c); } } CHAR #ifdef CK_ANSIC xl1dg(CHAR c) #else xl1dg(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1dg */ /* Latin-1 to DG ICS */ return(yl1dg[c]); } CHAR #ifdef CK_ANSIC xdml1(CHAR c) #else xdml1(c) CHAR c; #endif /* CK_ANSIC */ { /* xdml1 */ /* DEC MCS to Latin-1 */ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */ if (c == 215) { /* handle OE digraph. */ zmstuff('E'); return('O'); } else if (c == 247) { /* Also lowercase oe. */ zmstuff('e'); return('o'); } } return(ydml1[c]); } CHAR #ifdef CK_ANSIC xdml9(CHAR c) #else xdml9(c) CHAR c; #endif /* CK_ANSIC */ { /* xdml9 */ /* DEC MCS to Latin-9 */ switch (c) { case 215: return(188); /* OE */ case 247: return(189); /* oe */ case 188: return(215); /* and swap the other two... */ case 189: return(247); /* (1/4 and 1/2) */ default: /* to keep it invertible */ return(ydml1[c]); } } CHAR #ifdef CK_ANSIC xdgl1(CHAR c) #else xdgl1(c) CHAR c; #endif /* CK_ANSIC */ { /* xdgl1 */ /* DG International CS to Latin-1 */ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */ if (c == 215) { /* handle OE digraph. */ zmstuff('E'); return('O'); } else if (c == 247) { /* Also lowercase oe. */ zmstuff('e'); return('o'); } } return(ydgl1[c]); } CHAR #ifdef CK_ANSIC xr8l1(CHAR c) #else xr8l1(c) CHAR c; #endif /* CK_ANSIC */ { /* xr8l1 */ /* Hewlett Packard Roman8 to Latin-1 */ return(yr8l1[c]); } CHAR #ifdef CK_ANSIC xl1r8(CHAR c) #else xl1r8(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1r8 */ /* Latin-1 to Hewlett Packard Roman8 */ return(yl1r8[c]); } /* Translation functions for receiving files and translating them into ASCII */ CHAR #ifdef CK_ANSIC zl1as(CHAR c) #else zl1as(c) CHAR c; #endif /* CK_ANSIC */ { /* zl1as */ switch(langs[language].id) { case L_DUTCH: if (c == 255) { /* Dutch umlaut-y */ zdstuff('j'); /* becomes ij */ return('i'); } else return(yl1as[c]); /* all others by the book */ case L_GERMAN: switch (c) { /* German, special rules. */ case 196: /* umlaut-A -> Ae */ zdstuff('e'); return('A'); case 214: /* umlaut-O -> Oe */ zdstuff('e'); return('O'); case 220: /* umlaut-U -> Ue */ zdstuff('e'); return('U'); case 228: /* umlaut-a -> ae */ zdstuff('e'); return('a'); case 246: /* umlaut-o -> oe */ zdstuff('e'); return('o'); case 252: /* umlaut-u -> ue */ zdstuff('e'); return('u'); case 223: /* ess-zet -> ss */ zdstuff('s'); return('s'); default: return(yl1as[c]); /* all others by the book */ } case L_DANISH: case L_FINNISH: case L_NORWEGIAN: case L_SWEDISH: switch (c) { /* Scandanavian languages. */ case 196: /* umlaut-A -> Ae */ zdstuff('e'); return('A'); case 214: /* umlaut-O -> Oe */ case 216: /* O-slash -> Oe */ zdstuff('e'); return('O'); case 220: /* umlaut-U -> Y */ /* return('Y'); */ zdstuff('e'); return('U'); case 228: /* umlaut-a -> ae */ zdstuff('e'); return('a'); case 246: /* umlaut-o -> oe */ case 248: /* o-slash -> oe */ zdstuff('e'); return('o'); case 252: /* umlaut-u -> y */ /* return('y'); */ zdstuff('e'); return('u'); case 197: /* A-ring -> Aa */ zdstuff('a'); return('A'); case 229: /* a-ring -> aa */ zdstuff('a'); return('a'); default: return(yl1as[c]); /* All others by the book */ } default: return(yl1as[c]); /* No language, go by the table. */ } } CHAR /* IBM CP437 to Latin-1 */ #ifdef CK_ANSIC x43l1(CHAR c) #else x43l1(c) CHAR c; #endif /* CK_ANSIC */ { /* x43l1 */ return(y43l1[c]); } CHAR /* IBM CP850 to Latin-1 */ #ifdef CK_ANSIC x85l1(CHAR c) #else x85l1(c) CHAR c; #endif /* CK_ANSIC */ { /* x85l1 */ return(y85l1[c]); } CHAR /* Latin-1 to IBM CP437 */ #ifdef CK_ANSIC xl143(CHAR c) #else xl143(c) CHAR c; #endif /* CK_ANSIC */ { /* xl143 */ return(yl143[c]); } CHAR /* Latin-1 to CP850 */ #ifdef CK_ANSIC xl185(CHAR c) #else xl185(c) CHAR c; #endif /* CK_ANSIC */ { /* xl185 */ return(yl185[c]); } CHAR #ifdef CK_ANSIC x43as(CHAR c) #else x43as(c) CHAR c; #endif /* CK_ANSIC */ { /* x43as */ /* CP437 to ASCII */ c = y43l1[c]; /* Translate to Latin-1 */ return(xl143(c)); /* and from Latin-1 to ASCII. */ } CHAR #ifdef CK_ANSIC x85as(CHAR c) #else x85as(c) CHAR c; #endif /* CK_ANSIC */ { /* x85as */ /* CP850 to ASCII */ c = y85l1[c]; /* Translate to Latin-1 */ return(xl1as(c)); /* and from Latin-1 to ASCII. */ } CHAR /* Macintosh Latin to Latin-1 */ #ifdef CK_ANSIC xaql1(CHAR c) #else xaql1(c) CHAR c; #endif /* CK_ANSIC */ { /* xaql1 */ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */ if (c == 206) { /* handle OE digraph. */ zmstuff('E'); return('O'); } else if (c == 207) { /* Also lowercase oe. */ zmstuff('e'); return('o'); } } return(yaql1[c]); } CHAR /* Macintosh Latin to ASCII */ #ifdef CK_ANSIC xaqas(CHAR c) #else xaqas(c) CHAR c; #endif /* CK_ANSIC */ { /* xaqas */ if (langs[language].id == L_FRENCH) { /* If SET LANGUAGE FRENCH */ if (c == 206) { /* handle OE digraph. */ zmstuff('E'); return('O'); } else if (c == 207) { /* Also lowercase oe. */ zmstuff('e'); return('o'); } } c = yaql1[c]; /* Translate to Latin-1 */ return(xl1as(c)); /* then to ASCII. */ } CHAR /* Latin-1 to Macintosh Latin */ #ifdef CK_ANSIC xl1aq(CHAR c) #else xl1aq(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1aq */ return(yl1aq[c]); } #ifdef LATIN2 /* Translation functions for Latin Alphabet 2 */ CHAR /* Latin-2 to Latin-1 */ #ifdef CK_ANSIC xl2l1(CHAR c) #else xl2l1(c) CHAR c; #endif /* CK_ANSIC */ { /* xll2l1 */ return(yl2l1[c]); } CHAR #ifdef CK_ANSIC xl2w1(CHAR c) #else xl2w1(c) CHAR c; #endif /* CK_ANSIC */ { /* xl2w1 */ /* Latin-2 to CP1252 (Windows L1) */ if (c > 127 && c < 160) return(UNK); else return(yl2l1[c]); } CHAR /* Latin-1 to Latin-2 */ #ifdef CK_ANSIC xl1l2(CHAR c) #else xl1l2(c) CHAR c; #endif /* CK_ANSIC */ { /* xll1l2 */ return(yl1l2[c]); } CHAR /* CP1252 to Latin-1 */ #ifdef CK_ANSIC xw1l2(CHAR c) #else xw1l2(c) CHAR c; #endif /* CK_ANSIC */ { /* xw1l2 */ switch (c) { case 0x8a: return(0xa9); /* S caron */ case 0x8e: return(0xae); /* Z caron */ case 0x9a: return(0xb9); /* s caron */ case 0x9e: return(0xbe); /* z caron */ default: return((c < 160) ? xw1as(c) : xl1l2(c)); } } CHAR /* Latin-2 to ASCII */ #ifdef CK_ANSIC xl2as(CHAR c) #else xl2as(c) CHAR c; #endif /* CK_ANSIC */ { /* xll2as */ return(yl2as[c]); } CHAR /* Latin-2 to CP852 */ #ifdef CK_ANSIC xl252(CHAR c) #else xl252(c) CHAR c; #endif /* CK_ANSIC */ { /* xll252 */ return(yl252[c]); } CHAR /* Latin-2 to Mazovia */ #ifdef CK_ANSIC xl2mz(CHAR c) #else xl2mz(c) CHAR c; #endif /* CK_ANSIC */ { /* xll2mz */ return(yl2mz[c]); } CHAR /* Latin-1 to Mazovia */ #ifdef CK_ANSIC xl1mz(CHAR c) #else xl1mz(c) CHAR c; #endif /* CK_ANSIC */ { /* xll1mz */ return(yl2mz[yl1l2[c]]); } CHAR /* Mazovia to Latin-1 */ #ifdef CK_ANSIC xmzl1(CHAR c) #else xmzl1(c) CHAR c; #endif /* CK_ANSIC */ { /* xmzl1 */ return(yl2l1[ymzl2[c]]); } CHAR /* Mazovia to Latin-9 */ #ifdef CK_ANSIC xmzl9(CHAR c) #else xmzl9(c) CHAR c; #endif /* CK_ANSIC */ { /* xmzl9 */ return(xl2l9(ymzl2[c])); } CHAR /* CP852 to Latin-2 */ #ifdef CK_ANSIC x52l2(CHAR c) #else x52l2(c) CHAR c; #endif /* CK_ANSIC */ { /* x52l2 */ return(y52l2[c]); } CHAR /* Mazovia to Latin-2 */ #ifdef CK_ANSIC xmzl2(CHAR c) #else xmzl2(c) CHAR c; #endif /* CK_ANSIC */ { /* xmzl2 */ return(ymzl2[c]); } CHAR /* Latin-2 to CP1250 */ #ifdef CK_ANSIC xl21250(CHAR c) #else xl21250(c) CHAR c; #endif /* CK_ANSIC */ { /* xll21250 */ return(yl21250[c]); } CHAR /* CP1250 to Latin-2 */ #ifdef CK_ANSIC x1250l2(CHAR c) #else x1250l2(c) CHAR c; #endif /* CK_ANSIC */ { /* x1250l2 */ return(y1250l2[c]); } CHAR /* CP852 to ASCII */ #ifdef CK_ANSIC x52as(CHAR c) #else x52as(c) CHAR c; #endif /* CK_ANSIC */ { /* xl52as */ return(yl2as[y52l2[c]]); /* CP852 -> Latin-2 -> ASCII */ } CHAR /* CP1250 to ASCII */ #ifdef CK_ANSIC x1250as(CHAR c) #else x1250as(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1250as */ return(yl2as[y1250l2[c]]); /* CP81250 -> Latin-2 -> ASCII */ } CHAR /* CP852 to Latin-1 */ #ifdef CK_ANSIC x52l1(CHAR c) #else x52l1(c) CHAR c; #endif /* CK_ANSIC */ { /* xl52l1 */ return(yl2l1[y52l2[c]]); /* CP852 -> Latin-2 -> Latin-1 */ } CHAR /* CP1250 to Latin-1 */ #ifdef CK_ANSIC x1250l1(CHAR c) #else x1250l1(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1250l1 */ return(yl2l1[y1250l2[c]]); /* CP1250 -> Latin-2 -> Latin-1 */ } CHAR /* CP1250 to Latin-9 */ #ifdef CK_ANSIC x1250l9(CHAR c) #else x1250l9(c) CHAR c; #endif /* CK_ANSIC */ { /* x1250l9 */ if (c == (CHAR)128) /* Euro */ return((CHAR)164); else return(xl2l9(y1250l2[c])); /* CP1250 -> Latin-2 -> Latin-9 */ } CHAR /* Latin-1 to CP852 */ #ifdef CK_ANSIC xl152(CHAR c) #else xl152(c) CHAR c; #endif /* CK_ANSIC */ { /* xll152 */ return(yl252[yl1l2[c]]); /* Latin-1 -> Latin-2 -> CP852 */ } CHAR /* Latin-1 to CP1250 */ #ifdef CK_ANSIC xl11250(CHAR c) #else xl11250(c) CHAR c; #endif /* CK_ANSIC */ { /* xll11250 */ return(yl21250[yl1l2[c]]); /* Latin-1 -> Latin-2 -> CP1250 */ } CHAR /* Latin-9 to CP1250 */ #ifdef CK_ANSIC xl91250(CHAR c) #else xl91250(c) CHAR c; #endif /* CK_ANSIC */ { /* xll91250 */ if (c == (CHAR)164) /* Euro */ return((CHAR)128); else return(yl21250[xl9l2(c)]); /* Latin-9 -> Latin-2 -> CP1250 */ } CHAR /* Latin-9 to Mazovia */ #ifdef CK_ANSIC xl9mz(CHAR c) #else xl9mz(c) CHAR c; #endif /* CK_ANSIC */ { /* xll9mz */ return(yl2mz[xl9l2(c)]); /* Latin-9 -> Latin-2 -> Mazovia */ } CHAR /* Latin-9 to Mazovia */ #ifdef CK_ANSIC xmzas(CHAR c) #else xmzas(c) CHAR c; #endif /* CK_ANSIC */ { /* xmzas */ return(yl2as[xmzl2(c)]); /* Mazovia -> Latin-2 -> ASCII */ } CHAR /* Latin-2 to NeXT */ #ifdef CK_ANSIC xl2ne(CHAR c) #else xl2ne(c) CHAR c; #endif /* CK_ANSIC */ { /* xll2ne */ switch(c) { case 162: return(198); /* Breve */ case 163: return(232); /* L with stroke */ case 178: return(206); /* Ogonek */ case 179: return(248); /* l with stroke */ case 183: return(207); /* Caron */ case 189: return(205); /* Double acute */ case 208: return(144); /* D stroke = Eth */ case 240: return(230); /* d stroke = eth */ case 255: return(199); /* Dot above */ default: return(yl1ne[yl2l1[c]]); } } CHAR /* Latin-2 to CP437 */ #ifdef CK_ANSIC xl243(CHAR c) #else xl243(c) CHAR c; #endif /* CK_ANSIC */ { /* xll243 */ return(yl1l2[y43l1[c]]); } CHAR /* Latin-2 to CP850 */ #ifdef CK_ANSIC xl285(CHAR c) #else xl285(c) CHAR c; #endif /* CK_ANSIC */ { /* xll285 */ return(yl1l2[y85l1[c]]); } CHAR /* Latin-2 to Apple */ #ifdef CK_ANSIC xl2aq(CHAR c) #else xl2aq(c) CHAR c; #endif /* CK_ANSIC */ { /* xl2aq */ return(yl1aq[yl2l1[c]]); /* Could do more... */ } CHAR /* Latin-2 to DGI */ #ifdef CK_ANSIC xl2dg(CHAR c) #else xl2dg(c) CHAR c; #endif /* CK_ANSIC */ { /* xll2dg */ return(ydgl1[yl1l2[c]]); } CHAR /* Latin-2 to Short KOI */ #ifdef CK_ANSIC xl2sk(CHAR c) #else xl2sk(c) CHAR c; #endif /* CK_ANSIC */ { /* xll2sk */ return(islower(c) ? toupper(c) : c); } CHAR /* NeXT to Latin-2 */ #ifdef CK_ANSIC xnel2(CHAR c) #else xnel2(c) CHAR c; #endif /* CK_ANSIC */ { /* xnel2 */ switch (c) { case 144: return(208); /* D stroke = Eth */ case 198: return(162); /* Breve */ case 199: return(255); /* Dot above */ case 205: return(189); /* Double acute */ case 206: return(178); /* Ogonek */ case 207: return(183); /* Caron */ case 230: return(240); /* d stroke = eth */ case 232: return(163); /* L with stroke */ case 248: return(179); /* l with stroke */ default: return(yl1l2[ynel1[c]]); /* Others, go thru Latin-1 */ } } CHAR /* CP437 to Latin-2 */ #ifdef CK_ANSIC x43l2(CHAR c) #else x43l2(c) CHAR c; #endif /* CK_ANSIC */ { /* xl43l2 */ return(yl1l2[y43l1[c]]); } CHAR /* CP850 to Latin-2 */ #ifdef CK_ANSIC x85l2(CHAR c) #else x85l2(c) CHAR c; #endif /* CK_ANSIC */ { /* xl85l2 */ return(yl1l2[y85l1[c]]); } CHAR /* Apple to Latin-2 */ #ifdef CK_ANSIC xaql2(CHAR c) #else xaql2(c) CHAR c; #endif /* CK_ANSIC */ { /* xlaql2 */ switch (c) { case 249: return(162); /* Breve accent */ case 250: return(255); /* Dot accent */ case 253: return(189); /* Double acute */ default: return(yl1l2[yaql1[c]]); } } CHAR /* DGI to Latin-2 */ #ifdef CK_ANSIC xdgl2(CHAR c) #else xdgl2(c) CHAR c; #endif /* CK_ANSIC */ { /* xldgl2 */ return(yl1l2[ydgl1[c]]); /* (for now) */ } CHAR /* Short KOI to Latin-2 */ #ifdef CK_ANSIC xskl2(CHAR c) #else xskl2(c) CHAR c; #endif /* CK_ANSIC */ { /* xlskl2 */ return(islower(c) ? toupper(c) : c); } CHAR /* Latin-2 to German */ #ifdef CK_ANSIC xl2ge(CHAR c) #else xl2ge(c) CHAR c; #endif /* CK_ANSIC */ { /* xll2ge */ switch(c) { case 167: return(64); /* Paragraph sign */ case 196: return(91); /* A-diaeresis */ case 214: return(92); /* O-diaeresis */ case 220: return(93); /* U-diaeresis */ case 223: return(126); /* double-s */ case 228: return(123); /* a-diaeresis */ case 246: return(124); /* o-diaeresis */ case 252: return(125); /* u-diaeresis */ default: return(yl2as[c]); /* Others */ } } CHAR /* German to Latin-2 */ #ifdef CK_ANSIC xgel2(CHAR c) #else xgel2(c) CHAR c; #endif /* CK_ANSIC */ { /* xlgel2 */ if (c & 0x80) return(UNK); switch(c) { case 64: return(167); /* Paragraph sign */ case 91: return(196); /* A-diaeresis */ case 92: return(214); /* O-diaeresis */ case 93: return(220); /* U-diaeresis */ case 123: return(228); /* a-diaeresis */ case 126: return(223); /* double-s */ case 124: return(246); /* o-diaeresis */ case 125: return(252); /* u-diaeresis */ default: return(c); /* Others */ } } CHAR /* Latin-2 to Hungarian */ #ifdef CK_ANSIC xl2hu(CHAR c) #else xl2hu(c) CHAR c; #endif /* CK_ANSIC */ { /* xll2hu */ switch(c) { case 164: return(36); /* Currency symbol */ case 189: return(126); /* Double acute accent */ case 193: return(64); /* A-acute */ case 201: return(91); /* E-acute */ case 214: return(92); /* O-diaeresis */ case 220: return(93); /* U-diaeresis */ case 225: return(96); /* a-acute */ case 233: return(123); /* e-acute */ case 246: return(124); /* o-diaeresis */ case 252: return(125); /* u-diaeresis */ default: return(yl2as[c]); /* Others */ } } CHAR /* Hungarian to Latin-2 */ #ifdef CK_ANSIC xhul2(CHAR c) #else xhul2(c) CHAR c; #endif /* CK_ANSIC */ { /* xlhul2 */ if (c & 0x80) return(UNK); switch(c) { case 36: return(164); /* Currency symbol */ case 64: return(193); /* A-acute */ case 91: return(201); /* E-acute */ case 92: return(214); /* O-diaeresis */ case 93: return(220); /* U-diaeresis */ case 96: return(225); /* a-acute */ case 123: return(233); /* e-acute */ case 124: return(246); /* o-diaeresis */ case 125: return(252); /* u-diaeresis */ case 126: return(189); /* Double acute accent */ default: return(c); /* Others */ } } CHAR #ifdef CK_ANSIC xr8l2(CHAR c) #else xr8l2(c) CHAR c; #endif /* CK_ANSIC */ { /* xr8l2 */ /* Hewlett Packard Roman8 to Latin-2 */ switch (c) { case 235: return(169); /* S caron */ case 236: return(185); /* s caron */ default: return(yl1l2[yr8l1[c]]); } } CHAR #ifdef CK_ANSIC xl2r8(CHAR c) #else xl2r8(c) CHAR c; #endif /* CK_ANSIC */ { /* xl2r8 */ /* Latin-2 to Hewlett Packard Roman8 Character Set */ switch (c) { case 169: return(235); /* S caron */ case 185: return(236); /* s caron */ default: return(yr8l1[yl1l2[c]]); } } #else /* NOLATIN2 */ #define xl1mz NULL #define xmzl1 NULL #define xl2mz NULL #define xmzl2 NULL #define xl9mz NULL #define xmzl9 NULL #define xmzas NULL #define xl11250 NULL #define xl21250 NULL #define xl91250 NULL #define x1250as NULL #define x1250l1 NULL #define x1250l2 NULL #define x1250l9 NULL #define xl2l1 NULL #define xl2w1 NULL #define xl1l2 NULL #define xw1l2 NULL #define xl2as NULL #define xl252 NULL #define x52l2 NULL #define x52as NULL #define x52l1 NULL #define xl152 NULL #define xl2ne NULL #define xl243 NULL #define xl285 NULL #define xl2aq NULL #define xl2dg NULL #define xl2sk NULL #define xnel2 NULL #define x43l2 NULL #define x85l2 NULL #define xaql2 NULL #define xdgl2 NULL #define xskl2 NULL #define xl2ge NULL #define xgel2 NULL #define xl2hu NULL #define xhul2 NULL #define xl2r8 NULL #define xr8l2 NULL #endif /* LATIN2 */ /* This one can also be used for ELOT 927, Hebrew 7, etc */ CHAR #ifdef CK_ANSIC xassk(CHAR c) #else xassk(c) CHAR c; #endif /* CK_ANSIC */ { /* xassk */ /* ASCII to Short KOI */ if (c & 0x80) return(UNK); return((c > 95) ? (c - 32) : c); /* Fold columns 6-7 to 4-5 */ } #ifdef CYRILLIC /* Translation functions for Cyrillic character sets */ CHAR /* Latin/Cyrillic to CP866 */ #ifdef CK_ANSIC xlcac(CHAR c) #else xlcac(c) CHAR c; #endif /* CK_ANSIC */ { /* xlcac */ /* PC Code Page 866 */ return(ylcac[c]); } CHAR /* Latin/Cyrillic to */ #ifdef CK_ANSIC xlc55(CHAR c) #else xlc55(c) CHAR c; #endif /* CK_ANSIC */ { /* xlc55 */ /* PC Code Page 855 */ return(ylc55[c]); } CHAR /* Latin/Cyrillic to */ #ifdef CK_ANSIC xlc1251(CHAR c) #else xlc1251(c) CHAR c; #endif /* CK_ANSIC */ { /* xlc1251 */ /* PC Code Page 1251 */ return(ylc1251[c]); } CHAR /* Latin/Cyrillic to... */ #ifdef CK_ANSIC xlcbu(CHAR c) #else xlcbu(c) CHAR c; #endif /* CK_ANSIC */ { /* xlcbu */ /* Bulgarian PC Code Page */ return(ylcbu[c]); } CHAR /* Latin/Cyrillic to Old KOI-8 */ #ifdef CK_ANSIC xlck8(CHAR c) #else xlck8(c) CHAR c; #endif /* CK_ANSIC */ { /* xlck8 */ return(ylck8[c]); } CHAR /* Latin/Cyrillic to KOI8-R */ #ifdef CK_ANSIC xlckr(CHAR c) #else xlckr(c) CHAR c; #endif /* CK_ANSIC */ { /* xlckr */ switch(c) { case 0xa1: return(0xb3); /* Io */ case 0xf1: return(0xa3); /* io */ default: if (c > 0x7f && c < 0xc0) return(UNK); return(ylck8[c]); } } CHAR /* Latin/Cyrillic to KOI8-U */ #ifdef CK_ANSIC xlcku(CHAR c) #else xlcku(c) CHAR c; #endif /* CK_ANSIC */ { /* xlcku */ switch(c) { case 0xa1: return(0xb3); /* Io */ case 0xf1: return(0xa3); /* io */ case 0xf4: return(0xa4); /* Ukrainian ie */ case 0xf6: return(0xa6); /* Ukrainian i */ case 0xf7: return(0xa7); /* Ukrainian yi */ case 0xf3: return(0xad); /* Ukrainian ghe with upturn */ case 0xa4: return(0xb4); /* Ukrainian Ie */ case 0xa6: return(0xb6); /* Ukrainian I */ case 0xa7: return(0xb7); /* Ukrainian Yi */ case 0xa3: return(0xbd); /* Ukrainian Ghe with upturn */ default: if (c > 0x7f && c < 0xc0) return(UNK); return(ylck8[c]); } } CHAR #ifdef CK_ANSIC xlcsk(CHAR c) #else xlcsk(c) CHAR c; #endif /* CK_ANSIC */ { /* xlcsk */ /* Latin/Cyrillic to Short KOI */ return(ylcsk[c]); } CHAR #ifdef CK_ANSIC xlcas(CHAR c) #else xlcas(c) CHAR c; #endif /* CK_ANSIC */ { /* xlcas */ /* Latin/Cyrillic to ASCII */ if (langs[language].id == L_RUSSIAN) return(ylcsk[c]); else return((c > 127) ? '?' : c); } CHAR /* CP866 */ #ifdef CK_ANSIC xaclc(CHAR c) #else xaclc(c) CHAR c; #endif /* CK_ANSIC */ { /* xaclc */ /* to Latin/Cyrillic */ return(yaclc[c]); } CHAR /* CP855 */ #ifdef CK_ANSIC x55lc(CHAR c) #else x55lc(c) CHAR c; #endif /* CK_ANSIC */ { /* x55lc */ /* to Latin/Cyrillic */ return(y55lc[c]); } CHAR /* Bulgarian PC Code Page ... */ #ifdef CK_ANSIC xbulc(CHAR c) #else xbulc(c) CHAR c; #endif /* CK_ANSIC */ { /* xbulc */ /* to Latin/Cyrillic */ return(ybulc[c]); } CHAR /* CP1251 */ #ifdef CK_ANSIC x1251lc(CHAR c) #else x1251lc(c) CHAR c; #endif /* CK_ANSIC */ { /* x1251lc */ /* to Latin/Cyrillic */ return(y1251lc[c]); } CHAR /* Old KOI-8 to Latin/Cyrillic */ #ifdef CK_ANSIC xk8lc(CHAR c) #else xk8lc(c) CHAR c; #endif /* CK_ANSIC */ { /* xk8lc */ return(yk8lc[c]); } CHAR /* KOI8-R to Latin/Cyrillic */ #ifdef CK_ANSIC xkrlc(CHAR c) #else xkrlc(c) CHAR c; #endif /* CK_ANSIC */ { /* xkrlc */ if (c == 0xb3) return(0xa1); else if (c == 0xa3) return(0xf1); else if (c > 0x7f && c < 0xc0) return(UNK); return(yk8lc[c]); } CHAR /* KOI8-U to Latin/Cyrillic */ #ifdef CK_ANSIC xkulc(CHAR c) #else xkulc(c) CHAR c; #endif /* CK_ANSIC */ { /* xkulc */ switch (c) { case 0xb3: return(0xa1); /* Io */ case 0xa3: return(0xf1); /* io */ case 0xa4: return(0xf4); /* Ukrainian ie */ case 0xa6: return(0xf6); /* Ukrainian i */ case 0xa7: return(0xf7); /* Ukrainian yi */ case 0xad: return(0xf3); /* Ukrainian ghe with upturn */ case 0xb4: return(0xa4); /* Ukrainian Ie */ case 0xb6: return(0xa6); /* Ukrainian I */ case 0xb7: return(0xa7); /* Ukrainian Yi */ case 0xbd: return(0xa3); /* Ukrainian Ghe with upturn */ /* Note substitution of Gje for Ghe-Upturn, which is not in 8859-5 */ default: if (c > 0x7f && c < 0xc0) return(UNK); return(yk8lc[c]); } } CHAR #ifdef CK_ANSIC xskcy(CHAR c) #else xskcy(c) CHAR c; #endif /* CK_ANSIC */ { /* xskcy */ /* Short KOI to Latin/Cyrillic */ return(yskcy[c & 0x7f]); } CHAR #ifdef CK_ANSIC xascy(CHAR c) #else xascy(c) CHAR c; #endif /* CK_ANSIC */ { /* xascy */ /* ASCII to Latin/Cyrillic */ if (langs[language].id == L_RUSSIAN) { /* If LANGUAGE == RUSSIAN */ return(yskcy[c & 0x7f]); /* treat ASCII as Short KOI */ } else return((c > 127) ? '?' : c); } CHAR #ifdef CK_ANSIC xacas(CHAR c) #else xacas(c) CHAR c; #endif /* CK_ANSIC */ { /* xacas */ /* CP866 to ASCII */ if (langs[language].id == L_RUSSIAN) { c = yaclc[c]; /* First to Latin/Cyrillic */ return(ylcsk[c]); /* Then to Short KOI */ } else return((c > 127) ? '?' : c); } CHAR #ifdef CK_ANSIC x55as(CHAR c) #else x55as(c) CHAR c; #endif /* CK_ANSIC */ { /* x55as */ /* CP855 to ASCII */ if (langs[language].id == L_RUSSIAN) { c = y55lc[c]; /* First to Latin/Cyrillic */ return(ylcsk[c]); /* Then to Short KOI */ } else return((c > 127) ? '?' : c); } CHAR #ifdef CK_ANSIC x1251as(CHAR c) #else x1251as(c) CHAR c; #endif /* CK_ANSIC */ { /* x1251as */ /* CP81251 to ASCII */ if (langs[language].id == L_RUSSIAN) { c = y1251lc[c]; /* First to Latin/Cyrillic */ return(ylcsk[c]); /* Then to Short KOI */ } else return((c > 127) ? '?' : c); } CHAR #ifdef CK_ANSIC xskas(CHAR c) #else xskas(c) CHAR c; #endif /* CK_ANSIC */ { /* xskas */ /* Short KOI to ASCII */ return((c > 95) ? '?' : c); } CHAR #ifdef CK_ANSIC xk8as(CHAR c) #else xk8as(c) CHAR c; #endif /* CK_ANSIC */ { /* xk8as */ /* Old KOI-8 Cyrillic to ASCII */ if (langs[language].id == L_RUSSIAN) { c = yk8lc[c]; /* First to Latin/Cyrillic */ return(ylcsk[c]); /* Then to Short KOI */ } else return((c > 127) ? '?' : c); } CHAR #ifdef CK_ANSIC xl1sk(CHAR c) #else xl1sk(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1sk */ /* Latin-1 to Short KOI */ c = zl1as(c); /* Convert to ASCII */ return(c = xassk(c)); /* Convert ASCII to Short KOI */ } CHAR #ifdef CK_ANSIC xw1lc(CHAR c) #else xw1lc(c) CHAR c; #endif /* CK_ANSIC */ { /* xw1lc */ /* CP1252 to Latin/Cyrillic */ return((c < 160) ? xw1as(c) : zl1as(c)); } CHAR #ifdef CK_ANSIC xaslc(CHAR c) #else xaslc(c) CHAR c; #endif /* CK_ANSIC */ { /* xaslc */ /* ASCII to Latin/Cyrillic */ if (langs[language].id == L_RUSSIAN) return(yskcy[c & 0x7f]); else return(c & 0x7f); } CHAR #ifdef CK_ANSIC xasac(CHAR c) #else xasac(c) CHAR c; #endif /* CK_ANSIC */ { /* xasac */ /* ASCII to CP866 */ if (c & 0x80) return(UNK); if (langs[language].id == L_RUSSIAN) { /* Use Short KOI */ c = xskcy(c); /* Translate to Latin/Cyrillic */ return(ylcac[c]); /* Then to CP866 */ } else return(c & 0x7f); } CHAR #ifdef CK_ANSIC xas55(CHAR c) #else xas55(c) CHAR c; #endif /* CK_ANSIC */ { /* xas55 */ /* ASCII to CP855 */ if (c & 0x80) return(UNK); if (langs[language].id == L_RUSSIAN) { /* Use Short KOI */ c = xskcy(c); /* Translate to Latin/Cyrillic */ return(ylc55[c]); /* Then to CP866 */ } else return(c & 0x7f); } CHAR #ifdef CK_ANSIC xas1251(CHAR c) #else xas1251(c) CHAR c; #endif /* CK_ANSIC */ { /* xas1251 */ /* ASCII to CP81251 */ if (c & 0x80) return(UNK); if (langs[language].id == L_RUSSIAN) { /* Use Short KOI */ c = xskcy(c); /* Translate to Latin/Cyrillic */ return(ylc1251[c]); /* Then to CP866 */ } else return(c & 0x7f); } CHAR #ifdef CK_ANSIC xask8(CHAR c) #else xask8(c) CHAR c; #endif /* CK_ANSIC */ { /* xask8 */ /* ASCII to KOI-8 */ if (c & 0x80) return(UNK); if (langs[language].id == L_RUSSIAN) { /* Use Short KOI */ c = xskcy(c); /* Translate to Latin/Cyrillic */ return(ylck8[c]); /* Then to KOI-8 */ } else return(c & 0x7f); } #else /* No Cyrillic */ #define xacas NULL #define x55as NULL #define x1251as NULL #define xaclc NULL #define x55lc NULL #define x1251lc NULL #define xasac NULL #define xas55 NULL #define xas1251 NULL #define xascy NULL #define xask8 NULL #define xaslc NULL #define xassk NULL #define xk8as NULL #define xk8lc NULL #define xkrlc NULL #define xkulc NULL #define xl1sk NULL #define xw1lc NULL #define xlcac NULL #define xlc55 NULL #define xlc1251 NULL #define xlcas NULL #define xlck8 NULL #define xlckr NULL #define xlcku NULL #define xlch7 NULL #define xlcsk NULL #define xskas NULL #define xskcy NULL #define xbulc NULL #define xlcbu NULL #endif /* CYRILLIC */ /* Translation functions for Hebrew character sets */ #ifdef HEBREW CHAR #ifdef CK_ANSIC xash7(CHAR c) #else xash7(c) CHAR c; #endif /* CK_ANSIC */ { /* xash7 */ /* ASCII to Hebrew-7 */ if (c & 0x80) return(UNK); if (c == 96) return('?'); if (c > 96 && c < 123) return(c - 32); else return(c); } CHAR #ifdef CK_ANSIC xl1h7(CHAR c) #else xl1h7(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1h7 */ /* Latin-1 to Hebrew-7 */ return(xash7(xl1as(c))); } CHAR #ifdef CK_ANSIC xl1lh(CHAR c) #else xl1lh(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1lh */ /* Latin-1 to Latin/Hebrew */ switch(c) { case 170: return('a'); /* Feminine ordinal */ case 186: return('o'); /* Masculine ordinal */ case 215: return(170); /* Times */ case 247: return(186); /* Divide */ default: return( (c > 190) ? xl1as(c) : c ); } } CHAR #ifdef CK_ANSIC xw1lh(CHAR c) #else xw1lh(c) CHAR c; #endif /* CK_ANSIC */ { /* xw1lh */ /* CP1252 to Latin/Hebrew */ switch(c) { case 170: return('a'); /* Feminine ordinal */ case 186: return('o'); /* Masculine ordinal */ case 215: return(170); /* Times */ case 247: return(186); /* Divide */ default: if (c < 160) return(xw1as(c)); else return((c > 190) ? xl1as(c) : c); } } #ifdef LATIN2 CHAR #ifdef CK_ANSIC xl2h7(CHAR c) #else xl2h7(c) CHAR c; #endif /* CK_ANSIC */ { /* xl2h7 */ /* Latin-2 to Hebrew-7 */ return(xash7(xl2as(c))); } #else #define xl2h7 NULL #endif /* LATIN2 */ #ifndef NOCYRIL CHAR #ifdef CK_ANSIC xlch7(CHAR c) #else xlch7(c) CHAR c; #endif /* CK_ANSIC */ { /* xlch7 */ /* Latin/Cyrillic to Hebrew-7 */ return(xash7(xlcas(c))); } #endif /* NOCYRIL */ CHAR #ifdef CK_ANSIC xlhas(CHAR c) #else xlhas(c) CHAR c; #endif /* CK_ANSIC */ { /* xlhas */ /* Latin/Hebrew to ASCII */ return( (c > 127) ? '?' : c ); } CHAR #ifdef CK_ANSIC xlhl1(CHAR c) #else xlhl1(c) CHAR c; #endif /* CK_ANSIC */ { /* xlhl1 */ /* Latin/Hebrew to Latin-1 */ switch (c) { case 170: return(215); case 186: return(247); default: return( (c > 190) ? '?' : c ); } } CHAR #ifdef CK_ANSIC xlhw1(CHAR c) #else xlhw1(c) CHAR c; #endif /* CK_ANSIC */ { /* xlhw1 */ /* Latin/Hebrew to CP1252 */ if (c > 127 && c < 160) return('?'); switch (c) { case 170: return(215); case 186: return(247); default: return( (c > 190) ? '?' : c ); } } CHAR #ifdef CK_ANSIC xlh62(CHAR c) #else xlh62(c) CHAR c; #endif /* CK_ANSIC */ { /* xlh62 */ /* Latin/Hebrew to CP862 */ return(ylh62[c]); } CHAR #ifdef CK_ANSIC xl162(CHAR c) #else xl162(c) CHAR c; #endif /* CK_ANSIC */ { /* xl162 */ /* Latin-1 to CP862 */ return(xlh62(xl1lh(c))); /* Via Latin/Hebrew */ } CHAR #ifdef CK_ANSIC xlhh7(CHAR c) #else xlhh7(c) CHAR c; #endif /* CK_ANSIC */ { /* xlhh7 */ /* Latin/Hebrew to Hebrew-7 */ return(ylhh7[c]); } CHAR #ifdef CK_ANSIC xh7as(CHAR c) #else xh7as(c) CHAR c; #endif /* CK_ANSIC */ { /* xh7as */ /* Hebrew-7 to ASCII */ if (c & 0x80) return(UNK); return( (c > 95 && c < 123) ? '?' : c ); } CHAR #ifdef CK_ANSIC x62lh(CHAR c) #else x62lh(c) CHAR c; #endif /* CK_ANSIC */ { /* x62lh */ /* CP862 to Latin/Hebrew */ return(y62lh[c]); } CHAR #ifdef CK_ANSIC x62as(CHAR c) #else x62as(c) CHAR c; #endif /* CK_ANSIC */ { /* x62as */ /* CP862 to ASCII */ return( xlhas(x62lh(c)) ); } CHAR #ifdef CK_ANSIC x62l1(CHAR c) #else x62l1(c) CHAR c; #endif /* CK_ANSIC */ { /* x62l1 */ /* CP862 to Latin-1 */ return( xlhl1(x62lh(c)) ); } CHAR #ifdef CK_ANSIC xh7lh(CHAR c) #else xh7lh(c) CHAR c; #endif /* CK_ANSIC */ { /* xh7lh */ /* Hebrew-7 to Latin/Hebrew */ if (c & 0x80) return(UNK); return(yh7lh[c]); } #else /* No Hebrew */ #define xash7 NULL #define xl1h7 NULL #define xl2h7 NULL #define xlch7 NULL #define xl1lh NULL #define xw1lh NULL #define xlhas NULL #define xlhl1 NULL #define xlhw1 NULL #define xl162 NULL #define xlhh7 NULL #define xlh62 NULL #define xh7as NULL #define x62as NULL #define x62l1 NULL #define xh7lh NULL #define x62lh NULL #endif /* HEBREW */ /* Translation functions for Greek character sets */ #ifdef GREEK CHAR #ifdef CK_ANSIC xaseg(CHAR c) #else xaseg(c) CHAR c; #endif /* CK_ANSIC */ { /* xaseg */ /* ASCII to ELOT 927 */ if (c & 0x80) return(UNK); if (c > 96 && c < 123) return(c - 32); else return(c); } CHAR #ifdef CK_ANSIC xl1eg(CHAR c) #else xl1eg(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1ge */ /* Latin-1 to ELOT 927 */ return(xaseg(xl1as(c))); } CHAR #ifdef CK_ANSIC xl2lg(CHAR c) #else xl2lg(c) CHAR c; #endif /* CK_ANSIC */ { /* xl2lg */ /* Latin-1 to Latin/Greek */ if (c < 160) return(c); else if (c == 160 || c == 168 || c == 173 || c == 174) return(c); else return('?'); } CHAR #ifdef CK_ANSIC xl1lg(CHAR c) #else xl1lg(c) CHAR c; #endif /* CK_ANSIC */ { /* xl1lg */ /* Latin-1 to Latin/Greek */ if (c < 160) return(c); switch(c) { case 160: /* Themselves */ case 164: case 166: case 167: case 168: case 169: case 171: case 172: case 173: case 176: case 177: case 178: case 179: case 180: case 187: case 189: return(c); case 181: /* Lowercase mu */ return(236); default: return(UNK); } } CHAR #ifdef CK_ANSIC xw1lg(CHAR c) #else xw1lg(c) CHAR c; #endif /* CK_ANSIC */ { /* xw1lg */ /* CP1252 to Latin/Greek */ return((c < 160) ? xw1as(c) : xl1lg(c)); } #ifdef LATIN2 CHAR #ifdef CK_ANSIC xl2eg(CHAR c) #else xl2eg(c) CHAR c; #endif /* CK_ANSIC */ { /* xl2eg */ /* Latin-2 to ELOT 927 */ return(xaseg(xl2as(c))); } #else #define xl2eg NULL #endif /* LATIN2 */ #ifndef NOCYRIL CHAR #ifdef CK_ANSIC xlceg(CHAR c) #else xlceg(c) CHAR c; #endif /* CK_ANSIC */ { /* xlceg */ /* Latin/Cyrillic to ELOT 927 */ return(xaseg(xlcas(c))); } #endif /* NOCYRIL */ CHAR #ifdef CK_ANSIC xlgas(CHAR c) #else xlgas(c) CHAR c; #endif /* CK_ANSIC */ { /* xlgas */ /* Latin/Greek to ASCII */ return( (c > 127) ? '?' : c ); } CHAR #ifdef CK_ANSIC xlgl1(CHAR c) #else xlgl1(c) CHAR c; #endif /* CK_ANSIC */ { /* xlgl1 */ /* Latin/Greek to Latin-1 */ if (c == 236) return(181); else return(xl1lg(c)); } CHAR #ifdef CK_ANSIC xlgw1(CHAR c) #else xlgw1(c) CHAR c; #endif /* CK_ANSIC */ { /* xlgw1 */ /* Latin/Greek to Latin-1 */ if (c > 127 && c < 160) return('?'); return(xlgl1(c)); } CHAR #ifdef CK_ANSIC xlg69(CHAR c) #else xlg69(c) CHAR c; #endif /* CK_ANSIC */ { /* xlg69 */ /* Latin/Greek to CP869 */ return(ylg69[c]); } CHAR #ifdef CK_ANSIC xl169(CHAR c) #else xl169(c) CHAR c; #endif /* CK_ANSIC */ { /* xl169 */ /* Latin-1 to CP869 */ return(xlg69(xl1lg(c))); /* Via Latin/Greek */ } CHAR #ifdef CK_ANSIC xlgeg(CHAR c) #else xlgeg(c) CHAR c; #endif /* CK_ANSIC */ { /* xlgeg */ /* Latin/Greek to ELOT 927 */ return(ylgeg[c]); } CHAR #ifdef CK_ANSIC xegas(CHAR c) #else xegas(c) CHAR c; #endif /* CK_ANSIC */ { /* xegas */ /* ELOT 927 to ASCII */ if (c & 0x80) return(UNK); return( (c > 96 && c < 123) ? '?' : c ); } CHAR #ifdef CK_ANSIC x69lg(CHAR c) #else x69lg(c) CHAR c; #endif /* CK_ANSIC */ { /* x69lg */ /* CP869 to Latin/Greek */ return(y69lg[c]); } CHAR #ifdef CK_ANSIC x69as(CHAR c) #else x69as(c) CHAR c; #endif /* CK_ANSIC */ { /* x69as */ /* CP869 to ASCII */ return( xlgas(x69lg(c)) ); } CHAR #ifdef CK_ANSIC x69l1(CHAR c) #else x69l1(c) CHAR c; #endif /* CK_ANSIC */ { /* x69l1 */ /* CP869 to Latin-1 */ return( xlgl1(x69lg(c)) ); } CHAR #ifdef CK_ANSIC xeglg(CHAR c) #else xeglg(c) CHAR c; #endif /* CK_ANSIC */ { /* xeglg */ /* ELOT 927 to Latin/Greek */ return(yeglg[c]); } #else /* No Greek */ #define x69as NULL #define x69l1 NULL #define x69lg NULL #define xaseg NULL #define xegas NULL #define xeglg NULL #define xl169 NULL #define xl1eg NULL #define xl1lg NULL #define xw1lg NULL #define xl2ge NULL #define xl2lg NULL #define xlcge NULL #define xlg69 NULL #define xlgas NULL #define xlgeg NULL #define xlgge NULL #define xlgl1 NULL #define xlgw1 NULL #endif /* GREEK */ /* Translation functions for Japanese Kanji character sets */ #ifdef KANJI /* Translate Kanji Transfer Character Set (EUC) to local file character set, contributed by Dr. Hirofumi Fujii, Japan High Energy Research Laboratory (KEK), Tokyo, Japan. a is a byte to be translated, which may be a single-byte character, the Katakana prefix, the first byte of a two-byte Kanji character, or the second byte of 2-byte Kanji character. fn is the output function. Returns 0 on success, -1 on failure. */ #ifdef COMMENT /* Replaced by new prototypes above */ _PROTOTYP(static int jpnxas, (int, int[]) ); _PROTOTYP(static int jpnxkt, (int, int[]) ); _PROTOTYP(static int jpnxkn, (int[], int[]) ); #endif /* COMMENT */ static int jpncnt; /* Byte count for Japanese */ static int jpnlst; /* Last status (for JIS7) */ static int #ifdef CK_ANSIC jpnxas( int a, int obuf[] ) /* Translate ASCII to local file code */ #else jpnxas(a, obuf) int a; int obuf[]; #endif /* CK_ANSIC */ { int r; r = 0; if (fcharset == FC_JIS7) { switch (jpnlst) { case 1: obuf[0] = 0x0f; obuf[1] = a; r = 2; break; case 2: obuf[0] = 0x1b; obuf[1] = 0x28; obuf[2] = 0x4a; obuf[3] = a; r = 4; break; default: obuf[0] = a; r = 1; break; } } else { obuf[0] = a; r = 1; } return(r); } static int #ifdef CK_ANSIC jpnxkt( int a, int obuf[] ) #else jpnxkt(a, obuf) int a; int obuf[]; #endif /* CK_ANSIC */ { /* Translate JIS X 201 Katakana to local code */ int r; r = 0; if (fcharset == FC_JIS7) { switch (jpnlst) { case 2: /* from Kanji */ obuf[r++] = 0x1b; obuf[r++] = 0x28; obuf[r++] = 0x4a; case 0: /* from Roman */ obuf[r++] = 0x0e; default: obuf[r++] = (a & 0x7f); break; } } else { if (fcharset == FC_JEUC) obuf[r++] = 0x8e; obuf[r++] = (a | 0x80); } return(r); } static int #ifdef CK_ANSIC jpnxkn( int ibuf[], int obuf[] ) #else jpnxkn(ibuf, obuf) int ibuf[], obuf[]; #endif /* CK_ANSIC */ { /* Translate JIS X 0208 Kanji to local code */ int c1, c2; int r; c1 = ibuf[0] & 0x7f; c2 = ibuf[1] & 0x7f; if (fcharset == FC_SHJIS) { if (c1 & 1) c2 += 0x1f; else c2 += 0x7d; if (c2 >= 0x7f) c2++; c1 = ((c1 - 0x21) >> 1) + 0x81; if (c1 > 0x9f) c1 += 0x40; obuf[0] = c1; obuf[1] = c2; r = 2; } else if (fcharset == FC_JIS7) { r = 0; switch (jpnlst) { case 1: obuf[r++] = 0x0f; /* From Katakana */ case 0: obuf[r++] = 0x1b; obuf[r++] = 0x24; obuf[r++] = 0x42; default: obuf[r++] = c1; obuf[r++] = c2; break; } } else { obuf[0] = (c1 | 0x80); obuf[1] = (c2 | 0x80); r = 2; } return(r); } int xkanjf() { /* Initialize parameters for xkanji */ /* This function should be called when F/X-packet is received */ jpncnt = jpnlst = 0; return(0); } int #ifdef CK_ANSIC xkanjz(int (*fn)(char)) #else xkanjz(fn) int (*fn)(); #endif /* CK_ANSIC */ { /* xkanjz */ /* Terminate xkanji This function must be called when Z-packet is received (before closing the file). */ static int obuf[6]; int r, i, c; if (fcharset == FC_JIS7) { c = 'A'; /* Dummy Roman character */ r = jpnxas(c, obuf) - 1; /* -1 removes Dummy character */ if (r > 0) { for (i = 0; i < r; i++) if (((*fn)((char) obuf[i])) < 0) return(-1); } } return(0); } int #ifdef CK_ANSIC xkanji(int a, int (*fn)(char)) #else xkanji(a, fn) int a; int (*fn)(); #endif /* CK_ANSIC */ { /* xkanji */ static int xbuf[2]; static int obuf[8]; int i, r; int c7; int state=0; r = 0; if (jpncnt == 0) { /* 1st byte */ if ((a & 0x80) == 0) { /* 8th bit is 0, i.e., single-byte code */ r = jpnxas(a, obuf); state = 0; } else { /* 8th bit is 1, check the range */ c7 = a & 0x7f; if (((c7 > 0x20) && (c7 < 0x7f)) || (c7 == 0x0e)) { /* double byte code */ xbuf[jpncnt++] = a; } else { /* single byte code */ r = jpnxas(a, obuf); state = 0; } } } else { /* not the 1st byte */ xbuf[jpncnt++] = a; if (xbuf[0] == 0x8e) { r = jpnxkt(xbuf[1], obuf); state = 1; } else { r = jpnxkn(xbuf, obuf); state = 2; } } if (r > 0) { for (i = 0; i < r; i++ ) if (((*fn)((char) obuf[i])) < 0) return(-1); jpnlst = state; jpncnt = 0; } return(0); } /* Function for translating from Japanese file character set to Japanese EUC transfer character set. Returns a pointer to a string containing 0, 1, or 2 bytes. */ /* zkanji */ static int jpnstz; /* status for JIS-7 */ static int jpnpnd; /* number of pending bytes */ static int jpnpnt; /* pending buffer index */ static int jpnpbf[8]; /* pending buffer */ /* There is some duplication here between the old and new JIS-7 parsers */ /* to be cleaned up later... */ VOID j7init() { /* Initialize JIS-7 parser */ jpnstz = 0; jpnpnd = 0; jpnpnt = 0; } int getj7() { /* Reads JIS-7 returns next EUC byte */ int x; if (jpnpnd > 0) { /* If something is pending */ x = (unsigned) jpnpbf[jpnpnt++]; /* Get it */ jpnpnd--; if (jpnpnd < 0) jpnpnd = 0; return((unsigned)x); } jpnpnt = 0; if ((x = zminchar()) < 0) return(x); while (jpnpnd == 0) { /* While something is pending... */ if ((x > 0x20) && (x < 0x7f)) { /* 7-bit graphic character */ switch (jpnstz) { case 1: /* Katakana */ #ifdef COMMENT /* This can't be right... */ jpnpbf[jpnpnd++] = 0x80; /* Insert flag (NOT SS2???) */ #else jpnpbf[jpnpnd++] = 0x8e; /* Insert SS2 */ #endif /* COMMENT */ jpnpbf[jpnpnd++] = (x | 0x80); /* Insert Kana + 8th bit */ break; case 2: /* Kanji */ jpnpbf[jpnpnd++] = (x | 0x80); /* Get another byte */ if ((x = zminchar()) < 0) return(x); jpnpbf[jpnpnd++] = (x | 0x80); break; default: /* ASCII / JIS Roman */ jpnpbf[jpnpnd++] = x; break; } } else if (x == 0x0e) { /* ^N = SO */ jpnstz = 1; /* Katakana */ if ((x = zminchar()) < 0) return(x); } else if (x == 0x0f) { /* ^O = SI */ jpnstz = 0; /* ASCII / JIS Roman */ if ((x = zminchar()) < 0) return(x); } else if (x == 0x1b) { /* Escape */ jpnpbf[jpnpnd++] = x; /* Save in buffer */ if ((x = zminchar()) < 0) return(x); jpnpbf[jpnpnd++] = x; /* Save in buffer */ if (x == '$') { /* $ */ if ((x = zminchar()) < 0) return(x); jpnpbf[jpnpnd++] = x; if ((x == '@') || (x == 'B')) { /* Kanji */ jpnstz = 2; jpnpnt = jpnpnd = 0; if ((x = zminchar()) < 0) return(x); } } else if (x == '(') { /* ( == 94-byte single-byte set */ if ((x = zminchar()) < 0) return(x); jpnpbf[jpnpnd++] = x; if ((x == 'B') || (x == 'J')) { /* ASCII or JIS Roman */ jpnstz = 0; /* Set state */ jpnpnt = jpnpnd = 0; /* Reset pointers */ if ((x = zminchar()) < 0) return(x); } } else if (x == 0x1b) { /* */ jpnpnt = jpnpnd = 0; /* Reset pointers, stay in state */ if ((x = zminchar()) < 0) return(x); } } else { /* Not - just save it */ jpnpbf[jpnpnd++] = x; } } jpnpnt = 0; x = (unsigned)jpnpbf[jpnpnt++]; jpnpnd--; return((unsigned)x); } USHORT #ifdef CK_ANSIC eu_to_sj(USHORT eu) /* EUC-JP to Shift-JIS */ #else eu_to_sj(eu) USHORT eu; #endif /* CK_ANSIC */ { int c1, c2; union ck_short jcode,scode; jcode.x_short = eu; c1 = (jcode.x_char[byteorder] & 0x7f); c2 = (jcode.x_char[1-byteorder] & 0x7f); if (c1 & 1) c2 += 0x1f; else c2 += 0x7d; if (c2 >= 0x7f) c2++; c1 = ((c1 - 0x21) >> 1) + 0x81; if (c1 > 0x9f) c1 += 0x40; scode.x_char[byteorder] = c1; scode.x_char[1-byteorder] = c2; return(scode.x_short); } USHORT #ifdef CK_ANSIC sj_to_eu(USHORT sj) /* Shift-JIS to EUC-JP */ #else sj_to_eu(sj) USHORT sj; #endif /* CK_ANSIC */ { union ck_short jcode, scode; int c0, c1; scode.x_short = sj; c0 = scode.x_char[byteorder]; /* Left (hi order) byte */ c1 = scode.x_char[1-byteorder]; /* Right (lo order) byte */ if (((c0 >= 0x81) && (c0 <= 0x9f)) || /* High order byte has 8th bit set */ ((c0 >= 0xe0) && (c0 <= 0xfc))) { /* Kanji */ if (c0 <= 0x9f) /* Two bytes in */ c0 -= 0x71; /* Do the shifting... */ else c0 -= 0xb1; c0 = c0 * 2 + 1; if (c1 > 0x7f) c1 -= 1; if (c1 >= 0x9e) { c1 -= 0x7d; c0 += 1; } else { c1 -= 0x1f; } jcode.x_char[byteorder] = (c0 | 0x80); /* Two bytes out */ jcode.x_char[1-byteorder] = (c1 | 0x80); } else if (c0 == 0) { /* Single byte */ if (c1 >= 0xa1 && c1 <= 0xdf) { /* Katakana */ jcode.x_char[byteorder] = 0x8e; /* SS2 */ jcode.x_char[1-byteorder] = c1; /* Kana code */ } else { /* ASCII or C0 */ jcode.x_short = c1; } } else { /* Something bad */ debug(F001,"sj_to_eu bad sj","",sj); jcode.x_short = 0xffff; } return(jcode.x_short); } int zkanjf() { /* Initialize */ jpnstz = jpnpnd = jpnpnt = 0; return(0); } int zkanjz() { return(0); } int #ifdef CK_ANSIC zkanji(int (*fn)(void)) #else zkanji(fn) int (*fn)(); #endif /* CK_ANSIC */ { /* zkanji */ /* Read Japanese local code and translate to Japanese EUC */ int a; int sc[3]; /* No pending characters */ if (fcharset == FC_SHJIS) { /* Translating from Shift-JIS */ if (jpnpnd) { jpnpnd--; return(jpnpbf[jpnpnt++]); } a = (*fn)(); jpnpnd = jpnpnt = 0; if (((a >= 0x81) && (a <= 0x9f)) || ((a >= 0xe0) && (a <= 0xfc))) { /* 2-byte Kanji code */ sc[0] = a; if ((sc[1] = (*fn)()) < 0) /* Get second byte */ return(sc[1]); if (sc[0] <= 0x9f) sc[0] -= 0x71; else sc[0] -= 0xb1; sc[0] = sc[0] * 2 + 1; if (sc[1] > 0x7f) sc[1]--; if (sc[1] >= 0x9e) { sc[1] -= 0x7d; sc[0]++; } else { sc[1] -= 0x1f; } a = (sc[0] | 0x80); jpnpbf[0] = (sc[1] | 0x80); jpnpnd = 1; jpnpnt = 0; } else if ((a >= 0xa1) && (a <= 0xdf)) { /* Katakana */ jpnpbf[0] = a; jpnpnd = 1; jpnpnt = 0; a = 0x8e; } return(a); } else if (fcharset == FC_JIS7 ) { /* 7-bit JIS X 0208 */ if (jpnpnd) { a = jpnpbf[jpnpnt++]; jpnpnd--; return(a); } jpnpnt = 0; if ((a = (*fn)()) < 0) return(a); while (jpnpnd == 0) { if ((a > 0x20) && (a < 0x7f)) { switch (jpnstz) { case 1: jpnpbf[jpnpnd++] = 0x80; /* Katakana */ jpnpbf[jpnpnd++] = (a | 0x80); break; case 2: jpnpbf[jpnpnd++] = (a | 0x80); /* Kanji */ if ((a = (*fn)()) < 0) return(a); jpnpbf[jpnpnd++] = (a | 0x80); break; default: jpnpbf[jpnpnd++] = a; /* Single byte */ break; } } else if (a == 0x0e) { jpnstz = 1; if ((a = (*fn)()) < 0) return(a); } else if (a == 0x0f) { jpnstz = 0; if ((a = (*fn)()) < 0) return(a); } else if (a == 0x1b) { jpnpbf[jpnpnd++] = a; /* Escape */ if ((a = (*fn)()) < 0) return(a); jpnpbf[jpnpnd++] = a; if (a == '$') { if ((a = (*fn)()) < 0) return(a); jpnpbf[jpnpnd++] = a; if ((a == '@') || (a == 'B')) { jpnstz = 2; jpnpnt = jpnpnd = 0; if ((a = (*fn)()) < 0) return(a); } } else if (a == '(') { if ((a = (*fn)()) < 0) return(a); jpnpbf[jpnpnd++] = a; if ((a == 'B') || (a == 'J')) { jpnstz = 0; jpnpnt = jpnpnd = 0; if ((a = (*fn)()) < 0) return(a); } } else if (a == 0x1b) { jpnpnt = jpnpnd = 0; if ((a = (*fn)()) < 0) return(a); } } else { jpnpbf[jpnpnd++] = a; } } jpnpnt = 0; a = jpnpbf[jpnpnt++]; jpnpnd--; return(a); } else { a = (*fn)(); return(a); } } #endif /* KANJI */ /* Euro functions */ #ifdef LATIN2 CHAR #ifdef CK_ANSIC xl2l9(CHAR c) #else xl2l9(c) CHAR c; #endif /* CK_ANSIC */ { /* xl2l9 */ /* Latin-2 to Latin-9... */ switch (c) { case 169: return((CHAR)166); /* S caron */ case 185: return((CHAR)168); /* s caron */ case 174: return((CHAR)180); /* Z caron */ case 190: return((CHAR)184); /* z caron */ default: return(yl2l1[c]); } } _PROTOTYP( CHAR xl258, ( CHAR ) ); CHAR #ifdef CK_ANSIC xl258(CHAR c) #else xl258(c) CHAR c; #endif /* CK_ANSIC */ { /* xl258 */ /* Latin-2 to CP858... */ return(c); } #else #define xl2l9 NULL #define xl258 NULL #endif /* LATIN2 */ CHAR #ifdef CK_ANSIC zl9as(CHAR c) #else zl9as(c) CHAR c; #endif /* CK_ANSIC */ { /* zl9as */ /* Latin-9 to US ASCII... */ if (c < (CHAR)0x80) return(c); /* Save a function call */ switch (c) { case 0xa4: return(UNK); /* Euro */ case 0xa6: return('S'); /* S Caron */ case 0xa8: return('s'); /* s Caron */ case 0xb4: return('Z'); /* Z Caron */ case 0xbc: return('O'); /* OE digraph */ case 0xbd: return('o'); /* oe digraph */ case 0xbe: return('Y'); /* Y diaeresis */ default: return(zl1as(c)); /* The rest is like Latin-1 */ } } _PROTOTYP( CHAR xl9as, ( CHAR ) ); CHAR #ifdef CK_ANSIC xl9as(CHAR c) #else xl9as(c) CHAR c; #endif /* CK_ANSIC */ { /* xl9as */ /* Latin-9 to US ASCII... */ if (c < (CHAR)0x80) return(c); /* Save a function call */ switch (c) { case 0xa4: return(UNK); /* Euro */ case 0xa6: return('S'); /* S Caron */ case 0xa8: return('s'); /* s Caron */ case 0xb4: return('Z'); /* Z Caron */ case 0xb8: return('z'); /* z Caron */ case 0xbc: return('O'); /* OE digraph */ case 0xbd: return('o'); /* oe digraph */ case 0xbe: return('Y'); /* Y diaeresis */ default: return(xl1as(c)); /* The rest is like Latin-1 */ } } CHAR /* CP1252 to Latin-9 */ #ifdef CK_ANSIC xw1l9(CHAR c) #else xw1l9(c) CHAR c; #endif /* CK_ANSIC */ { /* xw1l9 */ switch (c) { case 0x80: return(0xa4); /* Euro sign */ case 0x8a: return(0xa6); /* S caron */ case 0x8c: return(0xbc); /* OE */ case 0x8e: return(0xb4); /* Z caron */ case 0x9a: return(0xa8); /* s caron */ case 0x9c: return(0xbd); /* oe */ case 0x9e: return(0xb8); /* z caron */ case 0x9f: return(0xbe); /* Y diaeresis */ case 0xa4: /* Currency sign */ case 0xa6: /* Broken vertical bar */ case 0xa8: /* Diaeresis */ case 0xb4: /* Acute accent */ case 0xb8: /* Cedilla */ case 0xbc: /* 1/4 */ case 0xbd: /* 1/2 */ case 0xbe: return('?'); /* 3/4 */ default: return((c < 160) ? xw1as(c) : c); } } #ifdef LATIN2 CHAR #ifdef CK_ANSIC xl9l2(CHAR c) #else xl9l2(c) CHAR c; #endif /* CK_ANSIC */ { /* xl9l2 */ /* Latin-9 to Latin-2... */ if (c < (CHAR)0x80) return(c); /* Save a function call */ switch (c) { case 0xa4: return(UNK); /* Euro */ case 0xa6: return((CHAR)0xa9); /* S Caron */ case 0xa8: return((CHAR)0xb9); /* s Caron */ case 0xb4: return((CHAR)0xae); /* Z Caron */ case 0xb8: return((CHAR)0xaf); /* z Caron */ case 0xbc: return('O'); /* OE digraph */ case 0xbd: return('o'); /* oe digraph */ case 0xbe: return('Y'); /* Y diaeresis */ default: return(xl1l2(c)); /* The rest is like Latin-1 */ } } #else #define xl9l2 NULL #endif /* LATIN2 */ CHAR #ifdef CK_ANSIC xl958(CHAR c) #else xl958(c) CHAR c; #endif /* CK_ANSIC */ { /* xl958 */ /* Latin-9 to CP858... */ if (c == 0xa4) /* Euro Symbol */ return((CHAR)0xd5); else if (c == 0x9e) /* This was currency symbol */ return((CHAR)0xcf); c = yl185[c]; return(c); } CHAR #ifdef CK_ANSIC x58as(CHAR c) #else x58as(c) CHAR c; #endif /* CK_ANSIC */ { /* x58as */ /* CP858 to US ASCII... */ if (c == 0xd5) /* Euro rather than dotless i */ return(UNK); else return(x85as(c)); /* The rest is like CP850 */ } CHAR #ifdef CK_ANSIC x58l1(CHAR c) #else x58l1(c) CHAR c; #endif /* CK_ANSIC */ { /* x58l1 */ /* CP858 to Latin-1... */ if (c == 0xd5) /* Euro rather than dotless i */ return((CHAR)0xa4); /* Return currency symbol */ else if (c == 0xcf) /* This keeps it invertible */ return((CHAR)0x9e); else return(x85l1(c)); } #ifdef LATIN2 CHAR #ifdef CK_ANSIC x58l2(CHAR c) #else x58l2(c) CHAR c; #endif /* CK_ANSIC */ { /* x58l2 */ /* CP858 to Latin-2... */ if (c == 0xd5) /* Euro rather than dotless i */ return((CHAR)0xa4); /* Return currency symbol */ else if (c == 0xcf) /* This keeps it invertible */ return((CHAR)0x9e); /* (if it ever was...) */ else /* Otherwise like CP850 */ return(x85l2(c)); } #else #define x58l2 NULL #endif /* LATIN2 */ CHAR #ifdef CK_ANSIC x58l9(CHAR c) #else x58l9(c) CHAR c; #endif /* CK_ANSIC */ { /* x58l9 */ /* CP-858 to Latin-9... */ if (c == 0xd5) /* Euro rather than dotless i */ return((CHAR)0xa4); /* Return currency symbol */ else if (c == 0xcf) /* This keeps it invertible */ return((CHAR)0x9e); /* (if it ever was...) */ else /* Otherwise like CP850 */ return(x85l1(c)); /* to Latin-1 */ } /* End Euro functions */ /* TABLES OF TRANSLATION FUNCTIONS */ /* First, the table of translation functions for RECEIVING files. That is, *from* the TRANSFER character set *to* the FILE character set, an array of pointers to functions. The first index is the TRANSFER CHARACTER-SET number, the second index is the FILE CHARACTER-SET number. These arrays must be fully populated, even if (as is the case with Kanji character sets), all the entries are NULL. Otherwise, subscript calculations will be wrong and we'll use the wrong functions. */ /* Pointers to byte-for-byte translation functions */ _PROTOTYP( CHAR (*rx), (CHAR) ); _PROTOTYP( CHAR (*sx), (CHAR) ); #ifdef UNICODE _PROTOTYP( int (*xut), (USHORT) ); /* Translation function UCS to TCS */ _PROTOTYP( int (*xuf), (USHORT) ); /* Translation function UCS to FCS */ _PROTOTYP( USHORT (*xtu), (CHAR) ); /* Translation function TCS to UCS */ _PROTOTYP( USHORT (*xfu), (CHAR) ); /* Translation function FCS to UCS */ #endif /* UNICODE */ #ifdef CK_ANSIC CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR) = #else CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])() = #endif /* CK_ANSIC */ { NULL, /* 0,0 transparent to us ascii */ NULL, /* 0,1 transparent to uk ascii */ NULL, /* 0,2 transparent to dutch nrc */ NULL, /* 0,3 transparent to finnish nrc */ NULL, /* 0,4 transparent to french nrc */ NULL, /* 0,5 transparent to fr-canadian nrc */ NULL, /* 0,6 transparent to german nrc */ NULL, /* 0,7 transparent to hungarian nrc */ NULL, /* 0,8 transparent to italian nrc */ NULL, /* 0,9 transparent to norge/danish nrc */ NULL, /* 0,10 transparent to portuguese nrc */ NULL, /* 0,11 transparent to spanish nrc */ NULL, /* 0,12 transparent to swedish nrc */ NULL, /* 0,13 transparent to swiss nrc */ NULL, /* 0,14 transparent to latin-1 */ NULL, /* 0,15 transparent to latin-2 */ NULL, /* 0,16 transparent to DEC MCS */ NULL, /* 0,17 transparent to NeXT */ NULL, /* 0,18 transparent to CP437 */ NULL, /* 0,19 transparent to CP850 */ NULL, /* 0,20 transparent to CP852 */ NULL, /* 0,21 transparent to Macintosh Latin */ NULL, /* 0,22 transparent to DGI */ NULL, /* 0,23 transparent to HP */ NULL, /* 0,24 transparent to Latin/Cyrillic */ NULL, /* 0,25 transparent to CP866 */ NULL, /* 0,26 transparent to Short KOI-7 */ NULL, /* 0,27 transparent to Old KOI-8 Cyrillic */ NULL, /* 0,28 transparent to JIS-7 */ NULL, /* 0,29 transparent to Shift-JIS */ NULL, /* 0,30 transparent to J-EUC */ NULL, /* 0,31 transparent to DEC Kanji */ NULL, /* 0,32 transparent to Hebrew-7 */ NULL, /* 0,33 transparent to Latin/Hebrew */ NULL, /* 0,34 transparent to CP862 Hebrew */ NULL, /* 0,35 transparent to ELOT 927 Greek */ NULL, /* 0,36 transparent to Latin/Greek */ NULL, /* 0,37 transparent to CP869 */ NULL, /* 0,38 transparent to Latin-9 */ NULL, /* 0,39 transparent to CP858 */ NULL, /* 0,40 transparent to CP855 */ NULL, /* 0,41 transparent to CP1251 */ NULL, /* 0,42 transparent to Bulgarian */ NULL, /* 0,43 transparent to CP1250 */ NULL, /* 0,44 transparent to Mazovia */ NULL, /* 0,45 transparent to UCS-2 */ NULL, /* 0,46 transparent to UTF-8 */ NULL, /* 0,47 transparent to KOI8R */ NULL, /* 0,48 transparent to KOI8U */ NULL, /* 0,49 transparent to CP1252 */ NULL, /* 1,0 ascii to us ascii */ NULL, /* 1,1 ascii to uk ascii */ NULL, /* 1,2 ascii to dutch nrc */ NULL, /* 1,3 ascii to finnish nrc */ NULL, /* 1,4 ascii to french nrc */ NULL, /* 1,5 ascii to fr-canadian nrc */ NULL, /* 1,6 ascii to german nrc */ NULL, /* 1,7 ascii to hungarian nrc */ NULL, /* 1,8 ascii to italian nrc */ NULL, /* 1,9 ascii to norge/danish nrc */ NULL, /* 1,10 ascii to portuguese nrc */ NULL, /* 1,11 ascii to spanish nrc */ NULL, /* 1,12 ascii to swedish nrc */ NULL, /* 1,13 ascii to swiss nrc */ NULL, /* 1,14 ascii to latin-1 */ NULL, /* 1,15 ascii to latin-2 */ NULL, /* 1,16 ascii to DEC MCS */ NULL, /* 1,17 ascii to NeXT */ NULL, /* 1,18 ascii to CP437 */ NULL, /* 1,19 ascii to CP850 */ NULL, /* 1,20 ascii to CP852 */ NULL, /* 1,21 ascii to Macintosh Latin */ NULL, /* 1,22 ascii to DGI */ NULL, /* 1,23 ascii to HP */ xaslc, /* 1,24 ascii to Latin/Cyrillic */ xasac, /* 1,25 ascii to CP866 */ xassk, /* 1,26 ascii to Short KOI */ xask8, /* 1,27 ascii to Old KOI-8 Cyrillic */ NULL, /* 1,28 ascii to JIS-7 */ NULL, /* 1,29 ascii to Shift-JIS */ NULL, /* 1,30 ascii to J-EUC */ NULL, /* 1,31 ascii to DEC Kanji */ xash7, /* 1,32 ascii to Hebrew-7 */ NULL, /* 1,33 ascii to Latin/Hebrew */ NULL, /* 1,34 ascii to CP862 Hebrew */ xaseg, /* 1,35 ascii to ELOT 927 Greek */ NULL, /* 1,36 ascii to Latin/Greek */ NULL, /* 1,37 ascii to CP869 */ NULL, /* 1,38 ascii to Latin-9 */ NULL, /* 1,39 ascii to CP858 */ xas55, /* 1,40 ascii to CP855 */ xas1251, /* 1,41 ascii to CP1251 */ xleft128, /* 1,42 ascii to bulgarian */ xleft128, /* 1,43 ascii to CP1250 */ xleft128, /* 1,44 ascii to Mazovia */ NULL, /* 1,45 ascii to UCS-2 */ NULL, /* 1,46 ascii to UTF-8 */ NULL, /* 1,47 ascii to KOI8-R */ NULL, /* 1,48 ascii to KOI8-U */ NULL, /* 1,49 ascii to CP1252 */ zl1as, /* 2,0 latin-1 to us ascii */ xl1uk, /* 2,1 latin-1 to uk ascii */ xl1du, /* 2,2 latin-1 to dutch nrc */ xl1fi, /* 2,3 latin-1 to finnish nrc */ xl1fr, /* 2,4 latin-1 to french nrc */ xl1fc, /* 2,5 latin-1 to fr-canadian nrc */ xl1ge, /* 2,6 latin-1 to german nrc */ xl1it, /* 2,7 latin-1 to italian nrc */ xl1hu, /* 2,8 latin-1 to hungarian nrc */ xl1no, /* 2,9 latin-1 to norge/danish nrc */ xl1po, /* 2,10 latin-1 to portuguese nrc */ xl1sp, /* 2,11 latin-1 to spanish nrc */ xl1sw, /* 2,12 latin-1 to swedish nrc */ xl1ch, /* 2,13 latin-1 to swiss nrc */ NULL, /* 2,14 latin-1 to latin-1 */ xl1l2, /* 2,15 latin-1 to latin-2 */ xl1dm, /* 2,16 latin-1 to DEC MCS */ xl1ne, /* 2,17 latin-1 to NeXT */ xl143, /* 2,18 latin-1 to CP437 */ xl185, /* 2,19 latin-1 to CP850 */ xl152, /* 2,20 latin-1 to CP852 */ xl1aq, /* 2,21 latin-1 to Macintosh Latin */ xl1dg, /* 2,22 latin-1 to DGI */ xl1r8, /* 2,23 latin-1 to HP Roman8 */ zl1as, /* 2,24 latin-1 to Latin/Cyrillic */ zl1as, /* 2,25 latin-1 to CP866 */ xl1sk, /* 2,26 latin-1 to Short KOI */ zl1as, /* 2,27 latin-1 to Old KOI-8 Cyrillic */ NULL, /* 2,28 latin-1 to JIS-7 */ NULL, /* 2,29 latin-1 to Shift-JIS */ NULL, /* 2,30 latin-1 to J-EUC */ NULL, /* 2,31 latin-1 to DEC Kanji */ xl1h7, /* 2,32 latin-1 to Hebrew-7 */ xl1lh, /* 2,33 latin-1 to Latin/Hebrew */ xl162, /* 2,34 latin-1 to CP862 Hebrew */ xl1eg, /* 2,35 latin-1 to ELOT 927 Greek */ xl1lg, /* 2,36 latin-1 to Latin/Greek */ xl169, /* 2,37 latin-1 to CP869 */ NULL, /* 2,38 latin-1 to Latin9 */ xl185, /* 2,39 latin-1 to CP858 */ zl1as, /* 2,40 latin-1 to CP855 */ zl1as, /* 2,41 latin-1 to CP1251 */ zl1as, /* 2,42 latin-1 to Bulgarian */ xl11250, /* 2,43 latin-1 to CP1250 */ xl1mz, /* 2,44 latin-1 to Mazovia */ NULL, /* 2,45 latin-1 to UCS-2 */ NULL, /* 2,46 latin-1 to UTF-8 */ zl1as, /* 2,47 latin-1 to KOI8R */ zl1as, /* 2,48 latin-1 to KOI8U */ xl1w1, /* 2,49 latin-1 to CP1252 */ xl2as, /* 3,0 latin-2 to us ascii */ xl2as, /* 3,1 latin-2 to uk ascii */ xl2as, /* 3,2 latin-2 to dutch nrc */ xl2as, /* 3,3 latin-2 to finnish nrc */ xl2as, /* 3,4 latin-2 to french nrc */ xl2as, /* 3,5 latin-2 to fr-canadian nrc */ xl2as, /* 3,6 latin-2 to german nrc */ xl2as, /* 3,7 latin-2 to italian nrc */ xl2as, /* 3,8 latin-2 to hungarian nrc */ xl2as, /* 3,9 latin-2 to norge/danish nrc */ xl2as, /* 3,10 latin-2 to portuguese nrc */ xl2as, /* 3,11 latin-2 to spanish nrc */ xl2as, /* 3,12 latin-2 to swedish nrc */ xl2as, /* 3,13 latin-2 to swiss nrc */ xl2l1, /* 3,14 latin-2 to latin-1 */ NULL, /* 3,15 latin-2 to latin-2 */ xl2l1, /* 3,16 latin-2 to DEC MCS */ xl2ne, /* 3,17 latin-2 to NeXT */ xl243, /* 3,18 latin-2 to CP437 */ xl285, /* 3,19 latin-2 to CP850 */ xl252, /* 3,20 latin-2 to CP852 */ xl2aq, /* 3,21 latin-2 to Macintosh Latin */ xl2dg, /* 3,22 latin-2 to DGI */ xl2r8, /* 3,23 latin-2 to HP */ xl2as, /* 3,24 latin-2 to Latin/Cyrillic */ xl2as, /* 3,25 latin-2 to CP866 */ xl2sk, /* 3,26 latin-2 to Short KOI */ xl2as, /* 3,27 latin-2 to Old KOI-8 Cyrillic */ NULL, /* 3,28 latin-2 to JIS-7 */ NULL, /* 3,29 latin-2 to Shift-JIS */ NULL, /* 3,30 latin-2 to J-EUC */ NULL, /* 3,31 latin-2 to DEC Kanji */ xl2h7, /* 3,32 latin-2 to Hebrew-7 */ xl2as, /* 3,33 latin-2 to Latin/Hebrew */ xl2as, /* 3,34 latin-2 to CP862 Hebrew */ xassk, /* 3,35 latin-2 to ELOT 927 Greek */ xl2as, /* 3,36 latin-2 to Latin/Greek */ xl2as, /* 3,37 latin-2 to CP869 */ xl2l9, /* 3,38 latin-2 to Latin-9 */ xl258, /* 3,39 latin-2 to CP858 */ xl2as, /* 3,40 latin-2 to CP855 */ xl2as, /* 3,41 latin-2 to CP1251 */ xl2as, /* 3,42 latin-2 to Bulgarian */ xl21250, /* 3,43 latin-2 to CP1250 */ xl2mz, /* 3,44 latin-2 to Mazovia */ NULL, /* 3,45 latin-2 to UCS-2 */ NULL, /* 3,46 latin-2 to UTF-8 */ xl2as, /* 3,47 latin-2 to KOI8R */ xl2as, /* 3,48 latin-2 to KOI8U */ xl2w1, /* 3,49 latin-2 to CP1252 */ xlcas, /* 4,0 latin/cyrillic to us ascii */ xlcas, /* 4,1 latin/cyrillic to uk ascii */ xlcas, /* 4,2 latin/cyrillic to dutch nrc */ xlcas, /* 4,3 latin/cyrillic to finnish ascii */ xlcas, /* 4,4 latin/cyrillic to french nrc */ xlcas, /* 4,5 latin/cyrillic to fr-canadian nrc */ xlcas, /* 4,6 latin/cyrillic to german nrc */ xlcas, /* 4,7 latin/cyrillic to italian nrc */ xlcas, /* 4,8 latin/cyrillic to hungarian nrc */ xlcas, /* 4,9 latin/cyrillic to norge/danish nrc */ xlcas, /* 4,10 latin/cyrillic to portuguese nrc */ xlcas, /* 4,11 latin/cyrillic to spanish nrc */ xlcas, /* 4,12 latin/cyrillic to swedish nrc */ xlcas, /* 4,13 latin/cyrillic to swiss nrc */ xlcas, /* 4,14 latin/cyrillic to latin-1 */ xlcas, /* 4,15 latin/cyrillic to latin-2 */ xlcas, /* 4,16 latin/cyrillic to DEC MCS */ xlcas, /* 4,17 latin/cyrillic to NeXT */ xlcas, /* 4,18 latin/cyrillic to CP437 */ xlcas, /* 4,19 latin/cyrillic to CP850 */ xlcas, /* 4,20 latin/cyrillic to CP852 */ xlcas, /* 4,21 latin/cyrillic to Macintosh Latin */ xlcas, /* 4,22 latin/cyrillic to DGI */ xlcas, /* 4,23 latin/cyrillic to HP */ NULL, /* 4,24 latin/cyrillic to Latin/Cyrillic */ xlcac, /* 4,25 latin/cyrillic to CP866 */ xlcsk, /* 4,26 latin/cyrillic to Short KOI */ xlck8, /* 4,27 latin/cyrillic to Old KOI-8 Cyrillic */ NULL, /* 4,28 latin/cyril to JIS-7 */ NULL, /* 4,29 latin/cyril to Shift-JIS */ NULL, /* 4,30 latin/cyril to J-EUC */ NULL, /* 4,31 latin/cyril to DEC Kanji */ xlch7, /* 4,32 latin/cyril to Hebrew-7 */ xlcas, /* 4,33 latin/cyril to Latin/Hebrew */ xlcas, /* 4,34 latin/cyril to CP862 Hebrew */ xassk, /* 4,35 latin/cyril to ELOT 927 Greek */ xleft160, /* 4,36 latin/cyril to Latin/Greek */ xleft128, /* 4,37 latin/cyril to CP869 */ xlcas, /* 4,38 latin/cyril to latin-9 */ xlcas, /* 4,39 latin/cyril to CP858 */ xlc55, /* 4,40 latin/cyril to CP855 */ xlc1251, /* 4,41 latin/cyril to CP1251 */ xlcbu, /* 4,42 latin/cyril to Bulgarian */ xlcas, /* 4,43 latin/cyril to CP1250 */ xlcas, /* 4,44 latin/cyril to Mazovia */ NULL, /* 4,45 latin/cyril to UCS-2 */ NULL, /* 4,46 latin/cyril to UTF-8 */ xlckr, /* 4,47 latin/cyril to KOI8R */ xlcku, /* 4,48 latin/cyril to KOI8U */ xlcas, /* 4,49 latin/cyril to CP1252 */ NULL, /* 5,00 */ NULL, /* 5,01 */ NULL, /* 5,02 */ NULL, /* 5,03 */ NULL, /* 5,04 */ NULL, /* 5,05 */ NULL, /* 5,06 */ NULL, /* 5,07 */ NULL, /* 5,08 */ NULL, /* 5,09 */ NULL, /* 5,10 */ NULL, /* 5,11 */ NULL, /* 5,12 */ NULL, /* 5,13 */ NULL, /* 5,14 */ NULL, /* 5,15 */ NULL, /* 5,16 */ NULL, /* 5,17 */ NULL, /* 5,18 */ NULL, /* 5,19 */ NULL, /* 5,20 */ NULL, /* 5,21 */ NULL, /* 5,22 */ NULL, /* 5,23 */ NULL, /* 5,24 */ NULL, /* 5,25 */ NULL, /* 5,26 */ NULL, /* 5,27 */ NULL, /* 5,28 */ NULL, /* 5,29 */ NULL, /* 5,30 */ NULL, /* 5,31 */ NULL, /* 5,32 */ NULL, /* 5,33 */ NULL, /* 5,34 */ NULL, /* 5,35 */ NULL, /* 5,36 */ NULL, /* 5,37 */ NULL, /* 5,38 */ NULL, /* 5,39 */ NULL, /* 5,40 */ NULL, /* 5,41 */ NULL, /* 5,42 */ NULL, /* 5,43 */ NULL, /* 5,44 */ NULL, /* 5,45 */ NULL, /* 5,46 */ NULL, /* 5,47 */ NULL, /* 5,48 */ NULL, /* 5,49 */ xlhas, /* 6,0 latin/hebrew to us ascii */ xlhas, /* 6,1 latin/hebrew to uk ascii */ xlhas, /* 6,2 latin/hebrew to dutch nrc */ xlhas, /* 6,3 latin/hebrew to finnish ascii */ xlhas, /* 6,4 latin/hebrew to french nrc */ xlhas, /* 6,5 latin/hebrew to fr-canadian nrc */ xlhas, /* 6,6 latin/hebrew to german nrc */ xlhas, /* 6,7 latin/hebrew to italian nrc */ xlhas, /* 6,8 latin/hebrew to hungarian nrc */ xlhas, /* 6,9 latin/hebrew to norge/danish nrc */ xlhas, /* 6,10 latin/hebrew to portuguese nrc */ xlhas, /* 6,11 latin/hebrew to spanish nrc */ xlhas, /* 6,12 latin/hebrew to swedish nrc */ xlhas, /* 6,13 latin/hebrew to swiss nrc */ xlhl1, /* 6,14 latin/hebrew to latin-1 */ xlhas, /* 6,15 latin/hebrew to latin-2 */ xlhl1, /* 6,16 latin/hebrew to DEC MCS */ xlhas, /* 6,17 latin/hebrew to NeXT */ xlhas, /* 6,18 latin/hebrew to CP437 */ xlhas, /* 6,19 latin/hebrew to CP850 */ xlhas, /* 6,20 latin/hebrew to CP852 */ xlhas, /* 6,21 latin/hebrew to Macintosh Latin */ xlhas, /* 6,22 latin/hebrew to DGI */ xlhas, /* 6,23 latin/hebrew to HP */ xlhas, /* 6,24 latin/hebrew to Latin/Cyrillic */ xlhas, /* 6,25 latin/hebrew to CP866 */ NULL, /* 6,26 latin/hebrew to Short KOI */ xlhas, /* 6,27 latin/hebrew to Old KOI-8 Cyrillic */ NULL, /* 6,28 latin/hebrew to JIS-7 */ NULL, /* 6,29 latin/hebrew to Shift-JIS */ NULL, /* 6,30 latin/hebrew to J-EUC */ NULL, /* 6,31 latin/hebrew to DEC Kanji */ xlhh7, /* 6,32 latin/hebrew to Hebrew-7 */ NULL, /* 6,33 latin/hebrew to Latin/Hebrew */ xlh62, /* 6,34 latin/hebrew to CP862 Hebrew */ NULL, /* 6,35 latin/hebrew to ELOT 927 Greek */ xlhas, /* 6,36 latin/hebrew to Latin/Greek */ xlhas, /* 6,37 latin/hebrew to CP869 */ xlhas, /* 6,38 latin/hebrew to Latin-9 */ xlhas, /* 6,39 latin/hebrew to CP858 */ xlhas, /* 6,40 latin/hebrew to CP855 */ xlhas, /* 6,41 latin/hebrew to CP1251 */ xlhas, /* 6,42 latin/hebrew to Bulgarian */ xlhas, /* 6,43 latin/hebrew to CP1250 */ xlhas, /* 6,44 latin/hebrew to Mazovia */ NULL, /* 6,45 latin/hebrew to UCS-2 */ NULL, /* 6,46 latin/hebrew to UTF-8 */ NULL, /* 6,47 latin/hebrew to KOI8R */ NULL, /* 6,48 latin/hebrew to KOI8U */ xlhw1, /* 6,49 latin/hebrew to CP1252 */ xlgas, /* 7,0 latin/greek to us ascii */ xlgas, /* 7,1 latin/greek to uk ascii */ xlgas, /* 7,2 latin/greek to dutch nrc */ xlgas, /* 7,3 latin/greek to finnish ascii */ xlgas, /* 7,4 latin/greek to french nrc */ xlgas, /* 7,5 latin/greek to fr-canadian nrc */ xlgas, /* 7,6 latin/greek to german nrc */ xlgas, /* 7,7 latin/greek to italian nrc */ xlgas, /* 7,8 latin/greek to hungarian nrc */ xlgas, /* 7,9 latin/greek to norge/danish nrc */ xlgas, /* 7,10 latin/greek to portuguese nrc */ xlgas, /* 7,11 latin/greek to spanish nrc */ xlgas, /* 7,12 latin/greek to swedish nrc */ xlgas, /* 7,13 latin/greek to swiss nrc */ xlgas, /* 7,14 latin/greek to latin-1 */ xlgas, /* 7,15 latin/greek to latin-2 */ xlgas, /* 7,16 latin/greek to DEC MCS */ xlgas, /* 7,17 latin/greek to NeXT */ xlgas, /* 7,18 latin/greek to CP437 */ xlgas, /* 7,19 latin/greek to CP850 */ xlgas, /* 7,20 latin/greek to CP852 */ xlgas, /* 7,21 latin/greek to Macintosh Latin */ xlgas, /* 7,22 latin/greek to DGI */ xlgas, /* 7,23 latin/greek to HP */ xleft160, /* 7,24 latin/greek to Latin/Cyrillic */ xleft128, /* 7,25 latin/greek to CP866 */ xassk, /* 7,26 latin/greek to Short KOI */ xleft160, /* 7,27 latin/greek to Old KOI-8 Greek */ NULL, /* 7,28 latin/greek to JIS-7 */ NULL, /* 7,29 latin/greek to Shift-JIS */ NULL, /* 7,30 latin/greek to J-EUC */ NULL, /* 7,31 latin/greek to DEC Kanji */ NULL, /* 7,32 latin/greek to Hebrew-7 */ xlgas, /* 7,33 latin/greek to Latin/Hebrew */ xlgas, /* 7,34 latin/greek to CP862 Hebrew */ xlgeg, /* 7,35 latin/greek to ELOT 927 Greek */ NULL, /* 7,36 latin/greek to Latin/Greek */ xlg69, /* 7,37 latin/greek to CP869 */ xlgas, /* 7,38 latin/greek to Latin-9 */ xlgas, /* 7,39 latin/greek to CP858 */ xleft128, /* 7,40 latin/greek to CP855 */ xleft128, /* 7,41 latin/greek to CP1251 */ xleft128, /* 7,42 latin/greek to Bulgarian */ xleft128, /* 7,43 latin/greek to CP1250 */ xleft128, /* 7,44 latin/greek to Mazovia */ NULL, /* 7,45 latin/greek to UCS-2 */ NULL, /* 7,46 latin/greek to UTF-8 */ NULL, /* 7,47 latin/greek to KOI8R */ NULL, /* 7,48 latin/greek to KOI8U */ xlgw1, /* 7,49 latin/greek to CP1252 */ zl9as, /* 8,0 latin-9 to us ascii */ xl1uk, /* 8,1 latin-9 to uk ascii */ xl1du, /* 8,2 latin-9 to dutch nrc */ xl1fi, /* 8,3 latin-9 to finnish nrc */ xl1fr, /* 8,4 latin-9 to french nrc */ xl1fc, /* 8,5 latin-9 to fr-canadian nrc */ xl1ge, /* 8,6 latin-9 to german nrc */ xl1it, /* 8,7 latin-9 to italian nrc */ xl1hu, /* 8,8 latin-9 to hungarian nrc */ xl1no, /* 8,9 latin-9 to norge/danish nrc */ xl1po, /* 8,10 latin-9 to portuguese nrc */ xl1sp, /* 8,11 latin-9 to spanish nrc */ xl1sw, /* 8,12 latin-9 to swedish nrc */ xl1ch, /* 8,13 latin-9 to swiss nrc */ NULL, /* 8,14 latin-9 to latin-1 */ xl1l2, /* 8,15 latin-9 to latin-2 */ xl9dm, /* 8,16 latin-9 to DEC MCS */ xl9ne, /* 8,17 latin-9 to NeXT */ xl143, /* 8,18 latin-9 to CP437 */ xl185, /* 8,19 latin-9 to CP850 */ xl152, /* 8,20 latin-9 to CP852 */ xl1aq, /* 8,21 latin-9 to Macintosh Latin */ xl1dg, /* 8,22 latin-9 to DGI */ xl1r8, /* 8,23 latin-9 to HP Roman8 */ zl1as, /* 8,24 latin-9 to Latin/Cyrillic */ zl1as, /* 8,25 latin-9 to CP866 */ xl1sk, /* 8,26 latin-9 to Short KOI */ zl1as, /* 8,27 latin-9 to Old KOI-8 Cyrillic */ NULL, /* 8,28 latin-9 to JIS-7 */ NULL, /* 8,29 latin-9 to Shift-JIS */ NULL, /* 8,30 latin-9 to J-EUC */ NULL, /* 8,31 latin-9 to DEC Kanji */ xl1h7, /* 8,32 latin-9 to Hebrew-7 */ xl1lh, /* 8,33 latin-9 to Latin/Hebrew */ xl162, /* 8,34 latin-9 to CP862 Hebrew */ xl1eg, /* 8,35 latin-9 to ELOT 927 Greek */ xl1lg, /* 8,36 latin-9 to Latin/Greek */ xl169, /* 8,37 latin-9 to CP869 */ NULL, /* 8,38 latin-9 to Latin9 */ xl958, /* 8,39 latin-9 to CP858 */ zl1as, /* 8,40 latin-9 to CP855 */ zl1as, /* 8,41 latin-9 to CP1251 */ xl1as, /* 8,42 latin-9 to Bulgarian */ xl91250, /* 8,43 latin-9 to CP1250 */ xl9mz, /* 8,44 latin-9 to Mazovia */ NULL, /* 8,45 latin-9 to UCS-2 */ NULL, /* 8,46 latin-9 to UTF-8 */ zl1as, /* 8,47 latin-9 to KOI8-R */ zl1as, /* 8,48 latin-9 to KOI8-U */ xl9w1, /* 8,49 latin-9 to CP1252 */ NULL, /* 9,00 Unicode... */ NULL, /* 9,01 */ NULL, /* 9,02 */ NULL, /* 9,03 */ NULL, /* 9,04 */ NULL, /* 9,05 */ NULL, /* 9,06 */ NULL, /* 9,07 */ NULL, /* 9,08 */ NULL, /* 9,09 */ NULL, /* 9,10 */ NULL, /* 9,11 */ NULL, /* 9,12 */ NULL, /* 9,13 */ NULL, /* 9,14 */ NULL, /* 9,15 */ NULL, /* 9,16 */ NULL, /* 9,17 */ NULL, /* 9,18 */ NULL, /* 9,19 */ NULL, /* 9,20 */ NULL, /* 9,21 */ NULL, /* 9,22 */ NULL, /* 9,23 */ NULL, /* 9,24 */ NULL, /* 9,25 */ NULL, /* 9,26 */ NULL, /* 9,27 */ NULL, /* 9,28 */ NULL, /* 9,29 */ NULL, /* 9,30 */ NULL, /* 9,31 */ NULL, /* 9,32 */ NULL, /* 9,33 */ NULL, /* 9,34 */ NULL, /* 9,35 */ NULL, /* 9,36 */ NULL, /* 9,37 */ NULL, /* 9,38 */ NULL, /* 9,39 */ NULL, /* 9,40 */ NULL, /* 9,41 */ NULL, /* 9,42 */ NULL, /* 9,43 */ NULL, /* 9,44 */ NULL, /* 9,45 */ NULL, /* 9,46 */ NULL, /* 9,47 */ NULL, /* 9,48 */ NULL, /* 9,49 */ NULL, /* 10,00 */ NULL, /* 10,01 */ NULL, /* 10,02 */ NULL, /* 10,03 */ NULL, /* 10,04 */ NULL, /* 10,05 */ NULL, /* 10,06 */ NULL, /* 10,07 */ NULL, /* 10,08 */ NULL, /* 10,09 */ NULL, /* 10,10 */ NULL, /* 10,11 */ NULL, /* 10,12 */ NULL, /* 10,13 */ NULL, /* 10,14 */ NULL, /* 10,15 */ NULL, /* 10,16 */ NULL, /* 10,17 */ NULL, /* 10,18 */ NULL, /* 10,19 */ NULL, /* 10,20 */ NULL, /* 10,21 */ NULL, /* 10,22 */ NULL, /* 10,23 */ NULL, /* 10,24 */ NULL, /* 10,25 */ NULL, /* 10,26 */ NULL, /* 10,27 */ NULL, /* 10,28 */ NULL, /* 10,29 */ NULL, /* 10,30 */ NULL, /* 10,31 */ NULL, /* 10,32 */ NULL, /* 10,33 */ NULL, /* 10,34 */ NULL, /* 10,35 */ NULL, /* 10,36 */ NULL, /* 10,37 */ NULL, /* 10,38 */ NULL, /* 10,39 */ NULL, /* 10,40 */ NULL, /* 10,41 */ NULL, /* 10,42 */ NULL, /* 10,43 */ NULL, /* 10,44 */ NULL, /* 10,45 */ NULL, /* 10,46 */ NULL, /* 10,47 */ NULL, /* 10,48 */ NULL /* 10,49 */ }; int nxlr = (sizeof(xlr) / sizeof(CHAR *)); /* Translation function table for sending files. Array of pointers to functions for translating from the local file character set to the transfer character set. Indexed in the same way as the xlr array above, but with the indices reversed. */ #ifdef CK_ANSIC CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR) = #else CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])() = #endif /* CK_ANSIC */ { NULL, /* 0,0 us ascii to transparent */ NULL, /* 0,1 uk ascii to transparent */ NULL, /* 0,2 dutch nrc to transparent */ NULL, /* 0,3 finnish nrc to transparent */ NULL, /* 0,4 french nrc to transparent */ NULL, /* 0,5 fr-canadian nrc to transparent */ NULL, /* 0,6 german nrc to transparent */ NULL, /* 0,7 hungarian nrc to transparent */ NULL, /* 0,8 italian nrc to transparent */ NULL, /* 0,9 norge/danish nrc to transparent */ NULL, /* 0,10 portuguese nrc to transparent */ NULL, /* 0,11 spanish nrc to transparent */ NULL, /* 0,12 swedish nrc to transparent */ NULL, /* 0,13 swiss nrc to transparent */ NULL, /* 0,14 latin-1 to transparent */ NULL, /* 0,15 latin-2 to transparent */ NULL, /* 0,16 DEC MCS to transparent */ NULL, /* 0,17 NeXT to transparent */ NULL, /* 0,18 CP437 to transparent */ NULL, /* 0,19 CP850 to transparent */ NULL, /* 0,20 CP852 to transparent */ NULL, /* 0,21 Macintosh Latin to transparent */ NULL, /* 0,22 DGI to transparent */ NULL, /* 0,23 HP to transparent */ NULL, /* 0,24 Latin/Cyrillic to transparent */ NULL, /* 0,25 CP866 to transparent */ NULL, /* 0,26 Short KOI to transparent */ NULL, /* 0,27 Old KOI-8 to transparent */ NULL, /* 0,28 JIS-7 to transparent */ NULL, /* 0,29 Shift JIS to transparent */ NULL, /* 0,30 Japanese EUC to transparent */ NULL, /* 0,31 DEC Kanji to transparent */ NULL, /* 0,32 Hebrew-7 to transparent */ NULL, /* 0,33 Latin/Hebrew to transparent */ NULL, /* 0,34 CP862 Hebrew to transparent */ NULL, /* 0,35 ELOT 927 Greek to transparent */ NULL, /* 0,36 Latin/Greek to transparent */ NULL, /* 0,37 CP869 to transparent */ NULL, /* 0,38 Latin-9 to transparent */ NULL, /* 0,39 CP858 to transparent */ NULL, /* 0,40 CP855 to transparent */ NULL, /* 0,41 CP1251 to transparent */ NULL, /* 0,42 Bulgarian to transparent */ NULL, /* 0,43 CP1250 to transparent */ NULL, /* 0,44 Mazovia to transparent */ NULL, /* 0,45 UCS-2 to transparent */ NULL, /* 0,46 UTF-8 to transparent */ NULL, /* 0,47 KOI8R to transparent */ NULL, /* 0,48 KOI8U to transparent */ NULL, /* 0,49 CP1252 to transparent */ NULL, /* 1,0 us ascii to ascii */ NULL, /* 1,1 uk ascii to ascii */ xduas, /* 1,2 dutch nrc to ascii */ xfias, /* 1,3 finnish nrc to ascii */ xfras, /* 1,4 french nrc to ascii */ xfcas, /* 1,5 french canadian nrc to ascii */ xgeas, /* 1,6 german nrc to ascii */ xhuas, /* 1,7 hungarian nrc to ascii */ xitas, /* 1,8 italian nrc to ascii */ xnoas, /* 1,9 norwegian/danish nrc to ascii */ xpoas, /* 1,10 portuguese nrc to ascii */ xspas, /* 1,11 spanish nrc to ascii */ xswas, /* 1,12 swedish nrc to ascii */ xchas, /* 1,13 swiss nrc to ascii */ xl1as, /* 1,14 latin-1 to ascii */ xl2as, /* 1,15 latin-2 to ascii */ xdmas, /* 1,16 dec mcs to ascii */ xneas, /* 1,17 NeXT to ascii */ x43as, /* 1,18 CP437 to ascii */ x85as, /* 1,19 CP850 to ascii */ x52as, /* 1,20 CP850 to ascii */ xaqas, /* 1,21 Macintosh Latin to ascii */ xdgas, /* 1,22 DGI to ascii */ xr8as, /* 1,23 HP to ASCII */ xlcas, /* 1,24 Latin/Cyrillic to ASCII */ xacas, /* 1,25 CP866 to ASCII */ xskas, /* 1,26 Short KOI to ASCII */ xk8as, /* 1,27 Old KOI-8 Cyrillic to ASCII */ NULL, /* 1,28 */ NULL, /* 1,29 */ NULL, /* 1,30 */ NULL, /* 1,31 */ xh7as, /* 1,32 Hebrew-7 to ASCII */ xlhas, /* 1,33 Latin/Hebrew to ASCII */ x62as, /* 1,34 CP862 Hebrew to ASCII */ xegas, /* 1,35 ELOT 927 Greek to ASCII */ xlgas, /* 1,36 Latin/Greek to ASCII */ x69as, /* 1,37 CP869 to ASCII */ xl9as, /* 1,38 Latin-9 to ASCII */ x58as, /* 1,39 CP858 to ASCII */ x55as, /* 1,40 CP855 to ASCII */ x1251as, /* 1,41 CP1251 to ASCII */ xleft128, /* 1,42 Bulgarian to ASCII */ x1250as, /* 1,43 CP1250 to ASCII */ xmzas, /* 1,44 Mazovia to ASCII */ NULL, /* 1,45 UCS-2 to ASCII */ NULL, /* 1,46 UTF-8 to ASCII */ xk8as, /* 1,47 KOI8R to ASCII */ xk8as, /* 1,48 KOI8U to ASCII */ xw1as, /* 1,49 CP1252 to ASCII */ NULL, /* 2,0 us ascii to latin-1 */ xukl1, /* 2,1 uk ascii to latin-1 */ xdul1, /* 2,2 dutch nrc to latin-1 */ xfil1, /* 2,3 finnish nrc to latin-1 */ xfrl1, /* 2,4 french nrc to latin-1 */ xfcl1, /* 2,5 french canadian nrc to latin-1 */ xgel1, /* 2,6 german nrc to latin-1 */ xhul1, /* 2,7 hungarian nrc to latin-1 */ xitl1, /* 2,8 italian nrc to latin-1 */ xnol1, /* 2,9 norwegian/danish nrc to latin-1 */ xpol1, /* 2,10 portuguese nrc to latin-1 */ xspl1, /* 2,11 spanish nrc to latin-1 */ xswl1, /* 2,12 swedish nrc to latin-1 */ xchl1, /* 2,13 swiss nrc to latin-1 */ NULL, /* 2,14 latin-1 to latin-1 */ xl2l1, /* 2,15 latin-2 to latin-1 */ xdml1, /* 2,16 dec mcs to latin-1 */ xnel1, /* 2,17 NeXT to Latin-1 */ x43l1, /* 2,18 CP437 to Latin-1 */ x85l1, /* 2,19 CP850 to Latin-1 */ x52l1, /* 2,20 CP852 to Latin-1 */ xaql1, /* 2,21 Macintosh Latin to Latin-1 */ xdgl1, /* 2,22 DGI to Latin-1 */ xr8l1, /* 2,23 HP to Latin-1 */ xlcas, /* 2,24 Latin/Cyrillic to Latin-1 */ xacas, /* 2,25 CP866 to Latin-1 */ xskas, /* 2,26 Short KOI to Latin-1 */ xk8as, /* 2,27 Old KOI-8 Cyrillic to Latin-1 */ NULL, /* 2,28 Kanji ... */ NULL, /* 2,29 */ NULL, /* 2,30 */ NULL, /* 2,31 */ xh7as, /* 2,32 Hebrew-7 to Latin-1 */ xlhl1, /* 2,33 Latin/Hebrew to Latin-1 */ x62l1, /* 2,34 CP862 Hebrew to Latin-1 */ xegas, /* 2,35 ELOT 927 Greek to Latin-1 */ xlgl1, /* 2,36 Latin/Greek to Latin-1 */ NULL, /* 2,37 CP869 to Latin-1 */ NULL, /* 2,38 Latin-9 to Latin-1 */ x58l1, /* 2,39 CP858 to Latin-1 */ x55as, /* 2,40 CP855 to Latin-1 */ x1251as, /* 2,41 CP1251 to Latin-1 */ xleft128, /* 2,42 Bulgarian to Latin-1 */ x1250l1, /* 2,43 CP1250 to Latin-1 */ xmzl1, /* 2,44 Mazovia to Latin-1 */ NULL, /* 2,45 UCS-2 to Latin-1 */ NULL, /* 2,46 UTF-8 to Latin-1 */ xk8as, /* 2,47 KOI8R to Latin-1 */ xk8as, /* 2,48 KOI8U to Latin-1 */ xw1l1, /* 2,49 CP1252 to Latin-1 */ NULL, /* 3,0 us ascii to latin-2 */ NULL, /* 3,1 uk ascii to latin-2 */ xduas, /* 3,2 dutch nrc to latin-2 */ xfias, /* 3,3 finnish nrc to latin-2 */ xfras, /* 3,4 french nrc to latin-2 */ xfcas, /* 3,5 french canadian nrc to latin-2 */ xgel2, /* 3,6 german nrc to latin-2 */ xhul2, /* 3,7 hungarian nrc to latin-2 */ xitas, /* 3,8 italian nrc to latin-2 */ xnoas, /* 3,9 norwegian/danish nrc to latin-2 */ xpoas, /* 3,10 portuguese nrc to latin-2 */ xspas, /* 3,11 spanish nrc to latin-2 */ xswas, /* 3,12 swedish nrc to latin-2 */ xchas, /* 3,13 swiss nrc to latin-2 */ xl1l2, /* 3,14 latin-1 to latin-2 */ NULL, /* 3,15 latin-2 to latin-2 */ xl1l2, /* 3,16 dec mcs to latin-2 */ xnel2, /* 3,17 NeXT to Latin-2 */ x43l2, /* 3,18 CP437 to Latin-2 */ x85l2, /* 3,19 CP850 to Latin-2 */ x52l2, /* 3,20 CP852 to Latin-2 */ xaql2, /* 3,21 Macintosh Latin to Latin-2 */ xdgl2, /* 3,22 DGI to Latin-2 */ xr8l2, /* 3,23 HP to Latin-2 */ xlcas, /* 3,24 Latin/Cyrillic to Latin-2 */ xacas, /* 3,25 CP866 to Latin-2 */ xskas, /* 3,26 Short KOI to Latin-2 */ xk8as, /* 3,27 Old KOI-8 Cyrillic to Latin-2 */ NULL, /* 3,28 Kanji ... */ NULL, /* 3,29 */ NULL, /* 3,30 */ NULL, /* 3,31 */ xh7as, /* 3,32 Hebrew-7 to Latin-2 */ xlhas, /* 3,33 Latin/Hebrew to Latin-2 */ x62as, /* 3,34 CP862 Hebrew to Latin-2 */ xegas, /* 3,35 ELOT 927 Greek to Latin-2 */ xl2lg, /* 3,36 Latin/Greek to Latin-2 */ xleft128, /* 3,37 CP869 to Latin-2 */ xl9l2, /* 3,38 Latin-9 to Latin-2 */ x58l2, /* 3,39 CP858 to Latin-2 */ x55as, /* 3,40 CP855 to Latin-2 */ x1251as, /* 3,41 CP1251 to Latin-2 */ xleft128, /* 3,42 Bulgarian to Latin-2 */ x1250l2, /* 3,43 CP1250 to Latin-2 */ xmzl2, /* 3,44 Mazovia to Latin-2 */ NULL, /* 3,45 UCS-2 to Latin-2 */ NULL, /* 3,46 UTF-8 to Latin-2 */ xk8as, /* 3,47 KOI8R to Latin-2 */ xk8as, /* 3,48 KOI8U to Latin-2 */ xw1l2, /* 3,49 CP1252 to latin-2 */ xaslc, /* 4,0 us ascii to latin/cyrillic */ xaslc, /* 4,1 uk ascii to latin/cyrillic */ xduas, /* 4,2 dutch nrc to latin/cyrillic */ xfias, /* 4,3 finnish nrc to latin/cyrillic */ xfras, /* 4,4 french nrc to latin/cyrillic */ xfcas, /* 4,5 french canadian nrc to latin/cyrillic */ xgeas, /* 4,6 german nrc to latin/cyrillic */ xhuas, /* 4,7 hungarian nrc to latin/cyrillic */ xitas, /* 4,8 italian nrc to latin/cyrillic */ xnoas, /* 4,9 norge/danish nrc to latin/cyrillic */ xpoas, /* 4,10 portuguese nrc to latin/cyrillic */ xspas, /* 4,11 spanish nrc to latin/cyrillic */ xswas, /* 4,12 swedish nrc to latin/cyrillic */ xchas, /* 4,13 swiss nrc to latin/cyrillic */ xl1as, /* 4,14 latin-1 to latin/cyrillic */ xl2as, /* 4,15 latin-2 to latin/cyrillic */ xdmas, /* 4,16 dec mcs to latin/cyrillic */ xneas, /* 4,17 NeXT to latin/cyrillic */ x43as, /* 4,18 CP437 to latin/cyrillic */ x85as, /* 4,19 CP850 to latin/cyrillic */ x52as, /* 4,20 CP852 to latin/cyrillic */ xaqas, /* 4,21 Macintosh Latin to latin/cyrillic */ xdgas, /* 4,22 DGI to Latin/Cyrillic */ xr8as, /* 4,23 HP to Latin/Cyrillic */ NULL, /* 4,24 Latin/Cyrillic to Latin/Cyrillic */ xaclc, /* 4,25 CP866 to Latin/Cyrillic */ xskcy, /* 4,26 Short KOI to Latin/Cyrillic */ xk8lc, /* 4,27 Old KOI-8 Cyrillic to Latin/Cyrillic */ NULL, /* 4,28 Kanji... */ NULL, /* 4,29 */ NULL, /* 4,30 */ NULL, /* 4,31 */ xh7as, /* 4,32 Hebrew-7 to Latin/Cyrillic */ xlhas, /* 4,33 Latin/Hebrew to Latin/Cyrillic */ x62as, /* 4,34 CP862 Hebrew to Latin/Cyrillic */ xegas, /* 4,35 ELOT 927 Greek to Latin/Cyrillic */ xleft160, /* 4,36 Latin/Greek to Latin/Cyrillic */ xleft128, /* 4,37 CP869 to Latin/Cyrillic */ xl1as, /* 4,38 latin-9 to latin/cyrillic */ xleft128, /* 4,39 CP858 to Latin/Cyrillic */ x55lc, /* 4,40 CP855 to Latin/Cyrillic */ x1251lc, /* 4,41 CP1251 to Latin/Cyrillic */ xbulc, /* 4,42 Bulgarian to Latin/Cyrillic */ x1250as, /* 4,43 CP1250 to Latin/Cyrillic */ xmzas, /* 4,44 Mazovia to Latin/Cyrillic */ NULL, /* 4,45 UCS-2 to Latin/Cyrillic */ NULL, /* 4,46 UTF-8 to Latin/Cyrillic */ xkrlc, /* 4,47 KOI8R to Latin/Cyrillic */ xkulc, /* 4,48 KOI8U to Latin/Cyrillic */ xw1lc, /* 4,49 CP1252 to Latin/Cyrillic */ NULL, /* 5,00 */ NULL, /* 5,01 */ NULL, /* 5,02 */ NULL, /* 5,03 */ NULL, /* 5,04 */ NULL, /* 5,05 */ NULL, /* 5,06 */ NULL, /* 4.07 */ NULL, /* 5,08 */ NULL, /* 5,09 */ NULL, /* 5,10 */ NULL, /* 5,11 */ NULL, /* 5,12 */ NULL, /* 5,13 */ NULL, /* 5,14 */ NULL, /* 5,15 */ NULL, /* 5,16 */ NULL, /* 5,17 */ NULL, /* 5,18 */ NULL, /* 5,19 */ NULL, /* 5,20 */ NULL, /* 5,21 */ NULL, /* 5,22 */ NULL, /* 5,23 */ NULL, /* 5,24 */ NULL, /* 5,25 */ NULL, /* 5,26 */ NULL, /* 5,27 */ NULL, /* 5,28 */ NULL, /* 5,29 */ NULL, /* 5,30 */ NULL, /* 5,31 */ NULL, /* 5,32 */ NULL, /* 5,33 */ NULL, /* 5,34 */ NULL, /* 5,35 */ NULL, /* 5,36 */ NULL, /* 5,37 */ NULL, /* 5,38 */ NULL, /* 5,39 */ NULL, /* 5,40 */ NULL, /* 5,41 */ NULL, /* 5,42 */ NULL, /* 5,43 */ NULL, /* 5,44 */ NULL, /* 5,45 */ NULL, /* 5,46 */ NULL, /* 5,47 */ NULL, /* 5,48 */ NULL, /* 5,49 */ NULL, /* 6,0 us ascii to Latin/Hebrew */ NULL, /* 6,1 uk ascii to Latin/Hebrew */ xduas, /* 6,2 dutch nrc to Latin/Hebrew */ xfias, /* 6,3 finnish nrc to Latin/Hebrew */ xfras, /* 6,4 french nrc to Latin/Hebrew */ xfcas, /* 6,5 french canadian nrc to Latin/Hebrew */ xgeas, /* 6,6 german nrc to Latin/Hebrew */ xhuas, /* 6,7 hungarian nrc to Latin/Hebrew */ xitas, /* 6,8 italian nrc to Latin/Hebrew */ xnoas, /* 6,9 norge/danish nrc to Latin/Hebrew */ xpoas, /* 6,10 portuguese nrc to Latin/Hebrew */ xspas, /* 6,11 spanish nrc to Latin/Hebrew */ xswas, /* 6,12 swedish nrc to Latin/Hebrew */ xchas, /* 6,13 swiss nrc to Latin/Hebrew */ xl1lh, /* 6,14 latin-1 to Latin/Hebrew */ xl2as, /* 6,15 latin-2 to Latin/Hebrew */ xdmas, /* 6,16 dec mcs to Latin/Hebrew */ xneas, /* 6,17 NeXT to Latin/Hebrew */ x43as, /* 6,18 CP437 to Latin/Hebrew */ x85as, /* 6,19 CP850 to Latin/Hebrew */ x52as, /* 6,20 CP852 to Latin/Hebrew */ xaqas, /* 6,21 Macintosh Latin to Latin/Hebrew */ xdgas, /* 6,22 DGI to Latin/Hebrew */ xr8as, /* 6,23 HP to Latin/Hebrew */ xlcas, /* 6,24 Latin/Cyrillic to Latin/Hebrew */ xacas, /* 6,25 CP866 to Latin/Hebrew */ xskas, /* 6,26 Short KOI to Latin/Hebrew */ xk8as, /* 6,27 Old KOI-8 Cyrillic to Latin/Hebrew */ NULL, /* 6,28 Kanji... */ NULL, /* 6,29 */ NULL, /* 6,30 */ NULL, /* 6,31 */ xh7lh, /* 6,32 Hebrew-7 to Latin/Hebrew */ NULL, /* 6,33 Latin/Hebrew to Latin/Hebrew */ x62lh, /* 6,34 CP862 Hebrew to Latin/Hebrew */ xegas, /* 6,35 ELOT 927 Greek to Latin/Hebrew */ xlgas, /* 6,36 Latin/Greek to Latin/Hebrew */ x69as, /* 6,37 CP869 to Latin/Hebrew */ xl1as, /* 6,38 latin-9 to Latin/Hebrew */ x58as, /* 6,39 CP858 to Latin/Hebrew */ x55as, /* 6,40 CP855 to Latin/Hebrew */ x1251as, /* 6,41 CP1251 to Latin/Hebrew */ xleft128, /* 6,42 Bulgarian to Latin/Hebrew */ x1250as, /* 6,43 CP1250 to Latin/Hebrew */ xmzas, /* 6,44 Mazovia to Latin/Hebrew */ NULL, /* 6,45 UCS-2 to Latin/Hebrew */ NULL, /* 6,46 UTF-8 to Latin/Hebrew */ NULL, /* 6,47 KOI8R to Latin/Hebrew */ NULL, /* 6,48 KOI8U to Latin/Hebrew */ xw1lh, /* 6,49 CP1252 to Latin/Hebrew */ NULL, /* 7,0 us ascii to Latin/Greek */ NULL, /* 7,1 uk ascii to Latin/Greek */ xduas, /* 7,2 dutch nrc to Latin/Greek */ xfias, /* 7,3 finnish nrc to Latin/Greek */ xfras, /* 7,4 french nrc to Latin/Greek */ xfcas, /* 7,5 french canadian nrc to Latin/Greek */ xgeas, /* 7,6 german nrc to Latin/Greek */ xhuas, /* 7,7 hungarian nrc to Latin/Greek */ xitas, /* 7,8 italian nrc to Latin/Greek */ xnoas, /* 7,9 norge/danish nrc to Latin/Greek */ xpoas, /* 7,10 portuguese nrc to Latin/Greek */ xspas, /* 7,11 spanish nrc to Latin/Greek */ xswas, /* 7,12 swedish nrc to Latin/Greek */ xchas, /* 7,13 swiss nrc to Latin/Greek */ xl1lg, /* 7,14 latin-1 to Latin/Greek */ xl2lg, /* 7,15 latin-2 to Latin/Greek */ xl1lg, /* 7,16 dec mcs to Latin/Greek */ xneas, /* 7,17 NeXT to Latin/Greek */ xleft128, /* 7,18 CP437 to Latin/Greek */ x85as, /* 7,19 CP850 to Latin/Greek */ x52as, /* 7,20 CP852 to Latin/Greek */ xaqas, /* 7,21 Macintosh Latin to Latin/Greek */ xdgas, /* 7,22 DGI to Latin/Greek */ xr8as, /* 7,23 HP to Latin/Greek */ xleft160, /* 7,24 Latin/Cyrillic to Latin/Greek */ xleft128, /* 7,25 CP866 to Latin/Greek */ xskas, /* 7,26 Short KOI to Latin/Greek */ xk8as, /* 7,27 Old KOI-8 Cyrillic to Latin/Greek */ NULL, /* 7,28 Kanji... */ NULL, /* 7,29 */ NULL, /* 7,30 */ NULL, /* 7,31 */ xh7as, /* 7,32 Hebrew-7 to Latin/Greek */ NULL, /* 7,33 Latin/Hebrew to Latin/Greek */ x62as, /* 7,34 CP862 Hebrew to Latin/Greek */ xeglg, /* 7,35 ELOT 927 Greek to Latin/Greek */ NULL, /* 7,36 Latin/Greek to Latin/Greek */ x69lg, /* 7,37 CP869 to Latin/Greek */ xl1as, /* 7,38 latin-9 to Latin/Greek */ xl1as, /* 7,39 latin-9 to Latin/Hebrew*/ xleft128, /* 7,40 CP855 to Latin/Greek */ xleft128, /* 7,41 CP1251 to Latin/Greek */ xleft128, /* 7,42 Bulgarian to Latin/Greek */ x1250as, /* 7,43 CP1250 to Latin/Greek */ xmzas, /* 7,44 Mazovia to Latin/Greek */ NULL, /* 7,45 UCS-2 to Latin/Greek */ NULL, /* 7,46 UTF-8 to Latin/Greek */ NULL, /* 7,47 KOI8R to Latin/Greek */ NULL, /* 7,48 KOI8U to Latin/Greek */ xw1lg, /* 7,49 CP1252 to Latin/Greek */ NULL, /* 8,0 us ascii to latin-9 */ xukl1, /* 8,1 uk ascii to latin-9 */ xdul1, /* 8,2 dutch nrc to latin-9 */ xfil1, /* 8,3 finnish nrc to latin-9 */ xfrl1, /* 8,4 french nrc to latin-9 */ xfcl1, /* 8,5 french canadian nrc to latin-9 */ xgel1, /* 8,6 german nrc to latin-9 */ xhul1, /* 8,7 hungarian nrc to latin-9 */ xitl1, /* 8,8 italian nrc to latin-9 */ xnol1, /* 8,9 norwegian/danish nrc to latin-9 */ xpol1, /* 8,10 portuguese nrc to latin-9 */ xspl1, /* 8,11 spanish nrc to latin-9 */ xswl1, /* 8,12 swedish nrc to latin-9 */ xchl1, /* 8,13 swiss nrc to latin-9 */ NULL, /* 8,14 latin-1 to latin-9 */ xl2l9, /* 8,15 latin-2 to latin-9 */ xdml9, /* 8,16 dec mcs to latin-9 */ xnel9, /* 8,17 NeXT To Latin-9 */ x43l1, /* 8,18 CP437 To Latin-9 */ x85l1, /* 8,19 CP850 To Latin-9 */ x52l1, /* 8,20 CP852 To Latin-9 */ xaql1, /* 8,21 Macintosh Latin To Latin-9 */ xdgl1, /* 8,22 DGI To Latin-9 */ xr8l1, /* 8,23 HP To Latin-9 */ xlcas, /* 8,24 Latin/Cyrillic To Latin-9 */ xacas, /* 8,25 CP866 To Latin-9 */ xskas, /* 8,26 Short KOI To Latin-9 */ xk8as, /* 8,27 Old KOI-8 Cyrillic To Latin-9 */ NULL, /* 8,28 Kanji ... */ NULL, /* 8,29 */ NULL, /* 8,30 */ NULL, /* 8,31 */ xh7as, /* 8,32 Hebrew-7 To Latin-9 */ xlhl1, /* 8,33 Latin/Hebrew To Latin-9 */ x62l1, /* 8,34 CP862 Hebrew To Latin-9 */ xegas, /* 8,35 ELOT 927 Greek To Latin-9 */ xlgl1, /* 8,36 Latin/Greek To Latin-9 */ xl169, /* 8,37 CP869 To Latin-9 */ NULL, /* 8,38 Latin-9 To Latin-9 */ x58l9, /* 8,39 cp858 To Latin-9 */ x55as, /* 8,40 cp855 To Latin-9 */ x55as, /* 8,41 cp1251 To Latin-9 */ xleft128, /* 8,42 Bulgarian To Latin-9 */ x1250l9, /* 8,43 CP1250 To Latin-9 */ xmzl9, /* 8,44 Mazovia To Latin-9 */ NULL, /* 8,45 UCS-2 to Latin-9 */ NULL, /* 8,46 UTF-8 to Latin-9 */ NULL, /* 8,47 KOI8R to Latin-9 */ NULL, /* 8,48 KOI8U to Latin-9 */ xw1l9, /* 8,49 CP1252 to Latin-9 */ NULL, /* 9,00 Unicode... */ NULL, /* 9,01 */ NULL, /* 9,02 */ NULL, /* 9,03 */ NULL, /* 9,04 */ NULL, /* 9,05 */ NULL, /* 9,06 */ NULL, /* 9,07 */ NULL, /* 9,08 */ NULL, /* 9,09 */ NULL, /* 9,10 */ NULL, /* 9,11 */ NULL, /* 9,12 */ NULL, /* 9,13 */ NULL, /* 9,14 */ NULL, /* 9,15 */ NULL, /* 9,16 */ NULL, /* 9,17 */ NULL, /* 9,18 */ NULL, /* 9,19 */ NULL, /* 9,20 */ NULL, /* 9,21 */ NULL, /* 9,22 */ NULL, /* 9,23 */ NULL, /* 9,24 */ NULL, /* 9,25 */ NULL, /* 9,26 */ NULL, /* 9,27 */ NULL, /* 9,28 */ NULL, /* 9,29 */ NULL, /* 9,30 */ NULL, /* 9,31 */ NULL, /* 9,32 */ NULL, /* 9,33 */ NULL, /* 9,34 */ NULL, /* 9,35 */ NULL, /* 9,36 */ NULL, /* 9,37 */ NULL, /* 9,38 */ NULL, /* 9,39 */ NULL, /* 9,40 */ NULL, /* 9,41 */ NULL, /* 9,42 */ NULL, /* 9,43 */ NULL, /* 9,44 */ NULL, /* 9,45 */ NULL, /* 9,46 */ NULL, /* 9,47 */ NULL, /* 9,48 */ NULL, /* 9,49 */ NULL, /* 10,00 */ NULL, /* 10,01 */ NULL, /* 10,02 */ NULL, /* 10,03 */ NULL, /* 10,04 */ NULL, /* 10,05 */ NULL, /* 10,06 */ NULL, /* 10,07 */ NULL, /* 10,08 */ NULL, /* 10,09 */ NULL, /* 10,10 */ NULL, /* 10,11 */ NULL, /* 10,12 */ NULL, /* 10,13 */ NULL, /* 10,14 */ NULL, /* 10,15 */ NULL, /* 10,16 */ NULL, /* 10,17 */ NULL, /* 10,18 */ NULL, /* 10,19 */ NULL, /* 10,20 */ NULL, /* 10,21 */ NULL, /* 10,22 */ NULL, /* 10,23 */ NULL, /* 10,24 */ NULL, /* 10,25 */ NULL, /* 10,26 */ NULL, /* 10,27 */ NULL, /* 10,28 */ NULL, /* 10,29 */ NULL, /* 10,30 */ NULL, /* 10,31 */ NULL, /* 10,32 */ NULL, /* 10,33 */ NULL, /* 10,34 */ NULL, /* 10,35 */ NULL, /* 10,36 */ NULL, /* 10,37 */ NULL, /* 10,38 */ NULL, /* 10,39 */ NULL, /* 10,40 */ NULL, /* 10,41 */ NULL, /* 10,42 */ NULL, /* 10,43 */ NULL, /* 10,44 */ NULL, /* 10,45 */ NULL, /* 10,46 */ NULL, /* 10,47 */ NULL, /* 10,48 */ NULL /* 10,49 */ }; int nxls = (sizeof(xls) / sizeof(CHAR *)); #ifndef NOLOCAL /* The following routines are useful only for terminal character sets, and so ifdef'd out for NOLOCAL compilations. */ /* C S _ I S _ N R C Returns nonzero if argument indicates a 7-bit national character set, zero otherwise. */ int #ifdef CK_ANSIC cs_is_nrc( int x ) #else cs_is_nrc(x) int x; #endif /* CK_ANSIC */ { #ifdef UNICODE if (x == TX_J201R || x == TX_DECSPEC || x == TX_DECTECH || txrinfo[x] == NULL) return(0); else return(txrinfo[x]->flags & X2U_STD && txrinfo[x]->size == 94); #else /* UNICODE */ if ((cs_size(x) == 94)) return(1); else return(0); #endif /* UNICODE */ } /* C S _ I S _ S T D Returns nonzero if argument indicates an ISO 4873-standard-format character set, i.e. one in which the control region is NOT used for graphics; zero otherwise. */ int #ifdef CK_ANSIC cs_is_std( int x ) #else cs_is_std(x) int x; #endif /* CK_ANSIC */ { #ifdef UNICODE if (!txrinfo[x]) /* Even more safety */ return(0); else if (txrinfo[x]->size == 128) /* Just for safety */ return(0); else return(txrinfo[x]->flags & X2U_STD); /* Only this should be needed */ #else switch (x) { case FC_CP437: /* Code pages use C1 graphics */ case FC_CP850: case FC_CP852: case FC_CP862: case FC_CP866: case FC_CP869: case FC_CP858: case FC_APPQD: /* So do Apple and NeXTSTEP */ case FC_NEXT: return(0); default: /* Others behave */ return(1); } #endif /* CKOUINI */ } int #ifdef CK_ANSIC cs_size( int x ) #else cs_size(x) int x; #endif /* CK_ANSIC */ { #ifdef UNICODE if (!txrinfo[x]) return(128); return(txrinfo[x]->size); #else switch(x) { case FC_USASCII: case FC_UKASCII: case FC_DUASCII: case FC_FIASCII: case FC_FRASCII: case FC_FCASCII: case FC_GEASCII: case FC_HUASCII: case FC_ITASCII: case FC_NOASCII: case FC_POASCII: case FC_SPASCII: case FC_SWASCII: case FC_CHASCII: case FC_KOI7: case FC_HE7: case FC_ELOT: return(94); case FC_1LATIN: case FC_2LATIN: case FC_DECMCS: case FC_DGMCS: case FC_HPR8: case FC_CYRILL: case FC_KOI8: case FC_HEBREW: case FC_GREEK: case FC_9LATIN: return(96); case FC_NEXT: case FC_CP437: case FC_CP850: case FC_CP852: case FC_CP855: case FC_CP862: case FC_CP866: case FC_CP1251: case FC_APPQD: return(128); #ifdef KANJI case FC_JIS7: return(-94); case FC_SHJIS: return(-128); case FC_JEUC: case FC_JDEC: return(-96); #endif /* KANJI */ case FC_CP858: default: return(-1); } #endif /* UNICODE */ } #endif /* NOLOCAL */ /* S E T X L A T Y P E -- Set Translation Type Sets global xlatype to indicate which kind of translation: XLA_NONE No translation XLA_BYTE Byte-for-Byte translation XLA_JAPAN Japanese Kanji translation XLA_UNICODE Unicode translations And sets up the appropriate translation function pointers as follows: For no translation: All function pointers are NULL. For Byte-for-Byte transation: rx = TCS to FCS (these functions are in this module...) sx = FCS to TCS For Unicode translations: xfu = FCS to UCS (these functions are in ckcuni.c...) xtu = TCS to UCS xuf = UCS to FCS xut = UCS to TCS */ VOID #ifdef CK_ANSIC setxlatype( int tcs, int fcs ) #else setxlatype(tcs, fcs) int tcs, fcs; #endif /* CK_ANSIC */ { #ifdef UNICODE xfu = NULL; /* Unicode <-> TCS/FCS functions */ xtu = NULL; xuf = NULL; xut = NULL; #endif /* UNICODE */ rx = sx = NULL; debug(F101,"setxlatype fcs","",fcs); debug(F101,"setxlatype tcs","",tcs); if (tcs < 0 || tcs > MAXTCSETS) { debug(F101,"setxlatype bad tcs","",tcs); return; } if (fcs < 0 || fcs > MAXFCSETS) { debug(F101,"setxlatype bad fcs","",fcs); return; } if (tcs == TC_TRANSP || xfrxla == 0) { /* Transfer charset TRANSPARENT */ debug(F101,"setxlatype transparent because TCS==Transparent","",tcs); xlatype = XLA_NONE; /* Translation type is None */ #ifdef UNICODE /* If any of our charsets is Unicode we use Unicode functions */ /* even if TCS and FCS are the same because of BOM and byte swapping */ } else if (tcs == TC_UCS2 || tcs == TC_UTF8 || fcs == FC_UCS2 || fcs == FC_UTF8) { debug(F101,"setxlatype Unicode tcs","",tcs); debug(F101,"setxlatype Unicode fcs","",fcs); /* Unicode <-> TCS/FCS functions */ xfu = xl_fcu[fcs]; /* FCS -> UCS */ xtu = xl_tcu[tcs]; /* TCS -> UCS */ xuf = xl_ufc[fcs]; /* UCS -> FCS */ xut = xl_utc[tcs]; /* UCS -> TCS */ xlatype = XLA_UNICODE; /* Translation type is Unicode */ #ifdef COMMENT /* These make trouble in 64-bit land */ debug(F001,"setxlatype Unicode xfu","",(unsigned)xfu); debug(F001,"setxlatype Unicode xuf","",(unsigned)xuf); #endif /* COMMENT */ #endif /* UNICODE */ } else if (cseqtab[tcs] == fcs) { /* Or if TCS == FCS */ debug(F101,"setxlatype transparent because TCS==FCS","",tcs); xlatype = XLA_NONE; /* translation type is also None */ #ifdef KANJI /* Otherwise if any of them is Japanese, we use Kanji functions */ } else if (tcs == TC_JEUC || fcsinfo[fcs].alphabet == AL_JAPAN) { debug(F101,"setxlatype Japanese tcs","",tcs); debug(F101,"setxlatype Japanese fcs","",fcs); xlatype = XLA_JAPAN; /* Translation type is Japanese */ #endif /* KANJI */ /* Otherwise we use byte functions */ } else { /* Otherwise... */ rx = xlr[tcs][fcs]; /* Input translation function */ sx = xls[tcs][fcs]; /* Output translation function */ debug(F101,"setxlatype Byte tcs","",tcs); debug(F101,"setxlatype Byte fcs","",fcs); xlatype = XLA_BYTE; /* Translation type is Byte */ } debug(F101,"setxlatype xlatype","",xlatype); } /* Set up translation between two file character sets with UCS intermediate */ #ifdef UNICODE VOID #ifdef CK_ANSIC initxlate( int csin, int csout ) #else initxlate(csin, csout) int csin, csout; #endif /* CK_ANSIC */ { xfu = NULL; xtu = NULL; xuf = NULL; xut = NULL; debug(F101,"initxlate csin","",csin); debug(F101,"initxlate csout","",csout); if (csin < 0 || csin > MAXFCSETS) { debug(F101,"initxlate bad csin","",csin); return; } if (csout < 0 || csout > MAXFCSETS) { debug(F101,"initxlate bad csout","",csout); return; } if (csin == csout && csin != FC_UCS2) { xlatype = XLA_NONE; /* Translation type is None */ return; } xlatype = XLA_UNICODE; /* Translation type is Unicode */ xfu = xl_fcu[csin]; /* FCS -> UCS */ xuf = xl_ufc[csout]; /* UCS -> FCS */ xpnbyte(-1,0,0,NULL); /* Reset UCS-2 */ #ifdef COMMENT debug(F001,"initxlate Unicode xfu","",(unsigned)xfu); debug(F001,"initxlate Unicode xuf","",(unsigned)xuf); #endif /* COMMENT */ debug(F101,"initxlate xlatype","",xlatype); } #endif /* UNICODE */ int csetsinited = 0; VOID initcsets() { /* Routine to reset or initialize */ int i; /* character-set associations. */ #ifdef UNICODE if (ucsorder < 0) /* For creating UCS-2 files. */ ucsorder = byteorder; if (ucsorder < 0) ucsorder = 0; if (fileorder < 0) /* For reading UCS-2 files. */ fileorder = ucsorder; #endif /* UNICODE */ debug(F101,"initcsets nxls","",nxls); debug(F101,"initcsets nxlr","",nxlr); debug(F101,"initcsets TERM LOCAL CSET","",tcsl); debug(F101,"initcsets TERM REMOTE CSET","",tcsr); for (i = 0; i <= MAXFCSETS; i++) /* First clear them all... */ afcset[i] = -1; for (i = 0; i <= MAXTCSETS; i++) axcset[i] = -1; /* Now set specific defaults for incoming files */ xlatype = XLA_NONE; axcset[TC_TRANSP] = FC_TRANSP; axcset[TC_USASCII] = FC_USASCII; #ifdef OS2 switch (fcharset) { case FC_CP850: case FC_CP858: case FC_CP437: case FC_1LATIN: axcset[TC_1LATIN] = fcharset; break; default: axcset[TC_1LATIN] = FC_CP850; } #else #ifdef HPUX axcset[TC_1LATIN] = FC_HPR8; #else #ifdef VMS axcset[TC_1LATIN] = FC_DECMCS; #else #ifdef NEXT axcset[TC_1LATIN] = FC_NEXT; #else #ifdef datageneral axcset[TC_1LATIN] = FC_DGMCS; #else /* Should we use code pages on some PC based UNIXes? */ axcset[TC_1LATIN] = FC_1LATIN; #endif /* datageneral */ #endif /* NEXT */ #endif /* VMS */ #endif /* HPUX */ #endif /* OS2 */ #ifdef OS2 axcset[TC_2LATIN] = FC_CP852; axcset[TC_CYRILL] = FC_CP866; axcset[TC_JEUC] = FC_SHJIS; axcset[TC_HEBREW] = FC_CP862; axcset[TC_GREEK] = FC_CP869; axcset[TC_9LATIN] = FC_CP858; axcset[TC_UCS2] = FC_UCS2; axcset[TC_UTF8] = FC_UCS2; #else axcset[TC_2LATIN] = FC_2LATIN; axcset[TC_CYRILL] = FC_CYRILL; axcset[TC_JEUC] = FC_JEUC; axcset[TC_HEBREW] = FC_HEBREW; axcset[TC_GREEK] = FC_GREEK; axcset[TC_9LATIN] = FC_9LATIN; axcset[TC_UCS2] = FC_UTF8; axcset[TC_UTF8] = FC_UTF8; #endif /* OS2 */ /* And for outbound files */ afcset[FC_USASCII] = TC_USASCII; afcset[FC_UKASCII] = TC_1LATIN; afcset[FC_DUASCII] = TC_1LATIN; afcset[FC_FIASCII] = TC_1LATIN; afcset[FC_FRASCII] = TC_1LATIN; afcset[FC_FCASCII] = TC_1LATIN; afcset[FC_GEASCII] = TC_1LATIN; afcset[FC_HUASCII] = TC_2LATIN; afcset[FC_ITASCII] = TC_1LATIN; afcset[FC_NOASCII] = TC_1LATIN; afcset[FC_POASCII] = TC_1LATIN; afcset[FC_SPASCII] = TC_1LATIN; afcset[FC_SWASCII] = TC_1LATIN; afcset[FC_CHASCII] = TC_1LATIN; afcset[FC_1LATIN] = TC_1LATIN; afcset[FC_2LATIN] = TC_2LATIN; afcset[FC_DECMCS] = TC_1LATIN; afcset[FC_NEXT] = TC_1LATIN; afcset[FC_CP437] = TC_1LATIN; afcset[FC_CP850] = TC_1LATIN; afcset[FC_CP852] = TC_2LATIN; afcset[FC_APPQD] = TC_1LATIN; afcset[FC_DGMCS] = TC_1LATIN; afcset[FC_HPR8] = TC_1LATIN; afcset[FC_CYRILL] = TC_CYRILL; afcset[FC_CP866] = TC_CYRILL; afcset[FC_KOI7] = TC_CYRILL; afcset[FC_KOI8] = TC_CYRILL; afcset[FC_JIS7] = TC_JEUC; afcset[FC_SHJIS] = TC_JEUC; afcset[FC_JEUC] = TC_JEUC; afcset[FC_JDEC] = TC_JEUC; afcset[FC_HE7] = TC_HEBREW; afcset[FC_HEBREW] = TC_HEBREW; afcset[FC_CP862] = TC_HEBREW; afcset[FC_ELOT] = TC_GREEK; afcset[FC_GREEK] = TC_GREEK; afcset[FC_CP869] = TC_GREEK; afcset[FC_9LATIN] = TC_9LATIN; afcset[FC_CP923] = TC_9LATIN; afcset[FC_CP858] = TC_9LATIN; afcset[FC_CP855] = TC_CYRILL; afcset[FC_CP1251] = TC_CYRILL; afcset[FC_BULGAR] = TC_CYRILL; afcset[FC_CP1250] = TC_2LATIN; afcset[FC_MAZOVIA] = TC_2LATIN; afcset[FC_UCS2] = TC_UTF8; afcset[FC_UTF8] = TC_UTF8; afcset[FC_KOI8R] = TC_CYRILL; afcset[FC_KOI8U] = TC_CYRILL; afcset[FC_CP1252] = TC_1LATIN; csetsinited++; return; } #endif /* NOCSETS */ ckuxla.h000664 045065 024037 00000007425 14767402206 012643 0ustar00fdckermit000000 000000 /* File CKUXLA.H C-Kermit language and character-set support for UNIX, VMS, OS/2, AOS/VS, and other systems. This file should be used as a template for the language support files for other C-Kermit implementations -- Macintosh, etc. */ /* Author: Frank da Cruz , Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 2009, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ #ifndef CKUXLA_H #define CKUXLA_H /* Codes for file character sets */ /* ISO 646 and other ISO-646-like 7-bit sets */ #define FC_USASCII 0 /* US ASCII */ #define FC_UKASCII 1 /* United Kingdom ASCII */ #define FC_DUASCII 2 /* Dutch ISO 646 NRC */ #define FC_FIASCII 3 /* Finnish ISO 646 NRC */ #define FC_FRASCII 4 /* French ISO 646 NRC */ #define FC_FCASCII 5 /* French Canadian ISO 646 NRC */ #define FC_GEASCII 6 /* German ISO 646 NRC */ #define FC_HUASCII 7 /* Hungarian ISO 646 NRC */ #define FC_ITASCII 8 /* Italian *ISO 646 NRC */ #define FC_NOASCII 9 /* Norwegian and Danish ISO 646 NRC */ #define FC_POASCII 10 /* Portuguese ISO 646 NRC */ #define FC_SPASCII 11 /* Spanish ISO 646 NRC */ #define FC_SWASCII 12 /* Swedish ISO 646 NRC */ #define FC_CHASCII 13 /* Swiss ISO 646 NRC */ /* 8-bit Roman character sets */ #define FC_1LATIN 14 /* ISO 8859-1 Latin Alphabet 1 */ #define FC_2LATIN 15 /* ISO 8859-2 Latin Alphabet 2 */ #define FC_DECMCS 16 /* DEC Multinational Character Set */ #define FC_NEXT 17 /* NeXT workstation character set */ #define FC_CP437 18 /* IBM PC Code Page 437 */ #define FC_CP850 19 /* IBM PC Code Page 850 */ #define FC_CP852 20 /* IBM PC Code Page 852 */ #define FC_APPQD 21 /* Apple Quickdraw */ #define FC_DGMCS 22 /* Data General International Character Set */ #define FC_HPR8 23 /* HP Roman8 */ /* Cyrillic sets */ #define FC_CYRILL 24 /* ISO 8859-5 Latin/Cyrillic */ #define FC_CP866 25 /* PC Code Page 866 Cyrillic */ #define FC_KOI7 26 /* KOI-7 = Short KOI */ #define FC_KOI8 27 /* KOI-8 */ /* Japanese sets */ #define FC_JIS7 28 /* JIS-7 */ #define FC_SHJIS 29 /* Shifted JIS = CP932 */ #define FC_JEUC 30 /* Japanese EUC (JAE) */ #define FC_JDEC 31 /* Japanese DEC Kanji */ /* Hebrew sets */ #define FC_HE7 32 /* 7-Bit DEC Hebrew */ #define FC_HEBREW 33 /* 8-Bit ISO 8859-8 Latin/Hebrew */ #define FC_CP862 34 /* Hebrew PC Code Page */ /* Greek sets */ #define FC_ELOT 35 /* 7-Bit ELOT 927 Greek */ #define FC_GREEK 36 /* 8-Bit ISO 8859-7 Latin/Greek */ #define FC_CP869 37 /* Greek PC Code Page */ /* New Roman sets with Euro symbol */ #define FC_9LATIN 38 /* ISO 8859-15 Latin Alphabet 9 */ #define FC_CP923 38 /* Same as Latin-9 */ #define FC_CP858 39 /* Western Europe with Euro */ /* Other new additions */ #define FC_CP855 40 /* Cyrillic PC Code Page */ #define FC_CP1251 41 /* Cyrillic Windows */ #define FC_BULGAR 42 /* Bulgarian PC code page */ #define FC_CP1250 43 /* Latin 2 Windows (different from Latin-2)*/ #define FC_MAZOVIA 44 /* Polish Mazovia PC code page */ /* Unicode */ #define FC_UCS2 45 /* ISO-10646 / Unicode UCS-2 */ #define FC_UTF8 46 /* ISO-10646 / Unicode UTF-8 */ /* Recent additions */ #define FC_KOI8R 47 /* KOI8-R (RFC1489) - Russian + boxdrawing */ #define FC_KOI8U 48 /* KOI8-U (RFC2319) - Ukrainian + boxdrawing */ #define FC_CP1252 49 /* Latin 1 Windows */ #define MAXFCSETS 49 /* Highest file character set number */ #ifdef OS2 #define FC_DECSPEC 253 /* Not real character-sets */ #define FC_DECTECH 252 #endif /* OS2 */ #ifdef UNICODE _PROTOTYP( VOID initxlate, (int, int) ); #endif /* UNICODE */ #endif /* CKUXLA_H */ ckustr.sed000775 045065 024037 00000003270 06722107771 013211 0ustar00fdckermit000000 000000 #! /bin/sh # Special cc preprocessor for using mkstr(1) to extract strings from the # kermit source. Change the "CC=cc" line to "CC=./ckustr.sed" to use # string extraction. NOTE: the file ckustr.c might need the StringFile # declaration modified to suit local system requirements. When installing # the kermit executable be sure to install kermit.sr and make it readable # by the public (mode 444). STRINGS=cku195.sr # Get filename and arguments. initargs=$@ while [ -n "$1" ] do if [ $1 = -o ] then exec cc $initargs exit 1 fi if [ `expr substr $1 1 1` = - ] then if [ $1 != -c ] then args="$args $1" fi else csrc=$1 fi shift done # Only process compilations, and then only for certain files. if [ $csrc = ckustr.c -o $csrc = ckwart.c ] then exec cc $initargs exit 1 fi # String extractions echo Extracting strings from ${csrc}... cc -E $args $csrc > xxmk.c sed -e 's/ferror(/strferrorf(/' \ -e 's/perror("/strperror("/' \ -e 's/experror(/strexperrorf(/' \ -e 's/sprintf(\([^,][^,]*\),[ ]*\("[^"]*"\)\([,)]\)/strsrerror(\2, \1\3/' \ -e '/sprintf(\([^,][^,]*\),/{N s/sprintf(\([^,][^,]*\),\n[ ]*\("[^"]*"\)\([,)]\)/strsrerror(\2, \1\3/ }' \ -e 's/fprintf(\([^,][^,]*\),[ ]*\("[^"]*"\)\([,)]\)/strfrerror(\2, \1\3/' \ -e '/fprintf(\([^,][^,]*\),/{N s/fprintf(\([^,][^,]*\),\n[ ]*\("[^"]*"\)\([,)]\)/strfrerror(\2, \1\3/ }' \ -e 's/printf[ ]*("/strprerror("/' \ -e '/printf[ ]*(/{N s/printf[ ]*(\n"/strprerror("/ }' xxmk.c > mk.c mkstr - $STRINGS xx mk.c sed -e 's/^# \([0-9]\)/#line \1/' xxmk.c | xstr -c - echo Compiling... cc -Dstrferrorf=ferror -Dstrexperrorf=experror $args -c x.c mv x.o `basename $csrc .c`.o rm -f x.c mk.c xxmk.c ckuker.nr000664 045065 024037 00000167656 14767402074 013050 0ustar00fdckermit000000 000000 .\" @(#) kermit.1 10.0 2022/11/28 The Open Source Kermit Project .TH KERMIT 1 "NOVEMBER 2022" "User Manuals" .na .SH NAME kermit \- .B C\(hyKermit 10.0: transport\(hy and platform\(hyindependent interactive and scriptable communications software. .IP This document is intended to give the beginner sufficient information to make basic use of C\(hyKermit 10.0. Although it might be rather long for a Unix manual page, it's still far shorter than the C\(hyKermit manual, which should be consulted for advanced topics such as customization, character\(hysets, scripting, etc. We also attempt to provide a clear structural overview of C\(hyKermit's many capabilities, functional areas, states, and modes and their interrelation, that should be helpful to beginners and veterans alike, as well as to those upgrading to version 10.0 from earlier releases. .PP This document is also available as a Web page at: .IP https://kermitproject.org/ckututor.html .SH DESCRIPTION C\(hyKermit is an all\(hypurpose communications software package originally from the Kermit Project at Columbia University and now from the independent Open Source Kermit Project that: .PP .nf \(bu Is portable to many platforms, Unix and non\(hyUnix alike. .br \(bu Can make both serial and network connections. .br \(bu Can conduct interactive terminal sessions over its connection. .br \(bu Can transfer text or binary files over the same connection. .br \(bu Can convert character sets in the terminal session. .br \(bu Can convert character sets during text\(hyfile file transfer. .br \(bu Is customizable in every aspect of its operation. .fi .PP C\(hyKermit is a modem program, a Telnet client, an SSH client, an FTP client, an HTTP client, and on selected platforms, also an X.25 client. It can make its own secure Internet connections using IETF\(hyapproved security methods including Kerberos IV, Kerberos V, SSL/TLS, and SRP and it can also make SSH connections through your external SSH client application. It can be the far\(hyend file\(hytransfer or client/server partner of your desktop Kermit client. It can also accept incoming dialed and network connections. It can even be installed as an Internet service on its own standard TCP socket, 1649 [RFC2839, RFC2840]. .PP And perhaps most important, everything you can do "by hand" (interactively) with C\(hyKermit, can be "scripted" (automated) using its built\(hyin cross\(hyplatform transport\(hyindependent script programming language, which happens to be identical to its interactive command language. .PP This manual page offers an overview of C\(hyKermit 10.0 for Unix ("Unix" is an operating system family that includes AIX, DG/UX, FreeBSD, HP\(hyUX, IRIX, Linux, Mac OS X, NetBSD, OpenBSD, Open Server, Open Unix, QNX, Solaris, SunOS, System V R3, System V R4, Tru64 Unix, Unixware, Xenix, and many others). For thorough coverage, please consult the published C\(hyKermit manual and supplements (see DOCUMENTATION below). For further information about C\(hyKermit, Kermit software for other platforms, and Kermit manuals, visit the Kermit Project website: .PP https://kermitproject.org/ .PP This is a longer\(hythan\(hyaverage manual page, and yet it barely scratches the surface. Don't be daunted. C\(hyKermit is a large and complex package, evolving over decades of practice and experience, but that doesn't mean it's hard to learn or use. Its most commonly used functions are explained here with pointers to additional information elsewhere. .SH SYNOPSIS .B kermit [ .I filename .B ] [ .I options .B ] [ {=,\-\-,+} .I text .B ] ] .PP or: .PP .B kermit .I URL .PP If the first command\(hyline argument is the name of a file, interactive\(hymode commands are executed from the file. The '=' (or "\-\-") argument tells Kermit not to parse the remainder of the command line, but to make the words following '=' available as \e%1, \e%2, ... \e%9. The "+" argument is like "=" but for use in "kerbang scripts" (explained below). A second command\(hyline format allows the one and only argument to be a Telnet, FTP, HTTP, or IKSD URL. .PP Order of execution: .TP 1. The command file (if any). .TP .nf 2. The initialization file, if any, unless suppressed with \-Y. .fi .TP 3. The customization file (if it is executed by the initialization file). .TP 4. The command\(hyline URL (if any, and if so, execution stops here). .TP 5. Command\(hyline options (if any). .TP 6. Interactive commands. .PP Some command\(hyline options can cause actions (such as \-s to send a file); others just set parameters. If any action options are included on the command line, Kermit exits when finished unless also given the \-S ("stay") option. If no action options are given, no initialization or command files contained an EXIT or QUIT command, and no fatal errors occurred, Kermit issues its prompt and waits for you to type commands. .IP Bear in mind that C\(hyKermit can be built with selected features disabled, and also that certain features are not available on all platforms. For example, C\(hyKermit can't be built with TCP/IP support on a platform that does not have TCP/IP header files and libraries (and even if Kermit does include TCP/IP support, it can't be used to make TCP/IP connections on a computer that does not have a TCP/IP stack installed). If your version of C\(hyKermit lacks a feature mentioned here, use its SHOW FEATURES command to see what might have been excluded. .PP C\(hyKermit has three kinds of commands: regular single\(hyletter command\(hyline options, extended\(hyformat command\(hyline options, and interactive commands. .PP Like most Unix commands, C\(hyKermit can be given options on the command line. But C\(hyKermit also can be used interactively by giving it commands composed of words, which are more intuitive than cryptic command\(hyline options, and more flexible too. In other words, you don't have to use C\(hyKermit's command\(hyline options, but they are available if you want to. (By the same token, you don't have to use its interactive commands either \(hy\(hy you can use either or both in any combination.) .PP C\(hyKermit is generally installed in the PATH as "kermit", and therefore is invoked by typing the word "kermit" (lowercase) at the shell prompt, and then pressing the Return or Enter key. If you wish to include command\(hyline options, put them after the word "kermit" but before pressing Return or Enter, separated by spaces, for example: .PP $ kermit \-s ckermit.tar.gz .PP ('$' is the shell prompt; "kermit \-s ckermit.tar.gz" is what you type, followed by Return or Enter.) .SH OPTIONS Here is a list of C\(hyKermit's single\(hyletter command\(hyline options, which start with a single dash (\-), in ASCII ("alphabetical") order. Alphabetic case is significant (\-A is not the same as \-a). Action options are tagged "ACTION". .TP \-0 (digit zero) 100% transparent Connect state for "in\(hythe\(hymiddle" operation: 8 bits, no parity, no escape character, everything passes through. .TP \-8 (digit eight) Connection is 8\(hybit clean (this is the default in C\(hyKermit 8.0 and later). Equivalent to the EIGHTBIT command, which in turn is a shortcut for SET TERMINAL BYTESIZE 8, SET COMMAND BYTESIZE 8, SET PARITY NONE. .TP \-9 arg (digit nine) Make a connection to an FTP server. Equivalent to the FTP OPEN command. Argument: IP\(hyaddress\(hyor\(hyhostname[:optional\(hyTCP\(hyport]. NOTE: C\(hyKermit also has a separate FTP command\(hyline personality, with regular FTP\(hylike command\(hyline syntax. More about this below. .TP \-A Kermit is to be started as an Internet service (IKSD) (only from inetd.conf). .TP \-B Kermit is running in Batch or Background (no controlling terminal). To be used in case Kermit doesn't automatically sense its background status. Equivalent to the SET BACKGROUND ON command. .TP \-C arg Interactive\(hymode Commands to be executed. Argument: Commands separated by commas, list in doublequotes. .TP \-D arg Delay before starting to send in Remote mode. Equivalent to the SET DELAY command. Argument: Number of seconds. .TP \-E Exit automatically when connection closes. Equivalent to SET EXIT ON\-DISCONNECT ON. .TP \-F arg Use an open TCP connection. Argument: Numeric file descriptor of open TCP connection. Also see: \-j, \-J. .TP \-G arg (ACTION) Get file(s) from server, send contents to standard output, which normally would be piped to another process. Argument: Remote file specification, in quotes if it contains metacharacters. Also see: \-g, \-k. .TP \-H Suppress program startup Herald and greeting. .TP \-I Tell Kermit it has a reliable connection, to force streaming to be used where it normally would not be. Equivalent to the SET RELIABLE ON command. .TP \-J arg (ACTION) "Be like Telnet." Like \-j but implies \-E. Argument: IP hostname/address optionally followed by service. NOTE: C\(hyKermit also has a separate Telnet command\(hyline personality, with regular Telnet\(hylike command\(hyline syntax. More about this below. .TP \-L Recursive directory descent for files in \-s option. .TP \-M arg My user name (for use with Telnet, SSH, FTP, etc). Equivalent to the SET LOGIN USER command. Argument: Username string. .TP \-O (ACTION) (Uppercase letter O) Be a server for One command only. Also see: \-x. .TP \-P Don't convert file (Path) names of transferred files. Equivalent to SET FILE NAMES LITERAL. .TP \-Q Quick Kermit protocol settings. Equivalent to the FAST command. This is the default in C\(hyKermit 7.0 and later. .TP \-R Remote\(hyonly (this just makes IF REMOTE true). .TP \-S Stay (enter command parser after action options). .TP \-T Force Text mode for file transfer; implies \-V. Equivalent to SET TRANSFER MODE MANUAL, SET FILE TYPE TEXT. .TP \-V Disable automatic per\(hyfile text/binary switching. Equivalent to SET TRANSFER MODE MANUAL. .TP \-Y Skip (don't execute) the initialization file. .TP \-a arg As\(hyname for file(s) in \-s, \-r, or \-g. Argument: As\(hyname string (alternative filename). When receiving files, this can be a directory name. .TP \-b arg Speed for serial device. Equivalent to SET SPEED. Argument: Numeric Bits per second for serial connections. .TP \-c (ACTION) Enter Connect state before transferring files. .TP \-d Create a debug.log file with detailed debugging information (a second \-d adds timestamps). Equivalent to LOG DEBUG but takes effect sooner. .TP \-e arg Maximum length for incoming Kermit file\(hytransfer packets. Equivalent to SET RECEIVE PACKET\-LENGTH. Argument: Length in bytes. .TP \-f (ACTION) Send a FINISH command to a Kermit server. .TP \-g arg Get file(s) from a Kermit server. Argument: File specification on other computer, in quotes if it contains metacharacters. Equivalent to GET. Also see: \-a, \-G, \-r. .TP \-h (ACTION) Print Help text for single\(hyletter command\(hyline options (pipe thru 'more' to prevent scrolling). .TP \-i Force binary (Image) mode for file transfer; implies \-V. Equivalent to SET TRANSFER MODE MANUAL, SET FILE TYPE BINARY. .TP \-j arg Make a TCP/IP connection. Argument: IP host name/address and optional service name or number. Equivalent to the TELNET command. Also see: \-J, \-F. .TP \-k (ACTION) Receive file(s) to standard output, which normally would be piped to another process. Also see: \-r, \-G. .TP \-l arg (Lowercase letter L) Make a connection on the given serial communications device. Equivalent to the SET LINE (SET PORT) command. Argument: Serial device name, e.g. /dev/ttyS0. .TP \-m arg Modem type for use with the \-l device. Equivalent to the SET MODEM TYPE command. Argument: Modem name as in SET MODEM TYPE command, e.g. "usrobotics". .TP \-n (ACTION) Enter Connect state after transferring files (historical). .TP \-p arg Parity. Equivalent to the SET PARITY command. Argument: One of the following: e(ven), o(dd), m(ark), n(one), s(pace). .TP \-q Quiet (suppress most messages). Equivalent to SET QUIET ON. .TP \-r (ACTION) Receive file(s). Equivalent to the RECEIVE command. Argument: (none, but see \-a) .TP \-s arg Send file(s). Argument: One or more local file specifications. Equivalent to the SEND command. Also see: \-a. .TP \-t (Historical) Xon (Ctrl\-Q) Turnaround character for half\(hyduplex connections (used on serial linemode connections to old mainframes). Equivalent to SET DUPLEX HALF, SET HANDSHAKE XON. .TP \-v arg Window size for Kermit protocol (ignored when streaming). Equivalent to SET WINDOW\-SIZE. Argument: Number, 1 to 32. .TP \-w Incoming files Write over existing files. Equivalent to SET FILE COLLISION OVERWRITE. .TP \-x (ACTION) Enter server mode. Equivalent to the SERVER command. Also see: \-O. .TP \-y arg Alternative initialization file. Argument: Filename. .TP \-z Force foreground behavior. To be used in case Kermit doesn't automatically sense its foreground status. Equivalent to the SET BACKGROUND OFF command. .PP Extended command\(hyline options (necessary because single\(hyletter ones are about used up) start with two dashes (\-\-), with words rather than single letters as option names. If an extended option takes an argument, it is separated from the option word by a colon (:). Extended options include: .TP \-\-bannerfile:filename File to display upon startup or IKSD login. .TP \-\-cdfile:filename File to be sent for display to the client when server changes directory (filename is relative to the changed\(hyto directory). .TP \-\-cdmessage:{on,off} Enable/disable the server CD message feature. .TP \-\-help Prints usage message for extended options. .TP \-\-helpfile:filename Designates a file containing custom text to replace the top\(hylevel HELP command. .TP \-\-nointerrupts Disables keyboard interrupts. .TP \-\-noperms Disables the Kermit protocol file Permissions attribute, to prevent transmission of file permissions (protection) from sender to receiver. .TP \-\-version (ACTION) C\(hyKermit prints its version number. .PP Plus several other IKSD\(hyOnly options described at: .PP https://kermitproject.org/iksd.html .PP See the file\(hytransfer section for examples of command\(hyline invocation. .SH COMMAND LANGUAGE C\(hyKermit's interactive command language is the subject of a 622\(hypage book and another several hundred pages of updates, far too much for a manual page. But it's not hard to get started. At the shell prompt, just type "kermit" to get C\(hyKermit's interactive command prompt: .PP .nf $ kermit (/current/directory) C\-Kermit> .fi .PP Begin by typing "help" (and then press the Return or Enter key) for a top\(hylevel overview, read it, and go from there. Your second command should probably be "intro" (introduction). Note the prompt shows your current directory (unless you tell Kermit to prompt you with something else). .PP Interactive commands are composed mainly of regular English words, usually in the form of imperative sentences, such as: .PP send somefile.txt .PP which tells Kermit to send (transfer) the file whose name is somefile.txt, or: .PP set transfer mode automatic .PP which sets Kermit's "transfer mode" to "automatic" (whatever that means). .PP While typing commands, you can abbreviate, ask for help (by pressing the "?" key anywhere in a command), complete keywords or filenames (with the Tab or Esc key), and edit your typing with Backspace or Delete, Ctrl\-W, Ctrl\-U, etc. You can also recall previous commands, save your command history, and who knows what else. Give the INTRO command for details. .PP C\(hyKermit has hundreds of commands, and they can be issued in infinite variety and combinations, including commands for: .nf .PP \(bu Making connections (SET LINE, DIAL, TELNET, SSH, FTP, ...) .br \(bu Breaking connections (HANGUP, CLOSE) .br \(bu Transferring files (SEND, GET, RECEIVE, MOVE, RESEND, ...) .br \(bu Establishing preferences (SET) .br \(bu Displaying preferences (SHOW) .br \(bu Managing local files (CD, DELETE, MKDIR, DIR, RENAME, TYPE, ...) .br \(bu Managing remote files (RCD, RDEL, RMKDIR, RDIR, ...) .br \(bu Using local files (FOPEN, FCLOSE, FREAD, FWRITE) .br \(bu Programming (TAKE, DEFINE, IF, FOR, WHILE, SWITCH, DECLARE, ...) .br \(bu Interacting with the user (ECHO, ASK, ...) .br \(bu Interacting with a remote computer (INPUT, OUTPUT, ...) .br \(bu Interacting with local programs (RUN, EXEC, PTY, ...) .br \(bu Logging things (LOG SESSION, LOG PACKETS, LOG DEBUG, ...) .PP .fi And of course QUIT or EXIT to get out and HELP to get help, and for programmers: loops, decision making, variables, arrays, associative arrays, integer and floating point arithmetic, macros, built\(hyin and user\(hydefined functions, string manipulation, pattern matching, block structure, scoping, recursion, and even a built-in LISP regular expression interpreter. To get a list of all C\(hyKermit's commands, type a question mark (?) at the prompt. To get a description of any command, type HELP followed by the name of the command, for example: .PP help send .PP The command interruption character is Ctrl\-C (hold down the Ctrl key and press the C key). .PP The command language "escape character", used to introduce variable names, function invocations, and so on, is backslash (\e). If you need to include a literal backslash in a command, type two of them, e.g.: .PP get c:\e\ek95\e\ek95custom.ini .SS Command Files, Macros, and Scripts A file containing Kermit commands is called a Kermit command file or Kermit script. It can be executed with Kermit's TAKE command: .PP (/current/dir) C\-Kermit> take commandfile .PP (where "commandfile" is the name of the command file). .PP In Unix only, a Kermit command file can also be executed directly by including a "kerbang" line as the first line of the file: .PP #!/usr/local/bin/kermit + .PP That is, a top line that starts with "#!", followed immediately by the full path of the Kermit executable, and then, if the Kermit script is to be given arguments on the command line, a space and a plus sign. The script file must also have execute permission: .PP chmod +x commandfile .PP Except for the " +" part, this is exactly the same as you would do for a shell script, a Perl script, etc. Here's a simple but useless example script that regurgitates its arguments (up to three of them): .PP #!/usr/local/bin/kermit + if defined \e%1 echo "Argument 1: \e%1" if defined \e%2 echo "Argument 2: \e%2" if defined \e%3 echo "Argument 3: \e%3" if defined \e%4 echo "etc..." exit .PP If this file is stored in your current directory as "commandfile", then: .PP ./commandfile one two three four five .PP prints: .PP Argument 1: one Argument 2: two Argument 3: three etc... .PP This illustrates the basic structure of a standalone Kermit script: the "kerbang line", then some commands. It should end with "exit" unless you want the Kermit prompt to appear when it is finished. \e%1 is the first argument, \e%2 the second, and so on. .PP You can also create your own commands by defining named macros composed of other Kermit commands (or macros). For example: .PP .nf define mydelete { local trash assign trash \ev(home)trashcan/ if not defined \e%1 end 1 "Delete what?" if wild \e%1 { end 1 "Deleting multiple files is too scary" } if not exist \e%1 end 1 "I can't find \e%1" if not directory \em(trash) { mkdir \em(trash) if fail end 1 "No trash can" } rename /list \e%1 \em(trash) } define myundelete { local trash assign trash \ev(home)trashcan/ if not defined \e%1 end 1 "Undelete what?" if wild \e%1 { end 1 "Undeleting multiple files is too hard" } if not directory \em(trash) end 1 "No trash can" if not exist \em(trash)\e%1 { end 1 "I can't find \e%1 in trash can" } rename /list \em(trash)\e%1 . } .PP .fi These sample macros are not exactly production quality (they don't handle filenames that include path segments, they don't handle multiple files, etc), but you get the idea: you can pass arguments to macros, and they can check them and make other kinds of decisions. If you put the above lines into your initialization or customization file (explained below), you'll have MYDELETE and MYUNDELETE commands available every time you start Kermit, at least as long as you don't suppress execution of the initialization file. (Exercise for the reader: Make these macros generally useful: remove limitations, add trashcan display, browsing, emptying, etc.) .PP Kerbang scripts execute without the initialization file. This to keep them portable and also to make them start faster. If you want to write Kerbang scripts that depend on the initialization file, include the command .PP take \ev(home).kermrc .PP at the desired spot in the script. By the way, \ev(xxx) is a built\(hyin variable (xxx is the variable name, "home" in this case). To see what built\(hyin variables are available, type "show variables" at the C\(hyKermit prompt. To see what else you can show, type "show ?". \em(xxx) is a user defined variable (strictly speaking, it is a macro used as a variable). .SS Command List C\(hyKermit has more than 200 top\(hylevel commands, and some of these, such as SET, branch off into hundreds of subcommands of their own, so it's not practical to describe them all here. Instead, here's a concise list of the most commonly used top\(hylevel commands, grouped by category. To learn about each command, type "help" followed by the command name, e.g. "help set". Terms such as Command state and Connect state are explained in subsequent sections. .PP Optional fields are shown in [ brackets ]. "filename" means the name of a single file. filespec means a file specification that is allowed to contain wildcard characters like '*' to match groups of files. options are (optional) switches like /PAGE, /NOPAGE, /QUIET, etc, listed in the HELP text for each command. Example: .PP .nf send /recursive /larger:10000 /after:\-1week /except:*.txt * .fi .PP which can be read as "send all the files in this directory and all the ones underneath it that are larger than 10000 bytes, no more than one week old, and whose names don't end with ".txt". .SS Basic Commands .RS .TP HELP Requests top\(hylevel help. .TP HELP command Requests help about the given command. .TP INTRODUCTION Requests a brief introduction to C\(hyKermit. .TP LICENSE Displays the C\(hyKermit software copyright and license. .TP VERSION Displays C\(hyKermit's version number. .TP EXIT [ number ] Exits from Kermit with the given status code (0 = success, nonzero = failure). Synonyms: QUIT, E, Q. .TP TAKE filename [ parameters... ] Executes commands from the given file. .TP LOG item [ filename ] Keeps a log of the given item (DEBUG, TRANSACTIONS, etc) in the given file. .TP [ DO ] macro [ parameters... ] Executes commands from the given macro. .TP SET parameter value Sets the given parameter to the given value. .TP SHOW category Shows settings in a given category. .TP STATUS Tells whether previous command succeeded or failed. .TP DATE [ date\(hyand/or\(hytime ] Shows current date\(hytime or interprets given date\(hytime. .TP RUN [ extern\(hycommand [ parameters... ] Runs the given external command. Synonym: !. .TP EXEC [ extern\(hycommand [ params... ] Kermit overlays itself with the given command. .TP SUSPEND Stops Kermit and puts it in the background. Synonym: Z. .RE .SS Local File Management .RS .TP TYPE [ options ] filename Displays the contents of the given file. .TP MORE [ options ] filename Equivalent to TYPE /PAGE (pause after each screenful). .TP CAT [ options ] filename Equivalent to TYPE /NOPAGE. .TP HEAD [ options ] filename Displays the first few lines of a given file. .TP TAIL [ options ] filename Displays the last few lines of a given file. .TP GREP [ options ] pattern filespec Displays lines from files that match the pattern. Synonym: FIND. .TP DIRECTORY [ options ] [filespec ] Lists files (built\(hyin, many options). .TP LS [ options ] [ filespec ] Lists files (runs external "ls" command). .TP DELETE [ options ] [ filespec ] Deletes files. Synonym: RM. .TP PURGE [ options ] [ filespec ] Removes backup (*.~n~) files. .TP COPY [ options ] [ filespecs... ] Copies files. Synonym: CP. .TP RENAME [ options ] [ filespecs... ] Renames files. Synonym: MV. .TP CHMOD [ options ] [ filespecs... ] Changes permissions of files. .TP TRANSLATE filename charsets [ filename ] Converts file's character set. Synonym: XLATE. .TP CD Changes your working directory to your home directory. .TP CD directory Changes your working directory to the one given. .TP CDUP Changes your working directory one level up. .TP PWD Displays your working directory. .TP BACK Returns to your previous working directory. .TP MKDIR [ directory ] Creates a directory. .TP RMDIR [ directory ] Removes a directory. .RE .SS Making Connections .RS .TP SET LINE [ options ] devicename Opens the named serial port. Synonym: SET PORT. .TP OPEN LINE [ options ] devicename Same as SET LINE. Synonym: OPEN PORT. .TP SET MODEM TYPE [ name ] Tells Kermit what kind of modem is on the port. .TP DIAL [ number ] Tells Kermit to dial the given phone number with the modem. .TP REDIAL Redials the most recently dialed phone number. .TP ANSWER Waits for and answers an incoming call on the modem. .TP AUTHENTICATE [ parameters... ] Performs secure authentication on a TCP/IP connection. .TP SET NETWORK TYPE { TCP/IP, X.25, ... } Selects network type for subsequent SET HOST commands. .TP SET HOST [ options ] host [ port ] Opens a network connection to the given host and port. .TP SET HOST * port Waits for an incoming TCP/IP connection on the given port. .TP SSH [ options ] host Opens a secure SSH connection to the host and enters Connect state. .TP TELNET [ options ] host Opens a Telnet connection to the host and enters Connect state. .TP RLOGIN [ options ] host Opens an Rlogin connection to the host and enters Connect state. .TP IKSD [ options ] host Opens a connection to an Internet Kermit Service. .TP FTP OPEN host [ options ] Opens an FTP connection to the host. .TP HTTP [ options ] OPEN host Opens an HTTP connection to the host. .TP PTY external\(hycommand Runs the command on a pseudoterminal as if it were a connection. .TP PIPE external\(hycommand Runs the command through a pipe as if it were a connection. .RE .SS Using Connections .RS .TP CONNECT [ options ] Enters Connect (terminal) state. Synonym: C. .TP REDIRECT command Redirects the given external command over the connection. .TP TELOPT command Sends a Telnet protocol command (Telnet connections only). .TP Ctrl\-\eC "Escapes back" from Connect state to Command state. .TP Ctrl\-\eB (In Connect state) Sends a BREAK signal (serial or Telnet). .TP Ctrl\-\e! (In Connect state) Enters inferior shell; "exit" to return. .TP Ctrl\-\e? (In Connect state) Shows a menu of other escape\(hylevel options. .TP Ctrl\-\eCtrl\-\e (In Connect state) Type two Ctrl\-Backslashes to send one of them. .TP SET ESCAPE [ character ] Changes Kermit's Connect\(hystate escape character. .RE .SS Closing Connections .RS .TP HANGUP Hangs up the currently open serial\(hyport or network connection. .TP CLOSE Closes the currently open serial\(hyport or network connection. .TP SET LINE (with no devicename) Closes the currently open serial\(hyport or network connection. .TP SET HOST (with no hostname) Closes the currently open serial\(hyport or network connection. .TP FTP CLOSE Closes the currently open FTP connection. .TP HTTP CLOSE Closes the currently open HTTP connection. .TP EXIT Also closes all connections. Synonym: QUIT. .TP SET EXIT WARNING OFF Suppresses warning about open connections on exit or close. .RE .SS File Transfer .RS .TP SEND [ options ] filename [ as\(hyname ] Sends the given file. Synonym: S. .TP SEND [ options ] filespec Sends all files that match. .TP RESEND [ options ] filespec Resumes an interrupted SEND from the point of failure. .TP RECEIVE [ options ] [ as\(hyname ] Waits passively for files to arrive. Synonym: R. .TP LOG TRANSACTIONS [ filename ] Keeps a record of file transfers. .TP FAST Use fast file\(hytransfer settings (default). .TP CAUTIOUS Use cautious and less fast file\(hytransfer settings. .TP ROBUST Use ultra\(hyconservative and slow file\(hytransfer settings. .TP STATISTICS [ options ] Gives statistics about the most recent file transfer. .TP WHERE After transfer: "Where did my files go?". .TP TRANSMIT [ options ] [ofilename ] Sends file without protocol. Synonym: XMIT. .TP LOG SESSION [ filename ] Captures remote text or files without protocol. .TP SET PROTOCOL [ name... ] Tells Kermit to use an external file\(hytransfer protocol. .TP FTP { PUT, MPUT, GET, MGET, ... } FTP client commands. .TP HTTP { PUT, GET, HEAD, POST, ... } HTTP client commands. .RE .SS Kermit Server .RS .TP ENABLE, DISABLE Controls which server features can be used by clients. .TP SET SERVER Sets parameters prior to entering Server state. .TP SERVER Enters Server state. .RE .SS Client of Kermit or FTP Server .RS .TP [ REMOTE ] LOGIN [ user password ] Logs in to a Kermit server or IKSD that requires it. .TP [ REMOTE ] LOGOUT Logs out from a Kermit server or IKSD. .TP SEND [ options ] filename [ as\(hyname ] Sends the given file to the server. Synonyms: S, PUT. .TP SEND [ options ] filespec Sends all files that match. .TP RESEND [ options ] filespec Resumes an interrupted SEND from the point of failure. .TP GET [ options ] remote\(hyfilespec Asks the server to send the given files. Synonym: G. .TP REGET [ options ] remote\(hyfilespec Resumes an interrupted GET from the point of failure. .TP REMOTE CD [ directory ] Asks server to change its working directory. Synonym: RCD. .TP REMOTE PWD [ directory ] Asks server to display its working directory. Synonym: RPWD. .TP REMOTE DIRECTORY [ filespec... ] Asks server to send a directory listing. Synonym: RDIR. .TP REMOTE DELETE [ filespec... ] Asks server to delete files. Synonym: RDEL. .TP REMOTE [ command... ] (Many other commands: "remote ?" for a list). .TP MAIL [ options ] filespec Sends file(s) to be delivered as e\(hymail (Kermit only). .TP FINISH Asks the server to exit server state (Kermit only). .TP BYE Asks the server to log out and close the connection. .RE .SS Script Programming .PP .RS DEFINE, DECLARE, UNDEFINE, UNDECLARE, ASSIGN, EVALUATE, SEXPRESSION, ARRAY, SORT, INPUT, OUTPUT, IF, FOR, WHILE, SWITCH, GOTO, ECHO, ASK, GETC, GETOK, ASSERT, WAIT, SLEEP, FOPEN, FREAD, FWRITE, FCLOSE, STOP, END, RETURN, LEARN, SHIFT, TRACE, VOID, INCREMENT, DECREMENT, ... For these and many more you'll need to consult the manual and supplements, and/or visit the Kermit Script Library, which also includes a brief tutorial. Hint: HELP LEARN to find out how to get Kermit to write simple scripts for you. .RE .PP Many of Kermit's commands have synonyms, variants, relatives, and so on. For example, MSEND is a version of SEND that accepts a list of file specifications to be sent, rather than just one file specification, and MPUT is a synonym of MSEND. MOVE means to SEND and then DELETE the source file if successful. MMOVE is like MOVE, but accepts a list of filespecs, and so on. These are described in the full documentation. .PP Use question mark to feel your way through an unfamiliar command, as in this example: .PP .nf C\-Kermit> remote ? One of the following: assign directory kermit print rmdir cd exit login pwd set copy help logout query space delete host mkdir rename type C\-Kermit> remote set ? One of the following: attributes file retry transfer block\-check receive server window C\-Kermit> remote set file ? One of the following: character\-set incomplete record\-length collision names type C\-Kermit> remote set file names ? One of the following: converted literal C\-Kermit> remote set file names literal C\-Kermit> .PP .fi This is called menu on demand: you get a menu when you want one, but menus are not forced on you even when know what you're doing. Note that you can also abbreviate most keywords, and you can complete them with the Tab or Esc key. Also note that ? works for filenames too, and that you can use it in the middle of a keyword or filename, not just at the beginning. For example, "send x?" lists all the files in the current directory whose names start with 'x'. .SH INITIALIZATION FILE In its default configuration, C\(hyKermit executes commands from a file called .kermrc in your home directory when it starts, unless it is given the \-Y or \-y command\(hyline option. Custom configurations might substitute a shared system\(hywide initialization file. The SHOW FILE command tells what initialization file, if any, was used. The standard initialization file "chains" to an individual customization file, .mykermc, in the home directory, in which each user can establish her/his own preferences, define macros, and so on. .PP Since execution of the initialization file (at least the standard one) makes C\(hyKermit take longer to start, it might be better not to have an initialization file, especially now that Kermit's default startup configuration is well attuned to modern computing and networking \(hy\(hy in other words, you no longer have do anything special to make Kermit transfers go fast. So instead of having an initialization file that is executed every time Kermit starts, you might consider making one or more kerbang scripts (with names other that .kermrc) that do NOT include an "exit" command, and invoke those when you need the settings, macro definitions, and/or scripted actions they contain, and invoke C\(hyKermit directly when you don't. .SH MODES OF OPERATION Kermit is said to be in Local mode if it has made a connection to another computer, e.g. by dialing it or establishing a Telnet connection to it. The other computer is remote, so if you start another copy of Kermit on the remote computer, it is said to be in Remote mode (as long as it has not made any connections of its own). The local Kermit communicates over the communications device or network connection, acting as a conduit between the remote computer and your keyboard and screen. The remote Kermit is the file\(hytransfer partner to the local Kermit and communicates only through its standard input and output. .PP At any moment, a Kermit program can be in any of the following states. It's important to know what they are and how to change from one to the other. .TP Command state In this state, Kermit reads commands from: .sp \(bu Your keyboard; or: .br \(bu A file, or: .br \(bu A macro definition. .sp You can exit from Command state back to Unix with the EXIT or QUIT command (same thing). You can enter Connect state with any of various commands (CONNECT, DIAL, TELNET, etc). You can enter file transfer state with commands like SEND, RECEIVE, and GET. You can enter Server state with the SERVER command. The TAKE command tells Kermit to read and execute commands from a file. The (perhaps implied) DO command tells Kermit to read and execute commands from a macro definition. While in Command state, you can interrupt any command, macro, or command file by typing Ctrl\-C (hold down the Ctrl key and press the C key); this normally brings you back to the prompt. .TP Shell state You can invoke an inferior shell or external command from the Kermit command prompt by using the PUSH, RUN (!), EDIT, or BROWSE command. While the inferior shell or command is active, Kermit is suspended and does nothing. Return to Kermit Command state by exiting from the inferior shell or application. .TP Connect state In this state, which can be entered only when in Local mode (i.e. when Kermit has made a connection to another computer), Kermit is acting as a terminal to the remote computer. Your keystrokes are sent to the remote computer and characters that arrive over the communication connection are displayed on your screen. This state is entered when you give a CONNECT, DIAL, TELNET, SSH, or IKSD command. You can return to command state by logging out of the remote computer, or by typing: .sp Ctrl\-\ec .sp That is: Hold down the Ctrl key and press the backslash key, then let go of the Ctrl key and press the C key. This is called escaping back. Certain other escape\(hylevel commands are also provided; type Ctrl\-\e? for a list. For example, you can enter Shell state with: .sp Ctrl\-\e! .sp To send a Ctrl\-\e to the host while in Connect state, type two of them in a row. See HELP CONNECT and HELP SET ESCAPE for more info. .TP Local file\(hytransfer state In this state, Kermit is sending packets back and forth with the other computer in order to transfer a file or accomplish some other file\(hyrelated task. And at the same time, it is displaying its progress on your screen and watching your keyboard for interruptions. In this state, the following single\(hykeystroke commands are accepted: .sp .RS .TP X Interrupt the current file and go on to the next (if any). .TP Z Interrupt the current file and skip all the rest. .TP E Like Z but uses a "stronger" protocol (use if X or Z don't work). .TP Ctrl\-C Interrupt file\(hytransfer mode (use if Z or E don't work). .sp .RE Kermit returns to its previous state (Command or Connect) when the transfer is complete or when interrupted successfully by X, Z, E, or Ctrl\-C (hold down the Ctrl key and press the C key). .TP Remote file\(hytransfer state In this state, Kermit is exchanging file\(hytransfer packets with its local partner over its standard i/o. It leaves this state automatically when the transfer is complete. In case you find your local Kermit in Connect state and the remote one in File\(hytransfer state (in which it seems to ignore your keystrokes), you can usually return it to command state by typing three Ctrl\-C's in a row. If that doesn't work, return your local Kermit to Command state (Ctrl\-\e C) and type "e\(hypacket" and then press the Return or Enter key; this forces a fatal Kermit protocol error. .TP Remote Server state This is like Remote File\(hytransfer state, except it never returns automatically to Command state. Rather, it awaits further instructions from the client program; that is, from your Local Kermit program. You can return the Remote Server to its previous state by issuing a "finish" command to the client, or if you are in Connect state, by typing three Ctrl\-C's in a row. You can tell the server job to log out and break the connection by issuing a "bye" command to the client. .TP Local Server state Like Remote\(hyServer state, but in local mode, and therefore with its file\(hytransfer display showing, and listening for single\(hykey commands, as in Local File\(hytransfer state. Usually this state is entered automatically when a remote Kermit program gives a GET command. .sp C\(hyKermit, Kermit 95, and MS\(hyDOS Kermit all can switch automatically from Connect state to Local File\(hytransfer state when you initiate a file transfer from the remote computer by starting Kermit and telling it to send or get a file, in which case, Connect state is automatically resumed after the file transfer is finished. .sp Note that C\(hyKermit is not a terminal emulator. It is a communications application that you run in a terminal window (e.g. console or Xterm). The specific emulation, such as VT100, VT220, Linux Console, or Xterm, is provided by the terminal window in which you are running C\(hyKermit. Kermit 95 and MS\(hyDOS Kermit, on the other hand, are true terminal emulators. Why is C\(hyKermit not a terminal emulator? CLICK HERE to read about it. .SH MAKING CONNECTIONS Here is how to make different kinds of connections using interactive Kermit commands (as noted above, you can also make connections with command\(hyline options). Note that you don't have to make connections with Kermit. It can also be used on the far end of a connection as the remote file transfer and management partner of your local communications software. .TP Making a Telnet Connection At the C\(hyKermit command prompt, simply type: .sp .nf telnet foo.bar.com .fi .sp (substituting desired hostname or address). You can also include a port number: .sp .nf telnet xyzcorp.com 3000 ; .fi .sp If the connection is successful, Kermit automically enters Connect state. When you logout from the remote host, Kermit automatically returns to its prompt. More info: HELP TELNET, HELP SET TELNET, HELP SET TELOPT. Also see the IKSD section below. .TP Making an Rlogin connection This is just like Telnet, except you have to be root to do it because Rlogin uses a privileged TCP port: .sp .nf rlogin foo.bar.com .fi .sp More info: HELP RLOGIN. .TP Making an SSH Connection Unlike Telnet and Rlogin, SSH connections are not built\(hyin, but handled by running your external SSH client through a pseudoterminal. Using C\(hyKermit to control the SSH client gives you all of Kermit's features (file transfer, character\(hyset conversion, scripting, etc) over SSH. .sp ssh foo.bar.com .sp More info: HELP SSH, HELP SET SSH. .TP Dialing with a Modem If it's an external modem, make sure it is connected to a usable serial port on your computer with a regular (straight\(hythrough) modem cable, and to the telephone jack with a telephone cable, and that it's turned on. Then use these commands: .sp .nf set modem type usrobotics ; Or other supported type set line /dev/ttyS0 ; Specify device name set speed 57600 ; Or other desired speed set flow rts/cts ; Most modern modems support this set dial method tone ; (or pulse) dial 7654321 ; Dial the desired number .fi .sp Type "set modem type ?" for a list of supported modem types. If you omit the SET MODEM TYPE command, the default type is "generic\(hyhigh\(hyspeed", which should work for most modern AT\(hycommand\(hyset modems. If the line is busy, Kermit redials automatically. If the call does not succeed, use "set dial display on" and try it again to watch what happens. If the call succeeds, Kermit enters Connect state automatically and returns to its prompt automatically when you log out from the remote computer or the connection is otherwise lost. .sp You can also dial from a modem that is accessible by Telnet, e.g. to a reverse terminal server. In this case the command sequence is: .sp .nf set host ts.xxx.com 2000 ; Terminal\(hyserver and port set modem type usrobotics ; Or other supported type set dial method tone ; (or pulse) dial 7654321 ; Dial the desired number .fi .sp If the terminal server supports the Telnet Com Port Option, RFC 2217, you can also give serial\(hyport related commands such as SET SPEED, SET PARITY, and so on, and Kermit relays them to the terminal server using the protocol specified in the RFC. .sp More info: HELP SET MODEM, HELP SET LINE, HELP SET SPEED, HELP SET FLOW, HELP DIAL, HELP SET DIAL, HELP SET MODEM, HELP SET CARRIER\-WATCH, SHOW COMMUNICATIONS, SHOW MODEM, SHOW DIAL. .TP Direct Serial Port Connect the two computers, A and B, with a null modem cable (or two modem cables interconnected with a null\(hymodem adapter or modem eliminator). From Computer A: .sp .nf set modem type none ; There is no modem set line /dev/ttyS0 ; Specify device name set carrier\-watch off ; If DTR CD are not cross\(hyconnected set speed 57600 ; Or other desired speed set flow rts/cts ; If RTS and CTS are cross\(hyconnected set parity even ; (or "mark" or "space", if necessary) set stop\-bits 2 ; (rarely necessary) set flow xon/xoff ; If you can't use RTS/CTS connect ; Enter Connect (terminal) state .fi .sp This assumes Computer B is set up to let you log in. If it isn't, you can run a copy of Kermit on Computer B and follow approximately the same directions. More info: As above plus HELP CONNECT. .PP With modems or direct serial connections, you might also have to "set parity even" (or "mark" or "space") if it's a 7\(hybit connection. .PP Of the connection types listed above, only one can be open at a time. However, any one of these can be open concurrently with an FTP or HTTP session. Each connection type can be customized to any desired degree, scripted, logged, you name it. See the manual. .PP NOTE: On selected platforms, C\(hyKermit also can make X.25 connections. See the manual for details. .SH TRANSFERRING FILES WITH KERMIT There is a widespread and persistent belief that Kermit is a slow protocol. This is because, until recently, it used conservative tuning by default to make sure file transfers succeeded, rather than failing because they overloaded the connection. Some extra commands (or command\(hyline options, like \-Q) were needed to make it go fast, but nobody bothered to find out about them. Also, it takes two to tango: most non\(hyKermit\(hyProject Kermit protocol implementations really ARE slow. The best file\(hytransfer partners for C\(hyKermit are: another copy of C\(hyKermit (7.0 or later) on Unix, (Open)VMS, or Microsoft Windows (formerly known as Kermit 95 or K95, now in Open Source release as C-Kermit 10.0 for Windows or CKW). These combinations work well and they work fast by default. MS\(hyDOS Kermit is good too, but you have to tell it to go fast (by giving it the FAST command). .PP Furthermore, all three of these Kermit programs support "autodownload" and "autoupload", meaning that when they are in Connect state and a Kermit packet comes in from the remote, they automatically switch into file transfer mode. .PP And plus, C\(hyKermit switches automatically between text and binary mode for each file, so there is no need to "set file type binary" or "set file type text", or to worry about files being corrupted because they were transferred in the wrong mode. .PP What all of these words add up to is that now, when you use up\(hyto\(hydate Kermit software from the Kermit Project, file transfer is not only fast, it's ridiculously easy. You barely have to give any commands at all. .SH Downloading Files Let's say you have C\(hyKermit for Unix or VMS, CKW for Windows, or MS\(hyDOS Kermit on your desktop computer, with a connection to a Unix computer that has C\(hyKermit installed as "kermit". To download a file (send it from Unix to your desktop computer), just type the following command at your Unix shell prompt: .sp kermit \-s somefile.txt .sp (where somefile.txt is the filename). If you want to send more than one file, you can put as many filenames as you want on the command line, and they can be any combination of text and binary: .sp kermit \-s somefile.txt somefile.zip somefile.html somefile.tar.gz .sp and/or you can use wildcards to send groups of files: .sp kermit \-s somefile.* .sp If you want to send a file under an assumed name, use: .sp kermit \-s friday.txt \-a today.txt .sp This sends the file friday.txt but tells the receiving Kermit that its name is today.txt. In all cases, as noted, when the file transfer is finished, your desktop Kermit returns automatically to Connect state. No worries about escaping back, re\(hyconnecting, text/binary mode switching. Almost too easy, right? .SH Uploading Files To upload files (send them from your desktop computer to the remote Unix computer) do the same thing, but use the \-g (GET) option instead of \-s: .sp kermit \-g somefile.txt .sp This causes your local Kermit to enter server mode; then the remote Kermit program requests the named file and the local Kermit sends it and returns automatically to Connect state when done. .sp If you want to upload multiple files, you have to use shell quoting rules, since these aren't local files: .sp .nf kermit \-g "somefile.txt somefile.zip somefile.html somefile.tar.gz" kermit \-g "somefile.*" .fi .sp If you want to upload a file but store it under a different name, use: .sp kermit \-g friday.txt \-a today.txt .SH Kermit Transfers the Old\(hyFashioned Way If your desktop communications software does not support autoupload or autodownload, or it does not include Kermit server mode, the procedure requires more steps. .sp To download a file, type: .sp kermit \-s filename .sp on the host as before, but if nothing happens automatically in response to this command, you have to switch your desktop communications software into Kermit Receive state. This might be done by escaping back using keyboard characters or hot keys (Alt\-x is typical) and/or with a command (like RECEIVE) or a menu. When the file transfer is complete, you have to go back to Connect state, Terminal emulation, or whatever terminology applies to your desktop communications software. .sp To upload a file, type: .sp kermit \-r .sp on the host (rather than "kermit \-g"). This tells C\(hyKermit to wait passively for a file to start arriving. Then regain the attention of your desktop software (Alt\-x or whatever) and instruct it to send the desired file(s) with Kermit protocol. When the transfer is finished, return to the Connect or Terminal screen. .SH If File Transfer Fails Although every aspect of Kermit's operation can be finely tuned, there are also three short and simple "omnibus tuning" commands you can use for troubleshooting: .RS .TP FAST Use fast file\(hytransfer settings. This has been the default since C\(hyKermit 7.0 now that most modern computers and connections support it. If transfers fail with fast settings, try . . . .TP CAUTIOUS Use cautious but not paranoid settings. File transfers, if they work, will go at medium speed. If not, try . . . .TP ROBUST Use the most robust, resilient, conservative, safe, and reliable settings. File transfers will almost certainly work, but they will be quite slow (of course this is a classic tradeoff; ROBUST was C\(hyKermit's default tuning in versions 6.0 and earlier, which made everybody think Kermit protocol was slow). If ROBUST doesn't do the trick, try again with SET PARITY SPACE first in case it's not an 8\(hybit connection. .RE .sp Obviously the success and performance of a file transfer also depends on C\(hyKermit's file transfer partner. Up\(hyto\(hydate, real Kermit Project partners are recommended because they contain the best Kermit protocol implementations and because we can support them in case of trouble. .sp If you still have trouble, consult Chapter 10 of Using C\(hyKermit, or send email to upport@kermitproject.org. .SH Advanced Kermit File\(hyTransfer Features Obviously there is a lot more to Kermit file transfer, including all sorts of interactive commands, preferences, options, logging, debugging, troubleshooting, and anything else you can imagine but that's what the manual and updates are for. Here are a few topics you can explore if you're interested by Typing HELP for the listed commands: .RS .TP Logging transfers: LOG TRANSACTIONS (HELP LOG) .TP Automatic per\(hyfile text/binary mode switching: SET TRANSFER MODE { AUTOMATIC, MANUAL } (HELP SET TRANSFER). .TP Cross\(hyplatform recursive directory tree transfer: SEND /RECURSIVE, GET /RECURSIVE (HELP SEND, HELP GET). .TP File collision options: SET FILE COLLISION { OVERWRITE, BACKUP, DISCARD, ... } (HELP SET FILE). .TP Update: Transfer only files that changed since last time: SET FILE COLLISION UPDATE (HELP SET FILE). .TP Filename selection patterns: (HELP WILDCARD). .TP Flexible file selection: SEND (or GET) /BEFORE /AFTER /LARGER /SMALLER /TYPE /EXCEPT, ... .TP Character\(hyset conversion: SET { FILE, TRANSFER } CHARACTER\-SET, ASSOCIATE, ... .TP File/Pathname control: SET { SEND, RECEIVE } PATHNAMES, SET FILE NAMES. .TP Atomic file movement: SEND (or GET) /DELETE /RENAME /MOVE\-TO .TP Transferring to/from standard i/o of other commands: SEND (or GET) /COMMAND .TP Recovery of interrupted transfer from point of failure: RESEND, REGET (HELP RESEND, HELP REGET). .RE .SH Non\(hyKermit File Transfer You can also use C\(hyKermit to transfer files with FTP or HTTP Internet protocols; see below. .sp On a regular serial or Telnet connection where the other computer doesn't support Kermit protocol at all, you have several options. For example, if your desktop communications software supports Zmodem, use "rz" and "sz" on the host rather than Kermit. But if Kermit is your desktop software, and you are using it to make calls or network connections to other computers that don't support Kermit protocol (or that don't have a good implementation of it), then if your computer also has external X, Y, or Zmodem programs that are redirectable, Kermit can use them as external protocols. HELP SET PROTOCOL for details. .sp You can also capture "raw" data streams from the other computer with LOG SESSION (HELP LOG and HELP SET SESSION\-LOG for details), and you can upload files without any protocol at all with TRANSMIT (HELP TRANSMIT, HELP SET TRANSMIT). .SH KERMIT'S BUILT\(hyIN FTP AND HTTP CLIENTS Kermit's FTP client is like the regular Unix FTP client that you're used to, but with some differences: .TP \(bu It has lots more commands and features. .TP \(bu Each FTP command must be prefixed with "ftp", for example "ftp open", "ftp get", "ftp bye", etc (this is not strictly true, but until you're more familiar with it, it's best to follow this rule). .TP \(bu Commands like "cd", "directory", etc, execute locally, not on the server. Use "ftp cd", "ftp dir", etc, to have them act on the server. .TP \(bu You can have an FTP session and a regular Kermit serial or Telnet session open at the same time. .TP \(bu FTP sessions can be fully automated. .PP The Kermit FTP client is thoroughly documented at the Kermit Project website: .sp https://kermitproject.org/ftpclient.html .sp You also can use HELP FTP and HELP SET FTP to get descriptions of Kermit's FTP\(hyrelated commands. .PP The HTTP client is similar to the FTP one, except you prefix each command with HTTP instead of FTP: HTTP OPEN, HTTP GET, HTTP PUT, HTTP CLOSE, etc. Type HELP HTTP for details, or visit the to view the manual supplements. HTTP connections can be open at the same time as regular serial or Telnet connections and FTP connections. So Kermit can manage up to three types connections simultaneously. .SH INTERNET KERMIT SERVICE C\(hyKermit can be configured and run as an Internet service (called IKSD), similar to an FTP server (FTPD) except you can (but need not) interact with it directly, plus it does a lot more than an FTP server can do. The TCP port for IKSD is 1649. It uses Telnet protocol. C\(hyKermit can be an Internet Kermit Server, or it can be a client of an IKSD. You can make connections from C\(hyKermit to an IKSD with any of the following commands: .sp .nf telnet foo.bar.edu 1649 telnet foo.bar.edu kermit ; if "kermit" is listed in /etc/services iksd foo.bar.edu .fi .sp The IKSD command is equivalent to a TELNET command specifying port 1649. For more information about making and using connections to an IKSD, see: .sp https://kermitproject.org/cuiksd.html .sp You can run an Internet Kermit Service on your own computer too (if you are the system administrator). For instructions, see: .sp https://kermitproject.org/iksd.html .SH SECURITY All of C\(hyKermit's built\(hyin TCP/IP networking methods (Telnet, Rlogin, IKSD, FTP, and HTTP) can be secured by one or more of the following IETF\(hyapproved methods: .PP \(bu MIT Kerberos IV .br \(bu MIT Kerberos V .br \(bu SSL/TLS .br \(bu Stanford SRP .PP The Windows version of C-Kermit 10.0 (CKW) has its own built-in SSH client; the Unix version makes SSH connections through the external SSH client. .PP For complete instructions see: .PP https://kermitproject.org/security.html .PP .SH ALTERNATIVE COMMAND\(hyLINE PERSONALITIES When invoked as "kermit" or any other name besides "ftp" or "telnet", C\(hyKermit has the command\(hyline options described above in the OPTIONS section. However, if you invoke C\(hyKermit as "telnet" or "ftp", it changes its command\(hyline personality to match. This can be done (among other ways) with symbolic links (symlinks). For example, if you want C\(hyKermit to be your regular Telnet client, or the Telnet helper of your Web browser, you can create a link like the following in a directory that lies in your PATH ahead of the regular telnet program: .sp ln \-s /usr/local/bin/kermit telnet .sp Now when you give a "telnet" command, you are invoking Kermit instead, but with its Telnet command\(hyline personality so, for example: .sp telnet xyzcorp.com .sp Makes a Telnet connection to xyzcorp.com, and Kermit exits automatically when the connection is closed (just like the regular Telnet client). Type "telnet \-h" to get a list of Kermit's Telnet\(hypersonality command\(hyline options, which are intended to be as compatible as possible with the regular Telnet client. .PP Similarly for FTP: .sp ln \-s /usr/local/bin/kermit ftp .sp And now type "ftp \-h" to see its command\(hyline options, and command lines just like you would give your regular FTP client: .sp ftp xyzcorp.com .sp but with additional options allowing an entire session to be specified on the command line. Finally, if Kermit's first command\(hyline option is a Telnet, FTP, IKSD, or HTTP URL, Kermit automatically makes the appropriate kind of connection and, if indicated by the URL, takes the desired action: .TP kermit telnet:xyzcorp.com Opens a Telnet session .TP kermit telnet://olga@xyzcorp.com Ditto for user olga .TP kermit ftp://olga@xyzcorp.com/public/somefile.zip Downloads a file .TP kermit https://kermitproject.org/index.html Grabs a web page .fi .SH LICENSE As of version 9.0 C\(hyKermit carries the Revised 3-Clause BSD License, which is 100% Open Source. C-Kermit's LICENSE command displays the license, and it is also available on the Kermit Project website: .TP kermit https://kermitproject.org/ck10license.html .SH OTHER TOPICS There's way more to C\(hyKermit than we've touched on here \(hy\(hy troubleshooting, customization, character sets, dialing directories, sending pages, script writing, and on and on, all of which are covered in the manual and updates and supplements. For the most up\(hyto\(hydate information on documentation (or updated documentation itself) visit the Kermit Project website: .sp https://kermitproject.org/ .PP There you will also find Kermit software packages for other platforms: different Unix varieties, Windows, DOS, VMS, IBM mainframes, and many others: over 40 years' worth at this writing (2022). .SH DOCUMENTATION AND UPDATES The manual for C\(hyKermit is: .TP .I Using C\(hyKermit Frank da Cruz and Christine M. Gianone, Second Edition, Digital Press / Butterworth\(hyHeinemann, Woburn, MA, 1997, 622 pages, ISBN 1\-55558\-164\-1. This is a printed book. It covers C\(hyKermit 6.0. As of 2016 it is also available online in PDF form: .sp https://www.kermitproject.org/onlinebooks/usingckermit3e.pdf .TP The C\(hyKermit 7.0 Supplement https://kermitproject.org/ckermit70.html .TP The C\(hyKermit 8.0 Supplement https://kermitproject.org/ckermit80.html .TP The C\(hyKermit 9.0 Supplement https://kermitproject.org/ckermit90.html .TP The C\(hyKermit 10.0 Specifications https://kermitproject.org/ck10specs.html .TP The C\(hyKermit 10.0 Complete Command List https://kermitproject.org/ck10commandref.html .PP Visit the C\(hyKermit home page: .sp https://kermitproject.org/ckermit.html .sp to learn about new versions, Beta tests, and other news; to read case studies and tutorials; to download source code, install packages, and prebuilt binaries for many platforms. Also visit: .TP https://kermitproject.org/ckscripts.html The Kermit script library and tutorial .TP https://kermitproject.org/ckfaq.html The C\(hyKermit FAQ (Frequently Asked Questions about C\(hyKermit) .TP https://kermitproject.org/telnet.html C\(hyKermit Telnet client documentation .TP https://kermitproject.org/security.html C\(hyKermit security documentation (Kerberos, SSL/TLS, etc) .TP https://kermitproject.org/cuiksd.html Internet Kermit Service user documentation .TP https://kermitproject.org/iksd.html Internet Kermit Service administrator documentation .TP https://kermitproject.org/studies.html Case studies. .TP https://kermitproject.org/support.html Technical support. .TP https://kermitproject.org/ckuins.html. Installation instructions for Unix. .TP https://kermitproject.org/ckcbwr.html. General C\(hyKermit bugs, hints, tips. .TP https://kermitproject.org/ckubwr.html. Unix\(hyspecific C\(hyKermit bugs, hints, tips. .TP https://kermitproject.org/ckcplm.html. C\(hyKermit program logic manual. .TP https://kermitproject.org/ckccfg.html. C\(hyKermit compile\(hytime configuration options. .TP /var/spool/locks (or whatever) UUCP lockfile for dialing out (see installation instructions). .TP ca_certs.pem Certificate Authority certifcates used for SSL connections. .SH AUTHORS .TP Software Frank da Cruz and Jeffrey E Altman, .br 1985\(hypresent, with contributions from hundreds of others all over the world, notably David Goodwin for converting the 2001 edition of Kermit 95 to Open Source C-Kermit 10.0 for Windows. .TP Documentation Frank da Cruz .TP Address .nf The Open Source Kermit Project Bronx NY USA .fi .TP E\(hyMail kermit@kermitproject.org .TP Web https://kermitproject.org/ .fi .br ckermit.ini000664 045065 024037 00000001056 14344455224 013333 0ustar00fdckermit000000 000000 COMMENT - Standard C-Kermit initialization file ; echo echo You can have C-Kermit execute any commands you want when it starts echo by putting them in your initialization file, which is: echo echo " * Unix (Linux, BSD, macOS, etc): .kermrc in your home (login) directory" echo " * Windows: k95custom.ini \\v(appdata) (your application data directory)" echo " * IBM OS/2: k2custom.ini \\v(appdata) (your application data directory)" echo " * VMS, OpenVMS: ckermit.ini Your home (login) directory" echo " * Other: ckermit.ini Your home (login) directory" echo android.txt000664 045065 024037 00000001767 12244425014 013355 0ustar00fdckermit000000 000000 cka - C-Kermit for Android This archive contains the source code for building C-Kermit 9.0.302 for Android. It has been taken from the source code downloaded from: ftp://ftp.kermitproject.org/kermit/archives/cku302.zip At this point the changes here are not part of the official release. all issues related to C-Kermit for Android should be directed at the github project, which can be found here: http://github.com/tesneddon/cka Assuming the Android NDK procedure "ndk-build" is in your PATH, you can use the following command to build the software for all ABIs: $ ndk-build NDK_PROJECT_PATH=./ \ APP_BUILD_SCRIPT=./android.mk \ APP_ABI=all \ LOCAL_DISABLE_FORMAT_STRING_CHECKS=true If you have any problems, flames, suggestions, praise, disbelief, etc. then please feel free to create an issue on the github page and I will follow it up as I get the opportunity. Tim Sneddon (with updates from Jake Thompson, 17 Nov 2013) android.mk000664 045065 024037 00000001723 12244424651 013143 0ustar00fdckermit000000 000000 LOCAL_PATH:= $(call my-dir) # ======================================================== # nano # ======================================================== include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ ckcmai.c ckclib.c ckutio.c ckufio.c \ ckcfns.c ckcfn2.c ckcfn3.c ckuxla.c \ ckcpro.c ckucmd.c ckuus2.c ckuus3.c \ ckuus4.c ckuus5.c ckuus6.c ckuus7.c \ ckuusx.c ckuusy.c ckuusr.c ckucns.c \ ckudia.c ckuscr.c ckcnet.c ckusig.c \ ckctel.c ckcuni.c ckupty.c ckcftp.c \ ckuath.c ck_crp.c ck_ssl.c LOCAL_C_INCLUDES += \ $(LOCAL_PATH) LOCAL_CFLAGS += \ -DFNFLOAT -DCK_NEWTERM -DTCPSOCKET \ -DLINUXFSSTND -DNOCOTFMC -DUSE_STRERROR \ -DHAVE_PTMX -D_LARGEFILE_SOURCE -DNO_OPENPTY \ -D_FILE_OFFSET_BITS=64 -DPOSIX -DUSE_FILE_R\ -DKTARGET=\"android\" -DNO_DNS_SRV -DNOIKSD \ -DNOTIMESTAMP -DNOZLOCALTIME -DNOUUCP \ -DNO_NL_LANGINFO -DNO_LOCALE LOCAL_MODULE := kermit LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) LOCAL_MODULE_TAGS := eng include $(BUILD_EXECUTABLE) ckubuildlog000755 045065 024037 00000035517 14504042126 013424 0ustar00fdckermit000000 000000 #!./wermit + # CKUBUILDLOG C-Kermit script for UNIX-based operating systems # Frank da Cruz, fdc@columbia.edu, Bronx # and Peter Eichhorn, Munich # 5 June 2023 # Most recent update: # Sun Sep 24 10:00:17 2023 # .version = 2.15 # Version .verdate = 2023/09/24 # Date of version # (v2.10 fixes reporting of OpenSSL version) # (v2.11 fixes reporting of Kerberos version) # (V2.12 tries harder to find compiler name and version) # (V2.13 put "No warnings" in last field if there were no warnings) # (V2.14 Don't "copy /append" on Macintosh - it clobbers the original file) # (V2.15 Undoes previous change and fixes a syntax error in: # .tmpcc := \fcommand(strings wermit | egrep -i "(cc |gcc|clang)") # (final paren was missing) and adds support for SunOS and Solaris # set debug message off # Use -v on command line to turn on # This script is distributed with C-Kermit source-code and is to be used # on Unix-based platforms (e.g. Linux, BSD, macOS) after compilation and # linking to produce a table entry for C-Kermit build log. # # Example of use (cd'd to C-Kermit source code directory, which must # include C-Kermit sources and 'wermit' executable. # # make linux 2>log # (compilation and linking occurs, producing a 'wermit' executable...) # ./ckubuildlog # # This produces an xxx.txt file in the same directory, where xxx is the # makefile target ("linux" in this example). # # You don't have to install the script, it comes with C-Kermit 10.0. # # Usage: ckubuildlog [ parameters ] # For parameters see: https://www.kermitproject.org/ckbuildlog.html # # Examples (in the C-Kermit build directory): # ./ckubuildlog (let the script try to figure the OS name a version) # ./ckubuildlog "NetBSD 9.3" (provide hostname and version to the script) # # Creates a C-Kermit 10.0 Beta test builds-table entry to be sent # to me for inclusion in https://kermitproject.org/ck10devbuilds.html. # # For compiler warnings to be included, C-Kermit must be built like this: # # cd ckermit (cd to your C-Kermit source code directory) # rm -f log (remove any previous log) # make targetname 2>log (log warnings and errors to file named 'log') # # (note: if you use a name other than 'log' you have to specify it # on the ckubuildlog command line, e.g. 'ckubuildlog logfile=build7.log') # # C-Kermit build examples: # # make linux 2>log (default Linux build) # make linux+ssl 2>log (Linux with OpenSSL) # make linux+krb5 2>log (Linux with MIT Kerberos 5) # make linux+krb5+ssl 2>log (Linux with MIT Kerberos 5 and OpenSSL) # make netbsd 2>log (default NetBSD build) # # Note: optional 'make' parameters as in 'make linux KFLAGS="-DNODEBUG"' # are not captured by this script but you can specify them on the # ckubuildlog command line. # # osname-and-version: # There is no standard Unix shell command or utility that returns the # computer's operating-system name and version. In some cases C-Kermit # (which is executing this script) can find the OS name and version on its # own, in which case they will be in one or more of the following built-in # C-Kermit variables: # # \v(osname) # \v(osversion) # \v(osrelease) # \v(platform) # # In other cases, for selected OS's, this script's GETOSNAME macro can find # them somewhere in the /etc/*release* or other directories. As a last # resort, you can simply provide the OS name and version as a command-line # parameter, e.g.: # # ckubuildlog "MINIX 3" # ckubuildlog "Solaris 11" # ckubuildlog "HP-UX 10.0" # ckubuildlog "4.2BSD" # # GETOSNAME clauses for additional platforms are welcome. # Note: string comparisons in this script are case-independent # if not equ "\v(system)" "UNIX" { exit 1 "Sorry, ckubuildlog only works in UNIX-based operating systems" } undef osname # Clear the OS name undef resultfile # Clear result-file name undef kflags # Clear KFLAGS undef logfile # Clear compilation log file name undef ccdata # Clear C compiler data .\%n = 0 # Command-line parameter counter if debug show args while def \%1 { # Get parameters from command line incr \%n msg LOOP \%n "\%1" if equ "\%1" "-h" { # -h = help msg HELP TEXT echo echo {Usage: ckubuildlog [-v] [-h] ["OS name and version"]} echo " -v = verbose; -h = help (this message)" echo { also: resultfile=filename, logfile=filename, - kflags="-Dxxxx [-Dyyyy ...]"} echo " All command-line options are optional." echo " Order doesn't matter." echo " Options that contain spaces must be enclosed in doublequotes." echo echo "Instructions:" echo " cd to the C-Kermit source directory." echo { Build C-Kermit with "make xxxx 2>log"} echo { where xxxx is the target from the makefile, e.g. 'linux'.} echo { '2>log' puts any warnings or errors in a filed named 'log'} echo { Example: 'make linux 2>log'} echo { Then run this script, supplying OS and version if necessary.} echo { Examples:} echo echo { ckubuildlog} echo { ckubuildlog "SunOS 4"} echo { ckubuildlog "HP-UX B10.20"} echo echo { The results are in the same directory as xxx.txt,} echo { where xxx is the make target name; e.g. linux.txt} echo { or, if 'resultfile=xxx' was given, in the file named xxx}, echo { where xxx is a name of your choice.} echo exit } if equ "\%1" "-v" { # -v = verbose echo SET DEBUG MESSAGE ON set debug message on shift continue } if \findex(=,\%1) { # Keyword parameter msg KEYWORD FROM COMMAND LINE = '\%1' void \fkeywordvalue(\%1); # Get keyword and its value shift continue } else if def \%1 { msg OSNAME FROM COMMAND LINE = '\%1' .osname := \%1 # OS name & version from command line shift continue } } # Macro to get OS name and version for selected OS's; others can be added. # WARNING: This requires C-Kermit to have BIGBUFOK defined in ckcdeb.h. # #if def osname forward :SKIPOSNAME define GETOSNAME { # Macintosh if ( match "\v(platform)" "mac*" || match "\v(platform)" "*OS_X*" ) { .osname := \freplace(\v(platform),_,\32) return } if exist /etc/release { # NetBSD... .name := \fcommand(grep NetBSD /etc/release | head -1) if def name { void \fsplit(\m(name),&a,\32/) .osname := \&a[1] \&a[2] return } } if not exist /etc/oracle-release { # Oracle has redhat-release AND oracle-release if exist /etc/redhat-release { # Ret Hat Enterprise Linux .name := \fcommand(grep "Red Hat" /etc/redhat-release | head -1) if def name { void \fsplit(\m(name),&a,\32) .osname := RHEL \&a[7] return } } } if exist /etc/fedora-release { # Fedora Linux .name := \fcommand(grep "Fedora" /etc/fedora-release | head -1) if def name { .osname := Fedora \fword(\m(name),3) return } } if \findex(HP-UX,\v(osname)) { # HP-UX local hpccdata &x &y .osname := HP-UX \v(osrelease) .hpccdata := \fcommand(what `whence cc`) if debug show mac hpccdata void \fsplit(\m(hpccdata),&x,$) void \fsplit(\&x[5],&y,\32) .ccdata := HP C Compiler \&y[2] if debug show mac ccdata return } if match \v(platform) SunOS* { # SunOS .osname := \v(osname) \v(osrelease) return } else if match \v(platform) Solaris* { # Solaris .osname := \v(osname) \v(osrelease) return } if match \v(platform) OpenBSD* { # OpenBSD .osname := \freplace(\v(platform),_,\32) return } if equ \v(platform) Linux { # Common Linux distributions # Centos, Debian, Fedora, Oracle, Red Hat, Rocky, SUSE, ... if exist /etc/os-release { .osname := \fcommand(grep "PRETTY_NAME" /etc/os-release) if def osname { .osname := \fword(\m(osname),2,\") } else { .osname := \fcommand(grep "NAME=" /etc/os-release) if def osname { .osname := \fword(\m(osname),2,\") .osversion := \fcommand(grep "VERSION-ID=" /etc/os-release) .osname := \m(osname) \m(osversion) } } if def osname return } } } :SKIPOSNAME echo ckubuildlog \m(version) \m(verdate) echo "This directory: \v(dir)" # Orientation if not def osname getosname # Get OS name if not passed on cmdline # Check for makefile if not exist makefile exit 1 "makefile not found in \v(dir)" dir /array:x /count:filecount ck*.[ch] if not exist ckcmai.c { echo "Error: ckcmai.c not found in \v(dir)" exit 1 "This script must be run in the C-Kermit build directory" } if < \m(filecount) 54 { echo "Warning: some C-Kermit source code files seem to be missing" } undeclare x msg C-Kermit source files found. # Check whether C-Kermit binary (wermit) exists if not exist ./wermit { echo 'wermit' binary not found in \v(dir). exit 1 "Please give an appropriate 'make' command to build C-Kermit" } # Run wermit to get SHOW FEATURES listing into a file void \fcommand(./wermit -C "show features" > shofeat.txt, exit) if fail exit 1 "wermit SHOW FEATURES failed" msg Feature list ok: if debug dir shofeat.txt void \fcommand(grep BIGBUFOK shofeat.txt) if fail { echo WARNING: BIGBUFOK not defined in this C-Kermit build echo Some operations might fail } # Makefile target... undef target .target := \fword(\fcommand(grep Target: shofeat.txt),2,\32,ALL) if not def target { exit 1 "Target not found in shofeat.txt" } if debug sho mac target # Check whether the build failed .failed = 0 if not exist wermit { echo "MOST RECENT BUILD FAILED - wermit binary not found" .failed = 1 # the build build failed forward :ARCH } # Build failed but previous wermit still exists if exist log { if newer log wermit { echo "MOST RECENT BUILD FAILED - wermit binary older than log" if exist log echo "See log for errors" .failed = 1 forward :ARCH } } # Check whether wermit binary is newer than all the source code modules dir /sort:date /reverse /top:1 /array:o ck*.[ch] if newer \&o[1] wermit { echo "Error: some source modules are newer than the wermit executable..." exit 1 "Please rebuild C-Kermit and run this script again." } # Check object files if \ffiles(ck*.o) { dir /sort:date /reverse /top:1 /array:o ck*.o if newer \&o[1] wermit { echo {'make' command failed - Object file(s) are newer than wermit.} echo {This probably means that the most recent 'make' command failed.} exit 1 } } undeclare o .banner := \fcommand(grep "C-Kermit " shofeat.txt | grep for) if def banner { echo wermit: \m(banner) } if failed { # If the build failed... .size = N/A } else { msg wermit executable found and up-to-date. if debug dir wermit .size := \fsize(wermit) if not numeric \m(size) .size = (unknown) } msg Size: \m(size) bytes # Architecture... :ARCH undef arch .arch := \fword(\fcommand(grep Machine: shofeat.txt),2,\32) if debug sho mac arch .maxnamelen := 72 if not def osname { .tmpname := \fcommand(grep "OS Version:" shofeat.txt) .dots = if > \flen(\m(tmpname)) \m(maxnamelen) .dots := ... .osname := \s(tmpname[14:\m(maxnamelen)])\m(dots) if debug sho mac osname } # Kermit code date from ckcmai.c undef codedate .tmpdate := \fcommand(grep EDITNDATE ckcmai.c | head -1) void \fsplit(\m(tmpdate),&a) # show array a .codedate := \fleft(\freplace(\fcvtdate(\&a[3],5),:,-),10) if debug show mac codedate # Look for compiler name and version .maxcclen := 72 undef cc .\%c = 0 .tag := "GCC version:" .tmpcc := \fcommand(grep "\m(tag)" shofeat.txt) # NOTE: can also look for __DECC and __DECC_VER in shofeat.txt. if def tmpcc { .\%c = 1 } else { .tag = "Compiler version:" .tmpcc := \fcommand(grep "\m(tag)" shofeat.txt) if def tmpcc { .\%c = 2 } else if def ccdata { .\%c = 3 .tmpcc := \m(ccdata) } else { .tmpcc := \fcommand(strings wermit | egrep -i "(cc |gcc|clang)") if def tmpcc .\%c = 4 else .tmpcc = "(unknown)" } } if def tmpcc { .tmpcc := \freplace(\m(tmpcc),{Compiler version: },) } msg tmpcc[\%c] = \m(tmpcc) if > \%c 0 { .dots = .tmpcc := \fltrim(\freplace(\m(tmpcc),GCC version:,)) if numeric \s(tmpcc[1.]) .tmpcc := gcc \m(tmpcc) # .tmpcc := \fltrim(\freplace(\m(tmpcc),\m(tag),)) if not \fverify(0123456789.,\m(tmpcc)) .tmpcc := "gcc \m(tmpcc)" if debug show mac tmpcc if > \flen(\m(tmpcc)) \m(maxcclen) .dots := ... .cc := \m(tmpcc)\m(dots) } if debug sho mac cc .security = .ssl = if \findex(ssl,\m(target)) { .ssl := \fcommand(openssl version) .security := \m(ssl) } .krb5 = if \findex(krb5,\m(target)) { .krb5 := \fcommand(krb5-config --version) .security := \m(security) \m(krb5) } .tmpsecurity := \m(security) if not def security .tmpsecurity = (none) msg Security: \m(tmpsecurity) if failed { .status = Failed } else { .status = OK } if not def resultfile .resultfile := \m(target).txt if not def logfile .logfile := log fopen /write \%o \m(resultfile) if fail exit 1 Can't create \m(target).txt fwrite /line \%o fwrite /line \%o \m(osname) fwrite /line \%o \m(arch) if def kflags { .kflags := KFLAGS="\m(kflags)" } fwrite /line \%o make \m(target) \m(kflags) fwrite /line \%o \m(codedate) fwrite /line \%o \m(size) fwrite /line \%o \m(cc) fwrite /line \%o \m(security) fwrite /line \%o \m(status) echo Executable: dir wermit if def logfile { if not exist \m(logfile) { echo "No log file found - if there were warnings or errors," xecho "please 'make clean' and then rebuild with " echo "'make \m(target) 2> log', thanks." } else if > \fsize(\m(logfile)) 0 { echo "(there were some warnings or errors):" dir \m(logfile) fwrite \%o fclose \%o copy /append \m(logfile) \m(resultfile) } else { fwrite /line \%o No warnings } } if \f_status(\%o) fclose \%o echo ckubuildlog done, result (please email it to fdc@columbia.edu): dir \m(resultfile) type \m(resultfile) exit ; Local Variables: ; comment-column:40 ; comment-start:"# " ; End: ckcpro.w000664 045065 024037 00000330356 14767401743 012663 0ustar00fdckermit000000 000000 char *protv = /* -*-C-*- */ "C-Kermit Protocol Module 10.0.170, 21 Mar 2024"; int kactive = 0; /* Kermit protocol is active */ /* This file, ckcpro.w, is the source file for the Kermit protocol state table switcher: ckcpro.c, which is created by running ckcpro.w through the "wart" program via "make ckcpro.c", which converts the part enclosed in double percent signs from Lex format to the C module called ckcpro.c. In November 2022 this file was retired on the unwise assumption that the Kermit protocol would never change again. Starting with edit 10.0.168 of 29 January 2024, ckcpro.w is reinstated because it proved impossible to make protocol changes or additions by editing ckcpro.c directly when a few simple client/server fuctions were needed: REMOTE CDUP and REMOTE STATUS. The makefile has not changed however, except for putting back "make wart" and "make ckcpro.c", so ckcpro.w is not automatically converted by the 'wart' program as it was before. In short, if you want to change the protocol module (this file), you have to build it by hand with: make wart make ckcpro.c */ #define PKTZEROHACK /* C K C P R O -- C-Kermit Protocol Module, in Wart preprocessor notation. */ /* Author: Frank da Cruz , Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 2024 Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ #ifndef NOXFER #include "ckcsym.h" #include "ckcdeb.h" #include "ckcasc.h" #include "ckcker.h" #ifdef OS2 #ifndef NT #define INCL_NOPM #define INCL_VIO /* Needed for ckocon.h */ #include #undef COMMENT #endif /* NT */ #include "ckocon.h" #endif /* OS2 */ #ifdef CK_AUTHENTICATION #include "ckuath.h" /* fdc 2021-12-17 */ #endif /* CK_AUTHENTICATION */ #include "ckcfnp.h" /* Prototypes (must be last) */ /* Note -- This file may also be preprocessed by the UNIX Lex program, but you must indent the above #include statements before using Lex, and then restore them to the left margin in the resulting C program before compilation. Also, the invocation of the "wart()" function below must be replaced by an invocation of the "yylex()" function. It might also be necessary to remove comments in the (%)(%)...(%)(%) section. */ /* State definitions for Wart (or Lex) */ %states ipkt rfile rattr rdpkt ssinit ssfile ssattr ssdata sseof sseot %states serve generic get rgen ssopkt ropkt _PROTOTYP(static VOID xxproto,(void)); _PROTOTYP(static VOID wheremsg,(void)); _PROTOTYP(int wart,(void)); _PROTOTYP(static int sgetinit,(int,int)); _PROTOTYP(int sndspace,(int)); /* External C-Kermit variable declarations */ extern char *versio, *srvtxt, *cmarg, *cmarg2, **cmlist, *rf_err; extern char * rfspec, * sfspec, * srfspec, * rrfspec; extern char * prfspec, * psfspec, * psrfspec, * prrfspec; extern char *cdmsgfile[]; extern char * snd_move, * snd_rename, * srimsg; extern char filnam[], ofilnam[], fspec[], ttname[], ofn1[]; extern CHAR sstate, *srvptr, *data; extern int timint, rtimo, nfils, hcflg, xflg, flow, mdmtyp, network; extern int oopts, omode, oname, opath, nopush, isguest, xcmdsrc, rcdactive; extern int rejection, moving, fncact, bye_active, urserver, fatalio; extern int protocol, prefixing, carrier, fnspath, interrupted; extern long filcnt; extern int recursive, inserver, nzxopts, idletmo, srvidl, xfrint; extern struct ck_p ptab[]; extern int remfile, rempipe, xferstat, filestatus, wearealike, fackpath; extern int patterns, filepeek, gnferror; extern char * remdest; #ifdef PKTZEROHACK #define PKTZEROLEN 32 static char ipktack[PKTZEROLEN]; static int ipktlen = 0; #endif /* PKTZEROHACK */ static int s_timint = -1; /* For saving timeout value */ static int myjob = 0; static int havefs = 0; #ifdef CK_LOGIN static int logtries = 0; #endif /* CK_LOGIN */ static int cancel = 0; int fackbug = 0; #ifdef STREAMING extern int streaming, streamok; static VOID streamon() { if (streamok) { debug(F100,"streamon","",0); streaming = 1; timint = 0; /* No timeouts while streaming. */ } } #ifdef COMMENT /* (not used) */ static VOID streamoff() { if (streaming) { debug(F100,"streamoff","",0); streaming = 0; timint = s_timint; /* Restore timeout */ } } #endif /* COMMENT */ #else /* STREAMING */ #define streamon() #define streamoff() #endif /* STREAMING */ #ifndef NOSPL _PROTOTYP( int addmac, (char *, char *) ); _PROTOTYP( int zzstring, (char *, char **, int *) ); #endif /* NOSPL */ #ifndef NOICP _PROTOTYP( int cmdsrc, (void) ); #endif /* NOICP */ #ifndef NOSERVER extern char * x_user, * x_passwd, * x_acct; extern int x_login, x_logged; #endif /* NOSERVER */ #include "ckcnet.h" #ifdef TNCODE extern int ttnproto; /* Network protocol */ #endif /* TNCODE */ #ifdef CK_SPEED extern short ctlp[]; /* Control-character prefix table */ #endif /* CK_SPEED */ #ifdef TNCODE extern int tn_b_nlm, tn_b_xfer, tn_nlm; #ifdef CK_ENCRYPTION extern int tn_no_encrypt_xfer; #endif /* CK_ENCRYPTION */ #endif /* TNCODE */ #ifdef TCPSOCKET #ifndef NOLISTEN extern int tcpsrfd; #endif /* NOLISTEN */ #endif /* TCPSOCKET */ extern int cxseen, czseen, server, srvdis, local, displa, bctu, bctr, bctl; extern int bctf; extern int quiet, tsecs, parity, backgrd, nakstate, atcapu, wslotn, winlo; extern int wslots, success, xitsta, rprintf, discard, cdtimo, keep, fdispla; extern int timef, stdinf, rscapu, sendmode, epktflg, epktrcvd, epktsent; extern int binary, fncnv, dest; extern long speed, crc16; extern CK_OFF_T calibrate, ffc; #ifdef COMMENT extern char *TYPCMD, *DIRCMD, *DIRCM2; #endif /* COMMENT */ #ifndef OS2 extern char *SPACMD, *SPACM2, *WHOCMD; #endif /* OS2 */ extern CHAR *rdatap; extern struct zattr iattr; #ifdef VMS extern int batch; #endif /* VMS */ #ifdef GFTIMER extern CKFLOAT fptsecs; #endif /* GFTIMER */ extern CHAR *srvcmd; extern CHAR *epktmsg; #ifdef CK_TMPDIR extern int f_tmpdir; /* Directory changed temporarily */ extern char savdir[]; /* For saving current directory */ extern char * dldir; #endif /* CK_TMPDIR */ extern int query; /* Query-active flag */ #ifndef NOSPL extern int cmdlvl; char querybuf[QBUFL+1] = { NUL, NUL }; /* QUERY response buffer */ char *qbufp = querybuf; /* Pointer to it */ int qbufn = 0; /* Length of data in it */ #else extern int tlevel; #endif /* NOSPL */ #ifndef NOICP extern int escape; #endif /* NOICP */ /* If the following flag is nonzero when the protocol module is entered, then server mode persists for exactly one transaction, rather than looping until BYE or FINISH is received. */ extern int justone; static int r_save = -1; static int p_save = -1; /* Function to let remote-mode user know where their file(s) went */ int whereflg = 1; /* Unset with SET XFER REPORT */ static VOID wheremsg() { extern int quiet; extern long filrej; long n; n = filcnt - filrej; debug(F101,"wheremsg n","",n); debug(F110,"wheremsg prfspec",prfspec,0); debug(F110,"wheremsg rfspec",rfspec,0); debug(F110,"wheremsg psfspec",psfspec,0); debug(F110,"wheremsg sfspec",sfspec,0); debug(F110,"wheremsg prrfspec",prrfspec,0); debug(F110,"wheremsg rrfspec",rrfspec,0); debug(F110,"wheremsg psrfspec",psrfspec,0); debug(F110,"wheremsg srfspec",srfspec,0); if (!quiet && !local) { if (n == 1) { switch (myjob) { case 's': if (sfspec) { printf(" SENT: [%s]",sfspec); if (srfspec) printf(" To: [%s]",srfspec); printf(" (%s)\r\n", success ? "OK" : "FAILED"); } break; case 'r': case 'v': if (rrfspec) { printf(" RCVD: [%s]",rrfspec); if (rfspec) printf(" To: [%s]",rfspec); printf(" (%s)\r\n", success ? "OK" : "FAILED"); } } } else if (n > 1) { switch (myjob) { case 's': if (sfspec) { printf(" SENT: (%ld files)",n); if (srfspec) printf(" Last: [%s]",srfspec); printf(" (%s)\r\n", success ? "OK" : "FAILED"); } break; case 'r': case 'v': if (rrfspec) { printf(" RCVD: (%ld files)",n); if (rfspec) printf(" Last: [%s]",rfspec); printf(" (%s)\r\n", success ? "OK" : "FAILED"); } } } else if (n == 0) { if (myjob == 's') printf(" SENT: (0 files) \r\n"); else if (myjob == 'r' || myjob == 'v') printf(" RCVD: (0 files) \r\n"); } } } static VOID rdebug() { if (server) debug(F111,"RESUME","server=1",justone); else debug(F111,"RESUME","server=0",justone); } /* Flags for the ENABLE and DISABLE commands */ extern int en_cpy, en_cwd, en_del, en_dir, en_fin, en_get, en_bye, en_mai, en_pri, en_hos, en_ren, en_sen, en_spa, en_set, en_typ, en_who, en_ret, en_xit, en_mkd, en_rmd; #ifndef NOSPL extern int en_asg, en_que; #endif /* NOSPL */ extern int what, lastxfer; /* Global variables declared here */ int whatru = 0; /* What are you. */ int whatru2 = 0; /* What are you, cont'd. */ /* Local variables */ static char vstate = 0; /* Saved State */ static char vcmd = 0; /* Saved Command */ static int reget = 0; /* Flag for executing REGET */ static int retrieve = 0; /* Flag for executing RETRIEVE */ static int opkt = 0; /* Send Extended GET packet */ static int x; /* General-purpose integer */ static char *s; /* General-purpose string pointer */ /* Macros - Note, BEGIN is predefined by Wart (and Lex) as "state = ", */ /* BEGIN is NOT a GOTO! */ #define TINIT if (tinit(1) < 0) return(-9) #define SERVE { TINIT; resetc(); nakstate=1; what=W_NOTHING; cmarg2=""; \ sendmode=SM_SEND; havefs=0; recursive=r_save; fnspath=p_save; BEGIN serve; } #define RESUME { rdebug(); if (!server) { wheremsg(); return(0); } else \ if (justone) { justone=0; wheremsg(); return(0); } else { SERVE; } } #ifdef GFTIMER #define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); \ fptsecs=gftimer(); quiet=x; return(success) #else #define QUIT x=quiet; quiet=1; clsif(); clsof(1); tsecs=gtimer(); quiet=x; \ return(success) #endif /* GFTIMER */ /* By late 1999, the big switch() statement generated from the following state table began choking even gcc, so here we extract the code from the larger states into static routines to reduce the size of the cases and the switch() overall. The routines follow the state table; the prototypes are here. Each of these routines simply contains the text from the corresponding case, but with return(-1) added in appropriate places; see instructions after the state table switcher. */ static int rc; /* Return code for these routines */ static int rcv_s_pkt(); /* Received an S packet */ static int rcv_firstdata(); /* Received first Data packet */ static int rcv_shortreply(); /* Short reply to a REMOTE command */ static int srv_query(); /* Server answers an query */ static int srv_copy(); /* Server executes REMOTE COPY */ static int srv_rename(); /* Server executes REMOTE RENAME */ static int srv_login(); /* Server executes REMOTE LOGIN */ static int srv_timeout(); /* Server times out */ %% /* Protocol entry points, one for each start state (sstate). The lowercase letters are internal "inputs" from the user interface. NOTE: The start state letters that appear on the left margin immediately below can NOT be used as packet types OR as G-packet subcodes. */ s { TINIT; /* Send file(s) */ if (sinit() > 0) BEGIN ssinit; else RESUME; } v { TINIT; nakstate = 1; BEGIN get; } /* Receive file(s) */ r { /* Client sends a GET command */ TINIT; vstate = get; reget = 0; retrieve = 0; opkt = 0; vcmd = 0; #ifdef PKTZEROHACK ipktack[0] = NUL; #endif /* PKTZEROHACK */ if (sipkt('I') >= 0) BEGIN ipkt; else RESUME; } h { /* Client sends a RETRIEVE command */ TINIT; vstate = get; reget = 0; retrieve = 1; opkt = 0; vcmd = 0; if (sipkt('I') >= 0) BEGIN ipkt; else RESUME; } j { /* Client sends a REGET command */ TINIT; vstate = get; reget = 1; retrieve = 0; opkt = 0; vcmd = 0; if (sipkt('I') >= 0) BEGIN ipkt; else RESUME; } o { /* Client sends Extended GET Packet */ TINIT; vstate = get; reget = oopts & GOPT_RES; retrieve = oopts & GOPT_DEL; opkt = 1; vcmd = 0; if (sipkt('I') >= 0) BEGIN ipkt; else RESUME; } c { /* Client sends a Host command */ TINIT; vstate = rgen; vcmd = 'C'; if (sipkt('I') >= 0) BEGIN ipkt; else RESUME; } k { TINIT; /* Client sends a Kermit command */ vstate = rgen; vcmd = 'K'; if (sipkt('I') >= 0) BEGIN ipkt; else RESUME; } g { /* Client sends a REMOTE command */ TINIT; vstate = rgen; vcmd = 'G'; if (sipkt('I') >= 0) BEGIN ipkt; else RESUME; } x { /* Enter server mode */ int x; x = justone; if (!ENABLED(en_del)) { /* If DELETE is disabled */ if (fncact == XYFX_B || /* undo any file collision action */ fncact == XYFX_U || /* that could result in deletion or */ fncact == XYFX_A || /* modification of existing files. */ fncact == XYFX_X) { #ifndef NOICP extern int g_fncact; g_fncact = fncact; /* Save current setting */ #endif /* NOICP */ fncact = XYFX_R; /* Change to RENAME */ debug(F101,"server DELETE disabled so fncact RENAME","",fncact); } } SERVE; /* tinit() clears justone... */ justone = x; #ifdef IKSDB if (ikdbopen) slotstate(what, "SERVER", "", ""); #endif /* IKSDB */ } a { int b1 = 0, b2 = 0; if (!data) TINIT; /* "ABEND" -- Tell other side. */ if (!bctf) { /* Block check 3 forced on all packets */ #ifndef pdp11 if (epktflg) { /* If because of E-PACKET command */ b1 = bctl; b2 = bctu; /* Save block check type */ bctl = bctu = 1; /* set it to 1 */ } #endif /* pdp11 */ } errpkt((CHAR *)"User cancelled"); /* Send the packet */ if (!bctf) { /* Block check 3 forced on all packets */ #ifndef pdp11 if (epktflg) { /* Restore the block check */ epktflg = 0; bctl = b1; bctu = b2; } } #endif /* pdp11 */ success = 0; return(0); /* Return from protocol. */ } /* Dynamic states: input-character { action } nakstate != 0 means we're in a receiving state, in which we send ACKs & NAKs. */ S { /* Receive Send-Init packet. */ rc = rcv_s_pkt(); cancel = 0; /* Reset cancellation counter */ debug(F101,"rcv_s_pkt","",rc); if (rc > -1) return(rc); /* (see below) */ } /* States in which we get replies back from commands sent to a server. */ /* Complicated because direction of protocol changes, packet number */ /* stays at zero through I-G-S sequence, and complicated even more by */ /* sliding windows buffer allocation. */ Y { /* Get ack for I-packet */ int x = 0; #ifdef PKTZEROHACK ckstrncpy(ipktack,(char *)rdatap,PKTZEROLEN); /* Save a copy of the ACK */ ipktlen = strlen(ipktack); #endif /* PKTZEROHACK */ spar(rdatap); /* Set parameters */ cancel = 0; winlo = 0; /* Set window-low back to zero */ debug(F101,"Y winlo","",winlo); urserver = 1; /* So I know I'm talking to a server */ if (vcmd) { /* If sending a generic command */ if (tinit(0) < 0) return(-9); /* Initialize many things */ x = scmd(vcmd,(CHAR *)cmarg); /* Do that */ if (x >= 0) x = 0; /* (because of O-Packet) */ debug(F101,"proto G packet scmd","",x); vcmd = 0; /* and then un-remember it. */ } else if (vstate == get) { debug(F101,"REGET sstate","",sstate); x = srinit(reget, retrieve, opkt); /* GET or REGET, etc */ } if (x < 0) { /* If command was too long */ if (!srimsg) srimsg = "Error sending string"; errpkt((CHAR *)srimsg); /* cancel both sides. */ success = 0; RESUME; } else if (x > 0) { /* Need to send more O-Packets */ BEGIN ssopkt; } else { rtimer(); /* Reset the elapsed seconds timer. */ #ifdef GFTIMER rftimer(); #endif /* GFTIMER */ winlo = 0; /* Window back to 0, again. */ debug(F101,"Y vstate","",vstate); nakstate = 1; /* Can send NAKs from here. */ BEGIN vstate; /* Switch to desired state */ } } Y { /* Got ACK to O-Packet */ debug(F100,"CPCPRO Y","",0); x = sopkt(); debug(F101,"CPCPRO Y x","",x); if (x < 0) { /* If error */ errpkt((CHAR *)srimsg); /* cancel both sides. */ success = 0; RESUME; } else if (x == 0) { /* This was the last O-Packet */ rtimer(); /* Reset the elapsed seconds timer. */ #ifdef GFTIMER rftimer(); #endif /* GFTIMER */ winlo = 0; /* Window back to 0, again. */ debug(F101,"Y winlo","",winlo); nakstate = 1; /* Can send NAKs from here. */ BEGIN vstate; /* Switch to desired state */ } debug(F101,"CPCPRO Y not changing state","",x); } E { /* Ignore Error reply to I packet */ int x = 0; winlo = 0; /* Set window-low back to zero */ debug(F101,"E winlo","",winlo); if (vcmd) { /* In case other Kermit doesn't */ if (tinit(0) < 0) return(-9); x = scmd(vcmd,(CHAR *)cmarg); /* understand I-packets. */ if (x >= 0) x = 0; /* (because of O-Packet) */ vcmd = 0; /* Otherwise act as above... */ } else if (vstate == get) x = srinit(reget, retrieve, opkt); if (x < 0) { /* If command was too long */ errpkt((CHAR *)srimsg); /* cancel both sides. */ success = 0; RESUME; } else if (x > 0) { /* Need to send more O-Packets */ BEGIN ssopkt; } else { freerpkt(winlo); /* Discard the Error packet. */ debug(F101,"E winlo","",winlo); winlo = 0; /* Back to packet 0 again. */ nakstate = 1; /* Can send NAKs from here. */ BEGIN vstate; } } Y { /* Resend of previous I-pkt ACK, same seq number */ freerpkt(0); /* Free the ACK's receive buffer */ resend(0); /* Send the GET packet again. */ } /* States in which we're being a server */ I { /* Get I-packet */ #ifndef NOSERVER spar(rdatap); /* Set parameters from it */ ack1(rpar()); /* Respond with our own parameters */ #ifdef COMMENT pktinit(); /* Reinitialize packet numbers */ #else #ifdef COMMENT /* This can't be right - it undoes the stuff we just negotiated */ x = justone; tinit(1); /* Reinitialize EVERYTHING */ justone = x; /* But this... */ #else tinit(0); /* Initialize most things */ #endif /* COMMENT */ #endif /* COMMENT */ #endif /* NOSERVER */ cancel = 0; /* Reset cancellation counter */ } R { /* GET */ #ifndef NOSERVER if (x_login && !x_logged) { errpkt((CHAR *)"Login required"); SERVE; } else if (sgetinit(0,0) < 0) { RESUME; } else { #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "GET", (char *)srvcmd); #endif /* CKSYSLOG */ BEGIN ssinit; } #endif /* NOSERVER */ } H { /* GET /DELETE (RETRIEVE) */ #ifndef NOSERVER if (x_login && !x_logged) { errpkt((CHAR *)"Login required"); RESUME; } else if (!ENABLED(en_del)) { errpkt((CHAR *)"Deleting files is disabled"); RESUME; } else if (sgetinit(0,0) < 0) { RESUME; } else { moving = 1; #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "GET /DELETE", (char *)srvcmd); #endif /* CKSYSLOG */ BEGIN ssinit; } #endif /* NOSERVER */ } V { /* GET /RECURSIVE */ #ifndef NOSERVER recursive = 1; /* Set these before sgetinit() */ if (fnspath == PATH_OFF) fnspath = PATH_REL; /* Don't worry, they will be */ if (x_login && !x_logged) { /* reset next time through. */ errpkt((CHAR *)"Login required"); RESUME; } else if (sgetinit(0,0) < 0) { RESUME; } else { #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "GET /RECURSIVE", (char *)srvcmd); #endif /* CKSYSLOG */ BEGIN ssinit; } #endif /* NOSERVER */ } W { /* GET /RECURSIVE /DELETE */ #ifndef NOSERVER recursive = 1; /* Set these before sgetinit() */ if (fnspath == PATH_OFF) fnspath = PATH_REL; /* Don't worry, they will be */ moving = 1; /* reset next time through. */ if (x_login && !x_logged) { errpkt((CHAR *)"Login required"); RESUME; } else if (!ENABLED(en_del)) { errpkt((CHAR *)"Deleting files is disabled"); RESUME; } else if (sgetinit(0,0) < 0) { RESUME; } else { #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR,1,"server", "GET /RECURSIVE /DELETE",(char *)srvcmd); #endif /* CKSYSLOG */ BEGIN ssinit; } #endif /* NOSERVER */ } J { /* GET /RECOVER (REGET) */ #ifndef NOSERVER if (x_login && !x_logged) { errpkt((CHAR *)"Login required"); SERVE; } else if (sgetinit(1,0) < 0) { RESUME; } else { #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "GET /RECOVER", (char *)srvcmd); #endif /* CKSYSLOG */ BEGIN ssinit; } #endif /* NOSERVER */ } O { /* Extended GET */ #ifndef NOSERVER if (x_login && !x_logged) { /* (any combination of options) */ errpkt((CHAR *)"Login required"); SERVE; } else if ((x = sgetinit(0,1)) < 0) { debug(F101,"CKCPRO O sgetinit fail","",x); RESUME; } else if (x == 0) { debug(F101,"CKCPRO O sgetinit done","",x); #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd); #endif /* CKSYSLOG */ BEGIN ssinit; } else { /* Otherwise stay in this state */ debug(F101,"CKCPRO O sgetinit TBC","",x); ack(); BEGIN ropkt; } #endif /* NOSERVER */ } O { #ifndef NOSERVER if (x_login && !x_logged) { /* (any combination of options) */ errpkt((CHAR *)"Login required"); SERVE; } else if ((x = sgetinit(0,1)) < 0) { debug(F101,"CKCPRO O sgetinit fail","",x); RESUME; } else if (x == 0) { debug(F101,"CKCPRO O sgetinit done","",x); #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "EXTENDED GET", (char *)srvcmd); #endif /* CKSYSLOG */ BEGIN ssinit; } else { /* Otherwise stay in this state */ debug(F101,"CKCPRO O sgetinit TBC","",x); ack(); } #endif /* NOSERVER */ } G { /* Generic server command */ #ifndef NOSERVER srvptr = srvcmd; /* Point to command buffer */ decode(rdatap,putsrv,0); /* Decode packet data into it */ putsrv(NUL); /* Insert a couple nulls */ putsrv(NUL); /* for termination */ if (srvcmd[0]) { sstate = srvcmd[0]; /* Set requested start state */ if (x_login && !x_logged && /* Login required? */ /* Login, Logout, and Help are allowed when not logged in */ sstate != 'I' && sstate != 'L' && sstate != 'H') { errpkt((CHAR *)"Login required"); SERVE; } else { nakstate = 0; /* Now I'm the sender. */ what = W_REMO; /* Doing a REMOTE command. */ #ifdef STREAMING if (!streaming) #endif /* STREAMING */ if (timint < 1) timint = chktimo(rtimo,timef); /* Switch to per-packet timer */ binary = XYFT_T; /* Switch to text mode */ BEGIN generic; /* Switch to generic command state */ } } else { errpkt((CHAR *)"Badly formed server command"); /* report error */ RESUME; /* & go back to server command wait */ } #endif /* NOSERVER */ } C { /* Receive Host command */ #ifndef NOSERVER if (x_login && !x_logged) { errpkt((CHAR *)"Login required"); SERVE; } else if (!ENABLED(en_hos)) { errpkt((CHAR *)"REMOTE HOST disabled"); RESUME; } else if (nopush) { errpkt((CHAR *)"HOST commands not available"); RESUME; } else { srvptr = srvcmd; /* Point to command buffer */ decode(rdatap,putsrv,0); /* Decode command packet into it */ putsrv(NUL); /* Null-terminate */ nakstate = 0; /* Now sending, not receiving */ binary = XYFT_T; /* Switch to text mode */ if (syscmd((char *)srvcmd,"")) { /* Try to execute the command */ what = W_REMO; /* Doing a REMOTE command. */ #ifdef STREAMING if (!streaming) #endif /* STREAMING */ if (timint < 1) timint = chktimo(rtimo,timef); /* Switch to per-packet timer */ #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE HOST", (char *)srvcmd); #endif /* CKSYSLOG */ BEGIN ssinit; /* If OK, send back its output */ } else { /* Otherwise */ errpkt((CHAR *)"Can't do system command"); /* report error */ RESUME; /* & go back to server command wait */ } } #endif /* NOSERVER */ } q { /* Interrupted or connection lost */ rc = srv_timeout(); debug(F101,"srv_timeout","",rc); if (rc > -1) return(rc); /* (see below) */ } N { /* Server got a NAK in command-wait */ #ifndef NOSERVER errpkt((CHAR *)"Did you say RECEIVE instead of GET?"); RESUME; #endif /* NOSERVER */ } . { /* Any other command in this state */ #ifndef NOSERVER if (c != ('E' - SP) && c != ('Y' - SP)) /* except E and Y packets. */ errpkt((CHAR *)"Unimplemented server function"); /* If we answer an E with an E, we get an infinite loop. */ /* A Y (ACK) can show up here if we sent back a short-form reply to */ /* a G packet and it was echoed. ACKs can be safely ignored here. */ RESUME; /* Go back to server command wait. */ #endif /* NOSERVER */ } I { /* Login/Out */ rc = srv_login(); debug(F101,"I srv_login","",rc); if (rc > -1) return(rc); /* (see below) */ } C { /* Got REMOTE CD command */ #ifndef NOSERVER #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE CD", (char *)srvcmd); #endif /* CKSYSLOG */ if (!ENABLED(en_cwd)) { errpkt((CHAR *)"REMOTE CD disabled"); RESUME; } else { char * p = NULL; x = cwd((char *)(srvcmd+1)); /* Try to change directory */ #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE CD", (char *)(srvcmd+2), ""); #endif /* IKSDB */ if (!x) { /* Failed */ errpkt((CHAR *)"Can't change directory"); RESUME; /* Back to server command wait */ } else if (x == 2) { /* User wants message */ if (!ENABLED(en_typ)) { /* Messages (REMOTE TYPE) disabled? */ errpkt((CHAR *)"REMOTE TYPE disabled"); RESUME; } else { /* TYPE is enabled */ int i; for (i = 0; i < 8; i++) { if (zchki(cdmsgfile[i]) > -1) { break; } } binary = XYFT_T; /* Use text mode for this. */ if (i < 8 && sndtype(cdmsgfile[i])) { /* Have readme file? */ BEGIN ssinit; /* OK */ } else { /* not OK */ p = zgtdir(); if (!p) p = ""; success = (*p) ? 1 : 0; ack1((CHAR *)p); /* ACK with new directory name */ success = 1; RESUME; /* wait for next server command */ } } } else { /* User doesn't want message */ p = zgtdir(); if (!p) p = ""; success = (*p) ? 1 : 0; ack1((CHAR *)p); success = 1; RESUME; /* Wait for next server command */ } } #endif /* NOSERVER */ } u { /* Got REMOTE CDUP command */ #ifndef NOSERVER #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE CDUP", (char *)srvcmd); #endif /* CKSYSLOG */ if (!ENABLED(en_cwd)) { errpkt((CHAR *)"REMOTE CD disabled"); RESUME; } else { char * p = NULL; char * s = NULL; #ifdef VMS s = "[-]"; #else #ifdef datageneral s = "^"; #else s = ".."; #endif /* datageneral */ #endif /* VMS */ x = cwd(s); /* Try to change directory */ #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE CD", (char *)(srvcmd+2), ""); #endif /* IKSDB */ if (!x) { /* Failed */ errpkt((CHAR *)"Can't change directory"); RESUME; /* Back to server command wait */ } else if (x == 2) { /* User wants message */ if (!ENABLED(en_typ)) { /* Messages (REMOTE TYPE) disabled? */ errpkt((CHAR *)"REMOTE TYPE disabled"); RESUME; } else { /* TYPE is enabled */ int i; for (i = 0; i < 8; i++) { if (zchki(cdmsgfile[i]) > -1) { break; } } binary = XYFT_T; /* Use text mode for this. */ if (i < 8 && sndtype(cdmsgfile[i])) { /* Have readme file? */ BEGIN ssinit; /* OK */ } else { /* not OK */ p = zgtdir(); if (!p) p = ""; success = (*p) ? 1 : 0; ack1((CHAR *)p); /* ACK with new directory name */ success = 1; RESUME; /* wait for next server command */ } } } else { /* User doesn't want message */ p = zgtdir(); if (!p) p = ""; success = (*p) ? 1 : 0; ack1((CHAR *)p); success = 1; RESUME; /* Wait for next server command */ } } #endif /* NOSERVER */ } A { /* Got REMOTE PWD command */ #ifndef NOSERVER #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE PWD", NULL); #endif /* CKSYSLOG */ if (!ENABLED(en_cwd)) { errpkt((CHAR *)"REMOTE CD disabled"); RESUME; } else { if (encstr((CHAR *)zgtdir()) > -1) { /* Encode current directory */ ack1(data); /* If it fits, send it back in ACK */ success = 1; } else { /* Failed */ ack(); /* Send empty ACK */ success = 0; /* and indicate failure locally */ } RESUME; /* Back to server command wait */ } #endif /* NOSERVER */ } D { /* REMOTE DIRECTORY command */ #ifndef NOSERVER char *n2; #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE DIRECTORY", (char *)srvcmd); #endif /* CKSYSLOG */ if (!ENABLED(en_dir)) { /* If DIR is disabled, */ errpkt((CHAR *)"REMOTE DIRECTORY disabled"); /* refuse. */ RESUME; } else { /* DIR is enabled. */ #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE DIR", (char *)(srvcmd+2), ""); #endif /* IKSDB */ if (!ENABLED(en_cwd)) { /* But CWD is disabled */ zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */ if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */ errpkt((CHAR *)"Access denied"); RESUME; /* Remember, this is not a goto! */ } } if (state == generic) { /* It's OK to go ahead. */ #ifdef COMMENT n2 = (*(srvcmd+2)) ? DIRCMD : DIRCM2; if (syscmd(n2,(char *)(srvcmd+2))) /* If it can be done */ #else int x; if ((x = snddir((char*)(srvcmd+2))) > 0) #endif /* COMMENT */ { BEGIN ssinit; /* send the results back; */ } else { /* otherwise */ if (x < 0) errpkt((CHAR *)"No files match"); else errpkt((CHAR *)"Can't list directory"); RESUME; /* return to server command wait */ } } } #endif /* NOSERVER */ } E { /* REMOTE DELETE (Erase) */ #ifndef NOSERVER char *n2; #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE DELETE", (char *)srvcmd); #endif /* CKSYSLOG */ if (!ENABLED(en_del)) { errpkt((CHAR *)"REMOTE DELETE disabled"); RESUME; } else { /* DELETE is enabled */ #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE DELETE", (char *)(srvcmd+2), ""); #endif /* IKSDB */ if (!ENABLED(en_cwd)) { /* but CWD is disabled */ zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */ if (strcmp((char *)(srvcmd+2),n2)) { /* so refuse. */ errpkt((CHAR *)"Access denied"); RESUME; /* Remember, this is not a goto! */ } } else if (isdir((char *)(srvcmd+2))) { /* A directory name? */ errpkt((CHAR *)"It's a directory"); RESUME; } if (state == generic) { /* It's OK to go ahead. */ int x; if ((x = snddel((char*)(srvcmd+2))) > 0) { BEGIN ssinit; /* If OK send results back */ } else { /* otherwise */ if (x < 0) errpkt((CHAR *)"File not found"); /* report failure */ else errpkt((CHAR *)"DELETE failed"); RESUME; /* & return to server command wait */ } } } #endif /* NOSERVER */ } F { /* FINISH */ #ifndef NOSERVER #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "FINISH", NULL); #endif /* CKSYSLOG */ #ifdef IKSDB if (ikdbopen) slotstate(what,"SERVER FINISH", "", ""); #endif /* IKSDB */ if (!ENABLED(en_fin)) { errpkt((CHAR *)"FINISH disabled"); RESUME; } else { ack(); /* Acknowledge */ xxscreen(SCR_TC,0,0L,""); /* Display */ success = 1; return(0); /* Done */ } #endif /* NOSERVER */ } X { /* EXIT */ #ifndef NOSERVER #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE EXIT", NULL); #endif /* CKSYSLOG */ #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE EXIT", "", ""); #endif /* IKSDB */ if (!ENABLED(en_xit)) { errpkt((CHAR *)"EXIT disabled"); RESUME; } else { ack(); /* Acknowledge */ xxscreen(SCR_TC,0,0L,""); /* Display */ doexit(GOOD_EXIT,xitsta); } #endif /* NOSERVER */ } L { /* BYE (Logout) */ #ifndef NOSERVER #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "BYE", NULL); #endif /* CKSYSLOG */ #ifdef IKSDB if (ikdbopen) slotstate(what,"SERVER BYE", "", ""); #endif /* IKSDB */ if (!ENABLED(en_bye)) { errpkt((CHAR *)"BYE disabled"); RESUME; } else { ack(); /* Acknowledge */ success = 1; msleep(750); /* Give the ACK time to get out */ if (local) ttres(); /* Reset the terminal */ xxscreen(SCR_TC,0,0L,""); /* Display */ doclean(1); /* Clean up files, etc */ #ifdef DEBUG debug(F100,"C-Kermit BYE - Logging out...","",0); zclose(ZDFILE); #endif /* DEBUG */ #ifdef IKSD #ifdef CK_LOGIN if (inserver) ckxlogout(); else #endif /* CK_LOGIN */ #endif /* IKSD */ #ifdef TCPSOCKET #ifndef NOLISTEN if (network && tcpsrfd > 0 && !inserver) doexit(GOOD_EXIT,xitsta); else #endif /* NOLISTEN */ #endif /* TCPSOCKET */ return(zkself()); /* Try to log self out */ } #endif /* NOSERVER */ } H { /* REMOTE HELP */ #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE HELP", NULL); #endif /* CKSYSLOG */ #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE HELP", "", ""); #endif /* IKSDB */ #ifndef NOSERVER if (sndhlp()) { BEGIN ssinit; /* try to send it */ } else { /* If not ok, */ errpkt((CHAR *)"Can't send help"); /* send error message instead */ RESUME; /* and return to server command wait */ } #endif /* NOSERVER */ } Q { /* REMOTE STATUS */ #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE STATUS", NULL); #endif /* CKSYSLOG */ #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE STATUS", "", ""); #endif /* IKSDB */ #ifndef NOSERVER if (sndstatus()) { BEGIN ssinit; /* try to send it */ } else { /* If not ok, */ errpkt((CHAR *)"Can't send status"); /* send error message instead */ RESUME; /* and return to server command wait */ } #endif /* NOSERVER */ } R { /* REMOTE RENAME */ rc = srv_rename(); debug(F101,"srv_rename","",rc); if (rc > -1) return(rc); /* (see below) */ } K { /* REMOTE COPY */ rc = srv_copy(); debug(F101,"srv_copy","",rc); if (rc > -1) return(rc); /* (see below) */ } S { /* REMOTE SET */ #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE SET", (char *)srvcmd); #endif /* CKSYSLOG */ #ifndef NOSERVER #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE SET", (char *)(srvcmd+1), ""); #endif /* IKSDB */ if (!ENABLED(en_set)) { errpkt((CHAR *)"REMOTE SET disabled"); RESUME; } else { if (remset((char *)(srvcmd+1))) { /* Try to do what they ask */ success = 1; ack(); /* If OK, then acknowledge */ } else /* Otherwise */ errpkt((CHAR *)"Unknown REMOTE SET parameter"); /* give error msg */ RESUME; /* Return to server command wait */ } #endif /* NOSERVER */ } T { /* REMOTE TYPE */ #ifndef NOSERVER char *n2; #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE TYPE", (char *)srvcmd); #endif /* CKSYSLOG */ if (!ENABLED(en_typ)) { errpkt((CHAR *)"REMOTE TYPE disabled"); RESUME; } else { #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE TYPE", (char *)(srvcmd+2), ""); #endif /* IKSDB */ if (!ENABLED(en_cwd)) { /* If CWD disabled */ zstrip((char *)(srvcmd+2),&n2); /* and they included a pathname, */ if (strcmp((char *)(srvcmd+2),n2)) { /* refuse. */ errpkt((CHAR *)"Access denied"); RESUME; /* Remember, this is not a goto! */ } } if (state == generic) { /* It's OK to go ahead. */ binary = XYFT_T; /* Use text mode for this. */ if ( /* (RESUME didn't change state) */ #ifdef COMMENT syscmd(TYPCMD,(char *)(srvcmd+2)) /* Old way */ #else sndtype((char *)(srvcmd+2)) /* New way */ #endif /* COMMENT */ ) BEGIN ssinit; /* OK */ else { /* not OK */ errpkt((CHAR *)"Can't type file"); /* give error message */ RESUME; /* wait for next server command */ } } } #endif /* NOSERVER */ } m { /* REMOTE MKDIR */ #ifndef NOSERVER #ifdef CK_MKDIR #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE MKDIR", (char *)srvcmd); #endif /* CKSYSLOG */ #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE MKDIR", (char *)(srvcmd+2), ""); #endif /* IKSDB */ if (!ENABLED(en_mkd)) { errpkt((CHAR *)"REMOTE MKDIR disabled"); RESUME; } else if (!ENABLED(en_cwd)) { /* If CWD disabled */ errpkt((CHAR *)"Directory access restricted"); RESUME; /* Remember, this is not a goto! */ } if (state == generic) { /* OK to go ahead. */ char *p = NULL; x = ckmkdir(0,(char *)(srvcmd+2),&p,0,1); /* Make the directory */ if (!p) p = ""; if (x > -1) { encstr((CHAR *)p); /* OK - encode the name */ ack1(data); /* Send short-form response */ success = 1; RESUME; } else { /* not OK */ if (!*p) p = "Directory creation failure"; errpkt((CHAR *)p); /* give error message */ RESUME; /* Wait for next server command */ } } #else errpkt((CHAR *)"REMOTE MKDIR not available"); RESUME; #endif /* CK_MKDIR */ #endif /* NOSERVER */ } d { /* REMOTE RMDIR */ #ifndef NOSERVER #ifdef CK_MKDIR #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE RMDIR", (char *)srvcmd); #endif /* CKSYSLOG */ #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE RMDIR", (char *)(srvcmd+2), ""); #endif /* IKSDB */ if (!ENABLED(en_rmd)) { errpkt((CHAR *)"REMOTE RMDIR disabled"); RESUME; } else if (!ENABLED(en_cwd)) { /* If CWD disabled */ errpkt((CHAR *)"Directory access restricted"); RESUME; /* Remember, this is not a goto! */ } if (state == generic) { /* OK to go ahead. */ char *p = NULL; x = ckmkdir(1,(char *)(srvcmd+2),&p,0,1); if (!p) p = ""; if (x > -1) { encstr((CHAR *)p); /* OK - encode the name */ ack1(data); /* Send short-form response */ success = 1; RESUME; } else { /* not OK */ if (!*p) p = "Directory removal failure"; errpkt((CHAR *)p); /* give error message */ RESUME; /* Wait for next server command */ } } #else errpkt((CHAR *)"REMOTE RMDIR not available"); RESUME; #endif /* CK_MKDIR */ #endif /* NOSERVER */ } U { /* REMOTE SPACE */ #ifndef NOSERVER #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE SPACE", (char *)srvcmd); #endif /* CKSYSLOG */ if (!ENABLED(en_spa)) { errpkt((CHAR *)"REMOTE SPACE disabled"); RESUME; } else { x = srvcmd[1]; /* Get area to check */ x = ((x == NUL) || (x == SP) #ifdef OS2 || (x == '!') || (srvcmd[3] == ':') #endif /* OS2 */ ); #ifdef IKSDB if (ikdbopen) slotstate(what, "REMOTE SPACE", (x ? "" : (char *)srvcmd), "" ); #endif /* IKSDB */ if (!x && !ENABLED(en_cwd)) { /* CWD disabled */ errpkt((CHAR *)"Access denied"); /* and non-default area given, */ RESUME; /* refuse. */ } else { #ifdef OS2 _PROTOTYP(int sndspace,(int)); if (sndspace(x ? toupper(srvcmd[2]) : 0)) { BEGIN ssinit; /* send the report. */ } else { /* If not ok, */ errpkt((CHAR *)"Can't send space"); /* send error message */ RESUME; /* and return to server command wait */ } #else if (nopush) x = 0; else x = (x ? syscmd(SPACMD,"") : syscmd(SPACM2,(char *)(srvcmd+2))); if (x) { /* If we got the info */ BEGIN ssinit; /* send it */ } else { /* otherwise */ errpkt((CHAR *)"Can't check space"); /* send error message */ RESUME; /* and await next server command */ } #endif /* OS2 */ } } #endif /* NOSERVER */ } W { /* REMOTE WHO */ #ifndef NOSERVER #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE WHO", (char *)srvcmd); #endif /* CKSYSLOG */ #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE WHO", (char *)(srvcmd+2), ""); #endif /* IKSDB */ if (!ENABLED(en_who)) { errpkt((CHAR *)"REMOTE WHO disabled"); RESUME; } else { #ifdef OS2 _PROTOTYP(int sndwho,(char *)); if (sndwho((char *)(srvcmd+2))) { BEGIN ssinit; /* try to send it */ } else { /* If not ok, */ errpkt((CHAR *)"Can't do who command"); /* send error msg */ RESUME; /* and return to server command wait */ } #else if (syscmd(WHOCMD,(char *)(srvcmd+2))) { BEGIN ssinit; } else { errpkt((CHAR *)"Can't do who command"); RESUME; } #endif /* OS2 */ } #endif /* NOSERVER */ } V { /* Variable query or set */ rc = srv_query(); debug(F101,"srv_query","",rc); if (rc > -1) return(rc); } M { /* REMOTE MESSAGE command */ #ifndef NOSERVER debug(F110,"RMSG",(char *)srvcmd+2,0); xxscreen(SCR_MS,0,0L,(char *)(srvcmd+2)); ack(); RESUME; #endif /* NOSERVER */ } q { /* Interrupted or connection lost */ #ifndef NOSERVER if (fatalio) { /* Connection lost */ #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL); #endif /* CKSYSLOG */ success = 0; xitsta |= (what & W_KERMIT); QUIT; } else if (interrupted) { if (!ENABLED(en_fin)) { /* Ctrl-C typed */ errpkt((CHAR *)"QUIT disabled"); RESUME; } else { #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL); #endif /* CKSYSLOG */ success = 0; xitsta |= (what & W_KERMIT); QUIT; } } else { /* Shouldn't happen */ debug(F100,"SERVER (generic) GOT UNEXPECTED 'q'","",0); QUIT; } #endif /* NOSERVER */ } . { /* Anything else in this state... */ #ifndef NOSERVER errpkt((CHAR *)"Unimplemented REMOTE command"); /* Complain */ RESUME; /* and return to server command wait */ #endif /* NOSERVER */ } q { /* Sent BYE and connection broken */ if (bye_active && ttchk() < 0) { msleep(500); bye_active = 0; ttclos(0); /* Close our end of the connection */ clsof(0); return(success = 1); } else { /* Other generic command */ return(success = 0); /* or connection not broken */ } } Y { /* Short-Form reply */ rc = rcv_shortreply(); debug(F101,"Y rcv_shortreply","",rc); if (rc > -1) return(rc); } F { /* File header */ /* char *n2; */ extern int rsn; debug(F101,"F winlo 1","",winlo); xflg = 0; /* Not screen data */ if (!czseen) cancel = 0; /* Reset cancellation counter */ #ifdef CALIBRATE if (dest == DEST_N) calibrate = 1; #endif /* CALIBRATE */ if (!rcvfil(filnam)) { /* Figure out local filename */ errpkt((CHAR *)rf_err); /* Trouble */ RESUME; } else { /* Real file, OK to receive */ char * fnp; debug(F111,"F winlo 2",fspec,winlo); if (filcnt == 1) /* rcvfil set this to 1 for 1st file */ crc16 = 0L; /* Clear file CRC */ fnp = fspec; /* This is the full path */ if (server && !ENABLED(en_cwd) || /* if DISABLE CD */ !fackpath /* or F-ACK-PATH OFF */ ) { zstrip(fspec,&fnp); /* don't send back full path */ #ifdef UNIX /* fdc, November 2012. Unix pathnames are getting longer, causing the full pathname that remote C-Kermit, when receiving a file, sends back to a local Kermit (e.g. K95) to overflow the file transfer display, so the user can't see which file is being transferred. Here we try to shorten the pathname that is sent from the remote receiver back to the local sender. */ } else if (!local) { /* Try to shorten by using '~' */ extern char homedirpath[]; /* Filled in at startup time */ char *p; int len = 0, ok = 0; /* fdc, March 2013: If the file is being received to Kermit's current directory, don't send the current-directory path. */ p = zgtdir(); /* Get current directory */ if (p) if (*p) { /* If we got one... */ len = strlen(p); /* and it matches the filespec path */ if (ckindex(p,fspec,0,0,1) == 1 && len > 3) { fnp = fspec + len; ok = 1; } } if (!ok) { /* Nov 2012: If not the current directory then if it is being sent from somewhere in the user's home directory tree, it can be shortened using ~ notation. */ p = homedirpath; /* Get home directory path */ if (p) if (*p) { /* If we got one... */ len = strlen(p); /* and it matches the filespec path */ if (ckindex(p,fspec,0,0,1) == 1 && len > 3) { int i = 0; char * s; fspec[i++] = '~'; /* ...replace it with "~/" */ fspec[i++] = '/'; s = (char *)fspec + len; while (*s) { fspec[i++] = *s++; } fspec[i] = '\0'; fnp = fspec; } } } #endif /* UNIX */ } encstr((CHAR *)fnp); if (fackbug) ack(); else ack1(data); /* Send it back in ACK */ initattr(&iattr); /* Clear file attribute structure */ streamon(); if (window(wslotn) < 0) { /* Allocate negotiated window slots */ errpkt((CHAR *)"Can't open window"); RESUME; } #ifdef IKSDB if (ikdbopen) slotstate(what, server ? "SERVER" : "", "RECEIVE", fspec ); #endif /* IKSDB */ BEGIN rattr; /* Now expect Attribute packets */ } } X { /* X-packet instead of file header */ xflg = 1; /* Screen data */ if (!czseen) cancel = 0; /* Reset cancellation counter */ ack(); /* Acknowledge the X-packet */ initattr(&iattr); /* Initialize attribute structure */ streamon(); if (window(wslotn) < 0) { /* allocate negotiated window slots */ errpkt((CHAR *)"Can't open window"); RESUME; } #ifndef NOSPL if (query) { /* If this is the response to */ qbufp = querybuf; /* a query that we sent, initialize */ qbufn = 0; /* the response buffer */ querybuf[0] = NUL; } #endif /* NOSPL */ what = W_REMO; /* we're doing a REMOTE command */ #ifdef IKSDB if (ikdbopen) slotstate(what, server ? "SERVER" : "", "RECEIVE", fspec ); #endif /* IKSDB */ BEGIN rattr; /* Expect Attribute packets */ } A { /* Attribute packet */ if (gattr(rdatap,&iattr) == 0) { /* Read into attribute structure */ #ifdef CK_RESEND ack1((CHAR *)iattr.reply.val); /* Reply with data */ #else ack(); /* If OK, acknowledge */ #endif /* CK_RESEND */ } else { /* Otherwise */ extern CK_OFF_T fsize; char *r; r = getreason(iattr.reply.val); ack1((CHAR *)iattr.reply.val); /* refuse to accept the file */ xxscreen(SCR_ST,ST_REFU,0L,r); /* reason */ #ifdef TLOG if (tralog && !tlogfmt) doxlog(what,filnam,fsize,binary,1,r); #endif /* TLOG */ } } D { /* First data packet */ debug(F100," D firstdata","",0); rc = rcv_firstdata(); debug(F101,"rcv_firstdata rc","",rc); if (rc > -1) return(rc); /* (see below) */ } B { /* EOT, no more files */ ack(); /* Acknowledge the B packet */ reot(); /* Do EOT things */ #ifdef CK_TMPDIR /* If we were cd'd temporarily to another device or directory ... */ if (f_tmpdir) { int x; x = zchdir((char *) savdir); /* ... restore previous directory */ f_tmpdir = 0; /* and remember we did it. */ debug(F111,"ckcpro.w B tmpdir restoring",savdir,x); } #endif /* CK_TMPDIR */ RESUME; /* and quit */ } D { /* Got Data packet */ debug(F101,"D cxseen","",cxseen); debug(F101,"D czseen","",czseen); if (cxseen || czseen || discard) { /* If file or group interruption */ CHAR * msg; msg = czseen ? (CHAR *)"Z" : (CHAR *)"X"; #ifdef STREAMING if (streaming) { /* Need to cancel */ debug(F111,"D streaming cancel",msg,cancel); if (cancel++ == 0) { /* Only do this once */ ack1(msg); /* Put "X" or "Z" in ACK */ } else if (czseen) { errpkt((CHAR *)"User canceled"); RESUME; } else { fastack(); } } else #endif /* STREAMING */ ack1(msg); } else { /* No interruption */ int rc, qf; #ifndef NOSPL qf = query; #else qf = 0; #endif /* NOSPL */ #ifdef CKTUNING rc = (binary && !parity) ? bdecode(rdatap,putfil): decode(rdatap, qf ? puttrm : putfil, 1); #else rc = decode(rdatap, qf ? puttrm : putfil, 1); #endif /* CKTUNING */ if (rc < 0) { discard = (keep == 0 || (keep == SET_AUTO && binary != XYFT_T)); errpkt((CHAR *)"Error writing data"); /* If failure, */ RESUME; } else /* Data written OK, send ACK */ #ifdef STREAMING if (streaming) fastack(); else #endif /* STREAMING */ ack(); } } Z { /* EOF immediately after A-Packet. */ rf_err = "Can't create file"; timint = s_timint; if (discard) { /* Discarding a real file... */ x = 1; } else if (xflg) { /* If screen data */ if (remfile) { /* redirected to file */ if (rempipe) /* or pipe */ x = openc(ZOFILE,remdest); /* Pipe: start command */ else x = opena(remdest,&iattr); /* File: open with attributes */ } else { /* otherwise */ x = opent(&iattr); /* "open" the screen */ } #ifdef CALIBRATE } else if (calibrate) { /* If calibration run */ x = ckopenx(&iattr); /* do this */ #endif /* CALIBRATE */ } else { /* otherwise */ x = opena(filnam,&iattr); /* open the file, with attributes */ if (x == -17) { /* REGET skipped because same size */ discard = 1; rejection = 1; } } if (!x || reof(filnam, &iattr) < 0) { /* Close output file */ errpkt((CHAR *) rf_err); /* If problem, send error msg */ RESUME; /* and quit */ } else { /* otherwise */ if (x == -17) xxscreen(SCR_ST,ST_SKIP,SKP_RES,""); ack(); /* acknowledge the EOF packet */ BEGIN rfile; /* and await another file */ } } q { /* Ctrl-C or connection loss. */ timint = s_timint; window(1); /* Set window size back to 1... */ cxseen = 1; x = clsof(1); /* Close file */ return(success = 0); /* Failed */ } Z { /* End Of File (EOF) Packet */ /* wslots = 1; */ /* (don't set) Window size back to 1 */ #ifndef COHERENT /* Coherent compiler blows up on this switch() statement. */ x = reof(filnam, &iattr); /* Handle the EOF packet */ switch (x) { /* reof() sets the success flag */ case -5: /* Handle problems */ errpkt((CHAR *)"RENAME failed"); /* Fatal */ RESUME; break; case -4: errpkt((CHAR *)"MOVE failed"); /* Fatal */ RESUME; break; case -3: /* If problem, send error msg */ errpkt((CHAR *)"Can't print file"); /* Fatal */ RESUME; break; case -2: errpkt((CHAR *)"Can't mail file"); /* Fatal */ RESUME; break; case 2: /* Not fatal */ case 3: xxscreen(SCR_EM,0,0L,"Receiver can't delete temp file"); RESUME; break; default: if (x < 0) { /* Fatal */ errpkt((CHAR *)"Can't close file"); RESUME; } else { /* Success */ #ifndef NOSPL if (query) /* Query reponses generally */ conoll(""); /* don't have line terminators */ #endif /* NOSPL */ if (czseen) { /* Batch canceled? */ if (cancel++ == 0) { /* If we haven't tried this yet */ ack1((CHAR *)"Z"); /* Try it once */ } else { /* Otherwise */ errpkt((CHAR *)"User canceled"); /* quite with Error */ RESUME; } } else ack(); /* Acknowledge the EOF packet */ BEGIN rfile; /* and await another file */ } } #else if (reof(filnam, &iattr) < 0) { /* Close the file */ errpkt((CHAR *)"Error at end of file"); RESUME; } else { /* reof() sets success flag */ ack(); BEGIN rfile; } #endif /* COHERENT */ } Y { /* ACK for Send-Init */ spar(rdatap); /* set parameters from it */ cancel = 0; if (bctf) { bctu = 3; bctl = 3; } else { bctu = bctr; /* switch to agreed-upon block check */ bctl = (bctu == 4) ? 2 : bctu; /* Set block-check length */ } #ifdef CK_RESEND if ((sendmode == SM_RESEND) && (!atcapu || !rscapu)) { /* RESEND */ errpkt((CHAR *) "RESEND capabilities not negotiated"); RESUME; } else { #endif /* CK_RESEND */ what = W_SEND; /* Remember we're sending */ lastxfer = W_SEND; x = sfile(xflg); /* Send X or F header packet */ cancel = 0; /* Reset cancellation counter */ if (x) { /* If the packet was sent OK */ if (!xflg && filcnt == 1) /* and it's a real file */ crc16 = 0L; /* Clear the file CRC */ resetc(); /* reset per-transaction counters */ rtimer(); /* reset timers */ #ifdef GFTIMER rftimer(); #endif /* GFTIMER */ streamon(); /* turn on streaming */ #ifdef IKSDB if (ikdbopen) slotstate(what, (server ? "SERVER" : ""), "SEND", filnam ); #endif /* IKSDB */ BEGIN ssfile; /* and switch to receive-file state */ } else { /* otherwise send error msg & quit */ s = xflg ? "Can't execute command" : (char *)epktmsg; if (!*s) s = "Can't open file"; errpkt((CHAR *)s); RESUME; } #ifdef CK_RESEND } #endif /* CK_RESEND */ } /* These states are necessary to handle the case where we get a server command packet (R, G, or C) reply with an S packet, but the client retransmits the command packet. The input() function doesn't catch this because the packet number is still zero. */ R { /* R packet was retransmitted. */ xsinit(); /* Resend packet 0 */ } G { /* Same deal if G packet comes again */ xsinit(); } /* should probably add cases for O, W, V, H, J, ... */ C { /* Same deal if C packet comes again */ xsinit(); } Y { /* ACK for F or X packet */ srvptr = srvcmd; /* Point to string buffer */ decode(rdatap,putsrv,0); /* Decode data field, if any */ putsrv(NUL); /* Terminate with null */ ffc = 0L; /* Reset file byte counter */ debug(F101,"Y cxseen","",cxseen); if (*srvcmd) { /* If remote name was recorded */ if (sendmode != SM_RESEND) { if (fdispla == XYFD_C || fdispla == XYFD_S) xxscreen(SCR_AN,0,0L,(char *)srvcmd); tlog(F110," remote name:",(char *) srvcmd,0L); makestr(&psrfspec,(char *)srvcmd); } } if (cxseen||czseen) { /* Interrupted? */ debug(F101,"Y canceling","",0); x = clsif(); /* Close input file */ sxeof(1); /* Send EOF(D) */ BEGIN sseof; /* and switch to EOF state. */ } else if (atcapu) { /* If attributes are to be used */ if (sattr(xflg | stdinf, 1) < 0) { /* send them */ errpkt((CHAR *)"Can't send attributes"); /* if problem, say so */ RESUME; /* and quit */ } else BEGIN ssattr; /* if ok, switch to attribute state */ } else { /* Attributes not negotiated */ if (window(wslotn) < 0) { /* Open window */ errpkt((CHAR *)"Can't open window"); RESUME; } else if ((x = sdata()) == -2) { /* Send first data packet data */ window(1); /* Connection lost, reset window */ x = clsif(); /* Close input file */ return(success = 0); /* Return failure */ } else if (x == -9) { /* User interrupted */ errpkt((CHAR *)"User cancelled"); /* Send Error packet */ window(1); /* Set window size back to 1... */ timint = s_timint; /* Restore timeout */ return(success = 0); /* Failed */ } else if (x < 0) { /* EOF (empty file) or interrupted */ window(1); /* put window size back to 1, */ debug(F101,"Y cxseen","",cxseen); x = clsif(); /* If not ok, close input file, */ if (x < 0) /* treating failure as interruption */ cxseen = 1; /* Send EOF packet */ seof(cxseen||czseen); BEGIN sseof; /* and switch to EOF state. */ } else { /* First data sent OK */ BEGIN ssdata; /* All ok, switch to send-data state */ } } } Y { /* Got ACK to A packet */ ffc = 0L; /* Reset file byte counter */ debug(F101,"Y cxseen","",cxseen); if (cxseen||czseen) { /* Interrupted? */ debug(F101,"Y canceling","",0); x = clsif(); /* Close input file */ sxeof(1); /* Send EOF(D) */ BEGIN sseof; /* and switch to EOF state. */ } else if (rsattr(rdatap) < 0) { /* Was the file refused? */ discard = 1; /* Set the discard flag */ clsif(); /* Close the file */ sxeof(1); /* send EOF with "discard" code */ BEGIN sseof; /* switch to send-EOF state */ } else if ((x = sattr(xflg | stdinf, 0)) < 0) { /* Send more? */ errpkt((CHAR *)"Can't send attributes"); /* Trouble... */ RESUME; } else if (x == 0) { /* No more to send so now the data */ if (window(wslotn) < 0) { /* Allocate negotiated window slots */ errpkt((CHAR *)"Can't open window"); RESUME; } if ((x = sdata()) == -2) { /* File accepted, send first data */ window(1); /* Connection broken */ x = clsif(); /* Close file */ return(success = 0); /* Return failure */ } else if (x == -9) { /* User interrupted */ errpkt((CHAR *)"User cancelled"); /* Send Error packet */ window(1); /* Set window size back to 1... */ timint = s_timint; /* Restore timeout */ return(success = 0); /* Failed */ } else if (x < 0) { /* If data was not sent */ window(1); /* put window size back to 1, */ debug(F101,"Y cxseen","",cxseen); if (clsif() < 0) /* Close input file */ cxseen = 1; /* Send EOF packet */ seof(cxseen||czseen); BEGIN sseof; /* and switch to EOF state. */ } else { BEGIN ssdata; /* All ok, switch to send-data state */ } } } q { /* Ctrl-C or connection loss. */ window(1); /* Set window size back to 1... */ cxseen = 1; /* To indicate interruption */ x = clsif(); /* Close file */ return(success = 0); /* Failed */ } Y { /* Got ACK to Data packet */ canned(rdatap); /* Check if file transfer cancelled */ debug(F111,"Y cxseen",rdatap,cxseen); debug(F111,"Y czseen",rdatap,czseen); if ((x = sdata()) == -2) { /* Try to send next data */ window(1); /* Connection lost, reset window */ x = clsif(); /* Close file */ return(success = 0); /* Failed */ } else if (x == -9) { /* User interrupted */ errpkt((CHAR *)"User cancelled"); /* Send Error packet */ window(1); /* Set window size back to 1... */ timint = s_timint; /* Restore original timeout */ return(success = 0); /* Failed */ } else if (x < 0) { /* EOF - finished sending data */ debug(F101,"Y cxseen","",cxseen); window(1); /* Set window size back to 1... */ if (clsif() < 0) /* Close input file */ cxseen = 1; /* Send EOF packet */ debug(F101,"Y CALLING SEOF()","",cxseen); seof(cxseen||czseen); BEGIN sseof; /* and enter send-eof state */ } /* NOTE: If x == 0 it means we're draining: see sdata()! */ } Y { /* Got ACK to EOF */ int g, xdiscard; canned(rdatap); /* Check if file transfer cancelled */ debug(F111,"Y cxseen",rdatap,cxseen); debug(F111,"Y czseen",rdatap,czseen); debug(F111,"Y discard",rdatap,discard); xdiscard = discard; discard = 0; success = (cxseen == 0 && czseen == 0); /* Transfer status... */ debug(F101,"Y success","",success); if (success && rejection > 0) /* If rejected, succeed if */ if (rejection != '#' && /* reason was date */ rejection != 1 && rejection != '?') /* or name; */ success = 0; /* fail otherwise. */ cxseen = 0; /* This goes back to zero. */ if (success) { /* Only if transfer succeeded... */ xxscreen(SCR_ST,ST_OK,0L,""); if (!xdiscard) { makestr(&sfspec,psfspec); /* Record filenames for WHERE */ makestr(&srfspec,psrfspec); } if (moving) { /* If MOVE'ing */ x = zdelet(filnam); /* Try to delete the source file */ #ifdef TLOG if (tralog) { if (x > -1) { tlog(F110," deleted",filnam,0); } else { tlog(F110," delete failed:",ck_errstr(),0); } } #endif /* TLOG */ } else if (snd_move) { /* Or move it */ int x; x = zrename(filnam,snd_move); #ifdef TLOG if (tralog) { if (x > -1) { tlog(F110," moved to ",snd_move,0); } else { tlog(F110," move failed:",ck_errstr(),0); } } #endif /* TLOG */ } else if (snd_rename) { /* Or rename it */ char *s = snd_rename; /* Renaming string */ #ifndef NOSPL int y; /* Pass it thru the evaluator */ extern int cmd_quoting; /* for \v(filename) */ if (cmd_quoting) { /* But only if cmd_quoting is on */ y = MAXRP; s = (char *)srvcmd; zzstring(snd_rename,&s,&y); s = (char *)srvcmd; } #endif /* NOSPL */ if (s) if (*s) { int x; x = zrename(filnam,s); #ifdef TLOG if (tralog) { if (x > -1) { tlog(F110," renamed to",s,0); } else { tlog(F110," rename failed:",ck_errstr(),0); } } #endif /* TLOG */ #ifdef COMMENT *s = NUL; #endif /* COMMENT */ } } } if (czseen) { /* Check group interruption flag */ g = 0; /* No more files if interrupted */ } else { /* Otherwise... */ #ifdef COMMENT /* This code makes any open error fatal to a file-group transfer. */ g = gnfile(); debug(F111,"Y gnfile",filnam,g); if (g > 0) { /* Any more files to send? */ if (sfile(xflg)) /* Yes, try to send next file header */ BEGIN ssfile; /* if ok, enter send-file state */ else { /* otherwise */ s = xflg ? "Can't execute command" : (char *)epktmsg; if (!*s) s = "Can't open file"; errpkt((CHAR *)s); /* send error message */ RESUME; /* and quit */ } } else { /* No next file */ tsecs = gtimer(); /* get statistics timers */ #ifdef GFTIMER fptsecs = gftimer(); #endif /* GFTIMER */ seot(); /* send EOT packet */ BEGIN sseot; /* enter send-eot state */ } #else /* COMMENT */ while (1) { /* Keep trying... */ g = gnfile(); /* Get next file */ debug(F111,"Y gnfile",filnam,g); if (g == 0 && gnferror == 0) /* No more, stop trying */ break; if (g > 0) { /* Have one */ if (sfile(xflg)) { /* Try to open and send F packet */ BEGIN ssfile; /* If OK, enter send-file state */ break; /* and break out of loop. */ } } /* Otherwise keep trying to get one we can send... */ } } if (g == 0) { debug(F101,"Y no more files","",czseen); tsecs = gtimer(); /* Get statistics timers */ #ifdef GFTIMER fptsecs = gftimer(); #endif /* GFTIMER */ seot(); /* Send EOT packet */ BEGIN sseot; /* Enter send-eot state */ } #endif /* COMMENT */ } Y { /* Got ACK to EOT */ debug(F101,"sseot justone","",justone); RESUME; /* All done, just quit */ } E { /* Got Error packet, in any state */ char *s = ""; window(1); /* Close window */ timint = s_timint; /* Restore original timeout */ if (*epktmsg) /* Message from Error packet */ s = (char *)epktmsg; if (!*s) { /* If not there then maybe here */ s = (char *)rdatap; ckstrncpy((char *)epktmsg,(char *)rdatap,PKTMSGLEN); } if (!*s) /* Hopefully we'll never see this. */ s = "Unknown error"; success = 0; /* For IF SUCCESS/FAIL. */ debug(F101,"ckcpro.w justone at E pkt","",justone); success = 0; /* Transfer failed */ xferstat = success; /* Remember transfer status */ if (!epktsent) { x = quiet; quiet = 1; /* Close files silently, */ epktrcvd = 1; /* Prevent messages from clsof() */ clsif(); clsof(1); /* discarding any output file. */ ermsg(s); /* Issue the message (calls screen). */ quiet = x; /* Restore quiet state */ } tstats(); /* Get stats */ /* If we are executing commands from a command file or macro, let the command file or macro decide whether to exit, based on SET { TAKE, MACRO } ERROR. */ if ( #ifndef NOICP !xcmdsrc && #endif /* NOICP */ backgrd && !server) fatal("Protocol error"); xitsta |= (what & W_KERMIT); /* Save this for doexit(). */ #ifdef CK_TMPDIR /* If we were cd'd temporarily to another device or directory ... */ if (f_tmpdir) { int x; x = zchdir((char *) savdir); /* ... restore previous directory */ f_tmpdir = 0; /* and remember we did it. */ debug(F111,"ckcpro.w E tmpdir restored",savdir,x); } #endif /* CK_TMPDIR */ #ifdef IKSDB if (ikdbopen) slotstate(what,"ERROR", (char *)epktmsg, ""); #endif /* IKSDB */ RESUME; } q { success = 0; QUIT; } /* Ctrl-C or connection loss. */ . { /* Anything not accounted for above */ errpkt((CHAR *)"Unexpected packet type"); /* Give error message */ window(1); xitsta |= (what & W_KERMIT); /* Save this for doexit(). */ RESUME; /* and quit */ } %% /* From here down to proto() are routines that were moved out of the state table switcher because the resulting switch() had become too large. To move the contents of a state-table case to a routine: 1. Add a prototype to the list above the state table switcher. 2. Make a routine with an appropriate name, returning int. 3. Move the code into it. 4. Put a call to the new routine in the former spot: rc = name_of_routine(); if (rc > -1) return(rc); 5. Add "return(-1);" after every RESUME, SERVE, or BEGIN macro and at the end if the code is open-ended. */ static int rcv_firstdata() { extern int dispos; debug(F101,"rcv_firstdata","",dispos); if (discard) { /* if we're discarding the file */ ack1((CHAR *)"X"); /* just ack the data like this. */ cancel++; /* and count it */ BEGIN rdpkt; /* and wait for more data packets. */ return(-1); } else { /* Not discarding. */ rf_err = "Can't open file"; if (xflg) { /* If screen data */ if (remfile) { /* redirected to file */ if (rempipe) /* or pipe */ x = openc(ZOFILE,remdest); /* Pipe: start command */ else x = opena(remdest,&iattr); /* File: open with attributes */ } else { /* otherwise */ x = opent(&iattr); /* "open" the screen */ } } else { /* otherwise */ #ifdef CALIBRATE if (calibrate) { /* If calibration run */ x = ckopenx(&iattr); /* open nothing */ #ifdef STREAMING if (streaming) /* Streaming */ fastack(); /* ACK without ACKing. */ else #endif /* STREAMING */ ack(); /* Send real ACK */ BEGIN rdpkt; /* Proceed to next state */ return(-1); } else #endif /* CALIBRATE */ #ifdef UNIX /* In UNIX we can pipe the file data into the mail program, which is to be preferred to writing it out to a temp file and then mailing it afterwards. This depends rather heavily on all UNIXes having a mail command that accepts '-s "subject"' on the command line. MAILCMD (e.g. mail, Mail, mailx) is defined in ckufio.c. */ if (dispos == 'M') { /* Mail... */ char *s; char * tmp = NULL; int n = 0; extern char *MAILCMD; s = iattr.disp.val + 1; n = (int)strlen(MAILCMD) + /* Mail command */ (int)strlen(s) + /* address */ (int)strlen(ofilnam) + 32; /* subject */ if ((tmp = (char *)malloc(n))) { ckmakxmsg(tmp,n, MAILCMD," -s \"",ofilnam,"\" ",s, NULL,NULL,NULL,NULL,NULL,NULL,NULL); debug(F111,"rcv_firsdata mail",tmp,(int)strlen(tmp)); x = openc(ZOFILE,(char *)tmp); free(tmp); } else x = 0; } else if (dispos == 'P') { /* Ditto for print */ char * tmp = NULL; int n; extern char *PRINTCMD; n = (int)strlen(PRINTCMD) + (int)strlen(iattr.disp.val+1) + 4; if ((tmp = (char *)malloc(n))) { sprintf(tmp, /* safe (prechecked) */ "%s %s", PRINTCMD, iattr.disp.val + 1); x = openc(ZOFILE,(char *)tmp); free(tmp); } else x = 0; } else #endif /* UNIX */ x = opena(filnam,&iattr); /* open the file, with attributes */ } if (x) { /* If file was opened ok */ int rc, qf; #ifndef NOSPL qf = query; #else qf = 0; #endif /* NOSPL */ #ifdef CKTUNING rc = (binary && !parity) ? bdecode(rdatap,putfil): decode(rdatap, qf ? puttrm : putfil, 1); #else rc = decode(rdatap, qf ? puttrm : putfil, 1); #endif /* CKTUNING */ if (rc < 0) { errpkt((CHAR *)"Error writing data"); RESUME; return(-1); } #ifdef STREAMING if (streaming) /* Streaming was negotiated */ fastack(); /* ACK without ACKing. */ else #endif /* STREAMING */ ack(); /* acknowledge it */ BEGIN rdpkt; /* and switch to receive-data state */ return(-1); } else { /* otherwise */ errpkt((CHAR *) rf_err); /* send error packet */ RESUME; /* and quit. */ return(-1); } } } static int rcv_shortreply() { #ifdef PKTZEROHACK success = 0; debug(F111,"rcv_shortreply",rdatap,ipktlen); if (ipktack[0] && !strncmp(ipktack,(char *)rdatap,ipktlen)) { /* No it's the ACK to the I packet again */ x = scmd(vcmd,(CHAR *)cmarg); /* So send the REMOTE command again */ /* Maybe this should be resend() */ debug(F110,"IPKTZEROHACK",ipktack,x); if (x < 0) { errpkt((CHAR *)srimsg); RESUME; return(-1); } } else { ipktack[0] = NUL; #endif /* PKTZEROHACK */ urserver = 1; #ifndef NOSERVER #ifndef NOSPL if (query) { /* If to query, */ qbufp = querybuf; /* initialize query response buffer */ qbufn = 0; querybuf[0] = NUL; } #endif /* NOSPL */ x = 1; if (remfile) { /* Response redirected to file */ rf_err = "Can't open file"; if (rempipe) /* or pipe */ x = #ifndef NOPUSH zxcmd(ZOFILE,remdest) /* Pipe: Start command */ #else 0 #endif /* NOPUSH */ ; else x = opena(remdest,&iattr); /* File: Open with attributes */ debug(F111,"rcv_shortreply remfile",remdest,x); } else { x = opent(&iattr); /* "open" the screen */ } if (x) { /* If file was opened ok */ if (decode(rdatap, #ifndef NOSPL (query || !remfile) ? puttrm : #else !remfile ? puttrm : #endif /* NOSPL */ zputfil, 1) < 0) { /* Note: zputfil, not putfil. */ errpkt((CHAR *)"Error writing data"); RESUME; return(-1); } else { if (rdatap) { /* If we had data */ if (*rdatap) { /* add a line terminator */ if (remfile) { /* to file */ zsoutl(ZOFILE,""); } else { /* or to screen. */ #ifndef NOICP if (!query || !xcmdsrc) #endif /* NOICP */ if (!(quiet && rcdactive)) conoll(""); } } } if (bye_active && network) { /* I sent BYE or REMOTE LOGOUT */ msleep(500); /* command and got the ACK... */ bye_active = 0; ttclos(0); } clsof(0); if (!epktsent && !epktrcvd) /* If no error packet... */ success = 1; /* success. */ RESUME; return(-1); } } else { /* File not opened OK */ errpkt((CHAR *) rf_err); /* send error message */ RESUME; /* and quit. */ return(-1); } #endif /* NOSERVER */ #ifdef PKTZEROHACK } #endif /* PKTZEROHACK */ debug(F101,"rcv_shortreply fallthru","",success); return(-1); } static int srv_query() { #ifndef NOSERVER #ifndef NOSPL char c; #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE QUERY", (char *)srvcmd); #endif /* CKSYSLOG */ #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE QUERY", (char *)(srvcmd+2), ""); #endif /* IKSDB */ c = *(srvcmd+2); /* Q = Query, S = Set */ if (c == 'Q') { /* Query */ if (!ENABLED(en_que)) { /* Security */ errpkt((CHAR *)"REMOTE QUERY disabled"); RESUME; return(-1); } else { /* Query allowed */ int n; char *p, *q; qbufp = querybuf; /* Wipe out old stuff */ qbufn = 0; querybuf[0] = NUL; p = (char *) srvcmd + 3; /* Pointer for making wrapper */ n = strlen((char *)srvcmd); /* Position of end */ c = *(srvcmd+4); /* Which type of variable */ if (*(srvcmd+6) == CMDQ) { /* Starts with command quote? */ p = (char *) srvcmd + 6; /* Take it literally */ if (*p == CMDQ) p++; } else { /* They played by the rules */ if (c == 'K') { /* Kermit variable */ int k; k = (int) strlen(p); if (k > 0 && p[k-1] == ')') { p = (char *)(srvcmd + 4); *(srvcmd+4) = CMDQ; *(srvcmd+5) = 'f'; /* Function, so make it \f...() */ } else { *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */ *(srvcmd+4) = 'v'; /* Variable, so make it \v(...) */ *(srvcmd+5) = '('; /* around variable name */ *(srvcmd+n) = ')'; *(srvcmd+n+1) = NUL; } } else { *(srvcmd+3) = CMDQ; /* Stuff wrapping into buffer */ *(srvcmd+4) = 'v'; /* Variable, so make it \v(...) */ *(srvcmd+5) = '('; /* around variable name */ *(srvcmd+n) = ')'; *(srvcmd+n+1) = NUL; if (c == 'S') { /* System variable */ *(srvcmd+4) = '$'; /* so it's \$(...) */ } else if (c == 'G') { /* Non-\ Global variable */ *(srvcmd+4) = 'm'; /* so wrap it in \m(...) */ } } } /* Now evaluate it */ n = QBUFL; /* Max length */ q = querybuf; /* Where to put it */ if (zzstring(p,&q,&n) < 0) { errpkt((n > 0) ? (CHAR *)"Can't get value" : (CHAR *)"Value too long" ); RESUME; return(-1); } else { if (encstr((CHAR *)querybuf) > -1) { /* Encode it */ ack1(data); /* If it fits, send it back in ACK */ success = 1; RESUME; return(-1); } else if (sndstring(querybuf)) { /* Long form response */ BEGIN ssinit; return(-1); } else { /* sndhlp() fails */ errpkt((CHAR *)"Can't send value"); RESUME; return(-1); } } } } else if (c == 'S') { /* Set (assign) */ if (!ENABLED(en_asg)) { /* Security */ errpkt((CHAR *)"REMOTE ASSIGN disabled"); RESUME; return(-1); } else { /* OK */ int n; n = xunchar(*(srvcmd+3)); /* Length of name */ n = 3 + n + 1; /* Position of length of value */ *(srvcmd+n) = NUL; /* Don't need it */ if (addmac((char *)(srvcmd+4),(char *)(srvcmd+n+1)) < 0) errpkt((CHAR *)"REMOTE ASSIGN failed"); else { ack(); success = 1; } RESUME; return(-1); } } else { errpkt((CHAR *)"Badly formed server command"); RESUME; return(-1); } #else errpkt((CHAR *)"Variable query/set not available"); RESUME; return(-1); #endif /* NOSPL */ #endif /* NOSERVER */ } static int srv_copy() { #ifndef NOSERVER #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE COPY", (char *)srvcmd); #endif /* CKSYSLOG */ #ifdef ZCOPY if (!ENABLED(en_cpy)) { errpkt((CHAR *)"REMOTE COPY disabled"); RESUME; return(-1); } else { char *str1, *str2, f1[256], f2[256]; int len1, len2; len1 = xunchar(srvcmd[1]); /* Separate the parameters */ len2 = xunchar(srvcmd[2+len1]); strncpy(f1,(char *)(srvcmd+2),len1); f1[len1] = NUL; strncpy(f2,(char *)(srvcmd+3+len1),len2); f2[len2] = NUL; #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE COPY", f1, f2); #endif /* IKSDB */ if (!ENABLED(en_cwd)) { /* If CWD is disabled */ zstrip(f1,&str1); /* and they included a pathname, */ zstrip(f2,&str2); if (strcmp(f1,str1) || strcmp(f2,str2)) { /* Refuse. */ errpkt((CHAR *)"Access denied"); RESUME; /* Remember, this is not a goto! */ return(-1); } } if (state == generic) { /* It's OK to go ahead. */ if (zcopy(f1,f2)) { /* Try */ errpkt((CHAR *)"Can't copy file"); /* give error message */ } else { success = 1; ack(); } RESUME; /* wait for next server command */ return(-1); } } return(-1); #else /* no ZCOPY */ errpkt((CHAR *)"REMOTE COPY not available"); /* give error message */ RESUME; /* wait for next server command */ return(-1); #endif /* ZCOPY */ #endif /* NOSERVER */ } static int srv_rename() { #ifndef NOSERVER #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE RENAME", (char *)srvcmd); #endif /* CKSYSLOG */ #ifdef ZRENAME if (!ENABLED(en_ren)) { errpkt((CHAR *)"REMOTE RENAME disabled"); RESUME; return(-1); } else { /* RENAME is enabled */ char *str1, *str2, f1[256], f2[256]; int len1, len2; len1 = xunchar(srvcmd[1]); /* Separate the parameters */ len2 = xunchar(srvcmd[2+len1]); strncpy(f1,(char *)(srvcmd+2),len1); f1[len1] = NUL; strncpy(f2,(char *)(srvcmd+3+len1),len2); f2[len2] = NUL; len2 = xunchar(srvcmd[2+len1]); strncpy(f1,(char *)(srvcmd+2),len1); f1[len1] = NUL; strncpy(f2,(char *)(srvcmd+3+len1),len2); f2[len2] = NUL; #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE RENAME", f1, f2); #endif /* IKSDB */ if (!ENABLED(en_cwd)) { /* If CWD is disabled */ zstrip(f1,&str1); /* and they included a pathname, */ zstrip(f2,&str2); if ( strcmp(f1,str1) || strcmp(f2,str2) ) { /* refuse. */ errpkt((CHAR *)"Access denied"); RESUME; /* Remember, this is not a goto! */ return(-1); } } if (state == generic) { /* It's OK to go ahead. */ if (zrename(f1,f2)) { /* Try */ errpkt((CHAR *)"Can't rename file"); /* Give error msg */ } else { success = 1; ack(); } RESUME; /* Wait for next server command */ return(-1); } } return(-1); #else /* no ZRENAME */ /* Give error message */ errpkt((CHAR *)"REMOTE RENAME not available"); RESUME; /* Wait for next server command */ return(-1); #endif /* ZRENAME */ #endif /* NOSERVER */ } static int srv_login() { #ifndef NOSERVER char f1[LOGINLEN+1], f2[LOGINLEN+1], f3[LOGINLEN+1]; CHAR *p; int len, i; debug(F101,"REMOTE LOGIN x_login","",x_login); debug(F101,"REMOTE LOGIN x_logged","",x_logged); f1[0] = NUL; f2[0] = NUL; f3[0] = NUL; len = 0; if (srvcmd[1]) /* First length field */ len = xunchar(srvcmd[1]); /* Separate the parameters */ if (x_login) { /* Login required */ if (x_logged) { /* And already logged in */ if (len > 0) { /* Logging in again */ errpkt((CHAR *)"Already logged in."); } else { /* Logging out */ debug(F101,"REMOTE LOGOUT","",x_logged); #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGOUT", NULL); #endif /* CKSYSLOG */ #ifdef IKSDB if (ikdbopen) slotstate(what,"REMOTE LOGOUT", "", ""); #endif /* IKSDB */ tlog(F110,"Logged out",x_user,0); ack1((CHAR *)"Logged out"); success = 1; msleep(500); #ifdef CK_LOGIN x_logged = 0; #ifdef IKSD if (inserver) ckxlogout(); #endif /* IKSD */ #endif /* CK_LOGIN */ } } else { /* Not logged in yet */ debug(F101,"REMOTE LOGIN len","",len); if (len > 0) { /* Have username */ #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "REMOTE LOGIN", NULL); #endif /* CKSYSLOG */ if (len > LOGINLEN) { errpkt((CHAR *)"Username too long"); } p = srvcmd + 2; /* Point to it */ for (i = 0; i < len; i++) /* Copy it */ f1[i] = p[i]; f1[len] = NUL; /* Terminate it */ p += len; /* Point to next length field */ if (*p) { /* If we have one */ len = xunchar(*p++); /* decode it */ if (len > 0 && len <= LOGINLEN) { for (i = 0; i < len; i++) /* Same deal for password */ f2[i] = p[i]; f2[len] = NUL; p += len; /* And account */ if (*p) { len = xunchar(*p++); if (len > 0 && len <= LOGINLEN) { for (i = 0; i < len; i++) f3[i] = p[i]; /* Set but never used */ f3[len] = NUL; /* (because account not used) */ } } } } debug(F101,"REMOTE LOGIN 1","",x_logged); #ifdef IKSD #ifdef CK_LOGIN if (inserver) { /* Log in to system for real */ x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0); debug(F101,"REMOTE LOGIN 2","",x_logged); if (x_logged) { /* Count attempts */ logtries = 0; justone = 1; } else { logtries++; sleep(logtries); } } else #endif /* CK_LOGIN */ #endif /* IKSD */ if (x_user && x_passwd) { /* User and password must match */ if (!strcmp(x_user,f1)) /* SET SERVER LOGIN */ if (!strcmp(x_passwd,f2)) x_logged = 1; debug(F101,"REMOTE LOGIN 3","",x_logged); } else if (x_user) { /* Only username given, no password */ if (!strcmp(x_user,f1)) /* so only username must match */ x_logged = 1; debug(F101,"REMOTE LOGIN 4","",x_logged); } #ifdef CK_LOGIN else { x_logged = ckxlogin((CHAR *)f1,(CHAR *)f2,NULL,0); debug(F101,"REMOTE LOGIN 5","",x_logged); } #endif /* CK_LOGIN */ if (x_logged) { /* Logged in? */ tlog(F110,"Logged in", x_user, 0); if (isguest) ack1((CHAR *)"Logged in as guest - restrictions apply"); else ack1((CHAR *)"Logged in"); success = 1; } else { tlog(F110,"Login failed", f1, 0); errpkt((CHAR *)"Access denied."); #ifdef IKSD #ifdef CK_LOGIN if (inserver && logtries > 2) ckxlogout(); #endif /* CK_LOGIN */ #endif /* IKSD */ } } else { /* LOGOUT */ errpkt((CHAR *)"Logout ignored"); } } } else { /* Login not required */ if (len > 0) errpkt((CHAR *)"Login ignored."); else errpkt((CHAR *)"Logout ignored."); } #endif /* NOSERVER */ RESUME; return(-1); } static int srv_timeout() { /* K95 does this its own way */ if (idletmo) { #ifdef IKSD if (inserver) { printf("\r\nIKSD IDLE TIMEOUT: %d sec\r\n", srvidl); doexit(GOOD_EXIT,xitsta); } #endif /* IKSD */ idletmo = 0; printf("\r\nSERVER IDLE TIMEOUT: %d sec\r\n", srvidl); xitsta |= (what & W_KERMIT); QUIT; } #ifndef NOSERVER else if (fatalio) { /* Connection lost */ #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "Connection lost", NULL); #endif /* CKSYSLOG */ #ifdef IKSDB if (ikdbopen) slotstate(what,"SERVER DISCONNECT",(char *)srvcmd, ""); #endif /* IKSDB */ xitsta |= what; QUIT; } else if (interrupted) { /* Interrupted by hand */ if (!ENABLED(en_fin)) { errpkt((CHAR *)"QUIT disabled"); RESUME; return(-1); } else { if (what == W_SEND || what == W_RECV || what == W_REMO) { success = 0; #ifdef CKSYSLOG if (ckxsyslog >= SYSLG_PR && ckxlogging) cksyslog(SYSLG_PR, 1, "server", "Interrupted", NULL); #endif /* CKSYSLOG */ } else if (what == W_NOTHING && filcnt == 0) { success = 1; } /* Otherwise leave success alone */ xitsta |= (what & W_KERMIT); QUIT; } } else { /* Shouldn't happen */ debug(F100,"SERVER (top) GOT UNEXPECTED 'q'","",0); QUIT; } #endif /* NOSERVER */ } static int rcv_s_pkt() { #ifndef NOSERVER if (state == rgen) urserver = 1; if (/* state == serve && */ x_login && !x_logged) { errpkt((CHAR *)"Login required"); SERVE; } else #endif /* NOSERVER */ if (state == serve && !ENABLED(en_sen)) { /* Not in server mode */ errpkt((CHAR *)"SEND disabled"); /* when SEND is disabled. */ RESUME; return(-1); } else { /* OK to go ahead. */ #ifdef CK_TMPDIR if (dldir && !f_tmpdir) { /* If they have a download directory */ debug(F110,"receive download dir",dldir,0); if ((s = zgtdir())) { /* Get current directory */ debug(F110,"receive current dir",s,0); if (zchdir(dldir)) { /* Change to download directory */ debug(F100,"receive zchdir ok","",0); ckstrncpy(savdir,s,TMPDIRLEN); f_tmpdir = 1; /* Remember that we did this */ } else debug(F100,"receive zchdir failed","",0); } } #endif /* CK_TMPDIR */ nakstate = 1; /* Can send NAKs from here. */ rinit(rdatap); /* Set parameters */ if (bctf) { bctu = 3; bctl = 3; } else { bctu = bctr; /* switch to agreed-upon block check */ bctl = (bctu == 4) ? 2 : bctu; /* Set block-check length */ } what = W_RECV; /* Remember we're receiving */ lastxfer = W_RECV; resetc(); /* Reset counters */ rtimer(); /* Reset timer */ #ifdef GFTIMER rftimer(); #endif /* GFTIMER */ streamon(); BEGIN rfile; /* Go into receive-file state */ } return(-1); } /* END OF ROUTINES MOVED OUT OF STATE MACHINE */ /* P R O T O -- Protocol entry function */ static int is_tn = 0; /* It's a Telnet connection */ #ifdef CK_SPEED int f_ctlp = 0; /* Control-character prefix table */ #ifdef COMMENT short s_ctlp[256]; #endif /* COMMENT */ #endif /* CK_SPEED */ /* This is simply a wrapper for the real protocol function just below, that saves any items that might be changed automatically by protocol negotiations and then restores them upon exit from protocol mode. */ VOID proto() { extern int b_save, f_save, c_save, ss_save, slostart, reliable, urclear; #ifndef NOCSETS extern int fcharset, fcs_save, tcharset, tcs_save; #endif /* NOCSETS */ #ifdef PIPESEND extern int pipesend; #endif /* PIPESEND */ #ifndef NOLOCAL #ifdef OS2 extern int cursorena[], cursor_save, term_io; extern BYTE vmode; int term_io_save; #endif /* OS2 */ #endif /* NOLOCAL */ #ifdef TNCODE int _u_bin=0, _me_bin = 0; #ifdef IKS_OPTION int /* _u_start=0, */ _me_start = 0; #endif /* IKS_OPTION */ #endif /* TNCODE */ #ifdef PATTERNS int pa_save; int i; #endif /* PATTERNS */ int scan_save; #ifdef PATTERNS pa_save = patterns; #endif /* PATTERNS */ scan_save = filepeek; myjob = sstate; #ifdef CK_LOGIN if (isguest) { /* If user is anonymous */ en_pri = 0; /* disable printing */ en_mai = 0; /* and disable email */ en_del = 0; /* and file deletion */ } #endif /* CK_LOGIN */ #ifndef NOLOCAL #ifdef OS2 cursor_save = cursorena[vmode]; cursorena[vmode] = 0; term_io_save = term_io; term_io = 0; #endif /* OS2 */ #endif /* NOLOCAL */ b_save = binary; /* SET FILE TYPE */ f_save = fncnv; /* SET FILE NAMES */ c_save = bctr; p_save = fnspath; r_save = recursive; s_timint = timint; ss_save = slostart; #ifndef NOCSETS fcs_save = fcharset; tcs_save = tcharset; #endif /* NOCSETS */ #ifdef COMMENT /* Don't do this because then user can never find out what happened. */ #ifdef CK_SPEED for (i = 0; i < 256; i++) s_ctlp[i] = ctlp[i]; f_ctlp = 1; #endif /* CK_SPEED */ #endif /* COMMENT */ if (reliable == SET_ON) slostart = 0; is_tn = (!local && sstelnet) #ifdef TNCODE || (local && network && ttnproto == NP_TELNET) #endif /* TNCODE */ ; #ifdef TNCODE if (is_tn) { if (tn_b_xfer && !(sstelnet || inserver)) { /* Save the current state of Telnet Binary */ _u_bin = TELOPT_U(TELOPT_BINARY); _me_bin = TELOPT_ME(TELOPT_BINARY); /* If either direction is not Binary attempt to negotiate it */ if (!_u_bin && TELOPT_U_MODE(TELOPT_BINARY) != TN_NG_RF) { tn_sopt(DO,TELOPT_BINARY); TELOPT_UNANSWERED_DO(TELOPT_BINARY) = 1; } if (!_me_bin && TELOPT_ME_MODE(TELOPT_BINARY) != TN_NG_RF) { tn_sopt(WILL,TELOPT_BINARY); TELOPT_UNANSWERED_WILL(TELOPT_BINARY) = 1; } if (!(_me_bin && _u_bin)) tn_wait("proto set binary mode"); } #ifdef IKS_OPTION #ifdef CK_XYZ if (protocol != PROTO_K) { /* Non-Kermit protocol selected */ if (TELOPT_U(TELOPT_KERMIT) && TELOPT_SB(TELOPT_KERMIT).kermit.u_start) { iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */ /* _u_start = 1; */ } if (TELOPT_ME(TELOPT_KERMIT) && TELOPT_SB(TELOPT_KERMIT).kermit.me_start) { tn_siks(KERMIT_STOP); /* I'm not servering */ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0; _me_start = 1; } } else #endif /* CK_XYZ */ if (sstate == 'x' || sstate == 'v') { /* Responding to a request */ if (!inserver && TELOPT_U(TELOPT_KERMIT) && TELOPT_SB(TELOPT_KERMIT).kermit.u_start) { iks_wait(KERMIT_REQ_STOP,0); /* Stop the other Server */ /* _u_start = 1; */ } if (TELOPT_ME(TELOPT_KERMIT) && !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) { tn_siks(KERMIT_START); /* Send Kermit-Server Start */ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1; } } else { /* Initiating a request */ if (TELOPT_ME(TELOPT_KERMIT) && TELOPT_SB(TELOPT_KERMIT).kermit.me_start) { tn_siks(KERMIT_STOP); /* I'm not servering */ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0; _me_start = 1; } if (TELOPT_U(TELOPT_KERMIT) && !TELOPT_SB(TELOPT_KERMIT).kermit.u_start) { /* Send Req-Server-Start */ if (!iks_wait(KERMIT_REQ_START,0)) { if (sstate != 's') { success = 0; /* Other Kermit refused to serve */ if (local) printf("A Kermit Server is not available\r\n"); debug(F110,"proto()", "A Kermit Server is not available",0); tlog(F110,"IKS client/server failure", "A Kermit Server is not available",0); goto xxprotox; } } } } #endif /* IKS_OPTION */ #ifdef CK_ENCRYPTION if (tn_no_encrypt_xfer && !(sstelnet || inserver)) { ck_tn_enc_stop(); /* fdc 2021-12-17 */ } #endif /* CK_ENCRYPTION */ } #endif /* TNCODE */ if (!xfrint) connoi(); xxproto(); /* Call the real protocol function */ #ifdef IKS_OPTION xxprotox: #endif /* IKS_OPTION */ xferstat = success; /* Remember transfer status */ kactive = 0; #ifdef TNCODE #ifdef CK_ENCRYPTION if (tn_no_encrypt_xfer && !(sstelnet || inserver)) { ck_tn_enc_start(); /* fdc 2021-12-17 */ } #endif /* CK_ENCRYPTION */ #ifdef IKS_OPTION if (TELOPT_ME(TELOPT_KERMIT) && TELOPT_SB(TELOPT_KERMIT).kermit.me_start && !_me_start) { tn_siks(KERMIT_STOP); /* Server is stopped */ TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0; } #endif /* IKS_OPTION */ if (is_tn && tn_b_xfer && !(sstelnet || inserver)) { /* if we negotiated Binary mode try to reset it */ if (!_u_bin) { /* Check to see if the state changed during the transfer */ if (TELOPT_U(TELOPT_BINARY)) { tn_sopt(DONT,TELOPT_BINARY); TELOPT_UNANSWERED_DONT(TELOPT_BINARY) = 1; } else _u_bin = 1; /* So we don't call tn_wait() */ } if (!_me_bin) { /* Check to see if the state changed during the transfer */ if (TELOPT_ME(TELOPT_BINARY)) { tn_sopt(WONT,TELOPT_BINARY); TELOPT_UNANSWERED_WONT(TELOPT_BINARY) = 1; } else _me_bin = 1; /* So we don't call tn_wait() */ } if (!(_me_bin && _u_bin)) tn_wait("proto reset binary mode"); } #endif /* TNCODE */ #ifdef PATTERNS patterns = pa_save; #endif /* PATTERNS */ filepeek = scan_save; #ifdef STREAMING streaming = 0; /* streamok = 0; */ #endif /* STREAMING */ #ifdef COMMENT #ifdef CK_SPEED for (i = 0; i < 256; i++) ctlp[i] = s_ctlp[i]; f_ctlp = 0; #endif /* CK_SPEED */ #endif /* COMMENT */ urclear = 0; if (!success) { xitsta |= (what & W_KERMIT); tlog(F110," failed:",(char *)epktmsg,0); } debug(F111,"proto xferstat",epktmsg,xferstat); slostart = ss_save; if (s_timint > -1) { /* Because of REMOTE SET */ timint = s_timint; s_timint = -1; } recursive = r_save; fnspath = p_save; if (c_save > -1) { /* Because of REMOTE SET */ bctr = c_save; c_save = -1; } fncnv = f_save; binary = b_save; #ifdef PIPESEND pipesend = 0; /* Next time might not be pipesend */ #endif /* PIPESEND */ #ifndef NOLOCAL #ifdef OS2 cursorena[vmode] = cursor_save; term_io = term_io_save; #endif /* OS2 */ #endif /* NOLOCAL */ } static VOID xxproto() { int x; long lx; #ifdef CK_XYZ #ifdef XYZ_INTERNAL _PROTOTYP( int pxyz, (int) ); #endif /* XYZ_INTERNAL */ #endif /* CK_XYZ */ char xss[2]; /* String representation of sstate */ xss[0] = sstate; xss[1] = NUL; s_timint = timint; debug(F101,"xxproto entry justone","",justone); success = 0; retrieve = 0; /* Reset these ... */ reget = 0; opkt = 0; if (local && ttchk() < 0) { /* Giving BYE or FIN */ if (bye_active) { /* but there is no connection */ ttclos(0); success = 1; return; } /* Ditto for any REMOTE command */ if (sstate == 'g' && cmarg ) { if (*cmarg == 'L' || *cmarg == 'F' || *cmarg == 'X') success = 1; else printf("?No connection\r\n"); return; } } /* Set up the communication line for file transfer. */ /* NOTE: All of the xxscreen() calls prior to the wart() invocation */ /* could just as easily be printf's or, for that matter, hints. */ if (local && (speed < 0L) && (network == 0)) { xxscreen(SCR_EM,0,0L,"Sorry, you must 'set speed' first"); return; } x = -1; if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) { debug(F111,"failed: proto ttopen local",ttname,local); xxscreen(SCR_EM,0,0L,"Can't open line"); return; } if (x > -1) local = x; debug(F111,"proto ttopen local",ttname,local); lx = (local && !network) ? speed : -1; #ifdef NETCONN #ifdef CK_SPEED if (is_tn) { ctlp[(unsigned)255] = ctlp[CK_CR] = 1; if (parity == 'e' || parity == 'm') ctlp[127] = 1; if (flow == FLO_XONX) { /* Also watch out for Xon/Xoff */ ctlp[17] = ctlp[19] = 1; ctlp[17+128] = ctlp[19+128] = 1; } } #endif /* CK_SPEED */ #endif /* NETCONN */ if (ttpkt(lx,flow,parity) < 0) { /* Put line in packet mode, */ xxscreen(SCR_EM,0,0L,"Can't condition line"); return; } if (local && !network && carrier != CAR_OFF) { int x; /* Serial connection */ x = ttgmdm(); /* with carrier checking */ if (x > -1) { if (!(x & BM_DCD)) { debug(F101,"proto ttgmdm","",0); xxscreen(SCR_EM,0,0L,"Carrier required but not detected"); return; } } } /* Send remote side's "receive" or "server" startup string, if any */ if (local && ckindex((char *)xss,"srgcjhk",0,0,1)) { char *s = NULL; if ( #ifdef IKS_OPTION /* Don't send auto-blah string if we know other side is serving */ !TELOPT_U(TELOPT_KERMIT) || !TELOPT_SB(TELOPT_KERMIT).kermit.u_start #else 1 #endif /* IKS_OPTION */ ) { if (sstate == 's') { /* Sending file(s) */ s = binary ? ptab[protocol].h_b_init : ptab[protocol].h_t_init; } else if (protocol == PROTO_K) { /* Command for server */ s = ptab[protocol].h_x_init; } } #ifdef CK_SPEED #ifndef UNPREFIXZERO if (protocol == PROTO_K) /* Because of C-strings... */ ctlp[0] = 1; #endif /* UNPREFIXZERO */ #endif /* CK_SPEED */ if (s) if (*s) { /* If we have a command to send... */ char tmpbuf[356]; int tmpbufsiz = 356; int stuff = -1, stuff2 = -1, len = 0; extern int tnlm; if (sstate == 's') { /* Sending file(s) */ #ifdef CK_XYZ if (protocol == PROTO_X) { char * s2; s2 = cmarg2[0] ? cmarg2 : cmarg; if ((int)strlen(s) + (int)strlen(s2) + 4 < 356) sprintf(tmpbuf, s, s2); else tmpbuf[0] = NUL; } else { #endif /* CK_XYZ */ ckmakmsg(tmpbuf, 356, s, NULL, NULL, NULL); #ifdef CK_XYZ } #endif /* CK_XYZ */ } else { /* Command for server */ ckstrncpy(tmpbuf,s,356); } ckstrncat(tmpbuf, "\015",sizeof(tmpbuf)); if (tnlm) /* TERMINAL NEWLINE ON */ stuff = LF; /* Stuff LF */ #ifdef TNCODE /* TELNET NEWLINE MODE */ if (is_tn) { switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) { case TNL_CR: break; case TNL_CRNUL: break; case TNL_CRLF: stuff2 = stuff; stuff = LF; break; } } #endif /* TNCODE */ #ifdef NETCONN #ifdef TCPSOCKET #ifdef RLOGCODE if (network && ttnproto == NP_RLOGIN) { switch (tn_b_nlm) { /* Always BINARY */ case TNL_CR: break; case TNL_CRNUL: stuff2 = stuff; stuff = NUL; break; case TNL_CRLF: stuff2 = stuff; stuff = LF; break; } } #endif /* RLOGCODE */ #endif /* TCPSOCKET */ #endif /* NETCONN */ len = strlen(tmpbuf); if (stuff >= 0 && len < tmpbufsiz - 1) { tmpbuf[len++] = stuff; if (stuff2 >= 0 && len < tmpbufsiz - 1) tmpbuf[len++] = stuff2; tmpbuf[len] = NUL; } ttol((CHAR *)tmpbuf,len); if (protocol == PROTO_K) /* Give remote Kermit time to start */ msleep(400); } } #ifdef CK_XYZ if (protocol != PROTO_K) { /* Non-Kermit protocol selected */ char tmpbuf[356]; int tmpbufsiz = 356; char * s = ""; #ifdef CK_TMPDIR if (sstate == 'v') { /* If receiving and... */ if (dldir && !f_tmpdir) { /* if they have a download directory */ if ((s = zgtdir())) { /* Get current directory */ if (zchdir(dldir)) { /* Change to download directory */ ckstrncpy(savdir,s,TMPDIRLEN); f_tmpdir = 1; /* Remember that we did this */ } } } } #endif /* CK_TMPDIR */ #ifdef XYZ_INTERNAL /* Internal */ success = !pxyz(sstate); #else #ifdef CK_REDIR /* External */ switch (sstate) { case 's': /* 'Tis better to SEND... */ s = binary ? ptab[protocol].p_b_scmd : ptab[protocol].p_t_scmd; break; case 'v': /* ... than RECEIVE */ s = binary ? ptab[protocol].p_b_rcmd : ptab[protocol].p_t_rcmd; break; } if (!s) s = ""; if (*s) { if (sstate == 's') { /* Sending */ extern int xfermode; int k = 0, x = 0, b = binary; /* If just one file we can scan it to set the xfer mode. Otherwise it's up to the external protocol program. */ if (patterns && xfermode == XMODE_A && !iswild(fspec)) { extern int nscanfile; k = scanfile(fspec,&x,nscanfile); if (k > -1) { b = (k == FT_BIN) ? XYFT_B : XYFT_T; s = b ? ptab[protocol].p_b_scmd : ptab[protocol].p_t_scmd; } } if ((int)strlen(s) + (int)strlen(fspec) < tmpbufsiz) { sprintf(tmpbuf,s,fspec); /* safe (prechecked) */ tlog(F110,"Sending",fspec,0L); } } else { /* Receiving */ if ((int)strlen(s) + (int)strlen(cmarg2) < tmpbufsiz) { sprintf(tmpbuf,s,cmarg2); /* safe (prechecked) */ tlog(F110,"Receiving",cmarg2,0L); } } tlog(F110," via external protocol:",tmpbuf,0); debug(F110,"ckcpro ttruncmd",tmpbuf,0); success = ttruncmd(tmpbuf); tlog(F110," status:",success ? "OK" : "FAILED", 0); } else { printf("?Sorry, no external protocol defined for %s\r\n", ptab[protocol].p_name ); } #else printf( "Sorry, only Kermit protocol is supported in this version of Kermit\n" ); #endif /* CK_REDIR */ #endif /* XYZ_INTERNAL */ return; } #endif /* CK_XYZ */ #ifdef NTSIGX conraw(); connoi(); #else if (!local) connoi(); /* No console interrupts if remote */ #endif /* NTSIG */ kactive = 1; if (sstate == 'x') { /* If entering server mode, */ extern int howcalled; server = 1; /* set flag, */ debug(F101,"server backgrd","",backgrd); debug(F101,"server quiet","",quiet); debug(F100,"SHOULD NOT SEE THIS IF IN BACKGROUND!","",0); if (howcalled == I_AM_SSHSUB) { /* and issue appropriate message. */ ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26); } else if (!local) { if (!quiet && !backgrd #ifdef IKS_OPTION && !TELOPT_ME(TELOPT_KERMIT) /* User was told by negotiation */ #endif /* IKS_OPTION */ ) { conoll(srvtxt); conoll("KERMIT READY TO SERVE..."); } } else { conol("Entering server mode on "); conoll(ttname); conoll("Type Ctrl-C to quit."); if (srvdis) intmsg(-1L); #ifdef TCPSOCKET #ifndef NOLISTEN if (network && tcpsrfd > 0) ttol((CHAR *)"KERMIT READY TO SERVE...\015\012",26); #endif /* NOLISTEN */ #endif /* TCPSOCKET */ } } else server = 0; #ifdef VMS if (!quiet && !backgrd) /* So message doesn't overwrite prompt */ conoll(""); if (local) conres(); /* So Ctrl-C will work */ #endif /* VMS */ /* If in remote mode, not shushed, not in background, and at top command level, issue a helpful message telling what to do... */ if (!local && !quiet && !backgrd) { if (sstate == 'v') { conoll("Return to your local Kermit and give a SEND command."); conoll(""); conoll("KERMIT READY TO RECEIVE..."); } else if (sstate == 's') { conoll("Return to your local Kermit and give a RECEIVE command."); conoll(""); conoll("KERMIT READY TO SEND..."); } else if ( sstate == 'g' || sstate == 'r' || sstate == 'h' || sstate == 'j' || sstate == 'c' ) { conoll("Return to your local Kermit and give a SERVER command."); conoll(""); conoll((sstate == 'r' || sstate == 'j' || sstate == 'h') ? "KERMIT READY TO GET..." : "KERMIT READY TO SEND SERVER COMMAND..."); } } #ifdef COMMENT if (!local) sleep(1); #endif /* COMMENT */ /* The 'wart()' function is generated by the wart program. It gets a character from the input() routine and then based on that character and the current state, selects the appropriate action, according to the state table above, which is transformed by the wart program into a big case statement. The function is active for one transaction. */ rtimer(); /* Reset elapsed-time timer */ #ifdef GFTIMER rftimer(); #endif /* GFTIMER */ resetc(); /* & other per-transaction counters. */ debug(F101,"proto calling wart, justone","",justone); wart(); /* Enter the state table switcher. */ /* Note: the following is necessary in case we have just done a remote-mode file transfer, in which case the controlling terminal modes have been changed by ttpkt(). In particular, special characters like Ctrl-C and Ctrl-\ might have been turned off (see ttpkt). So this call to ttres() is essential. IMPORTANT: restore interrupt handlers first, otherwise any terminal interrupts that occur before this is done in the normal place later will cause a crash. */ #ifdef OS2 ttres(); /* Reset the communication device */ #else if (!local) { setint(); /* Arm interrupt handlers FIRST */ msleep(500); ttres(); /* Then restore terminal. */ } #endif /* OS2 */ xxscreen(SCR_TC,0,0L,""); /* Transaction complete */ x = quiet; quiet=1; clsif(); /* Failsafe in case we missed */ clsof(1); /* a case in the state machine. */ quiet = x; if (server) { /* Back from packet protocol. */ if (!quiet && !backgrd #ifdef IKSD && !inserver #endif /* IKSD */ ) { /* Give appropriate message */ conoll(""); conoll("C-Kermit server done"); } server = 0; /* Not a server any more */ } } /* S G E T I N I T -- Handle incoming GET-Class packets */ /* Returns: -1: On error 0: GET packet processed OK - ready to Send. 1: Extended GET processed OK - wait for another. */ static int #ifdef CK_ANSIC sgetinit(int reget, int xget) #else sgetinit(reget,xget) int reget, xget; #endif /* CK_ANSIC */ { /* Server end of GET command */ char * fs = NULL; /* Pointer to filespec */ int i, n, done = 0; #ifdef PIPESEND extern int usepipes, pipesend; #endif /* PIPESEND */ extern int nolinks; if (!ENABLED(en_get)) { /* Only if not disabled! */ errpkt((CHAR *)"GET disabled"); return(-1); } /* OK to proceed */ nolinks = recursive; filcnt = 0; #ifdef WHATAMI /* If they are alike this was already done in whoarewe() */ debug(F101,"sgetinit whatru","",whatru); if (whatru & WMI_FLAG) { /* Did we get WHATAMI info? */ debug(F101,"sgetinit binary (1)","",binary); #ifdef VMS if (binary != XYFT_I && binary != XYFT_L) #else #ifdef OS2 if (binary != XYFT_L) #endif /* OS2 */ #endif /* VMS */ binary = (whatru & WMI_FMODE) ? /* Yes, set file type */ XYFT_B : XYFT_T; /* automatically */ debug(F101,"sgetinit binary (2)","",binary); if (!wearealike) fncnv = (whatru & WMI_FNAME) ? 1 : 0; /* And name conversion */ } #endif /* WHATAMI */ fs = (char *)srvcmd; srvptr = srvcmd; /* Point to server command buffer */ decode(rdatap,putsrv,0); /* Decode the GET command into it */ /* Accept multiple filespecs */ cmarg2 = ""; /* Don't use cmarg2 */ cmarg = ""; /* Don't use cmarg */ done = 1; /* Only 1 packet needed... */ if (xget) { /* Special decoding for Extended GET */ char L, next, c; /* PLV items */ int len, val; /* More PLV items */ char * p = (char *)srvcmd; /* String to decode */ done = 0; /* Maybe more packets needed */ fs = NULL; /* We don't know the filespec yet */ c = *p++; /* Get first parameter */ while (c) { /* For all parameters... */ debug(F000,"sgetinit c","",c); L = *p++; /* Get length */ if (L >= SP) /* Decode length */ len = xunchar(L); else if (c == '@') { /* Allow missing EOP length field */ len = 0; } else { len = (xunchar(*p++) * 95); len += xunchar(*p++); } debug(F101,"sgetinit len","",len); next = *(p+len); /* Get next parameter */ *(p+len) = NUL; /* Zero it out to terminal value */ debug(F110,"sgetinit p",p,0); switch (c) { /* Do the parameter */ case 'O': /* GET Options */ val = atoi(p); /* Convert to int */ debug(F101,"sgetinit O val","",val); if (val & GOPT_DEL) moving = 1; if (val & GOPT_RES) reget = 1; if (val & GOPT_REC) { recursive = 1; nolinks = 2; if (fnspath == PATH_OFF) fnspath = PATH_REL; } break; case 'M': /* Transfer Mode */ val = atoi(p); debug(F101,"sgetinit M val","",val); if (val < 1) break; patterns = 0; /* Takes precedence over patterns */ filepeek = 0; /* and FILE SCAN */ if (val == GMOD_TXT) binary = XYFT_T; /* Text */ if (val == GMOD_BIN) binary = XYFT_B; /* Binary */ if (val == GMOD_LBL) binary = XYFT_L; /* Labeled */ break; case 'F': /* Filename */ fs = p; debug(F110,"sgetinit filename",fs,0); break; case '@': /* End Of Parameters */ done = 1; debug(F100,"sgetinit EOP","",0); break; default: errpkt((CHAR *)"Unknown GET Parameter"); debug(F100,"sgetinit unknown parameter","",0); return(-1); } p += (len + 1); c = next; } } if (!fs) fs = ""; /* A filename is required */ if (*fs) { havefs = 1; n = 0; /* Check for quoted name */ if ((n = strlen(fs)) > 1) { /* Note: this does not allow for multiple quoted names */ if ((fs[0] == '{' && fs[n-1] == '}') || (fs[0] == '"' && fs[n-1] == '"')) { fs[n-1] = '\0'; fs++; debug(F111,"sgetinit unquoted filename",fs,n); } else n = 0; /* This means no quoting */ } #ifdef PIPESEND debug(F111,"sgetinit",fs,usepipes); if (usepipes && ENABLED(en_hos) && *fs == '!') { cmarg = fs + 1; /* Point past the bang */ *fs = NUL; nfils = -1; pipesend = 1; debug(F111,"sgetinit pipesend",cmarg,pipesend); } if (!pipesend) { /* If it's not a pipe */ #endif /* PIPESEND */ if (n == 0) { /* If the name was not quoted */ #ifndef NOMSEND nfils = fnparse(fs); /* Allow it to be a list of names */ debug(F111,"sgetinit A",fs,nfils); #ifdef COMMENT /* This doesn't work if a GET-PATH is set. */ if (nfils == 1 && !iswild(fs)) { /* Single file */ char * m; if ((x = zchki(fs)) < 0) { /* Check if it's sendable */ switch (x) { case -1: m = "File not found"; break; case -2: m = "Not a regular file"; break; case -3: m = "Read access denied"; break; } errpkt((CHAR *)m); return(-1); } } #endif /* COMMENT */ } else { /* If it was quoted */ #endif /* NOMSEND */ nzxopts = 0; #ifdef UNIXOROSK if (matchdot) nzxopts |= ZX_MATCHDOT; #endif /* UNIXOROSK */ if (recursive) nzxopts |= ZX_RECURSE; /* Treat as a single filespec */ nfils = 0 - nzxpand(fs,nzxopts); debug(F111,"sgetinit B",fs,nfils); cmarg = fs; } #ifdef PIPESEND } #endif /* PIPESEND */ } if (!done) { /* Need more O packets... */ debug(F100,"sgetinit O-Packet TBC","",0); /* To Be Continued */ return(1); } debug(F100,"sgetinit O-Packet done - havefs","",havefs); if (!havefs) { /* Done - make sure we have filename */ errpkt((CHAR *)"GET without filename"); return(-1); } freerpkt(winlo); winlo = 0; /* Back to packet 0 again. */ debug(F101,"sgetinit winlo","",winlo); nakstate = 0; /* Now I'm the sender! */ if (reget) sendmode = SM_RESEND; if (sinit() > 0) { /* Send Send-Init */ #ifdef STREAMING if (!streaming) #endif /* STREAMING */ timint = chktimo(rtimo,timef); /* Switch to per-packet timer */ return(0); /* If successful, switch state */ } else return(-1); /* Else back to server command wait */ } #else /* NOXFER */ #include "ckcdeb.h" VOID proto() { extern int success; success = 0; } #endif /* NOXFER */ ckwart.c000664 045065 024037 00000044453 14767411403 012643 0ustar00fdckermit000000 000000 #define CKWART_C #include #include #include #include "ckcdeb.h" #include "ckcsym.h" #include "ckcasc.h" #include "ckcker.h" #include "ckclib.h" char *wartv = "Wart Version 2.17, 04 February 2024 "; #ifdef MDEBUG /* Use the real ones in this module only */ #ifdef malloc #undef malloc #endif /* malloc */ #ifdef calloc #undef calloc #endif /* calloc */ #ifdef realloc #undef realloc #endif /* realloc */ #ifdef free #undef free #endif /* free */ #endif /* MDEBUG */ #ifdef MAC #define VOID void #endif /* MAC */ /* W A R T */ /* A small subset of "lex". Authors: Jeff Damens, Frank da Cruz Columbia University Center for Computing Activites. First released November 1984. Copyright (C) 1984, 2024, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. */ /* * input format is: * lines to be copied | %state * %% * | CHAR { actions } * ... * %% * more lines to be copied */ #include "ckcdeb.h" /* Includes */ #ifdef STRATUS /* Actually call printf, not our printf-catcher for Kermit */ #ifdef printf #undef printf #endif /* printf */ #ifdef fprintf #undef fprintf #endif /* fprintf */ #endif /* STRATUS */ #ifdef MAC /* Same deal for Macintosh */ #ifdef printf #undef printf #endif /* printf */ #ifdef fprintf #undef fprintf #endif /* fprintf */ #endif /* MAC */ #ifdef UNIX /* And UNIX */ #ifdef printf #undef printf #endif /* printf */ #ifdef fprintf #undef fprintf #endif /* fprintf */ #endif /* UNIX */ /* The following "char" should be changed to "short", "int", or "long" if your wart program will generate more than 127 states. Since wart is used mainly with C-Kermit, which has about 80 states, "char" is adequate. This keeps the program about 3K-4K smaller, which can be critical on 16-bit architectures. */ #ifdef IRIX60 /* Also use short or int if your compiler complains inordinately about "integer conversion resulted in a change of sign"... */ #define TBL_TYPE "short" /* C data type of state table */ #else #define TBL_TYPE "char" /* C data type of state table */ #endif /* IRIX60 */ #define C_L 014 /* Formfeed */ #define SEP 1 /* Token types */ #define LBRACK 2 #define RBRACK 3 #define WORD 4 #define COMMA 5 /* Storage sizes */ #define MAXSTATES 50 /* max number of states */ #define MAXWORD 50 /* max # of chars/word */ #define SBYTES ((MAXSTATES+6)/8) /* # of bytes for state bitmask */ /* Name of wart function in generated program */ #ifndef FNAME #define FNAME "wart" #endif /* FNAME */ /* Structure for state information */ struct transx { CHAR states[SBYTES]; /* included states */ int anyst; /* true if this good from any state */ CHAR inchr; /* input character */ int actno; /* associated action */ struct transx *nxt; }; /* next transition */ typedef struct transx *trans; /* Function prototypes */ #ifdef OS2 typedef VOID WMAINTYPE; #else typedef int WMAINTYPE; #endif /* OS2 */ _PROTOTYP( WMAINTYPE main, (int argc, char **argv) ); _PROTOTYP( VOID fatal, (char *msg) ); _PROTOTYP( VOID setwstate, (int state, trans t) ); _PROTOTYP( int teststate, (int, trans) ); _PROTOTYP( trans rdinput, (FILE *, FILE *) ); _PROTOTYP( VOID initial, (FILE *, FILE *) ); _PROTOTYP( int isin, (char *, int) ); _PROTOTYP( int isword, (int) ); _PROTOTYP( VOID rdword, (FILE *, char *) ); _PROTOTYP( VOID rdstates, (FILE *, FILE *) ); _PROTOTYP( trans newtrans, (void) ); _PROTOTYP( trans rdrules, (FILE *, FILE *) ); _PROTOTYP( VOID statelist, (FILE *, trans) ); _PROTOTYP( VOID copyact, (FILE *, FILE *, int) ); _PROTOTYP( int faction, (trans, int, int) ); _PROTOTYP( VOID emptytbl, (void) ); _PROTOTYP( VOID addaction, (int, int, int) ); _PROTOTYP( VOID writetbl, (FILE *) ); _PROTOTYP( VOID warray, (FILE *, char *, int [], int, char *) ); _PROTOTYP( VOID prolog, (FILE *) ); _PROTOTYP( VOID epilogue, (FILE *) ); _PROTOTYP( VOID copyrest, (FILE *, FILE *) ); _PROTOTYP( int gettoken, (FILE *) ); _PROTOTYP( VOID rdcmnt, (FILE *) ); _PROTOTYP( VOID clrhash, (void) ); _PROTOTYP( int hash, (char *) ); _PROTOTYP( VOID enter, (char *, int) ); _PROTOTYP( int lkup, (char *) ); _PROTOTYP( static char* copy, (char *s) ); /* Variables and tables */ /* lt 1992-10-08 Begin * provide definition for deblog variable * ckcdeb.h declares as extern. DECC AXP is strict about ref/def model * Variable is unused herein, to the best of my knowledge. */ #ifdef VMS int deblog; #endif /* VMS */ /* lt 1992-10-08 End */ static int lines, nstates, nacts; static char tokval[MAXWORD]; static int tbl[MAXSTATES*96]; char *tbl_type = TBL_TYPE; char *txt1 = "\n#define BEGIN state =\n\nint state = 0;\n\nint\n"; char *fname = FNAME; /* Generated function name goes here */ /* rest of program... */ char *txt2 = "()\n\ {\n\ int c,actno;\n\ extern "; /* Data type of state table is inserted here (short or int) */ char *txt2a = " tbl[];\n\ while (1) {\n\ c = input() - 32;\n\ debug(F000,\"PROTO input\",ckitoa(state),c+32);\n\ if (c < 0 || c > 95) c = 0;\n"; char *txt2b = " if ((actno = tbl[c + state*96]) != -1)\n\ switch(actno) {\n"; /* this program's output goes here, followed by final text... */ char *txt3 = "\n }\n }\n}\n\n"; /* * turn on the bit associated with the given state */ VOID #ifdef CK_ANSIC setwstate(int state, trans t) #else setwstate(state,t) int state; trans t; #endif /* CK_ANSIC */ /* setwstate */ { int idx,msk; idx = state/8; /* byte associated with state */ msk = 0x80 >> (state % 8); /* bit mask for state */ t->states[idx] |= msk; } /* * see if the state is involved in the transition */ int #ifdef CK_ANSIC teststate(int state, trans t) #else teststate(state,t) int state; trans t; #endif /* CK_ANSIC */ /* teststate */ { int idx,msk; idx = state/8; msk = 0x80 >> (state % 8); return(t->states[idx] & msk); } /* * read input from here... */ trans #ifdef CK_ANSIC rdinput(FILE *infp, FILE *outfp) #else rdinput(infp,outfp) FILE *infp,*outfp; #endif /* CK_ANSIC */ /* rdinput */ { trans x; lines = 1; /* line counter */ nstates = 0; /* no states */ nacts = 0; /* no actions yet */ fprintf(outfp,"\n%c* WARNING -- This C source program generated by ",'/'); fprintf(outfp,"Wart preprocessor. */\n"); fprintf(outfp,"%c* Do not edit this file; edit the Wart-format ",'/'); fprintf(outfp,"source file instead, */\n"); fprintf(outfp,"%c* and then run it through Wart to produce a new ",'/'); fprintf(outfp,"C source file. */\n\n"); fprintf(outfp,"%c* Wart Version Info: */\n",'/'); fprintf(outfp,"char *wartv = \"%s\";\n\n",wartv); initial(infp,outfp); /* read state names, initial defs */ prolog(outfp); /* write out our initial code */ x = rdrules(infp,outfp); /* read rules */ epilogue(outfp); /* write out epilogue code */ return(x); } /* * initial - read initial definitions and state names. Returns * on EOF or %%. */ VOID #ifdef CK_ANSIC initial(FILE *infp, FILE *outfp) #else initial(infp,outfp) FILE *infp, *outfp; #endif /* CK_ANSIC */ /* initial */ { int c; char wordbuf[MAXWORD]; while ((c = getc(infp)) != EOF) { if (c == '%') { rdword(infp,wordbuf); if (strcmp(wordbuf,"states") == 0) rdstates(infp,outfp); else if (strcmp(wordbuf,"%") == 0) return; else fprintf(outfp,"%%%s",wordbuf); } else putc(c,outfp); if (c == '\n') lines++; } } /* * boolean function to tell if the given character can be part of a word. */ int #ifdef CK_ANSIC isin(char *s, int c) #else isin(s,c) char *s; int c; #endif /* CK_ANSIC */ /* isin */ { for (; *s != '\0'; s++) if (*s == (char) c) return(1); return(0); } int #ifdef CK_ANSIC isword(int c) #else isword(c) int c; #endif /* CK_ANSIC */ /* isword */ { static char special[] = ".%_-$@"; /* these are allowable */ return(isalnum(c) || isin(special,c)); } /* * read the next word into the given buffer. */ VOID #ifdef CK_ANSIC rdword(FILE *fp, char *buf) #else rdword(fp,buf) FILE *fp; char *buf; #endif /* CK_ANSIC */ /* rdword */ { int len = 0,c; while (isword(c = getc(fp)) && ++len < MAXWORD) *buf++ = (char) c; *buf++ = '\0'; /* tie off word */ ungetc(c,fp); /* put break char back */ } /* * read state names, up to a newline. */ VOID #ifdef CK_ANSIC rdstates(FILE *fp, FILE *ofp) #else rdstates(fp,ofp) FILE *fp,*ofp; #endif /* CK_ANSIC */ /* rdstates */ { int c; char wordbuf[MAXWORD]; while ((c = getc(fp)) != EOF && c != '\n') { if (isspace(c) || c == C_L) continue; /* skip whitespace */ ungetc(c,fp); /* put char back */ rdword(fp,wordbuf); /* read the whole word */ enter(wordbuf,++nstates); /* put into symbol tbl */ fprintf(ofp,"#define %s %d\n",wordbuf,nstates); } lines++; } /* * Allocate a new, empty transition node */ trans #ifdef CK_ANSIC newtrans(void) #else newtrans() #endif /* CK_ANSIC */ /* newtrans */ { trans new; int i; new = (trans) malloc(sizeof (struct transx)); for (i=0; istates[i] = 0; new->anyst = 0; new->nxt = NULL; return(new); } /* * read all the rules. */ trans #ifdef CK_ANSIC rdrules(FILE *fp, FILE *out) #else rdrules(fp,out) FILE *fp,*out; #endif /* CK_ANSIC */ /* rdrules */ { trans head,cur,prev; int curtok; head = cur = prev = NULL; while ((curtok = gettoken(fp)) != SEP) switch(curtok) { case LBRACK: if (cur == NULL) cur = newtrans(); else fatal("duplicate state list"); statelist(fp,cur); /* set states */ continue; /* prepare to read char */ case WORD: if ((int)strlen(tokval) != 1) fatal("multiple chars in state"); if (cur == NULL) { cur = newtrans(); cur->anyst = 1; } cur->actno = ++nacts; cur->inchr = (char) (tokval[0] - 32); if (head == NULL) head = cur; else prev->nxt = cur; prev = cur; cur = NULL; copyact(fp,out,nacts); break; default: fatal("bad input format"); } return(head); } /* * read a list of (comma-separated) states, set them in the * given transition. */ VOID #ifdef CK_ANSIC statelist(FILE *fp, trans t) #else statelist(fp,t) FILE *fp; trans t; #endif /* CK_ANSIC */ /* statelist */ { int curtok,sval; curtok = COMMA; while (curtok != RBRACK) { if (curtok != COMMA) fatal("missing comma"); if ((curtok = gettoken(fp)) != WORD) fatal("missing state name"); if ((sval = lkup(tokval)) == -1) { fprintf(stderr,"state %s undefined\n",tokval); fatal("undefined state"); } setwstate(sval,t); curtok = gettoken(fp); } } /* * copy an action from the input to the output file * */ VOID #ifdef CK_ANSIC copyact(FILE *inp, FILE *outp, int actno) #else copyact(inp,outp,actno) FILE *inp,*outp; int actno; #endif /* CK_ANSIC */ /* copyact */ { int c,bcnt; fprintf(outp,"case %d:\n",actno); while (c = getc(inp), (isspace(c) || c == C_L)) if (c == '\n') lines++; if (c == '{') { bcnt = 1; fputs(" {",outp); while (bcnt > 0 && (c = getc(inp)) != EOF) { if (c == '{') bcnt++; else if (c == '}') bcnt--; else if (c == '\n') lines++; putc(c,outp); } if (bcnt > 0) fatal("action doesn't end"); } else { while (c != '\n' && c != EOF) { putc(c,outp); c = getc(inp); } lines++; } fprintf(outp,"\n break;\n"); } /* * find the action associated with a given character and state. * returns -1 if one can't be found. * */ int #ifdef CK_ANSIC faction(trans hd, int state, int chr) #else faction(hd,state,chr) trans hd; int state,chr; #endif /* CK_ANSIC */ /* faction */ { while (hd != NULL) { if (hd->anyst || teststate(state,hd)) if (hd->inchr == ('.' - 32) || hd->inchr == (char) chr) return(hd->actno); hd = hd->nxt; } return(-1); } /* * empty the table... * */ VOID #ifdef CK_ANSIC emptytbl(void) #else emptytbl() #endif /* CK_ANSIC */ { int i; for (i=0; i 1) { if ((infile = fopen(argv[1],"r")) == NULL) { fprintf(stderr,"Can't open %s\n",argv[1]); fatal("unreadable input file"); } } else infile = stdin; if (argc > 2) { if ((outfile = fopen(argv[2],"w")) == NULL) { fprintf(stderr,"Can't write to %s\n",argv[2]); fatal("bad output file"); } } else outfile = stdout; clrhash(); /* empty hash table */ head = rdinput(infile,outfile); /* read input file */ emptytbl(); /* empty our tables */ for (state = 0; state <= nstates; state++) for (c = 1; c < 96; c++) /* find actions, */ addaction(faction(head,state,c),state,c); /* add to tbl */ writetbl(outfile); copyrest(infile,outfile); printf("%d states, %d actions\n",nstates,nacts); exit(GOOD_EXIT); } /* * fatal error handler */ VOID #ifdef CK_ANSIC fatal(char *msg) #else fatal(msg) char *msg; #endif /* CK_ANSIC */ { fprintf(stderr,"error in line %d: %s\n",lines,msg); exit(BAD_EXIT); } VOID #ifdef CK_ANSIC prolog(FILE *outfp) #else prolog(outfp) FILE *outfp; #endif /* CK_ANSIC */ { int c; while ((c = *txt1++) != '\0') putc(c,outfp); while ((c = *fname++) != '\0') putc(c,outfp); while ((c = *txt2++) != '\0') putc(c,outfp); while ((c = *tbl_type++) != '\0') putc(c,outfp); while ((c = *txt2a++) != '\0') putc(c,outfp); while ((c = *txt2b++) != '\0') putc(c,outfp); } VOID #ifdef CK_ANSIC epilogue(FILE *outfp) #else epilogue(outfp) FILE *outfp; #endif /* CK_ANSIC */ { int c; while ((c = *txt3++) != '\0') putc(c,outfp); } VOID #ifdef CK_ANSIC copyrest(FILE *in, FILE *out) #else copyrest(in,out) FILE *in,*out; #endif /* CK_ANSIC */ { int c; while ((c = getc(in)) != EOF) putc(c,out); } /* * gettoken - returns token type of next token, sets tokval * to the string value of the token if appropriate. */ int #ifdef CK_ANSIC gettoken(FILE *fp) #else gettoken(fp) FILE *fp; #endif /* CK_ANSIC */ { int c; while (1) { /* loop if reading comments... */ do { c = getc(fp); if (c == '\n') lines++; } while ((isspace(c) || c == C_L)); /* skip whitespace */ switch(c) { case EOF: return(SEP); case '%': if ((c = getc(fp)) == '%') return(SEP); tokval[0] = '%'; tokval[1] = (char) c; rdword(fp,tokval+2); return(WORD); case '<': return(LBRACK); case '>': return(RBRACK); case ',': return(COMMA); case '/': if ((c = getc(fp)) == '*') { rdcmnt(fp); /* skip over the comment */ continue; } else { /* and keep looping */ ungetc(c,fp); /* put this back into input */ c = '/'; /* put character back, fall thru */ } default: if (isword(c)) { ungetc(c,fp); rdword(fp,tokval); return(WORD); } else fatal("Invalid character in input"); } } } /* * skip over a comment */ VOID #ifdef CK_ANSIC rdcmnt(FILE *fp) #else rdcmnt(fp) FILE *fp; #endif /* CK_ANSIC */ { int c,star,prcnt; prcnt = star = 0; /* no star seen yet */ while (!((c = getc(fp)) == '/' && star)) { if (c == EOF || (prcnt && c == '%')) fatal("Unterminated comment"); prcnt = (c == '%'); star = (c == '*'); if (c == '\n') lines++; } } /* * symbol table management for wart * * entry points: * clrhash - empty hash table. * enter - enter a name into the symbol table * lkup - find a name's value in the symbol table. * */ #define HASHSIZE 101 /* # of entries in hash table */ struct sym { char *name; /* symbol name */ int val; /* value */ struct sym *hnxt; /* next on collision chain */ } *htab[HASHSIZE]; /* the hash table */ /* * empty the hash table before using it... * */ VOID clrhash() { int i; for (i=0; iname = copy(name); cur->val = svalue; cur->hnxt = htab[h]; htab[h] = cur; } /* * find name in the symbol table, return its value. Returns -1 * if not found. */ int #ifdef CK_ANSIC lkup(char *name) #else lkup(name) char *name; #endif /* CK_ANSIC */ { struct sym *cur; for (cur = htab[hash(name)]; cur != NULL; cur = cur->hnxt) if (strcmp(cur->name,name) == 0) return(cur->val); return(-1); }